chatccc 0.2.269 → 0.2.272
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/README.md +8 -4
- package/config.sample.json +1 -0
- package/deepccc-agent/README.md +19 -1
- package/deepccc-agent/package.json +65 -65
- package/dist/deepccc-agent/src/cli.js +5 -0
- package/dist/deepccc-agent/src/config.js +8 -0
- package/dist/deepccc-agent/src/index.js +20 -5
- package/dist/src/adapters/ccc-adapter.js +4 -1
- package/dist/src/agent-team/application/task-execution-service.js +330 -97
- package/dist/src/agent-team/domain/task-run.js +14 -1
- package/dist/src/agent-team/infrastructure/task-execution-runtime.js +7 -2
- package/dist/src/agent-team/main-agent-bootstrap.js +24 -1
- package/dist/src/agent-team/repositories/json-task-run-repository.js +22 -4
- package/dist/src/agent-team/web/agent-team-page.js +14 -7
- package/dist/src/cards.js +0 -3
- package/dist/src/config.js +12 -0
- package/dist/src/safe-maintenance.js +4 -1
- package/dist/src/session.js +11 -2
- package/dist/src/web-ui.js +31 -4
- package/im-skills/feishu-skill/skill.md +26 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -159,9 +159,11 @@ Agent Team 提供本地任务看板和项目主 Agent 入口。每个规范化
|
|
|
159
159
|
|
|
160
160
|
打开项目后可以选择 CCC、Claude、Cursor 或 Codex 作为主 Agent。首次设置会创建固定命名为 `主Agent-<目录短名>` 的飞书群和空 Agent Session;后续切换 Agent 或重新关联目录会复用原群,运行中的主 Agent 不允许切换。建群成员取自机器人最近一次收到的飞书私聊;如果尚无私聊记录,网页会提示先给机器人发送任意私聊消息并自动检测。项目群名不会随第一句话或 `/forget` 改变。
|
|
161
161
|
|
|
162
|
-
任务卡片可通过“交给主 Agent”启动真实执行:任务会从 Todo 移到 Doing,成功后自动移到 Done
|
|
162
|
+
任务卡片可通过“交给主 Agent”启动真实执行:任务会从 Todo 移到 Doing,成功后自动移到 Done,失败、停止或中断则移到搁置并显示具体原因,支持安全重试。同一项目同一时间只运行一个看板任务;每次尝试都有独立的 Run ID、Trace ID、失败类型、耗时和完整执行时间线,可以在任务详情中切换历史尝试或复制记录。
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
运行中的时间线和最后进度会定期持久化;长时间没有进度会在看板中标记为疑似停滞,停止请求超过截止时间会强制收敛到终态。服务异常退出后会保留最后已写入的执行过程并把未完成任务标记为中断;启动时还会自动对账任务终态与卡片列,修复“Agent 已完成但卡片移动失败”等部分成功。损坏的单条运行 JSON 会被隔离为 `.corrupt-*` 文件,不会阻断同项目其他历史记录。
|
|
165
|
+
|
|
166
|
+
看板数据默认保存在 `~/.chatccc/agent-team/`,其中 `workspaces.json` 保存最近工作目录索引,`boards/` 保存按稳定 ID 分隔的看板 JSON,`main-agent-bindings/` 单独保存本机飞书群与 Session 绑定,`task-runs/` 保存每次任务执行及其诊断时间线。目录移动或重命名后,可从最近目录列表重新关联。数据访问通过仓储接口隔离,后续接入飞书多维表格时可增加双向同步适配器,无需把本机群聊和 Session 状态混入任务同步模型。选择目录、创建群聊和启动 Agent 等操作都由本机 Node 后端执行;当前实现不依赖 Electron。
|
|
165
167
|
|
|
166
168
|
#### 从源码运行
|
|
167
169
|
|
|
@@ -224,7 +226,7 @@ Claude Code、Cursor 和 Codex 需要对应的本地工具;CCC Agent 内置于
|
|
|
224
226
|
|
|
225
227
|
CCC Agent 是 ChatCCC 内置的编程 Agent,不需要额外安装 CLI,开箱即用。在首次配置向导或 Web 管理页中启用后,填写 API Key、Base URL 和模型即可使用;它可以设为 `/new` 的默认 Agent,也可以通过 `/new ccc` 显式创建会话。
|
|
226
228
|
|
|
227
|
-
ChatCCC 会把 `ccc.DEEPSEEK_API_KEY`、`ccc.DEEPSEEK_BASE_URL
|
|
229
|
+
ChatCCC 会把 `ccc.DEEPSEEK_API_KEY`、`ccc.DEEPSEEK_BASE_URL` 和模型显式传给内置 Agent;API Key 为空时 CCC Agent 会自动保持禁用。`ccc.effort` 与 `ccc.maxOutputTokens` 是可选 override:非空时覆盖 DeepCCC,留空时跟随 `~/.deepccc/config.json` / `DEEPCCC_*` 环境变量,DeepCCC 也未配置时使用模型服务端默认值。DeepCCC 的传输层选项 `provider`(默认 `openai`)和 `streaming`(默认 `true`)同样可通过内核配置,无需额外安装独立 CLI。
|
|
228
230
|
|
|
229
231
|
**协议 override:** 也可以在 ChatCCC 的配置(`config.json` 的 `ccc.provider`,或 Web 管理页的「CCC Agent → API 协议」)显式指定 `openai` / `anthropic` 覆盖内核配置;留空(默认)时跟随 `~/.deepccc/config.json` / `DEEPCCC_PROVIDER`。`streaming` 不做 override,始终由 DeepCCC 内核配置控制。
|
|
230
232
|
|
|
@@ -240,7 +242,7 @@ ChatCCC 会把 `ccc.DEEPSEEK_API_KEY`、`ccc.DEEPSEEK_BASE_URL`、模型和 effo
|
|
|
240
242
|
| 通义千问 / 智谱 GLM / 豆包 / MiniMax | 各家 `…/v1` 端点 | 国内 OpenAI 兼容服务 |
|
|
241
243
|
| Ollama / vLLM / LM Studio | `http://localhost:11434/v1` | 本地或自建推理服务 |
|
|
242
244
|
|
|
243
|
-
更换服务只需把 `ccc.DEEPSEEK_BASE_URL` 改为对应端点、`ccc.DEEPSEEK_API_KEY` 改为对应 Key、`ccc.model` 改为目标模型名即可。`
|
|
245
|
+
更换服务只需把 `ccc.DEEPSEEK_BASE_URL` 改为对应端点、`ccc.DEEPSEEK_API_KEY` 改为对应 Key、`ccc.model` 改为目标模型名即可。`effort` 留空时不会由 ChatCCC override DeepCCC;若两边都留空,则不发送 `reasoning_effort`。只有确认目标模型支持时才应显式填写,否则服务端可能返回参数错误。余额查询仅对官方 DeepSeek 域名(`api.deepseek.com`)生效,指向其他端点时自动跳过,不影响对话。
|
|
244
246
|
|
|
245
247
|
`ccc.alternativeModel` 是单个备选模型,只会加入 `/model` 的人工切换列表,不会在请求失败时自动重试或切换,避免重复执行带副作用的工具调用。
|
|
246
248
|
|
|
@@ -384,6 +386,8 @@ Codex 的默认模型和推理强度可继续由 `~/.codex/config.toml` 管理
|
|
|
384
386
|
| `ccc.DEEPSEEK_API_KEY` / `ccc.DEEPSEEK_BASE_URL` | CCC Agent 的 API Key 和服务地址;**不限于 DeepSeek**——可填任意 OpenAI 兼容端点(OpenAI、Kimi、通义、智谱、Ollama 本地等) |
|
|
385
387
|
| `ccc.model` | CCC Agent 默认模型 |
|
|
386
388
|
| `ccc.subModel` | CCC Agent 子模型(选填):用于内部轻量环节(压缩摘要生成、task 子代理任务);留空跟随主模型 |
|
|
389
|
+
| `ccc.effort` | CCC Agent 推理强度 override;留空跟随 DeepCCC 内核配置,内核也留空时使用模型服务端默认值 |
|
|
390
|
+
| `ccc.maxOutputTokens` | CCC Agent 主对话最大输出 token override;正整数,`null`/留空时跟随 DeepCCC 内核配置,内核也未配置时使用模型服务端默认值 |
|
|
387
391
|
| `ccc.compactionTimeoutMs` | CCC Agent 上下文压缩单轮超时(毫秒),默认 300000(5 分钟);压缩超时会让整轮对话失败,建议保持默认或调大 |
|
|
388
392
|
| `ccc.contextWindow` | CCC Agent 模型上下文窗口(token),默认 1048576(1M,DeepSeek V4 Pro/Flash 原生规格);压缩阈值自动 = 窗口 × 80%;超过模型/服务端实际上限会被 API 拒绝,可在 Web UI 下拉选择或自定义(单位 k) |
|
|
389
393
|
| `dsh.apiKey` / `dsh.baseUrl` | DeepSeek Harness 的 API Key 和官方 DeepSeek 服务地址 |
|
package/config.sample.json
CHANGED
package/deepccc-agent/README.md
CHANGED
|
@@ -47,6 +47,8 @@ deepccc 的本地缓存优化实测命中率 **96.7%**,有效降低重复请
|
|
|
47
47
|
export DEEPCCC_API_KEY="sk-..."
|
|
48
48
|
export DEEPCCC_BASE_URL="https://api.deepseek.com/v1"
|
|
49
49
|
export DEEPCCC_MODEL="deepseek-v4-pro"
|
|
50
|
+
export DEEPCCC_EFFORT="high"
|
|
51
|
+
export DEEPCCC_MAX_OUTPUT_TOKENS="32768"
|
|
50
52
|
export DEEPCCC_STREAMING="true"
|
|
51
53
|
```
|
|
52
54
|
|
|
@@ -57,6 +59,8 @@ $env:DEEPCCC_API_KEY="sk-..."
|
|
|
57
59
|
$env:DEEPCCC_PROVIDER="openai"
|
|
58
60
|
$env:DEEPCCC_BASE_URL="https://api.deepseek.com/v1"
|
|
59
61
|
$env:DEEPCCC_MODEL="deepseek-v4-pro"
|
|
62
|
+
$env:DEEPCCC_EFFORT="high"
|
|
63
|
+
$env:DEEPCCC_MAX_OUTPUT_TOKENS="32768"
|
|
60
64
|
$env:DEEPCCC_STREAMING="true"
|
|
61
65
|
```
|
|
62
66
|
|
|
@@ -77,6 +81,7 @@ $env:DEEPCCC_STREAMING="true"
|
|
|
77
81
|
"model": "deepseek-v4-pro",
|
|
78
82
|
"subModel": "",
|
|
79
83
|
"effort": "",
|
|
84
|
+
"maxOutputTokens": null,
|
|
80
85
|
"streaming": true,
|
|
81
86
|
"contextWindow": 1048576,
|
|
82
87
|
"git": {
|
|
@@ -104,11 +109,16 @@ $env:DEEPCCC_STREAMING="true"
|
|
|
104
109
|
`DEEPCCC_PROVIDER` 或命令行 `--provider` 覆盖:
|
|
105
110
|
|
|
106
111
|
- `openai` 使用 OpenAI-compatible Chat Completions 协议,兼容 DeepSeek、OpenAI、LiteLLM、vLLM 等服务。
|
|
107
|
-
- `anthropic` 使用 Anthropic Messages 协议。配置中的 `baseURL` **完全按填写值使用,不自动补 `/v1`**,请填写到完整版本化地址,例如 DeepSeek 官方 Anthropic 端点为 `https://api.deepseek.com/anthropic/v1`(官方 Anthropic SDK 使用的 `https://api.deepseek.com/anthropic` 基址会拼接为 `.../anthropic/v1/messages`)。`effort`
|
|
112
|
+
- `anthropic` 使用 Anthropic Messages 协议。配置中的 `baseURL` **完全按填写值使用,不自动补 `/v1`**,请填写到完整版本化地址,例如 DeepSeek 官方 Anthropic 端点为 `https://api.deepseek.com/anthropic/v1`(官方 Anthropic SDK 使用的 `https://api.deepseek.com/anthropic` 基址会拼接为 `.../anthropic/v1/messages`)。`effort` 在 OpenAI-compatible 模式映射为 `reasoning_effort`,在 Anthropic 模式映射为 `output_config.effort`;目标服务不支持时应留空。
|
|
108
113
|
|
|
109
114
|
`streaming` 控制主对话是否使用流式请求,默认 `true`;也可以通过
|
|
110
115
|
`DEEPCCC_STREAMING=true|false` 覆盖。关闭后,终端会在整条模型响应完成后一次性显示结果。
|
|
111
116
|
|
|
117
|
+
`maxOutputTokens` 限制主对话单次最大输出 token,默认不配置(`null`/缺失),此时不向
|
|
118
|
+
Provider 发送 `max_tokens`,使用模型服务端默认值。可通过 `DEEPCCC_MAX_OUTPUT_TOKENS`
|
|
119
|
+
或命令行 `--max-output-tokens` 覆盖;只接受正整数。该限制会同时覆盖模型思考内容、
|
|
120
|
+
工具参数和最终回答,设置过小可能导致工具调用或长回复被截断。
|
|
121
|
+
|
|
112
122
|
`contextWindow` 是模型上下文窗口(token),默认 `1048576`(1M,DeepSeek V4 Pro/Flash
|
|
113
123
|
原生规格);上下文压缩阈值自动 = `contextWindow × 0.8`(超出即把较早消息压缩为摘要)。
|
|
114
124
|
可通过 `DEEPCCC_CONTEXT_WINDOW` 环境变量覆盖。⚠️ 超过模型/服务端实际上限时请求会被
|
|
@@ -180,6 +190,14 @@ deepccc --effort high
|
|
|
180
190
|
|
|
181
191
|
可选值:`none` / `minimal` / `low` / `medium` / `high` / `xhigh` / `max`(留空则不传 `reasoning_effort` 请求字段)。
|
|
182
192
|
|
|
193
|
+
限制主对话最大输出 token:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
deepccc --max-output-tokens 8192
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
不设置时使用 Provider 默认值。
|
|
200
|
+
|
|
183
201
|
## 权限机制
|
|
184
202
|
|
|
185
203
|
`deepccc` 内置轻量权限机制,对标主流 agent 的审批体验:**只拦截有副作用的操作**(`run_command` 与文件写操作),只读工具(`read_file` / `list_dir` / `search_code`)永不拦截,常规文件编辑默认放行不打断工作流。
|
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "deepccc",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "A lightweight coding agent with OpenAI-compatible and Anthropic Messages API support.",
|
|
5
|
-
"license": "Apache-2.0",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"agent",
|
|
8
|
-
"deepseek",
|
|
9
|
-
"coding-agent",
|
|
10
|
-
"openai-compatible",
|
|
11
|
-
"anthropic",
|
|
12
|
-
"cli"
|
|
13
|
-
],
|
|
14
|
-
"repository": {
|
|
15
|
-
"type": "git",
|
|
16
|
-
"url": "git+https://github.com/wzj998/deepccc-agent.git"
|
|
17
|
-
},
|
|
18
|
-
"bugs": {
|
|
19
|
-
"url": "https://github.com/wzj998/deepccc-agent/issues"
|
|
20
|
-
},
|
|
21
|
-
"homepage": "https://github.com/wzj998/deepccc-agent#readme",
|
|
22
|
-
"type": "module",
|
|
23
|
-
"main": "./dist/index.js",
|
|
24
|
-
"types": "./dist/index.d.ts",
|
|
25
|
-
"exports": {
|
|
26
|
-
".": {
|
|
27
|
-
"types": "./dist/index.d.ts",
|
|
28
|
-
"import": "./dist/index.js"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"bin": {
|
|
32
|
-
"deepccc": "bin/deepccc.mjs"
|
|
33
|
-
},
|
|
34
|
-
"files": [
|
|
35
|
-
"dist/",
|
|
36
|
-
"bin/",
|
|
37
|
-
"docs/",
|
|
38
|
-
"os-prompts/",
|
|
39
|
-
"package.json",
|
|
40
|
-
"README.md",
|
|
41
|
-
"LICENSE"
|
|
42
|
-
],
|
|
43
|
-
"scripts": {
|
|
44
|
-
"build": "node node_modules/typescript/bin/tsc -p tsconfig.build.json",
|
|
45
|
-
"prepack": "node node_modules/typescript/bin/tsc -p tsconfig.build.json",
|
|
46
|
-
"test": "vitest run",
|
|
47
|
-
"test:watch": "vitest",
|
|
48
|
-
"typecheck": "node node_modules/typescript/bin/tsc --noEmit"
|
|
49
|
-
},
|
|
50
|
-
"dependencies": {
|
|
51
|
-
"@ai-sdk/anthropic": "^3.0.105",
|
|
52
|
-
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
53
|
-
"@vscode/ripgrep": "^1.18.0",
|
|
54
|
-
"ai": "^6.0.184"
|
|
55
|
-
},
|
|
56
|
-
"devDependencies": {
|
|
57
|
-
"@types/node": "^20.0.0",
|
|
58
|
-
"tsx": "^4.0.0",
|
|
59
|
-
"typescript": "^5.0.0",
|
|
60
|
-
"vitest": "^3.2.4"
|
|
61
|
-
},
|
|
62
|
-
"engines": {
|
|
63
|
-
"node": ">=20"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "deepccc",
|
|
3
|
+
"version": "0.1.28",
|
|
4
|
+
"description": "A lightweight coding agent with OpenAI-compatible and Anthropic Messages API support.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"agent",
|
|
8
|
+
"deepseek",
|
|
9
|
+
"coding-agent",
|
|
10
|
+
"openai-compatible",
|
|
11
|
+
"anthropic",
|
|
12
|
+
"cli"
|
|
13
|
+
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/wzj998/deepccc-agent.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/wzj998/deepccc-agent/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/wzj998/deepccc-agent#readme",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "./dist/index.js",
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"bin": {
|
|
32
|
+
"deepccc": "bin/deepccc.mjs"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist/",
|
|
36
|
+
"bin/",
|
|
37
|
+
"docs/",
|
|
38
|
+
"os-prompts/",
|
|
39
|
+
"package.json",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "node node_modules/typescript/bin/tsc -p tsconfig.build.json",
|
|
45
|
+
"prepack": "node node_modules/typescript/bin/tsc -p tsconfig.build.json",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:watch": "vitest",
|
|
48
|
+
"typecheck": "node node_modules/typescript/bin/tsc --noEmit"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@ai-sdk/anthropic": "^3.0.105",
|
|
52
|
+
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
53
|
+
"@vscode/ripgrep": "^1.18.0",
|
|
54
|
+
"ai": "^6.0.184"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^20.0.0",
|
|
58
|
+
"tsx": "^4.0.0",
|
|
59
|
+
"typescript": "^5.0.0",
|
|
60
|
+
"vitest": "^3.2.4"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=20"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -65,6 +65,10 @@ function parseArgs(argv = process.argv.slice(2)) {
|
|
|
65
65
|
config.effort = next;
|
|
66
66
|
i++;
|
|
67
67
|
}
|
|
68
|
+
else if (arg === "--max-output-tokens" && next !== undefined) {
|
|
69
|
+
config.maxOutputTokens = parsePositiveIntegerOption("--max-output-tokens", next);
|
|
70
|
+
i++;
|
|
71
|
+
}
|
|
68
72
|
else if (arg === "--base-url" && next !== undefined) {
|
|
69
73
|
config.baseURL = next;
|
|
70
74
|
i++;
|
|
@@ -131,6 +135,7 @@ function printHelp(appConfig) {
|
|
|
131
135
|
` --model <name> Model name (current default ${appConfig.model})`,
|
|
132
136
|
` --sub-model <name> Sub-model for lightweight steps (compaction/task; empty = follow main model)`,
|
|
133
137
|
` --effort <level> Reasoning effort: none/minimal/low/medium/high/xhigh/max (overrides config.effort)`,
|
|
138
|
+
` --max-output-tokens <n> Maximum output tokens (unset = Provider default)`,
|
|
134
139
|
` --base-url <url> Provider API base URL (current default ${appConfig.baseURL})`,
|
|
135
140
|
" --api-key <key> API key",
|
|
136
141
|
" --cwd <path> Working directory",
|
|
@@ -56,6 +56,12 @@ function numberEnv(name) {
|
|
|
56
56
|
const value = Number(env(name));
|
|
57
57
|
return Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
58
58
|
}
|
|
59
|
+
function optionalPositiveInteger(value) {
|
|
60
|
+
if (value === undefined || value === null || value === "")
|
|
61
|
+
return undefined;
|
|
62
|
+
const parsed = Number(value);
|
|
63
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
64
|
+
}
|
|
59
65
|
export function normalizeDeepCccProvider(value) {
|
|
60
66
|
if (value === undefined || value === null || String(value).trim() === "")
|
|
61
67
|
return "openai";
|
|
@@ -78,6 +84,8 @@ function loadConfig() {
|
|
|
78
84
|
model: env("DEEPCCC_MODEL") ?? env("DEEPSEEK_MODEL") ?? file.model ?? DEFAULT_CONFIG.model,
|
|
79
85
|
subModel: env("DEEPCCC_SUB_MODEL") ?? file.subModel ?? DEFAULT_CONFIG.subModel,
|
|
80
86
|
effort: env("DEEPCCC_EFFORT") ?? env("DEEPSEEK_EFFORT") ?? file.effort ?? DEFAULT_CONFIG.effort,
|
|
87
|
+
maxOutputTokens: optionalPositiveInteger(env("DEEPCCC_MAX_OUTPUT_TOKENS"))
|
|
88
|
+
?? optionalPositiveInteger(file.maxOutputTokens),
|
|
81
89
|
streaming: boolEnv("DEEPCCC_STREAMING") ?? file.streaming ?? DEFAULT_CONFIG.streaming,
|
|
82
90
|
contextWindow: numberEnv("DEEPCCC_CONTEXT_WINDOW") ?? file.contextWindow ?? DEFAULT_CONFIG.contextWindow,
|
|
83
91
|
git: {
|
|
@@ -77,6 +77,7 @@ const COMPACTION_RECOVERY_HINT_DISABLED = [
|
|
|
77
77
|
].join("\n");
|
|
78
78
|
export const DEFAULT_COMPACTION_TIMEOUT_MS = 5 * 60 * 1000;
|
|
79
79
|
const MAX_COMPACTION_OUTPUT_TOKENS = 16_384;
|
|
80
|
+
const OPENAI_COMPATIBLE_PROVIDER_NAME = "deepccc";
|
|
80
81
|
/** task 子代理工具:子代理单轮对话的最大工具步数(防失控循环,结果收敛后即结束) */
|
|
81
82
|
const TASK_MAX_STEPS = 20;
|
|
82
83
|
/** 子代理最终输出截断:保留前 MAX_TASK_OUTPUT_CHARS 字符,尾部注明截断信息 */
|
|
@@ -219,6 +220,14 @@ function normalizeMaxSteps(value) {
|
|
|
219
220
|
}
|
|
220
221
|
return value;
|
|
221
222
|
}
|
|
223
|
+
function normalizeMaxOutputTokens(value) {
|
|
224
|
+
if (value === undefined)
|
|
225
|
+
return undefined;
|
|
226
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
|
|
227
|
+
throw new Error("maxOutputTokens must be a positive integer when provided");
|
|
228
|
+
}
|
|
229
|
+
return value;
|
|
230
|
+
}
|
|
222
231
|
function normalizeAnthropicBaseURL(baseURL) {
|
|
223
232
|
// 完全按用户填写的地址使用,不自动补 /v1(AI SDK 仅对官方 api.anthropic.com
|
|
224
233
|
// 特判补一次 /v1,其他地址原样拼接 /messages)。
|
|
@@ -239,6 +248,7 @@ export class ChatSession {
|
|
|
239
248
|
compactionTimeoutMs;
|
|
240
249
|
maxSteps;
|
|
241
250
|
effort;
|
|
251
|
+
maxOutputTokens;
|
|
242
252
|
permissionMode;
|
|
243
253
|
permissionResolver;
|
|
244
254
|
permissionGate;
|
|
@@ -267,6 +277,7 @@ export class ChatSession {
|
|
|
267
277
|
baseURL: this.baseURL,
|
|
268
278
|
model: this.subModelId || this.modelId,
|
|
269
279
|
effort: this.effort,
|
|
280
|
+
maxOutputTokens: this.maxOutputTokens,
|
|
270
281
|
}, {
|
|
271
282
|
cwd: taskCwd,
|
|
272
283
|
persist: false,
|
|
@@ -304,6 +315,7 @@ export class ChatSession {
|
|
|
304
315
|
this.subModelId = (overrides.subModel ?? appConfig.subModel ?? "").trim();
|
|
305
316
|
this.provider = normalizeDeepCccProvider(overrides.provider ?? appConfig.provider);
|
|
306
317
|
this.effort = (overrides.effort ?? appConfig.effort ?? "").trim();
|
|
318
|
+
this.maxOutputTokens = normalizeMaxOutputTokens(overrides.maxOutputTokens ?? appConfig.maxOutputTokens);
|
|
307
319
|
this.apiKey = apiKey;
|
|
308
320
|
this.baseURL = baseURL;
|
|
309
321
|
const provider = this.provider === "anthropic"
|
|
@@ -312,7 +324,7 @@ export class ChatSession {
|
|
|
312
324
|
apiKey,
|
|
313
325
|
})
|
|
314
326
|
: createOpenAICompatible({
|
|
315
|
-
name:
|
|
327
|
+
name: OPENAI_COMPATIBLE_PROVIDER_NAME,
|
|
316
328
|
baseURL,
|
|
317
329
|
apiKey,
|
|
318
330
|
includeUsage: true,
|
|
@@ -415,14 +427,14 @@ export class ChatSession {
|
|
|
415
427
|
? addAnthropicToolJsonCompatibilityNote(hintedMessages)
|
|
416
428
|
: hintedMessages;
|
|
417
429
|
// effort 按协议映射:
|
|
418
|
-
// - OpenAI 兼容:providerOptions.
|
|
419
|
-
//
|
|
430
|
+
// - OpenAI 兼容:providerOptions 的 key 必须与 createOpenAICompatible.name 一致;
|
|
431
|
+
// reasoningEffort 由 SDK 映射为请求体 reasoning_effort 字段;
|
|
420
432
|
// - Anthropic:providerOptions.anthropic.effort 由 @ai-sdk/anthropic 组装为请求体
|
|
421
433
|
// output_config.effort(官方 Effort API,见 platform.claude.com/docs/en/build-with-claude/effort)
|
|
422
434
|
let effortProviderOptions;
|
|
423
435
|
if (this.effort) {
|
|
424
436
|
effortProviderOptions = this.provider === "openai"
|
|
425
|
-
? {
|
|
437
|
+
? { [OPENAI_COMPATIBLE_PROVIDER_NAME]: { reasoningEffort: this.effort } }
|
|
426
438
|
: { anthropic: { effort: this.effort } };
|
|
427
439
|
}
|
|
428
440
|
const baseGenerationOptions = {
|
|
@@ -438,6 +450,9 @@ export class ChatSession {
|
|
|
438
450
|
}),
|
|
439
451
|
stopWhen: maxSteps !== undefined ? stepCountIs(maxSteps) : isLoopFinished(),
|
|
440
452
|
abortSignal: signal,
|
|
453
|
+
...(this.maxOutputTokens !== undefined
|
|
454
|
+
? { maxOutputTokens: this.maxOutputTokens }
|
|
455
|
+
: {}),
|
|
441
456
|
...(effortProviderOptions ? { providerOptions: effortProviderOptions } : {}),
|
|
442
457
|
};
|
|
443
458
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
@@ -630,7 +645,7 @@ export class ChatSession {
|
|
|
630
645
|
// output_config.effort=low),避免继承主对话的高 effort 拖慢"压缩上下文中"阶段。
|
|
631
646
|
maxOutputTokens: MAX_COMPACTION_OUTPUT_TOKENS,
|
|
632
647
|
providerOptions: this.provider === "openai"
|
|
633
|
-
? {
|
|
648
|
+
? { [OPENAI_COMPATIBLE_PROVIDER_NAME]: { reasoningEffort: "none" } }
|
|
634
649
|
: { anthropic: { effort: "low" } },
|
|
635
650
|
});
|
|
636
651
|
if (!result.text.trim()) {
|
|
@@ -29,7 +29,10 @@ export function createCccAdapter(options = {}) {
|
|
|
29
29
|
...(options.baseURL !== undefined ? { baseURL: options.baseURL } : {}),
|
|
30
30
|
...(options.model !== undefined ? { model: options.model } : {}),
|
|
31
31
|
...(options.subModel !== undefined ? { subModel: options.subModel } : {}),
|
|
32
|
-
...(options.effort
|
|
32
|
+
...(options.effort?.trim() ? { effort: options.effort.trim() } : {}),
|
|
33
|
+
...(options.maxOutputTokens !== undefined
|
|
34
|
+
? { maxOutputTokens: options.maxOutputTokens }
|
|
35
|
+
: {}),
|
|
33
36
|
};
|
|
34
37
|
return {
|
|
35
38
|
displayName: "CCC Agent",
|