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
|
@@ -14,29 +14,32 @@ import { apiBaseFor } from "../providers/endpoints.js";
|
|
|
14
14
|
import { loadKeyForProvider } from "../providers/keychain.js";
|
|
15
15
|
import { createProviderFactory, createProviderFactoryAsync, detectProviderForModel, requireRuntimeProvider, resolveModelRuntime as resolveRuntime, } from "../providers/runtime.js";
|
|
16
16
|
import { ALL_PROVIDER_IDS } from "../providers/types.js";
|
|
17
|
-
import { appendCompaction, appendMessages, appendSystemMessage, buildChatEntries, getNextMessageSequence, getSessionTotalTokens, loadTranscript, loadTranscriptState, logInteraction, markMessageCompleted, recordUsageEvent, SessionStore, } from "../storage/index.js";
|
|
17
|
+
import { appendCompaction, appendMessages, appendSystemMessage, buildChatEntries, getLastTodoWriteArgs, getNextMessageSequence, getSessionTotalTokens, loadTranscript, loadTranscriptState, logInteraction, markMessageCompleted, recordUsageEvent, SessionStore, } from "../storage/index.js";
|
|
18
18
|
import { BashTool } from "../tools/bash.js";
|
|
19
19
|
import { createBuiltinTools } from "../tools/registry.js";
|
|
20
20
|
import { ScheduleManager } from "../tools/schedule.js";
|
|
21
|
+
import { snapshotFromTodoWriteArgs } from "../tools/todo-write-snapshot.js";
|
|
21
22
|
import { statusBarStore } from "../ui/status-bar/store.js";
|
|
22
23
|
import { appendCostLog } from "../usage/cost-log.js";
|
|
23
24
|
import { appendDecisionLog } from "../usage/decision-log.js";
|
|
24
|
-
import { projectCostUSD } from "../usage/estimator.js";
|
|
25
|
-
import {
|
|
25
|
+
import { projectCostUSD, sanitizeInputTokens } from "../usage/estimator.js";
|
|
26
|
+
import { logger } from "../utils/logger.js";
|
|
27
|
+
import { getAutoCompactThresholdPct, getCouncilRounds, getCurrentModel, getCurrentShellSettings, getModeSpecificModel, getRoleModel, getRoleModels, isAutoCompactAfterTurnEnabled, isCouncilMultiProviderPreferred, isProviderDisabled, loadUserSettings, } from "../utils/settings.js";
|
|
26
28
|
import { runSideQuestion } from "../utils/side-question.js";
|
|
27
29
|
import { buildVerifyDetectPrompt, normalizeVerifyRecipe } from "../verify/entrypoint.js";
|
|
28
30
|
import { runVerifyOrchestration } from "../verify/orchestrator.js";
|
|
29
31
|
import { COUNCIL_COLOR_BG, COUNCIL_COLOR_RESET, COUNCIL_ROLE_COLORS, } from "./agent-options.js";
|
|
32
|
+
import { AUTO_COMMIT_ATTRIBUTION, isAutoCommitEnabled, maybeAutoCommitTurn, snapshotDirtyPaths, } from "./auto-commit.js";
|
|
30
33
|
import { BatchTurnRunner } from "./batch-turn-runner.js";
|
|
31
34
|
import { accumulateUsage, buildAssistantBatchMessage, buildBatchChatCompletionRequest, buildBatchName, buildToolBatchMessage, extractJsonObject, getBatchUsage, hasUsage, parseToolArgumentsOrRaw, toLocalToolCall, } from "./batch-utils.js";
|
|
32
|
-
import { createCompactionSummaryMessage, DEFAULT_KEEP_RECENT_TOKENS, DEFAULT_RESERVE_TOKENS, estimateConversationTokens, extractUserContent, generateCompactionSummary, POST_TURN_MIN_TOKENS, prepareCompaction, shouldCompactContext, } from "./compaction.js";
|
|
35
|
+
import { createCompactionSummaryMessage, DEFAULT_KEEP_RECENT_TOKENS, DEFAULT_RESERVE_TOKENS, estimateConversationTokens, extractUserContent, generateCompactionSummary, POST_TURN_MIN_TOKENS, prepareCompaction, proposeCompaction, shouldCompactContext, } from "./compaction.js";
|
|
33
36
|
import { CouncilManager } from "./council-manager.js";
|
|
34
37
|
import { CrossTurnDedup, isCrossTurnDedupEnabled } from "./cross-turn-dedup.js";
|
|
35
38
|
import { DelegationManager } from "./delegations.js";
|
|
36
39
|
import { loadFlowResumeDigest } from "./flow-resume.js";
|
|
37
40
|
import { MessageProcessor } from "./message-processor.js";
|
|
38
41
|
import { lastPersistedSeq } from "./message-seq.js";
|
|
39
|
-
import { buildSystemPrompt, MAX_TOOL_ROUNDS } from "./prompts.js";
|
|
42
|
+
import { buildSystemPrompt, HARD_MAX_TOOL_ROUNDS, MAX_TOOL_ROUNDS } from "./prompts.js";
|
|
40
43
|
import { getReadPathBudgetCap, ReadPathBudget } from "./read-path-budget.js";
|
|
41
44
|
import { withStreamRetry } from "./retry-stream.js";
|
|
42
45
|
import { StreamRunner } from "./stream-runner.js";
|
|
@@ -105,6 +108,7 @@ function createTools(_bash, _provider, _mode, _opts) {
|
|
|
105
108
|
runDelegation: _opts?.runDelegation,
|
|
106
109
|
readDelegation: _opts?.readDelegation,
|
|
107
110
|
listDelegations: _opts?.listDelegations,
|
|
111
|
+
killDelegation: _opts?.killDelegation,
|
|
108
112
|
modelId: _opts?.modelId,
|
|
109
113
|
});
|
|
110
114
|
}
|
|
@@ -133,6 +137,7 @@ export class Agent {
|
|
|
133
137
|
/** UI-registered live-queue steer drain; see Agent.setSteerDrain. */
|
|
134
138
|
steerDrain = null;
|
|
135
139
|
maxToolRounds;
|
|
140
|
+
hardMaxToolRounds;
|
|
136
141
|
mode = "agent";
|
|
137
142
|
modelId;
|
|
138
143
|
maxTokens;
|
|
@@ -237,7 +242,10 @@ export class Agent {
|
|
|
237
242
|
this.setApiKey(apiKey, baseURL);
|
|
238
243
|
}
|
|
239
244
|
this.schedules = new ScheduleManager(() => this.bash.getCwd(), () => this.modelId);
|
|
240
|
-
|
|
245
|
+
const settings = loadUserSettings();
|
|
246
|
+
this.maxToolRounds = maxToolRounds || settings.maxToolRounds || MAX_TOOL_ROUNDS;
|
|
247
|
+
const baseHardMax = settings.hardMaxToolRounds || HARD_MAX_TOOL_ROUNDS;
|
|
248
|
+
this.hardMaxToolRounds = Math.max(Math.floor(this.maxToolRounds * 1.5), baseHardMax);
|
|
241
249
|
const envMax = Number(process.env.MUONROI_MAX_TOKENS);
|
|
242
250
|
this.maxTokens = Number.isFinite(envMax) && envMax > 0 ? envMax : 16_384;
|
|
243
251
|
this.batchApi = options.batchApi ?? false;
|
|
@@ -264,7 +272,7 @@ export class Agent {
|
|
|
264
272
|
warmMcpClients(filterMcpServersByMessage(loadMcpServers(), ""));
|
|
265
273
|
}
|
|
266
274
|
catch (err) {
|
|
267
|
-
|
|
275
|
+
logger.error("orchestrator", "MCP pre-warm skipped", { error: err });
|
|
268
276
|
}
|
|
269
277
|
})();
|
|
270
278
|
if (options.persistSession !== false) {
|
|
@@ -355,10 +363,12 @@ export class Agent {
|
|
|
355
363
|
return this.mode;
|
|
356
364
|
}
|
|
357
365
|
getSandboxMode() {
|
|
366
|
+
// Sandbox has been removed; BashTool.getSandboxMode() always returns "off".
|
|
358
367
|
return this.bash.getSandboxMode();
|
|
359
368
|
}
|
|
360
|
-
setSandboxMode(
|
|
361
|
-
|
|
369
|
+
setSandboxMode(_mode) {
|
|
370
|
+
// No-op: sandbox has been removed. BashTool no longer has a mutable sandbox mode.
|
|
371
|
+
// Will be re-implemented when the new sandbox is ready.
|
|
362
372
|
}
|
|
363
373
|
getSandboxSettings() {
|
|
364
374
|
return this.bash.getSandboxSettings();
|
|
@@ -419,6 +429,10 @@ export class Agent {
|
|
|
419
429
|
getMessages() {
|
|
420
430
|
return this.messages;
|
|
421
431
|
}
|
|
432
|
+
setMessages(messages) {
|
|
433
|
+
this.messages = messages;
|
|
434
|
+
this.messageSeqs = messages.map(() => null);
|
|
435
|
+
}
|
|
422
436
|
async listSchedules() {
|
|
423
437
|
return this.schedules.list();
|
|
424
438
|
}
|
|
@@ -516,6 +530,15 @@ export class Agent {
|
|
|
516
530
|
setToolLoopCapHandler(fn) {
|
|
517
531
|
this._toolLoopCapHandler = fn;
|
|
518
532
|
}
|
|
533
|
+
// Safety-override handler — set by the UI (app.tsx) at startup. Invoked
|
|
534
|
+
// from the message-processor tool-result pipeline when a safety block
|
|
535
|
+
// (catastrophic, dangerous, git-safety, empty-bash) is detected. The UI
|
|
536
|
+
// surfaces an askcard ("Allow once / Allow session / Block") and resolves
|
|
537
|
+
// with the verdict. When unset, blocks pass through as normal errors.
|
|
538
|
+
_safetyOverrideHandler = null;
|
|
539
|
+
setSafetyOverrideHandler(fn) {
|
|
540
|
+
this._safetyOverrideHandler = fn;
|
|
541
|
+
}
|
|
519
542
|
respondToToolApproval(approvalId, approved) {
|
|
520
543
|
const toolApprovalResponse = {
|
|
521
544
|
role: "tool",
|
|
@@ -640,6 +663,14 @@ export class Agent {
|
|
|
640
663
|
return [];
|
|
641
664
|
return buildChatEntries(this.session.id);
|
|
642
665
|
}
|
|
666
|
+
getLastTodoSnapshot() {
|
|
667
|
+
if (!this.session)
|
|
668
|
+
return null;
|
|
669
|
+
const argsJson = getLastTodoWriteArgs(this.session.id);
|
|
670
|
+
if (!argsJson)
|
|
671
|
+
return null;
|
|
672
|
+
return snapshotFromTodoWriteArgs(argsJson);
|
|
673
|
+
}
|
|
643
674
|
getSessionSnapshot() {
|
|
644
675
|
if (!this.session || !this.workspace)
|
|
645
676
|
return null;
|
|
@@ -765,6 +796,10 @@ export class Agent {
|
|
|
765
796
|
// where orchestrator/task/title traffic is actually spending.
|
|
766
797
|
// Best-effort: failures inside appendCostLog are swallowed (see cost-log.ts).
|
|
767
798
|
const breakdown = source === "message" ? (this._lastPromptBreakdown ?? undefined) : undefined;
|
|
799
|
+
// Sanitize actualInputTokens for providers (e.g. SiliconFlow) that return
|
|
800
|
+
// implausibly low prompt_tokens (e.g. 10) regardless of prompt size.
|
|
801
|
+
const estIn = breakdown ? Math.ceil(((breakdown.systemChars ?? 0) + (breakdown.messagesChars ?? 0)) / 4) : 0;
|
|
802
|
+
const actualInput = sanitizeInputTokens(totalInput, estIn);
|
|
768
803
|
appendCostLog({
|
|
769
804
|
ts: Date.now(),
|
|
770
805
|
provider: this.providerId,
|
|
@@ -772,7 +807,7 @@ export class Agent {
|
|
|
772
807
|
estimatedUsd: turnCostMicros / 1_000_000,
|
|
773
808
|
callsite: `orchestrator.${source}`,
|
|
774
809
|
phase: source,
|
|
775
|
-
actualInputTokens:
|
|
810
|
+
actualInputTokens: actualInput,
|
|
776
811
|
actualOutputTokens: output,
|
|
777
812
|
cachedInputTokens: cacheRead,
|
|
778
813
|
systemChars: breakdown?.systemChars,
|
|
@@ -1162,15 +1197,43 @@ export class Agent {
|
|
|
1162
1197
|
};
|
|
1163
1198
|
}
|
|
1164
1199
|
}
|
|
1200
|
+
async killDelegation(id) {
|
|
1201
|
+
try {
|
|
1202
|
+
return await this.delegations.kill(id);
|
|
1203
|
+
}
|
|
1204
|
+
catch (err) {
|
|
1205
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1206
|
+
return {
|
|
1207
|
+
success: false,
|
|
1208
|
+
output: `Failed to terminate delegation: ${msg}`,
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1165
1212
|
getCompactionSettings(contextWindow) {
|
|
1166
1213
|
let keepRecentTokens = DEFAULT_KEEP_RECENT_TOKENS;
|
|
1167
1214
|
// For models with very large context windows, keep more recent tokens
|
|
1168
1215
|
if (contextWindow && contextWindow > 200_000) {
|
|
1169
1216
|
keepRecentTokens = Math.min(100_000, Math.max(20_000, Math.floor(contextWindow * 0.1)));
|
|
1170
1217
|
}
|
|
1171
|
-
//
|
|
1218
|
+
// For long sessions, reduce keepRecentTokens slightly to slow context growth
|
|
1219
|
+
// (0.85 instead of old 0.75 — session bf58d0f46b51 showed 0.75 created a
|
|
1220
|
+
// tight compact-loop: keep 15K → add 50K tool results → re-compact immediately).
|
|
1172
1221
|
if (this._compactionStats.count >= 2) {
|
|
1173
|
-
keepRecentTokens = Math.floor(keepRecentTokens * 0.
|
|
1222
|
+
keepRecentTokens = Math.floor(keepRecentTokens * 0.85);
|
|
1223
|
+
}
|
|
1224
|
+
// For sub-sessions, reduce keepRecentTokens to 8000 to keep active history light
|
|
1225
|
+
try {
|
|
1226
|
+
if (this.session) {
|
|
1227
|
+
const { getDatabase } = require("../storage/db.js");
|
|
1228
|
+
const db = getDatabase();
|
|
1229
|
+
const row = db.prepare("SELECT parent_session_id FROM sessions WHERE id = ?").get(this.session.id);
|
|
1230
|
+
if (row?.parent_session_id) {
|
|
1231
|
+
keepRecentTokens = 8000;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
catch {
|
|
1236
|
+
// Ignored
|
|
1174
1237
|
}
|
|
1175
1238
|
return {
|
|
1176
1239
|
reserveTokens: Math.max(this.maxTokens, DEFAULT_RESERVE_TOKENS),
|
|
@@ -1186,12 +1249,28 @@ export class Agent {
|
|
|
1186
1249
|
async compactForContext(provider, system, contextWindow, signal, settings = this.getCompactionSettings(contextWindow), force = false) {
|
|
1187
1250
|
if (!this.session)
|
|
1188
1251
|
return false;
|
|
1252
|
+
// Phase 1: ask the compaction proposer model whether to compact and what to keep/drop.
|
|
1253
|
+
// Only compact if the model says yes. On error/skip, fall back to heuristic.
|
|
1254
|
+
const compactModelId = this._resolveCompactModel();
|
|
1255
|
+
const proposal = await proposeCompaction(provider, compactModelId, this.messages, signal);
|
|
1256
|
+
if (proposal !== null) {
|
|
1257
|
+
// Model decided — compact only if model says shouldCompact
|
|
1258
|
+
if (force) {
|
|
1259
|
+
// force always proceeds; the proposer's actions still guide what to keep/drop
|
|
1260
|
+
}
|
|
1261
|
+
else if (!proposal.shouldCompact) {
|
|
1262
|
+
return false;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
else {
|
|
1266
|
+
// Proposer unavailable — fall back to heuristic token-threshold check
|
|
1267
|
+
if (!force && !shouldCompactContext(estimateConversationTokens(system, this.messages), contextWindow, settings)) {
|
|
1268
|
+
return false;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1189
1271
|
const preparation = prepareCompaction(this.messages, system, settings);
|
|
1190
1272
|
if (!preparation)
|
|
1191
1273
|
return false;
|
|
1192
|
-
if (!force && !shouldCompactContext(preparation.tokensBefore, contextWindow, settings)) {
|
|
1193
|
-
return false;
|
|
1194
|
-
}
|
|
1195
1274
|
const trigger = force ? "manual" : "auto";
|
|
1196
1275
|
// Fire-and-forget: notify EE of stale suggestions before compaction
|
|
1197
1276
|
const { surfacedIds, timestamp } = getLastSurfacedState();
|
|
@@ -1219,9 +1298,24 @@ export class Agent {
|
|
|
1219
1298
|
await this.fireHook(preCompactInput, signal).catch(() => { });
|
|
1220
1299
|
const keptSeqs = this.messageSeqs.slice(preparation.firstKeptIndex);
|
|
1221
1300
|
const firstKeptSeq = keptSeqs.find((seq) => seq !== null) ?? getNextMessageSequence(this.session.id);
|
|
1222
|
-
const compactModelId = this._resolveCompactModel();
|
|
1223
1301
|
const compactStartedAt = Date.now();
|
|
1224
|
-
const
|
|
1302
|
+
const isSubSession = await (async () => {
|
|
1303
|
+
try {
|
|
1304
|
+
if (!this.session)
|
|
1305
|
+
return false;
|
|
1306
|
+
const { getDatabase } = await import("../storage/db.js");
|
|
1307
|
+
const db = getDatabase();
|
|
1308
|
+
const row = db.prepare("SELECT parent_session_id FROM sessions WHERE id = ?").get(this.session.id);
|
|
1309
|
+
return !!row?.parent_session_id;
|
|
1310
|
+
}
|
|
1311
|
+
catch {
|
|
1312
|
+
return false;
|
|
1313
|
+
}
|
|
1314
|
+
})();
|
|
1315
|
+
const customInstructions = isSubSession
|
|
1316
|
+
? "This is a temporary sub-session. Under sub-sessions, it is CRITICAL to preserve active files being worked on, compiler/linter error states, and exact line coordinates in the summary. Do not omit details of files edited, tests run, or compiler diagnostics, as the model needs this specific context to continue working without re-reading the files."
|
|
1317
|
+
: undefined;
|
|
1318
|
+
const { summary, usage: compactUsage } = await generateCompactionSummary(provider, compactModelId, preparation, customInstructions, signal);
|
|
1225
1319
|
// Record compaction call in cost-log — bypasses recordUsage because
|
|
1226
1320
|
// compaction returns usage separately and isn't routed through the
|
|
1227
1321
|
// status-bar / usage event pipeline (intentional: it's overhead, not user spend).
|
|
@@ -1285,11 +1379,15 @@ export class Agent {
|
|
|
1285
1379
|
.catch(() => { });
|
|
1286
1380
|
// Mark as surfaced for prompt-stale reconciliation (per plan Phase 1).
|
|
1287
1381
|
updateLastSurfacedState([`compact-checkpoint-${this._compactionStats.count + 1}`]);
|
|
1288
|
-
// Track compaction stats —
|
|
1382
|
+
// Track compaction stats — report the GROSS context reduction, NOT net-after-compact-cost.
|
|
1383
|
+
// Rationale: the compaction call's own prompt/completion tokens ARE already counted in
|
|
1384
|
+
// in_tokens/out_tokens/session_usd (updateStatusBar at line 986). Subtracting them here
|
|
1385
|
+
// would double-penalize: the user sees the real cost in the token counter AND sees
|
|
1386
|
+
// "0 saved" because compactCost >= grossSaved (the compact prompt is the full conversation).
|
|
1387
|
+
// grossSaved tells the user how many context tokens were reclaimed — a real benefit that
|
|
1388
|
+
// reduces subsequent turn costs.
|
|
1289
1389
|
const tokensAfter = estimateConversationTokens(system, this.messages);
|
|
1290
|
-
const
|
|
1291
|
-
const compactCost = compactUsage.promptTokens + compactUsage.completionTokens;
|
|
1292
|
-
const saved = Math.max(0, grossSaved - compactCost);
|
|
1390
|
+
const saved = Math.max(0, preparation.tokensBefore - tokensAfter);
|
|
1293
1391
|
const pct = preparation.tokensBefore > 0 ? ((saved / preparation.tokensBefore) * 100).toFixed(1) : "0.0";
|
|
1294
1392
|
this._compactionStats.count++;
|
|
1295
1393
|
this._compactionStats.totalSaved += saved;
|
|
@@ -1317,8 +1415,6 @@ export class Agent {
|
|
|
1317
1415
|
tokensBefore: preparation.tokensBefore,
|
|
1318
1416
|
tokensAfter,
|
|
1319
1417
|
saved,
|
|
1320
|
-
grossSaved,
|
|
1321
|
-
compactCost,
|
|
1322
1418
|
pct,
|
|
1323
1419
|
isLongSession,
|
|
1324
1420
|
},
|
|
@@ -1357,7 +1453,7 @@ export class Agent {
|
|
|
1357
1453
|
});
|
|
1358
1454
|
}
|
|
1359
1455
|
log(true, `over-threshold (${tokens} >= ${minMeaningfulTokens})`, { tokens, thresholdPct, minMeaningfulTokens });
|
|
1360
|
-
await this.compactForContext(provider, system, contextWindow, signal, this.getCompactionSettings(contextWindow), true).catch((err) =>
|
|
1456
|
+
await this.compactForContext(provider, system, contextWindow, signal, this.getCompactionSettings(contextWindow), true).catch((err) => logger.warn("orchestrator", "compaction failed", { error: err }));
|
|
1361
1457
|
}
|
|
1362
1458
|
// ========================================================================
|
|
1363
1459
|
// Council system — delegated to CouncilManager (Phase 12.1-02)
|
|
@@ -1383,23 +1479,67 @@ export class Agent {
|
|
|
1383
1479
|
const councilStats = { calls: 0, startMs: Date.now(), phases: [] };
|
|
1384
1480
|
const llm = createCouncilLLM(this.bash, this.mode, this.session?.id, councilStats);
|
|
1385
1481
|
const processMessageFn = (message) => this.processMessage(message, options?.observer);
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1482
|
+
// Ensure a turn-scoped AbortController exists so Esc → agent.abort() →
|
|
1483
|
+
// this.abortController.abort() actually cancels the council. Two entry points
|
|
1484
|
+
// reach here: the auto-council path runs INSIDE processMessage, which already
|
|
1485
|
+
// set this.abortController; the /council SLASH path calls runCouncilV2
|
|
1486
|
+
// directly with NONE set — so before this guard, pressing Esc during an
|
|
1487
|
+
// explicit /council run was a no-op (abort() hit a null controller) and the
|
|
1488
|
+
// multi-minute debate ran to completion regardless. Create one when absent
|
|
1489
|
+
// so the user-abort signal threads into every council generate/debate/
|
|
1490
|
+
// research call for BOTH entry points. Only tear down a controller we own.
|
|
1491
|
+
const ownsController = !this.abortController;
|
|
1492
|
+
if (ownsController) {
|
|
1493
|
+
this.abortController = new AbortController();
|
|
1494
|
+
}
|
|
1495
|
+
const signal = this.abortController?.signal;
|
|
1496
|
+
// B1: Resolve a run directory so runCouncil persists decisions.lock.md after
|
|
1497
|
+
// synthesis. The auto-council/sprint paths get a runDir from their own flow
|
|
1498
|
+
// wiring, but the explicit /council SLASH path never did — so its outcome was
|
|
1499
|
+
// never written to disk (no audit trail, nothing for a later /ideal to read).
|
|
1500
|
+
// Reuse the session's active flow run; create one if the session never booted
|
|
1501
|
+
// a flow. Fail-open: a runDir-resolution error must not block the council.
|
|
1502
|
+
let runDir;
|
|
1503
|
+
try {
|
|
1504
|
+
const nodePath = await import("node:path");
|
|
1505
|
+
const flowDir = await ensureFlowDir(this.bash.getCwd());
|
|
1506
|
+
let runId = this._activeRunId ?? (await getActiveRunId(flowDir));
|
|
1507
|
+
if (!runId) {
|
|
1508
|
+
runId = (await createRun(flowDir)).id;
|
|
1509
|
+
await setActiveRunId(flowDir, runId);
|
|
1510
|
+
this._activeRunId = runId;
|
|
1511
|
+
}
|
|
1512
|
+
runDir = nodePath.join(flowDir, "runs", runId);
|
|
1513
|
+
}
|
|
1514
|
+
catch (err) {
|
|
1515
|
+
logger.error("router", "runDir resolution failed (decisions.lock will be skipped)", { error: err });
|
|
1516
|
+
}
|
|
1517
|
+
try {
|
|
1518
|
+
const gen = runCouncil(topic, this.modelId, this.messages, this.session?.id, llm, this.councilManager.createQuestionResponder(), this.councilManager.createPreflightResponder(), processMessageFn, {
|
|
1519
|
+
skipClarification: options?.skipClarification,
|
|
1520
|
+
userModelMessage: options?.userModelMessage,
|
|
1521
|
+
cwd: this.bash.getCwd(),
|
|
1522
|
+
councilStats, // NEW — share orchestrator's stats object with runCouncil (Phase 14 CQ-01)
|
|
1523
|
+
signal,
|
|
1524
|
+
runDir, // B1 — persist decisions.lock.md for the /council slash path
|
|
1525
|
+
});
|
|
1526
|
+
let result;
|
|
1527
|
+
do {
|
|
1528
|
+
result = await gen.next();
|
|
1529
|
+
if (!result.done && result.value) {
|
|
1530
|
+
yield result.value;
|
|
1531
|
+
}
|
|
1532
|
+
} while (!result.done);
|
|
1533
|
+
const synthesis = result.value;
|
|
1534
|
+
this.councilManager.setLastSynthesis(synthesis);
|
|
1535
|
+
if (options?.userModelMessage && synthesis) {
|
|
1536
|
+
this.appendCompletedTurn(options.userModelMessage, [{ role: "assistant", content: synthesis }]);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
finally {
|
|
1540
|
+
if (ownsController && this.abortController?.signal === signal) {
|
|
1541
|
+
this.abortController = null;
|
|
1397
1542
|
}
|
|
1398
|
-
} while (!result.done);
|
|
1399
|
-
const synthesis = result.value;
|
|
1400
|
-
this.councilManager.setLastSynthesis(synthesis);
|
|
1401
|
-
if (options?.userModelMessage && synthesis) {
|
|
1402
|
-
this.appendCompletedTurn(options.userModelMessage, [{ role: "assistant", content: synthesis }]);
|
|
1403
1543
|
}
|
|
1404
1544
|
}
|
|
1405
1545
|
// ========================================================================
|
|
@@ -1904,6 +2044,9 @@ export class Agent {
|
|
|
1904
2044
|
get maxToolRounds() {
|
|
1905
2045
|
return self.maxToolRounds;
|
|
1906
2046
|
},
|
|
2047
|
+
get hardMaxToolRounds() {
|
|
2048
|
+
return self.hardMaxToolRounds;
|
|
2049
|
+
},
|
|
1907
2050
|
get maxTokens() {
|
|
1908
2051
|
return self.maxTokens;
|
|
1909
2052
|
},
|
|
@@ -1930,12 +2073,27 @@ export class Agent {
|
|
|
1930
2073
|
runDelegation: (request, signal) => self.runDelegation(request, signal),
|
|
1931
2074
|
readDelegation: (id) => self.readDelegation(id),
|
|
1932
2075
|
listDelegations: () => self.listDelegations(),
|
|
2076
|
+
killDelegation: (id) => self.killDelegation(id),
|
|
1933
2077
|
executeBatchToolCall: (tools, toolCall, messages, signal) => self.executeBatchToolCall(tools, toolCall, messages, signal),
|
|
1934
2078
|
appendCompletedTurn: (user, asst) => self.appendCompletedTurn(user, asst),
|
|
1935
2079
|
discardAbortedTurn: (user) => self.discardAbortedTurn(user),
|
|
1936
2080
|
recordUsage: (usage, source, model, shape) => self.recordUsage(usage, source, model, shape),
|
|
1937
2081
|
};
|
|
1938
2082
|
}
|
|
2083
|
+
appendMidTurnMessages(newMessages) {
|
|
2084
|
+
if (newMessages.length === 0)
|
|
2085
|
+
return;
|
|
2086
|
+
if (!this.sessionStore || !this.session) {
|
|
2087
|
+
this.messages.push(...newMessages);
|
|
2088
|
+
this.messageSeqs.push(...newMessages.map(() => null));
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
const insertedSeqs = appendMessages(this.session.id, newMessages);
|
|
2092
|
+
this.messages.push(...newMessages);
|
|
2093
|
+
this.messageSeqs.push(...insertedSeqs);
|
|
2094
|
+
this.sessionStore.touchSession(this.session.id, this.bash.getCwd());
|
|
2095
|
+
this.session = this.sessionStore.getRequiredSession(this.session.id);
|
|
2096
|
+
}
|
|
1939
2097
|
appendCompletedTurn(userMessage, newMessages) {
|
|
1940
2098
|
if (newMessages.length === 0)
|
|
1941
2099
|
return;
|
|
@@ -1981,13 +2139,257 @@ export class Agent {
|
|
|
1981
2139
|
fireHook(input, signal) {
|
|
1982
2140
|
return executeEventHooks(input, this.bash.getCwd(), signal);
|
|
1983
2141
|
}
|
|
2142
|
+
estimateConversationChars() {
|
|
2143
|
+
let count = 0;
|
|
2144
|
+
for (const m of this.messages) {
|
|
2145
|
+
if (typeof m.content === "string") {
|
|
2146
|
+
count += m.content.length;
|
|
2147
|
+
}
|
|
2148
|
+
else if (Array.isArray(m.content)) {
|
|
2149
|
+
for (const p of m.content) {
|
|
2150
|
+
if (p.type === "text" && p.text) {
|
|
2151
|
+
count += p.text.length;
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
return count;
|
|
2157
|
+
}
|
|
1984
2158
|
// ========================================================================
|
|
1985
2159
|
// processMessage — main streaming turn loop (PIL enrichment, routing, LLM
|
|
1986
2160
|
// stream, tool execution, compaction, hooks, observer notifications)
|
|
1987
2161
|
// ========================================================================
|
|
1988
2162
|
async *processMessage(userMessage, observer, images) {
|
|
1989
|
-
const
|
|
1990
|
-
|
|
2163
|
+
const threshold = Number(process.env.MUONROI_SILENT_ROTATION_THRESHOLD) || 80000;
|
|
2164
|
+
const currentChars = this.estimateConversationChars();
|
|
2165
|
+
logger.debug("orchestrator", "Checking silent session rotation threshold", { currentChars, threshold });
|
|
2166
|
+
// 1. Run classifier to decide execution route
|
|
2167
|
+
let routeAction = "DIRECT_ANSWER";
|
|
2168
|
+
try {
|
|
2169
|
+
const { classifySubSessionAction } = await import("../pil/llm-classify.js");
|
|
2170
|
+
const routeResult = await classifySubSessionAction(this.requireProvider(), this.modelId, userMessage);
|
|
2171
|
+
if (routeResult) {
|
|
2172
|
+
routeAction = routeResult.action;
|
|
2173
|
+
logger.info("orchestrator", "Routing action selected for user message", {
|
|
2174
|
+
action: routeAction,
|
|
2175
|
+
confidence: routeResult.confidence,
|
|
2176
|
+
reason: routeResult.reason,
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
catch (err) {
|
|
2181
|
+
logger.error("orchestrator", "Routing classification failed, falling back to DIRECT_ANSWER", { error: err });
|
|
2182
|
+
}
|
|
2183
|
+
const shouldRotate = currentChars > threshold || routeAction === "ROTATE_SESSION";
|
|
2184
|
+
if (shouldRotate && this.session && this.sessionStore) {
|
|
2185
|
+
logger.info("orchestrator", "Triggering silent session rotation", {
|
|
2186
|
+
parentSessionId: this.session.id,
|
|
2187
|
+
currentChars,
|
|
2188
|
+
});
|
|
2189
|
+
yield { type: "content", content: "\n⋯ Xoay vòng session ngầm để tối ưu hóa context (Anti-Mù active)...\n" };
|
|
2190
|
+
const parentSessionId = this.session.id;
|
|
2191
|
+
try {
|
|
2192
|
+
const path = await import("node:path");
|
|
2193
|
+
const flowDir = path.join(this.bash.getCwd(), ".muonroi-flow");
|
|
2194
|
+
const { deliberateCompact } = await import("../flow/compaction/index.js");
|
|
2195
|
+
const { getDatabase } = await import("../storage/db.js");
|
|
2196
|
+
const { appendCompaction, getNextMessageSequence } = await import("../storage/transcript.js");
|
|
2197
|
+
const cr = await deliberateCompact(flowDir, this.messages, "", 4096, this.requireProvider(), this.modelId);
|
|
2198
|
+
const newSession = this.sessionStore.createSession(this.modelId, this.mode, this.bash.getCwd());
|
|
2199
|
+
const db = getDatabase();
|
|
2200
|
+
db.prepare("UPDATE sessions SET parent_session_id = ? WHERE id = ?").run(parentSessionId, newSession.id);
|
|
2201
|
+
const summaryMessage = createCompactionSummaryMessage(cr.summary);
|
|
2202
|
+
const nextSeq = getNextMessageSequence(newSession.id);
|
|
2203
|
+
appendCompaction(newSession.id, nextSeq, cr.summary, cr.tokensBeforeCompress);
|
|
2204
|
+
this.session = this.sessionStore.getRequiredSession(newSession.id);
|
|
2205
|
+
this.messages = [summaryMessage];
|
|
2206
|
+
this.messageSeqs = [null];
|
|
2207
|
+
this.sessionStore.touchSession(newSession.id, this.bash.getCwd());
|
|
2208
|
+
logger.info("orchestrator", "Silent session rotation completed successfully", {
|
|
2209
|
+
parentSessionId,
|
|
2210
|
+
newSessionId: newSession.id,
|
|
2211
|
+
summaryLength: cr.summary.length,
|
|
2212
|
+
tokensBeforeCompress: cr.tokensBeforeCompress,
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
catch (err) {
|
|
2216
|
+
logger.error("orchestrator", "silent session rotation failed", { error: err });
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
let isSubSessionForked = false;
|
|
2220
|
+
let parentSessionId = null;
|
|
2221
|
+
let subSessionId = null;
|
|
2222
|
+
if (routeAction === "SPAWN_SUB_SESSION" && this.session && this.sessionStore) {
|
|
2223
|
+
yield { type: "content", content: "\n⋯ Đang khởi tạo sub-session ngầm để xử lý tác vụ...\n" };
|
|
2224
|
+
parentSessionId = this.session.id;
|
|
2225
|
+
try {
|
|
2226
|
+
const { loadLatestCompaction, getNextMessageSequence, appendCompaction, loadTranscriptState } = await import("../storage/transcript.js");
|
|
2227
|
+
const { getDatabase } = await import("../storage/db.js");
|
|
2228
|
+
const db = getDatabase();
|
|
2229
|
+
// Check if there is already an active child session for this parent session
|
|
2230
|
+
const activeSubSession = db
|
|
2231
|
+
.prepare("SELECT id, updated_at FROM sessions WHERE parent_session_id = ? AND status = 'active' ORDER BY updated_at DESC LIMIT 1")
|
|
2232
|
+
.get(parentSessionId);
|
|
2233
|
+
let shouldResume = false;
|
|
2234
|
+
if (activeSubSession) {
|
|
2235
|
+
const updatedAt = new Date(activeSubSession.updated_at).getTime();
|
|
2236
|
+
const now = Date.now();
|
|
2237
|
+
const diffMins = (now - updatedAt) / (60 * 1000);
|
|
2238
|
+
if (diffMins > 15) {
|
|
2239
|
+
// Stale: mark as abandoned
|
|
2240
|
+
db.prepare("UPDATE sessions SET status = 'abandoned', updated_at = ? WHERE id = ?").run(new Date().toISOString(), activeSubSession.id);
|
|
2241
|
+
logger.info("orchestrator", "Stale sub-session found, marked as abandoned", {
|
|
2242
|
+
parentSessionId,
|
|
2243
|
+
subSessionId: activeSubSession.id,
|
|
2244
|
+
diffMins,
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
else {
|
|
2248
|
+
shouldResume = true;
|
|
2249
|
+
subSessionId = activeSubSession.id;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
if (shouldResume && subSessionId) {
|
|
2253
|
+
yield { type: "content", content: "\n⋯ Phát hiện sub-session trước đó bị gián đoạn, đang khôi phục...\n" };
|
|
2254
|
+
this.session = this.sessionStore.getRequiredSession(subSessionId);
|
|
2255
|
+
const childState = loadTranscriptState(subSessionId);
|
|
2256
|
+
this.messages = childState.messages;
|
|
2257
|
+
this.messageSeqs = childState.seqs;
|
|
2258
|
+
this.sessionStore.touchSession(subSessionId, this.bash.getCwd());
|
|
2259
|
+
isSubSessionForked = true;
|
|
2260
|
+
logger.info("orchestrator", "Resumed child sub-session successfully", {
|
|
2261
|
+
parentSessionId,
|
|
2262
|
+
subSessionId,
|
|
2263
|
+
});
|
|
2264
|
+
}
|
|
2265
|
+
else {
|
|
2266
|
+
const latest = loadLatestCompaction(parentSessionId);
|
|
2267
|
+
const newSession = this.sessionStore.createSession(this.modelId, this.mode, this.bash.getCwd());
|
|
2268
|
+
db.prepare("UPDATE sessions SET parent_session_id = ? WHERE id = ?").run(parentSessionId, newSession.id);
|
|
2269
|
+
subSessionId = newSession.id;
|
|
2270
|
+
let seedMessages = [];
|
|
2271
|
+
let seedSeqs = [];
|
|
2272
|
+
if (latest?.summary) {
|
|
2273
|
+
const summaryMsg = createCompactionSummaryMessage(latest.summary);
|
|
2274
|
+
seedMessages = [summaryMsg];
|
|
2275
|
+
seedSeqs = [null];
|
|
2276
|
+
const nextSeq = getNextMessageSequence(subSessionId);
|
|
2277
|
+
appendCompaction(subSessionId, nextSeq, latest.summary, latest.tokensBefore);
|
|
2278
|
+
}
|
|
2279
|
+
else {
|
|
2280
|
+
seedMessages = [...this.messages];
|
|
2281
|
+
seedSeqs = [...this.messageSeqs];
|
|
2282
|
+
}
|
|
2283
|
+
// Add sub-session overlay system message
|
|
2284
|
+
const overlayMessage = {
|
|
2285
|
+
role: "system",
|
|
2286
|
+
content: `You are executing a sub-task delegated by the Main Session in an isolated, temporary Sub-Session.\n` +
|
|
2287
|
+
`Your goal is to satisfy the user's request: "${userMessage}"\n\n` +
|
|
2288
|
+
`Your Operating Boundaries & Rules:\n` +
|
|
2289
|
+
`1. You have full access to tools (bash, edit_file, read_file, grep, etc.). Execute them as needed to build, debug, and verify the work.\n` +
|
|
2290
|
+
`2. Stay strictly focused on completing the request. Do not engage in social chat or pleasantries.\n` +
|
|
2291
|
+
`3. Once the goal is achieved and verified, you MUST return your final response using the 'respond_general' (or final answer) tool.\n` +
|
|
2292
|
+
`4. Your final response MUST contain a structured summary (Key Changes, Verification Details, Result Summary).\n` +
|
|
2293
|
+
`5. All intermediate tool calls, raw tool outputs, and diagnostic traces will remain isolated inside this sub-session and will not bloat the parent session.`,
|
|
2294
|
+
};
|
|
2295
|
+
seedMessages.push(overlayMessage);
|
|
2296
|
+
seedSeqs.push(null);
|
|
2297
|
+
this.session = this.sessionStore.getRequiredSession(subSessionId);
|
|
2298
|
+
this.messages = seedMessages;
|
|
2299
|
+
this.messageSeqs = seedSeqs;
|
|
2300
|
+
this.sessionStore.touchSession(subSessionId, this.bash.getCwd());
|
|
2301
|
+
isSubSessionForked = true;
|
|
2302
|
+
logger.info("orchestrator", "Forked child sub-session successfully", {
|
|
2303
|
+
parentSessionId,
|
|
2304
|
+
subSessionId,
|
|
2305
|
+
});
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
catch (err) {
|
|
2309
|
+
logger.error("orchestrator", "Forking child sub-session failed, falling back to main session", { error: err });
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
let processor = new MessageProcessor(this._buildMessageProcessorDeps());
|
|
2313
|
+
const autoCommitOn = isAutoCommitEnabled();
|
|
2314
|
+
const cwd = this.bash.getCwd();
|
|
2315
|
+
const dirtyBefore = autoCommitOn ? await snapshotDirtyPaths(cwd) : new Set();
|
|
2316
|
+
try {
|
|
2317
|
+
let attempts = 0;
|
|
2318
|
+
const maxAttempts = 3;
|
|
2319
|
+
const messagesSnapshot = [...this.messages];
|
|
2320
|
+
const seqsSnapshot = [...this.messageSeqs];
|
|
2321
|
+
while (attempts < maxAttempts) {
|
|
2322
|
+
try {
|
|
2323
|
+
attempts++;
|
|
2324
|
+
yield* processor.run(userMessage, observer, images);
|
|
2325
|
+
break;
|
|
2326
|
+
}
|
|
2327
|
+
catch (err) {
|
|
2328
|
+
if (isSubSessionForked && isTransientError(err) && attempts < maxAttempts && subSessionId) {
|
|
2329
|
+
logger.warn("orchestrator", "Transient error in sub-session, retrying", {
|
|
2330
|
+
attempt: attempts,
|
|
2331
|
+
error: err,
|
|
2332
|
+
});
|
|
2333
|
+
yield {
|
|
2334
|
+
type: "content",
|
|
2335
|
+
content: `\n⚠️ Có lỗi mạng hoặc rate limit xảy ra trong sub-session (lần thử ${attempts}/${maxAttempts}). Đang thử lại...\n`,
|
|
2336
|
+
};
|
|
2337
|
+
this.messages = [...messagesSnapshot];
|
|
2338
|
+
this.messageSeqs = [...seqsSnapshot];
|
|
2339
|
+
processor = new MessageProcessor(this._buildMessageProcessorDeps());
|
|
2340
|
+
}
|
|
2341
|
+
else {
|
|
2342
|
+
throw err;
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
if (autoCommitOn) {
|
|
2347
|
+
const auto = await maybeAutoCommitTurn({ cwd, dirtyBefore, userMessage }).catch((err) => {
|
|
2348
|
+
logger.error("orchestrator", "auto-commit unexpected failure", { error: err });
|
|
2349
|
+
return { committed: false };
|
|
2350
|
+
});
|
|
2351
|
+
if (auto.committed) {
|
|
2352
|
+
yield {
|
|
2353
|
+
type: "content",
|
|
2354
|
+
content: `\n✓ Auto-committed ${auto.fileCount} file(s) → ${auto.sha} (${AUTO_COMMIT_ATTRIBUTION})\n`,
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
finally {
|
|
2360
|
+
if (isSubSessionForked && parentSessionId && this.sessionStore) {
|
|
2361
|
+
try {
|
|
2362
|
+
const finalMessages = salvageSubSessionOutput(this.messages);
|
|
2363
|
+
// Restore parent session
|
|
2364
|
+
this.session = this.sessionStore.getRequiredSession(parentSessionId);
|
|
2365
|
+
const { loadTranscriptState } = await import("../storage/transcript.js");
|
|
2366
|
+
const parentState = loadTranscriptState(parentSessionId);
|
|
2367
|
+
this.messages = parentState.messages;
|
|
2368
|
+
this.messageSeqs = parentState.seqs;
|
|
2369
|
+
const userModelMessage = {
|
|
2370
|
+
role: "user",
|
|
2371
|
+
content: userMessage,
|
|
2372
|
+
};
|
|
2373
|
+
if (finalMessages.length > 0) {
|
|
2374
|
+
this.appendCompletedTurn(userModelMessage, finalMessages);
|
|
2375
|
+
logger.info("orchestrator", "Absorbed sub-session outcome into parent session", {
|
|
2376
|
+
parentSessionId,
|
|
2377
|
+
subSessionId,
|
|
2378
|
+
absorbedMessagesCount: finalMessages.length,
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2381
|
+
else {
|
|
2382
|
+
logger.warn("orchestrator", "No assistant messages found to absorb from sub-session", {
|
|
2383
|
+
parentSessionId,
|
|
2384
|
+
subSessionId,
|
|
2385
|
+
});
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
catch (err) {
|
|
2389
|
+
logger.error("orchestrator", "Failed to absorb sub-session final summary", { error: err });
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
1991
2393
|
}
|
|
1992
2394
|
/**
|
|
1993
2395
|
* Build the DI surface MessageProcessor (Phase 12.4) needs to reach back
|
|
@@ -2026,6 +2428,9 @@ export class Agent {
|
|
|
2026
2428
|
get maxToolRounds() {
|
|
2027
2429
|
return self.maxToolRounds;
|
|
2028
2430
|
},
|
|
2431
|
+
get hardMaxToolRounds() {
|
|
2432
|
+
return self.hardMaxToolRounds;
|
|
2433
|
+
},
|
|
2029
2434
|
get batchApi() {
|
|
2030
2435
|
return self.batchApi;
|
|
2031
2436
|
},
|
|
@@ -2120,6 +2525,39 @@ export class Agent {
|
|
|
2120
2525
|
},
|
|
2121
2526
|
requireProvider: () => self.requireProvider(),
|
|
2122
2527
|
emitSubagentStatus: (s) => self.emitSubagentStatus(s),
|
|
2528
|
+
consultParentSession: async (question) => {
|
|
2529
|
+
if (!self.session) {
|
|
2530
|
+
return "No active session found to consult.";
|
|
2531
|
+
}
|
|
2532
|
+
const { getDatabase } = await import("../storage/db.js");
|
|
2533
|
+
const db = getDatabase();
|
|
2534
|
+
const row = db.prepare("SELECT parent_session_id FROM sessions WHERE id = ?").get(self.session.id);
|
|
2535
|
+
if (!row?.parent_session_id) {
|
|
2536
|
+
return "No parent session found to consult.";
|
|
2537
|
+
}
|
|
2538
|
+
const parentSessionId = row.parent_session_id;
|
|
2539
|
+
const { loadTranscriptState } = await import("../storage/transcript.js");
|
|
2540
|
+
const parentState = loadTranscriptState(parentSessionId);
|
|
2541
|
+
const { serializeConversation } = await import("./compaction.js");
|
|
2542
|
+
const serializedParent = serializeConversation(parentState.messages);
|
|
2543
|
+
const systemPrompt = `You are the Main Session of an AI coding assistant.\n` +
|
|
2544
|
+
`A child sub-session has been spawned to execute a sub-task and is requesting your advice/guidance.\n` +
|
|
2545
|
+
`Below is your conversation history (Main Session Context):\n\n` +
|
|
2546
|
+
`${serializedParent}\n\n` +
|
|
2547
|
+
`Provide clear, actionable guidance to resolve the child's query.`;
|
|
2548
|
+
const { generateText } = await import("ai");
|
|
2549
|
+
const provider = self.requireProvider();
|
|
2550
|
+
const modelId = self.modelId;
|
|
2551
|
+
const runtime = resolveModelRuntime(provider, modelId);
|
|
2552
|
+
const result = await generateText({
|
|
2553
|
+
model: runtime.model,
|
|
2554
|
+
system: systemPrompt,
|
|
2555
|
+
prompt: `Child Sub-session is stuck. Question:\n${question}`,
|
|
2556
|
+
temperature: 0.2,
|
|
2557
|
+
...(runtime.providerOptions ? { providerOptions: runtime.providerOptions } : {}),
|
|
2558
|
+
});
|
|
2559
|
+
return result.text;
|
|
2560
|
+
},
|
|
2123
2561
|
fireHook: (input, signal) => self.fireHook(input, signal),
|
|
2124
2562
|
consumeBackgroundNotifications: () => self.consumeBackgroundNotifications(),
|
|
2125
2563
|
initOAuthProvider: () => self._initOAuthProvider(),
|
|
@@ -2133,7 +2571,9 @@ export class Agent {
|
|
|
2133
2571
|
runDelegation: (request, signal) => self.runDelegation(request, signal),
|
|
2134
2572
|
readDelegation: (id) => self.readDelegation(id),
|
|
2135
2573
|
listDelegations: () => self.listDelegations(),
|
|
2574
|
+
killDelegation: (id) => self.killDelegation(id),
|
|
2136
2575
|
drainSteerMessages: () => self.steerDrain?.() ?? [],
|
|
2576
|
+
appendMidTurnMessages: (msgs) => self.appendMidTurnMessages(msgs),
|
|
2137
2577
|
appendCompletedTurn: (user, asst) => self.appendCompletedTurn(user, asst),
|
|
2138
2578
|
discardAbortedTurn: (user) => self.discardAbortedTurn(user),
|
|
2139
2579
|
recordUsage: (usage, source, model, shape) => self.recordUsage(usage, source, model, shape),
|
|
@@ -2146,10 +2586,24 @@ export class Agent {
|
|
|
2146
2586
|
return await h(info);
|
|
2147
2587
|
}
|
|
2148
2588
|
catch (err) {
|
|
2149
|
-
|
|
2589
|
+
logger.error("orchestrator", "askToolLoopContinue crashed", { error: err });
|
|
2150
2590
|
return "stop";
|
|
2151
2591
|
}
|
|
2152
2592
|
},
|
|
2593
|
+
askSafetyOverride: async (info) => {
|
|
2594
|
+
const h = self._safetyOverrideHandler;
|
|
2595
|
+
if (!h) {
|
|
2596
|
+
logger.warn("orchestrator", `askSafetyOverride called but no handler registered — blocking ${info.kind}: ${info.reason}`);
|
|
2597
|
+
return { action: "block" };
|
|
2598
|
+
}
|
|
2599
|
+
try {
|
|
2600
|
+
return await h(info);
|
|
2601
|
+
}
|
|
2602
|
+
catch (err) {
|
|
2603
|
+
logger.error("orchestrator", "askSafetyOverride crashed", { error: err });
|
|
2604
|
+
return { action: "block" };
|
|
2605
|
+
}
|
|
2606
|
+
},
|
|
2153
2607
|
runCouncilV2: (msg, opts) => self.runCouncilV2(msg, opts),
|
|
2154
2608
|
processMessage: (msg, obs, imgs) => self.processMessage(msg, obs, imgs),
|
|
2155
2609
|
processMessageBatchTurn: (args) => self.processMessageBatchTurn(args),
|
|
@@ -2322,4 +2776,37 @@ export class Agent {
|
|
|
2322
2776
|
}
|
|
2323
2777
|
}
|
|
2324
2778
|
}
|
|
2779
|
+
function isTransientError(err) {
|
|
2780
|
+
if (!(err instanceof Error))
|
|
2781
|
+
return false;
|
|
2782
|
+
const msg = err.message.toLowerCase();
|
|
2783
|
+
return (msg.includes("fetch failed") ||
|
|
2784
|
+
msg.includes("rate limit") ||
|
|
2785
|
+
msg.includes("429") ||
|
|
2786
|
+
msg.includes("503") ||
|
|
2787
|
+
msg.includes("502") ||
|
|
2788
|
+
msg.includes("network") ||
|
|
2789
|
+
msg.includes("timeout") ||
|
|
2790
|
+
msg.includes("econnreset") ||
|
|
2791
|
+
msg.includes("econnrefused"));
|
|
2792
|
+
}
|
|
2793
|
+
function salvageSubSessionOutput(messages) {
|
|
2794
|
+
let lastAsstIdx = -1;
|
|
2795
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
2796
|
+
if (messages[i].role === "assistant") {
|
|
2797
|
+
lastAsstIdx = i;
|
|
2798
|
+
break;
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
const finalMessages = [];
|
|
2802
|
+
if (lastAsstIdx >= 0) {
|
|
2803
|
+
finalMessages.push(messages[lastAsstIdx]);
|
|
2804
|
+
for (let i = lastAsstIdx + 1; i < messages.length; i++) {
|
|
2805
|
+
if (messages[i].role === "tool") {
|
|
2806
|
+
finalMessages.push(messages[i]);
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
return finalMessages;
|
|
2811
|
+
}
|
|
2325
2812
|
//# sourceMappingURL=orchestrator.js.map
|