@bolloon/bolloon-agent 0.5.0 → 0.5.1

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 (106) hide show
  1. package/dist/agents/execution-supervisor.js +87 -5
  2. package/dist/agents/model-policy.js +651 -0
  3. package/dist/agents/pi-sdk-tools.js +84 -33
  4. package/dist/agents/pi-sdk.js +83 -23
  5. package/dist/agents/run-store.js +53 -0
  6. package/dist/agents/task/task-runner.js +8 -1
  7. package/dist/agents/workflow-pivot-loop.js +19 -12
  8. package/dist/cli/clipboard.js +65 -0
  9. package/dist/cli/ink-app.js +145 -17
  10. package/dist/cli/log-gate.js +386 -0
  11. package/dist/cli/mention-data.js +2 -0
  12. package/dist/cli/model-selector.js +538 -0
  13. package/dist/cli/reply-hygiene.js +54 -0
  14. package/dist/cli/setup-wizard.js +686 -69
  15. package/dist/cli/startup-notice.js +160 -0
  16. package/dist/cli/stores.js +22 -1
  17. package/dist/cli/theme.js +49 -0
  18. package/dist/cli/tui-select.js +970 -0
  19. package/dist/cli-entry.js +125 -18
  20. package/dist/electron-build/agents/execution-supervisor.js +86 -4
  21. package/dist/electron-build/agents/execution-supervisor.js.map +1 -1
  22. package/dist/electron-build/agents/goal-store.js.map +1 -1
  23. package/dist/electron-build/agents/model-policy.js +706 -0
  24. package/dist/electron-build/agents/model-policy.js.map +1 -0
  25. package/dist/electron-build/agents/pi-sdk-tools.js +84 -33
  26. package/dist/electron-build/agents/pi-sdk-tools.js.map +1 -1
  27. package/dist/electron-build/agents/pi-sdk-types.js.map +1 -1
  28. package/dist/electron-build/agents/pi-sdk.js +83 -23
  29. package/dist/electron-build/agents/pi-sdk.js.map +1 -1
  30. package/dist/electron-build/agents/run-store.js +55 -1
  31. package/dist/electron-build/agents/run-store.js.map +1 -1
  32. package/dist/electron-build/agents/task/task-runner.js +8 -1
  33. package/dist/electron-build/agents/task/task-runner.js.map +1 -1
  34. package/dist/electron-build/agents/workflow-pivot-loop.js +19 -12
  35. package/dist/electron-build/agents/workflow-pivot-loop.js.map +1 -1
  36. package/dist/electron-build/llm/config-store.js +146 -6
  37. package/dist/electron-build/llm/config-store.js.map +1 -1
  38. package/dist/electron-build/llm/connection-probe.js +764 -0
  39. package/dist/electron-build/llm/connection-probe.js.map +1 -0
  40. package/dist/electron-build/llm/custom-provider-store.js +272 -0
  41. package/dist/electron-build/llm/custom-provider-store.js.map +1 -0
  42. package/dist/electron-build/llm/data/provider-catalog-baked.js +23 -0
  43. package/dist/electron-build/llm/data/provider-catalog-baked.js.map +1 -0
  44. package/dist/electron-build/llm/model-catalog.js +778 -0
  45. package/dist/electron-build/llm/model-catalog.js.map +1 -0
  46. package/dist/electron-build/llm/model-discovery.js +1202 -0
  47. package/dist/electron-build/llm/model-discovery.js.map +1 -0
  48. package/dist/electron-build/llm/model-selection.js +1315 -0
  49. package/dist/electron-build/llm/model-selection.js.map +1 -0
  50. package/dist/electron-build/llm/pi-ai.js +70 -11
  51. package/dist/electron-build/llm/pi-ai.js.map +1 -1
  52. package/dist/electron-build/llm/provider-catalog.js +969 -0
  53. package/dist/electron-build/llm/provider-catalog.js.map +1 -0
  54. package/dist/electron-build/llm/provider-registry.js +950 -0
  55. package/dist/electron-build/llm/provider-registry.js.map +1 -0
  56. package/dist/electron-build/llm/tool-name.js +266 -0
  57. package/dist/electron-build/llm/tool-name.js.map +1 -0
  58. package/dist/electron-build/utils/dual-source-facts.js +236 -0
  59. package/dist/electron-build/utils/dual-source-facts.js.map +1 -0
  60. package/dist/electron-build/utils/dual-source.js +32 -156
  61. package/dist/electron-build/utils/dual-source.js.map +1 -1
  62. package/dist/electron-build/utils/update-manager.js +22 -72
  63. package/dist/electron-build/utils/update-manager.js.map +1 -1
  64. package/dist/electron-build/utils/update-state.js +2 -19
  65. package/dist/electron-build/utils/update-state.js.map +1 -1
  66. package/dist/electron-build/utils/version-identity.js +193 -0
  67. package/dist/electron-build/utils/version-identity.js.map +1 -0
  68. package/dist/electron-build/utils/version-info.js +47 -101
  69. package/dist/electron-build/utils/version-info.js.map +1 -1
  70. package/dist/index.js +282 -96
  71. package/dist/ios/bolloon-web.json +10 -0
  72. package/dist/ios/mobile-contacts.js +44 -11
  73. package/dist/ios/mobile-core.js +1723 -84
  74. package/dist/ios/mobile-tasks.js +339 -0
  75. package/dist/ios/mobile-update.js +1442 -0
  76. package/dist/ios/mobile.js +308 -35
  77. package/dist/ios/routes-llm-config.js +344 -52
  78. package/dist/ios/routes-mobile-tasks.js +353 -0
  79. package/dist/ios/server.js +163 -4
  80. package/dist/ios/sw.js +1 -1
  81. package/dist/llm/config-store.js +146 -6
  82. package/dist/llm/connection-probe.js +744 -0
  83. package/dist/llm/custom-provider-store.js +224 -0
  84. package/dist/llm/data/provider-catalog-baked.js +19 -0
  85. package/dist/llm/model-catalog.js +717 -0
  86. package/dist/llm/model-discovery.js +1137 -0
  87. package/dist/llm/model-selection.js +1241 -0
  88. package/dist/llm/pi-ai.js +70 -11
  89. package/dist/llm/provider-catalog.js +898 -0
  90. package/dist/llm/provider-registry.js +917 -0
  91. package/dist/llm/tool-name.js +220 -0
  92. package/dist/setup/onboard.js +34 -8
  93. package/dist/utils/dual-source-facts.js +223 -0
  94. package/dist/utils/dual-source.js +12 -141
  95. package/dist/utils/update-manager.js +16 -59
  96. package/dist/utils/update-state.js +6 -18
  97. package/dist/utils/version-identity.js +176 -0
  98. package/dist/utils/version-info.js +9 -78
  99. package/dist/web/bolloon-web.json +10 -0
  100. package/dist/web/mobile-core.js +1721 -84
  101. package/dist/web/mobile-update.js +1442 -0
  102. package/dist/web/mobile.js +308 -35
  103. package/dist/web/routes-llm-config.js +344 -52
  104. package/dist/web/sw.js +1 -1
  105. package/package.json +1 -1
  106. package/scripts/build-web.ts +36 -0
@@ -1 +1 @@
1
- {"version":3,"file":"pi-sdk-types.js","sourceRoot":"","sources":["../../../src/agents/pi-sdk-types.ts"],"names":[],"mappings":";;;AA4Ha,QAAA,gBAAgB,GAAG;;;;;;;;;;;;CAY/B,CAAC"}
1
+ {"version":3,"file":"pi-sdk-types.js","sourceRoot":"","sources":["../../../src/agents/pi-sdk-types.ts"],"names":[],"mappings":";;;AAwIa,QAAA,gBAAgB,GAAG;;;;;;;;;;;;CAY/B,CAAC"}
@@ -67,6 +67,9 @@ const workflow_pivot_loop_js_1 = require("./workflow-pivot-loop.js");
67
67
  const p2p_document_tools_js_1 = require("./p2p-document-tools.js");
68
68
  const run_store_js_1 = require("./run-store.js");
69
69
  const goal_store_js_1 = require("./goal-store.js");
70
+ const model_selection_js_1 = require("../llm/model-selection.js");
71
+ // 2026-09-26: 工具名出网净化 (pi-ai.ts 唯一边界) + 回程派发还原 (原名 ↔ API 名)
72
+ const tool_name_js_1 = require("../llm/tool-name.js");
70
73
  const pi_harness_js_1 = require("./pi-harness.js");
71
74
  const heartbeat_js_1 = require("../social/heartbeat.js");
72
75
  const constraint_runtime_2 = require("@bolloon/constraint-runtime");
@@ -688,6 +691,18 @@ class PiAgentSession {
688
691
  return false;
689
692
  }
690
693
  }
694
+ /**
695
+ * 2026-09-26: 这个 Run 开始那一刻**真实生效**的模型配置快照, 由 startRun 落进 Run 记录。
696
+ * 拿不到 (配置读不出来) 就返回 undefined —— 宁可这个字段缺, 也不编一个假的进去。
697
+ */
698
+ async runModelSnapshot() {
699
+ try {
700
+ return await (0, model_selection_js_1.captureRunModelConfig)();
701
+ }
702
+ catch {
703
+ return undefined;
704
+ }
705
+ }
691
706
  /** 2026-08-07: prompt 出口统一上报 token 用量到 ContextManager (fallback/pivot/react 全路径覆盖) —
692
707
  * 之前只有 runReActLoop 迭代内上报, chitchat/fallback/pivot 路径状态栏恒 0 */
693
708
  reportUsageToContextManager() {
@@ -792,6 +807,7 @@ class PiAgentSession {
792
807
  goalId: boundGoalId,
793
808
  channelId: this.currentChannelId || undefined,
794
809
  agentId: this.currentAgentId || undefined,
810
+ modelConfig: await this.runModelSnapshot(),
795
811
  });
796
812
  this.lastRunId = rec.runId;
797
813
  await (0, goal_store_js_1.attachRun)(boundGoalId, rec.runId).catch(() => null);
@@ -1124,7 +1140,7 @@ class PiAgentSession {
1124
1140
  const backoffMs = 1000 * Math.pow(2, attempt - 1); // 1s, 2s, 4s
1125
1141
  console.log(`[PiAgent] loop 自动重试 ${attempt}/${MAX_LOOP_RETRIES}, 等待 ${backoffMs}ms`);
1126
1142
  if (onStream) {
1127
- onStream({ type: 'status', content: `↻ 自动重试 loop ${attempt}/${MAX_LOOP_RETRIES} (${(backoffMs / 1000).toFixed(0)}s 后)`, tool: 'system' });
1143
+ onStream({ type: 'status', internal: true, content: `↻ 自动重试 loop ${attempt}/${MAX_LOOP_RETRIES} (${(backoffMs / 1000).toFixed(0)}s 后)`, tool: 'system' });
1128
1144
  }
1129
1145
  // 中途 abort 也要响应
1130
1146
  await new Promise((resolve, reject) => {
@@ -1424,17 +1440,51 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1424
1440
  * 2026-09-16 (M2): 从 checkpoint 恢复一次运行 —— **不是**重发原 prompt。
1425
1441
  * 语义: prepareResume (校验状态 + 读 checkpoint + 记 recovery + 落 recovering) → 用恢复指令
1426
1442
  * 驱动同一个 runId 继续 (历史保留), 非幂等动作由重放守卫挡住。
1443
+ *
1444
+ * 2026-09-26: 恢复前**反查一次模型配置**。Run 记录里存的 `modelConfig` 快照此前只被写进
1445
+ * 快照和回显, 没人拿它核对现状 —— 于是"快照记的是 A, 现在盘上生效的是 B"这种情况会被
1446
+ * 静默继续下去 (长任务的历史执行链就说不清了)。现在: 漂了就 `console.warn` 说清哪几个字段漂了,
1447
+ * 并把结论放进返回值 (`modelDrift`) 让调用方能上报; 一致时也有一句明确结论。
1448
+ * 判断失败 (读不到 Run 等) 不阻塞恢复。
1427
1449
  */
1428
1450
  async resumeRun(runId) {
1451
+ let modelDrift;
1452
+ let modelApplied;
1453
+ try {
1454
+ const { detectRunConfigDrift } = await Promise.resolve().then(() => __importStar(require('../llm/model-selection.js')));
1455
+ modelDrift = (await detectRunConfigDrift(runId)) || undefined;
1456
+ if (modelDrift?.drifted) {
1457
+ console.warn('[pi-sdk] 恢复时模型配置已偏离 Run 快照:', modelDrift.message);
1458
+ }
1459
+ else if (modelDrift) {
1460
+ console.log('[pi-sdk] 恢复前核对:', modelDrift.message);
1461
+ }
1462
+ }
1463
+ catch { /* 核对本身失败不阻塞恢复 */ }
1429
1464
  const prep = await (0, run_store_js_1.prepareResume)(runId);
1430
1465
  if (!prep.ok || !prep.plan)
1431
- return { ok: false, reason: prep.reason };
1466
+ return { ok: false, reason: prep.reason, ...(modelDrift ? { modelDrift } : {}) };
1467
+ // 2026-09-26 (P6 × P7): 恢复一个在跑的 Run, 用的是**它自己那份快照**, 不是盘上现在的全局默认 ——
1468
+ // 否则这次恢复就是"带着漂移继续跑", 之后再存快照会把漂移固化成历史。
1469
+ // 只在"漂了"或"核对不了"时重装 (一致时运行时本来就是对的, 重装是白跑一趟)。
1470
+ // 装配只有一处实现: `applyRunModelConfigToRuntime` → `installRuntime` (这里不自己 initMinimax)。
1471
+ if (modelDrift && (modelDrift.drifted || !modelDrift.verified)) {
1472
+ try {
1473
+ const { applyRunModelConfigToRuntime } = await Promise.resolve().then(() => __importStar(require('../llm/model-selection.js')));
1474
+ modelApplied = await applyRunModelConfigToRuntime(modelDrift.snapshot);
1475
+ console.log(`[pi-sdk] 已按 Run 快照装配运行时: ${modelApplied.provider}/${modelApplied.model} (configHash ${String(modelApplied.configHash).slice(0, 12)})`);
1476
+ }
1477
+ catch (e) {
1478
+ // 装配失败不阻塞恢复 (如实说; 调用方可以从返回值里看出没装成)
1479
+ console.warn('[pi-sdk] 按 Run 快照装配运行时失败, 保持当前运行时:', String(e?.message || e).slice(0, 160));
1480
+ }
1481
+ }
1432
1482
  this.resumeRunId = runId;
1433
1483
  this.resumePlan = prep.plan;
1434
1484
  this.currentGoalId = prep.plan.goalId || this.currentGoalId;
1435
1485
  try {
1436
1486
  const reply = await this.prompt((0, run_store_js_1.buildResumeInstruction)(prep.plan), {});
1437
- return { ok: true, reply };
1487
+ return { ok: true, reply, ...(modelDrift ? { modelDrift } : {}), ...(modelApplied ? { modelApplied } : {}) };
1438
1488
  }
1439
1489
  finally {
1440
1490
  this.resumeRunId = '';
@@ -1504,7 +1554,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1504
1554
  const loopActionLog = [];
1505
1555
  // 发送循环开始的事件
1506
1556
  if (onStream) {
1507
- onStream({ type: 'status', content: '🔄 开始 ReAct 循环...', tool: 'system' });
1557
+ onStream({ type: 'status', internal: true, content: '🔄 开始 ReAct 循环...', tool: 'system' });
1508
1558
  }
1509
1559
  // React Harness: 循环开始 (重置 turn 计数 + 触发 harness sessionStart)
1510
1560
  // 失败静默 (fail-open), 不阻塞主循环
@@ -1536,7 +1586,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1536
1586
  }
1537
1587
  const doneN = this.resumePlan?.completedSteps.length ?? 0;
1538
1588
  const guards = this.resumePlan?.replayGuards.length ?? 0;
1539
- onStream?.({ type: 'status', content: `♻️ 从 checkpoint 恢复运行 ${this.currentRunId} (已完成 ${doneN} 步, 非幂等重放守卫 ${guards} 条)`, tool: 'harness' });
1589
+ onStream?.({ type: 'status', internal: true, content: `♻️ 从 checkpoint 恢复运行 ${this.currentRunId} (已完成 ${doneN} 步, 非幂等重放守卫 ${guards} 条)`, tool: 'harness' });
1540
1590
  }
1541
1591
  else {
1542
1592
  // 2026-09-16 (M2): 目标绑定 —— 有 goalId 就在该 Goal 下执行; 没有就建 Goal 再建 Run。
@@ -1579,6 +1629,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1579
1629
  goalId: boundGoalId || undefined,
1580
1630
  channelId: this.currentChannelId || undefined,
1581
1631
  agentId: this.currentAgentId || undefined,
1632
+ modelConfig: await this.runModelSnapshot(),
1582
1633
  });
1583
1634
  this.currentRunId = rec.runId;
1584
1635
  this.lastRunId = rec.runId;
@@ -1587,7 +1638,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1587
1638
  // Run → Goal 反查链: runId → goalId → objective / success criteria
1588
1639
  await (0, goal_store_js_1.attachRun)(this.currentGoalId, rec.runId).catch((err) => console.warn('[PiAgent] attachRun 失败:', err?.message));
1589
1640
  }
1590
- onStream?.({ type: 'status', content: `🧷 运行已登记 (run=${rec.runId}${this.currentGoalId ? `, goal=${this.currentGoalId}` : ''}, 预算 ${rec.budget.maxSteps} 步 / ${Math.round(rec.budget.deadlineMs / 60000)} 分钟)`, tool: 'harness' });
1641
+ onStream?.({ type: 'status', internal: true, content: `🧷 运行已登记 (run=${rec.runId}${this.currentGoalId ? `, goal=${this.currentGoalId}` : ''}, 预算 ${rec.budget.maxSteps} 步 / ${Math.round(rec.budget.deadlineMs / 60000)} 分钟)`, tool: 'harness' });
1591
1642
  }
1592
1643
  catch (err) {
1593
1644
  // 核心写失败: 不再 warn 后继续 —— 没有运行记录就不执行 (strict 模式默认如此)
@@ -1705,7 +1756,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1705
1756
  if ((0, react_loop_js_1.shouldCompactBeforeIteration)(estimatedTokensBefore, compactThreshold)) {
1706
1757
  const tokensBeforeCompact = estimatedTokensBefore;
1707
1758
  console.log(`[PiAgent] loop 入口 token ${tokensBeforeCompact} > ${compactThreshold}, 触发自动压缩`);
1708
- onStream?.({ type: 'status', content: `🗜️ loop 自动压缩 (token ${tokensBeforeCompact} > ${compactThreshold})`, tool: 'compactor' });
1759
+ onStream?.({ type: 'status', internal: true, content: `🗜️ loop 自动压缩 (token ${tokensBeforeCompact} > ${compactThreshold})`, tool: 'compactor' });
1709
1760
  try {
1710
1761
  await this.maybeAutoCompact(onStream, signal);
1711
1762
  }
@@ -1727,7 +1778,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1727
1778
  // 调试日志:显示每次循环开始
1728
1779
  console.log(`[PiAgent] 循环 ${iteration}/${this.MAX_REACT_ITERATIONS} 开始`);
1729
1780
  if (onStream) {
1730
- onStream({ type: 'status', content: `🔄 循环 ${iteration}/${this.MAX_REACT_ITERATIONS}`, tool: 'loop' });
1781
+ onStream({ type: 'status', internal: true, content: `🔄 循环 ${iteration}/${this.MAX_REACT_ITERATIONS}`, tool: 'loop' });
1731
1782
  }
1732
1783
  const context = this.buildContext();
1733
1784
  // M3.5 (2026-06-17): 也构造 messages 数组版本, 让 LLM 看到结构化 tool 角色
@@ -1916,7 +1967,10 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1916
1967
  }
1917
1968
  // 路径 B: 文本解析 (parseAllToolCalls 收集全部)
1918
1969
  if (toolCalls.length === 0) {
1919
- const knownTools = new Set(Array.from(this.tools.keys()));
1970
+ // 2026-09-26: 已知名集合 = 注册表原名 + 它们的 API 名 (净化后的).
1971
+ // 出网时工具面给的是 API 名 (见 pi-ai.ts 的唯一净化边界), LLM 在文本里
1972
+ // 回吐的也可能是 API 名 —— 只用原名集合过滤会把这类调用整个丢掉.
1973
+ const knownTools = (0, tool_name_js_1.expandKnownToolNames)(this.tools.keys());
1920
1974
  toolCalls = (0, parse_tool_call_js_1.parseAllToolCalls)(reply, { tools: knownTools });
1921
1975
  }
1922
1976
  // 回退路径 C: 原生 parseToolCall (单个)
@@ -1925,6 +1979,12 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1925
1979
  if (single)
1926
1980
  toolCalls.push(single);
1927
1981
  }
1982
+ // 2026-09-26: **回程派发的唯一还原点** —— LLM 回吐的是 API 名 (净化过的), 这里
1983
+ // 还原成注册表真名再交给 this.tools.get(); 原名 (LLM 照 system prompt 抄的) 原样穿透.
1984
+ for (const tc of toolCalls) {
1985
+ if (typeof tc.name === 'string' && tc.name)
1986
+ tc.name = (0, tool_name_js_1.resolveApiToolName)(tc.name);
1987
+ }
1928
1988
  // 给每个 toolCall 分配稳定 id
1929
1989
  for (const tc of toolCalls) {
1930
1990
  if (!tc.id) {
@@ -1949,7 +2009,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
1949
2009
  if (onStream) {
1950
2010
  onStream({ type: 'tool', content: `🔧 调用工具 (${ti + 1}/${toolCalls.length}): ${toolCall.name}`, tool: toolCall.name });
1951
2011
  if (toolCall.args && Object.keys(toolCall.args).length > 0) {
1952
- onStream({ type: 'status', content: `📋 参数: ${JSON.stringify(toolCall.args)}`, tool: toolCall.name });
2012
+ onStream({ type: 'status', internal: true, content: `📋 参数: ${JSON.stringify(toolCall.args)}`, tool: toolCall.name });
1953
2013
  }
1954
2014
  onStream({
1955
2015
  type: 'step_start',
@@ -2079,7 +2139,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2079
2139
  const toolDurationMs = Date.now() - toolStart;
2080
2140
  if (replaySkip) {
2081
2141
  console.log(`[PiAgent] 恢复重放守卫: 跳过已完成的非幂等工具 ${toolCall.name}`);
2082
- onStream?.({ type: 'status', content: `🛡️ 恢复保护: ${toolCall.name} 此前已成功执行, 本次不重复执行`, tool: toolCall.name });
2142
+ onStream?.({ type: 'status', internal: true, content: `🛡️ 恢复保护: ${toolCall.name} 此前已成功执行, 本次不重复执行`, tool: toolCall.name });
2083
2143
  }
2084
2144
  console.log(`[PiAgent] 工具 ${toolCall.name} 执行完成: success=${result.success} (${toolDurationMs}ms)`);
2085
2145
  // 2026-09-16 (M3): 失败接线 —— 分类 + recovery 留痕 + 熔断 / 外部等待
@@ -2152,7 +2212,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2152
2212
  }
2153
2213
  if (onStream) {
2154
2214
  if (result.success) {
2155
- onStream({ type: 'status', content: `✅ ${toolCall.name} 执行成功`, tool: toolCall.name });
2215
+ onStream({ type: 'status', internal: true, content: `✅ ${toolCall.name} 执行成功`, tool: toolCall.name });
2156
2216
  if (result.output) {
2157
2217
  onStream({ type: 'tool', content: `📤 结果: ${result.output.substring(0, 200)}${result.output.length > 200 ? '...' : ''}`, tool: toolCall.name });
2158
2218
  }
@@ -2182,7 +2242,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2182
2242
  refineAttempts++;
2183
2243
  }
2184
2244
  if (onStream) {
2185
- onStream({ type: 'status', content: `🔄 工具执行完成,继续循环...`, tool: 'loop' });
2245
+ onStream({ type: 'status', internal: true, content: `🔄 工具执行完成,继续循环...`, tool: 'loop' });
2186
2246
  }
2187
2247
  }
2188
2248
  else {
@@ -2268,7 +2328,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2268
2328
  content: `[dive-into stop condition] 你之前已成功执行了 ${unreported} 个工具, 但当前回复里没把它们的结果告诉用户. 请基于已有的工具结果 (在 history 里) 写一个完整总结回复给用户, 用 <final gen> 结尾. 不要再调工具.`
2269
2329
  });
2270
2330
  if (onStream) {
2271
- onStream({ type: 'status', content: `🔄 还有 ${unreported} 个工具结果未汇报, 让 LLM 继续总结 (${unreportedRetries}/${MAX_UNREPORTED_RETRIES})`, tool: 'system' });
2331
+ onStream({ type: 'status', internal: true, content: `🔄 还有 ${unreported} 个工具结果未汇报, 让 LLM 继续总结 (${unreportedRetries}/${MAX_UNREPORTED_RETRIES})`, tool: 'system' });
2272
2332
  }
2273
2333
  continue;
2274
2334
  }
@@ -2281,7 +2341,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2281
2341
  content: `[dive-into stop condition] 已多次提示汇报工具结果仍未完成 (超过 ${MAX_UNREPORTED_RETRIES} 次). 现在直接基于你已知的信息写最终回复给用户, 用 <final gen> 结尾, 不要再调任何工具.`
2282
2342
  });
2283
2343
  if (onStream) {
2284
- onStream({ type: 'status', content: `🔄 工具结果汇报超限, 强制收尾`, tool: 'system' });
2344
+ onStream({ type: 'status', internal: true, content: `🔄 工具结果汇报超限, 强制收尾`, tool: 'system' });
2285
2345
  }
2286
2346
  }
2287
2347
  lastQualityScore = this.estimateResponseQuality(reply);
@@ -2311,7 +2371,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2311
2371
  console.log(`[PiAgent] review ${loopReviewCount}/${loop_review_js_1.DEFAULT_MAX_REVIEWS}: LLM 想 final 但先对齐需求深挖一次`);
2312
2372
  this.messageHistory.push({ role: 'system', content: reviewDecision.hint });
2313
2373
  if (onStream) {
2314
- onStream({ type: 'status', content: `🔄 目标对齐 review ${loopReviewCount}/${loop_review_js_1.DEFAULT_MAX_REVIEWS}: 深挖续跑`, tool: 'system' });
2374
+ onStream({ type: 'status', internal: true, content: `🔄 目标对齐 review ${loopReviewCount}/${loop_review_js_1.DEFAULT_MAX_REVIEWS}: 深挖续跑`, tool: 'system' });
2315
2375
  }
2316
2376
  continue; // 让 LLM 看到 hint, 深挖或确认完成后再次 final
2317
2377
  }
@@ -2335,14 +2395,14 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2335
2395
  if (needsMoreWork && iteration < this.MAX_REACT_ITERATIONS) {
2336
2396
  console.log(`[PiAgent] 继续循环处理 (${iteration}/${this.MAX_REACT_ITERATIONS}): needsMoreWork=${needsMoreWork}, hasError=${hasError}, containsToolCallIntent=${containsToolCallIntent}`);
2337
2397
  if (onStream) {
2338
- onStream({ type: 'status', content: `🔄 继续处理,循环 ${iteration}...`, tool: 'loop' });
2398
+ onStream({ type: 'status', internal: true, content: `🔄 继续处理,循环 ${iteration}...`, tool: 'loop' });
2339
2399
  }
2340
2400
  continue;
2341
2401
  }
2342
2402
  // 否则把这个当作可能的最终回答
2343
2403
  finalResponse = reply;
2344
2404
  if (onStream) {
2345
- onStream({ type: 'status', content: `📝 提取最终回答,长度 ${reply.length}`, tool: 'system' });
2405
+ onStream({ type: 'status', internal: true, content: `📝 提取最终回答,长度 ${reply.length}`, tool: 'system' });
2346
2406
  }
2347
2407
  break;
2348
2408
  }
@@ -2360,7 +2420,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2360
2420
  }
2361
2421
  // 通知前端循环完成
2362
2422
  if (onStream) {
2363
- onStream({ type: 'status', content: `✅ 处理完成,共 ${iteration - 1} 次循环`, tool: 'system' });
2423
+ onStream({ type: 'status', internal: true, content: `✅ 处理完成,共 ${iteration - 1} 次循环`, tool: 'system' });
2364
2424
  }
2365
2425
  this.messageHistory.push({ role: 'assistant', content: finalResponse });
2366
2426
  // React Harness: 循环结束
@@ -2450,7 +2510,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2450
2510
  ? `🎯 目标已达成 (仍要过完成门): ${view.decision.reason}`
2451
2511
  : `🎯 目标仍在进行 (未判完成): ${view.decision.reason}`;
2452
2512
  onStream?.({
2453
- type: 'status',
2513
+ type: 'status', internal: true,
2454
2514
  content: `${line}${applied.gateRejected ? ` [完成门拒绝: ${applied.gateRejected}]` : ''} `
2455
2515
  + `(收尾 ${view.steps} 步 · memory ${view.memories} · skill 候选 ${view.candidates} · goal=${this.currentGoalId})`,
2456
2516
  tool: 'harness',
@@ -2640,7 +2700,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2640
2700
  const estimated = this.estimateHistoryTokens();
2641
2701
  if (estimated > this.maxContextTokens() * 0.8) {
2642
2702
  console.warn(`[PiAgent] reactive compaction pre-check (${estimated} tokens > 80% threshold)`);
2643
- onStream?.({ type: 'status', content: '⚠️ reactive compaction 预检触发', tool: 'recovery' });
2703
+ onStream?.({ type: 'status', internal: true, content: '⚠️ reactive compaction 预检触发', tool: 'recovery' });
2644
2704
  try {
2645
2705
  const compacted = this.compressHistorySync(this.messageHistory);
2646
2706
  this.messageHistory = compacted;
@@ -2794,7 +2854,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2794
2854
  async maybeAutoCompact(onStream, signal) {
2795
2855
  if (this.messageHistory.length < 10)
2796
2856
  return; // 历史太短, 不值得压
2797
- onStream?.({ type: 'status', content: '🗜️ 评估是否需要压缩上下文...', tool: 'compactor' });
2857
+ onStream?.({ type: 'status', internal: true, content: '🗜️ 评估是否需要压缩上下文...', tool: 'compactor' });
2798
2858
  // 注入 LLM (用 getMinimax().chat, 与 judgment 注入门 / ReAct 循环同一来源)
2799
2859
  // 给 Context Collapse (虚拟投影) 和 Auto-Compact (摘要) 共用
2800
2860
  const llm = (0, index_js_1.getMinimax)();
@@ -2822,7 +2882,7 @@ ${PiAgentSession.TOOL_SELECTION_GUIDE}
2822
2882
  const savedTokens = Math.max(0, beforeTokens - afterTokens);
2823
2883
  cm.markCompressStart(beforeTokens);
2824
2884
  onStream?.({
2825
- type: 'status',
2885
+ type: 'status', internal: true,
2826
2886
  content: `🗜️ 上下文压缩: ${stagesApplied || 'no-op'} | 节省 ${saved} 条 / ${savedTokens.toLocaleString()} tokens (剩余 ${result.history.length}, collapse=${isContextCollapseEnabled() ? 'on' : 'off'})`,
2827
2887
  tool: 'compactor',
2828
2888
  });