@gird/ccli 2.17.0 → 2.19.0
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 +53 -2
- package/dist/agent/ai.js +3 -50
- package/dist/agent/ai.js.map +1 -1
- package/dist/agent/os.js +69 -0
- package/dist/agent/os.js.map +1 -0
- package/dist/agent/providers/anthropic.js +56 -5
- package/dist/agent/providers/anthropic.js.map +1 -1
- package/dist/agent/providers/gemini.js +10 -93
- package/dist/agent/providers/gemini.js.map +1 -1
- package/dist/agent/providers/openai.js +9 -1
- package/dist/agent/providers/openai.js.map +1 -1
- package/dist/agent/tool-projection.js +57 -0
- package/dist/agent/tool-projection.js.map +1 -0
- package/dist/cli/args/index.js +40 -0
- package/dist/cli/args/index.js.map +1 -1
- package/dist/cli/clipboard-image.js +51 -0
- package/dist/cli/clipboard-image.js.map +1 -0
- package/dist/cli/image-compress.js +62 -0
- package/dist/cli/image-compress.js.map +1 -0
- package/dist/cli/image-reference.js +190 -0
- package/dist/cli/image-reference.js.map +1 -0
- package/dist/cli/repl/index.js +52 -3
- package/dist/cli/repl/index.js.map +1 -1
- package/dist/cli/run/index.js +75 -12
- package/dist/cli/run/index.js.map +1 -1
- package/dist/cli/run/task.js +37 -0
- package/dist/cli/run/task.js.map +1 -1
- package/dist/cli/session/checkpoint.js +5 -4
- package/dist/cli/session/checkpoint.js.map +1 -1
- package/dist/cli/slash/config/model.js +30 -9
- package/dist/cli/slash/config/model.js.map +1 -1
- package/dist/cli/slash/index.js +14 -0
- package/dist/cli/slash/index.js.map +1 -1
- package/dist/cli/slash/session/replay.js +118 -0
- package/dist/cli/slash/session/replay.js.map +1 -0
- package/dist/cli/slash/system/agent.js +1 -0
- package/dist/cli/slash/system/agent.js.map +1 -1
- package/dist/cli/slash/system/goal.js +1 -0
- package/dist/cli/slash/system/goal.js.map +1 -1
- package/dist/cli/slash/system/help.js +1 -0
- package/dist/cli/slash/system/help.js.map +1 -1
- package/dist/cli/slash/system/plan.js +3 -0
- package/dist/cli/slash/system/plan.js.map +1 -1
- package/dist/config/config.js +32 -1
- package/dist/config/config.js.map +1 -1
- package/dist/config/plugins.js +378 -0
- package/dist/config/plugins.js.map +1 -0
- package/dist/config/skills.js +39 -2
- package/dist/config/skills.js.map +1 -1
- package/dist/harness/index.js +29 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/records.js +98 -0
- package/dist/harness/records.js.map +1 -0
- package/dist/index.js +77 -2
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +338 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/sessions.js +181 -0
- package/dist/server/sessions.js.map +1 -0
- package/dist/server/webui.html +1341 -0
- package/dist/server/webui.js +12 -0
- package/dist/server/webui.js.map +1 -0
- package/dist/tools/bash-background.js +5 -6
- package/dist/tools/bash-background.js.map +1 -1
- package/dist/tools/bash.js +6 -7
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit-file.js +10 -4
- package/dist/tools/edit-file.js.map +1 -1
- package/dist/tools/glob.js +40 -6
- package/dist/tools/glob.js.map +1 -1
- package/dist/tools/grep.js +48 -8
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/list-dir.js +13 -2
- package/dist/tools/list-dir.js.map +1 -1
- package/dist/tools/read-file.js +4 -2
- package/dist/tools/read-file.js.map +1 -1
- package/dist/tools/shared.js.map +1 -1
- package/dist/tools/write-file.js +11 -4
- package/dist/tools/write-file.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ ccli "用一句话介绍 CCLI" # 非交互式单次调用
|
|
|
24
24
|
cat file.ts | ccli "给这段代码加注释" # 从 stdin 读取内容作为上下文
|
|
25
25
|
ccli --yes "在当前目录创建 test.txt" # 自动确认破坏性工具调用
|
|
26
26
|
ccli --role coder "review 这段代码" # 使用 coding 角色单次调用
|
|
27
|
+
ccli serve # 启动本地 HTTP server + Web UI(默认 127.0.0.1:4000)
|
|
28
|
+
ccli plugin # 列出已安装的插件包
|
|
27
29
|
```
|
|
28
30
|
|
|
29
31
|
> ⚠️ `--yes` 会自动批准本次调用内**所有**需确认的工具调用(写文件、编辑文件、bash、MCP 工具),包括 `rm`、`git push` 这类高风险操作。请只在任务范围明确、且目录可丢弃或改动已提交时使用;拿不准就不加,逐项确认。
|
|
@@ -38,6 +40,51 @@ ccli --role coder "review 这段代码" # 使用 coding 角色单次调用
|
|
|
38
40
|
|
|
39
41
|
**技能(自定义提示词模板)**:在 `.ccli/skills/`(项目)或 `~/.ccli/skills/`(用户)放置 `*.md` 文件即可定义一个「技能」——一段可复用的提示词,支持 `$ARGUMENTS` 参数占位。用 `/skills` 列出、`/skill <名称> [参数]` 调用(会展开成一条消息交给 AI)。md 可带 `name` / `description` 的 YAML frontmatter;同名时项目技能覆盖用户技能。技能也可以是**目录技能包** `<名>/SKILL.md` + 附属文件(脚本/模板/资料,调用时告知模型路径供 `read_file`),嵌套 `SKILL.md` 成为**子技能**。除了手动 `/skill`,**模型也会在意图匹配时自动调用技能**(frontmatter 加 `disableModelInvocation: true` 可只保留手动调用)。
|
|
40
42
|
|
|
43
|
+
除了手动 `/skill`,**模型也会在意图匹配时自动调用技能**(frontmatter 加 `disableModelInvocation: true` 可只保留手动调用)。
|
|
44
|
+
|
|
45
|
+
## 插件包
|
|
46
|
+
|
|
47
|
+
比 skill 更大的扩展单元是**插件包**:一个目录 + `plugin.json`,把技能、MCP server、hooks 打包成一个可分发、可启停的整体。适合团队把「内部代码规范 + 文档 MCP + 审计 hook」一次分发。
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"name": "company-dev",
|
|
52
|
+
"version": "0.1.0",
|
|
53
|
+
"skills": ["skills/review.md"],
|
|
54
|
+
"mcpServers": {
|
|
55
|
+
"docs": { "command": "node", "args": ["server.js"] }
|
|
56
|
+
},
|
|
57
|
+
"hooks": [
|
|
58
|
+
{ "event": "PreToolUse", "matcher": "bash", "command": "echo 'audit'" }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
ccli plugin list # 查看已安装插件
|
|
65
|
+
ccli plugin install ./plugins/company-dev # 安装到 ~/.ccli/plugins/
|
|
66
|
+
ccli plugin install ./p --project # 安装到项目级 .ccli/plugins/
|
|
67
|
+
ccli plugin enable company-dev # 重新启用
|
|
68
|
+
ccli plugin disable company-dev # 临时停用
|
|
69
|
+
ccli plugin uninstall company-dev # 卸载
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
安装后,插件里的技能以 `plugin` 来源混入技能列表,MCP server 与 hooks 自动折叠进当前会话配置,无需手动改 `config.json`。
|
|
73
|
+
|
|
74
|
+
## 本地 Server 与 Web UI
|
|
75
|
+
|
|
76
|
+
CCLI 可以作为一个本地服务运行,把交互式 Agent 能力通过 HTTP + SSE 暴露给浏览器或其他客户端:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
ccli serve # 默认 127.0.0.1:4000
|
|
80
|
+
ccli serve --port 8080 --token my-token
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- `POST /sessions` 创建会话,`GET /sessions/:id/stream` 通过 SSE 实时推送 `text_delta`、`tool_call`、`tool_result` 等事件。
|
|
84
|
+
- 破坏性工具(写文件、bash 等)会通过 `POST /sessions/:id/approvals` 等待客户端确认,安全阻塞。
|
|
85
|
+
- 内置轻量 Web UI,打开 `http://127.0.0.1:4000` 即可在浏览器里多轮对话、查看 Markdown 渲染与代码高亮、切换日/夜间主题、进行工具审批。
|
|
86
|
+
- 默认自动生成随机 16 位 token,所有 API 需要 `Authorization: Bearer <token>`。
|
|
87
|
+
|
|
41
88
|
进入对话后:
|
|
42
89
|
|
|
43
90
|
- 直接输入即与 AI 对话,模型会记住上文(多轮对话)。
|
|
@@ -48,13 +95,15 @@ ccli --role coder "review 这段代码" # 使用 coding 角色单次调用
|
|
|
48
95
|
- `write_file` 的内容会随模型生成**逐行实时流式**显示(`⚙ write_file …(生成中…)` 后一行行长出来,像看着模型写代码),不再等参数到齐才一次性铺出;`edit_file` 等工具仍走「摘要 + 折叠」。流式超过 40 行也会**自动停打**并显示「…(后续内容已折叠,按 ctrl+o 展开)」,在空闲提示符下按 `ctrl+o` 同样进入全屏可滚动查看器查看被隐藏的剩余行(主 / 子代理共用同一套,阈值与第 57 步折叠一致)。
|
|
49
96
|
- 多步骤任务时模型可用 `todo` 工具把任务拆成**待办清单**(`[x]` 完成 / `[>]` 进行中 / `[ ]` 待办,按状态上色),一眼看到总共几步、走到哪;无副作用、不需确认。待办面板**常驻在终端底部**(滚动区域法固定,不进全屏、保留 scrollback),todo 一更新立即重绘;非 TTY 时回退为回合末打印;子代理的待办与主会话隔离,各自展示;全部完成时回合结束自动清空,模型多轮不更新会收到系统提醒(引导重写或清空过时清单);不传 items 可只读查询当前清单,/compact 压缩后待办快照保留在摘要里。
|
|
50
97
|
- 模型可调用 `task` 工具把**独立子任务委派给子代理**:子代理用独立上下文 + 全套工具(读/写/编辑/搜索/bash)自行完成,完成后只把结论返回主代理,避免中间过程污染主对话;子代理共享主会话的确认/「始终允许」/token 统计,且**不可再调用 task 继续委派**(防递归);子代理的 `write_file` 同样**逐行实时流式**展示,与主代理观感一致;可用 `subagent_type` 选 `explore`(只读探索,仅 `read_file`/`list_dir`/`grep`/`bash_output`,执行层硬边界保证不能改文件)或 `code`(编码,除 `task` 外全套工具),省略则为通用子代理;子代理运行时的工具调用 / 结果 / 流式写入 / 结论都会**缩进成 ` │ ` 嵌套块**(开始 / 结束横幅顶格作边界),与主代理输出区分开,折叠块按 `ctrl+o` 展开时同样带缩进。
|
|
51
|
-
- `/
|
|
98
|
+
- `/undo [n]` 撤销最近 n 轮对话;写入/编辑文件前会自动建立**文件系统快照**,反悔时 `/revert` 可 diff 预览并选择按文件回滚(撤回 Agent 的文件改动,而不只是撤对话消息)。
|
|
99
|
+
- `/help` 查看可用命令,`/clear` 清空历史。
|
|
52
100
|
- `/compact` 把对话历史压缩成一段摘要,释放上下文(长对话逼近上限时用;仅在确有收益时替换)。上下文占比达到约 80% 时也会**自动压缩**。
|
|
53
|
-
- `/model [id]`
|
|
101
|
+
- `/model [id|alias]` 查看当前模型或切换到新模型(也支持 `/model vision` 这类别名,输入空参数只查看)。
|
|
54
102
|
- `/save [name]` 保存当前会话,`/load <name>` 加载会话(`Tab` 子串补全;多个候选时列出序号,输入数字即可加载),`/sessions` 列出已保存会话,`/delete <name>` 删除指定会话(需确认)。
|
|
55
103
|
- `/agent <任务描述>` 进入自动任务执行模式:AI 先制定计划,经你确认后自动调用工具逐步完成;待办清单未完成时,模型只输出过渡文字也不会提前收工,会被提醒继续执行(连续空转 3 次兜底放弃)。
|
|
56
104
|
- `/goal <任务> [| <完成条件>]` 进入目标执行模式:在 `/agent` 基础上,执行结束后再按完成条件做一次达成判定;完成条件可省略,省略时由规划阶段先补一条可检查条件。
|
|
57
105
|
- `/resume` 手动恢复上次退出时自动保存的会话。
|
|
106
|
+
- `/replay [sessionId]` 回放会话执行过程:带时间线展示用户消息、模型回答、工具调用与结果、回合结束原因(读取 `~/.ccli/records/` 下的事件记录,Tab 可补全会话 ID)。
|
|
58
107
|
- `/reload` 重新加载 `.ccli/config.json` 并刷新 MCP server。
|
|
59
108
|
- `/stats` 查看当前会话累计 token 消耗与上下文占比(估算值)。
|
|
60
109
|
- `/mcp list` 查看已连接的 MCP server,`/mcp add <name> <command> [args...]` 动态添加,`/mcp remove <name>` 移除,`/mcp reload` 重连所有 server。
|
|
@@ -63,7 +112,9 @@ ccli --role coder "review 这段代码" # 使用 coding 角色单次调用
|
|
|
63
112
|
- 粘贴多行文本时会自动合并成一条消息发送,不会被截断。
|
|
64
113
|
- 终端输出使用统一的语义化颜色(标签、警告、错误、Agent/Goal 进度等);设置 `NO_COLOR=1` 可关闭颜色,设置 `FORCE_COLOR=1` 可强制上色。
|
|
65
114
|
- 支持 MCP (Model Context Protocol) 扩展:在 `~/.ccli/config.json` 配置 `mcpServers` 即可接入外部 server 的工具。
|
|
115
|
+
- 支持**多模态图片输入**:在 prompt 里引用 `@图片.png`(相对/绝对路径),macOS 下也可直接按 `Ctrl-V` 粘贴剪贴板图片;模型不支持视觉时会自动降级为文字说明,避免浪费 token;发送前过大的图片会自动降分辨率(最长边 1024)。
|
|
66
116
|
- 退出时自动保存 `last` 恢复点;下次启动会询问是否恢复上次会话。
|
|
117
|
+
- 每个回合的执行过程(用户消息、模型回答、工具调用与结果、token 统计)会**自动记录**到 `~/.ccli/records/<sessionId>.jsonl`(本地只追加文件,可安全删除),用于复盘 agent 到底做了什么;task 子代理的内部过程也会记入同一文件(带 `subagent` 标记);启动时自动清理 30 天前或超出最近 50 个会话的旧记录。
|
|
67
118
|
- `/exit` 或 `/quit` 退出,也可按 Ctrl-C / Ctrl-D。
|
|
68
119
|
|
|
69
120
|
## 配置
|
package/dist/agent/ai.js
CHANGED
|
@@ -15,56 +15,9 @@ export function createAIClient(config) {
|
|
|
15
15
|
* 严格投影工具消息:只保留「assistant.tool_calls 后紧跟对应 tool 结果」
|
|
16
16
|
* 的完整配对,丢弃孤儿 tool 结果与未完成的 tool_calls,避免 provider
|
|
17
17
|
* 因 tool_use / tool_result 不配对拒绝整段上下文。
|
|
18
|
-
*/
|
|
19
|
-
export function projectToolPairedMessages(messages) {
|
|
20
|
-
const projected = [];
|
|
21
|
-
const pendingToolCallIds = [];
|
|
22
|
-
for (let i = 0; i < messages.length; i++) {
|
|
23
|
-
const m = messages[i];
|
|
24
|
-
if (m.role === 'tool') {
|
|
25
|
-
const toolCallId = m.tool_call_id;
|
|
26
|
-
const pendingIndex = pendingToolCallIds.indexOf(toolCallId);
|
|
27
|
-
if (pendingIndex < 0)
|
|
28
|
-
continue;
|
|
29
|
-
projected.push(m);
|
|
30
|
-
pendingToolCallIds.splice(pendingIndex, 1);
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
if (m.role === 'assistant') {
|
|
34
|
-
const toolCalls = m.tool_calls;
|
|
35
|
-
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
36
|
-
const validToolCallIds = toolCalls
|
|
37
|
-
.map((tc) => tc?.id)
|
|
38
|
-
.filter((id) => typeof id === 'string' && id.length > 0);
|
|
39
|
-
const resultIds = collectFollowingToolResultIds(messages, i);
|
|
40
|
-
if (validToolCallIds.length !== toolCalls.length ||
|
|
41
|
-
!validToolCallIds.every((id) => resultIds.has(id))) {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
projected.push(m);
|
|
45
|
-
pendingToolCallIds.push(...validToolCallIds);
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
projected.push(m);
|
|
50
|
-
}
|
|
51
|
-
return projected;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* 从某条 assistant.tool_calls 后面连续的 tool 消息里收集结果 id。
|
|
55
18
|
*
|
|
56
|
-
*
|
|
19
|
+
* 实现已拆到叶子模块 ./tool-projection.js(打破 ai.ts ↔ providers 的
|
|
20
|
+
* 循环 import),这里 re-export 保持既有引用不破。
|
|
57
21
|
*/
|
|
58
|
-
|
|
59
|
-
const ids = new Set();
|
|
60
|
-
for (let i = assistantIndex + 1; i < messages.length; i++) {
|
|
61
|
-
const m = messages[i];
|
|
62
|
-
if (m.role !== 'tool')
|
|
63
|
-
break;
|
|
64
|
-
const id = m.tool_call_id;
|
|
65
|
-
if (id)
|
|
66
|
-
ids.add(id);
|
|
67
|
-
}
|
|
68
|
-
return ids;
|
|
69
|
-
}
|
|
22
|
+
export { projectToolPairedMessages } from './tool-projection.js';
|
|
70
23
|
//# sourceMappingURL=ai.js.map
|
package/dist/agent/ai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/agent/ai.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/agent/ai.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAyErD,sBAAsB;AACtB,MAAM,UAAU,cAAc,CAAC,MAAc;IACzC,IAAI,MAAM,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAID;;;;;;;GAOG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/agent/os.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { spawn as childSpawn } from 'node:child_process';
|
|
2
|
+
import { promises as fsPromises, existsSync } from 'node:fs';
|
|
3
|
+
import { resolve as pathResolve, dirname as pathDirname, relative as pathRelative, join as pathJoin, sep as pathSep } from 'node:path';
|
|
4
|
+
export class LocalOS {
|
|
5
|
+
async exists(path) {
|
|
6
|
+
return existsSync(path);
|
|
7
|
+
}
|
|
8
|
+
async isDirectory(path) {
|
|
9
|
+
try {
|
|
10
|
+
const st = await fsPromises.stat(path);
|
|
11
|
+
return st.isDirectory();
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async readFile(path, encoding = 'utf8') {
|
|
18
|
+
return fsPromises.readFile(path, encoding);
|
|
19
|
+
}
|
|
20
|
+
async writeFile(path, content, encoding = 'utf8') {
|
|
21
|
+
await fsPromises.writeFile(path, content, encoding);
|
|
22
|
+
}
|
|
23
|
+
async mkdir(path, options) {
|
|
24
|
+
await fsPromises.mkdir(path, { recursive: options?.recursive ?? true });
|
|
25
|
+
}
|
|
26
|
+
async readdir(path) {
|
|
27
|
+
const list = await fsPromises.readdir(path, { withFileTypes: true });
|
|
28
|
+
return list.map(entry => ({
|
|
29
|
+
name: entry.name,
|
|
30
|
+
isDirectory: () => entry.isDirectory()
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
async stat(path) {
|
|
34
|
+
const st = await fsPromises.stat(path);
|
|
35
|
+
return {
|
|
36
|
+
size: st.size,
|
|
37
|
+
isDirectory: () => st.isDirectory()
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async unlink(path) {
|
|
41
|
+
await fsPromises.unlink(path);
|
|
42
|
+
}
|
|
43
|
+
resolve(...paths) {
|
|
44
|
+
return pathResolve(...paths);
|
|
45
|
+
}
|
|
46
|
+
dirname(path) {
|
|
47
|
+
return pathDirname(path);
|
|
48
|
+
}
|
|
49
|
+
relative(from, to) {
|
|
50
|
+
return pathRelative(from, to);
|
|
51
|
+
}
|
|
52
|
+
join(...paths) {
|
|
53
|
+
return pathJoin(...paths);
|
|
54
|
+
}
|
|
55
|
+
get sep() {
|
|
56
|
+
return pathSep;
|
|
57
|
+
}
|
|
58
|
+
get defaultShell() {
|
|
59
|
+
return process.env.SHELL || '/bin/bash';
|
|
60
|
+
}
|
|
61
|
+
async spawn(command, args, options) {
|
|
62
|
+
const proc = childSpawn(command, args, {
|
|
63
|
+
cwd: options?.cwd,
|
|
64
|
+
env: options?.env ?? process.env
|
|
65
|
+
});
|
|
66
|
+
return proc;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=os.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"os.js","sourceRoot":"","sources":["../../src/agent/os.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import { toolDefs } from '../../tools/index.js';
|
|
3
|
-
import { projectToolPairedMessages } from '../
|
|
3
|
+
import { projectToolPairedMessages } from '../tool-projection.js';
|
|
4
4
|
export class AnthropicClient {
|
|
5
5
|
client;
|
|
6
6
|
model;
|
|
@@ -20,6 +20,10 @@ export class AnthropicClient {
|
|
|
20
20
|
setModel(model) {
|
|
21
21
|
this.model = model;
|
|
22
22
|
}
|
|
23
|
+
/** Claude 3 及以后全系支持图像;老的 claude-2 / instant 不支持。 */
|
|
24
|
+
supportsVision() {
|
|
25
|
+
return !/claude-2|claude-instant/i.test(this.model);
|
|
26
|
+
}
|
|
23
27
|
/**
|
|
24
28
|
* Anthropic SDK 没有稳定的模型列表接口,返回常用模型。
|
|
25
29
|
* 用户仍可用 /model <完整名> 切换到列表外的模型。
|
|
@@ -62,8 +66,16 @@ export class AnthropicClient {
|
|
|
62
66
|
let content = '';
|
|
63
67
|
const acc = {};
|
|
64
68
|
let usage;
|
|
69
|
+
// Anthropic 流式协议:input_tokens 只出现在 message_start 事件,
|
|
70
|
+
// message_delta 只带 output_tokens——两处都要读才能拼出完整 usage。
|
|
71
|
+
let inputTokens = 0;
|
|
65
72
|
for await (const event of stream) {
|
|
66
|
-
if (event.type === '
|
|
73
|
+
if (event.type === 'message_start') {
|
|
74
|
+
const u = event.message?.usage;
|
|
75
|
+
if (u)
|
|
76
|
+
inputTokens = u.input_tokens ?? 0;
|
|
77
|
+
}
|
|
78
|
+
else if (event.type === 'content_block_delta') {
|
|
67
79
|
if (event.delta.type === 'text_delta') {
|
|
68
80
|
content += event.delta.text;
|
|
69
81
|
onDelta(event.delta.text);
|
|
@@ -93,10 +105,12 @@ export class AnthropicClient {
|
|
|
93
105
|
else if (event.type === 'message_delta') {
|
|
94
106
|
const u = event.usage;
|
|
95
107
|
if (u) {
|
|
108
|
+
const promptTokens = inputTokens || (u.input_tokens ?? 0);
|
|
109
|
+
const completionTokens = u.output_tokens ?? 0;
|
|
96
110
|
usage = {
|
|
97
|
-
promptTokens
|
|
98
|
-
completionTokens
|
|
99
|
-
totalTokens:
|
|
111
|
+
promptTokens,
|
|
112
|
+
completionTokens,
|
|
113
|
+
totalTokens: promptTokens + completionTokens,
|
|
100
114
|
};
|
|
101
115
|
}
|
|
102
116
|
}
|
|
@@ -173,6 +187,24 @@ export function toAnthropicMessages(messages) {
|
|
|
173
187
|
if (typeof m.content === 'string') {
|
|
174
188
|
anthropicMessages.push({ role: 'user', content: m.content });
|
|
175
189
|
}
|
|
190
|
+
else if (Array.isArray(m.content)) {
|
|
191
|
+
// 多模态:把 OpenAI 风格的 text / image_url 片段翻译成 Anthropic block
|
|
192
|
+
const blocks = [];
|
|
193
|
+
for (const part of m.content) {
|
|
194
|
+
if (part?.type === 'text') {
|
|
195
|
+
blocks.push({ type: 'text', text: part.text });
|
|
196
|
+
}
|
|
197
|
+
else if (part?.type === 'image_url') {
|
|
198
|
+
const img = dataUrlToImageBlock(part.image_url?.url);
|
|
199
|
+
if (img)
|
|
200
|
+
blocks.push(img);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
anthropicMessages.push({
|
|
204
|
+
role: 'user',
|
|
205
|
+
content: blocks.length > 0 ? blocks : '',
|
|
206
|
+
});
|
|
207
|
+
}
|
|
176
208
|
else {
|
|
177
209
|
anthropicMessages.push({
|
|
178
210
|
role: 'user',
|
|
@@ -195,6 +227,25 @@ export function toAnthropicTools(allowedNames) {
|
|
|
195
227
|
},
|
|
196
228
|
}));
|
|
197
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* 把 `data:<mime>;base64,<data>` 解析成 Anthropic 的 base64 image block。
|
|
232
|
+
* 非 data URL 或格式不符时返回 null(跳过该图,不阻断整段请求)。
|
|
233
|
+
*/
|
|
234
|
+
function dataUrlToImageBlock(url) {
|
|
235
|
+
if (typeof url !== 'string')
|
|
236
|
+
return null;
|
|
237
|
+
const m = /^data:([^;]+);base64,(.+)$/s.exec(url);
|
|
238
|
+
if (!m)
|
|
239
|
+
return null;
|
|
240
|
+
return {
|
|
241
|
+
type: 'image',
|
|
242
|
+
source: {
|
|
243
|
+
type: 'base64',
|
|
244
|
+
media_type: m[1],
|
|
245
|
+
data: m[2],
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
198
249
|
/** 解析模型给出的工具参数;失败时回落为空对象,避免坏 JSON 破坏整段 Anthropic 请求。 */
|
|
199
250
|
function safeParse(json) {
|
|
200
251
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/agent/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAShD,OAAO,EAAE,yBAAyB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/agent/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAShD,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,OAAO,eAAe;IAChB,MAAM,CAAY;IAClB,KAAK,CAAS;IAEtB,oDAAoD;IACpD,YAAY,MAAc;QACtB,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC;YACxB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,OAAO,EAAE,MAAM,CAAC,OAAO;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC9B,CAAC;IAED,8CAA8C;IAC9C,QAAQ;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,iCAAiC;IACjC,QAAQ,CAAC,KAAa;QAClB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;IAED,oDAAoD;IACpD,cAAc;QACV,OAAO,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU;QACZ,OAAO;YACH,0BAA0B;YAC1B,4BAA4B;YAC5B,4BAA4B;YAC5B,4BAA4B;YAC5B,wBAAwB;YACxB,0BAA0B;YAC1B,yBAAyB;SAC5B,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,CACN,QAAuB,EACvB,OAA+B,EAC/B,OAAqB,EACrB,WAAoC,EACpC,mBAIS;QAET,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC9E,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAEtD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC7C,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,UAAU,EAAE,IAAI;YAChB,MAAM;YACN,QAAQ,EAAE,iBAAiB;YAC3B,MAAM,EAAE,IAAI;YACZ,GAAG,CAAC,OAAO,EAAE,YAAY;gBACrB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACI,KAAK;oBACL,GAAG,CAAC,OAAO,EAAE,YAAY;wBACrB,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAW,EAAE;wBAC3C,CAAC,CAAC,EAAE,CAAC;iBACZ,CAAC;SACX,CAAC,CAAC;QAEH,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,MAAM,GAAG,GAA6B,EAAE,CAAC;QACzC,IAAI,KAAwB,CAAC;QAC7B,qDAAqD;QACrD,qDAAqD;QACrD,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;gBACjC,MAAM,CAAC,GAAI,KAAa,CAAC,OAAO,EAAE,KAAK,CAAC;gBACxC,IAAI,CAAC;oBAAE,WAAW,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;YAC7C,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBAC9C,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBACpC,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;oBAC5B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC9B,CAAC;qBAAM,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;oBAC/C,WAAW,EAAE,CAAE,KAAK,CAAC,KAAa,CAAC,QAAQ,CAAC,CAAC;gBACjD,CAAC;qBAAM,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;oBACjD,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBAC5B,IAAI,EAAE,EAAE,CAAC;wBACL,EAAE,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC;wBACzC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;4BACV,mBAAmB,EAAE,CACjB,KAAK,CAAC,KAAK,EACX,EAAE,CAAC,IAAI,EACP,EAAE,CAAC,SAAS,CACf,CAAC;wBACN,CAAC;oBACL,CAAC;gBACL,CAAC;YACL,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBAC9C,IAAI,KAAK,CAAC,aAAa,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBAC1C,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG;wBACf,EAAE,EAAE,KAAK,CAAC,aAAa,CAAC,EAAE;wBAC1B,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,IAAI;wBAC9B,SAAS,EAAE,EAAE;qBAChB,CAAC;gBACN,CAAC;YACL,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;gBACxC,MAAM,CAAC,GAAI,KAAa,CAAC,KAAK,CAAC;gBAC/B,IAAI,CAAC,EAAE,CAAC;oBACJ,MAAM,YAAY,GAAG,WAAW,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;oBAC1D,MAAM,gBAAgB,GAAG,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC;oBAC9C,KAAK,GAAG;wBACJ,YAAY;wBACZ,gBAAgB;wBAChB,WAAW,EAAE,YAAY,GAAG,gBAAgB;qBAC/C,CAAC;gBACN,CAAC;YACL,CAAC;QACL,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;aAC7B,GAAG,CAAC,MAAM,CAAC;aACX,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;aACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACzC,CAAC;CACJ;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAuB;IAIvD,MAAM,iBAAiB,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,iBAAiB,GAAsC,EAAE,CAAC;IAChE,MAAM,iBAAiB,GAAa,EAAE,CAAC;IAEvC,KAAK,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC;QAChC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAChC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;YACD,SAAS;QACb,CAAC;QAED,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,wCAAwC;YACxC,MAAM,UAAU,GAAI,CAAS,CAAC,YAAY,IAAI,EAAE,CAAC;YACjD,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC1C,SAAS;YACb,CAAC;YACD,MAAM,UAAU,GACZ,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC1E,iBAAiB,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACL;wBACI,IAAI,EAAE,aAAa;wBACnB,WAAW,EAAE,UAAU;wBACvB,OAAO,EAAE,UAAU;qBACqB;iBAC/C;aACJ,CAAC,CAAC;YACH,iBAAiB,CAAC,MAAM,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;YACnE,SAAS;QACb,CAAC;QAED,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACzB,MAAM,OAAO,GAA2C,EAAE,CAAC;YAC3D,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;gBAC7C,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACpD,CAAC;YAED,MAAM,SAAS,GAAI,CAAS,CAAC,UAAU,CAAC;YACxC,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3B,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;oBACzB,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;wBACjC,SAAS;oBACb,CAAC;oBACD,OAAO,CAAC,IAAI,CAAC;wBACT,IAAI,EAAE,UAAU;wBAChB,EAAE,EAAE,EAAE,CAAC,EAAE;wBACT,IAAI,EAAE,EAAE,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE;wBAC7B,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,IAAI,IAAI,CAAC;qBACX,CAAC,CAAC;oBAC3C,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAClC,CAAC;YACL,CAAC;YAED,iBAAiB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;YACvD,SAAS;QACb,CAAC;QAED,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAChC,iBAAiB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACjE,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,0DAA0D;gBAC1D,MAAM,MAAM,GAA2C,EAAE,CAAC;gBAC1D,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,OAAgB,EAAE,CAAC;oBACpC,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,EAAE,CAAC;wBACxB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;oBACnD,CAAC;yBAAM,IAAI,IAAI,EAAE,IAAI,KAAK,WAAW,EAAE,CAAC;wBACpC,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;wBACrD,IAAI,GAAG;4BAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC9B,CAAC;gBACL,CAAC;gBACD,iBAAiB,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;iBAC3C,CAAC,CAAC;YACP,CAAC;iBAAM,CAAC;gBACJ,iBAAiB,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;iBACrC,CAAC,CAAC;YACP,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;AAC7E,CAAC;AAED;8CAC8C;AAC9C,MAAM,UAAU,gBAAgB,CAC5B,YAAuB;IAEvB,OAAO,QAAQ,CAAC,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI;QACrB,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW;QACnC,YAAY,EAAE;YACV,IAAI,EAAE,QAAiB;YACvB,GAAG,CAAC,CAAC,QAAQ,CAAC,UAAU;SAC3B;KACJ,CAAC,CAAC,CAAC;AACR,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CACxB,GAAY;IAEZ,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,CAAC,GAAG,6BAA6B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO;QACH,IAAI,EAAE,OAAO;QACb,MAAM,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,CAAC,CAAC,CAAC,CAAuD;YACtE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;SACb;KACJ,CAAC;AACN,CAAC;AAED,wDAAwD;AACxD,SAAS,SAAS,CAAC,IAAY;IAC3B,IAAI,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC"}
|
|
@@ -1,97 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { OpenAIClient } from './openai.js';
|
|
2
|
+
/** Gemini 的 OpenAI 兼容端点(config.baseURL 未配置时的默认指向)。 */
|
|
3
|
+
export const DEFAULT_GEMINI_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/openai/';
|
|
4
|
+
/**
|
|
5
|
+
* Gemini 后端:走 Google 的 OpenAI 兼容协议,请求/流式聚合逻辑与
|
|
6
|
+
* OpenAIClient 完全一致,因此直接继承,只改默认 baseURL。
|
|
7
|
+
* (此前是 70 行逐字复制的 chat 循环,两处分叉风险已被继承结构消除。)
|
|
8
|
+
*/
|
|
9
|
+
export class GeminiClient extends OpenAIClient {
|
|
8
10
|
constructor(config) {
|
|
9
|
-
|
|
10
|
-
apiKey: config.apiKey,
|
|
11
|
-
baseURL: config.baseURL || 'https://generativelanguage.googleapis.com/v1beta/openai/',
|
|
12
|
-
});
|
|
13
|
-
this.model = config.model;
|
|
14
|
-
}
|
|
15
|
-
/** 获取当前正在使用的模型名。 */
|
|
16
|
-
getModel() {
|
|
17
|
-
return this.model;
|
|
18
|
-
}
|
|
19
|
-
/** 在不重建客户端的情况下切换模型。 */
|
|
20
|
-
setModel(model) {
|
|
21
|
-
this.model = model;
|
|
22
|
-
}
|
|
23
|
-
/** 拉取后端可用模型列表(结果缓存,避免重复请求)。 */
|
|
24
|
-
modelCache;
|
|
25
|
-
async listModels() {
|
|
26
|
-
if (!this.modelCache) {
|
|
27
|
-
const list = await this.client.models.list();
|
|
28
|
-
this.modelCache = list.data.map((m) => m.id).sort();
|
|
29
|
-
}
|
|
30
|
-
return this.modelCache;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* 发送聊天请求并接收流式回复与工具调用。
|
|
34
|
-
*/
|
|
35
|
-
async chat(messages, onDelta, options, onReasoning, onToolArgumentDelta) {
|
|
36
|
-
const body = {
|
|
37
|
-
model: this.model,
|
|
38
|
-
messages: projectToolPairedMessages(messages),
|
|
39
|
-
stream: true,
|
|
40
|
-
stream_options: { include_usage: true },
|
|
41
|
-
};
|
|
42
|
-
if (!options?.disableTools) {
|
|
43
|
-
body.tools = toolDefs(options?.allowedTools);
|
|
44
|
-
if (options?.requireTools) {
|
|
45
|
-
body.tool_choice = 'required';
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const stream = (await this.client.chat.completions.create(body));
|
|
49
|
-
let content = '';
|
|
50
|
-
const acc = {};
|
|
51
|
-
let usage;
|
|
52
|
-
for await (const chunk of stream) {
|
|
53
|
-
const delta = chunk.choices[0]?.delta;
|
|
54
|
-
if (!delta) {
|
|
55
|
-
const u = chunk.usage;
|
|
56
|
-
if (u) {
|
|
57
|
-
usage = {
|
|
58
|
-
promptTokens: u.prompt_tokens ?? 0,
|
|
59
|
-
completionTokens: u.completion_tokens ?? 0,
|
|
60
|
-
totalTokens: u.total_tokens ?? 0,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
const reasoning = delta.reasoning_content;
|
|
66
|
-
if (reasoning)
|
|
67
|
-
onReasoning?.(reasoning);
|
|
68
|
-
if (delta.content) {
|
|
69
|
-
content += delta.content;
|
|
70
|
-
onDelta(delta.content);
|
|
71
|
-
}
|
|
72
|
-
for (const tc of delta.tool_calls ?? []) {
|
|
73
|
-
const cur = (acc[tc.index] ??= {
|
|
74
|
-
id: '',
|
|
75
|
-
name: '',
|
|
76
|
-
arguments: '',
|
|
77
|
-
});
|
|
78
|
-
if (tc.id)
|
|
79
|
-
cur.id = tc.id;
|
|
80
|
-
if (tc.function?.name)
|
|
81
|
-
cur.name = tc.function.name;
|
|
82
|
-
if (tc.function?.arguments) {
|
|
83
|
-
cur.arguments += tc.function.arguments;
|
|
84
|
-
if (cur.name) {
|
|
85
|
-
onToolArgumentDelta?.(tc.index, cur.name, cur.arguments);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const toolCalls = Object.keys(acc)
|
|
91
|
-
.map(Number)
|
|
92
|
-
.sort((a, b) => a - b)
|
|
93
|
-
.map((i) => acc[i]);
|
|
94
|
-
return { content, toolCalls, usage };
|
|
11
|
+
super({ ...config, baseURL: config.baseURL || DEFAULT_GEMINI_BASE_URL });
|
|
95
12
|
}
|
|
96
13
|
}
|
|
97
14
|
//# sourceMappingURL=gemini.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/agent/providers/gemini.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/agent/providers/gemini.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,sDAAsD;AACtD,MAAM,CAAC,MAAM,uBAAuB,GAChC,0DAA0D,CAAC;AAE/D;;;;GAIG;AACH,MAAM,OAAO,YAAa,SAAQ,YAAY;IAC1C,YAAY,MAAc;QACtB,KAAK,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,uBAAuB,EAAE,CAAC,CAAC;IAC7E,CAAC;CACJ"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import OpenAI from 'openai';
|
|
2
2
|
import { toolDefs } from '../../tools/index.js';
|
|
3
|
-
import { projectToolPairedMessages } from '../
|
|
3
|
+
import { projectToolPairedMessages } from '../tool-projection.js';
|
|
4
4
|
export class OpenAIClient {
|
|
5
5
|
client;
|
|
6
6
|
model;
|
|
@@ -20,6 +20,14 @@ export class OpenAIClient {
|
|
|
20
20
|
setModel(model) {
|
|
21
21
|
this.model = model;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* 按模型名启发式判断是否支持图像输入。OpenAI 兼容后端型号繁杂,没有统一的
|
|
25
|
+
* capability 接口,只能靠常见命名规律匹配(qwen-vl / *-vision / gpt-4o /
|
|
26
|
+
* gemini / *-4v / omni 等)。宁可漏判降级为文字,也不误判导致后端报错。
|
|
27
|
+
*/
|
|
28
|
+
supportsVision() {
|
|
29
|
+
return /vl|vision|4o|omni|4v|gemini|internvl|llava|pixtral|claude/i.test(this.model);
|
|
30
|
+
}
|
|
23
31
|
/** 拉取后端可用模型列表(结果缓存,避免重复请求)。 */
|
|
24
32
|
modelCache;
|
|
25
33
|
async listModels() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/agent/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAShD,OAAO,EAAE,yBAAyB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/agent/providers/openai.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 严格投影工具消息:只保留「assistant.tool_calls 后紧跟对应 tool 结果」
|
|
3
|
+
* 的完整配对,丢弃孤儿 tool 结果与未完成的 tool_calls,避免 provider
|
|
4
|
+
* 因 tool_use / tool_result 不配对拒绝整段上下文。
|
|
5
|
+
*/
|
|
6
|
+
export function projectToolPairedMessages(messages) {
|
|
7
|
+
const projected = [];
|
|
8
|
+
const pendingToolCallIds = [];
|
|
9
|
+
for (let i = 0; i < messages.length; i++) {
|
|
10
|
+
const m = messages[i];
|
|
11
|
+
if (m.role === 'tool') {
|
|
12
|
+
const toolCallId = m.tool_call_id;
|
|
13
|
+
const pendingIndex = pendingToolCallIds.indexOf(toolCallId);
|
|
14
|
+
if (pendingIndex < 0)
|
|
15
|
+
continue;
|
|
16
|
+
projected.push(m);
|
|
17
|
+
pendingToolCallIds.splice(pendingIndex, 1);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (m.role === 'assistant') {
|
|
21
|
+
const toolCalls = m.tool_calls;
|
|
22
|
+
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
23
|
+
const validToolCallIds = toolCalls
|
|
24
|
+
.map((tc) => tc?.id)
|
|
25
|
+
.filter((id) => typeof id === 'string' && id.length > 0);
|
|
26
|
+
const resultIds = collectFollowingToolResultIds(messages, i);
|
|
27
|
+
if (validToolCallIds.length !== toolCalls.length ||
|
|
28
|
+
!validToolCallIds.every((id) => resultIds.has(id))) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
projected.push(m);
|
|
32
|
+
pendingToolCallIds.push(...validToolCallIds);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
projected.push(m);
|
|
37
|
+
}
|
|
38
|
+
return projected;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 从某条 assistant.tool_calls 后面连续的 tool 消息里收集结果 id。
|
|
42
|
+
*
|
|
43
|
+
* 一旦遇到非 tool 消息就停止,因为 provider 语义要求 tool_result 紧跟对应 tool_use。
|
|
44
|
+
*/
|
|
45
|
+
function collectFollowingToolResultIds(messages, assistantIndex) {
|
|
46
|
+
const ids = new Set();
|
|
47
|
+
for (let i = assistantIndex + 1; i < messages.length; i++) {
|
|
48
|
+
const m = messages[i];
|
|
49
|
+
if (m.role !== 'tool')
|
|
50
|
+
break;
|
|
51
|
+
const id = m.tool_call_id;
|
|
52
|
+
if (id)
|
|
53
|
+
ids.add(id);
|
|
54
|
+
}
|
|
55
|
+
return ids;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=tool-projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-projection.js","sourceRoot":"","sources":["../../src/agent/tool-projection.ts"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAuB;IAC7D,MAAM,SAAS,GAAkB,EAAE,CAAC;IACpC,MAAM,kBAAkB,GAAa,EAAE,CAAC;IAExC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAEtB,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACpB,MAAM,UAAU,GAAI,CAAS,CAAC,YAAY,CAAC;YAC3C,MAAM,YAAY,GAAG,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC5D,IAAI,YAAY,GAAG,CAAC;gBAAE,SAAS;YAC/B,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,kBAAkB,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;YAC3C,SAAS;QACb,CAAC;QAED,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACzB,MAAM,SAAS,GAAI,CAAS,CAAC,UAAU,CAAC;YACxC,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnD,MAAM,gBAAgB,GAAG,SAAS;qBAC7B,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;qBACnB,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAC3E,MAAM,SAAS,GAAG,6BAA6B,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;gBAC7D,IACI,gBAAgB,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;oBAC5C,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EACpD,CAAC;oBACC,SAAS;gBACb,CAAC;gBACD,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,kBAAkB,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,CAAC;gBAC7C,SAAS;YACb,CAAC;QACL,CAAC;QAED,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,SAAS,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,SAAS,6BAA6B,CAClC,QAAuB,EACvB,cAAsB;IAEtB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,cAAc,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;YAAE,MAAM;QAC7B,MAAM,EAAE,GAAI,CAAS,CAAC,YAAY,CAAC;QACnC,IAAI,EAAE;YAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC"}
|