@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.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-CAah-_8h.js → activity-store-BlxqErph.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BhXGsupm.js → agent-avatar-dicebear-CJJzpYYS.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-Blzn2H6t.js → agent-defaults-settings-panel-0dRjnL2s.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-Cmp-z8Y_.js → agents-je3sRGmk.js} +1 -1
- package/dist/gateway/static/root/assets/{api-B2tKxbcz.js → api-BbXzyQMj.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CezjAP1K.js → app-management-settings-panel-Cnn3i00c.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C-CfS05x.js → appearance-settings-BToQaw_v.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-7Y13_bqZ.js → apps-page-EpUZsl4h.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-BmSx7wzY.js → archive-plugin-DD2SweEH.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DI4CoIga.js → attachment-load-BFtcib5t.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-D04Xceck.js → automations-page-XS8wIl5o.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-wEO1OWk0.js → automations-workspace-BGQdHrip.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-BJQe8TRu.js → binary-plugins-Xs7pLHxR.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-BSzGjJC6.js → block-editor-BPdSzceB.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-DjAZ_LF2.js → browser-settings-page-DJGcm7rH.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-CRnkgZHI.js → browser-workflow-inputs-BAAc151l.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-CwbxA3B7.js → browser-workflows-page-DUPPvE30.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-jt9bqUMK.js → capabilities-settings-panel-cl9kYilL.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-Cz_TWY3a.js → channels-settings-BcIr-_GM.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-DuY4MGxe.js → channels-status-swr-CCBCtLDg.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-D3gj2D3U.js → chat-terminal-dock-DKW1M6aJ.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-Shs5vbzx.js → connectors-page-DNHqaZfX.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-expression-DgWHw0jX.js → cron-expression-Bijb0ZQu.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-CKg-RPbs.js → date-picker-BZuHw-SY.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-CVYkw-NN.js → dependency-picker-BsBD2JFY.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-Bf46oXTY.js → desktop-pet-Ceuw3QKb.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BJO_klc7.js → desktop-pet-settings-DctOXexM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-T2PmFFOW.js → extension-debug-page-BNlMPATK.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-2wAE2RCe.js → extension-page-CK4Uvzge.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Y9ZiCJ21.js → extension-settings-page-CpnXXemw.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-DaYY1Gkn.js → gateway-config-api-C_mlpe-r.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-BC3pgb_P.js → gateway-config-swr-826dipyU.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-eO3IzW_J.js → gateway-settings-DSSW17ed.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-uMcSfLru.js → gateway-startup-retry-DyvcAIMm.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-BAgrkyHc.js → heartbeat-settings-hbmIZTpg.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-GTjKH7LK.js → home-page-CaVvW77l.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-D1qlQA-A.js → image-generation-api-D7cyfks6.js} +1 -1
- package/dist/gateway/static/root/assets/{index-DUz0O54y.js → index-eZjksPvq.js} +10 -10
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CWGqL6o5.js → keyboard-shortcuts-settings-BQrDwwgi.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-DKJ-rks0.js → local-app-workbench-page-D3K1XmOM.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-Bfidv29d.js → local-apps-page-D-YWD6LS.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-CMZljTJx.js → locale-store-CBoCuIMx.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-DwAHrPbF.js → logs-page-DvLc9l59.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-BG7j1I9f.js → management-settings-DsULLUUv.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-AnmmpLs6.js → markdown-split-CjqlP6IB.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-PPCLt7fu.js → markdown-view-BXsHghJd.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-CGS-05cE.js → media-plugins-DQL029DU.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BbdwoxVo.js +3 -0
- package/dist/gateway/static/root/assets/{mobile-pairing-wizard-DoKK5GfV.js → mobile-pairing-wizard-gauprAae.js} +1 -1
- package/dist/gateway/static/root/assets/models-hub-cache-88f4fzYS.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-Lr8rsFAR.js → notes-page-AsEfLZt9.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-workbench-ISWnKLxO.js → notes-workbench-CI30cDh3.js} +2 -2
- package/dist/gateway/static/root/assets/{oauth-api-4VeMbkTJ.js → oauth-api-BjSUDIgq.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-BU0HiZtv.js → product-open-page-CAJeUXeU.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-BZqr4yam.js → project-detail-page-jO_4I5zN.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-Dau8733A.js → projects-page-BrTGFME0.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-CWOtPFrE.js → registry-api-BhGKnvLP.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-DdChlvGP.js → remote-access-hub-CH70D5SH.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CmZTNv1W.js → runtime-tools-settings-panel-DH6EilMV.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-XlVPyiVQ.js → schema-form-DYHmEZeZ.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-C3kADsd4.js → sessions-page-hbfUNtNs.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-Vg3_jua6.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-DblUeM3V.js → settings-page-BHwPd_M3.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-bDfRfSnq.js → setup-status-panel-DkcpWSss.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-DBMWFMN-.js → share-preview-page-BjwrS03F.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-Bu6lIStj.js → shares-settings-BL4DEt6p.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CafhNktn.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-CSOseeQe.js → skills-page-OHyK25op.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-CniRGhkJ.js → skills-page.utils-DQx9ulmg.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-D0GqNpKy.js → system-settings-panel-wO7DWv4C.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-BRCq-nR7.js → task-detail-page-anyomXsu.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-uxUwr10D.js → theme-store-hybK3oC9.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-BtjS2nrM.js → tunnel-api-CVC8BHZu.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-TwuAycG8.js → use-autosave-DMvRu2XZ.js} +1 -1
- package/dist/gateway/static/root/assets/{user-context-page-CbqPu8xZ.js → user-context-page-BBk9YdBn.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-CzwG5plu.js → voice-api-key-field-DuBK2NDG.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-MqyI6cgq.js → voice-config-api-CBbiF1T3.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-DS15FzQA.js → work-discovery-overlay-B7VXWpDr.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C_boCemi.js → workflow-run-setup-panel-BokVAsWN.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-CaI2ruyy.js → workflows-page-RUTv0yvR.js} +1 -1
- package/dist/gateway/static/root/index.html +11 -11
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/turn-outcome.js +3 -1
- package/dist/src/agent/agent-instance-gateway.d.ts +3 -1
- package/dist/src/agent/agent-manager.d.ts +2 -4
- package/dist/src/agent/agent-manager.js +24 -28
- package/dist/src/agent/background-review/coordinator.js +1 -1
- package/dist/src/agent/background-review/run-background-review.js +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +10 -7
- package/dist/src/agent/child-agent-factory.js +112 -158
- package/dist/src/agent/coding/index.d.ts +1 -1
- package/dist/src/agent/coding/index.js +2 -2
- package/dist/src/agent/coding/repository-instructions.d.ts +12 -0
- package/dist/src/agent/coding/repository-instructions.js +76 -0
- package/dist/src/agent/coding/run-verification.d.ts +34 -0
- package/dist/src/agent/coding/run-verification.js +134 -0
- package/dist/src/agent/coding/verification-command.d.ts +3 -0
- package/dist/src/agent/coding/verification-command.js +50 -0
- package/dist/src/agent/coding/workspace-revision.d.ts +2 -0
- package/dist/src/agent/coding/workspace-revision.js +77 -0
- package/dist/src/agent/commands/command-isolation.d.ts +21 -0
- package/dist/src/agent/commands/command-isolation.js +71 -0
- package/dist/src/agent/commands/command-registry.d.ts +56 -0
- package/dist/src/agent/commands/command-registry.js +259 -0
- package/dist/src/agent/embedded/index.js +1 -1
- package/dist/src/agent/embedded/run-for-session.js +2 -1
- package/dist/src/agent/embedded/run-turn.js +88 -25
- package/dist/src/agent/embedded/session-tool-result-guard.js +2 -2
- package/dist/src/agent/embedded/subscribe-session.d.ts +2 -1
- package/dist/src/agent/embedded/subscribe-session.js +2 -1
- package/dist/src/agent/embedded/types.d.ts +3 -1
- package/dist/src/agent/embedded/xopc-tools-bridge.js +4 -1
- package/dist/src/agent/image/index.js +1 -1
- package/dist/src/agent/index.js +3 -3
- package/dist/src/agent/memory/user-context-coordinator.js +1 -1
- package/dist/src/agent/middleware/index.d.ts +0 -5
- package/dist/src/agent/middleware/index.js +1 -2
- package/dist/src/agent/orchestration/agent-event-handler.d.ts +0 -5
- package/dist/src/agent/orchestration/agent-event-handler.js +1 -96
- package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
- package/dist/src/agent/orchestration/agent-turn-policy.js +5 -5
- package/dist/src/agent/orchestration/index.d.ts +1 -1
- package/dist/src/agent/orchestration/index.js +2 -2
- package/dist/src/agent/orchestration/loop-guard.d.ts +4 -31
- package/dist/src/agent/orchestration/loop-guard.js +14 -99
- package/dist/src/agent/prompt/sections/tooling.js +2 -4
- package/dist/src/agent/sandbox/types.d.ts +2 -2
- package/dist/src/agent/sandbox/types.js +1 -1
- package/dist/src/agent/service/direct-turn-helpers.js +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +1 -1
- package/dist/src/agent/service.d.ts +0 -2
- package/dist/src/agent/service.js +6 -23
- package/dist/src/agent/tasks/task-judge-service.d.ts +7 -0
- package/dist/src/agent/tasks/task-judge-service.js +24 -2
- package/dist/src/agent/tools/delegate-tool.d.ts +2 -1
- package/dist/src/agent/tools/delegate-tool.js +102 -124
- package/dist/src/agent/tools/exec-command.d.ts +8 -1
- package/dist/src/agent/tools/exec-command.js +77 -169
- package/dist/src/agent/tools/executor.js +9 -2
- package/dist/src/agent/tools/factory.js +50 -5
- package/dist/src/agent/tools/find.d.ts +10 -13
- package/dist/src/agent/tools/find.js +33 -80
- package/dist/src/agent/tools/grep.d.ts +14 -18
- package/dist/src/agent/tools/grep.js +56 -144
- package/dist/src/agent/tools/index.d.ts +0 -1
- package/dist/src/agent/tools/index.js +2 -3
- package/dist/src/agent/tools/language-diagnostics.d.ts +11 -0
- package/dist/src/agent/tools/language-diagnostics.js +62 -0
- package/dist/src/agent/tools/managed-job-tool.d.ts +2 -1
- package/dist/src/agent/tools/managed-job-tool.js +58 -118
- package/dist/src/agent/tools/read.js +24 -7
- package/dist/src/agent/tools/repository-search.d.ts +5 -0
- package/dist/src/agent/tools/repository-search.js +56 -0
- package/dist/src/agent/tools/review-workspace.d.ts +2 -0
- package/dist/src/agent/tools/review-workspace.js +103 -0
- package/dist/src/agent/tools/write.js +4 -4
- package/dist/src/agent/transcript/index.js +2 -2
- package/dist/src/agent/transcript/transcript-hygiene.js +2 -2
- package/dist/src/agent/workflow/subagent-runner.d.ts +0 -2
- package/dist/src/agent/workflow/subagent-runner.js +12 -31
- package/dist/src/agent-config/schema.d.ts +42 -0
- package/dist/src/agent-config/schema.js +5 -0
- package/dist/src/cli/commands/agent.js +2 -2
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/profile.js +1 -1
- package/dist/src/cli/commands/tunnel.js +1 -1
- package/dist/src/cli/commands/update.js +1 -1
- package/dist/src/cli/extension-cli-register.js +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/config/schema.d.ts +28 -0
- package/dist/src/execution-environments/local-worktree-manager.d.ts +3 -1
- package/dist/src/execution-environments/local-worktree-manager.js +8 -3
- package/dist/src/execution-environments/session-environment-service.js +5 -3
- package/dist/src/gateway/hono/lib/config-payload.d.ts +7 -0
- package/dist/src/gateway/hono/routes/sessions.js +1 -1
- package/dist/src/gateway/media-access.js +1 -1
- package/dist/src/gateway/run-loop.js +1 -1
- package/dist/src/gateway/service/run-gateway-agent.js +4 -1
- package/dist/src/gateway/service.js +3 -3
- package/dist/src/gateway/session-reset-service.js +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +0 -6
- package/dist/src/gateway/workspace-ripgrep.js +2 -40
- package/dist/src/infra/ripgrep.d.ts +13 -0
- package/dist/src/infra/ripgrep.js +46 -0
- package/dist/src/proactive/execution/agent-executor.js +1 -1
- package/dist/src/session/store.js +1 -1
- package/dist/src/session/turn-outcome-projector.js +26 -6
- package/dist/src/tasks/task-run-coordinator.d.ts +2 -2
- package/dist/src/tasks/task-run-coordinator.js +14 -12
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/dist/src/voice/realtime/agentEngine.d.ts +1 -1
- package/dist/src/voice/realtime/runtime.d.ts +3 -68
- package/dist/src/voice/realtime/runtime.types.d.ts +69 -0
- package/dist/src/voice/realtime/runtime.types.js +1 -0
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-ZrbGRiGY.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CSYy6SUa.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BNMc4l04.js +0 -1
- package/dist/src/agent/coding/turn-diff-tracker.d.ts +0 -67
- package/dist/src/agent/coding/turn-diff-tracker.js +0 -231
- package/dist/src/agent/middleware/self-verify.d.ts +0 -136
- package/dist/src/agent/middleware/self-verify.js +0 -380
- package/dist/src/agent/tools/execute-code-tool.d.ts +0 -11
- package/dist/src/agent/tools/execute-code-tool.js +0 -208
|
@@ -1,105 +1,20 @@
|
|
|
1
|
-
import {
|
|
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
|
|
23
|
-
return
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return
|
|
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
|
-
*
|
|
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'
|
|
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;
|
|
@@ -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
|
|
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({
|
|
41
|
-
context: Type.Optional(Type.String(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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: "
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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:
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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:
|
|
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
|
-
|
|
169
|
-
|
|
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: `
|
|
156
|
+
text: `Delegation failed: ${String(error)}${environmentId ? `; work retained in ${workspace} (${environmentId})` : ""}`
|
|
184
157
|
}],
|
|
185
158
|
details: {
|
|
186
|
-
|
|
187
|
-
|
|
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 };
|