@kafca/agentdock 0.1.28 → 0.1.30

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 (70) hide show
  1. package/README.md +5 -0
  2. package/dist/renderer/assets/{Badge-B-Ayib4h.js → Badge-DlVJI1Ys.js} +1 -1
  3. package/dist/renderer/assets/{Chat-CNEOxtyz.js → Chat-oa8OjaHQ.js} +1 -1
  4. package/dist/renderer/assets/{ChatMarkdown-BTd1QBj9.js → ChatMarkdown-C-N8KS5C.js} +1 -1
  5. package/dist/renderer/assets/{Config-ByKhcLa6.js → Config-D9sL_d4D.js} +1 -1
  6. package/dist/renderer/assets/{CronList-0mi8dcC5.js → CronList-Z5JU3DHk.js} +1 -1
  7. package/dist/renderer/assets/{Dashboard-C8-tB_qg.js → Dashboard-D3BwbG43.js} +2 -2
  8. package/dist/renderer/assets/{EmptyState-TR-9nr5e.js → EmptyState-QOj765Ul.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-DKAxFOXc.js → KnowledgeDetail-J7n01mPu.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeHome-CM-1IDr4.js → KnowledgeHome-BFnH0NVk.js} +1 -1
  11. package/dist/renderer/assets/{Logs-DI5RFPri.js → Logs-DfSUifXc.js} +1 -1
  12. package/dist/renderer/assets/{Modal-CQpa4NPP.js → Modal-QjEGhyru.js} +1 -1
  13. package/dist/renderer/assets/{Page-BHXEAwzQ.js → Page-qdHFSw7x.js} +1 -1
  14. package/dist/renderer/assets/{ProjectDetail-Dn5elnHx.js → ProjectDetail-DS_rfvhh.js} +1 -1
  15. package/dist/renderer/assets/{ProjectList-D6yvEgb5.js → ProjectList-COtyZd7H.js} +1 -1
  16. package/dist/renderer/assets/{Select-BbkcXnXL.js → Select-BQ8mncVu.js} +1 -1
  17. package/dist/renderer/assets/{SessionChat-Vkf-7gvX.js → SessionChat-DjVnjuQy.js} +1 -1
  18. package/dist/renderer/assets/{SessionList-c5encjWd.js → SessionList-88dgGZJ8.js} +1 -1
  19. package/dist/renderer/assets/ThreadChat-BCdbTxBo.js +23 -0
  20. package/dist/renderer/assets/{Workspace-BC7hWqhP.js → Workspace-D_hzSJjX.js} +1 -1
  21. package/dist/renderer/assets/{arrow-left-I_Y1kdN9.js → arrow-left-BMpknulW.js} +1 -1
  22. package/dist/renderer/assets/{book-open-B3anUYvp.js → book-open-CiaOeQbU.js} +1 -1
  23. package/dist/renderer/assets/{check-BPNCDKgS.js → check-CgwYH4GF.js} +1 -1
  24. package/dist/renderer/assets/{chevron-down-BaxUcOIV.js → chevron-down-BzD2S1OO.js} +1 -1
  25. package/dist/renderer/assets/{circle-DJQiypFS.js → circle-BDHD7g7l.js} +1 -1
  26. package/dist/renderer/assets/{desktop-Cv51clcN.js → desktop-BiR5LPL5.js} +1 -1
  27. package/dist/renderer/assets/{funnel-DqKBtiqE.js → funnel-Bruf5FYA.js} +1 -1
  28. package/dist/renderer/assets/{heart-CmoNjvMO.js → heart-D7Mz04B0.js} +1 -1
  29. package/dist/renderer/assets/{index-DXJl2HOK.js → index-CL1e8m3U.js} +2 -2
  30. package/dist/renderer/assets/{index-BfXqhQ1Z.js → index-gZIRr4_o.js} +1 -1
  31. package/dist/renderer/assets/{pencil-CLUBszbw.js → pencil-C6gzDMse.js} +1 -1
  32. package/dist/renderer/assets/{play-l2RPZuAi.js → play-DqTXX-Pr.js} +1 -1
  33. package/dist/renderer/assets/{plug-CeUPIjRt.js → plug-ykmbeaO3.js} +1 -1
  34. package/dist/renderer/assets/{plus-BjkefS2P.js → plus-DHE60vMX.js} +1 -1
  35. package/dist/renderer/assets/projects-Bx5p10th.js +1 -0
  36. package/dist/renderer/assets/{save-D0yYt9tz.js → save-CGIvrdQI.js} +1 -1
  37. package/dist/renderer/assets/{search-B7s473Y4.js → search-D7IFAwyE.js} +1 -1
  38. package/dist/renderer/assets/{server-Dz_h8X_8.js → server-aOsirp7I.js} +1 -1
  39. package/dist/renderer/assets/{session-utils-BvNRTRXA.js → session-utils-Dxfp4ohQ.js} +1 -1
  40. package/dist/renderer/assets/{sessions-KPJsgKbQ.js → sessions-Db1XPbG2.js} +1 -1
  41. package/dist/renderer/assets/{shield-check-Wc5wfUUs.js → shield-check-ChXeQK-d.js} +1 -1
  42. package/dist/renderer/assets/{trash-2-7INdaB9w.js → trash-2-CfN-c1zw.js} +1 -1
  43. package/dist/renderer/assets/{user-CLbCgWNR.js → user-C7OHaBp4.js} +1 -1
  44. package/dist/renderer/assets/{wifi-off-BfDVPXbO.js → wifi-off-CpaJigye.js} +1 -1
  45. package/dist/renderer/index.html +1 -1
  46. package/dist-electron/electron/agent-runtime-detector.test.js +20 -0
  47. package/dist-electron/electron/lac-cli.test.js +2 -13
  48. package/dist-electron/electron/local-core-refactor.test.js +424 -64
  49. package/dist-electron/electron/workspace-task-store.test.js +118 -0
  50. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-backend.js +17 -10
  51. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-progress.js +245 -9
  52. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +24 -11
  53. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-store.js +36 -11
  54. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-transport.js +2 -0
  55. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-turn-coordinator.js +90 -7
  56. package/dist-electron/services/local-ai-core/src/channel/lark/runtime-state.js +35 -40
  57. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +43 -18
  58. package/dist-electron/services/local-ai-core/src/cli/lac.js +1 -17
  59. package/dist-electron/services/local-ai-core/src/router/workspace-router.js +2 -2
  60. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +1 -1
  61. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +31 -1
  62. package/dist-electron/services/local-ai-core/src/scheduler/local-schedule-adapter.js +4 -1
  63. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +4 -1
  64. package/dist-electron/src/pages/Threads/thread-chat-message-blocks.js +4 -114
  65. package/dist-electron/src/pages/Threads/thread-chat-model.js +14 -23
  66. package/dist-electron/src/pages/Threads/thread-chat-page-state.js +1 -1
  67. package/dist-electron/src/pages/Threads/thread-chat-permission.test.js +58 -31
  68. package/package.json +1 -1
  69. package/dist/renderer/assets/ThreadChat-DY4wzomi.js +0 -23
  70. package/dist/renderer/assets/projects-De73QY_o.js +0 -1
@@ -458,6 +458,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
458
458
  });
459
459
  (0, node_test_1.default)('ACP progress projection applies assistant and thought chunks with bridge metadata', () => {
460
460
  const currentTurn = {
461
+ runId: 'run-1',
461
462
  previewHandle: 'preview-1',
462
463
  thoughtPreviewHandle: 'thought-preview-1',
463
464
  thoughtMessageId: 'run-1-thought',
@@ -470,27 +471,33 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
470
471
  bridgeType: 'preview_start',
471
472
  previewHandle: 'preview-1',
472
473
  content: 'hello',
474
+ bridgeKind: 'assistant',
473
475
  });
474
476
  strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyAssistantMessageChunk)(currentTurn, ' world'), {
475
477
  bridgeType: 'update_message',
476
478
  previewHandle: 'preview-1',
477
479
  content: 'hello world',
480
+ bridgeKind: 'assistant',
478
481
  });
479
482
  strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyThoughtChunk)(currentTurn, '先理解'), {
480
483
  bridgeType: 'preview_start',
481
484
  previewHandle: 'thought-preview-1',
482
485
  messageId: 'run-1-thought',
483
- content: '💭 先理解',
486
+ content: '先理解',
487
+ bridgeKind: 'thought',
484
488
  });
485
489
  strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyThoughtChunk)(currentTurn, ',再修改'), {
486
490
  bridgeType: 'update_message',
487
491
  previewHandle: 'thought-preview-1',
488
492
  messageId: 'run-1-thought',
489
- content: '💭 先理解,再修改',
493
+ content: '先理解,再修改',
494
+ bridgeKind: 'thought',
490
495
  });
496
+ strict_1.default.equal(currentTurn.thoughtText, '先理解,再修改');
491
497
  });
492
498
  (0, node_test_1.default)('ACP thought chunks merge provider snapshots without duplicating text', () => {
493
499
  const currentTurn = {
500
+ runId: 'run-1',
494
501
  thoughtPreviewHandle: 'thought-preview-1',
495
502
  thoughtMessageId: 'run-1-thought',
496
503
  thoughtText: '',
@@ -500,16 +507,47 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
500
507
  bridgeType: 'preview_start',
501
508
  previewHandle: 'thought-preview-1',
502
509
  messageId: 'run-1-thought',
503
- content: '💭 The user wants to see their desktop files.',
510
+ content: 'The user wants to see their desktop files.',
511
+ bridgeKind: 'thought',
504
512
  });
505
513
  strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyThoughtChunk)(currentTurn, 'The user wants to see their desktop files. Let me show them.'), {
506
514
  bridgeType: 'update_message',
507
515
  previewHandle: 'thought-preview-1',
508
516
  messageId: 'run-1-thought',
509
- content: '💭 The user wants to see their desktop files. Let me show them.',
517
+ content: 'The user wants to see their desktop files. Let me show them.',
518
+ bridgeKind: 'thought',
510
519
  });
511
520
  strict_1.default.equal(currentTurn.thoughtText, 'The user wants to see their desktop files. Let me show them.');
512
521
  });
522
+ (0, node_test_1.default)('ACP thought segment close starts a new streaming preview for web and app', () => {
523
+ const currentTurn = {
524
+ runId: 'run-1',
525
+ thoughtPreviewHandle: 'thought-preview-1',
526
+ thoughtMessageId: 'run-1-thought-1',
527
+ thoughtText: '',
528
+ thoughtSequence: 1,
529
+ thoughtPreviewStarted: false,
530
+ };
531
+ strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyThoughtChunk)(currentTurn, 'first thought'), {
532
+ bridgeType: 'preview_start',
533
+ previewHandle: 'thought-preview-1',
534
+ messageId: 'run-1-thought-1',
535
+ content: 'first thought',
536
+ bridgeKind: 'thought',
537
+ });
538
+ (0, local_core_acp_progress_js_1.closeThoughtSegment)(currentTurn);
539
+ strict_1.default.equal(currentTurn.thoughtText, '');
540
+ strict_1.default.equal(currentTurn.thoughtPreviewStarted, false);
541
+ strict_1.default.equal(currentTurn.thoughtMessageId, 'run-1-thought-2');
542
+ strict_1.default.equal(currentTurn.thoughtPreviewHandle, 'run-1-thought-preview-2');
543
+ strict_1.default.deepEqual((0, local_core_acp_progress_js_1.applyThoughtChunk)(currentTurn, 'second thought'), {
544
+ bridgeType: 'preview_start',
545
+ previewHandle: 'run-1-thought-preview-2',
546
+ messageId: 'run-1-thought-2',
547
+ content: 'second thought',
548
+ bridgeKind: 'thought',
549
+ });
550
+ });
513
551
  (0, node_test_1.default)('ACP progress projection registers pending tool calls in order', () => {
514
552
  const currentTurn = {
515
553
  toolCallSequence: 0,
@@ -557,7 +595,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
557
595
  { content: '检查消息流' },
558
596
  { content: ' ' },
559
597
  { content: '修复持久化' },
560
- ]), '💭 检查消息流 | 修复持久化');
598
+ ]), '检查消息流 | 修复持久化');
561
599
  strict_1.default.equal((0, local_core_acp_progress_js_1.formatPlanProgress)([{ content: '' }]), '');
562
600
  });
563
601
  (0, node_test_1.default)('ACP tool call running and completed updates share one message id', () => {
@@ -863,10 +901,11 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
863
901
  strict_1.default.match(upserted[0]?.content || '', /ls -la ~\/Desktop/);
864
902
  strict_1.default.match(upserted[0]?.content || '', /completed - Desktop file list/);
865
903
  });
866
- (0, node_test_1.default)('ACP permission button rows preserve always allow actions', () => {
904
+ (0, node_test_1.default)('ACP permission button rows preserve always allow actions with structured status', () => {
905
+ const appended = [];
867
906
  const emitted = [];
868
907
  const coordinator = new local_core_acp_turn_coordinator_js_1.LocalCoreAcpTurnCoordinator({
869
- appendMessage: () => { },
908
+ appendMessage: (_threadId, _role, content, kind, _toolCall, bridgeKind, bridgeStatus) => appended.push({ content, kind, bridgeKind, bridgeStatus }),
870
909
  emitBridge: (event) => emitted.push(event),
871
910
  updateRunStatus: () => { },
872
911
  sendRaw: () => true,
@@ -905,6 +944,10 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
905
944
  ],
906
945
  },
907
946
  });
947
+ strict_1.default.equal(appended[0]?.bridgeKind, 'permission');
948
+ strict_1.default.equal(appended[0]?.bridgeStatus, 'awaiting_input');
949
+ strict_1.default.equal(emitted[0]?.bridgeKind, 'permission');
950
+ strict_1.default.equal(emitted[0]?.bridgeStatus, 'awaiting_input');
908
951
  strict_1.default.deepEqual(emitted[0]?.buttonRows, [[
909
952
  { text: 'allow', data: 'allow' },
910
953
  { text: 'allow all', data: 'allow all' },
@@ -1014,6 +1057,177 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1014
1057
  strict_1.default.equal(emitted[0]?.content, '🔧 Terminal');
1015
1058
  strict_1.default.equal(session.currentTurn.assistantText, 'done');
1016
1059
  });
1060
+ (0, node_test_1.default)('ACP tool-scoped assistant chunks stay out of final assistant buffer', () => {
1061
+ const appended = [];
1062
+ const emitted = [];
1063
+ const coordinator = new local_core_acp_turn_coordinator_js_1.LocalCoreAcpTurnCoordinator({
1064
+ appendMessage: (_threadId, _role, content, _kind, _toolCall, bridgeKind) => appended.push({ content, bridgeKind }),
1065
+ emitBridge: (event) => emitted.push(event),
1066
+ updateRunStatus: () => { },
1067
+ sendRaw: () => true,
1068
+ });
1069
+ const session = {
1070
+ threadId: 'thread-1',
1071
+ bridgeSessionKey: 'session:thread-1',
1072
+ currentRunId: 'run-1',
1073
+ currentTurn: {
1074
+ runId: 'run-1',
1075
+ replyCtx: 'run-1',
1076
+ previewHandle: 'preview-1',
1077
+ assistantText: '',
1078
+ typingStarted: true,
1079
+ previewStarted: false,
1080
+ permission: null,
1081
+ },
1082
+ loadReplayMode: false,
1083
+ schedulerJobCreatedByRun: new Map(),
1084
+ };
1085
+ coordinator.handleAgentNotification(session, {
1086
+ method: 'session/update',
1087
+ params: {
1088
+ update: {
1089
+ sessionUpdate: 'agent_message_chunk',
1090
+ _meta: {
1091
+ claudeCode: {
1092
+ parentToolUseId: 'tool-1',
1093
+ },
1094
+ },
1095
+ content: {
1096
+ type: 'text',
1097
+ text: 'tool scoped transcript',
1098
+ },
1099
+ },
1100
+ },
1101
+ });
1102
+ coordinator.handleAgentNotification(session, {
1103
+ method: 'session/update',
1104
+ params: {
1105
+ update: {
1106
+ sessionUpdate: 'agent_message_chunk',
1107
+ content: { type: 'text', text: 'final answer' },
1108
+ },
1109
+ },
1110
+ });
1111
+ strict_1.default.deepEqual(appended, [{ content: 'tool scoped transcript', bridgeKind: 'tool' }]);
1112
+ strict_1.default.equal(emitted[0]?.bridgeKind, 'tool');
1113
+ strict_1.default.equal(emitted[0]?.content, 'tool scoped transcript');
1114
+ strict_1.default.equal(session.currentTurn.assistantText, 'final answer');
1115
+ });
1116
+ (0, node_test_1.default)('ACP raw local command output assistant chunks stay out of final assistant buffer', () => {
1117
+ const appended = [];
1118
+ const coordinator = new local_core_acp_turn_coordinator_js_1.LocalCoreAcpTurnCoordinator({
1119
+ appendMessage: (_threadId, _role, content, _kind, _toolCall, bridgeKind) => appended.push({ content, bridgeKind }),
1120
+ emitBridge: () => { },
1121
+ updateRunStatus: () => { },
1122
+ sendRaw: () => true,
1123
+ });
1124
+ const session = {
1125
+ threadId: 'thread-1',
1126
+ bridgeSessionKey: 'session:thread-1',
1127
+ currentRunId: 'run-1',
1128
+ currentTurn: {
1129
+ runId: 'run-1',
1130
+ replyCtx: 'run-1',
1131
+ previewHandle: 'preview-1',
1132
+ assistantText: '',
1133
+ typingStarted: true,
1134
+ previewStarted: false,
1135
+ permission: null,
1136
+ },
1137
+ loadReplayMode: false,
1138
+ schedulerJobCreatedByRun: new Map(),
1139
+ pendingRawAssistantProgressChunks: [],
1140
+ };
1141
+ coordinator.handleAgentNotification(session, {
1142
+ method: '_claude/sdkMessage',
1143
+ params: {
1144
+ message: {
1145
+ type: 'system',
1146
+ subtype: 'local_command_output',
1147
+ content: 'raw command output',
1148
+ },
1149
+ },
1150
+ });
1151
+ coordinator.handleAgentNotification(session, {
1152
+ method: 'session/update',
1153
+ params: {
1154
+ update: {
1155
+ sessionUpdate: 'agent_message_chunk',
1156
+ content: { type: 'text', text: 'raw command output' },
1157
+ },
1158
+ },
1159
+ });
1160
+ coordinator.handleAgentNotification(session, {
1161
+ method: 'session/update',
1162
+ params: {
1163
+ update: {
1164
+ sessionUpdate: 'agent_message_chunk',
1165
+ content: { type: 'text', text: 'final answer' },
1166
+ },
1167
+ },
1168
+ });
1169
+ strict_1.default.deepEqual(appended, [{ content: 'raw command output', bridgeKind: 'tool' }]);
1170
+ strict_1.default.equal(session.currentTurn.assistantText, 'final answer');
1171
+ });
1172
+ (0, node_test_1.default)('ACP final text strips observed provider tool transcript prefix', () => {
1173
+ const currentTurn = {
1174
+ runId: 'run-1',
1175
+ replyCtx: 'run-1',
1176
+ previewHandle: 'preview-1',
1177
+ assistantText: '',
1178
+ thoughtText: '',
1179
+ typingStarted: true,
1180
+ previewStarted: false,
1181
+ thoughtPreviewStarted: false,
1182
+ permission: null,
1183
+ toolObservations: [],
1184
+ };
1185
+ (0, local_core_acp_progress_js_1.recordToolObservation)(currentTurn, {
1186
+ name: 'webReader',
1187
+ title: 'webReader',
1188
+ input: {
1189
+ url: 'https://github.com/Thysrael/Horizon',
1190
+ return_format: 'markdown',
1191
+ retain_images: false,
1192
+ },
1193
+ status: 'completed',
1194
+ outputText: JSON.stringify([{
1195
+ title: 'GitHub - Thysrael/Horizon: Your own AI-powered news radar',
1196
+ description: 'Your own AI-powered news radar. Generates daily briefings in English & Chinese.',
1197
+ url: 'https://github.com/Thysrael/Horizon',
1198
+ }]),
1199
+ });
1200
+ const polluted = [
1201
+ '**🌐 Z.ai Built-in Tool: webReader**',
1202
+ '',
1203
+ '**Input:**',
1204
+ '```json',
1205
+ '{"url":"https://github.com/Thysrael/Horizon","return_format":"markdown","retain_images":false}',
1206
+ '```',
1207
+ '',
1208
+ '*Executing on server...*',
1209
+ ' **Output:**',
1210
+ '**webReader_result_summary:** [{"text": {"title": "GitHub - Thysrael/Horizon: Your own AI-powered news radar", "description": "Your own AI-powered news radar. Generates daily briefings in English & Chinese.", "url": "https...',
1211
+ ' 已放入 `00-Inbox/Horizon.md`。这个项目和咱们的 AI 早报 skill 功能高度重叠,架构可以作为参考。',
1212
+ ].join('\n');
1213
+ strict_1.default.equal((0, local_core_acp_progress_js_1.stripObservedToolTranscriptsFromAssistantText)(polluted, currentTurn.toolObservations), '已放入 `00-Inbox/Horizon.md`。这个项目和咱们的 AI 早报 skill 功能高度重叠,架构可以作为参考。');
1214
+ strict_1.default.equal((0, local_core_acp_progress_js_1.stripObservedToolTranscriptsFromAssistantText)(polluted, []), polluted.trim());
1215
+ });
1216
+ (0, node_test_1.default)('ACP final text keeps normal answers that mention observed tool evidence', () => {
1217
+ const observations = [{
1218
+ name: 'webReader',
1219
+ input: { url: 'https://github.com/Thysrael/Horizon' },
1220
+ outputText: JSON.stringify([{
1221
+ title: 'GitHub - Thysrael/Horizon: Your own AI-powered news radar',
1222
+ url: 'https://github.com/Thysrael/Horizon',
1223
+ }]),
1224
+ }];
1225
+ const answer = [
1226
+ '我看了 https://github.com/Thysrael/Horizon,它是一个 AI 新闻雷达项目。',
1227
+ '结论:可以作为早报 skill 的参考,但不需要直接照搬。',
1228
+ ].join('\n');
1229
+ strict_1.default.equal((0, local_core_acp_progress_js_1.stripObservedToolTranscriptsFromAssistantText)(answer, observations), answer);
1230
+ });
1017
1231
  (0, node_test_1.default)('ACP plan updates are persisted and emitted as thinking progress', () => {
1018
1232
  const appended = [];
1019
1233
  const emitted = [];
@@ -1053,15 +1267,16 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1053
1267
  });
1054
1268
  strict_1.default.deepEqual(appended, [
1055
1269
  {
1056
- content: '💭 检查消息流 | 修复持久化',
1270
+ content: '检查消息流 | 修复持久化',
1057
1271
  kind: 'progress',
1058
1272
  },
1059
1273
  ]);
1060
1274
  strict_1.default.equal(emitted.length, 1);
1061
1275
  strict_1.default.equal(emitted[0]?.type, 'reply');
1276
+ strict_1.default.equal(emitted[0]?.bridgeKind, 'plan');
1062
1277
  strict_1.default.equal(emitted[0]?.content, appended[0]?.content);
1063
1278
  });
1064
- (0, node_test_1.default)('ACP thought chunks are streamed as thinking preview updates', () => {
1279
+ (0, node_test_1.default)('ACP thought chunks stream for web/app and start a fresh segment at tool boundaries', () => {
1065
1280
  const appended = [];
1066
1281
  const upserted = [];
1067
1282
  const emitted = [];
@@ -1081,9 +1296,10 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1081
1296
  replyCtx: 'run-1',
1082
1297
  previewHandle: 'preview-1',
1083
1298
  thoughtPreviewHandle: 'thought-preview-1',
1084
- thoughtMessageId: 'run-1-thought',
1299
+ thoughtMessageId: 'run-1-thought-1',
1085
1300
  assistantText: '',
1086
1301
  thoughtText: '',
1302
+ thoughtSequence: 1,
1087
1303
  typingStarted: true,
1088
1304
  previewStarted: false,
1089
1305
  thoughtPreviewStarted: false,
@@ -1101,6 +1317,16 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1101
1317
  },
1102
1318
  },
1103
1319
  });
1320
+ strict_1.default.deepEqual(appended, []);
1321
+ strict_1.default.deepEqual(upserted, [
1322
+ {
1323
+ id: 'run-1-thought-1',
1324
+ content: '先理解问题',
1325
+ kind: 'progress',
1326
+ },
1327
+ ]);
1328
+ strict_1.default.deepEqual(emitted.map((event) => event.type), ['preview_start']);
1329
+ strict_1.default.equal(emitted[0]?.content, '先理解问题');
1104
1330
  coordinator.handleAgentNotification(session, {
1105
1331
  method: 'session/update',
1106
1332
  params: {
@@ -1111,37 +1337,40 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1111
1337
  },
1112
1338
  });
1113
1339
  strict_1.default.deepEqual(appended, []);
1114
- strict_1.default.deepEqual(upserted, [
1115
- {
1116
- id: 'run-1-thought',
1117
- content: '💭 先理解问题',
1118
- kind: 'progress',
1119
- },
1120
- {
1121
- id: 'run-1-thought',
1122
- content: '💭 先理解问题,再检查代码',
1123
- kind: 'progress',
1124
- },
1125
- ]);
1340
+ strict_1.default.deepEqual(upserted.map((entry) => entry.content), ['先理解问题', '先理解问题,再检查代码']);
1126
1341
  strict_1.default.deepEqual(emitted.map((event) => event.type), ['preview_start', 'update_message']);
1127
- strict_1.default.equal(emitted[0]?.previewHandle, 'thought-preview-1');
1128
- strict_1.default.equal(emitted[0]?.content, '💭 先理解问题');
1129
- strict_1.default.equal(emitted[1]?.content, '💭 先理解问题,再检查代码');
1130
- strict_1.default.equal(session.currentTurn.thoughtText, '先理解问题,再检查代码');
1342
+ strict_1.default.equal(emitted[1]?.content, '先理解问题,再检查代码');
1343
+ coordinator.handleAgentNotification(session, {
1344
+ method: 'session/update',
1345
+ params: {
1346
+ update: {
1347
+ sessionUpdate: 'tool_call',
1348
+ title: 'webReader',
1349
+ },
1350
+ },
1351
+ });
1352
+ strict_1.default.deepEqual(appended, []);
1353
+ strict_1.default.equal(session.currentTurn.thoughtText, '');
1354
+ strict_1.default.equal(session.currentTurn.thoughtMessageId, 'run-1-thought-2');
1355
+ strict_1.default.equal(session.currentTurn.thoughtPreviewHandle, 'run-1-thought-preview-2');
1131
1356
  });
1132
- (0, node_test_1.default)('ACP store upserts thought progress as one durable message', () => {
1357
+ (0, node_test_1.default)('ACP store preserves structured progress metadata', () => {
1133
1358
  const userDataPath = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'agentdock-thought-store-'));
1134
1359
  const store = new local_core_acp_store_js_1.LocalCoreAcpStore(userDataPath);
1135
1360
  try {
1136
1361
  const thread = store.createThread('project-1', 'Thread');
1137
- store.upsertMessage(thread.id, 'run-1-thought', 'assistant', '💭 先理解问题', 'progress');
1138
- store.upsertMessage(thread.id, 'run-1-thought', 'assistant', '💭 先理解问题,再检查代码', 'progress');
1362
+ store.upsertMessage(thread.id, 'run-1-thought', 'assistant', '先理解问题', 'progress', undefined, 'thought');
1363
+ store.upsertMessage(thread.id, 'run-1-thought', 'assistant', '先理解问题,再检查代码', 'progress', undefined, 'thought');
1364
+ store.appendMessage(thread.id, 'assistant', '等待确认', 'progress', undefined, 'permission', 'awaiting_input');
1139
1365
  const detail = store.getThread(thread.id, []);
1140
- strict_1.default.equal(detail.messages.length, 1);
1366
+ strict_1.default.equal(detail.messages.length, 2);
1141
1367
  strict_1.default.equal(detail.messages[0]?.id, 'run-1-thought');
1142
1368
  strict_1.default.equal(detail.messages[0]?.kind, 'progress');
1143
- strict_1.default.equal(detail.messages[0]?.content, '💭 先理解问题,再检查代码');
1144
- strict_1.default.equal(detail.historyCount, 1);
1369
+ strict_1.default.equal(detail.messages[0]?.bridgeKind, 'thought');
1370
+ strict_1.default.equal(detail.messages[0]?.content, '先理解问题,再检查代码');
1371
+ strict_1.default.equal(detail.messages[1]?.bridgeKind, 'permission');
1372
+ strict_1.default.equal(detail.messages[1]?.bridgeStatus, 'awaiting_input');
1373
+ strict_1.default.equal(detail.historyCount, 2);
1145
1374
  }
1146
1375
  finally {
1147
1376
  store.close();
@@ -1240,14 +1469,16 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1240
1469
  sessionKey: 'session:thread-1',
1241
1470
  replyCtx: 'run-1',
1242
1471
  previewHandle: 'thought-preview-1',
1243
- content: '💭 先理解问题',
1472
+ bridgeKind: 'thought',
1473
+ content: '先理解问题',
1244
1474
  });
1245
1475
  await gateway.onBridgeEvent({
1246
1476
  type: 'update_message',
1247
1477
  sessionKey: 'session:thread-1',
1248
1478
  replyCtx: 'run-1',
1249
1479
  previewHandle: 'thought-preview-1',
1250
- content: '💭 先理解问题,再检查代码',
1480
+ bridgeKind: 'thought',
1481
+ content: '先理解问题,再检查代码',
1251
1482
  });
1252
1483
  await gateway.onBridgeEvent({
1253
1484
  type: 'reply',
@@ -1256,7 +1487,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1256
1487
  content: '最终回答',
1257
1488
  });
1258
1489
  strict_1.default.equal(createdCards.length, 2);
1259
- strict_1.default.equal(createdCards[0]?.text, '💭 先理解问题,再检查代码');
1490
+ strict_1.default.equal(createdCards[0]?.text, '先理解问题,再检查代码');
1260
1491
  strict_1.default.equal(createdCards[1]?.text, '最终回答');
1261
1492
  strict_1.default.equal(patchedCards.length, 0);
1262
1493
  strict_1.default.deepEqual(storedMessageIds, ['lark-msg-2']);
@@ -1336,6 +1567,77 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1336
1567
  strict_1.default.deepEqual(patchedCards, []);
1337
1568
  strict_1.default.deepEqual(storedMessageIds, ['lark-msg-1']);
1338
1569
  });
1570
+ (0, node_test_1.default)('lark bridge creates final replies without patching prior final cards', async () => {
1571
+ const createdCards = [];
1572
+ const patchedCards = [];
1573
+ const client = {
1574
+ im: {
1575
+ message: {
1576
+ create: async (request) => {
1577
+ const messageId = `lark-msg-${createdCards.length + 1}`;
1578
+ const card = JSON.parse(String(request.data.content || '{}'));
1579
+ createdCards.push({
1580
+ messageId,
1581
+ text: String(card.elements?.[0]?.content || ''),
1582
+ });
1583
+ return { data: { message_id: messageId } };
1584
+ },
1585
+ patch: async (request) => {
1586
+ const card = JSON.parse(String(request.data.content || '{}'));
1587
+ patchedCards.push({
1588
+ messageId: String(request.path.message_id || ''),
1589
+ text: String(card.elements?.[0]?.content || ''),
1590
+ });
1591
+ },
1592
+ },
1593
+ },
1594
+ };
1595
+ const gateway = new local_core_lark_gateway_js_1.LocalCoreLarkGateway({
1596
+ store: {
1597
+ getPlatformThreadBinding: () => ({
1598
+ workspace_id: 'default',
1599
+ platform: 'lark',
1600
+ chat_id: 'chat-1',
1601
+ platform_user_id: 'user-1',
1602
+ thread_id: 'thread-1',
1603
+ last_platform_message_id: null,
1604
+ }),
1605
+ updatePlatformThreadMessageId: () => { },
1606
+ },
1607
+ readConfig: async () => null,
1608
+ getWorkspaceRouter: () => ({}),
1609
+ eventBus: { emit: () => { }, on: () => () => { } },
1610
+ });
1611
+ const internals = gateway;
1612
+ internals.runtime.set('default', {
1613
+ workspaceId: 'default',
1614
+ enabled: true,
1615
+ status: 'running',
1616
+ connected: true,
1617
+ appId: 'app-1',
1618
+ client,
1619
+ });
1620
+ internals.threadRouting.set('session:thread-1', {
1621
+ workspaceId: 'default',
1622
+ platformUserId: 'user-1',
1623
+ chatId: 'chat-1',
1624
+ threadId: 'thread-1',
1625
+ });
1626
+ await gateway.onBridgeEvent({
1627
+ type: 'reply',
1628
+ sessionKey: 'session:thread-1',
1629
+ replyCtx: 'run-1',
1630
+ content: 'first final',
1631
+ });
1632
+ await gateway.onBridgeEvent({
1633
+ type: 'reply',
1634
+ sessionKey: 'session:thread-1',
1635
+ replyCtx: 'run-2',
1636
+ content: 'second final',
1637
+ });
1638
+ strict_1.default.deepEqual(createdCards.map((card) => card.text), ['first final', 'second final']);
1639
+ strict_1.default.deepEqual(patchedCards, []);
1640
+ });
1339
1641
  (0, node_test_1.default)('lark bridge sends tool and final as separate cards without patching tool progress', async () => {
1340
1642
  const createdCards = [];
1341
1643
  const patchedCards = [];
@@ -1406,7 +1708,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1406
1708
  sessionKey: 'session:thread-1',
1407
1709
  replyCtx: 'run-1',
1408
1710
  messageId: 'tool-1',
1409
- content: '🔧 bash: completed - Sent file CLAUDE.md to chat-1: msg-file-1',
1711
+ bridgeKind: 'tool',
1712
+ content: 'bash completed',
1713
+ toolCall: {
1714
+ id: 'tool-1',
1715
+ name: 'bash',
1716
+ status: 'completed',
1717
+ output: 'Sent file CLAUDE.md to chat-1: msg-file-1',
1718
+ },
1410
1719
  });
1411
1720
  await gateway.onBridgeEvent({
1412
1721
  type: 'reply',
@@ -1485,25 +1794,30 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1485
1794
  sessionKey: 'session:thread-1',
1486
1795
  replyCtx: 'run-1',
1487
1796
  previewHandle: 'thought-preview-1',
1488
- content: '💭 先理解',
1797
+ bridgeKind: 'thought',
1798
+ content: '先理解',
1489
1799
  });
1490
1800
  await gateway.onBridgeEvent({
1491
1801
  type: 'update_message',
1492
1802
  sessionKey: 'session:thread-1',
1493
1803
  replyCtx: 'run-1',
1494
1804
  previewHandle: 'thought-preview-1',
1495
- content: '💭 先理解用户需求',
1805
+ bridgeKind: 'thought',
1806
+ content: '先理解用户需求',
1496
1807
  });
1497
1808
  await gateway.onBridgeEvent({
1498
1809
  type: 'reply',
1499
1810
  sessionKey: 'session:thread-1',
1500
1811
  replyCtx: 'run-1',
1501
1812
  messageId: 'run-1-tool-1',
1502
- content: '🔧 Terminal: config - running',
1813
+ bridgeKind: 'tool',
1814
+ content: 'Terminal running',
1503
1815
  toolCall: {
1504
1816
  id: 'call-1',
1505
1817
  name: 'Terminal',
1818
+ status: 'running',
1506
1819
  input: { command: 'uname -a', description: 'Get system info' },
1820
+ output: '',
1507
1821
  },
1508
1822
  });
1509
1823
  await gateway.onBridgeEvent({
@@ -1511,11 +1825,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1511
1825
  sessionKey: 'session:thread-1',
1512
1826
  replyCtx: 'run-1',
1513
1827
  messageId: 'run-1-tool-1',
1514
- content: '🔧 Terminal: config - completed - Linux',
1828
+ bridgeKind: 'tool',
1829
+ content: 'Terminal completed',
1515
1830
  toolCall: {
1516
1831
  id: 'call-1',
1517
1832
  name: 'Terminal',
1833
+ status: 'completed',
1518
1834
  input: { command: 'uname -a', description: 'Get system info' },
1835
+ output: 'Linux',
1519
1836
  },
1520
1837
  });
1521
1838
  await gateway.onBridgeEvent({
@@ -1523,7 +1840,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1523
1840
  sessionKey: 'session:thread-1',
1524
1841
  replyCtx: 'run-1',
1525
1842
  previewHandle: 'thought-preview-1',
1526
- content: '💭 看到了 Linux',
1843
+ bridgeKind: 'thought',
1844
+ content: '看到了 Linux',
1527
1845
  });
1528
1846
  await gateway.onBridgeEvent({
1529
1847
  type: 'reply',
@@ -1532,9 +1850,9 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1532
1850
  content: '最终回答',
1533
1851
  });
1534
1852
  strict_1.default.deepEqual(createdCards.map((card) => card.text), [
1535
- '💭 先理解用户需求',
1853
+ '先理解用户需求',
1536
1854
  '🔧 Terminal\n\n参数:`{"command":"uname -a","description":"Get system info"}`',
1537
- '💭 看到了 Linux',
1855
+ '看到了 Linux',
1538
1856
  '最终回答',
1539
1857
  ]);
1540
1858
  strict_1.default.deepEqual(patchedCards, []);
@@ -1606,28 +1924,31 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1606
1924
  sessionKey: 'session:thread-1',
1607
1925
  replyCtx: 'run-1',
1608
1926
  previewHandle: 'thought-preview-1',
1609
- content: '💭 The user',
1927
+ bridgeKind: 'thought',
1928
+ content: 'The user',
1610
1929
  });
1611
1930
  await gateway.onBridgeEvent({
1612
1931
  type: 'update_message',
1613
1932
  sessionKey: 'session:thread-1',
1614
1933
  replyCtx: 'run-1',
1615
1934
  previewHandle: 'thought-preview-1',
1616
- content: '💭 The user sent a short casual message.',
1935
+ bridgeKind: 'thought',
1936
+ content: 'The user sent a short casual message.',
1617
1937
  });
1618
1938
  await gateway.onBridgeEvent({
1619
1939
  type: 'update_message',
1620
1940
  sessionKey: 'session:thread-1',
1621
1941
  replyCtx: 'run-1',
1622
1942
  previewHandle: 'thought-preview-1',
1623
- content: '💭 The user sent a short casual message. I should reply briefly.',
1943
+ bridgeKind: 'thought',
1944
+ content: 'The user sent a short casual message. I should reply briefly.',
1624
1945
  });
1625
1946
  await gateway.onBridgeEvent({
1626
1947
  type: 'typing_stop',
1627
1948
  sessionKey: 'session:thread-1',
1628
1949
  replyCtx: 'run-1',
1629
1950
  });
1630
- strict_1.default.deepEqual(createdCards.map((card) => card.text), ['💭 The user sent a short casual message. I should reply briefly.']);
1951
+ strict_1.default.deepEqual(createdCards.map((card) => card.text), ['The user sent a short casual message. I should reply briefly.']);
1631
1952
  strict_1.default.deepEqual(patchedCards.map((card) => card.text), []);
1632
1953
  strict_1.default.ok(!createdCards.some((card) => /处理中|正在思考/.test(card.text)));
1633
1954
  });
@@ -1905,7 +2226,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1905
2226
  sessionKey: 'session:thread-1',
1906
2227
  replyCtx: 'run-1',
1907
2228
  messageId: 'tool-1',
1908
- content: '🔧 Terminal',
2229
+ bridgeKind: 'tool',
2230
+ content: 'Terminal running',
1909
2231
  toolCall: {
1910
2232
  id: 'tool-1',
1911
2233
  name: 'Terminal',
@@ -1919,7 +2241,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
1919
2241
  sessionKey: 'session:thread-1',
1920
2242
  replyCtx: 'run-1',
1921
2243
  messageId: 'tool-1',
1922
- content: '🔧 Terminal: ls ~/Desktop - completed - secret terminal output',
2244
+ bridgeKind: 'tool',
2245
+ content: 'Terminal completed',
1923
2246
  toolCall: {
1924
2247
  id: 'tool-1',
1925
2248
  name: 'Terminal',
@@ -2590,7 +2913,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2590
2913
  sessionKey: 'session-1',
2591
2914
  replyCtx: 'run-1',
2592
2915
  previewHandle: 'tool-1',
2593
- content: '🔧 bash: Tool update - pending',
2916
+ bridgeKind: 'tool',
2917
+ content: 'bash pending',
2918
+ toolCall: {
2919
+ id: 'tool-1',
2920
+ name: 'bash',
2921
+ status: 'pending',
2922
+ output: '',
2923
+ },
2594
2924
  });
2595
2925
  strict_1.default.equal(rendered.text, '');
2596
2926
  strict_1.default.equal(rendered.key, 'noop');
@@ -2599,7 +2929,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2599
2929
  sessionKey: 'session-1',
2600
2930
  replyCtx: 'run-1',
2601
2931
  previewHandle: 'tool-1',
2602
- content: '🔧 bash: Tool update - completed - verbose output',
2932
+ bridgeKind: 'tool',
2933
+ content: 'bash completed',
2934
+ toolCall: {
2935
+ id: 'tool-1',
2936
+ name: 'bash: Tool update',
2937
+ status: 'completed',
2938
+ output: 'verbose output',
2939
+ },
2603
2940
  });
2604
2941
  strict_1.default.equal(completed.text, '🔧 bash: Tool update');
2605
2942
  });
@@ -2773,8 +3110,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2773
3110
  getRun: () => ({ status: 'completed' }),
2774
3111
  },
2775
3112
  workspaceRouter: {
2776
- sendThreadMessage: async (threadId, prompt) => {
2777
- calls.push(`send:${threadId}:${prompt}`);
3113
+ sendThreadMessage: async (threadId, prompt, options) => {
3114
+ calls.push(`send:${threadId}:${prompt}:${options?.permissionMode || ''}`);
2778
3115
  return { runId: 'run-1' };
2779
3116
  },
2780
3117
  getThread: async (threadId) => ({
@@ -2802,7 +3139,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2802
3139
  }, 1000);
2803
3140
  strict_1.default.deepEqual(calls, [
2804
3141
  'before:thread-1',
2805
- 'send:thread-1:ping',
3142
+ 'send:thread-1:ping:bypassPermissions',
2806
3143
  'after:thread-1',
2807
3144
  ]);
2808
3145
  strict_1.default.equal(result.replyText, 'done');
@@ -2837,8 +3174,8 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2837
3174
  calls.push(`create:${workspaceId}:${title}`);
2838
3175
  return { id: 'thread-local-1', title };
2839
3176
  },
2840
- sendThreadMessage: async (threadId, prompt) => {
2841
- calls.push(`send:${threadId}:${prompt}`);
3177
+ sendThreadMessage: async (threadId, prompt, options) => {
3178
+ calls.push(`send:${threadId}:${prompt}:${options?.permissionMode || ''}`);
2842
3179
  return { runId: 'run-local-1' };
2843
3180
  },
2844
3181
  getThread: async (threadId) => ({
@@ -2853,7 +3190,7 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
2853
3190
  strict_1.default.deepEqual(calls, [
2854
3191
  'list:知识库',
2855
3192
  'create:知识库:[Scheduled] local ping',
2856
- 'send:thread-local-1:ping local',
3193
+ 'send:thread-local-1:ping local:bypassPermissions',
2857
3194
  ]);
2858
3195
  strict_1.default.equal(result.threadId, 'thread-local-1');
2859
3196
  strict_1.default.equal(result.runId, 'run-local-1');
@@ -3635,14 +3972,24 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
3635
3972
  threadId: 'thread-1',
3636
3973
  });
3637
3974
  try {
3638
- await gateway.onBridgeEvent({ type: 'reply', sessionKey: 'session:thread-1', content: '🔧 list desktop' });
3975
+ await gateway.onBridgeEvent({
3976
+ type: 'reply',
3977
+ sessionKey: 'session:thread-1',
3978
+ bridgeKind: 'tool',
3979
+ content: 'list desktop',
3980
+ toolCall: {
3981
+ name: 'list desktop',
3982
+ status: 'running',
3983
+ output: '',
3984
+ },
3985
+ });
3639
3986
  await gateway.onBridgeEvent({ type: 'reply', sessionKey: 'session:thread-1', content: 'final reply' });
3640
3987
  strict_1.default.equal(sentBodies.length, 2);
3641
3988
  strict_1.default.equal(sentBodies[0]?.msg?.message_state, 2);
3642
3989
  strict_1.default.equal(sentBodies[1]?.msg?.message_state, 2);
3643
3990
  strict_1.default.equal(sentBodies[0]?.msg?.context_token, 'ctx-1');
3644
3991
  strict_1.default.equal(sentBodies[1]?.msg?.context_token, 'ctx-1');
3645
- strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '🔧 list desktop');
3992
+ strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '**处理中**\n• list desktop - running');
3646
3993
  strict_1.default.equal(sentBodies[1]?.msg?.item_list?.[0]?.text_item?.text, 'final reply');
3647
3994
  }
3648
3995
  finally {
@@ -3700,7 +4047,13 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
3700
4047
  await gateway.onBridgeEvent({
3701
4048
  type: 'reply',
3702
4049
  sessionKey: 'session:thread-1',
3703
- content: '🔧 Tool update - completed - /Users/mochuxian/Desktop has many files and this result should not be sent',
4050
+ bridgeKind: 'tool',
4051
+ content: 'Tool update completed',
4052
+ toolCall: {
4053
+ name: 'Tool update',
4054
+ status: 'completed',
4055
+ output: '/Users/mochuxian/Desktop has many files and this result should not be sent',
4056
+ },
3704
4057
  });
3705
4058
  await gateway.onBridgeEvent({ type: 'reply', sessionKey: 'session:thread-1', content: 'final reply' });
3706
4059
  strict_1.default.equal(sentBodies.length, 1);
@@ -3762,10 +4115,16 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
3762
4115
  await gateway.onBridgeEvent({
3763
4116
  type: 'reply',
3764
4117
  sessionKey: 'session:thread-1',
3765
- content: '🔧 Tool update - failed - stack trace and command output should not be sent',
4118
+ bridgeKind: 'tool',
4119
+ content: 'Tool update failed',
4120
+ toolCall: {
4121
+ name: 'Tool update',
4122
+ status: 'failed',
4123
+ output: 'stack trace and command output should not be sent',
4124
+ },
3766
4125
  });
3767
4126
  strict_1.default.equal(sentBodies.length, 1);
3768
- strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '🔧 Tool update - failed');
4127
+ strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '**处理中**\n• Tool update - failed');
3769
4128
  }
3770
4129
  finally {
3771
4130
  globalThis.fetch = originalFetch;
@@ -3823,13 +4182,14 @@ const server_routes_js_1 = require("../services/local-ai-core/src/runtime/server
3823
4182
  await gateway.onBridgeEvent({
3824
4183
  type: 'reply',
3825
4184
  sessionKey: 'session:thread-1',
4185
+ bridgeKind: 'status',
3826
4186
  content: `🔧 tool ${index}`,
3827
4187
  });
3828
4188
  }
3829
4189
  await gateway.onBridgeEvent({ type: 'reply', sessionKey: 'session:thread-1', content: 'final reply' });
3830
4190
  strict_1.default.equal(sentBodies.length, 10);
3831
- strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '🔧 tool 1');
3832
- strict_1.default.equal(sentBodies[8]?.msg?.item_list?.[0]?.text_item?.text, '🔧 tool 9');
4191
+ strict_1.default.equal(sentBodies[0]?.msg?.item_list?.[0]?.text_item?.text, '**处理中**\n• 🔧 tool 1');
4192
+ strict_1.default.match(sentBodies[8]?.msg?.item_list?.[0]?.text_item?.text, /🔧 tool 9/);
3833
4193
  strict_1.default.doesNotMatch(sentBodies.map((body) => body?.msg?.item_list?.[0]?.text_item?.text || '').join('\n'), /🔧 tool 10|🔧 tool 11|🔧 tool 12/);
3834
4194
  strict_1.default.match(sentBodies[9]?.msg?.item_list?.[0]?.text_item?.text, /已省略 3 条过程消息/);
3835
4195
  strict_1.default.match(sentBodies[9]?.msg?.item_list?.[0]?.text_item?.text, /final reply/);