lark-remote 0.5.19 → 0.5.21
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/CHANGELOG.md +29 -0
- package/dist/bridge/approval-actions.d.ts +1 -1
- package/dist/bridge/approval-actions.js +1 -1
- package/dist/bridge/bash-run.d.ts +71 -0
- package/dist/bridge/bash-run.js +217 -0
- package/dist/bridge/compact.d.ts +155 -0
- package/dist/bridge/compact.js +450 -0
- package/dist/bridge/final-usage.js +4 -4
- package/dist/bridge/inbound-media.js +72 -46
- package/dist/bridge/index.d.ts +106 -153
- package/dist/bridge/index.js +400 -1000
- package/dist/bridge/job-watch.d.ts +68 -0
- package/dist/bridge/job-watch.js +146 -0
- package/dist/bridge/queue-manager.d.ts +3 -3
- package/dist/bridge/queue-manager.js +10 -29
- package/dist/card/approval-render.d.ts +2 -2
- package/dist/card/approval-render.js +141 -130
- package/dist/card/card-budget.js +123 -98
- package/dist/card/card-helpers.d.ts +3 -3
- package/dist/card/card-helpers.js +6 -6
- package/dist/card/final-answer-file.js +1 -1
- package/dist/card/run-renderer.d.ts +3 -3
- package/dist/card/run-renderer.js +114 -159
- package/dist/card/run-state.d.ts +1 -15
- package/dist/card/run-state.js +358 -292
- package/dist/card/tool-render.d.ts +1 -1
- package/dist/card/tool-render.js +21 -17
- package/dist/card/usage-format.d.ts +22 -7
- package/dist/card/usage-format.js +119 -100
- package/dist/cli.js +15 -3
- package/dist/clone.js +2 -2
- package/dist/common/text-width.js +36 -24
- package/dist/common/tool-summary.js +132 -90
- package/dist/config/codex-config.js +130 -106
- package/dist/config/index.d.ts +16 -2
- package/dist/config/index.js +23 -8
- package/dist/connector/index.js +6 -6
- package/dist/error-classification.js +3 -2
- package/dist/inbound/placeholder.d.ts +1 -1
- package/dist/inbound/placeholder.js +1 -1
- package/dist/index.js +387 -281
- package/dist/logger/index.js +6 -6
- package/dist/message-handlers.d.ts +0 -5
- package/dist/message-handlers.js +254 -237
- package/dist/model-catalog.d.ts +2 -2
- package/dist/model-catalog.js +3 -8
- package/dist/platform/identity.js +1 -1
- package/dist/platform/path.d.ts +1 -1
- package/dist/platform/path.js +1 -1
- package/dist/platform/sleep-blocker.js +1 -1
- package/dist/platform/terminator-win32.js +2 -1
- package/dist/router/commands/ls.d.ts +3 -0
- package/dist/router/commands/ls.js +256 -175
- package/dist/router/commands/order.js +184 -159
- package/dist/router/commands/resume.js +190 -152
- package/dist/router/commands/ws.js +219 -174
- package/dist/router/config/dsh.d.ts +4 -8
- package/dist/router/config/dsh.js +3 -10
- package/dist/router/config/kimi.js +1 -1
- package/dist/router/config/types.d.ts +1 -1
- package/dist/router/config-diff.js +1 -1
- package/dist/router/index.d.ts +56 -11
- package/dist/router/index.js +401 -391
- package/dist/runner/bash/runner.js +2 -4
- package/dist/runner/claude/session.d.ts +1 -1
- package/dist/runner/claude/session.js +6 -4
- package/dist/runner/codex/app-server/runner.d.ts +9 -2
- package/dist/runner/codex/app-server/runner.js +30 -25
- package/dist/runner/codex/app-server/translator.d.ts +2 -5
- package/dist/runner/codex/app-server/translator.js +291 -238
- package/dist/runner/common/acp/acp-approval.d.ts +1 -1
- package/dist/runner/common/acp/acp-approval.js +1 -1
- package/dist/runner/common/acp/base-acp-runner.d.ts +5 -2
- package/dist/runner/common/acp/base-acp-runner.js +26 -65
- package/dist/runner/common/acp/base-translator.d.ts +12 -2
- package/dist/runner/common/acp/base-translator.js +50 -26
- package/dist/runner/common/acp/protocol-types.d.ts +1 -1
- package/dist/runner/common/acp/protocol-types.js +2 -2
- package/dist/runner/common/connection-based-runner.d.ts +32 -1
- package/dist/runner/common/connection-based-runner.js +32 -2
- package/dist/runner/common/jsonl-stream.js +154 -187
- package/dist/runner/common/jsonrpc/client.d.ts +29 -0
- package/dist/runner/common/jsonrpc/client.js +43 -12
- package/dist/runner/common/jsonrpc/connection-manager.d.ts +2 -2
- package/dist/runner/common/jsonrpc/connection-manager.js +4 -4
- package/dist/runner/common/spawning-runner.d.ts +6 -1
- package/dist/runner/common/spawning-runner.js +9 -4
- package/dist/runner/common/turn-started.d.ts +8 -0
- package/dist/runner/common/turn-started.js +11 -0
- package/dist/runner/dsh/approval.js +84 -51
- package/dist/runner/dsh/catalog-probe.d.ts +17 -0
- package/dist/runner/dsh/catalog-probe.js +10 -0
- package/dist/runner/dsh/client.d.ts +7 -11
- package/dist/runner/dsh/client.js +356 -289
- package/dist/runner/dsh/exit-cancel.d.ts +2 -2
- package/dist/runner/dsh/exit-cancel.js +2 -2
- package/dist/runner/dsh/inflight.d.ts +1 -1
- package/dist/runner/dsh/inflight.js +1 -1
- package/dist/runner/dsh/mux-stream.js +28 -8
- package/dist/runner/dsh/runner.d.ts +44 -4
- package/dist/runner/dsh/runner.js +296 -199
- package/dist/runner/dsh/translator.d.ts +1 -31
- package/dist/runner/dsh/translator.js +180 -178
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/kimi/acp/runner.d.ts +1 -2
- package/dist/runner/kimi/acp/runner.js +82 -46
- package/dist/runner/kimi/acp/translator.d.ts +1 -1
- package/dist/runner/kimi/acp/translator.js +3 -4
- package/dist/runner/opencode/acp/error-monitor.js +5 -5
- package/dist/runner/opencode/acp/runner.d.ts +2 -2
- package/dist/runner/opencode/acp/runner.js +4 -4
- package/dist/runner/pi/rpc/client.js +4 -13
- package/dist/runner/pi/rpc/protocol-types.d.ts +1 -1
- package/dist/runner/pi/rpc/protocol-types.js +1 -1
- package/dist/runner/pi/rpc/runner.d.ts +3 -0
- package/dist/runner/pi/rpc/runner.js +27 -42
- package/dist/runner/pi/rpc/translator.js +61 -60
- package/dist/runner/types.d.ts +2 -2
- package/dist/runner/types.js +1 -1
- package/dist/session/claude/sessions.d.ts +45 -0
- package/dist/session/claude/sessions.js +160 -122
- package/dist/session/codex/rollout-reader.js +181 -182
- package/dist/session/common/throw-session-list-error.d.ts +10 -0
- package/dist/session/common/throw-session-list-error.js +16 -0
- package/dist/session/dsh/sessions.js +291 -235
- package/dist/session/kimi/sessions.d.ts +40 -8
- package/dist/session/kimi/sessions.js +373 -301
- package/dist/session/opencode/sessions.d.ts +142 -1
- package/dist/session/opencode/sessions.js +378 -321
- package/dist/session/pi/sessions.js +4 -5
- package/dist/session/session-store.d.ts +9 -1
- package/dist/session/session-store.js +99 -99
- package/dist/update/version-check.js +2 -1
- package/dist/workspace/index.d.ts +1 -1
- package/dist/workspace/index.js +1 -1
- package/package.json +1 -1
|
@@ -52,101 +52,143 @@ export function asRecord(input) {
|
|
|
52
52
|
}
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
// --- 字段选取原语 ---
|
|
56
|
+
// 模块级纯函数:调用方(`summarizeToolInput`)只负责选路,字段口径各自独立。
|
|
57
|
+
function pickField(rec, key, max = HEADER_SUMMARY_MAX) {
|
|
58
|
+
const v = rec[key];
|
|
59
|
+
if (typeof v !== 'string')
|
|
58
60
|
return '';
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
const oneLine = v.replace(/\s+/g, ' ').trim();
|
|
62
|
+
// 码点安全截断:裸 slice 切在代理对中间会留下孤立代理项进卡片
|
|
63
|
+
// (同族修复见 tool-render.ts 的 toolHeaderText)。
|
|
64
|
+
return truncate(oneLine, max);
|
|
65
|
+
}
|
|
66
|
+
/** First non-empty of several keys(DSH 同名工具跨版本改过参数名)。 */
|
|
67
|
+
function pickAnyField(rec, keys, max = HEADER_SUMMARY_MAX) {
|
|
68
|
+
for (const key of keys) {
|
|
69
|
+
const v = pickField(rec, key, max);
|
|
70
|
+
if (v)
|
|
71
|
+
return v;
|
|
72
|
+
}
|
|
73
|
+
return '';
|
|
74
|
+
}
|
|
75
|
+
/** 数组参数的第一个字符串项(DSH web_search 的 queries、present 的 files)。 */
|
|
76
|
+
function pickFirstField(rec, key, max = HEADER_SUMMARY_MAX) {
|
|
77
|
+
const v = rec[key];
|
|
78
|
+
if (typeof v === 'string')
|
|
79
|
+
return pickField(rec, key, max);
|
|
80
|
+
if (!Array.isArray(v))
|
|
75
81
|
return '';
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (typeof v === 'string')
|
|
81
|
-
return pick(key, max);
|
|
82
|
-
if (!Array.isArray(v))
|
|
83
|
-
return '';
|
|
84
|
-
for (const item of v) {
|
|
85
|
-
if (typeof item === 'string' && item.trim()) {
|
|
86
|
-
const oneLine = item.replace(/\s+/g, ' ').trim();
|
|
87
|
-
return truncate(oneLine, max);
|
|
88
|
-
}
|
|
89
|
-
if (item && typeof item === 'object') {
|
|
90
|
-
const path = item.path;
|
|
91
|
-
if (typeof path === 'string' && path.trim())
|
|
92
|
-
return path;
|
|
93
|
-
}
|
|
82
|
+
for (const item of v) {
|
|
83
|
+
if (typeof item === 'string' && item.trim()) {
|
|
84
|
+
const oneLine = item.replace(/\s+/g, ' ').trim();
|
|
85
|
+
return truncate(oneLine, max);
|
|
94
86
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return pick('command');
|
|
100
|
-
case 'file':
|
|
101
|
-
return pick('file_path') || pick('path');
|
|
102
|
-
case 'grep': {
|
|
103
|
-
const pat = pick('pattern', 40);
|
|
104
|
-
const p = pick('path', 30);
|
|
105
|
-
return p ? `${pat} in ${p}` : pat;
|
|
87
|
+
if (item && typeof item === 'object') {
|
|
88
|
+
const path = item.path;
|
|
89
|
+
if (typeof path === 'string' && path.trim())
|
|
90
|
+
return path;
|
|
106
91
|
}
|
|
107
|
-
case 'glob':
|
|
108
|
-
return pick('pattern');
|
|
109
|
-
case 'ls':
|
|
110
|
-
return pick('path');
|
|
111
|
-
case 'webfetch':
|
|
112
|
-
return pick('url');
|
|
113
|
-
case 'websearch':
|
|
114
|
-
case 'websearch_queries':
|
|
115
|
-
return pickFirst('queries', 60) || pick('query', 60);
|
|
116
|
-
default:
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
switch (name) {
|
|
120
|
-
case 'Agent':
|
|
121
|
-
case 'Task':
|
|
122
|
-
case 'subagent':
|
|
123
|
-
case 'workflow':
|
|
124
|
-
return pick('description') || pick('subagent_type');
|
|
125
|
-
case 'todo_write':
|
|
126
|
-
return summarizeTodos(rec);
|
|
127
|
-
case 'job_output':
|
|
128
|
-
case 'job_kill':
|
|
129
|
-
return pick('job_id');
|
|
130
|
-
case 'job_list':
|
|
131
|
-
return '(列出任务)';
|
|
132
|
-
case 'present':
|
|
133
|
-
return pickFirst('files');
|
|
134
|
-
case 'skill':
|
|
135
|
-
return pick('name');
|
|
136
|
-
case 'run_code':
|
|
137
|
-
return pick('description') || pick('language');
|
|
138
|
-
case 'terminal_send':
|
|
139
|
-
return pick('text');
|
|
140
|
-
case 'ask_user_question': {
|
|
141
|
-
const questions = rec.questions;
|
|
142
|
-
return Array.isArray(questions) ? `${questions.length} 个问题` : '';
|
|
143
|
-
}
|
|
144
|
-
case 'send_message':
|
|
145
|
-
case 'interrupt_agent':
|
|
146
|
-
return pick('description') || pick('agent_id');
|
|
147
|
-
default:
|
|
148
|
-
return pickAny(['command', 'file_path', 'path', 'query', 'url']);
|
|
149
92
|
}
|
|
93
|
+
return '';
|
|
94
|
+
}
|
|
95
|
+
function shellSummary(rec) {
|
|
96
|
+
return pickField(rec, 'command');
|
|
97
|
+
}
|
|
98
|
+
function fileSummary(rec) {
|
|
99
|
+
return pickField(rec, 'file_path') || pickField(rec, 'path');
|
|
100
|
+
}
|
|
101
|
+
function grepSummary(rec) {
|
|
102
|
+
const pat = pickField(rec, 'pattern', 40);
|
|
103
|
+
const p = pickField(rec, 'path', 30);
|
|
104
|
+
return p ? `${pat} in ${p}` : pat;
|
|
105
|
+
}
|
|
106
|
+
function patternSummary(rec) {
|
|
107
|
+
return pickField(rec, 'pattern');
|
|
108
|
+
}
|
|
109
|
+
function pathSummary(rec) {
|
|
110
|
+
return pickField(rec, 'path');
|
|
111
|
+
}
|
|
112
|
+
function urlSummary(rec) {
|
|
113
|
+
return pickField(rec, 'url');
|
|
114
|
+
}
|
|
115
|
+
function queriesSummary(rec) {
|
|
116
|
+
return pickFirstField(rec, 'queries', 60) || pickField(rec, 'query', 60);
|
|
117
|
+
}
|
|
118
|
+
function subagentSummary(rec) {
|
|
119
|
+
return pickField(rec, 'description') || pickField(rec, 'subagent_type');
|
|
120
|
+
}
|
|
121
|
+
function messageSummary(rec) {
|
|
122
|
+
return pickField(rec, 'description') || pickField(rec, 'agent_id');
|
|
123
|
+
}
|
|
124
|
+
function jobIdSummary(rec) {
|
|
125
|
+
return pickField(rec, 'job_id');
|
|
126
|
+
}
|
|
127
|
+
function jobListSummary() {
|
|
128
|
+
return '(列出任务)';
|
|
129
|
+
}
|
|
130
|
+
function filesSummary(rec) {
|
|
131
|
+
return pickFirstField(rec, 'files');
|
|
132
|
+
}
|
|
133
|
+
function nameSummary(rec) {
|
|
134
|
+
return pickField(rec, 'name');
|
|
135
|
+
}
|
|
136
|
+
function runCodeSummary(rec) {
|
|
137
|
+
return pickField(rec, 'description') || pickField(rec, 'language');
|
|
138
|
+
}
|
|
139
|
+
function textSummary(rec) {
|
|
140
|
+
return pickField(rec, 'text');
|
|
141
|
+
}
|
|
142
|
+
function questionCountSummary(rec) {
|
|
143
|
+
const questions = rec.questions;
|
|
144
|
+
return Array.isArray(questions) ? `${questions.length} 个问题` : '';
|
|
145
|
+
}
|
|
146
|
+
function todoSummary(rec) {
|
|
147
|
+
return summarizeTodos(rec);
|
|
148
|
+
}
|
|
149
|
+
const FALLBACK_FIELDS = ['command', 'file_path', 'path', 'query', 'url'];
|
|
150
|
+
/** 类别 → 摘要器。ToolKind 的每个成员都必须有条目。 */
|
|
151
|
+
const KIND_SUMMARY = new Map([
|
|
152
|
+
['shell', shellSummary],
|
|
153
|
+
['file', fileSummary],
|
|
154
|
+
['grep', grepSummary],
|
|
155
|
+
['glob', patternSummary],
|
|
156
|
+
['ls', pathSummary],
|
|
157
|
+
['webfetch', urlSummary],
|
|
158
|
+
['websearch', queriesSummary],
|
|
159
|
+
['websearch_queries', queriesSummary],
|
|
160
|
+
]);
|
|
161
|
+
/**
|
|
162
|
+
* 工具名 → 摘要器。用 Map 而非对象字面量:`constructor` / `toString` 这类
|
|
163
|
+
* 工具名会命中 Object.prototype,查表会拿到非函数值。
|
|
164
|
+
*/
|
|
165
|
+
const NAME_SUMMARY = new Map([
|
|
166
|
+
['Agent', subagentSummary],
|
|
167
|
+
['Task', subagentSummary],
|
|
168
|
+
['subagent', subagentSummary],
|
|
169
|
+
['workflow', subagentSummary],
|
|
170
|
+
['todo_write', todoSummary],
|
|
171
|
+
['job_output', jobIdSummary],
|
|
172
|
+
['job_kill', jobIdSummary],
|
|
173
|
+
['job_list', jobListSummary],
|
|
174
|
+
['present', filesSummary],
|
|
175
|
+
['skill', nameSummary],
|
|
176
|
+
['run_code', runCodeSummary],
|
|
177
|
+
['terminal_send', textSummary],
|
|
178
|
+
['ask_user_question', questionCountSummary],
|
|
179
|
+
['send_message', messageSummary],
|
|
180
|
+
['interrupt_agent', messageSummary],
|
|
181
|
+
]);
|
|
182
|
+
export function summarizeToolInput(name, input) {
|
|
183
|
+
const rec = asRecord(input);
|
|
184
|
+
if (!rec)
|
|
185
|
+
return '';
|
|
186
|
+
const kind = toolKindOf(name);
|
|
187
|
+
const byKind = kind === undefined ? undefined : KIND_SUMMARY.get(kind);
|
|
188
|
+
if (byKind)
|
|
189
|
+
return byKind(rec);
|
|
190
|
+
const byName = NAME_SUMMARY.get(name);
|
|
191
|
+
return byName ? byName(rec) : pickAnyField(rec, FALLBACK_FIELDS);
|
|
150
192
|
}
|
|
151
193
|
/** todo_write 摘要:完成进度 + 当前 in_progress 项主题。 */
|
|
152
194
|
function summarizeTodos(rec) {
|
|
@@ -392,6 +392,123 @@ function extractCustomProvider(providers) {
|
|
|
392
392
|
const keys = Object.keys(providers);
|
|
393
393
|
return keys.find((k) => k !== 'openai' && k !== 'anthropic');
|
|
394
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* 管线第 1 段(IO):读 + 解析 config.toml,不做任何语义解释。
|
|
397
|
+
* - missing:文件不存在;
|
|
398
|
+
* - parsed:TOML 解析成功(内容后续由 normalizeProviders 解释);
|
|
399
|
+
* - invalid:读取/解析抛错(含 TOCTOU 窗口内的文件损坏)——错误在此分类收口,
|
|
400
|
+
* 消费方(loadCodexConfig)据此走「解析失败」兜底,绝不向上抛异常。
|
|
401
|
+
*/
|
|
402
|
+
function readCodexToml(codexHome) {
|
|
403
|
+
const configFile = path.join(codexHome, 'config.toml');
|
|
404
|
+
if (!fs.existsSync(configFile))
|
|
405
|
+
return { state: 'missing' };
|
|
406
|
+
try {
|
|
407
|
+
const raw = fs.readFileSync(configFile, 'utf-8');
|
|
408
|
+
return { state: 'parsed', parsed: TOML.parse(raw) };
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
return { state: 'invalid' };
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* 管线第 2 段(纯转换):把已解析的 TOML + 目录上下文归一成 provider/model 事实。
|
|
416
|
+
* Model filtering strategy:
|
|
417
|
+
* - Custom provider: model from config.toml (single model)
|
|
418
|
+
* - openai: all bundled models
|
|
419
|
+
* - anthropic: bundled models with 'claude-*' prefix
|
|
420
|
+
*/
|
|
421
|
+
function normalizeProviders(parsed, ctx) {
|
|
422
|
+
const { catalogMode, catalogSlugs, allModels, anthropicModels } = ctx;
|
|
423
|
+
const modelKeyRaw = typeof parsed.model === 'string' && parsed.model.length > 0 ? parsed.model : undefined;
|
|
424
|
+
const currentProvider = String(parsed.model_provider ?? FALLBACK_PROVIDERS[0]);
|
|
425
|
+
// Extract model_providers section
|
|
426
|
+
const modelProviders = (parsed.model_providers ?? {});
|
|
427
|
+
const rawProviderNames = Object.keys(modelProviders);
|
|
428
|
+
if (catalogMode) {
|
|
429
|
+
// catalog 模式:provider 列表 = 内置 openai + [model_providers.*](对齐 codex
|
|
430
|
+
// merge_configured_model_providers(built_in_model_providers, cfg.model_providers),
|
|
431
|
+
// core/src/config/mod.rs:3655;model_provider 未声明时默认 "openai",mod.rs:3659)。
|
|
432
|
+
// anthropic 不是 codex 内置 provider,未显式配置时不得出现。模型列表仍只来自
|
|
433
|
+
// 活动目录——openai+内置 gpt-5.x 的失效路径不因 provider 合并复活。
|
|
434
|
+
const providerNames = rawProviderNames.includes('openai')
|
|
435
|
+
? rawProviderNames
|
|
436
|
+
: ['openai', ...rawProviderNames];
|
|
437
|
+
const providerEnvKeys = { openai: 'OPENAI_API_KEY' };
|
|
438
|
+
for (const [name, config] of Object.entries(modelProviders)) {
|
|
439
|
+
if (typeof config.env_key === 'string') {
|
|
440
|
+
providerEnvKeys[name] = config.env_key;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
// 活动目录全局:codex 运行时 provider 与模型无绑定(StaticModelsManager),
|
|
444
|
+
// 每个 provider 下拉都展示目录全部 slug
|
|
445
|
+
// 活动目录不可用(命令失败/空)时回退 [currentModel]——无目录元数据时档位/能力
|
|
446
|
+
// 不可信;禁止泄漏 FALLBACK_MODELS/内置目录。model 键缺失时不得虚构 'o3'。
|
|
447
|
+
const catalogCurrentModel = modelKeyRaw ?? catalogSlugs[0] ?? '';
|
|
448
|
+
const providerModelList = catalogSlugs.length > 0 ? catalogSlugs : modelKeyRaw ? [modelKeyRaw] : [];
|
|
449
|
+
const providerModels = {};
|
|
450
|
+
for (const name of providerNames) {
|
|
451
|
+
providerModels[name] = providerModelList;
|
|
452
|
+
}
|
|
453
|
+
const resolvedProvider = typeof parsed.model_provider === 'string' && parsed.model_provider.length > 0
|
|
454
|
+
? parsed.model_provider
|
|
455
|
+
: 'openai';
|
|
456
|
+
return {
|
|
457
|
+
currentModel: catalogCurrentModel,
|
|
458
|
+
currentProvider: resolvedProvider,
|
|
459
|
+
providerNames,
|
|
460
|
+
providerEnvKeys,
|
|
461
|
+
providerModels,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
// fallback 模式:保持原行为(openai/anthropic 内置 + bundled 模型)
|
|
465
|
+
const currentModel = modelKeyRaw ?? catalogSlugs[0] ?? 'o3';
|
|
466
|
+
const providerNames = rawProviderNames;
|
|
467
|
+
if (!providerNames.includes('openai')) {
|
|
468
|
+
providerNames.unshift('openai');
|
|
469
|
+
}
|
|
470
|
+
const customProvider = extractCustomProvider(modelProviders);
|
|
471
|
+
const providerEnvKeys = {};
|
|
472
|
+
providerEnvKeys['openai'] = 'OPENAI_API_KEY';
|
|
473
|
+
for (const [name, config] of Object.entries(modelProviders)) {
|
|
474
|
+
if (typeof config.env_key === 'string') {
|
|
475
|
+
providerEnvKeys[name] = config.env_key;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// anthropic 显式配置但未写 env_key 时保留默认键(恢复旧版无条件映射的
|
|
479
|
+
// 配置场景行为;未配置时不再虚构)
|
|
480
|
+
if (rawProviderNames.includes('anthropic') &&
|
|
481
|
+
!modelProviders['anthropic']?.env_key &&
|
|
482
|
+
providerEnvKeys['anthropic'] === undefined) {
|
|
483
|
+
providerEnvKeys['anthropic'] = 'ANTHROPIC_API_KEY';
|
|
484
|
+
}
|
|
485
|
+
const providerModels = { openai: allModels };
|
|
486
|
+
// anthropic 仅在用户显式配置时才存在(非 codex 内置 provider)
|
|
487
|
+
if (rawProviderNames.includes('anthropic')) {
|
|
488
|
+
providerModels['anthropic'] = anthropicModels;
|
|
489
|
+
}
|
|
490
|
+
if (customProvider) {
|
|
491
|
+
// Custom provider: use the model from config.toml
|
|
492
|
+
providerModels[customProvider] = [currentModel];
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
currentModel,
|
|
496
|
+
currentProvider,
|
|
497
|
+
providerNames,
|
|
498
|
+
providerEnvKeys,
|
|
499
|
+
providerModels,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* 管线第 3 段(纯装配):给 provider 事实挂上 modelOptions 查询闭包,产出
|
|
504
|
+
* 对外的 CodexConfigResult。
|
|
505
|
+
*/
|
|
506
|
+
function applyProfiles(profile) {
|
|
507
|
+
return {
|
|
508
|
+
...profile,
|
|
509
|
+
modelOptions: (provider) => buildModelOptions(profile.currentModel, profile.currentProvider, provider, profile.providerModels),
|
|
510
|
+
};
|
|
511
|
+
}
|
|
395
512
|
/**
|
|
396
513
|
* Read codex config.toml, extract provider and model info
|
|
397
514
|
*
|
|
@@ -401,8 +518,9 @@ function extractCustomProvider(providers) {
|
|
|
401
518
|
* - anthropic: bundled models with 'claude-*' prefix
|
|
402
519
|
*/
|
|
403
520
|
export function loadCodexConfig(opts = {}) {
|
|
521
|
+
// 红线:resolveCodexHome 环境变量优先级(codexHome 参数 > $CODEX_HOME > ~/.codex)
|
|
522
|
+
// 只在此解析一次,下游各段共用同一 codexHome,不得重复解析。
|
|
404
523
|
const codexHome = resolveCodexHome(opts.codexHome);
|
|
405
|
-
const configFile = path.join(codexHome, 'config.toml');
|
|
406
524
|
const catalogMode = isCodexCatalogMode(codexHome);
|
|
407
525
|
// 统一目录来源:catalog 模式 = 活动目录(model_catalog_json 整体替换内置目录);
|
|
408
526
|
// 否则 = bundled(与原行为一致)
|
|
@@ -413,111 +531,21 @@ export function loadCodexConfig(opts = {}) {
|
|
|
413
531
|
const anthropicModels = catalogSlugs.length > 0
|
|
414
532
|
? catalogSlugs.filter((m) => m.startsWith('claude-'))
|
|
415
533
|
: ANTHROPIC_FALLBACK_MODELS;
|
|
416
|
-
|
|
534
|
+
const toml = readCodexToml(codexHome);
|
|
535
|
+
if (toml.state === 'missing') {
|
|
417
536
|
// 无 config.toml:默认模型取目录首个可用模型(codex default_model_from_available),
|
|
418
537
|
// 目录不可用时回退 'o3'(FALLBACK_MODELS 首项,非 catalog 默认)
|
|
419
538
|
const currentModel = allModels[0] ?? 'o3';
|
|
420
539
|
// No config file: only openai has bundled models
|
|
421
|
-
|
|
422
|
-
openai: allModels,
|
|
423
|
-
};
|
|
424
|
-
return {
|
|
540
|
+
return applyProfiles({
|
|
425
541
|
currentModel,
|
|
426
542
|
currentProvider: FALLBACK_PROVIDERS[0],
|
|
427
543
|
providerNames: FALLBACK_PROVIDERS,
|
|
428
544
|
providerEnvKeys: { openai: 'OPENAI_API_KEY' },
|
|
429
|
-
providerModels,
|
|
430
|
-
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
try {
|
|
434
|
-
const raw = fs.readFileSync(configFile, 'utf-8');
|
|
435
|
-
const parsed = TOML.parse(raw);
|
|
436
|
-
const modelKeyRaw = typeof parsed.model === 'string' && parsed.model.length > 0 ? parsed.model : undefined;
|
|
437
|
-
const currentProvider = String(parsed.model_provider ?? FALLBACK_PROVIDERS[0]);
|
|
438
|
-
// Extract model_providers section
|
|
439
|
-
const modelProviders = (parsed.model_providers ?? {});
|
|
440
|
-
const rawProviderNames = Object.keys(modelProviders);
|
|
441
|
-
let providerNames;
|
|
442
|
-
let providerEnvKeys;
|
|
443
|
-
let providerModels;
|
|
444
|
-
if (catalogMode) {
|
|
445
|
-
// catalog 模式:provider 列表 = 内置 openai + [model_providers.*](对齐 codex
|
|
446
|
-
// merge_configured_model_providers(built_in_model_providers, cfg.model_providers),
|
|
447
|
-
// core/src/config/mod.rs:3655;model_provider 未声明时默认 "openai",mod.rs:3659)。
|
|
448
|
-
// anthropic 不是 codex 内置 provider,未显式配置时不得出现。模型列表仍只来自
|
|
449
|
-
// 活动目录——openai+内置 gpt-5.x 的失效路径不因 provider 合并复活。
|
|
450
|
-
providerNames = rawProviderNames.includes('openai')
|
|
451
|
-
? rawProviderNames
|
|
452
|
-
: ['openai', ...rawProviderNames];
|
|
453
|
-
providerEnvKeys = { openai: 'OPENAI_API_KEY' };
|
|
454
|
-
for (const [name, config] of Object.entries(modelProviders)) {
|
|
455
|
-
if (typeof config.env_key === 'string') {
|
|
456
|
-
providerEnvKeys[name] = config.env_key;
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
// 活动目录全局:codex 运行时 provider 与模型无绑定(StaticModelsManager),
|
|
460
|
-
// 每个 provider 下拉都展示目录全部 slug
|
|
461
|
-
// 活动目录不可用(命令失败/空)时回退 [currentModel]——无目录元数据时档位/能力
|
|
462
|
-
// 不可信;禁止泄漏 FALLBACK_MODELS/内置目录。model 键缺失时不得虚构 'o3'。
|
|
463
|
-
const catalogCurrentModel = modelKeyRaw ?? catalogSlugs[0] ?? '';
|
|
464
|
-
const providerModelList = catalogSlugs.length > 0 ? catalogSlugs : modelKeyRaw ? [modelKeyRaw] : [];
|
|
465
|
-
providerModels = {};
|
|
466
|
-
for (const name of providerNames) {
|
|
467
|
-
providerModels[name] = providerModelList;
|
|
468
|
-
}
|
|
469
|
-
const resolvedProvider = typeof parsed.model_provider === 'string' && parsed.model_provider.length > 0
|
|
470
|
-
? parsed.model_provider
|
|
471
|
-
: 'openai';
|
|
472
|
-
return {
|
|
473
|
-
currentModel: catalogCurrentModel,
|
|
474
|
-
currentProvider: resolvedProvider,
|
|
475
|
-
providerNames,
|
|
476
|
-
providerEnvKeys,
|
|
477
|
-
providerModels,
|
|
478
|
-
modelOptions: (provider) => buildModelOptions(catalogCurrentModel, resolvedProvider, provider, providerModels),
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
// fallback 模式:保持原行为(openai/anthropic 内置 + bundled 模型)
|
|
482
|
-
const currentModel = modelKeyRaw ?? catalogSlugs[0] ?? 'o3';
|
|
483
|
-
providerNames = rawProviderNames;
|
|
484
|
-
if (!providerNames.includes('openai')) {
|
|
485
|
-
providerNames.unshift('openai');
|
|
486
|
-
}
|
|
487
|
-
const customProvider = extractCustomProvider(modelProviders);
|
|
488
|
-
providerEnvKeys = {};
|
|
489
|
-
providerEnvKeys['openai'] = 'OPENAI_API_KEY';
|
|
490
|
-
for (const [name, config] of Object.entries(modelProviders)) {
|
|
491
|
-
if (typeof config.env_key === 'string') {
|
|
492
|
-
providerEnvKeys[name] = config.env_key;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
// anthropic 显式配置但未写 env_key 时保留默认键(恢复旧版无条件映射的
|
|
496
|
-
// 配置场景行为;未配置时不再虚构)
|
|
497
|
-
if (rawProviderNames.includes('anthropic') &&
|
|
498
|
-
!modelProviders['anthropic']?.env_key &&
|
|
499
|
-
providerEnvKeys['anthropic'] === undefined) {
|
|
500
|
-
providerEnvKeys['anthropic'] = 'ANTHROPIC_API_KEY';
|
|
501
|
-
}
|
|
502
|
-
providerModels = { openai: allModels };
|
|
503
|
-
// anthropic 仅在用户显式配置时才存在(非 codex 内置 provider)
|
|
504
|
-
if (rawProviderNames.includes('anthropic')) {
|
|
505
|
-
providerModels['anthropic'] = anthropicModels;
|
|
506
|
-
}
|
|
507
|
-
if (customProvider) {
|
|
508
|
-
// Custom provider: use the model from config.toml
|
|
509
|
-
providerModels[customProvider] = [currentModel];
|
|
510
|
-
}
|
|
511
|
-
return {
|
|
512
|
-
currentModel,
|
|
513
|
-
currentProvider,
|
|
514
|
-
providerNames,
|
|
515
|
-
providerEnvKeys,
|
|
516
|
-
providerModels,
|
|
517
|
-
modelOptions: (provider) => buildModelOptions(currentModel, currentProvider, provider, providerModels),
|
|
518
|
-
};
|
|
545
|
+
providerModels: { openai: allModels },
|
|
546
|
+
});
|
|
519
547
|
}
|
|
520
|
-
|
|
548
|
+
if (toml.state === 'invalid') {
|
|
521
549
|
// config.toml 读取/解析失败:readModelCatalogJsonPath 对此返回
|
|
522
550
|
// TOML_PARSE_FAILED_SENTINEL(isCodexCatalogMode → false),因此正常路径下
|
|
523
551
|
// catalogMode 恒为 false,下面的 `if (catalogMode)` 分支只在两次读取之间
|
|
@@ -533,19 +561,15 @@ export function loadCodexConfig(opts = {}) {
|
|
|
533
561
|
modelOptions: () => [],
|
|
534
562
|
};
|
|
535
563
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
openai: allModels,
|
|
539
|
-
};
|
|
540
|
-
return {
|
|
541
|
-
currentModel,
|
|
564
|
+
return applyProfiles({
|
|
565
|
+
currentModel: catalogSlugs[0] ?? 'o3',
|
|
542
566
|
currentProvider: FALLBACK_PROVIDERS[0],
|
|
543
567
|
providerNames: FALLBACK_PROVIDERS,
|
|
544
568
|
providerEnvKeys: { openai: 'OPENAI_API_KEY' },
|
|
545
|
-
providerModels,
|
|
546
|
-
|
|
547
|
-
};
|
|
569
|
+
providerModels: { openai: allModels },
|
|
570
|
+
});
|
|
548
571
|
}
|
|
572
|
+
return applyProfiles(normalizeProviders(toml.parsed, { catalogMode, catalogSlugs, allModels, anthropicModels }));
|
|
549
573
|
}
|
|
550
574
|
/**
|
|
551
575
|
* Build model options for a provider.
|
package/dist/config/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { getConfigDir } from './dir.js';
|
|
|
4
4
|
export declare const CLAUDE_EFFORTS: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
5
5
|
/**
|
|
6
6
|
* Claude 的权限模式取值:'default' 之外都是 CLI `--permission-mode` 的真实枚举
|
|
7
|
-
* (
|
|
7
|
+
* (claude --help:acceptEdits | auto | bypassPermissions | manual
|
|
8
8
|
* | dontAsk | plan)。
|
|
9
9
|
* 'default' 是本项目自造的值,不是 CLI 的取值 —— 它表示"不传 --permission-mode",
|
|
10
10
|
* 由 CLI 自己决定默认模式,转换在 runner/claude/session.ts 的 spawn 参数处。
|
|
@@ -27,7 +27,7 @@ export declare const DEFAULT_APPROVAL_TIMEOUT_MS: number;
|
|
|
27
27
|
/**
|
|
28
28
|
* 入站媒体默认配置(schema 默认与 connector 兜底共用,避免双源漂移)。
|
|
29
29
|
*
|
|
30
|
-
* 单文件上限默认 100MB:50MB 对视频偏小(
|
|
30
|
+
* 单文件上限默认 100MB:50MB 对视频偏小(mp4 会被丢弃)。
|
|
31
31
|
* 注意飞书侧 `type=file` 超过 100MB 必须用 Range 分片下载,而 SDK 的
|
|
32
32
|
* `downloadResourceToFile` 不分片(必报 234037),所以 100 是实际可用上限
|
|
33
33
|
* (inbound-message-matrix.md §4 第 4 条)。
|
|
@@ -93,6 +93,16 @@ declare const OpencodeConfigSchema: z.ZodObject<{
|
|
|
93
93
|
turnIdleTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
|
|
94
94
|
}, z.core.$strip>>;
|
|
95
95
|
}, z.core.$strip>;
|
|
96
|
+
/**
|
|
97
|
+
* pi 默认配置:schema default、src/index.ts 注册兜底与 runner 构造器兜底
|
|
98
|
+
* 三处共用,避免三抄漂移。
|
|
99
|
+
*/
|
|
100
|
+
export declare const PI_DEFAULTS: {
|
|
101
|
+
readonly provider: "Volcano";
|
|
102
|
+
readonly model: "glm-5.2";
|
|
103
|
+
readonly thinking: "medium";
|
|
104
|
+
readonly tools: "read,bash,edit,write,grep,find,ls";
|
|
105
|
+
};
|
|
96
106
|
/** Pi-specific configuration. pi is a spawn-per-message CLI like Claude. */
|
|
97
107
|
declare const PiConfigSchema: z.ZodObject<{
|
|
98
108
|
provider: z.ZodDefault<z.ZodString>;
|
|
@@ -107,6 +117,10 @@ declare const PiConfigSchema: z.ZodObject<{
|
|
|
107
117
|
}>>;
|
|
108
118
|
tools: z.ZodDefault<z.ZodString>;
|
|
109
119
|
}, z.core.$strip>;
|
|
120
|
+
/** kimi 默认模型:schema default 与 src/index.ts 注册兜底共用,避免双抄漂移。 */
|
|
121
|
+
export declare const KIMI_DEFAULTS: {
|
|
122
|
+
readonly model: "kimi-code/k3";
|
|
123
|
+
};
|
|
110
124
|
/** Kimi-specific configuration. Pure ACP mode (persistent `kimi acp` connection). */
|
|
111
125
|
declare const KimiConfigSchema: z.ZodObject<{
|
|
112
126
|
model: z.ZodDefault<z.ZodString>;
|
package/dist/config/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import YAML from 'yaml';
|
|
5
5
|
import { getLogger } from '../logger/index.js';
|
|
6
6
|
import { atomicWrite } from '../persistence/atomic-write.js';
|
|
7
|
+
import { AGENT_KINDS } from '../agent-kinds.js';
|
|
7
8
|
export { getConfigDir } from './dir.js';
|
|
8
9
|
// Import constants from agent config files (SSOT: Layer 1 source)
|
|
9
10
|
import { KIMI_THINKING_EFFORTS } from './kimi-config.js';
|
|
@@ -11,7 +12,7 @@ import { KIMI_THINKING_EFFORTS } from './kimi-config.js';
|
|
|
11
12
|
export const CLAUDE_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
12
13
|
/**
|
|
13
14
|
* Claude 的权限模式取值:'default' 之外都是 CLI `--permission-mode` 的真实枚举
|
|
14
|
-
* (
|
|
15
|
+
* (claude --help:acceptEdits | auto | bypassPermissions | manual
|
|
15
16
|
* | dontAsk | plan)。
|
|
16
17
|
* 'default' 是本项目自造的值,不是 CLI 的取值 —— 它表示"不传 --permission-mode",
|
|
17
18
|
* 由 CLI 自己决定默认模式,转换在 runner/claude/session.ts 的 spawn 参数处。
|
|
@@ -55,7 +56,7 @@ export const DEFAULT_APPROVAL_TIMEOUT_MS = DEFAULTS.APPROVAL_TIMEOUT_MS;
|
|
|
55
56
|
/**
|
|
56
57
|
* 入站媒体默认配置(schema 默认与 connector 兜底共用,避免双源漂移)。
|
|
57
58
|
*
|
|
58
|
-
* 单文件上限默认 100MB:50MB 对视频偏小(
|
|
59
|
+
* 单文件上限默认 100MB:50MB 对视频偏小(mp4 会被丢弃)。
|
|
59
60
|
* 注意飞书侧 `type=file` 超过 100MB 必须用 Range 分片下载,而 SDK 的
|
|
60
61
|
* `downloadResourceToFile` 不分片(必报 234037),所以 100 是实际可用上限
|
|
61
62
|
* (inbound-message-matrix.md §4 第 4 条)。
|
|
@@ -141,21 +142,35 @@ const OpencodeConfigSchema = z.object({
|
|
|
141
142
|
})
|
|
142
143
|
.optional(),
|
|
143
144
|
});
|
|
145
|
+
/**
|
|
146
|
+
* pi 默认配置:schema default、src/index.ts 注册兜底与 runner 构造器兜底
|
|
147
|
+
* 三处共用,避免三抄漂移。
|
|
148
|
+
*/
|
|
149
|
+
export const PI_DEFAULTS = {
|
|
150
|
+
provider: 'Volcano',
|
|
151
|
+
model: 'glm-5.2',
|
|
152
|
+
thinking: 'medium',
|
|
153
|
+
tools: 'read,bash,edit,write,grep,find,ls',
|
|
154
|
+
};
|
|
144
155
|
/** Pi-specific configuration. pi is a spawn-per-message CLI like Claude. */
|
|
145
156
|
const PiConfigSchema = z.object({
|
|
146
157
|
/** LLM provider, e.g. 'Volcano', 'anthropic', 'openai'. */
|
|
147
|
-
provider: z.string().default(
|
|
158
|
+
provider: z.string().default(PI_DEFAULTS.provider),
|
|
148
159
|
/** Model ID or alias, e.g. 'glm-5.2'. */
|
|
149
|
-
model: z.string().default(
|
|
160
|
+
model: z.string().default(PI_DEFAULTS.model),
|
|
150
161
|
/** Thinking level: off/minimal/low/medium/high/xhigh. */
|
|
151
|
-
thinking: z.enum(PI_THINKING_LEVELS).default(
|
|
162
|
+
thinking: z.enum(PI_THINKING_LEVELS).default(PI_DEFAULTS.thinking),
|
|
152
163
|
/** Comma-separated tool whitelist. */
|
|
153
|
-
tools: z.string().default(
|
|
164
|
+
tools: z.string().default(PI_DEFAULTS.tools),
|
|
154
165
|
});
|
|
166
|
+
/** kimi 默认模型:schema default 与 src/index.ts 注册兜底共用,避免双抄漂移。 */
|
|
167
|
+
export const KIMI_DEFAULTS = {
|
|
168
|
+
model: 'kimi-code/k3',
|
|
169
|
+
};
|
|
155
170
|
/** Kimi-specific configuration. Pure ACP mode (persistent `kimi acp` connection). */
|
|
156
171
|
const KimiConfigSchema = z.object({
|
|
157
172
|
/** Model ID or alias, e.g. 'kimi-code/k3'. */
|
|
158
|
-
model: z.string().default(
|
|
173
|
+
model: z.string().default(KIMI_DEFAULTS.model),
|
|
159
174
|
/** Thinking effort,取值见 KIMI_THINKING_EFFORTS('low' | 'high' | 'max')。 */
|
|
160
175
|
thinkingEffort: z.enum(KIMI_THINKING_EFFORTS).default('max'),
|
|
161
176
|
/** Permission mode: 'manual' (approve each), 'auto' (engine decides), 'yolo' (allow all). */
|
|
@@ -307,7 +322,7 @@ export const AppConfigSchema = z.object({
|
|
|
307
322
|
/** 入站媒体(图片/文件)落盘配置。 */
|
|
308
323
|
inboundMedia: InboundMediaConfigSchema.default(InboundMediaConfigSchema.parse({})),
|
|
309
324
|
/** Default agent for new runs. */
|
|
310
|
-
defaultAgent: z.enum(
|
|
325
|
+
defaultAgent: z.enum(AGENT_KINDS).default('claude'),
|
|
311
326
|
/** Check for updates on lark-remote startup (default: false). */
|
|
312
327
|
checkUpdateOnStartup: z.boolean().default(false),
|
|
313
328
|
});
|