mixdog 1.3.1 → 1.3.3
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 +8 -4
- package/package.json +8 -8
- package/scripts/native-release-status.mjs +238 -0
- package/scripts/verify-runtime-dependency-versions.mjs +158 -0
- package/src/agents/reviewer/AGENT.md +5 -7
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +9 -1
- package/src/defaults/skills/browser-use/SKILL.md +6 -3
- package/src/defaults/skills/local-provider/SKILL.md +33 -6
- package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
- package/src/defaults/skills/setup/SKILL.md +23 -1
- package/src/defaults/skills/setup/references/actions.md +50 -3
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +7 -3
- package/src/defaults/skills/visualize/SKILL.md +9 -6
- package/src/defaults/skills/visualize/references/craft.md +8 -1
- package/src/help.mjs +1 -1
- package/src/lib/keychain-cjs.cjs +4 -1
- package/src/lib/rules-builder.cjs +14 -7
- package/src/rules/agent-mode/AGENT_MODE.md +8 -5
- package/src/rules/agent-mode/MIXY.md +6 -8
- package/src/rules/lead/LEAD.md +7 -10
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- package/src/rules/shared/45-destructive.md +5 -1
- package/src/rules/shared/60-verification.md +6 -4
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
- package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
- package/src/runtime/agent/orchestrator/config.mjs +11 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
- package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +84 -32
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +84 -42
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
- package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
- package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
- package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +52 -6
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +35 -13
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +196 -45
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +45 -19
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +185 -37
- package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +240 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +102 -35
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +19 -9
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +199 -109
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +33 -8
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +27 -14
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +115 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +4 -9
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +14 -1
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +52 -11
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +126 -12
- package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +16 -3
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +15 -5
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +49 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +80 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +47 -14
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +10 -12
- package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +42 -23
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
- package/src/runtime/attachments/attachment-reference.mjs +155 -0
- package/src/runtime/attachments/legacy-office.mjs +110 -0
- package/src/runtime/attachments/limits.mjs +5 -1
- package/src/runtime/attachments/office-extract.mjs +3 -6
- package/src/runtime/attachments/pdf-extract.mjs +84 -10
- package/src/runtime/attachments/prompt-restore.mjs +70 -0
- package/src/runtime/attachments/store.mjs +109 -33
- package/src/runtime/browser-bridge/client.mjs +73 -20
- package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
- package/src/runtime/channels/lib/scheduler.mjs +14 -7
- package/src/runtime/channels/lib/state-file.mjs +15 -15
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
- package/src/runtime/channels/lib/worker-main.mjs +3 -2
- package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
- package/src/runtime/effort-judge/judge-client.mjs +66 -16
- package/src/runtime/effort-judge/model-install.mjs +47 -7
- package/src/runtime/local-provider/asset-installer.mjs +10 -4
- package/src/runtime/local-provider/catalog.mjs +5 -2
- package/src/runtime/local-provider/registered-models.mjs +64 -27
- package/src/runtime/local-provider/server.mjs +2 -3
- package/src/runtime/media/adapters/image-api.mjs +89 -0
- package/src/runtime/media/auth.mjs +64 -1
- package/src/runtime/media/catalog.mjs +66 -4
- package/src/runtime/media/jobs.mjs +4 -0
- package/src/runtime/media/lanes.mjs +46 -5
- package/src/runtime/media/media-usage.mjs +17 -0
- package/src/runtime/media/renditions.mjs +15 -15
- package/src/runtime/media/store.mjs +36 -35
- package/src/runtime/media/tool.mjs +8 -1
- package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
- package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
- package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
- package/src/runtime/memory/lib/pg/process.mjs +8 -4
- package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
- package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
- package/src/runtime/office/core/journal.mjs +7 -14
- package/src/runtime/office/design/library/design-library-core.mjs +4 -16
- package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
- package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
- package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
- package/src/runtime/office/pdf/pdf-render.mjs +30 -18
- package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +135 -29
- package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
- package/src/runtime/shared/agent-avatar.mjs +3 -2
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
- package/src/runtime/shared/agent-message-envelope.mjs +44 -0
- package/src/runtime/shared/agent-reap-state.d.mts +4 -0
- package/src/runtime/shared/agent-room-host.d.mts +31 -0
- package/src/runtime/shared/agent-room-host.mjs +58 -0
- package/src/runtime/shared/agent-store.mjs +24 -7
- package/src/runtime/shared/agent-task-starts.mjs +27 -0
- package/src/runtime/shared/atomic-file.d.mts +50 -0
- package/src/runtime/shared/atomic-file.mjs +394 -132
- package/src/runtime/shared/background-tasks.mjs +7 -4
- package/src/runtime/shared/bot-hops.mjs +35 -0
- package/src/runtime/shared/bot-split-migration.mjs +1 -1
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/defaults-separation.mjs +6 -2
- package/src/runtime/shared/delegated-approval-host.mjs +74 -0
- package/src/runtime/shared/err-text.mjs +4 -0
- package/src/runtime/shared/error-presentation.mjs +22 -4
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/process-lifecycle.mjs +8 -12
- package/src/runtime/shared/projects.mjs +50 -41
- package/src/runtime/shared/provider-accounts.mjs +17 -12
- package/src/runtime/shared/redact-directories.mjs +18 -0
- package/src/runtime/shared/remove-directory.mjs +28 -0
- package/src/runtime/shared/routine-trigger.d.mts +6 -1
- package/src/runtime/shared/routine-trigger.mjs +14 -6
- package/src/runtime/shared/run-child.d.mts +3 -0
- package/src/runtime/shared/run-child.mjs +24 -3
- package/src/runtime/shared/session-baseline-store.mjs +8 -2
- package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
- package/src/runtime/shared/session-sidebar-host.mjs +16 -3
- package/src/runtime/shared/singleton-owner.mjs +7 -6
- package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
- package/src/runtime/shared/staged-update.mjs +4 -2
- package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
- package/src/runtime/shared/tool-execution-contract.mjs +10 -0
- package/src/runtime/shared/tool-work-units.mjs +12 -9
- package/src/runtime/shared/transcript-metadata.mjs +28 -3
- package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
- package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
- package/src/runtime/shared/turn-snapshot.mjs +277 -124
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +92 -61
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +251 -61
- package/src/runtime/shared/worktrees/contract.mjs +11 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
- package/src/runtime/shared/worktrees/manager.mjs +419 -52
- package/src/runtime/shared/worktrees/registry.mjs +29 -27
- package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/tidy/process.mjs +41 -8
- package/src/runtime/tidy/resolve.mjs +10 -7
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +542 -204
- package/src/session-runtime/agent-profile-changes.mjs +16 -0
- package/src/session-runtime/agent-room-delivery.mjs +81 -35
- package/src/session-runtime/agent-task-sessions.mjs +811 -179
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +48 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +16 -7
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +2 -2
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +23 -3
- package/src/session-runtime/bot-status.mjs +432 -0
- package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
- package/src/session-runtime/config-lifecycle.mjs +60 -55
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/held-requests.mjs +31 -33
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +24 -26
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown.mjs +11 -3
- package/src/session-runtime/mcp-glue/connect.mjs +100 -186
- package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
- package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
- package/src/session-runtime/media-api.mjs +5 -2
- package/src/session-runtime/model-recency.mjs +1 -0
- package/src/session-runtime/model-route/route-tuning.mjs +4 -1
- package/src/session-runtime/model-route/set-route.mjs +61 -1
- package/src/session-runtime/owned-automation-run.mjs +8 -1
- package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
- package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
- package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
- package/src/session-runtime/route-resolution.mjs +16 -8
- package/src/session-runtime/route-state.mjs +1 -59
- package/src/session-runtime/routine-home-turn.mjs +5 -3
- package/src/session-runtime/runtime-bootstrap.mjs +5 -3
- package/src/session-runtime/runtime-paths.mjs +11 -5
- package/src/session-runtime/runtime-review-api.mjs +4 -1
- package/src/session-runtime/runtime-tunables.mjs +6 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
- package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
- package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +34 -19
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +7 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
- package/src/session-runtime/services/agent-tool.mjs +6 -0
- package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
- package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
- package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
- package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
- package/src/session-runtime/services/plugin-admin.mjs +26 -26
- package/src/session-runtime/services/provider-admin.mjs +26 -6
- package/src/session-runtime/services/schedule-access.mjs +33 -4
- package/src/session-runtime/services/seeds.mjs +4 -3
- package/src/session-runtime/services/usage-dashboard.mjs +1 -1
- package/src/session-runtime/services/usage-stats-model.mjs +2 -1
- package/src/session-runtime/services/worktree-access.mjs +27 -0
- package/src/session-runtime/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/session-hooks.mjs +9 -17
- package/src/session-runtime/settings-builtin-tools-api.mjs +65 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +12 -2
- package/src/session-runtime/setup-tool/settings-contract.mjs +34 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
- package/src/session-runtime/skills-api.mjs +12 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +349 -0
- package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
- package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +183 -0
- package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
- package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
- package/src/session-runtime/tool-policy-refresh.mjs +48 -369
- package/src/session-runtime/tool-surface.mjs +10 -4
- package/src/session-runtime/turn/session-ops.mjs +8 -0
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +7 -2
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +527 -333
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +85 -63
- package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
- package/src/session-runtime/workspace/transition-steps.mjs +1 -18
- package/src/session-runtime/workspace/transitions.mjs +279 -67
- package/src/session-runtime/workspace/workspace-state.mjs +7 -6
- package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-lag-profiler.mjs +3 -1
- package/src/standalone/daemon-session-control.mjs +173 -15
- package/src/standalone/daemon-telemetry.mjs +9 -0
- package/src/standalone/daemon.mjs +33 -10
- package/src/standalone/local-session-runtime.mjs +33 -16
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +8 -0
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
- package/src/standalone/session-service/agent-route-follow.mjs +69 -0
- package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
- package/src/standalone/session-service.mjs +21 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +36 -9
- package/src/standalone/staged-import.mjs +47 -0
- package/src/tui/App.jsx +2 -0
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- package/src/tui/app/message-selector.mjs +15 -2
- package/src/tui/app/model-options.mjs +16 -2
- package/src/tui/app/model-picker.mjs +2 -1
- package/src/tui/app/route-pickers.mjs +3 -1
- package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
- package/src/tui/dist/index.mjs +617 -369
- package/src/tui/paste-attachments.mjs +0 -1
- package/src/tui/paste-text-policy.mjs +4 -5
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/notice-surface.mjs +3 -0
- package/src/tui/session/session-api/intake/abort.mjs +52 -18
- package/src/tui/session/session-api/intake/rewind.mjs +39 -4
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +76 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -247
- package/src/tui/session/session-api/settings.mjs +14 -1
- package/src/tui/session/session-flow/drain.mjs +28 -3
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
- package/src/tui/session/session-flow/steering.mjs +8 -3
- package/src/tui/session/tool-approval.mjs +142 -14
- package/src/tui/session/transcript-intake.mjs +2 -0
- package/src/tui/session/turn.mjs +23 -14
- package/src/tui/transcript-tool-failures.mjs +8 -2
- package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
- package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
- package/src/rules/agent-mode/ROUTINE.md +0 -6
- package/src/session-runtime/room-member-gate.mjs +0 -48
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// A big paste is replaced in the prompt by a compact token so the editor does
|
|
4
4
|
// not choke on thousands of raw characters; the original text lives in the
|
|
5
5
|
// surface's pasted-text map and is expanded back on submit.
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
// Same rule as Claude Code / Codex (LARGE_PASTE_CHAR_THRESHOLD): only a paste
|
|
7
|
+
// longer than this many characters folds; the line count never matters.
|
|
8
|
+
export const PASTE_TOKEN_MIN_CHARS = 1000;
|
|
8
9
|
|
|
9
10
|
// VISIBLE lines: a copy that ends in a newline ("a\nb\n") is two lines, not
|
|
10
11
|
// three. Counting the empty trailing chunk folded ordinary two-line copies
|
|
@@ -18,9 +19,7 @@ export function pastedTextLineCount(text) {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export function shouldFoldPastedText(text) {
|
|
21
|
-
|
|
22
|
-
if (!value) return false;
|
|
23
|
-
return pastedTextLineCount(value) >= PASTE_TOKEN_MIN_LINES || value.length > PASTE_TOKEN_MIN_CHARS;
|
|
22
|
+
return String(text ?? '').length > PASTE_TOKEN_MIN_CHARS;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
export function formatPastedTextRef(id, text) {
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Stored under MIXDOG data dir (not the repo working tree).
|
|
4
4
|
*/
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { mkdirSync } from 'node:fs';
|
|
7
|
+
import { mkdir } from 'node:fs/promises';
|
|
8
8
|
import { dirname, join, resolve } from 'node:path';
|
|
9
|
+
import { readJsonStateSync, writeFileAtomicAsync, writeFileAtomicSync } from '../runtime/shared/atomic-file.mjs';
|
|
9
10
|
import { resolvePluginData } from '../runtime/shared/plugin-paths.mjs';
|
|
10
11
|
|
|
11
12
|
export const PROMPT_HISTORY_LIMIT = 50;
|
|
@@ -33,10 +34,18 @@ function historyFilePath(cwd) {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
function readEntries(filePath) {
|
|
36
|
-
if (!filePath
|
|
37
|
+
if (!filePath) return [];
|
|
37
38
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
// A damaged file (NUL, truncated) is kept aside as *.corrupt-<ts> and the
|
|
40
|
+
// history starts empty; the next flush writes a fresh file.
|
|
41
|
+
const parsed = readJsonStateSync(filePath, {
|
|
42
|
+
mode: 0o600,
|
|
43
|
+
validate: (value) => {
|
|
44
|
+
if (!Array.isArray(value?.entries)) throw new TypeError('prompt history has no entries');
|
|
45
|
+
return value;
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
const entries = parsed ? parsed.entries : [];
|
|
40
49
|
return entries.map((entry) => String(entry || '').trim()).filter((entry) => promptHistoryKey(entry));
|
|
41
50
|
} catch {
|
|
42
51
|
return [];
|
|
@@ -52,14 +61,7 @@ function writeEntriesSync(filePath, entries) {
|
|
|
52
61
|
try {
|
|
53
62
|
// Prompt text may be sensitive; restrict directory/file to the owning user.
|
|
54
63
|
mkdirSync(dirname(filePath), { recursive: true, mode: 0o700 });
|
|
55
|
-
|
|
56
|
-
writeFileSync(tmp, buildPayload(entries), { encoding: 'utf8', mode: 0o600 });
|
|
57
|
-
renameSync(tmp, filePath);
|
|
58
|
-
try {
|
|
59
|
-
chmodSync(filePath, 0o600);
|
|
60
|
-
} catch {
|
|
61
|
-
/* best-effort; Windows may ignore mode bits */
|
|
62
|
-
}
|
|
64
|
+
writeFileAtomicSync(filePath, buildPayload(entries), { mode: 0o600 });
|
|
63
65
|
return true;
|
|
64
66
|
} catch {
|
|
65
67
|
return false;
|
|
@@ -72,14 +74,7 @@ async function writeEntriesAsync(filePath, entries) {
|
|
|
72
74
|
if (!filePath) return false;
|
|
73
75
|
try {
|
|
74
76
|
await mkdir(dirname(filePath), { recursive: true, mode: 0o700 });
|
|
75
|
-
|
|
76
|
-
await writeFile(tmp, buildPayload(entries), { encoding: 'utf8', mode: 0o600 });
|
|
77
|
-
await rename(tmp, filePath);
|
|
78
|
-
try {
|
|
79
|
-
await chmod(filePath, 0o600);
|
|
80
|
-
} catch {
|
|
81
|
-
/* best-effort; Windows may ignore mode bits */
|
|
82
|
-
}
|
|
77
|
+
await writeFileAtomicAsync(filePath, buildPayload(entries), { mode: 0o600 });
|
|
83
78
|
return true;
|
|
84
79
|
} catch {
|
|
85
80
|
return false;
|
|
@@ -86,10 +86,13 @@ export function createExecutionDelivery({
|
|
|
86
86
|
// active loop can attach them after the next tool batch. The immediate
|
|
87
87
|
// response card was already pushed above, so the queued twin stays
|
|
88
88
|
// model-visible but suppresses its drain-time transcript card.
|
|
89
|
-
const { execution } = markCompletionEntry(resumeBody, { executionId, meta: event?.meta });
|
|
89
|
+
const { execution, hop } = markCompletionEntry(resumeBody, { executionId, meta: event?.meta });
|
|
90
90
|
const enqueued = enqueue(resumeBody, {
|
|
91
91
|
mode: 'task-notification',
|
|
92
92
|
...(execution ? { execution } : {}),
|
|
93
|
+
// The launching turn's bot-chain hop: the turn this wakes, or the running
|
|
94
|
+
// turn this joins, resumes at it (bot-hops.mjs).
|
|
95
|
+
...(hop ? { transcriptMeta: { hop } } : {}),
|
|
93
96
|
priority: 'next',
|
|
94
97
|
key: notificationKey || undefined,
|
|
95
98
|
abortDiscardOnAbort: true,
|
|
@@ -77,6 +77,10 @@ export function createContextState({
|
|
|
77
77
|
autoClear: autoClearState(),
|
|
78
78
|
workflow: runtime.workflow || null,
|
|
79
79
|
orchestrationMode: runtime.orchestrationMode || 'none',
|
|
80
|
+
// A workflow / orchestration mode chosen during a turn: shown above,
|
|
81
|
+
// applied when the next turn starts (tool-policy-refresh.mjs).
|
|
82
|
+
pendingWorkflowSwitch: runtime.session?.pendingWorkflowId !== undefined,
|
|
83
|
+
pendingOrchestrationModeSwitch: runtime.session?.pendingOrchestrationMode !== undefined,
|
|
80
84
|
// Every `set({ ...routeState() })` (the 2s runtime pulse, model/effort
|
|
81
85
|
// switches, turn end, resume) republishes the Goal. It must read it
|
|
82
86
|
// through the goal-continuation mask: the raw record still holds a
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* src/tui/session/notice-surface.mjs - toasts, transcript notices, progress hint.
|
|
3
3
|
*/
|
|
4
|
+
import { roomRowSender } from '../../runtime/agent/orchestrator/session/agent-room.mjs';
|
|
4
5
|
import { polishNoticeText } from './notice-text.mjs';
|
|
5
6
|
import { nextId } from './transcript-spill.mjs';
|
|
6
7
|
|
|
@@ -59,6 +60,8 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
|
|
|
59
60
|
// A schedule result posted into a home thread (routine-result.mjs).
|
|
60
61
|
...(options.routine ? { routine: options.routine } : {}),
|
|
61
62
|
...(options.room ? { room: options.room } : {}),
|
|
63
|
+
// A room message another session sent shows its sender, as restored.
|
|
64
|
+
...(userRow ? roomRowSender(options.room) : {}),
|
|
62
65
|
// A room user row's files, in the fields a prompt row draws them from;
|
|
63
66
|
// a task report's or member speech's returned files likewise.
|
|
64
67
|
...(Array.isArray(options.attachments) && options.attachments.length ? { attachments: options.attachments } : {}),
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
// during a turn cancels it and, unless a steering prompt is already queued,
|
|
3
3
|
// reclaims the in-flight prompt, its history slot and its requeue entries.
|
|
4
4
|
import { hydratePastedAttachments, hydrateRestorableFileParts } from '../../../../runtime/attachments/store.mjs';
|
|
5
|
+
import { USER_CANCEL_KEEP_PROMPT_REASON } from '../../../../runtime/agent/orchestrator/session/manager/turn-interruption.mjs';
|
|
5
6
|
import { abortGoalTurn } from '../../goal-turn-state.mjs';
|
|
6
7
|
import { promptHistoryWithout } from '../../prompt-history.mjs';
|
|
7
8
|
import { isQueuedEntryEditable } from '../../queue-helpers.mjs';
|
|
8
9
|
|
|
9
10
|
// An attachment whose blob is gone is dropped alone; the prompt is kept.
|
|
10
|
-
function hydrateTolerantly(pastedImages, pastedTexts, content = null) {
|
|
11
|
+
export function hydrateTolerantly(pastedImages, pastedTexts, content = null) {
|
|
11
12
|
let unreadable = 0;
|
|
12
13
|
const onUnreadable = () => {
|
|
13
14
|
unreadable += 1;
|
|
@@ -56,9 +57,13 @@ export function createAbortAction(bag) {
|
|
|
56
57
|
|
|
57
58
|
// Pull the interrupted prompt back out of the transcript and history and
|
|
58
59
|
// put its unsent requeue entries at the front of the queue.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
// `keepPrompt` only requeues: the submitted rows stay in the transcript.
|
|
61
|
+
const reclaimInFlightPrompt = (
|
|
62
|
+
restoreState,
|
|
63
|
+
{ restoreText, requeueEntries, handoff = false, keepPrompt = false }
|
|
64
|
+
) => {
|
|
65
|
+
if (!keepPrompt) restoreState.reclaimed = true;
|
|
66
|
+
const idSet = new Set((keepPrompt ? [] : restoreState.submittedIds || []).filter((id) => id != null));
|
|
62
67
|
const patch = { spinner: null, thinking: null, lastTurn: null };
|
|
63
68
|
// Another device cancelled this turn: the prompt travels to the device that
|
|
64
69
|
// sent it through the state, never through the canceller's reply.
|
|
@@ -124,14 +129,26 @@ export function createAbortAction(bag) {
|
|
|
124
129
|
const canceller = typeof options?.device === 'string' ? options.device : '';
|
|
125
130
|
const crossDevice = Boolean(canceller && restoreState?.device && canceller !== restoreState.device);
|
|
126
131
|
const hasAttachments = Boolean(restoreState?.pastedImages || restoreState?.pastedTexts || restoreState?.content);
|
|
127
|
-
const
|
|
132
|
+
const wantsRestore =
|
|
128
133
|
options?.restorePrompt !== false &&
|
|
129
134
|
restoreState?.restorable &&
|
|
130
135
|
!hasPendingSteering &&
|
|
131
136
|
!(crossDevice && hasAttachments);
|
|
137
|
+
// Hydrate BEFORE the turn is aborted or the prompt reclaimed: an attachment
|
|
138
|
+
// read error then cannot strand a prompt that left the transcript with no
|
|
139
|
+
// draft to land in. On failure the prompt is kept (like a Stop that hands
|
|
140
|
+
// nothing back) and the error is surfaced as the notice.
|
|
141
|
+
let restored = null;
|
|
142
|
+
let hydrateFailure = '';
|
|
143
|
+
if (wantsRestore) {
|
|
144
|
+
try {
|
|
145
|
+
restored = hydrateTolerantly(restoreState?.pastedImages, restoreState?.pastedTexts, restoreState?.content);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
hydrateFailure = `Could not restore the attachments (${error?.message || error}); the prompt was kept.`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const canRestore = wantsRestore && !hydrateFailure;
|
|
132
151
|
const restoreText = canRestore ? restoreState.text : '';
|
|
133
|
-
const restorePastedImages = canRestore && restoreState?.pastedImages ? restoreState.pastedImages : null;
|
|
134
|
-
const restorePastedTexts = canRestore && restoreState?.pastedTexts ? restoreState.pastedTexts : null;
|
|
135
152
|
// When steering suppresses the restore, the interrupted prompt's pasted
|
|
136
153
|
// images never get committed (onCommitted won't fire) nor re-installed into
|
|
137
154
|
// the draft, so hand them back for cleanup to avoid a stale `[Image #id]`
|
|
@@ -146,34 +163,51 @@ export function createAbortAction(bag) {
|
|
|
146
163
|
(entry) => entry?.abortDiscardOnAbort !== true && entry?.mode !== 'pending-resume'
|
|
147
164
|
)
|
|
148
165
|
: [];
|
|
149
|
-
|
|
166
|
+
// A user Stop that hands the prompt back is rewound by the runtime (the
|
|
167
|
+
// prompt returns to the input box); one that does not keeps it in the
|
|
168
|
+
// stored transcript, as it stays in the visible one. A turn that already
|
|
169
|
+
// committed (output produced) needs neither.
|
|
170
|
+
const keepsPrompt = reason === 'user-cancel' && !canRestore && restoreState?.restorable && !restoreState.committed;
|
|
171
|
+
const aborted = abortGoalTurn(
|
|
172
|
+
runtime,
|
|
173
|
+
flags,
|
|
174
|
+
hasPendingSteering,
|
|
175
|
+
keepsPrompt ? USER_CANCEL_KEEP_PROMPT_REASON : reason
|
|
176
|
+
);
|
|
150
177
|
if (restoreState) {
|
|
178
|
+
// A user Stop consumes this input even when no draft is requested.
|
|
179
|
+
// Explicit draft reclamation also releases it; automatic interruptions
|
|
180
|
+
// such as the watchdog must retain input that has not been committed.
|
|
181
|
+
if (aborted !== false && !restoreState.committed && (reason === 'user-cancel' || restoreText)) {
|
|
182
|
+
restoreState.onAborted?.();
|
|
183
|
+
restoreState.onAborted = null;
|
|
184
|
+
}
|
|
151
185
|
if (aborted !== false && Array.isArray(restoreState.discardExecutionPendingResumeKeys)) {
|
|
152
186
|
discardExecutionPendingResume?.(restoreState.discardExecutionPendingResumeKeys);
|
|
153
187
|
}
|
|
154
188
|
if ((restoreText || requeueEntries.length > 0) && aborted !== false) {
|
|
155
|
-
reclaimInFlightPrompt(restoreState, {
|
|
189
|
+
reclaimInFlightPrompt(restoreState, {
|
|
190
|
+
restoreText,
|
|
191
|
+
requeueEntries,
|
|
192
|
+
handoff: crossDevice,
|
|
193
|
+
keepPrompt: Boolean(hydrateFailure),
|
|
194
|
+
});
|
|
156
195
|
}
|
|
157
196
|
restoreState.restorable = false;
|
|
158
197
|
restoreState.requeueEntries = [];
|
|
159
198
|
restoreState.discardExecutionPendingResumeKeys = [];
|
|
160
199
|
}
|
|
161
200
|
kickDrainAfterAbort();
|
|
162
|
-
const restored = hydrateTolerantly(
|
|
163
|
-
restorePastedImages,
|
|
164
|
-
restorePastedTexts,
|
|
165
|
-
canRestore ? restoreState?.content : null
|
|
166
|
-
);
|
|
167
201
|
// The canceller never receives another device's prompt.
|
|
168
202
|
const handedOver = crossDevice && Boolean(restoreText) && aborted !== false;
|
|
169
203
|
return {
|
|
170
204
|
aborted,
|
|
171
205
|
restoreText: handedOver ? '' : restoreText,
|
|
172
|
-
...(restored
|
|
173
|
-
...(restored
|
|
174
|
-
pastedImages: restored
|
|
206
|
+
...(restored?.content ? { content: restored.content } : {}),
|
|
207
|
+
...(restored?.notice || hydrateFailure ? { notice: restored?.notice || hydrateFailure } : {}),
|
|
208
|
+
pastedImages: restored?.pastedImages ?? null,
|
|
175
209
|
discardPastedImages,
|
|
176
|
-
pastedTexts: restored
|
|
210
|
+
pastedTexts: restored?.pastedTexts ?? null,
|
|
177
211
|
discardPastedTexts,
|
|
178
212
|
restoredSubmissionIds:
|
|
179
213
|
restoreText && !handedOver ? (restoreState?.submittedIds || []).map(String).filter(Boolean) : [],
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
// Message selector ("jump back to a previous message"): rewind the
|
|
2
2
|
// conversation to just before a user prompt and hand its text back for
|
|
3
3
|
// editing. Idle-only — a live turn must be interrupted first.
|
|
4
|
+
import { restorableAttachmentsFromPrompt } from '../../../../runtime/attachments/prompt-restore.mjs';
|
|
4
5
|
import { promptHistoryWithout } from '../../prompt-history.mjs';
|
|
6
|
+
import { hydrateTolerantly } from './abort.mjs';
|
|
5
7
|
|
|
6
8
|
export function createRewindAction(bag) {
|
|
7
9
|
const { runtime, getState, set, flushEmitImmediate, replaceItems, syncContextStats } = bag;
|
|
8
10
|
|
|
9
11
|
return {
|
|
10
|
-
|
|
12
|
+
// `restoreFiles: false` is a composer that cannot hold PDF/Office file
|
|
13
|
+
// parts (the terminal one): a prompt carrying any is refused untouched.
|
|
14
|
+
rewindToItem: async (itemId, { restoreFiles = true } = {}) => {
|
|
11
15
|
const target = String(itemId ?? '').trim();
|
|
12
16
|
if (!target) return null;
|
|
13
17
|
if (getState().busy || getState().commandBusy) return null;
|
|
@@ -19,8 +23,31 @@ export function createRewindAction(bag) {
|
|
|
19
23
|
if (!text) return null;
|
|
20
24
|
set({ commandBusy: true });
|
|
21
25
|
try {
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
// Matched by the row's stable message id (the stored prompt is the
|
|
27
|
+
// expanded text); rows without one fall back to the text.
|
|
28
|
+
const messageId = String(items[index]?.messageId || '');
|
|
29
|
+
const rewindOptions = { text, ...(messageId ? { messageId } : {}) };
|
|
30
|
+
// Resolve the prompt and build the whole restore payload BEFORE any
|
|
31
|
+
// history changes: a refusal or an attachment read error then leaves the
|
|
32
|
+
// model history and the transcript both untouched.
|
|
33
|
+
const preview = await runtime.rewindMessages?.({ ...rewindOptions, dryRun: true });
|
|
34
|
+
if (!preview) return null;
|
|
35
|
+
// The stored prompt's attachment references become the restore payload
|
|
36
|
+
// the abort/queue restores use (pastedTexts / pastedImages / file parts).
|
|
37
|
+
const content = preview.message?.content;
|
|
38
|
+
if (!restoreFiles && Array.isArray(content) && content.some((part) => part?.type === 'file')) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
'this message has PDF/Office attachments the terminal composer cannot restore; edit it in the desktop app'
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const refs = restorableAttachmentsFromPrompt(content, text);
|
|
44
|
+
const attachments = hydrateTolerantly(refs.pastedImages, refs.pastedTexts, content);
|
|
45
|
+
// Refused when the history changed since the preview.
|
|
46
|
+
const rewound = await runtime.rewindMessages?.({
|
|
47
|
+
...rewindOptions,
|
|
48
|
+
...(preview.historyMarker ? { expectedHistoryMarker: preview.historyMarker } : {}),
|
|
49
|
+
});
|
|
50
|
+
if (!rewound) throw new Error('the conversation changed; select the message again');
|
|
24
51
|
set({
|
|
25
52
|
items: replaceItems(items.slice(0, index), {
|
|
26
53
|
preserveSpill: true,
|
|
@@ -36,7 +63,15 @@ export function createRewindAction(bag) {
|
|
|
36
63
|
syncContextStats({ allowEstimated: true });
|
|
37
64
|
set({ stats: { ...getState().stats } });
|
|
38
65
|
flushEmitImmediate?.();
|
|
39
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
text,
|
|
68
|
+
removed: items.length - index,
|
|
69
|
+
messages: rewound.removed,
|
|
70
|
+
...(attachments.pastedImages ? { pastedImages: attachments.pastedImages } : {}),
|
|
71
|
+
...(attachments.pastedTexts ? { pastedTexts: attachments.pastedTexts } : {}),
|
|
72
|
+
...(attachments.content ? { content: attachments.content } : {}),
|
|
73
|
+
...(attachments.notice ? { notice: attachments.notice } : {}),
|
|
74
|
+
};
|
|
40
75
|
} finally {
|
|
41
76
|
set({ commandBusy: false });
|
|
42
77
|
}
|
|
@@ -119,7 +119,8 @@ export function createSessionMediaApi(bag) {
|
|
|
119
119
|
// Media studio (image/video generation). Reads stay quiet, and there is no
|
|
120
120
|
// notice on start either: the Studio surfaces progress on its own pending
|
|
121
121
|
// tile, and a toast for a user-initiated generation is pure noise.
|
|
122
|
-
|
|
122
|
+
// `{ budgetMs }` bounds the per-lane catalog wait (Studio, Settings).
|
|
123
|
+
listMediaLanes: (options) => runtime.listMediaLanes?.(options),
|
|
123
124
|
getMediaDefault: (kind) => runtime.getMediaDefault?.(kind),
|
|
124
125
|
setMediaDefault: (input) => runtime.setMediaDefault?.(input),
|
|
125
126
|
getMediaPins: () => runtime.getMediaPins?.(),
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* routes-agent-definitions.mjs — the session route surface's passthroughs to
|
|
3
|
+
* the runtime's agent, workflow-pack, connector and lead-identity services.
|
|
4
|
+
*/
|
|
5
|
+
export function createAgentDefinitionApi(runtime) {
|
|
6
|
+
return {
|
|
7
|
+
listAgents: () => {
|
|
8
|
+
return runtime.listAgents?.() || [];
|
|
9
|
+
},
|
|
10
|
+
listWorkflows: () => {
|
|
11
|
+
return runtime.listWorkflows?.() || [];
|
|
12
|
+
},
|
|
13
|
+
// Workflow pack editing (desktop Workflows page): direct passthroughs —
|
|
14
|
+
// the runtime owns validation, user-pack persistence, and delete guards.
|
|
15
|
+
getWorkflowPack: (workflowId) => runtime.getWorkflowPack?.(workflowId) ?? null,
|
|
16
|
+
saveWorkflowPack: async (payload) => runtime.saveWorkflowPack?.(payload) ?? null,
|
|
17
|
+
createWorkflow: async (payload) => runtime.createWorkflow?.(payload) ?? null,
|
|
18
|
+
deleteWorkflow: async (workflowId) => runtime.deleteWorkflow?.(workflowId) ?? null,
|
|
19
|
+
getAgentDefinition: (agentId) => runtime.getAgentDefinition?.(agentId) ?? null,
|
|
20
|
+
getAgentAvatarImage: (agentId) => runtime.getAgentAvatarImage?.(agentId) ?? null,
|
|
21
|
+
getAgentConnectors: (agentId) => runtime.getAgentConnectors?.(agentId) ?? [],
|
|
22
|
+
listConnectors: () => runtime.listConnectors?.() ?? [],
|
|
23
|
+
listConnectorTools: (connectorId) => runtime.listConnectorTools?.(connectorId) ?? [],
|
|
24
|
+
// `options.noWiden` is only ever added by the desktop's remote method table: the
|
|
25
|
+
// change is refused if it would give the agent more authority (checked atomically with the write).
|
|
26
|
+
setAgentConnectors: async (agentId, connectors, options) =>
|
|
27
|
+
runtime.setAgentConnectors?.(agentId, connectors, options) ?? null,
|
|
28
|
+
setAgentConnectorEnabled: async (agentId, connectorId, enabled, options) =>
|
|
29
|
+
runtime.setAgentConnectorEnabled?.(agentId, connectorId, enabled, options) ?? [],
|
|
30
|
+
getProjectConnectors: (projectPath) => runtime.getProjectConnectors?.(projectPath) ?? [],
|
|
31
|
+
setProjectConnectorEnabled: async (projectPath, connectorId, enabled, options) =>
|
|
32
|
+
runtime.setProjectConnectorEnabled?.(projectPath, connectorId, enabled, options) ?? [],
|
|
33
|
+
setAgentConnectorToolPermission: async (agentId, connectorId, toolName, permission, options) =>
|
|
34
|
+
runtime.setAgentConnectorToolPermission?.(agentId, connectorId, toolName, permission, options) ?? null,
|
|
35
|
+
getAgentAlwaysAllowedTools: (agentId) => runtime.getAgentAlwaysAllowedTools?.(agentId) ?? [],
|
|
36
|
+
// Per-agent action-kind permissions (ask / allow / block) for the profile.
|
|
37
|
+
getAgentPermissions: async (agentId) =>
|
|
38
|
+
(await import('../../../runtime/agent/orchestrator/session/human-gate/store.mjs')).agentPermissions(agentId),
|
|
39
|
+
setAgentPermission: async (agentId, action, mode, options) =>
|
|
40
|
+
(await import('../../../runtime/agent/orchestrator/session/human-gate/store.mjs')).setAgentPermission(
|
|
41
|
+
agentId,
|
|
42
|
+
action,
|
|
43
|
+
mode,
|
|
44
|
+
options
|
|
45
|
+
),
|
|
46
|
+
recordAgentApprovalAudit: async (agentId, action, decision) =>
|
|
47
|
+
(await import('../../../runtime/agent/orchestrator/session/human-gate/store.mjs')).recordAgentApprovalAudit(
|
|
48
|
+
agentId,
|
|
49
|
+
action,
|
|
50
|
+
decision
|
|
51
|
+
),
|
|
52
|
+
getLeadPersona: () => runtime.getLeadPersona?.() ?? '',
|
|
53
|
+
saveLeadPersona: async (text) => runtime.saveLeadPersona?.(text) ?? '',
|
|
54
|
+
getLeadAgentBody: () => runtime.getLeadAgentBody?.() ?? '',
|
|
55
|
+
saveLeadAgentBody: async (text) => runtime.saveLeadAgentBody?.(text) ?? '',
|
|
56
|
+
getLeadStatus: () =>
|
|
57
|
+
runtime.getLeadStatus?.() ?? { created: null, name: '', avatar: null, homeChatted: false, route: null },
|
|
58
|
+
getLeadHomeRoute: () => runtime.getLeadHomeRoute?.() ?? null,
|
|
59
|
+
saveLeadIdentity: async (payload) => runtime.saveLeadIdentity?.(payload) ?? null,
|
|
60
|
+
setLeadCreated: async (created, description) => runtime.setLeadCreated?.(created, description) ?? null,
|
|
61
|
+
saveAgentDefinition: async (payload, options) => runtime.saveAgentDefinition?.(payload, options) ?? null,
|
|
62
|
+
deleteAgentDefinition: async (agentId) => runtime.deleteAgentDefinition?.(agentId) ?? null,
|
|
63
|
+
agentDefinitionPresence: (agentIds) => runtime.agentDefinitionPresence?.(agentIds) ?? null,
|
|
64
|
+
restoreAgentDefinition: async (agentId) => runtime.restoreAgentDefinition?.(agentId) ?? null,
|
|
65
|
+
purgeAgentDefinition: async (agentId) => runtime.purgeAgentDefinition?.(agentId) ?? null,
|
|
66
|
+
archivedAgentIdentities: (agentIds) => runtime.archivedAgentIdentities?.(agentIds) ?? null,
|
|
67
|
+
// Group-room rows posted by the desktop host into a room's log session.
|
|
68
|
+
appendRoomRows: async (sessionId, rows) =>
|
|
69
|
+
(await import('../../../session-runtime/agent-room-delivery.mjs')).appendRoomRows(sessionId, rows),
|
|
70
|
+
// One group-room supervisor step on the Maintainer route.
|
|
71
|
+
decideRoomTurn: async (input) =>
|
|
72
|
+
(await import('../../../runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs')).decideRoomTurn(
|
|
73
|
+
input
|
|
74
|
+
),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* routes-write.mjs — the serialized, optimistic route write behind the
|
|
3
|
+
* session's setRoute (every model picker, presets, agent child routes).
|
|
4
|
+
*/
|
|
5
|
+
import { modelSwitchItem } from '../../../runtime/agent/orchestrator/session/transcript-restore/restore.mjs';
|
|
6
|
+
import { selectedModel } from '../../../session-runtime/model-route/model-switch-target.mjs';
|
|
7
|
+
|
|
8
|
+
// Optimistic route preview: the requested provider/model/effort/fast are
|
|
9
|
+
// published before the runtime write settles. What is NOT previewed about the
|
|
10
|
+
// route (effort options, Fast capability, context window) is provider
|
|
11
|
+
// metadata the runtime resolves while the preview is already on screen.
|
|
12
|
+
const ROUTE_PREVIEW_KEYS = [
|
|
13
|
+
'provider',
|
|
14
|
+
'model',
|
|
15
|
+
'effort',
|
|
16
|
+
'fast',
|
|
17
|
+
'autoEffort',
|
|
18
|
+
'modelParameters',
|
|
19
|
+
'contextPercent',
|
|
20
|
+
'contextTokens',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The patch that publishes a requested route before the runtime write settles.
|
|
25
|
+
* Returns null when the request carries nothing previewable.
|
|
26
|
+
*/
|
|
27
|
+
function optimisticRoutePatch(requested = {}, current = {}) {
|
|
28
|
+
const route = requested && typeof requested === 'object' ? requested : {};
|
|
29
|
+
const has = (key) => Object.hasOwn(route, key);
|
|
30
|
+
const patch = {};
|
|
31
|
+
for (const key of ROUTE_PREVIEW_KEYS) {
|
|
32
|
+
if (has(key)) patch[key] = route[key];
|
|
33
|
+
}
|
|
34
|
+
if (!has('provider') && !has('model')) {
|
|
35
|
+
return Object.keys(patch).length > 0 ? patch : null;
|
|
36
|
+
}
|
|
37
|
+
const sameModel =
|
|
38
|
+
String(patch.provider ?? current.provider ?? '') === String(current.provider ?? '') &&
|
|
39
|
+
String(patch.model ?? current.model ?? '') === String(current.model ?? '');
|
|
40
|
+
// A different model carries none of the previous model's tuning: an omitted
|
|
41
|
+
// key means "this model has no such control", not "keep the old value".
|
|
42
|
+
if (!sameModel) {
|
|
43
|
+
if (!has('effort')) patch.effort = null;
|
|
44
|
+
if (!has('fast')) patch.fast = false;
|
|
45
|
+
if (!has('modelParameters')) patch.modelParameters = {};
|
|
46
|
+
}
|
|
47
|
+
return patch;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const SESSION_ONLY_KEYS = new Set(['provider', 'model', 'effort', 'fast', 'autoEffort']);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A session-only request (an agent child's route) may name just the model, just
|
|
54
|
+
* the tuning, or both. Completed here, inside the serialized route write,
|
|
55
|
+
* against the latest selected route — so a Fast-only change keeps the effort a
|
|
56
|
+
* previous write selected. `unchanged` when it asks for nothing the selected
|
|
57
|
+
* route does not already have.
|
|
58
|
+
*/
|
|
59
|
+
function completeSessionOnlyRequest(request, selected) {
|
|
60
|
+
const named = Boolean(request.provider || request.model);
|
|
61
|
+
const target = named ? request : { ...request, provider: selected.provider, model: selected.model };
|
|
62
|
+
const sameModel = target.provider === selected.provider && target.model === selected.model;
|
|
63
|
+
if (!sameModel) return { request: target, unchanged: false };
|
|
64
|
+
const unchanged =
|
|
65
|
+
Object.keys(request).every((key) => SESSION_ONLY_KEYS.has(key)) &&
|
|
66
|
+
(request.effort === undefined || request.effort === selected.effort) &&
|
|
67
|
+
(request.fast === undefined || request.fast === (selected.fast === true)) &&
|
|
68
|
+
(request.autoEffort === undefined || request.autoEffort === (selected.autoEffort !== false));
|
|
69
|
+
return {
|
|
70
|
+
unchanged,
|
|
71
|
+
request: {
|
|
72
|
+
...(selected.effort ? { effort: selected.effort } : {}),
|
|
73
|
+
fast: selected.fast === true,
|
|
74
|
+
autoEffort: selected.autoEffort !== false,
|
|
75
|
+
...target,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The live divider of an in-place model switch (restored from message meta
|
|
81
|
+
* after a reload); every switch path publishes it the same way. */
|
|
82
|
+
export function publishModelSwitch(bag, modelSwitch) {
|
|
83
|
+
if (modelSwitch) bag.pushItem(modelSwitchItem(bag.nextId(), modelSwitch));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function createRouteWrite(
|
|
87
|
+
bag,
|
|
88
|
+
{ runtime, getState, set, flushEmitImmediate, routeState, syncContextStats, publishRoute }
|
|
89
|
+
) {
|
|
90
|
+
let routeWrite = null;
|
|
91
|
+
let routeSequence = 0;
|
|
92
|
+
// Whether this API (not another command) is the one holding commandBusy.
|
|
93
|
+
let routeLocked = false;
|
|
94
|
+
|
|
95
|
+
// A preset selector previews as the preset's model, never as its id.
|
|
96
|
+
const previewedRequest = (routeOpts) => {
|
|
97
|
+
if (routeOpts.provider || !routeOpts.model) return routeOpts;
|
|
98
|
+
const target = selectedModel(runtime, routeOpts, '', '');
|
|
99
|
+
return target.provider ? { ...routeOpts, ...target } : routeOpts;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const setRoute = async (opts) => {
|
|
103
|
+
const routeOpts = opts && typeof opts === 'object' ? opts : {};
|
|
104
|
+
// All model pickers save a selection for the conversation's next turn; a
|
|
105
|
+
// running turn keeps the session model it started on. A selection is never
|
|
106
|
+
// refused: another command's lock neither blocks it nor is released by it.
|
|
107
|
+
const token = ++routeSequence;
|
|
108
|
+
const previousWrite = routeWrite;
|
|
109
|
+
// The session generation this selection was made under. The write below
|
|
110
|
+
// waits behind earlier ones, so "current" is never read later: the runtime
|
|
111
|
+
// validates this token before every route side effect, and `settle` below
|
|
112
|
+
// is the only place the display is touched once the write has started.
|
|
113
|
+
const originGeneration = runtime.sessionGeneration;
|
|
114
|
+
const owned = () => runtime.sessionGeneration === originGeneration;
|
|
115
|
+
// A conditional fill (only when the route is still empty) may not apply, so
|
|
116
|
+
// it never previews: the runtime's answer is what gets published.
|
|
117
|
+
const onlyIfEmpty = routeOpts.onlyIfEmpty === true;
|
|
118
|
+
const preview = onlyIfEmpty ? null : optimisticRoutePatch(previewedRequest(routeOpts), getState());
|
|
119
|
+
// Preview immediately, serialize persistence without dropping a later
|
|
120
|
+
// click. Earlier completions cannot replace the newest visible choice.
|
|
121
|
+
if (!getState().commandBusy) routeLocked = true;
|
|
122
|
+
set({ ...(routeLocked ? { commandBusy: true } : {}), ...(preview || {}) });
|
|
123
|
+
flushEmitImmediate();
|
|
124
|
+
const write = (async () => {
|
|
125
|
+
if (previousWrite) await previousWrite.catch(() => {});
|
|
126
|
+
const previousRoute = routeState();
|
|
127
|
+
// A stale selection only republishes the route that is actually
|
|
128
|
+
// selected; it never restores or announces its own session's state.
|
|
129
|
+
const settle = ({ failed = false, sync = false, modelSwitch = null } = {}) => {
|
|
130
|
+
const stillOwned = owned();
|
|
131
|
+
if (stillOwned) publishModelSwitch(bag, modelSwitch);
|
|
132
|
+
// A newer selection publishes the final route itself.
|
|
133
|
+
if (token !== routeSequence) return;
|
|
134
|
+
if (stillOwned && failed) {
|
|
135
|
+
if (preview) set({ ...previousRoute, stats: { ...getState().stats } });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (stillOwned && sync) syncContextStats({ allowEstimated: true });
|
|
139
|
+
publishRoute();
|
|
140
|
+
};
|
|
141
|
+
try {
|
|
142
|
+
// Keep the durable session address while deferring route application.
|
|
143
|
+
const applyToCurrentSession = routeOpts.applyToCurrentSession === true;
|
|
144
|
+
const keepMainModel = routeOpts.keepMainModel !== false;
|
|
145
|
+
const sessionOnly = routeOpts.sessionOnly === true;
|
|
146
|
+
const {
|
|
147
|
+
applyToCurrentSession: _drop,
|
|
148
|
+
keepMainModel: _keep,
|
|
149
|
+
sessionOnly: _scope,
|
|
150
|
+
onlyIfEmpty: _fill,
|
|
151
|
+
...requested
|
|
152
|
+
} = routeOpts;
|
|
153
|
+
let nextRoute = requested;
|
|
154
|
+
if (sessionOnly) {
|
|
155
|
+
const completed = completeSessionOnlyRequest(requested, previousRoute);
|
|
156
|
+
if (completed.unchanged) {
|
|
157
|
+
// An earlier failed write skipped its rollback because this one is
|
|
158
|
+
// newer, so the shown route may still be that write's preview.
|
|
159
|
+
settle();
|
|
160
|
+
return previousRoute;
|
|
161
|
+
}
|
|
162
|
+
nextRoute = completed.request;
|
|
163
|
+
}
|
|
164
|
+
const resolvedRoute = await runtime.setRoute(nextRoute, {
|
|
165
|
+
applyToCurrentSession,
|
|
166
|
+
keepMainModel,
|
|
167
|
+
...(sessionOnly ? { sessionOnly } : {}),
|
|
168
|
+
...(onlyIfEmpty ? { onlyIfEmpty } : {}),
|
|
169
|
+
...(originGeneration !== undefined ? { originGeneration } : {}),
|
|
170
|
+
switchEstablished: true,
|
|
171
|
+
deferUntilNextTurn: true,
|
|
172
|
+
});
|
|
173
|
+
settle({
|
|
174
|
+
sync: applyToCurrentSession || Boolean(resolvedRoute?.modelSwitch),
|
|
175
|
+
modelSwitch: resolvedRoute?.modelSwitch,
|
|
176
|
+
});
|
|
177
|
+
return resolvedRoute;
|
|
178
|
+
} catch (error) {
|
|
179
|
+
settle({ failed: true });
|
|
180
|
+
throw error;
|
|
181
|
+
} finally {
|
|
182
|
+
if (token === routeSequence) {
|
|
183
|
+
if (routeLocked) set({ commandBusy: false });
|
|
184
|
+
routeLocked = false;
|
|
185
|
+
// Publish the resolved route (or rollback) before an RPC reply
|
|
186
|
+
// reads getState(), even while the display-frame clock is busy.
|
|
187
|
+
flushEmitImmediate();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
})();
|
|
191
|
+
routeWrite = write;
|
|
192
|
+
try {
|
|
193
|
+
return await write;
|
|
194
|
+
} finally {
|
|
195
|
+
if (routeWrite === write) routeWrite = null;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
// The settings surface's setModel (/model, presets) is the same user
|
|
199
|
+
// model choice and runs through this one path.
|
|
200
|
+
bag.setSessionRoute = setRoute;
|
|
201
|
+
|
|
202
|
+
return setRoute;
|
|
203
|
+
}
|