Skip to content

Refactor/engine packages - #4

Merged
plunjoin merged 9 commits into
mainfrom
refactor/engine-packages
Oct 27, 2026
Merged

plunjoin merged 9 commits into
mainfrom
refactor/engine-packages

Conversation

@plunjoin

Copy link
Copy Markdown
Owner

No description provided.

线上反复翻车的四处平台差异,先以补丁形式收进独立分支固定行为:

- Responses 入站:function_call_output 按 call_id 回填函数名(MiniMax /
  Gemini functionResponse 均需要 name);仅含 tool_calls 的 assistant
  content 统一为 "" 而非 null
- OpenAI 兼容出站:normalizeAssistantContent 把 assistant.content=null
  改写为 "",避免 MiniMax 等上游 400
- Custom 引擎:带 tools 请求上游 400 时去掉 tools 降级重试一次,
  保证纯文本可用(与 Antigravity 降级策略一致);stripChatTools
  深拷贝消息,tool 历史折成 user 文本
- Antigravity:并行工具结果合并进同一条 user content(Gemini 惯例);
  无工具通道丢弃空 tool-only assistant;400 无工具重试深拷贝 Messages,
  避免换号重试时污染工具历史
- 失败用量:Manager.Chat/ChatStream 失败时仍返回带 Engine 的
  ChatResult,gateway recordChat 不再传 nil,用量明细可显示引擎来源

回归用例:parseResponsesInput 补名/空 content、chatPayload content
非 null、stripChatTools 折叠、并行 functionResponse 合并均已覆盖。

阶段 1(IR + 能力表)将在此基础上抽内部协议,不改公开行为。
新增 internal/ir:/v1/responses 与 /v1/chat/completions 两个 Wire 入站
解析后统一经过 NormalizeChat,保证所有引擎拿到的是同一份规范化请求——
tools 只含 function(不明类型丢弃并记日志)、tool_choice 随 tools 存亡、
带 tool_calls 的 assistant content 为 ""、role=tool 消息按调用史回填
name。此前这些不变量散在 parseResponsesInput 与各引擎出站前改写里,
chat 入口完全没有保障。

新增 provider.EngineCaps 能力表(CapsFor 按引擎+模型族查询):
antigravity 仅 Gemini 透传 tools(替代 antigravityToolsSupported 的
模型名 if)、custom 带 tools 400 无工具重试、b/codex 直接透传、未知
引擎保守纯文本。antigravity 的 Claude 清洗与 400 重试、custom 的
MiniMax 降级改为查能力表,共享路径不再出现模型名特判。

Responses 入口 toChatTools 对 web_search 等不明类型的丢弃现在记日志
(logf 参数),与 IR 层丢弃日志同一格式。
- toChatTools 只保留 type=function(namespace 拍平),local_shell /
  apply_patch / web_search 等内置工具在入口丢弃并记日志,不再降级成
  同名 function 下发上游。原转换造出的调用客户端可能执行不了;计划
  §5.2 要求非 function 工具不进入任何上游报文。Codex 0.16x+ 的
  shell 工具本就是 function 形态,不受影响
- stripChatTools / isHTTPStatus 从共享 engines_tools.go 挪进
  engine_custom.go(custom 适配器专属降级路径)
- Antigravity 的 tools 透传与 400 无工具重试、custom 的 400 降级均由
  能力表 CapsFor 驱动,共享路由与引擎代码不再按模型名 if/else
- OpenAPI 文档同步更新 /v1/responses 工具行为描述
- contract_matrix_test:Manager.Chat/ChatStream 失败仍返回带 Engine 的
  ChatResult(失败用量可显示引擎来源);model_not_found 无引擎来源可记
- fakeEngine 增加 chatErr/streamErr 注入
- 新增 .github/workflows/test.yml:push main / PR 跑 go vet + go test ./...,
  覆盖 gateway / provider / ir / engine/upstream / upstream/antigravity
- 计划文档进度区更新至阶段 3 完成
- internal/upstream/{antigravity,kiro,workbuddy,codex} → internal/engine/<同名>/
- internal/upstream/custombalance → internal/engine/custombalance
- internal/aistudio → internal/engine/aistudio(含 waa/goja fork 的自引用路径)
- internal/engine/geminiweb 原地不动
- 全部 import 路径同步更新;包名与代码不变,行为无差
- 语义化错误(ModelNotFound/UnsupportedEndpoint/UnavailableError 及
  KindLabel/EndpointForKind)从 provider/errors.go 与 manager.go 下沉到
  internal/engine/errors.go;firstAccountError 改为反射读取账号状态字段,
  避免 engine 包反向依赖具体引擎类型
- 订阅引擎共享转换(SubImageURLs/SubSystemText/SubCooldownActive/
  SubResultUsage/MarshalCompact/DerefInt)下沉到 internal/engine/support.go
- 能力表 CapsFor/EngineCaps 移入 internal/engine/capability.go(引擎包
  将需要查询能力表而不能反向 import provider)
- provider/errors.go 仅保留 IsModelNotFound/IsUnsupportedEndpoint 兼容别名
  (gateway/admin 公共 API 不变)
每个引擎一个目录(实现 + 上游客户端同包),provider 只留 Manager 路由层:

- engine_a.go → engine/geminiweb(GeminiWebEngine→geminiweb.Engine,
  NewGeminiWeb→geminiweb.New,GeminiCredentials→geminiweb.Credentials)
- engine_b.go / engine_b_native.go → engine/aistudio(AIStudioEngine→
  aistudio.Engine、NativeAIStudioEngine→aistudio.NativeEngine,新增公开
  ProbeImage/ProbeEmbedding 替代 manager 越权访问私有 up 字段)
- engine_antigravity.go → engine/antigravity;engine_codex.go → engine/codex;
  engine_kiro.go → engine/kiro;engine_workbuddy.go → engine/workbuddy;
  engine_custom.go → engine/custom(stripChatTools/isHTTPStatus 随迁,
  ProbeCustomModels 一并归位)
- AccountState/AccountCooldown 上移 engine 基础包(所有订阅引擎的管理台
  状态结构;firstAccountError 用反射读取,解 engine 包对具体引擎的反向依赖)
- 编译期 ToolEngine 断言与测试随类型迁入对应包;provider 保留路由、Manager
  与 IsModelNotFound/IsUnsupportedEndpoint 兼容别名

行为无变化:引擎注册名仍为 a/b/codex/antigravity/kiro/workbuddy/custom
(下一提交统一改 a→geminiweb、b→aistudio)。
引擎注册名、模型目录归属、用量记录与账号库全部使用新标识:

- 引擎 Name() 与 ChatResult.Engine:geminiweb(原 a)、aistudio(原 b);
  能力表 case 同步(aistudio/codex 走 OpenAI 兼容族)
- Manager:register/池/账号装配/凭据更新/EngineProxy/引擎目录全部改名;
  加载存量账号与统一账号添加入口同时接受旧值 a/b(gemini 别名保留)
- admin:AccountInput 枚举、就绪统计、凭据更新分支兼容旧值;
  gateway /health 的 engine_a/engine_b 键改为 engine_geminiweb/engine_aistudio,
  Model 的 engine 枚举同步 OpenAPI 文档
- store:账号与用量明细读出时归一历史值(a→geminiweb、b→aistudio),
  存量 DB 行无需迁移即可在新 UI/统计里统一显示
- config:新 yaml 键 engine_geminiweb/engine_aistudio 与
  engine_geminiweb_models/engine_aistudio_models;旧键 engine_a/engine_b
  (含 _models)继续可读,新键优先;default_engine 的 a/b(gemini 别名)
  在 yaml 与 WEB2API_DEFAULT_ENGINE 环境变量两条路径都归一为新名
- Manager 方法 EngineA()/EngineB() 更名 GeminiWeb()/AIStudio();
  Config 字段 EngineA/EngineB 更名 GeminiWeb/AIStudio
- 新增 internal/config/compat_test.go 固定旧键/旧值兼容行为
@plunjoin
plunjoin merged commit 82ac38f into main Oct 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant