@wacry/codeks-bridge 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +13 -0
- package/README.md +40 -2
- package/catalog/README.md +63 -0
- package/catalog/claude-opus-5-5.json +194 -0
- package/catalog/claude-sonnet-5-5.json +194 -0
- package/catalog/deepseek-flash.json +203 -0
- package/catalog/gpt-5.6-sol.json +152 -0
- package/catalog/gpt-6-astra.json +184 -0
- package/catalog/gpt-6-luna.json +178 -0
- package/catalog/gpt-6-sol.json +182 -0
- package/catalog/gpt-6.1-sol.json +187 -0
- package/dist/auth.d.ts +2 -0
- package/dist/auth.js +42 -0
- package/dist/backends/anthropic.d.ts +8 -0
- package/dist/backends/anthropic.js +309 -0
- package/dist/backends/chat.d.ts +16 -0
- package/dist/backends/chat.js +284 -0
- package/dist/backends/deepseek.d.ts +6 -0
- package/dist/backends/deepseek.js +37 -0
- package/dist/backends/responses.d.ts +5 -0
- package/dist/backends/responses.js +205 -0
- package/dist/carrier.d.ts +22 -0
- package/dist/carrier.js +61 -0
- package/dist/catalog.d.ts +8 -0
- package/dist/catalog.js +40 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +64 -0
- package/dist/compaction-handoff.d.ts +13 -0
- package/dist/compaction-handoff.js +126 -0
- package/dist/compaction-history.d.ts +7 -0
- package/dist/compaction-history.js +20 -0
- package/dist/compaction.d.ts +20 -0
- package/dist/compaction.js +134 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +167 -0
- package/dist/errors.d.ts +43 -0
- package/dist/errors.js +141 -0
- package/dist/headers.d.ts +6 -0
- package/dist/headers.js +39 -0
- package/dist/history.d.ts +7 -0
- package/dist/history.js +85 -0
- package/dist/ids.d.ts +1 -0
- package/dist/ids.js +4 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -0
- package/dist/inspect/capture.d.ts +119 -0
- package/dist/inspect/capture.js +370 -0
- package/dist/inspect/http.d.ts +7 -0
- package/dist/inspect/http.js +149 -0
- package/dist/inspect/view.d.ts +239 -0
- package/dist/inspect/view.js +388 -0
- package/dist/model-catalog.d.ts +18 -0
- package/dist/model-catalog.js +16 -0
- package/dist/profiles.d.ts +6 -0
- package/dist/profiles.js +63 -0
- package/dist/prompts.d.ts +5 -0
- package/dist/prompts.js +118 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +232 -0
- package/dist/sse.d.ts +12 -0
- package/dist/sse.js +93 -0
- package/dist/tool-history.d.ts +4 -0
- package/dist/tool-history.js +72 -0
- package/dist/tools.d.ts +33 -0
- package/dist/tools.js +182 -0
- package/dist/types.d.ts +115 -0
- package/dist/types.js +1 -0
- package/dist/upstream.d.ts +3 -0
- package/dist/upstream.js +84 -0
- package/dist/writer.d.ts +95 -0
- package/dist/writer.js +430 -0
- package/docs/backends-anthropic.md +61 -0
- package/docs/backends-deepseek-chat.md +75 -0
- package/docs/backends-responses.md +33 -0
- package/docs/compaction.md +176 -0
- package/docs/config.md +231 -0
- package/docs/design.md +93 -0
- package/docs/inspect.md +138 -0
- package/docs/reasoning.md +72 -0
- package/docs/releasing.md +50 -0
- package/docs/responses-stream.md +90 -0
- package/docs/testing.md +177 -0
- package/docs/tools.md +55 -0
- package/examples/config.json +35 -0
- package/package.json +46 -4
- package/ui/api.js +64 -0
- package/ui/app.css +375 -0
- package/ui/app.js +489 -0
- package/ui/detail.js +682 -0
- package/ui/diff.js +281 -0
- package/ui/dom.js +258 -0
- package/ui/events.js +351 -0
- package/ui/favicon.svg +1 -0
- package/ui/index.html +58 -0
- package/ui/labels.js +101 -0
- package/ui/list.js +180 -0
- package/ui/structure.js +285 -0
- package/ui/tree.js +158 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# 压缩与跨模型恢复
|
|
2
|
+
|
|
3
|
+
压缩不是普通 reasoning:检查点可能是早期对话的唯一剩余表示。bridge 支持直接生成文字摘要,也支持先生成原生检查点,在目标需要文字时再向原来源复述。生成方式、执行模型与恢复时的来源策略分别配置。这项机制用于切换模型,前提是原模型、原端点和对应配置仍然可用。
|
|
4
|
+
|
|
5
|
+
## 配置
|
|
6
|
+
|
|
7
|
+
| 配置 | 含义 | 默认 |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| `compaction.mode: "summary"` | 用标准压缩 prompt 汇总原历史,只保存文字摘要 | Claude / DeepSeek |
|
|
10
|
+
| `compaction.mode: "native"` | 保存原生检查点及复述配方,按需生成文字表示 | GPT Responses |
|
|
11
|
+
| `compaction.model` | 执行压缩的已有模型别名;只引用一层,不改变生成模式 | 工作模型自身 |
|
|
12
|
+
| `compaction.native_replay` | 恢复时是否使用允许来源的原生表示 | GPT 为 true,其他为 false |
|
|
13
|
+
| `replay.native_compaction_from` | 除自身外,允许的原生来源模型别名 | 空列表 |
|
|
14
|
+
| 顶层 `compaction_cache_dir` | 保存成功的按需复述及其用量 | `$XDG_CACHE_HOME/codeks-bridge/compaction`,未设置 XDG 时为 `~/.cache/codeks-bridge/compaction` |
|
|
15
|
+
|
|
16
|
+
例如 GPT 目标可以设 `mode: "summary"`、`native_replay: true`:它自己只生成文字摘要,但仍可读取允许来源的原生检查点。另一目标可以使用 `native` 生成原生检查点,却通过 `native_replay: false` 在后续请求中始终使用文字表示。Claude/DeepSeek adapter 没有原生压缩格式,自己执行时使用 `summary`;也可设置 `mode: "native"` 和 `model`,委托支持原生格式的别名执行。工作模型的 `native_replay` 不因此改变。
|
|
17
|
+
|
|
18
|
+
原生表示由 adapter 的 `native_compaction_format` 声明,不通过 GPT 模型名判定。未来其他协议提供原生检查点时,需要实现该格式的生成与恢复;文字摘要、来源策略和压缩协调层可以继续复用。只有参数或部署能力不同,则优先使用目录及配置表达。
|
|
19
|
+
|
|
20
|
+
允许来源是定向、非传递的关系,与 reasoning 的列表互不影响。bridge 只检查格式能否还原,兼容配对由配置明确选择。原生压缩生成失败或原生检查点被拒绝都按上游错误返回,不自动改成文字压缩重试。
|
|
21
|
+
|
|
22
|
+
`compaction.model` 复用已有连接、adapter、参数与鉴权;实际调用只跟随这一层引用,模式始终取工作模型的 `compaction.mode`。未设置执行别名或引用自身别名时沿用请求 effort;引用其他别名时使用执行别名的默认 effort,再做该模型的原生映射。原生参数 options 保持正常覆盖规则。检查点来源及复述配方记录实际执行模型,后续修改委托配置不会改变旧检查点的来源。配置示例见[压缩模式与执行模型](config.md#压缩模式与执行模型)。
|
|
23
|
+
|
|
24
|
+
## 客户端契约与保留历史
|
|
25
|
+
|
|
26
|
+
codeks 的远程压缩 V2 仍调用 `POST /responses`,输入末项为 `{"type":"compaction_trigger"}`,保留完整历史及 Lite `additional_tools` 声明。bridge 在 `response.completed` 前交付恰好一个 `compaction` item。
|
|
27
|
+
|
|
28
|
+
```toml
|
|
29
|
+
[model_providers.bridge.capabilities]
|
|
30
|
+
remote_compaction = "v2"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
两种生成模式都使用这条路径,客户端继续执行远程 V2 的历史保留规则。bridge 不提供独立的 `/responses/compact` 接口,也不把整个压缩前历史藏进载荷。
|
|
34
|
+
|
|
35
|
+
已核对的 codeks `0.162.1` 与 Codex `0.163.0` 行为是成功后保留最多约 64,000 tokens 的近期用户消息及其他符合规则的消息,再附检查点;本地 prompt 压缩路径约为 20,000 tokens。下文将压缩前历史称为 `AAAA`,保留消息称为 `U`,原生检查点称为 `K`,压缩后新增的工作称为 `BBBB`。
|
|
36
|
+
|
|
37
|
+
按需复述在后续请求中取得客户端已经保存的 `U + K + BBBB`,直接使用 `K` 前的实际保留消息,不再次裁剪,也不把 `BBBB` 放进旧检查点的复述请求。客户端重新注入的环境上下文也随实际保留历史使用。升级客户端时应复核 `codex-rs/core/src/compact_remote_v2_attempt.rs`、`compact_remote_v2.rs` 和 `codex-rs/protocol/src/models.rs`。
|
|
38
|
+
|
|
39
|
+
### `comp_hash` 与原生状态兼容性
|
|
40
|
+
|
|
41
|
+
Codex 目录中的 `comp_hash` 是压缩兼容组的标识,不是提示词内容的 hash。`0.163.0` 在前后两轮的非空值不同时,会先调用上一模型执行压缩;切换到更小窗口时也有独立的压缩判断。相同值只避免因兼容组变化而额外压缩,不关闭窗口用量检查。
|
|
42
|
+
|
|
43
|
+
当前八个条目保留源目录的 `"3000"`。bridge 检查点提供文字摘要,或提供向原来源生成文字摘要的配方,因此目标可以继续消费同一个检查点,无需按模型另造兼容组。是否恢复其中的原生密文仍由来源、格式和 `native_replay` 策略决定;相同 `comp_hash` 不表示 GPT、Claude 或不同区域之间能直接共享密文。
|
|
44
|
+
|
|
45
|
+
上游改变 `comp_hash` 或切换模型时的压缩逻辑后,应复核 `codex-rs/core/src/session/turn.rs` 及检查点恢复契约,再决定是否沿用新值。提示词或窗口调整本身不是重新计算此字段的理由。
|
|
46
|
+
|
|
47
|
+
## 生成与提示词
|
|
48
|
+
|
|
49
|
+
### `summary`:标准文字压缩
|
|
50
|
+
|
|
51
|
+
将 trigger 换成现有的 `CRITICAL: Respond with TEXT ONLY. Do NOT call any tools...` 标准 prompt,保留原 instructions、历史、工具定义及工具选择,移除结构化输出格式。
|
|
52
|
+
|
|
53
|
+
这份提示词要求按对话顺序梳理用户意图、技术决策、相关文件与代码、错误修复、待办和当前工作,并原样保留用户提出的安全约束。它区分真实 user 消息与 assistant 引用的“用户话语”,输出 `<analysis>` 和 `<summary>` 两个文本块,完整文本一并保存。它没有要求逐条复述全部用户消息,因为客户端会自行保留符合预算的用户历史。
|
|
54
|
+
|
|
55
|
+
Claude 摘要保留工具及公共前缀的 `1h` 缓存,只将最后的摘要请求末块设为 `5m`。缓存是否命中不影响正确性。
|
|
56
|
+
|
|
57
|
+
### `native`:原生压缩与按需复述
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
压缩时:AAAA + compaction_trigger → 保存 K 和复述配方
|
|
61
|
+
兼容目标续聊:U + K + BBBB → 直接使用 K
|
|
62
|
+
需要文字时:原来源接收源请求前缀 + U + K + handoff prompt → 缓存文字摘要
|
|
63
|
+
目标续聊:U + 文字摘要 + BBBB
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
复述由生成 `K` 的原模型和原连接执行。原生请求移除普通回答的输出预算,交由上游管理;复述使用普通回答预算。源请求前缀包括开头的 system/developer 消息和工具声明;中途新增的 Lite 工具声明也按原顺序收集,确保原工具仍可解释。工具声明集中放在源前缀,不保留它们与旧对话的交错位置;因此精确保留 `U` 不代表完整工具布局也逐字一致。复述保留源 instructions、reasoning、缓存 key、工具选择和未知请求参数,重新构造 input、stream,并移除文字输出约束。
|
|
67
|
+
|
|
68
|
+
这是用户选择的质量策略:优先让原生压缩整理任务状态,再把该状态交接给其他模型。复述 prompt 是 Codex 压缩 prompt 的微调英文版本,明确说明此前已压缩,要求全面完整地复述现有任务状态,覆盖进度、决策、约束、待办和关键引用;不再要求再次精简,也不强制标准文字压缩的 `<analysis>/<summary>` 格式。保留用户给定的正文,末尾补充只输出文字、不调用工具的要求。原文集中在 [`src/prompts.ts`](https://github.com/WAcry/codeks-bridge/blob/main/src/prompts.ts) 的 `HANDOFF_PROMPT`。
|
|
69
|
+
|
|
70
|
+
复述仍是模型生成,并不是密文的可逆解码,可能遗漏或误述细节。实测的长度和事实覆盖用于选择提示词,不能保证任意历史都无损;输出 token 数也不是独立的质量证明。
|
|
71
|
+
|
|
72
|
+
按需复述保留了正常续聊的 `U + K` 前缀,有机会复用 prompt cache;真实命中还受请求布局、服务路由和缓存有效期影响,不保证命中。确定的收益是始终使用兼容目标时,完全没有额外的文字复述请求。需要文字的目标会等待首次复述完成;“按需”表示延后到真正使用时生成,不是后台任务。
|
|
73
|
+
|
|
74
|
+
原来源在配置中继续可用。bridge 优先选择配方记录的原别名,也接受连接、adapter 和实际部署相同的其他别名;实际鉴权与 options 读取当前配置。配方保存源请求前缀,以及除 `input`、`stream`、`text` 外的请求 body,避免参数白名单遗漏未来字段;不保存 HTTP header、连接凭据或完整 `AAAA`。复述沿用本次客户端请求的 metadata,见 [header 边界](responses-stream.md#header-与转发边界)。
|
|
75
|
+
|
|
76
|
+
成功的复述及其独立 usage 写入 `compaction_cache_dir`。缓存键包含原来源、实际复述请求及 prompt,不包含 `BBBB`;同一输入的后续请求与服务重启可以复用结果。文件以 `0600` 权限原子写入,新目录使用 `0700`。同一服务实例内,相同键的请求排队后读取已有结果,各自取消互不牵连;不同进程之间没有去重协调。
|
|
77
|
+
|
|
78
|
+
缓存保存的是可读任务摘要,应按会话数据管理。删除缓存后,下次需要时重新生成。缓存写入失败会返回错误,不继续发送目标请求;没有失效条目或失败响应的缓存。若目标请求随后失败,已经成功保存的复述仍可供客户端重试复用。
|
|
79
|
+
|
|
80
|
+
### 委托压缩与切换模型
|
|
81
|
+
|
|
82
|
+
先选择实际执行模型,再按它的策略恢复待压缩历史。普通请求按工作模型恢复历史;压缩请求按 `compaction.model` 指向的执行模型恢复。因此,Claude 已经用过某个检查点的文字摘要,也不会迫使兼容的 GPT 压缩器继续使用该摘要:原生 `K` 仍在客户端历史中,执行模型允许时直接恢复它。执行模型不允许该来源时,先取得文字表示,再用它压缩。
|
|
83
|
+
|
|
84
|
+
以 Claude 委托 GPT 为例:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
Claude 请求压缩:GPT 接收 AAAA + trigger → bridge 返回 K
|
|
88
|
+
codeks 安装实际保留历史 U + K
|
|
89
|
+
Claude 下一请求:原 GPT 接收源前缀 + U + K + handoff prompt → 缓存摘要 S
|
|
90
|
+
Claude 接收 U + S + 后续内容
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
GPT 返回 `K` 时,客户端尚未选定最终的 `U`。让 codeks 先安装检查点,再从下一条真实请求取得 `U`,可以复用现有按需复述流程,无需复制客户端的保留算法。自动压缩后正常继续的请求即可触发,不需要用户再发一轮消息。
|
|
94
|
+
|
|
95
|
+
同样适用于多次切换:GPT 生成 `K1`,Claude 首次接续时使用 `S1`;Claude 的新工作使上下文再次达到阈值后,兼容的 GPT 执行模型接收 `U1 + K1 + 新工作` 并生成 `K2`。Claude 随后取得 `S2`;切回允许该来源的 GPT 时仍可恢复 `K2`。历史中的外来 reasoning 继续由执行模型的独立来源策略筛选,不因压缩委托而共享。
|
|
96
|
+
|
|
97
|
+
用户选择这一可选路径,是希望即使主要使用文字模型,也能利用原生压缩整理任务状态的能力。已有 GPT 复述实验支持该设计,但未证明每种 Claude 历史都优于标准摘要。委托会增加实际调用与等待,跨模型输入也可能无法复用 prompt cache;不承诺固定成本增幅。标准 `summary` 保持可选。压缩阈值仍由工作模型决定,bridge 不换算不同模型的 token 比例、不裁剪超限输入,实际容量错误直接返回。
|
|
98
|
+
|
|
99
|
+
### 工具选择与缓存
|
|
100
|
+
|
|
101
|
+
文字摘要和按需复述沿用普通请求的工具定义及 `tool_choice`,包括原生 options 的覆盖;缺省保持缺省,`auto` 保持 `auto`,显式 `required` 或指定工具也不静默改写。各 adapter 继续执行正常的协议转换,不因为是摘要而强制设置 `none`。只输出文字、不调用工具的要求写在 prompt 中。
|
|
102
|
+
|
|
103
|
+
用户选择这项策略,是为了保留正常会话的缓存条件,并信任模型遵守摘要指令。Claude 官方说明,改变 `tool_choice` 会使消息缓存失效,工具和 system 缓存仍可复用。[缓存失效规则](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#what-invalidates-the-cache) GPT 尚未做隔离该参数的 A/B 实测,因此不宣称同样修改必然导致 GPT 缓存失效。保持参数一致只减少桥接器主动引入的差异,不保证远端命中。
|
|
104
|
+
|
|
105
|
+
模型若仍返回工具调用,摘要直接以 `invalid_prompt` 失败,不执行工具、不伪造工具结果,也不再发一轮“禁止工具”的请求。显式强制工具选择与摘要任务冲突时,也按同样的上游或摘要校验错误暴露。codeks 决定后续处理;bridge 不增加重试或改成 `none` 兜底。
|
|
106
|
+
|
|
107
|
+
## 交付、错误与用量
|
|
108
|
+
|
|
109
|
+
`summary` 在摘要成功后交付;`native` 在原生压缩成功后交付。原生结果须恰好包含一个非空压缩项,文字摘要须非空且完整结束;工具调用、拒绝或截断都不当作完整摘要。辅助请求的 incomplete 返回 `invalid_prompt`,原响应保留为诊断;流内失败保留原 error,但不交付辅助请求的部分 output 或 usage。
|
|
110
|
+
|
|
111
|
+
下游 HTTP 200 等目标上游请求被接受后才发送;需要按需复述时,先完成文字准备,再发送目标请求。这样各阶段的 HTTP 失败仍能保留原状态码。若上游已经进入 SSE 后失败,则保留原流内错误路径。等待期间没有下游心跳,具体边界见 [Responses 流](responses-stream.md)。
|
|
112
|
+
|
|
113
|
+
bridge 不重试、不自动换端点或换压缩方式。原生压缩失败时不交付新检查点;已经交付 `K` 后复述失败时,`K` 仍保存在客户端,目标请求收到错误但不会被发送到目标上游,重试可直接重新复述。复述成功但目标请求失败时,后续重试可复用缓存。客户端断开会取消当前正在执行的请求,已经发生的用量仍可能计费。
|
|
114
|
+
|
|
115
|
+
客户端 `response.usage` 与实际调用按下面的边界分开:
|
|
116
|
+
|
|
117
|
+
| 客户端响应 | 返回的 usage |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `summary` 压缩 | 执行模型的 summary 调用 |
|
|
120
|
+
| `native` 压缩,包括委托其他模型 | 执行模型的 native 调用 |
|
|
121
|
+
| 需要先生成 handoff 的普通请求 | 最后工作模型的 main 调用 |
|
|
122
|
+
|
|
123
|
+
handoff 的 usage 单独保存在缓存及[检查器](inspect.md)捕获的上游响应中,不加入压缩响应或后续回答。codeks 会用 usage 判断当前上下文,累加不同调用会把辅助请求误算成目标上下文;不同模型的 token 计量也不应混合。代价是客户端累计用量不包含 handoff 开销,排查实际消耗时应查看各次上游调用。缓存命中没有新调用,不再次计入之前保存的用量。
|
|
124
|
+
|
|
125
|
+
## 保存格式与恢复
|
|
126
|
+
|
|
127
|
+
`compaction` item 使用:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
cxbc1:<base64url(JSON)>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`cxbc` 标识 bridge 的压缩封装,`1` 标识持久化数据格式,不代表 bridge 版本、模型或密文兼容组。格式标记供恢复会话时解释载荷;模型之间能否复用仍由来源、格式和配置决定。
|
|
134
|
+
|
|
135
|
+
`native` 检查点保存原生状态和复述配方:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"native": {
|
|
140
|
+
"source": {
|
|
141
|
+
"id": "source-fingerprint",
|
|
142
|
+
"connection": "connection-fingerprint",
|
|
143
|
+
"model": "deployment-name",
|
|
144
|
+
"adapter": "gpt-responses"
|
|
145
|
+
},
|
|
146
|
+
"format": "responses.compaction.v1",
|
|
147
|
+
"data": {
|
|
148
|
+
"type": "compaction",
|
|
149
|
+
"encrypted_content": "original-encrypted-content"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"handoff": {
|
|
153
|
+
"prefix": [],
|
|
154
|
+
"parameters": { "model": "source-alias" },
|
|
155
|
+
"responsesLite": true
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`summary` 检查点只保存 `summary` 文字字段。原生检查点的 `handoff` 包含 `prefix`、上述请求 `parameters` 和 `responsesLite` 标记,足以在后续请求提供的 `U` 上生成文字。原生 data 保留完整上游 item;来源指纹计算见 [reasoning](reasoning.md)。
|
|
161
|
+
|
|
162
|
+
每次普通请求或再次压缩前,bridge 按实际执行目标选表示;普通请求是工作模型,压缩请求是选定的压缩执行模型:
|
|
163
|
+
|
|
164
|
+
1. 有原生状态、开启 `native_replay`、来源允许、格式匹配:还原原生 item。
|
|
165
|
+
2. 其他情况已有文字摘要:将恢复前缀和文字摘要作为 user message。
|
|
166
|
+
3. 其他情况尚无文字摘要:读取缓存或向原来源按需生成,再执行第二步。
|
|
167
|
+
|
|
168
|
+
这是发送前的表示选择;第一种请求被上游拒绝时直接返回错误,不自动再试文字表示。生成复述必须读取源自身的 `K`,不受源路由普通续聊的 `native_replay: false` 限制。
|
|
169
|
+
|
|
170
|
+
恢复不改写客户端保存的载荷。按需复述只更新本次请求的副本,并通过本地缓存复用;切换模型再切回来,仍可使用原检查点。再次压缩后,新检查点取代旧检查点,不累积每个模型的检查点版本。外部原生检查点若没有 bridge 摘要或复述配方,不能保证跨目标恢复,因此明确报错。
|
|
171
|
+
|
|
172
|
+
恢复前缀逐字取自 Codex `rust-v0.162.1` 的 `codex-rs/prompts/templates/compact/summary_prefix.md`;handoff prompt 的许可归属见 `NOTICE`。外层是编码而非加密:文字摘要、请求前缀和参数可读,原生密文保持原样。
|
|
173
|
+
|
|
174
|
+
近期保留消息可能与摘要包含相同信息,这是客户端历史策略的一部分。客户端压缩后可能按 `encrypted_content` 长度粗估 token,复述配方会让估算偏保守;下一次正常响应的 usage 提供实际用量。bridge 不伪造 usage 或修改客户端公式。
|
|
175
|
+
|
|
176
|
+
实现见 [`src/compaction.ts`](https://github.com/WAcry/codeks-bridge/blob/main/src/compaction.ts)、[`src/compaction-history.ts`](https://github.com/WAcry/codeks-bridge/blob/main/src/compaction-history.ts)、[`src/compaction-handoff.ts`](https://github.com/WAcry/codeks-bridge/blob/main/src/compaction-handoff.ts)、[`src/carrier.ts`](https://github.com/WAcry/codeks-bridge/blob/main/src/carrier.ts) 和 [`src/history.ts`](https://github.com/WAcry/codeks-bridge/blob/main/src/history.ts)。
|
package/docs/config.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# 配置
|
|
2
|
+
|
|
3
|
+
`serve --config FILE` 在启动时读取 JSON。配置文件和凭据放在仓库外,完整起点见 [examples/config.json](../examples/config.json)。
|
|
4
|
+
|
|
5
|
+
## 目录、别名与连接
|
|
6
|
+
|
|
7
|
+
`upstreams` 只描述连接。`models` 的键是 codeks 显示和请求的别名,每个别名由三项配置组成:
|
|
8
|
+
|
|
9
|
+
| 字段 | 示例 | 用途 |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| `catalog` | `gpt-6.1-sol` | 选择已审阅的模型条目,包括提示词、能力、默认参数与 adapter |
|
|
12
|
+
| `upstream` | `primary` | 选择连接、鉴权和区域 |
|
|
13
|
+
| `model` | `deployment-a` | 实际发给上游的模型或部署名 |
|
|
14
|
+
|
|
15
|
+
当前支持的八个 key 见[模型目录](../catalog/README.md)。没有通用兜底条目,未知 key 在加载配置时报错。实际部署名无需与 key 相同,也不用于推断协议。
|
|
16
|
+
|
|
17
|
+
| 目录模型 | 条目指定的 adapter | 上游路径 |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| GPT 系列 | [`gpt-responses`](backends-responses.md) | `/responses` |
|
|
20
|
+
| Claude Opus / Sonnet | [`claude-messages`](backends-anthropic.md) | `/messages` |
|
|
21
|
+
| DeepSeek Flash | [`deepseek-chat`](backends-deepseek-chat.md) | `/chat/completions` |
|
|
22
|
+
|
|
23
|
+
同一个兼容网关的连接可供不同条目使用。服务按每条请求的别名独立选路,因此父代理、子代理和并行会话可以同时使用不同上游。别名固定对应一个目标,不做上游模型发现或自动负载均衡。
|
|
24
|
+
|
|
25
|
+
多个别名也可选择同一目录条目和部署,仅设置不同的窗口预算:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"gpt-small": {
|
|
30
|
+
"catalog": "gpt-6.1-sol", "upstream": "primary", "model": "deployment-a",
|
|
31
|
+
"context_window": 272000
|
|
32
|
+
},
|
|
33
|
+
"gpt-large": {
|
|
34
|
+
"catalog": "gpt-6.1-sol", "upstream": "primary", "model": "deployment-a",
|
|
35
|
+
"context_window": 872000
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
窗口值只是客户端预算,实际部署必须支持该值。同一连接、adapter 和部署的状态身份相同,不因别名或窗口预设而变化。
|
|
41
|
+
|
|
42
|
+
## 服务
|
|
43
|
+
|
|
44
|
+
| 字段 | 含义 |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `host` | 默认 `127.0.0.1` |
|
|
47
|
+
| `port` | 默认 `8787`;程序集成测试可用 `0` 分配端口 |
|
|
48
|
+
| `token_env` | 保存 bridge 入口 Bearer token 的环境变量名称 |
|
|
49
|
+
| `compaction_cache_dir` | 按需复述缓存目录;默认 `$XDG_CACHE_HOME/codeks-bridge/compaction`,未设置 XDG 时为 `~/.cache/codeks-bridge/compaction` |
|
|
50
|
+
| `upstreams` | 上游连接配置表 |
|
|
51
|
+
| `models` | 模型别名表,是否进入客户端目录由各自的 `expose` 控制 |
|
|
52
|
+
| `inspect` | 可选;`capture` 决定启动时是否捕获,`max_mib` 是内存软上限,见[调试检查器](inspect.md) |
|
|
53
|
+
|
|
54
|
+
监听非 loopback 地址时必须配置 `token_env`,客户端也要设置同一个变量。它是 bridge 入口鉴权,不是上游 API key。HTTP 请求体最多 64 MiB,包含所有图片编码;入口没有 CORS。携带 `Origin` 的请求必须使用配置好的 bridge token,即使监听 loopback 也一样,避免网页的简单 POST 在无法读取响应时仍触发上游调用。没有 `Origin` 的 codeks 请求保持原行为。`GET /health`、`GET /v1/models` 和 `POST /v1/responses` 使用同一鉴权。`/inspect/` 页面与接口使用[自己的规则](inspect.md#访问与鉴权)。
|
|
55
|
+
|
|
56
|
+
## 上游连接
|
|
57
|
+
|
|
58
|
+
| 字段 | 含义 |
|
|
59
|
+
| --- | --- |
|
|
60
|
+
| `base_url` | 包含版本前缀的 HTTP(S) URL;adapter 在其后追加请求路径 |
|
|
61
|
+
| `api_key_env` | API key 环境变量名称 |
|
|
62
|
+
| `api_key_command` | 与 `api_key_env` 二选一;argv 数组,程序 stdout 返回当前凭据 |
|
|
63
|
+
| `auth_header` | 覆盖鉴权 header 名;默认 GPT/DeepSeek 用 `authorization: Bearer …`,Claude 用 `x-api-key` |
|
|
64
|
+
| `stream_idle_timeout_ms` | 等待上游 headers 或后续字节的最长空闲时间,默认 300000 ms |
|
|
65
|
+
| `headers` | 静态 header,覆盖同名客户端 header,例如 API 版本 |
|
|
66
|
+
| `options` | 原生请求参数,覆盖 adapter 推导出的参数 |
|
|
67
|
+
|
|
68
|
+
`api_key_command` 不经过 shell,每条上游请求执行一次,最多 30 秒,适合短期凭据。命令错误不会把 stdout/stderr 回传客户端。连接无需 key 的服务时可省略凭据设置。Claude 默认版本 header 为 `anthropic-version: 2023-06-01`。客户端 metadata 默认透传,鉴权使用上游配置;覆盖顺序及必要过滤见 [header 边界](responses-stream.md#header-与转发边界)。
|
|
69
|
+
|
|
70
|
+
## 模型
|
|
71
|
+
|
|
72
|
+
| 字段 | 含义 |
|
|
73
|
+
| --- | --- |
|
|
74
|
+
| `upstream` | 连接表中的 ID;不同区域或凭据域使用不同 ID |
|
|
75
|
+
| `model` | 实际上游模型名;可以是部署别名 |
|
|
76
|
+
| `catalog` | 必填,已审阅条目的 key;条目决定 adapter |
|
|
77
|
+
| `expose` | 默认 `true`;设为 `false` 时不进入客户端 HTTP 目录和 CLI 导出的静态目录 |
|
|
78
|
+
| `context_window` | 可选窗口预算;设置时同时覆盖客户端的 `context_window` 和 `max_context_window` |
|
|
79
|
+
| `max_output_tokens` | 覆盖目录的默认回答输出预算;请求中的显式值优先于模型配置 |
|
|
80
|
+
| `input_modalities` | 可选,覆盖条目中的 `text`/`image` 能力声明 |
|
|
81
|
+
| `reasoning` | 默认 effort 及其到原生值的映射 |
|
|
82
|
+
| `replay` | 分别允许哪些来源的 reasoning、原生压缩 |
|
|
83
|
+
| `compaction` | 压缩方式、执行模型,以及本目标是否接收原生压缩 |
|
|
84
|
+
| `options` | 原生请求参数,覆盖上游级 options |
|
|
85
|
+
|
|
86
|
+
`expose` 控制目录展示,不改变别名的路由、来源身份或访问权限。隐藏模型仍可用于压缩、handoff 和状态复用,显式按别名发送请求也仍可调用;inspector 保留其诊断记录。`config-snippet` 选择首个公开别名作为默认模型;全部隐藏时目录为空,该命令明确报错。
|
|
87
|
+
|
|
88
|
+
不设置窗口时,原条目的两个窗口字段各自保留。当前 GPT 条目为 `context_window: 272000`、`max_context_window: 872000`;Opus 5.5、Sonnet 5.5 和 DeepSeek Flash 的两个字段均为 `1000000`。压缩阈值沿用模板的 `auto_compact_token_limit: null`,由客户端按窗口计算。Claude Messages 必须提供 `max_tokens`,对应目录外层默认预算为 `128000`;GPT 和 DeepSeek 使用请求、模型配置或上游提供的默认值。原生 options 也可调整预算,实际限制由部署端点裁决。
|
|
89
|
+
|
|
90
|
+
请求先由 adapter 转换,再浅层合并 `upstream.options`、`model.options`;后者优先,嵌套对象整体替换。例如模型 `options.output_config` 会替换推导值和上游同名对象。由此可以显式调整 thinking budget、原生 effort 或端点专有字段。
|
|
91
|
+
|
|
92
|
+
最终由 bridge 固定模型路由、转换后的历史、工具定义、流模式和必要协议字段。摘要请求保留普通工具选择并移除结构化输出约束;原生压缩移除普通回答的输出上限。必须重建的字段承载桥接契约,不由 options 改写。详见上表链接的后端文档,以及[摘要的工具选择](compaction.md#工具选择与缓存)。
|
|
93
|
+
|
|
94
|
+
## Reasoning 与模型目录
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"reasoning": {
|
|
99
|
+
"default_effort": "high",
|
|
100
|
+
"effort_map": { "low": "low", "high": "high", "max": "max" }
|
|
101
|
+
},
|
|
102
|
+
"input_modalities": ["text", "image"]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`effort_map` 的键是 codeks 可选档位,值是发给上游的原生值。提供映射时完整替换目录条目的默认映射;`default_effort` 必须出现在映射中。未指定默认档位时,保留映射中仍存在的条目默认值,否则选映射第一项。映射为原生 `none` 时,Messages/DeepSeek adapter 发送 `thinking.type: "disabled"`,是否接受由上游决定。Claude 5.5 目录不提供这个档位;Sonnet 的 `between_tools` 模式可通过显式 options 选择,含义和配置见 [Messages](backends-anthropic.md)。
|
|
107
|
+
|
|
108
|
+
请求没有 effort 时使用配置默认值;有映射则转换,未列出的显式 effort 直接透传,交给上游判断。catalog 与实际请求使用同一份配置;通过原生 `options` 再覆盖 thinking/effort 时,应同时调整这里的展示设置。
|
|
109
|
+
|
|
110
|
+
codeks 的 `ultra` 是客户端特殊档位:注入多代理提示词,并优先使用条目的 `multi_agent_reasoning_effort`,未配置时按客户端规则选择 `max` 或其他可用普通档位。GPT 条目保留各自原值;GPT-6.1 Sol 和 Opus 5.5 使用 `xhigh`,Sonnet 5.5 和 DeepSeek Flash 使用 `max`。若显式覆盖 `effort_map` 并提供 `ultra`,映射中还须有一个非 `ultra`/`persistent` 档位指向相同原生值;bridge 据此填写客户端字段,不能表达时明确报错。例如 `ultra: "max"` 与 `max: "max"` 配对。直接 HTTP 请求中的未知 effort 仍按上述规则透传。
|
|
111
|
+
|
|
112
|
+
摘要显示由 codeks 的顶层配置控制,bridge 不强制打开:
|
|
113
|
+
|
|
114
|
+
```toml
|
|
115
|
+
model_reasoning_summary = "auto"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
也可选择 `concise`、`detailed` 或 `none`。Claude 和 DeepSeek 目录沿用 GPT-6.1 Sol 的 `default_reasoning_summary: "none"`;客户端配置为 `none` 时省略请求的 summary 字段。bridge 对缺省或 `none` 不展示可见摘要,对其他上述值请求或展示可用内容;Claude 使用原生 summarized 显示,DeepSeek 展示原生 reasoning 文本。它不承诺所有模型区分摘要长度,也不因此关闭实际推理或历史载荷回放。
|
|
119
|
+
|
|
120
|
+
`input_modalities` 用于客户端能力声明,不是 bridge 的模型能力预检。bridge 负责转换能表达的输入,具体模型能否处理由上游裁决。
|
|
121
|
+
|
|
122
|
+
## 压缩模式与执行模型
|
|
123
|
+
|
|
124
|
+
`models.<别名>.compaction.mode` 可选择 `summary` 或 `native`。默认值取自工作模型:GPT 默认 `native`,Claude/DeepSeek 默认 `summary`。`compaction.model` 可引用另一个已配置的模型别名,让它执行压缩;省略时由工作模型自己执行。两项独立,仅设置执行模型不会改变模式。
|
|
125
|
+
|
|
126
|
+
GPT 的默认配置等价于:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{ "compaction": { "mode": "native", "native_replay": true } }
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`native` 初始只生成原生检查点;目标无法按来源策略回放它时,先向生成检查点的模型和连接复述为文字。原来源须继续在配置中可用。成功摘要及辅助 usage 存入顶层 `compaction_cache_dir`,重启后可复用;它不是上游 prompt cache。`summary` 继续使用标准 prompt 直接压缩原历史。
|
|
133
|
+
|
|
134
|
+
例如让 Claude 的历史由 GPT 原生压缩,再按需复述给 Claude:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"models": {
|
|
139
|
+
"claude": {
|
|
140
|
+
"catalog": "claude-opus-5-5", "upstream": "anthropic", "model": "claude-opus-5-5",
|
|
141
|
+
"compaction": { "mode": "native", "model": "gpt-compactor" }
|
|
142
|
+
},
|
|
143
|
+
"gpt-compactor": {
|
|
144
|
+
"catalog": "gpt-6.1-sol", "upstream": "openai", "model": "gpt-6.1-sol",
|
|
145
|
+
"expose": false,
|
|
146
|
+
"reasoning": { "default_effort": "xhigh" }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
这里的 `anthropic` 和 `openai` 使用已有 `upstreams` 连接。`gpt-compactor` 通过 `expose: false` 隐藏于客户端目录,仍复用普通模型配置,不需要另一套压缩器注册表。压缩只跟随一次 `compaction.model`,不继续读取执行模型自己的委托配置或生成模式。工作模型的窗口与压缩阈值仍决定何时压缩,执行模型须能接收实际历史;超限由上游报错。
|
|
153
|
+
|
|
154
|
+
未设置 `compaction.model` 或显式引用自身别名时,沿用请求的 reasoning effort;引用其他别名时使用执行别名的 `reasoning.default_effort`,未设置则使用它的目录默认值,再按该模型的映射转换。即使两个别名指向同一部署,也可用专用压缩别名选择不同默认 effort。复述配方保留选定的请求 effort,后续切换工作模型不改变它。显式原生 options 仍按普通请求的规则覆盖推导参数;后续修改原来源的 options 也会作用于复述,它们不作为快照固化。
|
|
155
|
+
|
|
156
|
+
Claude 的 `native_replay` 仍默认为 `false`:委托生成不会让 Claude 获得读取 GPT 密文的能力。`native` 要求执行模型的 adapter 支持原生压缩格式;`native_replay` 则要求工作模型能恢复该格式。它们与[状态复用](#状态复用)的来源策略独立。完整时序、失败及用量规则见[压缩](compaction.md)。
|
|
157
|
+
|
|
158
|
+
## 状态复用
|
|
159
|
+
|
|
160
|
+
以下模型片段演示 B 接受 A 的原生压缩,但仍隔离 reasoning。实际部署名是占位示例,配对是否可用须由真实端点验证。
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"gpt-a": {
|
|
165
|
+
"upstream": "primary",
|
|
166
|
+
"model": "deployment-a",
|
|
167
|
+
"catalog": "gpt-6.1-sol",
|
|
168
|
+
"context_window": 272000
|
|
169
|
+
},
|
|
170
|
+
"gpt-b": {
|
|
171
|
+
"upstream": "secondary",
|
|
172
|
+
"model": "deployment-b",
|
|
173
|
+
"catalog": "gpt-6.1-sol",
|
|
174
|
+
"context_window": 272000,
|
|
175
|
+
"replay": {
|
|
176
|
+
"reasoning_from": [],
|
|
177
|
+
"native_compaction_from": ["gpt-a"]
|
|
178
|
+
},
|
|
179
|
+
"compaction": { "mode": "summary", "native_replay": true }
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
自身状态默认允许恢复;两份列表增加其他允许来源,关系有方向且不传递。若也要接受 A 的 reasoning,把 A 加入 B 的 `reasoning_from`。这个例子的 B 自己只生成文字摘要,但仍可读取 A 的原生检查点:生成和恢复是独立能力。设置 `native_replay: false` 则所有压缩都使用文字表示,包括自身生成的检查点。
|
|
185
|
+
|
|
186
|
+
引用按连接、实际模型和 adapter 解析为来源身份,不绑定显示别名。加载配置时检查来源是否存在、源与目标的格式标识是否一致;每条请求恢复时再检查实际载荷。bridge 不探测密文是否被上游接受。上游拒绝被允许的状态时直接报错,不删掉状态再试。详见 [reasoning](reasoning.md) 和[压缩](compaction.md)。
|
|
187
|
+
|
|
188
|
+
连接身份包含 upstream ID 和去掉末尾斜杠的 URL,来源身份再包含 adapter 与实际模型。密钥、header 和 options 不参与身份。如果同一 URL 通过 header 或凭据切换到不兼容区域,使用不同 upstream ID;改显示别名不影响已保存状态。
|
|
189
|
+
|
|
190
|
+
## 客户端目录
|
|
191
|
+
|
|
192
|
+
bridge 的 `GET /v1/models` 返回 Codex 专用的 `{"models": [...]}`,每项包含完整提示词、窗口、工具、多代理和 reasoning 元数据。它与经典 OpenAI 的 `{"object":"list","data":[...]}` 格式不同。仅列出配置中的别名,不暴露上游连接、实际部署名或凭据设置。
|
|
193
|
+
|
|
194
|
+
这些条目来自仓库内已审阅的 [catalog](../catalog/README.md),运行时只展开别名和显式配置覆盖。GPT 分别使用自己的 Codex 源码条目;Claude 和 DeepSeek 使用经过精调的 GPT-6.1 Sol 模板。不会启动 codeks 导出模板,也不请求订阅账号的模型目录。目录版本随 bridge 代码更新,升级客户端不会自动改写它。
|
|
195
|
+
|
|
196
|
+
### HTTP 发现
|
|
197
|
+
|
|
198
|
+
```sh
|
|
199
|
+
codeks-bridge config-snippet --config /absolute/path/bridge.json
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
默认输出 `model_providers.bridge.model_catalog_url`,指向 bridge 的 `/v1/models`。只设置 `base_url` 不足以让自定义 provider 使用这份目录。codeks 的 API key 模型发现功能默认启用;若用户配置关闭了 `api_key_model_discovery`,需要重新启用。
|
|
203
|
+
|
|
204
|
+
配置了 `token_env` 时,片段用 `env_key` 传递 bridge 入口凭据。匿名 loopback 服务使用公开标记 `experimental_bearer_token = "codeks-bridge-local"`,让 codeks 进入 API key 目录发现流程。这个固定字符串不是密钥,也不为服务提供鉴权;需要入口鉴权时应配置 `token_env`。
|
|
205
|
+
|
|
206
|
+
provider 显示名为 `Local bridge`,并显式声明 `[model_providers.bridge.capabilities] remote_compaction = "v2"`,无需借用 Azure 或 OpenAI 名称触发能力。片段关闭 `web_search` 和 `features.image_generation`,图片输入仍然支持。
|
|
207
|
+
|
|
208
|
+
片段还设置 `[features.multi_agent_v2] tool_namespace = "agents"`。在默认的保留 namespace `collaboration` 下,`spawn_agent`、`send_message` 和 `followup_task` 的 `message` 带 `encrypted` 标记,GPT 上游会把子代理任务写成密文。GPT 父代理创建的 Claude 或 DeepSeek 子代理只能收到读不懂的密文,会话记录和请求日志里也看不到任务内容。改用其他 namespace 后,codeks 去掉这个标记并按明文投递消息(见 [codeks patch 0005](https://github.com/WAcry/codeks/blob/main/fork/patches/0005-plaintext-agent-messages.md)),任何模型的子代理都能读懂任务,日志中也能看到原始 prompt。没有这个补丁的 Codex 只会改变工具名,消息仍然加密。
|
|
209
|
+
|
|
210
|
+
这张表不写 `enabled`,只修改 namespace;多代理 V2 是否启用仍由目录的 `multi_agent_version` 和已有配置决定。若已有配置在 `[features]` 下写了 `multi_agent_v2 = true`,合并时改为在 `[features.multi_agent_v2]` 中写 `enabled = true`,因为同一个 TOML 文件不能把同一个键同时写成值和表。
|
|
211
|
+
|
|
212
|
+
bridge 使用 HTTP/SSE。已核对 Codex `0.163.0` 的 `codex-rs/model-provider-info/src/lib.rs` 与 `codex-rs/core/src/client.rs`:自定义 provider 的 `supports_websockets` 默认为 `false`,生成的片段沿用该默认值;目录中的 `prefer_websockets: true` 保留源条目原值,不会越过 provider 的能力开关。若将片段合并到已有 provider 配置,应确认没有遗留的 `supports_websockets = true`。今后接入 WebSocket 时需实现相应传输契约,而不只是修改目录偏好。
|
|
213
|
+
|
|
214
|
+
目录响应带 `ETag`,普通响应带同值的 `x-models-etag`。服务配置修改后重启 bridge,新内容的标记会让客户端刷新模型目录;客户端也有定时缓存刷新。当前 Codex 的目录请求限制为 1 MiB、5 秒且不跟随重定向。每个别名都包含完整提示词,大量窗口或部署别名会增大响应。超过 1 MiB 时,HTTP 目录返回明确的 413 错误,不删减条目;模型请求和静态目录导出仍可用。可减少别名,或使用下方的静态 `model_catalog_json` 方案。这是客户端接口的固定限制,不是上游模型能力预检。
|
|
215
|
+
|
|
216
|
+
顶层 `model_catalog_json` 的优先级高于 HTTP 目录。若已有该配置,迁移时移除它,再重载客户端配置。
|
|
217
|
+
|
|
218
|
+
### 静态文件
|
|
219
|
+
|
|
220
|
+
需要固定本地快照时,可导出相同的完整目录:
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
codeks-bridge catalog --config /absolute/path/bridge.json \
|
|
224
|
+
--output /absolute/path/models.json
|
|
225
|
+
codeks-bridge config-snippet --config /absolute/path/bridge.json \
|
|
226
|
+
--catalog /absolute/path/models.json
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
这种模式通过顶层 `model_catalog_json` 读取文件。模型列表或参数修改后,需要重新导出并重载客户端配置。
|
|
230
|
+
|
|
231
|
+
维护者更新源模板、审查差异和新增受支持 key 的步骤见[目录更新流程](../catalog/README.md#更新流程)。
|
package/docs/design.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# 设计与取舍
|
|
2
|
+
|
|
3
|
+
## 独立 provider
|
|
4
|
+
|
|
5
|
+
bridge 是独立本地 HTTP 服务。codeks 负责工具执行、子代理、权限、工作区和会话持久化;bridge 负责模型协议转换。客户端只配置一个 Responses provider,每条请求的模型别名选择独立上游。
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart LR
|
|
9
|
+
C[codeks Responses] --> R[按模型别名选路]
|
|
10
|
+
R --> G[GPT Responses]
|
|
11
|
+
R --> A[Claude Messages]
|
|
12
|
+
R --> D[DeepSeek Chat]
|
|
13
|
+
G --> W[Responses writer]
|
|
14
|
+
A --> W
|
|
15
|
+
D --> W
|
|
16
|
+
W --> C
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
运行时只用 Node 内置模块,构建使用 TypeScript,测试使用 node:test。桥接器不依赖客户端启动方式,也不需要修改 codeks 源码。
|
|
20
|
+
|
|
21
|
+
## 客户端协议跟随 Codex
|
|
22
|
+
|
|
23
|
+
优先匹配最新 Codex 的 GPT 默认行为,以 OpenAI 订阅、AWS 和 Azure 的使用场景为基准。当前已审阅模型目录使用 Responses Lite,保留 `use_responses_lite: true`、Code Mode Only 和多代理字段。目录固定到明确的 Codex 源码版本,不随用户本机二进制或订阅账号变化。
|
|
24
|
+
|
|
25
|
+
Lite 仍调用 `/responses` 并返回 Responses SSE。完整工具 schema 位于历史中的 `additional_tools` 项,普通函数和 custom 工具归入默认 `functions` namespace。GPT 路径保留这些声明的位置、顺序、schema 和 grammar,并发送 `x-openai-internal-codex-responses-lite: true`。Claude/DeepSeek 只在各自协议转换入口提取声明,组合为原生工具表;声明不会变成 user reminder。中途提醒保留所在对话位置;若插在一次完整的工具交换内,则移至该批结果之后,以满足目标协议的配对要求。
|
|
26
|
+
|
|
27
|
+
已核对 Codex `0.163.0`:Lite 设置 `reasoning.context: "all_turns"` 和 `parallel_tool_calls: false`。bridge 保留客户端传入值,原生 options 仍可按配置覆盖普通参数。reasoning 的来源筛选与服务端 context 语义是两件事:前者决定发送哪些载荷,后者决定 GPT 如何使用它们。原生压缩与随后的复述保留源 Lite 工具声明及 transport 标记。
|
|
28
|
+
|
|
29
|
+
该版本最新 OpenAI GPT 目录启用 Lite,但原生 AWS Bedrock 目录仍主动关闭 Lite 和 Code Mode。统一启用是本项目的明确选择,不能把它描述为所有官方 provider 当前完全相同的默认值。上游是否接受请求由端点裁决,错误直接返回;bridge 不自动转回另一种协议。升级时复核 `core/src/client.rs`、`tools/src/tool_spec.rs`、`core/src/context/world_state/top_level_tools.rs` 和 provider 的模型目录处理。
|
|
30
|
+
|
|
31
|
+
## 有限目录与显式精调
|
|
32
|
+
|
|
33
|
+
项目只支持明确列出的模型。`catalog/` 保存每个模型的完整条目及来源;GPT 分别使用 Codex 源码中各自的版本,保留提示词、默认 effort、摘要、窗口和工具元数据的差异。Claude 与 DeepSeek 从 GPT-6.1 Sol 模板开始,只替换底层模型身份(如 `You are Codex, an agent based on Claude.`),保留 Codex 代理角色及 `As Codex` 人格说明;参数和确有差异的能力逐项精调,记录在条目的 `adjustments`。摘要默认值继续使用模板的 `none`,是否展示由客户端配置决定,不为第三方模型强制打开。
|
|
34
|
+
|
|
35
|
+
导入脚本只生成独立候选文件,供人或 Agent 对比审阅。运行时使用已提交的完整条目,不自动导入、不猜测未知模型,也不从 ChatGPT 订阅获取目录。这样更新仍有工具辅助,同时提示词和能力变化可审查、可追踪。来源及更新步骤见[模型目录](../catalog/README.md)。
|
|
36
|
+
|
|
37
|
+
## 配置表达策略,adapter 负责协议
|
|
38
|
+
|
|
39
|
+
`models.catalog` 选择条目;`upstreams` 只包含连接与鉴权;别名和真实部署名独立。目录条目决定 adapter,实际模型名不参与方言推断。模型窗口、输入模态、effort 映射、状态复用范围、压缩模式及执行模型可由配置覆盖。
|
|
40
|
+
|
|
41
|
+
`src/profiles.ts` 将目录与配置组合为运行时 profile,同时用于客户端目录和出站请求,避免界面显示一套 effort、实际发送另一套。未覆盖字段保留原模型差异,不能用一套通用默认值改写所有 GPT。来源身份继续取连接、adapter 与实际部署,不因提示词更新或窗口预设改变。
|
|
42
|
+
|
|
43
|
+
`GET /v1/models` 提供 Codex 原生目录响应,CLI 默认生成显式 `model_catalog_url`;也可导出静态文件。两种目录都只包含 `expose` 未关闭的别名,让专用压缩预设复用模型配置而不占客户端列表;该字段不改变调用权限或状态身份。服务启动时展开配置,目录与普通响应通过 ETag 关联,客户端看到新版本后刷新。目录只包含客户端需要的公开模型元数据,不包含连接或凭据配置。
|
|
44
|
+
|
|
45
|
+
底层 Chat 负责消息、工具、图片和 SSE;DeepSeek 方言只负责 thinking 参数、reasoning 字段和 usage。新增方言时复用稳定的协议部分,把差异留在对应 adapter。协议相同的模型版本可共用 adapter,参数差异先在新的目录条目中表达;真正改变载荷结构时再增加转换代码和格式版本。当前实现三类 adapter,不为尚未接入的模型维护空接口或版本矩阵。
|
|
46
|
+
|
|
47
|
+
## 历史保存事实,配置决定恢复
|
|
48
|
+
|
|
49
|
+
Reasoning 载荷记录来源、格式和原始数据;压缩载荷保存文字摘要及可选原生状态,或保存原生状态与按需复述配方。它们写入 Responses item 的 `encrypted_content`,由 codeks 原样持久化。bridge 不维护完整会话或响应 ID 索引;按需复述的成功结果及独立 usage 另存本地文件缓存,避免重复付费和服务重启后重复生成。
|
|
50
|
+
|
|
51
|
+
来源包括连接指纹、adapter 和实际模型,独立于显示别名和复用配置。连接凭据和 HTTP header 不写进载荷;复述配方保存源请求前缀及除输入、流式开关和文字输出约束外的请求参数,包括未知参数。外层编码不提供加密:文字 reasoning、签名、压缩摘要及请求前缀按普通聊天历史保护,按需复述缓存以 `0600` 文件权限保存。
|
|
52
|
+
|
|
53
|
+
每次请求按当前配置选取历史,不改写已保存载荷。Reasoning 和原生压缩有独立的允许来源列表,默认只接受自身,关系有方向且不传递。修改配置即可改变已有历史的恢复方式;格式版本负责解释数据,不编码“永远隔离”这类策略。
|
|
54
|
+
|
|
55
|
+
明文 reasoning 使用可共享的文本格式;不同 adapter 将来可把同一格式恢复到各自字段。密文与签名保留各自原生结构,不把格式可解码等同于上游允许使用。
|
|
56
|
+
|
|
57
|
+
## 进攻式发送,保留错误
|
|
58
|
+
|
|
59
|
+
这是快速迭代的协议桥接器。用户选择默认透传、尽早暴露不兼容:请求、响应、header 和错误中的新增字段不应因为桥接器未认识它们而静默消失。GPT 路径保留原始 body 和事件,只修改桥接必需字段;header 采用排除必要边界字段的方式转发,不维护白名单。Claude/DeepSeek 仍需转换消息、工具及错误结构,不能机械地把 Responses 字段搬进另一套协议;原生扩展参数通过 options 保留。具体 HTTP 与鉴权边界见 [Responses 流](responses-stream.md#header-与转发边界)。
|
|
60
|
+
|
|
61
|
+
bridge 检查自身必须维持的不变量:配置引用存在、历史能转换、工具调用完整、usage 可用、压缩检查点完整。这些检查避免静默丢失上下文或执行半段工具调用。
|
|
62
|
+
|
|
63
|
+
上游负责判定模型能力:effort、thinking、强制工具选择、schema、图片以及允许复用的密文是否可接受。bridge 不预先维护这些能力的限制列表,也不在失败后自动移除 reasoning、关闭 thinking、换端点或改压缩模式。原生参数可通过 options 显式覆盖。
|
|
64
|
+
|
|
65
|
+
GPT 原生 HTTP 失败保留 status、body 和诊断 header,流内失败保留 error 对象。下游 HTTP 200 推迟到上游接受请求后,避免把 HTTP 失败变成 SSE 错误而改变 codeks 的重试判断;等待响应头期间没有 keepalive,是这一选择的明确代价。Claude/DeepSeek 只在协议转换边界映射错误分类。重试和退避由客户端控制,bridge 不叠加第二层重试。详见 [Responses 流](responses-stream.md)。
|
|
66
|
+
|
|
67
|
+
## 压缩的生成和恢复分开
|
|
68
|
+
|
|
69
|
+
`compaction.mode` 决定如何生成:`summary` 用标准 prompt 汇总原历史;`native` 先生成原生检查点,只在目标需要文字时由原来源复述。默认值取工作模型,GPT 默认 `native`,其他 adapter 默认 `summary`。`compaction.model` 独立选择已有模型别名作为执行者,仅跟随一层引用,不继承执行者自己的委托或模式。这样 Claude 也可明确选择 GPT 原生压缩,同时保留标准文字模式。
|
|
70
|
+
|
|
71
|
+
先选执行者,再按它的来源策略恢复输入。兼容的 GPT 压缩器可以继续读取旧原生状态,不必沿用工作模型此前使用的文字表示。来源身份、参数与复述配方记录实际执行者;消费者的 `native_replay` 保持独立。未设置执行别名或引用自身别名时保留请求 effort;引用其他别名时选择执行别名的默认 effort,复述沿用保存的请求参数。
|
|
72
|
+
|
|
73
|
+
用户选择先原生再复述,是为了以原生压缩整理的状态为交接基础;按需执行则可省去始终使用兼容目标时的额外推理。这是可选的质量策略,不承诺所有输入上的质量优势、缓存命中或固定成本。实际模型容量由上游裁决,bridge 不引入跨模型 token 换算或自动裁剪。
|
|
74
|
+
|
|
75
|
+
按需复述使用 `U + K + handoff prompt`:`U` 直接取自后续请求中客户端实际保留的历史,`K` 是原生检查点。bridge 先交付 K,由客户端确定 U,下一条需要文字的请求等待复述完成;不复制客户端的保留算法。bridge 不再裁剪 U,不保存完整旧历史,也不把检查点后的新工作纳入旧摘要。复述 prompt 是用户给定的 Codex prompt 微调版,要求完整复述已有状态;summary 模式继续使用现有的详细标准 prompt。
|
|
76
|
+
|
|
77
|
+
`native_replay` 和来源列表决定恢复时是否使用原生表示,独立于生成模式。目标无法使用原生时,选择已有文字或向原来源按需生成文字。这项能力用于模型切换,假定原模型、原端点和配置仍可用;缓存只复用成功结果,错误直接返回。已经发送的原生状态被上游拒绝时不会自动降级。支持原生格式不等于每个部署都提供生成能力,因此同一 GPT adapter 可配置不同模式。[压缩细节](compaction.md)
|
|
78
|
+
|
|
79
|
+
## 调试捕获只观察
|
|
80
|
+
|
|
81
|
+
[检查器](inspect.md)记录 bridge 真正收发的字节,不重新构造请求。入口请求在解析前保存原文;所有上游请求都经过 `upstreamFetch`,在这里保存实际发送的 JSON 和逐块到达的响应;写回 codeks 的内容在 `writeHead`/`write`/`end` 处记录。每条请求在 AsyncLocalStorage 中持有自己的记录,上游调用按用途附加 `main`、`summary`、`native` 或 `handoff` 标签,因此并发会话和子代理不会混在一起,后端代码不需要传递捕获参数。需要生成文字摘要时,`handoff` 先完成,再执行目标调用;命中摘要缓存时没有辅助上游调用。客户端响应只报告对应 main、summary 或 native 调用的 usage;handoff 用量留在缓存与独立上游记录,避免把辅助消耗当作客户端当前上下文。
|
|
82
|
+
|
|
83
|
+
服务端保存完整正文,折叠、截断和格式化都在页面完成,避免字段白名单遗漏协议新增内容。状态标注调用与 `prepareHistory` 相同的回放判断函数,显示的决定不会与实际转换分叉。页面是零依赖的静态文件,和运行时一样不引入第三方包。捕获关闭时不保存任何内容,每条请求只多一个 AsyncLocalStorage 作用域。
|
|
84
|
+
|
|
85
|
+
## 协议边界
|
|
86
|
+
|
|
87
|
+
客户端发送完整 Responses Lite 历史。Responses 后端保留 namespace 与 grammar;Claude/DeepSeek 将它们转换成普通函数并恢复调用身份。Lark/regex 只转换为描述约束,不追加特定工具的提示词。
|
|
88
|
+
|
|
89
|
+
Responses 后端保留原生事件及 response envelope,其他后端由 writer 生成 Responses 协议。writer 从第一个工具起缓存全部后续事件,成功后按原顺序交付,失败时整体丢弃;代价是工具之后的文字也暂时不能显示。Reasoning item 的载荷必须出现在 `output_item.done`,确保 codeks 可以保存。远程 V2 压缩也由同一个 writer 返回,客户端继续执行自己的历史保留规则。
|
|
90
|
+
|
|
91
|
+
Codex 的命名通知可以没有 `call_id`,Code Mode 的多次 `notify()` 也可以复用同一个调用 ID。非 Responses 目标将无配对通知及追加结果转成带身份的 user 消息,保留文字和图片,不补造工具调用或改写此前结果。转换只影响当前出站请求;规则和边界见[工具转换](tools.md)。
|
|
92
|
+
|
|
93
|
+
协议转换参考了现有 Responses、Messages 和 Chat 实践。标准文字压缩使用详细摘要提示词;原生检查点复述 prompt 改编自 Codex,摘要恢复前缀逐字来自 Codex。Apache-2.0 许可归属列在 `NOTICE`。
|