evolcore 0.0.7 → 0.0.9
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 +43 -0
- package/README.md +38 -4
- package/dist/agents/baseagent.js +117 -24
- package/dist/agents/claude-runner.js +31 -2
- package/dist/agents/codex-app-server-client.js +37 -2
- package/dist/agents/codex-runner.js +11 -3
- package/dist/aun/aid/control-aid.js +40 -27
- package/dist/aun/aid/domain.js +23 -0
- package/dist/aun/msg/group.js +9 -9
- package/dist/aun/msg/p2p.js +11 -6
- package/dist/aun/msg/upload.js +43 -29
- package/dist/aun/outbox.js +48 -5
- package/dist/channels/aun.js +225 -71
- package/dist/cli/aun-commands.js +10 -7
- package/dist/cli/bench.js +4 -3
- package/dist/cli/daemon-commands.js +208 -68
- package/dist/cli/data-command.js +62 -35
- package/dist/cli/index.js +11 -1
- package/dist/cli/init-channel.js +1 -1
- package/dist/cli/init.js +112 -17
- package/dist/cli/model.js +5 -5
- package/dist/cli/restart-monitor.js +102 -22
- package/dist/config/builtin-role-templates.js +4 -3
- package/dist/config/config-field-policy.js +6 -2
- package/dist/config/config-manager.js +79 -11
- package/dist/config/gateway-config.js +80 -35
- package/dist/config/role-schema.js +18 -3
- package/dist/config/role-service.js +3 -3
- package/dist/config/role-store.js +4 -3
- package/dist/config-store.js +19 -3
- package/dist/core/auth/operation-authorizer.js +3 -1
- package/dist/core/baseagent-loader.js +5 -3
- package/dist/core/bootstrap-service.js +0 -12
- package/dist/core/capability/providers/codex-capability-provider.js +2 -2
- package/dist/core/channel-loader.js +15 -2
- package/dist/core/command/command-handler.js +1 -1
- package/dist/core/command/evol-menu-version-gate.js +3 -2
- package/dist/core/command/menu-handler.js +50 -28
- package/dist/core/command/menu-protocol.js +7 -4
- package/dist/core/command/slash-handler.js +4 -4
- package/dist/core/data-migration.js +517 -24
- package/dist/core/inference/text-inference.js +18 -5
- package/dist/core/message/message-bridge.js +17 -6
- package/dist/core/message/response-engine.js +22 -3
- package/dist/core/model/config-scope.js +3 -3
- package/dist/core/permission/tool-policy.js +18 -0
- package/dist/core/protected-paths.js +12 -1
- package/dist/index.js +794 -725
- package/dist/ipc.js +3 -1
- package/dist/product.js +1 -0
- package/dist/utils/autostart.js +27 -0
- package/dist/utils/codex-cli.js +39 -0
- package/dist/utils/cross-platform.js +147 -18
- package/dist/utils/ecweb-utils.js +15 -2
- package/dist/utils/instance-registry.js +43 -6
- package/dist/utils/macos-autostart.js +179 -0
- package/dist/utils/process-introspect.js +7 -3
- package/dist/utils/windows-autostart.js +130 -0
- package/ecagent/dist/agent-loop.d.ts +1 -1
- package/ecagent/dist/agent-loop.js +1 -1
- package/ecagent/dist/agent.d.ts +1 -1
- package/ecagent/dist/agent.js +1 -1
- package/ecagent/dist/harness/agent-harness.d.ts +1 -1
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts +1 -1
- package/ecagent/dist/harness/compaction/compaction.d.ts +1 -1
- package/ecagent/dist/harness/compaction/utils.d.ts +1 -1
- package/ecagent/dist/harness/messages.d.ts +1 -1
- package/ecagent/dist/harness/session/session.d.ts +1 -1
- package/ecagent/dist/harness/types.d.ts +1 -1
- package/ecagent/dist/proxy.d.ts +1 -1
- package/ecagent/dist/proxy.js +1 -1
- package/ecagent/dist/types.d.ts +1 -1
- package/kits/migrations/migrate-role-config-v5.mjs +27 -2
- package/kits/rules/01-overview.md +3 -2
- package/kits/schemas/_meta.json +2 -1
- package/kits/schemas/agent-config.schema.10.json +19 -1
- package/kits/schemas/daemon.schema.4.json +136 -0
- package/kits/schemas/defaults.schema.4.json +15 -1
- package/kits/schemas/relation-config.schema.8.json +22 -1
- package/kits/schemas/role-config.schema.1.json +2 -2
- package/package.json +2 -4
- package/ecagent/dist/agent-loop.d.ts.map +0 -1
- package/ecagent/dist/agent-loop.js.map +0 -1
- package/ecagent/dist/agent.d.ts.map +0 -1
- package/ecagent/dist/agent.js.map +0 -1
- package/ecagent/dist/harness/agent-harness.d.ts.map +0 -1
- package/ecagent/dist/harness/agent-harness.js.map +0 -1
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/branch-summarization.js.map +0 -1
- package/ecagent/dist/harness/compaction/compaction.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/compaction.js.map +0 -1
- package/ecagent/dist/harness/compaction/utils.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/utils.js.map +0 -1
- package/ecagent/dist/harness/env/nodejs.d.ts.map +0 -1
- package/ecagent/dist/harness/env/nodejs.js.map +0 -1
- package/ecagent/dist/harness/messages.d.ts.map +0 -1
- package/ecagent/dist/harness/messages.js.map +0 -1
- package/ecagent/dist/harness/prompt-templates.d.ts.map +0 -1
- package/ecagent/dist/harness/prompt-templates.js.map +0 -1
- package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +0 -1
- package/ecagent/dist/harness/session/jsonl-repo.js.map +0 -1
- package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +0 -1
- package/ecagent/dist/harness/session/jsonl-storage.js.map +0 -1
- package/ecagent/dist/harness/session/memory-repo.d.ts.map +0 -1
- package/ecagent/dist/harness/session/memory-repo.js.map +0 -1
- package/ecagent/dist/harness/session/memory-storage.d.ts.map +0 -1
- package/ecagent/dist/harness/session/memory-storage.js.map +0 -1
- package/ecagent/dist/harness/session/repo-utils.d.ts.map +0 -1
- package/ecagent/dist/harness/session/repo-utils.js.map +0 -1
- package/ecagent/dist/harness/session/session.d.ts.map +0 -1
- package/ecagent/dist/harness/session/session.js.map +0 -1
- package/ecagent/dist/harness/session/uuid.d.ts.map +0 -1
- package/ecagent/dist/harness/session/uuid.js.map +0 -1
- package/ecagent/dist/harness/skills.d.ts.map +0 -1
- package/ecagent/dist/harness/skills.js.map +0 -1
- package/ecagent/dist/harness/system-prompt.d.ts.map +0 -1
- package/ecagent/dist/harness/system-prompt.js.map +0 -1
- package/ecagent/dist/harness/types.d.ts.map +0 -1
- package/ecagent/dist/harness/types.js.map +0 -1
- package/ecagent/dist/harness/utils/shell-output.d.ts.map +0 -1
- package/ecagent/dist/harness/utils/shell-output.js.map +0 -1
- package/ecagent/dist/harness/utils/truncate.d.ts.map +0 -1
- package/ecagent/dist/harness/utils/truncate.js.map +0 -1
- package/ecagent/dist/index.d.ts.map +0 -1
- package/ecagent/dist/index.js.map +0 -1
- package/ecagent/dist/node.d.ts.map +0 -1
- package/ecagent/dist/node.js.map +0 -1
- package/ecagent/dist/proxy.d.ts.map +0 -1
- package/ecagent/dist/proxy.js.map +0 -1
- package/ecagent/dist/runtime/api/lazy.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/lazy.js.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.js.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +0 -1
- package/ecagent/dist/runtime/auth/context.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/context.js.map +0 -1
- package/ecagent/dist/runtime/auth/credential-store.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/credential-store.js.map +0 -1
- package/ecagent/dist/runtime/auth/helpers.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/helpers.js.map +0 -1
- package/ecagent/dist/runtime/auth/resolve.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/resolve.js.map +0 -1
- package/ecagent/dist/runtime/auth/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/types.js.map +0 -1
- package/ecagent/dist/runtime/compat.d.ts.map +0 -1
- package/ecagent/dist/runtime/compat.js.map +0 -1
- package/ecagent/dist/runtime/index.d.ts.map +0 -1
- package/ecagent/dist/runtime/index.js.map +0 -1
- package/ecagent/dist/runtime/models.d.ts.map +0 -1
- package/ecagent/dist/runtime/models.js.map +0 -1
- package/ecagent/dist/runtime/oauth.d.ts.map +0 -1
- package/ecagent/dist/runtime/oauth.js.map +0 -1
- package/ecagent/dist/runtime/providers/faux.d.ts.map +0 -1
- package/ecagent/dist/runtime/providers/faux.js.map +0 -1
- package/ecagent/dist/runtime/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/types.js.map +0 -1
- package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/diagnostics.js.map +0 -1
- package/ecagent/dist/runtime/utils/event-stream.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/event-stream.js.map +0 -1
- package/ecagent/dist/runtime/utils/headers.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/headers.js.map +0 -1
- package/ecagent/dist/runtime/utils/json-parse.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/json-parse.js.map +0 -1
- package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/oauth/types.js.map +0 -1
- package/ecagent/dist/runtime/utils/overflow.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/overflow.js.map +0 -1
- package/ecagent/dist/runtime/utils/provider-env.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/provider-env.js.map +0 -1
- package/ecagent/dist/runtime/utils/retry.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/retry.js.map +0 -1
- package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/typebox-helpers.js.map +0 -1
- package/ecagent/dist/runtime/utils/validation.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/validation.js.map +0 -1
- package/ecagent/dist/types.d.ts.map +0 -1
- package/ecagent/dist/types.js.map +0 -1
- package/ecagent/package.json +0 -93
- package/ecagent/src/agent-loop.ts +0 -792
- package/ecagent/src/agent.ts +0 -575
- package/ecagent/src/harness/agent-harness.ts +0 -1029
- package/ecagent/src/harness/compaction/branch-summarization.ts +0 -261
- package/ecagent/src/harness/compaction/compaction.ts +0 -753
- package/ecagent/src/harness/compaction/utils.ts +0 -144
- package/ecagent/src/harness/env/nodejs.ts +0 -569
- package/ecagent/src/harness/messages.ts +0 -164
- package/ecagent/src/harness/prompt-templates.ts +0 -267
- package/ecagent/src/harness/session/jsonl-repo.ts +0 -179
- package/ecagent/src/harness/session/jsonl-storage.ts +0 -314
- package/ecagent/src/harness/session/memory-repo.ts +0 -50
- package/ecagent/src/harness/session/memory-storage.ts +0 -133
- package/ecagent/src/harness/session/repo-utils.ts +0 -51
- package/ecagent/src/harness/session/session.ts +0 -338
- package/ecagent/src/harness/session/uuid.ts +0 -54
- package/ecagent/src/harness/skills.ts +0 -375
- package/ecagent/src/harness/system-prompt.ts +0 -34
- package/ecagent/src/harness/types.ts +0 -838
- package/ecagent/src/harness/utils/shell-output.ts +0 -135
- package/ecagent/src/harness/utils/truncate.ts +0 -344
- package/ecagent/src/index.ts +0 -46
- package/ecagent/src/node.ts +0 -2
- package/ecagent/src/proxy.ts +0 -367
- package/ecagent/src/runtime/api/lazy.ts +0 -70
- package/ecagent/src/runtime/api/pi-messages.lazy.ts +0 -4
- package/ecagent/src/runtime/api/pi-messages.ts +0 -436
- package/ecagent/src/runtime/auth/context.ts +0 -45
- package/ecagent/src/runtime/auth/credential-store.ts +0 -47
- package/ecagent/src/runtime/auth/helpers.ts +0 -46
- package/ecagent/src/runtime/auth/resolve.ts +0 -141
- package/ecagent/src/runtime/auth/types.ts +0 -182
- package/ecagent/src/runtime/compat.ts +0 -158
- package/ecagent/src/runtime/index.ts +0 -31
- package/ecagent/src/runtime/models.ts +0 -452
- package/ecagent/src/runtime/oauth.ts +0 -1
- package/ecagent/src/runtime/providers/faux.ts +0 -538
- package/ecagent/src/runtime/types.ts +0 -718
- package/ecagent/src/runtime/utils/diagnostics.ts +0 -45
- package/ecagent/src/runtime/utils/event-stream.ts +0 -88
- package/ecagent/src/runtime/utils/headers.ts +0 -18
- package/ecagent/src/runtime/utils/json-parse.ts +0 -124
- package/ecagent/src/runtime/utils/oauth/types.ts +0 -79
- package/ecagent/src/runtime/utils/overflow.ts +0 -165
- package/ecagent/src/runtime/utils/provider-env.ts +0 -52
- package/ecagent/src/runtime/utils/retry.ts +0 -101
- package/ecagent/src/runtime/utils/typebox-helpers.ts +0 -24
- package/ecagent/src/runtime/utils/validation.ts +0 -310
- package/ecagent/src/types.ts +0 -430
- package/ecagent/tsconfig.build.json +0 -32
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,49 @@
|
|
|
3
3
|
本文件记录 EvolCore 的重要变更。EvolClaw 版本线的历史记录已归档至
|
|
4
4
|
[`docs/_archive/CHANGELOG-evolclaw.md`](docs/_archive/CHANGELOG-evolclaw.md)。
|
|
5
5
|
|
|
6
|
+
## 0.0.9 (2026-08-06)
|
|
7
|
+
|
|
8
|
+
### 安装与自启
|
|
9
|
+
|
|
10
|
+
- 支持在安装或初始化时配置登录自启,Windows 与 macOS 开机登录后自动拉起 EvolCore。
|
|
11
|
+
- 已完成初始化的安装可单独开关登录自启,无需重跑初始化流程。
|
|
12
|
+
|
|
13
|
+
### AUN 通信
|
|
14
|
+
|
|
15
|
+
- 出站消息默认加密,可通过配置调整;观察者转发与回执一并遵循该设置。
|
|
16
|
+
- 未连接时的图片与消息发送进入待发队列,连接恢复后按序重投,不再直接丢弃。
|
|
17
|
+
- 完善图片上传的类型识别与结构化内容处理。
|
|
18
|
+
|
|
19
|
+
### BaseAgent 配置
|
|
20
|
+
|
|
21
|
+
- 支持为 BaseAgent 自定义请求头和查询参数,便于对接需要额外标识的网关。
|
|
22
|
+
- 统一各 BaseAgent 的推理强度配置项,旧字段仍可识别。
|
|
23
|
+
|
|
24
|
+
### 运行可靠性
|
|
25
|
+
|
|
26
|
+
- 修复 Agent 在启动阶段被中断时的状态残留。
|
|
27
|
+
- EC Web 版本过低时拒绝启动并提示升级命令,避免新旧组件搭配下的异常行为。
|
|
28
|
+
- 完善菜单协议的权限校验,并修正系统信息查询。
|
|
29
|
+
|
|
30
|
+
## 0.0.8 (2026-08-04)
|
|
31
|
+
|
|
32
|
+
### AID 与域名管理
|
|
33
|
+
|
|
34
|
+
- 支持通过配置控制 AID 所属域名,并可在变更后自动迁移已有身份记录。
|
|
35
|
+
|
|
36
|
+
### 运行稳定性
|
|
37
|
+
|
|
38
|
+
- 完善数据迁移的归档与收尾清理逻辑,降低目录结构演进带来的遗留数据风险。
|
|
39
|
+
- 增强 daemon 启停流程与运行状态诊断,异常时定位信息更准确。
|
|
40
|
+
- 完善 Agent 运行时在失败场景下的状态标记与回退行为。
|
|
41
|
+
- 修复 Windows 下 Codex CLI 的命令解析与进程启动兼容问题。
|
|
42
|
+
|
|
43
|
+
### 交互体验
|
|
44
|
+
|
|
45
|
+
- AUN 交互卡片有效期延长至 24 小时,与实际使用节奏匹配。
|
|
46
|
+
- 修复 Web 控制台触发器视图中 daemon 控制触发器无处归属的问题,升级检查触发器包名一并修正。
|
|
47
|
+
- 优化 EC Web 网关状态展示。
|
|
48
|
+
|
|
6
49
|
## 0.0.7 (2026-08-03)
|
|
7
50
|
|
|
8
51
|
### 运行可靠性
|
package/README.md
CHANGED
|
@@ -86,16 +86,16 @@ ResponseEngine.processMessage()
|
|
|
86
86
|
**一行安装(macOS / Linux)**:
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
curl -fsSL https://
|
|
89
|
+
curl -fsSL https://download.evolai.cn/releases/evolcore/2026-08-05.2/install.sh | bash
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
**Windows PowerShell**:
|
|
93
93
|
|
|
94
94
|
```powershell
|
|
95
|
-
irm https://
|
|
95
|
+
& ([scriptblock]::Create((irm https://download.evolai.cn/releases/evolcore/2026-08-05.2/install.ps1))) -AutoStart
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
安装器会自动进入 `ec init` 交互向导;只有已有配置同时包含控制 AID 和 Owner
|
|
98
|
+
安装器会自动进入 `ec init` 交互向导;只有已有配置同时包含控制 AID 和 Owner 时才跳过。上面的 Windows 命令会在绑定完成后自动运行 `ec start`;macOS/Linux 需手动运行 `ec start`。安装器不会停止或重启已有服务,详细流程见 [一键安装脚本说明](docs/evolcore-install-script.md)。
|
|
99
99
|
|
|
100
100
|
**npm 全局安装**:
|
|
101
101
|
|
|
@@ -169,11 +169,45 @@ ec init aun
|
|
|
169
169
|
```
|
|
170
170
|
|
|
171
171
|
**API 继承机制**:`agents.claude` 整个 section 可省略,系统自动按以下优先级继承:
|
|
172
|
-
- `apiKey`:配置文件 → `ANTHROPIC_AUTH_TOKEN` 环境变量 → `~/.claude/settings.json`
|
|
172
|
+
- `apiKey`:配置文件 → `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_API_KEY` 环境变量 → `~/.claude/settings.json` 中对应变量
|
|
173
173
|
- `baseUrl`:配置文件 → `ANTHROPIC_BASE_URL` 环境变量 → `~/.claude/settings.json`
|
|
174
174
|
- `model`:配置文件 → `~/.claude/settings.json` → 默认 `sonnet`
|
|
175
175
|
- `effort`:配置文件 → `~/.claude/settings.json` → SDK 默认值(`auto`)
|
|
176
176
|
|
|
177
|
+
Claude/Codex 兼容网关需要额外请求头或查询参数时,可以直接在 EvolCore 的
|
|
178
|
+
`baseagents` 配置中设置,不需要修改 Claude/Codex 的全局配置文件:
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"baseagents": {
|
|
183
|
+
"claude": {
|
|
184
|
+
"baseUrl": "https://example.com/claude",
|
|
185
|
+
"headers": {
|
|
186
|
+
"X-Tenant-Id": "${TENANT_ID}"
|
|
187
|
+
},
|
|
188
|
+
"queryParams": {
|
|
189
|
+
"source": "evolcore"
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
"codex": {
|
|
193
|
+
"baseUrl": "https://example.com/codex",
|
|
194
|
+
"headers": {
|
|
195
|
+
"X-Tenant-Id": "${TENANT_ID}"
|
|
196
|
+
},
|
|
197
|
+
"queryParams": {
|
|
198
|
+
"source": "evolcore"
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`${VAR}` 会按 EvolCore 的环境变量规则展开。Claude 通过 `ANTHROPIC_CUSTOM_HEADERS`
|
|
206
|
+
传递 Header;Codex app-server 启动时由 EvolCore 注入 `env_http_headers` 和
|
|
207
|
+
`query_params`,所以不需要手改 `~/.codex/config.toml`。`queryParams` 不应放置密钥等敏感信息。
|
|
208
|
+
|
|
209
|
+
完整设计、运行链路和排障说明见:[Claude/Codex 自定义请求元数据技术文档](docs/baseagent-request-metadata.md)。
|
|
210
|
+
|
|
177
211
|
### 3. 运行
|
|
178
212
|
|
|
179
213
|
```bash
|
package/dist/agents/baseagent.js
CHANGED
|
@@ -50,6 +50,39 @@ function directInferenceValue(...values) {
|
|
|
50
50
|
}
|
|
51
51
|
return undefined;
|
|
52
52
|
}
|
|
53
|
+
const HTTP_HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
54
|
+
function normalizeStringMap(value, field) {
|
|
55
|
+
if (value === undefined || value === null)
|
|
56
|
+
return undefined;
|
|
57
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
58
|
+
throw new Error(`${field} must be an object with string values`);
|
|
59
|
+
}
|
|
60
|
+
const entries = [];
|
|
61
|
+
for (const [key, item] of Object.entries(value)) {
|
|
62
|
+
if (!key)
|
|
63
|
+
throw new Error(`${field} names cannot be empty`);
|
|
64
|
+
if (typeof item !== 'string')
|
|
65
|
+
throw new Error(`${field}.${key} must be a string`);
|
|
66
|
+
if (field === 'headers') {
|
|
67
|
+
if (!HTTP_HEADER_NAME.test(key))
|
|
68
|
+
throw new Error(`Invalid HTTP header name: ${key}`);
|
|
69
|
+
if (/[\0\r\n]/.test(item))
|
|
70
|
+
throw new Error(`HTTP header ${key} cannot contain NUL or line breaks`);
|
|
71
|
+
}
|
|
72
|
+
entries.push([key, item]);
|
|
73
|
+
}
|
|
74
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
75
|
+
}
|
|
76
|
+
function normalizeRequestMetadata(value) {
|
|
77
|
+
return {
|
|
78
|
+
headers: normalizeStringMap(value?.headers, 'headers'),
|
|
79
|
+
queryParams: normalizeStringMap(value?.queryParams, 'queryParams'),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Claude Code accepts both names; AUTH_TOKEN is kept first for compatibility. */
|
|
83
|
+
function resolveAnthropicApiKey(...values) {
|
|
84
|
+
return directInferenceValue(...values);
|
|
85
|
+
}
|
|
53
86
|
function loadClaudeSettings() {
|
|
54
87
|
try {
|
|
55
88
|
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
@@ -67,25 +100,36 @@ function loadClaudeSettings() {
|
|
|
67
100
|
*/
|
|
68
101
|
export function resolveAnthropicDirectConfig(override) {
|
|
69
102
|
const explicit = directInferencePair(override?.apiKey, override?.baseUrl);
|
|
70
|
-
if (explicit)
|
|
71
|
-
return
|
|
103
|
+
if (explicit) {
|
|
104
|
+
return {
|
|
105
|
+
...explicit,
|
|
106
|
+
...normalizeRequestMetadata(override),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
72
109
|
const environment = directInferencePair(directInferenceValue(process.env.ANTHROPIC_AUTH_TOKEN, process.env.ANTHROPIC_API_KEY), process.env.ANTHROPIC_BASE_URL);
|
|
73
|
-
if (environment)
|
|
74
|
-
return
|
|
110
|
+
if (environment) {
|
|
111
|
+
return {
|
|
112
|
+
...environment,
|
|
113
|
+
...normalizeRequestMetadata(override),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
75
116
|
const settings = loadClaudeSettings();
|
|
76
|
-
|
|
117
|
+
const settingsResolved = directInferencePair(directInferenceValue(settings.env?.ANTHROPIC_AUTH_TOKEN, settings.env?.ANTHROPIC_API_KEY), settings.env?.ANTHROPIC_BASE_URL);
|
|
118
|
+
return settingsResolved
|
|
119
|
+
? {
|
|
120
|
+
...settingsResolved,
|
|
121
|
+
...normalizeRequestMetadata(override),
|
|
122
|
+
}
|
|
123
|
+
: undefined;
|
|
77
124
|
}
|
|
78
125
|
export function resolveAnthropicConfig(config, override) {
|
|
79
126
|
const settings = loadClaudeSettings();
|
|
80
127
|
const isPlaceholder = (v) => !v || v.includes('your-') || v.includes('placeholder');
|
|
81
128
|
const overrideApiKey = isPlaceholder(override?.apiKey) ? undefined : override?.apiKey;
|
|
82
129
|
const globalApiKey = isPlaceholder(config.agents?.claude?.apiKey) ? undefined : config.agents?.claude?.apiKey;
|
|
83
|
-
const apiKey = overrideApiKey
|
|
84
|
-
|| globalApiKey
|
|
85
|
-
|| process.env.ANTHROPIC_AUTH_TOKEN
|
|
86
|
-
|| settings.env?.ANTHROPIC_AUTH_TOKEN;
|
|
130
|
+
const apiKey = resolveAnthropicApiKey(overrideApiKey, globalApiKey, process.env.ANTHROPIC_AUTH_TOKEN, process.env.ANTHROPIC_API_KEY, settings.env?.ANTHROPIC_AUTH_TOKEN, settings.env?.ANTHROPIC_API_KEY);
|
|
87
131
|
if (!apiKey) {
|
|
88
|
-
throw new Error('No API key found. Set
|
|
132
|
+
throw new Error('No API key found for Claude. Set baseagents.claude.apiKey, env ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY, or the corresponding variable in ~/.claude/settings.json');
|
|
89
133
|
}
|
|
90
134
|
const isPlaceholderUrl = (v) => !v || v.includes('api.anthropic.com');
|
|
91
135
|
const overrideBaseUrl = isPlaceholderUrl(override?.baseUrl) ? undefined : override?.baseUrl;
|
|
@@ -94,6 +138,8 @@ export function resolveAnthropicConfig(config, override) {
|
|
|
94
138
|
|| globalBaseUrl
|
|
95
139
|
|| process.env.ANTHROPIC_BASE_URL
|
|
96
140
|
|| settings.env?.ANTHROPIC_BASE_URL;
|
|
141
|
+
const headers = normalizeStringMap(override?.headers ?? config.agents?.claude?.headers, 'headers');
|
|
142
|
+
const queryParams = normalizeStringMap(override?.queryParams ?? config.agents?.claude?.queryParams, 'queryParams');
|
|
97
143
|
const model = override?.model
|
|
98
144
|
|| config.agents?.claude?.model
|
|
99
145
|
|| settings.model
|
|
@@ -105,19 +151,22 @@ export function resolveAnthropicConfig(config, override) {
|
|
|
105
151
|
const pickExec = (v) => (!v || v.includes('your-') || v.includes('placeholder')) ? undefined : v;
|
|
106
152
|
const pathToClaudeCodeExecutable = pickExec(override?.pathToClaudeCodeExecutable)
|
|
107
153
|
|| pickExec(config.agents?.claude?.pathToClaudeCodeExecutable);
|
|
108
|
-
return { apiKey, baseUrl, model, effort, pathToClaudeCodeExecutable };
|
|
154
|
+
return { apiKey, baseUrl, headers, queryParams, model, effort, pathToClaudeCodeExecutable };
|
|
109
155
|
}
|
|
110
156
|
function loadCodexSettings() {
|
|
111
157
|
try {
|
|
112
|
-
const
|
|
158
|
+
const configuredHome = process.env.CODEX_HOME?.trim();
|
|
159
|
+
const codexHome = configuredHome ? path.resolve(configuredHome) : path.join(os.homedir(), '.codex');
|
|
160
|
+
const authPath = path.join(codexHome, 'auth.json');
|
|
113
161
|
let apiKey;
|
|
114
162
|
if (fs.existsSync(authPath)) {
|
|
115
163
|
const auth = JSON.parse(fs.readFileSync(authPath, 'utf-8'));
|
|
116
164
|
apiKey = auth.OPENAI_API_KEY;
|
|
117
165
|
}
|
|
118
|
-
const configPath = path.join(
|
|
166
|
+
const configPath = path.join(codexHome, 'config.toml');
|
|
119
167
|
let model;
|
|
120
168
|
let baseUrl;
|
|
169
|
+
let provider;
|
|
121
170
|
if (fs.existsSync(configPath)) {
|
|
122
171
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
123
172
|
const modelMatch = content.match(/^model\s*=\s*"([^"]+)"/m);
|
|
@@ -125,17 +174,35 @@ function loadCodexSettings() {
|
|
|
125
174
|
model = modelMatch[1];
|
|
126
175
|
const providerMatch = content.match(/^model_provider\s*=\s*"([^"]+)"/m);
|
|
127
176
|
if (providerMatch) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (baseUrlMatch)
|
|
131
|
-
baseUrl = baseUrlMatch[1];
|
|
177
|
+
provider = providerMatch[1];
|
|
178
|
+
baseUrl = readCodexProviderBaseUrl(content, provider);
|
|
132
179
|
}
|
|
133
180
|
}
|
|
134
|
-
return { apiKey, baseUrl, model };
|
|
181
|
+
return { apiKey, baseUrl, model, provider };
|
|
135
182
|
}
|
|
136
183
|
catch { }
|
|
137
184
|
return {};
|
|
138
185
|
}
|
|
186
|
+
function escapeRegExp(value) {
|
|
187
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
188
|
+
}
|
|
189
|
+
function readCodexProviderBaseUrl(content, provider) {
|
|
190
|
+
const segments = /^[A-Za-z0-9_-]+$/.test(provider)
|
|
191
|
+
? [provider, JSON.stringify(provider)]
|
|
192
|
+
: [JSON.stringify(provider)];
|
|
193
|
+
for (const segment of segments) {
|
|
194
|
+
const section = new RegExp(`^\\s*\\[\\s*model_providers\\s*\\.\\s*${escapeRegExp(segment)}\\s*\\]\\s*(?:#.*)?$`, 'm').exec(content);
|
|
195
|
+
if (!section || section.index === undefined)
|
|
196
|
+
continue;
|
|
197
|
+
const tail = content.slice(section.index + section[0].length);
|
|
198
|
+
const nextSection = tail.search(/^\s*\[/m);
|
|
199
|
+
const block = nextSection >= 0 ? tail.slice(0, nextSection) : tail;
|
|
200
|
+
const baseUrl = block.match(/^\s*base_url\s*=\s*"([^"]+)"/m)?.[1];
|
|
201
|
+
if (baseUrl)
|
|
202
|
+
return baseUrl;
|
|
203
|
+
}
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
139
206
|
/**
|
|
140
207
|
* Resolve a complete credential/endpoint pair for direct OpenAI HTTP calls.
|
|
141
208
|
* auth.json and config.toml together form the Codex SDK source; fields are
|
|
@@ -143,13 +210,27 @@ function loadCodexSettings() {
|
|
|
143
210
|
*/
|
|
144
211
|
export function resolveOpenaiDirectConfig(override) {
|
|
145
212
|
const explicit = directInferencePair(override?.apiKey, override?.baseUrl);
|
|
146
|
-
if (explicit)
|
|
147
|
-
return
|
|
213
|
+
if (explicit) {
|
|
214
|
+
return {
|
|
215
|
+
...explicit,
|
|
216
|
+
...normalizeRequestMetadata(override),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
148
219
|
const environment = directInferencePair(process.env.OPENAI_API_KEY, process.env.OPENAI_BASE_URL);
|
|
149
|
-
if (environment)
|
|
150
|
-
return
|
|
220
|
+
if (environment) {
|
|
221
|
+
return {
|
|
222
|
+
...environment,
|
|
223
|
+
...normalizeRequestMetadata(override),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
151
226
|
const settings = loadCodexSettings();
|
|
152
|
-
|
|
227
|
+
const settingsResolved = directInferencePair(settings.apiKey, settings.baseUrl);
|
|
228
|
+
return settingsResolved
|
|
229
|
+
? {
|
|
230
|
+
...settingsResolved,
|
|
231
|
+
...normalizeRequestMetadata(override),
|
|
232
|
+
}
|
|
233
|
+
: undefined;
|
|
153
234
|
}
|
|
154
235
|
export function resolveOpenaiConfig(config, override) {
|
|
155
236
|
const codexSettings = loadCodexSettings();
|
|
@@ -171,6 +252,8 @@ export function resolveOpenaiConfig(config, override) {
|
|
|
171
252
|
|| process.env.OPENAI_BASE_URL
|
|
172
253
|
|| codexSettings.baseUrl
|
|
173
254
|
|| undefined;
|
|
255
|
+
const headers = normalizeStringMap(override?.headers ?? config.agents?.codex?.headers, 'headers');
|
|
256
|
+
const queryParams = normalizeStringMap(override?.queryParams ?? config.agents?.codex?.queryParams, 'queryParams');
|
|
174
257
|
const model = override?.model
|
|
175
258
|
|| config.agents?.codex?.model
|
|
176
259
|
|| codexSettings.model
|
|
@@ -186,7 +269,17 @@ export function resolveOpenaiConfig(config, override) {
|
|
|
186
269
|
const approvalsReviewer = override?.approvalsReviewer
|
|
187
270
|
?? config.agents?.codex?.approvalsReviewer
|
|
188
271
|
?? undefined;
|
|
189
|
-
return {
|
|
272
|
+
return {
|
|
273
|
+
apiKey,
|
|
274
|
+
baseUrl,
|
|
275
|
+
provider: codexSettings.provider,
|
|
276
|
+
headers,
|
|
277
|
+
queryParams,
|
|
278
|
+
model,
|
|
279
|
+
effort,
|
|
280
|
+
enableRequestUserInput,
|
|
281
|
+
approvalsReviewer,
|
|
282
|
+
};
|
|
190
283
|
}
|
|
191
284
|
export function resolveGoogleConfig(config, override) {
|
|
192
285
|
const googleCfg = config.agents?.gemini;
|
|
@@ -65,6 +65,19 @@ function isClaudeMcpTool(toolName) {
|
|
|
65
65
|
function isUnknownClaudeTool(toolName) {
|
|
66
66
|
return !isClaudeMcpTool(toolName) && !CLAUDE_BUILTIN_TOOLS.has(toolName);
|
|
67
67
|
}
|
|
68
|
+
function appendQueryParams(baseUrl, queryParams) {
|
|
69
|
+
if (!baseUrl || !queryParams || Object.keys(queryParams).length === 0)
|
|
70
|
+
return baseUrl;
|
|
71
|
+
try {
|
|
72
|
+
const parsed = new URL(baseUrl);
|
|
73
|
+
for (const [name, value] of Object.entries(queryParams))
|
|
74
|
+
parsed.searchParams.set(name, value);
|
|
75
|
+
return parsed.toString();
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return baseUrl;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
68
81
|
function stableClaudePermissionValue(value, depth = 0) {
|
|
69
82
|
if (depth > 8)
|
|
70
83
|
return '[truncated]';
|
|
@@ -529,6 +542,8 @@ export class AgentRunner {
|
|
|
529
542
|
effort;
|
|
530
543
|
permissionMode = DEFAULT_PERMISSION_MODE;
|
|
531
544
|
baseUrl;
|
|
545
|
+
customHeaders;
|
|
546
|
+
customQueryParams;
|
|
532
547
|
config;
|
|
533
548
|
activeSessions = new Map();
|
|
534
549
|
activeStreams = new Map();
|
|
@@ -556,15 +571,22 @@ export class AgentRunner {
|
|
|
556
571
|
if (config) {
|
|
557
572
|
const anthropic = resolveAnthropicConfig(config);
|
|
558
573
|
this.claudeExecutablePath = anthropic.pathToClaudeCodeExecutable;
|
|
574
|
+
this.customHeaders = anthropic.headers;
|
|
575
|
+
this.customQueryParams = anthropic.queryParams;
|
|
559
576
|
}
|
|
560
577
|
}
|
|
561
578
|
getAgentEnv(runtimeEnv, evolcoreSessionId) {
|
|
579
|
+
const anthropicBaseUrl = appendQueryParams(this.baseUrl, this.customQueryParams);
|
|
562
580
|
const env = {
|
|
563
581
|
...process.env,
|
|
564
582
|
ANTHROPIC_AUTH_TOKEN: this.apiKey,
|
|
583
|
+
ANTHROPIC_API_KEY: this.apiKey,
|
|
565
584
|
PATH: process.env.PATH,
|
|
566
585
|
DISABLE_AUTOUPDATER: '1',
|
|
567
|
-
...(
|
|
586
|
+
...(anthropicBaseUrl ? { ANTHROPIC_BASE_URL: anthropicBaseUrl } : {}),
|
|
587
|
+
...(this.customHeaders
|
|
588
|
+
? { ANTHROPIC_CUSTOM_HEADERS: Object.entries(this.customHeaders).map(([name, value]) => `${name}: ${value}`).join('\n') }
|
|
589
|
+
: {}),
|
|
568
590
|
...(evolcoreSessionId ? { EVOLCORE_SESSION_ID: evolcoreSessionId } : {}),
|
|
569
591
|
...(runtimeEnv ?? {}),
|
|
570
592
|
};
|
|
@@ -2297,6 +2319,7 @@ export class AgentRunner {
|
|
|
2297
2319
|
})();
|
|
2298
2320
|
}
|
|
2299
2321
|
async interrupt(sessionId) {
|
|
2322
|
+
const streamRegistered = this.activeStreams.has(sessionId);
|
|
2300
2323
|
const fn = this.interruptFns.get(sessionId);
|
|
2301
2324
|
const query = this.activeQueries.get(sessionId);
|
|
2302
2325
|
const cancelledInputIds = [];
|
|
@@ -2326,7 +2349,10 @@ export class AgentRunner {
|
|
|
2326
2349
|
if (query && typeof query.close === 'function')
|
|
2327
2350
|
query.close();
|
|
2328
2351
|
const done = this.streamDone.get(sessionId);
|
|
2329
|
-
|
|
2352
|
+
// A stream interrupted after runQuery resolves but before registerStream has
|
|
2353
|
+
// no consumer that can enter the wrapper generator's finally block. Waiting
|
|
2354
|
+
// for streamDone here would always burn the full timeout.
|
|
2355
|
+
if (done && streamRegistered) {
|
|
2330
2356
|
await Promise.race([done, new Promise(resolve => setTimeout(resolve, 5_000))]);
|
|
2331
2357
|
}
|
|
2332
2358
|
this.interruptFns.delete(sessionId);
|
|
@@ -2342,6 +2368,9 @@ export class AgentRunner {
|
|
|
2342
2368
|
cleanupStream(sessionId) {
|
|
2343
2369
|
this.activeMessageStreams.get(sessionId)?.end();
|
|
2344
2370
|
this.activeMessageStreams.delete(sessionId);
|
|
2371
|
+
this.streamDoneResolvers.get(sessionId)?.();
|
|
2372
|
+
this.streamDoneResolvers.delete(sessionId);
|
|
2373
|
+
this.streamDone.delete(sessionId);
|
|
2345
2374
|
this.activeStreams.delete(sessionId);
|
|
2346
2375
|
this.interruptFns.delete(sessionId);
|
|
2347
2376
|
this.activeQueries.delete(sessionId);
|
|
@@ -2,6 +2,23 @@ import { spawn } from 'child_process';
|
|
|
2
2
|
import readline from 'readline';
|
|
3
3
|
import { logger } from '../utils/logger.js';
|
|
4
4
|
import { buildHClassGuardCommand } from '../core/permission/sandbox-runtime.js';
|
|
5
|
+
import { resolveCodexLaunchCommand } from '../utils/codex-cli.js';
|
|
6
|
+
import { createHash } from 'crypto';
|
|
7
|
+
function tomlProviderKey(value) {
|
|
8
|
+
if (!value || /[\0\r\n]/.test(value)) {
|
|
9
|
+
throw new Error(`Invalid Codex provider name: ${value}`);
|
|
10
|
+
}
|
|
11
|
+
return /^[A-Za-z0-9_-]+$/.test(value) ? value : JSON.stringify(value);
|
|
12
|
+
}
|
|
13
|
+
function tomlInlineStringTable(values) {
|
|
14
|
+
return `{${Object.entries(values)
|
|
15
|
+
.map(([name, value]) => `${JSON.stringify(name)}=${JSON.stringify(value)}`)
|
|
16
|
+
.join(',')}}`;
|
|
17
|
+
}
|
|
18
|
+
function codexHeaderEnvName(headerName) {
|
|
19
|
+
const digest = createHash('sha256').update(headerName).digest('hex').slice(0, 16).toUpperCase();
|
|
20
|
+
return `EVOLCORE_CODEX_HEADER_${digest}`;
|
|
21
|
+
}
|
|
5
22
|
function hasPermissionProfile(config) {
|
|
6
23
|
if (!config || typeof config.default_permissions !== 'string' || !config.default_permissions)
|
|
7
24
|
return false;
|
|
@@ -326,15 +343,21 @@ export class CodexAppServerClient {
|
|
|
326
343
|
startProcess() {
|
|
327
344
|
const env = { ...process.env, ...this.options.env };
|
|
328
345
|
env.CODEX_API_KEY = this.options.apiKey;
|
|
346
|
+
for (const [name, value] of Object.entries(this.options.headers ?? {})) {
|
|
347
|
+
env[codexHeaderEnvName(name)] = value;
|
|
348
|
+
}
|
|
329
349
|
if (this.options.baseUrl) {
|
|
330
350
|
env.OPENAI_BASE_URL = this.options.baseUrl;
|
|
331
351
|
}
|
|
332
352
|
const args = this.buildProcessArgs();
|
|
333
|
-
const
|
|
353
|
+
const launchCommand = resolveCodexLaunchCommand(args);
|
|
354
|
+
if (!launchCommand)
|
|
355
|
+
throw new Error('Codex CLI not found');
|
|
356
|
+
const guardedCommand = buildHClassGuardCommand(launchCommand.command, launchCommand.args);
|
|
334
357
|
if (process.platform === 'linux' && !guardedCommand) {
|
|
335
358
|
throw new Error('Codex 缺少 EvolCore H 类路径隔离运行时,已拒绝启动 app-server');
|
|
336
359
|
}
|
|
337
|
-
this.proc = spawn(guardedCommand?.command ??
|
|
360
|
+
this.proc = spawn(guardedCommand?.command ?? launchCommand.command, guardedCommand?.args ?? launchCommand.args, {
|
|
338
361
|
cwd: this.options.cwd,
|
|
339
362
|
env,
|
|
340
363
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -363,6 +386,18 @@ export class CodexAppServerClient {
|
|
|
363
386
|
if (this.options.baseUrl) {
|
|
364
387
|
args.push('--config', `openai_base_url=${JSON.stringify(this.options.baseUrl)}`);
|
|
365
388
|
}
|
|
389
|
+
const headerEnvNames = Object.fromEntries(Object.keys(this.options.headers ?? {}).map(name => [name, codexHeaderEnvName(name)]));
|
|
390
|
+
const hasHeaders = Object.keys(headerEnvNames).length > 0;
|
|
391
|
+
const hasQueryParams = Object.keys(this.options.queryParams ?? {}).length > 0;
|
|
392
|
+
if (hasHeaders || hasQueryParams) {
|
|
393
|
+
const provider = tomlProviderKey(this.options.provider || 'openai');
|
|
394
|
+
if (hasHeaders) {
|
|
395
|
+
args.push('--config', `model_providers.${provider}.env_http_headers=${tomlInlineStringTable(headerEnvNames)}`);
|
|
396
|
+
}
|
|
397
|
+
if (hasQueryParams) {
|
|
398
|
+
args.push('--config', `model_providers.${provider}.query_params=${tomlInlineStringTable(this.options.queryParams ?? {})}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
366
401
|
if (this.options.effort) {
|
|
367
402
|
args.push('--config', `model_reasoning_effort=${JSON.stringify(this.options.effort)}`);
|
|
368
403
|
}
|
|
@@ -23,6 +23,7 @@ import { compareVersions } from '../utils/npm-ops.js';
|
|
|
23
23
|
import { resolvePaths, resolveRoot } from '../paths.js';
|
|
24
24
|
import { buildSessionTurnList } from '../core/session/session-turns.js';
|
|
25
25
|
import { execFileSync } from 'child_process';
|
|
26
|
+
import { execCodexCliSync, resolveCodexCliPath } from '../utils/codex-cli.js';
|
|
26
27
|
import { createHash, randomBytes } from 'crypto';
|
|
27
28
|
import fs from 'fs';
|
|
28
29
|
import path from 'path';
|
|
@@ -128,7 +129,7 @@ export function isCodexCliVersionSupported(version) {
|
|
|
128
129
|
}
|
|
129
130
|
export function getCodexCliVersion() {
|
|
130
131
|
try {
|
|
131
|
-
const output =
|
|
132
|
+
const output = execCodexCliSync(['--version'], {
|
|
132
133
|
encoding: 'utf-8',
|
|
133
134
|
timeout: 3000,
|
|
134
135
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -140,6 +141,10 @@ export function getCodexCliVersion() {
|
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
export function getCodexAppServerAvailability() {
|
|
144
|
+
if (!resolveCodexCliPath()) {
|
|
145
|
+
const upgradeHint = '请升级 Codex CLI:npm install -g @openai/codex@latest';
|
|
146
|
+
return { available: false, reason: `未检测到可用 Codex CLI。${upgradeHint}` };
|
|
147
|
+
}
|
|
143
148
|
const version = getCodexCliVersion();
|
|
144
149
|
const upgradeHint = '请升级 Codex CLI:npm install -g @openai/codex@latest';
|
|
145
150
|
if (!version) {
|
|
@@ -153,7 +158,7 @@ export function getCodexAppServerAvailability() {
|
|
|
153
158
|
};
|
|
154
159
|
}
|
|
155
160
|
try {
|
|
156
|
-
|
|
161
|
+
execCodexCliSync(['app-server', '--help'], {
|
|
157
162
|
encoding: 'utf-8',
|
|
158
163
|
timeout: 3000,
|
|
159
164
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -171,7 +176,7 @@ function fetchCodexCatalog() {
|
|
|
171
176
|
if (codexCatalogCache)
|
|
172
177
|
return codexCatalogCache;
|
|
173
178
|
try {
|
|
174
|
-
const output =
|
|
179
|
+
const output = execCodexCliSync(['debug', 'models'], {
|
|
175
180
|
encoding: 'utf-8',
|
|
176
181
|
timeout: 5000,
|
|
177
182
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -250,6 +255,9 @@ export class CodexRunner {
|
|
|
250
255
|
const client = new CodexAppServerClient({
|
|
251
256
|
apiKey: this.resolvedConfig.apiKey,
|
|
252
257
|
baseUrl: this.resolvedConfig.baseUrl,
|
|
258
|
+
provider: this.resolvedConfig.provider,
|
|
259
|
+
headers: this.resolvedConfig.headers,
|
|
260
|
+
queryParams: this.resolvedConfig.queryParams,
|
|
253
261
|
model: this.model,
|
|
254
262
|
effort: this.effort,
|
|
255
263
|
enableRequestUserInput: this.resolvedConfig.enableRequestUserInput,
|
|
@@ -1,35 +1,46 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
import { aidCreate } from './index.js';
|
|
3
|
+
import { DEFAULT_AID_DOMAIN, normalizeAidDomain } from './domain.js';
|
|
3
4
|
import { getAidStore, SLOT } from './store.js';
|
|
4
5
|
import { logger } from '../../utils/logger.js';
|
|
5
6
|
const MAX_ATTEMPTS = 5;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
7
|
+
export { DEFAULT_AID_DOMAIN } from './domain.js';
|
|
8
|
+
function environmentValue(name) {
|
|
9
|
+
if (!Object.prototype.hasOwnProperty.call(process.env, name))
|
|
10
|
+
return undefined;
|
|
11
|
+
return process.env[name]?.trim() ?? '';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the AID domain for automatically generated control identities.
|
|
15
|
+
*
|
|
16
|
+
* Explicit values fail closed. This avoids silently registering an identity
|
|
17
|
+
* under a different domain when deployment configuration is malformed.
|
|
18
|
+
*/
|
|
19
|
+
export function resolveControlAidDomain(configuredAidDomain) {
|
|
20
|
+
const environmentDomain = environmentValue('EVOLCORE_AID_DOMAIN');
|
|
21
|
+
if (environmentDomain !== undefined)
|
|
22
|
+
return normalizeAidDomain(environmentDomain, 'EVOLCORE_AID_DOMAIN');
|
|
23
|
+
const legacyEnvironmentDomain = environmentValue('EVOLCORE_ISSUER');
|
|
24
|
+
if (legacyEnvironmentDomain !== undefined) {
|
|
25
|
+
logger.warn('[control-aid] EVOLCORE_ISSUER is deprecated; use EVOLCORE_AID_DOMAIN instead');
|
|
26
|
+
return normalizeAidDomain(legacyEnvironmentDomain, 'EVOLCORE_ISSUER');
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
if (configuredAidDomain !== undefined) {
|
|
29
|
+
return normalizeAidDomain(configuredAidDomain, 'daemon.json.aun.defaultAidDomain');
|
|
30
|
+
}
|
|
31
|
+
return DEFAULT_AID_DOMAIN;
|
|
32
|
+
}
|
|
33
|
+
/** @deprecated Use resolveControlAidDomain(). */
|
|
34
|
+
export function resolveControlIssuer(configuredAidDomain) {
|
|
35
|
+
return resolveControlAidDomain(configuredAidDomain);
|
|
27
36
|
}
|
|
28
|
-
/** 生成候选控制 AID:ec + 5位随机数字 + .{
|
|
29
|
-
export function candidateAid(
|
|
37
|
+
/** 生成候选控制 AID:ec + 5位随机数字 + .{aidDomain} */
|
|
38
|
+
export function candidateAid(aidDomain) {
|
|
30
39
|
const n = crypto.randomInt(10000, 100000); // 5 位:10000-99999
|
|
31
|
-
const
|
|
32
|
-
|
|
40
|
+
const finalAidDomain = aidDomain === undefined
|
|
41
|
+
? resolveControlAidDomain()
|
|
42
|
+
: normalizeAidDomain(aidDomain, 'aidDomain');
|
|
43
|
+
return `ec${n}.${finalAidDomain}`;
|
|
33
44
|
}
|
|
34
45
|
/**
|
|
35
46
|
* 候选 AID 是否已在 PKI 注册。
|
|
@@ -56,12 +67,14 @@ async function candidateExists(store, candidate) {
|
|
|
56
67
|
* - fail-fast:查重探测失败(网关不可达)立即抛错,不掩盖成"均冲突"
|
|
57
68
|
* - agent.md 不上传:aidCreate 仅注册身份 + 写私钥,不调 agentmdPut
|
|
58
69
|
*/
|
|
59
|
-
export async function generateControlAid() {
|
|
60
|
-
const
|
|
70
|
+
export async function generateControlAid(aidDomain) {
|
|
71
|
+
const finalAidDomain = aidDomain === undefined
|
|
72
|
+
? resolveControlAidDomain()
|
|
73
|
+
: normalizeAidDomain(aidDomain, 'aidDomain');
|
|
61
74
|
const store = await getAidStore({ slotId: SLOT.cli });
|
|
62
75
|
try {
|
|
63
76
|
for (let i = 0; i < MAX_ATTEMPTS; i++) {
|
|
64
|
-
const candidate = candidateAid(
|
|
77
|
+
const candidate = candidateAid(finalAidDomain);
|
|
65
78
|
if (await candidateExists(store, candidate)) {
|
|
66
79
|
logger.info(`[control-aid] ${candidate} 已注册,重试 (${i + 1}/${MAX_ATTEMPTS})`);
|
|
67
80
|
continue;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const DEFAULT_AID_DOMAIN = 'agentid.cn';
|
|
2
|
+
const DOMAIN_RE = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/i;
|
|
3
|
+
const IPV4_RE = /^(?:\d{1,3}\.){3}\d{1,3}$/;
|
|
4
|
+
/** Normalize and validate the suffix domain used to construct an AID. */
|
|
5
|
+
export function normalizeAidDomain(value, source) {
|
|
6
|
+
if (typeof value !== 'string') {
|
|
7
|
+
throw new Error(`[aid-domain] ${source} must be a string`);
|
|
8
|
+
}
|
|
9
|
+
const aidDomain = value.trim().toLowerCase();
|
|
10
|
+
if (!DOMAIN_RE.test(aidDomain)) {
|
|
11
|
+
throw new Error(`[aid-domain] ${source} must be a valid multi-level domain: ${value}`);
|
|
12
|
+
}
|
|
13
|
+
if (IPV4_RE.test(aidDomain)) {
|
|
14
|
+
throw new Error(`[aid-domain] ${source} cannot be an IP address: ${value}`);
|
|
15
|
+
}
|
|
16
|
+
if (aidDomain.endsWith('.localhost')) {
|
|
17
|
+
throw new Error(`[aid-domain] ${source} cannot be a localhost/local domain: ${value}`);
|
|
18
|
+
}
|
|
19
|
+
if (aidDomain.length > 253) {
|
|
20
|
+
throw new Error(`[aid-domain] ${source} is too long: ${aidDomain.length} chars`);
|
|
21
|
+
}
|
|
22
|
+
return aidDomain;
|
|
23
|
+
}
|