mixdog 0.9.2 → 0.9.4
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/package.json +8 -3
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- package/scripts/bench/lead-review-tasks-r3.json +20 -0
- package/scripts/bench/lead-review-tasks.json +20 -0
- package/scripts/bench/r4-mixed-tasks.json +20 -0
- package/scripts/bench/review-tasks.json +20 -0
- package/scripts/bench/round-codex.json +114 -0
- package/scripts/bench/round-mixdog-lead-r3.json +269 -0
- package/scripts/bench/round-mixdog-lead.json +269 -0
- package/scripts/bench/round-mixdog.json +126 -0
- package/scripts/bench/round-r10-bigsample.json +679 -0
- package/scripts/bench/round-r11-codexalign.json +257 -0
- package/scripts/bench/round-r4-codex.json +114 -0
- package/scripts/bench/round-r4-mixed.json +225 -0
- package/scripts/bench/round-r5-gpt-lead.json +259 -0
- package/scripts/bench/round-r6-codex.json +114 -0
- package/scripts/bench/round-r6-solo.json +257 -0
- package/scripts/bench/round-r7-full.json +254 -0
- package/scripts/bench/round-r8-fulldefault.json +255 -0
- package/scripts/bench-run.mjs +215 -29
- package/scripts/build-tui.mjs +13 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/freevar-smoke.mjs +95 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/internal-comms-bench.mjs +1 -0
- package/scripts/internal-comms-smoke.mjs +10 -9
- package/scripts/mouse-probe.mjs +45 -0
- package/scripts/output-style-bench.mjs +13 -6
- package/scripts/output-style-smoke.mjs +4 -4
- package/scripts/path-suffix-test.mjs +57 -0
- package/scripts/provider-toolcall-test.mjs +7 -3
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/recall-usecase-cases.json +18 -0
- package/scripts/recall-usecase-probe.json +6 -0
- package/scripts/session-bench.mjs +152 -6
- package/scripts/tool-smoke.mjs +30 -67
- package/scripts/tui-render-smoke.mjs +90 -0
- package/scripts/webhook-smoke.mjs +208 -0
- package/src/agents/debugger/AGENT.md +5 -2
- package/src/agents/heavy-worker/AGENT.md +21 -11
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +3 -2
- package/src/agents/worker/AGENT.md +21 -11
- package/src/lib/rules-builder.cjs +4 -0
- package/src/mixdog-session-runtime.mjs +933 -3731
- package/src/output-styles/default.md +34 -9
- package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
- package/src/output-styles/minimal.md +4 -1
- package/src/output-styles/simple.md +22 -7
- package/src/repl.mjs +5 -5
- package/src/rules/agent/00-common.md +2 -0
- package/src/rules/agent/30-explorer.md +8 -11
- package/src/rules/lead/lead-brief.md +12 -0
- package/src/rules/lead/lead-tool.md +2 -9
- package/src/rules/shared/01-tool.md +11 -5
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
- package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
- package/src/runtime/agent/orchestrator/config.mjs +69 -2
- package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
- package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
- package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
- package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
- package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
- package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
- package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
- package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
- package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
- package/src/runtime/channels/backends/discord-access.mjs +32 -0
- package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
- package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
- package/src/runtime/channels/backends/discord.mjs +12 -292
- package/src/runtime/channels/index.mjs +241 -894
- package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
- package/src/runtime/channels/lib/event-queue.mjs +63 -4
- package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
- package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
- package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
- package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
- package/src/runtime/channels/lib/session-discovery.mjs +56 -4
- package/src/runtime/channels/lib/telegram-format.mjs +19 -22
- package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
- package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
- package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
- package/src/runtime/channels/lib/webhook/log.mjs +42 -0
- package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
- package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
- package/src/runtime/channels/lib/webhook.mjs +36 -570
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/channels/tool-defs.mjs +11 -130
- package/src/runtime/memory/index.mjs +258 -2050
- package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
- package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
- package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -0
- package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
- package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
- package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
- package/src/runtime/memory/lib/memory-embed.mjs +149 -0
- package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +20 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/query-handlers.mjs +780 -0
- package/src/runtime/memory/lib/recall-format.mjs +238 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
- package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
- package/src/runtime/memory/tool-defs.mjs +6 -14
- package/src/runtime/search/lib/http-fetch.mjs +274 -0
- package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
- package/src/runtime/search/lib/web-tools.mjs +24 -602
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +26 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/launcher-control.mjs +2 -2
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +308 -0
- package/src/runtime/shared/tool-result-summary.mjs +515 -0
- package/src/runtime/shared/tool-surface.mjs +80 -898
- package/src/runtime/shared/transcript-writer.mjs +52 -2
- package/src/runtime/shared/update-checker.mjs +7 -4
- package/src/session-runtime/config-helpers.mjs +291 -0
- package/src/session-runtime/config-lifecycle.mjs +232 -0
- package/src/session-runtime/cwd-plugins.mjs +226 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/mcp-glue.mjs +177 -0
- package/src/session-runtime/model-capabilities.mjs +130 -0
- package/src/session-runtime/model-recency.mjs +111 -0
- package/src/session-runtime/native-search.mjs +247 -0
- package/src/session-runtime/output-styles.mjs +126 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- package/src/session-runtime/prewarm.mjs +142 -0
- package/src/session-runtime/provider-models.mjs +278 -0
- package/src/session-runtime/provider-usage.mjs +120 -0
- package/src/session-runtime/quick-model-rows.mjs +170 -0
- package/src/session-runtime/quick-search-models.mjs +46 -0
- package/src/session-runtime/session-hooks.mjs +93 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/settings-api.mjs +319 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/tool-defs.mjs +84 -0
- package/src/session-runtime/warmup-schedulers.mjs +201 -0
- package/src/session-runtime/workflow.mjs +358 -0
- package/src/standalone/agent-tool/helpers.mjs +237 -0
- package/src/standalone/agent-tool/notify.mjs +107 -0
- package/src/standalone/agent-tool/provider-init.mjs +143 -0
- package/src/standalone/agent-tool/render.mjs +152 -0
- package/src/standalone/agent-tool/tool-def.mjs +55 -0
- package/src/standalone/agent-tool.mjs +155 -677
- package/src/standalone/channel-worker.mjs +7 -9
- package/src/standalone/explore-tool.mjs +40 -12
- package/src/standalone/hook-bus/config.mjs +207 -0
- package/src/standalone/hook-bus/constants.mjs +90 -0
- package/src/standalone/hook-bus/handlers.mjs +481 -0
- package/src/standalone/hook-bus/payload.mjs +31 -0
- package/src/standalone/hook-bus/rules.mjs +77 -0
- package/src/standalone/hook-bus.mjs +110 -746
- package/src/standalone/memory-runtime-proxy.mjs +7 -0
- package/src/standalone/opencode-go-login.mjs +125 -0
- package/src/standalone/provider-admin.mjs +15 -19
- package/src/standalone/usage-dashboard.mjs +3 -1
- package/src/tui/App.jsx +1163 -7571
- package/src/tui/app/app-format.mjs +206 -0
- package/src/tui/app/channel-pickers.mjs +510 -0
- package/src/tui/app/clipboard.mjs +67 -0
- package/src/tui/app/core-memory-picker.mjs +210 -0
- package/src/tui/app/extension-pickers.mjs +506 -0
- package/src/tui/app/input-parsers.mjs +193 -0
- package/src/tui/app/maintenance-pickers.mjs +324 -0
- package/src/tui/app/model-options.mjs +330 -0
- package/src/tui/app/model-picker.mjs +365 -0
- package/src/tui/app/onboarding-steps.mjs +400 -0
- package/src/tui/app/project-picker.mjs +247 -0
- package/src/tui/app/provider-setup-picker.mjs +580 -0
- package/src/tui/app/resume-picker.mjs +55 -0
- package/src/tui/app/route-pickers.mjs +419 -0
- package/src/tui/app/settings-picker.mjs +490 -0
- package/src/tui/app/slash-commands.mjs +101 -0
- package/src/tui/app/slash-dispatch.mjs +427 -0
- package/src/tui/app/text-layout.mjs +46 -0
- package/src/tui/app/theme-effort-pickers.mjs +154 -0
- package/src/tui/app/transcript-window.mjs +671 -0
- package/src/tui/app/use-mouse-input.mjs +460 -0
- package/src/tui/app/use-prompt-handlers.mjs +310 -0
- package/src/tui/app/use-transcript-scroll.mjs +510 -0
- package/src/tui/app/use-transcript-window.mjs +589 -0
- package/src/tui/components/ConfirmBar.jsx +1 -1
- package/src/tui/components/Picker.jsx +32 -4
- package/src/tui/components/PromptInput.jsx +259 -80
- package/src/tui/components/SlashCommandPalette.jsx +8 -1
- package/src/tui/components/StatusLine.jsx +63 -12
- package/src/tui/components/TextEntryPanel.jsx +11 -0
- package/src/tui/components/ToolExecution.jsx +56 -588
- package/src/tui/components/TranscriptItem.jsx +105 -0
- package/src/tui/components/UsagePanel.jsx +18 -4
- package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
- package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
- package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
- package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
- package/src/tui/components/tool-execution/text-format.mjs +161 -0
- package/src/tui/components/tool-output-format.mjs +2 -2
- package/src/tui/display-width.mjs +20 -3
- package/src/tui/dist/index.mjs +18034 -17188
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/agent-job-feed.mjs +133 -0
- package/src/tui/engine/boot-profile.mjs +21 -0
- package/src/tui/engine/labels.mjs +67 -0
- package/src/tui/engine/notice-text.mjs +112 -0
- package/src/tui/engine/notification-plan.mjs +76 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/render-timing.mjs +17 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-approval.mjs +94 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -0
- package/src/tui/engine/tool-card-results.mjs +234 -0
- package/src/tui/engine/tool-result-status.mjs +135 -0
- package/src/tui/engine/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +405 -1385
- package/src/tui/figures.mjs +5 -0
- package/src/tui/index.jsx +105 -0
- package/src/tui/input-editing.mjs +60 -10
- package/src/tui/keyboard-protocol.mjs +2 -2
- package/src/tui/lib/voice-recorder.mjs +35 -19
- package/src/tui/markdown/format-token.mjs +11 -9
- package/src/tui/paste-attachments.mjs +38 -0
- package/src/tui/statusline-ansi-bridge.mjs +11 -3
- package/src/tui/theme.mjs +6 -0
- package/src/tui/themes/base.mjs +2 -2
- package/src/tui/themes/kanagawa.mjs +4 -4
- package/src/tui/themes/teal.mjs +4 -5
- package/src/tui/themes/utils.mjs +1 -1
- package/src/ui/statusline-agents.mjs +213 -0
- package/src/ui/statusline-format.mjs +146 -0
- package/src/ui/statusline-segments.mjs +148 -0
- package/src/ui/statusline.mjs +77 -462
- package/src/ui/tool-card.mjs +0 -1
- package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
- package/src/workflows/default/WORKFLOW.md +16 -9
- package/src/workflows/sequential/WORKFLOW.md +16 -11
- package/src/workflows/solo/WORKFLOW.md +5 -1
- package/vendor/ink/build/display-width.js +19 -3
- package/vendor/ink/build/ink.js +103 -6
- package/vendor/ink/build/log-update.js +17 -3
- package/vendor/ink/build/wrap-text.js +125 -0
- package/scripts/_test-folder-dialog.mjs +0 -30
- package/scripts/fix-brief-fn.mjs +0 -35
- package/scripts/fix-format-tool-surface.mjs +0 -24
- package/scripts/fix-tool-exec-visible.mjs +0 -42
- package/scripts/patch-agent-brief.mjs +0 -48
- package/scripts/patch-app.mjs +0 -21
- package/scripts/patch-app2.mjs +0 -18
- package/scripts/patch-dist-brief.mjs +0 -96
- package/scripts/patch-tool-exec.mjs +0 -70
- package/src/examples/schedules/SCHEDULE.example.md +0 -32
- package/src/examples/webhooks/WEBHOOK.example.md +0 -40
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
- package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
- package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
- package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
- package/src/standalone/agent-task-status.test.mjs +0 -76
- package/src/tui/components/tool-output-format.test.mjs +0 -399
- package/src/tui/display-width.test.mjs +0 -35
- package/src/tui/engine-runtime-notification.test.mjs +0 -115
- package/src/tui/engine-tool-result-text.test.mjs +0 -75
- package/src/tui/markdown/format-token.test.mjs +0 -354
- package/src/tui/markdown/render-ansi.test.mjs +0 -108
- package/src/tui/markdown/stream-fence.test.mjs +0 -26
- package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
- package/src/tui/prompt-history-store.test.mjs +0 -52
- package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
- package/src/tui/transcript-tool-failures.test.mjs +0 -111
- package/src/ui/markdown.test.mjs +0 -70
- package/src/ui/statusline-context-label.test.mjs +0 -15
- package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
- package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// Session tool schema resolution + permission narrowing, extracted verbatim
|
|
2
|
+
// from manager.mjs. Behavior-preserving: same toolset ids, same ordering,
|
|
3
|
+
// same dedup, same fail-closed permission intersection.
|
|
4
|
+
import { getMcpTools } from '../../mcp/client.mjs';
|
|
5
|
+
import { getInternalTools } from '../../internal-tools.mjs';
|
|
6
|
+
import { BUILTIN_TOOLS } from '../../tools/builtin/builtin-tools.mjs';
|
|
7
|
+
import { PATCH_TOOL_DEFS } from '../../tools/patch-tool-defs.mjs';
|
|
8
|
+
import { CODE_GRAPH_TOOL_DEFS } from '../../tools/code-graph-tool-defs.mjs';
|
|
9
|
+
import { buildSkillToolDefs } from '../../context/collect.mjs';
|
|
10
|
+
import { getHiddenAgent, listHiddenAgentNames } from '../../internal-agents.mjs';
|
|
11
|
+
|
|
12
|
+
// Merge externally-connected MCP tools with the plugin's in-process tools
|
|
13
|
+
// (registered by agent's toolExecutor adapter). Internal tools are exposed
|
|
14
|
+
// under their bare names — no mcp__ prefix, since the dispatcher in
|
|
15
|
+
// server.mjs handles them directly without a transport.
|
|
16
|
+
// Sorted deterministically by name — protects BP_1 hash stability from
|
|
17
|
+
// listTools() ordering churn. Anthropic / OpenAI / Gemini all hash the
|
|
18
|
+
// tools array verbatim, so any reorder rewrites the prefix.
|
|
19
|
+
// No cache: getMcpTools() and getInternalTools() are O(n) in-memory reads;
|
|
20
|
+
// the sort overhead on ~30 tools is negligible.
|
|
21
|
+
function _getMcpTools() {
|
|
22
|
+
const mcp = getMcpTools() || [];
|
|
23
|
+
const internalRaw = getInternalTools() || [];
|
|
24
|
+
const internal = internalRaw.map(t => ({
|
|
25
|
+
name: t.name,
|
|
26
|
+
description: typeof t.description === 'string' ? t.description : '',
|
|
27
|
+
inputSchema: t.inputSchema || { type: 'object', properties: {} },
|
|
28
|
+
// Keep annotations so the permission filter / role invariants can
|
|
29
|
+
// tell read-only from write-capable internal tools, and so
|
|
30
|
+
// agentHidden can be read during deny filtering.
|
|
31
|
+
annotations: t.annotations || {},
|
|
32
|
+
}));
|
|
33
|
+
return [...mcp, ...internal].sort((a, b) => {
|
|
34
|
+
const an = a?.name || '';
|
|
35
|
+
const bn = b?.name || '';
|
|
36
|
+
return an < bn ? -1 : an > bn ? 1 : 0;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const SESSION_ROUTE_TOOL_ORDER = [
|
|
41
|
+
'code_graph',
|
|
42
|
+
'find',
|
|
43
|
+
'glob',
|
|
44
|
+
'list',
|
|
45
|
+
'grep',
|
|
46
|
+
'read',
|
|
47
|
+
'apply_patch',
|
|
48
|
+
'shell',
|
|
49
|
+
'task',
|
|
50
|
+
];
|
|
51
|
+
const SESSION_ROUTE_TOOL_RANK = new Map(SESSION_ROUTE_TOOL_ORDER.map((name, index) => [name, index]));
|
|
52
|
+
const FILESYSTEM_TOOL_NAMES = new Set([
|
|
53
|
+
'code_graph',
|
|
54
|
+
'find',
|
|
55
|
+
'glob',
|
|
56
|
+
'list',
|
|
57
|
+
'grep',
|
|
58
|
+
'read',
|
|
59
|
+
'apply_patch',
|
|
60
|
+
]);
|
|
61
|
+
const READONLY_TOOL_NAMES = new Set([
|
|
62
|
+
'code_graph',
|
|
63
|
+
'find',
|
|
64
|
+
'glob',
|
|
65
|
+
'list',
|
|
66
|
+
'grep',
|
|
67
|
+
'read',
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
const AGENT_STRING_PERMISSION_READ_ALLOW = Object.freeze([
|
|
71
|
+
'code_graph',
|
|
72
|
+
'find',
|
|
73
|
+
'glob',
|
|
74
|
+
'list',
|
|
75
|
+
'grep',
|
|
76
|
+
'read',
|
|
77
|
+
'explore',
|
|
78
|
+
'search',
|
|
79
|
+
'web_fetch',
|
|
80
|
+
'Skill',
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
function stringToolPermissionAllowList(toolPermission) {
|
|
84
|
+
if (toolPermission === 'read') return AGENT_STRING_PERMISSION_READ_ALLOW;
|
|
85
|
+
if (toolPermission === 'read-write') return AGENT_STRING_PERMISSION_READ_WRITE_ALLOW;
|
|
86
|
+
if (toolPermission === 'none') return [];
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const AGENT_STRING_PERMISSION_READ_WRITE_ALLOW = Object.freeze([
|
|
91
|
+
'code_graph',
|
|
92
|
+
'find',
|
|
93
|
+
'glob',
|
|
94
|
+
'list',
|
|
95
|
+
'grep',
|
|
96
|
+
'read',
|
|
97
|
+
'apply_patch',
|
|
98
|
+
'explore',
|
|
99
|
+
'search',
|
|
100
|
+
'web_fetch',
|
|
101
|
+
'Skill',
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
export function applyToolPermissionNarrowing(tools, toolPermission, warnRole = null) {
|
|
105
|
+
if (toolPermission === 'none') return [];
|
|
106
|
+
const allowList = stringToolPermissionAllowList(toolPermission);
|
|
107
|
+
if (allowList) {
|
|
108
|
+
const allowSet = new Set(allowList.map((n) => String(n).toLowerCase()));
|
|
109
|
+
return tools.filter((t) => allowSet.has(String(t?.name || '').toLowerCase()));
|
|
110
|
+
}
|
|
111
|
+
if (toolPermission && typeof toolPermission === 'object') {
|
|
112
|
+
const allowSet = Array.isArray(toolPermission.allow) && toolPermission.allow.length > 0
|
|
113
|
+
? new Set(toolPermission.allow.map(n => String(n).toLowerCase()))
|
|
114
|
+
: null;
|
|
115
|
+
const denySet = Array.isArray(toolPermission.deny) && toolPermission.deny.length > 0
|
|
116
|
+
? new Set(toolPermission.deny.map(n => String(n).toLowerCase()))
|
|
117
|
+
: null;
|
|
118
|
+
if (allowSet || denySet) {
|
|
119
|
+
const filtered = tools.filter(t => {
|
|
120
|
+
const name = String(t?.name || '').toLowerCase();
|
|
121
|
+
if (denySet && denySet.has(name)) return false;
|
|
122
|
+
if (allowSet && !allowSet.has(name)) return false;
|
|
123
|
+
return true;
|
|
124
|
+
});
|
|
125
|
+
if (filtered.length === 0) {
|
|
126
|
+
process.stderr.write(`[session] WARN: role permission intersection produced 0 tools — failing closed (role=${warnRole || 'unknown'})\n`);
|
|
127
|
+
}
|
|
128
|
+
return filtered;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return tools;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function recursiveWrapperToolNameForPublicAgent(agent) {
|
|
135
|
+
if (!agent) return null;
|
|
136
|
+
const key = String(agent).trim();
|
|
137
|
+
if (key === 'explore') return 'explore';
|
|
138
|
+
for (const hiddenName of listHiddenAgentNames()) {
|
|
139
|
+
const def = getHiddenAgent(hiddenName);
|
|
140
|
+
const invokedBy = typeof def?.invokedBy === 'string' ? def.invokedBy.trim() : '';
|
|
141
|
+
if (hiddenName === key && invokedBy) return invokedBy;
|
|
142
|
+
if (invokedBy && invokedBy === key) return invokedBy;
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function finalizeSessionToolList(tools, {
|
|
148
|
+
schemaAllowedTools = null,
|
|
149
|
+
disallowedTools = null,
|
|
150
|
+
ownerIsAgent = false,
|
|
151
|
+
resolvedAgent = null,
|
|
152
|
+
} = {}) {
|
|
153
|
+
let out = Array.isArray(tools) ? tools : [];
|
|
154
|
+
const hasCallerAllow = Array.isArray(schemaAllowedTools);
|
|
155
|
+
if (hasCallerAllow) {
|
|
156
|
+
const allowSet = new Set(schemaAllowedTools.map(n => String(n).toLowerCase()));
|
|
157
|
+
out = out.filter(t => allowSet.has(String(t?.name || '').toLowerCase()));
|
|
158
|
+
}
|
|
159
|
+
const callerDeny = Array.isArray(disallowedTools) ? disallowedTools.map(n => String(n)) : [];
|
|
160
|
+
if (callerDeny.length) {
|
|
161
|
+
const denySet = new Set(callerDeny.map(n => n.toLowerCase()));
|
|
162
|
+
out = out.filter(t => !denySet.has(String(t?.name || '').toLowerCase()));
|
|
163
|
+
}
|
|
164
|
+
const recursiveDeny = ownerIsAgent ? recursiveWrapperToolNameForPublicAgent(resolvedAgent) : null;
|
|
165
|
+
if (recursiveDeny) {
|
|
166
|
+
const deny = recursiveDeny.toLowerCase();
|
|
167
|
+
out = out.filter(t => String(t?.name || '').toLowerCase() !== deny);
|
|
168
|
+
}
|
|
169
|
+
if (ownerIsAgent) {
|
|
170
|
+
out = out.filter(t => !t?.annotations?.agentHidden);
|
|
171
|
+
out = orderSessionTools(out);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function orderSessionTools(tools) {
|
|
177
|
+
return tools.map((tool, index) => ({ tool, index }))
|
|
178
|
+
.sort((a, b) => {
|
|
179
|
+
const ar = SESSION_ROUTE_TOOL_RANK.get(a.tool?.name) ?? 10_000;
|
|
180
|
+
const br = SESSION_ROUTE_TOOL_RANK.get(b.tool?.name) ?? 10_000;
|
|
181
|
+
if (ar !== br) return ar - br;
|
|
182
|
+
return a.index - b.index;
|
|
183
|
+
})
|
|
184
|
+
.map((entry) => entry.tool);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const ALL_BUILTIN_SESSION_TOOLS = orderSessionTools(_dedupByName([
|
|
188
|
+
...BUILTIN_TOOLS,
|
|
189
|
+
...PATCH_TOOL_DEFS,
|
|
190
|
+
...CODE_GRAPH_TOOL_DEFS,
|
|
191
|
+
]));
|
|
192
|
+
|
|
193
|
+
export function resolveSessionTools(toolSpec, skills, { ownerIsAgentSession = false } = {}) {
|
|
194
|
+
const mcp = _getMcpTools();
|
|
195
|
+
// Agent sessions freeze the skill meta-tool into the schema
|
|
196
|
+
// unconditionally — concrete skill resolution is cwd-scoped at tool-call
|
|
197
|
+
// time (loop.mjs), so the schema bytes stay bit-identical across roles /
|
|
198
|
+
// cwds and the provider cache shard does not fragment.
|
|
199
|
+
const skillTools = buildSkillToolDefs(skills, { ownerIsAgentSession });
|
|
200
|
+
return _computeBaseTools(toolSpec, mcp, skillTools);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function previewSessionTools(toolSpec, skills = [], options = {}) {
|
|
204
|
+
return resolveSessionTools(toolSpec, skills, options);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Dedup by name, first occurrence wins. BUILTIN_TOOLS is passed in ahead
|
|
208
|
+
// of the MCP-registered internal tools so plugin-side definitions take
|
|
209
|
+
// precedence when both surfaces declare the same name (e.g. read / grep / glob).
|
|
210
|
+
// Without this merge, Anthropic rejected the request with
|
|
211
|
+
// "tools: Tool names must be unique" and the orchestrator burned up to
|
|
212
|
+
// 20 iterations retrying before the final answer landed.
|
|
213
|
+
function _dedupByName(tools) {
|
|
214
|
+
const seen = new Map();
|
|
215
|
+
for (const t of tools) {
|
|
216
|
+
const n = t?.name;
|
|
217
|
+
if (!n || seen.has(n)) continue;
|
|
218
|
+
seen.set(n, t);
|
|
219
|
+
}
|
|
220
|
+
return [...seen.values()];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Agent visibility is declared per-tool via annotations.agentHidden.
|
|
224
|
+
// Tools with agentHidden:true are stripped from agent sessions at schema
|
|
225
|
+
// build time (see deny filtering below). No code-level name list needed.
|
|
226
|
+
|
|
227
|
+
function _computeBaseTools(toolSpec, mcp, skillTools) {
|
|
228
|
+
if (Array.isArray(toolSpec)) {
|
|
229
|
+
if (toolSpec.length === 0) {
|
|
230
|
+
// Explicit "no tools" — skill meta tools still travel so the model
|
|
231
|
+
// can at least discover and invoke skills if that is the one
|
|
232
|
+
// dynamic surface the profile retains.
|
|
233
|
+
return _dedupByName([...skillTools]);
|
|
234
|
+
}
|
|
235
|
+
if (toolSpec.includes('full')) {
|
|
236
|
+
return _dedupByName([...ALL_BUILTIN_SESSION_TOOLS, ...mcp, ...skillTools]);
|
|
237
|
+
}
|
|
238
|
+
const byName = new Map();
|
|
239
|
+
const add = (tool) => { if (tool?.name && !byName.has(tool.name)) byName.set(tool.name, tool); };
|
|
240
|
+
const addMany = (arr) => { for (const t of arr) add(t); };
|
|
241
|
+
for (const tagRaw of toolSpec) {
|
|
242
|
+
const tag = String(tagRaw || '').trim();
|
|
243
|
+
switch (tag) {
|
|
244
|
+
case 'tools:filesystem':
|
|
245
|
+
addMany(ALL_BUILTIN_SESSION_TOOLS.filter(t => FILESYSTEM_TOOL_NAMES.has(t.name)));
|
|
246
|
+
break;
|
|
247
|
+
case 'tools:readonly':
|
|
248
|
+
addMany(ALL_BUILTIN_SESSION_TOOLS.filter(t => READONLY_TOOL_NAMES.has(t.name)));
|
|
249
|
+
break;
|
|
250
|
+
case 'tools:shell':
|
|
251
|
+
case 'tools:git':
|
|
252
|
+
case 'tools:analysis':
|
|
253
|
+
// Shell-class toolset. `tools:git` / `tools:analysis` exist so
|
|
254
|
+
// profile authors can name the intent (git workflows / data
|
|
255
|
+
// analysis) without inventing new toolset ids.
|
|
256
|
+
addMany(ALL_BUILTIN_SESSION_TOOLS.filter(t => t.name === 'shell' || t.name === 'task'));
|
|
257
|
+
break;
|
|
258
|
+
case 'tools:mcp':
|
|
259
|
+
addMany(mcp);
|
|
260
|
+
break;
|
|
261
|
+
case 'tools:search':
|
|
262
|
+
// Name-pattern match: picks up `search` and any future tool
|
|
263
|
+
// whose name contains `search`. `recall` and `explore` deliberately do NOT match
|
|
264
|
+
// — they need `tools:mcp` (full mcp surface) or their own
|
|
265
|
+
// toolset id if a role wants targeted retrieval. Public agent
|
|
266
|
+
// roles never reach the wrapper bodies regardless: see the
|
|
267
|
+
// isBlockedPublicWrapperCall guard in session/loop.mjs.
|
|
268
|
+
addMany(mcp.filter(t => /search/i.test(t?.name || '')));
|
|
269
|
+
break;
|
|
270
|
+
default:
|
|
271
|
+
process.stderr.write(`[session] unknown toolset id "${tag}" (profile.tools); skipping\n`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return _dedupByName([...byName.values(), ...skillTools]);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
switch (toolSpec) {
|
|
278
|
+
case 'mcp':
|
|
279
|
+
return _dedupByName([...mcp, ...skillTools]);
|
|
280
|
+
case 'readonly': {
|
|
281
|
+
const readTools = ALL_BUILTIN_SESSION_TOOLS.filter(t => READONLY_TOOL_NAMES.has(t.name));
|
|
282
|
+
return _dedupByName([...readTools, ...mcp, ...skillTools]);
|
|
283
|
+
}
|
|
284
|
+
case 'full':
|
|
285
|
+
default:
|
|
286
|
+
return _dedupByName([...ALL_BUILTIN_SESSION_TOOLS, ...mcp, ...skillTools]);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function permissionFromToolSpec(toolSpec) {
|
|
291
|
+
if (toolSpec === 'readonly') return 'read';
|
|
292
|
+
if (toolSpec === 'mcp') return 'mcp';
|
|
293
|
+
if (Array.isArray(toolSpec)) {
|
|
294
|
+
const tags = new Set(toolSpec.map(t => String(t || '').trim()));
|
|
295
|
+
const hasWriteOrShell = tags.has('full')
|
|
296
|
+
|| tags.has('tools:filesystem')
|
|
297
|
+
|| tags.has('tools:shell')
|
|
298
|
+
|| tags.has('tools:git')
|
|
299
|
+
|| tags.has('tools:analysis');
|
|
300
|
+
if (tags.has('tools:readonly') && !hasWriteOrShell) return 'read';
|
|
301
|
+
}
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// Incremental + terminal usage-metrics accounting for sessions.
|
|
2
|
+
// Extracted verbatim from manager.mjs (behavior-preserving). Pure helpers plus
|
|
3
|
+
// per-session idempotency tracking for incremental usage persistence.
|
|
4
|
+
//
|
|
5
|
+
// Runtime coupling is injected: persistIterationMetrics needs the live
|
|
6
|
+
// _runtimeState map (owned by manager.mjs) to read the in-memory session and
|
|
7
|
+
// flag usageMetricsTurnIncremental. manager.mjs wires it via configureUsageMetricsRuntime().
|
|
8
|
+
import { providerInputExcludesCache } from '../../providers/registry.mjs';
|
|
9
|
+
import { loadSession, saveSessionAsync } from '../store.mjs';
|
|
10
|
+
|
|
11
|
+
// Per-session idempotency tracking: sessionId → Set of seen
|
|
12
|
+
// turn:epoch:iteration:source keys.
|
|
13
|
+
const _metricSeenIter = new Map();
|
|
14
|
+
|
|
15
|
+
// Injected accessor for manager's _runtimeState. Defaults to a no-op lookup so
|
|
16
|
+
// the pure helpers remain usable (and unit-testable) before wiring.
|
|
17
|
+
let _getRuntimeEntry = () => null;
|
|
18
|
+
|
|
19
|
+
/** Wire the live runtime-state accessor from manager.mjs. */
|
|
20
|
+
export function configureUsageMetricsRuntime({ getRuntimeEntry } = {}) {
|
|
21
|
+
if (typeof getRuntimeEntry === 'function') _getRuntimeEntry = getRuntimeEntry;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Drop the per-session metric-idempotency Set (called on session close). */
|
|
25
|
+
export function dropMetricSeenState(sessionId) {
|
|
26
|
+
if (sessionId) _metricSeenIter.delete(sessionId);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Monotonic per-session ask/turn id for incremental usage idempotency. */
|
|
30
|
+
export function bumpUsageMetricsTurnId(session) {
|
|
31
|
+
if (!session || typeof session !== 'object') return 0;
|
|
32
|
+
const next = (Number(session.usageMetricsTurnId) || 0) + 1;
|
|
33
|
+
session.usageMetricsTurnId = next;
|
|
34
|
+
return next;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function resolveUsageMetricsTurnId(session, delta = {}) {
|
|
38
|
+
if (delta.usageMetricsTurnId != null && Number.isFinite(Number(delta.usageMetricsTurnId))) {
|
|
39
|
+
return Number(delta.usageMetricsTurnId);
|
|
40
|
+
}
|
|
41
|
+
return Number(session?.usageMetricsTurnId) || 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Advance loop metrics epoch when agentLoop resets its iteration counter (post-compact). */
|
|
45
|
+
export function bumpUsageMetricsEpoch(session) {
|
|
46
|
+
if (!session || typeof session !== 'object') return 0;
|
|
47
|
+
const next = (Number(session.usageMetricsEpoch) || 0) + 1;
|
|
48
|
+
session.usageMetricsEpoch = next;
|
|
49
|
+
return next;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Resolve usage-metrics epoch for idempotency (exported for regression smoke).
|
|
54
|
+
* Prefers session.usageMetricsEpoch (bumped in loop on compact reset) and optional
|
|
55
|
+
* delta.usageMetricsEpoch; falls back to iteration regression when loop did not bump.
|
|
56
|
+
*/
|
|
57
|
+
export function resolveUsageMetricsEpoch(session, delta = {}) {
|
|
58
|
+
if (!session) return 0;
|
|
59
|
+
let epoch = Number(session.usageMetricsEpoch) || 0;
|
|
60
|
+
if (delta.usageMetricsEpoch != null && Number.isFinite(Number(delta.usageMetricsEpoch))) {
|
|
61
|
+
epoch = Math.max(epoch, Number(delta.usageMetricsEpoch));
|
|
62
|
+
}
|
|
63
|
+
const idx = Number(delta.iterationIndex);
|
|
64
|
+
const prevLastIdx = typeof session.lastIterationIndex === 'number'
|
|
65
|
+
? session.lastIterationIndex
|
|
66
|
+
: null;
|
|
67
|
+
if (
|
|
68
|
+
(delta.usageMetricsEpoch == null || !Number.isFinite(Number(delta.usageMetricsEpoch)))
|
|
69
|
+
&& prevLastIdx !== null
|
|
70
|
+
&& Number.isFinite(idx)
|
|
71
|
+
&& idx < prevLastIdx
|
|
72
|
+
) {
|
|
73
|
+
epoch += 1;
|
|
74
|
+
}
|
|
75
|
+
return epoch;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function usageMetricsSourceKey(delta = {}) {
|
|
79
|
+
const raw = delta.source ?? delta.usageSource;
|
|
80
|
+
if (raw == null || raw === '') return 'provider_send';
|
|
81
|
+
return String(raw);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Idempotency key for incremental usage persistence (exported for regression smoke). */
|
|
85
|
+
export function usageMetricsIdempotencyKey(sessionId, session, delta = {}) {
|
|
86
|
+
const turnId = resolveUsageMetricsTurnId(session, delta);
|
|
87
|
+
const epoch = resolveUsageMetricsEpoch(session, delta);
|
|
88
|
+
const source = usageMetricsSourceKey(delta);
|
|
89
|
+
return `${sessionId}:${turnId}:${epoch}:${delta.iterationIndex}:${source}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function uncachedInputTokensForProvider(provider, inputTokens, cachedReadTokens = 0, cacheWriteTokens = 0) {
|
|
93
|
+
const input = Number(inputTokens) || 0;
|
|
94
|
+
if (input <= 0) return 0;
|
|
95
|
+
// Anthropic-style providers report input_tokens excluding cache reads; OpenAI
|
|
96
|
+
// Responses/Gemini-style providers report input_tokens inclusive of cached
|
|
97
|
+
// prefix tokens. Keep both views so UI can show the real context footprint
|
|
98
|
+
// and the fresh/new token portion without mistaking cache hits for a cache
|
|
99
|
+
// break.
|
|
100
|
+
if (providerInputExcludesCache(provider)) return input + (Number(cacheWriteTokens) || 0);
|
|
101
|
+
return Math.max(input - (Number(cachedReadTokens) || 0) - (Number(cacheWriteTokens) || 0), 0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Apply terminal ask usage to session totals. Skips lifetime totals when incremental
|
|
106
|
+
* per-iteration persistence already counted this turn (askSession path).
|
|
107
|
+
*/
|
|
108
|
+
export function applyAskTerminalUsageTotals(session, result, options = {}) {
|
|
109
|
+
if (!session || !result?.usage) return;
|
|
110
|
+
const skipTotals = options.skipTotalsIfIncremental === true;
|
|
111
|
+
if (!skipTotals) {
|
|
112
|
+
const inputTokens = result.usage.inputTokens || 0;
|
|
113
|
+
const outputTokens = result.usage.outputTokens || 0;
|
|
114
|
+
const cachedTokens = result.usage.cachedTokens || 0;
|
|
115
|
+
const cacheWriteTokens = result.usage.cacheWriteTokens || 0;
|
|
116
|
+
const uncachedInputTokens = uncachedInputTokensForProvider(session.provider, inputTokens, cachedTokens, cacheWriteTokens);
|
|
117
|
+
session.totalInputTokens = (session.totalInputTokens || 0) + inputTokens;
|
|
118
|
+
session.totalOutputTokens = (session.totalOutputTokens || 0) + outputTokens;
|
|
119
|
+
session.tokensCumulative = (session.tokensCumulative || 0)
|
|
120
|
+
+ inputTokens
|
|
121
|
+
+ outputTokens;
|
|
122
|
+
session.totalCachedReadTokens = (session.totalCachedReadTokens || 0) + cachedTokens;
|
|
123
|
+
session.totalCacheWriteTokens = (session.totalCacheWriteTokens || 0) + cacheWriteTokens;
|
|
124
|
+
session.totalUncachedInputTokens = (session.totalUncachedInputTokens || 0) + uncachedInputTokens;
|
|
125
|
+
}
|
|
126
|
+
const _lastTurn = result.lastTurnUsage || result.usage || {};
|
|
127
|
+
const _lastInputTokens = _lastTurn.inputTokens || 0;
|
|
128
|
+
const _lastCachedReadTokens = _lastTurn.cachedTokens || 0;
|
|
129
|
+
const _lastCacheWriteTokens = _lastTurn.cacheWriteTokens || 0;
|
|
130
|
+
session.lastInputTokens = _lastInputTokens;
|
|
131
|
+
session.lastOutputTokens = _lastTurn.outputTokens || 0;
|
|
132
|
+
session.lastCachedReadTokens = _lastCachedReadTokens;
|
|
133
|
+
session.lastCacheWriteTokens = _lastCacheWriteTokens;
|
|
134
|
+
session.lastUncachedInputTokens = uncachedInputTokensForProvider(
|
|
135
|
+
session.provider,
|
|
136
|
+
_lastInputTokens,
|
|
137
|
+
_lastCachedReadTokens,
|
|
138
|
+
_lastCacheWriteTokens,
|
|
139
|
+
);
|
|
140
|
+
const _inputExcludesCache = providerInputExcludesCache(session.provider);
|
|
141
|
+
session.lastContextTokens = _inputExcludesCache
|
|
142
|
+
? _lastInputTokens + _lastCachedReadTokens + _lastCacheWriteTokens
|
|
143
|
+
: _lastInputTokens;
|
|
144
|
+
session.lastContextTokensUpdatedAt = Date.now();
|
|
145
|
+
session.lastContextTokensStaleAfterCompact = false;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Persist incremental usage delta immediately after each provider.send iteration.
|
|
150
|
+
* Idempotency key `sessionId:turnId:epoch:iterationIndex:source` scopes retries
|
|
151
|
+
* per ask, compaction epoch, iteration, and usage source.
|
|
152
|
+
*/
|
|
153
|
+
export async function persistIterationMetrics(delta) {
|
|
154
|
+
if (!delta || !delta.sessionId) return;
|
|
155
|
+
const { sessionId, iterationIndex, deltaInput, deltaOutput, deltaCachedRead, deltaCacheWrite, ts } = delta;
|
|
156
|
+
const runtimeEntry = _getRuntimeEntry(sessionId);
|
|
157
|
+
const session = runtimeEntry?.session ?? loadSession(sessionId);
|
|
158
|
+
if (!session || session.closed) return;
|
|
159
|
+
const epoch = resolveUsageMetricsEpoch(session, delta);
|
|
160
|
+
if (epoch !== (Number(session.usageMetricsEpoch) || 0)) {
|
|
161
|
+
session.usageMetricsEpoch = epoch;
|
|
162
|
+
}
|
|
163
|
+
let seen = _metricSeenIter.get(sessionId);
|
|
164
|
+
if (!seen) {
|
|
165
|
+
seen = new Set();
|
|
166
|
+
_metricSeenIter.set(sessionId, seen);
|
|
167
|
+
}
|
|
168
|
+
const ikey = usageMetricsIdempotencyKey(sessionId, session, delta);
|
|
169
|
+
const isReplay = seen.has(ikey);
|
|
170
|
+
seen.add(ikey);
|
|
171
|
+
if (!isReplay) {
|
|
172
|
+
if (runtimeEntry) runtimeEntry.usageMetricsTurnIncremental = true;
|
|
173
|
+
const deltaUncachedInput = delta.deltaUncachedInput != null
|
|
174
|
+
? Number(delta.deltaUncachedInput) || 0
|
|
175
|
+
: uncachedInputTokensForProvider(session.provider, deltaInput, deltaCachedRead, deltaCacheWrite);
|
|
176
|
+
session.totalInputTokens = (session.totalInputTokens || 0) + (deltaInput || 0);
|
|
177
|
+
session.totalOutputTokens = (session.totalOutputTokens || 0) + (deltaOutput || 0);
|
|
178
|
+
session.tokensCumulative = (session.tokensCumulative || 0) + (deltaInput || 0) + (deltaOutput || 0);
|
|
179
|
+
// Cache totals — additive fields, default 0 on legacy sessions; both
|
|
180
|
+
// are undefined-safe so the schema migrates lazily as new iterations
|
|
181
|
+
// land. Keeps live + terminal aggregates in lock-step (loop.mjs already
|
|
182
|
+
// includes cached_read / cache_write in its terminal usage rollup).
|
|
183
|
+
session.totalCachedReadTokens = (session.totalCachedReadTokens || 0) + (deltaCachedRead || 0);
|
|
184
|
+
session.totalCacheWriteTokens = (session.totalCacheWriteTokens || 0) + (deltaCacheWrite || 0);
|
|
185
|
+
session.totalUncachedInputTokens = (session.totalUncachedInputTokens || 0) + deltaUncachedInput;
|
|
186
|
+
// Window snapshot updated per iteration so agent type=list reflects the
|
|
187
|
+
// most-recent provider-reported input size even for short dispatches
|
|
188
|
+
// that finish before askSession's terminal save lands.
|
|
189
|
+
session.lastInputTokens = deltaInput || 0;
|
|
190
|
+
session.lastOutputTokens = deltaOutput || 0;
|
|
191
|
+
session.lastCachedReadTokens = deltaCachedRead || 0;
|
|
192
|
+
session.lastCacheWriteTokens = deltaCacheWrite || 0;
|
|
193
|
+
session.lastUncachedInputTokens = deltaUncachedInput;
|
|
194
|
+
// Normalized last-call context footprint: how many prompt tokens the
|
|
195
|
+
// model actually saw on the most-recent send, comparable ACROSS
|
|
196
|
+
// providers. Anthropic reports input_tokens EXCLUDING cache (cache_read
|
|
197
|
+
// is a separate field), so the cached portion must be added back to
|
|
198
|
+
// reflect real context size; openai/grok/gemini already fold cached
|
|
199
|
+
// tokens INTO the input count, so input alone is the footprint.
|
|
200
|
+
const _inputExcludesCache = providerInputExcludesCache(session.provider);
|
|
201
|
+
session.lastContextTokens = _inputExcludesCache
|
|
202
|
+
? (deltaInput || 0) + (deltaCachedRead || 0) + (deltaCacheWrite || 0)
|
|
203
|
+
: (deltaInput || 0);
|
|
204
|
+
session.lastContextTokensUpdatedAt = ts || Date.now();
|
|
205
|
+
session.lastContextTokensStaleAfterCompact = false;
|
|
206
|
+
}
|
|
207
|
+
session.lastIterationIndex = iterationIndex;
|
|
208
|
+
session.updatedAt = ts || Date.now();
|
|
209
|
+
await saveSessionAsync(session, { expectedGeneration: session.generation });
|
|
210
|
+
}
|