mixdog 1.3.1 → 1.3.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/README.md +8 -4
- package/package.json +2 -2
- package/scripts/native-release-status.mjs +238 -0
- package/src/defaults/shipped-history.json +5 -1
- package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
- package/src/defaults/skills/setup/SKILL.md +23 -1
- package/src/defaults/skills/setup/references/actions.md +50 -3
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +7 -3
- package/src/defaults/skills/visualize/SKILL.md +9 -6
- package/src/defaults/skills/visualize/references/craft.md +8 -1
- package/src/help.mjs +1 -1
- package/src/lib/keychain-cjs.cjs +4 -1
- package/src/lib/rules-builder.cjs +14 -7
- package/src/rules/agent-mode/AGENT_MODE.md +8 -5
- package/src/rules/agent-mode/MIXY.md +6 -8
- package/src/rules/lead/LEAD.md +2 -2
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
- package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
- package/src/runtime/agent/orchestrator/config.mjs +11 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
- package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +80 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +67 -38
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
- package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
- package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
- package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +12 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +17 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +133 -38
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +14 -11
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +68 -18
- package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +136 -32
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +21 -9
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +189 -105
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +38 -5
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +99 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +3 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +42 -10
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +120 -9
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +36 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +35 -13
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -14
- package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +34 -21
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
- package/src/runtime/attachments/attachment-reference.mjs +155 -0
- package/src/runtime/attachments/limits.mjs +5 -1
- package/src/runtime/attachments/office-extract.mjs +3 -6
- package/src/runtime/attachments/pdf-extract.mjs +84 -10
- package/src/runtime/attachments/store.mjs +49 -30
- package/src/runtime/browser-bridge/client.mjs +73 -20
- package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
- package/src/runtime/channels/lib/scheduler.mjs +14 -7
- package/src/runtime/channels/lib/state-file.mjs +15 -15
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
- package/src/runtime/channels/lib/worker-main.mjs +3 -2
- package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
- package/src/runtime/effort-judge/judge-client.mjs +5 -2
- package/src/runtime/effort-judge/model-install.mjs +16 -8
- package/src/runtime/local-provider/asset-installer.mjs +10 -4
- package/src/runtime/local-provider/catalog.mjs +5 -2
- package/src/runtime/local-provider/registered-models.mjs +64 -27
- package/src/runtime/local-provider/server.mjs +2 -3
- package/src/runtime/media/adapters/image-api.mjs +89 -0
- package/src/runtime/media/auth.mjs +64 -1
- package/src/runtime/media/catalog.mjs +66 -4
- package/src/runtime/media/jobs.mjs +4 -0
- package/src/runtime/media/lanes.mjs +46 -5
- package/src/runtime/media/media-usage.mjs +17 -0
- package/src/runtime/media/renditions.mjs +15 -15
- package/src/runtime/media/store.mjs +36 -35
- package/src/runtime/media/tool.mjs +8 -1
- package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
- package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
- package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
- package/src/runtime/memory/lib/pg/process.mjs +8 -4
- package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
- package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
- package/src/runtime/office/core/journal.mjs +7 -14
- package/src/runtime/office/design/library/design-library-core.mjs +4 -16
- package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
- package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
- package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
- package/src/runtime/office/pdf/pdf-render.mjs +30 -18
- package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +4 -0
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
- package/src/runtime/shared/agent-message-envelope.mjs +44 -0
- package/src/runtime/shared/agent-reap-state.d.mts +4 -0
- package/src/runtime/shared/agent-store.mjs +24 -7
- package/src/runtime/shared/agent-task-starts.mjs +27 -0
- package/src/runtime/shared/atomic-file.d.mts +50 -0
- package/src/runtime/shared/atomic-file.mjs +394 -132
- package/src/runtime/shared/background-tasks.mjs +7 -4
- package/src/runtime/shared/bot-hops.mjs +30 -0
- package/src/runtime/shared/bot-split-migration.mjs +1 -1
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/defaults-separation.mjs +6 -2
- package/src/runtime/shared/delegated-approval-host.mjs +74 -0
- package/src/runtime/shared/err-text.mjs +4 -0
- package/src/runtime/shared/error-presentation.mjs +22 -4
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/process-lifecycle.mjs +8 -12
- package/src/runtime/shared/projects.mjs +50 -41
- package/src/runtime/shared/provider-accounts.mjs +17 -12
- package/src/runtime/shared/routine-trigger.d.mts +6 -1
- package/src/runtime/shared/routine-trigger.mjs +14 -6
- package/src/runtime/shared/run-child.d.mts +3 -0
- package/src/runtime/shared/run-child.mjs +24 -3
- package/src/runtime/shared/session-baseline-store.mjs +8 -2
- package/src/runtime/shared/singleton-owner.mjs +7 -6
- package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
- package/src/runtime/shared/staged-update.mjs +4 -2
- package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
- package/src/runtime/shared/tool-execution-contract.mjs +6 -0
- package/src/runtime/shared/transcript-metadata.mjs +28 -3
- package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
- package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
- package/src/runtime/shared/turn-snapshot.mjs +44 -2
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +41 -42
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +269 -61
- package/src/runtime/shared/worktrees/registry.mjs +26 -26
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +555 -199
- package/src/session-runtime/agent-room-delivery.mjs +143 -36
- package/src/session-runtime/agent-task-sessions.mjs +667 -165
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +45 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +11 -1
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +2 -2
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +2 -2
- package/src/session-runtime/bot-status.mjs +432 -0
- package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
- package/src/session-runtime/config-lifecycle.mjs +60 -55
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/held-requests.mjs +36 -33
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +19 -4
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown.mjs +11 -3
- package/src/session-runtime/mcp-glue/connect.mjs +100 -186
- package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
- package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
- package/src/session-runtime/media-api.mjs +5 -2
- package/src/session-runtime/model-route/route-tuning.mjs +4 -1
- package/src/session-runtime/model-route/set-route.mjs +61 -1
- package/src/session-runtime/owned-automation-run.mjs +8 -1
- package/src/session-runtime/room-member-gate.mjs +16 -3
- package/src/session-runtime/route-resolution.mjs +16 -8
- package/src/session-runtime/route-state.mjs +1 -59
- package/src/session-runtime/routine-home-turn.mjs +5 -3
- package/src/session-runtime/runtime-bootstrap.mjs +5 -3
- package/src/session-runtime/runtime-paths.mjs +11 -5
- package/src/session-runtime/runtime-tunables.mjs +6 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
- package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
- package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
- package/src/session-runtime/services/agent-tool.mjs +6 -0
- package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
- package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
- package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
- package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
- package/src/session-runtime/services/plugin-admin.mjs +26 -26
- package/src/session-runtime/services/provider-admin.mjs +14 -4
- package/src/session-runtime/services/schedule-access.mjs +33 -4
- package/src/session-runtime/services/seeds.mjs +4 -3
- package/src/session-runtime/services/usage-dashboard.mjs +1 -1
- package/src/session-runtime/services/usage-stats-model.mjs +2 -1
- package/src/session-runtime/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +63 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +8 -2
- package/src/session-runtime/setup-tool/settings-contract.mjs +31 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
- package/src/session-runtime/skills-api.mjs +12 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +265 -0
- package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
- package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +165 -0
- package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
- package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
- package/src/session-runtime/tool-policy-refresh.mjs +47 -369
- package/src/session-runtime/tool-surface.mjs +5 -3
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +2 -1
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +519 -333
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +46 -46
- package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
- package/src/session-runtime/workspace/workspace-state.mjs +7 -6
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-session-control.mjs +51 -10
- package/src/standalone/daemon.mjs +28 -10
- package/src/standalone/local-session-runtime.mjs +22 -14
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-service.mjs +11 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +35 -9
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
- package/src/tui/dist/index.mjs +529 -333
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/session-api/intake/abort.mjs +19 -1
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +75 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -247
- package/src/tui/session/session-api/settings.mjs +14 -1
- package/src/tui/session/session-flow/drain.mjs +28 -3
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
- package/src/tui/session/session-flow/steering.mjs +8 -3
- package/src/tui/session/tool-approval.mjs +185 -20
- package/src/tui/session/transcript-intake.mjs +2 -0
- package/src/tui/session/turn.mjs +23 -14
- package/src/tui/transcript-tool-failures.mjs +8 -2
- package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
- package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
- package/src/rules/agent-mode/ROUTINE.md +0 -6
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Unattended runs. A schedule or webhook run never asks (its saved routine is
|
|
3
|
+
* the user's grant; human-gate/run-policy.mjs), so only group-room members
|
|
4
|
+
* still use held requests: an approval-needing call is HELD instead of shown as
|
|
4
5
|
* a card: the run pauses on it, a structured held-request row lands in the
|
|
5
6
|
* owning agent's home thread (agent-home-delivery.mjs queue), a phone push
|
|
6
7
|
* says only "<agent>가 승인을 기다립니다" (no tool, arguments or text), and the
|
|
7
|
-
* request
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* request waits, like any approval, until the user answers it (Approve/Deny,
|
|
9
|
+
* through the ordinary approval call with the held id,
|
|
10
|
+
* runtime/shared/held-request-host.mjs) or the run is cancelled (Stop, abort,
|
|
11
|
+
* app quit), which denies it. It never expires on a timer.
|
|
10
12
|
*
|
|
11
13
|
* Importing this module installs the unattended port of human-gate/gate.mjs.
|
|
12
14
|
* Rooms: a room member session counts as unattended by its id; a surface that
|
|
@@ -23,20 +25,13 @@ import {
|
|
|
23
25
|
} from '../runtime/agent/orchestrator/session/human-gate/gate.mjs';
|
|
24
26
|
import { normalizeHumanResponse } from '../runtime/agent/orchestrator/session/human-gate/requests.mjs';
|
|
25
27
|
import { normalizeHeldRequest } from '../runtime/agent/orchestrator/session/human-gate/held-message.mjs';
|
|
28
|
+
import { delegationOf } from '../runtime/agent/orchestrator/session/human-gate/delegation.mjs';
|
|
26
29
|
import {
|
|
27
30
|
notifyHeldRequest,
|
|
28
31
|
recordRunOwner,
|
|
29
32
|
registerHeldRequestResolver,
|
|
30
33
|
} from '../runtime/shared/held-request-host.mjs';
|
|
31
34
|
|
|
32
|
-
/** Default expiry; MIXDOG_HELD_REQUEST_EXPIRY_MS overrides it. */
|
|
33
|
-
export const HELD_REQUEST_EXPIRY_MS = 5 * 60_000;
|
|
34
|
-
|
|
35
|
-
function configuredExpiryMs() {
|
|
36
|
-
const value = Number(process.env.MIXDOG_HELD_REQUEST_EXPIRY_MS);
|
|
37
|
-
return Number.isFinite(value) && value > 0 ? value : HELD_REQUEST_EXPIRY_MS;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
35
|
const runs = new Map(); // sessionId → { kind, agentId, name }
|
|
41
36
|
|
|
42
37
|
/** Mark `sessionId` as an unattended schedule/webhook run of `agentId`. */
|
|
@@ -54,12 +49,28 @@ export function markUnattendedRun(sessionId, { kind, agentId, name = '' }) {
|
|
|
54
49
|
};
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
/** The unattended run `sessionId` belongs to, or null for an attended session.
|
|
52
|
+
/** The unattended run `sessionId` belongs to, or null for an attended session.
|
|
53
|
+
* Work delegated from a run or a room (a sub-agent at any depth, a task
|
|
54
|
+
* session the bot created) belongs to it by the origin recorded on its own
|
|
55
|
+
* session record when it was created (human-gate/delegation.mjs) — however
|
|
56
|
+
* long ago that run ended, across restarts: its approvals are held like the
|
|
57
|
+
* run's own. */
|
|
58
58
|
export function unattendedRunOf(sessionId) {
|
|
59
59
|
const run = runs.get(sessionId);
|
|
60
60
|
if (run) return run;
|
|
61
61
|
const member = roomMemberOfSession(sessionId);
|
|
62
|
-
|
|
62
|
+
if (member) return { kind: 'room', agentId: member.agentId, name: member.roomId };
|
|
63
|
+
const delegation = delegationOf(sessionId);
|
|
64
|
+
if (delegation.state !== 'resolved') return null;
|
|
65
|
+
if (delegation.via === 'run') {
|
|
66
|
+
return {
|
|
67
|
+
kind: delegation.run.kind === 'webhook' ? 'webhook' : 'schedule',
|
|
68
|
+
agentId: delegation.rootAgentId,
|
|
69
|
+
name: String(delegation.run.name || ''),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const root = delegation.via === 'room' ? roomMemberOfSession(delegation.rootSessionId) : null;
|
|
73
|
+
return root ? { kind: 'room', agentId: root.agentId, name: root.roomId } : null;
|
|
63
74
|
}
|
|
64
75
|
|
|
65
76
|
/**
|
|
@@ -98,9 +109,7 @@ export function createHeldRequests({
|
|
|
98
109
|
push = notifyHeldRequest,
|
|
99
110
|
record = recordHumanDecision,
|
|
100
111
|
agentName = defaultAgentName,
|
|
101
|
-
expiryMs = configuredExpiryMs,
|
|
102
112
|
runOf = unattendedRunOf,
|
|
103
|
-
now = Date.now,
|
|
104
113
|
log = (line) => process.stderr.write(`mixdog held-requests: ${line}\n`),
|
|
105
114
|
}) {
|
|
106
115
|
const pending = new Map();
|
|
@@ -113,7 +122,6 @@ export function createHeldRequests({
|
|
|
113
122
|
const entry = pending.get(id);
|
|
114
123
|
if (!entry) return false;
|
|
115
124
|
pending.delete(id);
|
|
116
|
-
clearTimeout(entry.timer);
|
|
117
125
|
entry.release();
|
|
118
126
|
void post(entry.agentId, { ...entry.held, status, ...(approval.device ? { device: approval.device } : {}) });
|
|
119
127
|
void Promise.resolve()
|
|
@@ -123,11 +131,10 @@ export function createHeldRequests({
|
|
|
123
131
|
return true;
|
|
124
132
|
}
|
|
125
133
|
|
|
126
|
-
/** Hold `request` (the approval hook's payload) until answered or
|
|
134
|
+
/** Hold `request` (the approval hook's payload) until answered or the run is cancelled. */
|
|
127
135
|
function hold(request = {}, { signal } = {}) {
|
|
128
136
|
const run = runOf(request.sessionId) || { kind: 'schedule', agentId: MIXY_AGENT_ID, name: '' };
|
|
129
137
|
const id = `held_${randomUUID()}`;
|
|
130
|
-
const ms = typeof expiryMs === 'function' ? expiryMs() : expiryMs;
|
|
131
138
|
const held = normalizeHeldRequest({
|
|
132
139
|
id,
|
|
133
140
|
status: 'pending',
|
|
@@ -145,12 +152,13 @@ export function createHeldRequests({
|
|
|
145
152
|
details: request.outbound?.details,
|
|
146
153
|
}
|
|
147
154
|
: {}),
|
|
148
|
-
|
|
155
|
+
// An unattended run never remembers: its held row offers once only.
|
|
156
|
+
remember: ['once'],
|
|
149
157
|
run: { kind: run.kind, name: run.name, sessionId: request.sessionId },
|
|
150
|
-
expiresAt: now() + ms,
|
|
151
158
|
});
|
|
152
|
-
const shape = { kind: held.kind, outbound: request.outbound, remember:
|
|
159
|
+
const shape = { kind: held.kind, outbound: request.outbound, remember: ['once'] };
|
|
153
160
|
const gate = {
|
|
161
|
+
remember: ['once'],
|
|
154
162
|
agentId: run.agentId,
|
|
155
163
|
kind: held.kind,
|
|
156
164
|
...(held.action ? { action: held.action } : {}),
|
|
@@ -167,17 +175,7 @@ export function createHeldRequests({
|
|
|
167
175
|
agentId: run.agentId,
|
|
168
176
|
resolve,
|
|
169
177
|
release: () => signal?.removeEventListener?.('abort', onAbort),
|
|
170
|
-
timer: setTimeout(
|
|
171
|
-
() =>
|
|
172
|
-
settle(
|
|
173
|
-
id,
|
|
174
|
-
{ ...normalizeHumanResponse(shape, false), reason: 'held request expired', timedOut: true },
|
|
175
|
-
'expired'
|
|
176
|
-
),
|
|
177
|
-
ms
|
|
178
|
-
),
|
|
179
178
|
};
|
|
180
|
-
entry.timer.unref?.();
|
|
181
179
|
pending.set(id, entry);
|
|
182
180
|
void post(run.agentId, held);
|
|
183
181
|
try {
|
|
@@ -219,6 +217,11 @@ function heldRequests() {
|
|
|
219
217
|
return processHeld;
|
|
220
218
|
}
|
|
221
219
|
|
|
220
|
+
/** The held requests still waiting for an answer (session bots reads them). */
|
|
221
|
+
export function pendingHeldRequests() {
|
|
222
|
+
return processHeld ? processHeld.pending() : [];
|
|
223
|
+
}
|
|
224
|
+
|
|
222
225
|
/** Hold one request for its session's agent (rooms call this from their own hook). */
|
|
223
226
|
export function holdApprovalRequest(request, options) {
|
|
224
227
|
return heldRequests().hold(request, options);
|
|
@@ -6,6 +6,8 @@ import { executeTerminalTool } from '../../runtime/terminal-bridge/client.mjs';
|
|
|
6
6
|
import { executeVisualizeTool } from '../../runtime/visualize-bridge/client.mjs';
|
|
7
7
|
import { featureEnvOverride, moduleEnabled } from '../../runtime/agent/orchestrator/runtime-core/config-helpers.mjs';
|
|
8
8
|
import { createCallerContextResolvers } from './caller-context.mjs';
|
|
9
|
+
import { unattendedApprovalPort } from '../../runtime/agent/orchestrator/session/human-gate/unattended-port.mjs';
|
|
10
|
+
import { isGrantedRun } from '../../runtime/agent/orchestrator/session/human-gate/run-policy.mjs';
|
|
9
11
|
|
|
10
12
|
export function createBridgeToolHandlers({ rt }) {
|
|
11
13
|
const { sessionIdFor, signalFor } = createCallerContextResolvers(rt);
|
|
@@ -19,9 +21,16 @@ export function createBridgeToolHandlers({ rt }) {
|
|
|
19
21
|
if (environmentDisabled(callerCtx, 'MIXDOG_FEATURE_BROWSER')) {
|
|
20
22
|
throw new Error('the browser tool is disabled in this environment');
|
|
21
23
|
}
|
|
24
|
+
const sessionId = sessionIdFor(callerCtx);
|
|
25
|
+
const run = unattendedApprovalPort()?.runOf?.(sessionId);
|
|
22
26
|
return await executeBrowserTool(args, {
|
|
23
27
|
tool: name,
|
|
24
|
-
sessionId
|
|
28
|
+
sessionId,
|
|
29
|
+
// A schedule/webhook run never asks for form submits, posts or uploads;
|
|
30
|
+
// the bot that owns the run comes from the run's record, so its `block`
|
|
31
|
+
// applies whatever the display metadata says.
|
|
32
|
+
unattendedRun: isGrantedRun(run),
|
|
33
|
+
unattendedAgent: run?.agentId || '',
|
|
25
34
|
turnId: callerCtx?.turnId || rt.session?.usageMetricsTurnId,
|
|
26
35
|
signal: signalFor(callerCtx),
|
|
27
36
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Optional feature tools gated by settings for model-initiated calls: office,
|
|
2
2
|
// media and tidy (each loaded on first use), and the setup tool.
|
|
3
|
-
import {
|
|
3
|
+
import { standaloneDataDir } from '../runtime-paths.mjs';
|
|
4
4
|
import { createCallerContextResolvers } from './caller-context.mjs';
|
|
5
5
|
|
|
6
6
|
export function createFeatureToolHandlers({ rt, setupTool, officeToolsEnabled, mediaToolEnabled, tidyToolEnabled }) {
|
|
@@ -17,7 +17,7 @@ export function createFeatureToolHandlers({ rt, setupTool, officeToolsEnabled, m
|
|
|
17
17
|
const { executeOfficeTool } = await import('../../runtime/office/index.mjs');
|
|
18
18
|
return await executeOfficeTool(args, {
|
|
19
19
|
cwd: callerCwd,
|
|
20
|
-
dataDir:
|
|
20
|
+
dataDir: standaloneDataDir(),
|
|
21
21
|
requestApproval: callerCtx?.toolApprovalHook,
|
|
22
22
|
sessionId: callerCtx?.sessionId,
|
|
23
23
|
toolCallId: callerCtx?.toolCallId,
|
|
@@ -7,18 +7,20 @@ import { applySessionSidebarChange } from '../../runtime/shared/session-sidebar-
|
|
|
7
7
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
8
8
|
import { AGENT_MODE, resolveSessionMode } from '../../runtime/agent/orchestrator/session/agent-mode.mjs';
|
|
9
9
|
import { agentIdOfHomeSession } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
10
|
+
import { turnHopOf } from '../../runtime/shared/bot-hops.mjs';
|
|
10
11
|
import { scheduleCallerScope } from '../services/schedule-access.mjs';
|
|
11
12
|
import { resolveHandoffAttachments, sessionRoots } from '../handoff-attachments.mjs';
|
|
12
13
|
|
|
13
14
|
const USER_TITLE_ERROR = 'session: the user already titled this session; the title was not changed';
|
|
14
15
|
|
|
15
|
-
/** The agent an attended agent conversation (an agent's home thread
|
|
16
|
+
/** The agent an attended agent conversation (an agent's home thread, or its
|
|
17
|
+
* member session in a group room, where the user is present too) acts as;
|
|
16
18
|
* '' for every other caller: delegated workers, coding sessions (task
|
|
17
19
|
* sessions included) and unattended schedule/webhook runs. */
|
|
18
20
|
function attendedAgentOf(session) {
|
|
19
21
|
const { mode, agentId } = resolveSessionMode({ session });
|
|
20
22
|
const { kind } = scheduleCallerScope(session);
|
|
21
|
-
return mode === AGENT_MODE && (kind === 'human' || kind === 'agent') ? agentId : '';
|
|
23
|
+
return mode === AGENT_MODE && (kind === 'human' || kind === 'agent' || kind === 'room-member') ? agentId : '';
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
/** The caller's `attachments` as stored prompt parts, resolved against its own
|
|
@@ -89,7 +91,10 @@ export function createWorkspaceToolHandlers({
|
|
|
89
91
|
const session = async (args, { callerCtx, callerCwd }) => {
|
|
90
92
|
const action = clean(args?.action || (args?.path ? 'set-project' : 'status')).toLowerCase();
|
|
91
93
|
const target = clean(args?.session_id);
|
|
92
|
-
if (
|
|
94
|
+
if (
|
|
95
|
+
['list', 'bots', 'read', 'send', 'cancel', 'delete', 'create'].includes(action) ||
|
|
96
|
+
(action === 'status' && target)
|
|
97
|
+
) {
|
|
93
98
|
const callerSessionId = assertLead(action, callerCtx);
|
|
94
99
|
const callerAgentId = attendedAgentOf(rt.session);
|
|
95
100
|
if (action === 'create' && !callerAgentId) {
|
|
@@ -117,7 +122,15 @@ export function createWorkspaceToolHandlers({
|
|
|
117
122
|
return JSON.stringify(
|
|
118
123
|
await executeSessionControl(
|
|
119
124
|
{ ...rest, action },
|
|
120
|
-
{
|
|
125
|
+
{
|
|
126
|
+
callerSessionId,
|
|
127
|
+
callerAgentId,
|
|
128
|
+
callerCwd,
|
|
129
|
+
...(action === 'send' || action === 'create' ? { callerHop: turnHopOf(rt.session) } : {}),
|
|
130
|
+
// Which bots and sessions it may see (bot-status.mjs).
|
|
131
|
+
...(action === 'bots' || action === 'list' ? { callerScope: scheduleCallerScope(rt.session) } : {}),
|
|
132
|
+
...(attachmentParts.length ? { attachmentParts } : {}),
|
|
133
|
+
}
|
|
121
134
|
)
|
|
122
135
|
);
|
|
123
136
|
}
|
|
@@ -252,6 +265,8 @@ export function createWorkspaceToolHandlers({
|
|
|
252
265
|
clientHostPid: callerCtx?.clientHostPid || rt.session?.clientHostPid || process.pid,
|
|
253
266
|
signal: callerCtx?.signal,
|
|
254
267
|
notifyFn: notifyFnForSession(callerSessionId),
|
|
268
|
+
// The jobs this call starts are recorded under it (agent-task-starts.mjs).
|
|
269
|
+
...(callerCtx?.toolCallId ? { toolCallId: callerCtx.toolCallId } : {}),
|
|
255
270
|
});
|
|
256
271
|
},
|
|
257
272
|
};
|
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
clean,
|
|
17
17
|
} from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
18
18
|
|
|
19
|
+
import {
|
|
20
|
+
incomingTailOf,
|
|
21
|
+
wantsIncomingTail,
|
|
22
|
+
} from '../../runtime/agent/orchestrator/session/store-summary-last-message.mjs';
|
|
19
23
|
import { isRealTurnMessage } from '../../runtime/agent/orchestrator/session/compact/user-message-kind.mjs';
|
|
20
24
|
import { realTurnCount as realTurnCountOf } from '../../runtime/agent/orchestrator/session/store-summary-fields.mjs';
|
|
21
25
|
|
|
@@ -44,6 +48,7 @@ function previewOf(s) {
|
|
|
44
48
|
let preview = isSessionPreviewNoise(rawPreview) ? '' : cleanSessionPreview(rawPreview);
|
|
45
49
|
let messageCount = Math.max(0, Number(s.messageCount) || 0);
|
|
46
50
|
let realTurnCount = realTurnCountOf(s);
|
|
51
|
+
let incomingTail = Array.isArray(s.incomingTail) ? s.incomingTail : null;
|
|
47
52
|
if (!preview && Array.isArray(s.messages)) {
|
|
48
53
|
realTurnCount = s.messages.filter(isRealTurnMessage).length;
|
|
49
54
|
const msgs = s.messages;
|
|
@@ -55,8 +60,9 @@ function previewOf(s) {
|
|
|
55
60
|
.filter(Boolean);
|
|
56
61
|
preview = userPreviews[0] || '';
|
|
57
62
|
messageCount = msgs.filter((m) => m && (m.role === 'user' || m.role === 'assistant')).length;
|
|
63
|
+
if (wantsIncomingTail(s.id)) incomingTail = incomingTailOf(msgs);
|
|
58
64
|
}
|
|
59
|
-
return { preview, messageCount, realTurnCount };
|
|
65
|
+
return { preview, messageCount, realTurnCount, incomingTail };
|
|
60
66
|
}
|
|
61
67
|
|
|
62
68
|
/** `working`: this session's turn is running in the daemon right now. */
|
|
@@ -70,7 +76,7 @@ export function leadSessionRow(s, working = false) {
|
|
|
70
76
|
// One-shot `mixdog exec` runs are never resumable conversations.
|
|
71
77
|
if (sourceType === 'exec') return null;
|
|
72
78
|
if (!agentSession && !isLeadShaped(s, owner, sourceType)) return null;
|
|
73
|
-
const { preview, messageCount, realTurnCount } = previewOf(s);
|
|
79
|
+
const { preview, messageCount, realTurnCount, incomingTail } = previewOf(s);
|
|
74
80
|
if (!preview && messageCount === 0) return null;
|
|
75
81
|
const lastMessageRoutine = normalizeRoutineProvenance(s.lastMessageRoutine);
|
|
76
82
|
return {
|
|
@@ -95,6 +101,10 @@ export function leadSessionRow(s, working = false) {
|
|
|
95
101
|
model: s.model,
|
|
96
102
|
provider: s.provider,
|
|
97
103
|
messageCount,
|
|
104
|
+
// Where the messages that arrived (not the user's own, not tool calls)
|
|
105
|
+
// sit among the counted ones: a bot row's unread pill counts those past
|
|
106
|
+
// the read cursor. Absent when unknown; clients then show one.
|
|
107
|
+
...(incomingTail ? { incomingTail } : {}),
|
|
98
108
|
title: cleanSessionPreview(s.title || '', 100),
|
|
99
109
|
preview,
|
|
100
110
|
// The latest user or assistant line (an agent contact's row shows it).
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { SessionClosedError } from '../../runtime/agent/orchestrator/session/manager/session-errors.mjs';
|
|
9
9
|
import { forgetSessionSaveBaseline } from '../../runtime/agent/orchestrator/session/store/save-worker.mjs';
|
|
10
10
|
import { flushAllIndexWrites } from '../services/agent-tool/index-write-queue.mjs';
|
|
11
|
+
import { PROCESS_RESTART_FAILURE } from '../services/agent-tool/worker-index/row-liveness.mjs';
|
|
11
12
|
import { unregisterLiveSession } from '../../runtime/shared/staged-update.mjs';
|
|
12
13
|
import { abortRuntime, closeCanonicalSession, closeOwnSession, dispatchSessionEnd } from './teardown/session-close.mjs';
|
|
13
14
|
import { settleAll, settleDetached, startRuntimeStops, startWorkStops } from './teardown/runtime-stops.mjs';
|
|
@@ -111,11 +112,14 @@ export function createTeardown(deps, { ingestSessionIntoMemory, closeSurfaceSess
|
|
|
111
112
|
function reapWork(reason, scope) {
|
|
112
113
|
if (!scope.teardownReapsWork) return;
|
|
113
114
|
try {
|
|
114
|
-
// A task that dies for a reason its owner never asked for must still be
|
|
115
|
+
// A task that dies for a reason its owner never asked for must still be
|
|
116
|
+
// reported: now for a scoped close; for a process exit (its owner is
|
|
117
|
+
// closing too) by the next process, which tells the owner of each agent
|
|
118
|
+
// turn the exit cut off (agent-tool restart-notify).
|
|
115
119
|
cancelBackgroundTasks(
|
|
116
120
|
scope.scopedTeardown
|
|
117
121
|
? { reason, notify: true, executionSessionId: scope.closingSessionId }
|
|
118
|
-
: { reason, notify: false }
|
|
122
|
+
: { reason, notify: false, terminalReason: PROCESS_RESTART_FAILURE }
|
|
119
123
|
);
|
|
120
124
|
} catch {}
|
|
121
125
|
}
|
|
@@ -204,7 +208,11 @@ export function createTeardown(deps, { ingestSessionIntoMemory, closeSurfaceSess
|
|
|
204
208
|
const settled = () => {
|
|
205
209
|
outstandingCloses.delete(closing);
|
|
206
210
|
};
|
|
207
|
-
|
|
211
|
+
// processExit: the workers close, their rows stay for the next process.
|
|
212
|
+
closing = new Promise((resolve) => resolve(agentTool.closeAll(reason, { processExit: true }))).then(
|
|
213
|
+
settled,
|
|
214
|
+
settled
|
|
215
|
+
);
|
|
208
216
|
outstandingCloses.add(closing);
|
|
209
217
|
try {
|
|
210
218
|
await withTeardownDeadline(closing, CLOSE_ALL_DEADLINE_MS, false);
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
// connect. All mutable progress lives on the caller-owned `state`.
|
|
4
4
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
5
5
|
import { envFlag } from '../../runtime/shared/env.mjs';
|
|
6
|
+
import { awaitInitialConnect } from './initial-connect-gate.mjs';
|
|
6
7
|
import { ensurePluginServerData } from './plugin-servers.mjs';
|
|
8
|
+
import { createServerConnection } from './server-connection.mjs';
|
|
7
9
|
|
|
8
10
|
export function createMcpConnect({
|
|
9
11
|
mcpClient,
|
|
@@ -29,58 +31,100 @@ export function createMcpConnect({
|
|
|
29
31
|
// Answer it with the redirect URL pasted from the browser.
|
|
30
32
|
const completeMcpLogin = (name, callbackUrl) => mcpClient.completeMcpLogin(clean(name), callbackUrl, scopeOptions());
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
await
|
|
48
|
-
|
|
34
|
+
const { applyMcpServerConnection, reconcileServers } = createServerConnection({
|
|
35
|
+
mcpClient,
|
|
36
|
+
state,
|
|
37
|
+
resolveEffectiveMcpServers,
|
|
38
|
+
getMcpScopeId,
|
|
39
|
+
scopeOptions,
|
|
40
|
+
applied,
|
|
41
|
+
fingerprint,
|
|
42
|
+
syncScopeRoot,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Wait for a prior run (its failures were already captured in state).
|
|
46
|
+
async function settled(prior) {
|
|
47
|
+
if (!prior) return;
|
|
48
|
+
try {
|
|
49
|
+
await prior;
|
|
50
|
+
} catch {
|
|
51
|
+
/* prior run's failures already captured */
|
|
49
52
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Register `run` as the in-flight connect so a later reset serializes
|
|
56
|
+
// behind it instead of interleaving disconnect/connect.
|
|
57
|
+
async function trackInFlight(run) {
|
|
58
|
+
state.mcpConnectInFlight = run;
|
|
53
59
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
target,
|
|
58
|
-
cfg,
|
|
59
|
-
login ? { interactive: true, openBrowser: login.openBrowser } : {}
|
|
60
|
-
);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
const failure = { name: target, msg: error?.message || String(error) };
|
|
63
|
-
if (error?.authRequired) failure.authRequired = true;
|
|
64
|
-
const failures = Array.isArray(error?.failures) ? error.failures : [failure];
|
|
65
|
-
state.mcpFailures = [...(state.mcpFailures || []), ...failures];
|
|
60
|
+
await run;
|
|
61
|
+
} finally {
|
|
62
|
+
if (state.mcpConnectInFlight === run) state.mcpConnectInFlight = null;
|
|
66
63
|
}
|
|
67
64
|
}
|
|
68
65
|
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
66
|
+
// Scoped single-server toggle (or reconcile): non-superseding. It must NEVER
|
|
67
|
+
// cancel a pending full {reset} (cwd-change/boot). So do not bump the
|
|
68
|
+
// generation; just wait for any in-flight run, then bail if a newer full
|
|
69
|
+
// reset has been requested in the meantime.
|
|
70
|
+
async function connectScoped({ only, enabled, reconcile, login }) {
|
|
71
|
+
// A disable/remove must not wait out an interactive login of the
|
|
72
|
+
// connect it queues behind: cancel that login first.
|
|
73
|
+
if (only && enabled === false) cancelMcpLogin(only);
|
|
74
|
+
// Atomically capture the current generation AND the prior in-flight
|
|
75
|
+
// promise in the same synchronous step, then chain our op onto it. No
|
|
76
|
+
// await sits between the capture and the `state.mcpConnectInFlight = run`
|
|
77
|
+
// assignment, so concurrent {only} calls queue FIFO instead of resuming
|
|
78
|
+
// together and clobbering the in-flight slot. We never bump the
|
|
79
|
+
// generation; a {reset} does, so any {only} queued behind a reset sees
|
|
80
|
+
// the newer generation when its turn comes and bails.
|
|
81
|
+
const gen = state.mcpConnectGeneration;
|
|
82
|
+
const prev = state.mcpConnectInFlight;
|
|
83
|
+
await trackInFlight(
|
|
84
|
+
(async () => {
|
|
85
|
+
await settled(prev);
|
|
86
|
+
if (gen !== state.mcpConnectGeneration) return;
|
|
87
|
+
if (reconcile) await reconcileServers();
|
|
88
|
+
else await applyMcpServerConnection(only, enabled, undefined, login);
|
|
89
|
+
})()
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Serialize reconnects: boot connect, cwd-change reset, and rapid cwd
|
|
94
|
+
// switches must never interleave their disconnect/connect phases, or an
|
|
95
|
+
// older run finishing after a newer reset could re-add stale servers into
|
|
96
|
+
// the shared client registry. Approach: a generation token + a single
|
|
97
|
+
// in-flight promise. Each call bumps the generation, waits for any prior
|
|
98
|
+
// run to finish, then bails if a newer call has superseded it — leaving the
|
|
99
|
+
// latest requested effective-server-set in the registry.
|
|
100
|
+
async function connectAll({ reset }) {
|
|
101
|
+
const gen = ++state.mcpConnectGeneration;
|
|
102
|
+
await settled(state.mcpConnectInFlight);
|
|
103
|
+
if (gen !== state.mcpConnectGeneration) return;
|
|
104
|
+
await trackInFlight(
|
|
105
|
+
(async () => {
|
|
106
|
+
if (reset) {
|
|
107
|
+
await mcpClient.disconnectAll?.(scopeOptions());
|
|
108
|
+
applied().clear();
|
|
109
|
+
}
|
|
110
|
+
state.mcpFailures = [];
|
|
111
|
+
syncScopeRoot();
|
|
112
|
+
const { servers } = resolveEffectiveMcpServers();
|
|
113
|
+
for (const [name, cfg] of Object.entries(servers)) {
|
|
114
|
+
if (cfg?.enabled === false) applied().delete(name);
|
|
115
|
+
else applied().set(name, fingerprint(cfg));
|
|
116
|
+
}
|
|
117
|
+
if (Object.keys(servers).length === 0) return;
|
|
118
|
+
try {
|
|
119
|
+
for (const cfg of Object.values(servers)) if (cfg?.enabled !== false) ensurePluginServerData(cfg);
|
|
120
|
+
await mcpClient.connectMcpServers(servers, scopeOptions());
|
|
121
|
+
} catch (error) {
|
|
122
|
+
state.mcpFailures = Array.isArray(error?.failures)
|
|
123
|
+
? error.failures
|
|
124
|
+
: [{ name: 'mcp', msg: error?.message || String(error) }];
|
|
125
|
+
}
|
|
126
|
+
})()
|
|
127
|
+
);
|
|
84
128
|
}
|
|
85
129
|
|
|
86
130
|
async function connectConfiguredMcp({
|
|
@@ -98,146 +142,16 @@ export function createMcpConnect({
|
|
|
98
142
|
else await mcpClient.disconnectAll?.(scopeOptions());
|
|
99
143
|
return mcpStatus();
|
|
100
144
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// just wait for any in-flight run, then bail if a newer full reset has
|
|
104
|
-
// been requested in the meantime. Registering as in-flight makes a later
|
|
105
|
-
// reset serialize behind us instead of interleaving disconnect/connect.
|
|
106
|
-
if (only || reconcile) {
|
|
107
|
-
// A disable/remove must not wait out an interactive login of the
|
|
108
|
-
// connect it queues behind: cancel that login first.
|
|
109
|
-
if (only && enabled === false) cancelMcpLogin(only);
|
|
110
|
-
// Atomically capture the current generation AND the prior in-flight
|
|
111
|
-
// promise in the same synchronous step, then chain our op onto it. No
|
|
112
|
-
// await sits between the capture and the `state.mcpConnectInFlight = run`
|
|
113
|
-
// assignment, so concurrent {only} calls queue FIFO instead of resuming
|
|
114
|
-
// together and clobbering the in-flight slot. We never bump the
|
|
115
|
-
// generation; a {reset} does, so any {only} queued behind a reset sees
|
|
116
|
-
// the newer generation when its turn comes and bails.
|
|
117
|
-
const gen = state.mcpConnectGeneration;
|
|
118
|
-
const prev = state.mcpConnectInFlight;
|
|
119
|
-
const run = (async () => {
|
|
120
|
-
if (prev) {
|
|
121
|
-
try {
|
|
122
|
-
await prev;
|
|
123
|
-
} catch {
|
|
124
|
-
/* prior run's failures already captured */
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (gen !== state.mcpConnectGeneration) return;
|
|
128
|
-
if (reconcile) await reconcileServers();
|
|
129
|
-
else await applyMcpServerConnection(only, enabled, undefined, login);
|
|
130
|
-
})();
|
|
131
|
-
state.mcpConnectInFlight = run;
|
|
132
|
-
try {
|
|
133
|
-
await run;
|
|
134
|
-
} finally {
|
|
135
|
-
if (state.mcpConnectInFlight === run) state.mcpConnectInFlight = null;
|
|
136
|
-
}
|
|
137
|
-
return mcpStatus();
|
|
138
|
-
}
|
|
139
|
-
// Serialize reconnects: boot connect, cwd-change reset, and rapid cwd
|
|
140
|
-
// switches must never interleave their disconnect/connect phases, or an
|
|
141
|
-
// older run finishing after a newer reset could re-add stale servers into
|
|
142
|
-
// the shared client registry. Approach: a generation token + a single
|
|
143
|
-
// in-flight promise. Each call bumps the generation, waits for any prior
|
|
144
|
-
// run to finish, then bails if a newer call has superseded it — leaving the
|
|
145
|
-
// latest requested effective-server-set in the registry.
|
|
146
|
-
const gen = ++state.mcpConnectGeneration;
|
|
147
|
-
if (state.mcpConnectInFlight) {
|
|
148
|
-
try {
|
|
149
|
-
await state.mcpConnectInFlight;
|
|
150
|
-
} catch {
|
|
151
|
-
/* prior run's failures already captured */
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (gen !== state.mcpConnectGeneration) return mcpStatus();
|
|
155
|
-
const run = (async () => {
|
|
156
|
-
if (reset) {
|
|
157
|
-
await mcpClient.disconnectAll?.(scopeOptions());
|
|
158
|
-
applied().clear();
|
|
159
|
-
}
|
|
160
|
-
state.mcpFailures = [];
|
|
161
|
-
syncScopeRoot();
|
|
162
|
-
const { servers } = resolveEffectiveMcpServers();
|
|
163
|
-
for (const [name, cfg] of Object.entries(servers)) {
|
|
164
|
-
if (cfg?.enabled === false) applied().delete(name);
|
|
165
|
-
else applied().set(name, fingerprint(cfg));
|
|
166
|
-
}
|
|
167
|
-
if (Object.keys(servers).length === 0) return;
|
|
168
|
-
try {
|
|
169
|
-
for (const cfg of Object.values(servers)) if (cfg?.enabled !== false) ensurePluginServerData(cfg);
|
|
170
|
-
await mcpClient.connectMcpServers(servers, scopeOptions());
|
|
171
|
-
} catch (error) {
|
|
172
|
-
state.mcpFailures = Array.isArray(error?.failures)
|
|
173
|
-
? error.failures
|
|
174
|
-
: [{ name: 'mcp', msg: error?.message || String(error) }];
|
|
175
|
-
}
|
|
176
|
-
})();
|
|
177
|
-
state.mcpConnectInFlight = run;
|
|
178
|
-
try {
|
|
179
|
-
await run;
|
|
180
|
-
} finally {
|
|
181
|
-
if (state.mcpConnectInFlight === run) state.mcpConnectInFlight = null;
|
|
182
|
-
}
|
|
145
|
+
if (only || reconcile) await connectScoped({ only, enabled, reconcile, login });
|
|
146
|
+
else await connectAll({ reset });
|
|
183
147
|
return mcpStatus();
|
|
184
148
|
}
|
|
185
149
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
let budgetMs = 10000;
|
|
194
|
-
try {
|
|
195
|
-
// The gate must outlast the slowest enabled server's own startup budget;
|
|
196
|
-
// a server with its budget disabled (0) means the connect may never
|
|
197
|
-
// settle, so the whole gate is disabled (handled below).
|
|
198
|
-
const configs = Object.values(resolveEffectiveMcpServers().servers).filter((cfg) => cfg?.enabled !== false);
|
|
199
|
-
const budgets = (configs.length > 0 ? configs : [{}])
|
|
200
|
-
.map((cfg) => mcpClient.resolveMcpStartupTimeoutMs?.(cfg))
|
|
201
|
-
.filter((value) => Number.isFinite(value));
|
|
202
|
-
if (budgets.length > 0) budgetMs = budgets.includes(0) ? 0 : Math.max(...budgets);
|
|
203
|
-
} catch {
|
|
204
|
-
/* fall back to default budget */
|
|
205
|
-
}
|
|
206
|
-
if (maxWaitMs !== null && maxWaitMs !== undefined) {
|
|
207
|
-
const requestedMaxWaitMs = Number(maxWaitMs);
|
|
208
|
-
if (Number.isFinite(requestedMaxWaitMs) && requestedMaxWaitMs >= 0) {
|
|
209
|
-
budgetMs = Math.min(budgetMs, requestedMaxWaitMs);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
// Budget disabled (0/off) = no per-server startup timeout, so the connect
|
|
213
|
-
// promise may never settle; never gate the turn on it — fall back to the
|
|
214
|
-
// legacy fire-and-forget behavior (late servers use the deferred path).
|
|
215
|
-
if (!(budgetMs > 0)) return;
|
|
216
|
-
let timer = null;
|
|
217
|
-
let expired = false;
|
|
218
|
-
const budget = new Promise((resolveBudget) => {
|
|
219
|
-
timer = setTimeout(() => {
|
|
220
|
-
expired = true;
|
|
221
|
-
resolveBudget();
|
|
222
|
-
}, budgetMs);
|
|
223
|
-
});
|
|
224
|
-
try {
|
|
225
|
-
// Follow replacement connects (a reconnect queued behind the captured
|
|
226
|
-
// run installs a new in-flight promise) inside ONE fixed deadline.
|
|
227
|
-
// Failures are already captured in state.mcpFailures, so rejections are
|
|
228
|
-
// swallowed: this gate must never reject the turn.
|
|
229
|
-
let current = inFlight;
|
|
230
|
-
while (current && !expired) {
|
|
231
|
-
await Promise.race([Promise.resolve(current).catch(() => {}), budget]);
|
|
232
|
-
if (expired) break;
|
|
233
|
-
// Let a queued reconnect install its promise before re-checking.
|
|
234
|
-
await Promise.race([new Promise((resolveTick) => setImmediate(resolveTick)), budget]);
|
|
235
|
-
current = state.mcpConnectInFlight;
|
|
236
|
-
}
|
|
237
|
-
} finally {
|
|
238
|
-
if (timer) clearTimeout(timer);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return { connectConfiguredMcp, awaitInitialMcpConnect, cancelMcpLogin, completeMcpLogin };
|
|
150
|
+
return {
|
|
151
|
+
connectConfiguredMcp,
|
|
152
|
+
awaitInitialMcpConnect: (maxWaitMs) =>
|
|
153
|
+
awaitInitialConnect({ state, mcpClient, resolveEffectiveMcpServers }, maxWaitMs),
|
|
154
|
+
cancelMcpLogin,
|
|
155
|
+
completeMcpLogin,
|
|
156
|
+
};
|
|
243
157
|
}
|