mixdog 1.4.0 → 1.4.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/package.json +3 -2
- package/scripts/build-shipped-history.mjs +115 -33
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +183 -63
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +91 -66
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +124 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/lib/test-failure-records.mjs +14 -1
- package/scripts/lib/test-failure-summary.mjs +16 -4
- package/scripts/lib/test-spawn-ledger.mjs +12 -3
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -5
- package/scripts/suite-health.mjs +115 -24
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +9 -14
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/explore/AGENT.md +22 -0
- package/src/agents/explore/agent.json +6 -0
- package/src/app.mjs +4 -0
- package/src/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +23 -2
- package/src/defaults/skills/browser-use/SKILL.md +10 -5
- package/src/defaults/skills/code-tidy/SKILL.md +71 -102
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
- package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
- package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
- package/src/defaults/skills/computer-use/SKILL.md +16 -4
- package/src/defaults/skills/goal-management/SKILL.md +1 -1
- package/src/defaults/skills/setup/references/actions.md +12 -6
- package/src/defaults/skills/setup/references/surfaces.md +2 -2
- package/src/defaults/skills/setup-guide/SKILL.md +5 -2
- package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
- package/src/defaults/skills/skill-creator/SKILL.md +85 -190
- package/src/defaults/skills/skill-creator/references/design.md +70 -162
- package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
- package/src/defaults/skills/test-suite/SKILL.md +194 -0
- package/src/defaults/skills/test-suite/references/case-management.md +51 -0
- package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
- package/src/defaults/skills/test-suite/references/reliability.md +49 -0
- package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
- package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
- package/src/defaults/skills/visualize/SKILL.md +6 -2
- package/src/lib/rules-builder.cjs +35 -42
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +12 -7
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +8 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
- package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
- package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
- package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
- package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +29 -11
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
- package/src/runtime/connectors/gmail-app-password.mjs +3 -3
- package/src/runtime/explore/explorer.mjs +93 -0
- package/src/runtime/explore/tool-defs.mjs +35 -0
- package/src/runtime/explore/tool.mjs +123 -0
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/agent-route-config.mjs +17 -2
- package/src/runtime/shared/atomic-file.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +15 -6
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/connector-accounts.mjs +5 -5
- package/src/runtime/shared/connector-catalog.d.mts +11 -4
- package/src/runtime/shared/connector-catalog.mjs +60 -52
- package/src/runtime/shared/custom-provider-keys.mjs +20 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-has-data.mjs +26 -2
- package/src/runtime/shared/file-lock.mjs +13 -15
- package/src/runtime/shared/git-launch.d.mts +9 -0
- package/src/runtime/shared/git-launch.mjs +213 -0
- package/src/runtime/shared/git-runner-worker.mjs +2 -1
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +11 -2
- package/src/runtime/shared/llm/http-agent.mjs +313 -29
- package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
- package/src/runtime/shared/llm/model-catalog.mjs +46 -6
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
- package/src/runtime/shared/llm/system-proxy.mjs +452 -0
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/provider-accounts.mjs +52 -2
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +113 -36
- package/src/runtime/shared/tool-work-units.mjs +6 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
- package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
- package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
- package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +72 -0
- package/src/runtime/shared/worktrees/manager.mjs +285 -168
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/tidy/install.mjs +95 -15
- package/src/runtime/tidy/languages.mjs +17 -15
- package/src/runtime/tidy/process.mjs +7 -4
- package/src/runtime/tidy/resolve.mjs +19 -16
- package/src/runtime/tidy/runners/biome.mjs +3 -3
- package/src/runtime/tidy/tool.mjs +1 -1
- package/src/runtime/tidy/worktree.mjs +10 -6
- package/src/runtime/visualize-bridge/client.mjs +6 -1
- package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
- package/src/runtime/web-search/index.mjs +1 -1
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +458 -312
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +7 -1
- package/src/session-runtime/bot-status.mjs +107 -101
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +401 -36
- package/src/session-runtime/conversation-import/service.mjs +35 -8
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/held-requests.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
- package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
- package/src/session-runtime/mixy-heartbeat.mjs +1 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-auth/login.mjs +2 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +98 -35
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
- package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
- package/src/session-runtime/resource-mcp-servers.mjs +5 -4
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
- package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
- package/src/session-runtime/services/daemon-candidate.mjs +4 -1
- package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
- package/src/session-runtime/services/plugin-admin.mjs +10 -6
- package/src/session-runtime/services/provider-admin.mjs +283 -11
- package/src/session-runtime/session-turn-api.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
- package/src/session-runtime/settings-system-api.mjs +1 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
- package/src/session-runtime/setup-tool/executor.mjs +6 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/turn/agent-ops.mjs +23 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/activity-guards.mjs +176 -0
- package/src/session-runtime/workspace/session-view.mjs +149 -0
- package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
- package/src/session-runtime/workspace/transition-runner.mjs +188 -0
- package/src/session-runtime/workspace/transitions.mjs +108 -1041
- package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
- package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
- package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
- package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +169 -138
- package/src/standalone/daemon.mjs +7 -0
- package/src/standalone/desktop-service-registry.mjs +9 -0
- package/src/standalone/local-session-runtime.mjs +5 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
- package/src/standalone/session-client.mjs +5 -1
- package/src/standalone/session-frame-stream.mjs +83 -11
- package/src/standalone/session-protocol.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/agent-tree.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/App.jsx +154 -164
- package/src/tui/app/app-view/floating-panel.jsx +10 -4
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +21 -10
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
- package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
- package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
- package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +29 -18
- package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
- package/src/tui/app/slash-dispatch.mjs +1 -1
- package/src/tui/app/use-btw-panel.mjs +29 -0
- package/src/tui/app/use-context-panel-refresh.mjs +31 -0
- package/src/tui/app/use-model-catalog-cache.mjs +13 -10
- package/src/tui/app/use-mouse-input.mjs +11 -0
- package/src/tui/app/use-onboarding-start.mjs +8 -3
- package/src/tui/app/use-panel-transition.mjs +10 -1
- package/src/tui/app/use-pasted-buffers.mjs +28 -20
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
- package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +3 -2
- package/src/tui/app/use-selection-focus.mjs +11 -2
- package/src/tui/app/use-selection-geometry.mjs +18 -9
- package/src/tui/app/use-selection-paint.mjs +4 -4
- package/src/tui/app/use-selection-stitch.mjs +3 -3
- package/src/tui/app/use-slash-palette.mjs +62 -0
- package/src/tui/app/use-terminal-chrome.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +47 -32
- package/src/tui/app/use-transcript-follow.mjs +12 -4
- package/src/tui/app/use-transcript-scroll.mjs +46 -17
- package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
- package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
- package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
- package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +21 -11
- package/src/tui/app/use-tui-ready.mjs +18 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
- package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
- package/src/tui/components/Picker.jsx +27 -3
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/components/SignInUrl.jsx +68 -0
- package/src/tui/components/TextEntryPanel.jsx +76 -46
- package/src/tui/components/sign-in-url-layout.mjs +24 -0
- package/src/tui/dist/index.mjs +1963 -1361
- package/src/tui/session/goal-turn-state.mjs +6 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +8 -0
- package/src/tui/session/session-api/intake/abort.mjs +2 -1
- package/src/tui/session/session-api/intake.mjs +2 -0
- package/src/tui/session/session-api/integrations.mjs +2 -2
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +2 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
- package/src/tui/session/transcript-spill.mjs +92 -4
- package/src/tui/session/transcript-store.mjs +2 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -17,6 +17,7 @@ import { scheduleCallerScope } from '../services/schedule-access.mjs';
|
|
|
17
17
|
import { worktreeCallerScope } from '../services/worktree-access.mjs';
|
|
18
18
|
import { resolveHandoffAttachments, sessionRoots } from '../handoff-attachments.mjs';
|
|
19
19
|
import { delegationChainOf } from '../bot-chain.mjs';
|
|
20
|
+
import { BOT_TARGET_ACTIONS, resolveBotTarget } from '../bot-target.mjs';
|
|
20
21
|
|
|
21
22
|
const USER_TITLE_ERROR = 'session: the user already titled this session; the title was not changed';
|
|
22
23
|
|
|
@@ -41,6 +42,140 @@ function callerAttachmentParts(rt, args, callerCwd, surface) {
|
|
|
41
42
|
}).parts;
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
/** `session` actions that act on another session through session control
|
|
46
|
+
* (list, bots, read, send, cancel, delete, create, status of a target). */
|
|
47
|
+
async function runSessionControl(
|
|
48
|
+
{ rt, executeSessionControl, listBots, getSessionManager },
|
|
49
|
+
args,
|
|
50
|
+
{ action, target, callerSessionId, callerCwd }
|
|
51
|
+
) {
|
|
52
|
+
// `callerAgentId`: the bot whose conversation gets results reported
|
|
53
|
+
// back; `callerBotId`: the bot the caller acts as, attended or not,
|
|
54
|
+
// for what only a bot's own sessions allow (an effort change).
|
|
55
|
+
const callerAgentId = attendedAgentOf(rt.session);
|
|
56
|
+
const acting = resolveSessionMode({ session: rt.session });
|
|
57
|
+
const callerBotId = acting.mode === AGENT_MODE ? acting.agentId : '';
|
|
58
|
+
if (action === 'create' && !callerAgentId) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
'session: create belongs to a bot conversation; delegated workers, agent task sessions and schedule/webhook runs cannot create agent task sessions'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
// A bot id names that bot's home chat; every check below and in the
|
|
64
|
+
// control runs on the chat it resolves to.
|
|
65
|
+
const sessionTarget = BOT_TARGET_ACTIONS.has(action) && target ? await resolveBotTarget(target, listBots) : target;
|
|
66
|
+
// A task session reaches its agent only through its reported result.
|
|
67
|
+
const origin = rt.session?.taskOrigin;
|
|
68
|
+
if (
|
|
69
|
+
action === 'send' &&
|
|
70
|
+
origin &&
|
|
71
|
+
(sessionTarget === origin.sessionId || agentIdOfHomeSession(sessionTarget) === origin.agentId)
|
|
72
|
+
) {
|
|
73
|
+
throw new Error('session: a task session reports to its agent only through its result');
|
|
74
|
+
}
|
|
75
|
+
if (typeof executeSessionControl !== 'function') {
|
|
76
|
+
throw new Error('session: cross-session control is unavailable in this runtime');
|
|
77
|
+
}
|
|
78
|
+
const { attachments, ...rest } = args || {};
|
|
79
|
+
if (attachments !== undefined && action !== 'send' && action !== 'create') {
|
|
80
|
+
throw new Error(`session: attachments apply to send and create, not action=${action}`);
|
|
81
|
+
}
|
|
82
|
+
const attachmentParts = callerAttachmentParts(rt, args, callerCwd, 'session');
|
|
83
|
+
return JSON.stringify(
|
|
84
|
+
await executeSessionControl(
|
|
85
|
+
{ ...rest, action, ...(sessionTarget !== target ? { session_id: sessionTarget } : {}) },
|
|
86
|
+
{
|
|
87
|
+
callerSessionId,
|
|
88
|
+
callerAgentId,
|
|
89
|
+
callerBotId,
|
|
90
|
+
callerCwd,
|
|
91
|
+
...(action === 'send' || action === 'create'
|
|
92
|
+
? {
|
|
93
|
+
callerHop: turnHopOf(rt.session),
|
|
94
|
+
// The bot chain this turn acts in (bot-chain.mjs), checked
|
|
95
|
+
// against the target and carried to the turn it starts —
|
|
96
|
+
// only when the sender is a bot conversation (a bot's chat,
|
|
97
|
+
// room seat or run); any other session hands work to any
|
|
98
|
+
// bot as before, whatever started its turn (the hop limit
|
|
99
|
+
// still bounds a loop).
|
|
100
|
+
callerBotChain: callerBotId
|
|
101
|
+
? delegationChainOf(callerSessionId, (id) =>
|
|
102
|
+
id === rt.session?.id ? rt.session : getSessionManager()?.getSession?.(id) || null
|
|
103
|
+
)
|
|
104
|
+
: [],
|
|
105
|
+
}
|
|
106
|
+
: {}),
|
|
107
|
+
// Whether a create may provision a worktree (worktree-access.mjs).
|
|
108
|
+
...(action === 'create' ? { callerScope: worktreeCallerScope(rt.session) } : {}),
|
|
109
|
+
// Which bots and sessions it may see (bot-status.mjs).
|
|
110
|
+
...(action === 'bots' || action === 'list' ? { callerScope: scheduleCallerScope(rt.session) } : {}),
|
|
111
|
+
...(attachmentParts.length ? { attachmentParts } : {}),
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** `session action=rename`: the AI title of the Lead session, mirrored onto the live session. */
|
|
118
|
+
async function renameSession({ rt, getSessionManager }, action, sessionId, args) {
|
|
119
|
+
if (rt.config?.aiSessionTitles === false) throw new Error('session: AI session titles are disabled in settings');
|
|
120
|
+
const title = clean(args?.title);
|
|
121
|
+
if (!title) throw new Error('session: title is required for action=rename');
|
|
122
|
+
const result = await getSessionManager()?.updateSessionAiTitle(sessionId, title);
|
|
123
|
+
if (!result?.ok) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
result?.reason === 'user-title' ? USER_TITLE_ERROR : `session: rename failed (${result?.reason || 'unavailable'})`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
// Mirror the store's truth onto the live session, never the AI title
|
|
129
|
+
// itself: a manual rename that landed while the save was awaited wins.
|
|
130
|
+
const stored = getSessionManager()?.getSession?.(sessionId);
|
|
131
|
+
if (stored && rt.session?.id === sessionId && stored !== rt.session) {
|
|
132
|
+
rt.session.title = stored.title;
|
|
133
|
+
rt.session.titleLocked = stored.titleLocked;
|
|
134
|
+
rt.session.titleSource = stored.titleSource;
|
|
135
|
+
rt.session.titleUpdatedAt = stored.titleUpdatedAt;
|
|
136
|
+
}
|
|
137
|
+
if (stored && stored.titleSource === 'user') throw new Error(USER_TITLE_ERROR);
|
|
138
|
+
return JSON.stringify({ action, sessionId, title: result.title }, null, 2);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** `session action=fork`: inherit the Lead session into a new one. */
|
|
142
|
+
async function forkSession(getLifecycleApi, action, sessionId, args) {
|
|
143
|
+
const lifecycle = getLifecycleApi();
|
|
144
|
+
if (typeof lifecycle?.inheritToNewSession !== 'function') {
|
|
145
|
+
throw new Error('session: fork is unavailable in this runtime');
|
|
146
|
+
}
|
|
147
|
+
const result = await lifecycle.inheritToNewSession(sessionId, {
|
|
148
|
+
compact: args?.compact === true,
|
|
149
|
+
titleSuffix: ' (Fork)',
|
|
150
|
+
});
|
|
151
|
+
return JSON.stringify(
|
|
152
|
+
{ action, sourceSessionId: sessionId, sessionId: result.sessionId, compacted: result.compacted === true },
|
|
153
|
+
null,
|
|
154
|
+
2
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** `session action=status`: the current session's identity, folder and route. */
|
|
159
|
+
function sessionStatusJson(rt, callerCtx, currentCwd) {
|
|
160
|
+
const current = rt.session;
|
|
161
|
+
return JSON.stringify(
|
|
162
|
+
{
|
|
163
|
+
sessionId: callerCtx?.callerSessionId || current?.id || null,
|
|
164
|
+
title: current?.title || null,
|
|
165
|
+
titleSource: current?.titleSource || null,
|
|
166
|
+
cwd: currentCwd,
|
|
167
|
+
project: current?.workspace?.projectPath || current?.desktopSession?.projectPath || currentCwd,
|
|
168
|
+
provider: current?.provider || null,
|
|
169
|
+
model: current?.model || null,
|
|
170
|
+
effort: current?.effort || null,
|
|
171
|
+
autoEffort: current?.autoEffort !== false,
|
|
172
|
+
fast: current?.fast === true,
|
|
173
|
+
},
|
|
174
|
+
null,
|
|
175
|
+
2
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
44
179
|
export function createWorkspaceToolHandlers({
|
|
45
180
|
rt,
|
|
46
181
|
goalRuntime,
|
|
@@ -50,6 +185,7 @@ export function createWorkspaceToolHandlers({
|
|
|
50
185
|
getSessionManager = () => null,
|
|
51
186
|
getLifecycleApi = () => null,
|
|
52
187
|
executeSessionControl = null,
|
|
188
|
+
listBots,
|
|
53
189
|
}) {
|
|
54
190
|
const assertLead = (action, callerCtx) => {
|
|
55
191
|
const callerSessionId = callerCtx?.callerSessionId || rt.session?.id || null;
|
|
@@ -99,66 +235,12 @@ export function createWorkspaceToolHandlers({
|
|
|
99
235
|
(action === 'status' && target)
|
|
100
236
|
) {
|
|
101
237
|
const callerSessionId = assertLead(action, callerCtx);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (action === 'create' && !callerAgentId) {
|
|
109
|
-
throw new Error(
|
|
110
|
-
'session: create belongs to a bot conversation; delegated workers, agent task sessions and schedule/webhook runs cannot create agent task sessions'
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
// A task session reaches its agent only through its reported result.
|
|
114
|
-
const origin = rt.session?.taskOrigin;
|
|
115
|
-
if (
|
|
116
|
-
action === 'send' &&
|
|
117
|
-
origin &&
|
|
118
|
-
(target === origin.sessionId || agentIdOfHomeSession(target) === origin.agentId)
|
|
119
|
-
) {
|
|
120
|
-
throw new Error('session: a task session reports to its agent only through its result');
|
|
121
|
-
}
|
|
122
|
-
if (typeof executeSessionControl !== 'function') {
|
|
123
|
-
throw new Error('session: cross-session control is unavailable in this runtime');
|
|
124
|
-
}
|
|
125
|
-
const { attachments, ...rest } = args || {};
|
|
126
|
-
if (attachments !== undefined && action !== 'send' && action !== 'create') {
|
|
127
|
-
throw new Error(`session: attachments apply to send and create, not action=${action}`);
|
|
128
|
-
}
|
|
129
|
-
const attachmentParts = callerAttachmentParts(rt, args, callerCwd, 'session');
|
|
130
|
-
return JSON.stringify(
|
|
131
|
-
await executeSessionControl(
|
|
132
|
-
{ ...rest, action },
|
|
133
|
-
{
|
|
134
|
-
callerSessionId,
|
|
135
|
-
callerAgentId,
|
|
136
|
-
callerBotId,
|
|
137
|
-
callerCwd,
|
|
138
|
-
...(action === 'send' || action === 'create'
|
|
139
|
-
? {
|
|
140
|
-
callerHop: turnHopOf(rt.session),
|
|
141
|
-
// The bot chain this turn acts in (bot-chain.mjs), checked
|
|
142
|
-
// against the target and carried to the turn it starts —
|
|
143
|
-
// only when the sender is a bot conversation (a bot's chat,
|
|
144
|
-
// room seat or run); any other session hands work to any
|
|
145
|
-
// bot as before, whatever started its turn (the hop limit
|
|
146
|
-
// still bounds a loop).
|
|
147
|
-
callerBotChain: callerBotId
|
|
148
|
-
? delegationChainOf(callerSessionId, (id) =>
|
|
149
|
-
id === rt.session?.id ? rt.session : getSessionManager()?.getSession?.(id) || null
|
|
150
|
-
)
|
|
151
|
-
: [],
|
|
152
|
-
}
|
|
153
|
-
: {}),
|
|
154
|
-
// Whether a create may provision a worktree (worktree-access.mjs).
|
|
155
|
-
...(action === 'create' ? { callerScope: worktreeCallerScope(rt.session) } : {}),
|
|
156
|
-
// Which bots and sessions it may see (bot-status.mjs).
|
|
157
|
-
...(action === 'bots' || action === 'list' ? { callerScope: scheduleCallerScope(rt.session) } : {}),
|
|
158
|
-
...(attachmentParts.length ? { attachmentParts } : {}),
|
|
159
|
-
}
|
|
160
|
-
)
|
|
161
|
-
);
|
|
238
|
+
return runSessionControl({ rt, executeSessionControl, listBots, getSessionManager }, args, {
|
|
239
|
+
action,
|
|
240
|
+
target,
|
|
241
|
+
callerSessionId,
|
|
242
|
+
callerCwd,
|
|
243
|
+
});
|
|
162
244
|
}
|
|
163
245
|
// Mixy's proposals to the user (mixy-heartbeat.mjs): kept so none repeats.
|
|
164
246
|
if (action === 'suggest') {
|
|
@@ -178,28 +260,7 @@ export function createWorkspaceToolHandlers({
|
|
|
178
260
|
if (action === 'status' || action === 'list-projects' || action === 'set-project') assertLead(action, callerCtx);
|
|
179
261
|
if (action === 'rename') {
|
|
180
262
|
const sessionId = assertLead(action, callerCtx);
|
|
181
|
-
|
|
182
|
-
const title = clean(args?.title);
|
|
183
|
-
if (!title) throw new Error('session: title is required for action=rename');
|
|
184
|
-
const result = await getSessionManager()?.updateSessionAiTitle(sessionId, title);
|
|
185
|
-
if (!result?.ok) {
|
|
186
|
-
throw new Error(
|
|
187
|
-
result?.reason === 'user-title'
|
|
188
|
-
? USER_TITLE_ERROR
|
|
189
|
-
: `session: rename failed (${result?.reason || 'unavailable'})`
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
// Mirror the store's truth onto the live session, never the AI title
|
|
193
|
-
// itself: a manual rename that landed while the save was awaited wins.
|
|
194
|
-
const stored = getSessionManager()?.getSession?.(sessionId);
|
|
195
|
-
if (stored && rt.session?.id === sessionId && stored !== rt.session) {
|
|
196
|
-
rt.session.title = stored.title;
|
|
197
|
-
rt.session.titleLocked = stored.titleLocked;
|
|
198
|
-
rt.session.titleSource = stored.titleSource;
|
|
199
|
-
rt.session.titleUpdatedAt = stored.titleUpdatedAt;
|
|
200
|
-
}
|
|
201
|
-
if (stored && stored.titleSource === 'user') throw new Error(USER_TITLE_ERROR);
|
|
202
|
-
return JSON.stringify({ action, sessionId, title: result.title }, null, 2);
|
|
263
|
+
return renameSession({ rt, getSessionManager }, action, sessionId, args);
|
|
203
264
|
}
|
|
204
265
|
if (action === 'compact') {
|
|
205
266
|
const sessionId = assertLead(action, callerCtx);
|
|
@@ -213,38 +274,10 @@ export function createWorkspaceToolHandlers({
|
|
|
213
274
|
}
|
|
214
275
|
if (action === 'fork') {
|
|
215
276
|
const sessionId = assertLead(action, callerCtx);
|
|
216
|
-
|
|
217
|
-
if (typeof lifecycle?.inheritToNewSession !== 'function') {
|
|
218
|
-
throw new Error('session: fork is unavailable in this runtime');
|
|
219
|
-
}
|
|
220
|
-
const result = await lifecycle.inheritToNewSession(sessionId, {
|
|
221
|
-
compact: args?.compact === true,
|
|
222
|
-
titleSuffix: ' (Fork)',
|
|
223
|
-
});
|
|
224
|
-
return JSON.stringify(
|
|
225
|
-
{ action, sourceSessionId: sessionId, sessionId: result.sessionId, compacted: result.compacted === true },
|
|
226
|
-
null,
|
|
227
|
-
2
|
|
228
|
-
);
|
|
277
|
+
return forkSession(getLifecycleApi, action, sessionId, args);
|
|
229
278
|
}
|
|
230
279
|
if (action === 'status') {
|
|
231
|
-
|
|
232
|
-
return JSON.stringify(
|
|
233
|
-
{
|
|
234
|
-
sessionId: callerCtx?.callerSessionId || current?.id || null,
|
|
235
|
-
title: current?.title || null,
|
|
236
|
-
titleSource: current?.titleSource || null,
|
|
237
|
-
cwd: currentCwd,
|
|
238
|
-
project: current?.workspace?.projectPath || current?.desktopSession?.projectPath || currentCwd,
|
|
239
|
-
provider: current?.provider || null,
|
|
240
|
-
model: current?.model || null,
|
|
241
|
-
effort: current?.effort || null,
|
|
242
|
-
autoEffort: current?.autoEffort !== false,
|
|
243
|
-
fast: current?.fast === true,
|
|
244
|
-
},
|
|
245
|
-
null,
|
|
246
|
-
2
|
|
247
|
-
);
|
|
280
|
+
return sessionStatusJson(rt, callerCtx, currentCwd);
|
|
248
281
|
}
|
|
249
282
|
if (action === 'list-projects') {
|
|
250
283
|
return JSON.stringify(
|
|
@@ -150,14 +150,19 @@ export function buildColdHeir(source, now = Date.now()) {
|
|
|
150
150
|
// earlier folder) is the source's own: the heir's prompt is built for the
|
|
151
151
|
// folder it actually starts in. Project memory follows the Project, which a
|
|
152
152
|
// worktree shares, so the source's current memory slice carries over.
|
|
153
|
+
// In the same folder only the environment facts are rebuilt: they name the
|
|
154
|
+
// heir's own scratch directory, never the source's, while the inherited
|
|
155
|
+
// instruction files and memory stay as the source presented them.
|
|
153
156
|
const pending = source.workspaceReroot;
|
|
154
157
|
delete heir.workspaceReroot;
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
if (heir.cwd) {
|
|
159
|
+
const context = buildWorkspacePromptContext(heir, heir.cwd);
|
|
160
|
+
refreshSessionWorkspaceContext(
|
|
161
|
+
heir,
|
|
162
|
+
projectFolder || pending
|
|
163
|
+
? { cwd: heir.cwd, ...context, coreMemoryContext: pending?.target?.coreMemoryContext }
|
|
164
|
+
: { cwd: heir.cwd, environmentContext: context.environmentContext }
|
|
165
|
+
);
|
|
161
166
|
}
|
|
162
167
|
invalidateContextUsageSnapshot(heir);
|
|
163
168
|
invalidateProviderContextBaseline(heir);
|
|
@@ -21,7 +21,11 @@ import {
|
|
|
21
21
|
wantsIncomingTail,
|
|
22
22
|
} from '../../runtime/agent/orchestrator/session/store-summary-last-message.mjs';
|
|
23
23
|
import { isRealTurnMessage } from '../../runtime/agent/orchestrator/session/compact/user-message-kind.mjs';
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
compactCount as compactCountOf,
|
|
26
|
+
compactCountField,
|
|
27
|
+
realTurnCount as realTurnCountOf,
|
|
28
|
+
} from '../../runtime/agent/orchestrator/session/store-summary-fields.mjs';
|
|
25
29
|
|
|
26
30
|
const VISIBLE_OWNERS = ['cli', 'user', 'mixdog'];
|
|
27
31
|
|
|
@@ -107,6 +111,10 @@ export function leadSessionRow(s, working = false) {
|
|
|
107
111
|
// sit among the counted ones: a bot row's unread pill counts those past
|
|
108
112
|
// the read cursor. Absent when unknown; clients then show one.
|
|
109
113
|
...(incomingTail ? { incomingTail } : {}),
|
|
114
|
+
// The numbering epoch of messageCount: each compaction restarts it. A
|
|
115
|
+
// summary row carries it at the top; a stored session in its compaction
|
|
116
|
+
// record. Unknown stays absent.
|
|
117
|
+
...compactCountField(compactCountOf(s) === null ? s.compaction : s),
|
|
110
118
|
title: cleanSessionPreview(s.title || '', 100),
|
|
111
119
|
preview,
|
|
112
120
|
// The latest user or assistant line (an agent contact's row shows it).
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* tombstone barrier and the turn abort.
|
|
5
5
|
*/
|
|
6
6
|
import { SessionClosedError } from '../../../runtime/agent/orchestrator/session/manager/session-errors.mjs';
|
|
7
|
+
import { armTurnTimeout } from '../../../runtime/agent/orchestrator/session/manager/turn-reap.mjs';
|
|
7
8
|
import { isScratchSession } from '../shared.mjs';
|
|
8
9
|
|
|
9
10
|
// SessionEnd reason mapped to standard values ('clear'/'exit' where
|
|
@@ -88,11 +89,15 @@ export function closeCanonicalSession(deps, reason = 'canonical-session-close',
|
|
|
88
89
|
return true;
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
/** `options.timeout` is the progress watchdog's explicit "this abort is a
|
|
93
|
+
* timeout": the reap is armed before either abort runs, while the turn is
|
|
94
|
+
* still un-aborted (the outer abort cascades into the manager's controller). */
|
|
95
|
+
export function abortRuntime(deps, reason = 'cli-abort', { timeout = false } = {}) {
|
|
92
96
|
const { getSession, getReservedSessionId, abortActiveTurns, mgr } = deps;
|
|
93
97
|
const session = getSession();
|
|
94
98
|
const sessionId = session?.id || getReservedSessionId?.() || 'pending';
|
|
95
99
|
const abortError = new SessionClosedError(sessionId, `runtime abort (reason=${reason})`, reason);
|
|
100
|
+
if (timeout && session?.id) armTurnTimeout(session.id);
|
|
96
101
|
let outerAborted = false;
|
|
97
102
|
try {
|
|
98
103
|
outerAborted = abortActiveTurns?.(abortError) === true;
|
|
@@ -281,6 +281,6 @@ export function createTeardown(deps, { ingestSessionIntoMemory, closeSurfaceSess
|
|
|
281
281
|
return {
|
|
282
282
|
closeCanonicalSession: (reason, options) => closeCanonicalSession(deps, reason, options),
|
|
283
283
|
close,
|
|
284
|
-
abort: (reason) => abortRuntime(deps, reason),
|
|
284
|
+
abort: (reason, options) => abortRuntime(deps, reason, options),
|
|
285
285
|
};
|
|
286
286
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
connectorOfServer,
|
|
10
10
|
gmailAppPasswordAccount,
|
|
11
11
|
} from '../../runtime/shared/connector-catalog.mjs';
|
|
12
|
-
import { connectorAccountHealth } from '../../runtime/connectors/connector-accounts-mcp.mjs';
|
|
12
|
+
import { connectorAccountHealth, connectorAccountInUse } from '../../runtime/connectors/connector-accounts-mcp.mjs';
|
|
13
13
|
import { googleOAuthClient } from '../../runtime/shared/google-oauth-client.mjs';
|
|
14
14
|
import { envFlag } from '../../runtime/shared/env.mjs';
|
|
15
15
|
import { resolveMcpServerCatalog } from './plugin-servers.mjs';
|
|
@@ -119,10 +119,12 @@ export function createMcpServerCatalog({
|
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
/** One account of a
|
|
123
|
-
* `{ name, email, enabled?, appPassword?, oauth?, ownClient?, error?, authRequired? }`
|
|
124
|
-
* (`enabled: false` only for an account that is switched off
|
|
125
|
-
|
|
122
|
+
/** One account of a connector server, as its row lists it:
|
|
123
|
+
* `{ name, email, enabled?, inUse?, appPassword?, oauth?, ownClient?, error?, authRequired? }`
|
|
124
|
+
* (`enabled: false` only for an account that is switched off; `inUse:
|
|
125
|
+
* true` only for the connector's last-used account, the one a call
|
|
126
|
+
* without a conversation history uses). */
|
|
127
|
+
function accountRow(accountCfg, enabled, inUse) {
|
|
126
128
|
const address = gmailAppPasswordAccount(accountCfg);
|
|
127
129
|
const oauth = address ? null : mcpClient.getMcpServerOAuthState?.(accountCfg);
|
|
128
130
|
const state = connectorAccountHealth(accountCfg.name);
|
|
@@ -130,6 +132,7 @@ export function createMcpServerCatalog({
|
|
|
130
132
|
return {
|
|
131
133
|
name: accountCfg.name,
|
|
132
134
|
...(enabled ? {} : { enabled: false }),
|
|
135
|
+
...(inUse ? { inUse: true } : {}),
|
|
133
136
|
email: address || oauth?.account || state?.email || '',
|
|
134
137
|
...(address ? { appPassword: { account: address } } : {}),
|
|
135
138
|
...(oauth ? { oauth } : {}),
|
|
@@ -152,11 +155,14 @@ export function createMcpServerCatalog({
|
|
|
152
155
|
failures.get(name) || (dead ? { msg: live.error || live.lastError || 'MCP server is not alive' } : undefined);
|
|
153
156
|
const entry = entries[name] || {};
|
|
154
157
|
const loginPending = !(live && !dead) && mcpClient.isMcpLoginPending?.(name, getMcpScopeId()) === true;
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
158
|
+
const stored = entry.owner ? [] : connectorAccountsOf(cfg);
|
|
159
|
+
// The connector's last-used account (none when that one was removed),
|
|
160
|
+
// else its topmost switched-on one.
|
|
161
|
+
const recorded = stored.length ? connectorAccountInUse(connectorOfServer(cfg)) : '';
|
|
162
|
+
const inUse = recorded || stored.find(connectorAccountEnabled)?.name;
|
|
163
|
+
const accounts = stored.map((account) =>
|
|
164
|
+
accountRow(connectorAccountServer(cfg, account), connectorAccountEnabled(account), account.name === inUse)
|
|
165
|
+
);
|
|
160
166
|
// A connector server none of whose accounts is signed in needs a sign-in, not a repair.
|
|
161
167
|
const accountsSignIn = accounts.length > 0 && accounts.every((account) => account.authRequired === true);
|
|
162
168
|
const status = mcpServerStatus(
|
|
@@ -79,8 +79,11 @@ export function createMcpServerInput({ mcpClient, getCurrentCwd }) {
|
|
|
79
79
|
const type = clean(input.type).toLowerCase();
|
|
80
80
|
if (url) {
|
|
81
81
|
const kind = URL_TRANSPORT_TYPES.get(type) || (/^wss?:\/\//i.test(url) ? 'ws' : 'http');
|
|
82
|
-
const
|
|
82
|
+
const normalizedUrl =
|
|
83
83
|
typeof mcpClient.normalizeMcpTransportUrl === 'function' ? mcpClient.normalizeMcpTransportUrl(url, kind) : url;
|
|
84
|
+
// URL parsing adds a "/" to a bare origin (`https://mcp.stripe.com`):
|
|
85
|
+
// keep the address as it was given, as the catalog and legacy entries do.
|
|
86
|
+
const secureUrl = normalizedUrl === `${url}/` ? url : normalizedUrl;
|
|
84
87
|
return { name, config: withOptionalHeaders({ type: kind, url: secureUrl }) };
|
|
85
88
|
}
|
|
86
89
|
const command = clean(input.command);
|
|
@@ -635,7 +635,7 @@ export function createMixyHeartbeat({
|
|
|
635
635
|
now = Date.now,
|
|
636
636
|
path = defaultStatePath(),
|
|
637
637
|
isEnabled = async () =>
|
|
638
|
-
(await import('../runtime/agent/orchestrator/config.mjs')).loadConfig({ secrets: false }).heartbeat
|
|
638
|
+
(await import('../runtime/agent/orchestrator/config.mjs')).loadConfig({ secrets: false }).heartbeat === true,
|
|
639
639
|
// Whether the representative bot exists (mixy-presence.mjs, the rule the
|
|
640
640
|
// desktop and her routines follow): without it no check runs at all.
|
|
641
641
|
mixyExists = async () => (await import('./routine-owner.mjs')).readMixyExists(),
|
|
@@ -217,11 +217,20 @@ function switchSessionInPlace(deps, session) {
|
|
|
217
217
|
|
|
218
218
|
/** The Lead's fallback models after this selection, checked like an agent's
|
|
219
219
|
* chain (leaf routes, distinct providers): an explicit list replaces the
|
|
220
|
-
* stored one ([] clears it), a selection without one keeps it
|
|
220
|
+
* stored one ([] clears it), a selection without one keeps it as stored — a
|
|
221
|
+
* fallback on the new main model's provider stays saved and is inactive
|
|
222
|
+
* (executionFallbacks). */
|
|
221
223
|
async function leadFallbackChain(deps, next, primary) {
|
|
222
224
|
const storedPreset = findPreset(deps.getConfig(), workflowPresetId('lead'));
|
|
223
|
-
const
|
|
225
|
+
const explicit = hasOwn(next || {}, 'fallbacks');
|
|
226
|
+
const requested = explicit ? next.fallbacks : storedPreset?.fallbacks;
|
|
224
227
|
if (!Array.isArray(requested) || !requested.length) return [];
|
|
228
|
+
if (!explicit) {
|
|
229
|
+
return (
|
|
230
|
+
normalizeWorkflowRoute({ provider: primary.provider, model: primary.model, fallbacks: requested })?.fallbacks ||
|
|
231
|
+
[]
|
|
232
|
+
);
|
|
233
|
+
}
|
|
225
234
|
const chain = routeChain({ provider: primary.provider, model: primary.model, fallbacks: requested });
|
|
226
235
|
validateRouteChainProviders(chain);
|
|
227
236
|
const storedChain = routeChain(storedPreset || {});
|
|
@@ -61,8 +61,8 @@ export function createLoginApi({ cfgMod, awaitKeychainPrewarm, reloadFullConfig,
|
|
|
61
61
|
reloadFullConfig();
|
|
62
62
|
return completeOAuthLogin(result);
|
|
63
63
|
},
|
|
64
|
-
async saveProviderApiKey(providerId, secret) {
|
|
65
|
-
const result = await saveProviderApiKey(cfgMod, providerId, secret);
|
|
64
|
+
async saveProviderApiKey(providerId, secret, options) {
|
|
65
|
+
const result = await saveProviderApiKey(cfgMod, providerId, secret, options);
|
|
66
66
|
refresh.afterCredentialChange();
|
|
67
67
|
return result;
|
|
68
68
|
},
|
|
@@ -37,6 +37,19 @@ let sharedPartialEntries = null;
|
|
|
37
37
|
let sharedCatalogPromise = null;
|
|
38
38
|
let sharedCatalogPromiseKey = null;
|
|
39
39
|
let sharedCatalogPromiseForced = false;
|
|
40
|
+
// Every read that publishes to the shared state (a full load or a scoped
|
|
41
|
+
// refresh) runs through this queue, one at a time, so the last write is always
|
|
42
|
+
// the newest successful answer.
|
|
43
|
+
// A catalog state that moved on (new revision or account epoch) starts a fresh
|
|
44
|
+
// queue: reads of the old state never publish, so nothing waits for them.
|
|
45
|
+
let publishing = { key: null, tail: Promise.resolve() };
|
|
46
|
+
function serial(key, run) {
|
|
47
|
+
if (publishing.key !== key) publishing = { key, tail: Promise.resolve() };
|
|
48
|
+
const queue = publishing;
|
|
49
|
+
const result = queue.tail.then(run);
|
|
50
|
+
queue.tail = result.catch(() => {});
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
40
53
|
|
|
41
54
|
export function catalogRevision(registry) {
|
|
42
55
|
const value = Number(registry?.providerCatalogRevision?.());
|
|
@@ -60,6 +73,24 @@ export function invalidateSharedProviderCatalog() {
|
|
|
60
73
|
|
|
61
74
|
const answered = (entry) => !Object.hasOwn(entry, 'error');
|
|
62
75
|
|
|
76
|
+
/** Folds a scoped refresh into the shared state of `key`: only the providers it
|
|
77
|
+
* answered are replaced; a failed entry replaces nothing. */
|
|
78
|
+
function mergeScopedEntries(key, scoped) {
|
|
79
|
+
const fresh = new Map(scoped.filter(answered).map((entry) => [entry.name, entry]));
|
|
80
|
+
const merge = (current) => current.map((entry) => fresh.get(entry.name) ?? entry);
|
|
81
|
+
if (sharedCatalogKey === key) {
|
|
82
|
+
sharedCatalogEntries = merge(sharedCatalogEntries);
|
|
83
|
+
} else if (sharedPartialKey === key) {
|
|
84
|
+
const merged = merge(sharedPartialEntries);
|
|
85
|
+
if (merged.every(answered)) {
|
|
86
|
+
// The refresh answered the last missing provider: the catalog is whole.
|
|
87
|
+
[sharedCatalogKey, sharedCatalogEntries, sharedPartialKey, sharedPartialEntries] = [key, merged, null, null];
|
|
88
|
+
} else {
|
|
89
|
+
sharedPartialEntries = merged;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
63
94
|
async function providerEntry(name, provider, timeoutMs, epoch) {
|
|
64
95
|
if (typeof provider?.listModels !== 'function') return { name, models: [], ms: 0 };
|
|
65
96
|
const startedAt = performance.now();
|
|
@@ -78,6 +109,23 @@ async function providerEntry(name, provider, timeoutMs, epoch) {
|
|
|
78
109
|
return { name, models: Array.isArray(outcome.value) ? outcome.value : [], ms };
|
|
79
110
|
}
|
|
80
111
|
|
|
112
|
+
/** Fresh entries for just the named providers (an account-pool provider is one
|
|
113
|
+
* entry, however many accounts it holds), merged into the shared catalog. */
|
|
114
|
+
export function scopedProviderCatalog(registry, names, { timeoutMs = PROVIDER_CATALOG_TIMEOUT_MS } = {}) {
|
|
115
|
+
const key = catalogKey(registry);
|
|
116
|
+
const wanted = new Set(names);
|
|
117
|
+
return serial(key, async () => {
|
|
118
|
+
const entries = await Promise.all(
|
|
119
|
+
[...registry.getAllProviders()]
|
|
120
|
+
.filter(([name]) => wanted.has(name))
|
|
121
|
+
.map(([name, provider]) => providerEntry(name, provider, timeoutMs, key))
|
|
122
|
+
);
|
|
123
|
+
// A catalog state that moved on while this read ran is not written to.
|
|
124
|
+
if (catalogKey(registry) === key) mergeScopedEntries(key, entries);
|
|
125
|
+
return entries;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
81
129
|
export async function sharedProviderCatalog(registry, { force = false, timeoutMs = PROVIDER_CATALOG_TIMEOUT_MS } = {}) {
|
|
82
130
|
const key = catalogKey(registry);
|
|
83
131
|
if (!force && sharedCatalogKey === key && Array.isArray(sharedCatalogEntries)) {
|
|
@@ -86,45 +134,43 @@ export async function sharedProviderCatalog(registry, { force = false, timeoutMs
|
|
|
86
134
|
if (sharedCatalogPromise && sharedCatalogPromiseKey === key && (sharedCatalogPromiseForced || !force)) {
|
|
87
135
|
return await sharedCatalogPromise;
|
|
88
136
|
}
|
|
89
|
-
const kept = new Map();
|
|
90
|
-
if (!force && sharedPartialKey === key) {
|
|
91
|
-
const now = Date.now();
|
|
92
|
-
for (const entry of sharedPartialEntries) {
|
|
93
|
-
if (answered(entry) || now < entry.retryAt) kept.set(entry.name, entry);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const providers = [...registry.getAllProviders()];
|
|
97
|
-
// Every missing provider is still inside its backoff: the partial answer is
|
|
98
|
-
// the answer, without asking anyone.
|
|
99
|
-
if (providers.length > 0 && providers.every(([name]) => kept.has(name))) {
|
|
100
|
-
return providers.map(([name]) => kept.get(name));
|
|
101
|
-
}
|
|
102
|
-
// A pending list from an older catalog state (revision or account epoch) is
|
|
103
|
-
// not joined: its answer may describe the previous catalog.
|
|
104
|
-
const epoch = key;
|
|
105
137
|
sharedCatalogPromiseKey = key;
|
|
106
138
|
sharedCatalogPromiseForced = force;
|
|
107
|
-
const request =
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const partial = !complete && entries.some(answered);
|
|
114
|
-
sharedCatalogKey = complete ? key : null;
|
|
115
|
-
sharedCatalogEntries = complete ? entries : null;
|
|
116
|
-
sharedPartialKey = partial ? key : null;
|
|
117
|
-
sharedPartialEntries = partial ? entries : null;
|
|
139
|
+
const request = serial(key, async () => {
|
|
140
|
+
const kept = new Map();
|
|
141
|
+
if (!force && sharedPartialKey === key) {
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
for (const entry of sharedPartialEntries) {
|
|
144
|
+
if (answered(entry) || now < entry.retryAt) kept.set(entry.name, entry);
|
|
118
145
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
}
|
|
147
|
+
const providers = [...registry.getAllProviders()];
|
|
148
|
+
// Every missing provider is still inside its backoff: the partial answer is
|
|
149
|
+
// the answer, without asking anyone.
|
|
150
|
+
if (providers.length > 0 && providers.every(([name]) => kept.has(name))) {
|
|
151
|
+
return providers.map(([name]) => kept.get(name));
|
|
152
|
+
}
|
|
153
|
+
// A pending list from an older catalog state (revision or account epoch) is
|
|
154
|
+
// not joined: its answer may describe the previous catalog.
|
|
155
|
+
const entries = await Promise.all(
|
|
156
|
+
providers.map(([name, provider]) => kept.get(name) || providerEntry(name, provider, timeoutMs, key))
|
|
157
|
+
);
|
|
158
|
+
if (sharedCatalogPromise === request && catalogKey(registry) === key) {
|
|
159
|
+
const complete = entries.every(answered);
|
|
160
|
+
const partial = !complete && entries.some(answered);
|
|
161
|
+
sharedCatalogKey = complete ? key : null;
|
|
162
|
+
sharedCatalogEntries = complete ? entries : null;
|
|
163
|
+
sharedPartialKey = partial ? key : null;
|
|
164
|
+
sharedPartialEntries = partial ? entries : null;
|
|
165
|
+
}
|
|
166
|
+
return entries;
|
|
167
|
+
}).finally(() => {
|
|
168
|
+
if (sharedCatalogPromise === request) {
|
|
169
|
+
sharedCatalogPromise = null;
|
|
170
|
+
sharedCatalogPromiseKey = null;
|
|
171
|
+
sharedCatalogPromiseForced = false;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
128
174
|
sharedCatalogPromise = request;
|
|
129
175
|
return await request;
|
|
130
176
|
}
|