mixdog 1.3.0 → 1.3.2
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/NOTICE.md +52 -9
- package/README.md +8 -4
- package/package.json +2 -2
- package/scripts/native-release-status.mjs +238 -0
- package/src/defaults/shipped-history.json +8 -1
- 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 +54 -4
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +17 -10
- 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/output-styles/common.md +13 -8
- package/src/rules/agent-mode/AGENT_MODE.md +9 -6
- package/src/rules/agent-mode/MIXY.md +11 -6
- package/src/rules/lead/LEAD.md +2 -2
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- 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 +81 -16
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -4
- 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 +80 -31
- 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 +67 -38
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +34 -16
- 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.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +19 -1
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -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-retry-profile.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +10 -2
- 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-responses-input.mjs +3 -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/provider-error-kind.mjs +14 -2
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
- 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-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +5 -5
- 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 +12 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +17 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +41 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +2 -0
- 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 +21 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +149 -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/execution-tail.mjs +14 -11
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +68 -18
- 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 +5 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +1 -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 +230 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +156 -25
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +21 -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 +189 -105
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +111 -9
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +11 -14
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +38 -5
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +21 -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/loop/usage.mjs +46 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +99 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -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/provider-replay.mjs +50 -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-lifecycle.mjs +62 -47
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +6 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +42 -10
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +35 -4
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +179 -16
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -1
- 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/sweep-record.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +36 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -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/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 +49 -14
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +134 -17
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +35 -13
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -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/lib/shell-job-records.mjs +6 -14
- 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 +34 -21
- 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/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/store.mjs +55 -30
- 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 +6 -3
- package/src/runtime/effort-judge/model-install.mjs +16 -8
- package/src/runtime/effort-judge/model-manifest.json +7 -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/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 +4 -0
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-kind.mjs +152 -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-route-config.d.mts +1 -0
- package/src/runtime/shared/agent-route-config.mjs +22 -8
- package/src/runtime/shared/agent-store.mjs +149 -0
- 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 +30 -0
- package/src/runtime/shared/bot-split-migration.mjs +457 -0
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config-patch.mjs +20 -1
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/connector-catalog.d.mts +1 -2
- package/src/runtime/shared/connector-catalog.mjs +2 -4
- package/src/runtime/shared/connector-triggers.mjs +2 -0
- 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 +7 -1
- package/src/runtime/shared/error-presentation.mjs +113 -10
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
- package/src/runtime/shared/handoff-artifacts.mjs +61 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +6 -1
- package/src/runtime/shared/llm/usage-accounting.mjs +7 -1
- package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/model-route-fallback.mjs +79 -7
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/plain-preview.mjs +22 -17
- 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/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/sensitive-path-rules.d.mts +15 -0
- package/src/runtime/shared/sensitive-path-rules.mjs +256 -0
- package/src/runtime/shared/session-baseline-store.mjs +8 -2
- 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 +6 -0
- 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 +44 -2
- package/src/runtime/shared/usage-readout-totals.mjs +15 -13
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +46 -44
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +269 -61
- package/src/runtime/shared/worktrees/registry.mjs +26 -26
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +859 -136
- package/src/session-runtime/agent-room-delivery.mjs +167 -19
- package/src/session-runtime/agent-task-sessions.mjs +831 -69
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +58 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +11 -1
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +16 -6
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +2 -2
- 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 +78 -32
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/handoff-attachments.mjs +593 -0
- package/src/session-runtime/held-requests.mjs +36 -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 +45 -6
- 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-route/route-persist.mjs +2 -2
- package/src/session-runtime/model-route/route-tuning.mjs +11 -2
- package/src/session-runtime/model-route/set-route.mjs +82 -2
- package/src/session-runtime/native-web-search.mjs +2 -2
- package/src/session-runtime/new-session-config.mjs +6 -1
- package/src/session-runtime/owned-automation-run.mjs +8 -1
- package/src/session-runtime/room-member-gate.mjs +16 -3
- package/src/session-runtime/route-resolution.mjs +21 -19
- 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-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/helpers.mjs +24 -5
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +36 -24
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -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 +12 -6
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +5 -8
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- 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 +14 -4
- 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/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +63 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +20 -3
- package/src/session-runtime/setup-tool/extended-actions.mjs +19 -7
- package/src/session-runtime/setup-tool/settings-contract.mjs +37 -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 +265 -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 +165 -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 +47 -358
- package/src/session-runtime/tool-surface.mjs +5 -3
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +99 -81
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +2 -1
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +578 -301
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +113 -53
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
- 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/workspace-state.mjs +7 -6
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-session-control.mjs +60 -11
- package/src/standalone/daemon.mjs +34 -4
- package/src/standalone/local-session-runtime.mjs +22 -14
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +46 -3
- package/src/standalone/session-service/agent-tree.mjs +4 -3
- package/src/standalone/session-service/session-calls/session-turns.mjs +19 -0
- package/src/standalone/session-service.mjs +11 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +35 -9
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- 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 +599 -342
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/notice-surface.mjs +3 -4
- package/src/tui/session/session-api/intake/abort.mjs +19 -1
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +75 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -236
- 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 +185 -20
- package/src/tui/session/transcript-intake.mjs +4 -0
- package/src/tui/session/turn-live-call.mjs +11 -3
- package/src/tui/session/turn.mjs +36 -17
- 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
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
// connect. All mutable progress lives on the caller-owned `state`.
|
|
4
4
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
5
5
|
import { envFlag } from '../../runtime/shared/env.mjs';
|
|
6
|
+
import { awaitInitialConnect } from './initial-connect-gate.mjs';
|
|
6
7
|
import { ensurePluginServerData } from './plugin-servers.mjs';
|
|
8
|
+
import { createServerConnection } from './server-connection.mjs';
|
|
7
9
|
|
|
8
10
|
export function createMcpConnect({
|
|
9
11
|
mcpClient,
|
|
@@ -29,58 +31,100 @@ export function createMcpConnect({
|
|
|
29
31
|
// Answer it with the redirect URL pasted from the browser.
|
|
30
32
|
const completeMcpLogin = (name, callbackUrl) => mcpClient.completeMcpLogin(clean(name), callbackUrl, scopeOptions());
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
await
|
|
48
|
-
|
|
34
|
+
const { applyMcpServerConnection, reconcileServers } = createServerConnection({
|
|
35
|
+
mcpClient,
|
|
36
|
+
state,
|
|
37
|
+
resolveEffectiveMcpServers,
|
|
38
|
+
getMcpScopeId,
|
|
39
|
+
scopeOptions,
|
|
40
|
+
applied,
|
|
41
|
+
fingerprint,
|
|
42
|
+
syncScopeRoot,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Wait for a prior run (its failures were already captured in state).
|
|
46
|
+
async function settled(prior) {
|
|
47
|
+
if (!prior) return;
|
|
48
|
+
try {
|
|
49
|
+
await prior;
|
|
50
|
+
} catch {
|
|
51
|
+
/* prior run's failures already captured */
|
|
49
52
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Register `run` as the in-flight connect so a later reset serializes
|
|
56
|
+
// behind it instead of interleaving disconnect/connect.
|
|
57
|
+
async function trackInFlight(run) {
|
|
58
|
+
state.mcpConnectInFlight = run;
|
|
53
59
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
target,
|
|
58
|
-
cfg,
|
|
59
|
-
login ? { interactive: true, openBrowser: login.openBrowser } : {}
|
|
60
|
-
);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
const failure = { name: target, msg: error?.message || String(error) };
|
|
63
|
-
if (error?.authRequired) failure.authRequired = true;
|
|
64
|
-
const failures = Array.isArray(error?.failures) ? error.failures : [failure];
|
|
65
|
-
state.mcpFailures = [...(state.mcpFailures || []), ...failures];
|
|
60
|
+
await run;
|
|
61
|
+
} finally {
|
|
62
|
+
if (state.mcpConnectInFlight === run) state.mcpConnectInFlight = null;
|
|
66
63
|
}
|
|
67
64
|
}
|
|
68
65
|
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
66
|
+
// Scoped single-server toggle (or reconcile): non-superseding. It must NEVER
|
|
67
|
+
// cancel a pending full {reset} (cwd-change/boot). So do not bump the
|
|
68
|
+
// generation; just wait for any in-flight run, then bail if a newer full
|
|
69
|
+
// reset has been requested in the meantime.
|
|
70
|
+
async function connectScoped({ only, enabled, reconcile, login }) {
|
|
71
|
+
// A disable/remove must not wait out an interactive login of the
|
|
72
|
+
// connect it queues behind: cancel that login first.
|
|
73
|
+
if (only && enabled === false) cancelMcpLogin(only);
|
|
74
|
+
// Atomically capture the current generation AND the prior in-flight
|
|
75
|
+
// promise in the same synchronous step, then chain our op onto it. No
|
|
76
|
+
// await sits between the capture and the `state.mcpConnectInFlight = run`
|
|
77
|
+
// assignment, so concurrent {only} calls queue FIFO instead of resuming
|
|
78
|
+
// together and clobbering the in-flight slot. We never bump the
|
|
79
|
+
// generation; a {reset} does, so any {only} queued behind a reset sees
|
|
80
|
+
// the newer generation when its turn comes and bails.
|
|
81
|
+
const gen = state.mcpConnectGeneration;
|
|
82
|
+
const prev = state.mcpConnectInFlight;
|
|
83
|
+
await trackInFlight(
|
|
84
|
+
(async () => {
|
|
85
|
+
await settled(prev);
|
|
86
|
+
if (gen !== state.mcpConnectGeneration) return;
|
|
87
|
+
if (reconcile) await reconcileServers();
|
|
88
|
+
else await applyMcpServerConnection(only, enabled, undefined, login);
|
|
89
|
+
})()
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Serialize reconnects: boot connect, cwd-change reset, and rapid cwd
|
|
94
|
+
// switches must never interleave their disconnect/connect phases, or an
|
|
95
|
+
// older run finishing after a newer reset could re-add stale servers into
|
|
96
|
+
// the shared client registry. Approach: a generation token + a single
|
|
97
|
+
// in-flight promise. Each call bumps the generation, waits for any prior
|
|
98
|
+
// run to finish, then bails if a newer call has superseded it — leaving the
|
|
99
|
+
// latest requested effective-server-set in the registry.
|
|
100
|
+
async function connectAll({ reset }) {
|
|
101
|
+
const gen = ++state.mcpConnectGeneration;
|
|
102
|
+
await settled(state.mcpConnectInFlight);
|
|
103
|
+
if (gen !== state.mcpConnectGeneration) return;
|
|
104
|
+
await trackInFlight(
|
|
105
|
+
(async () => {
|
|
106
|
+
if (reset) {
|
|
107
|
+
await mcpClient.disconnectAll?.(scopeOptions());
|
|
108
|
+
applied().clear();
|
|
109
|
+
}
|
|
110
|
+
state.mcpFailures = [];
|
|
111
|
+
syncScopeRoot();
|
|
112
|
+
const { servers } = resolveEffectiveMcpServers();
|
|
113
|
+
for (const [name, cfg] of Object.entries(servers)) {
|
|
114
|
+
if (cfg?.enabled === false) applied().delete(name);
|
|
115
|
+
else applied().set(name, fingerprint(cfg));
|
|
116
|
+
}
|
|
117
|
+
if (Object.keys(servers).length === 0) return;
|
|
118
|
+
try {
|
|
119
|
+
for (const cfg of Object.values(servers)) if (cfg?.enabled !== false) ensurePluginServerData(cfg);
|
|
120
|
+
await mcpClient.connectMcpServers(servers, scopeOptions());
|
|
121
|
+
} catch (error) {
|
|
122
|
+
state.mcpFailures = Array.isArray(error?.failures)
|
|
123
|
+
? error.failures
|
|
124
|
+
: [{ name: 'mcp', msg: error?.message || String(error) }];
|
|
125
|
+
}
|
|
126
|
+
})()
|
|
127
|
+
);
|
|
84
128
|
}
|
|
85
129
|
|
|
86
130
|
async function connectConfiguredMcp({
|
|
@@ -98,146 +142,16 @@ export function createMcpConnect({
|
|
|
98
142
|
else await mcpClient.disconnectAll?.(scopeOptions());
|
|
99
143
|
return mcpStatus();
|
|
100
144
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// just wait for any in-flight run, then bail if a newer full reset has
|
|
104
|
-
// been requested in the meantime. Registering as in-flight makes a later
|
|
105
|
-
// reset serialize behind us instead of interleaving disconnect/connect.
|
|
106
|
-
if (only || reconcile) {
|
|
107
|
-
// A disable/remove must not wait out an interactive login of the
|
|
108
|
-
// connect it queues behind: cancel that login first.
|
|
109
|
-
if (only && enabled === false) cancelMcpLogin(only);
|
|
110
|
-
// Atomically capture the current generation AND the prior in-flight
|
|
111
|
-
// promise in the same synchronous step, then chain our op onto it. No
|
|
112
|
-
// await sits between the capture and the `state.mcpConnectInFlight = run`
|
|
113
|
-
// assignment, so concurrent {only} calls queue FIFO instead of resuming
|
|
114
|
-
// together and clobbering the in-flight slot. We never bump the
|
|
115
|
-
// generation; a {reset} does, so any {only} queued behind a reset sees
|
|
116
|
-
// the newer generation when its turn comes and bails.
|
|
117
|
-
const gen = state.mcpConnectGeneration;
|
|
118
|
-
const prev = state.mcpConnectInFlight;
|
|
119
|
-
const run = (async () => {
|
|
120
|
-
if (prev) {
|
|
121
|
-
try {
|
|
122
|
-
await prev;
|
|
123
|
-
} catch {
|
|
124
|
-
/* prior run's failures already captured */
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (gen !== state.mcpConnectGeneration) return;
|
|
128
|
-
if (reconcile) await reconcileServers();
|
|
129
|
-
else await applyMcpServerConnection(only, enabled, undefined, login);
|
|
130
|
-
})();
|
|
131
|
-
state.mcpConnectInFlight = run;
|
|
132
|
-
try {
|
|
133
|
-
await run;
|
|
134
|
-
} finally {
|
|
135
|
-
if (state.mcpConnectInFlight === run) state.mcpConnectInFlight = null;
|
|
136
|
-
}
|
|
137
|
-
return mcpStatus();
|
|
138
|
-
}
|
|
139
|
-
// Serialize reconnects: boot connect, cwd-change reset, and rapid cwd
|
|
140
|
-
// switches must never interleave their disconnect/connect phases, or an
|
|
141
|
-
// older run finishing after a newer reset could re-add stale servers into
|
|
142
|
-
// the shared client registry. Approach: a generation token + a single
|
|
143
|
-
// in-flight promise. Each call bumps the generation, waits for any prior
|
|
144
|
-
// run to finish, then bails if a newer call has superseded it — leaving the
|
|
145
|
-
// latest requested effective-server-set in the registry.
|
|
146
|
-
const gen = ++state.mcpConnectGeneration;
|
|
147
|
-
if (state.mcpConnectInFlight) {
|
|
148
|
-
try {
|
|
149
|
-
await state.mcpConnectInFlight;
|
|
150
|
-
} catch {
|
|
151
|
-
/* prior run's failures already captured */
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (gen !== state.mcpConnectGeneration) return mcpStatus();
|
|
155
|
-
const run = (async () => {
|
|
156
|
-
if (reset) {
|
|
157
|
-
await mcpClient.disconnectAll?.(scopeOptions());
|
|
158
|
-
applied().clear();
|
|
159
|
-
}
|
|
160
|
-
state.mcpFailures = [];
|
|
161
|
-
syncScopeRoot();
|
|
162
|
-
const { servers } = resolveEffectiveMcpServers();
|
|
163
|
-
for (const [name, cfg] of Object.entries(servers)) {
|
|
164
|
-
if (cfg?.enabled === false) applied().delete(name);
|
|
165
|
-
else applied().set(name, fingerprint(cfg));
|
|
166
|
-
}
|
|
167
|
-
if (Object.keys(servers).length === 0) return;
|
|
168
|
-
try {
|
|
169
|
-
for (const cfg of Object.values(servers)) if (cfg?.enabled !== false) ensurePluginServerData(cfg);
|
|
170
|
-
await mcpClient.connectMcpServers(servers, scopeOptions());
|
|
171
|
-
} catch (error) {
|
|
172
|
-
state.mcpFailures = Array.isArray(error?.failures)
|
|
173
|
-
? error.failures
|
|
174
|
-
: [{ name: 'mcp', msg: error?.message || String(error) }];
|
|
175
|
-
}
|
|
176
|
-
})();
|
|
177
|
-
state.mcpConnectInFlight = run;
|
|
178
|
-
try {
|
|
179
|
-
await run;
|
|
180
|
-
} finally {
|
|
181
|
-
if (state.mcpConnectInFlight === run) state.mcpConnectInFlight = null;
|
|
182
|
-
}
|
|
145
|
+
if (only || reconcile) await connectScoped({ only, enabled, reconcile, login });
|
|
146
|
+
else await connectAll({ reset });
|
|
183
147
|
return mcpStatus();
|
|
184
148
|
}
|
|
185
149
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
let budgetMs = 10000;
|
|
194
|
-
try {
|
|
195
|
-
// The gate must outlast the slowest enabled server's own startup budget;
|
|
196
|
-
// a server with its budget disabled (0) means the connect may never
|
|
197
|
-
// settle, so the whole gate is disabled (handled below).
|
|
198
|
-
const configs = Object.values(resolveEffectiveMcpServers().servers).filter((cfg) => cfg?.enabled !== false);
|
|
199
|
-
const budgets = (configs.length > 0 ? configs : [{}])
|
|
200
|
-
.map((cfg) => mcpClient.resolveMcpStartupTimeoutMs?.(cfg))
|
|
201
|
-
.filter((value) => Number.isFinite(value));
|
|
202
|
-
if (budgets.length > 0) budgetMs = budgets.includes(0) ? 0 : Math.max(...budgets);
|
|
203
|
-
} catch {
|
|
204
|
-
/* fall back to default budget */
|
|
205
|
-
}
|
|
206
|
-
if (maxWaitMs !== null && maxWaitMs !== undefined) {
|
|
207
|
-
const requestedMaxWaitMs = Number(maxWaitMs);
|
|
208
|
-
if (Number.isFinite(requestedMaxWaitMs) && requestedMaxWaitMs >= 0) {
|
|
209
|
-
budgetMs = Math.min(budgetMs, requestedMaxWaitMs);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
// Budget disabled (0/off) = no per-server startup timeout, so the connect
|
|
213
|
-
// promise may never settle; never gate the turn on it — fall back to the
|
|
214
|
-
// legacy fire-and-forget behavior (late servers use the deferred path).
|
|
215
|
-
if (!(budgetMs > 0)) return;
|
|
216
|
-
let timer = null;
|
|
217
|
-
let expired = false;
|
|
218
|
-
const budget = new Promise((resolveBudget) => {
|
|
219
|
-
timer = setTimeout(() => {
|
|
220
|
-
expired = true;
|
|
221
|
-
resolveBudget();
|
|
222
|
-
}, budgetMs);
|
|
223
|
-
});
|
|
224
|
-
try {
|
|
225
|
-
// Follow replacement connects (a reconnect queued behind the captured
|
|
226
|
-
// run installs a new in-flight promise) inside ONE fixed deadline.
|
|
227
|
-
// Failures are already captured in state.mcpFailures, so rejections are
|
|
228
|
-
// swallowed: this gate must never reject the turn.
|
|
229
|
-
let current = inFlight;
|
|
230
|
-
while (current && !expired) {
|
|
231
|
-
await Promise.race([Promise.resolve(current).catch(() => {}), budget]);
|
|
232
|
-
if (expired) break;
|
|
233
|
-
// Let a queued reconnect install its promise before re-checking.
|
|
234
|
-
await Promise.race([new Promise((resolveTick) => setImmediate(resolveTick)), budget]);
|
|
235
|
-
current = state.mcpConnectInFlight;
|
|
236
|
-
}
|
|
237
|
-
} finally {
|
|
238
|
-
if (timer) clearTimeout(timer);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return { connectConfiguredMcp, awaitInitialMcpConnect, cancelMcpLogin, completeMcpLogin };
|
|
150
|
+
return {
|
|
151
|
+
connectConfiguredMcp,
|
|
152
|
+
awaitInitialMcpConnect: (maxWaitMs) =>
|
|
153
|
+
awaitInitialConnect({ state, mcpClient, resolveEffectiveMcpServers }, maxWaitMs),
|
|
154
|
+
cancelMcpLogin,
|
|
155
|
+
completeMcpLogin,
|
|
156
|
+
};
|
|
243
157
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The turn gate on the initial MCP connect: a bounded wait, never a rejection.
|
|
2
|
+
|
|
3
|
+
// Turn gate: await the in-flight INITIAL connect, bounded by both the global
|
|
4
|
+
// server startup budget and the caller's TTFT grace. A server still
|
|
5
|
+
// connecting after the grace flows through the existing late-tool deferred
|
|
6
|
+
// announcement path unchanged.
|
|
7
|
+
export async function awaitInitialConnect({ state, mcpClient, resolveEffectiveMcpServers }, maxWaitMs = undefined) {
|
|
8
|
+
const inFlight = state.mcpConnectInFlight;
|
|
9
|
+
if (!inFlight) return;
|
|
10
|
+
let budgetMs = 10000;
|
|
11
|
+
try {
|
|
12
|
+
// The gate must outlast the slowest enabled server's own startup budget;
|
|
13
|
+
// a server with its budget disabled (0) means the connect may never
|
|
14
|
+
// settle, so the whole gate is disabled (handled below).
|
|
15
|
+
const configs = Object.values(resolveEffectiveMcpServers().servers).filter((cfg) => cfg?.enabled !== false);
|
|
16
|
+
const budgets = (configs.length > 0 ? configs : [{}])
|
|
17
|
+
.map((cfg) => mcpClient.resolveMcpStartupTimeoutMs?.(cfg))
|
|
18
|
+
.filter((value) => Number.isFinite(value));
|
|
19
|
+
if (budgets.length > 0) budgetMs = budgets.includes(0) ? 0 : Math.max(...budgets);
|
|
20
|
+
} catch {
|
|
21
|
+
/* fall back to default budget */
|
|
22
|
+
}
|
|
23
|
+
if (maxWaitMs !== null && maxWaitMs !== undefined) {
|
|
24
|
+
const requestedMaxWaitMs = Number(maxWaitMs);
|
|
25
|
+
if (Number.isFinite(requestedMaxWaitMs) && requestedMaxWaitMs >= 0) {
|
|
26
|
+
budgetMs = Math.min(budgetMs, requestedMaxWaitMs);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Budget disabled (0/off) = no per-server startup timeout, so the connect
|
|
30
|
+
// promise may never settle; never gate the turn on it — fall back to the
|
|
31
|
+
// legacy fire-and-forget behavior (late servers use the deferred path).
|
|
32
|
+
if (!(budgetMs > 0)) return;
|
|
33
|
+
let timer = null;
|
|
34
|
+
let expired = false;
|
|
35
|
+
const budget = new Promise((resolveBudget) => {
|
|
36
|
+
timer = setTimeout(() => {
|
|
37
|
+
expired = true;
|
|
38
|
+
resolveBudget();
|
|
39
|
+
}, budgetMs);
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
// Follow replacement connects (a reconnect queued behind the captured
|
|
43
|
+
// run installs a new in-flight promise) inside ONE fixed deadline.
|
|
44
|
+
// Failures are already captured in state.mcpFailures, so rejections are
|
|
45
|
+
// swallowed: this gate must never reject the turn.
|
|
46
|
+
let current = inFlight;
|
|
47
|
+
while (current && !expired) {
|
|
48
|
+
await Promise.race([Promise.resolve(current).catch(() => {}), budget]);
|
|
49
|
+
if (expired) break;
|
|
50
|
+
// Let a queued reconnect install its promise before re-checking.
|
|
51
|
+
await Promise.race([new Promise((resolveTick) => setImmediate(resolveTick)), budget]);
|
|
52
|
+
current = state.mcpConnectInFlight;
|
|
53
|
+
}
|
|
54
|
+
} finally {
|
|
55
|
+
if (timer) clearTimeout(timer);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Connecting, disconnecting and reconciling individual MCP servers in the live
|
|
2
|
+
// registry. The caller (connect.mjs) owns the serialization and the shared state.
|
|
3
|
+
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
4
|
+
import { ensurePluginServerData } from './plugin-servers.mjs';
|
|
5
|
+
|
|
6
|
+
export function createServerConnection({
|
|
7
|
+
mcpClient,
|
|
8
|
+
state,
|
|
9
|
+
resolveEffectiveMcpServers,
|
|
10
|
+
getMcpScopeId,
|
|
11
|
+
scopeOptions,
|
|
12
|
+
applied,
|
|
13
|
+
fingerprint,
|
|
14
|
+
syncScopeRoot,
|
|
15
|
+
}) {
|
|
16
|
+
// Connect/disconnect exactly one server in the live registry, leaving all
|
|
17
|
+
// others untouched. Used by the enable/disable toggle so a single-server
|
|
18
|
+
// change never triggers a full disconnectAll()/reconnect freeze. Only an
|
|
19
|
+
// explicit sign-in passes `login` ({ openBrowser }): every other connect is
|
|
20
|
+
// non-interactive and reports a server that needs one as sign-in required.
|
|
21
|
+
async function applyMcpServerConnection(name, enabled, servers = resolveEffectiveMcpServers().servers, login = null) {
|
|
22
|
+
const target = clean(name);
|
|
23
|
+
if (!target) return;
|
|
24
|
+
// Changing this server's state clears any stale failure record for it.
|
|
25
|
+
if (Array.isArray(state.mcpFailures)) {
|
|
26
|
+
state.mcpFailures = state.mcpFailures.filter((row) => row.name !== target);
|
|
27
|
+
}
|
|
28
|
+
const cfg = servers[target];
|
|
29
|
+
if (enabled === false || !cfg || cfg.enabled === false) {
|
|
30
|
+
applied().delete(target);
|
|
31
|
+
await mcpClient.disconnectMcpServer?.(target, scopeOptions());
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
applied().set(target, fingerprint(cfg));
|
|
35
|
+
// Close-then-connect as one generation-guarded op: a shutdown landing
|
|
36
|
+
// between the close and the connect never resurrects the server.
|
|
37
|
+
try {
|
|
38
|
+
ensurePluginServerData(cfg);
|
|
39
|
+
await mcpClient.reconnectSingleMcpServer(
|
|
40
|
+
getMcpScopeId(),
|
|
41
|
+
target,
|
|
42
|
+
cfg,
|
|
43
|
+
login ? { interactive: true, openBrowser: login.openBrowser } : {}
|
|
44
|
+
);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
const failure = { name: target, msg: error?.message || String(error) };
|
|
47
|
+
if (error?.authRequired) failure.authRequired = true;
|
|
48
|
+
const failures = Array.isArray(error?.failures) ? error.failures : [failure];
|
|
49
|
+
state.mcpFailures = [...(state.mcpFailures || []), ...failures];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Bring the registry in line with the effective set: drop servers that are
|
|
54
|
+
// gone or disabled, (re)connect servers that are new or whose resolved
|
|
55
|
+
// config changed; untouched servers keep their connection.
|
|
56
|
+
async function reconcileServers() {
|
|
57
|
+
syncScopeRoot();
|
|
58
|
+
const { servers } = resolveEffectiveMcpServers();
|
|
59
|
+
const known = applied();
|
|
60
|
+
const drops = [...known.keys()].filter((name) => !servers[name] || servers[name].enabled === false);
|
|
61
|
+
const connects = Object.entries(servers)
|
|
62
|
+
.filter(([name, cfg]) => cfg?.enabled !== false && known.get(name) !== fingerprint(cfg))
|
|
63
|
+
.map(([name]) => name);
|
|
64
|
+
await Promise.allSettled([
|
|
65
|
+
...drops.map((name) => applyMcpServerConnection(name, false, servers)),
|
|
66
|
+
...connects.map((name) => applyMcpServerConnection(name, true, servers)),
|
|
67
|
+
]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { applyMcpServerConnection, reconcileServers };
|
|
71
|
+
}
|
|
@@ -41,8 +41,11 @@ export function createMediaApi() {
|
|
|
41
41
|
});
|
|
42
42
|
return { status: await module.getVoiceStatus(), error };
|
|
43
43
|
},
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
// `budgetMs` (Studio) caps the per-lane catalog wait; slower lanes come
|
|
45
|
+
// back `catalogPending`. Capped so a caller cannot park the call.
|
|
46
|
+
async listMediaLanes(options) {
|
|
47
|
+
const budgetMs = Math.min(30_000, Math.max(0, Math.trunc(Number(options?.budgetMs) || 0)));
|
|
48
|
+
return (await lanes()).listMediaLanes({ budgetMs });
|
|
46
49
|
},
|
|
47
50
|
// The Studio's current selection is the runtime's default: a tool call
|
|
48
51
|
// that omits lane/model follows it. Studio pushes on every settled change.
|
|
@@ -35,7 +35,7 @@ export function createRoutePersistence(deps) {
|
|
|
35
35
|
hasSecrets: getConfigHasSecrets(),
|
|
36
36
|
});
|
|
37
37
|
},
|
|
38
|
-
persistAdoptedModelSettings(route, { keepMainModel } = {}) {
|
|
38
|
+
persistAdoptedModelSettings(route, { keepMainModel, onlyIfAbsent = false } = {}) {
|
|
39
39
|
// saveModelSettings is in-memory only. persistLeadRoute debounce-writes
|
|
40
40
|
// the adopted config (including modelSettings). If the lead preset cannot
|
|
41
41
|
// be normalized, still debounce-persist so effort/fast are not memory-only.
|
|
@@ -43,7 +43,7 @@ export function createRoutePersistence(deps) {
|
|
|
43
43
|
keepMainModel === true ||
|
|
44
44
|
(keepMainModel !== false && tunesNonMainModel(getRoute(), route, resolveRoute(getConfig(), {})))
|
|
45
45
|
? null
|
|
46
|
-
: persistLeadRoute(route);
|
|
46
|
+
: persistLeadRoute(route, { onlyIfAbsent });
|
|
47
47
|
if (!leadRoute) saveConfigAndAdopt(getConfig());
|
|
48
48
|
return leadRoute;
|
|
49
49
|
},
|
|
@@ -10,7 +10,13 @@ export function createRouteTuning(deps, persist) {
|
|
|
10
10
|
const { getConfig, getRoute, setRouteState, resolveRoute, lookupModelMeta, refreshRouteEffort } = deps;
|
|
11
11
|
|
|
12
12
|
/** Save the live route's modelSettings, re-resolve through the lead preset
|
|
13
|
-
* when one exists, refresh effort and tune the current session.
|
|
13
|
+
* when one exists, refresh effort and tune the current session.
|
|
14
|
+
*
|
|
15
|
+
* This is not a Main-model write and needs no compare-and-set: it persists
|
|
16
|
+
* the LIVE route (read after every await), and only when that route's model
|
|
17
|
+
* is already the Main model (persistAdoptedModelSettings: tunesNonMainModel),
|
|
18
|
+
* so the lead preset's model is rewritten with itself and never changes. A
|
|
19
|
+
* live route without a model normalizes to nothing and writes no preset. */
|
|
14
20
|
async function commitRouteTuning(fastCapable, modelMeta) {
|
|
15
21
|
persist.saveRouteModelSettings(getRoute(), fastCapable);
|
|
16
22
|
const leadRoute = persist.persistAdoptedModelSettings(getRoute());
|
|
@@ -61,7 +67,10 @@ export function createRouteTuning(deps, persist) {
|
|
|
61
67
|
},
|
|
62
68
|
async setEffort(value) {
|
|
63
69
|
const normalized = normalizeEffortInput(value);
|
|
64
|
-
|
|
70
|
+
// An explicit level is the user's choice for this route: Auto effort
|
|
71
|
+
// would replace it on the next turn (its base is fixed), so the pick
|
|
72
|
+
// turns the route's Auto off until it is switched back on.
|
|
73
|
+
setRouteState({ ...getRoute(), effort: normalized, ...(normalized ? { autoEffort: false } : {}) });
|
|
65
74
|
const modelMeta = await lookupModelMeta(getRoute().provider, getRoute().model);
|
|
66
75
|
const fastCapable = selectionFastCapable(getRoute().provider, modelMeta, normalized, getRoute().modelParameters);
|
|
67
76
|
await commitRouteTuning(fastCapable, modelMeta);
|
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
} from '../../runtime/agent/orchestrator/runtime-core/session-route-policy.mjs';
|
|
25
25
|
import { rebuildToolSurfaceForProviderWithMigration } from '../../runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs';
|
|
26
26
|
import { UNOWNED_LEASE, openRouteLease } from './route-ownership.mjs';
|
|
27
|
+
import { resolveSessionMode } from '../../runtime/agent/orchestrator/session/agent-mode.mjs';
|
|
28
|
+
import { ownerRouteFallbacks } from '../../runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs';
|
|
29
|
+
import { normalizeWorkflowRoute } from '../../runtime/agent/orchestrator/runtime-core/workflow.mjs';
|
|
30
|
+
import { routeChain, validateRouteChainProviders } from '../../runtime/shared/model-route-chain.mjs';
|
|
31
|
+
import { resolveChainEntry } from '../workflow-agents-api/agent-route.mjs';
|
|
27
32
|
|
|
28
33
|
/** The request, completed from the live route where the caller left gaps. */
|
|
29
34
|
function completeRequest(deps, next) {
|
|
@@ -105,6 +110,32 @@ async function recreateEmptySession(deps, lease) {
|
|
|
105
110
|
if (closed) await createCurrentSession('model-switch-empty');
|
|
106
111
|
}
|
|
107
112
|
|
|
113
|
+
/** The fallback chain a Lead-class session follows on `route`: its owner's chain
|
|
114
|
+
* while the route is the owner's primary model, none otherwise (see
|
|
115
|
+
* owner-route-fallbacks.mjs). Nothing for an agent's session, which keeps its own. */
|
|
116
|
+
export function sessionRouteFallbackFields(deps, session, route) {
|
|
117
|
+
const { mode, agentId } = resolveSessionMode({ session });
|
|
118
|
+
if (!agentId) return {};
|
|
119
|
+
return {
|
|
120
|
+
routeFallbacks: ownerRouteFallbacks({
|
|
121
|
+
sessionMode: mode,
|
|
122
|
+
agentId,
|
|
123
|
+
provider: route.provider,
|
|
124
|
+
model: route.model,
|
|
125
|
+
config: deps.getConfig(),
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** A same-model selection (a bot profile saved with new fallbacks) restarts the
|
|
131
|
+
* addressed session's chain when the owner's chain no longer matches it. */
|
|
132
|
+
function refreshSessionFallbacks(deps, session) {
|
|
133
|
+
const fields = sessionRouteFallbackFields(deps, session, deps.getRoute());
|
|
134
|
+
if (!fields.routeFallbacks) return;
|
|
135
|
+
if (JSON.stringify(fields.routeFallbacks) === JSON.stringify(session.routeFallbacks || [])) return;
|
|
136
|
+
deps.mgr.updateSessionRoute?.(session.id, fields, { session });
|
|
137
|
+
}
|
|
138
|
+
|
|
108
139
|
/** Rewrite the addressed empty session to the route it was asked to run on. */
|
|
109
140
|
function updateSessionInPlace(deps, session, updateOptions) {
|
|
110
141
|
const { getRoute, getSession, setSession, mgr, statusRoutes } = deps;
|
|
@@ -119,6 +150,7 @@ function updateSessionInPlace(deps, session, updateOptions) {
|
|
|
119
150
|
contextPercent: route.contextPercent,
|
|
120
151
|
contextTokens: route.contextTokens || null,
|
|
121
152
|
selectedContextWindow: route.selectedContextWindow || null,
|
|
153
|
+
...sessionRouteFallbackFields(deps, session, route),
|
|
122
154
|
};
|
|
123
155
|
const updated = mgr.updateSessionRoute?.(session.id, fields, updateOptions);
|
|
124
156
|
if (updated) setSession(updated);
|
|
@@ -183,6 +215,27 @@ function switchSessionInPlace(deps, session) {
|
|
|
183
215
|
return recorded ? boundary : null;
|
|
184
216
|
}
|
|
185
217
|
|
|
218
|
+
/** The Lead's fallback models after this selection, checked like an agent's
|
|
219
|
+
* chain (leaf routes, distinct providers): an explicit list replaces the
|
|
220
|
+
* stored one ([] clears it), a selection without one keeps it. */
|
|
221
|
+
async function leadFallbackChain(deps, next, primary) {
|
|
222
|
+
const storedPreset = findPreset(deps.getConfig(), workflowPresetId('lead'));
|
|
223
|
+
const requested = hasOwn(next || {}, 'fallbacks') ? next.fallbacks : storedPreset?.fallbacks;
|
|
224
|
+
if (!Array.isArray(requested) || !requested.length) return [];
|
|
225
|
+
const chain = routeChain({ provider: primary.provider, model: primary.model, fallbacks: requested });
|
|
226
|
+
validateRouteChainProviders(chain);
|
|
227
|
+
const storedChain = routeChain(storedPreset || {});
|
|
228
|
+
// Each entry goes through the agents' normalizer (fast clamp, context window).
|
|
229
|
+
const resolved = [];
|
|
230
|
+
for (const entry of chain.slice(1)) {
|
|
231
|
+
const previous = storedChain.find((c) => c.provider === entry.provider && c.model === entry.model);
|
|
232
|
+
resolved.push(await resolveChainEntry(deps, entry, previous || {}));
|
|
233
|
+
}
|
|
234
|
+
return (
|
|
235
|
+
normalizeWorkflowRoute({ provider: primary.provider, model: primary.model, fallbacks: resolved })?.fallbacks || []
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
186
239
|
/** Validate, persist and adopt the requested route as the runtime's route. */
|
|
187
240
|
async function adoptRoute(deps, persist, next, options, lease) {
|
|
188
241
|
const {
|
|
@@ -195,9 +248,29 @@ async function adoptRoute(deps, persist, next, options, lease) {
|
|
|
195
248
|
scheduleStatuslineUsageRefresh,
|
|
196
249
|
} = deps;
|
|
197
250
|
const { selectedRoute, fastCapable, modelMeta } = await resolveSelectedRoute(deps, next);
|
|
251
|
+
// The Lead's fallback chain travels with an explicit main-model choice only
|
|
252
|
+
// (the Lead editor, the setup tool); a session's own pick never touches it.
|
|
253
|
+
const persistedRoute =
|
|
254
|
+
options?.keepMainModel === false && options?.sessionOnly !== true
|
|
255
|
+
? { ...selectedRoute, fallbacks: await leadFallbackChain(deps, next, selectedRoute) }
|
|
256
|
+
: selectedRoute;
|
|
257
|
+
// The Lead route a conditional fill wrote, until the file confirms it.
|
|
258
|
+
let filled = null;
|
|
198
259
|
// Provider readiness may outlast the session the selection was made for.
|
|
199
260
|
const adopted = lease.run(
|
|
200
261
|
() => {
|
|
262
|
+
// Compare-and-set: a route that already has a model (picked while this
|
|
263
|
+
// selection was resolving) is never replaced. Checked synchronously with
|
|
264
|
+
// the adopt below, so nothing can set a route in between. A Lead route
|
|
265
|
+
// another process persisted may not have reached this runtime yet (the
|
|
266
|
+
// change notification is debounced): the config is re-read from disk
|
|
267
|
+
// right here, which adopts it and fills the empty route, and that route
|
|
268
|
+
// is the winner this selection answers with.
|
|
269
|
+
if (options?.onlyIfEmpty === true) {
|
|
270
|
+
if (clean(getRoute()?.model)) return false;
|
|
271
|
+
deps.reloadFullConfig?.();
|
|
272
|
+
if (clean(getRoute()?.model)) return false;
|
|
273
|
+
}
|
|
201
274
|
if (options?.sessionOnly === true) {
|
|
202
275
|
// An agent child's route belongs to that session alone: the shared
|
|
203
276
|
// modelSettings bucket (saved effort/Fast per model) and the main
|
|
@@ -208,9 +281,11 @@ async function adoptRoute(deps, persist, next, options, lease) {
|
|
|
208
281
|
// The main model changes only on an explicit main-model choice
|
|
209
282
|
// (keepMainModel: false, e.g. the setup tool); every other selection
|
|
210
283
|
// — the session surface's model pick, an heir — keeps it.
|
|
211
|
-
const leadRoute = persist.persistAdoptedModelSettings(
|
|
284
|
+
const leadRoute = persist.persistAdoptedModelSettings(persistedRoute, {
|
|
212
285
|
keepMainModel: options?.keepMainModel !== false,
|
|
286
|
+
onlyIfAbsent: options?.onlyIfEmpty === true,
|
|
213
287
|
});
|
|
288
|
+
filled = leadRoute;
|
|
214
289
|
setRouteState(resolveRoute(getConfig(), leadRoute ? { model: workflowPresetId('lead') } : selectedRoute));
|
|
215
290
|
}
|
|
216
291
|
return true;
|
|
@@ -218,9 +293,13 @@ async function adoptRoute(deps, persist, next, options, lease) {
|
|
|
218
293
|
() => false
|
|
219
294
|
);
|
|
220
295
|
if (!adopted) return false;
|
|
296
|
+
// A conditional fill reaches the file only while no Lead route is stored
|
|
297
|
+
// there (judged under the config file lock). When another process wrote one
|
|
298
|
+
// after the re-read above, the file's route replaces the fill in the runtime.
|
|
299
|
+
const replaced = filled && (await deps.confirmLeadFill?.(filled)) === true;
|
|
221
300
|
// The refresh completes against the route just adopted and only while the
|
|
222
301
|
// selection still owns it.
|
|
223
|
-
await refreshRouteEffort(modelMeta, getRoute(), null, lease);
|
|
302
|
+
await refreshRouteEffort(replaced ? null : modelMeta, getRoute(), null, lease);
|
|
224
303
|
return lease.run(
|
|
225
304
|
() => {
|
|
226
305
|
refreshStatuslineUsageSnapshot(getRoute());
|
|
@@ -320,6 +399,7 @@ export function createSetRoute(deps, persist) {
|
|
|
320
399
|
return modelSwitch ? { ...getRoute(), modelSwitch } : getRoute();
|
|
321
400
|
}
|
|
322
401
|
persist.applySessionTuning();
|
|
402
|
+
refreshSessionFallbacks(deps, session);
|
|
323
403
|
return getRoute();
|
|
324
404
|
}
|
|
325
405
|
// An addressed runtime keeps its durable id: the empty session is updated
|