@gird/ccli 2.17.0 → 2.18.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 +2 -0
- package/dist/agent/ai.js +3 -50
- package/dist/agent/ai.js.map +1 -1
- 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 +4 -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 +51 -3
- package/dist/cli/repl/index.js.map +1 -1
- package/dist/cli/run/index.js +72 -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/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 +11 -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 +23 -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 +55 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/shared.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ ccli --role coder "review 这段代码" # 使用 coding 角色单次调用
|
|
|
55
55
|
- `/agent <任务描述>` 进入自动任务执行模式:AI 先制定计划,经你确认后自动调用工具逐步完成;待办清单未完成时,模型只输出过渡文字也不会提前收工,会被提醒继续执行(连续空转 3 次兜底放弃)。
|
|
56
56
|
- `/goal <任务> [| <完成条件>]` 进入目标执行模式:在 `/agent` 基础上,执行结束后再按完成条件做一次达成判定;完成条件可省略,省略时由规划阶段先补一条可检查条件。
|
|
57
57
|
- `/resume` 手动恢复上次退出时自动保存的会话。
|
|
58
|
+
- `/replay [sessionId]` 回放会话执行过程:带时间线展示用户消息、模型回答、工具调用与结果、回合结束原因(读取 `~/.ccli/records/` 下的事件记录,Tab 可补全会话 ID)。
|
|
58
59
|
- `/reload` 重新加载 `.ccli/config.json` 并刷新 MCP server。
|
|
59
60
|
- `/stats` 查看当前会话累计 token 消耗与上下文占比(估算值)。
|
|
60
61
|
- `/mcp list` 查看已连接的 MCP server,`/mcp add <name> <command> [args...]` 动态添加,`/mcp remove <name>` 移除,`/mcp reload` 重连所有 server。
|
|
@@ -64,6 +65,7 @@ ccli --role coder "review 这段代码" # 使用 coding 角色单次调用
|
|
|
64
65
|
- 终端输出使用统一的语义化颜色(标签、警告、错误、Agent/Goal 进度等);设置 `NO_COLOR=1` 可关闭颜色,设置 `FORCE_COLOR=1` 可强制上色。
|
|
65
66
|
- 支持 MCP (Model Context Protocol) 扩展:在 `~/.ccli/config.json` 配置 `mcpServers` 即可接入外部 server 的工具。
|
|
66
67
|
- 退出时自动保存 `last` 恢复点;下次启动会询问是否恢复上次会话。
|
|
68
|
+
- 每个回合的执行过程(用户消息、模型回答、工具调用与结果、token 统计)会**自动记录**到 `~/.ccli/records/<sessionId>.jsonl`(本地只追加文件,可安全删除),用于复盘 agent 到底做了什么;task 子代理的内部过程也会记入同一文件(带 `subagent` 标记);启动时自动清理 30 天前或超出最近 50 个会话的旧记录。
|
|
67
69
|
- `/exit` 或 `/quit` 退出,也可按 Ctrl-C / Ctrl-D。
|
|
68
70
|
|
|
69
71
|
## 配置
|
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"}
|
|
@@ -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"}
|
package/dist/cli/args/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export function parseArgs(argv) {
|
|
|
10
10
|
help: false,
|
|
11
11
|
yes: false,
|
|
12
12
|
noHooks: false,
|
|
13
|
+
project: false,
|
|
13
14
|
unknown: [],
|
|
14
15
|
positionals: [],
|
|
15
16
|
};
|
|
@@ -31,6 +32,9 @@ export function parseArgs(argv) {
|
|
|
31
32
|
case '--no-hooks':
|
|
32
33
|
result.noHooks = true;
|
|
33
34
|
break;
|
|
35
|
+
case '--project':
|
|
36
|
+
result.project = true;
|
|
37
|
+
break;
|
|
34
38
|
case '-r':
|
|
35
39
|
case '--role': {
|
|
36
40
|
const next = argv[i + 1];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/args/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/args/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH,MAAM,UAAU,SAAS,CAAC,IAAc;IACpC,MAAM,MAAM,GAAe;QACvB,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,KAAK;QACX,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,KAAK;QACd,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,EAAE;KAClB,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,QAAQ,GAAG,EAAE,CAAC;YACV,KAAK,IAAI,CAAC;YACV,KAAK,WAAW;gBACZ,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;gBACtB,MAAM;YACV,KAAK,IAAI,CAAC;YACV,KAAK,QAAQ;gBACT,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;gBACnB,MAAM;YACV,KAAK,IAAI,CAAC;YACV,KAAK,OAAO;gBACR,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC;gBAClB,MAAM;YACV,KAAK,YAAY;gBACb,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;gBACtB,MAAM;YACV,KAAK,WAAW;gBACZ,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;gBACtB,MAAM;YACV,KAAK,IAAI,CAAC;YACV,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACZ,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACzB,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBAChC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;oBACnB,CAAC,EAAE,CAAC;gBACR,CAAC;qBAAM,CAAC;oBACJ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC7B,CAAC;gBACD,MAAM;YACV,CAAC;YACD;gBACI,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACtB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC7B,CAAC;qBAAM,CAAC;oBACJ,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjC,CAAC;QACT,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 从系统剪贴板取图片(Ctrl-V 粘贴图片用)。
|
|
3
|
+
*
|
|
4
|
+
* 参考 Kimi Code:终端里 Cmd-V 会被终端 App 截走(程序收不到),所以走
|
|
5
|
+
* **Ctrl-V**——它能真正传到程序里。这里负责把剪贴板里的图像位图落成一个临时
|
|
6
|
+
* PNG 文件,交给已有的图片引用管线(`@路径`)发送。
|
|
7
|
+
*
|
|
8
|
+
* 目前仅实现 macOS(osascript,系统自带、无需装东西)。其它平台返回不支持,
|
|
9
|
+
* 后续可补 Linux(wl-paste / xclip)与 Windows(PowerShell)。
|
|
10
|
+
*/
|
|
11
|
+
import { execFileSync } from 'node:child_process';
|
|
12
|
+
import { randomUUID } from 'node:crypto';
|
|
13
|
+
import { existsSync, statSync } from 'node:fs';
|
|
14
|
+
import { tmpdir } from 'node:os';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
/** osascript:把剪贴板内容按 PNG 写到 outPath;剪贴板无图会非零退出。 */
|
|
17
|
+
function readViaOsascript(outPath) {
|
|
18
|
+
execFileSync('osascript', [
|
|
19
|
+
'-e',
|
|
20
|
+
'set png to (the clipboard as «class PNGf»)',
|
|
21
|
+
'-e',
|
|
22
|
+
`set f to open for access POSIX file "${outPath}" with write permission`,
|
|
23
|
+
'-e',
|
|
24
|
+
'set eof f to 0',
|
|
25
|
+
'-e',
|
|
26
|
+
'write png to f',
|
|
27
|
+
'-e',
|
|
28
|
+
'close access f',
|
|
29
|
+
], { stdio: ['ignore', 'ignore', 'ignore'], timeout: 5000 });
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 取剪贴板图片,成功时返回落地的临时 PNG 路径。
|
|
33
|
+
* 剪贴板没有图片、平台不支持或提取失败都返回 `{ ok:false, reason }`。
|
|
34
|
+
*/
|
|
35
|
+
export function readClipboardImage() {
|
|
36
|
+
if (process.platform !== 'darwin') {
|
|
37
|
+
return { ok: false, reason: '当前平台暂不支持剪贴板取图(仅 macOS)' };
|
|
38
|
+
}
|
|
39
|
+
const outPath = join(tmpdir(), `ccli-paste-${randomUUID()}.png`);
|
|
40
|
+
try {
|
|
41
|
+
readViaOsascript(outPath);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return { ok: false, reason: '剪贴板里没有图片' };
|
|
45
|
+
}
|
|
46
|
+
if (!existsSync(outPath) || statSync(outPath).size === 0) {
|
|
47
|
+
return { ok: false, reason: '剪贴板里没有图片' };
|
|
48
|
+
}
|
|
49
|
+
return { ok: true, path: outPath };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=clipboard-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard-image.js","sourceRoot":"","sources":["../../src/cli/clipboard-image.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAMjC,mDAAmD;AACnD,SAAS,gBAAgB,CAAC,OAAe;IACrC,YAAY,CACR,WAAW,EACX;QACI,IAAI;QACJ,4CAA4C;QAC5C,IAAI;QACJ,wCAAwC,OAAO,yBAAyB;QACxE,IAAI;QACJ,gBAAgB;QAChB,IAAI;QACJ,gBAAgB;QAChB,IAAI;QACJ,gBAAgB;KACnB,EACD,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAC3D,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAC9B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IAC3D,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,UAAU,EAAE,MAAM,CAAC,CAAC;IACjE,IAAI,CAAC;QACD,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC7C,CAAC;IACD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACvD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 发送前给过大的图片降分辨率,省 token / 请求体。
|
|
3
|
+
*
|
|
4
|
+
* 背景(实测 qwen-vl-plus):图片 token 按分辨率算,且服务端对超大图有封顶
|
|
5
|
+
* (~1M 像素 ≈ 1280 token)。把最长边压到 1024,一张全屏截图能从 ~1259 token
|
|
6
|
+
* 降到 ~684(省 ~46%),文字基本仍可读;对按面积计费的 Claude/GPT-4o 省得更多。
|
|
7
|
+
*
|
|
8
|
+
* 实现走 macOS 自带的 `sips`(零依赖,剪贴板取图本就靠 macOS)。非 macOS 或任何
|
|
9
|
+
* 失败都**原样透传**——压缩只是优化,绝不能挡住发送。只在最长边超过上限时才降,
|
|
10
|
+
* 小图一律不动(`sips -Z` 会放大小图,必须先判断)。
|
|
11
|
+
*/
|
|
12
|
+
import { execFileSync } from 'node:child_process';
|
|
13
|
+
import { randomUUID } from 'node:crypto';
|
|
14
|
+
import { existsSync, statSync } from 'node:fs';
|
|
15
|
+
import { tmpdir } from 'node:os';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
/** 默认最长边上限(px);超过才降,小图不动。 */
|
|
18
|
+
export const MAX_IMAGE_EDGE = 1024;
|
|
19
|
+
/** 用 sips 读像素宽高;失败返回 null。 */
|
|
20
|
+
function sipsDimensions(path) {
|
|
21
|
+
try {
|
|
22
|
+
const out = execFileSync('sips', ['-g', 'pixelWidth', '-g', 'pixelHeight', path], { encoding: 'utf8', timeout: 5000 });
|
|
23
|
+
const w = /pixelWidth:\s*(\d+)/.exec(out);
|
|
24
|
+
const h = /pixelHeight:\s*(\d+)/.exec(out);
|
|
25
|
+
if (!w || !h)
|
|
26
|
+
return null;
|
|
27
|
+
return { width: Number(w[1]), height: Number(h[1]) };
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 若图片最长边超过 maxEdge,用 sips 等比降到 maxEdge 并输出临时 PNG;
|
|
35
|
+
* 否则(含非 macOS、读尺寸失败、压缩失败)原样透传。
|
|
36
|
+
*/
|
|
37
|
+
export function compressImageForModel(path, maxEdge = MAX_IMAGE_EDGE) {
|
|
38
|
+
if (process.platform !== 'darwin')
|
|
39
|
+
return { path, changed: false };
|
|
40
|
+
const from = sipsDimensions(path);
|
|
41
|
+
if (!from)
|
|
42
|
+
return { path, changed: false };
|
|
43
|
+
if (Math.max(from.width, from.height) <= maxEdge) {
|
|
44
|
+
return { path, changed: false };
|
|
45
|
+
}
|
|
46
|
+
const out = join(tmpdir(), `ccli-shrink-${randomUUID()}.png`);
|
|
47
|
+
try {
|
|
48
|
+
execFileSync('sips', ['-Z', String(maxEdge), path, '--out', out], {
|
|
49
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
50
|
+
timeout: 10000,
|
|
51
|
+
});
|
|
52
|
+
if (!existsSync(out) || statSync(out).size === 0) {
|
|
53
|
+
return { path, changed: false };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return { path, changed: false };
|
|
58
|
+
}
|
|
59
|
+
const to = sipsDimensions(out) ?? undefined;
|
|
60
|
+
return { path: out, changed: true, from, to };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=image-compress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-compress.js","sourceRoot":"","sources":["../../src/cli/image-compress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,6BAA6B;AAC7B,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAWnC,8BAA8B;AAC9B,SAAS,cAAc,CACnB,IAAY;IAEZ,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,YAAY,CACpB,MAAM,EACN,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,EAC/C,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CACtC,CAAC;QACF,MAAM,CAAC,GAAG,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACjC,IAAY,EACZ,UAAkB,cAAc;IAEhC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACnE,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC3C,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,UAAU,EAAE,MAAM,CAAC,CAAC;IAC9D,IAAI,CAAC;QACD,YAAY,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE;YAC9D,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,OAAO,EAAE,KAAK;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACpC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;IACD,MAAM,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;IAC5C,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AAClD,CAAC"}
|