mixdog 1.2.5 → 1.3.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/LICENSES/simple-icons-CC0-1.0.txt +30 -0
- package/NOTICE.md +19 -0
- package/package.json +4 -1
- package/scripts/check-model-recommendations.mjs +89 -0
- package/scripts/gate-local.mjs +7 -0
- package/scripts/lib/gate-scheduler.mjs +2 -2
- package/scripts/lib/isolated-test-env.mjs +16 -0
- package/scripts/lib/run-node-tests.mjs +5 -14
- package/scripts/provider-pingpong-live.mjs +9 -9
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +5 -4
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +17 -0
- package/src/defaults/skills/browser-use/SKILL.md +7 -1
- package/src/defaults/skills/computer-use/SKILL.md +3 -1
- package/src/defaults/skills/memory-management/SKILL.md +4 -1
- package/src/defaults/skills/setup/references/actions.md +11 -4
- package/src/defaults/skills/setup-guide/SKILL.md +175 -0
- package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
- package/src/defaults/skills/visualize/SKILL.md +3 -2
- package/src/lib/rules-builder.cjs +56 -7
- package/src/output-styles/common.md +22 -6
- package/src/output-styles/detailed.md +7 -5
- package/src/output-styles/minimal.md +7 -3
- package/src/output-styles/simple.md +2 -3
- package/src/rules/agent/AGENT.md +7 -1
- package/src/rules/agent-mode/AGENT_MODE.md +24 -0
- package/src/rules/agent-mode/MIXY.md +21 -0
- package/src/rules/agent-mode/ROUTINE.md +6 -0
- package/src/rules/lead/LEAD.md +9 -4
- package/src/rules/shared/10-tool-workflow.md +2 -1
- package/src/rules/shared/60-verification.md +4 -5
- package/src/rules/shared/70-delivery.md +3 -0
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
- package/src/runtime/agent/orchestrator/config.mjs +6 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
- package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
- package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
- package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
- package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
- package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
- 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 +4 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
- package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
- package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
- package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
- package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
- package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
- package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
- package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
- package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
- package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
- package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
- package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
- package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
- package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/attachments/office-extract.mjs +11 -9
- package/src/runtime/browser-bridge/client.mjs +24 -0
- package/src/runtime/channels/lib/scheduler.mjs +40 -12
- package/src/runtime/channels/lib/schedules-db.mjs +71 -12
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
- package/src/runtime/channels/lib/webhook.mjs +0 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
- package/src/runtime/channels/lib/worker-main.mjs +17 -20
- package/src/runtime/computer-bridge/client.mjs +28 -1
- package/src/runtime/connectors/gmail-app-password.mjs +690 -0
- package/src/runtime/connectors/google-mcp.mjs +446 -0
- package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
- package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
- package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
- package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
- package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
- package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
- package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
- package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
- package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
- package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
- package/src/runtime/memory/lib/memory.mjs +7 -1
- package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
- package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
- package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
- package/src/runtime/memory/tool-defs.mjs +5 -0
- package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
- package/src/runtime/office/core/tabular.mjs +1 -1
- package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
- package/src/runtime/office/portable/docx-formatting.mjs +1 -1
- package/src/runtime/office/portable/docx-runs.mjs +1 -1
- package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
- package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
- package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
- package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
- package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
- package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
- package/src/runtime/office/portable/portable-opc.mjs +27 -13
- package/src/runtime/office/portable/portable-pivot.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
- package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
- package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
- package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
- package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
- package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
- package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
- package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
- package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
- package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
- package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
- package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
- package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
- package/src/runtime/office/portable/portable-xml.mjs +1 -1
- package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
- package/src/runtime/shared/agent-avatar.d.mts +64 -0
- package/src/runtime/shared/agent-avatar.mjs +320 -0
- package/src/runtime/shared/agent-route-config.d.mts +3 -0
- package/src/runtime/shared/agent-route-config.mjs +16 -0
- package/src/runtime/shared/atomic-file.mjs +36 -14
- package/src/runtime/shared/background-tasks.mjs +60 -20
- package/src/runtime/shared/child-spawn-gate.mjs +26 -16
- package/src/runtime/shared/config.mjs +8 -11
- package/src/runtime/shared/connector-accounts.mjs +15 -0
- package/src/runtime/shared/connector-catalog.d.mts +52 -0
- package/src/runtime/shared/connector-catalog.mjs +230 -0
- package/src/runtime/shared/connector-triggers.d.mts +3 -0
- package/src/runtime/shared/connector-triggers.mjs +43 -0
- package/src/runtime/shared/file-lock.mjs +7 -1
- package/src/runtime/shared/file-permissions-worker.mjs +38 -0
- package/src/runtime/shared/file-permissions.d.mts +19 -4
- package/src/runtime/shared/file-permissions.mjs +310 -4
- package/src/runtime/shared/git-runner-worker.mjs +6 -78
- package/src/runtime/shared/google-oauth-client.mjs +24 -0
- package/src/runtime/shared/held-request-host.d.mts +12 -0
- package/src/runtime/shared/held-request-host.mjs +71 -0
- package/src/runtime/shared/llm/http-agent.mjs +7 -3
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
- package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
- package/src/runtime/shared/memory-snapshot.mjs +5 -1
- package/src/runtime/shared/notify-trace.mjs +8 -1
- package/src/runtime/shared/plain-preview.d.mts +1 -0
- package/src/runtime/shared/plain-preview.mjs +28 -0
- package/src/runtime/shared/pristine-execution-contract.json +5 -1
- package/src/runtime/shared/process-runner-worker.mjs +7 -0
- package/src/runtime/shared/process-runner.mjs +38 -0
- package/src/runtime/shared/provider-accounts.mjs +2 -1
- package/src/runtime/shared/provider-api-key.mjs +0 -1
- package/src/runtime/shared/read-row-numbers.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +60 -18
- package/src/runtime/shared/routine-limits.d.mts +11 -0
- package/src/runtime/shared/routine-limits.mjs +21 -0
- package/src/runtime/shared/routine-trigger.d.mts +10 -0
- package/src/runtime/shared/routine-trigger.mjs +44 -0
- package/src/runtime/shared/run-child.mjs +84 -0
- package/src/runtime/shared/schedule-model-ref.mjs +9 -10
- package/src/runtime/shared/session-activity-signal.mjs +23 -0
- package/src/runtime/shared/shell-output-summary.mjs +23 -0
- package/src/runtime/shared/singleton-owner.mjs +126 -42
- package/src/runtime/shared/slow-span.mjs +4 -12
- package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
- package/src/runtime/shared/tool-output-limit.mjs +4 -2
- package/src/runtime/shared/tool-output-marker.mjs +58 -0
- package/src/runtime/shared/transcript-metadata.mjs +10 -0
- package/src/runtime/shared/turn-changes.mjs +0 -8
- package/src/runtime/shared/usage-readout-totals.mjs +56 -0
- package/src/runtime/shared/user-data-guard.mjs +131 -34
- package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
- package/src/runtime/shared/worktrees/git-head.mjs +20 -2
- package/src/runtime/shared/worktrees/lock.mjs +3 -2
- package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
- package/src/runtime/tidy/runners/biome.mjs +3 -1
- package/src/runtime/tidy/shadow.mjs +2 -1
- package/src/runtime/web-search/index.mjs +5 -7
- package/src/runtime/web-search/lib/formatter.mjs +42 -6
- package/src/runtime/web-search/tool-defs.mjs +6 -1
- package/src/session-runtime/agent-home-delivery.mjs +459 -0
- package/src/session-runtime/agent-profile-changes.mjs +21 -0
- package/src/session-runtime/agent-room-delivery.mjs +92 -0
- package/src/session-runtime/agent-task-sessions.mjs +200 -0
- package/src/session-runtime/boot/apis.mjs +50 -18
- package/src/session-runtime/boot/facade.mjs +5 -8
- package/src/session-runtime/boot/infrastructure.mjs +28 -17
- package/src/session-runtime/boot/tools.mjs +3 -0
- package/src/session-runtime/channel-config-api.mjs +53 -5
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
- package/src/session-runtime/held-requests.mjs +228 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
- package/src/session-runtime/internal-tool-executor.mjs +2 -0
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
- package/src/session-runtime/lifecycle/shared.mjs +25 -2
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +5 -2
- package/src/session-runtime/lifecycle-api.mjs +3 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
- package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +112 -15
- package/src/session-runtime/model-route/set-route.mjs +14 -3
- package/src/session-runtime/owned-automation-run.mjs +229 -0
- package/src/session-runtime/provider-auth/login.mjs +10 -6
- package/src/session-runtime/provider-auth/setup.mjs +19 -2
- package/src/session-runtime/provider-catalog-cache.mjs +101 -25
- package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
- package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
- package/src/session-runtime/provider-models.mjs +76 -10
- package/src/session-runtime/provider-readiness.mjs +4 -0
- package/src/session-runtime/resource-api.mjs +5 -0
- package/src/session-runtime/resource-mcp-api.mjs +107 -13
- package/src/session-runtime/resource-skills-api.mjs +12 -0
- package/src/session-runtime/room-member-gate.mjs +48 -0
- package/src/session-runtime/routine-home-turn.mjs +156 -0
- package/src/session-runtime/routine-owner.mjs +48 -0
- package/src/session-runtime/schedule-session-run.mjs +30 -64
- package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
- package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
- package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
- package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
- package/src/session-runtime/services/agent-tool.mjs +20 -0
- package/src/session-runtime/services/channel-admin.mjs +93 -24
- package/src/session-runtime/services/memory-access.mjs +37 -0
- package/src/session-runtime/services/provider-admin.mjs +166 -59
- package/src/session-runtime/services/schedule-access.mjs +91 -0
- package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
- package/src/session-runtime/services/usage-dashboard.mjs +27 -69
- package/src/session-runtime/session-create/session-options.mjs +34 -7
- package/src/session-runtime/session-hooks.mjs +16 -8
- package/src/session-runtime/setup-tool/executor.mjs +68 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
- package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
- package/src/session-runtime/skills-api.mjs +16 -1
- package/src/session-runtime/tool-policy-refresh.mjs +238 -29
- package/src/session-runtime/turn/session-ops.mjs +10 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
- package/src/session-runtime/usage-stats-api.mjs +6 -1
- package/src/session-runtime/webhook-session-run.mjs +49 -67
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
- package/src/session-runtime/workflow-agents-api.mjs +4 -1
- package/src/standalone/channel-transport/http-routes.mjs +10 -9
- package/src/standalone/daemon-agent-control.mjs +1 -8
- package/src/standalone/daemon-desktop-runtime.mjs +20 -7
- package/src/standalone/daemon-owner.mjs +117 -25
- package/src/standalone/daemon-session-control.mjs +11 -2
- package/src/standalone/daemon.mjs +61 -17
- package/src/standalone/session-call-cache.mjs +6 -0
- package/src/standalone/session-protocol.mjs +28 -1
- package/src/standalone/session-service/retention/busy.mjs +7 -2
- package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
- package/src/standalone/session-service.mjs +19 -0
- package/src/standalone/session-transport/routes.mjs +7 -6
- package/src/tui/app/model-options.mjs +39 -2
- package/src/tui/app/model-picker.mjs +16 -2
- package/src/tui/app/provider-setup-picker.mjs +1 -2
- package/src/tui/app/slash-commands.mjs +20 -0
- package/src/tui/dist/index.mjs +487 -128
- package/src/tui/session/context-state.mjs +6 -1
- package/src/tui/session/notice-surface.mjs +35 -4
- package/src/tui/session/notice-text.mjs +0 -1
- package/src/tui/session/queue-helpers.mjs +2 -1
- package/src/tui/session/session-api/extensions.mjs +4 -0
- package/src/tui/session/session-api/intake/submission.mjs +12 -13
- package/src/tui/session/session-api/integrations.mjs +9 -5
- package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
- package/src/tui/session/session-api/lifecycle.mjs +17 -1
- package/src/tui/session/session-api/routes.mjs +48 -3
- package/src/tui/session/session-flow/drain.mjs +20 -3
- package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
- package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
- package/src/tui/session/session-flow/steering.mjs +104 -24
- package/src/tui/session/session-flow.mjs +2 -0
- package/src/tui/session/tool-approval.mjs +26 -5
- package/src/tui/session/transcript-intake.mjs +6 -2
- package/src/tui/session/transcript-spill.mjs +5 -1
- package/src/tui/session/tui-steering-persist.mjs +65 -42
- package/src/tui/session/turn-live-call.mjs +56 -0
- package/src/tui/session/turn-stream.mjs +33 -0
- package/src/tui/session/turn.mjs +50 -7
- package/src/ui/statusline.mjs +1 -6
- package/src/ui/streaming-markdown-heal.mjs +24 -7
- package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
- package/src/workflows/default/WORKFLOW.md +9 -13
- package/src/session-runtime/automation-agents.mjs +0 -94
- package/src/session-runtime/automation-workflow.mjs +0 -59
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* lifecycle groups (teardown, session switching, inheritance).
|
|
4
4
|
*/
|
|
5
5
|
import { hasUserConversationMessage } from '../../runtime/agent/orchestrator/session/manager/prompt-utils.mjs';
|
|
6
|
+
import { isAgentHomeSessionId } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
7
|
+
import { isRoomThreadSessionId } from '../../runtime/agent/orchestrator/session/agent-room.mjs';
|
|
6
8
|
|
|
7
9
|
export { SESSION_ID_PATTERN } from '../../runtime/agent/orchestrator/runtime-core/session-id.mjs';
|
|
8
10
|
|
|
@@ -19,13 +21,34 @@ export function isScratchConversation(messages, liveTurnMessages) {
|
|
|
19
21
|
);
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
/** An agent's home thread is never scratch: a blank one is tombstoned on no
|
|
25
|
+
* close, so its fixed id stays open for the next visit. Neither is a group
|
|
26
|
+
* room's log or member session (agent-room.mjs), whose ids are fixed too. */
|
|
22
27
|
export function isScratchSession(session) {
|
|
28
|
+
if (isAgentHomeSessionId(session?.id) || isRoomThreadSessionId(session?.id)) return false;
|
|
23
29
|
return isScratchConversation(session?.messages, session?.liveTurnMessages);
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
|
|
32
|
+
/** `nonBlocking`: the closer returns the manager's closeSessionAsync promise
|
|
33
|
+
* (when it has one), whose barrier never sleeps the event loop. */
|
|
34
|
+
export function createSurfaceSessionCloser(mgr, nonBlocking = false) {
|
|
27
35
|
return function closeSurfaceSession(session, reason, options) {
|
|
28
36
|
if (!session?.id) return false;
|
|
29
|
-
return mgr
|
|
37
|
+
return closeManagedSession(mgr, session.id, reason, options, nonBlocking);
|
|
30
38
|
};
|
|
31
39
|
}
|
|
40
|
+
|
|
41
|
+
/** Await a switch path's close of the outgoing session. A close whose durable
|
|
42
|
+
* barrier failed leaves the session open, so the switch must not proceed. */
|
|
43
|
+
export async function closeOutgoingSession(closeSurfaceSession, session, reason, options) {
|
|
44
|
+
if ((await closeSurfaceSession(session, reason, options)) === false) {
|
|
45
|
+
throw new Error(`session close failed (reason=${reason}); the current session is kept`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The manager's close: closeSessionAsync when asked for and available,
|
|
50
|
+
* else its closeSession, unchanged. */
|
|
51
|
+
export function closeManagedSession(mgr, id, reason, options, nonBlocking = true) {
|
|
52
|
+
if (nonBlocking && typeof mgr.closeSessionAsync === 'function') return mgr.closeSessionAsync(id, reason, options);
|
|
53
|
+
return mgr.closeSession(id, reason, options);
|
|
54
|
+
}
|
|
@@ -47,6 +47,8 @@ export function closeOwnSession(deps, closeSurfaceSession, reason) {
|
|
|
47
47
|
clearRuntimeNotifications,
|
|
48
48
|
notificationListeners,
|
|
49
49
|
} = deps;
|
|
50
|
+
// The close's answer: a boolean, or the promise of one when the closer
|
|
51
|
+
// retries a refused barrier rename on timers (callers await it).
|
|
50
52
|
let ok = false;
|
|
51
53
|
const session = getSession();
|
|
52
54
|
if (session?.id) {
|
|
@@ -226,13 +226,16 @@ export function createTeardown(deps, { ingestSessionIntoMemory, closeSurfaceSess
|
|
|
226
226
|
};
|
|
227
227
|
if (outstandingCloses.size > 0) void finish();
|
|
228
228
|
else await finish();
|
|
229
|
-
const {
|
|
229
|
+
const { ownClose, stops } = await inOwnLoopTurn(() => {
|
|
230
230
|
const runtimeStops = startRuntimeStops(deps, reason, scope);
|
|
231
231
|
const closed = closeOwnSession(deps, closeSurfaceSession, reason);
|
|
232
|
-
return {
|
|
232
|
+
return { ownClose: closed, stops: { channelStop, ...runtimeStops, ...startWorkStops(deps, reason, scope) } };
|
|
233
233
|
});
|
|
234
234
|
if (scope.detach) await settleDetached(withTeardownDeadline, stops);
|
|
235
235
|
else await settleAll(withTeardownDeadline, stops);
|
|
236
|
+
// Reported closed only once the barrier is on disk (closeSessionAsync),
|
|
237
|
+
// and its write control is released only after that.
|
|
238
|
+
const ok = await ownClose;
|
|
236
239
|
// The session went away (idle eviction included): free its save baselines.
|
|
237
240
|
if (scope.closingSessionId) forgetSessionSaveBaseline(scope.closingSessionId, { releaseWriteControl: true });
|
|
238
241
|
// Self-update stages in the background and swaps on the next clean launch
|
|
@@ -20,7 +20,9 @@ export { resolveResumeCwd } from './lifecycle/session-switch.mjs';
|
|
|
20
20
|
export function createLifecycleApi(deps) {
|
|
21
21
|
const shared = {
|
|
22
22
|
cancelBackgroundTasks: deps.cancelBackgroundTasks || cancelBackgroundTasks,
|
|
23
|
-
|
|
23
|
+
// Teardown and the switch paths await their close: a barrier rename the OS
|
|
24
|
+
// refuses is retried on timers instead of sleeping the daemon loop.
|
|
25
|
+
closeSurfaceSession: createSurfaceSessionCloser(deps.mgr, true),
|
|
24
26
|
ingestSessionIntoMemory: createMemoryIngest(deps),
|
|
25
27
|
};
|
|
26
28
|
const teardown = createTeardown(deps, shared);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// servers plus the servers registered plugins declare (resolved live, with
|
|
3
3
|
// explicit owner metadata), per-server config reads, and the live/failed rollup.
|
|
4
4
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
5
|
+
import { connectorOfServer, gmailAppPasswordAccount } from '../../runtime/shared/connector-catalog.mjs';
|
|
5
6
|
import { envFlag } from '../../runtime/shared/env.mjs';
|
|
6
7
|
import { resolveMcpServerCatalog } from './plugin-servers.mjs';
|
|
7
8
|
|
|
@@ -142,9 +143,16 @@ export function createMcpServerCatalog({
|
|
|
142
143
|
source: sources[name] || 'config',
|
|
143
144
|
};
|
|
144
145
|
if (authRequired) row.authRequired = true;
|
|
146
|
+
// The catalog service this server connects (connector-catalog.mjs):
|
|
147
|
+
// its marker.
|
|
148
|
+
const connector = entry.owner ? '' : connectorOfServer(cfg);
|
|
149
|
+
if (connector) row.connector = connector;
|
|
145
150
|
const oauth = mcpClient.getMcpServerOAuthState?.(cfg);
|
|
146
151
|
// Why the last sign-in did not complete (already credential-scrubbed).
|
|
147
152
|
if (oauth) row.oauth = authRequired && fail?.msg ? { ...oauth, lastError: fail.msg } : oauth;
|
|
153
|
+
// Gmail connected with an app password: the account it runs as.
|
|
154
|
+
const appPasswordAccount = gmailAppPasswordAccount(cfg);
|
|
155
|
+
if (appPasswordAccount) row.appPassword = { account: appPasswordAccount };
|
|
148
156
|
if (entry.owner) {
|
|
149
157
|
row.owner = entry.owner;
|
|
150
158
|
row.pluginEnabled = entry.pluginEnabled;
|
|
@@ -70,6 +70,9 @@ export function createMcpServerInput({ mcpClient, getCurrentCwd }) {
|
|
|
70
70
|
if (bearerTokenEnvVar) config.bearer_token_env_var = bearerTokenEnvVar;
|
|
71
71
|
const envHeaders = coerceStringRecord(input.env_http_headers || input.envHttpHeaders);
|
|
72
72
|
if (envHeaders) config.env_http_headers = envHeaders;
|
|
73
|
+
// The user's own OAuth client (앱 번호); its secret never lands here.
|
|
74
|
+
const oauthClientId = clean(input.oauthClientId);
|
|
75
|
+
if (oauthClientId) config.oauthClientId = oauthClientId;
|
|
73
76
|
return config;
|
|
74
77
|
};
|
|
75
78
|
const url = clean(input.url);
|
|
@@ -8,6 +8,15 @@ import { openInBrowser } from '../runtime/shared/open-url.mjs';
|
|
|
8
8
|
// Settled flows stay readable long enough for a poller to observe the result.
|
|
9
9
|
const SETTLED_FLOW_TTL_MS = 10 * 60_000;
|
|
10
10
|
const NOT_COMPLETED = 'MCP OAuth sign-in was not completed';
|
|
11
|
+
export const MCP_OAUTH_LOGIN_TIMED_OUT = 'MCP OAuth sign-in timed out';
|
|
12
|
+
// A sign-in nobody finishes ends here, ahead of the OAuth layer's own 5-minute
|
|
13
|
+
// abort, so its failure is reported as the timeout it is.
|
|
14
|
+
const LOGIN_DEADLINE_MS = 5 * 60_000 - 10_000;
|
|
15
|
+
// The longest a status read waits for a change (local callers only).
|
|
16
|
+
const MAX_STATUS_WAIT_MS = 15_000;
|
|
17
|
+
// How a sign-in treats the account (mcp/oauth-account.mjs): a normal
|
|
18
|
+
// authorization, a repair of the same connection, or a transactional switch.
|
|
19
|
+
const MODES = new Set(['connect', 'reauth', 'switch']);
|
|
11
20
|
|
|
12
21
|
const NOT_PENDING = 'MCP OAuth sign-in is no longer pending';
|
|
13
22
|
|
|
@@ -19,17 +28,36 @@ const NOT_PENDING = 'MCP OAuth sign-in is no longer pending';
|
|
|
19
28
|
const flows = new Map();
|
|
20
29
|
|
|
21
30
|
// A pending flow keeps its authorization URL readable: a client polling the
|
|
22
|
-
// status (remote sign-in) still shows the page to open.
|
|
31
|
+
// status (remote sign-in) still shows the page to open. `step` names what a
|
|
32
|
+
// pending flow waits for: `browser` (the sign-in page), `connecting` (the
|
|
33
|
+
// callback arrived; tokens are exchanged), `tools` (signed in; the server
|
|
34
|
+
// connects and lists its tools).
|
|
23
35
|
const view = (flow) => ({
|
|
24
36
|
flowId: flow.flowId,
|
|
25
37
|
state: flow.state,
|
|
38
|
+
...(flow.state === 'pending' ? { step: flow.step } : {}),
|
|
26
39
|
...(flow.state === 'pending' && flow.url ? { url: flow.url } : {}),
|
|
27
40
|
...(flow.error ? { error: flow.error } : {}),
|
|
41
|
+
...(flow.reason ? { reason: flow.reason } : {}),
|
|
28
42
|
});
|
|
43
|
+
const versionOf = (flow) => `${flow.state}:${flow.step}`;
|
|
44
|
+
// Wake every status read waiting on this flow.
|
|
45
|
+
function changed(flow) {
|
|
46
|
+
const waiters = flow.waiters;
|
|
47
|
+
flow.waiters = [];
|
|
48
|
+
for (const wake of waiters) wake();
|
|
49
|
+
}
|
|
50
|
+
function setStep(flow, step) {
|
|
51
|
+
if (flow.state !== 'pending' || flow.step === step) return;
|
|
52
|
+
flow.step = step;
|
|
53
|
+
changed(flow);
|
|
54
|
+
}
|
|
29
55
|
function settle(flow, state, error = null) {
|
|
30
56
|
if (flow.state !== 'pending') return;
|
|
31
57
|
flow.state = state;
|
|
32
58
|
if (state === 'failed') flow.error = error || NOT_COMPLETED;
|
|
59
|
+
clearTimeout(flow.deadline);
|
|
60
|
+
changed(flow);
|
|
33
61
|
setTimeout(() => flows.delete(flow.flowId), SETTLED_FLOW_TTL_MS).unref?.();
|
|
34
62
|
}
|
|
35
63
|
function flowOf(flowId) {
|
|
@@ -40,19 +68,23 @@ function flowOf(flowId) {
|
|
|
40
68
|
async function cancelFlow(flow) {
|
|
41
69
|
if (flow.state === 'pending') {
|
|
42
70
|
flow.cancelled = true;
|
|
43
|
-
flow.
|
|
71
|
+
flow.abort();
|
|
44
72
|
await flow.done;
|
|
45
73
|
}
|
|
46
74
|
return view(flow);
|
|
47
75
|
}
|
|
48
76
|
|
|
49
77
|
/**
|
|
50
|
-
* `connect(name,
|
|
51
|
-
* `
|
|
78
|
+
* `connect(name, launch)` reconnects the server interactively, calling
|
|
79
|
+
* `launch(url)` when a login starts, and resolves `{ connected, error }`.
|
|
52
80
|
* `cancel(name)` aborts that server's pending login. `completeCallback(name,
|
|
53
81
|
* callbackUrl)` answers it with a pasted redirect URL (throws a fixed message
|
|
54
|
-
* for an invalid one). `
|
|
55
|
-
*
|
|
82
|
+
* for an invalid one). `switchAccount(name, launch, attempt)` runs an account
|
|
83
|
+
* switch instead (mode `switch`): it registers `attempt.abort` / `attempt.answer`
|
|
84
|
+
* and resolves `{ connected, error }` only after committing (or rolling back)
|
|
85
|
+
* the new sign-in. `launch` carries `accountMode` and the progress hooks
|
|
86
|
+
* `onCallback` / `onAuthorized` the OAuth layer calls. `onComplete(name)` runs
|
|
87
|
+
* after a successful sign-in, once the flow already reports complete.
|
|
56
88
|
*/
|
|
57
89
|
export function createMcpOAuthLogins({
|
|
58
90
|
connect,
|
|
@@ -60,8 +92,12 @@ export function createMcpOAuthLogins({
|
|
|
60
92
|
completeCallback = () => {
|
|
61
93
|
throw new Error(NOT_PENDING);
|
|
62
94
|
},
|
|
95
|
+
switchAccount = async () => {
|
|
96
|
+
throw new Error('Switching the account is not supported here');
|
|
97
|
+
},
|
|
63
98
|
onComplete = async () => {},
|
|
64
99
|
openBrowser = openInBrowser,
|
|
100
|
+
loginTimeoutMs = LOGIN_DEADLINE_MS,
|
|
65
101
|
}) {
|
|
66
102
|
// name -> tail of that server's serialized begin/cancel/sign-out steps, so
|
|
67
103
|
// replacing a pending flow is atomic and exactly one can be pending.
|
|
@@ -89,10 +125,11 @@ export function createMcpOAuthLogins({
|
|
|
89
125
|
Promise.all([...flows.values()].filter((flow) => flow.owner === owner && flow.name === name).map(cancelFlow));
|
|
90
126
|
|
|
91
127
|
async function begin(name, options = {}) {
|
|
92
|
-
const { openBrowser: hostBrowser } = options || {};
|
|
128
|
+
const { openBrowser: hostBrowser, mode = 'connect' } = options || {};
|
|
93
129
|
if (hostBrowser !== undefined && typeof hostBrowser !== 'boolean') {
|
|
94
130
|
throw new TypeError('openBrowser must be a boolean');
|
|
95
131
|
}
|
|
132
|
+
if (!MODES.has(mode)) throw new TypeError('mode must be connect, reauth or switch');
|
|
96
133
|
let announceUrl;
|
|
97
134
|
const urlReady = new Promise((resolve) => {
|
|
98
135
|
announceUrl = resolve;
|
|
@@ -105,10 +142,17 @@ export function createMcpOAuthLogins({
|
|
|
105
142
|
flowId: `mcp_oauth_${randomUUID()}`,
|
|
106
143
|
name,
|
|
107
144
|
owner,
|
|
145
|
+
mode,
|
|
108
146
|
state: 'pending',
|
|
147
|
+
step: 'starting',
|
|
109
148
|
error: null,
|
|
149
|
+
reason: null,
|
|
110
150
|
cancelled: false,
|
|
151
|
+
timedOut: false,
|
|
111
152
|
url: null,
|
|
153
|
+
waiters: [],
|
|
154
|
+
abort: () => owner.cancel(name),
|
|
155
|
+
answer: (callbackUrl) => owner.completeCallback(name, callbackUrl),
|
|
112
156
|
};
|
|
113
157
|
flows.set(flow.flowId, flow);
|
|
114
158
|
const launch = async (url) => {
|
|
@@ -117,22 +161,51 @@ export function createMcpOAuthLogins({
|
|
|
117
161
|
if (flow.cancelled) throw new Error('MCP OAuth login cancelled');
|
|
118
162
|
flow.awaitingCallback = true;
|
|
119
163
|
flow.url = url;
|
|
164
|
+
setStep(flow, 'browser');
|
|
120
165
|
announceUrl(url);
|
|
121
166
|
if (hostBrowser !== false) openBrowser(url);
|
|
167
|
+
// Nobody finished the sign-in page in time.
|
|
168
|
+
flow.deadline = setTimeout(() => {
|
|
169
|
+
if (flow.state !== 'pending' || flow.step !== 'browser') return;
|
|
170
|
+
flow.timedOut = flow.cancelled = true;
|
|
171
|
+
flow.abort();
|
|
172
|
+
}, loginTimeoutMs);
|
|
173
|
+
flow.deadline.unref?.();
|
|
122
174
|
};
|
|
175
|
+
launch.accountMode = mode;
|
|
176
|
+
launch.onCallback = () => setStep(flow, 'connecting');
|
|
177
|
+
launch.onAuthorized = () => setStep(flow, 'tools');
|
|
123
178
|
flow.done = (async () => {
|
|
124
179
|
try {
|
|
125
|
-
const outcome =
|
|
126
|
-
|
|
180
|
+
const outcome =
|
|
181
|
+
mode === 'switch'
|
|
182
|
+
? await switchAccount(name, launch, {
|
|
183
|
+
set abort(fn) {
|
|
184
|
+
flow.abort = fn;
|
|
185
|
+
},
|
|
186
|
+
set answer(fn) {
|
|
187
|
+
flow.answer = fn;
|
|
188
|
+
},
|
|
189
|
+
})
|
|
190
|
+
: await connect(name, launch);
|
|
191
|
+
if (flow.timedOut) {
|
|
192
|
+
flow.reason = 'timeout';
|
|
193
|
+
settle(flow, 'failed', MCP_OAUTH_LOGIN_TIMED_OUT);
|
|
194
|
+
} else if (flow.cancelled) settle(flow, 'cancelled');
|
|
127
195
|
else if (outcome?.connected) {
|
|
128
|
-
|
|
129
|
-
|
|
196
|
+
settle(flow, 'complete');
|
|
197
|
+
// The other runtimes reconnect after the flow already reports
|
|
198
|
+
// complete: the caller never waits for every peer's reconnect, and
|
|
199
|
+
// a failed follow-up never undoes the sign-in.
|
|
200
|
+
void Promise.resolve()
|
|
130
201
|
.then(() => onComplete(name))
|
|
131
202
|
.catch(() => {});
|
|
132
|
-
settle(flow, 'complete');
|
|
133
203
|
} else settle(flow, 'failed', outcome?.error);
|
|
134
204
|
} catch (error) {
|
|
135
|
-
|
|
205
|
+
if (flow.timedOut) {
|
|
206
|
+
flow.reason = 'timeout';
|
|
207
|
+
settle(flow, 'failed', MCP_OAUTH_LOGIN_TIMED_OUT);
|
|
208
|
+
} else settle(flow, flow.cancelled ? 'cancelled' : 'failed', error?.message || String(error));
|
|
136
209
|
}
|
|
137
210
|
})();
|
|
138
211
|
return flow;
|
|
@@ -147,7 +220,31 @@ export function createMcpOAuthLogins({
|
|
|
147
220
|
|
|
148
221
|
return {
|
|
149
222
|
begin,
|
|
150
|
-
|
|
223
|
+
/** The flow's view. With `{ since, waitMs }` (the `state:step` a caller
|
|
224
|
+
* last saw) the read resolves on the flow's next change, or after at most
|
|
225
|
+
* `waitMs` unchanged: the caller follows each step as it happens. */
|
|
226
|
+
status(flowId, options = {}) {
|
|
227
|
+
const flow = flowOf(flowId);
|
|
228
|
+
const { since, waitMs } = options || {};
|
|
229
|
+
if (since === undefined) return view(flow);
|
|
230
|
+
if (typeof since !== 'string') throw new TypeError('since must be a string');
|
|
231
|
+
if (!Number.isFinite(waitMs) || waitMs < 0) throw new TypeError('waitMs must be a non-negative number');
|
|
232
|
+
if (since !== versionOf(flow) || flow.state !== 'pending' || waitMs === 0) return view(flow);
|
|
233
|
+
return new Promise((resolve) => {
|
|
234
|
+
const wake = () => {
|
|
235
|
+
clearTimeout(timer);
|
|
236
|
+
resolve(view(flow));
|
|
237
|
+
};
|
|
238
|
+
const timer = setTimeout(
|
|
239
|
+
() => {
|
|
240
|
+
flow.waiters = flow.waiters.filter((waiter) => waiter !== wake);
|
|
241
|
+
resolve(view(flow));
|
|
242
|
+
},
|
|
243
|
+
Math.min(waitMs, MAX_STATUS_WAIT_MS)
|
|
244
|
+
);
|
|
245
|
+
flow.waiters.push(wake);
|
|
246
|
+
});
|
|
247
|
+
},
|
|
151
248
|
cancel(flowId) {
|
|
152
249
|
const flow = flowOf(flowId);
|
|
153
250
|
return flow.owner.exclusive(flow.name, () => cancelFlow(flow));
|
|
@@ -158,7 +255,7 @@ export function createMcpOAuthLogins({
|
|
|
158
255
|
async complete(flowId, callbackUrl) {
|
|
159
256
|
const flow = flowOf(flowId);
|
|
160
257
|
if (flow.state !== 'pending' || flow.cancelled || !flow.awaitingCallback) throw new Error(NOT_PENDING);
|
|
161
|
-
flow.
|
|
258
|
+
flow.answer(callbackUrl);
|
|
162
259
|
await flow.done;
|
|
163
260
|
return view(flow);
|
|
164
261
|
},
|
|
@@ -140,15 +140,26 @@ function modelSwitchAnchorIndex(messages) {
|
|
|
140
140
|
* (like an inheritance boundary): the transcript shows it live and after a
|
|
141
141
|
* restore, and the model conversation gains no synthetic message. */
|
|
142
142
|
export function recordModelSwitchBoundary(session, boundary) {
|
|
143
|
+
return recordTranscriptBoundary(
|
|
144
|
+
session,
|
|
145
|
+
'modelSwitches',
|
|
146
|
+
boundary,
|
|
147
|
+
(entry) => entry?.at === boundary.at && entry?.modelId === boundary.modelId
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** A display-only boundary appended to `meta[field]` of the switch anchor
|
|
152
|
+
* message (model and workflow switches); `same` finds an already recorded one. */
|
|
153
|
+
export function recordTranscriptBoundary(session, field, boundary, same) {
|
|
143
154
|
const messages = Array.isArray(session?.messages) ? session.messages : [];
|
|
144
155
|
const index = modelSwitchAnchorIndex(messages);
|
|
145
156
|
if (index < 0) return false;
|
|
146
157
|
const anchor = messages[index];
|
|
147
|
-
const switches = Array.isArray(anchor.meta?.
|
|
148
|
-
if (switches.some(
|
|
158
|
+
const switches = Array.isArray(anchor.meta?.[field]) ? anchor.meta[field] : [];
|
|
159
|
+
if (switches.some(same)) return true;
|
|
149
160
|
// Replace the message object: the session save worker detects changed
|
|
150
161
|
// messages by reference identity, so an in-place meta edit is never saved.
|
|
151
|
-
messages[index] = { ...anchor, meta: { ...anchor.meta,
|
|
162
|
+
messages[index] = { ...anchor, meta: { ...anchor.meta, [field]: [...switches, boundary] } };
|
|
152
163
|
return true;
|
|
153
164
|
}
|
|
154
165
|
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One run of an owned automation — a schedule or a webhook endpoint. The run
|
|
3
|
+
* itself is a turn in the owner bot's home thread (routine-home-turn.mjs);
|
|
4
|
+
* the bot's reply there is its result, so nothing is posted besides it. A run
|
|
5
|
+
* whose owner bot does not exist (routine-owner.mjs) never fires: it is
|
|
6
|
+
* skipped as paused, never run elsewhere. A second run of the same automation
|
|
7
|
+
* while one is in flight is skipped (and recorded).
|
|
8
|
+
*
|
|
9
|
+
* Unattended runs (timed fires, received webhooks; not the app's or a chat's
|
|
10
|
+
* "Run now") also back off after consecutive failures (ROUTINE_LIMITS).
|
|
11
|
+
* Runs have no concurrency cap or deadline (user decision).
|
|
12
|
+
*
|
|
13
|
+
* Routine results from before routines ran in the bot's thread may still sit
|
|
14
|
+
* on a routine's record (`result_delivery`): redeliverRoutine and the daemon's
|
|
15
|
+
* recovery queue them into the owner's thread (agent-home-delivery.mjs),
|
|
16
|
+
* never running the routine again.
|
|
17
|
+
*/
|
|
18
|
+
import { announceRoutineRun, deliverScheduleResult } from './agent-home-delivery.mjs';
|
|
19
|
+
import { ROUTINE_LIMITS, routineBackoffRemaining } from '../runtime/shared/routine-limits.mjs';
|
|
20
|
+
import { ROUTINE_OWNER_PROBLEMS, routineOwnerProblem } from './routine-owner.mjs';
|
|
21
|
+
|
|
22
|
+
const DELIVERY_RETRY_MS = 60_000;
|
|
23
|
+
const errorText = (error) => error?.message || String(error);
|
|
24
|
+
const defaultLog = (line) => process.stderr.write(`mixdog routines: ${line}\n`);
|
|
25
|
+
|
|
26
|
+
// `${kind}:${name}` of every run in flight in this process: timed fires,
|
|
27
|
+
// received webhooks and the app's "Run now" all come through here.
|
|
28
|
+
const activeRuns = new Set();
|
|
29
|
+
|
|
30
|
+
// The PG record of each kind, imported on first use.
|
|
31
|
+
const RECORDS = {
|
|
32
|
+
schedule: () =>
|
|
33
|
+
import('../runtime/channels/lib/schedules-db.mjs').then((db) => ({
|
|
34
|
+
state: (name) => db.getSchedule(name),
|
|
35
|
+
list: () => db.listSchedules(),
|
|
36
|
+
recordDelivery: db.recordScheduleDelivery,
|
|
37
|
+
})),
|
|
38
|
+
webhook: () =>
|
|
39
|
+
import('../runtime/channels/lib/webhooks-db.mjs').then((db) => ({
|
|
40
|
+
state: (name) => db.loadEndpointConfig(name),
|
|
41
|
+
list: () => db.listEndpoints(),
|
|
42
|
+
recordDelivery: db.recordEndpointDelivery,
|
|
43
|
+
})),
|
|
44
|
+
};
|
|
45
|
+
/** `deps` over the kind's PG record for whatever `deps` leaves out. */
|
|
46
|
+
async function withRecord(kind, deps) {
|
|
47
|
+
if (deps.state && deps.list && deps.recordDelivery) return deps;
|
|
48
|
+
const record = await RECORDS[kind]();
|
|
49
|
+
return {
|
|
50
|
+
...deps,
|
|
51
|
+
state: deps.state || record.state,
|
|
52
|
+
list: deps.list || record.list,
|
|
53
|
+
recordDelivery: deps.recordDelivery || record.recordDelivery,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let retryArmed = false;
|
|
58
|
+
/** One timer for the whole host: re-queue every record's undelivered result. */
|
|
59
|
+
function armDeliveryRetry() {
|
|
60
|
+
if (retryArmed) return;
|
|
61
|
+
retryArmed = true;
|
|
62
|
+
setTimeout(() => {
|
|
63
|
+
retryArmed = false;
|
|
64
|
+
recoverRoutineDeliveries().catch((error) => defaultLog(`delivery retry failed: ${errorText(error)}`));
|
|
65
|
+
}, DELIVERY_RETRY_MS).unref?.();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Show `run`'s live-only row in the owner's home; a failure only logs. */
|
|
69
|
+
async function announceRun(announce, row, run, log) {
|
|
70
|
+
try {
|
|
71
|
+
await announce(row, run);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
log(`${run.kind} "${row.name}": run row not shown: ${errorText(error)}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Queue `item` for `row`'s owner; clear the record on success, mark it
|
|
78
|
+
* 'failed' (and arm the retry) when the queue refuses it. */
|
|
79
|
+
async function queueResult(row, item, entry, { deliver, recordDelivery, onDeliveryFailed, announce, log }) {
|
|
80
|
+
try {
|
|
81
|
+
await deliver(row, item);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
const message = errorText(error);
|
|
84
|
+
log(`${item.kind} "${row.name}": result could not be queued (${message}); retrying later`);
|
|
85
|
+
await recordDelivery(row.name, item.runId, { ...entry, state: 'failed', error: message }).catch((recordError) =>
|
|
86
|
+
log(`${item.kind} "${row.name}": delivery failure not recorded: ${errorText(recordError)}`)
|
|
87
|
+
);
|
|
88
|
+
// The home's run row turns into "result not delivered" (retry: retryRoutineDelivery).
|
|
89
|
+
await announceRun(announce, row, { ...item, state: 'undelivered' }, log);
|
|
90
|
+
onDeliveryFailed();
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
// A clear that fails leaves the record 'pending': the next recovery re-queues
|
|
94
|
+
// it, which the queue's run-id key turns into a no-op.
|
|
95
|
+
await recordDelivery(row.name, item.runId, null).catch((error) =>
|
|
96
|
+
log(`${item.kind} "${row.name}": delivered result not cleared: ${errorText(error)}`)
|
|
97
|
+
);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* `row` is `{ name, ownerAgentId }`; `run({ signal })` resolves `{ sessionId,
|
|
103
|
+
* result }` (`signal` is the caller's cancellation, if any). Resolves the
|
|
104
|
+
* outcome, or `{ skipped: true, reason: 'owner' | 'overlap' | 'backoff' }`
|
|
105
|
+
* (an owner skip also names `ownerProblem` and its `message`); a failed run
|
|
106
|
+
* rejects.
|
|
107
|
+
*/
|
|
108
|
+
export async function runOwnedAutomation(kind, row, run, deps = {}) {
|
|
109
|
+
if (!row?.name) throw new Error(`${kind} run: a ${kind} row is required`);
|
|
110
|
+
const {
|
|
111
|
+
recordSkip = async () => {},
|
|
112
|
+
active = activeRuns,
|
|
113
|
+
limits = ROUTINE_LIMITS,
|
|
114
|
+
attended = false,
|
|
115
|
+
signal = null,
|
|
116
|
+
now = Date.now,
|
|
117
|
+
ownerProblem = routineOwnerProblem,
|
|
118
|
+
log = defaultLog,
|
|
119
|
+
} = deps;
|
|
120
|
+
const name = row.name;
|
|
121
|
+
const key = `${kind}:${name}`;
|
|
122
|
+
const skip = async (reason, extra = {}) => {
|
|
123
|
+
await Promise.resolve()
|
|
124
|
+
.then(() => recordSkip(name, new Date(now())))
|
|
125
|
+
.catch((error) => log(`${kind} "${name}": skip record failed: ${errorText(error)}`));
|
|
126
|
+
return { name, skipped: true, reason, sessionId: null, result: '', ...extra };
|
|
127
|
+
};
|
|
128
|
+
// A routine runs only in its own bot's thread: without that bot it waits.
|
|
129
|
+
const problem = await Promise.resolve()
|
|
130
|
+
.then(() => ownerProblem(row.ownerAgentId))
|
|
131
|
+
.catch(() => '');
|
|
132
|
+
if (problem) {
|
|
133
|
+
log(`${kind} "${name}": paused, ${ROUTINE_OWNER_PROBLEMS[problem]}`);
|
|
134
|
+
return skip('owner', { ownerProblem: problem, message: ROUTINE_OWNER_PROBLEMS[problem] });
|
|
135
|
+
}
|
|
136
|
+
if (active.has(key)) return skip('overlap');
|
|
137
|
+
active.add(key);
|
|
138
|
+
try {
|
|
139
|
+
if (!attended) {
|
|
140
|
+
const record = await withRecord(kind, deps);
|
|
141
|
+
const state = await Promise.resolve()
|
|
142
|
+
.then(() => record.state(name))
|
|
143
|
+
.catch(() => null);
|
|
144
|
+
const wait = routineBackoffRemaining(state, now(), limits);
|
|
145
|
+
if (wait > 0) {
|
|
146
|
+
log(`${kind} "${name}": skipped, backing off ${Math.ceil(wait / 1000)}s after failures in a row`);
|
|
147
|
+
return await skip('backoff');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return await run({ signal });
|
|
151
|
+
} finally {
|
|
152
|
+
active.delete(key);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Re-queue every result `row`'s record still holds, oldest first; resolves
|
|
157
|
+
* the errors of the ones the queue still refuses. Never reruns the routine. */
|
|
158
|
+
export async function redeliverRoutine(kind, row, deps = {}) {
|
|
159
|
+
const {
|
|
160
|
+
deliver = deliverScheduleResult,
|
|
161
|
+
onDeliveryFailed = armDeliveryRetry,
|
|
162
|
+
announce = announceRoutineRun,
|
|
163
|
+
log = defaultLog,
|
|
164
|
+
} = deps;
|
|
165
|
+
const record = await withRecord(kind, deps);
|
|
166
|
+
const entries = Object.entries(row?.resultDelivery || {}).sort(([, a], [, b]) =>
|
|
167
|
+
String(a?.at).localeCompare(String(b?.at))
|
|
168
|
+
);
|
|
169
|
+
const errors = [];
|
|
170
|
+
for (const [runId, entry] of entries) {
|
|
171
|
+
const result = entry?.result || {};
|
|
172
|
+
const item = {
|
|
173
|
+
runId,
|
|
174
|
+
kind,
|
|
175
|
+
ok: result.ok === true,
|
|
176
|
+
text: result.text || '',
|
|
177
|
+
runSessionId: result.runSessionId,
|
|
178
|
+
reason: result.reason,
|
|
179
|
+
paused: result.paused,
|
|
180
|
+
};
|
|
181
|
+
await queueResult(row, item, entry, {
|
|
182
|
+
...record,
|
|
183
|
+
deliver,
|
|
184
|
+
announce,
|
|
185
|
+
log,
|
|
186
|
+
onDeliveryFailed: () => errors.push(runId),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (errors.length) onDeliveryFailed();
|
|
190
|
+
return errors;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Daemon start (and the retry timer): re-queue every undelivered result of
|
|
194
|
+
* every schedule and webhook. Resolves how many runs still wait. Without a
|
|
195
|
+
* PostgreSQL cluster no routine exists, and none is started for this. */
|
|
196
|
+
export async function recoverRoutineDeliveries(depsByKind = null) {
|
|
197
|
+
if (!depsByKind) {
|
|
198
|
+
const [{ pgClusterExists }, { resolvePluginData }] = await Promise.all([
|
|
199
|
+
import('../runtime/memory/lib/pg/adapter.mjs'),
|
|
200
|
+
import('../runtime/shared/plugin-paths.mjs'),
|
|
201
|
+
]);
|
|
202
|
+
if (!pgClusterExists(resolvePluginData())) return 0;
|
|
203
|
+
}
|
|
204
|
+
let waiting = 0;
|
|
205
|
+
for (const kind of ['schedule', 'webhook']) {
|
|
206
|
+
const deps = await withRecord(kind, depsByKind?.[kind] || {});
|
|
207
|
+
for (const row of await deps.list()) {
|
|
208
|
+
if (row?.resultDelivery && Object.keys(row.resultDelivery).length) {
|
|
209
|
+
waiting += (await redeliverRoutine(kind, row, deps)).length;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return waiting;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** The app's "retry" on one routine: rejects with the error when still refused. */
|
|
217
|
+
export async function retryRoutineDelivery(kind, name, deps = {}) {
|
|
218
|
+
if (kind !== 'schedule' && kind !== 'webhook') throw new Error(`unknown routine kind "${kind}"`);
|
|
219
|
+
const record = await withRecord(kind, deps);
|
|
220
|
+
const row = await record.state(name);
|
|
221
|
+
if (!row) throw new Error(`${kind} "${name}" does not exist`);
|
|
222
|
+
const failed = await redeliverRoutine(kind, row, { ...deps, ...record });
|
|
223
|
+
if (failed.length) {
|
|
224
|
+
const latest = await record.state(name);
|
|
225
|
+
const error = latest?.resultDelivery?.[failed.at(-1)]?.error;
|
|
226
|
+
throw new Error(`"${name}": the result still could not be delivered${error ? ` (${error})` : ''}`);
|
|
227
|
+
}
|
|
228
|
+
return { name, delivered: Object.keys(row.resultDelivery || {}).length };
|
|
229
|
+
}
|
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
forgetProviderAuth,
|
|
7
7
|
loginOAuthProvider,
|
|
8
8
|
saveOpenAIUsageSessionKey,
|
|
9
|
-
saveOpenCodeGoUsageAuth,
|
|
10
9
|
saveProviderApiKey,
|
|
11
10
|
saveCustomProvider,
|
|
12
11
|
removeCustomProvider,
|
|
13
12
|
updateCustomProviderModel,
|
|
13
|
+
saveModelPreferences,
|
|
14
14
|
testCustomProvider,
|
|
15
15
|
checkCustomProviderKeyEnv,
|
|
16
16
|
discoverCustomProviderModels,
|
|
@@ -70,11 +70,6 @@ export function createLoginApi({ cfgMod, awaitKeychainPrewarm, reloadFullConfig,
|
|
|
70
70
|
refresh.afterUsageAuthChange();
|
|
71
71
|
return result;
|
|
72
72
|
},
|
|
73
|
-
async saveOpenCodeGoUsageAuth(opts) {
|
|
74
|
-
const result = await saveOpenCodeGoUsageAuth(cfgMod, opts);
|
|
75
|
-
refresh.afterUsageAuthChange();
|
|
76
|
-
return result;
|
|
77
|
-
},
|
|
78
73
|
async saveCustomProvider(input) {
|
|
79
74
|
await awaitKeychainPrewarm();
|
|
80
75
|
const result = await saveCustomProvider(cfgMod, input);
|
|
@@ -86,6 +81,15 @@ export function createLoginApi({ cfgMod, awaitKeychainPrewarm, reloadFullConfig,
|
|
|
86
81
|
refresh.afterCredentialChange();
|
|
87
82
|
return result;
|
|
88
83
|
},
|
|
84
|
+
/** Model management: /model visibility and favorites of one provider.
|
|
85
|
+
* Catalog rows read modelSettings on every answer, so only a custom
|
|
86
|
+
* provider's catalog (its hidden overrides) needs the refresh chain. */
|
|
87
|
+
setModelPreferences(providerId, changes) {
|
|
88
|
+
const result = saveModelPreferences(cfgMod, providerId, changes);
|
|
89
|
+
if (result.customCatalogChanged) refresh.afterCredentialChange();
|
|
90
|
+
else reloadFullConfig();
|
|
91
|
+
return result;
|
|
92
|
+
},
|
|
89
93
|
async removeCustomProvider(providerId) {
|
|
90
94
|
await awaitKeychainPrewarm();
|
|
91
95
|
const result = await removeCustomProvider(cfgMod, providerId);
|