mixdog 1.3.5 → 1.4.0
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 +2 -2
- package/README.md +2 -2
- package/package.json +2 -11
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/gate-local.mjs +4 -2
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +10 -1
- package/scripts/test.mjs +7 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +17 -1
- package/src/defaults/skills/browser-use/SKILL.md +59 -11
- package/src/defaults/skills/code-tidy/SKILL.md +142 -270
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
- package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
- package/src/defaults/skills/computer-use/SKILL.md +33 -9
- package/src/defaults/skills/setup/SKILL.md +22 -0
- package/src/defaults/skills/setup/references/actions.md +39 -5
- package/src/defaults/skills/setup/references/surfaces.md +11 -2
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/rules-builder.cjs +10 -8
- package/src/rules/agent/AGENT.md +6 -6
- package/src/rules/lead/LEAD.md +18 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
- package/src/runtime/agent/orchestrator/config.mjs +17 -1
- package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
- package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +181 -133
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +145 -66
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -13
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/registry.mjs +26 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
- package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +133 -22
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
- package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
- package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
- package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
- package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
- package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +18 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
- package/src/runtime/browser-bridge/action-schema.mjs +13 -2
- package/src/runtime/browser-bridge/client.mjs +73 -8
- package/src/runtime/browser-bridge/input-fields.mjs +8 -9
- package/src/runtime/browser-bridge/mail-links.mjs +107 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
- package/src/runtime/channels/lib/config.mjs +6 -61
- package/src/runtime/channels/lib/crash-log.mjs +1 -1
- package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
- package/src/runtime/channels/lib/event-queue.mjs +3 -18
- package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
- package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
- package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
- package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
- package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
- package/src/runtime/channels/lib/scheduler.mjs +33 -147
- package/src/runtime/channels/lib/schedules-db.mjs +34 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
- package/src/runtime/channels/lib/worker-main.mjs +10 -34
- package/src/runtime/computer-bridge/action-schema.mjs +42 -1
- package/src/runtime/computer-bridge/actions.mjs +9 -1
- package/src/runtime/computer-bridge/client.mjs +180 -8
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
- package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
- package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
- package/src/runtime/connectors/gmail-app-password.mjs +172 -39
- package/src/runtime/connectors/google-mcp.mjs +10 -12
- package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
- package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
- package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
- package/src/runtime/session-search/session-search-db.mjs +73 -9
- package/src/runtime/session-search/session-search-ingest.mjs +110 -20
- package/src/runtime/shared/abort-race.mjs +89 -0
- package/src/runtime/shared/agent-avatar.d.mts +0 -1
- package/src/runtime/shared/agent-kind.mjs +4 -3
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +2 -13
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +29 -0
- package/src/runtime/shared/connector-catalog.mjs +150 -0
- package/src/runtime/shared/connector-triggers.mjs +22 -19
- package/src/runtime/shared/defaults-separation.mjs +2 -14
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/err-text.mjs +24 -15
- package/src/runtime/shared/file-permissions.d.mts +0 -8
- package/src/runtime/shared/file-permissions.mjs +0 -11
- package/src/runtime/shared/git-direct.test-support.mjs +19 -0
- package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
- package/src/runtime/shared/heartbeat-interval.mjs +19 -0
- package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/mixy-presence.mjs +22 -0
- package/src/runtime/shared/orchestration.d.mts +2 -0
- package/src/runtime/shared/pg-schema-db.mjs +27 -16
- package/src/runtime/shared/profile-config.cjs +1 -1
- package/src/runtime/shared/prompt-origin.d.mts +4 -0
- package/src/runtime/shared/prompt-origin.mjs +21 -0
- package/src/runtime/shared/provider-accounts.mjs +7 -1
- package/src/runtime/shared/provider-display-name.mjs +29 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
- package/src/runtime/shared/routine-trigger.d.mts +2 -0
- package/src/runtime/shared/routine-trigger.mjs +10 -0
- package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
- package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
- package/src/runtime/shared/session-activity-signal.mjs +34 -1
- package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
- package/src/runtime/shared/session-sidebar-host.mjs +7 -3
- package/src/runtime/shared/session-turn-prelude.mjs +18 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -14
- package/src/runtime/shared/worktrees/test-support.mjs +9 -4
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +27 -8
- package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
- package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
- package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
- package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
- package/src/session-runtime/agent-home-delivery.mjs +448 -185
- package/src/session-runtime/agent-task-sessions.mjs +329 -180
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/infrastructure.mjs +4 -0
- package/src/session-runtime/boot/providers.mjs +3 -0
- package/src/session-runtime/boot/tools.mjs +6 -1
- package/src/session-runtime/config-lifecycle.mjs +6 -0
- package/src/session-runtime/connector-merge-migration.mjs +305 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
- package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
- package/src/session-runtime/lifecycle/teardown.mjs +23 -5
- package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +153 -33
- package/src/session-runtime/notification-bus.mjs +31 -117
- package/src/session-runtime/notification-completion-queue.mjs +54 -0
- package/src/session-runtime/notification-listeners.mjs +76 -0
- package/src/session-runtime/owned-automation-run.mjs +2 -1
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/resource-mcp-api.mjs +143 -224
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
- package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
- package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
- package/src/session-runtime/resource-mcp-servers.mjs +78 -0
- package/src/session-runtime/resource-mcp-store.mjs +49 -0
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
- package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
- package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
- package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
- package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +7 -13
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +1 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
- package/src/session-runtime/settings-compaction-api.mjs +2 -40
- package/src/session-runtime/settings-system-api.mjs +13 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +145 -22
- package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +16 -2
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
- package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
- package/src/standalone/channel-transport/client-registry.mjs +24 -163
- package/src/standalone/channel-transport.mjs +1 -1
- package/src/standalone/daemon-channels-loader.mjs +10 -8
- package/src/standalone/daemon-session-control/list-page.mjs +72 -0
- package/src/standalone/daemon-session-control/request.mjs +51 -0
- package/src/standalone/daemon-session-control/room-host.mjs +57 -0
- package/src/standalone/daemon-session-control/route-control.mjs +48 -0
- package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
- package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
- package/src/standalone/daemon-session-control.mjs +124 -188
- package/src/standalone/daemon.mjs +26 -3
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
- package/src/standalone/session-service/quota-resume.mjs +3 -0
- package/src/standalone/session-service/retention/busy.mjs +65 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-tool-output.mjs +15 -7
- package/src/tui/app/model-options.mjs +3 -28
- package/src/tui/dist/index.mjs +58 -64
- package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/notice-surface.mjs +7 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
- package/src/tui/session/session-api/routes-write.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +17 -1
- package/src/tui/session/session-flow/auto-clear.mjs +4 -33
- package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
- package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
- package/src/tui/session/session-flow/drain-retry.mjs +35 -0
- package/src/tui/session/session-flow/drain.mjs +118 -149
- package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
- package/src/tui/session/tool-approval-delegation.mjs +64 -0
- package/src/tui/session/tool-approval-request.mjs +39 -0
- package/src/tui/session/tool-approval-settle.mjs +62 -0
- package/src/tui/session/tool-approval.mjs +69 -115
- package/src/tui/session/tui-steering-persist.mjs +8 -1
- package/src/tui/session/turn-stream.mjs +19 -2
- package/src/tui/session/turn.mjs +1 -0
- package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
- package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
- package/scripts/code-graph-description-contract.mjs +0 -188
- package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { clean } from './session-text.mjs';
|
|
2
|
+
import { parseMcpToolName } from '../../../shared/tool-primitives.mjs';
|
|
3
|
+
import { mcpServerLines } from '../context/deferred-tools.mjs';
|
|
2
4
|
|
|
3
5
|
function compactDescription(value) {
|
|
4
6
|
return String(value || '')
|
|
@@ -8,23 +10,36 @@ function compactDescription(value) {
|
|
|
8
10
|
.slice(0, 240);
|
|
9
11
|
}
|
|
10
12
|
|
|
13
|
+
function addedEntry(entry) {
|
|
14
|
+
const name = clean(entry?.name);
|
|
15
|
+
return name ? { name, description: compactDescription(entry?.description) } : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
function normalizedDelta(value) {
|
|
12
19
|
const source = value && typeof value === 'object' ? value : {};
|
|
13
20
|
const addedByName = new Map();
|
|
14
21
|
for (const entry of Array.isArray(source.added) ? source.added : []) {
|
|
15
|
-
const
|
|
16
|
-
if (
|
|
22
|
+
const added = addedEntry(entry);
|
|
23
|
+
if (added) addedByName.set(added.name, added);
|
|
17
24
|
}
|
|
18
|
-
const removed = new Set(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
const removed = new Set();
|
|
26
|
+
// Removed tool name → its server, for removals that came with one.
|
|
27
|
+
const removedServers = new Map(
|
|
28
|
+
Object.entries(source.removedServers && typeof source.removedServers === 'object' ? source.removedServers : {})
|
|
22
29
|
);
|
|
30
|
+
for (const entry of Array.isArray(source.removed) ? source.removed : []) {
|
|
31
|
+
const name = clean(typeof entry === 'string' ? entry : entry?.name);
|
|
32
|
+
if (!name) continue;
|
|
33
|
+
removed.add(name);
|
|
34
|
+
if (typeof entry === 'object' && clean(entry?.server)) removedServers.set(name, clean(entry.server));
|
|
35
|
+
}
|
|
23
36
|
for (const name of addedByName.keys()) removed.delete(name);
|
|
37
|
+
for (const name of [...removedServers.keys()]) if (!removed.has(name)) removedServers.delete(name);
|
|
24
38
|
return {
|
|
25
39
|
revision: Math.max(0, Number(source.revision) || 0),
|
|
26
40
|
addedByName,
|
|
27
41
|
removed,
|
|
42
|
+
removedServers,
|
|
28
43
|
};
|
|
29
44
|
}
|
|
30
45
|
|
|
@@ -33,19 +48,20 @@ export function mergePendingDeferredToolDelta(session, change = {}) {
|
|
|
33
48
|
const current = normalizedDelta(session.pendingDeferredToolDelta);
|
|
34
49
|
const nextRevision = Math.max(current.revision, Math.max(0, Number(session.deferredToolDeltaRevision) || 0)) + 1;
|
|
35
50
|
for (const entry of Array.isArray(change.added) ? change.added : []) {
|
|
36
|
-
const
|
|
37
|
-
if (!
|
|
38
|
-
if (current.removed.delete(name))
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
51
|
+
const added = addedEntry(entry);
|
|
52
|
+
if (!added) continue;
|
|
53
|
+
if (current.removed.delete(added.name)) {
|
|
54
|
+
current.removedServers.delete(added.name);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
current.addedByName.set(added.name, added);
|
|
43
58
|
}
|
|
44
59
|
for (const entry of Array.isArray(change.removed) ? change.removed : []) {
|
|
45
60
|
const name = clean(typeof entry === 'string' ? entry : entry?.name);
|
|
46
61
|
if (!name) continue;
|
|
47
62
|
if (current.addedByName.delete(name)) continue;
|
|
48
63
|
current.removed.add(name);
|
|
64
|
+
if (typeof entry === 'object' && clean(entry?.server)) current.removedServers.set(name, clean(entry.server));
|
|
49
65
|
}
|
|
50
66
|
const added = [...current.addedByName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
51
67
|
const removed = [...current.removed].sort();
|
|
@@ -61,27 +77,88 @@ export function mergePendingDeferredToolDelta(session, change = {}) {
|
|
|
61
77
|
revision: nextRevision,
|
|
62
78
|
added,
|
|
63
79
|
removed,
|
|
80
|
+
...(current.removedServers.size
|
|
81
|
+
? { removedServers: Object.fromEntries([...current.removedServers].sort(([a], [b]) => a.localeCompare(b))) }
|
|
82
|
+
: {}),
|
|
64
83
|
};
|
|
65
84
|
session.updatedAt = Date.now();
|
|
66
85
|
return session.pendingDeferredToolDelta;
|
|
67
86
|
}
|
|
68
87
|
|
|
88
|
+
// MCP changes render one line per affected server, like the BP2 manifest; the tool-level sets stay exact in the snapshot for acknowledgement.
|
|
89
|
+
// A tool's server comes from the session's catalog definitions (an added
|
|
90
|
+
// tool) or the server recorded when it was removed; only a name neither knows
|
|
91
|
+
// falls back to the recorded/`mcp__<server>__<tool>` parse. Other tools are
|
|
92
|
+
// listed one by one.
|
|
93
|
+
function deltaLines(session, added, removed, removedServers) {
|
|
94
|
+
const catalogServer = new Map();
|
|
95
|
+
for (const key of ['deferredToolCatalog', 'deferredLateToolCatalog', 'tools']) {
|
|
96
|
+
for (const tool of Array.isArray(session?.[key]) ? session[key] : []) {
|
|
97
|
+
const name = clean(tool?.name);
|
|
98
|
+
const server = name && parseMcpToolName(tool)?.server;
|
|
99
|
+
if (server) catalogServer.set(name, server);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const serverOf = (name, hint) => hint || catalogServer.get(name) || parseMcpToolName(name)?.server || '';
|
|
103
|
+
const items = [];
|
|
104
|
+
|
|
105
|
+
const addedServers = new Map();
|
|
106
|
+
for (const entry of added) {
|
|
107
|
+
const server = serverOf(entry.name);
|
|
108
|
+
if (!server) {
|
|
109
|
+
items.push({
|
|
110
|
+
label: entry.name,
|
|
111
|
+
line: entry.description ? `- ${entry.name}: ${entry.description}` : `- ${entry.name}`,
|
|
112
|
+
});
|
|
113
|
+
} else if (addedServers.has(server)) addedServers.get(server).push(entry);
|
|
114
|
+
else addedServers.set(server, [entry]);
|
|
115
|
+
}
|
|
116
|
+
const addedLines = mcpServerLines(addedServers, session?.mcpServerInstructions);
|
|
117
|
+
for (const line of addedLines) items.push({ label: line.label, line: `- ${line.label}: ${line.trigger}` });
|
|
118
|
+
// A server whose name cannot be listed safely is listed by its tools.
|
|
119
|
+
const listed = new Set(addedLines.map((line) => line.label));
|
|
120
|
+
for (const [server, entries] of addedServers) {
|
|
121
|
+
if (listed.has(`mcp__${server}`)) continue;
|
|
122
|
+
for (const entry of entries) items.push({ label: entry.name, line: `- ${entry.name}` });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const connected = Array.isArray(session?.deferredMcpToolNames) ? session.deferredMcpToolNames : null;
|
|
126
|
+
const liveServers = new Set((connected || []).map((name) => serverOf(clean(name))).filter(Boolean));
|
|
127
|
+
const removedByServer = new Map();
|
|
128
|
+
const removedItems = [];
|
|
129
|
+
for (const name of removed) {
|
|
130
|
+
const server = serverOf(name, removedServers.get(name));
|
|
131
|
+
if (!server) {
|
|
132
|
+
removedItems.push({ label: name, line: `- ${name}` });
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (removedByServer.has(server)) removedByServer.get(server).push(name);
|
|
136
|
+
else removedByServer.set(server, [name]);
|
|
137
|
+
}
|
|
138
|
+
// Gone only when the connected set is known and none of its tools is left.
|
|
139
|
+
for (const [server, names] of removedByServer) {
|
|
140
|
+
const label = `mcp__${server}`;
|
|
141
|
+
const gone = connected && !liveServers.has(server);
|
|
142
|
+
const plural = names.length === 1 ? '' : 's';
|
|
143
|
+
removedItems.push({
|
|
144
|
+
label,
|
|
145
|
+
line: gone ? `- ${label}` : `- ${label}: ${names.length} tool${plural} removed`,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const render = (list) => list.sort((a, b) => a.label.localeCompare(b.label)).map((item) => item.line);
|
|
150
|
+
return { added: render(items), removed: render(removedItems) };
|
|
151
|
+
}
|
|
152
|
+
|
|
69
153
|
export function snapshotPendingDeferredToolDelta(session) {
|
|
70
154
|
const current = normalizedDelta(session?.pendingDeferredToolDelta);
|
|
71
155
|
const added = [...current.addedByName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
72
156
|
const removed = [...current.removed].sort();
|
|
73
157
|
if (!added.length && !removed.length) return null;
|
|
158
|
+
const rendered = deltaLines(session, added, removed, current.removedServers);
|
|
74
159
|
const lines = ['<system-reminder>', '<deferred_tools_delta>'];
|
|
75
|
-
if (added.length)
|
|
76
|
-
|
|
77
|
-
for (const entry of added) {
|
|
78
|
-
lines.push(entry.description ? `- ${entry.name}: ${entry.description}` : `- ${entry.name}`);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
if (removed.length) {
|
|
82
|
-
lines.push('Removed deferred tools:');
|
|
83
|
-
for (const name of removed) lines.push(`- ${name}`);
|
|
84
|
-
}
|
|
160
|
+
if (rendered.added.length) lines.push('Added deferred tools:', ...rendered.added);
|
|
161
|
+
if (rendered.removed.length) lines.push('Removed deferred tools:', ...rendered.removed);
|
|
85
162
|
lines.push('</deferred_tools_delta>', '</system-reminder>');
|
|
86
163
|
return {
|
|
87
164
|
revision: current.revision,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { clean } from '../../../shared/clean.mjs';
|
|
3
3
|
import { stripInjectedBlocks } from '../../../shared/injected-display-text.mjs';
|
|
4
4
|
import { CONTROL_MARKER_RE } from '../../../shared/tool-execution-contract.mjs';
|
|
5
|
+
import { isRoutineQuietReply } from '../../../shared/routine-trigger.mjs';
|
|
5
6
|
|
|
6
7
|
export function sessionMessageText(content) {
|
|
7
8
|
if (content == null) return '';
|
|
@@ -69,6 +70,7 @@ export function isSessionPreviewNoise(text) {
|
|
|
69
70
|
const value = String(text || '').trim();
|
|
70
71
|
return (
|
|
71
72
|
!value ||
|
|
73
|
+
isRoutineQuietReply(value) ||
|
|
72
74
|
isSyntheticSessionText(value) ||
|
|
73
75
|
!cleanSessionPreview(value) ||
|
|
74
76
|
isLateToolAnnouncement(value) ||
|
|
@@ -26,7 +26,7 @@ import { providerToolExclusionReason, routeToolExclusionReason } from '../sessio
|
|
|
26
26
|
|
|
27
27
|
export { isToolBridgeEnabled } from './tool-exposure.mjs';
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
const BRIDGE_LOAD_TOOL_NAME = 'load_tool';
|
|
30
30
|
export const BRIDGE_CALL_TOOL_NAME = 'call_tool';
|
|
31
31
|
const DESCRIBE_MAX_NAMES = 8;
|
|
32
32
|
// Most definitions one request resolves to: every name an alias of the widest
|
|
@@ -344,7 +344,9 @@ function largestChunk(text, offset, buildPage) {
|
|
|
344
344
|
return low;
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
-
|
|
347
|
+
// `instructionsFor(names)` (pure) returns the MCP instruction text the page
|
|
348
|
+
// carries for those entries, counted inside the result budget.
|
|
349
|
+
export function describeBridgeTools(session, args = {}, { mode, instructionsFor } = {}) {
|
|
348
350
|
const syntaxHint = ' Use load_tool {"names":["exact_tool_name"]}; the required key is names, not name.';
|
|
349
351
|
const invalid = unknownKeysError(args, DESCRIBE_KEYS, BRIDGE_LOAD_TOOL_NAME);
|
|
350
352
|
if (invalid) {
|
|
@@ -409,11 +411,16 @@ export function describeBridgeTools(session, args = {}, { mode } = {}) {
|
|
|
409
411
|
}
|
|
410
412
|
const entries = [];
|
|
411
413
|
const reserve = { names: reserveContinuation(docs.length, available.length) };
|
|
414
|
+
const instructionsOf = (list) => {
|
|
415
|
+
const text = instructionsFor?.(list.map((entry) => entry.name)) || '';
|
|
416
|
+
return text ? { mcpInstructions: text } : {};
|
|
417
|
+
};
|
|
412
418
|
const page = (extra) => ({
|
|
413
419
|
entries: [...entries, extra],
|
|
414
420
|
missing,
|
|
415
421
|
blocked,
|
|
416
422
|
...found,
|
|
423
|
+
...instructionsOf([...entries, extra]),
|
|
417
424
|
note: DESCRIBE_NOTE,
|
|
418
425
|
continueWith: reserve,
|
|
419
426
|
});
|
|
@@ -431,7 +438,15 @@ export function describeBridgeTools(session, args = {}, { mode } = {}) {
|
|
|
431
438
|
// A document that fits on a page of its own starts the next page whole.
|
|
432
439
|
if (
|
|
433
440
|
entries.length &&
|
|
434
|
-
fits({
|
|
441
|
+
fits({
|
|
442
|
+
entries: [whole],
|
|
443
|
+
missing,
|
|
444
|
+
blocked,
|
|
445
|
+
...found,
|
|
446
|
+
...instructionsOf([whole]),
|
|
447
|
+
note: DESCRIBE_NOTE,
|
|
448
|
+
continueWith: reserve,
|
|
449
|
+
})
|
|
435
450
|
) {
|
|
436
451
|
nextPosition = [entryIndex, 0];
|
|
437
452
|
break;
|
|
@@ -464,7 +479,7 @@ export function describeBridgeTools(session, args = {}, { mode } = {}) {
|
|
|
464
479
|
'the remaining definitions cannot be continued; describe fewer tools at once.'
|
|
465
480
|
);
|
|
466
481
|
}
|
|
467
|
-
return { entries, missing, blocked, ...found, note: DESCRIBE_NOTE, continueWith };
|
|
482
|
+
return { entries, missing, blocked, ...found, ...instructionsOf(entries), note: DESCRIBE_NOTE, continueWith };
|
|
468
483
|
}
|
|
469
484
|
|
|
470
485
|
// ---------------------------------------------------------------------------
|
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
import { clean } from './session-text.mjs';
|
|
5
5
|
import { mergePendingDeferredToolDelta } from './deferred-tool-delta.mjs';
|
|
6
6
|
import { applyInitialDeferredToolManifestToBp2 } from '../context/collect.mjs';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
listedDeferredToolNames,
|
|
9
|
+
mcpServerManifestLabel,
|
|
10
|
+
sanitizeMcpInstructionText,
|
|
11
|
+
} from '../context/deferred-tools.mjs';
|
|
8
12
|
import { parseMcpToolName } from '../../../shared/tool-primitives.mjs';
|
|
9
13
|
import { getMcpServerInstructionsMap, getMcpTools, getMcpToolGeneration } from '../mcp/client.mjs';
|
|
10
14
|
import { filterMcpToolsForSession } from './extension-scopes.mjs';
|
|
@@ -380,10 +384,35 @@ export function applyDeferredToolSurface(session, mode, extraTools = [], options
|
|
|
380
384
|
session.deferredDiscoveredTools || []
|
|
381
385
|
);
|
|
382
386
|
}
|
|
387
|
+
const catalog = surfaceCatalog(session, extraTools, options);
|
|
388
|
+
const defaultNames = surfaceDefaultNames(session, catalog, mode);
|
|
389
|
+
const selected = new Set(surfaceSelectedNames(session, catalog, defaultNames, providerMode, bridge));
|
|
390
|
+
session.deferredToolCatalog = catalog;
|
|
391
|
+
session.deferredToolUsage = MEASURED_TOOL_USAGE;
|
|
392
|
+
session.deferredDefaultTools = sortedNamesByMeasuredUsage(defaultNames);
|
|
393
|
+
session.deferredProviderMode = providerMode;
|
|
394
|
+
session.deferredNativeTools = providerMode === 'native';
|
|
395
|
+
session.deferredSurfaceMode = mode;
|
|
396
|
+
const active = installSurfaceTools(session, catalog, selected, mode, bridge);
|
|
397
|
+
session.deferredCallableTools = sortedNamesByMeasuredUsage(active);
|
|
398
|
+
if (providerMode === 'native') {
|
|
399
|
+
const restored = previousExposure === TOOL_EXPOSURE_BRIDGE ? session.nativeDeferredDiscovery || [] : [];
|
|
400
|
+
delete session.nativeDeferredDiscovery;
|
|
401
|
+
const discovered = canonicalDeferredToolNames(catalog, [...(session.deferredDiscoveredTools || []), ...restored]);
|
|
402
|
+
session.deferredSelectedTools = active;
|
|
403
|
+
session.deferredDiscoveredTools = discovered.filter((name) => !selected.has(name));
|
|
404
|
+
} else {
|
|
405
|
+
setDeferredToolState(session, active);
|
|
406
|
+
}
|
|
407
|
+
refreshSurfaceManifest(session, exposureChanged);
|
|
408
|
+
return session;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// The surface's catalog, rebuilt from the full catalog, not just its eager
|
|
412
|
+
// projection. Current definitions still take precedence over retained
|
|
413
|
+
// definitions. Bridge definitions belong to the exposure, never to the catalog.
|
|
414
|
+
function surfaceCatalog(session, extraTools, options) {
|
|
383
415
|
const byName = new Map();
|
|
384
|
-
// Rebuild from the full catalog, not just its eager projection. Current
|
|
385
|
-
// definitions still take precedence over retained definitions. Bridge
|
|
386
|
-
// definitions belong to the exposure, never to the catalog.
|
|
387
416
|
const candidates = filterDisallowedTools(
|
|
388
417
|
filterModelEditTools(
|
|
389
418
|
[...session.tools, ...(extraTools || []), ...deferredCatalogUnion(session)].filter(
|
|
@@ -398,7 +427,11 @@ export function applyDeferredToolSurface(session, mode, extraTools = [], options
|
|
|
398
427
|
if (!name || byName.has(name)) continue;
|
|
399
428
|
byName.set(name, activeToolForSurface(tool));
|
|
400
429
|
}
|
|
401
|
-
|
|
430
|
+
return sortedCatalogByMeasuredUsage([...byName.values()]);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// The mode's eager tools in `catalog`, less those the session keeps loadable.
|
|
434
|
+
function surfaceDefaultNames(session, catalog, mode) {
|
|
402
435
|
const defaultNames = defaultDeferredToolNames(catalog, mode);
|
|
403
436
|
// Solo keeps `agent` in the deferred pool: loadable on request, never eager.
|
|
404
437
|
// The mode the prompt was built with: a mid-conversation workflow or
|
|
@@ -413,19 +446,24 @@ export function applyDeferredToolSurface(session, mode, extraTools = [], options
|
|
|
413
446
|
for (const name of Array.isArray(session.workflowOpenedTools) ? session.workflowOpenedTools : []) {
|
|
414
447
|
defaultNames.delete(name);
|
|
415
448
|
}
|
|
449
|
+
return defaultNames;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// The names the surface selects: the session's stored selection, else the
|
|
453
|
+
// defaults.
|
|
454
|
+
function surfaceSelectedNames(session, catalog, defaultNames, providerMode, bridge) {
|
|
416
455
|
// Bridge sessions expose the mode's core only: a stored (legacy all-selected)
|
|
417
456
|
// selection never widens the wire surface, and load_tool is the bridge's own.
|
|
418
457
|
const storedNames = providerMode === 'native' || bridge ? [] : storedDeferredToolNames(session);
|
|
419
458
|
let selectedNames = storedNames.length ? canonicalDeferredToolNames(catalog, storedNames) : [];
|
|
420
459
|
if (!selectedNames.length || providerMode === 'native') selectedNames = sortedNamesByMeasuredUsage(defaultNames);
|
|
421
460
|
if (bridge) selectedNames = selectedNames.filter((name) => name !== 'load_tool');
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
session.deferredSurfaceMode = mode;
|
|
461
|
+
return selectedNames;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Replace `session.tools` with the selected definitions (plus the bridge's
|
|
465
|
+
// own) and record the exposure; returns the active tool names.
|
|
466
|
+
function installSurfaceTools(session, catalog, selected, mode, bridge) {
|
|
429
467
|
session.tools.length = 0;
|
|
430
468
|
const active = [];
|
|
431
469
|
for (const tool of catalog) {
|
|
@@ -439,16 +477,12 @@ export function applyDeferredToolSurface(session, mode, extraTools = [], options
|
|
|
439
477
|
if (bridge && catalog.length) session.tools.push(...BRIDGE_SURFACE_TOOLS);
|
|
440
478
|
if (bridge) session.toolExposureMode = TOOL_EXPOSURE_BRIDGE;
|
|
441
479
|
else delete session.toolExposureMode;
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
session.deferredDiscoveredTools = discovered.filter((name) => !selected.has(name));
|
|
449
|
-
} else {
|
|
450
|
-
setDeferredToolState(session, active);
|
|
451
|
-
}
|
|
480
|
+
return active;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Keep the system prompt's fixed deferred-tool block (BP2) and the announced
|
|
484
|
+
// set in step with the surface.
|
|
485
|
+
function refreshSurfaceManifest(session, exposureChanged) {
|
|
452
486
|
if (exposureChanged && session.messages?.some((m) => m?.role === 'system')) {
|
|
453
487
|
// Replace the previous exposure's fixed block once: the native deferred
|
|
454
488
|
// manifest, or the bridge roster + guidance. History stays as is.
|
|
@@ -473,7 +507,6 @@ export function applyDeferredToolSurface(session, mode, extraTools = [], options
|
|
|
473
507
|
// the startup pool.
|
|
474
508
|
session.deferredAnnouncedTools = deferredPoolToolNames(session);
|
|
475
509
|
}
|
|
476
|
-
return session;
|
|
477
510
|
}
|
|
478
511
|
|
|
479
512
|
export function rebuildDeferredToolSurfaceForProvider(session, provider) {
|
|
@@ -669,9 +702,8 @@ function reconcileDeferredMcpToolCatalogUncached(session, liveMcpTools) {
|
|
|
669
702
|
const lateCatalog = Array.isArray(session.deferredLateToolCatalog) ? session.deferredLateToolCatalog : [];
|
|
670
703
|
// A bridge session judges a removal by the definition it had before this
|
|
671
704
|
// reconciliation (a disconnected late tool leaves the late pool below).
|
|
672
|
-
const
|
|
673
|
-
|
|
674
|
-
: null;
|
|
705
|
+
const catalogBefore = new Map(deferredCatalogUnion(session).map((tool) => [clean(tool?.name), tool]));
|
|
706
|
+
const knownBefore = isToolBridgeEnabled(session) ? catalogBefore : null;
|
|
675
707
|
const active = persistentToolSurfaceNames(session);
|
|
676
708
|
|
|
677
709
|
const liveMcpByName = new Map();
|
|
@@ -723,12 +755,14 @@ function reconcileDeferredMcpToolCatalogUncached(session, liveMcpTools) {
|
|
|
723
755
|
for (const name of previousNames) {
|
|
724
756
|
if (nextNames.has(name)) continue;
|
|
725
757
|
if (knownBefore && !rosterPermits(session, knownBefore.get(name) || { name })) continue;
|
|
726
|
-
|
|
758
|
+
// The server comes from the definition the session had, so a shortened
|
|
759
|
+
// name never has to be parsed.
|
|
760
|
+
removed.push({ name, server: parseMcpToolName(catalogBefore.get(name) || name)?.server || '' });
|
|
727
761
|
}
|
|
728
762
|
if (!added.length && !removed.length) return null;
|
|
729
763
|
mergePendingDeferredToolDelta(session, { added, removed });
|
|
730
764
|
session.updatedAt = Date.now();
|
|
731
|
-
return [...added.map((entry) => entry.name)
|
|
765
|
+
return [...added, ...removed].map((entry) => entry.name);
|
|
732
766
|
}
|
|
733
767
|
|
|
734
768
|
/**
|
|
@@ -742,6 +776,9 @@ function reconcileDeferredMcpToolCatalogUncached(session, liveMcpTools) {
|
|
|
742
776
|
* Returns the re-armed names, or null when there are none.
|
|
743
777
|
*/
|
|
744
778
|
export function rearmLateDeferredTools(session) {
|
|
779
|
+
// The compaction also drops the load results that carried a server's
|
|
780
|
+
// instruction text, so the next load of its tools delivers it again.
|
|
781
|
+
if (session) delete session.mcpInstructionsAnnounced;
|
|
745
782
|
if (!session || !Array.isArray(session.tools) || fixedSurfaceSession(session)) return null;
|
|
746
783
|
if (!Array.isArray(session.deferredMcpToolNames) || !Array.isArray(session.deferredAnnouncedTools)) return null;
|
|
747
784
|
// Listed in the boot manifest, or already loaded/discovered: still visible.
|
|
@@ -797,7 +834,8 @@ export function selectDeferredTools(session, names, mode, { exact = false } = {}
|
|
|
797
834
|
const key = clean(raw);
|
|
798
835
|
if (byName.has(key) || byName.has(key.toLowerCase())) return [key];
|
|
799
836
|
const members = mcpServerSelection(catalog, key).map((tool) => clean(tool?.name));
|
|
800
|
-
|
|
837
|
+
if (members.length) return members;
|
|
838
|
+
return [key];
|
|
801
839
|
});
|
|
802
840
|
for (const rawName of new Set(requested)) {
|
|
803
841
|
const requestedName = clean(rawName);
|
|
@@ -878,14 +916,67 @@ function resolvableCatalog(session) {
|
|
|
878
916
|
return filterSessionToolPolicy(tools, session);
|
|
879
917
|
}
|
|
880
918
|
|
|
919
|
+
// A server's instruction text rides the first load_tool naming any of its
|
|
920
|
+
// tools (loaded now, already active, or described on the bridge), once until
|
|
921
|
+
// compaction (`mcpInstructionsAnnounced`; rearmLateDeferredTools clears it with
|
|
922
|
+
// the transcript that held the text): `## <server>` + body, sanitized and
|
|
923
|
+
// capped like the BP2 block it replaces. No text, nothing sent or recorded.
|
|
924
|
+
function pendingMcpInstructions(session, catalog, names) {
|
|
925
|
+
const map = session?.mcpServerInstructions;
|
|
926
|
+
if (!map || typeof map !== 'object' || !names.length) return [];
|
|
927
|
+
const byName = new Map(catalog.map((tool) => [clean(tool?.name), tool]));
|
|
928
|
+
const announced = new Set(Array.isArray(session.mcpInstructionsAnnounced) ? session.mcpInstructionsAnnounced : []);
|
|
929
|
+
const pending = [];
|
|
930
|
+
for (const name of names) {
|
|
931
|
+
const server = parseMcpToolName(byName.get(name) || name)?.server;
|
|
932
|
+
if (!server || announced.has(server) || !mcpServerManifestLabel(server)) continue;
|
|
933
|
+
const text = sanitizeMcpInstructionText(map[server]);
|
|
934
|
+
if (!text) continue;
|
|
935
|
+
announced.add(server);
|
|
936
|
+
pending.push({ server, block: `## ${server}\n${text}` });
|
|
937
|
+
}
|
|
938
|
+
return pending;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
function announceMcpServers(session, pending) {
|
|
942
|
+
if (!pending.length) return;
|
|
943
|
+
session.mcpInstructionsAnnounced = [
|
|
944
|
+
...new Set([...(session.mcpInstructionsAnnounced || []), ...pending.map((entry) => entry.server)]),
|
|
945
|
+
];
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
function claimMcpServerInstructions(session, catalog, names) {
|
|
949
|
+
const pending = pendingMcpInstructions(session, catalog, names);
|
|
950
|
+
announceMcpServers(session, pending);
|
|
951
|
+
return pending.map((entry) => entry.block).join('\n');
|
|
952
|
+
}
|
|
953
|
+
|
|
881
954
|
// Pure loader. Input is exact deferred-tool names/aliases; output reports
|
|
882
955
|
// loaded / already-active / missing / blocked tools PLUS pending/failed MCP
|
|
883
956
|
// servers. No listing, no ranking, no substring filter. `options.mcpStatus` is
|
|
884
957
|
// the runtime getter for per-server status.
|
|
885
958
|
export function renderToolSearch(args = {}, session, mode = 'full', options = {}) {
|
|
886
959
|
// Bridge mode: load_tool describes (bounded, paged) and never loads.
|
|
887
|
-
if (isToolBridgeEnabled(session)) return formatBridgeResult(describeBridgeTools(session, args, { mode }));
|
|
888
960
|
const catalog = resolvableCatalog(session);
|
|
961
|
+
if (isToolBridgeEnabled(session)) {
|
|
962
|
+
// The page counts the instruction text inside its size budget; only the
|
|
963
|
+
// servers whose text made it into the returned page are marked announced.
|
|
964
|
+
const pendingFor = (names) => pendingMcpInstructions(session, catalog, names);
|
|
965
|
+
const described = describeBridgeTools(session, args, {
|
|
966
|
+
mode,
|
|
967
|
+
instructionsFor: (names) =>
|
|
968
|
+
pendingFor(names)
|
|
969
|
+
.map((entry) => entry.block)
|
|
970
|
+
.join('\n'),
|
|
971
|
+
});
|
|
972
|
+
if (!described.error && described.mcpInstructions) {
|
|
973
|
+
announceMcpServers(
|
|
974
|
+
session,
|
|
975
|
+
pendingFor((described.entries || []).map((entry) => clean(entry?.name)).filter(Boolean))
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
return formatBridgeResult(described);
|
|
979
|
+
}
|
|
889
980
|
const requestedNames = parseToolSelection(args.names);
|
|
890
981
|
const { pending: pendingMcpServers, failed: failedMcpServers } = pendingAndFailedMcpServers(options?.mcpStatus);
|
|
891
982
|
const mcpFields = {
|
|
@@ -955,11 +1046,15 @@ export function renderToolSearch(args = {}, session, mode = 'full', options = {}
|
|
|
955
1046
|
if (missing.length && failedMcpServers.length) {
|
|
956
1047
|
notes.push('Some requested names may belong to a failed MCP server; those tools are unavailable.');
|
|
957
1048
|
}
|
|
1049
|
+
// Tools the session already had active (loaded before, or eager) count too:
|
|
1050
|
+
// their server's text may never have been delivered.
|
|
1051
|
+
const mcpInstructions = claimMcpServerInstructions(session, catalog, [...loaded, ...alreadyActive]);
|
|
958
1052
|
return JSON.stringify(
|
|
959
1053
|
{
|
|
960
1054
|
// `selected` retained for back-compat consumers (mode is always 'select').
|
|
961
1055
|
selected: { mode: 'select', tools: toolSelection },
|
|
962
1056
|
...(nativeToolSearch ? { nativeToolSearch } : {}),
|
|
1057
|
+
...(mcpInstructions ? { mcpInstructions } : {}),
|
|
963
1058
|
loaded,
|
|
964
1059
|
alreadyActive,
|
|
965
1060
|
...(alreadyActiveSchemas.length ? { alreadyActiveSchemas } : {}),
|