|
|
688dce88d1
|
refactor(rename)!: llmsproxy → modelrouter(module / 二进制 / 路径 / env)
产品名早已是 ModelRouter,但仓库标识符仍沿用旧名。这次统一,读写两侧都做兼容,
已部署的机器不会因为顺序问题立刻失效。
- go module `llmsproxy` → `modelrouter`;全仓 import 与 `cmd/modelrouter` 同步。
- `Makefile BINARY=modelrouter`;发行包名、systemd unit、/usr/share 资源、
`/usr/local/bin` 目标全部改为 modelrouter。
- 默认配置目录 `/etc/llmsproxy` → `/etc/modelrouter`。**读取侧回退**:插件与
`storeDir` 仍会检查旧路径,所以"先换二进制、后改 unit"不会立即失效。
- 环境变量 `LLMSPROXY_*`(PLUGIN_DIR / XDISPLAY_BASE / ARCH / LIVE_ZEN /
BUILD_DIR)改为 `MODELROUTER_*`;`LLMS_PROXY_MASTER_KEY` →
`MODELROUTER_MASTER_KEY`。旧名在读取侧继续接受。
- 桌面端内嵌核心 `bin/llmsproxy` → `bin/modelrouter`,并保留旧文件名回退,
避免升级到一半的 profile 被判成"core binary missing"。
- 新增 `packaging/migrate-to-modelrouter.sh`:**默认 dry-run**,复制而非移动、
旧目录永不删除、支持 `--rollback`;随 release tar 分发并由 core-dist 校验。
- `deploy.sh` 增加改名保护:发现旧 `/etc/llmsproxy` 而新配置不存在时**中止**,
否则会部署出一个"能启动但没有 key、没有源"的空实例。
- 临时目录前缀 `/tmp/llmsproxy-*` → `/tmp/modelrouter-*`;清理逻辑同时回收两代。
兼容别名(`__llmsproxy_*` 全局、`llmsproxy` SDK 别名、旧路径/旧 env)刻意保留,
它们是升级路径而非遗留;docs/plugins.md 已标注为废弃。
本提交未包含:`adapters/opencodezen.lua`、`adapter_opencodezen_test.go`、
`adapter_opencodezen_live_test.go`(OpenCode UA/免费池的既有改动,另批提交)。
|
2026-10-26 22:28:08 +08:00 |
|
|
|
3c59c33c58
|
feat(adapters): 入向端点移交适配器 —— adapter.ingress + deserialize_request,内核主动让出
plan.md 的 R2 目标里有三行钩子契约,出向两条(serialize_response/serialize_chunk)
Phase 2 已落地,第三条 parse_request(protocol_body) -> unified 一直空着:
/v1/messages 的入向解析硬编码在内核 Go 里(anthropicRequest.toUnified),
Anthropic 改协议就得改内核。本次补齐这条对偶。
## 机制(与出向序列化对称)
- 适配器声明 adapter.ingress = "/v1/messages" 认领入站路径,并实现
deserialize_request(raw_body) -> unified_json。
- 内核 handleMessages 经新增的 parseViaIngress 判定:
- 有适配器认领该路径且实现了钩子 → 让出,解析由适配器完成;
- 无适配器认领 → 内核内置解析运行(R5 兜底,未配置部署仍可服务)。
- 认领了但钩子执行失败 → 硬错误 400,不静默换用另一种协议解析
(客户端说的正是该适配器声称支持的协议,悄悄换解析器只会错误调度)。
- 这是内核里唯一的新判定点,与 serializerFor 对称:出向选序列化器,入向选解析器。
## 内核改动
- internal/lua/vm.go:staticInfo 增 ingress 字段;inspectScript 读取;
新增 VM.AdapterForIngress(path)(确定性选择:同名多认领取字典序最小)。
- internal/gateway/messages.go:handleMessages 改为先读 body → parseViaIngress
(让出)→ 未认领时回落内置 anthropicRequest.toUnified。
内置解析与 anthropicRequest 类型保留——它们是兜底,不是死代码。
## 适配器改动
- internal/lua/adapters/anthropic.lua:声明 adapter.ingress = "/v1/messages",
新增 deserialize_request,把内核原 Go 解析逻辑逐字段移植(system 两种拼写、
content 原样透传、缺省 thinking={enabled:false}、缺 messages 报错)。
内置 anthropic 默认随包播种,因此真实部署里内核总是让出给它,
Go 侧 anthropicRequest.toUnified 退化为纯兜底。
## 测试
- gateway:TestMessagesIngressYieldsToBundledAnthropic(让出后仍 200)、
TestAdapterForIngressClaim(声明可被找到、未声明路径为空、钩子存在)、
TestMessagesKernelFallbackWhenNoAdapterClaims(移除认领适配器后内核兜底仍 200)。
- lua:TestAnthropicDeserializeRequestShape 逐字段核对 Lua 与 Go 产出一致
(system 拼接、content、max_tokens/stream/temperature/top_p/top_k/stop_sequences、
缺省 thinking),TestAnthropicDeserializeRejectsMissingMessages。
- 全量回归:gateway/lua/core/config/types/provider/scheduler/e2e 全绿。
- 文档:docs/lua-adapters.md 补「入向让出钩子」章节 + plan.md 台账更新。
|
2026-10-12 16:32:30 +08:00 |
|
|
|
e4111337cd
|
feat(gateway): /v1/messages 端到端 —— 内核不含任何 Anthropic 出站字段名
Phase 2 收尾。证明「对外协议由适配器决定、内核只调度」不是纸面主张:
Anthropic 客户端打 /v1/messages,拿到的是 Anthropic 形状。
- internal/gateway/messages.go:入向把 Anthropic 请求解析进统一格式
(content blocks 原样保留——只有适配器知道自己的上游接受哪种块类型;
system 支持字符串与 [{type:text,text}] 两种写法)。
调度/配额/AUTO 链/冷却/审计/插件 hook 全部复用 /v1/chat/completions
的同一条路径(serveUnified),差别只有两端线格式。
- internal/lua/adapters/anthropic.lua:新增 serialize_response /
serialize_open_preamble / serialize_chunk / serialize_close,
把统一格式译回 Anthropic Messages 形状(含 content 分块、
stop_reason 反向映射、input/output_tokens 改名)。
- 流式是 message_start → content_block_delta → message_delta →
message_stop;DoneMarker 为空所以内核**不会**擅自加 [DONE]。
内核出向零 Anthropic 字段名:解析是表驱动的,序列化属于适配器。
测试:
- messages_test.go 5 个端到端用例(真实 core+gateway + 只懂 Anthropic 的
假上游):形状/stop_reason/块顺序/usage 命名、流式事件序列、入向校验、
鉴权、以及「未声明钩子时回落 OpenAI 兜底」。
- 修正两个 serializer 测试的前提断言(anthropic 现在确实声明了钩子,
这正是 Phase 2 的意图),并发测试改为按适配器各自校验形状。
golden 字节级未漂移;go test -tags luajit ./... 全绿。
|
2026-10-11 09:51:27 +08:00 |
|