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
|
@@ -46,7 +46,8 @@ import { executionFallbacks } from '../../../../shared/model-route-chain.mjs';
|
|
|
46
46
|
import { ownerRouteFallbacks } from './owner-route-fallbacks.mjs';
|
|
47
47
|
import { applyPendingWorkspaceReroot, refreshSessionBp3Environment } from './prompt-utils.mjs';
|
|
48
48
|
import { isWorktreeBound } from '../../../../shared/worktrees/contract.mjs';
|
|
49
|
-
import { applyAgentToolExposure } from '../loop/tool-exposure-migration.mjs';
|
|
49
|
+
import { applyAgentToolExposure, markToolSurfaceMigrated } from '../loop/tool-exposure-migration.mjs';
|
|
50
|
+
import { useOwnScratchEnvironment } from './session-scratch-environment.mjs';
|
|
50
51
|
import { prewarmSessionAutoEffort } from './ask-turn-auto-effort.mjs';
|
|
51
52
|
import { cancelCacheWarm } from '../cache-warm.mjs';
|
|
52
53
|
|
|
@@ -164,9 +165,9 @@ function resolveSessionRoute(opts, presetObj, profile) {
|
|
|
164
165
|
const modelName = opts.model || presetObj?.model;
|
|
165
166
|
// opts.tools (caller-supplied) wins over presetObj.tools — caller
|
|
166
167
|
// intent ('tools:readonly' from Pool C, etc.) must override the
|
|
167
|
-
// preset's default 'full'
|
|
168
|
-
//
|
|
169
|
-
//
|
|
168
|
+
// preset's default 'full'; otherwise a preset's tools='full' would shadow
|
|
169
|
+
// an explicit readonly request and leak write tools and bash into a
|
|
170
|
+
// read-only agent.
|
|
170
171
|
const toolPreset = opts.tools || presetObj?.tools || (typeof opts.preset === 'string' ? opts.preset : null) || 'full';
|
|
171
172
|
const effort = Object.hasOwn(opts, 'effort') ? opts.effort || null : presetObj?.effort || null;
|
|
172
173
|
const fast = presetObj?.fast === true || opts.fast === true;
|
|
@@ -237,17 +238,21 @@ export function createSession(createOpts) {
|
|
|
237
238
|
: { ...createOpts, sessionMode };
|
|
238
239
|
// A Lead-class session (actingAgent set) takes its owner's chain while it
|
|
239
240
|
// runs on the owner's primary model; an agent keeps its preset's.
|
|
240
|
-
const
|
|
241
|
-
|
|
241
|
+
const explicitRouteFallbacks = Object.hasOwn(opts, 'routeFallbacks');
|
|
242
|
+
let routeFallbacks;
|
|
243
|
+
if (actingAgent) {
|
|
244
|
+
routeFallbacks = explicitRouteFallbacks
|
|
242
245
|
? opts.routeFallbacks
|
|
243
|
-
: ownerRouteFallbacks({ sessionMode, agentId: actingAgent, provider: providerName, model: modelName })
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
)
|
|
246
|
+
: ownerRouteFallbacks({ sessionMode, agentId: actingAgent, provider: providerName, model: modelName });
|
|
247
|
+
} else {
|
|
248
|
+
routeFallbacks = executionFallbacks(
|
|
249
|
+
normalizeWorkflowRoute({
|
|
250
|
+
provider: providerName,
|
|
251
|
+
model: modelName,
|
|
252
|
+
fallbacks: explicitRouteFallbacks ? opts.routeFallbacks : presetObj?.fallbacks,
|
|
253
|
+
})
|
|
254
|
+
);
|
|
255
|
+
}
|
|
251
256
|
// Provider cache strategy — agentRuntime.resolveSync() above is a
|
|
252
257
|
// best-effort injection point (setAgentRuntime() has no live caller
|
|
253
258
|
// today, so that branch never fires); build it directly here so every
|
|
@@ -594,6 +599,12 @@ export async function resumeSession(sessionId, preset, options = {}) {
|
|
|
594
599
|
_recoverTurnCheckpointDurably(session, sessionId);
|
|
595
600
|
_refreshResumedTools(session, sessionId, preset);
|
|
596
601
|
refreshSessionProviderCacheOpts(session);
|
|
602
|
+
// An archive saved before clear learned to rename it still names the
|
|
603
|
+
// session it was copied from: a changed prefix is one cache break.
|
|
604
|
+
if (useOwnScratchEnvironment(session)) {
|
|
605
|
+
invalidateContextUsageSnapshot(session);
|
|
606
|
+
markToolSurfaceMigrated(session, 'prompt_fold');
|
|
607
|
+
}
|
|
597
608
|
// The live session already owns the refreshed tools and desktop scope.
|
|
598
609
|
// Defer the structured clone + worker round-trip so opening a conversation
|
|
599
610
|
// is not blocked on persisting the same in-memory state back to disk.
|
|
@@ -25,6 +25,18 @@ import { sessionScratchDir } from '../../../../shared/session-scratch.mjs';
|
|
|
25
25
|
import { delegationDisabled } from './session-tool-surface.mjs';
|
|
26
26
|
import { contextAckMessage } from '../compact/user-message-kind.mjs';
|
|
27
27
|
|
|
28
|
+
/** What the generated scratch line starts with; the one place that line is recognised. */
|
|
29
|
+
export const SCRATCH_LINE_PREFIX = '- Scratch: ';
|
|
30
|
+
|
|
31
|
+
/** The environment line naming `sessionId`'s scratch directory, '' without one. */
|
|
32
|
+
export function scratchEnvironmentLine(sessionId) {
|
|
33
|
+
// Fixed per session id and data dir, so the line never changes across turns.
|
|
34
|
+
const scratchDir = sessionScratchDir(sessionId);
|
|
35
|
+
return scratchDir
|
|
36
|
+
? `${SCRATCH_LINE_PREFIX}${scratchDir} — this session's scratch directory; TEMP, TMP and TMPDIR in shell commands point here.`
|
|
37
|
+
: '';
|
|
38
|
+
}
|
|
39
|
+
|
|
28
40
|
// Preserve the exact pre-layout environment payload: Lead carried the
|
|
29
41
|
// shell preference in Profile Preferences, while any routing surface with
|
|
30
42
|
// shell carried the startup capability line in BP1.
|
|
@@ -33,8 +45,6 @@ import { contextAckMessage } from '../compact/user-message-kind.mjs';
|
|
|
33
45
|
// resolves explicit session signals first and never leaks the daemon's
|
|
34
46
|
// install root (user-cwd.mjs safe fallback chain).
|
|
35
47
|
function buildShellEnvironmentContext(opts, ownerIsAgent, toolsForRouting, sessionId = null) {
|
|
36
|
-
// Fixed per session id and data dir, so the line never changes across turns.
|
|
37
|
-
const scratchDir = sessionScratchDir(sessionId);
|
|
38
48
|
const sessionCwdLine = opts.cwd || captureOriginalUserCwd();
|
|
39
49
|
const wantsGitStartupLine = toolsForRouting.some((tool) => tool?.name === 'git');
|
|
40
50
|
let cwdContextLine = '';
|
|
@@ -48,9 +58,7 @@ function buildShellEnvironmentContext(opts, ownerIsAgent, toolsForRouting, sessi
|
|
|
48
58
|
return [
|
|
49
59
|
cwdContextLine,
|
|
50
60
|
`- Shell: ${shellName}. Use ${shellName} syntax unless the user specifies otherwise.`,
|
|
51
|
-
|
|
52
|
-
? `- Scratch: ${scratchDir} — this session's scratch directory; TEMP, TMP and TMPDIR in shell commands point here.`
|
|
53
|
-
: '',
|
|
61
|
+
scratchEnvironmentLine(sessionId),
|
|
54
62
|
// Which common tools the shell can run, measured where commands run
|
|
55
63
|
// (login shell on POSIX, this process's PATH on Windows); see
|
|
56
64
|
// runtime-capabilities.mjs. Recorded runs spent a round per session
|
|
@@ -113,15 +121,11 @@ export function sessionRolePromptFields(identity, { ownerIsAgent, toolFreeRole,
|
|
|
113
121
|
const mixy = (identity.agent || MIXY_AGENT_ID) === MIXY_AGENT_ID;
|
|
114
122
|
let roleRules = '';
|
|
115
123
|
if (!skipRules) {
|
|
116
|
-
roleRules = ownerIsAgent
|
|
117
|
-
? _buildAgentRules(identity.agentRulesProfile)
|
|
118
|
-
: _buildLeadRules({ includeLeadBrief: !delegationFree });
|
|
124
|
+
roleRules = ownerIsAgent ? _buildAgentRules() : _buildLeadRules({ includeLeadBrief: !delegationFree });
|
|
119
125
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
? _buildLeadRules({ includeLeadBrief: !delegationFree, part: 'identity' })
|
|
124
|
-
: '';
|
|
126
|
+
let identityLine = '';
|
|
127
|
+
if (agentMode) identityLine = agentModeIdentityLine(identity.agent || MIXY_AGENT_ID);
|
|
128
|
+
else if (lead) identityLine = _buildLeadRules({ includeLeadBrief: !delegationFree, part: 'identity' });
|
|
125
129
|
return {
|
|
126
130
|
roleRules,
|
|
127
131
|
...(lead
|
|
@@ -172,7 +176,6 @@ export function composeSessionSystem(opts, { profile, providerName, modelName, s
|
|
|
172
176
|
skipAgentRules: opts.skipAgentRules === true,
|
|
173
177
|
profileSkip: { ...profile?.skip },
|
|
174
178
|
agent: resolvedAgent,
|
|
175
|
-
agentRulesProfile: surface.agentRulesProfile,
|
|
176
179
|
};
|
|
177
180
|
const roleFields = sessionRolePromptFields(promptIdentity, {
|
|
178
181
|
ownerIsAgent,
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// manager/session-scratch-environment.mjs
|
|
2
|
+
// A session record that was copied from another session (a clear archive)
|
|
3
|
+
// still names the SOURCE's scratch directory in its generated environment,
|
|
4
|
+
// while its shell commands use its own. This rewrites only that line.
|
|
5
|
+
import {
|
|
6
|
+
BP3_PART_SEPARATOR,
|
|
7
|
+
bp3SystemMessage,
|
|
8
|
+
bpEnvSystemMessage,
|
|
9
|
+
replaceSystemMessageContent,
|
|
10
|
+
replaceWorkspaceEnvironment,
|
|
11
|
+
} from './prompt-utils.mjs';
|
|
12
|
+
import { SCRATCH_LINE_PREFIX, scratchEnvironmentLine } from './session-prompt-composition.mjs';
|
|
13
|
+
|
|
14
|
+
// The first line the generator's own prefix starts is the scratch line.
|
|
15
|
+
function withLine(text, line) {
|
|
16
|
+
if (typeof text !== 'string') return text;
|
|
17
|
+
const rows = text.split('\n');
|
|
18
|
+
const at = rows.findIndex((row) => row.startsWith(SCRATCH_LINE_PREFIX));
|
|
19
|
+
if (at < 0) return text;
|
|
20
|
+
rows[at] = line;
|
|
21
|
+
return rows.join('\n');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Only the generated environment facts (the first part of the environment
|
|
25
|
+
// tail) hold the line; memory and instruction files never do.
|
|
26
|
+
function tailWithLine(tail, line) {
|
|
27
|
+
if (typeof tail !== 'string') return tail;
|
|
28
|
+
const facts = tail.split(BP3_PART_SEPARATOR)[0];
|
|
29
|
+
const fixed = withLine(facts, line);
|
|
30
|
+
return fixed === facts ? tail : replaceWorkspaceEnvironment(tail, fixed);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Make `session`'s generated environment name its own scratch directory:
|
|
35
|
+
* the persisted environment tail, the system block carrying it and the
|
|
36
|
+
* environment facts of a staged workspace change. Instruction files, memory
|
|
37
|
+
* and every conversation message stay as they are; a session that already
|
|
38
|
+
* names its own directory is left byte-identical (message objects included).
|
|
39
|
+
* System messages are replaced in the session's own array, never mutated.
|
|
40
|
+
* @returns {boolean} whether the system prefix changed
|
|
41
|
+
*/
|
|
42
|
+
export function useOwnScratchEnvironment(session) {
|
|
43
|
+
const line = scratchEnvironmentLine(session?.id);
|
|
44
|
+
if (!line) return false;
|
|
45
|
+
const oldTail = session.bp3EnvironmentContext;
|
|
46
|
+
const newTail = tailWithLine(oldTail, line);
|
|
47
|
+
session.bp3EnvironmentContext = newTail;
|
|
48
|
+
const pending = session.workspaceReroot;
|
|
49
|
+
const seen = tailWithLine(pending?.seen?.environmentContext, line);
|
|
50
|
+
const target = tailWithLine(pending?.target?.environmentContext, line);
|
|
51
|
+
if (seen !== pending?.seen?.environmentContext || target !== pending?.target?.environmentContext) {
|
|
52
|
+
// The staged state may be shared with the session this one was copied
|
|
53
|
+
// from: replace it, never edit it.
|
|
54
|
+
session.workspaceReroot = {
|
|
55
|
+
...pending,
|
|
56
|
+
seen: { ...pending.seen, environmentContext: seen },
|
|
57
|
+
target: { ...pending.target, environmentContext: target },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (newTail === oldTail || typeof oldTail !== 'string') return false;
|
|
61
|
+
// The generated environment closes its block (split env block, or the
|
|
62
|
+
// combined tier3 block after core + session start): swap that suffix.
|
|
63
|
+
const block = session.bp3EnvSplit === true ? bpEnvSystemMessage(session) : bp3SystemMessage(session);
|
|
64
|
+
const content = block?.content;
|
|
65
|
+
const suffix = oldTail.trim();
|
|
66
|
+
if (typeof content !== 'string' || !suffix || !content.endsWith(suffix)) return false;
|
|
67
|
+
const next = content.slice(0, -suffix.length) + newTail.trim();
|
|
68
|
+
// The prefix changed exactly when the system block's text did.
|
|
69
|
+
return replaceSystemMessageContent(session, block, next) && next !== content;
|
|
70
|
+
}
|
|
@@ -74,8 +74,6 @@ function schemaOmittedToolNames(toolsForRouting, tools) {
|
|
|
74
74
|
export function resolveSessionToolSurface(opts, { profile, toolPreset, modelName }) {
|
|
75
75
|
const ownerIsAgent = isAgentOwner(opts.owner);
|
|
76
76
|
const resolvedAgent = opts.agent || opts.role || profile?.taskType || null;
|
|
77
|
-
const hiddenAgent = getHiddenAgent(resolvedAgent);
|
|
78
|
-
const isRetrievalAgent = hiddenAgent?.kind === 'retrieval';
|
|
79
77
|
const hasCallerAllow = Array.isArray(opts.schemaAllowedTools);
|
|
80
78
|
const schemaAllowedTools = honoredSchemaAllowlist(opts.schemaAllowedTools, { ownerIsAgent, agent: resolvedAgent });
|
|
81
79
|
// Lead and Agent share the same cwd-scoped Skill inventory. A session that
|
|
@@ -112,7 +110,6 @@ export function resolveSessionToolSurface(opts, { profile, toolPreset, modelName
|
|
|
112
110
|
return {
|
|
113
111
|
ownerIsAgent,
|
|
114
112
|
resolvedAgent,
|
|
115
|
-
agentRulesProfile: isRetrievalAgent ? 'retrieval' : 'full',
|
|
116
113
|
skills,
|
|
117
114
|
sessionDeny,
|
|
118
115
|
toolPermission,
|
|
@@ -91,6 +91,11 @@ const ALL_BUILTIN_SESSION_TOOLS = orderSessionTools(
|
|
|
91
91
|
_dedupByName([...BUILTIN_TOOLS, ...PATCH_TOOL_DEFS, ...CODE_GRAPH_TOOL_DEFS])
|
|
92
92
|
);
|
|
93
93
|
|
|
94
|
+
/** The read-only filesystem tools (`tools:readonly`), in session route order. */
|
|
95
|
+
export function readOnlyFilesystemTools() {
|
|
96
|
+
return ALL_BUILTIN_SESSION_TOOLS.filter((t) => READONLY_FS_TOOL_NAMES.has(t.name));
|
|
97
|
+
}
|
|
98
|
+
|
|
94
99
|
export function resolveSessionTools(
|
|
95
100
|
toolSpec,
|
|
96
101
|
skills,
|
|
@@ -154,7 +159,7 @@ function _computeBaseTools(toolSpec, mcp, skillTools) {
|
|
|
154
159
|
addMany(ALL_BUILTIN_SESSION_TOOLS.filter((t) => FILESYSTEM_TOOL_NAMES.has(t.name)));
|
|
155
160
|
break;
|
|
156
161
|
case 'tools:readonly':
|
|
157
|
-
addMany(
|
|
162
|
+
addMany(readOnlyFilesystemTools());
|
|
158
163
|
break;
|
|
159
164
|
case 'tools:shell':
|
|
160
165
|
case 'tools:analysis':
|
|
@@ -186,8 +191,7 @@ function _computeBaseTools(toolSpec, mcp, skillTools) {
|
|
|
186
191
|
case 'mcp':
|
|
187
192
|
return orderSessionTools(_dedupByName([...mcp, ...skillTools]));
|
|
188
193
|
case 'readonly': {
|
|
189
|
-
|
|
190
|
-
return orderSessionTools(_dedupByName([...readTools, ...mcp, ...skillTools]));
|
|
194
|
+
return orderSessionTools(_dedupByName([...readOnlyFilesystemTools(), ...mcp, ...skillTools]));
|
|
191
195
|
}
|
|
192
196
|
// 'full' and any unknown spec.
|
|
193
197
|
default:
|
|
@@ -195,8 +195,8 @@ function appendObservedTurnOutput(
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
function newInterruptionState() {
|
|
199
|
+
return {
|
|
200
200
|
responseStarted: false,
|
|
201
201
|
partialAssistantContent: '',
|
|
202
202
|
tombstonedAssistantContent: '',
|
|
@@ -213,7 +213,10 @@ export function createTurnInterruptionTracker() {
|
|
|
213
213
|
tombEpoch: 0,
|
|
214
214
|
callsEpoch: 0,
|
|
215
215
|
};
|
|
216
|
+
}
|
|
216
217
|
|
|
218
|
+
/** Streamed assistant text, including the tombstone of a retracted attempt. */
|
|
219
|
+
function textBufferMethods(state) {
|
|
217
220
|
return {
|
|
218
221
|
recordTextDelta(chunk) {
|
|
219
222
|
const value = String(chunk ?? '');
|
|
@@ -263,33 +266,12 @@ export function createTurnInterruptionTracker() {
|
|
|
263
266
|
state.tombEpoch += 1;
|
|
264
267
|
return true;
|
|
265
268
|
},
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
state.responseStarted = true;
|
|
273
|
-
state.partialReasoningContent += value;
|
|
274
|
-
},
|
|
275
|
-
recordAssistantText(text) {
|
|
276
|
-
const value = String(text ?? '');
|
|
277
|
-
if (!value.trim()) return;
|
|
278
|
-
state.responseStarted = true;
|
|
279
|
-
// Buffered providers report the whole segment here; streaming
|
|
280
|
-
// providers already accumulated the same segment via text deltas.
|
|
281
|
-
if (!state.partialAssistantContent.trim()) state.partialAssistantContent += value;
|
|
282
|
-
},
|
|
283
|
-
markAssistantMessageCommitted() {
|
|
284
|
-
state.partialAssistantContent = '';
|
|
285
|
-
state.tombstonedAssistantContent = '';
|
|
286
|
-
state.partialReasoningContent = '';
|
|
287
|
-
state.observedToolCalls.clear();
|
|
288
|
-
state.textEpoch += 1;
|
|
289
|
-
state.reasoningEpoch += 1;
|
|
290
|
-
state.tombEpoch += 1;
|
|
291
|
-
state.callsEpoch += 1;
|
|
292
|
-
},
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Tool calls and early-notified results observed during the turn. */
|
|
273
|
+
function toolObservationMethods(state) {
|
|
274
|
+
return {
|
|
293
275
|
recordToolCalls(calls, { eagerStarted = false } = {}) {
|
|
294
276
|
for (const call of Array.isArray(calls) ? calls : []) {
|
|
295
277
|
if (!call?.id) continue;
|
|
@@ -317,6 +299,42 @@ export function createTurnInterruptionTracker() {
|
|
|
317
299
|
state.observedToolResults.delete(callId);
|
|
318
300
|
}
|
|
319
301
|
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export function createTurnInterruptionTracker() {
|
|
306
|
+
const state = newInterruptionState();
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
...textBufferMethods(state),
|
|
310
|
+
...toolObservationMethods(state),
|
|
311
|
+
hasResponseStarted() {
|
|
312
|
+
return state.responseStarted;
|
|
313
|
+
},
|
|
314
|
+
recordReasoningDelta(chunk) {
|
|
315
|
+
const value = String(chunk ?? '');
|
|
316
|
+
if (!value) return;
|
|
317
|
+
state.responseStarted = true;
|
|
318
|
+
state.partialReasoningContent += value;
|
|
319
|
+
},
|
|
320
|
+
recordAssistantText(text) {
|
|
321
|
+
const value = String(text ?? '');
|
|
322
|
+
if (!value.trim()) return;
|
|
323
|
+
state.responseStarted = true;
|
|
324
|
+
// Buffered providers report the whole segment here; streaming
|
|
325
|
+
// providers already accumulated the same segment via text deltas.
|
|
326
|
+
if (!state.partialAssistantContent.trim()) state.partialAssistantContent += value;
|
|
327
|
+
},
|
|
328
|
+
markAssistantMessageCommitted() {
|
|
329
|
+
state.partialAssistantContent = '';
|
|
330
|
+
state.tombstonedAssistantContent = '';
|
|
331
|
+
state.partialReasoningContent = '';
|
|
332
|
+
state.observedToolCalls.clear();
|
|
333
|
+
state.textEpoch += 1;
|
|
334
|
+
state.reasoningEpoch += 1;
|
|
335
|
+
state.tombEpoch += 1;
|
|
336
|
+
state.callsEpoch += 1;
|
|
337
|
+
},
|
|
320
338
|
markProviderSendStarted() {
|
|
321
339
|
state.phase = 'streaming';
|
|
322
340
|
},
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// manager/turn-reap.mjs
|
|
2
|
+
// A turn abandoned by a timeout or stall stops the background shell work that
|
|
3
|
+
// turn started — a job auto-promoted during it, and the survivors its commands
|
|
4
|
+
// left running. Only those: a user cancel, a steering interrupt, a normal
|
|
5
|
+
// finish, and jobs from earlier turns keep their jobs. Only the entry's own
|
|
6
|
+
// turn start is armed, and a new turn clears it, so a reap that runs late
|
|
7
|
+
// never touches a newer turn's work.
|
|
8
|
+
import { cancelBackgroundTasks, getBackgroundTask } from '../../../../shared/background-tasks.mjs';
|
|
9
|
+
import { runtimeState } from './runtime-state.mjs';
|
|
10
|
+
|
|
11
|
+
// Timeout ownership is explicit and turn-scoped: the code that makes a timeout
|
|
12
|
+
// WIN (the watchdog's own abort, the provider's terminal error) arms the reap
|
|
13
|
+
// itself, and only while nothing else has stopped the turn. An abort that
|
|
14
|
+
// arrives first stays a cancel; an error chain is never read afterwards.
|
|
15
|
+
|
|
16
|
+
// Codes of the runtime's own timeout/stall errors (stall-policy's
|
|
17
|
+
// streamStalledError / providerTimeoutError, the Gemini stream timeout).
|
|
18
|
+
const PROVIDER_TIMEOUT_CODES = new Set(['ESTREAMSTALL', 'EPROVIDERTIMEOUT', 'EGEMINITIMEOUT']);
|
|
19
|
+
|
|
20
|
+
/** A timeout is the first thing to stop this session's turn: arm its reap now,
|
|
21
|
+
* before the abort propagates. No-op when the turn's controller is already
|
|
22
|
+
* aborted (a cancel, interrupt or close won) or no turn runs. */
|
|
23
|
+
export function armTurnTimeout(id) {
|
|
24
|
+
const entry = runtimeState.get(id);
|
|
25
|
+
if (!entry || entry.controller?.signal.aborted) return;
|
|
26
|
+
armTurnShellReap(id, entry);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The turn ended with a provider timeout/stall error that no retry recovered
|
|
30
|
+
* from: arm only while the turn's own signal is un-aborted and the error
|
|
31
|
+
* itself carries a timeout code or the producer's own `streamStalled` flag. */
|
|
32
|
+
export function armTurnTimeoutOnProviderError(id, entry, turnSignal, err) {
|
|
33
|
+
if (turnSignal?.aborted) return;
|
|
34
|
+
if (!PROVIDER_TIMEOUT_CODES.has(err?.code) && err?.streamStalled !== true) return;
|
|
35
|
+
armTurnShellReap(id, entry);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// session id -> jobs stopped by a timeout reap, until the owner's handoff
|
|
39
|
+
// reports them (or the session's next turn starts).
|
|
40
|
+
const stoppedJobs = new Map();
|
|
41
|
+
|
|
42
|
+
// What the cancel path already produces, read without waiting: a task whose
|
|
43
|
+
// own cancel hook kills (survivors of a finished command) answers with its
|
|
44
|
+
// kill outcome; a promoted job is over once its process tree is no longer
|
|
45
|
+
// tracked.
|
|
46
|
+
function trackStoppedJob(taskId) {
|
|
47
|
+
const job = { taskId, outcome: null, terminated: false };
|
|
48
|
+
const kill = getBackgroundTask(taskId)?.cancelOutcome;
|
|
49
|
+
if (kill) {
|
|
50
|
+
job.outcome = kill;
|
|
51
|
+
Promise.resolve(kill).then(
|
|
52
|
+
(result) => {
|
|
53
|
+
job.terminated = result?.terminated === true;
|
|
54
|
+
},
|
|
55
|
+
() => {}
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
return job;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// shell-jobs depends on the session manager, which loads this module, so it is
|
|
62
|
+
// loaded at the first reap. The classification awaits only this module load,
|
|
63
|
+
// never a process; a probe that cannot be loaded leaves a job "still stopping".
|
|
64
|
+
let shellJobProbe = null;
|
|
65
|
+
function loadShellJobProbe() {
|
|
66
|
+
shellJobProbe ??= import('../../tools/builtin/shell-jobs.mjs').then(
|
|
67
|
+
(shellJobs) => shellJobs.isShellJobRunning,
|
|
68
|
+
() => null
|
|
69
|
+
);
|
|
70
|
+
return shellJobProbe;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Confirmed by the runtime's own state, never assumed: a task whose cancel hook
|
|
74
|
+
// kills is confirmed by that kill's `terminated`; a promoted job once neither
|
|
75
|
+
// its native task nor its process-tree tracker is live. Without the probe
|
|
76
|
+
// (shell-jobs not loaded) nothing is confirmed.
|
|
77
|
+
function isConfirmedGone(job, isRunning) {
|
|
78
|
+
if (job.outcome) return job.terminated;
|
|
79
|
+
return Boolean(isRunning) && !isRunning(job.taskId);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function reap(id, entry) {
|
|
83
|
+
loadShellJobProbe();
|
|
84
|
+
const { taskIds } = cancelBackgroundTasks({
|
|
85
|
+
surface: 'shell',
|
|
86
|
+
executionSessionId: id,
|
|
87
|
+
startedSinceMs: entry.shellReapSince,
|
|
88
|
+
reason: 'turn-timeout',
|
|
89
|
+
notify: false,
|
|
90
|
+
});
|
|
91
|
+
if (taskIds.length > 0) stoppedJobs.set(id, [...(stoppedJobs.get(id) || []), ...taskIds.map(trackStoppedJob)]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The turn is being abandoned by a timeout: remember when it started and stop
|
|
95
|
+
* what it has started so far. A settled (idle) entry has no turn to reap. */
|
|
96
|
+
export function armTurnShellReap(id, entry) {
|
|
97
|
+
if (!(entry?.askStartedAt > 0) || entry.closed) return;
|
|
98
|
+
entry.shellReapSince = entry.askStartedAt;
|
|
99
|
+
reap(id, entry);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The abandoned turn has unwound: sweep what it registered while stopping
|
|
103
|
+
* (survivors of its aborted commands). No-op unless this turn was armed. */
|
|
104
|
+
export function reapTurnShellJobs(id, entry) {
|
|
105
|
+
if (entry?.shellReapSince > 0 && !entry.closed && runtimeState.get(id) === entry) reap(id, entry);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** A new turn owns the session: nothing earlier may be reaped on its account. */
|
|
109
|
+
export function resetTurnShellReap(id, entry) {
|
|
110
|
+
entry.shellReapSince = null;
|
|
111
|
+
stoppedJobs.delete(id);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The jobs the reap stopped, split by what is known now: `stopped` are
|
|
115
|
+
* confirmed gone, `stopping` were killed but their processes are not yet
|
|
116
|
+
* confirmed gone (they keep being terminated). */
|
|
117
|
+
export async function takeStoppedShellJobs(id) {
|
|
118
|
+
const jobs = stoppedJobs.get(id) || [];
|
|
119
|
+
stoppedJobs.delete(id);
|
|
120
|
+
if (jobs.length === 0) return { stopped: [], stopping: [] };
|
|
121
|
+
const isRunning = await loadShellJobProbe();
|
|
122
|
+
const taskIds = (confirmed) =>
|
|
123
|
+
jobs.filter((job) => isConfirmedGone(job, isRunning) === confirmed).map((job) => job.taskId);
|
|
124
|
+
return { stopped: taskIds(true), stopping: taskIds(false) };
|
|
125
|
+
}
|
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
// Every model- or user-facing string that names it reads this, re-read on each
|
|
4
4
|
// use so a rename applies at once. Text shared across agents (tool schemas,
|
|
5
5
|
// other agents' shared prompt block) says "the representative agent" instead,
|
|
6
|
-
// so a rename never changes cached bytes.
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
// so a rename never changes those cached bytes. Each other bot's own contact
|
|
7
|
+
// catalog (workflow/context.mjs) names her, so a request naming her finds her.
|
|
8
|
+
// Light imports only: the prompt's contact catalog (workflow/context.mjs) reads
|
|
9
|
+
// the name too, and must not pull the skill catalog and config in with it.
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { resolvePluginData } from '../../../shared/plugin-paths.mjs';
|
|
9
13
|
import { mixyIdentityDir } from '../../../shared/agent-store.mjs';
|
|
10
14
|
|
|
11
15
|
export const DEFAULT_MIXY_NAME = 'Mixy';
|
|
@@ -19,9 +23,11 @@ export function mixyNameOf(manifest) {
|
|
|
19
23
|
export function mixyDisplayName() {
|
|
20
24
|
try {
|
|
21
25
|
// bots/mixy once Mixy is its own bot, agents/lead before (agent-store.mjs).
|
|
22
|
-
const dir = mixyIdentityDir(
|
|
23
|
-
return mixyNameOf(JSON.parse(
|
|
26
|
+
const dir = mixyIdentityDir(resolvePluginData());
|
|
27
|
+
return mixyNameOf(JSON.parse(readFileSync(join(dir, 'agent.json'), 'utf8')));
|
|
24
28
|
} catch {
|
|
29
|
+
// Never throws: prompt composition calls this unguarded, and the name only labels Mixy.
|
|
30
|
+
// A missing, empty, unreadable or malformed agent.json is the unrenamed default.
|
|
25
31
|
return DEFAULT_MIXY_NAME;
|
|
26
32
|
}
|
|
27
33
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Child process of restart-prefix-parity.test.mjs: one phase of a scripted
|
|
1
|
+
// Child process of restart-prefix-parity.slow.test.mjs: one phase of a scripted
|
|
2
2
|
// anthropic-oauth session in its own process, so a "restart" is a real new
|
|
3
3
|
// process reading the data dir the previous one left. The fake provider
|
|
4
4
|
// records the request body the real OAuth builder makes for every main-loop
|