ai-lab-bridge 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +34 -3
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -219,6 +219,7 @@ class Session {
219
219
  this.thinkOpen = false; // <think> 区间状态:思考内容包标签后按普通文本增量下发
220
220
  this.options = {};
221
221
  this.seenTools = new Set(); // 工具 callID 去重(opencode 会对同一 part 按状态多次推送)
222
+ this.toolNames = new Map(); // callID -> 工具名(claude 系 tool_result 块只带 tool_use_id,配对还原工具名)
222
223
  this.fileDir = null; // 附件下载临时目录
223
224
  }
224
225
 
@@ -391,13 +392,42 @@ function handleClaudeLine(session, obj) {
391
392
  // Claude 扩展思考块:包 <think> 标签按文本增量下发,平台/前端已支持渲染
392
393
  session.emitThink(block.thinking);
393
394
  } else if (block.type === "tool_use") {
395
+ // 结构化 tool_call:claude/qwen 系 tool_use 块带 id/name/input,
396
+ // 平台按 call_id 渲染工具块(args 可展示),不再退化为纯名字摘要
394
397
  session.endThink();
395
- session.emitToolUse(block.name);
398
+ const callId = String(block.id || "");
399
+ const name = String(block.name || "tool");
400
+ if (callId) session.toolNames.set(callId, name);
401
+ if (callId && !session.seenTools.has(callId)) {
402
+ session.seenTools.add(callId);
403
+ session.emitEvent("tool_call", {
404
+ call_id: callId,
405
+ name,
406
+ args: JSON.stringify(block.input || {}),
407
+ });
408
+ } else if (!callId) {
409
+ session.emitToolUse(name);
410
+ }
396
411
  }
397
412
  }
398
413
  } else if (obj.type === "user" && obj.message && Array.isArray(obj.message.content)) {
399
414
  for (const block of obj.message.content) {
400
- if (block.type === "tool_result" && !block.is_error) session.emitToolUse("tool_result");
415
+ if (block.type === "tool_result") {
416
+ // 配对 tool_result:tool_use_id 关联上面缓存的工具名,content/is_error 归一化
417
+ const callId = String(block.tool_use_id || "");
418
+ const name = session.toolNames.get(callId) || "tool";
419
+ if (callId) {
420
+ const output = block.content;
421
+ session.emitEvent("tool_result", {
422
+ call_id: callId,
423
+ name,
424
+ output: typeof output === "string" ? output : JSON.stringify(output ?? ""),
425
+ status: block.is_error ? "error" : "success",
426
+ });
427
+ } else if (!block.is_error) {
428
+ session.emitToolUse("tool_result");
429
+ }
430
+ }
401
431
  }
402
432
  } else if (obj.type === "result") {
403
433
  session.emitSession(obj.session_id);
@@ -795,7 +825,8 @@ function startSession(message) {
795
825
  } else if (cli === "qwen") {
796
826
  // qwen 0.24+ 与 claude 同源(实测 0.24.6 stream-json 格式兼容),启动参数使用 qwen 自己的
797
827
  // --approval-mode(5 档:plan/default/auto-edit/auto/yolo),不复用 claude 的 --permission-mode
798
- argv = [cli, ["-p", "--output-format", "stream-json", "--verbose"]];
828
+ // 注意:不能带 --verbose(那是 Claude Code 的参数,qwen 会报 Unknown argument 并退出 1)
829
+ argv = [cli, ["-p", "--output-format", "stream-json"]];
799
830
  if (sessionRef) argv[1].push("--resume", sessionRef);
800
831
  if (options.permission_mode) argv[1].push("--approval-mode", String(options.permission_mode));
801
832
  if (options.model) argv[1].push("--model", String(options.model));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-lab-bridge",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "AI 开发平台设备桥接进程:反连平台 WebSocket,驱动本地 Claude Code / Codex CLI 执行任务并回传事件流",
5
5
  "license": "MIT",
6
6
  "files": [