muonroi-cli 1.7.2 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/packages/agent-harness-core/src/event-filter.js +1 -0
- package/dist/packages/agent-harness-core/src/event-redact.js +8 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +16 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +88 -10
- package/dist/packages/agent-harness-core/src/protocol.d.ts +15 -0
- package/dist/packages/agent-harness-core/src/selector.js +2 -2
- package/dist/packages/agent-harness-core/src/transports/sidechannel.js +1 -1
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +1 -1
- package/dist/packages/agent-harness-opentui/src/install.js +1 -1
- package/dist/src/__test-stubs__/vitest-setup.js +4 -0
- package/dist/src/agent-harness/__tests__/mock-model.spec.js +54 -0
- package/dist/src/agent-harness/mock-model.d.ts +1 -1
- package/dist/src/agent-harness/mock-model.js +143 -6
- package/dist/src/agent-harness/test-spawn.js +3 -1
- package/dist/src/chat/chat-keychain.js +9 -1
- package/dist/src/cli/cost-forensics.js +7 -4
- package/dist/src/cli/keys.d.ts +2 -2
- package/dist/src/cli/keys.js +107 -28
- package/dist/src/cli/usage-report.js +2 -2
- package/dist/src/council/__tests__/abort-threading.test.d.ts +1 -0
- package/dist/src/council/__tests__/abort-threading.test.js +193 -0
- package/dist/src/council/__tests__/clarification-prompt.test.js +21 -1
- package/dist/src/council/__tests__/council-turn-length-emit.test.d.ts +1 -0
- package/dist/src/council/__tests__/council-turn-length-emit.test.js +130 -0
- package/dist/src/council/__tests__/debate-round-budget.test.d.ts +1 -0
- package/dist/src/council/__tests__/debate-round-budget.test.js +45 -0
- package/dist/src/council/__tests__/evaluator-metrics.test.js +3 -0
- package/dist/src/council/__tests__/post-debate-recommendation.test.d.ts +1 -0
- package/dist/src/council/__tests__/post-debate-recommendation.test.js +58 -0
- package/dist/src/council/__tests__/research-tools.test.js +4 -0
- package/dist/src/council/__tests__/round-tools.test.js +6 -0
- package/dist/src/council/clarifier-question-cap.test.d.ts +12 -0
- package/dist/src/council/clarifier-question-cap.test.js +73 -0
- package/dist/src/council/clarifier.d.ts +29 -1
- package/dist/src/council/clarifier.js +64 -1
- package/dist/src/council/debate-planner.d.ts +2 -1
- package/dist/src/council/debate-planner.js +5 -3
- package/dist/src/council/debate.d.ts +9 -0
- package/dist/src/council/debate.js +88 -8
- package/dist/src/council/index.d.ts +46 -1
- package/dist/src/council/index.js +125 -19
- package/dist/src/council/llm.js +41 -13
- package/dist/src/council/prompts.js +36 -1
- package/dist/src/council/types.d.ts +14 -1
- package/dist/src/ee/__tests__/export-transcripts.test.js +1 -1
- package/dist/src/ee/bridge.d.ts +3 -1
- package/dist/src/ee/bridge.js +9 -3
- package/dist/src/ee/bridge.test.js +1 -2
- package/dist/src/ee/client.js +15 -2
- package/dist/src/ee/recall-ledger.d.ts +20 -0
- package/dist/src/ee/recall-ledger.js +40 -1
- package/dist/src/ee/search.d.ts +25 -0
- package/dist/src/ee/search.js +73 -0
- package/dist/src/ee/types.d.ts +15 -1
- package/dist/src/ee/who-am-i.d.ts +41 -0
- package/dist/src/ee/who-am-i.js +143 -0
- package/dist/src/ee/who-am-i.test.d.ts +1 -0
- package/dist/src/ee/who-am-i.test.js +101 -0
- package/dist/src/flow/compaction/index.d.ts +1 -0
- package/dist/src/flow/compaction/index.js +4 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/headless/council-answers.js +1 -0
- package/dist/src/headless/output.d.ts +30 -1
- package/dist/src/headless/output.js +180 -0
- package/dist/src/headless/output.test.js +61 -1
- package/dist/src/hooks/index.js +48 -2
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +59 -62
- package/dist/src/lsp/client-normalize.test.d.ts +12 -0
- package/dist/src/lsp/client-normalize.test.js +34 -0
- package/dist/src/lsp/client.d.ts +1 -0
- package/dist/src/lsp/client.js +10 -2
- package/dist/src/lsp/manager.d.ts +1 -1
- package/dist/src/lsp/manager.js +13 -5
- package/dist/src/lsp/manager.test.js +41 -2
- package/dist/src/lsp/runtime.d.ts +1 -1
- package/dist/src/lsp/runtime.js +2 -2
- package/dist/src/maintain/__tests__/gh-create-pr.test.js +7 -3
- package/dist/src/maintain/__tests__/pr-builder.test.js +7 -3
- package/dist/src/mcp/__tests__/client-pool.spec.js +3 -3
- package/dist/src/mcp/__tests__/ee-tools.test.js +42 -14
- package/dist/src/mcp/__tests__/forensics-tools.test.js +3 -3
- package/dist/src/mcp/__tests__/lsp-tools.test.js +4 -4
- package/dist/src/mcp/auto-setup.js +0 -8
- package/dist/src/mcp/client-pool.d.ts +1 -1
- package/dist/src/mcp/client-pool.js +25 -9
- package/dist/src/mcp/ee-tools.d.ts +10 -0
- package/dist/src/mcp/ee-tools.js +34 -0
- package/dist/src/mcp/self-verify-jobs.d.ts +1 -0
- package/dist/src/mcp/self-verify-jobs.js +1 -3
- package/dist/src/mcp/self-verify-runner.js +1 -1
- package/dist/src/models/catalog-gemini.test.js +12 -10
- package/dist/src/models/catalog.json +106 -38
- package/dist/src/orchestrator/__tests__/auto-commit.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/auto-commit.test.js +142 -0
- package/dist/src/orchestrator/__tests__/batch-turn-runner.test.js +3 -0
- package/dist/src/orchestrator/__tests__/delegations.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/delegations.test.js +96 -0
- package/dist/src/orchestrator/__tests__/message-processor.test.js +2 -0
- package/dist/src/orchestrator/__tests__/prompts.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/prompts.test.js +88 -0
- package/dist/src/orchestrator/__tests__/stream-runner.test.js +29 -0
- package/dist/src/orchestrator/__tests__/sub-session-delegation.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/sub-session-delegation.test.js +507 -0
- package/dist/src/orchestrator/agent.test.js +5 -2
- package/dist/src/orchestrator/auto-commit.d.ts +110 -0
- package/dist/src/orchestrator/auto-commit.js +366 -0
- package/dist/src/orchestrator/batch-turn-runner.d.ts +3 -2
- package/dist/src/orchestrator/batch-turn-runner.js +2 -1
- package/dist/src/orchestrator/compaction-proposer-prompt.d.ts +8 -0
- package/dist/src/orchestrator/compaction-proposer-prompt.js +43 -0
- package/dist/src/orchestrator/compaction.d.ts +22 -0
- package/dist/src/orchestrator/compaction.js +42 -0
- package/dist/src/orchestrator/delegations.d.ts +1 -0
- package/dist/src/orchestrator/delegations.js +41 -0
- package/dist/src/orchestrator/error-utils.js +27 -2
- package/dist/src/orchestrator/message-processor.d.ts +23 -5
- package/dist/src/orchestrator/message-processor.js +226 -2573
- package/dist/src/orchestrator/orchestrator.d.ts +11 -2
- package/dist/src/orchestrator/orchestrator.js +530 -43
- package/dist/src/orchestrator/pending-calls.js +2 -1
- package/dist/src/orchestrator/preprocessor.d.ts +13 -0
- package/dist/src/orchestrator/preprocessor.js +146 -0
- package/dist/src/orchestrator/prompts.d.ts +16 -0
- package/dist/src/orchestrator/prompts.js +130 -67
- package/dist/src/orchestrator/safety-askcard.d.ts +66 -0
- package/dist/src/orchestrator/safety-askcard.js +74 -0
- package/dist/src/orchestrator/sandbox.test.js +8 -5
- package/dist/src/orchestrator/scope-ceiling.js +1 -1
- package/dist/src/orchestrator/stall-watchdog.d.ts +47 -0
- package/dist/src/orchestrator/stall-watchdog.js +23 -0
- package/dist/src/orchestrator/stall-watchdog.test.js +36 -1
- package/dist/src/orchestrator/stream-runner.js +52 -30
- package/dist/src/orchestrator/sub-agent-cap.d.ts +2 -0
- package/dist/src/orchestrator/sub-agent-cap.js +12 -4
- package/dist/src/orchestrator/sub-agent-model-tier.js +1 -1
- package/dist/src/orchestrator/subagent-compactor.d.ts +21 -0
- package/dist/src/orchestrator/subagent-compactor.js +148 -24
- package/dist/src/orchestrator/subagent-compactor.spec.js +249 -1
- package/dist/src/orchestrator/text-tool-call-detector.d.ts +9 -5
- package/dist/src/orchestrator/text-tool-call-detector.js +16 -12
- package/dist/src/orchestrator/text-tool-call-detector.test.js +66 -8
- package/dist/src/orchestrator/tool-args-repair.js +1 -1
- package/dist/src/orchestrator/tool-engine.d.ts +153 -0
- package/dist/src/orchestrator/tool-engine.js +3138 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +3 -0
- package/dist/src/pil/__tests__/discovery-types.test.js +15 -4
- package/dist/src/pil/__tests__/discovery.test.js +89 -145
- package/dist/src/pil/__tests__/dual-run.test.js +2 -0
- package/dist/src/pil/__tests__/layer1-intent-trace.test.js +3 -0
- package/dist/src/pil/__tests__/layer1-intent.test.js +3 -0
- package/dist/src/pil/__tests__/layer16-clarity.test.js +35 -32
- package/dist/src/pil/__tests__/layer18-acceptance.test.js +1 -78
- package/dist/src/pil/__tests__/layer2_5-ponytail.test.d.ts +1 -0
- package/dist/src/pil/__tests__/layer2_5-ponytail.test.js +53 -0
- package/dist/src/pil/__tests__/layer3-ee-injection.test.js +67 -4
- package/dist/src/pil/__tests__/layer3-injected-chunk.test.js +14 -2
- package/dist/src/pil/__tests__/layer4-gsd.test.js +30 -0
- package/dist/src/pil/__tests__/layer5-context.test.js +39 -1
- package/dist/src/pil/__tests__/layer6-output.test.js +30 -2
- package/dist/src/pil/__tests__/llm-classify.test.js +79 -1
- package/dist/src/pil/__tests__/orchestrator-integration.test.js +3 -1
- package/dist/src/pil/__tests__/pipeline.test.js +11 -8
- package/dist/src/pil/__tests__/response-tools.test.js +52 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +5 -3
- package/dist/src/pil/agent-operating-contract.test.js +2 -2
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +1 -1
- package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
- package/dist/src/pil/cheap-model-workbooks.js +1 -1
- package/dist/src/pil/config.d.ts +20 -0
- package/dist/src/pil/config.js +35 -0
- package/dist/src/pil/discovery-types.d.ts +32 -9
- package/dist/src/pil/discovery.d.ts +3 -3
- package/dist/src/pil/discovery.js +138 -244
- package/dist/src/pil/index.d.ts +1 -1
- package/dist/src/pil/index.js +1 -1
- package/dist/src/pil/layer1-intent.d.ts +9 -1
- package/dist/src/pil/layer1-intent.js +62 -7
- package/dist/src/pil/layer1-intent.test.js +112 -2
- package/dist/src/pil/layer15-context-scan.js +1 -1
- package/dist/src/pil/layer16-clarity.d.ts +21 -25
- package/dist/src/pil/layer16-clarity.js +52 -88
- package/dist/src/pil/layer18-acceptance.d.ts +13 -3
- package/dist/src/pil/layer18-acceptance.js +1 -75
- package/dist/src/pil/layer2-personality.js +7 -8
- package/dist/src/pil/layer2_5-ponytail.d.ts +2 -0
- package/dist/src/pil/layer2_5-ponytail.js +41 -0
- package/dist/src/pil/layer3-ee-injection.js +180 -14
- package/dist/src/pil/layer4-gsd.js +22 -8
- package/dist/src/pil/layer5-context.d.ts +1 -0
- package/dist/src/pil/layer5-context.js +26 -11
- package/dist/src/pil/layer6-output.js +23 -5
- package/dist/src/pil/llm-classify.d.ts +11 -0
- package/dist/src/pil/llm-classify.js +196 -3
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +4 -3
- package/dist/src/pil/pipeline.js +15 -1
- package/dist/src/pil/response-tools.d.ts +16 -0
- package/dist/src/pil/response-tools.js +41 -0
- package/dist/src/pil/schema.d.ts +8 -0
- package/dist/src/pil/schema.js +24 -3
- package/dist/src/pil/task-tier-map.js +7 -7
- package/dist/src/pil/types.d.ts +9 -3
- package/dist/src/product-loop/__tests__/discovery-interview.test.js +103 -1
- package/dist/src/product-loop/__tests__/gather-selectable-alts.test.js +34 -0
- package/dist/src/product-loop/__tests__/sprint-self-verify.test.js +12 -12
- package/dist/src/product-loop/discovery-interview.d.ts +20 -0
- package/dist/src/product-loop/discovery-interview.js +121 -7
- package/dist/src/product-loop/gather.js +19 -5
- package/dist/src/product-loop/loop-driver.js +2 -2
- package/dist/src/product-loop/sprint-self-verify.js +2 -2
- package/dist/src/providers/__tests__/reasoning-roundtrip.test.js +12 -0
- package/dist/src/providers/auth/__tests__/gemini-oauth.test.d.ts +1 -5
- package/dist/src/providers/auth/__tests__/gemini-oauth.test.js +1 -5
- package/dist/src/providers/auth/gcloud.d.ts +28 -0
- package/dist/src/providers/auth/gcloud.js +102 -0
- package/dist/src/providers/auth/gemini-oauth.d.ts +46 -19
- package/dist/src/providers/auth/gemini-oauth.js +292 -105
- package/dist/src/providers/auth/grok-oauth.d.ts +1 -1
- package/dist/src/providers/auth/grok-oauth.js +1 -1
- package/dist/src/providers/auth/registry.js +28 -6
- package/dist/src/providers/gemini.d.ts +1 -1
- package/dist/src/providers/gemini.js +10 -3
- package/dist/src/providers/keychain.d.ts +2 -2
- package/dist/src/providers/keychain.js +20 -2
- package/dist/src/providers/openai.js +5 -1
- package/dist/src/providers/runtime.d.ts +1 -1
- package/dist/src/providers/runtime.js +11 -2
- package/dist/src/providers/siliconflow-sse-repair.js +1 -1
- package/dist/src/providers/strategies/google.strategy.d.ts +9 -2
- package/dist/src/providers/strategies/google.strategy.js +159 -9
- package/dist/src/providers/strategies/thinking-mode.js +19 -6
- package/dist/src/providers/types.d.ts +1 -1
- package/dist/src/router/decide.test.js +40 -8
- package/dist/src/router/step-router.d.ts +20 -0
- package/dist/src/router/step-router.js +73 -0
- package/dist/src/self-qa/agentic-loop.js +30 -21
- package/dist/src/self-qa/orchestrator.js +5 -5
- package/dist/src/self-qa/scenario-planner.js +1 -1
- package/dist/src/self-qa/spec-emitter.js +4 -4
- package/dist/src/storage/__tests__/hierarchical-session.test.d.ts +1 -0
- package/dist/src/storage/__tests__/hierarchical-session.test.js +161 -0
- package/dist/src/storage/__tests__/sweep-stale-pending.test.js +2 -2
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/migrations.js +13 -1
- package/dist/src/storage/transcript-response-entry.test.js +18 -5
- package/dist/src/storage/transcript-view.js +7 -1
- package/dist/src/storage/transcript.d.ts +3 -0
- package/dist/src/storage/transcript.js +254 -73
- package/dist/src/storage/ui-interaction-log.d.ts +17 -0
- package/dist/src/storage/usage.js +22 -5
- package/dist/src/tools/__tests__/native-tools.test.js +6 -0
- package/dist/src/tools/bash.d.ts +36 -23
- package/dist/src/tools/bash.js +59 -301
- package/dist/src/tools/bash.test.js +2 -257
- package/dist/src/tools/file-tracker.d.ts +5 -0
- package/dist/src/tools/file-tracker.js +14 -0
- package/dist/src/tools/file.js +2 -0
- package/dist/src/tools/git-safety.d.ts +38 -1
- package/dist/src/tools/git-safety.js +94 -4
- package/dist/src/tools/git-safety.test.js +45 -1
- package/dist/src/tools/native-tools.d.ts +1 -1
- package/dist/src/tools/native-tools.js +66 -1
- package/dist/src/tools/registry-bash-empty-command.test.js +4 -3
- package/dist/src/tools/registry-git-safety.test.js +17 -6
- package/dist/src/tools/registry.d.ts +6 -0
- package/dist/src/tools/registry.js +215 -13
- package/dist/src/types/index.d.ts +8 -2
- package/dist/src/ui/app.d.ts +1 -0
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/components/council-question-card.js +1 -0
- package/dist/src/ui/components/message-view.js +37 -3
- package/dist/src/ui/components/structured-response-view.js +7 -0
- package/dist/src/ui/components/task-list-panel.js +3 -12
- package/dist/src/ui/containers/chat-feed.d.ts +40 -0
- package/dist/src/ui/containers/chat-feed.js +66 -0
- package/dist/src/ui/containers/modals-layer.d.ts +87 -0
- package/dist/src/ui/containers/modals-layer.js +18 -0
- package/dist/src/ui/slash/__tests__/menu-parity.test.d.ts +1 -0
- package/dist/src/ui/slash/__tests__/menu-parity.test.js +1 -0
- package/dist/src/ui/slash/__tests__/ponytail.test.d.ts +1 -0
- package/dist/src/ui/slash/__tests__/ponytail.test.js +37 -0
- package/dist/src/ui/slash/expand.js +14 -1
- package/dist/src/ui/slash/export.js +16 -1
- package/dist/src/ui/slash/menu-items.js +1 -0
- package/dist/src/ui/slash/ponytail.d.ts +2 -0
- package/dist/src/ui/slash/ponytail.js +19 -0
- package/dist/src/ui/status-bar/store.js +0 -1
- package/dist/src/ui/status-bar/store.test.js +2 -2
- package/dist/src/ui/use-app-logic.d.ts +26 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/relaunch.js +1 -1
- package/dist/src/ui/utils/text.d.ts +11 -0
- package/dist/src/ui/utils/text.js +21 -1
- package/dist/src/ui/utils/text.test.js +25 -1
- package/dist/src/ui/utils/tools.js +3 -1
- package/dist/src/usage/cost-log.js +2 -2
- package/dist/src/usage/estimator.d.ts +14 -0
- package/dist/src/usage/estimator.js +22 -0
- package/dist/src/utils/__tests__/compaction-caps.test.d.ts +21 -0
- package/dist/src/utils/__tests__/compaction-caps.test.js +187 -0
- package/dist/src/utils/__tests__/llm-deadline-abort.test.d.ts +1 -0
- package/dist/src/utils/__tests__/llm-deadline-abort.test.js +33 -0
- package/dist/src/utils/__tests__/llm-deadline.test.js +16 -4
- package/dist/src/utils/__tests__/logger.test.d.ts +1 -0
- package/dist/src/utils/__tests__/logger.test.js +115 -0
- package/dist/src/utils/__tests__/settings-agent-first.test.d.ts +1 -0
- package/dist/src/utils/__tests__/settings-agent-first.test.js +48 -0
- package/dist/src/utils/install-manager.d.ts +1 -0
- package/dist/src/utils/install-manager.js +76 -7
- package/dist/src/utils/install-manager.test.js +43 -1
- package/dist/src/utils/llm-deadline.d.ts +9 -1
- package/dist/src/utils/llm-deadline.js +31 -2
- package/dist/src/utils/logger.d.ts +28 -0
- package/dist/src/utils/logger.js +171 -0
- package/dist/src/utils/permission-mode.d.ts +33 -0
- package/dist/src/utils/permission-mode.js +164 -3
- package/dist/src/utils/permission-mode.test.js +92 -1
- package/dist/src/utils/settings.d.ts +36 -32
- package/dist/src/utils/settings.js +151 -123
- package/dist/src/utils/update-checker.test.js +5 -1
- package/package.json +1 -1
|
@@ -39,21 +39,23 @@ afterEach(() => {
|
|
|
39
39
|
vi.doUnmock("../storage/index.js");
|
|
40
40
|
});
|
|
41
41
|
describe("Agent sandbox mode", { timeout: 30_000 }, () => {
|
|
42
|
-
it("can switch sandbox mode at runtime", async () => {
|
|
42
|
+
it("can switch sandbox mode at runtime — always 'off' (sandbox removed)", async () => {
|
|
43
43
|
const { Agent } = await importAgentModule();
|
|
44
44
|
const agent = new Agent(undefined, undefined, undefined, undefined, {
|
|
45
45
|
persistSession: false,
|
|
46
46
|
sandboxMode: "off",
|
|
47
47
|
});
|
|
48
48
|
expect(agent.getSandboxMode()).toBe("off");
|
|
49
|
+
// Sandbox has been removed: setSandboxMode is a no-op stub.
|
|
50
|
+
// The mode remains "off" regardless of what is passed.
|
|
49
51
|
agent.setSandboxMode("shuru");
|
|
50
|
-
expect(agent.getSandboxMode()).toBe("
|
|
52
|
+
expect(agent.getSandboxMode()).toBe("off");
|
|
51
53
|
});
|
|
52
|
-
it("passes sandbox mode into background delegations", async () => {
|
|
54
|
+
it("passes sandbox mode into background delegations — always 'off' (sandbox removed)", async () => {
|
|
53
55
|
const { Agent } = await importAgentModule();
|
|
54
56
|
const agent = new Agent(undefined, undefined, undefined, undefined, {
|
|
55
57
|
persistSession: false,
|
|
56
|
-
sandboxMode: "shuru",
|
|
58
|
+
sandboxMode: "shuru", // accepted for back-compat but ignored
|
|
57
59
|
});
|
|
58
60
|
const startMock = vi.fn(async () => ({ success: true, output: "ok" }));
|
|
59
61
|
agent.delegations.start = startMock;
|
|
@@ -62,7 +64,8 @@ describe("Agent sandbox mode", { timeout: 30_000 }, () => {
|
|
|
62
64
|
description: "Inspect",
|
|
63
65
|
prompt: "Look around",
|
|
64
66
|
});
|
|
65
|
-
|
|
67
|
+
// Sandbox removed: delegations always receive sandboxMode: "off".
|
|
68
|
+
expect(startMock).toHaveBeenCalledWith(expect.objectContaining({ agent: "explore" }), expect.objectContaining({ sandboxMode: "off" }));
|
|
66
69
|
});
|
|
67
70
|
it("can get and set sandbox settings", async () => {
|
|
68
71
|
const { Agent } = await importAgentModule();
|
|
@@ -80,7 +80,7 @@ export function parseBudgetOverride(raw) {
|
|
|
80
80
|
return { override: undefined, cleanedPrompt: raw };
|
|
81
81
|
// Strip the entire matched segment including its leading/trailing whitespace
|
|
82
82
|
// and re-collapse the surrounding spaces.
|
|
83
|
-
const cleaned =
|
|
83
|
+
const cleaned = `${raw.slice(0, match.index ?? 0)} ${raw.slice((match.index ?? 0) + match[0].length)}`
|
|
84
84
|
.replace(/\s+/g, " ")
|
|
85
85
|
.trim();
|
|
86
86
|
return { override: n, cleanedPrompt: cleaned };
|
|
@@ -57,6 +57,53 @@ export interface StallRepromptState {
|
|
|
57
57
|
* effects) so it is unit-testable in isolation from the orchestrator loop.
|
|
58
58
|
*/
|
|
59
59
|
export declare function shouldRepromptStall(s: StallRepromptState): boolean;
|
|
60
|
+
/** Inputs to the mid-loop stall continuation decision — see {@link shouldContinueAfterMidLoopStall}. */
|
|
61
|
+
export interface MidLoopStallState {
|
|
62
|
+
/** The watchdog fired for this attempt. */
|
|
63
|
+
stallTriggered: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Real content parts received across the WHOLE streamText attempt (all steps).
|
|
66
|
+
* `> 0` proves earlier tool steps already ran — so this is NOT a time-to-first-
|
|
67
|
+
* byte stall (that case is handled by {@link shouldRepromptStall}).
|
|
68
|
+
*/
|
|
69
|
+
chunksThisAttempt: number;
|
|
70
|
+
/**
|
|
71
|
+
* Real content parts received since the last step boundary (reset in
|
|
72
|
+
* `prepareStep`). `0` means the in-flight step's provider request produced no
|
|
73
|
+
* byte before the watchdog fired — a dead socket on a SINGLE step, with every
|
|
74
|
+
* prior step fully completed. Safe to continue: the completed steps'
|
|
75
|
+
* assistant+tool messages are appended to history before re-issuing, so no
|
|
76
|
+
* tool is re-run and no text is duplicated.
|
|
77
|
+
*/
|
|
78
|
+
chunksThisStep: number;
|
|
79
|
+
/** How many mid-loop continuations have already happened this turn. */
|
|
80
|
+
retryCount: number;
|
|
81
|
+
/** Configured cap (getProviderStallRetries); 0 disables continuation. */
|
|
82
|
+
maxRetries: number;
|
|
83
|
+
/** True on genuine user cancel (never continue over a cancel). */
|
|
84
|
+
aborted: boolean;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Decide whether a fired stall watchdog should CONTINUE the turn (append the
|
|
88
|
+
* completed steps' messages, then re-issue streamText to resume from the
|
|
89
|
+
* stalled step) instead of falling through to the partial-answer rescue.
|
|
90
|
+
*
|
|
91
|
+
* This is the mid-loop counterpart to {@link shouldRepromptStall}. The TTFB
|
|
92
|
+
* re-prompt restarts the WHOLE request from the original prompt, so it is gated
|
|
93
|
+
* on `chunksThisAttempt === 0` to avoid re-running tools. Continuation instead
|
|
94
|
+
* preserves all completed steps in history (assistant tool-calls + their
|
|
95
|
+
* tool-results), so re-issuing cannot re-run a tool — making it safe even when
|
|
96
|
+
* earlier steps had side effects (writes, commits).
|
|
97
|
+
*
|
|
98
|
+
* Qualifies ONLY when: the watchdog fired, earlier steps ran
|
|
99
|
+
* (`chunksThisAttempt > 0`), the CURRENT step produced nothing
|
|
100
|
+
* (`chunksThisStep === 0` → a clean dead socket, no partial text to duplicate),
|
|
101
|
+
* under the retry cap, and not a user cancel. A step that emitted partial text
|
|
102
|
+
* then stalled (`chunksThisStep > 0`) falls through to rescue instead, since
|
|
103
|
+
* re-issuing would duplicate that partial output. Pure (no side effects) so it
|
|
104
|
+
* is unit-testable in isolation from the orchestrator loop.
|
|
105
|
+
*/
|
|
106
|
+
export declare function shouldContinueAfterMidLoopStall(s: MidLoopStallState): boolean;
|
|
60
107
|
/**
|
|
61
108
|
* Exponential backoff (ms, capped at 4s) before the Nth stall re-prompt
|
|
62
109
|
* (1-based): 500 → 1000 → 2000 → 4000 → 4000.
|
|
@@ -40,6 +40,29 @@ export function shouldRepromptStall(s) {
|
|
|
40
40
|
s.assistantTextEmpty &&
|
|
41
41
|
!s.aborted);
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Decide whether a fired stall watchdog should CONTINUE the turn (append the
|
|
45
|
+
* completed steps' messages, then re-issue streamText to resume from the
|
|
46
|
+
* stalled step) instead of falling through to the partial-answer rescue.
|
|
47
|
+
*
|
|
48
|
+
* This is the mid-loop counterpart to {@link shouldRepromptStall}. The TTFB
|
|
49
|
+
* re-prompt restarts the WHOLE request from the original prompt, so it is gated
|
|
50
|
+
* on `chunksThisAttempt === 0` to avoid re-running tools. Continuation instead
|
|
51
|
+
* preserves all completed steps in history (assistant tool-calls + their
|
|
52
|
+
* tool-results), so re-issuing cannot re-run a tool — making it safe even when
|
|
53
|
+
* earlier steps had side effects (writes, commits).
|
|
54
|
+
*
|
|
55
|
+
* Qualifies ONLY when: the watchdog fired, earlier steps ran
|
|
56
|
+
* (`chunksThisAttempt > 0`), the CURRENT step produced nothing
|
|
57
|
+
* (`chunksThisStep === 0` → a clean dead socket, no partial text to duplicate),
|
|
58
|
+
* under the retry cap, and not a user cancel. A step that emitted partial text
|
|
59
|
+
* then stalled (`chunksThisStep > 0`) falls through to rescue instead, since
|
|
60
|
+
* re-issuing would duplicate that partial output. Pure (no side effects) so it
|
|
61
|
+
* is unit-testable in isolation from the orchestrator loop.
|
|
62
|
+
*/
|
|
63
|
+
export function shouldContinueAfterMidLoopStall(s) {
|
|
64
|
+
return (s.stallTriggered && s.chunksThisAttempt > 0 && s.chunksThisStep === 0 && s.retryCount < s.maxRetries && !s.aborted);
|
|
65
|
+
}
|
|
43
66
|
/**
|
|
44
67
|
* Exponential backoff (ms, capped at 4s) before the Nth stall re-prompt
|
|
45
68
|
* (1-based): 500 → 1000 → 2000 → 4000 → 4000.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { createStallWatchdog, STALL_ABORT_REASON, shouldRepromptStall, stallRepromptBackoffMs, } from "./stall-watchdog.js";
|
|
2
|
+
import { createStallWatchdog, STALL_ABORT_REASON, shouldContinueAfterMidLoopStall, shouldRepromptStall, stallRepromptBackoffMs, } from "./stall-watchdog.js";
|
|
3
3
|
describe("createStallWatchdog", () => {
|
|
4
4
|
beforeEach(() => vi.useFakeTimers());
|
|
5
5
|
afterEach(() => vi.useRealTimers());
|
|
@@ -103,6 +103,41 @@ describe("shouldRepromptStall", () => {
|
|
|
103
103
|
expect(shouldRepromptStall(ttfb({ aborted: true }))).toBe(false);
|
|
104
104
|
});
|
|
105
105
|
});
|
|
106
|
+
describe("shouldContinueAfterMidLoopStall", () => {
|
|
107
|
+
// A clean mid-loop dead socket: watchdog fired AFTER earlier steps ran
|
|
108
|
+
// (chunksThisAttempt > 0), but the in-flight step produced nothing
|
|
109
|
+
// (chunksThisStep === 0). The ONLY shape that continues. Distinct from the
|
|
110
|
+
// TTFB re-prompt, which requires chunksThisAttempt === 0.
|
|
111
|
+
const midLoop = (over = {}) => ({
|
|
112
|
+
stallTriggered: true,
|
|
113
|
+
chunksThisAttempt: 132, // 66 prior steps' worth of chunks
|
|
114
|
+
chunksThisStep: 0,
|
|
115
|
+
retryCount: 0,
|
|
116
|
+
maxRetries: 1,
|
|
117
|
+
aborted: false,
|
|
118
|
+
...over,
|
|
119
|
+
});
|
|
120
|
+
it("continues a mid-loop dead-socket stall under the cap", () => {
|
|
121
|
+
expect(shouldContinueAfterMidLoopStall(midLoop())).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
it("does NOT continue when the watchdog never fired", () => {
|
|
124
|
+
expect(shouldContinueAfterMidLoopStall(midLoop({ stallTriggered: false }))).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
it("does NOT continue a time-to-first-byte stall (chunksThisAttempt === 0 → TTFB re-prompt owns it)", () => {
|
|
127
|
+
expect(shouldContinueAfterMidLoopStall(midLoop({ chunksThisAttempt: 0 }))).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
it("does NOT continue when the stalled step already emitted output (would duplicate)", () => {
|
|
130
|
+
expect(shouldContinueAfterMidLoopStall(midLoop({ chunksThisStep: 3 }))).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
it("does NOT continue once the retry cap is reached", () => {
|
|
133
|
+
expect(shouldContinueAfterMidLoopStall(midLoop({ retryCount: 1, maxRetries: 1 }))).toBe(false);
|
|
134
|
+
// maxRetries=0 means the feature is disabled — never continue.
|
|
135
|
+
expect(shouldContinueAfterMidLoopStall(midLoop({ retryCount: 0, maxRetries: 0 }))).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
it("does NOT continue over a genuine user cancel", () => {
|
|
138
|
+
expect(shouldContinueAfterMidLoopStall(midLoop({ aborted: true }))).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
106
141
|
describe("stallRepromptBackoffMs", () => {
|
|
107
142
|
it("grows exponentially and caps at 4s", () => {
|
|
108
143
|
expect(stallRepromptBackoffMs(1)).toBe(500);
|
|
@@ -34,8 +34,10 @@ import { normalizeModelId } from "../models/registry.js";
|
|
|
34
34
|
import { cheapModelShellLine, injectCheapModelPlaybook, injectCheapModelShellDirective, shouldInjectCheapModelPlaybook, } from "../pil/cheap-model-playbook.js";
|
|
35
35
|
import { injectCheapModelWorkbook, shouldInjectCheapModelWorkbook, subagentTaskType, } from "../pil/cheap-model-workbooks.js";
|
|
36
36
|
import { getProviderCapabilities } from "../providers/capabilities.js";
|
|
37
|
+
import { getVisionGuidanceForTextOnly } from "../providers/mcp-vision-bridge.js";
|
|
37
38
|
import { captureToolSchemas } from "../providers/patch-zod-schema.js";
|
|
38
39
|
import { buildTurnProviderOptions, requireRuntimeProvider, resolveModelRuntime, shouldDropParam, } from "../providers/runtime.js";
|
|
40
|
+
import { needsVisionProxy } from "../providers/vision-proxy.js";
|
|
39
41
|
import { wireDebug } from "../providers/wire-debug.js";
|
|
40
42
|
import { BashTool } from "../tools/bash.js";
|
|
41
43
|
import { createBuiltinTools } from "../tools/registry.js";
|
|
@@ -56,7 +58,7 @@ import { attachReminderToMessages, buildScopeReminder, cadenceForSize, shouldInj
|
|
|
56
58
|
import { recordCompaction, recordElision } from "./session-experience.js";
|
|
57
59
|
import { createStallWatchdog, STALL_ERROR_MESSAGE } from "./stall-watchdog.js";
|
|
58
60
|
import { wrapToolSetWithCap } from "./sub-agent-cap.js";
|
|
59
|
-
import { compactSubAgentMessages } from "./subagent-compactor.js";
|
|
61
|
+
import { compactSubAgentMessages, applyAnthropicPromptCaching } from "./subagent-compactor.js";
|
|
60
62
|
import { combineAbortSignals, firstLine, formatSubagentActivity } from "./tool-utils.js";
|
|
61
63
|
/**
|
|
62
64
|
* StreamRunner — extracted sub-agent stream lifecycle.
|
|
@@ -133,10 +135,19 @@ export class StreamRunner {
|
|
|
133
135
|
: topBash.getSandboxSettings(),
|
|
134
136
|
shellSettings: getCurrentShellSettings(),
|
|
135
137
|
});
|
|
138
|
+
// Resolve child model early so we can pass modelId to createBuiltinTools
|
|
139
|
+
// (needed for vision-proxy tools: analyze_image / ask_vision_proxy).
|
|
140
|
+
const childModelId = normalizeModelId(isVision
|
|
141
|
+
? VISION_MODEL
|
|
142
|
+
: isComputer
|
|
143
|
+
? COMPUTER_MODEL
|
|
144
|
+
: custom
|
|
145
|
+
? custom.model
|
|
146
|
+
: this.deps.resolveModelForTask(isExplore ? "explore" : isVerify || isVerifyDetect || isVerifyManifest ? "verify" : "general"));
|
|
136
147
|
// Mirror the file-local `createTools` wrapper from orchestrator.ts —
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
const childBaseToolsRaw = createBuiltinTools(childBash, childMode);
|
|
148
|
+
// pass modelId so registry can inject analyze_image/ask_vision_proxy for
|
|
149
|
+
// text-only child models (needsVisionProxy).
|
|
150
|
+
const childBaseToolsRaw = createBuiltinTools(childBash, childMode, { modelId: childModelId });
|
|
140
151
|
// Wrap with the cumulative cap so the sub-agent's tool loop cannot
|
|
141
152
|
// accumulate unbounded tool_result tokens. See sub-agent-cap.ts for the
|
|
142
153
|
// tiered compression schedule. The cap is per-invocation; each sub-agent
|
|
@@ -161,13 +172,6 @@ export class StreamRunner {
|
|
|
161
172
|
let lastActivity = initialDetail;
|
|
162
173
|
let childTools = childBaseTools;
|
|
163
174
|
let closeMcp;
|
|
164
|
-
const childModelId = normalizeModelId(isVision
|
|
165
|
-
? VISION_MODEL
|
|
166
|
-
: isComputer
|
|
167
|
-
? COMPUTER_MODEL
|
|
168
|
-
: custom
|
|
169
|
-
? custom.model
|
|
170
|
-
: this.deps.resolveModelForTask(isExplore ? "explore" : isVerify || isVerifyDetect || isVerifyManifest ? "verify" : "general"));
|
|
171
175
|
const topModelId = this.deps.getModelId();
|
|
172
176
|
if (childModelId !== topModelId) {
|
|
173
177
|
statusBarStore.setState({ routed_from: topModelId, model: childModelId });
|
|
@@ -212,6 +216,11 @@ export class StreamRunner {
|
|
|
212
216
|
const childSystem = shouldInjectCheapModelPlaybook(childRuntime.modelInfo)
|
|
213
217
|
? injectCheapModelShellDirective(childWithPlaybook, cheapModelShellLine(resolveShell({}).kind, process.platform))
|
|
214
218
|
: childWithPlaybook;
|
|
219
|
+
// Inject vision proxy guidance for text-only child models (DeepSeek etc.)
|
|
220
|
+
// so sub-agents know to use analyze_image / ask_vision_proxy when they
|
|
221
|
+
// receive image context or file paths. Mirrors top-level in message-processor.
|
|
222
|
+
const visionGuidance = needsVisionProxy(childModelId) ? getVisionGuidanceForTextOnly(childModelId) : "";
|
|
223
|
+
const childSystemWithVision = visionGuidance ? `${childSystem}\n\n${visionGuidance}` : childSystem;
|
|
215
224
|
onActivity?.(initialDetail);
|
|
216
225
|
if (childMode === "agent" && taskCaps.supportsClientTools(childRuntime.modelInfo)) {
|
|
217
226
|
const mcpBundle = await acquireMcpTools(loadMcpServers(), {
|
|
@@ -245,7 +254,8 @@ export class StreamRunner {
|
|
|
245
254
|
// signal is intentionally unused on this branch — vision was the only consumer.
|
|
246
255
|
void signal;
|
|
247
256
|
const childMessages = [{ role: "user", content: childPrompt }];
|
|
248
|
-
|
|
257
|
+
// The main agent manages its sub-agents, so don't apply an arbitrary hard limit.
|
|
258
|
+
const maxSteps = request.maxToolRounds ?? (this.deps.getMaxToolRounds() * 2);
|
|
249
259
|
// F1 parity — derive per-turn providerOptions so the sub-agent OpenAI calls
|
|
250
260
|
// carry a stable session-derived promptCacheKey (every tool round routes to
|
|
251
261
|
// the same cache node, keeping the unchanging prefix cached). The top-level
|
|
@@ -265,7 +275,7 @@ export class StreamRunner {
|
|
|
265
275
|
childMode,
|
|
266
276
|
childBash,
|
|
267
277
|
childRuntime,
|
|
268
|
-
childSystem,
|
|
278
|
+
childSystem: childSystemWithVision,
|
|
269
279
|
childMessages,
|
|
270
280
|
childTools,
|
|
271
281
|
childProviderOptions,
|
|
@@ -348,16 +358,16 @@ export class StreamRunner {
|
|
|
348
358
|
// Explore sub-agents are READ-ONLY research — a codebase investigation
|
|
349
359
|
// legitimately needs more grep/read steps than the tight general/medium=10
|
|
350
360
|
// cell allows. Cutting it early (esp. for reasoning models that front-load
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
//
|
|
361
|
+
// Sub-agent ceiling is no longer a hard halt. Per user request:
|
|
362
|
+
// "cũng áp dụng với sub agent nhé không nên hardcode maxtool mà nếu có
|
|
363
|
+
// vấn đề gì sẽ có main agent (khi spawn) kiểm soát đừng hard"
|
|
354
364
|
const _subCeiling = isExplore ? resolveCeiling("analyze", "large") : resolveCeiling("general", "medium");
|
|
355
365
|
const _subCounterKey = `subagent:${subCallId}`;
|
|
356
366
|
const _subStopWhen = (async (state) => {
|
|
367
|
+
incSessionStep(_subCounterKey); // Keep telemetry counter ticking
|
|
357
368
|
if (state.steps.length >= maxSteps)
|
|
358
369
|
return true;
|
|
359
|
-
|
|
360
|
-
return next >= _subCeiling;
|
|
370
|
+
return false;
|
|
361
371
|
});
|
|
362
372
|
// Silent-hang guard — mirror the top-level loop (message-processor.ts).
|
|
363
373
|
// A sub-agent provider connection can accept the request but never send a
|
|
@@ -436,12 +446,19 @@ export class StreamRunner {
|
|
|
436
446
|
/* fail-open */
|
|
437
447
|
}
|
|
438
448
|
};
|
|
449
|
+
// T1.1 + T1.2 — reasoning models (DeepSeek V4 Flash, R1) emit 2K-5K
|
|
450
|
+
// CoT tokens per turn that accumulate across the multi-step loop.
|
|
451
|
+
// Strip old reasoning and compact earlier (ratio 0.3 vs 0.5) to
|
|
452
|
+
// cut ~40-60% of cumulative input tokens.
|
|
453
|
+
const isReasoningModel = childRuntime.modelInfo?.reasoning === true;
|
|
439
454
|
const compacted = compactSubAgentMessages(stripped, {
|
|
440
455
|
thresholdChars: compactThreshold,
|
|
441
456
|
keepLastTurns: compactKeepLast,
|
|
442
457
|
contextWindowTokens: childCtxWindow,
|
|
458
|
+
contextFillRatio: isReasoningModel ? 0.3 : undefined,
|
|
443
459
|
keepToolIds: subKeepToolIds.length ? subKeepToolIds : undefined,
|
|
444
460
|
persistArtifact: persistSubArtifact,
|
|
461
|
+
stripOldReasoning: isReasoningModel,
|
|
445
462
|
});
|
|
446
463
|
if (compacted !== stripped)
|
|
447
464
|
recordCompaction(stepNumber);
|
|
@@ -456,21 +473,26 @@ export class StreamRunner {
|
|
|
456
473
|
const _subK = cadenceForSize(_subSize);
|
|
457
474
|
const _subShouldRemind = shouldInjectReminder(stepNumber, _subK);
|
|
458
475
|
const _subShouldWarn = shouldInjectSoftWarn(stepNumber, _subCeiling, _subCounterKey);
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
476
|
+
const finalMessages = (() => {
|
|
477
|
+
if (_subShouldRemind || _subShouldWarn) {
|
|
478
|
+
const _baseReminder = buildScopeReminder({
|
|
479
|
+
step: stepNumber,
|
|
480
|
+
ceiling: _subCeiling,
|
|
481
|
+
taskType: "general",
|
|
482
|
+
size: _subSize,
|
|
483
|
+
originalPrompt: prepared.request.prompt,
|
|
484
|
+
});
|
|
485
|
+
const _reminder = _subShouldWarn ? `[approaching ceiling] ${_baseReminder}` : _baseReminder;
|
|
486
|
+
return attachReminderToMessages(compacted, _reminder);
|
|
487
|
+
}
|
|
488
|
+
return compacted;
|
|
489
|
+
})();
|
|
490
|
+
if (childRuntime.modelId.startsWith("claude")) {
|
|
491
|
+
return { messages: applyAnthropicPromptCaching(finalMessages, childRuntime.modelId) };
|
|
470
492
|
}
|
|
471
493
|
if (compacted === stripped && stripped === messages)
|
|
472
494
|
return undefined;
|
|
473
|
-
return { messages:
|
|
495
|
+
return { messages: finalMessages };
|
|
474
496
|
},
|
|
475
497
|
...(childDropTemperature ? {} : { temperature: isExplore ? 0.2 : 0.5 }),
|
|
476
498
|
...(childDropMaxOutput ? {} : { maxOutputTokens: Math.min(this.deps.getMaxTokens(), 8_192) }),
|
|
@@ -64,6 +64,8 @@ export interface SubAgentCapState {
|
|
|
64
64
|
cumulative: number;
|
|
65
65
|
/** Configured ceiling. */
|
|
66
66
|
max: number;
|
|
67
|
+
/** Hard cap ceiling (e.g. max * 2). */
|
|
68
|
+
hardMax?: number;
|
|
67
69
|
/** True once `cumulative >= max` (sub-agent should wrap up). */
|
|
68
70
|
exhausted: boolean;
|
|
69
71
|
/** Number of duplicate-output detections (telemetry / tests). */
|
|
@@ -46,7 +46,9 @@ function shortHash(text) {
|
|
|
46
46
|
return createHash("sha1").update(text).digest("hex").slice(0, 12);
|
|
47
47
|
}
|
|
48
48
|
export function compressForCap(state, raw) {
|
|
49
|
-
|
|
49
|
+
const hardCeiling = state.hardMax ?? state.max;
|
|
50
|
+
if (state.exhausted || state.cumulative >= hardCeiling) {
|
|
51
|
+
state.exhausted = true;
|
|
50
52
|
return `[${state.label} tool budget exhausted (${state.cumulative}/${state.max} chars). Further tool calls will return this stub. Summarize findings now and return.]`;
|
|
51
53
|
}
|
|
52
54
|
state.callIndex += 1;
|
|
@@ -68,7 +70,11 @@ export function compressForCap(state, raw) {
|
|
|
68
70
|
}
|
|
69
71
|
const ratio = state.cumulative / state.max;
|
|
70
72
|
let out;
|
|
71
|
-
if (
|
|
73
|
+
if (state.cumulative >= state.max) {
|
|
74
|
+
const trimmed = trimHead(raw, state.highTierChars, state.label);
|
|
75
|
+
out = `${trimmed}\n\n[Warning: ${state.label} tool budget exceeded (${state.cumulative}/${state.max} chars). Please finalize your work and summarize findings now.]`;
|
|
76
|
+
}
|
|
77
|
+
else if (ratio >= state.highTierRatio) {
|
|
72
78
|
out = trimHead(raw, state.highTierChars, state.label);
|
|
73
79
|
}
|
|
74
80
|
else if (ratio >= state.midTierRatio) {
|
|
@@ -78,7 +84,7 @@ export function compressForCap(state, raw) {
|
|
|
78
84
|
out = raw;
|
|
79
85
|
}
|
|
80
86
|
state.cumulative += out.length;
|
|
81
|
-
if (state.cumulative >=
|
|
87
|
+
if (state.cumulative >= hardCeiling)
|
|
82
88
|
state.exhausted = true;
|
|
83
89
|
return out;
|
|
84
90
|
}
|
|
@@ -141,9 +147,11 @@ function wrapInternal(tools, state) {
|
|
|
141
147
|
* cumulative state.
|
|
142
148
|
*/
|
|
143
149
|
export function wrapToolSetWithCap(tools, opts = {}) {
|
|
150
|
+
const max = Math.max(20_000, opts.maxCumulativeChars ?? DEFAULT_MAX_CUMULATIVE_CHARS);
|
|
144
151
|
const state = {
|
|
145
152
|
cumulative: 0,
|
|
146
|
-
max
|
|
153
|
+
max,
|
|
154
|
+
hardMax: max * 2,
|
|
147
155
|
exhausted: false,
|
|
148
156
|
dedupHits: 0,
|
|
149
157
|
seenHashes: new Map(),
|
|
@@ -24,7 +24,7 @@ export const TASK_TIER_PREFS = {
|
|
|
24
24
|
// general sub-agents downgrade to balanced (was premium-first) — the top
|
|
25
25
|
// model already planned the delegation; the focused execution doesn't need
|
|
26
26
|
// premium. Premium remains the fallback so premium-only providers are unaffected.
|
|
27
|
-
general: ["balanced", "premium"],
|
|
27
|
+
general: ["balanced", "fast", "premium"],
|
|
28
28
|
// verify keeps premium-first: a downgrade here would weaken the very check it
|
|
29
29
|
// exists to perform. Mirrors council `verify` role preference.
|
|
30
30
|
verify: ["premium", "balanced"],
|
|
@@ -96,6 +96,14 @@ export interface SubAgentCompactorOptions {
|
|
|
96
96
|
* source:"tool-artifact" so layer3/ee.query can later fetch "full tool result id=xxx".
|
|
97
97
|
*/
|
|
98
98
|
persistArtifact?: (toolCallId: string, toolName: string, fullContent: string, reason: string) => void;
|
|
99
|
+
/**
|
|
100
|
+
* T1.1 — strip reasoning parts from old assistant turns (older than
|
|
101
|
+
* keepLastTurns). Reasoning tokens (CoT / <think>) from prior turns are
|
|
102
|
+
* never re-read by the model but accumulate O(N) chars per turn, costing
|
|
103
|
+
* full input billing on every subsequent step. Default true for reasoning
|
|
104
|
+
* models, false otherwise.
|
|
105
|
+
*/
|
|
106
|
+
stripOldReasoning?: boolean;
|
|
99
107
|
}
|
|
100
108
|
/**
|
|
101
109
|
* G1 — coarse char→token conversion. The real ratio is provider/tokenizer
|
|
@@ -140,3 +148,16 @@ export declare function cumulativeMessageChars(messages: ReadonlyArray<ModelMess
|
|
|
140
148
|
* step.
|
|
141
149
|
*/
|
|
142
150
|
export declare function compactSubAgentMessages(messages: ReadonlyArray<ModelMessage>, opts?: SubAgentCompactorOptions): ModelMessage[];
|
|
151
|
+
/**
|
|
152
|
+
* Injects Anthropic prompt caching (cacheControl) into the last message's content
|
|
153
|
+
* block(s) if the model is Claude (starts with 'claude').
|
|
154
|
+
* Creates a copy of the messages array and the last message to avoid mutating in-place.
|
|
155
|
+
*/
|
|
156
|
+
export declare function applyAnthropicPromptCaching(messages: readonly ModelMessage[], modelId: string): ModelMessage[];
|
|
157
|
+
/**
|
|
158
|
+
* Safely slice message history to keep at most `maxMessages` messages.
|
|
159
|
+
* Preserves the system message(s) at the front and ensures that the slice
|
|
160
|
+
* starts with a "user" message and does not split assistant tool calls and
|
|
161
|
+
* corresponding tool results.
|
|
162
|
+
*/
|
|
163
|
+
export declare function sliceMessageHistory(messages: ReadonlyArray<ModelMessage>, maxMessages?: number): ModelMessage[];
|