muonroi-cli 1.8.3 → 1.8.5
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/LICENSE +21 -21
- package/README.md +133 -122
- package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
- package/dist/packages/agent-harness-core/src/driver.js +46 -0
- package/dist/packages/agent-harness-core/src/event-tee.d.ts +48 -0
- package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
- package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
- package/dist/packages/agent-harness-core/src/protocol.js +15 -0
- package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
- package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
- package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
- package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
- package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
- package/dist/packages/agent-harness-opentui/src/install.js +10 -0
- package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
- package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
- package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
- package/dist/src/agent-harness/mock-model.d.ts +28 -0
- package/dist/src/agent-harness/mock-model.js +63 -1
- package/dist/src/agent-harness/test-spawn.js +31 -0
- package/dist/src/cli/config/screen-providers.js +1 -1
- package/dist/src/cli/cost-forensics.d.ts +10 -0
- package/dist/src/cli/cost-forensics.js +30 -15
- package/dist/src/cli/keys-bundle.d.ts +1 -1
- package/dist/src/cli/keys-bundle.js +1 -1
- package/dist/src/cli/keys.d.ts +2 -2
- package/dist/src/cli/keys.js +19 -81
- package/dist/src/council/clarifier.d.ts +28 -2
- package/dist/src/council/clarifier.js +81 -15
- package/dist/src/council/context.js +49 -15
- package/dist/src/council/debate-checkpoint.d.ts +129 -0
- package/dist/src/council/debate-checkpoint.js +176 -0
- package/dist/src/council/debate-planner.js +51 -3
- package/dist/src/council/debate-summary.d.ts +25 -0
- package/dist/src/council/debate-summary.js +85 -0
- package/dist/src/council/debate.d.ts +169 -2
- package/dist/src/council/debate.js +1210 -134
- package/dist/src/council/index.d.ts +85 -1
- package/dist/src/council/index.js +634 -196
- package/dist/src/council/leader.d.ts +26 -0
- package/dist/src/council/leader.js +150 -9
- package/dist/src/council/llm.d.ts +32 -0
- package/dist/src/council/llm.js +231 -38
- package/dist/src/council/panel-select.d.ts +30 -0
- package/dist/src/council/panel-select.js +72 -0
- package/dist/src/council/planner.js +23 -0
- package/dist/src/council/preflight.d.ts +7 -0
- package/dist/src/council/preflight.js +14 -2
- package/dist/src/council/prompts.d.ts +30 -3
- package/dist/src/council/prompts.js +254 -84
- package/dist/src/council/stance-recall.d.ts +42 -0
- package/dist/src/council/stance-recall.js +57 -0
- package/dist/src/council/strip-think.d.ts +17 -0
- package/dist/src/council/strip-think.js +33 -0
- package/dist/src/council/types.d.ts +128 -0
- package/dist/src/ee/artifact-cache.d.ts +16 -0
- package/dist/src/ee/artifact-cache.js +32 -0
- package/dist/src/ee/auth.d.ts +1 -0
- package/dist/src/ee/auth.js +15 -2
- package/dist/src/ee/bridge.d.ts +10 -0
- package/dist/src/ee/bridge.js +58 -0
- package/dist/src/ee/client.js +81 -18
- package/dist/src/ee/export-transcripts.d.ts +1 -0
- package/dist/src/ee/export-transcripts.js +8 -10
- package/dist/src/ee/extract-session.js +29 -0
- package/dist/src/ee/extract-style.d.ts +58 -0
- package/dist/src/ee/extract-style.js +270 -0
- package/dist/src/ee/recall-ledger.d.ts +9 -0
- package/dist/src/ee/recall-ledger.js +3 -0
- package/dist/src/ee/scope.d.ts +1 -0
- package/dist/src/ee/scope.js +26 -1
- package/dist/src/ee/search.d.ts +7 -0
- package/dist/src/ee/search.js +24 -0
- package/dist/src/ee/transcript-emit.js +2 -0
- package/dist/src/ee/types.d.ts +22 -0
- package/dist/src/ee/who-am-i-brain.d.ts +35 -0
- package/dist/src/ee/who-am-i-brain.js +220 -0
- package/dist/src/ee/who-am-i.d.ts +10 -3
- package/dist/src/ee/who-am-i.js +12 -0
- package/dist/src/ee/workflow-event.d.ts +48 -0
- package/dist/src/ee/workflow-event.js +81 -0
- package/dist/src/flow/compaction/compress.d.ts +3 -3
- package/dist/src/flow/compaction/compress.js +45 -8
- package/dist/src/flow/compaction/extract.d.ts +4 -7
- package/dist/src/flow/compaction/extract.js +50 -10
- package/dist/src/flow/compaction/index.d.ts +13 -1
- package/dist/src/flow/compaction/index.js +70 -3
- package/dist/src/flow/compaction/input-guard.d.ts +24 -0
- package/dist/src/flow/compaction/input-guard.js +43 -0
- package/dist/src/flow/fold-planning.d.ts +36 -0
- package/dist/src/flow/fold-planning.js +83 -0
- package/dist/src/flow/hierarchy.d.ts +146 -0
- package/dist/src/flow/hierarchy.js +427 -0
- package/dist/src/flow/index.d.ts +1 -0
- package/dist/src/flow/index.js +2 -0
- package/dist/src/flow/run-artifacts.d.ts +102 -0
- package/dist/src/flow/run-artifacts.js +208 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/gsd/assessment-schema.d.ts +44 -0
- package/dist/src/gsd/assessment-schema.js +134 -0
- package/dist/src/gsd/capability-registry.d.ts +45 -0
- package/dist/src/gsd/capability-registry.js +337 -0
- package/dist/src/gsd/complexity-assessor.d.ts +39 -0
- package/dist/src/gsd/complexity-assessor.js +152 -0
- package/dist/src/gsd/config-bridge.d.ts +7 -0
- package/dist/src/gsd/config-bridge.js +114 -0
- package/dist/src/gsd/config-loader.d.ts +27 -0
- package/dist/src/gsd/config-loader.js +50 -0
- package/dist/src/gsd/council-context.d.ts +44 -0
- package/dist/src/gsd/council-context.js +114 -0
- package/dist/src/gsd/ee-closure.d.ts +28 -0
- package/dist/src/gsd/ee-closure.js +49 -0
- package/dist/src/gsd/flags.d.ts +55 -0
- package/dist/src/gsd/flags.js +83 -0
- package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
- package/dist/src/gsd/gsd-dispatch.js +131 -0
- package/dist/src/gsd/gsd-runtime.d.ts +22 -0
- package/dist/src/gsd/gsd-runtime.js +37 -0
- package/dist/src/gsd/host-adapter.d.ts +11 -0
- package/dist/src/gsd/host-adapter.js +29 -0
- package/dist/src/gsd/index.d.ts +24 -1
- package/dist/src/gsd/index.js +27 -0
- package/dist/src/gsd/loop-host-contract.d.ts +21 -0
- package/dist/src/gsd/loop-host-contract.js +39 -0
- package/dist/src/gsd/loop-host.d.ts +69 -0
- package/dist/src/gsd/loop-host.js +245 -0
- package/dist/src/gsd/loop-resolver.d.ts +36 -0
- package/dist/src/gsd/loop-resolver.js +79 -0
- package/dist/src/gsd/model-tier.d.ts +13 -0
- package/dist/src/gsd/model-tier.js +45 -0
- package/dist/src/gsd/mutation-gate.d.ts +16 -0
- package/dist/src/gsd/mutation-gate.js +41 -0
- package/dist/src/gsd/native-roadmap.d.ts +89 -0
- package/dist/src/gsd/native-roadmap.js +343 -0
- package/dist/src/gsd/native-state.d.ts +47 -0
- package/dist/src/gsd/native-state.js +220 -0
- package/dist/src/gsd/paths.d.ts +23 -0
- package/dist/src/gsd/paths.js +66 -0
- package/dist/src/gsd/phase-dag.d.ts +12 -0
- package/dist/src/gsd/phase-dag.js +94 -0
- package/dist/src/gsd/phase-sync.d.ts +42 -0
- package/dist/src/gsd/phase-sync.js +321 -0
- package/dist/src/gsd/pil-gate-context.d.ts +13 -0
- package/dist/src/gsd/pil-gate-context.js +64 -0
- package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
- package/dist/src/gsd/pil-gate-critic.js +74 -0
- package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
- package/dist/src/gsd/plan-council-prompts.js +79 -0
- package/dist/src/gsd/plan-council.d.ts +44 -0
- package/dist/src/gsd/plan-council.js +251 -0
- package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
- package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
- package/dist/src/gsd/product-workspace.d.ts +13 -0
- package/dist/src/gsd/product-workspace.js +124 -0
- package/dist/src/gsd/ship-bridge.d.ts +25 -0
- package/dist/src/gsd/ship-bridge.js +65 -0
- package/dist/src/gsd/state-document.d.ts +40 -0
- package/dist/src/gsd/state-document.js +163 -0
- package/dist/src/gsd/verdict-schema.d.ts +39 -0
- package/dist/src/gsd/verdict-schema.js +144 -0
- package/dist/src/gsd/verify-context.d.ts +22 -0
- package/dist/src/gsd/verify-context.js +27 -0
- package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
- package/dist/src/gsd/verify-council-prompts.js +85 -0
- package/dist/src/gsd/verify-council.d.ts +25 -0
- package/dist/src/gsd/verify-council.js +119 -0
- package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
- package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
- package/dist/src/gsd/workflow-engine.d.ts +60 -0
- package/dist/src/gsd/workflow-engine.js +207 -0
- package/dist/src/gsd/workflow-tools.d.ts +13 -0
- package/dist/src/gsd/workflow-tools.js +277 -0
- package/dist/src/hooks/index.js +1 -1
- package/dist/src/index.js +44 -11
- package/dist/src/maintain/pr-builder.js +23 -13
- package/dist/src/mcp/auto-setup.js +57 -32
- package/dist/src/mcp/client-pool.js +1 -1
- package/dist/src/mcp/ee-tools.js +1 -0
- package/dist/src/mcp/oauth-callback.js +2 -2
- package/dist/src/mcp/research-onboarding.js +8 -7
- package/dist/src/mcp/runtime.js +34 -2
- package/dist/src/mcp/setup-guide-text.d.ts +1 -1
- package/dist/src/mcp/setup-guide-text.js +77 -76
- package/dist/src/models/catalog-client.d.ts +87 -0
- package/dist/src/models/catalog-client.js +105 -38
- package/dist/src/models/catalog.json +528 -265
- package/dist/src/models/registry.d.ts +22 -7
- package/dist/src/models/registry.js +73 -10
- package/dist/src/ops/doctor.js +8 -8
- package/dist/src/orchestrator/auto-commit.js +1 -1
- package/dist/src/orchestrator/batch-turn-runner.js +2 -2
- package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
- package/dist/src/orchestrator/cache-prefix.js +83 -0
- package/dist/src/orchestrator/compact-request.d.ts +32 -0
- package/dist/src/orchestrator/compact-request.js +41 -0
- package/dist/src/orchestrator/compaction.d.ts +10 -0
- package/dist/src/orchestrator/compaction.js +27 -7
- package/dist/src/orchestrator/council-manager.d.ts +12 -3
- package/dist/src/orchestrator/council-manager.js +65 -24
- package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
- package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
- package/dist/src/orchestrator/error-utils.d.ts +29 -0
- package/dist/src/orchestrator/error-utils.js +132 -24
- package/dist/src/orchestrator/grounding-check.js +39 -1
- package/dist/src/orchestrator/message-processor.js +242 -33
- package/dist/src/orchestrator/orchestrator.d.ts +39 -3
- package/dist/src/orchestrator/orchestrator.js +651 -102
- package/dist/src/orchestrator/preprocessor.js +1 -1
- package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
- package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
- package/dist/src/orchestrator/prompts.js +159 -159
- package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
- package/dist/src/orchestrator/reactive-delegation.js +59 -0
- package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
- package/dist/src/orchestrator/retry-classifier.js +46 -2
- package/dist/src/orchestrator/safety-intercept.d.ts +45 -0
- package/dist/src/orchestrator/safety-intercept.js +55 -0
- package/dist/src/orchestrator/scope-reminder.js +1 -1
- package/dist/src/orchestrator/session-experience.d.ts +2 -1
- package/dist/src/orchestrator/session-experience.js +2 -1
- package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
- package/dist/src/orchestrator/should-run-gate.js +18 -0
- package/dist/src/orchestrator/stall-watchdog.d.ts +24 -3
- package/dist/src/orchestrator/stall-watchdog.js +47 -13
- package/dist/src/orchestrator/stream-runner.js +62 -29
- package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-cap.js +16 -1
- package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
- package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
- package/dist/src/orchestrator/subagent-compactor.js +126 -15
- package/dist/src/orchestrator/tool-engine.d.ts +26 -0
- package/dist/src/orchestrator/tool-engine.js +669 -56
- package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
- package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
- package/dist/src/orchestrator/turn-watchdog.d.ts +37 -0
- package/dist/src/orchestrator/turn-watchdog.js +55 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +1 -1
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +5 -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/discovery-types.d.ts +1 -0
- package/dist/src/pil/discovery.js +16 -11
- package/dist/src/pil/layer1-intent.d.ts +18 -6
- package/dist/src/pil/layer1-intent.js +66 -757
- package/dist/src/pil/layer15-context-scan.js +15 -1
- package/dist/src/pil/layer2_5-ponytail.js +8 -8
- package/dist/src/pil/layer3-ee-injection.js +23 -8
- package/dist/src/pil/layer4-gsd.js +69 -16
- package/dist/src/pil/layer5-context.js +7 -3
- package/dist/src/pil/layer6-output.d.ts +23 -0
- package/dist/src/pil/layer6-output.js +5 -1
- package/dist/src/pil/llm-classify.d.ts +33 -2
- package/dist/src/pil/llm-classify.js +123 -131
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +1 -0
- package/dist/src/pil/pipeline.js +34 -2
- package/dist/src/pil/response-tools.js +5 -3
- package/dist/src/pil/schema.d.ts +1 -0
- package/dist/src/pil/schema.js +2 -0
- package/dist/src/pil/types.d.ts +18 -0
- package/dist/src/playbook/directives.d.ts +4 -0
- package/dist/src/playbook/directives.js +17 -5
- package/dist/src/product-loop/backlog-builder.d.ts +14 -1
- package/dist/src/product-loop/backlog-builder.js +30 -6
- package/dist/src/product-loop/discovery-context-format.js +3 -1
- package/dist/src/product-loop/discovery-ecosystem.js +4 -1
- package/dist/src/product-loop/discovery-interview.js +32 -3
- package/dist/src/product-loop/discovery-schema.js +5 -1
- package/dist/src/product-loop/done-gate.js +3 -3
- package/dist/src/product-loop/ideal-trace.d.ts +7 -0
- package/dist/src/product-loop/ideal-trace.js +64 -0
- package/dist/src/product-loop/index.d.ts +13 -1
- package/dist/src/product-loop/index.js +333 -52
- package/dist/src/product-loop/loop-driver.d.ts +7 -0
- package/dist/src/product-loop/loop-driver.js +327 -116
- package/dist/src/product-loop/phase-plan.d.ts +5 -0
- package/dist/src/product-loop/phase-plan.js +39 -2
- package/dist/src/product-loop/phase-runner.js +9 -1
- package/dist/src/product-loop/progress-snapshot.js +4 -4
- package/dist/src/product-loop/sprint-runner.d.ts +111 -0
- package/dist/src/product-loop/sprint-runner.js +559 -16
- package/dist/src/product-loop/types.d.ts +36 -5
- package/dist/src/providers/adapter.d.ts +1 -1
- package/dist/src/providers/adapter.js +3 -4
- package/dist/src/providers/auth/browser-flow.d.ts +1 -1
- package/dist/src/providers/auth/browser-flow.js +1 -1
- package/dist/src/providers/auth/openai-oauth.js +1 -1
- package/dist/src/providers/auth/registry.js +0 -34
- package/dist/src/providers/auth/token-store.js +4 -1
- package/dist/src/providers/auth/types.d.ts +1 -1
- package/dist/src/providers/auth/types.js +1 -1
- package/dist/src/providers/capabilities.d.ts +24 -5
- package/dist/src/providers/capabilities.js +42 -24
- package/dist/src/providers/endpoints.d.ts +2 -2
- package/dist/src/providers/endpoints.js +11 -10
- package/dist/src/providers/keychain.d.ts +1 -1
- package/dist/src/providers/keychain.js +7 -9
- package/dist/src/providers/mcp-vision-bridge.js +82 -172
- package/dist/src/providers/openai-compatible.js +8 -1
- package/dist/src/providers/pricing.d.ts +2 -2
- package/dist/src/providers/pricing.js +3 -13
- package/dist/src/providers/runtime.d.ts +27 -2
- package/dist/src/providers/runtime.js +78 -15
- package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
- package/dist/src/providers/strategies/base.strategy.js +24 -1
- package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
- package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
- package/dist/src/providers/strategies/registry.js +4 -4
- package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
- package/dist/src/providers/strategies/thinking-mode.js +280 -1
- package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
- package/dist/src/providers/strategies/zai.strategy.js +44 -0
- package/dist/src/providers/types.d.ts +5 -6
- package/dist/src/providers/types.js +2 -2
- package/dist/src/providers/vision-backend.d.ts +47 -0
- package/dist/src/providers/vision-backend.js +258 -0
- package/dist/src/providers/vision-proxy.d.ts +22 -9
- package/dist/src/providers/vision-proxy.js +63 -132
- package/dist/src/providers/wire-debug.js +95 -0
- package/dist/src/reporter/index.js +1 -1
- package/dist/src/router/decide.d.ts +13 -0
- package/dist/src/router/decide.js +138 -36
- package/dist/src/router/peak-hour.d.ts +38 -0
- package/dist/src/router/peak-hour.js +107 -0
- package/dist/src/router/step-router.js +3 -2
- package/dist/src/router/warm.js +4 -5
- package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
- package/dist/src/scaffold/bb-quality-gate.js +5 -5
- package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
- package/dist/src/scaffold/continuation-prompt.js +86 -60
- package/dist/src/scaffold/init-new.js +453 -453
- package/dist/src/scaffold/point-to-existing.d.ts +21 -0
- package/dist/src/scaffold/point-to-existing.js +25 -0
- package/dist/src/self-qa/agentic-loop.js +22 -22
- package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
- package/dist/src/{ui/state → state}/active-run.js +21 -0
- package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
- package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
- package/dist/src/state/turn-trace.d.ts +43 -0
- package/dist/src/state/turn-trace.js +32 -0
- package/dist/src/storage/db.js +2 -1
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/interaction-log.d.ts +1 -1
- package/dist/src/storage/interaction-log.js +5 -5
- package/dist/src/storage/migrations.js +196 -126
- package/dist/src/storage/session-experience-store.js +4 -4
- package/dist/src/storage/sessions.d.ts +28 -10
- package/dist/src/storage/sessions.js +112 -55
- package/dist/src/storage/transcript-view.js +1 -1
- package/dist/src/storage/transcript.d.ts +51 -0
- package/dist/src/storage/transcript.js +383 -112
- package/dist/src/storage/usage.js +14 -14
- package/dist/src/storage/workspaces.js +12 -12
- package/dist/src/tools/file.d.ts +15 -0
- package/dist/src/tools/file.js +32 -0
- package/dist/src/tools/native-tools.js +5 -0
- package/dist/src/tools/registry.d.ts +3 -0
- package/dist/src/tools/registry.js +460 -22
- package/dist/src/tools/research.d.ts +29 -0
- package/dist/src/tools/research.js +233 -0
- package/dist/src/types/index.d.ts +118 -3
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/cards/product-status-card.js +1 -1
- package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
- package/dist/src/ui/components/bubble-body-guard.js +50 -0
- package/dist/src/ui/components/context-rail.d.ts +26 -0
- package/dist/src/ui/components/context-rail.js +33 -0
- package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
- package/dist/src/ui/components/council-conclusion-card.js +420 -0
- package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
- package/dist/src/ui/components/council-debate-pill.js +34 -0
- package/dist/src/ui/components/council-info-card.js +2 -2
- package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
- package/dist/src/ui/components/council-leader-bubble.js +21 -11
- package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
- package/dist/src/ui/components/council-message-bubble.js +16 -15
- package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
- package/dist/src/ui/components/council-phase-timeline.js +49 -15
- package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
- package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
- package/dist/src/ui/components/council-question-card.js +12 -12
- package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
- package/dist/src/ui/components/council-rail-rounds.js +57 -0
- package/dist/src/ui/components/council-round-group.d.ts +38 -0
- package/dist/src/ui/components/council-round-group.js +88 -0
- package/dist/src/ui/components/council-status-list.d.ts +3 -1
- package/dist/src/ui/components/council-status-list.js +36 -24
- package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
- package/dist/src/ui/components/council-synthesis-banner.js +20 -5
- package/dist/src/ui/components/halt-recovery-card.js +9 -5
- package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
- package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
- package/dist/src/ui/components/prompt-box.js +18 -16
- package/dist/src/ui/components/session-tree-card.d.ts +14 -0
- package/dist/src/ui/components/session-tree-card.js +46 -0
- package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
- package/dist/src/ui/components/slash-inline-menu.js +26 -5
- package/dist/src/ui/components/task-list-panel.d.ts +14 -1
- package/dist/src/ui/components/task-list-panel.js +22 -2
- package/dist/src/ui/containers/modals-layer.d.ts +2 -1
- package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
- package/dist/src/ui/mcp-modal.js +2 -4
- package/dist/src/ui/modals/api-key-modal.js +1 -1
- package/dist/src/ui/modals/connect-modal.js +4 -3
- package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
- package/dist/src/ui/modals/session-picker-modal.js +3 -5
- package/dist/src/ui/picker-providers.d.ts +1 -1
- package/dist/src/ui/picker-providers.js +1 -1
- package/dist/src/ui/primitives/index.d.ts +1 -0
- package/dist/src/ui/primitives/index.js +2 -0
- package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
- package/dist/src/ui/primitives/semantic-primitives.js +81 -0
- package/dist/src/ui/slash/compact.js +5 -7
- package/dist/src/ui/slash/cost.js +1 -1
- package/dist/src/ui/slash/council-inspect.js +4 -4
- package/dist/src/ui/slash/council.js +19 -1
- package/dist/src/ui/slash/debug.d.ts +3 -31
- package/dist/src/ui/slash/debug.js +9 -20
- package/dist/src/ui/slash/ideal.d.ts +6 -2
- package/dist/src/ui/slash/ideal.js +97 -7
- package/dist/src/ui/slash/menu-items.d.ts +7 -0
- package/dist/src/ui/slash/menu-items.js +12 -18
- package/dist/src/ui/slash/registry.d.ts +2 -0
- package/dist/src/ui/slash/registry.js +4 -0
- package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
- package/dist/src/ui/status-bar/cache-hit.js +9 -0
- package/dist/src/ui/status-bar/index.d.ts +1 -1
- package/dist/src/ui/status-bar/index.js +7 -3
- package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
- package/dist/src/ui/status-bar/usd-meter.js +6 -4
- package/dist/src/ui/theme.d.ts +1 -0
- package/dist/src/ui/theme.js +2 -0
- package/dist/src/ui/types.d.ts +7 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/format.d.ts +14 -0
- package/dist/src/ui/utils/format.js +23 -3
- package/dist/src/usage/downgrade.js +2 -2
- package/dist/src/usage/product-ledger.js +2 -2
- package/dist/src/utils/clipboard-image.js +23 -23
- package/dist/src/utils/install-manager.js +14 -11
- package/dist/src/utils/logger.js +2 -2
- package/dist/src/utils/permission-mode.js +5 -3
- package/dist/src/utils/redactor.js +1 -1
- package/dist/src/utils/settings.d.ts +153 -5
- package/dist/src/utils/settings.js +233 -29
- package/dist/src/utils/side-question.js +2 -2
- package/dist/src/utils/skills.js +3 -3
- package/dist/src/utils/visible-retry.d.ts +11 -0
- package/dist/src/utils/visible-retry.js +10 -1
- package/dist/src/verify/entrypoint.d.ts +1 -1
- package/dist/src/verify/entrypoint.js +1 -1
- package/dist/src/verify/recipes.d.ts +13 -0
- package/dist/src/verify/recipes.js +15 -0
- package/package.json +135 -132
- package/dist/src/providers/auth/gcloud.d.ts +0 -28
- package/dist/src/providers/auth/gcloud.js +0 -102
- package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
- package/dist/src/providers/auth/gemini-oauth.js +0 -472
- package/dist/src/providers/gemini.d.ts +0 -11
- package/dist/src/providers/gemini.js +0 -45
- package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
- package/dist/src/providers/siliconflow-sse-repair.js +0 -177
- package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
- package/dist/src/providers/strategies/google.strategy.js +0 -174
- package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
- package/dist/src/ui/containers/chat-feed.d.ts +0 -40
- package/dist/src/ui/containers/chat-feed.js +0 -66
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const LATEST_DB_VERSION =
|
|
1
|
+
const LATEST_DB_VERSION = 10;
|
|
2
2
|
export function applyMigrations(db) {
|
|
3
3
|
const version = Number(db.pragma("user_version", { simple: true })) || 0;
|
|
4
4
|
if (version >= LATEST_DB_VERSION)
|
|
@@ -13,9 +13,9 @@ export function applyMigrations(db) {
|
|
|
13
13
|
db.pragma("user_version = 2");
|
|
14
14
|
}
|
|
15
15
|
if (version < 3) {
|
|
16
|
-
db.exec(`
|
|
17
|
-
ALTER TABLE usage_events ADD COLUMN pil_active INTEGER NOT NULL DEFAULT 0;
|
|
18
|
-
ALTER TABLE usage_events ADD COLUMN enrichment_delta INTEGER NOT NULL DEFAULT 0;
|
|
16
|
+
db.exec(`
|
|
17
|
+
ALTER TABLE usage_events ADD COLUMN pil_active INTEGER NOT NULL DEFAULT 0;
|
|
18
|
+
ALTER TABLE usage_events ADD COLUMN enrichment_delta INTEGER NOT NULL DEFAULT 0;
|
|
19
19
|
`);
|
|
20
20
|
db.pragma("user_version = 3");
|
|
21
21
|
}
|
|
@@ -34,24 +34,24 @@ export function applyMigrations(db) {
|
|
|
34
34
|
db.pragma("user_version = 4");
|
|
35
35
|
}
|
|
36
36
|
if (version < 5) {
|
|
37
|
-
db.exec(`
|
|
38
|
-
CREATE TABLE IF NOT EXISTS interaction_logs (
|
|
39
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
40
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
41
|
-
event_type TEXT NOT NULL,
|
|
42
|
-
event_subtype TEXT,
|
|
43
|
-
model TEXT,
|
|
44
|
-
duration_ms INTEGER,
|
|
45
|
-
input_tokens INTEGER,
|
|
46
|
-
output_tokens INTEGER,
|
|
47
|
-
metadata_json TEXT,
|
|
48
|
-
created_at TEXT NOT NULL
|
|
49
|
-
) STRICT;
|
|
50
|
-
|
|
51
|
-
CREATE INDEX IF NOT EXISTS idx_interaction_logs_session
|
|
52
|
-
ON interaction_logs(session_id, created_at DESC);
|
|
53
|
-
CREATE INDEX IF NOT EXISTS idx_interaction_logs_event_type
|
|
54
|
-
ON interaction_logs(event_type, created_at DESC);
|
|
37
|
+
db.exec(`
|
|
38
|
+
CREATE TABLE IF NOT EXISTS interaction_logs (
|
|
39
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
40
|
+
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
41
|
+
event_type TEXT NOT NULL,
|
|
42
|
+
event_subtype TEXT,
|
|
43
|
+
model TEXT,
|
|
44
|
+
duration_ms INTEGER,
|
|
45
|
+
input_tokens INTEGER,
|
|
46
|
+
output_tokens INTEGER,
|
|
47
|
+
metadata_json TEXT,
|
|
48
|
+
created_at TEXT NOT NULL
|
|
49
|
+
) STRICT;
|
|
50
|
+
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_interaction_logs_session
|
|
52
|
+
ON interaction_logs(session_id, created_at DESC);
|
|
53
|
+
CREATE INDEX IF NOT EXISTS idx_interaction_logs_event_type
|
|
54
|
+
ON interaction_logs(event_type, created_at DESC);
|
|
55
55
|
`);
|
|
56
56
|
db.pragma("user_version = 5");
|
|
57
57
|
}
|
|
@@ -96,117 +96,187 @@ export function applyMigrations(db) {
|
|
|
96
96
|
db.exec("CREATE INDEX IF NOT EXISTS idx_sessions_parent_id ON sessions(parent_session_id)");
|
|
97
97
|
db.pragma("user_version = 8");
|
|
98
98
|
}
|
|
99
|
+
if (version < 9) {
|
|
100
|
+
db.exec(`
|
|
101
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS session_history_fts USING fts5(
|
|
102
|
+
session_id UNINDEXED,
|
|
103
|
+
seq UNINDEXED,
|
|
104
|
+
role UNINDEXED,
|
|
105
|
+
tool_name UNINDEXED,
|
|
106
|
+
content,
|
|
107
|
+
tool_args,
|
|
108
|
+
tool_output
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
CREATE TRIGGER IF NOT EXISTS t_sessions_delete_fts
|
|
112
|
+
AFTER DELETE ON sessions
|
|
113
|
+
BEGIN
|
|
114
|
+
DELETE FROM session_history_fts WHERE session_id = old.id;
|
|
115
|
+
END;
|
|
116
|
+
`);
|
|
117
|
+
db.pragma("user_version = 9");
|
|
118
|
+
}
|
|
119
|
+
if (version < 10) {
|
|
120
|
+
// Thread-aware resume. The resume picker groups sessions by conversation
|
|
121
|
+
// tree; `kind` distinguishes the two kinds of child (both previously only
|
|
122
|
+
// set parent_session_id, indistinguishable) and `root_session_id`
|
|
123
|
+
// denormalizes the tree root so the picker groups without a recursive CTE.
|
|
124
|
+
const cols = db.prepare("PRAGMA table_info(sessions)").all();
|
|
125
|
+
const colNames = new Set(cols.map((c) => c.name));
|
|
126
|
+
if (!colNames.has("kind")) {
|
|
127
|
+
db.exec("ALTER TABLE sessions ADD COLUMN kind TEXT NOT NULL DEFAULT 'conversation'");
|
|
128
|
+
}
|
|
129
|
+
if (!colNames.has("root_session_id")) {
|
|
130
|
+
db.exec("ALTER TABLE sessions ADD COLUMN root_session_id TEXT");
|
|
131
|
+
}
|
|
132
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_sessions_root ON sessions(workspace_id, root_session_id)");
|
|
133
|
+
backfillSessionTrees(db);
|
|
134
|
+
db.pragma("user_version = 10");
|
|
135
|
+
}
|
|
99
136
|
});
|
|
100
137
|
migrate();
|
|
101
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Backfill kind + root_session_id for pre-v10 rows.
|
|
141
|
+
*
|
|
142
|
+
* - Rows with no parent become their own root (kind 'conversation').
|
|
143
|
+
* - Rows WITH a parent are marked 'rotation' — historical data cannot tell
|
|
144
|
+
* rotation apart from sub-agent spawns, and marking them 'rotation' collapses
|
|
145
|
+
* them under their root rather than risking hiding a real conversation.
|
|
146
|
+
* - root_session_id propagates down the parent chain via a bounded fixpoint
|
|
147
|
+
* loop (chains are shallow; the bound also guards against FK cycles).
|
|
148
|
+
*/
|
|
149
|
+
function backfillSessionTrees(db) {
|
|
150
|
+
// Roots: own id, keep default kind 'conversation'.
|
|
151
|
+
db.exec("UPDATE sessions SET root_session_id = id WHERE parent_session_id IS NULL AND root_session_id IS NULL");
|
|
152
|
+
// Children of a real parent → rotation (default kind was 'conversation').
|
|
153
|
+
db.exec("UPDATE sessions SET kind = 'rotation' WHERE parent_session_id IS NOT NULL");
|
|
154
|
+
// Propagate root down the chain until no row changes (bounded to 100 passes).
|
|
155
|
+
for (let i = 0; i < 100; i++) {
|
|
156
|
+
db.exec(`
|
|
157
|
+
UPDATE sessions
|
|
158
|
+
SET root_session_id = (SELECT p.root_session_id FROM sessions p WHERE p.id = sessions.parent_session_id)
|
|
159
|
+
WHERE root_session_id IS NULL
|
|
160
|
+
AND parent_session_id IS NOT NULL
|
|
161
|
+
AND (SELECT p.root_session_id FROM sessions p WHERE p.id = sessions.parent_session_id) IS NOT NULL
|
|
162
|
+
`);
|
|
163
|
+
const remaining = db
|
|
164
|
+
.prepare("SELECT COUNT(*) AS c FROM sessions WHERE root_session_id IS NULL AND parent_session_id IS NOT NULL")
|
|
165
|
+
.get();
|
|
166
|
+
if (!remaining || remaining.c === 0)
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
// Any leftover (orphaned/cyclic parent chains) → treat as its own root.
|
|
170
|
+
db.exec("UPDATE sessions SET root_session_id = id WHERE root_session_id IS NULL");
|
|
171
|
+
}
|
|
102
172
|
function createInitialSchema(db) {
|
|
103
|
-
db.exec(`
|
|
104
|
-
CREATE TABLE IF NOT EXISTS workspaces (
|
|
105
|
-
id TEXT PRIMARY KEY,
|
|
106
|
-
scope_key TEXT NOT NULL UNIQUE,
|
|
107
|
-
canonical_path TEXT NOT NULL,
|
|
108
|
-
git_root TEXT,
|
|
109
|
-
display_name TEXT NOT NULL,
|
|
110
|
-
last_seen_at TEXT NOT NULL
|
|
111
|
-
) STRICT;
|
|
112
|
-
|
|
113
|
-
CREATE TABLE IF NOT EXISTS sessions (
|
|
114
|
-
id TEXT PRIMARY KEY,
|
|
115
|
-
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
116
|
-
parent_session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
117
|
-
title TEXT,
|
|
118
|
-
model TEXT NOT NULL,
|
|
119
|
-
mode TEXT NOT NULL,
|
|
120
|
-
cwd_at_start TEXT NOT NULL,
|
|
121
|
-
cwd_last TEXT NOT NULL,
|
|
122
|
-
status TEXT NOT NULL,
|
|
123
|
-
created_at TEXT NOT NULL,
|
|
124
|
-
updated_at TEXT NOT NULL
|
|
125
|
-
) STRICT;
|
|
126
|
-
|
|
127
|
-
CREATE TABLE IF NOT EXISTS messages (
|
|
128
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
129
|
-
seq INTEGER NOT NULL,
|
|
130
|
-
role TEXT NOT NULL,
|
|
131
|
-
message_json TEXT NOT NULL,
|
|
132
|
-
created_at TEXT NOT NULL,
|
|
133
|
-
status TEXT,
|
|
134
|
-
PRIMARY KEY (session_id, seq)
|
|
135
|
-
) STRICT;
|
|
136
|
-
|
|
137
|
-
CREATE TABLE IF NOT EXISTS tool_calls (
|
|
138
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
139
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
140
|
-
message_seq INTEGER NOT NULL,
|
|
141
|
-
tool_call_id TEXT NOT NULL,
|
|
142
|
-
tool_name TEXT NOT NULL,
|
|
143
|
-
args_json TEXT NOT NULL,
|
|
144
|
-
status TEXT NOT NULL,
|
|
145
|
-
started_at TEXT NOT NULL,
|
|
146
|
-
completed_at TEXT,
|
|
147
|
-
UNIQUE(session_id, tool_call_id)
|
|
148
|
-
) STRICT;
|
|
149
|
-
|
|
150
|
-
CREATE TABLE IF NOT EXISTS tool_results (
|
|
151
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152
|
-
tool_call_row_id INTEGER NOT NULL REFERENCES tool_calls(id) ON DELETE CASCADE,
|
|
153
|
-
output_kind TEXT NOT NULL,
|
|
154
|
-
output_json TEXT NOT NULL,
|
|
155
|
-
success INTEGER NOT NULL,
|
|
156
|
-
created_at TEXT NOT NULL
|
|
157
|
-
) STRICT;
|
|
158
|
-
|
|
159
|
-
CREATE TABLE IF NOT EXISTS usage_events (
|
|
160
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
161
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
162
|
-
message_seq INTEGER,
|
|
163
|
-
source TEXT NOT NULL,
|
|
164
|
-
model TEXT NOT NULL,
|
|
165
|
-
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
166
|
-
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
167
|
-
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
168
|
-
cost_micros INTEGER NOT NULL DEFAULT 0,
|
|
169
|
-
created_at TEXT NOT NULL,
|
|
170
|
-
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
|
171
|
-
cache_creation_tokens INTEGER NOT NULL DEFAULT 0
|
|
172
|
-
) STRICT;
|
|
173
|
-
|
|
174
|
-
CREATE TABLE IF NOT EXISTS compactions (
|
|
175
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
176
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
177
|
-
first_kept_seq INTEGER NOT NULL,
|
|
178
|
-
summary TEXT NOT NULL,
|
|
179
|
-
tokens_before INTEGER NOT NULL DEFAULT 0,
|
|
180
|
-
created_at TEXT NOT NULL
|
|
181
|
-
) STRICT;
|
|
182
|
-
|
|
183
|
-
CREATE INDEX IF NOT EXISTS idx_sessions_workspace_updated
|
|
184
|
-
ON sessions(workspace_id, updated_at DESC);
|
|
185
|
-
CREATE INDEX IF NOT EXISTS idx_sessions_parent_id
|
|
186
|
-
ON sessions(parent_session_id);
|
|
187
|
-
CREATE INDEX IF NOT EXISTS idx_messages_session_seq
|
|
188
|
-
ON messages(session_id, seq);
|
|
189
|
-
CREATE INDEX IF NOT EXISTS idx_tool_calls_session_seq
|
|
190
|
-
ON tool_calls(session_id, message_seq);
|
|
191
|
-
CREATE INDEX IF NOT EXISTS idx_usage_events_session_created
|
|
192
|
-
ON usage_events(session_id, created_at DESC);
|
|
193
|
-
CREATE INDEX IF NOT EXISTS idx_compactions_session_created
|
|
194
|
-
ON compactions(session_id, created_at DESC);
|
|
173
|
+
db.exec(`
|
|
174
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
175
|
+
id TEXT PRIMARY KEY,
|
|
176
|
+
scope_key TEXT NOT NULL UNIQUE,
|
|
177
|
+
canonical_path TEXT NOT NULL,
|
|
178
|
+
git_root TEXT,
|
|
179
|
+
display_name TEXT NOT NULL,
|
|
180
|
+
last_seen_at TEXT NOT NULL
|
|
181
|
+
) STRICT;
|
|
182
|
+
|
|
183
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
184
|
+
id TEXT PRIMARY KEY,
|
|
185
|
+
workspace_id TEXT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
186
|
+
parent_session_id TEXT REFERENCES sessions(id) ON DELETE SET NULL,
|
|
187
|
+
title TEXT,
|
|
188
|
+
model TEXT NOT NULL,
|
|
189
|
+
mode TEXT NOT NULL,
|
|
190
|
+
cwd_at_start TEXT NOT NULL,
|
|
191
|
+
cwd_last TEXT NOT NULL,
|
|
192
|
+
status TEXT NOT NULL,
|
|
193
|
+
created_at TEXT NOT NULL,
|
|
194
|
+
updated_at TEXT NOT NULL
|
|
195
|
+
) STRICT;
|
|
196
|
+
|
|
197
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
198
|
+
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
199
|
+
seq INTEGER NOT NULL,
|
|
200
|
+
role TEXT NOT NULL,
|
|
201
|
+
message_json TEXT NOT NULL,
|
|
202
|
+
created_at TEXT NOT NULL,
|
|
203
|
+
status TEXT,
|
|
204
|
+
PRIMARY KEY (session_id, seq)
|
|
205
|
+
) STRICT;
|
|
206
|
+
|
|
207
|
+
CREATE TABLE IF NOT EXISTS tool_calls (
|
|
208
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
209
|
+
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
210
|
+
message_seq INTEGER NOT NULL,
|
|
211
|
+
tool_call_id TEXT NOT NULL,
|
|
212
|
+
tool_name TEXT NOT NULL,
|
|
213
|
+
args_json TEXT NOT NULL,
|
|
214
|
+
status TEXT NOT NULL,
|
|
215
|
+
started_at TEXT NOT NULL,
|
|
216
|
+
completed_at TEXT,
|
|
217
|
+
UNIQUE(session_id, tool_call_id)
|
|
218
|
+
) STRICT;
|
|
219
|
+
|
|
220
|
+
CREATE TABLE IF NOT EXISTS tool_results (
|
|
221
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
222
|
+
tool_call_row_id INTEGER NOT NULL REFERENCES tool_calls(id) ON DELETE CASCADE,
|
|
223
|
+
output_kind TEXT NOT NULL,
|
|
224
|
+
output_json TEXT NOT NULL,
|
|
225
|
+
success INTEGER NOT NULL,
|
|
226
|
+
created_at TEXT NOT NULL
|
|
227
|
+
) STRICT;
|
|
228
|
+
|
|
229
|
+
CREATE TABLE IF NOT EXISTS usage_events (
|
|
230
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
231
|
+
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
232
|
+
message_seq INTEGER,
|
|
233
|
+
source TEXT NOT NULL,
|
|
234
|
+
model TEXT NOT NULL,
|
|
235
|
+
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
236
|
+
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
237
|
+
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
238
|
+
cost_micros INTEGER NOT NULL DEFAULT 0,
|
|
239
|
+
created_at TEXT NOT NULL,
|
|
240
|
+
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
|
241
|
+
cache_creation_tokens INTEGER NOT NULL DEFAULT 0
|
|
242
|
+
) STRICT;
|
|
243
|
+
|
|
244
|
+
CREATE TABLE IF NOT EXISTS compactions (
|
|
245
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
246
|
+
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
247
|
+
first_kept_seq INTEGER NOT NULL,
|
|
248
|
+
summary TEXT NOT NULL,
|
|
249
|
+
tokens_before INTEGER NOT NULL DEFAULT 0,
|
|
250
|
+
created_at TEXT NOT NULL
|
|
251
|
+
) STRICT;
|
|
252
|
+
|
|
253
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_workspace_updated
|
|
254
|
+
ON sessions(workspace_id, updated_at DESC);
|
|
255
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_parent_id
|
|
256
|
+
ON sessions(parent_session_id);
|
|
257
|
+
CREATE INDEX IF NOT EXISTS idx_messages_session_seq
|
|
258
|
+
ON messages(session_id, seq);
|
|
259
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_session_seq
|
|
260
|
+
ON tool_calls(session_id, message_seq);
|
|
261
|
+
CREATE INDEX IF NOT EXISTS idx_usage_events_session_created
|
|
262
|
+
ON usage_events(session_id, created_at DESC);
|
|
263
|
+
CREATE INDEX IF NOT EXISTS idx_compactions_session_created
|
|
264
|
+
ON compactions(session_id, created_at DESC);
|
|
195
265
|
`);
|
|
196
266
|
}
|
|
197
267
|
function createCompactionSchema(db) {
|
|
198
|
-
db.exec(`
|
|
199
|
-
CREATE TABLE IF NOT EXISTS compactions (
|
|
200
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
201
|
-
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
202
|
-
first_kept_seq INTEGER NOT NULL,
|
|
203
|
-
summary TEXT NOT NULL,
|
|
204
|
-
tokens_before INTEGER NOT NULL DEFAULT 0,
|
|
205
|
-
created_at TEXT NOT NULL
|
|
206
|
-
) STRICT;
|
|
207
|
-
|
|
208
|
-
CREATE INDEX IF NOT EXISTS idx_compactions_session_created
|
|
209
|
-
ON compactions(session_id, created_at DESC);
|
|
268
|
+
db.exec(`
|
|
269
|
+
CREATE TABLE IF NOT EXISTS compactions (
|
|
270
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
271
|
+
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
272
|
+
first_kept_seq INTEGER NOT NULL,
|
|
273
|
+
summary TEXT NOT NULL,
|
|
274
|
+
tokens_before INTEGER NOT NULL DEFAULT 0,
|
|
275
|
+
created_at TEXT NOT NULL
|
|
276
|
+
) STRICT;
|
|
277
|
+
|
|
278
|
+
CREATE INDEX IF NOT EXISTS idx_compactions_session_created
|
|
279
|
+
ON compactions(session_id, created_at DESC);
|
|
210
280
|
`);
|
|
211
281
|
}
|
|
212
282
|
//# sourceMappingURL=migrations.js.map
|
|
@@ -70,8 +70,8 @@ function parseCounts(json) {
|
|
|
70
70
|
export function selectSessionExperience(sessionId) {
|
|
71
71
|
try {
|
|
72
72
|
const row = getDatabase()
|
|
73
|
-
.prepare(`SELECT metadata_json FROM interaction_logs
|
|
74
|
-
WHERE session_id = ? AND event_type = ?
|
|
73
|
+
.prepare(`SELECT metadata_json FROM interaction_logs
|
|
74
|
+
WHERE session_id = ? AND event_type = ?
|
|
75
75
|
ORDER BY created_at DESC, id DESC LIMIT 1`)
|
|
76
76
|
.get(sessionId, EVENT_TYPE);
|
|
77
77
|
return parseCounts(row?.metadata_json ?? null);
|
|
@@ -150,8 +150,8 @@ export function computeExperienceAggregate(rows, limit = 100) {
|
|
|
150
150
|
export function aggregateSessionExperience(limit = 100) {
|
|
151
151
|
try {
|
|
152
152
|
const rows = getDatabase()
|
|
153
|
-
.prepare(`SELECT session_id, metadata_json, created_at FROM interaction_logs
|
|
154
|
-
WHERE event_type = ?
|
|
153
|
+
.prepare(`SELECT session_id, metadata_json, created_at FROM interaction_logs
|
|
154
|
+
WHERE event_type = ?
|
|
155
155
|
ORDER BY created_at DESC, id DESC`)
|
|
156
156
|
.all(EVENT_TYPE);
|
|
157
157
|
return computeExperienceAggregate(rows, limit);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { AgentMode, SessionInfo, SessionStatus, WorkspaceInfo } from "../types/index.js";
|
|
1
|
+
import type { AgentMode, ResumeEntry, SessionInfo, SessionKind, SessionStatus, WorkspaceInfo } from "../types/index.js";
|
|
2
|
+
import { type SQLiteDatabase } from "./db.js";
|
|
2
3
|
export declare class SessionStore {
|
|
3
4
|
private readonly workspace;
|
|
4
5
|
constructor(cwd: string);
|
|
@@ -6,18 +7,22 @@ export declare class SessionStore {
|
|
|
6
7
|
openSession(selector: string | undefined, model: string, mode: AgentMode, cwd: string): SessionInfo;
|
|
7
8
|
createSession(model: string, mode: AgentMode, cwd: string): SessionInfo;
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* CLI launch WITHOUT `--session` opens a fresh empty session, and test /
|
|
14
|
-
* harness runs leave behind title-only stubs — without this filter the picker
|
|
15
|
-
* fills with empty rows that resume to a blank screen, so a user picking one
|
|
16
|
-
* thinks resume is broken.
|
|
10
|
+
* Link a freshly-created session as a child of `parentId`, tagging its `kind`
|
|
11
|
+
* and inheriting the parent's `root_session_id` so the whole tree shares one
|
|
12
|
+
* root. Replaces the ad-hoc `UPDATE sessions SET parent_session_id = ?` the
|
|
13
|
+
* orchestrator previously hand-wrote (which never set kind/root).
|
|
17
14
|
*/
|
|
18
|
-
|
|
15
|
+
linkChild(childId: string, parentId: string, kind: SessionKind): void;
|
|
16
|
+
listRecentSessions(limit?: number): ResumeEntry[];
|
|
19
17
|
getLatestSession(): SessionInfo | null;
|
|
20
18
|
getSessionById(id: string): SessionInfo | null;
|
|
19
|
+
/**
|
|
20
|
+
* Authoritative session kind ("conversation" | "rotation" | "subagent").
|
|
21
|
+
* SessionInfo omits `kind`, so callers that need to know whether a session is
|
|
22
|
+
* a forked child (e.g. the turn_tool_load instrument) read it here. Returns
|
|
23
|
+
* null when the session row is absent.
|
|
24
|
+
*/
|
|
25
|
+
getSessionKind(id: string): SessionKind | null;
|
|
21
26
|
getRequiredSession(id: string): SessionInfo;
|
|
22
27
|
setStatus(id: string, status: SessionStatus): void;
|
|
23
28
|
setTitle(id: string, title: string | null): void;
|
|
@@ -25,4 +30,17 @@ export declare class SessionStore {
|
|
|
25
30
|
setMode(id: string, mode: AgentMode): void;
|
|
26
31
|
touchSession(id: string, cwd: string): void;
|
|
27
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* One row per conversation tree for the `/sessions` resume picker.
|
|
35
|
+
*
|
|
36
|
+
* - Groups by `root_session_id`; sub-agent sessions (`kind='subagent'`) are
|
|
37
|
+
* internal side-conversations and are excluded entirely.
|
|
38
|
+
* - Only trees with at least one persisted message surface (hides empty stub
|
|
39
|
+
* rows every keyless CLI launch creates).
|
|
40
|
+
* - The row's `title`/`created_at` come from the tree ROOT; `resume_id`,
|
|
41
|
+
* `model`, `updated_at`, `status` come from the LATEST leaf (the active tail
|
|
42
|
+
* of a rotation chain), so Enter resumes into the live session, not the
|
|
43
|
+
* compacted root. Ordered by tree activity, newest first.
|
|
44
|
+
*/
|
|
45
|
+
export declare function queryResumeList(db: SQLiteDatabase, workspaceId: string, limit: number): ResumeEntry[];
|
|
28
46
|
export { getSessionDir } from "./session-dir.js";
|
|
@@ -43,12 +43,12 @@ export class SessionStore {
|
|
|
43
43
|
const now = new Date().toISOString();
|
|
44
44
|
const id = createSessionId();
|
|
45
45
|
const db = getDatabase();
|
|
46
|
-
db.prepare(`
|
|
47
|
-
INSERT INTO sessions (
|
|
48
|
-
id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
|
|
49
|
-
) VALUES (
|
|
50
|
-
@id, @workspace_id, NULL, @model, @mode, @cwd_at_start, @cwd_last, 'active', @created_at, @updated_at
|
|
51
|
-
)
|
|
46
|
+
db.prepare(`
|
|
47
|
+
INSERT INTO sessions (
|
|
48
|
+
id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at, kind, root_session_id
|
|
49
|
+
) VALUES (
|
|
50
|
+
@id, @workspace_id, NULL, @model, @mode, @cwd_at_start, @cwd_last, 'active', @created_at, @updated_at, 'conversation', @id
|
|
51
|
+
)
|
|
52
52
|
`).run({
|
|
53
53
|
id,
|
|
54
54
|
workspace_id: this.workspace.id,
|
|
@@ -62,50 +62,52 @@ export class SessionStore {
|
|
|
62
62
|
return this.getRequiredSession(id);
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* CLI launch WITHOUT `--session` opens a fresh empty session, and test /
|
|
70
|
-
* harness runs leave behind title-only stubs — without this filter the picker
|
|
71
|
-
* fills with empty rows that resume to a blank screen, so a user picking one
|
|
72
|
-
* thinks resume is broken.
|
|
65
|
+
* Link a freshly-created session as a child of `parentId`, tagging its `kind`
|
|
66
|
+
* and inheriting the parent's `root_session_id` so the whole tree shares one
|
|
67
|
+
* root. Replaces the ad-hoc `UPDATE sessions SET parent_session_id = ?` the
|
|
68
|
+
* orchestrator previously hand-wrote (which never set kind/root).
|
|
73
69
|
*/
|
|
70
|
+
linkChild(childId, parentId, kind) {
|
|
71
|
+
const db = getDatabase();
|
|
72
|
+
const parent = db.prepare("SELECT root_session_id FROM sessions WHERE id = ?").get(parentId);
|
|
73
|
+
const root = parent?.root_session_id ?? parentId;
|
|
74
|
+
db.prepare("UPDATE sessions SET parent_session_id = ?, kind = ?, root_session_id = ?, updated_at = ? WHERE id = ?").run(parentId, kind, root, new Date().toISOString(), childId);
|
|
75
|
+
}
|
|
74
76
|
listRecentSessions(limit = 20) {
|
|
75
|
-
|
|
76
|
-
.prepare(`
|
|
77
|
-
SELECT s.id, s.workspace_id, s.title, s.model, s.mode, s.cwd_at_start, s.cwd_last, s.status, s.created_at, s.updated_at
|
|
78
|
-
FROM sessions s
|
|
79
|
-
WHERE s.workspace_id = ?
|
|
80
|
-
AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = s.id)
|
|
81
|
-
ORDER BY s.updated_at DESC
|
|
82
|
-
LIMIT ?
|
|
83
|
-
`)
|
|
84
|
-
.all(this.workspace.id, limit);
|
|
85
|
-
return rows.map(toSessionInfo);
|
|
77
|
+
return queryResumeList(getDatabase(), this.workspace.id, limit);
|
|
86
78
|
}
|
|
87
79
|
getLatestSession() {
|
|
88
80
|
const row = getDatabase()
|
|
89
|
-
.prepare(`
|
|
90
|
-
SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
|
|
91
|
-
FROM sessions
|
|
92
|
-
WHERE workspace_id = ?
|
|
93
|
-
ORDER BY updated_at DESC
|
|
94
|
-
LIMIT 1
|
|
81
|
+
.prepare(`
|
|
82
|
+
SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
|
|
83
|
+
FROM sessions
|
|
84
|
+
WHERE workspace_id = ?
|
|
85
|
+
ORDER BY updated_at DESC
|
|
86
|
+
LIMIT 1
|
|
95
87
|
`)
|
|
96
88
|
.get(this.workspace.id);
|
|
97
89
|
return row ? toSessionInfo(row) : null;
|
|
98
90
|
}
|
|
99
91
|
getSessionById(id) {
|
|
100
92
|
const row = getDatabase()
|
|
101
|
-
.prepare(`
|
|
102
|
-
SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
|
|
103
|
-
FROM sessions
|
|
104
|
-
WHERE id = ?
|
|
93
|
+
.prepare(`
|
|
94
|
+
SELECT id, workspace_id, title, model, mode, cwd_at_start, cwd_last, status, created_at, updated_at
|
|
95
|
+
FROM sessions
|
|
96
|
+
WHERE id = ?
|
|
105
97
|
`)
|
|
106
98
|
.get(id);
|
|
107
99
|
return row ? toSessionInfo(row) : null;
|
|
108
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Authoritative session kind ("conversation" | "rotation" | "subagent").
|
|
103
|
+
* SessionInfo omits `kind`, so callers that need to know whether a session is
|
|
104
|
+
* a forked child (e.g. the turn_tool_load instrument) read it here. Returns
|
|
105
|
+
* null when the session row is absent.
|
|
106
|
+
*/
|
|
107
|
+
getSessionKind(id) {
|
|
108
|
+
const row = getDatabase().prepare("SELECT kind FROM sessions WHERE id = ?").get(id);
|
|
109
|
+
return row?.kind ?? null;
|
|
110
|
+
}
|
|
109
111
|
getRequiredSession(id) {
|
|
110
112
|
const session = this.getSessionById(id);
|
|
111
113
|
if (!session) {
|
|
@@ -116,49 +118,49 @@ export class SessionStore {
|
|
|
116
118
|
setStatus(id, status) {
|
|
117
119
|
const now = new Date().toISOString();
|
|
118
120
|
getDatabase()
|
|
119
|
-
.prepare(`
|
|
120
|
-
UPDATE sessions
|
|
121
|
-
SET status = ?, updated_at = ?
|
|
122
|
-
WHERE id = ?
|
|
121
|
+
.prepare(`
|
|
122
|
+
UPDATE sessions
|
|
123
|
+
SET status = ?, updated_at = ?
|
|
124
|
+
WHERE id = ?
|
|
123
125
|
`)
|
|
124
126
|
.run(status, now, id);
|
|
125
127
|
}
|
|
126
128
|
setTitle(id, title) {
|
|
127
129
|
const now = new Date().toISOString();
|
|
128
130
|
getDatabase()
|
|
129
|
-
.prepare(`
|
|
130
|
-
UPDATE sessions
|
|
131
|
-
SET title = ?, updated_at = ?
|
|
132
|
-
WHERE id = ?
|
|
131
|
+
.prepare(`
|
|
132
|
+
UPDATE sessions
|
|
133
|
+
SET title = ?, updated_at = ?
|
|
134
|
+
WHERE id = ?
|
|
133
135
|
`)
|
|
134
136
|
.run(title, now, id);
|
|
135
137
|
}
|
|
136
138
|
setModel(id, model) {
|
|
137
139
|
const now = new Date().toISOString();
|
|
138
140
|
getDatabase()
|
|
139
|
-
.prepare(`
|
|
140
|
-
UPDATE sessions
|
|
141
|
-
SET model = ?, updated_at = ?
|
|
142
|
-
WHERE id = ?
|
|
141
|
+
.prepare(`
|
|
142
|
+
UPDATE sessions
|
|
143
|
+
SET model = ?, updated_at = ?
|
|
144
|
+
WHERE id = ?
|
|
143
145
|
`)
|
|
144
146
|
.run(model, now, id);
|
|
145
147
|
}
|
|
146
148
|
setMode(id, mode) {
|
|
147
149
|
const now = new Date().toISOString();
|
|
148
150
|
getDatabase()
|
|
149
|
-
.prepare(`
|
|
150
|
-
UPDATE sessions
|
|
151
|
-
SET mode = ?, updated_at = ?
|
|
152
|
-
WHERE id = ?
|
|
151
|
+
.prepare(`
|
|
152
|
+
UPDATE sessions
|
|
153
|
+
SET mode = ?, updated_at = ?
|
|
154
|
+
WHERE id = ?
|
|
153
155
|
`)
|
|
154
156
|
.run(mode, now, id);
|
|
155
157
|
}
|
|
156
158
|
touchSession(id, cwd) {
|
|
157
159
|
getDatabase()
|
|
158
|
-
.prepare(`
|
|
159
|
-
UPDATE sessions
|
|
160
|
-
SET cwd_last = ?, updated_at = ?
|
|
161
|
-
WHERE id = ?
|
|
160
|
+
.prepare(`
|
|
161
|
+
UPDATE sessions
|
|
162
|
+
SET cwd_last = ?, updated_at = ?
|
|
163
|
+
WHERE id = ?
|
|
162
164
|
`)
|
|
163
165
|
.run(cwd, new Date().toISOString(), id);
|
|
164
166
|
}
|
|
@@ -180,6 +182,61 @@ function toSessionInfo(row) {
|
|
|
180
182
|
updatedAt: new Date(row.updated_at),
|
|
181
183
|
};
|
|
182
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* One row per conversation tree for the `/sessions` resume picker.
|
|
187
|
+
*
|
|
188
|
+
* - Groups by `root_session_id`; sub-agent sessions (`kind='subagent'`) are
|
|
189
|
+
* internal side-conversations and are excluded entirely.
|
|
190
|
+
* - Only trees with at least one persisted message surface (hides empty stub
|
|
191
|
+
* rows every keyless CLI launch creates).
|
|
192
|
+
* - The row's `title`/`created_at` come from the tree ROOT; `resume_id`,
|
|
193
|
+
* `model`, `updated_at`, `status` come from the LATEST leaf (the active tail
|
|
194
|
+
* of a rotation chain), so Enter resumes into the live session, not the
|
|
195
|
+
* compacted root. Ordered by tree activity, newest first.
|
|
196
|
+
*/
|
|
197
|
+
export function queryResumeList(db, workspaceId, limit) {
|
|
198
|
+
const rows = db
|
|
199
|
+
.prepare(`
|
|
200
|
+
WITH candidates AS (
|
|
201
|
+
SELECT s.id, s.workspace_id, s.title, s.model, s.mode, s.cwd_at_start,
|
|
202
|
+
s.cwd_last, s.status, s.created_at, s.updated_at, s.root_session_id
|
|
203
|
+
FROM sessions s
|
|
204
|
+
WHERE s.workspace_id = ?
|
|
205
|
+
AND s.kind != 'subagent'
|
|
206
|
+
AND EXISTS (SELECT 1 FROM messages m WHERE m.session_id = s.id)
|
|
207
|
+
),
|
|
208
|
+
ranked AS (
|
|
209
|
+
SELECT c.*,
|
|
210
|
+
ROW_NUMBER() OVER (
|
|
211
|
+
PARTITION BY c.root_session_id
|
|
212
|
+
ORDER BY c.updated_at DESC, c.id DESC
|
|
213
|
+
) AS rn
|
|
214
|
+
FROM candidates c
|
|
215
|
+
)
|
|
216
|
+
SELECT
|
|
217
|
+
r.root_session_id AS id,
|
|
218
|
+
r.id AS resume_id,
|
|
219
|
+
COALESCE(root.title, r.title) AS title,
|
|
220
|
+
r.model AS model,
|
|
221
|
+
r.mode AS mode,
|
|
222
|
+
COALESCE(root.cwd_at_start, r.cwd_at_start) AS cwd_at_start,
|
|
223
|
+
r.cwd_last AS cwd_last,
|
|
224
|
+
r.status AS status,
|
|
225
|
+
COALESCE(root.created_at, r.created_at) AS created_at,
|
|
226
|
+
r.updated_at AS updated_at,
|
|
227
|
+
r.workspace_id AS workspace_id
|
|
228
|
+
FROM ranked r
|
|
229
|
+
LEFT JOIN sessions root ON root.id = r.root_session_id
|
|
230
|
+
WHERE r.rn = 1
|
|
231
|
+
ORDER BY r.updated_at DESC
|
|
232
|
+
LIMIT ?
|
|
233
|
+
`)
|
|
234
|
+
.all(workspaceId, limit);
|
|
235
|
+
return rows.map(toResumeEntry);
|
|
236
|
+
}
|
|
237
|
+
function toResumeEntry(row) {
|
|
238
|
+
return { ...toSessionInfo(row), resumeId: row.resume_id };
|
|
239
|
+
}
|
|
183
240
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
184
241
|
// B-3: Re-export getSessionDir from the isolated session-dir module.
|
|
185
242
|
//
|
|
@@ -10,7 +10,7 @@ export function buildEffectiveTranscript(messages, seqs, timestamps, compaction)
|
|
|
10
10
|
}
|
|
11
11
|
const firstKeptIndex = seqs.findIndex((seq) => seq >= compaction.firstKeptSeq);
|
|
12
12
|
let keptIndex = firstKeptIndex >= 0 ? firstKeptIndex : messages.length;
|
|
13
|
-
// Anti-mù / Resilience: if firstKeptSeq landed on a `tool` message (e.g. due to seq array
|
|
13
|
+
// Anti-mù / Resilience: if firstKeptSeq landed on a `tool` message (e.g. due to seq array
|
|
14
14
|
// misalignment or forced cut), we MUST step back to include its preceding `assistant` message.
|
|
15
15
|
// Otherwise Vercel AI SDK throws: "Messages with role 'tool' must be a response to a preceding message with 'tool_calls'"
|
|
16
16
|
if (keptIndex > 0 && messages[keptIndex]?.role === "tool") {
|