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
|
@@ -22,6 +22,9 @@ import {
|
|
|
22
22
|
} from './anthropic-effort.mjs';
|
|
23
23
|
import { normalizeContentForAnthropic } from './media-normalization.mjs';
|
|
24
24
|
import { enrichModels } from './model-catalog.mjs';
|
|
25
|
+
import { sanitizeModelList } from './model-list-sanitize.mjs';
|
|
26
|
+
import { makeModelCache } from './model-cache.mjs';
|
|
27
|
+
import { resolveAnthropicMaxTokens } from './anthropic-max-tokens.mjs';
|
|
25
28
|
import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
|
|
26
29
|
|
|
27
30
|
const require = createRequire(import.meta.url);
|
|
@@ -79,12 +82,30 @@ function resolveCacheTtls(opts) {
|
|
|
79
82
|
if (v === 'none') return null;
|
|
80
83
|
return fallback;
|
|
81
84
|
};
|
|
82
|
-
|
|
85
|
+
const resolved = {
|
|
83
86
|
tools: pick('tools', null),
|
|
84
87
|
system: pick('system', CACHE_TTL_STABLE),
|
|
85
88
|
tier3: pick('tier3', CACHE_TTL_STABLE),
|
|
86
89
|
messages: pick('messages', CACHE_TTL_STABLE),
|
|
87
90
|
};
|
|
91
|
+
// A partial cacheStrategy override (e.g. {system:'5m'} while tier3/
|
|
92
|
+
// messages default to '1h') can put a longer TTL after a shorter one in
|
|
93
|
+
// request order, which Anthropic rejects: 1h breakpoints must all appear
|
|
94
|
+
// before any 5m breakpoint. Normalize left-to-right in wire order
|
|
95
|
+
// (system -> tier3 -> messages; tools is emitted before system and is
|
|
96
|
+
// excluded from the run) so a later layer is downgraded to the earliest
|
|
97
|
+
// shorter TTL seen so far — never re-promoted. Layers set to null ('none')
|
|
98
|
+
// emit no breakpoint at all, so they neither violate nor constrain
|
|
99
|
+
// ordering and are skipped. Mirrors anthropic-oauth.mjs.
|
|
100
|
+
const ttlRank = (ttl) => (ttl === CACHE_TTL_STABLE ? 2 : 1); // 1h=2, 5m=1
|
|
101
|
+
let minRank = Infinity;
|
|
102
|
+
for (const layer of ['system', 'tier3', 'messages']) {
|
|
103
|
+
if (!resolved[layer]) continue;
|
|
104
|
+
const rank = ttlRank(resolved[layer]);
|
|
105
|
+
if (rank > minRank) resolved[layer] = CACHE_TTL_VOLATILE;
|
|
106
|
+
else minRank = rank;
|
|
107
|
+
}
|
|
108
|
+
return resolved;
|
|
88
109
|
}
|
|
89
110
|
|
|
90
111
|
function buildSystemBlocks(systemMsgs, systemTtl, tier3Ttl) {
|
|
@@ -100,10 +121,20 @@ function buildSystemBlocks(systemMsgs, systemTtl, tier3Ttl) {
|
|
|
100
121
|
}))
|
|
101
122
|
.filter(it => it.text)
|
|
102
123
|
: [];
|
|
124
|
+
// Anthropic caps cache_control breakpoints at 4 per request; defensively
|
|
125
|
+
// cap it here too so an unexpectedly large systemMsgs array can never
|
|
126
|
+
// mark more than 4 blocks (extras keep their text, just lose the
|
|
127
|
+
// cache_control breakpoint, not the block itself). Mirrors
|
|
128
|
+
// anthropic-oauth.mjs.
|
|
129
|
+
const MAX_SYSTEM_BREAKPOINTS = 4;
|
|
130
|
+
let bpCount = 0;
|
|
103
131
|
return items.map(it => {
|
|
104
132
|
const block = { type: 'text', text: it.text };
|
|
105
133
|
const ttl = it.tier === 'tier3' ? tier3Ttl : systemTtl;
|
|
106
|
-
if (ttl
|
|
134
|
+
if (ttl && bpCount < MAX_SYSTEM_BREAKPOINTS) {
|
|
135
|
+
block.cache_control = ttl;
|
|
136
|
+
bpCount++;
|
|
137
|
+
}
|
|
107
138
|
return block;
|
|
108
139
|
});
|
|
109
140
|
}
|
|
@@ -159,14 +190,49 @@ function _normalizeAnthropicModel(raw, provider = 'anthropic') {
|
|
|
159
190
|
}
|
|
160
191
|
// Family-based heuristic so new model ids (including custom user-configured
|
|
161
192
|
// ones) resolve a sensible max_tokens without requiring a code change.
|
|
193
|
+
// The API-key provider has no catalog cache of its own — it reads the same
|
|
194
|
+
// anthropic-oauth-models.json disk cache (read-only) that the OAuth provider
|
|
195
|
+
// maintains. Both providers hit the same Anthropic /v1/models catalog, so a
|
|
196
|
+
// per-model outputTokens entry is valid regardless of which auth path wrote
|
|
197
|
+
// it. If this provider is ever run standalone without the OAuth provider
|
|
198
|
+
// ever having populated the cache, loadSync() simply returns null and we
|
|
199
|
+
// fall through to the shared static heuristic in anthropic-max-tokens.mjs.
|
|
200
|
+
const ANTHROPIC_OAUTH_MODEL_CACHE_TTL_MS = 24 * 60 * 60_000;
|
|
201
|
+
const _sharedOAuthModelCache = makeModelCache({
|
|
202
|
+
fileName: 'anthropic-oauth-models.json',
|
|
203
|
+
ttlMs: ANTHROPIC_OAUTH_MODEL_CACHE_TTL_MS,
|
|
204
|
+
version: 1,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// In-memory mirror populated by this provider's own listModels() fetch.
|
|
208
|
+
// API-key-only installs never have the OAuth provider write the shared disk
|
|
209
|
+
// cache, so without this mirror catalog outputTokens would stay invisible to
|
|
210
|
+
// resolveMaxTokens until an OAuth session runs. listModels() results flow in
|
|
211
|
+
// here (memory only — the disk cache stays OAuth-owned/read-only for us).
|
|
212
|
+
let _apiKeyCatalogMirror = null;
|
|
213
|
+
|
|
214
|
+
function _catalogOutputTokensFromSharedCache(model) {
|
|
215
|
+
if (!model) return null;
|
|
216
|
+
try {
|
|
217
|
+
const models = Array.isArray(_apiKeyCatalogMirror)
|
|
218
|
+
? _apiKeyCatalogMirror
|
|
219
|
+
: _sharedOAuthModelCache.loadSync();
|
|
220
|
+
if (!Array.isArray(models)) return null;
|
|
221
|
+
const entry = models.find(m => m?.id === model);
|
|
222
|
+
const out = Number(entry?.outputTokens);
|
|
223
|
+
return Number.isFinite(out) && out > 0 ? out : null;
|
|
224
|
+
} catch {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
162
229
|
function resolveMaxTokens(model) {
|
|
163
|
-
|
|
164
|
-
if (id.includes('opus')) return 32768;
|
|
165
|
-
if (id.includes('sonnet')) return 16384;
|
|
166
|
-
if (id.includes('haiku')) return 8192;
|
|
167
|
-
return 8192;
|
|
230
|
+
return resolveAnthropicMaxTokens(model, { catalogLookup: _catalogOutputTokensFromSharedCache });
|
|
168
231
|
}
|
|
169
232
|
|
|
233
|
+
// Test-only escape hatch for scripts/anthropic-maxtokens-test.mjs.
|
|
234
|
+
export const _test = { resolveMaxTokens };
|
|
235
|
+
|
|
170
236
|
const MIN_THINKING_BUDGET = 1024;
|
|
171
237
|
const THINKING_OUTPUT_RESERVE = 1024;
|
|
172
238
|
|
|
@@ -464,8 +530,7 @@ export class AnthropicProvider {
|
|
|
464
530
|
const usedSlots = toolsBpUsed + systemBpUsed;
|
|
465
531
|
// Env override for BP strategy. ANTHROPIC_MSG_SLOTS=0 disables
|
|
466
532
|
// message caching entirely. Any value >=1 first marks the previous
|
|
467
|
-
// user text turn; a second free slot marks the tail.
|
|
468
|
-
// anthropic-oauth.mjs for twin parity.
|
|
533
|
+
// user text turn; a second free slot marks the tail.
|
|
469
534
|
const msgSlotsCap = Number.parseInt(process.env.ANTHROPIC_MSG_SLOTS, 10);
|
|
470
535
|
const defaultMsgSlots = Math.max(0, 4 - usedSlots);
|
|
471
536
|
const msgSlots = ttls.messages
|
|
@@ -825,7 +890,10 @@ export class AnthropicProvider {
|
|
|
825
890
|
const normalized = items
|
|
826
891
|
.map((m) => _normalizeAnthropicModel(m, this.name))
|
|
827
892
|
.filter(Boolean);
|
|
828
|
-
const enriched = await enrichModels(normalized);
|
|
893
|
+
const enriched = sanitizeModelList(await enrichModels(normalized), { provider: this.name });
|
|
894
|
+
// Feed the resolver-visible mirror so API-key-only installs get
|
|
895
|
+
// catalog outputTokens without depending on the OAuth disk cache.
|
|
896
|
+
if (enriched.length) _apiKeyCatalogMirror = enriched.slice();
|
|
829
897
|
return enriched.length ? enriched : MODELS;
|
|
830
898
|
}
|
|
831
899
|
catch (err) {
|
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { updateJsonAtomicSync } from '../../../shared/atomic-file.mjs';
|
|
4
4
|
import { resolvePluginData } from '../../../shared/plugin-paths.mjs';
|
|
5
5
|
import { getAgentApiKey, getOpenAIUsageSessionKey } from '../../../shared/config.mjs';
|
|
6
|
+
import { num, round } from './lib/usage-primitives.mjs';
|
|
6
7
|
|
|
7
8
|
const CACHE_FILE = 'api-usage-cache.json';
|
|
8
9
|
const LIVE_TTL_MS = 5 * 60_000;
|
|
@@ -10,19 +11,6 @@ const STALE_TTL_MS = 60 * 60_000;
|
|
|
10
11
|
const DISK_JSON_MEMORY_TTL_MS = 1000;
|
|
11
12
|
let diskJsonCache = { at: 0, file: '', value: null };
|
|
12
13
|
|
|
13
|
-
function num(value, fallback = null) {
|
|
14
|
-
if (value === null || value === undefined || value === '') return fallback;
|
|
15
|
-
const n = Number(value);
|
|
16
|
-
return Number.isFinite(n) ? n : fallback;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function round(value, digits = 4) {
|
|
20
|
-
const n = Number(value);
|
|
21
|
-
if (!Number.isFinite(n)) return null;
|
|
22
|
-
const scale = 10 ** digits;
|
|
23
|
-
return Math.round(n * scale) / scale;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
14
|
function cachePath() {
|
|
27
15
|
return join(resolvePluginData(), CACHE_FILE);
|
|
28
16
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* codex-client-meta.mjs — codex client identity headers for the OpenAI OAuth
|
|
3
|
+
* transports.
|
|
4
|
+
*
|
|
5
|
+
* codex-rs sends two client-identity headers on EVERY request including the
|
|
6
|
+
* WS handshake:
|
|
7
|
+
* - `User-Agent: codex_cli_rs/<version> (<os> <ver>; <arch>) <terminal>`
|
|
8
|
+
* (login/src/auth/default_client.rs get_codex_user_agent + default_headers)
|
|
9
|
+
* - `version: <CARGO_PKG_VERSION>` via the built-in provider http_headers
|
|
10
|
+
* (model-provider-info/src/lib.rs:339-343), merged into the WS handshake by
|
|
11
|
+
* merge_request_headers (codex-api/src/endpoint/responses_websocket.rs).
|
|
12
|
+
* The backend uses these for client gating (model catalog visibility measured
|
|
13
|
+
* 2026-07-03) and plausibly for x-codex-turn-state issuance / sticky
|
|
14
|
+
* cache-node routing, so mixdog mirrors both.
|
|
15
|
+
*/
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
|
|
18
|
+
// Offline fallback only; live value refreshes from npm (24h TTL, in-process).
|
|
19
|
+
export const CODEX_CLIENT_VERSION_FLOOR = '0.142.5';
|
|
20
|
+
const VERSION_TTL_MS = 24 * 60 * 60_000;
|
|
21
|
+
let _cache = { value: null, fetchedAt: 0 };
|
|
22
|
+
let _refreshInFlight = null;
|
|
23
|
+
|
|
24
|
+
async function _refresh() {
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetch('https://registry.npmjs.org/@openai/codex/latest', {
|
|
27
|
+
signal: AbortSignal.timeout(5_000),
|
|
28
|
+
});
|
|
29
|
+
if (res.ok) {
|
|
30
|
+
const j = await res.json();
|
|
31
|
+
const v = String(j?.version || '').trim();
|
|
32
|
+
if (/^\d+\.\d+\.\d+/.test(v)) {
|
|
33
|
+
_cache = { value: v, fetchedAt: Date.now() };
|
|
34
|
+
return v;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} catch { /* offline — keep floor */ }
|
|
38
|
+
_cache = { value: CODEX_CLIENT_VERSION_FLOOR, fetchedAt: Date.now() };
|
|
39
|
+
return CODEX_CLIENT_VERSION_FLOOR;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Sync accessor for hot request paths: returns the cached npm version when
|
|
44
|
+
* fresh, otherwise kicks a background refresh and returns the floor. The
|
|
45
|
+
* handshake must never await a registry fetch.
|
|
46
|
+
*/
|
|
47
|
+
export function codexClientVersionSync() {
|
|
48
|
+
if (_cache.value && Date.now() - _cache.fetchedAt < VERSION_TTL_MS) return _cache.value;
|
|
49
|
+
if (!_refreshInFlight) {
|
|
50
|
+
_refreshInFlight = _refresh().finally(() => { _refreshInFlight = null; });
|
|
51
|
+
}
|
|
52
|
+
return _cache.value || CODEX_CLIENT_VERSION_FLOOR;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function _osType() {
|
|
56
|
+
// codex os_info reports "Windows"/"Mac OS"/"Linux"; node os.type() gives
|
|
57
|
+
// Windows_NT/Darwin/Linux. Map to codex's vocabulary.
|
|
58
|
+
const t = os.type();
|
|
59
|
+
if (t === 'Windows_NT') return 'Windows';
|
|
60
|
+
if (t === 'Darwin') return 'Mac OS';
|
|
61
|
+
return t;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _arch() {
|
|
65
|
+
// codex reports rust-style arch tokens.
|
|
66
|
+
const a = os.arch();
|
|
67
|
+
if (a === 'x64') return 'x86_64';
|
|
68
|
+
if (a === 'arm64') return 'aarch64';
|
|
69
|
+
return a;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** codex_cli_rs/<version> (<os> <ver>; <arch>) <terminal> */
|
|
73
|
+
export function codexUserAgent() {
|
|
74
|
+
const terminal = String(process.env.TERM_PROGRAM || 'unknown').trim() || 'unknown';
|
|
75
|
+
return `codex_cli_rs/${codexClientVersionSync()} (${_osType()} ${os.release()}; ${_arch()}) ${terminal}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Bare version header value — codex built-in provider http_headers "version". */
|
|
79
|
+
export function codexVersionHeader() {
|
|
80
|
+
return codexClientVersionSync();
|
|
81
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gemini-cache.mjs — Gemini explicit cachedContents prefix accounting:
|
|
3
|
+
* token estimation, prefix hashing, the process-global cache registry
|
|
4
|
+
* (create de-dupe + prune), cache-state attach, usage resolution, and the
|
|
5
|
+
* cache trace writer.
|
|
6
|
+
*
|
|
7
|
+
* Extracted from gemini.mjs (no behavior change). Owns the module-level
|
|
8
|
+
* geminiGlobalCaches / geminiGlobalCacheCreates maps. gemini.mjs imports
|
|
9
|
+
* these helpers; no re-export needed (all names are internal to the
|
|
10
|
+
* provider — none were part of the module's external surface).
|
|
11
|
+
*/
|
|
12
|
+
import { traceHash, stableTraceStringify, summarizeTraceTools, traceTextShape } from './trace-utils.mjs';
|
|
13
|
+
|
|
14
|
+
function summarizeTracePart(part) {
|
|
15
|
+
if (!part || typeof part !== 'object') return { type: typeof part };
|
|
16
|
+
if ('text' in part) {
|
|
17
|
+
return { type: 'text', ...traceTextShape(part.text) };
|
|
18
|
+
}
|
|
19
|
+
if (part.functionCall) {
|
|
20
|
+
return {
|
|
21
|
+
type: 'functionCall',
|
|
22
|
+
name: part.functionCall.name || null,
|
|
23
|
+
argsHash: traceHash(stableTraceStringify(part.functionCall.args || {})),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (part.functionResponse) {
|
|
27
|
+
const response = part.functionResponse.response || {};
|
|
28
|
+
const responseShape = stableTraceStringify(response);
|
|
29
|
+
return {
|
|
30
|
+
type: 'functionResponse',
|
|
31
|
+
name: part.functionResponse.name || null,
|
|
32
|
+
responseChars: responseShape.length,
|
|
33
|
+
responseHash: traceHash(responseShape),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return { type: Object.keys(part).sort().join('|') || 'unknown' };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function summarizeTraceContents(contents) {
|
|
40
|
+
const summaries = (contents || []).map((content, index) => ({
|
|
41
|
+
index,
|
|
42
|
+
role: content?.role || null,
|
|
43
|
+
parts: Array.isArray(content?.parts) ? content.parts.map(summarizeTracePart) : [],
|
|
44
|
+
}));
|
|
45
|
+
if (summaries.length <= 12) return summaries;
|
|
46
|
+
return [
|
|
47
|
+
...summaries.slice(0, 8),
|
|
48
|
+
{ omittedTurns: summaries.length - 12 },
|
|
49
|
+
...summaries.slice(-4),
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Gemini cachedContents API rejects prefixes below the model-specific minimum
|
|
54
|
+
// (Gemini 2.0/2.5 = 2048 tokens, Gemini 3.x = 4096 tokens) with HTTP 400
|
|
55
|
+
// "Cached content is too small". Estimating chars/4 ≈ tokens lets us skip the
|
|
56
|
+
// roundtrip when the prefix cannot satisfy the invariant. Estimate undercount
|
|
57
|
+
// is harmless (we attempt and get the same 400 we would have skipped); overcount
|
|
58
|
+
// is harmless (we skip, fall back to implicit cache).
|
|
59
|
+
export function _estimateGeminiCacheTokens(systemInstruction, geminiTools, contents) {
|
|
60
|
+
let chars = 0;
|
|
61
|
+
if (typeof systemInstruction === 'string') chars += systemInstruction.length;
|
|
62
|
+
if (Array.isArray(geminiTools) && geminiTools.length) {
|
|
63
|
+
try { chars += JSON.stringify(geminiTools).length; } catch {}
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(contents) && contents.length > 1) {
|
|
66
|
+
for (let i = 0; i < contents.length - 1; i++) {
|
|
67
|
+
try { chars += JSON.stringify(contents[i]?.parts ?? '').length; } catch {}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return Math.ceil(chars / 4);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function _geminiCacheMinTokens(model) {
|
|
74
|
+
return /^gemini-3/i.test(String(model || '')) ? 4096 : 2048;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function _geminiCachePrefixCount(contents) {
|
|
78
|
+
return Array.isArray(contents) && contents.length > 1 ? contents.length - 1 : 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function _geminiCachePrefixContents(contents, prefixCount) {
|
|
82
|
+
if (!Array.isArray(contents) || prefixCount <= 0) return [];
|
|
83
|
+
return contents.slice(0, prefixCount).map(c => {
|
|
84
|
+
const r = c?.role;
|
|
85
|
+
const safeRole = (r === 'model' || r === 'user') ? r : 'user';
|
|
86
|
+
return {
|
|
87
|
+
role: safeRole,
|
|
88
|
+
parts: Array.isArray(c?.parts) ? c.parts : [],
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function _geminiCachePrefixHash({ model, systemInstruction, geminiTools, contents, prefixCount }) {
|
|
94
|
+
return traceHash(stableTraceStringify({
|
|
95
|
+
model: model || null,
|
|
96
|
+
systemInstruction: systemInstruction || '',
|
|
97
|
+
tools: geminiTools || [],
|
|
98
|
+
contents: _geminiCachePrefixContents(contents, prefixCount),
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const GEMINI_GLOBAL_CACHE_MIN_LIVE_MS = 6 * 60 * 1000;
|
|
103
|
+
export const GEMINI_GLOBAL_CACHE_MAX_ENTRIES = 128;
|
|
104
|
+
// Grace window before deleting a superseded cachedContents name (see the
|
|
105
|
+
// cross-session race note at the delete call site in gemini.mjs). Long enough
|
|
106
|
+
// that a concurrent session still mid-flight on the old name has time to finish.
|
|
107
|
+
export const GEMINI_GLOBAL_CACHE_DELETE_GRACE_MS = 2 * 60 * 1000;
|
|
108
|
+
export const geminiGlobalCaches = new Map();
|
|
109
|
+
export const geminiGlobalCacheCreates = new Map();
|
|
110
|
+
|
|
111
|
+
export function _geminiGlobalCacheKey({ apiKey, model, cachePrefixHash, cachePrefixContentCount }) {
|
|
112
|
+
return traceHash(stableTraceStringify({
|
|
113
|
+
apiKeyHash: traceHash(apiKey || ''),
|
|
114
|
+
model: model || null,
|
|
115
|
+
cachePrefixHash,
|
|
116
|
+
cachePrefixContentCount,
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function _pruneGeminiGlobalCaches(now = Date.now()) {
|
|
121
|
+
for (const [key, entry] of geminiGlobalCaches) {
|
|
122
|
+
if (!entry?.cacheName || Number(entry.cacheExpiresAt || 0) <= now) {
|
|
123
|
+
geminiGlobalCaches.delete(key);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
while (geminiGlobalCaches.size > GEMINI_GLOBAL_CACHE_MAX_ENTRIES) {
|
|
127
|
+
const oldest = geminiGlobalCaches.keys().next().value;
|
|
128
|
+
if (oldest === undefined) break;
|
|
129
|
+
geminiGlobalCaches.delete(oldest);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function _getGeminiGlobalCache(key, now = Date.now()) {
|
|
134
|
+
_pruneGeminiGlobalCaches(now);
|
|
135
|
+
const entry = geminiGlobalCaches.get(key);
|
|
136
|
+
if (!entry?.cacheName) return null;
|
|
137
|
+
if ((entry.cacheExpiresAt || 0) - now <= GEMINI_GLOBAL_CACHE_MIN_LIVE_MS) {
|
|
138
|
+
geminiGlobalCaches.delete(key);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
entry.lastUsedAt = now;
|
|
142
|
+
return entry;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function _setGeminiGlobalCache(key, entry) {
|
|
146
|
+
if (!key || !entry?.cacheName) return;
|
|
147
|
+
geminiGlobalCaches.set(key, {
|
|
148
|
+
...entry,
|
|
149
|
+
lastUsedAt: Date.now(),
|
|
150
|
+
});
|
|
151
|
+
_pruneGeminiGlobalCaches();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function _geminiGlobalCacheNameIsLive(cacheName, now = Date.now()) {
|
|
155
|
+
if (!cacheName) return false;
|
|
156
|
+
for (const entry of geminiGlobalCaches.values()) {
|
|
157
|
+
if (entry?.cacheName === cacheName && Number(entry.cacheExpiresAt || 0) > now) return true;
|
|
158
|
+
}
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function _attachGeminiCacheState(opts, entry, currentIter) {
|
|
163
|
+
if (!entry?.cacheName) return;
|
|
164
|
+
opts.providerState = {
|
|
165
|
+
...(opts.providerState || {}),
|
|
166
|
+
gemini: {
|
|
167
|
+
cacheName: entry.cacheName,
|
|
168
|
+
cacheCreatedAt: entry.cacheCreatedAt,
|
|
169
|
+
cacheCreatedAtIter: currentIter,
|
|
170
|
+
cacheExpiresAt: entry.cacheExpiresAt,
|
|
171
|
+
cacheModel: entry.cacheModel,
|
|
172
|
+
cacheTokenSize: entry.cacheTokenSize,
|
|
173
|
+
cachePrefixContentCount: entry.cachePrefixContentCount,
|
|
174
|
+
cachePrefixHash: entry.cachePrefixHash,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function _resolveGeminiCacheUsage({ usageMetadata, cachedContent, providerState }) {
|
|
180
|
+
const inputTokens = Number(usageMetadata?.promptTokenCount || usageMetadata?.totalTokenCount || 0) || 0;
|
|
181
|
+
const reportedCachedTokens = Number(usageMetadata?.cachedContentTokenCount || 0) || 0;
|
|
182
|
+
const cachedFallbackTokens = cachedContent
|
|
183
|
+
? Number(providerState?.gemini?.cacheTokenSize || 0) || 0
|
|
184
|
+
: 0;
|
|
185
|
+
const rawCachedTokens = reportedCachedTokens > 0 ? reportedCachedTokens : cachedFallbackTokens;
|
|
186
|
+
const cachedTokens = inputTokens > 0 ? Math.min(rawCachedTokens, inputTokens) : rawCachedTokens;
|
|
187
|
+
const cacheTokenSource = reportedCachedTokens > 0
|
|
188
|
+
? 'usage_metadata'
|
|
189
|
+
: (cachedFallbackTokens > 0 ? 'cache_create_fallback' : 'none');
|
|
190
|
+
return {
|
|
191
|
+
inputTokens,
|
|
192
|
+
reportedCachedTokens,
|
|
193
|
+
cachedFallbackTokens,
|
|
194
|
+
cachedTokens,
|
|
195
|
+
cacheTokenSource,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function writeGeminiCacheTrace({ opts, model, systemInstruction, tools, contents, usageMetadata, cachedContent }) {
|
|
200
|
+
if (process.env.MIXDOG_GEMINI_CACHE_TRACE !== '1') return;
|
|
201
|
+
try {
|
|
202
|
+
const session = opts?.session || {};
|
|
203
|
+
const {
|
|
204
|
+
inputTokens,
|
|
205
|
+
reportedCachedTokens,
|
|
206
|
+
cachedFallbackTokens,
|
|
207
|
+
cachedTokens,
|
|
208
|
+
cacheTokenSource,
|
|
209
|
+
} = _resolveGeminiCacheUsage({
|
|
210
|
+
usageMetadata,
|
|
211
|
+
cachedContent,
|
|
212
|
+
providerState: opts?.providerState,
|
|
213
|
+
});
|
|
214
|
+
const toolShape = summarizeTraceTools(tools);
|
|
215
|
+
const trace = {
|
|
216
|
+
event: 'generate',
|
|
217
|
+
provider: 'gemini',
|
|
218
|
+
model,
|
|
219
|
+
owner: session.owner || null,
|
|
220
|
+
agent: session.agent || null,
|
|
221
|
+
permission: session.permission || null,
|
|
222
|
+
toolPermission: session.toolPermission || null,
|
|
223
|
+
profileId: session.profileId || null,
|
|
224
|
+
sourceType: session.sourceType || null,
|
|
225
|
+
sourceName: session.sourceName || null,
|
|
226
|
+
sessionIdHash: opts?.sessionId ? traceHash(opts.sessionId) : null,
|
|
227
|
+
providerCacheKeyHash: opts?.providerCacheKey ? traceHash(opts.providerCacheKey) : null,
|
|
228
|
+
promptCacheKeyHash: opts?.promptCacheKey ? traceHash(opts.promptCacheKey) : null,
|
|
229
|
+
systemChars: systemInstruction ? systemInstruction.length : 0,
|
|
230
|
+
systemHash: systemInstruction ? traceHash(systemInstruction) : null,
|
|
231
|
+
toolCount: Array.isArray(tools) ? tools.length : 0,
|
|
232
|
+
toolSchemaHash: traceHash(stableTraceStringify(toolShape)),
|
|
233
|
+
contentTurnCount: Array.isArray(contents) ? contents.length : 0,
|
|
234
|
+
contents: summarizeTraceContents(contents),
|
|
235
|
+
inputTokens,
|
|
236
|
+
cachedTokens,
|
|
237
|
+
reportedCachedTokens,
|
|
238
|
+
cachedFallbackTokens,
|
|
239
|
+
cacheTokenSource,
|
|
240
|
+
cacheAttached: !!cachedContent,
|
|
241
|
+
cachePrefixContentCount: opts?.providerState?.gemini?.cachePrefixContentCount ?? null,
|
|
242
|
+
cacheHitRate: inputTokens > 0 ? Number((cachedTokens / inputTokens).toFixed(6)) : null,
|
|
243
|
+
};
|
|
244
|
+
process.stderr.write(`[gemini-cache-trace] ${JSON.stringify(trace)}\n`);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
process.stderr.write(`[gemini-cache-trace] failed: ${err?.message || err}\n`);
|
|
247
|
+
}
|
|
248
|
+
}
|