@xopcai/xopc 0.0.244 → 0.0.246

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 (209) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-CAah-_8h.js → activity-store-BlxqErph.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BhXGsupm.js → agent-avatar-dicebear-CJJzpYYS.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-Blzn2H6t.js → agent-defaults-settings-panel-0dRjnL2s.js} +1 -1
  6. package/dist/gateway/static/root/assets/{agents-Cmp-z8Y_.js → agents-je3sRGmk.js} +1 -1
  7. package/dist/gateway/static/root/assets/{api-B2tKxbcz.js → api-BbXzyQMj.js} +1 -1
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-CezjAP1K.js → app-management-settings-panel-Cnn3i00c.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-C-CfS05x.js → appearance-settings-BToQaw_v.js} +1 -1
  10. package/dist/gateway/static/root/assets/{apps-page-7Y13_bqZ.js → apps-page-EpUZsl4h.js} +1 -1
  11. package/dist/gateway/static/root/assets/{archive-plugin-BmSx7wzY.js → archive-plugin-DD2SweEH.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-DI4CoIga.js → attachment-load-BFtcib5t.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-D04Xceck.js → automations-page-XS8wIl5o.js} +1 -1
  14. package/dist/gateway/static/root/assets/{automations-workspace-wEO1OWk0.js → automations-workspace-BGQdHrip.js} +1 -1
  15. package/dist/gateway/static/root/assets/{binary-plugins-BJQe8TRu.js → binary-plugins-Xs7pLHxR.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-BSzGjJC6.js → block-editor-BPdSzceB.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-settings-page-DjAZ_LF2.js → browser-settings-page-DJGcm7rH.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-CRnkgZHI.js → browser-workflow-inputs-BAAc151l.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-CwbxA3B7.js → browser-workflows-page-DUPPvE30.js} +1 -1
  20. package/dist/gateway/static/root/assets/{capabilities-settings-panel-jt9bqUMK.js → capabilities-settings-panel-cl9kYilL.js} +1 -1
  21. package/dist/gateway/static/root/assets/{channels-settings-Cz_TWY3a.js → channels-settings-BcIr-_GM.js} +1 -1
  22. package/dist/gateway/static/root/assets/{channels-status-swr-DuY4MGxe.js → channels-status-swr-CCBCtLDg.js} +1 -1
  23. package/dist/gateway/static/root/assets/{chat-terminal-dock-D3gj2D3U.js → chat-terminal-dock-DKW1M6aJ.js} +1 -1
  24. package/dist/gateway/static/root/assets/{connectors-page-Shs5vbzx.js → connectors-page-DNHqaZfX.js} +1 -1
  25. package/dist/gateway/static/root/assets/{cron-expression-DgWHw0jX.js → cron-expression-Bijb0ZQu.js} +1 -1
  26. package/dist/gateway/static/root/assets/{date-picker-CKg-RPbs.js → date-picker-BZuHw-SY.js} +1 -1
  27. package/dist/gateway/static/root/assets/{dependency-picker-CVYkw-NN.js → dependency-picker-BsBD2JFY.js} +1 -1
  28. package/dist/gateway/static/root/assets/{desktop-pet-Bf46oXTY.js → desktop-pet-Ceuw3QKb.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-settings-BJO_klc7.js → desktop-pet-settings-DctOXexM.js} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-debug-page-T2PmFFOW.js → extension-debug-page-BNlMPATK.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-page-2wAE2RCe.js → extension-page-CK4Uvzge.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-settings-page-Y9ZiCJ21.js → extension-settings-page-CpnXXemw.js} +1 -1
  33. package/dist/gateway/static/root/assets/{gateway-config-api-DaYY1Gkn.js → gateway-config-api-C_mlpe-r.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-config-swr-BC3pgb_P.js → gateway-config-swr-826dipyU.js} +1 -1
  35. package/dist/gateway/static/root/assets/{gateway-settings-eO3IzW_J.js → gateway-settings-DSSW17ed.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-startup-retry-uMcSfLru.js → gateway-startup-retry-DyvcAIMm.js} +1 -1
  37. package/dist/gateway/static/root/assets/{heartbeat-settings-BAgrkyHc.js → heartbeat-settings-hbmIZTpg.js} +1 -1
  38. package/dist/gateway/static/root/assets/{home-page-GTjKH7LK.js → home-page-CaVvW77l.js} +1 -1
  39. package/dist/gateway/static/root/assets/{image-generation-api-D1qlQA-A.js → image-generation-api-D7cyfks6.js} +1 -1
  40. package/dist/gateway/static/root/assets/{index-DUz0O54y.js → index-eZjksPvq.js} +10 -10
  41. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CWGqL6o5.js → keyboard-shortcuts-settings-BQrDwwgi.js} +1 -1
  42. package/dist/gateway/static/root/assets/{local-app-workbench-page-DKJ-rks0.js → local-app-workbench-page-D3K1XmOM.js} +1 -1
  43. package/dist/gateway/static/root/assets/{local-apps-page-Bfidv29d.js → local-apps-page-D-YWD6LS.js} +1 -1
  44. package/dist/gateway/static/root/assets/{locale-store-CMZljTJx.js → locale-store-CBoCuIMx.js} +1 -1
  45. package/dist/gateway/static/root/assets/{logs-page-DwAHrPbF.js → logs-page-DvLc9l59.js} +1 -1
  46. package/dist/gateway/static/root/assets/{management-settings-BG7j1I9f.js → management-settings-DsULLUUv.js} +1 -1
  47. package/dist/gateway/static/root/assets/{markdown-split-AnmmpLs6.js → markdown-split-CjqlP6IB.js} +1 -1
  48. package/dist/gateway/static/root/assets/{markdown-view-PPCLt7fu.js → markdown-view-BXsHghJd.js} +1 -1
  49. package/dist/gateway/static/root/assets/{media-plugins-CGS-05cE.js → media-plugins-DQL029DU.js} +1 -1
  50. package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +3 -0
  51. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-DoKK5GfV.js → mobile-pairing-wizard-gauprAae.js} +1 -1
  52. package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +1 -0
  53. package/dist/gateway/static/root/assets/{notes-page-Lr8rsFAR.js → notes-page-AsEfLZt9.js} +1 -1
  54. package/dist/gateway/static/root/assets/{notes-workbench-ISWnKLxO.js → notes-workbench-CI30cDh3.js} +2 -2
  55. package/dist/gateway/static/root/assets/{oauth-api-4VeMbkTJ.js → oauth-api-BjSUDIgq.js} +1 -1
  56. package/dist/gateway/static/root/assets/{product-open-page-BU0HiZtv.js → product-open-page-CAJeUXeU.js} +1 -1
  57. package/dist/gateway/static/root/assets/{project-detail-page-BZqr4yam.js → project-detail-page-jO_4I5zN.js} +1 -1
  58. package/dist/gateway/static/root/assets/{projects-page-Dau8733A.js → projects-page-BrTGFME0.js} +1 -1
  59. package/dist/gateway/static/root/assets/{registry-api-CWOtPFrE.js → registry-api-BhGKnvLP.js} +1 -1
  60. package/dist/gateway/static/root/assets/{remote-access-hub-DdChlvGP.js → remote-access-hub-CH70D5SH.js} +1 -1
  61. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CmZTNv1W.js → runtime-tools-settings-panel-DH6EilMV.js} +1 -1
  62. package/dist/gateway/static/root/assets/{schema-form-XlVPyiVQ.js → schema-form-DYHmEZeZ.js} +1 -1
  63. package/dist/gateway/static/root/assets/{sessions-page-C3kADsd4.js → sessions-page-hbfUNtNs.js} +1 -1
  64. package/dist/gateway/static/root/assets/settings-advanced-gate-Vg3_jua6.js +1 -0
  65. package/dist/gateway/static/root/assets/{settings-page-DblUeM3V.js → settings-page-BHwPd_M3.js} +1 -1
  66. package/dist/gateway/static/root/assets/{setup-status-panel-bDfRfSnq.js → setup-status-panel-DkcpWSss.js} +1 -1
  67. package/dist/gateway/static/root/assets/{share-preview-page-DBMWFMN-.js → share-preview-page-BjwrS03F.js} +1 -1
  68. package/dist/gateway/static/root/assets/{shares-settings-Bu6lIStj.js → shares-settings-BL4DEt6p.js} +1 -1
  69. package/dist/gateway/static/root/assets/skill-reload-api-CafhNktn.js +1 -0
  70. package/dist/gateway/static/root/assets/{skills-page-CSOseeQe.js → skills-page-OHyK25op.js} +1 -1
  71. package/dist/gateway/static/root/assets/{skills-page.utils-CniRGhkJ.js → skills-page.utils-DQx9ulmg.js} +1 -1
  72. package/dist/gateway/static/root/assets/{system-settings-panel-D0GqNpKy.js → system-settings-panel-wO7DWv4C.js} +1 -1
  73. package/dist/gateway/static/root/assets/{task-detail-page-BRCq-nR7.js → task-detail-page-anyomXsu.js} +1 -1
  74. package/dist/gateway/static/root/assets/{theme-store-uxUwr10D.js → theme-store-hybK3oC9.js} +1 -1
  75. package/dist/gateway/static/root/assets/{tunnel-api-BtjS2nrM.js → tunnel-api-CVC8BHZu.js} +1 -1
  76. package/dist/gateway/static/root/assets/{use-autosave-TwuAycG8.js → use-autosave-DMvRu2XZ.js} +1 -1
  77. package/dist/gateway/static/root/assets/{user-context-page-CbqPu8xZ.js → user-context-page-BBk9YdBn.js} +1 -1
  78. package/dist/gateway/static/root/assets/{voice-api-key-field-CzwG5plu.js → voice-api-key-field-DuBK2NDG.js} +1 -1
  79. package/dist/gateway/static/root/assets/{voice-config-api-MqyI6cgq.js → voice-config-api-CBbiF1T3.js} +1 -1
  80. package/dist/gateway/static/root/assets/{work-discovery-overlay-DS15FzQA.js → work-discovery-overlay-B7VXWpDr.js} +1 -1
  81. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C_boCemi.js → workflow-run-setup-panel-BokVAsWN.js} +1 -1
  82. package/dist/gateway/static/root/assets/{workflows-page-CaI2ruyy.js → workflows-page-RUTv0yvR.js} +1 -1
  83. package/dist/gateway/static/root/index.html +11 -11
  84. package/dist/package.js +1 -1
  85. package/dist/packages/gateway-contract/src/turn-outcome.js +3 -1
  86. package/dist/src/agent/agent-instance-gateway.d.ts +3 -1
  87. package/dist/src/agent/agent-manager.d.ts +2 -4
  88. package/dist/src/agent/agent-manager.js +24 -28
  89. package/dist/src/agent/background-review/coordinator.js +1 -1
  90. package/dist/src/agent/background-review/run-background-review.js +1 -1
  91. package/dist/src/agent/child-agent-factory.d.ts +10 -7
  92. package/dist/src/agent/child-agent-factory.js +112 -158
  93. package/dist/src/agent/coding/index.d.ts +1 -1
  94. package/dist/src/agent/coding/index.js +2 -2
  95. package/dist/src/agent/coding/repository-instructions.d.ts +12 -0
  96. package/dist/src/agent/coding/repository-instructions.js +76 -0
  97. package/dist/src/agent/coding/run-verification.d.ts +34 -0
  98. package/dist/src/agent/coding/run-verification.js +134 -0
  99. package/dist/src/agent/coding/verification-command.d.ts +3 -0
  100. package/dist/src/agent/coding/verification-command.js +50 -0
  101. package/dist/src/agent/coding/workspace-revision.d.ts +2 -0
  102. package/dist/src/agent/coding/workspace-revision.js +77 -0
  103. package/dist/src/agent/commands/command-isolation.d.ts +21 -0
  104. package/dist/src/agent/commands/command-isolation.js +71 -0
  105. package/dist/src/agent/commands/command-registry.d.ts +56 -0
  106. package/dist/src/agent/commands/command-registry.js +259 -0
  107. package/dist/src/agent/embedded/index.js +1 -1
  108. package/dist/src/agent/embedded/run-for-session.js +2 -1
  109. package/dist/src/agent/embedded/run-turn.js +88 -25
  110. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -2
  111. package/dist/src/agent/embedded/subscribe-session.d.ts +2 -1
  112. package/dist/src/agent/embedded/subscribe-session.js +2 -1
  113. package/dist/src/agent/embedded/types.d.ts +3 -1
  114. package/dist/src/agent/embedded/xopc-tools-bridge.js +4 -1
  115. package/dist/src/agent/image/index.js +1 -1
  116. package/dist/src/agent/index.js +3 -3
  117. package/dist/src/agent/memory/user-context-coordinator.js +1 -1
  118. package/dist/src/agent/middleware/index.d.ts +0 -5
  119. package/dist/src/agent/middleware/index.js +1 -2
  120. package/dist/src/agent/orchestration/agent-event-handler.d.ts +0 -5
  121. package/dist/src/agent/orchestration/agent-event-handler.js +1 -96
  122. package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
  123. package/dist/src/agent/orchestration/agent-turn-policy.js +5 -5
  124. package/dist/src/agent/orchestration/index.d.ts +1 -1
  125. package/dist/src/agent/orchestration/index.js +2 -2
  126. package/dist/src/agent/orchestration/loop-guard.d.ts +4 -31
  127. package/dist/src/agent/orchestration/loop-guard.js +14 -99
  128. package/dist/src/agent/prompt/sections/tooling.js +2 -4
  129. package/dist/src/agent/sandbox/types.d.ts +2 -2
  130. package/dist/src/agent/sandbox/types.js +1 -1
  131. package/dist/src/agent/service/direct-turn-helpers.js +1 -1
  132. package/dist/src/agent/service/process-direct-streaming.js +1 -1
  133. package/dist/src/agent/service.d.ts +0 -2
  134. package/dist/src/agent/service.js +6 -23
  135. package/dist/src/agent/tasks/task-judge-service.d.ts +7 -0
  136. package/dist/src/agent/tasks/task-judge-service.js +24 -2
  137. package/dist/src/agent/tools/delegate-tool.d.ts +2 -1
  138. package/dist/src/agent/tools/delegate-tool.js +102 -124
  139. package/dist/src/agent/tools/exec-command.d.ts +8 -1
  140. package/dist/src/agent/tools/exec-command.js +77 -169
  141. package/dist/src/agent/tools/executor.js +9 -2
  142. package/dist/src/agent/tools/factory.js +50 -5
  143. package/dist/src/agent/tools/find.d.ts +10 -13
  144. package/dist/src/agent/tools/find.js +33 -80
  145. package/dist/src/agent/tools/grep.d.ts +14 -18
  146. package/dist/src/agent/tools/grep.js +56 -144
  147. package/dist/src/agent/tools/index.d.ts +0 -1
  148. package/dist/src/agent/tools/index.js +2 -3
  149. package/dist/src/agent/tools/language-diagnostics.d.ts +11 -0
  150. package/dist/src/agent/tools/language-diagnostics.js +62 -0
  151. package/dist/src/agent/tools/managed-job-tool.d.ts +2 -1
  152. package/dist/src/agent/tools/managed-job-tool.js +58 -118
  153. package/dist/src/agent/tools/read.js +24 -7
  154. package/dist/src/agent/tools/repository-search.d.ts +5 -0
  155. package/dist/src/agent/tools/repository-search.js +56 -0
  156. package/dist/src/agent/tools/review-workspace.d.ts +2 -0
  157. package/dist/src/agent/tools/review-workspace.js +103 -0
  158. package/dist/src/agent/tools/write.js +4 -4
  159. package/dist/src/agent/transcript/index.js +2 -2
  160. package/dist/src/agent/transcript/transcript-hygiene.js +2 -2
  161. package/dist/src/agent/workflow/subagent-runner.d.ts +0 -2
  162. package/dist/src/agent/workflow/subagent-runner.js +12 -31
  163. package/dist/src/agent-config/schema.d.ts +42 -0
  164. package/dist/src/agent-config/schema.js +5 -0
  165. package/dist/src/cli/commands/agent.js +2 -2
  166. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  167. package/dist/src/cli/commands/models.js +1 -1
  168. package/dist/src/cli/commands/onboard.js +1 -1
  169. package/dist/src/cli/commands/profile.js +1 -1
  170. package/dist/src/cli/commands/tunnel.js +1 -1
  171. package/dist/src/cli/commands/update.js +1 -1
  172. package/dist/src/cli/extension-cli-register.js +1 -1
  173. package/dist/src/config/index.js +1 -1
  174. package/dist/src/config/schema.d.ts +28 -0
  175. package/dist/src/execution-environments/local-worktree-manager.d.ts +3 -1
  176. package/dist/src/execution-environments/local-worktree-manager.js +8 -3
  177. package/dist/src/execution-environments/session-environment-service.js +5 -3
  178. package/dist/src/gateway/hono/lib/config-payload.d.ts +7 -0
  179. package/dist/src/gateway/hono/routes/sessions.js +1 -1
  180. package/dist/src/gateway/media-access.js +1 -1
  181. package/dist/src/gateway/run-loop.js +1 -1
  182. package/dist/src/gateway/service/run-gateway-agent.js +4 -1
  183. package/dist/src/gateway/service.js +3 -3
  184. package/dist/src/gateway/session-reset-service.js +1 -1
  185. package/dist/src/gateway/workspace-ripgrep.d.ts +0 -6
  186. package/dist/src/gateway/workspace-ripgrep.js +2 -40
  187. package/dist/src/infra/ripgrep.d.ts +13 -0
  188. package/dist/src/infra/ripgrep.js +46 -0
  189. package/dist/src/proactive/execution/agent-executor.js +1 -1
  190. package/dist/src/session/store.js +1 -1
  191. package/dist/src/session/turn-outcome-projector.js +26 -6
  192. package/dist/src/tasks/task-run-coordinator.d.ts +2 -2
  193. package/dist/src/tasks/task-run-coordinator.js +14 -12
  194. package/dist/src/tui/backends/embedded-backend.js +1 -1
  195. package/dist/src/voice/realtime/agentEngine.d.ts +1 -1
  196. package/dist/src/voice/realtime/runtime.d.ts +3 -68
  197. package/dist/src/voice/realtime/runtime.types.d.ts +69 -0
  198. package/dist/src/voice/realtime/runtime.types.js +1 -0
  199. package/package.json +3 -3
  200. package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +0 -3
  201. package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +0 -1
  202. package/dist/gateway/static/root/assets/settings-advanced-gate-CSYy6SUa.js +0 -1
  203. package/dist/gateway/static/root/assets/skill-reload-api-BNMc4l04.js +0 -1
  204. package/dist/src/agent/coding/turn-diff-tracker.d.ts +0 -67
  205. package/dist/src/agent/coding/turn-diff-tracker.js +0 -231
  206. package/dist/src/agent/middleware/self-verify.d.ts +0 -136
  207. package/dist/src/agent/middleware/self-verify.js +0 -380
  208. package/dist/src/agent/tools/execute-code-tool.d.ts +0 -11
  209. package/dist/src/agent/tools/execute-code-tool.js +0 -208
@@ -1,105 +1,20 @@
1
- import { createLogger } from "../../utils/logger/index.js";
2
- import { init_logger } from "../../utils/logger.js";
1
+ import { createHash } from "node:crypto";
3
2
  //#region src/agent/orchestration/loop-guard.ts
4
- init_logger();
5
- const log = createLogger("LoopGuard");
6
- const DEFAULT_CONFIG = {
7
- softThreshold: 2,
8
- hideThreshold: 3
9
- };
10
- /**
11
- * Stable fingerprint for tool call comparison.
12
- * Recursively sorts object keys; truncates long string values.
13
- */
14
- function stableJson(value) {
15
- return JSON.stringify(value, (_key, item) => {
16
- if (typeof item === "object" && item !== null && !Array.isArray(item)) return Object.fromEntries(Object.entries(item).sort(([a], [b]) => a.localeCompare(b)));
17
- if (typeof item === "string" && item.length > 200) return `${item.slice(0, 80)}…[${item.length}]`;
18
- return item;
19
- });
20
- }
21
3
  function fingerprint(call) {
22
- const result = call.resultPreview === void 0 ? "" : `::result=${stableJson(call.resultPreview)}`;
23
- return `${call.name}::${stableJson(call.params)}${result}`;
24
- }
25
- /**
26
- * Analyze recent tool calls and produce loop guard result.
27
- *
28
- * Pure function — no side effects, no shared state.
29
- */
30
- function detectToolLoops(recentCalls, config = {}) {
31
- const { softThreshold, hideThreshold } = {
32
- ...DEFAULT_CONFIG,
33
- ...config
34
- };
35
- if (recentCalls.length === 0) return {
36
- injection: null,
37
- hiddenTools: /* @__PURE__ */ new Set()
38
- };
39
- const consecutiveGroups = findConsecutiveRepeats(recentCalls);
40
- const frequencyMap = countFrequency(recentCalls);
41
- const warnings = [];
42
- const hiddenTools = /* @__PURE__ */ new Set();
43
- for (const group of consecutiveGroups) if (group.count >= hideThreshold) {
44
- hiddenTools.add(group.toolName);
45
- warnings.push(`Tool '${group.toolName}' has been called ${group.count} times consecutively with identical arguments and is now unavailable. Use a completely different approach.`);
46
- log.warn({
47
- tool: group.toolName,
48
- consecutiveCount: group.count
49
- }, "Loop guard: hiding tool from LLM");
50
- } else if (group.count >= softThreshold) {
51
- warnings.push(`You have called '${group.toolName}' ${group.count} times with the same arguments. This is not producing new information. Do NOT call it again with the same arguments — try a different approach.`);
52
- log.debug({
53
- tool: group.toolName,
54
- consecutiveCount: group.count
55
- }, "Loop guard: soft warning injected");
56
- }
57
- for (const [fp, count] of frequencyMap) {
58
- const toolName = fp.split("::")[0];
59
- if (count >= hideThreshold + 1 && !hiddenTools.has(toolName)) {
60
- if (!consecutiveGroups.some((g) => g.toolName === toolName && g.count >= softThreshold)) warnings.push(`Tool '${toolName}' has been called ${count} times this turn with the same arguments (interleaved). Stop repeating this pattern.`);
61
- }
62
- }
63
- return {
64
- injection: warnings.length > 0 ? `⚠️ LOOP DETECTION:\n${warnings.join("\n")}\n\nYou MUST take a different approach. Do not repeat the same tool calls.` : null,
65
- hiddenTools
66
- };
67
- }
68
- /**
69
- * Find consecutive runs of identical (tool+params) calls from the end of history.
70
- * Returns all groups with count >= 2 (most recent first).
71
- */
72
- function findConsecutiveRepeats(calls) {
73
- const groups = [];
74
- let index = calls.length - 1;
75
- while (index >= 0) {
76
- const current = calls[index];
77
- const fp = fingerprint(current);
78
- let count = 1;
79
- while (index - count >= 0) {
80
- const prev = calls[index - count];
81
- if (fingerprint(prev) !== fp) break;
82
- count++;
83
- }
84
- if (count >= 2) groups.push({
85
- toolName: current.name,
86
- fingerprint: fp,
87
- count
88
- });
89
- index -= count;
90
- }
91
- return groups;
4
+ const value = JSON.stringify(call, (_key, item) => item && typeof item === "object" && !Array.isArray(item) ? Object.fromEntries(Object.entries(item).sort(([a], [b]) => a.localeCompare(b))) : item);
5
+ return createHash("sha256").update(value).digest("hex");
92
6
  }
93
- /**
94
- * Count how many times each (tool+params) fingerprint appears.
95
- */
96
- function countFrequency(calls) {
97
- const map = /* @__PURE__ */ new Map();
98
- for (const call of calls) {
99
- const fp = fingerprint(call);
100
- map.set(fp, (map.get(fp) ?? 0) + 1);
101
- }
102
- return map;
7
+ /** Warn on a stalled tail, without removing tools needed to recover or verify a repair. */
8
+ function detectToolLoops(recentCalls) {
9
+ const calls = recentCalls.slice(-12);
10
+ const last = calls.at(-1);
11
+ if (!last) return { injection: null };
12
+ const hashes = calls.map(fingerprint);
13
+ let count = 0;
14
+ for (let index = hashes.length - 1; index >= 0 && hashes[index] === hashes.at(-1); index--) count++;
15
+ const alternating = hashes.length >= 6 && hashes.slice(-6, -3).every((hash, index) => hash === hashes.at(-3 + index));
16
+ if (count < 2 && !alternating) return { injection: null };
17
+ return { injection: `Repeated tool calls are producing no new evidence (${last.name}, ${count >= 2 ? `${count} identical calls` : "repeated cycle"}). Change the query or fix the cause before retrying. For a running job use managed_job wait. Tools remain available for a different argument or a changed workspace.` };
103
18
  }
104
19
  //#endregion
105
20
  export { detectToolLoops };
@@ -34,8 +34,7 @@ const CORE_TOOL_ORDER = [
34
34
  "text_to_speech",
35
35
  "image",
36
36
  "image_generate",
37
- "create_share",
38
- "execute_code"
37
+ "create_share"
39
38
  ];
40
39
  const CORE_TOOL_SUMMARIES = {
41
40
  read_file: "Read targeted file contents before editing",
@@ -72,8 +71,7 @@ const CORE_TOOL_SUMMARIES = {
72
71
  text_to_speech: "Send a standalone voice message",
73
72
  image: "Analyze an image with the configured vision model",
74
73
  image_generate: "Generate images with the configured image model",
75
- create_share: "Create a shareable link for workspace files",
76
- execute_code: "Run code in a sandbox with a restricted tool subset"
74
+ create_share: "Create a shareable link for workspace files"
77
75
  };
78
76
  function buildToolingSection(params) {
79
77
  const rawToolNames = (params.toolNames ?? []).map((tool) => tool.trim()).filter(Boolean);
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Sandbox type definitions for Phase 1 process-level isolation.
2
+ * Preflight command/path policy. OS isolation is provided by the command runtime.
3
3
  */
4
4
  /** Controls how strictly the sandbox enforces isolation. */
5
- export type SandboxMode = 'off' | 'basic' | 'container';
5
+ export type SandboxMode = 'off' | 'basic';
6
6
  /** Result of path validation against the sandbox policy. */
7
7
  export type PathValidationResult = {
8
8
  allowed: boolean;
@@ -3,7 +3,7 @@
3
3
  const DEFAULT_SANDBOX_CONFIG = {
4
4
  mode: "basic",
5
5
  allowedRoots: [],
6
- maxExecutionTimeMs: 3e5,
6
+ maxExecutionTimeMs: 240 * 6e4,
7
7
  maxOutputBytes: 50 * 1024
8
8
  };
9
9
  //#endregion
@@ -1,6 +1,6 @@
1
- import { buildTaskExecutionDirective } from "../../tasks/task-context-assembler.js";
2
1
  import { resolveImageHandlingStrategy } from "../image/vision-detection.js";
3
2
  import { hydrateUserTurnForLlm } from "../inbound/attachment-pipeline.js";
3
+ import { buildTaskExecutionDirective } from "../../tasks/task-context-assembler.js";
4
4
  import { prependAgentContext } from "../../user-context/planner.js";
5
5
  import { extractAgentUserPlainText } from "../memory/user-message-text.js";
6
6
  import { shouldSkipResetOverlapCommand } from "../../session/reset-triggers.js";
@@ -1,4 +1,5 @@
1
1
  import { readAgentMessageContent } from "../memory/agent-message-access.js";
2
+ import { abortEmbeddedRun } from "../embedded/runs.js";
2
3
  import { clearPendingTranscriptUserMessage, setPendingTranscriptUserMessage } from "../inbound/attachment-pipeline.js";
3
4
  import { formatAgentRunErrorForClient } from "../client-error-format.js";
4
5
  import { resolveConfiguredActivityDetailDefault, resolveEffectiveReasoningLevel } from "../../session/thinking-resolve.js";
@@ -6,7 +7,6 @@ import { initSessionTurn } from "../../session/init-session-turn.js";
6
7
  import "../../session/index.js";
7
8
  import { mergeSttConfigFromAppConfig } from "../../voice/stt/config.js";
8
9
  import "../../voice/stt/index.js";
9
- import { abortEmbeddedRun } from "../embedded/runs.js";
10
10
  import { isVoiceLikeAttachment, mergeVoiceTranscriptsIntoUserText } from "../../channels/attachments/voice-stt-webchat.js";
11
11
  import { applyReasoningVisibility } from "../streaming/reasoning-visibility.js";
12
12
  import { isSessionSourceBinding, summarizeSourceContext } from "../source-context/types.js";
@@ -38,8 +38,6 @@ export declare class AgentService {
38
38
  private toolUsageAnalyzer;
39
39
  private toolChainTracker;
40
40
  private errorPatternMatcher;
41
- private selfVerifyMiddleware;
42
- private turnDiffTracker;
43
41
  private contextMiddleware;
44
42
  private messageRouter;
45
43
  private commandHandler;
@@ -15,10 +15,11 @@ import { removeSkillsLockEntry } from "./skills/hub-lock.js";
15
15
  import { installSkillFromZip } from "./skills/managed-store.js";
16
16
  import { pullSkillFromSource } from "./skills/hub-pull.js";
17
17
  import { resolveAgentTurnTimeoutMs } from "./orchestration/run-agent-turn-with-timeout.js";
18
- import { resolveResponseLanguageForSession } from "./prompt/response-language.js";
19
- import { normalizeSkillInstallTarget } from "./skills/install-target.js";
20
18
  import { onSessionTranscriptUpdate } from "../session/transcript-events.js";
21
19
  import { persistInboundAttachments } from "../channels/attachments/inbound-persist.js";
20
+ import { runXopcEmbeddedTurn } from "./embedded/run-turn.js";
21
+ import { resolveResponseLanguageForSession } from "./prompt/response-language.js";
22
+ import { normalizeSkillInstallTarget } from "./skills/install-target.js";
22
23
  import { AgentManager } from "./agent-manager.js";
23
24
  import { maybeRefineSessionTitleWithLlm, maybeSetProvisionalSessionTitle } from "../session/session-title.js";
24
25
  import { resolveCompactionPolicy } from "./memory/compaction-policy.js";
@@ -38,13 +39,10 @@ import { SystemReminder } from "./prompt/system-reminder.js";
38
39
  import { ToolUsageAnalyzer } from "./tools/usage-analyzer.js";
39
40
  import { ToolChainTracker } from "./tools/chain-tracker.js";
40
41
  import { ErrorPatternMatcher } from "./tools/error-pattern-matcher.js";
41
- import { SelfVerifyMiddleware } from "./middleware/self-verify.js";
42
42
  import { ContextMiddleware } from "./middleware/context.js";
43
43
  import "./middleware/index.js";
44
- import { TurnDiffTracker } from "./coding/turn-diff-tracker.js";
45
44
  import { LifecycleManager } from "./lifecycle/manager.js";
46
45
  import "./lifecycle/index.js";
47
- import { runXopcEmbeddedTurn } from "./embedded/run-turn.js";
48
46
  import { runWithEmbeddedExecutionSession } from "./embedded/execution-context.js";
49
47
  import { MessageRouter } from "./messaging/message-router.js";
50
48
  import { CommandHandler } from "./messaging/command-handler.js";
@@ -106,8 +104,6 @@ var AgentService = class {
106
104
  toolUsageAnalyzer;
107
105
  toolChainTracker;
108
106
  errorPatternMatcher;
109
- selfVerifyMiddleware;
110
- turnDiffTracker;
111
107
  contextMiddleware;
112
108
  messageRouter;
113
109
  commandHandler;
@@ -242,19 +238,16 @@ var AgentService = class {
242
238
  onSkillsUpdated: config.onSkillsUpdated,
243
239
  installSkillFromSource: (opts) => this.installSkillFromSource(opts),
244
240
  installSkillFromMarketplace: (opts) => this.installSkillFromMarketplace(opts),
245
- isWorkspaceTrusted: config.isWorkspaceTrusted,
246
- getSelfVerifyPromptContext: (sessionKey, agentId) => [this.selfVerifyMiddleware.getPendingVerificationContext(sessionKey, agentId), this.turnDiffTracker.buildFinalGuardContext(sessionKey)].filter(Boolean).join("\n\n")
241
+ isWorkspaceTrusted: config.isWorkspaceTrusted
247
242
  });
248
243
  this.agentEventHandler = new AgentEventHandler({
249
244
  errorTracker: this.errorTracker,
250
245
  requestLimiter: this.requestLimiter,
251
246
  lifecycleManager: this.lifecycleManager,
252
247
  toolChainTracker: this.toolChainTracker,
253
- selfVerifyMiddleware: this.selfVerifyMiddleware,
254
248
  systemReminder: this.systemReminder,
255
249
  toolUsageAnalyzer: this.toolUsageAnalyzer,
256
- errorPatternMatcher: this.errorPatternMatcher,
257
- turnDiffTracker: this.turnDiffTracker
250
+ errorPatternMatcher: this.errorPatternMatcher
258
251
  });
259
252
  this.agentEventHandler.registerListener("message_end", (event, context) => {
260
253
  const message = event.message;
@@ -438,13 +431,6 @@ var AgentService = class {
438
431
  maxTotalFailures: 5,
439
432
  resetOnTurnEnd: true
440
433
  });
441
- this.selfVerifyMiddleware = new SelfVerifyMiddleware({
442
- maxEditsPerFile: 5,
443
- enablePreCompletionCheck: true,
444
- minTurnsForVerification: 4,
445
- resetOnVerification: true
446
- });
447
- this.turnDiffTracker = new TurnDiffTracker();
448
434
  this.requestLimiter = new RequestLimiter({
449
435
  maxRequestsPerTurn: 50,
450
436
  warnThreshold: .8,
@@ -836,10 +822,7 @@ var AgentService = class {
836
822
  handleSessionEvent(sessionKey, event) {
837
823
  const currentContext = this.sessionContextManager.getContext();
838
824
  if (!currentContext) return;
839
- if (currentContext.sessionKey !== sessionKey) {
840
- this.agentEventHandler.handle(event, currentContext);
841
- return;
842
- }
825
+ if (currentContext.sessionKey !== sessionKey) return;
843
826
  if (event.type === "message_update") {
844
827
  const msgEvent = event;
845
828
  if (msgEvent.message?.role === "assistant") {
@@ -1,6 +1,7 @@
1
1
  import type { TaskJudgment } from '@xopcai/gateway-contract';
2
2
  import { type Config } from '../../config/schema.js';
3
3
  import type { SessionStore } from '../../session/store.js';
4
+ import type { TranscriptStoredRow } from '../../session/session-context-for-llm.js';
4
5
  import type { ModelManager } from '../models/index.js';
5
6
  export interface TaskTurnCompletion {
6
7
  sessionKey: string;
@@ -19,6 +20,12 @@ export interface TaskJudgeDecision {
19
20
  judgment: TaskJudgment;
20
21
  }
21
22
  export declare function parseTaskJudgeDecision(raw: string, criteriaCount: number): TaskJudgeDecision;
23
+ export declare function codingCompletionEvidence(rows: readonly TranscriptStoredRow[]): {
24
+ allowed: boolean;
25
+ workspace?: string;
26
+ revision?: string;
27
+ evidence?: unknown;
28
+ };
22
29
  export declare class TaskJudgeService {
23
30
  #private;
24
31
  private readonly options;
@@ -6,6 +6,7 @@ import { getApiKey, init_providers, resolveModel } from "../../providers/index.j
6
6
  import { TaskRepository } from "../../tasks/task-repository.js";
7
7
  import { TaskConversationRepository } from "../../tasks/task-conversation-repository.js";
8
8
  import { TaskRunRepository } from "../../tasks/task-run-repository.js";
9
+ import { readWorkspaceRevision } from "../coding/workspace-revision.js";
9
10
  import { completeWithResolvedCredentials } from "../../providers/model-call.js";
10
11
  import { TaskApplicationService } from "../../tasks/task-application-service.js";
11
12
  import { extractAssistantText, getAssistantMessageErrorReason, stripCodeFences } from "../../providers/model-response.js";
@@ -51,6 +52,21 @@ function parseTaskJudgeDecision(raw, criteriaCount) {
51
52
  }
52
53
  };
53
54
  }
55
+ function codingCompletionEvidence(rows) {
56
+ const entries = rows;
57
+ const start = entries.findLastIndex((row) => row.type === "custom" && row.customType === "coding_run_started");
58
+ const final = entries.findLastIndex((row) => row.type === "custom" && row.customType === "coding_verification");
59
+ const checkpoint = entries[Math.max(start, final)]?.data;
60
+ if (!checkpoint?.required) return { allowed: true };
61
+ if (start > final) return { allowed: false };
62
+ const evidence = Array.isArray(checkpoint.evidence) ? checkpoint.evidence : [];
63
+ return {
64
+ allowed: checkpoint.changed !== true || evidence.some((item) => item.kind === "check" && item.status === "passed") && evidence.some((item) => item.kind === "diff-review" && item.status === "passed") && evidence.every((item) => item.status === "passed"),
65
+ evidence,
66
+ workspace: typeof checkpoint.workspace === "string" ? checkpoint.workspace : void 0,
67
+ revision: typeof checkpoint.revision === "string" ? checkpoint.revision : void 0
68
+ };
69
+ }
54
70
  function resolveJudgeModel(config, sessionKey, runtimeModel) {
55
71
  if (config) {
56
72
  const profile = resolveEffectiveAgentProfileForSession(config, sessionKey);
@@ -94,12 +110,14 @@ var TaskJudgeService = class {
94
110
  return;
95
111
  }
96
112
  const history = compactHistory(await this.options.sessionStore.loadMessages(payload.sessionKey));
113
+ const proof = codingCompletionEvidence(await this.options.sessionStore.loadTranscriptRows(payload.sessionKey));
97
114
  const criteria = task.contract.acceptanceCriteria;
98
115
  const request = {
99
116
  role: "user",
100
117
  content: [
101
118
  "You are an independent task verifier. Be strict and evidence-driven.",
102
- "Mark a criterion complete only when the transcript or latest response directly proves it.",
119
+ "Mark a criterion complete only when observed tool results or user-provided facts prove it. An assistant completion claim is not verification evidence.",
120
+ `Runtime coding evidence: ${JSON.stringify(proof)}`,
103
121
  "needsUser is true only when a specific decision, permission, credential, or missing fact must come from the user.",
104
122
  "Make one clear recommendation. Explain the decisive reasons, rejected alternatives, uncertainty, and calibrated confidence.",
105
123
  "Return only JSON: {\"completedCriteria\":[0],\"needsUser\":false,\"nextAction\":\"...\",\"recommendation\":\"...\",\"reasons\":[\"...\"],\"rejectedAlternatives\":[{\"option\":\"...\",\"reason\":\"...\"}],\"uncertainty\":\"...\",\"confidence\":0.8}.",
@@ -120,6 +138,10 @@ var TaskJudgeService = class {
120
138
  const modelError = getAssistantMessageErrorReason(response);
121
139
  if (modelError) throw new Error(modelError);
122
140
  const decision = parseTaskJudgeDecision(extractAssistantText(response.content), criteria.length);
141
+ if (!proof.allowed || proof.workspace && (!proof.revision || await readWorkspaceRevision(proof.workspace) !== proof.revision)) {
142
+ decision.completedCriteria = [];
143
+ decision.judgment.reasons.unshift("Current workspace verification is missing, failed or stale.");
144
+ }
123
145
  const now = Date.now();
124
146
  const evidence = decision.completedCriteria.map((index) => ({
125
147
  kind: "state",
@@ -181,4 +203,4 @@ var TaskJudgeService = class {
181
203
  }
182
204
  };
183
205
  //#endregion
184
- export { TaskJudgeService, parseTaskJudgeDecision };
206
+ export { TaskJudgeService, codingCompletionEvidence, parseTaskJudgeDecision };
@@ -15,7 +15,6 @@ export interface DelegateToolDeps {
15
15
  to?: string;
16
16
  threadId?: string | number;
17
17
  } | null;
18
- hookRunner?: import('../../extensions/index.js').ExtensionHookRunner;
19
18
  toolExecutorConfig?: Partial<import('./executor.js').ToolExecutorConfig>;
20
19
  /**
21
20
  * Construct the child agent's tool set. Injected by `AgentToolsFactory` so
@@ -24,4 +23,6 @@ export interface DelegateToolDeps {
24
23
  */
25
24
  buildChildTools: (opts: BuildChildToolsOptions) => AgentTool<any, any>[];
26
25
  }
26
+ export declare const INSPECTION_TOOLS: Set<string>;
27
+ export declare function delegateToolNames(mode: 'inspect' | 'review' | 'implement', requested?: string[]): string[];
27
28
  export declare function createDelegateTool(deps: DelegateToolDeps): AgentTool;
@@ -1,9 +1,12 @@
1
+ import { readWorkspaceRevision } from "../coding/workspace-revision.js";
1
2
  import { EXTERNAL_TOOL_NAMES } from "../external-tools/gateway-tools.js";
2
3
  import "../external-tools/index.js";
3
4
  import { createDelegateChildHandle } from "../child-agent-factory.js";
5
+ import { runGit } from "../../execution-environments/git.js";
6
+ import { LocalWorktreeManager } from "../../execution-environments/local-worktree-manager.js";
7
+ import { SessionEnvironmentService } from "../../execution-environments/session-environment-service.js";
4
8
  import { Type } from "@sinclair/typebox";
5
9
  //#region src/agent/tools/delegate-tool.ts
6
- const DEFAULT_MAX_ITERATIONS = 30;
7
10
  const DEFAULT_DELEGATE_TOOLS = [
8
11
  "exec_command",
9
12
  "read_file",
@@ -36,160 +39,135 @@ const DELEGATE_BLOCKED_TOOLS = new Set([
36
39
  EXTERNAL_TOOL_NAMES.execute,
37
40
  "managed_job"
38
41
  ]);
42
+ const INSPECTION_TOOLS = new Set([
43
+ "read_file",
44
+ "grep",
45
+ "find",
46
+ "list_dir",
47
+ "review_workspace"
48
+ ]);
39
49
  const DelegateTaskSchema = Type.Object({
40
- goal: Type.String({ description: "Clear description of what the sub-agent should accomplish" }),
41
- context: Type.Optional(Type.String({ description: "Additional context the sub-agent needs (file paths, constraints, etc.)" })),
42
- toolset: Type.Optional(Type.Array(Type.String(), { description: "Tool names the sub-agent may use. Defaults to exec_command, read_file, write_file, apply_patch, grep, find, list_dir, web_search, web_fetch. Dangerous or interactive tools are always removed." })),
43
- maxIterations: Type.Optional(Type.Number({
44
- description: "Maximum tool executions in the sub-agent (default: 30)",
45
- default: DEFAULT_MAX_ITERATIONS
50
+ goal: Type.String({ minLength: 1 }),
51
+ context: Type.Optional(Type.String()),
52
+ mode: Type.Optional(Type.Union([
53
+ Type.Literal("inspect"),
54
+ Type.Literal("review"),
55
+ Type.Literal("implement")
56
+ ])),
57
+ toolset: Type.Optional(Type.Array(Type.String())),
58
+ maxIterations: Type.Optional(Type.Integer({
59
+ minimum: 1,
60
+ maximum: 60
46
61
  }))
47
62
  });
63
+ function delegateToolNames(mode, requested) {
64
+ const available = mode === "implement" ? new Set([
65
+ ...DEFAULT_DELEGATE_TOOLS,
66
+ "review_workspace",
67
+ "language_diagnostics"
68
+ ]) : INSPECTION_TOOLS;
69
+ return [...new Set(requested ?? [...available])].filter((name) => available.has(name) && !DELEGATE_BLOCKED_TOOLS.has(name));
70
+ }
48
71
  function createDelegateTool(deps) {
49
72
  return {
50
73
  name: "delegate_task",
51
- label: "🤖 Delegate",
52
- description: "Spawn a sub-agent for an isolated subtask with a fresh conversation (no parent transcript).\n\nThe sub-agent returns a text summary only — tool traces stay out of your context.\n\nWHEN TO USE:\n- Independent work (research, multi-file exploration) where you only need the task\n- Avoiding context bloat from long intermediate tool output\n\nWHEN NOT TO USE:\n- Tasks that need this chat history or user clarification\n- Single trivial steps\n\nSub-agents cannot use clarify, messaging, memory tools, todo, or nested delegate_task.",
74
+ label: "Delegate task",
53
75
  parameters: DelegateTaskSchema,
54
- async execute(_toolCallId, params, signal) {
55
- const p = params;
56
- const maxIterations = p.maxIterations ?? DEFAULT_MAX_ITERATIONS;
57
- if (!Number.isFinite(maxIterations) || maxIterations < 1 || maxIterations > 200) return {
58
- content: [{
59
- type: "text",
60
- text: "Invalid maxIterations (use 1–200)."
61
- }],
62
- details: {
63
- summary: "",
64
- iterations: 0
65
- }
66
- };
67
- const requested = p.toolset ?? [...DEFAULT_DELEGATE_TOOLS];
68
- const allowedNames = [...new Set(requested.map((t) => String(t).trim()).filter(Boolean).filter((t) => !DELEGATE_BLOCKED_TOOLS.has(t)))];
69
- if (allowedNames.length === 0) return {
70
- content: [{
71
- type: "text",
72
- text: "No allowed tools remain after applying the delegation blocklist. Expand `toolset` with safe tools."
73
- }],
74
- details: {
75
- summary: "",
76
- iterations: 0
77
- }
78
- };
79
- let model;
80
- try {
81
- model = deps.getSubagentModel();
82
- } catch (e) {
83
- return {
84
- content: [{
85
- type: "text",
86
- text: `delegate_task: ${e instanceof Error ? e.message : String(e)}`
87
- }],
88
- details: {
89
- summary: "",
90
- iterations: 0
91
- }
92
- };
76
+ description: "Run one bounded leaf worker with a fresh context. inspect/review receive only read tools; review reports findings against a workspace revision. implement requires an attached project and clean Git workspace, creates a separate managed worktree, and returns its patch for parent review. Child changes are never merged automatically. No nested delegation, external messages or background jobs. Up to 60 tool calls, 100k tokens and five minutes per child.",
77
+ supportsParallel: false,
78
+ idempotent: false,
79
+ async execute(_id, input, signal) {
80
+ signal?.throwIfAborted();
81
+ const mode = input.mode ?? "inspect";
82
+ const tools = delegateToolNames(mode, input.toolset);
83
+ if (!tools.length) throw new Error("No permitted tools in the requested toolset");
84
+ const parentSessionKey = deps.getCurrentContext?.()?.sessionKey;
85
+ const model = deps.getSubagentModel();
86
+ let workspace = deps.workspace, environmentId;
87
+ if (mode === "implement") {
88
+ if (!parentSessionKey) throw new Error("Implementation delegation requires a project session");
89
+ const parent = new SessionEnvironmentService().get(parentSessionKey);
90
+ if (!parent?.projectId) throw new Error("Attach this session to a project before implementation delegation");
91
+ const environment = await new LocalWorktreeManager().provisionManagedWorktree({
92
+ projectId: parent.projectId,
93
+ repositoryPath: workspace
94
+ });
95
+ workspace = environment.rootPath;
96
+ environmentId = environment.id;
93
97
  }
94
- const ctx = deps.getCurrentContext?.() ?? null;
95
- const parentSessionKey = ctx?.sessionKey;
96
- const childOptions = {
97
- workspace: deps.workspace,
98
- goal: p.goal,
99
- context: p.context,
98
+ const revision = await readWorkspaceRevision(workspace);
99
+ const child = createDelegateChildHandle({
100
+ workspace,
101
+ goal: mode === "review" ? `Independently review the actual changes. Inspect review_workspace and relevant source/tests. Report actionable defects with file and line evidence, severity and a concrete failure example. If there are no findings, state the checks and remaining uncertainty. Do not treat the parent's completion claim as evidence.\n\n${input.goal}` : input.goal,
102
+ context: input.context,
100
103
  requesterSessionKey: parentSessionKey,
101
- allowedToolNames: allowedNames,
102
- maxIterations,
104
+ allowedToolNames: tools,
105
+ maxIterations: input.maxIterations ?? 30,
103
106
  model,
104
107
  bus: deps.bus,
105
108
  getConfig: deps.getConfig,
106
109
  toolExecutorConfig: deps.toolExecutorConfig,
107
- buildChildTools: deps.buildChildTools
108
- };
109
- let childSessionKey;
110
- try {
111
- if (deps.hookRunner && parentSessionKey) {
112
- const { parseSessionKey, buildSessionKey } = await import("../../routing/session-key.js");
113
- const parsed = parseSessionKey(parentSessionKey);
114
- if (parsed) childSessionKey = buildSessionKey({
115
- agentId: "subagent",
116
- source: parsed.agentId,
117
- accountId: parsed.accountId,
118
- peerKind: parsed.peerKind,
119
- peerId: parsed.peerId,
120
- threadId: parsed.threadId,
121
- scopeId: parsed.scopeId
122
- });
123
- if (childSessionKey) {
124
- const r = await deps.hookRunner.runHooksWithResult("subagent_spawning", {
125
- childSessionKey,
126
- requester: {
127
- channel: ctx?.channel,
128
- accountId: ctx?.accountId,
129
- to: ctx?.to,
130
- threadId: ctx?.threadId
131
- },
132
- threadRequested: true,
133
- agentId: "subagent",
134
- label: "delegate_task"
135
- }, {
136
- sessionKey: parentSessionKey,
137
- agentId: ctx?.channel
138
- });
139
- if (r && r.status === "error") return {
140
- content: [{
141
- type: "text",
142
- text: `delegate_task: ${String(r.error || "subagent spawn blocked")}`
143
- }],
144
- details: {
145
- summary: "",
146
- iterations: 0
147
- }
148
- };
149
- }
150
- }
151
- } catch {}
152
- const child = createDelegateChildHandle(childOptions);
153
- if (signal) signal.addEventListener("abort", () => child.abort(), { once: true });
110
+ buildChildTools: deps.buildChildTools,
111
+ verifyChanges: mode === "implement"
112
+ });
113
+ const abort = () => child.abort();
114
+ signal?.addEventListener("abort", abort, { once: true });
115
+ if (signal?.aborted) abort();
154
116
  try {
155
- const { summary, toolIterations } = await child.run();
156
- try {
157
- if (deps.hookRunner && childSessionKey) await deps.hookRunner.runHooks("subagent_ended", {
158
- targetSessionKey: childSessionKey,
159
- accountId: ctx?.accountId
160
- }, { sessionKey: parentSessionKey });
161
- } catch {}
117
+ const result = await child.run();
118
+ const currentRevision = await readWorkspaceRevision(workspace);
119
+ const stale = mode !== "implement" && (!revision || revision !== currentRevision);
120
+ const patch = mode === "implement" ? await runGit(workspace, [
121
+ "diff",
122
+ "--no-ext-diff",
123
+ "--no-textconv",
124
+ "--binary",
125
+ "HEAD"
126
+ ]).catch(() => "") : void 0;
162
127
  return {
163
128
  content: [{
164
129
  type: "text",
165
- text: `Sub-agent completed:\n\n${summary}`
130
+ text: [
131
+ result.summary,
132
+ stale ? "Workspace changed or could not be fingerprinted; review findings require revalidation." : "",
133
+ environmentId ? `Changes retained in ${workspace} (environment ${environmentId}). Review and integrate from this workspace, then verify the parent workspace again.` : "",
134
+ patch ? `Patch preview:\n${patch.slice(0, 3e4)}` : ""
135
+ ].filter(Boolean).join("\n\n")
166
136
  }],
167
137
  details: {
168
- summary,
169
- iterations: toolIterations
138
+ status: stale && result.status === "success" ? "partial" : result.status,
139
+ mode,
140
+ summary: result.summary,
141
+ iterations: result.toolIterations,
142
+ revision: currentRevision,
143
+ reviewedRevision: revision,
144
+ ...result.verification ? { childVerification: result.verification } : {},
145
+ ...environmentId ? {
146
+ environmentId,
147
+ workspace,
148
+ patchTruncated: (patch?.length ?? 0) > 3e4
149
+ } : {}
170
150
  }
171
151
  };
172
152
  } catch (error) {
173
- child.abort();
174
- try {
175
- if (deps.hookRunner && childSessionKey) await deps.hookRunner.runHooks("subagent_ended", {
176
- targetSessionKey: childSessionKey,
177
- accountId: ctx?.accountId
178
- }, { sessionKey: parentSessionKey });
179
- } catch {}
180
153
  return {
181
154
  content: [{
182
155
  type: "text",
183
- text: `Sub-agent failed: ${error instanceof Error ? error.message : String(error)}`
156
+ text: `Delegation failed: ${String(error)}${environmentId ? `; work retained in ${workspace} (${environmentId})` : ""}`
184
157
  }],
185
158
  details: {
186
- summary: "",
187
- iterations: 0
159
+ status: signal?.aborted ? "cancelled" : "failed",
160
+ ...environmentId ? {
161
+ environmentId,
162
+ workspace
163
+ } : {}
188
164
  }
189
165
  };
166
+ } finally {
167
+ signal?.removeEventListener("abort", abort);
190
168
  }
191
169
  }
192
170
  };
193
171
  }
194
172
  //#endregion
195
- export { DEFAULT_DELEGATE_TOOLS, DELEGATE_BLOCKED_TOOLS, createDelegateTool };
173
+ export { DEFAULT_DELEGATE_TOOLS, DELEGATE_BLOCKED_TOOLS, INSPECTION_TOOLS, createDelegateTool, delegateToolNames };