mixdog 1.4.1 → 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/gate-local.mjs +172 -61
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/run-node-tests.mjs +54 -29
- package/scripts/lib/scoped-temp.mjs +1 -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/pptx-kit-index.mjs +5 -6
- package/scripts/suite-health.mjs +110 -28
- 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/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +18 -2
- package/src/defaults/skills/browser-use/SKILL.md +4 -1
- 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 +12 -2
- 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 +6 -30
- package/src/rules/lead/LEAD.md +3 -3
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +4 -3
- 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 +130 -21
- 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/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +7 -7
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- 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 +83 -52
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +43 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +30 -28
- 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/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.mjs +1 -1
- 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/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 +48 -31
- 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.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-oauth-login.mjs +26 -28
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +1 -0
- 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 +33 -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/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -0
- 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/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-warm.mjs +94 -10
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +10 -5
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +5 -5
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +11 -1
- 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/fresh-context.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +21 -2
- 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/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +3 -4
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +2 -0
- 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 +25 -14
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +17 -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 +7 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +47 -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/restart-prefix-parity.fixture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +243 -38
- 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/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +36 -26
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +3 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- 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/graph-manifest.json +13 -13
- 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 +2 -0
- 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/whisper-port.mjs +19 -10
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- 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/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +4 -0
- package/src/runtime/office/quality/assurance-structure-docx.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/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/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/llm/cost.mjs +6 -1
- 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/provider-accounts.mjs +52 -2
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-surface.mjs +110 -36
- package/src/runtime/shared/tool-work-units.mjs +4 -0
- 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/git.mjs +57 -0
- package/src/runtime/shared/worktrees/manager.mjs +205 -137
- 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 +4 -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-task-sessions.mjs +410 -353
- package/src/session-runtime/boot/tools.mjs +2 -0
- package/src/session-runtime/bot-status.mjs +103 -103
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/discovery.mjs +159 -40
- package/src/session-runtime/conversation-import/service.mjs +9 -3
- package/src/session-runtime/handoff-attachments.mjs +1 -1
- package/src/session-runtime/held-requests.mjs +3 -1
- 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/workspace-tools.mjs +143 -116
- 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/provider-auth/login.mjs +2 -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/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-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 +281 -10
- 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/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-route.mjs +10 -1
- 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 -1066
- 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 +54 -54
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +151 -136
- 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.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/tui/App.jsx +154 -164
- package/src/tui/app/app-view/floating-panel.jsx +3 -0
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +21 -10
- 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 +25 -6
- package/src/tui/app/provider-setup-picker.mjs +20 -13
- 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/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 +1896 -1341
- 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/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/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { TOOL_SYNC_EXECUTION_CONTRACT } from '../shared/tool-execution-contract.mjs';
|
|
2
|
+
|
|
3
|
+
export const EXPLORE_MAX_QUERIES = 8;
|
|
4
|
+
|
|
5
|
+
export const TOOL_DEFS = [
|
|
6
|
+
{
|
|
7
|
+
name: 'explore',
|
|
8
|
+
title: 'Explore',
|
|
9
|
+
annotations: {
|
|
10
|
+
title: 'Explore',
|
|
11
|
+
readOnlyHint: true,
|
|
12
|
+
destructiveHint: false,
|
|
13
|
+
idempotentHint: true,
|
|
14
|
+
openWorldHint: false,
|
|
15
|
+
},
|
|
16
|
+
description:
|
|
17
|
+
'Read-only code search in parallel explorers outside your context; returns one merged answer with path:line evidence. ' +
|
|
18
|
+
'Use when locating needs 3+ searches, spans 2+ files or areas, or covers independent questions; a known file or one lookup: read/grep. ' +
|
|
19
|
+
TOOL_SYNC_EXECUTION_CONTRACT,
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
query: {
|
|
24
|
+
anyOf: [
|
|
25
|
+
{ type: 'string', minLength: 1 },
|
|
26
|
+
{ type: 'array', items: { type: 'string', minLength: 1 }, minItems: 1, maxItems: EXPLORE_MAX_QUERIES },
|
|
27
|
+
],
|
|
28
|
+
description: 'One self-contained question, or an array of independent ones (one explorer each).',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ['query'],
|
|
32
|
+
additionalProperties: false,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
];
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// The explore tool: one read-only explorer loop per query (explorer.mjs), all
|
|
2
|
+
// in parallel, merged into one bounded answer within the same tool call.
|
|
3
|
+
import { resolveMaintenanceRoute } from '../agent/orchestrator/agent-runtime/maintenance-route.mjs';
|
|
4
|
+
import { loadConfig } from '../agent/orchestrator/config.mjs';
|
|
5
|
+
import { getProvider, initProviders } from '../agent/orchestrator/providers/registry.mjs';
|
|
6
|
+
import { EXPLORE_MAX_QUERIES } from './tool-defs.mjs';
|
|
7
|
+
import { runExplorer } from './explorer.mjs';
|
|
8
|
+
|
|
9
|
+
// Hidden ids are reserved from user agents, so this one keeps the `-agent`
|
|
10
|
+
// suffix: a plain `explorer` would hide a user's own Explorer agent.
|
|
11
|
+
export const EXPLORER_AGENT = 'explore-agent';
|
|
12
|
+
export const EXPLORE_TIMEOUT_MS = 120_000;
|
|
13
|
+
export const EXPLORE_OUTPUT_CAP = 24_000;
|
|
14
|
+
const TRUNCATED = '\n[explore: answer truncated]';
|
|
15
|
+
|
|
16
|
+
function result(text, isError = false) {
|
|
17
|
+
return { content: [{ type: 'text', text }], ...(isError ? { isError: true } : {}) };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function normalizeExploreQueries(raw) {
|
|
21
|
+
const list = Array.isArray(raw) ? raw : [raw];
|
|
22
|
+
return list.map((q) => (typeof q === 'string' ? q.trim() : '')).filter(Boolean);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function capped(text, budget) {
|
|
26
|
+
return text.length <= budget ? text : text.slice(0, Math.max(0, budget - TRUNCATED.length)) + TRUNCATED;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Headings and error lines are labels, not answers: the truncation marker
|
|
30
|
+
// would tell the caller that evidence was lost when none was.
|
|
31
|
+
function shortened(text, max) {
|
|
32
|
+
return text.length <= max ? text : `${text.slice(0, max - 1)}…`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {{ query: string|string[] }} args
|
|
37
|
+
* @param {{ cwd?: string, signal?: AbortSignal, callerSessionId?: string }} ctx
|
|
38
|
+
* @param {object} [deps] injectable for tests
|
|
39
|
+
*/
|
|
40
|
+
export async function runExplore(args = {}, ctx = {}, deps = {}) {
|
|
41
|
+
const {
|
|
42
|
+
load = () => loadConfig({ secrets: false }),
|
|
43
|
+
initialize = initProviders,
|
|
44
|
+
providerFor = getProvider,
|
|
45
|
+
timeoutMs = EXPLORE_TIMEOUT_MS,
|
|
46
|
+
} = deps;
|
|
47
|
+
const queries = normalizeExploreQueries(args.query);
|
|
48
|
+
if (!queries.length) return result('[explore error] query is required', true);
|
|
49
|
+
if (queries.length > EXPLORE_MAX_QUERIES) {
|
|
50
|
+
return result(`[explore error] at most ${EXPLORE_MAX_QUERIES} queries per call`, true);
|
|
51
|
+
}
|
|
52
|
+
const config = load();
|
|
53
|
+
const route = resolveMaintenanceRoute({ agent: EXPLORER_AGENT, config, includeDefault: false });
|
|
54
|
+
if (!route || typeof route !== 'object') {
|
|
55
|
+
return result('[explore error] Explore has no model; pick one under Workflows → Built-in agents → Explore', true);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// One controller per call: caller cancellation and the deadline both abort
|
|
59
|
+
// every explorer, and the call waits for each loop to settle.
|
|
60
|
+
const controller = new AbortController();
|
|
61
|
+
const parent = ctx.signal;
|
|
62
|
+
const onParentAbort = () => controller.abort(parent.reason);
|
|
63
|
+
if (parent?.aborted) return result('[explore error] cancelled', true);
|
|
64
|
+
parent?.addEventListener('abort', onParentAbort, { once: true });
|
|
65
|
+
let timedOut = false;
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
timedOut = true;
|
|
68
|
+
const reason = new Error(`explore timed out after ${Math.round(timeoutMs / 1000)}s`);
|
|
69
|
+
// Lets an explorer return the answer text it already wrote.
|
|
70
|
+
reason.salvagePartial = true;
|
|
71
|
+
controller.abort(reason);
|
|
72
|
+
}, timeoutMs);
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await initialize(config.providers || {}, { signal: controller.signal });
|
|
76
|
+
const provider = providerFor(route.provider);
|
|
77
|
+
if (!provider || typeof provider.send !== 'function') {
|
|
78
|
+
return result(`[explore error] provider "${route.provider}" is not ready`, true);
|
|
79
|
+
}
|
|
80
|
+
const settled = await Promise.all(
|
|
81
|
+
queries.map((query) =>
|
|
82
|
+
runExplorer({
|
|
83
|
+
query,
|
|
84
|
+
route,
|
|
85
|
+
provider,
|
|
86
|
+
cwd: ctx.cwd || null,
|
|
87
|
+
signal: controller.signal,
|
|
88
|
+
ownerSessionId: ctx.callerSessionId || null,
|
|
89
|
+
}).then(
|
|
90
|
+
(text) => {
|
|
91
|
+
const answer = String(text || '').trim();
|
|
92
|
+
return { ok: Boolean(answer), text: answer, late: timedOut };
|
|
93
|
+
},
|
|
94
|
+
(error) => ({ ok: false, error, late: timedOut })
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
if (parent?.aborted) return result('[explore error] cancelled', true);
|
|
99
|
+
const budget = Math.floor(EXPLORE_OUTPUT_CAP / queries.length);
|
|
100
|
+
const bodies = settled.map((entry) => {
|
|
101
|
+
if (entry.ok) return capped(entry.late ? `${entry.text}\n[explore: partial, timed out]` : entry.text, budget);
|
|
102
|
+
if (entry.late) return `[explore error] timed out after ${Math.round(timeoutMs / 1000)}s with no answer`;
|
|
103
|
+
if (entry.error) return `[explore error] ${shortened(String(entry.error?.message || entry.error), 500)}`;
|
|
104
|
+
return '[explore error] explorer returned no answer';
|
|
105
|
+
});
|
|
106
|
+
const text =
|
|
107
|
+
queries.length === 1
|
|
108
|
+
? bodies[0]
|
|
109
|
+
: bodies
|
|
110
|
+
.map((body, i) => `## Q${i + 1}: ${shortened(queries[i].replace(/\s+/g, ' '), 100)}\n${body}`)
|
|
111
|
+
.join('\n\n');
|
|
112
|
+
return result(
|
|
113
|
+
text,
|
|
114
|
+
settled.every((entry) => !entry.ok)
|
|
115
|
+
);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (parent?.aborted) return result('[explore error] cancelled', true);
|
|
118
|
+
return result(`[explore error] ${error?.message || error}`, true);
|
|
119
|
+
} finally {
|
|
120
|
+
clearTimeout(timer);
|
|
121
|
+
parent?.removeEventListener('abort', onParentAbort);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -71,6 +71,7 @@ import {
|
|
|
71
71
|
} from './lib/trace-store.mjs';
|
|
72
72
|
import { writeJsonAtomicSync } from '../shared/atomic-file.mjs';
|
|
73
73
|
import { safeIpcSend } from '../shared/safe-ipc-send.mjs';
|
|
74
|
+
import { adoptSystemProxy } from '../shared/llm/system-proxy.mjs';
|
|
74
75
|
import { resolvePluginData, mixdogHome } from '../shared/plugin-paths.mjs';
|
|
75
76
|
import { scheduledCycle1Signature } from './lib/cycle-signatures.mjs';
|
|
76
77
|
import { createTranscriptIngest } from './lib/transcript-ingest.mjs';
|
|
@@ -96,6 +97,9 @@ import {
|
|
|
96
97
|
} from './lib/memory-config-flags.mjs';
|
|
97
98
|
const IS_MEMORY_ENTRY = !!process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href;
|
|
98
99
|
if (IS_MEMORY_ENTRY) {
|
|
100
|
+
// Runtime and model downloads follow the system proxy the launching daemon
|
|
101
|
+
// handed over (removed from this env so child processes never see it).
|
|
102
|
+
adoptSystemProxy();
|
|
99
103
|
// Node's own warning printer stays off in this runtime, but a listener leak
|
|
100
104
|
// is still logged, with the stack that names its source.
|
|
101
105
|
process.removeAllListeners('warning');
|
|
@@ -12,6 +12,7 @@ import { writeProfilePoint } from './model-profile.mjs';
|
|
|
12
12
|
import { createCompactVectorCache } from './compact-vector-cache.mjs';
|
|
13
13
|
import { EMBED_KEEP_WARM_MS } from './embedding-idle-lease.mjs';
|
|
14
14
|
import { workerExecArgv } from '../../shared/worker-exec-argv.mjs';
|
|
15
|
+
import { systemProxyHandoffEnv } from '../../shared/llm/system-proxy.mjs';
|
|
15
16
|
import {
|
|
16
17
|
getConfiguredEmbeddingModelId,
|
|
17
18
|
getDefaultEmbeddingDtype,
|
|
@@ -69,7 +70,9 @@ function ensureWorker() {
|
|
|
69
70
|
_lastRestartMs = now;
|
|
70
71
|
const execArgv = embeddingWorkerExecArgv();
|
|
71
72
|
const created = new Worker(WORKER_PATH, {
|
|
72
|
-
|
|
73
|
+
// The model download runs in this worker: it gets the system proxy
|
|
74
|
+
// decision explicitly (and removes it from its own env on start).
|
|
75
|
+
env: { ...process.env, ...systemProxyHandoffEnv() },
|
|
73
76
|
execArgv,
|
|
74
77
|
workerData: { dtype: _configuredDtype },
|
|
75
78
|
});
|
|
@@ -8,6 +8,7 @@ import os from 'node:os';
|
|
|
8
8
|
import { execFile } from 'node:child_process';
|
|
9
9
|
import { promisify } from 'node:util';
|
|
10
10
|
import { resolvePluginData } from '../../shared/plugin-paths.mjs';
|
|
11
|
+
import { adoptSystemProxy } from '../../shared/llm/system-proxy.mjs';
|
|
11
12
|
import { compressEmbeddingModelCache } from './embedding-model-cache-compression.mjs';
|
|
12
13
|
import { createIdleLease } from './embedding-idle-lease.mjs';
|
|
13
14
|
import { ensureModelFile, ensureModelGraph } from './embedding-model-files.mjs';
|
|
@@ -24,6 +25,9 @@ import {
|
|
|
24
25
|
prepareEmbeddingInput,
|
|
25
26
|
} from './embedding-model-config.mjs';
|
|
26
27
|
|
|
28
|
+
// The model download goes through the system proxy the parent handed over.
|
|
29
|
+
adoptSystemProxy();
|
|
30
|
+
|
|
27
31
|
const MODEL_ID = getConfiguredEmbeddingModelId();
|
|
28
32
|
|
|
29
33
|
// Reroute ALL worker-thread stdio through parentPort. Without stdout:true/
|
|
@@ -235,7 +235,7 @@ function shortTableSplitIssues(tables, issues) {
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
// A total row is a total by its label; it reads as one only when it is set apart from the rows it sums.
|
|
238
|
-
|
|
238
|
+
const TOTAL_LABEL = /^(?:(?:grand\s+total|sub\s*total|total)\b|(?:합계|총계|소계|계)(?:\s|$))/i;
|
|
239
239
|
const FIGURE_TEXT = /^[\s+\-−₩$€¥]*[\d,.]+\s*(?:%|%p|[가-힣A-Za-z]{0,3})?\s*$/;
|
|
240
240
|
const DISPLAY_SIZE = 18;
|
|
241
241
|
|
|
@@ -12,9 +12,16 @@ export const DEFAULT_DISABLED_AGENT_IDS = Object.freeze([
|
|
|
12
12
|
'writer',
|
|
13
13
|
]);
|
|
14
14
|
|
|
15
|
+
export const EXPLORE_AGENT_ID = 'explore';
|
|
16
|
+
|
|
15
17
|
// The Maintainer also starts off: background upkeep spends model calls, so it
|
|
16
|
-
// runs only once the user turns it on and picks its model.
|
|
17
|
-
|
|
18
|
+
// runs only once the user turns it on and picks its model. Explore likewise:
|
|
19
|
+
// its tool reaches the model only once the user picks its model.
|
|
20
|
+
export const DEFAULT_DISABLED_AGENT_ROSTER = Object.freeze([
|
|
21
|
+
...DEFAULT_DISABLED_AGENT_IDS,
|
|
22
|
+
'maintainer',
|
|
23
|
+
EXPLORE_AGENT_ID,
|
|
24
|
+
]);
|
|
18
25
|
|
|
19
26
|
/** The AGENT.md frontmatter `kind` the Workflows page writes when it creates
|
|
20
27
|
* an agent: a workflow delegation role, never a contact (봇). */
|
|
@@ -149,6 +156,14 @@ export function configuredAgentRouteCandidates(config, agentId) {
|
|
|
149
156
|
return route ? [route] : [];
|
|
150
157
|
}
|
|
151
158
|
|
|
159
|
+
/** The explore tool runs only on Explore's own model (never Main) while it is on. */
|
|
160
|
+
export function exploreRouteConfigured(config) {
|
|
161
|
+
return (
|
|
162
|
+
!isAgentDisabled(config, EXPLORE_AGENT_ID) &&
|
|
163
|
+
configuredAgentRouteCandidates(config, EXPLORE_AGENT_ID).some(isCompleteAgentRoute)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
152
167
|
function canonicalizeAgentRoutes(config = {}) {
|
|
153
168
|
const agents = Object.fromEntries(
|
|
154
169
|
Object.entries(record(config.agents)).filter(([, route]) => isCompleteAgentRoute(route))
|
|
@@ -128,12 +128,113 @@ export function renameWithRetrySync(src, dst, opts = {}) {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// Windows refuses to rename over a file while any handle on it is open, so
|
|
132
|
+
// this process's own reads of a busy state file (a delivery loop polling it)
|
|
133
|
+
// could fail every attempt of its writer's rename until the retries ran out.
|
|
134
|
+
// Here a rename attempt waits for the reads of its target in flight and holds
|
|
135
|
+
// new ones off only while it runs; other processes are what the retries cover.
|
|
136
|
+
// A read still open after RENAME_READ_WAIT_MS is left behind with its path's
|
|
137
|
+
// entry (a stuck read must not hold the writer, its lock, or later readers),
|
|
138
|
+
// and the attempt goes ahead under those same retries. Likewise a rename not
|
|
139
|
+
// returned by then: readers held off read anyway, as without it. A reader's
|
|
140
|
+
// bound counts from the rename call, not from the attempt's own (bounded)
|
|
141
|
+
// wait for reads, so a rename that just started is never read across.
|
|
142
|
+
export const RENAME_READ_WAIT_MS = 1_000;
|
|
143
|
+
const targetUse = new Map();
|
|
144
|
+
const targetKey = (path) => {
|
|
145
|
+
const full = resolve(path);
|
|
146
|
+
return process.platform === 'win32' ? full.toLowerCase() : full;
|
|
147
|
+
};
|
|
148
|
+
function useOf(key) {
|
|
149
|
+
let use = targetUse.get(key);
|
|
150
|
+
if (!use) targetUse.set(key, (use = { reads: 0, renaming: null, draining: null, drained: [] }));
|
|
151
|
+
return use;
|
|
152
|
+
}
|
|
153
|
+
function forgetIfIdle(key, use) {
|
|
154
|
+
if (use.reads === 0 && !use.renaming && targetUse.get(key) === use) targetUse.delete(key);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Waits for the rename `use` runs; one that has not returned within the bound
|
|
158
|
+
// is left behind with the entry, and the caller goes on as without it.
|
|
159
|
+
async function outwaitRename(key, use) {
|
|
160
|
+
await use.draining;
|
|
161
|
+
if (use.renaming && !(await settlesWithin(use.renaming, RENAME_READ_WAIT_MS)) && targetUse.get(key) === use) {
|
|
162
|
+
targetUse.delete(key);
|
|
163
|
+
}
|
|
164
|
+
return useOf(key);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function settlesWithin(promise, ms) {
|
|
168
|
+
let timer;
|
|
169
|
+
const bound = new Promise((resolve) => {
|
|
170
|
+
timer = setTimeout(() => resolve(false), ms);
|
|
171
|
+
});
|
|
172
|
+
return Promise.race([promise.then(() => true), bound]).finally(() => clearTimeout(timer));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function readTarget(path, read) {
|
|
176
|
+
const key = targetKey(path);
|
|
177
|
+
let use = useOf(key);
|
|
178
|
+
while (use.renaming) use = await outwaitRename(key, use);
|
|
179
|
+
use.reads += 1;
|
|
180
|
+
try {
|
|
181
|
+
return await read();
|
|
182
|
+
} finally {
|
|
183
|
+
use.reads -= 1;
|
|
184
|
+
if (use.reads === 0) for (const done of use.drained.splice(0)) done();
|
|
185
|
+
forgetIfIdle(key, use);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function renameOver(src, dst) {
|
|
190
|
+
const key = targetKey(dst);
|
|
191
|
+
let use = useOf(key);
|
|
192
|
+
while (use.renaming) use = await outwaitRename(key, use);
|
|
193
|
+
let finish;
|
|
194
|
+
use.renaming = new Promise((resolve) => {
|
|
195
|
+
finish = resolve;
|
|
196
|
+
});
|
|
197
|
+
use.draining = use.reads > 0 ? readsDrained(use, RENAME_READ_WAIT_MS) : null;
|
|
198
|
+
try {
|
|
199
|
+
if (use.draining && !(await use.draining) && targetUse.get(key) === use) targetUse.delete(key);
|
|
200
|
+
await renameAsync(src, dst);
|
|
201
|
+
} finally {
|
|
202
|
+
use.renaming = null;
|
|
203
|
+
use.draining = null;
|
|
204
|
+
finish();
|
|
205
|
+
forgetIfIdle(key, use);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// True once `use` has no read in flight, false after `ms` (its waiter removed).
|
|
210
|
+
function readsDrained(use, ms) {
|
|
211
|
+
return new Promise((resolve) => {
|
|
212
|
+
const done = () => {
|
|
213
|
+
clearTimeout(timer);
|
|
214
|
+
resolve(true);
|
|
215
|
+
};
|
|
216
|
+
const timer = setTimeout(() => {
|
|
217
|
+
const at = use.drained.indexOf(done);
|
|
218
|
+
if (at >= 0) use.drained.splice(at, 1);
|
|
219
|
+
resolve(false);
|
|
220
|
+
}, ms);
|
|
221
|
+
use.drained.push(done);
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Test seam: the per-path coordination left (entries, drain waiters). */
|
|
226
|
+
export function _renameCoordinationForTest() {
|
|
227
|
+
let waiters = 0;
|
|
228
|
+
for (const use of targetUse.values()) waiters += use.drained.length;
|
|
229
|
+
return { entries: targetUse.size, waiters };
|
|
230
|
+
}
|
|
231
|
+
|
|
131
232
|
async function renameWithRetry(src, dst, opts = {}) {
|
|
132
233
|
const backoffs = renameBackoffs(opts);
|
|
133
234
|
let lastErr = null;
|
|
134
235
|
for (let attempt = 0; attempt <= backoffs.length; attempt++) {
|
|
135
236
|
try {
|
|
136
|
-
await
|
|
237
|
+
await renameOver(src, dst);
|
|
137
238
|
return true;
|
|
138
239
|
} catch (err) {
|
|
139
240
|
lastErr = err;
|
|
@@ -433,7 +534,7 @@ function readContentOrNullSync(filePath) {
|
|
|
433
534
|
|
|
434
535
|
async function readContentOrNullAsync(filePath) {
|
|
435
536
|
try {
|
|
436
|
-
return await readFileAsync(filePath);
|
|
537
|
+
return await readTarget(filePath, () => readFileAsync(filePath));
|
|
437
538
|
} catch (err) {
|
|
438
539
|
if (err?.code === 'ENOENT') return null;
|
|
439
540
|
throw err;
|
|
@@ -310,7 +310,9 @@ export function cleanupBackgroundTasks(options = {}) {
|
|
|
310
310
|
function cancelRunningTask(task, reason, notify, terminalReason = null) {
|
|
311
311
|
try {
|
|
312
312
|
task.cancel?.();
|
|
313
|
-
} catch {
|
|
313
|
+
} catch {
|
|
314
|
+
// A failing cancel hook must not stop the task from being marked cancelled.
|
|
315
|
+
}
|
|
314
316
|
completeBackgroundTask(task.taskId, { status: 'cancelled', error: reason, notify: notify === true, terminalReason });
|
|
315
317
|
if (task.notifyOnCancel !== true || notify === true || task.status !== 'cancelled' || task.cancelNotify) return;
|
|
316
318
|
if (notify === false) {
|
|
@@ -370,9 +372,12 @@ export function cancelBackgroundTasks(options = {}) {
|
|
|
370
372
|
const wanted = clean(options.surface);
|
|
371
373
|
const executionSessionId = clean(options.executionSessionId);
|
|
372
374
|
const scope = normalizeTaskScope(options);
|
|
373
|
-
|
|
375
|
+
// Optional: only tasks started at/after this time (a turn's own work).
|
|
376
|
+
const startedSinceMs = Number(options.startedSinceMs) || 0;
|
|
377
|
+
const taskIds = [];
|
|
374
378
|
for (const task of [...tasks.values()]) {
|
|
375
379
|
if (wanted && task.surface !== wanted) continue;
|
|
380
|
+
if (startedSinceMs > 0 && !(task.startedAtMs >= startedSinceMs)) continue;
|
|
376
381
|
// Scoped teardown must be exact. Legacy tasks without ownership stay
|
|
377
382
|
// visible/recoverable, but may not be claimed by whichever session happens
|
|
378
383
|
// to close first.
|
|
@@ -386,9 +391,9 @@ export function cancelBackgroundTasks(options = {}) {
|
|
|
386
391
|
continue;
|
|
387
392
|
}
|
|
388
393
|
cancelRunningTask(task, reason, options.notify, terminalReason);
|
|
389
|
-
|
|
394
|
+
taskIds.push(task.taskId);
|
|
390
395
|
}
|
|
391
|
-
return { cancelled };
|
|
396
|
+
return { cancelled: taskIds.length, taskIds };
|
|
392
397
|
}
|
|
393
398
|
|
|
394
399
|
export function acknowledgeBackgroundTaskCompletion(taskId, options = {}) {
|
|
@@ -415,13 +420,17 @@ function resultTextForTask(task) {
|
|
|
415
420
|
// fallback below so the completion notification still carries a body.
|
|
416
421
|
try {
|
|
417
422
|
process.stderr.write(`[background-${task.surface}] renderResult failed: ${err?.message || err}\n`);
|
|
418
|
-
} catch {
|
|
423
|
+
} catch {
|
|
424
|
+
// A closed stderr must not lose the completion body.
|
|
425
|
+
}
|
|
419
426
|
}
|
|
420
427
|
}
|
|
421
428
|
if (typeof task.result === 'string') return task.result;
|
|
422
429
|
try {
|
|
423
430
|
return JSON.stringify(task.result, null, 2);
|
|
424
|
-
} catch {
|
|
431
|
+
} catch {
|
|
432
|
+
// Unserializable result (circular, BigInt): fall back to the empty body.
|
|
433
|
+
}
|
|
425
434
|
}
|
|
426
435
|
return '';
|
|
427
436
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// What a
|
|
1
|
+
// What a connector server tells the model about its accounts (MCP
|
|
2
2
|
// `instructions`), in one line: the connected accounts, and that each tool
|
|
3
|
-
// takes `account` (
|
|
4
|
-
//
|
|
3
|
+
// takes `account` (left out, the account used last). An account that cannot
|
|
4
|
+
// be used right now is listed with why.
|
|
5
5
|
|
|
6
6
|
/** The MCP instructions naming `accounts` (`{ email, note? }`, `note` a short
|
|
7
7
|
* reason it is unusable such as "needs sign-in"; one without an address is
|
|
@@ -12,12 +12,12 @@ export function connectorAccountsInstructions(accounts) {
|
|
|
12
12
|
const list = named.map(({ email, note }) => (note ? `${email} (${note})` : email)).join(', ');
|
|
13
13
|
return named.length === 1
|
|
14
14
|
? `Accounts: ${list}. \`account\` may be left out.`
|
|
15
|
-
: `Accounts: ${list}.
|
|
15
|
+
: `Accounts: ${list}. \`account\` picks one; left out, a call uses the account used last, and its result names it.`;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/** The account addresses instructions from connectorAccountsInstructions name. */
|
|
19
19
|
export function accountsOfInstructions(instructions) {
|
|
20
|
-
const list = /^Accounts: (.+?)\.
|
|
20
|
+
const list = /^Accounts: (.+?)\. `account`/.exec(String(instructions || ''))?.[1] || '';
|
|
21
21
|
return list
|
|
22
22
|
.split(', ')
|
|
23
23
|
.map((part) => part.replace(/ \(.*\)$/, '').trim())
|
|
@@ -40,8 +40,7 @@ export function connectorToolDefault(connectorId: string, tool: string): 'auto'
|
|
|
40
40
|
export function connectorServerInput(
|
|
41
41
|
entry: ConnectorCatalogEntry,
|
|
42
42
|
name: string,
|
|
43
|
-
key?: string
|
|
44
|
-
options?: { extraAccount?: boolean }
|
|
43
|
+
key?: string
|
|
45
44
|
): Record<string, unknown>;
|
|
46
45
|
export function connectorAppPasswordOnly(entry: ConnectorCatalogEntry | null | undefined): boolean;
|
|
47
46
|
export function connectorUsesGoogleClient(entry: ConnectorCatalogEntry | null | undefined): boolean;
|
|
@@ -52,12 +51,19 @@ export function gmailAppPasswordValue(value: unknown): string;
|
|
|
52
51
|
export function gmailAppPasswordAccount(cfg: unknown): string;
|
|
53
52
|
export function gmailAppPasswordServerInput(name: string, email: string, password: string): Record<string, unknown>;
|
|
54
53
|
|
|
55
|
-
/** One stored account of a
|
|
54
|
+
/** One stored account of a connector server. */
|
|
56
55
|
export interface ConnectorAccountEntry {
|
|
57
56
|
name: string;
|
|
58
|
-
|
|
57
|
+
/** Absent: http. */
|
|
58
|
+
type?: string;
|
|
59
|
+
url?: string;
|
|
59
60
|
headers?: Record<string, string>;
|
|
60
61
|
oauthClientId?: string;
|
|
62
|
+
/** The account's own sign-in key, when another account signs in at its URL. */
|
|
63
|
+
oauthKey?: string;
|
|
64
|
+
command?: string;
|
|
65
|
+
args?: string[];
|
|
66
|
+
env?: Record<string, string>;
|
|
61
67
|
/** `false`: the account is kept but neither connected nor called. */
|
|
62
68
|
enabled?: boolean;
|
|
63
69
|
}
|
|
@@ -76,6 +82,7 @@ export function withConnectorAccountEnabled(
|
|
|
76
82
|
enabled: boolean
|
|
77
83
|
): Record<string, unknown>;
|
|
78
84
|
export function connectorAccountEntry(name: string, cfg: Record<string, unknown>): ConnectorAccountEntry;
|
|
85
|
+
export function connectorServerSettings(cfg: Record<string, unknown>): Record<string, unknown>;
|
|
79
86
|
export function mergeConnectorAccountServers(servers: Record<string, unknown>): {
|
|
80
87
|
servers: Record<string, unknown>;
|
|
81
88
|
merged: { connector: string; name: string; from: string[] }[];
|