@prestyj/cli 5.30.0 → 5.30.2
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/README.md +54 -39
- package/assets/skills/bulletproof/SKILL.md +1 -1
- package/assets/skills/clarify/SKILL.md +1 -1
- package/assets/skills/code-review/SKILL.md +1 -1
- package/assets/skills/compliance-guard/SKILL.md +1 -1
- package/assets/skills/durable/SKILL.md +1 -1
- package/assets/skills/evidence-led-ui/SKILL.md +1 -1
- package/assets/skills/lean/SKILL.md +1 -1
- package/assets/skills/refactoring/SKILL.md +1 -1
- package/assets/skills/root-cause/SKILL.md +1 -1
- package/assets/skills/shared-language/SKILL.md +1 -1
- package/assets/skills/tdd/SKILL.md +1 -1
- package/dist/app-sidecar/app-settings.d.ts +63 -0
- package/dist/app-sidecar/app-settings.js +147 -0
- package/dist/app-sidecar/app-settings.js.map +1 -0
- package/dist/app-sidecar/attachments.d.ts +11 -0
- package/dist/app-sidecar/attachments.js +47 -0
- package/dist/app-sidecar/attachments.js.map +1 -0
- package/dist/app-sidecar/auth-routes.d.ts +3 -0
- package/dist/app-sidecar/auth-routes.js +293 -0
- package/dist/app-sidecar/auth-routes.js.map +1 -0
- package/dist/app-sidecar/autopilot-runner.d.ts +62 -0
- package/dist/app-sidecar/autopilot-runner.js +373 -0
- package/dist/app-sidecar/autopilot-runner.js.map +1 -0
- package/dist/app-sidecar/file-search.d.ts +15 -0
- package/dist/app-sidecar/file-search.js +103 -0
- package/dist/app-sidecar/file-search.js.map +1 -0
- package/dist/app-sidecar/hf-pull-manager.d.ts +20 -0
- package/dist/app-sidecar/hf-pull-manager.js +224 -0
- package/dist/app-sidecar/hf-pull-manager.js.map +1 -0
- package/dist/app-sidecar/history-routes.d.ts +3 -0
- package/dist/app-sidecar/history-routes.js +375 -0
- package/dist/app-sidecar/history-routes.js.map +1 -0
- package/dist/app-sidecar/history.d.ts +67 -0
- package/dist/app-sidecar/history.js +23 -0
- package/dist/app-sidecar/history.js.map +1 -0
- package/dist/app-sidecar/http.d.ts +5 -0
- package/dist/app-sidecar/http.js +27 -0
- package/dist/app-sidecar/http.js.map +1 -0
- package/dist/app-sidecar/integration-routes.d.ts +3 -0
- package/dist/app-sidecar/integration-routes.js +286 -0
- package/dist/app-sidecar/integration-routes.js.map +1 -0
- package/dist/app-sidecar/json-mode.d.ts +10 -0
- package/dist/app-sidecar/json-mode.js +73 -0
- package/dist/app-sidecar/json-mode.js.map +1 -0
- package/dist/app-sidecar/keep-awake.d.ts +4 -0
- package/dist/app-sidecar/keep-awake.js +5 -0
- package/dist/app-sidecar/keep-awake.js.map +1 -0
- package/dist/app-sidecar/mcp-routes.d.ts +3 -0
- package/dist/app-sidecar/mcp-routes.js +185 -0
- package/dist/app-sidecar/mcp-routes.js.map +1 -0
- package/dist/app-sidecar/mcp-rows.d.ts +31 -0
- package/dist/app-sidecar/mcp-rows.js +77 -0
- package/dist/app-sidecar/mcp-rows.js.map +1 -0
- package/dist/app-sidecar/nolan-context.d.ts +20 -0
- package/dist/app-sidecar/nolan-context.js +55 -0
- package/dist/app-sidecar/nolan-context.js.map +1 -0
- package/dist/app-sidecar/progress-manager.d.ts +10 -0
- package/dist/app-sidecar/progress-manager.js +116 -0
- package/dist/app-sidecar/progress-manager.js.map +1 -0
- package/dist/app-sidecar/prompt-routes.d.ts +3 -0
- package/dist/app-sidecar/prompt-routes.js +355 -0
- package/dist/app-sidecar/prompt-routes.js.map +1 -0
- package/dist/app-sidecar/repo-polls.d.ts +18 -0
- package/dist/app-sidecar/repo-polls.js +45 -0
- package/dist/app-sidecar/repo-polls.js.map +1 -0
- package/dist/app-sidecar/route-context.d.ts +147 -0
- package/dist/app-sidecar/route-context.js +2 -0
- package/dist/app-sidecar/route-context.js.map +1 -0
- package/dist/app-sidecar/run-control-routes.d.ts +3 -0
- package/dist/app-sidecar/run-control-routes.js +437 -0
- package/dist/app-sidecar/run-control-routes.js.map +1 -0
- package/dist/app-sidecar/session-routes.d.ts +3 -0
- package/dist/app-sidecar/session-routes.js +115 -0
- package/dist/app-sidecar/session-routes.js.map +1 -0
- package/dist/app-sidecar/session-types.d.ts +39 -0
- package/dist/app-sidecar/session-types.js +5 -0
- package/dist/app-sidecar/session-types.js.map +1 -0
- package/dist/app-sidecar/task-routes.d.ts +3 -0
- package/dist/app-sidecar/task-routes.js +232 -0
- package/dist/app-sidecar/task-routes.js.map +1 -0
- package/dist/app-sidecar/usage.d.ts +19 -0
- package/dist/app-sidecar/usage.js +153 -0
- package/dist/app-sidecar/usage.js.map +1 -0
- package/dist/app-sidecar/workspace-routes.d.ts +3 -0
- package/dist/app-sidecar/workspace-routes.js +374 -0
- package/dist/app-sidecar/workspace-routes.js.map +1 -0
- package/dist/app-sidecar.js +541 -3971
- package/dist/app-sidecar.js.map +1 -1
- package/dist/chat-agents/jiwa.js +2 -0
- package/dist/chat-agents/jiwa.js.map +1 -1
- package/dist/chat-agents/memory.js +2 -0
- package/dist/chat-agents/memory.js.map +1 -1
- package/dist/cli/auth.js +13 -9
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli.js +10 -11
- package/dist/cli.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/core/acceptance-checks.js +3 -9
- package/dist/core/acceptance-checks.js.map +1 -1
- package/dist/core/agent-session/helpers.d.ts +26 -0
- package/dist/core/agent-session/helpers.js +47 -0
- package/dist/core/agent-session/helpers.js.map +1 -0
- package/dist/core/agent-session/mcp-tools.d.ts +68 -0
- package/dist/core/agent-session/mcp-tools.js +195 -0
- package/dist/core/agent-session/mcp-tools.js.map +1 -0
- package/dist/core/agent-session/run-loop-monitor.d.ts +63 -0
- package/dist/core/agent-session/run-loop-monitor.js +164 -0
- package/dist/core/agent-session/run-loop-monitor.js.map +1 -0
- package/dist/core/agent-session/transcript-markers.d.ts +57 -0
- package/dist/core/agent-session/transcript-markers.js +166 -0
- package/dist/core/agent-session/transcript-markers.js.map +1 -0
- package/dist/core/agent-session/verification-tracker.d.ts +50 -0
- package/dist/core/agent-session/verification-tracker.js +269 -0
- package/dist/core/agent-session/verification-tracker.js.map +1 -0
- package/dist/core/agent-session.d.ts +27 -87
- package/dist/core/agent-session.js +166 -713
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-providers.js +3 -3
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/autopilot-cycle.d.ts +8 -2
- package/dist/core/autopilot-cycle.js +22 -3
- package/dist/core/autopilot-cycle.js.map +1 -1
- package/dist/core/bundled-agents.js +6 -6
- package/dist/core/bundled-agents.js.map +1 -1
- package/dist/core/checklist-git.d.ts +19 -0
- package/dist/core/checklist-git.js +54 -0
- package/dist/core/checklist-git.js.map +1 -0
- package/dist/core/checklist-items.d.ts +10 -1
- package/dist/core/checklist-items.js +22 -0
- package/dist/core/checklist-items.js.map +1 -1
- package/dist/core/checklist-prompt.d.ts +14 -3
- package/dist/core/checklist-prompt.js +38 -8
- package/dist/core/checklist-prompt.js.map +1 -1
- package/dist/core/checklist-snapshot.d.ts +5 -1
- package/dist/core/checklist-snapshot.js +20 -3
- package/dist/core/checklist-snapshot.js.map +1 -1
- package/dist/core/checklist-store.d.ts +5 -1
- package/dist/core/checklist-store.js +35 -4
- package/dist/core/checklist-store.js.map +1 -1
- package/dist/core/context-limits.js +1 -1
- package/dist/core/context-limits.js.map +1 -1
- package/dist/core/event-bus.d.ts +1 -1
- package/dist/core/event-bus.js +39 -13
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/extensions/plugin-bundles.js +4 -2
- package/dist/core/extensions/plugin-bundles.js.map +1 -1
- package/dist/core/hashline.d.ts +10 -8
- package/dist/core/hashline.js.map +1 -1
- package/dist/core/mcp/client.js +2 -0
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/loopback.d.ts +2 -2
- package/dist/core/mcp/loopback.js +2 -2
- package/dist/core/mcp/shared-pool.js +4 -3
- package/dist/core/mcp/shared-pool.js.map +1 -1
- package/dist/core/persistent-shell.js +2 -1
- package/dist/core/persistent-shell.js.map +1 -1
- package/dist/core/plan-handoff.d.ts +30 -0
- package/dist/core/plan-handoff.js +10 -0
- package/dist/core/plan-handoff.js.map +1 -0
- package/dist/core/plan-submission-gate.d.ts +28 -0
- package/dist/core/plan-submission-gate.js +27 -0
- package/dist/core/plan-submission-gate.js.map +1 -0
- package/dist/core/process-manager.js +9 -1
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/project-health-scan.d.ts +109 -0
- package/dist/core/project-health-scan.js +673 -0
- package/dist/core/project-health-scan.js.map +1 -0
- package/dist/core/project-health-score.d.ts +41 -0
- package/dist/core/project-health-score.js +257 -0
- package/dist/core/project-health-score.js.map +1 -0
- package/dist/core/prompt-commands.js +44 -6
- package/dist/core/prompt-commands.js.map +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-storage.d.ts +1 -0
- package/dist/core/session-storage.js +1 -1
- package/dist/core/session-storage.js.map +1 -1
- package/dist/core/skills.js +6 -9
- package/dist/core/skills.js.map +1 -1
- package/dist/core/style-packs/index.js +2 -11
- package/dist/core/style-packs/index.js.map +1 -1
- package/dist/core/style-packs/packs.d.ts +3 -12
- package/dist/core/style-packs/packs.js +132 -173
- package/dist/core/style-packs/packs.js.map +1 -1
- package/dist/core/subagent-manager.js +11 -6
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-receipt.js +3 -4
- package/dist/core/subagent-receipt.js.map +1 -1
- package/dist/core/ui-adoption.js +2 -0
- package/dist/core/ui-adoption.js.map +1 -1
- package/dist/core/ui-registry.js +5 -4
- package/dist/core/ui-registry.js.map +1 -1
- package/dist/core/verification-evidence.d.ts +21 -2
- package/dist/core/verification-evidence.js +283 -8
- package/dist/core/verification-evidence.js.map +1 -1
- package/dist/core/verification-gate.js +4 -2
- package/dist/core/verification-gate.js.map +1 -1
- package/dist/core/verify-commands.js +2 -3
- package/dist/core/verify-commands.js.map +1 -1
- package/dist/modes/agent-home-mode.js +1 -4
- package/dist/modes/agent-home-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.js +13 -8
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/system-prompt.js +70 -87
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/ask-user.js +13 -74
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/bash.d.ts +3 -1
- package/dist/tools/bash.js +28 -84
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/checklist.d.ts +7 -14
- package/dist/tools/checklist.js +22 -41
- package/dist/tools/checklist.js.map +1 -1
- package/dist/tools/code-nav.js +7 -29
- package/dist/tools/code-nav.js.map +1 -1
- package/dist/tools/edit.d.ts +4 -9
- package/dist/tools/edit.js +175 -65
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/enter-plan.js +2 -7
- package/dist/tools/enter-plan.js.map +1 -1
- package/dist/tools/exit-plan.js +2 -3
- package/dist/tools/exit-plan.js.map +1 -1
- package/dist/tools/find.js +3 -4
- package/dist/tools/find.js.map +1 -1
- package/dist/tools/grep.js +9 -20
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/index.js +10 -7
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/ls.js +3 -3
- package/dist/tools/ls.js.map +1 -1
- package/dist/tools/prompt-hints.js +34 -47
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/read-only-bash.js +3 -0
- package/dist/tools/read-only-bash.js.map +1 -1
- package/dist/tools/read.js +8 -20
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/search-code.js +4 -12
- package/dist/tools/search-code.js.map +1 -1
- package/dist/tools/skill.js +13 -7
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/subagent-control.js +7 -22
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent.js +1 -1
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/task-output.js +4 -15
- package/dist/tools/task-output.js.map +1 -1
- package/dist/tools/task-send.js +5 -17
- package/dist/tools/task-send.js.map +1 -1
- package/dist/tools/task-stop.js +2 -2
- package/dist/tools/task-stop.js.map +1 -1
- package/dist/tools/tool-search.js +2 -7
- package/dist/tools/tool-search.js.map +1 -1
- package/dist/tools/tool-tiers.d.ts +21 -4
- package/dist/tools/tool-tiers.js +44 -17
- package/dist/tools/tool-tiers.js.map +1 -1
- package/dist/tools/web-fetch.js +7 -33
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/write.js +3 -4
- package/dist/tools/write.js.map +1 -1
- package/dist/ui/App.js +20 -26
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/Footer.js +1 -2
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/components/InputArea.js +0 -2
- package/dist/ui/components/InputArea.js.map +1 -1
- package/dist/ui/components/ToolExecution.js +4 -3
- package/dist/ui/components/ToolExecution.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +7 -6
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/sessions.js +1 -5
- package/dist/ui/sessions.js.map +1 -1
- package/dist/ui/utils/highlight.d.ts +0 -5
- package/dist/ui/utils/highlight.js +3 -49
- package/dist/ui/utils/highlight.js.map +1 -1
- package/dist/ui/utils/markdown-renderer.d.ts +6 -0
- package/dist/ui/utils/markdown-renderer.js +21 -5
- package/dist/ui/utils/markdown-renderer.js.map +1 -1
- package/dist/utils/process.js +3 -3
- package/dist/utils/process.js.map +1 -1
- package/dist/utils/shared-poll.d.ts +37 -0
- package/dist/utils/shared-poll.js +104 -0
- package/dist/utils/shared-poll.js.map +1 -0
- package/package.json +8 -8
- package/dist/core/api-benchmark.d.ts +0 -63
- package/dist/core/api-benchmark.js +0 -381
- package/dist/core/api-benchmark.js.map +0 -1
- package/dist/core/bash-spawn-benchmark.d.ts +0 -1
- package/dist/core/bash-spawn-benchmark.js +0 -139
- package/dist/core/bash-spawn-benchmark.js.map +0 -1
- package/dist/core/cache-warm-benchmark.d.ts +0 -21
- package/dist/core/cache-warm-benchmark.js +0 -170
- package/dist/core/cache-warm-benchmark.js.map +0 -1
- package/dist/core/fast-apply-benchmark.d.ts +0 -25
- package/dist/core/fast-apply-benchmark.js +0 -284
- package/dist/core/fast-apply-benchmark.js.map +0 -1
- package/dist/core/hashline-edit-benchmark.d.ts +0 -88
- package/dist/core/hashline-edit-benchmark.js +0 -518
- package/dist/core/hashline-edit-benchmark.js.map +0 -1
- package/dist/core/semantic-search-benchmark.d.ts +0 -36
- package/dist/core/semantic-search-benchmark.js +0 -211
- package/dist/core/semantic-search-benchmark.js.map +0 -1
- package/dist/core/speed-benchmark.d.ts +0 -132
- package/dist/core/speed-benchmark.js +0 -410
- package/dist/core/speed-benchmark.js.map +0 -1
- package/dist/ui/activity-phrases.d.ts +0 -10
- package/dist/ui/activity-phrases.js +0 -184
- package/dist/ui/activity-phrases.js.map +0 -1
- package/dist/ui/components/PlanApproval.d.ts +0 -7
- package/dist/ui/components/PlanApproval.js +0 -60
- package/dist/ui/components/PlanApproval.js.map +0 -1
- package/dist/ui/components/PlanBanner.d.ts +0 -5
- package/dist/ui/components/PlanBanner.js +0 -31
- package/dist/ui/components/PlanBanner.js.map +0 -1
- package/dist/ui/components/PlanProgress.d.ts +0 -6
- package/dist/ui/components/PlanProgress.js +0 -30
- package/dist/ui/components/PlanProgress.js.map +0 -1
- package/dist/ui/hooks/useMinDisplayTime.d.ts +0 -10
- package/dist/ui/hooks/useMinDisplayTime.js +0 -34
- package/dist/ui/hooks/useMinDisplayTime.js.map +0 -1
- package/dist/ui/hooks/useSessionManager.d.ts +0 -12
- package/dist/ui/hooks/useSessionManager.js +0 -43
- package/dist/ui/hooks/useSessionManager.js.map +0 -1
- package/dist/ui/hooks/useSlashCommands.d.ts +0 -6
- package/dist/ui/hooks/useSlashCommands.js +0 -11
- package/dist/ui/hooks/useSlashCommands.js.map +0 -1
- package/dist/ui/terminal-history-spacing.d.ts +0 -1
- package/dist/ui/terminal-history-spacing.js +0 -2
- package/dist/ui/terminal-history-spacing.js.map +0 -1
- package/dist/ui/utils/markdown-cache.d.ts +0 -10
- package/dist/ui/utils/markdown-cache.js +0 -58
- package/dist/ui/utils/markdown-cache.js.map +0 -1
- package/dist/ui/utils/token-to-ansi.d.ts +0 -8
- package/dist/ui/utils/token-to-ansi.js +0 -323
- package/dist/ui/utils/token-to-ansi.js.map +0 -1
|
@@ -14,20 +14,14 @@ import { z } from "zod";
|
|
|
14
14
|
*/
|
|
15
15
|
export const MAX_ACCEPTANCE_CHECKS = 10;
|
|
16
16
|
export const AcceptanceCheckSchema = z.object({
|
|
17
|
-
type: z
|
|
18
|
-
|
|
19
|
-
.describe("file_exists: the path exists when the helper finishes. file_changed: the helper " +
|
|
20
|
-
"wrote or edited the path. command_passed: the helper ran this exact command and " +
|
|
21
|
-
"its last run exited 0 with no file edits after it."),
|
|
22
|
-
target: z.string().min(1).max(500).describe("The file path or the exact shell command"),
|
|
17
|
+
type: z.enum(["file_exists", "file_changed", "command_passed"]),
|
|
18
|
+
target: z.string().min(1).max(500).describe("Path or exact command"),
|
|
23
19
|
});
|
|
24
20
|
export const AcceptanceChecksParam = z
|
|
25
21
|
.array(AcceptanceCheckSchema)
|
|
26
22
|
.max(MAX_ACCEPTANCE_CHECKS)
|
|
27
23
|
.optional()
|
|
28
|
-
.describe("
|
|
29
|
-
"helper's real tool calls when it finishes, at no model cost, and reported as " +
|
|
30
|
-
"PASS / FAIL / UNVERIFIED alongside its answer.");
|
|
24
|
+
.describe("Verified by code on finish");
|
|
31
25
|
const MUTATING_TOOLS = new Set(["write", "edit"]);
|
|
32
26
|
/**
|
|
33
27
|
* Parse checks arriving over a process boundary (the worker's stdin). Invalid
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acceptance-checks.js","sourceRoot":"","sources":["../../src/core/acceptance-checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,IAAI,EAAE,CAAC
|
|
1
|
+
{"version":3,"file":"acceptance-checks.js","sourceRoot":"","sources":["../../src/core/acceptance-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Message, Provider } from "@prestyj/ai";
|
|
2
|
+
/**
|
|
3
|
+
* A run whose tool calls fail more often than this is thrashing, not
|
|
4
|
+
* progressing — refuse to extend its turn budget.
|
|
5
|
+
*/
|
|
6
|
+
export declare const TURN_EXTENSION_MAX_FAILURE_RATIO = 0.5;
|
|
7
|
+
/** Resolve the per-result cap passed to the agent loop for the active transport. */
|
|
8
|
+
export declare function resolveSessionToolResultCharLimit(model: string, provider: Provider, accountId?: string): number;
|
|
9
|
+
/**
|
|
10
|
+
* Aggregate budget for ALL tool results produced in one assistant turn.
|
|
11
|
+
* Individual results are already capped, but wide parallel fan-outs (GPT-5.6's
|
|
12
|
+
* signature behavior) were observed injecting 100k+ uncached tokens in a single
|
|
13
|
+
* turn. ~15% of the context window in chars (1 token ≈ 3.5 chars), floored at
|
|
14
|
+
* 100KB so small windows still fit two full-size reads, ceilinged at 240KB so
|
|
15
|
+
* 1M-context models don't waive the budget entirely.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveSessionTurnToolResultCharLimit(model: string, provider: Provider, accountId?: string): number;
|
|
18
|
+
/** Marker the compactor prepends to the summary message it injects. */
|
|
19
|
+
/**
|
|
20
|
+
* True when an assistant message ends a turn with tool calls still awaiting
|
|
21
|
+
* their results. Inserting a user message there would orphan the tool_use
|
|
22
|
+
* blocks and the provider rejects the next request.
|
|
23
|
+
*/
|
|
24
|
+
export declare function hasUnresolvedToolCalls(message: Message): boolean;
|
|
25
|
+
/** Expand a leading `~` so `/import ~/.codex/...` works from any shell. */
|
|
26
|
+
export declare function resolveHomePath(filePath: string): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getContextWindow, getToolResultCharLimit } from "../model-registry.js";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* A run whose tool calls fail more often than this is thrashing, not
|
|
6
|
+
* progressing — refuse to extend its turn budget.
|
|
7
|
+
*/
|
|
8
|
+
export const TURN_EXTENSION_MAX_FAILURE_RATIO = 0.5;
|
|
9
|
+
// ── Tool-result policy ─────────────────────────────────────
|
|
10
|
+
/** Resolve the per-result cap passed to the agent loop for the active transport. */
|
|
11
|
+
export function resolveSessionToolResultCharLimit(model, provider, accountId) {
|
|
12
|
+
return (getToolResultCharLimit(model, { provider, accountId }) ??
|
|
13
|
+
Math.floor(getContextWindow(model, { provider, accountId }) * 3.5 * 0.3));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Aggregate budget for ALL tool results produced in one assistant turn.
|
|
17
|
+
* Individual results are already capped, but wide parallel fan-outs (GPT-5.6's
|
|
18
|
+
* signature behavior) were observed injecting 100k+ uncached tokens in a single
|
|
19
|
+
* turn. ~15% of the context window in chars (1 token ≈ 3.5 chars), floored at
|
|
20
|
+
* 100KB so small windows still fit two full-size reads, ceilinged at 240KB so
|
|
21
|
+
* 1M-context models don't waive the budget entirely.
|
|
22
|
+
*/
|
|
23
|
+
export function resolveSessionTurnToolResultCharLimit(model, provider, accountId) {
|
|
24
|
+
const contextChars = getContextWindow(model, { provider, accountId }) * 3.5;
|
|
25
|
+
return Math.max(100_000, Math.min(Math.floor(contextChars * 0.15), 240_000));
|
|
26
|
+
}
|
|
27
|
+
/** Marker the compactor prepends to the summary message it injects. */
|
|
28
|
+
/**
|
|
29
|
+
* True when an assistant message ends a turn with tool calls still awaiting
|
|
30
|
+
* their results. Inserting a user message there would orphan the tool_use
|
|
31
|
+
* blocks and the provider rejects the next request.
|
|
32
|
+
*/
|
|
33
|
+
export function hasUnresolvedToolCalls(message) {
|
|
34
|
+
if (typeof message.content === "string" || !Array.isArray(message.content))
|
|
35
|
+
return false;
|
|
36
|
+
return message.content.some((part) => part.type === "tool_call");
|
|
37
|
+
}
|
|
38
|
+
/** Expand a leading `~` so `/import ~/.codex/...` works from any shell. */
|
|
39
|
+
export function resolveHomePath(filePath) {
|
|
40
|
+
if (filePath === "~")
|
|
41
|
+
return os.homedir();
|
|
42
|
+
if (filePath.startsWith("~/") || filePath.startsWith("~\\")) {
|
|
43
|
+
return path.join(os.homedir(), filePath.slice(2));
|
|
44
|
+
}
|
|
45
|
+
return filePath;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/core/agent-session/helpers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAAG,CAAC;AAEpD,8DAA8D;AAE9D,oFAAoF;AACpF,MAAM,UAAU,iCAAiC,CAC/C,KAAa,EACb,QAAkB,EAClB,SAAkB;IAElB,OAAO,CACL,sBAAsB,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QACtD,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CACzE,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qCAAqC,CACnD,KAAa,EACb,QAAkB,EAClB,SAAkB;IAElB,MAAM,YAAY,GAAG,gBAAgB,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,GAAG,GAAG,CAAC;IAC5E,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,uEAAuE;AACvE;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACzF,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;AACnE,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,IAAI,QAAQ,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;IAC1C,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { AgentTool } from "@prestyj/agent";
|
|
2
|
+
import { MCPClientManager, type MCPElicitHandler } from "../mcp/index.js";
|
|
3
|
+
import type { MCPServerConfig } from "../mcp/types.js";
|
|
4
|
+
import type { ContextLimits } from "../context-limits.js";
|
|
5
|
+
/**
|
|
6
|
+
* MCP tool wiring for one session: the client manager, the deferred
|
|
7
|
+
* `tool_search` catalog (shared with deferred built-ins), cached-catalog stubs
|
|
8
|
+
* and the live/cached reconcile maps.
|
|
9
|
+
*
|
|
10
|
+
* Never owns the tool array — it reads the session's CURRENT array through
|
|
11
|
+
* `getTools` (the session may filter-replace it) and only appends to it or
|
|
12
|
+
* swaps same-named entries in place, so the cached tool prefix stays stable.
|
|
13
|
+
*/
|
|
14
|
+
export declare class McpToolRegistry {
|
|
15
|
+
private readonly getTools;
|
|
16
|
+
private readonly getContextLimits;
|
|
17
|
+
manager?: MCPClientManager;
|
|
18
|
+
/** Deferred MCP tools awaiting discovery via tool_search. */
|
|
19
|
+
private catalog?;
|
|
20
|
+
/** Live (connected) MCP tools by name — the reconcile target for cached stubs. */
|
|
21
|
+
private readonly liveTools;
|
|
22
|
+
/** Server name for each cached-only tool, so a stub knows what to wait on. */
|
|
23
|
+
private readonly cachedToolServers;
|
|
24
|
+
private readonly catalogCache;
|
|
25
|
+
constructor(getTools: () => AgentTool[], getContextLimits: () => ContextLimits);
|
|
26
|
+
createManager(options: {
|
|
27
|
+
modernProtocol: boolean;
|
|
28
|
+
onElicit: MCPElicitHandler | undefined;
|
|
29
|
+
}): void;
|
|
30
|
+
private ensureCatalog;
|
|
31
|
+
/** Hold tools in the tool_search catalog and make sure tool_search exists. */
|
|
32
|
+
addDeferred(tools: AgentTool[]): void;
|
|
33
|
+
/** Pull named entries out of the catalog (empty when no catalog exists). */
|
|
34
|
+
promote(names: string[]): AgentTool[];
|
|
35
|
+
/** Forget every MCP tool before a provider-switch reconnect re-adds them. */
|
|
36
|
+
clearMcpTools(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Route freshly connected MCP tools: deferred into the tool_search catalog
|
|
39
|
+
* (default — keeps ~8k tokens of schema out of every cache-miss turn) or
|
|
40
|
+
* pushed eagerly when `defer` is false.
|
|
41
|
+
* Promotion pushes onto the live tools array the running agent loop
|
|
42
|
+
* re-reads every turn, so promoted tools are callable on the next step.
|
|
43
|
+
*/
|
|
44
|
+
addMcpTools(mcpTools: AgentTool[], defer: boolean): void;
|
|
45
|
+
/**
|
|
46
|
+
* Register `tool_search` once. Promotion of a cached-only entry waits for its
|
|
47
|
+
* server so the model is told immediately when that capability turns out to
|
|
48
|
+
* be unreachable, instead of promoting a tool that fails on first call.
|
|
49
|
+
*
|
|
50
|
+
* The catalog is created on demand rather than required up front: deferred
|
|
51
|
+
* built-in tools populate it with zero MCP servers connected, so gating
|
|
52
|
+
* registration on an existing catalog would leave those tools unreachable.
|
|
53
|
+
*/
|
|
54
|
+
ensureToolSearchTool(): void;
|
|
55
|
+
/** Append tools, replacing any same-named entry (cached stub → live tool). */
|
|
56
|
+
private replaceOrPushTools;
|
|
57
|
+
/** Swap already-promoted cached stubs for their live equivalents, in place. */
|
|
58
|
+
private replaceLivePromotedTools;
|
|
59
|
+
/**
|
|
60
|
+
* Publish cached tool definitions into the deferred catalog so `tool_search`
|
|
61
|
+
* answers correctly on turn 1. A cached stub carries the real name, one-line
|
|
62
|
+
* description and input schema; calling it waits for the live connection and
|
|
63
|
+
* then dispatches against the real client, or returns a clear error when that
|
|
64
|
+
* server ultimately failed. Live tools replace stubs on connect.
|
|
65
|
+
*/
|
|
66
|
+
seedFromCache(servers: MCPServerConfig[]): Promise<void>;
|
|
67
|
+
private buildCachedMcpTool;
|
|
68
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { log } from "../logger.js";
|
|
3
|
+
import { MCPClientManager } from "../mcp/index.js";
|
|
4
|
+
import { clampMcpToolDescription, DeferredToolCatalog } from "../mcp/deferred-catalog.js";
|
|
5
|
+
import { McpCatalogCache } from "../mcp/catalog-cache.js";
|
|
6
|
+
import { createToolSearchTool } from "../../tools/tool-search.js";
|
|
7
|
+
/**
|
|
8
|
+
* MCP tool wiring for one session: the client manager, the deferred
|
|
9
|
+
* `tool_search` catalog (shared with deferred built-ins), cached-catalog stubs
|
|
10
|
+
* and the live/cached reconcile maps.
|
|
11
|
+
*
|
|
12
|
+
* Never owns the tool array — it reads the session's CURRENT array through
|
|
13
|
+
* `getTools` (the session may filter-replace it) and only appends to it or
|
|
14
|
+
* swaps same-named entries in place, so the cached tool prefix stays stable.
|
|
15
|
+
*/
|
|
16
|
+
export class McpToolRegistry {
|
|
17
|
+
getTools;
|
|
18
|
+
getContextLimits;
|
|
19
|
+
manager;
|
|
20
|
+
/** Deferred MCP tools awaiting discovery via tool_search. */
|
|
21
|
+
catalog;
|
|
22
|
+
/** Live (connected) MCP tools by name — the reconcile target for cached stubs. */
|
|
23
|
+
liveTools = new Map();
|
|
24
|
+
/** Server name for each cached-only tool, so a stub knows what to wait on. */
|
|
25
|
+
cachedToolServers = new Map();
|
|
26
|
+
catalogCache = new McpCatalogCache();
|
|
27
|
+
constructor(getTools, getContextLimits) {
|
|
28
|
+
this.getTools = getTools;
|
|
29
|
+
this.getContextLimits = getContextLimits;
|
|
30
|
+
}
|
|
31
|
+
createManager(options) {
|
|
32
|
+
this.manager = new MCPClientManager({
|
|
33
|
+
catalogCache: this.catalogCache,
|
|
34
|
+
modernProtocol: options.modernProtocol,
|
|
35
|
+
onElicit: options.onElicit,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
ensureCatalog() {
|
|
39
|
+
this.catalog ??= new DeferredToolCatalog(this.getContextLimits());
|
|
40
|
+
return this.catalog;
|
|
41
|
+
}
|
|
42
|
+
/** Hold tools in the tool_search catalog and make sure tool_search exists. */
|
|
43
|
+
addDeferred(tools) {
|
|
44
|
+
this.ensureCatalog().add(tools);
|
|
45
|
+
this.ensureToolSearchTool();
|
|
46
|
+
}
|
|
47
|
+
/** Pull named entries out of the catalog (empty when no catalog exists). */
|
|
48
|
+
promote(names) {
|
|
49
|
+
return this.catalog?.promote(names) ?? [];
|
|
50
|
+
}
|
|
51
|
+
/** Forget every MCP tool before a provider-switch reconnect re-adds them. */
|
|
52
|
+
clearMcpTools() {
|
|
53
|
+
this.catalog?.removeWhere((name) => name.startsWith("mcp__"));
|
|
54
|
+
this.liveTools.clear();
|
|
55
|
+
this.cachedToolServers.clear();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Route freshly connected MCP tools: deferred into the tool_search catalog
|
|
59
|
+
* (default — keeps ~8k tokens of schema out of every cache-miss turn) or
|
|
60
|
+
* pushed eagerly when `defer` is false.
|
|
61
|
+
* Promotion pushes onto the live tools array the running agent loop
|
|
62
|
+
* re-reads every turn, so promoted tools are callable on the next step.
|
|
63
|
+
*/
|
|
64
|
+
addMcpTools(mcpTools, defer) {
|
|
65
|
+
if (mcpTools.length === 0)
|
|
66
|
+
return;
|
|
67
|
+
for (const tool of mcpTools) {
|
|
68
|
+
this.liveTools.set(tool.name, tool);
|
|
69
|
+
this.cachedToolServers.delete(tool.name);
|
|
70
|
+
}
|
|
71
|
+
if (!defer) {
|
|
72
|
+
// Eager path bypasses the catalog, so budget descriptions here too.
|
|
73
|
+
this.replaceOrPushTools(mcpTools.map((tool) => clampMcpToolDescription(tool, this.getContextLimits())));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// `add` is name-keyed, so live definitions replace cached stubs in place.
|
|
77
|
+
this.ensureCatalog().add(mcpTools);
|
|
78
|
+
// A stub the model already promoted lives in the tools array; swap it for
|
|
79
|
+
// the live tool so later calls dispatch directly instead of through the stub.
|
|
80
|
+
this.replaceLivePromotedTools(mcpTools);
|
|
81
|
+
this.ensureToolSearchTool();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Register `tool_search` once. Promotion of a cached-only entry waits for its
|
|
85
|
+
* server so the model is told immediately when that capability turns out to
|
|
86
|
+
* be unreachable, instead of promoting a tool that fails on first call.
|
|
87
|
+
*
|
|
88
|
+
* The catalog is created on demand rather than required up front: deferred
|
|
89
|
+
* built-in tools populate it with zero MCP servers connected, so gating
|
|
90
|
+
* registration on an existing catalog would leave those tools unreachable.
|
|
91
|
+
*/
|
|
92
|
+
ensureToolSearchTool() {
|
|
93
|
+
const catalog = this.ensureCatalog();
|
|
94
|
+
if (this.getTools().some((t) => t.name === "tool_search"))
|
|
95
|
+
return;
|
|
96
|
+
this.getTools().push(createToolSearchTool(catalog, (promoted) => {
|
|
97
|
+
this.getTools().push(...promoted);
|
|
98
|
+
}, async (toolName) => {
|
|
99
|
+
if (this.liveTools.has(toolName))
|
|
100
|
+
return undefined;
|
|
101
|
+
const serverName = this.cachedToolServers.get(toolName);
|
|
102
|
+
if (!serverName)
|
|
103
|
+
return undefined;
|
|
104
|
+
const outcome = (await this.manager?.whenConnected(serverName)) ?? {
|
|
105
|
+
ok: false,
|
|
106
|
+
error: "MCP is disabled for this session",
|
|
107
|
+
};
|
|
108
|
+
return outcome.ok
|
|
109
|
+
? { serverName, ok: true }
|
|
110
|
+
: { serverName, ok: false, error: outcome.error };
|
|
111
|
+
}, this.getContextLimits()));
|
|
112
|
+
}
|
|
113
|
+
/** Append tools, replacing any same-named entry (cached stub → live tool). */
|
|
114
|
+
replaceOrPushTools(tools) {
|
|
115
|
+
const live = this.getTools();
|
|
116
|
+
for (const tool of tools) {
|
|
117
|
+
const index = live.findIndex((t) => t.name === tool.name);
|
|
118
|
+
if (index >= 0)
|
|
119
|
+
live[index] = tool;
|
|
120
|
+
else
|
|
121
|
+
live.push(tool);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Swap already-promoted cached stubs for their live equivalents, in place. */
|
|
125
|
+
replaceLivePromotedTools(tools) {
|
|
126
|
+
const live = this.getTools();
|
|
127
|
+
for (const tool of tools) {
|
|
128
|
+
const index = live.findIndex((t) => t.name === tool.name);
|
|
129
|
+
if (index >= 0)
|
|
130
|
+
live[index] = tool;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Publish cached tool definitions into the deferred catalog so `tool_search`
|
|
135
|
+
* answers correctly on turn 1. A cached stub carries the real name, one-line
|
|
136
|
+
* description and input schema; calling it waits for the live connection and
|
|
137
|
+
* then dispatches against the real client, or returns a clear error when that
|
|
138
|
+
* server ultimately failed. Live tools replace stubs on connect.
|
|
139
|
+
*/
|
|
140
|
+
async seedFromCache(servers) {
|
|
141
|
+
let entries;
|
|
142
|
+
try {
|
|
143
|
+
entries = await this.catalogCache.entriesFor(servers);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const stubs = [];
|
|
149
|
+
for (const [serverName, entry] of entries) {
|
|
150
|
+
for (const cached of entry.tools) {
|
|
151
|
+
if (this.liveTools.has(cached.name))
|
|
152
|
+
continue;
|
|
153
|
+
this.cachedToolServers.set(cached.name, serverName);
|
|
154
|
+
stubs.push(this.buildCachedMcpTool(serverName, cached));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (stubs.length === 0)
|
|
158
|
+
return;
|
|
159
|
+
log("INFO", "mcp", "Seeded deferred tool catalog from cache", {
|
|
160
|
+
tools: String(stubs.length),
|
|
161
|
+
servers: String(entries.size),
|
|
162
|
+
});
|
|
163
|
+
// Catalog-only registration for cached stubs — never marks them live.
|
|
164
|
+
this.addDeferred(stubs);
|
|
165
|
+
}
|
|
166
|
+
buildCachedMcpTool(serverName, cached) {
|
|
167
|
+
return {
|
|
168
|
+
name: cached.name,
|
|
169
|
+
description: cached.description,
|
|
170
|
+
parameters: z.record(z.string(), z.unknown()),
|
|
171
|
+
rawInputSchema: cached.rawInputSchema,
|
|
172
|
+
execute: async (args, context) => {
|
|
173
|
+
const live = this.liveTools.get(cached.name);
|
|
174
|
+
if (live)
|
|
175
|
+
return live.execute(args, context);
|
|
176
|
+
const outcome = (await this.manager?.whenConnected(serverName)) ?? {
|
|
177
|
+
ok: false,
|
|
178
|
+
error: "MCP is disabled for this session",
|
|
179
|
+
};
|
|
180
|
+
if (!outcome.ok) {
|
|
181
|
+
return (`MCP tool ${cached.name} is unavailable: server "${serverName}" did not connect ` +
|
|
182
|
+
`(${outcome.error}). This tool was offered from a cached catalog. ` +
|
|
183
|
+
`Use a different approach or ask the user to check their MCP configuration.`);
|
|
184
|
+
}
|
|
185
|
+
const connected = this.liveTools.get(cached.name);
|
|
186
|
+
if (!connected) {
|
|
187
|
+
return (`MCP tool ${cached.name} no longer exists: server "${serverName}" connected but ` +
|
|
188
|
+
`does not expose it. The cached catalog entry was stale.`);
|
|
189
|
+
}
|
|
190
|
+
return connected.execute(args, context);
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=mcp-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tools.js","sourceRoot":"","sources":["../../../src/core/agent-session/mcp-tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,gBAAgB,EAAyB,MAAM,iBAAiB,CAAC;AAE1E,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAmB,MAAM,yBAAyB,CAAC;AAE3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE;;;;;;;;GAQG;AACH,MAAM,OAAO,eAAe;IAWP;IACA;IAXnB,OAAO,CAAoB;IAC3B,6DAA6D;IACrD,OAAO,CAAuB;IACtC,kFAAkF;IACjE,SAAS,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC1D,8EAA8E;IAC7D,iBAAiB,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,YAAY,GAAG,IAAI,eAAe,EAAE,CAAC;IAEtD,YACmB,QAA2B,EAC3B,gBAAqC;QADrC,aAAQ,GAAR,QAAQ,CAAmB;QAC3B,qBAAgB,GAAhB,gBAAgB,CAAqB;IACrD,CAAC;IAEJ,aAAa,CAAC,OAGb;QACC,IAAI,CAAC,OAAO,GAAG,IAAI,gBAAgB,CAAC;YAClC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;IACL,CAAC;IAEO,aAAa;QACnB,IAAI,CAAC,OAAO,KAAK,IAAI,mBAAmB,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,8EAA8E;IAC9E,WAAW,CAAC,KAAkB;QAC5B,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAC9B,CAAC;IAED,4EAA4E;IAC5E,OAAO,CAAC,KAAe;QACrB,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,6EAA6E;IAC7E,aAAa;QACX,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC;IACjC,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,QAAqB,EAAE,KAAc;QAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAClC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,CAAC;QACD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,oEAAoE;YACpE,IAAI,CAAC,kBAAkB,CACrB,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,uBAAuB,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAC/E,CAAC;YACF,OAAO;QACT,CAAC;QACD,0EAA0E;QAC1E,IAAI,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnC,0EAA0E;QAC1E,8EAA8E;QAC9E,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAC9B,CAAC;IAED;;;;;;;;OAQG;IACH,oBAAoB;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC;YAAE,OAAO;QAClE,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAClB,oBAAoB,CAClB,OAAO,EACP,CAAC,QAAQ,EAAE,EAAE;YACX,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QACpC,CAAC,EACD,KAAK,EAAE,QAAQ,EAAE,EAAE;YACjB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAAE,OAAO,SAAS,CAAC;YACnD,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxD,IAAI,CAAC,UAAU;gBAAE,OAAO,SAAS,CAAC;YAClC,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI;gBACjE,EAAE,EAAE,KAAc;gBAClB,KAAK,EAAE,kCAAkC;aAC1C,CAAC;YACF,OAAO,OAAO,CAAC,EAAE;gBACf,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE;gBAC1B,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QACtD,CAAC,EACD,IAAI,CAAC,gBAAgB,EAAE,CACxB,CACF,CAAC;IACJ,CAAC;IAED,8EAA8E;IACtE,kBAAkB,CAAC,KAAkB;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1D,IAAI,KAAK,IAAI,CAAC;gBAAE,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;;gBAC9B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,+EAA+E;IACvE,wBAAwB,CAAC,KAAkB;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1D,IAAI,KAAK,IAAI,CAAC;gBAAE,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QACrC,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,aAAa,CAAC,OAA0B;QAC5C,IAAI,OAA2D,CAAC;QAChE,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAgB,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;YAC1C,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBACjC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAC9C,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBACpD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC/B,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,yCAAyC,EAAE;YAC5D,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;YAC3B,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SAC9B,CAAC,CAAC;QACH,sEAAsE;QACtE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAEO,kBAAkB,CAAC,UAAkB,EAAE,MAAkB;QAC/D,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YAC7C,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;gBAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC7C,IAAI,IAAI;oBAAE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAC7C,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI;oBACjE,EAAE,EAAE,KAAc;oBAClB,KAAK,EAAE,kCAAkC;iBAC1C,CAAC;gBACF,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;oBAChB,OAAO,CACL,YAAY,MAAM,CAAC,IAAI,4BAA4B,UAAU,oBAAoB;wBACjF,IAAI,OAAO,CAAC,KAAK,kDAAkD;wBACnE,4EAA4E,CAC7E,CAAC;gBACJ,CAAC;gBACD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAClD,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO,CACL,YAAY,MAAM,CAAC,IAAI,8BAA8B,UAAU,kBAAkB;wBACjF,yDAAyD,CAC1D,CAAC;gBACJ,CAAC;gBACD,OAAO,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1C,CAAC;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { CycleDetector, ToolCallProgressTracker, type CycleDetection, type LoopBreakDecision } from "../loop-breaker.js";
|
|
2
|
+
import { type SemanticCallDigest, type SemanticLoopVerdict } from "../semantic-loop-check.js";
|
|
3
|
+
/** LLM-judged loop detection state for one run. */
|
|
4
|
+
export interface SemanticLoopRunState {
|
|
5
|
+
checksUsed: number;
|
|
6
|
+
lastCheckTurn: number;
|
|
7
|
+
pending: boolean;
|
|
8
|
+
verdict: SemanticLoopVerdict | null;
|
|
9
|
+
injected: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Per-run stuck-detection state (mirrors the TUI's useAgentLoop refs): tool
|
|
13
|
+
* stats, streamed text, progress/cycle trackers, the two-stage loop-breaker and
|
|
14
|
+
* the semantic loop judge's budget. Reset at the start of every run; observed
|
|
15
|
+
* from the event stream. Owns state and decisions only — logging, events and
|
|
16
|
+
* the judge call stay with the session.
|
|
17
|
+
*/
|
|
18
|
+
export declare class RunLoopMonitor {
|
|
19
|
+
stats: {
|
|
20
|
+
toolCalls: number;
|
|
21
|
+
toolFailures: number;
|
|
22
|
+
turns: number;
|
|
23
|
+
};
|
|
24
|
+
text: string;
|
|
25
|
+
consecutiveFailures: number;
|
|
26
|
+
repeatedNoProgressCalls: number;
|
|
27
|
+
readonly progressTracker: ToolCallProgressTracker;
|
|
28
|
+
readonly cycleDetector: CycleDetector;
|
|
29
|
+
cyclicPattern: CycleDetection | null;
|
|
30
|
+
/** 0 = none; 1 = first nudge sent; 2 = final stop-and-report injected. */
|
|
31
|
+
loopBreakInjected: 0 | 1 | 2;
|
|
32
|
+
/** Recent tool-call digests for the semantic loop judge — bounded ring. */
|
|
33
|
+
recentCalls: SemanticCallDigest[];
|
|
34
|
+
/** LLM-judged loop detection state. `verdict` holds a LOOP verdict awaiting
|
|
35
|
+
* injection at the next steering poll; judge failures fail open (no
|
|
36
|
+
* injection) and still consume budget + cooldown. Replaced (never mutated)
|
|
37
|
+
* on reset so a late judge from an earlier run cannot write into it. */
|
|
38
|
+
semanticLoop: SemanticLoopRunState;
|
|
39
|
+
/** Clean slate for a new run. */
|
|
40
|
+
reset(): void;
|
|
41
|
+
recordText(text: string): void;
|
|
42
|
+
recordToolEnd(name: string, args: Record<string, unknown> | undefined, result: string, isError: boolean): void;
|
|
43
|
+
recordTurn(turn: number): void;
|
|
44
|
+
/** Deterministic stuck verdict from the current signals. */
|
|
45
|
+
evaluateLoopBreak(): LoopBreakDecision;
|
|
46
|
+
/**
|
|
47
|
+
* Two-stage loop-breaker: stage 1 nudges; a FRESH detection after that
|
|
48
|
+
* escalates to stage 2. Returns the stage to inject (signals reset so stage 2
|
|
49
|
+
* only fires on new evidence), or null when nothing should be injected.
|
|
50
|
+
*/
|
|
51
|
+
takeLoopBreakStage(decision: LoopBreakDecision): 1 | 2 | null;
|
|
52
|
+
/** Consume a pending semantic LOOP verdict, exactly once per run. */
|
|
53
|
+
takeSemanticVerdict(): SemanticLoopVerdict | null;
|
|
54
|
+
shouldRunSemanticCheck(deterministicBreak: boolean): boolean;
|
|
55
|
+
/** Mark a judge call in flight; the returned run state is its stale-guard token. */
|
|
56
|
+
beginSemanticCheck(): SemanticLoopRunState;
|
|
57
|
+
/** Publish a judge verdict only if its run is still the current one. */
|
|
58
|
+
publishSemanticVerdict(runState: SemanticLoopRunState, verdict: SemanticLoopVerdict): void;
|
|
59
|
+
/** Settle a judge call: consume budget + cooldown, unless its run is stale. */
|
|
60
|
+
settleSemanticCheck(runState: SemanticLoopRunState): void;
|
|
61
|
+
/** Reasons to refuse a turn-budget extension; empty means grant. */
|
|
62
|
+
turnExtensionRefusals(): string[];
|
|
63
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { evaluateLoopBreak, CycleDetector, ToolCallProgressTracker, detectTextRepetition, } from "../loop-breaker.js";
|
|
2
|
+
import { MAX_SEMANTIC_LOOP_CALLS, shouldRunSemanticLoopCheck, } from "../semantic-loop-check.js";
|
|
3
|
+
import { TURN_EXTENSION_MAX_FAILURE_RATIO } from "./helpers.js";
|
|
4
|
+
function freshSemanticLoopState() {
|
|
5
|
+
return { checksUsed: 0, lastCheckTurn: 0, pending: false, verdict: null, injected: false };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Per-run stuck-detection state (mirrors the TUI's useAgentLoop refs): tool
|
|
9
|
+
* stats, streamed text, progress/cycle trackers, the two-stage loop-breaker and
|
|
10
|
+
* the semantic loop judge's budget. Reset at the start of every run; observed
|
|
11
|
+
* from the event stream. Owns state and decisions only — logging, events and
|
|
12
|
+
* the judge call stay with the session.
|
|
13
|
+
*/
|
|
14
|
+
export class RunLoopMonitor {
|
|
15
|
+
stats = { toolCalls: 0, toolFailures: 0, turns: 0 };
|
|
16
|
+
text = "";
|
|
17
|
+
consecutiveFailures = 0;
|
|
18
|
+
repeatedNoProgressCalls = 0;
|
|
19
|
+
progressTracker = new ToolCallProgressTracker();
|
|
20
|
+
cycleDetector = new CycleDetector();
|
|
21
|
+
cyclicPattern = null;
|
|
22
|
+
/** 0 = none; 1 = first nudge sent; 2 = final stop-and-report injected. */
|
|
23
|
+
loopBreakInjected = 0;
|
|
24
|
+
/** Recent tool-call digests for the semantic loop judge — bounded ring. */
|
|
25
|
+
recentCalls = [];
|
|
26
|
+
/** LLM-judged loop detection state. `verdict` holds a LOOP verdict awaiting
|
|
27
|
+
* injection at the next steering poll; judge failures fail open (no
|
|
28
|
+
* injection) and still consume budget + cooldown. Replaced (never mutated)
|
|
29
|
+
* on reset so a late judge from an earlier run cannot write into it. */
|
|
30
|
+
semanticLoop = freshSemanticLoopState();
|
|
31
|
+
/** Clean slate for a new run. */
|
|
32
|
+
reset() {
|
|
33
|
+
this.stats = { toolCalls: 0, toolFailures: 0, turns: 0 };
|
|
34
|
+
this.text = "";
|
|
35
|
+
this.consecutiveFailures = 0;
|
|
36
|
+
this.repeatedNoProgressCalls = 0;
|
|
37
|
+
this.progressTracker.reset();
|
|
38
|
+
this.cycleDetector.reset();
|
|
39
|
+
this.cyclicPattern = null;
|
|
40
|
+
this.loopBreakInjected = 0;
|
|
41
|
+
this.recentCalls = [];
|
|
42
|
+
this.semanticLoop = freshSemanticLoopState();
|
|
43
|
+
}
|
|
44
|
+
recordText(text) {
|
|
45
|
+
this.text += text;
|
|
46
|
+
}
|
|
47
|
+
recordToolEnd(name, args, result, isError) {
|
|
48
|
+
this.stats.toolCalls += 1;
|
|
49
|
+
if (isError)
|
|
50
|
+
this.stats.toolFailures += 1;
|
|
51
|
+
this.consecutiveFailures = isError ? this.consecutiveFailures + 1 : 0;
|
|
52
|
+
this.repeatedNoProgressCalls = this.progressTracker.record(name, args, result, isError);
|
|
53
|
+
this.cyclicPattern = this.cycleDetector.record(name, args, result, isError);
|
|
54
|
+
// Semantic-loop judge input: a bounded digest of WHAT was attempted and
|
|
55
|
+
// HOW it came out. Args/results are sliced AT RECORD TIME — a write with
|
|
56
|
+
// a 50 KiB payload or a bash dump must never inflate the ring, and the
|
|
57
|
+
// judge needs shapes, not payloads.
|
|
58
|
+
this.recentCalls.push({
|
|
59
|
+
tool: name,
|
|
60
|
+
args: args === undefined ? "" : JSON.stringify(args).slice(0, 300),
|
|
61
|
+
ok: !isError,
|
|
62
|
+
result: result.slice(0, 400),
|
|
63
|
+
});
|
|
64
|
+
if (this.recentCalls.length > MAX_SEMANTIC_LOOP_CALLS) {
|
|
65
|
+
this.recentCalls.splice(0, this.recentCalls.length - MAX_SEMANTIC_LOOP_CALLS);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
recordTurn(turn) {
|
|
69
|
+
this.stats.turns = turn;
|
|
70
|
+
}
|
|
71
|
+
/** Deterministic stuck verdict from the current signals. */
|
|
72
|
+
evaluateLoopBreak() {
|
|
73
|
+
return evaluateLoopBreak({
|
|
74
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
75
|
+
repeatedNoProgressCalls: this.repeatedNoProgressCalls,
|
|
76
|
+
textRepetitionDetected: detectTextRepetition(this.text),
|
|
77
|
+
...(this.cyclicPattern ? { cyclicPattern: this.cyclicPattern } : {}),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Two-stage loop-breaker: stage 1 nudges; a FRESH detection after that
|
|
82
|
+
* escalates to stage 2. Returns the stage to inject (signals reset so stage 2
|
|
83
|
+
* only fires on new evidence), or null when nothing should be injected.
|
|
84
|
+
*/
|
|
85
|
+
takeLoopBreakStage(decision) {
|
|
86
|
+
if (this.loopBreakInjected >= 2)
|
|
87
|
+
return null;
|
|
88
|
+
if (!decision.shouldBreak)
|
|
89
|
+
return null;
|
|
90
|
+
const stage = this.loopBreakInjected === 0 ? 1 : 2;
|
|
91
|
+
this.loopBreakInjected = stage;
|
|
92
|
+
this.progressTracker.reset();
|
|
93
|
+
this.cycleDetector.reset();
|
|
94
|
+
this.cyclicPattern = null;
|
|
95
|
+
this.consecutiveFailures = 0;
|
|
96
|
+
this.repeatedNoProgressCalls = 0;
|
|
97
|
+
// The deterministic breaker owns this burst — a semantic verdict from
|
|
98
|
+
// the same burst must not double-correct on the next poll.
|
|
99
|
+
this.semanticLoop.verdict = null;
|
|
100
|
+
// Clear the text buffer too — otherwise a stage-1 text-repetition
|
|
101
|
+
// trigger still sees the same repeated tail on the next check and
|
|
102
|
+
// escalates to stage 2 on stale evidence.
|
|
103
|
+
this.text = "";
|
|
104
|
+
return stage;
|
|
105
|
+
}
|
|
106
|
+
/** Consume a pending semantic LOOP verdict, exactly once per run. */
|
|
107
|
+
takeSemanticVerdict() {
|
|
108
|
+
if (!this.semanticLoop.verdict || this.semanticLoop.injected)
|
|
109
|
+
return null;
|
|
110
|
+
const verdict = this.semanticLoop.verdict;
|
|
111
|
+
this.semanticLoop.injected = true;
|
|
112
|
+
this.semanticLoop.verdict = null;
|
|
113
|
+
// The judged burst has been addressed; a fresh burst must re-accumulate.
|
|
114
|
+
this.consecutiveFailures = 0;
|
|
115
|
+
return verdict;
|
|
116
|
+
}
|
|
117
|
+
shouldRunSemanticCheck(deterministicBreak) {
|
|
118
|
+
return shouldRunSemanticLoopCheck({
|
|
119
|
+
consecutiveFailures: this.consecutiveFailures,
|
|
120
|
+
totalFailures: this.stats.toolFailures,
|
|
121
|
+
turns: this.stats.turns,
|
|
122
|
+
lastCheckTurn: this.semanticLoop.lastCheckTurn,
|
|
123
|
+
checksUsed: this.semanticLoop.checksUsed,
|
|
124
|
+
checkPending: this.semanticLoop.pending,
|
|
125
|
+
deterministicBreak,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/** Mark a judge call in flight; the returned run state is its stale-guard token. */
|
|
129
|
+
beginSemanticCheck() {
|
|
130
|
+
const runState = this.semanticLoop;
|
|
131
|
+
runState.pending = true;
|
|
132
|
+
return runState;
|
|
133
|
+
}
|
|
134
|
+
/** Publish a judge verdict only if its run is still the current one. */
|
|
135
|
+
publishSemanticVerdict(runState, verdict) {
|
|
136
|
+
if (this.semanticLoop === runState)
|
|
137
|
+
runState.verdict = verdict;
|
|
138
|
+
}
|
|
139
|
+
/** Settle a judge call: consume budget + cooldown, unless its run is stale. */
|
|
140
|
+
settleSemanticCheck(runState) {
|
|
141
|
+
if (this.semanticLoop === runState) {
|
|
142
|
+
runState.pending = false;
|
|
143
|
+
runState.checksUsed += 1;
|
|
144
|
+
runState.lastCheckTurn = this.stats.turns;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Reasons to refuse a turn-budget extension; empty means grant. */
|
|
148
|
+
turnExtensionRefusals() {
|
|
149
|
+
const refusals = [];
|
|
150
|
+
const stuck = this.evaluateLoopBreak();
|
|
151
|
+
if (stuck.shouldBreak)
|
|
152
|
+
refusals.push(...stuck.reasons);
|
|
153
|
+
// Stage 2 means the loop-breaker already detected spinning twice and told
|
|
154
|
+
// the agent to stop and report. Do not overrule that with more turns.
|
|
155
|
+
if (this.loopBreakInjected >= 2)
|
|
156
|
+
refusals.push("loop-breaker already escalated");
|
|
157
|
+
const { toolCalls, toolFailures } = this.stats;
|
|
158
|
+
if (toolCalls > 0 && toolFailures / toolCalls > TURN_EXTENSION_MAX_FAILURE_RATIO) {
|
|
159
|
+
refusals.push(`${toolFailures}/${toolCalls} tool calls failed`);
|
|
160
|
+
}
|
|
161
|
+
return refusals;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=run-loop-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-loop-monitor.js","sourceRoot":"","sources":["../../../src/core/agent-session/run-loop-monitor.ts"],"names":[],"mappings":"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"}
|