mixdog 1.0.12 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -182
- package/package.json +4 -2
- package/scripts/build-shipped-history.mjs +131 -0
- package/scripts/latest-guard.mjs +63 -0
- package/scripts/lib/run-node-tests.mjs +330 -32
- package/scripts/lib/test-failure-records.mjs +5 -0
- package/scripts/lib/test-failure-summary.mjs +14 -3
- package/scripts/lib/test-spawn-ledger.mjs +19 -0
- package/scripts/merge-mac-update-feed.mjs +107 -0
- package/scripts/mobile-release.mjs +210 -0
- package/scripts/post-release-check.mjs +353 -0
- package/scripts/prune-embedding-runtime.mjs +9 -5
- package/scripts/publish-asset-release.mjs +43 -0
- package/scripts/release-guard.mjs +63 -0
- package/scripts/test-direct.mjs +16 -1
- package/scripts/test.mjs +29 -7
- package/src/agents/advisor/AGENT.md +38 -0
- package/src/agents/advisor/agent.json +6 -0
- package/src/agents/reviewer/AGENT.md +5 -2
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +383 -0
- package/src/defaults/skills/computer-use/SKILL.md +1 -1
- package/src/defaults/skills/goal-management/SKILL.md +11 -5
- package/src/defaults/skills/setup/SKILL.md +5 -8
- package/src/defaults/skills/setup/references/actions.md +62 -31
- package/src/defaults/skills/setup/references/surfaces.md +12 -10
- package/src/lib/keychain-cjs.cjs +582 -17
- package/src/lib/rules-builder.cjs +1 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.d.mts +1 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +44 -0
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +9 -1
- package/src/runtime/agent/orchestrator/config-storage.mjs +32 -4
- package/src/runtime/agent/orchestrator/config.mjs +120 -21
- package/src/runtime/agent/orchestrator/context/instruction-files.mjs +130 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +77 -26
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +44 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +92 -109
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +107 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +51 -9
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/open-login-url.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +254 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +218 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-tokens.mjs +239 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +233 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-login.mjs +247 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth-tokens.mjs +225 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +542 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +18 -10
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +51 -11
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +7 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +37 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +12 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog-store.mjs +99 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-catalog.mjs +4 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +3 -7
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +70 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +42 -3
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +19 -35
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +7 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +0 -17
- package/src/runtime/agent/orchestrator/runtime-core/goal-state.mjs +0 -3
- package/src/runtime/agent/orchestrator/runtime-core/goal-store.mjs +0 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-text.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-defs.mjs +16 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +18 -4
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -1
- package/src/runtime/agent/orchestrator/runtime-core/session-route-policy.mjs +16 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +2 -2
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +7 -7
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +28 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-call-ids.mjs +90 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +19 -11
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +24 -11
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +2 -6
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +63 -3
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/turn-effort.mjs +18 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +0 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +11 -8
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +27 -12
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +245 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +13 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +49 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +9 -7
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +19 -20
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +67 -19
- package/src/runtime/agent/orchestrator/tools/builtin/file-version-test-helpers.mjs +11 -0
- package/src/runtime/agent/orchestrator/tools/builtin/file-version.mjs +13 -0
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +28 -3
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-single-file-rescue.mjs +8 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +25 -12
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +73 -1
- package/src/runtime/agent/orchestrator/tools/builtin/raw-content-publication.mjs +17 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +136 -76
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +15 -17
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +11 -10
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +30 -16
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +17 -6
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +23 -5
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +93 -43
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +4 -11
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +7 -3
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-validation.mjs +16 -19
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +32 -6
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +9 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +14 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +58 -8
- package/src/runtime/agent/orchestrator/tools/patch/content-guard.mjs +47 -0
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +155 -0
- package/src/runtime/agent/orchestrator/tools/patch/dispatch/native-proofs.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/dispatch/native-snapshots.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +19 -16
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +13 -44
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/post-patch-excerpts.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +47 -7
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +72 -8
- package/src/runtime/agent/orchestrator/tools/patch/section-coalesce.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/patch/sequence/run.mjs +9 -1
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +9 -1
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +16 -4
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +35 -14
- package/src/runtime/agent/orchestrator/tools/patch/wave.mjs +42 -4
- package/src/runtime/agent/orchestrator/tools/shell-codepage.mjs +296 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +124 -81
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +75 -24
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +19 -4
- package/src/runtime/channels/lib/config.mjs +3 -8
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +7 -3
- package/src/{tui → runtime/channels}/lib/voice-setup.mjs +38 -22
- package/src/runtime/channels/lib/webhook/request-handler.mjs +42 -8
- package/src/runtime/computer-bridge/actions.mjs +2 -0
- package/src/runtime/computer-bridge/client.mjs +25 -1
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +84 -0
- package/src/runtime/computer-bridge/linux-readiness.d.mts +52 -0
- package/src/runtime/computer-bridge/linux-readiness.mjs +411 -0
- package/src/runtime/computer-bridge/test-linux-display.mjs +5 -0
- package/src/runtime/effort-judge/compact-tokenizer.mjs +13 -8
- package/src/runtime/effort-judge/judge-client.mjs +12 -3
- package/src/runtime/effort-judge/judge-input.mjs +5 -2
- package/src/runtime/effort-judge/model-install.mjs +9 -3
- package/src/runtime/effort-judge/model-manifest.json +8 -8
- package/src/runtime/effort-judge/previous-human-request.mjs +162 -0
- package/src/runtime/effort-judge/verified-context-input.mjs +10 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +12 -0
- package/src/runtime/memory/lib/embedding-worker.mjs +9 -3
- package/src/runtime/memory/lib/http-router/session-routes.mjs +2 -1
- package/src/runtime/memory/lib/memory-config-flags.mjs +3 -2
- package/src/runtime/memory/lib/memory-embed.mjs +5 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +3 -0
- package/src/runtime/shared/agent-route-config.mjs +50 -2
- package/src/runtime/shared/bounded-file-read.mjs +166 -0
- package/src/runtime/shared/builtin-grandfathering.mjs +37 -0
- package/src/runtime/shared/config.mjs +74 -6
- package/src/runtime/shared/defaults-separation.mjs +263 -0
- package/src/runtime/shared/developer-options.mjs +7 -0
- package/src/runtime/shared/instruction-files-mode.mjs +9 -0
- package/src/runtime/shared/llm/anthropic-effort.mjs +4 -0
- package/src/runtime/shared/llm/model-catalog.mjs +25 -1
- package/src/runtime/shared/llm/openai-daybreak.mjs +79 -0
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +105 -1
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +2 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +72 -5
- package/src/runtime/shared/onnx-runtime-support.mjs +6 -0
- package/src/runtime/shared/orchestration.mjs +14 -6
- package/src/runtime/shared/pristine-execution-contract.json +9 -0
- package/src/runtime/shared/pristine-execution.mjs +1 -1
- package/src/runtime/shared/projects.mjs +65 -48
- package/src/runtime/shared/provider-accounts.mjs +49 -6
- package/src/runtime/shared/quota-resume-store.mjs +255 -0
- package/src/runtime/shared/resource-admission.mjs +10 -3
- package/src/runtime/shared/schedule-model-ref.mjs +11 -0
- package/src/runtime/shared/session-approval-wait.mjs +35 -0
- package/src/runtime/shared/shell-display.mjs +4 -2
- package/src/runtime/shared/shipped-definitions.mjs +275 -0
- package/src/runtime/shared/tool-card-model.golden.json +3 -3
- package/src/runtime/shared/tool-result-summary.mjs +86 -15
- package/src/runtime/shared/transcript-metadata.mjs +2 -0
- package/src/runtime/shared/turn-review-reply.mjs +2 -0
- package/src/runtime/shared/turn-snapshot.mjs +65 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +208 -27
- package/src/session-runtime/boot/apis.mjs +24 -0
- package/src/session-runtime/boot/config.mjs +4 -0
- package/src/session-runtime/boot/facade.mjs +4 -1
- package/src/session-runtime/boot/infrastructure.mjs +21 -2
- package/src/session-runtime/boot/session.mjs +3 -0
- package/src/session-runtime/channel-config-api.mjs +5 -0
- package/src/session-runtime/config-lifecycle/config-writers.mjs +3 -0
- package/src/session-runtime/config-lifecycle.mjs +31 -6
- package/src/session-runtime/goal-facade-api.mjs +4 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +28 -6
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +3 -0
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +7 -1
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +6 -0
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +14 -2
- package/src/session-runtime/media-api.mjs +32 -22
- package/src/session-runtime/model-recency.mjs +17 -0
- package/src/session-runtime/model-route/route-tuning.mjs +3 -5
- package/src/session-runtime/model-route/set-route.mjs +49 -21
- package/src/session-runtime/model-route-api.mjs +2 -1
- package/src/session-runtime/notification-bus.mjs +31 -6
- package/src/session-runtime/provider-auth/login.mjs +16 -10
- package/src/session-runtime/provider-auth/setup.mjs +22 -2
- package/src/session-runtime/provider-models/catalog-load.mjs +3 -1
- package/src/session-runtime/provider-models/row-hydration.mjs +26 -17
- package/src/session-runtime/provider-readiness.mjs +4 -0
- package/src/session-runtime/quick-model-rows/model-meta.mjs +26 -0
- package/src/session-runtime/quick-model-rows/provider-rows.mjs +40 -14
- package/src/session-runtime/resource-api.mjs +8 -1
- package/src/session-runtime/runtime-core.mjs +4 -0
- package/src/session-runtime/runtime-facade.mjs +25 -1
- package/src/session-runtime/runtime-review-api.mjs +12 -1
- package/src/session-runtime/schedule-session-run.mjs +3 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +4 -0
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +63 -27
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +15 -3
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +11 -3
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/approval-wait.mjs +97 -0
- package/src/session-runtime/services/agent-tool/worker-index/mutation-batch.mjs +4 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +3 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +58 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +69 -15
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +2 -0
- package/src/session-runtime/services/channel-admin.mjs +91 -15
- package/src/session-runtime/services/provider-admin.mjs +336 -80
- package/src/session-runtime/services/seeds.mjs +80 -152
- package/src/session-runtime/services/usage-dashboard-model.mjs +35 -0
- package/src/session-runtime/services/usage-dashboard.mjs +7 -0
- package/src/session-runtime/session-address.mjs +125 -0
- package/src/session-runtime/session-create.mjs +57 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +23 -0
- package/src/session-runtime/settings-compaction-api.mjs +13 -0
- package/src/session-runtime/setup-tool/executor.mjs +97 -40
- package/src/session-runtime/setup-tool/extended-actions.mjs +64 -5
- package/src/session-runtime/setup-tool/settings-contract.mjs +44 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -7
- package/src/session-runtime/tool-policy-refresh.mjs +3 -0
- package/src/session-runtime/tool-surface.mjs +16 -9
- package/src/session-runtime/turn/session-ops.mjs +3 -0
- package/src/session-runtime/turn/share-ops.mjs +4 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +6 -0
- package/src/session-runtime/usage-stats-api.mjs +15 -0
- package/src/session-runtime/webhook-session-run.mjs +3 -1
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +31 -5
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +4 -0
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +27 -7
- package/src/standalone/daemon-boot-coordinator.mjs +10 -0
- package/src/standalone/daemon-drain-policy.mjs +9 -0
- package/src/standalone/daemon-stored-session-views.mjs +7 -8
- package/src/standalone/daemon.mjs +21 -5
- package/src/standalone/local-session-runtime.mjs +11 -0
- package/src/standalone/session-client.mjs +52 -7
- package/src/standalone/session-protocol.mjs +9 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +2 -0
- package/src/standalone/session-service/entries/lifecycle.mjs +2 -0
- package/src/standalone/session-service/entries/session-loads.mjs +9 -0
- package/src/standalone/session-service/projection/revisions.mjs +28 -4
- package/src/standalone/session-service/projection.mjs +1 -0
- package/src/standalone/session-service/quota-resume.mjs +140 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +2 -2
- package/src/standalone/session-service/session-calls.mjs +10 -2
- package/src/standalone/session-service/stored-reader.mjs +26 -1
- package/src/standalone/session-service.mjs +21 -0
- package/src/standalone/session-transport/routes.mjs +2 -0
- package/src/tui/app/doctor.mjs +7 -11
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +3 -5
- package/src/tui/app/model-options.mjs +13 -1
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +10 -4
- package/src/tui/app/provider-setup/oauth-actions.mjs +5 -0
- package/src/tui/app/settings-picker/settings-rows.mjs +4 -6
- package/src/tui/app/settings-picker/settings-toggles/store-toggles.mjs +1 -1
- package/src/tui/app/slash-dispatch/route-commands.mjs +3 -2
- package/src/tui/components/ContextPanel.jsx +5 -1
- package/src/tui/components/Spinner.jsx +34 -319
- package/src/tui/components/SpinnerByline.jsx +256 -0
- package/src/tui/components/use-spinner-progress.mjs +113 -0
- package/src/tui/dist/index.mjs +15421 -14283
- package/src/tui/session/agent-job-feed/execution-delivery.mjs +13 -1
- package/src/tui/session/agent-job-feed/notification-router.mjs +3 -0
- package/src/tui/session/agent-job-feed/pending-resume.mjs +14 -1
- package/src/tui/session/agent-job-feed.mjs +4 -0
- package/src/tui/session/context-state.mjs +15 -1
- package/src/tui/session/initial-state.mjs +6 -0
- package/src/tui/session/live-share/owner.mjs +17 -0
- package/src/tui/session/oauth-flows.mjs +2 -0
- package/src/tui/session/quota-resume.mjs +263 -0
- package/src/tui/session/session-api/intake/abort.mjs +39 -35
- package/src/tui/session/session-api/intake/submission.mjs +13 -21
- package/src/tui/session/session-api/intake.mjs +3 -3
- package/src/tui/session/session-api/integrations.mjs +13 -9
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle/inheritance.mjs +2 -2
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +4 -0
- package/src/tui/session/session-api/lifecycle.mjs +71 -2
- package/src/tui/session/session-api/media.mjs +2 -2
- package/src/tui/session/session-api/quota-resume.mjs +21 -0
- package/src/tui/session/session-api/routes.mjs +4 -2
- package/src/tui/session/session-api/settings.mjs +2 -0
- package/src/tui/session/session-api.mjs +2 -0
- package/src/tui/session/session-flow/auto-clear.mjs +14 -6
- package/src/tui/session/session-flow/drain.mjs +52 -5
- package/src/tui/session/session-flow/queue/take-entries.mjs +2 -3
- package/src/tui/session/session-flow/queue.mjs +3 -0
- package/src/tui/session/session-flow/steering.mjs +11 -0
- package/src/tui/session/session-flow.mjs +1 -0
- package/src/tui/session/tool-approval.mjs +7 -2
- package/src/tui/session/tool-card-results/grouped-result.mjs +11 -2
- package/src/tui/session/transcript-intake.mjs +1 -0
- package/src/tui/session/transcript-spill/spill-dir.mjs +22 -6
- package/src/tui/session/turn.mjs +40 -3
- package/src/tui/spinner-meta.mjs +26 -10
- package/src/vendor/statusline/bin/statusline-route.mjs +3 -2
|
@@ -44,6 +44,10 @@ export function createGoalFacadeApi({ agentStatusState, createCurrentSession, ge
|
|
|
44
44
|
const sessionId = getSessionId();
|
|
45
45
|
return sessionId ? goalRuntime.settleTurn(sessionId, detail) : null;
|
|
46
46
|
},
|
|
47
|
+
reactivateUsageLimitedGoal(goalId) {
|
|
48
|
+
const sessionId = getSessionId();
|
|
49
|
+
return sessionId ? goalRuntime.reactivateUsageLimited(sessionId, goalId) : null;
|
|
50
|
+
},
|
|
47
51
|
archiveCompletedGoalOnUserInput() {
|
|
48
52
|
const sessionId = getSessionId();
|
|
49
53
|
return sessionId ? goalRuntime.archiveCompletedOnUserInput(sessionId) : null;
|
|
@@ -23,15 +23,23 @@ export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
|
23
23
|
* budget, and no mutation of either session. Returns the conversation to
|
|
24
24
|
* carry, or null when the route has no boundary to compact toward.
|
|
25
25
|
*/
|
|
26
|
-
async function compactConversationForHeir(source, target) {
|
|
26
|
+
async function compactConversationForHeir(source, target, { summarize = false } = {}) {
|
|
27
27
|
const plan = inheritanceCompactionPlan(target);
|
|
28
28
|
if (!plan) return null;
|
|
29
29
|
// The compactor sees the whole transcript — system blocks included — so it
|
|
30
30
|
// preserves the protected head and the recent tail exactly as /compact
|
|
31
31
|
// does. Only the conversation half of the result travels.
|
|
32
32
|
const messages = structuredClone(Array.isArray(source.messages) ? source.messages : []);
|
|
33
|
+
// The compactor writes a model summary only once the conversation passes
|
|
34
|
+
// its size threshold; below it, it trims by rules and the transcript comes
|
|
35
|
+
// back nearly whole. An explicitly chosen compacted carry must summarize
|
|
36
|
+
// whatever its size, so the compactor gets a COPY of the source whose
|
|
37
|
+
// threshold is the floor — the source session itself is left untouched.
|
|
38
|
+
const compactSource = summarize
|
|
39
|
+
? { ...source, compaction: { ...source.compaction, conversationThresholdTokens: 1 } }
|
|
40
|
+
: source;
|
|
33
41
|
const result = await compactConversation({
|
|
34
|
-
session:
|
|
42
|
+
session: compactSource,
|
|
35
43
|
messages,
|
|
36
44
|
...plan,
|
|
37
45
|
// Memory ingest belongs to the session that HELD the conversation; the
|
|
@@ -46,17 +54,26 @@ export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
|
46
54
|
// instead of sending the user away to run /compact by hand. The compaction
|
|
47
55
|
// is sized for the HEIR and runs on a copy, so the source session keeps
|
|
48
56
|
// every message it has.
|
|
49
|
-
|
|
57
|
+
// `required`: the user explicitly chose a compacted carry. Then a compaction
|
|
58
|
+
// that cannot run (or yields nothing) is a refusal even when the original
|
|
59
|
+
// would fit — silently carrying the full conversation would answer a
|
|
60
|
+
// different request than the one made.
|
|
61
|
+
async function fitConversationForHeir(source, target, carried, fit, { required = false } = {}) {
|
|
50
62
|
let compactionFault = null;
|
|
51
63
|
let compacted = null;
|
|
52
64
|
try {
|
|
53
|
-
compacted = await compactConversationForHeir(source, target);
|
|
65
|
+
compacted = await compactConversationForHeir(source, target, { summarize: required });
|
|
54
66
|
} catch (reason) {
|
|
55
67
|
// A compaction that cannot run is a refusal, not a half-carry: the
|
|
56
68
|
// user reads the same measured sentence they would have read without
|
|
57
69
|
// the attempt, and the engine fault travels along as its cause.
|
|
58
70
|
compactionFault = reason;
|
|
59
71
|
}
|
|
72
|
+
if (required && !compacted) {
|
|
73
|
+
const refusal = new Error('inheritFrom: the conversation could not be compacted for the new session');
|
|
74
|
+
if (compactionFault) refusal.cause = compactionFault;
|
|
75
|
+
throw refusal;
|
|
76
|
+
}
|
|
60
77
|
let next = carried;
|
|
61
78
|
let nextFit = fit;
|
|
62
79
|
if (compacted) {
|
|
@@ -138,7 +155,8 @@ export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
|
138
155
|
* The target must still be empty: interleaving two transcripts would
|
|
139
156
|
* produce a conversation neither model ever had.
|
|
140
157
|
*/
|
|
141
|
-
async function inheritFrom(sourceSessionId) {
|
|
158
|
+
async function inheritFrom(sourceSessionId, options = null) {
|
|
159
|
+
const compact = options?.compact === true;
|
|
142
160
|
const id = clean(sourceSessionId);
|
|
143
161
|
if (!id) throw new TypeError('inheritFrom: source session id is required');
|
|
144
162
|
// A daemon-created heir is still only RESERVED when the desktop calls
|
|
@@ -168,7 +186,11 @@ export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
|
168
186
|
// offered the carry and the runtime that performs it cannot disagree —
|
|
169
187
|
// and a refusal no longer has to unwind a half-filled transcript.
|
|
170
188
|
const fit = inheritanceFit(carried, target);
|
|
171
|
-
|
|
189
|
+
// compact:true summarizes even a conversation that fits; otherwise only
|
|
190
|
+
// one that cannot fit is compacted.
|
|
191
|
+
if (compact || (fit.known && !fit.fits)) {
|
|
192
|
+
carried = await fitConversationForHeir(source, target, carried, fit, { required: compact });
|
|
193
|
+
}
|
|
172
194
|
target.messages.push(
|
|
173
195
|
...stripEffortConfiguration(inheritedCompatReplayMessages(structuredClone(carried), source.provider))
|
|
174
196
|
);
|
|
@@ -21,6 +21,8 @@ export function createContextSwitch(deps, { ingestSessionIntoMemory, closeSurfac
|
|
|
21
21
|
} = deps;
|
|
22
22
|
|
|
23
23
|
async function switchContext({ cwd, desktopSession: nextDesktopSession, forResume = false } = {}) {
|
|
24
|
+
// Leaving the open conversation would re-key an addressed runtime.
|
|
25
|
+
deps.assertNotAddressed?.('switchContext');
|
|
24
26
|
clearRoutePreparation?.();
|
|
25
27
|
const session = getSession();
|
|
26
28
|
if (session?.id) {
|
|
@@ -55,6 +57,7 @@ export function createContextSwitch(deps, { ingestSessionIntoMemory, closeSurfac
|
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
async function newSession() {
|
|
60
|
+
deps.assertNotAddressed?.('newSession');
|
|
58
61
|
const session = getSession();
|
|
59
62
|
if (session?.id) {
|
|
60
63
|
void ingestSessionIntoMemory(session);
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { writeStatuslineRoute } from '../../statusline-route.mjs';
|
|
7
7
|
import { clean, hasOwn } from '../../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
toolSpecForMode,
|
|
10
|
+
deferredSurfaceModeForLead,
|
|
11
|
+
} from '../../../runtime/agent/orchestrator/runtime-core/effort.mjs';
|
|
9
12
|
import { isScratchConversation } from '../shared.mjs';
|
|
10
13
|
|
|
11
14
|
export function resolveResumeCwd(session, currentCwd) {
|
|
@@ -97,6 +100,9 @@ export function createSessionResume(deps, { ingestSessionIntoMemory, closeSurfac
|
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
async function resume(id) {
|
|
103
|
+
// An addressed runtime may only reopen its own conversation; checked
|
|
104
|
+
// before anything is retired or closed.
|
|
105
|
+
deps.assertResumeTarget?.(id);
|
|
100
106
|
clearRoutePreparation?.();
|
|
101
107
|
const prev = getSession();
|
|
102
108
|
// Captured before the manager reopens anything: the scratch decision for
|
|
@@ -88,6 +88,12 @@ export function createSessionDelete(deps, { cancelBackgroundTasks }) {
|
|
|
88
88
|
setSession(null);
|
|
89
89
|
invalidateContextStatusCache();
|
|
90
90
|
invalidatePreSessionToolSurface();
|
|
91
|
+
// An addressed runtime never mints a replacement under the deleted
|
|
92
|
+
// address: it becomes terminal and a new conversation needs a new entry.
|
|
93
|
+
if (deps.getAddressedSessionId?.()) {
|
|
94
|
+
deps.markAddressTerminal?.();
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
91
97
|
await createCurrentSession();
|
|
92
98
|
return true;
|
|
93
99
|
}
|
|
@@ -63,10 +63,22 @@ export function closeOwnSession(deps, closeSurfaceSession, reason) {
|
|
|
63
63
|
/** Plant the ordinary manager/store tombstone barrier for a canonical
|
|
64
64
|
* child session without running whole-process teardown. */
|
|
65
65
|
export function closeCanonicalSession(deps, reason = 'canonical-session-close') {
|
|
66
|
-
const { getSession, setSession, mgr, invalidateContextStatusCache } = deps;
|
|
66
|
+
const { getSession, setSession, mgr, invalidateContextStatusCache, beginCanonicalClose, finishCanonicalClose } = deps;
|
|
67
|
+
// Already terminal: closing is idempotent and keeps the address.
|
|
68
|
+
if (deps.isCanonicallyClosed?.() === true) return true;
|
|
67
69
|
const session = getSession?.();
|
|
68
70
|
if (!session?.id || session.remoteAttached === true) return false;
|
|
69
|
-
|
|
71
|
+
// Fence execution admission BEFORE the manager close: that close cancels the
|
|
72
|
+
// session's shells synchronously, and their completions must not be able to
|
|
73
|
+
// enqueue model work or create a conversation.
|
|
74
|
+
const fence = beginCanonicalClose?.(session.id);
|
|
75
|
+
let closed = false;
|
|
76
|
+
try {
|
|
77
|
+
closed = mgr.closeSession(session.id, reason, { tombstone: true }) === true;
|
|
78
|
+
} finally {
|
|
79
|
+
// Terminal after a durable close; admission restored when it failed.
|
|
80
|
+
finishCanonicalClose?.(fence, closed);
|
|
81
|
+
}
|
|
70
82
|
if (!closed) return false;
|
|
71
83
|
setSession?.(null);
|
|
72
84
|
invalidateContextStatusCache?.();
|
|
@@ -4,33 +4,43 @@
|
|
|
4
4
|
* The media graph (lane catalog, adapters, asset store) is imported on first
|
|
5
5
|
* use: a session that never opens the Studio must not pay for it at boot.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
async
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async function jobs() {
|
|
17
|
-
jobModule ??= await import('../runtime/media/jobs.mjs');
|
|
18
|
-
return jobModule;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function store() {
|
|
22
|
-
storeModule ??= await import('../runtime/media/store.mjs');
|
|
23
|
-
return storeModule;
|
|
7
|
+
// Each loader keeps its literal import() so bundlers can trace it; only a
|
|
8
|
+
// resolved module is cached, so a failed import is retried on the next call.
|
|
9
|
+
function lazy(load) {
|
|
10
|
+
let module = null;
|
|
11
|
+
return async () => {
|
|
12
|
+
module ??= await load();
|
|
13
|
+
return module;
|
|
14
|
+
};
|
|
24
15
|
}
|
|
25
16
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
const lanes = lazy(() => import('../runtime/media/lanes.mjs'));
|
|
18
|
+
const jobs = lazy(() => import('../runtime/media/jobs.mjs'));
|
|
19
|
+
const store = lazy(() => import('../runtime/media/store.mjs'));
|
|
20
|
+
const defaults = lazy(() => import('../runtime/media/defaults.mjs'));
|
|
21
|
+
const voice = lazy(() => import('../runtime/channels/lib/voice-setup.mjs'));
|
|
31
22
|
|
|
32
23
|
export function createMediaApi() {
|
|
33
24
|
return {
|
|
25
|
+
/** Read-only voice state: `voice.enabled` plus the managed whisper/ffmpeg
|
|
26
|
+
* runtime on disk. */
|
|
27
|
+
async getVoiceStatus() {
|
|
28
|
+
return (await voice()).getVoiceStatus();
|
|
29
|
+
},
|
|
30
|
+
/** Same toggle as the session `toggleVoice` action: enabling installs any
|
|
31
|
+
* missing whisper/ffmpeg component first. `error` carries the last
|
|
32
|
+
* warning or failure the toggle reported. */
|
|
33
|
+
async setVoiceEnabled(enabled) {
|
|
34
|
+
const module = await voice();
|
|
35
|
+
let error = null;
|
|
36
|
+
await module.toggleVoice({
|
|
37
|
+
enabled,
|
|
38
|
+
pushNotice: (text, level) => {
|
|
39
|
+
if (level === 'warn' || level === 'error') error = text;
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
return { status: await module.getVoiceStatus(), error };
|
|
43
|
+
},
|
|
34
44
|
async listMediaLanes() {
|
|
35
45
|
return (await lanes()).listMediaLanes();
|
|
36
46
|
},
|
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
// injected route provider (for sort priority) and webSearchCapableFor predicate.
|
|
4
4
|
import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
5
5
|
import { contextWindowRange } from '../runtime/shared/llm/default-context-window.mjs';
|
|
6
|
+
import { isCustomProviderName } from '../runtime/agent/orchestrator/providers/custom-reasoning.mjs';
|
|
7
|
+
|
|
8
|
+
// A custom provider's effective row fields, carried when the row states them
|
|
9
|
+
// (explicit false included); first-party rows never carry them.
|
|
10
|
+
function customRowFields(name, m) {
|
|
11
|
+
if (!isCustomProviderName(name)) return {};
|
|
12
|
+
return {
|
|
13
|
+
...(typeof m.name === 'string' && m.name ? { name: m.name } : {}),
|
|
14
|
+
...(typeof m.hidden === 'boolean' ? { hidden: m.hidden } : {}),
|
|
15
|
+
...(typeof m.manual === 'boolean' ? { manual: m.manual } : {}),
|
|
16
|
+
...(m.customReasoning && typeof m.customReasoning === 'object' ? { customReasoning: m.customReasoning } : {}),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
6
19
|
|
|
7
20
|
function parsedProviderModelVersion(id) {
|
|
8
21
|
const text = clean(id).toLowerCase();
|
|
@@ -138,6 +151,9 @@ export function providerModelCacheRow(name, m, webSearchCapableFor) {
|
|
|
138
151
|
serviceTiers: Array.isArray(m.serviceTiers) ? m.serviceTiers : [],
|
|
139
152
|
additionalSpeedTiers: Array.isArray(m.additionalSpeedTiers) ? m.additionalSpeedTiers : [],
|
|
140
153
|
defaultServiceTier: m.defaultServiceTier || null,
|
|
154
|
+
...(Array.isArray(m.accessPrograms) ? { accessPrograms: m.accessPrograms } : {}),
|
|
155
|
+
// A catalog-hidden model leaves the pickers; its metadata still resolves.
|
|
156
|
+
...(m.hidden === true ? { hidden: true } : {}),
|
|
141
157
|
fastCapable: m.fastCapable === true,
|
|
142
158
|
fastEfforts: Array.isArray(m.fastEfforts) ? m.fastEfforts : undefined,
|
|
143
159
|
modelParameterOptions: Array.isArray(m.modelParameterOptions) ? m.modelParameterOptions : [],
|
|
@@ -148,5 +164,6 @@ export function providerModelCacheRow(name, m, webSearchCapableFor) {
|
|
|
148
164
|
defaultFast: m.defaultFast === true,
|
|
149
165
|
supportsMaxMode: m.supportsMaxMode === true,
|
|
150
166
|
mode: m.mode || null,
|
|
167
|
+
...customRowFields(name, m),
|
|
151
168
|
};
|
|
152
169
|
}
|
|
@@ -29,11 +29,9 @@ export function createRouteTuning(deps, persist) {
|
|
|
29
29
|
throw new Error(`ultrafast is not available for ${getRoute().provider}/${getRoute().model}`);
|
|
30
30
|
}
|
|
31
31
|
const { serviceTier: previousTier, ...otherParameters } = getRoute().modelParameters || {};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
? otherParameters
|
|
36
|
-
: getRoute().modelParameters;
|
|
32
|
+
let modelParameters = getRoute().modelParameters;
|
|
33
|
+
if (ultra) modelParameters = { ...otherParameters, serviceTier: 'ultrafast' };
|
|
34
|
+
else if (previousTier === 'ultrafast') modelParameters = otherParameters;
|
|
37
35
|
const fastCapable = selectionFastCapable(
|
|
38
36
|
getRoute().provider,
|
|
39
37
|
modelMeta,
|
|
@@ -16,6 +16,7 @@ import { resolveRouteContextState, selectionFastCapable } from '../route-state.m
|
|
|
16
16
|
import { writeStatuslineRoute } from '../statusline-route.mjs';
|
|
17
17
|
import {
|
|
18
18
|
sessionHasRouteHistory,
|
|
19
|
+
sessionRouteCommitted,
|
|
19
20
|
shouldRecreateEmptySessionForRouteChange,
|
|
20
21
|
} from '../../runtime/agent/orchestrator/runtime-core/session-route-policy.mjs';
|
|
21
22
|
import { rebuildDeferredToolSurfaceForProvider } from '../../runtime/agent/orchestrator/runtime-core/tool-catalog.mjs';
|
|
@@ -84,7 +85,7 @@ async function recreateEmptySession(deps) {
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
/** Rewrite the addressed empty session to the route it was asked to run on. */
|
|
87
|
-
function
|
|
88
|
+
function updateSessionInPlace(deps, session, updateOptions) {
|
|
88
89
|
const { getRoute, getSession, setSession, mgr, statusRoutes } = deps;
|
|
89
90
|
const route = getRoute();
|
|
90
91
|
const fields = {
|
|
@@ -96,56 +97,83 @@ function updateEmptySessionInPlace(deps, session) {
|
|
|
96
97
|
contextPercent: route.contextPercent,
|
|
97
98
|
selectedContextWindow: route.selectedContextWindow || null,
|
|
98
99
|
};
|
|
99
|
-
const updated = mgr.updateSessionRoute?.(session.id, fields);
|
|
100
|
+
const updated = mgr.updateSessionRoute?.(session.id, fields, updateOptions);
|
|
100
101
|
if (updated) setSession(updated);
|
|
101
102
|
else Object.assign(session, fields);
|
|
102
103
|
rebuildDeferredToolSurfaceForProvider(getSession(), route.provider);
|
|
103
104
|
writeStatuslineRoute(statusRoutes, getSession(), route);
|
|
104
105
|
}
|
|
105
106
|
|
|
106
|
-
|
|
107
|
+
/** Validate, persist and adopt the requested route as the runtime's route. */
|
|
108
|
+
async function adoptRoute(deps, persist, next, options) {
|
|
107
109
|
const {
|
|
108
110
|
getConfig,
|
|
109
111
|
getRoute,
|
|
110
112
|
setRouteState,
|
|
111
|
-
getSession,
|
|
112
113
|
resolveRoute,
|
|
113
114
|
refreshRouteEffort,
|
|
114
115
|
refreshStatuslineUsageSnapshot,
|
|
115
116
|
scheduleStatuslineUsageRefresh,
|
|
116
|
-
invalidateContextStatusCache,
|
|
117
|
-
createCurrentSession,
|
|
118
117
|
} = deps;
|
|
118
|
+
const { selectedRoute, fastCapable, modelMeta } = await resolveSelectedRoute(deps, next);
|
|
119
|
+
persist.saveRouteModelSettings(selectedRoute, fastCapable);
|
|
120
|
+
// An heir opening on its source's model is not a main-model choice.
|
|
121
|
+
const leadRoute = persist.persistAdoptedModelSettings(selectedRoute, {
|
|
122
|
+
keepMainModel: options?.keepMainModel === true,
|
|
123
|
+
});
|
|
124
|
+
setRouteState(resolveRoute(getConfig(), leadRoute ? { model: workflowPresetId('lead') } : selectedRoute));
|
|
125
|
+
await refreshRouteEffort(modelMeta);
|
|
126
|
+
refreshStatuslineUsageSnapshot(getRoute());
|
|
127
|
+
scheduleStatuslineUsageRefresh();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Quota-exhaustion escape hatch: apply `next` to the addressed, ESTABLISHED
|
|
132
|
+
* session in place. The caller (session API) has already proven the latest
|
|
133
|
+
* settled turn failed on quota and that nothing is running. Starts no turn;
|
|
134
|
+
* the next turn's auto-compaction fits history to the new window.
|
|
135
|
+
*/
|
|
136
|
+
export function createContinueSessionInModel(deps, persist) {
|
|
137
|
+
const { getSession, invalidateContextStatusCache } = deps;
|
|
138
|
+
return async function continueSessionInModel(sessionId, next) {
|
|
139
|
+
const session = getSession();
|
|
140
|
+
if (!sessionId || !session?.id || session.id !== sessionId) {
|
|
141
|
+
throw new Error(`session ${sessionId || ''} is not the active session`);
|
|
142
|
+
}
|
|
143
|
+
await adoptRoute(deps, persist, next, {});
|
|
144
|
+
updateSessionInPlace(deps, session, { crossProvider: true });
|
|
145
|
+
invalidateContextStatusCache();
|
|
146
|
+
return true;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function createSetRoute(deps, persist) {
|
|
151
|
+
const { getRoute, getSession, invalidateContextStatusCache, createCurrentSession } = deps;
|
|
119
152
|
|
|
120
153
|
return async function setRoute(next, options = {}) {
|
|
121
154
|
// Selection is for a new/inherited session. An explicit durable address
|
|
122
155
|
// permits initializing an EMPTY session, never rewriting an existing
|
|
123
156
|
// conversation's model, context boundary or provider cache.
|
|
124
157
|
const applyToCurrentSession = options?.applyToCurrentSession === true;
|
|
125
|
-
|
|
126
|
-
persist.saveRouteModelSettings(selectedRoute, fastCapable);
|
|
127
|
-
// An heir opening on its source's model is not a main-model choice.
|
|
128
|
-
const leadRoute = persist.persistAdoptedModelSettings(selectedRoute, {
|
|
129
|
-
keepMainModel: options?.keepMainModel === true,
|
|
130
|
-
});
|
|
131
|
-
setRouteState(resolveRoute(getConfig(), leadRoute ? { model: workflowPresetId('lead') } : selectedRoute));
|
|
132
|
-
await refreshRouteEffort(modelMeta);
|
|
133
|
-
refreshStatuslineUsageSnapshot(getRoute());
|
|
134
|
-
scheduleStatuslineUsageRefresh();
|
|
158
|
+
await adoptRoute(deps, persist, next, options);
|
|
135
159
|
const session = getSession();
|
|
136
160
|
// Model/provider changes are next-session-only for a session the user
|
|
137
161
|
// has already talked in or compacted (provider-keyed prompt cache). But
|
|
138
|
-
//
|
|
139
|
-
// first
|
|
140
|
-
//
|
|
141
|
-
|
|
162
|
+
// a current session with no model reply, no compaction summary and no
|
|
163
|
+
// in-flight first turn — empty, or holding only refused prompts — has no
|
|
164
|
+
// cache to protect, so /model takes effect live: route + statusline
|
|
165
|
+
// update immediately. Only a truly empty session is recreated below.
|
|
166
|
+
const currentSessionEmpty = !!session && !sessionRouteCommitted(session);
|
|
142
167
|
if (!currentSessionEmpty) {
|
|
143
168
|
// Some desktop effort changes travel as a same-model route update.
|
|
144
169
|
// Only effort/Fast may affect the source, starting with its next turn.
|
|
145
170
|
if (applyToCurrentSession) persist.applySessionTuning();
|
|
146
171
|
return getRoute();
|
|
147
172
|
}
|
|
173
|
+
// An addressed runtime keeps its durable id: the empty session is updated
|
|
174
|
+
// in place, never closed and replaced by a freshly minted one.
|
|
148
175
|
if (
|
|
176
|
+
!deps.getAddressedSessionId?.() &&
|
|
149
177
|
shouldRecreateEmptySessionForRouteChange(session, applyToCurrentSession) &&
|
|
150
178
|
session?.id &&
|
|
151
179
|
typeof createCurrentSession === 'function'
|
|
@@ -159,7 +187,7 @@ export function createSetRoute(deps, persist) {
|
|
|
159
187
|
// durable address. The caller asked to apply this route to THIS empty
|
|
160
188
|
// session, so update it in place instead of closing A and silently
|
|
161
189
|
// materializing B before the first prompt.
|
|
162
|
-
|
|
190
|
+
updateSessionInPlace(deps, session);
|
|
163
191
|
invalidateContextStatusCache();
|
|
164
192
|
}
|
|
165
193
|
return getRoute();
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { createRoutePersistence } from './model-route/route-persist.mjs';
|
|
14
14
|
import { createWebSearchRouteApi } from './model-route/web-search-route.mjs';
|
|
15
|
-
import { createSetRoute } from './model-route/set-route.mjs';
|
|
15
|
+
import { createSetRoute, createContinueSessionInModel } from './model-route/set-route.mjs';
|
|
16
16
|
import { createRouteTuning } from './model-route/route-tuning.mjs';
|
|
17
17
|
|
|
18
18
|
export { shouldRecreateEmptySessionForRouteChange } from '../runtime/agent/orchestrator/runtime-core/session-route-policy.mjs';
|
|
@@ -22,6 +22,7 @@ export function createModelRouteApi(deps) {
|
|
|
22
22
|
return {
|
|
23
23
|
...createWebSearchRouteApi(deps),
|
|
24
24
|
setRoute: createSetRoute(deps, persist),
|
|
25
|
+
continueSessionInModel: createContinueSessionInModel(deps, persist),
|
|
25
26
|
...createRouteTuning(deps, persist),
|
|
26
27
|
};
|
|
27
28
|
}
|
|
@@ -29,7 +29,13 @@ function cleanSessionId(value) {
|
|
|
29
29
|
// the wake would leave its durable entry parked until the next user message.
|
|
30
30
|
// A completion whose owner is no longer the live session is still dropped (the
|
|
31
31
|
// durable queue carries it into that session's next turn).
|
|
32
|
-
export function createCompletionWakeScheduler({ getCurrentSessionId, getTurnApi }) {
|
|
32
|
+
export function createCompletionWakeScheduler({ getCurrentSessionId, getTurnApi, getOwnerLifecycle }) {
|
|
33
|
+
// A closing/terminal owner never starts inference from a completion; the
|
|
34
|
+
// check runs at request time and again inside the delayed callback.
|
|
35
|
+
const ownerOpen = (sessionId) => {
|
|
36
|
+
const life = getOwnerLifecycle?.(sessionId);
|
|
37
|
+
return !life || life.state === 'open';
|
|
38
|
+
};
|
|
33
39
|
// sessionId -> the oldest request suppressed while this session's wake is in
|
|
34
40
|
// flight, or null when nothing was suppressed. A present key means in flight.
|
|
35
41
|
const inFlight = new Map();
|
|
@@ -41,6 +47,7 @@ export function createCompletionWakeScheduler({ getCurrentSessionId, getTurnApi
|
|
|
41
47
|
try {
|
|
42
48
|
const turnApi = getTurnApi();
|
|
43
49
|
if (cleanSessionId(getCurrentSessionId()) !== ownerSessionId || !turnApi) return;
|
|
50
|
+
if (!ownerOpen(ownerSessionId)) return;
|
|
44
51
|
const delayMs = Math.max(0, Date.now() - queuedAt);
|
|
45
52
|
if (delayMs >= WAKE_DELAY_REPORT_MS) {
|
|
46
53
|
process.stderr.write(
|
|
@@ -70,7 +77,7 @@ export function createCompletionWakeScheduler({ getCurrentSessionId, getTurnApi
|
|
|
70
77
|
|
|
71
78
|
return function wakeQueuedCompletion({ sessionId, executionId, enqueuedAt } = {}) {
|
|
72
79
|
const ownerSessionId = cleanSessionId(sessionId);
|
|
73
|
-
if (!ownerSessionId) return false;
|
|
80
|
+
if (!ownerSessionId || !ownerOpen(ownerSessionId)) return false;
|
|
74
81
|
if (inFlight.has(ownerSessionId)) {
|
|
75
82
|
const suppressed = inFlight.get(ownerSessionId);
|
|
76
83
|
// Keep the oldest suppressed request so the replay reports the real wait.
|
|
@@ -99,10 +106,22 @@ function emitToListeners(source, content, meta = {}) {
|
|
|
99
106
|
return { handled, modelVisibleDelivered: event.modelVisibleDelivered === true };
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
export function createNotificationBus({ listeners, mgr, onCompletionQueued }) {
|
|
109
|
+
export function createNotificationBus({ listeners, mgr, onCompletionQueued, getOwnerLifecycle }) {
|
|
103
110
|
const boundSessionListeners = new Map();
|
|
104
111
|
const queuedCompletionIds = new Map();
|
|
105
112
|
|
|
113
|
+
// Owner identity + lifecycle generation. A closing/terminal owner (or a
|
|
114
|
+
// callback captured under an earlier generation) keeps its result for
|
|
115
|
+
// UI/history only: it is flagged `owner_closed`, never queued for the model
|
|
116
|
+
// and never wakes inference.
|
|
117
|
+
function ownerOpen(sessionId, capturedGeneration) {
|
|
118
|
+
const life = getOwnerLifecycle?.(sessionId);
|
|
119
|
+
if (!life) return true;
|
|
120
|
+
if (life.state !== 'open') return false;
|
|
121
|
+
return capturedGeneration === undefined || capturedGeneration === life.generation;
|
|
122
|
+
}
|
|
123
|
+
const closedMeta = (meta) => ({ ...(meta && typeof meta === 'object' ? meta : {}), owner_closed: true });
|
|
124
|
+
|
|
106
125
|
function emitRuntimeNotification(content, meta = {}) {
|
|
107
126
|
return emitToListeners(listeners, content, meta);
|
|
108
127
|
}
|
|
@@ -111,8 +130,10 @@ export function createNotificationBus({ listeners, mgr, onCompletionQueued }) {
|
|
|
111
130
|
const targetSessionId = cleanSessionId(sessionId);
|
|
112
131
|
if (!targetSessionId) return false;
|
|
113
132
|
const targetListeners = sessionNotificationListeners.get(targetSessionId) || [];
|
|
114
|
-
const
|
|
133
|
+
const open = ownerOpen(targetSessionId);
|
|
134
|
+
const { handled } = emitToListeners(targetListeners, content, open ? meta : closedMeta(meta));
|
|
115
135
|
if (handled) return true;
|
|
136
|
+
if (!open) return false;
|
|
116
137
|
if (typeof mgr.enqueuePendingMessage !== 'function') return false;
|
|
117
138
|
try {
|
|
118
139
|
return mgr.enqueuePendingMessage(targetSessionId, content) > 0;
|
|
@@ -168,13 +189,15 @@ export function createNotificationBus({ listeners, mgr, onCompletionQueued }) {
|
|
|
168
189
|
return true;
|
|
169
190
|
}
|
|
170
191
|
|
|
171
|
-
function notifySessionCompletion(sessionId, text, meta = {}) {
|
|
192
|
+
function notifySessionCompletion(sessionId, text, meta = {}, capturedGeneration = undefined) {
|
|
172
193
|
const targetSessionId = cleanSessionId(sessionId);
|
|
173
194
|
if (!targetSessionId) return false;
|
|
174
195
|
const targetListeners = sessionNotificationListeners.get(targetSessionId) || [];
|
|
196
|
+
const open = ownerOpen(targetSessionId, capturedGeneration);
|
|
175
197
|
const ownerMeta = {
|
|
176
198
|
...(meta && typeof meta === 'object' ? meta : {}),
|
|
177
199
|
caller_session_id: targetSessionId,
|
|
200
|
+
...(open ? {} : { owner_closed: true }),
|
|
178
201
|
};
|
|
179
202
|
delete ownerMeta.routing_session_id;
|
|
180
203
|
const { handled, modelVisibleDelivered } = emitToListeners(targetListeners, text, ownerMeta);
|
|
@@ -187,6 +210,7 @@ export function createNotificationBus({ listeners, mgr, onCompletionQueued }) {
|
|
|
187
210
|
handled,
|
|
188
211
|
mvd: modelVisibleDelivered,
|
|
189
212
|
});
|
|
213
|
+
if (!open) return handled;
|
|
190
214
|
if (modelVisibleDelivered) {
|
|
191
215
|
try {
|
|
192
216
|
recordDeliveredCompletion({
|
|
@@ -219,7 +243,8 @@ export function createNotificationBus({ listeners, mgr, onCompletionQueued }) {
|
|
|
219
243
|
|
|
220
244
|
function notifyFnForSession(callerSessionId) {
|
|
221
245
|
const ownerSessionId = cleanSessionId(callerSessionId);
|
|
222
|
-
|
|
246
|
+
const generation = getOwnerLifecycle?.(ownerSessionId)?.generation;
|
|
247
|
+
return (text, meta = {}) => notifySessionCompletion(ownerSessionId, text, meta, generation);
|
|
223
248
|
}
|
|
224
249
|
|
|
225
250
|
function bindListenerToSession(sessionId, listener) {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
saveProviderApiKey,
|
|
11
11
|
saveCustomProvider,
|
|
12
12
|
removeCustomProvider,
|
|
13
|
+
updateCustomProviderModel,
|
|
13
14
|
testCustomProvider,
|
|
14
15
|
discoverCustomProviderModels,
|
|
15
16
|
} from '../services/provider-admin.mjs';
|
|
@@ -41,7 +42,7 @@ export function createLoginApi({ cfgMod, awaitKeychainPrewarm, reloadFullConfig,
|
|
|
41
42
|
async authenticateProvider(providerId, secret) {
|
|
42
43
|
await awaitKeychainPrewarm();
|
|
43
44
|
const result = String(secret || '').trim()
|
|
44
|
-
? saveProviderApiKey(cfgMod, providerId, secret)
|
|
45
|
+
? await saveProviderApiKey(cfgMod, providerId, secret)
|
|
45
46
|
: await loginOAuthProvider(cfgMod, providerId);
|
|
46
47
|
refresh.afterCredentialChange();
|
|
47
48
|
return result;
|
|
@@ -58,18 +59,18 @@ export function createLoginApi({ cfgMod, awaitKeychainPrewarm, reloadFullConfig,
|
|
|
58
59
|
reloadFullConfig();
|
|
59
60
|
return completeOAuthLogin(result);
|
|
60
61
|
},
|
|
61
|
-
saveProviderApiKey(providerId, secret) {
|
|
62
|
-
const result = saveProviderApiKey(cfgMod, providerId, secret);
|
|
62
|
+
async saveProviderApiKey(providerId, secret) {
|
|
63
|
+
const result = await saveProviderApiKey(cfgMod, providerId, secret);
|
|
63
64
|
refresh.afterCredentialChange();
|
|
64
65
|
return result;
|
|
65
66
|
},
|
|
66
|
-
saveOpenAIUsageSessionKey(secret) {
|
|
67
|
-
const result = saveOpenAIUsageSessionKey(cfgMod, secret);
|
|
67
|
+
async saveOpenAIUsageSessionKey(secret) {
|
|
68
|
+
const result = await saveOpenAIUsageSessionKey(cfgMod, secret);
|
|
68
69
|
refresh.afterUsageAuthChange();
|
|
69
70
|
return result;
|
|
70
71
|
},
|
|
71
|
-
saveOpenCodeGoUsageAuth(opts) {
|
|
72
|
-
const result = saveOpenCodeGoUsageAuth(cfgMod, opts);
|
|
72
|
+
async saveOpenCodeGoUsageAuth(opts) {
|
|
73
|
+
const result = await saveOpenCodeGoUsageAuth(cfgMod, opts);
|
|
73
74
|
refresh.afterUsageAuthChange();
|
|
74
75
|
return result;
|
|
75
76
|
},
|
|
@@ -79,9 +80,14 @@ export function createLoginApi({ cfgMod, awaitKeychainPrewarm, reloadFullConfig,
|
|
|
79
80
|
refresh.afterCredentialChange();
|
|
80
81
|
return result;
|
|
81
82
|
},
|
|
83
|
+
async updateCustomProviderModel(providerId, modelId, patch) {
|
|
84
|
+
const result = await updateCustomProviderModel(cfgMod, providerId, modelId, patch);
|
|
85
|
+
refresh.afterCredentialChange();
|
|
86
|
+
return result;
|
|
87
|
+
},
|
|
82
88
|
async removeCustomProvider(providerId) {
|
|
83
89
|
await awaitKeychainPrewarm();
|
|
84
|
-
const result = removeCustomProvider(cfgMod, providerId);
|
|
90
|
+
const result = await removeCustomProvider(cfgMod, providerId);
|
|
85
91
|
onCustomProviderRemoved?.(result.provider);
|
|
86
92
|
refresh.afterCredentialChange();
|
|
87
93
|
return result;
|
|
@@ -94,8 +100,8 @@ export function createLoginApi({ cfgMod, awaitKeychainPrewarm, reloadFullConfig,
|
|
|
94
100
|
await awaitKeychainPrewarm();
|
|
95
101
|
return await discoverCustomProviderModels(cfgMod, input);
|
|
96
102
|
},
|
|
97
|
-
forgetProviderAuth(providerId, accountId) {
|
|
98
|
-
const result = forgetProviderAuth(cfgMod, providerId, accountId);
|
|
103
|
+
async forgetProviderAuth(providerId, accountId) {
|
|
104
|
+
const result = await forgetProviderAuth(cfgMod, providerId, accountId);
|
|
99
105
|
refresh.afterCredentialChange();
|
|
100
106
|
return result;
|
|
101
107
|
},
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
// provider-auth/setup.mjs — read-side provider surfaces: the setup snapshot
|
|
2
2
|
// (quick until the keychain is ready), usage dashboard, Codex reset credit and
|
|
3
3
|
// the model catalog.
|
|
4
|
+
import { refreshKeychainStatus, retryKeychain } from '../../runtime/shared/config.mjs';
|
|
5
|
+
import { keychainIssueFor } from '../services/provider-admin.mjs';
|
|
6
|
+
|
|
7
|
+
// The keyring alert must reflect the live state (it can lock or unlock while a
|
|
8
|
+
// cached setup is served), so overlay it on every ready read.
|
|
9
|
+
function withLiveKeychain(setup) {
|
|
10
|
+
if (!setup || typeof setup !== 'object') return setup;
|
|
11
|
+
const { keychain: _stale, ...rest } = setup;
|
|
12
|
+
const keychain = keychainIssueFor(true);
|
|
13
|
+
return keychain ? { ...rest, keychain } : rest;
|
|
14
|
+
}
|
|
15
|
+
|
|
4
16
|
export function createSetupApi({
|
|
5
17
|
awaitKeychainPrewarm,
|
|
6
18
|
isKeychainPrewarmReady,
|
|
@@ -28,8 +40,16 @@ export function createSetupApi({
|
|
|
28
40
|
return { ...quick, pendingSecrets: !isKeychainPrewarmReady() };
|
|
29
41
|
}
|
|
30
42
|
await awaitKeychainPrewarm();
|
|
31
|
-
|
|
32
|
-
|
|
43
|
+
// A keyring the user has since unlocked: rebuild the setup that was cached
|
|
44
|
+
// while every stored key read as absent.
|
|
45
|
+
const recovered = await retryKeychain({ interactive: options?.unlockKeychain === true });
|
|
46
|
+
if (force || recovered) reloadFullConfig();
|
|
47
|
+
// Passive: detects a re-locked keyring and re-snapshots a stale cache so
|
|
48
|
+
// external (CLI / other process) changes show up.
|
|
49
|
+
// `recheckKeychain` (window focus) skips the snapshot TTL.
|
|
50
|
+
const changed = await refreshKeychainStatus({ force: options?.recheckKeychain === true });
|
|
51
|
+
if (changed) reloadFullConfig();
|
|
52
|
+
return withLiveKeychain(await cachedProviderSetup({ force: force || recovered || changed }));
|
|
33
53
|
},
|
|
34
54
|
async getUsageDashboard(options = {}) {
|
|
35
55
|
return await getUsageDashboard(options);
|