mixdog 1.3.5 → 1.4.1
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/NOTICE.md +2 -2
- package/README.md +2 -2
- package/package.json +2 -11
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/gate-local.mjs +16 -5
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +37 -37
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +123 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -4
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +20 -2
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +7 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/app.mjs +4 -0
- package/src/defaults/shipped-history.json +22 -1
- package/src/defaults/skills/browser-use/SKILL.md +62 -12
- package/src/defaults/skills/code-tidy/SKILL.md +142 -270
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
- package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
- package/src/defaults/skills/computer-use/SKILL.md +35 -9
- package/src/defaults/skills/setup/SKILL.md +22 -0
- package/src/defaults/skills/setup/references/actions.md +39 -5
- package/src/defaults/skills/setup/references/surfaces.md +11 -2
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/rules-builder.cjs +39 -20
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +11 -10
- package/src/rules/lead/LEAD.md +23 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/rules/shared/70-delivery.md +7 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +17 -1
- package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +73 -68
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +57 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
- package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +192 -133
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +159 -69
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +70 -33
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +25 -13
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +20 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/registry.mjs +38 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +49 -16
- package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +9 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +798 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +280 -45
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +51 -25
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +37 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +31 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +20 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +49 -21
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +130 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +81 -8
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -8
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +9 -4
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +21 -5
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +24 -9
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
- package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
- package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +81 -22
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +92 -3
- package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
- package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +79 -3
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +31 -6
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +110 -26
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
- package/src/runtime/browser-bridge/action-schema.mjs +13 -2
- package/src/runtime/browser-bridge/client.mjs +73 -8
- package/src/runtime/browser-bridge/input-fields.mjs +8 -9
- package/src/runtime/browser-bridge/mail-links.mjs +107 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
- package/src/runtime/channels/lib/config.mjs +6 -61
- package/src/runtime/channels/lib/crash-log.mjs +1 -1
- package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
- package/src/runtime/channels/lib/event-queue.mjs +3 -18
- package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
- package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
- package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
- package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
- package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
- package/src/runtime/channels/lib/scheduler.mjs +33 -147
- package/src/runtime/channels/lib/schedules-db.mjs +34 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- package/src/runtime/channels/lib/whisper-port.mjs +10 -1
- package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
- package/src/runtime/channels/lib/worker-main.mjs +10 -34
- package/src/runtime/computer-bridge/action-schema.mjs +42 -1
- package/src/runtime/computer-bridge/actions.mjs +9 -1
- package/src/runtime/computer-bridge/client.mjs +180 -8
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +28 -2
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
- package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
- package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
- package/src/runtime/connectors/gmail-app-password.mjs +172 -39
- package/src/runtime/connectors/google-mcp.mjs +10 -12
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
- package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
- package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/session-search/session-search-db.mjs +73 -9
- package/src/runtime/session-search/session-search-ingest.mjs +110 -20
- package/src/runtime/shared/abort-race.mjs +89 -0
- package/src/runtime/shared/agent-avatar.d.mts +0 -1
- package/src/runtime/shared/agent-kind.mjs +4 -3
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +2 -13
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +29 -0
- package/src/runtime/shared/connector-catalog.mjs +150 -0
- package/src/runtime/shared/connector-triggers.mjs +22 -19
- package/src/runtime/shared/defaults-separation.mjs +2 -17
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/err-text.mjs +24 -15
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-permissions.d.mts +0 -8
- package/src/runtime/shared/file-permissions.mjs +0 -11
- package/src/runtime/shared/git-direct.test-support.mjs +19 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
- package/src/runtime/shared/heartbeat-interval.mjs +19 -0
- package/src/runtime/shared/idle-auto-clear-gate.mjs +126 -0
- package/src/runtime/shared/llm/cost.mjs +5 -1
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/mixy-presence.mjs +22 -0
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/orchestration.d.mts +2 -0
- package/src/runtime/shared/pg-schema-db.mjs +27 -16
- package/src/runtime/shared/profile-config.cjs +1 -1
- package/src/runtime/shared/prompt-origin.d.mts +4 -0
- package/src/runtime/shared/prompt-origin.mjs +21 -0
- package/src/runtime/shared/provider-accounts.mjs +7 -1
- package/src/runtime/shared/provider-display-name.mjs +29 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
- package/src/runtime/shared/routine-trigger.d.mts +2 -0
- package/src/runtime/shared/routine-trigger.mjs +10 -0
- package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
- package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
- package/src/runtime/shared/session-activity-signal.mjs +48 -1
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
- package/src/runtime/shared/session-sidebar-host.mjs +7 -3
- package/src/runtime/shared/session-turn-prelude.mjs +18 -0
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +2 -15
- package/src/runtime/shared/tool-surface.mjs +3 -0
- package/src/runtime/shared/tool-work-units.mjs +2 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +15 -0
- package/src/runtime/shared/worktrees/manager.mjs +87 -38
- package/src/runtime/shared/worktrees/test-support.mjs +14 -13
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +29 -8
- package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
- package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
- package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
- package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
- package/src/session-runtime/agent-home-delivery.mjs +489 -185
- package/src/session-runtime/agent-task-sessions.mjs +467 -229
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/infrastructure.mjs +4 -0
- package/src/session-runtime/boot/providers.mjs +3 -0
- package/src/session-runtime/boot/tools.mjs +11 -2
- package/src/session-runtime/bot-status.mjs +12 -6
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/config-lifecycle.mjs +6 -0
- package/src/session-runtime/connector-merge-migration.mjs +305 -0
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +271 -25
- package/src/session-runtime/conversation-import/service.mjs +26 -5
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +144 -41
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
- package/src/session-runtime/lifecycle/teardown.mjs +23 -5
- package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +153 -33
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/notification-bus.mjs +31 -117
- package/src/session-runtime/notification-completion-queue.mjs +54 -0
- package/src/session-runtime/notification-listeners.mjs +76 -0
- package/src/session-runtime/owned-automation-run.mjs +2 -1
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +143 -224
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
- package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
- package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
- package/src/session-runtime/resource-mcp-servers.mjs +78 -0
- package/src/session-runtime/resource-mcp-store.mjs +49 -0
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +13 -4
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
- package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
- package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
- package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
- package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +7 -13
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/provider-admin.mjs +2 -1
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +1 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
- package/src/session-runtime/settings-compaction-api.mjs +2 -40
- package/src/session-runtime/settings-system-api.mjs +13 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +145 -22
- package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +17 -2
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/session-runtime/workspace/transitions.mjs +25 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
- package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
- package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
- package/src/standalone/channel-transport/client-registry.mjs +24 -163
- package/src/standalone/channel-transport.mjs +1 -1
- package/src/standalone/daemon-channels-loader.mjs +10 -8
- package/src/standalone/daemon-session-control/list-page.mjs +72 -0
- package/src/standalone/daemon-session-control/request.mjs +51 -0
- package/src/standalone/daemon-session-control/room-host.mjs +57 -0
- package/src/standalone/daemon-session-control/route-control.mjs +48 -0
- package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
- package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
- package/src/standalone/daemon-session-control.mjs +142 -190
- package/src/standalone/daemon.mjs +26 -3
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/quota-resume.mjs +3 -0
- package/src/standalone/session-service/retention/busy.mjs +65 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +30 -2
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-tool-output.mjs +15 -7
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/app/app-view/floating-panel.jsx +7 -4
- package/src/tui/app/model-options.mjs +3 -28
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +9 -5
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/dist/index.mjs +133 -92
- package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/notice-surface.mjs +7 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
- package/src/tui/session/session-api/routes-write.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +17 -1
- package/src/tui/session/session-flow/auto-clear.mjs +4 -33
- package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
- package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
- package/src/tui/session/session-flow/drain-retry.mjs +35 -0
- package/src/tui/session/session-flow/drain.mjs +118 -149
- package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +16 -2
- package/src/tui/session/tool-approval-delegation.mjs +64 -0
- package/src/tui/session/tool-approval-request.mjs +39 -0
- package/src/tui/session/tool-approval-settle.mjs +62 -0
- package/src/tui/session/tool-approval.mjs +69 -115
- package/src/tui/session/tui-steering-persist.mjs +8 -1
- package/src/tui/session/turn-stream.mjs +19 -2
- package/src/tui/session/turn.mjs +1 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
- package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
- package/scripts/code-graph-description-contract.mjs +0 -188
- package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
|
@@ -5,6 +5,17 @@
|
|
|
5
5
|
* close, all-settled for a full one.
|
|
6
6
|
*/
|
|
7
7
|
import { releaseComputerSession } from '../../../runtime/computer-bridge/client.mjs';
|
|
8
|
+
import {
|
|
9
|
+
pendingSummaryIndexIds,
|
|
10
|
+
settleSummaryIndexWrites,
|
|
11
|
+
} from '../../../runtime/agent/orchestrator/session/store-summary-index.mjs';
|
|
12
|
+
import { settleGatewayUsageWrites } from '../../../runtime/agent/orchestrator/providers/statusline-route-meta.mjs';
|
|
13
|
+
import { closeSessionSearch } from '../../../runtime/session-search/session-search-ingest.mjs';
|
|
14
|
+
|
|
15
|
+
// How long a close waits for a stop that owns files (memory, goals, and the
|
|
16
|
+
// close's own persistence): briefly for a detached close, longer for a full one.
|
|
17
|
+
const DETACHED_FILE_STOP_MS = 1500;
|
|
18
|
+
const FULL_FILE_STOP_MS = 5500;
|
|
8
19
|
|
|
9
20
|
export function startRuntimeStops(deps, reason, { detach, isProcessExit }) {
|
|
10
21
|
const { mcpClient, getMcpScopeId, closePatchRuntimeIfLoaded, getMemoryModPromise, setMemoryModPromise } = deps;
|
|
@@ -66,8 +77,8 @@ export async function settleDetached(withTeardownDeadline, stops) {
|
|
|
66
77
|
const bounded = [
|
|
67
78
|
[stops.channelStop, 300],
|
|
68
79
|
[stops.shellJobsStop, 300],
|
|
69
|
-
[stops.memoryStop,
|
|
70
|
-
[stops.goalStop,
|
|
80
|
+
[stops.memoryStop, DETACHED_FILE_STOP_MS],
|
|
81
|
+
[stops.goalStop, DETACHED_FILE_STOP_MS],
|
|
71
82
|
];
|
|
72
83
|
for (const [stop, deadlineMs] of bounded) {
|
|
73
84
|
try {
|
|
@@ -79,14 +90,49 @@ export async function settleDetached(withTeardownDeadline, stops) {
|
|
|
79
90
|
}
|
|
80
91
|
}
|
|
81
92
|
|
|
93
|
+
/**
|
|
94
|
+
* The close's deferred data-dir writes, under the file-stop deadline: this
|
|
95
|
+
* session's summary-index ops (every queued op when no session is closing),
|
|
96
|
+
* the buffered gateway usage events with their compaction, and this session's
|
|
97
|
+
* session-search writes (cancelled, PostgreSQL install included). Past the
|
|
98
|
+
* deadline the close stops waiting and reports what is still pending; those
|
|
99
|
+
* writes stay queued and land later.
|
|
100
|
+
*/
|
|
101
|
+
export async function settlePersistence(withTeardownDeadline, { detach, closingSessionId }) {
|
|
102
|
+
const ids = closingSessionId ? [closingSessionId] : null;
|
|
103
|
+
const giveUp = new AbortController();
|
|
104
|
+
const pending = new Set(['summary index', 'gateway usage', 'session search']);
|
|
105
|
+
const track = (name, work) =>
|
|
106
|
+
Promise.resolve(work).then((settled) => {
|
|
107
|
+
if (settled !== false) pending.delete(name);
|
|
108
|
+
});
|
|
109
|
+
const settled = await withTeardownDeadline(
|
|
110
|
+
Promise.all([
|
|
111
|
+
track('summary index', settleSummaryIndexWrites({ ids, signal: giveUp.signal })),
|
|
112
|
+
track('gateway usage', settleGatewayUsageWrites()),
|
|
113
|
+
track('session search', closingSessionId ? closeSessionSearch(closingSessionId) : null),
|
|
114
|
+
]).then(() => true),
|
|
115
|
+
detach ? DETACHED_FILE_STOP_MS : FULL_FILE_STOP_MS,
|
|
116
|
+
false
|
|
117
|
+
);
|
|
118
|
+
if (settled) return;
|
|
119
|
+
giveUp.abort();
|
|
120
|
+
const detail = [...pending].map((name) =>
|
|
121
|
+
name === 'summary index' && ids ? `summary index (sessions: ${pendingSummaryIndexIds(ids).join(', ')})` : name
|
|
122
|
+
);
|
|
123
|
+
process.emitWarning(`close persistence incomplete; still pending: ${detail.join('; ')}`, {
|
|
124
|
+
code: 'TEARDOWN_PERSISTENCE_PENDING',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
82
128
|
export async function settleAll(withTeardownDeadline, stops) {
|
|
83
129
|
await Promise.allSettled([
|
|
84
130
|
withTeardownDeadline(stops.channelStop, 5500, false),
|
|
85
131
|
withTeardownDeadline(stops.mcpStop, 1500, false),
|
|
86
132
|
withTeardownDeadline(stops.openaiWsStop, 1500, false),
|
|
87
133
|
withTeardownDeadline(stops.patchStop, 1500, false),
|
|
88
|
-
withTeardownDeadline(stops.memoryStop,
|
|
89
|
-
withTeardownDeadline(stops.goalStop,
|
|
134
|
+
withTeardownDeadline(stops.memoryStop, FULL_FILE_STOP_MS, false),
|
|
135
|
+
withTeardownDeadline(stops.goalStop, FULL_FILE_STOP_MS, false),
|
|
90
136
|
withTeardownDeadline(stops.shellJobsStop, 1500, false),
|
|
91
137
|
withTeardownDeadline(stops.nativeToolStop, 1500, false),
|
|
92
138
|
withTeardownDeadline(stops.computerStop, 1500, false),
|
|
@@ -11,7 +11,13 @@ import { flushAllIndexWrites } from '../services/agent-tool/index-write-queue.mj
|
|
|
11
11
|
import { PROCESS_RESTART_FAILURE } from '../services/agent-tool/worker-index/row-liveness.mjs';
|
|
12
12
|
import { unregisterLiveSession } from '../../runtime/shared/staged-update.mjs';
|
|
13
13
|
import { abortRuntime, closeCanonicalSession, closeOwnSession, dispatchSessionEnd } from './teardown/session-close.mjs';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
settleAll,
|
|
16
|
+
settleDetached,
|
|
17
|
+
settlePersistence,
|
|
18
|
+
startRuntimeStops,
|
|
19
|
+
startWorkStops,
|
|
20
|
+
} from './teardown/runtime-stops.mjs';
|
|
15
21
|
|
|
16
22
|
const CLOSE_ALL_DEADLINE_MS = 5000;
|
|
17
23
|
const PROCESS_EXIT_REASON = /exit|quit|shutdown|sighup|sigint|sigterm/;
|
|
@@ -243,9 +249,22 @@ export function createTeardown(deps, { ingestSessionIntoMemory, closeSurfaceSess
|
|
|
243
249
|
else await settleAll(withTeardownDeadline, stops);
|
|
244
250
|
// Reported closed only once the barrier is on disk (closeSessionAsync),
|
|
245
251
|
// and its write control is released only after that.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
252
|
+
let ok = false;
|
|
253
|
+
try {
|
|
254
|
+
ok = await ownClose;
|
|
255
|
+
// The session went away (idle eviction included): free its save baselines.
|
|
256
|
+
if (scope.closingSessionId) forgetSessionSaveBaseline(scope.closingSessionId, { releaseWriteControl: true });
|
|
257
|
+
// The close's saves and turns queued buffered data-dir writes (summary
|
|
258
|
+
// index ops, gateway usage events, session-search writes) that run on
|
|
259
|
+
// later ticks: land or cancel them under the teardown deadline.
|
|
260
|
+
await settlePersistence(withTeardownDeadline, scope);
|
|
261
|
+
} finally {
|
|
262
|
+
finishClose(scope);
|
|
263
|
+
}
|
|
264
|
+
return ok;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function finishClose(scope) {
|
|
249
268
|
// Self-update stages in the background and swaps on the next clean launch
|
|
250
269
|
// (see staged-update.mjs) — nothing installs at shutdown. On a real
|
|
251
270
|
// process exit we just drop this session's live-refcount pid file so a
|
|
@@ -257,7 +276,6 @@ export function createTeardown(deps, { ingestSessionIntoMemory, closeSurfaceSess
|
|
|
257
276
|
/* advisory refcount only */
|
|
258
277
|
}
|
|
259
278
|
}
|
|
260
|
-
return ok;
|
|
261
279
|
}
|
|
262
280
|
|
|
263
281
|
return {
|
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
// servers plus the servers registered plugins declare (resolved live, with
|
|
3
3
|
// explicit owner metadata), per-server config reads, and the live/failed rollup.
|
|
4
4
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
connectorAccountEnabled,
|
|
7
|
+
connectorAccountServer,
|
|
8
|
+
connectorAccountsOf,
|
|
9
|
+
connectorOfServer,
|
|
10
|
+
gmailAppPasswordAccount,
|
|
11
|
+
} from '../../runtime/shared/connector-catalog.mjs';
|
|
12
|
+
import { connectorAccountHealth } from '../../runtime/connectors/connector-accounts-mcp.mjs';
|
|
6
13
|
import { googleOAuthClient } from '../../runtime/shared/google-oauth-client.mjs';
|
|
7
14
|
import { envFlag } from '../../runtime/shared/env.mjs';
|
|
8
15
|
import { resolveMcpServerCatalog } from './plugin-servers.mjs';
|
|
@@ -112,6 +119,25 @@ export function createMcpServerCatalog({
|
|
|
112
119
|
};
|
|
113
120
|
}
|
|
114
121
|
|
|
122
|
+
/** One account of a multi-account connector server, as its row lists it:
|
|
123
|
+
* `{ name, email, enabled?, appPassword?, oauth?, ownClient?, error?, authRequired? }`
|
|
124
|
+
* (`enabled: false` only for an account that is switched off). */
|
|
125
|
+
function accountRow(accountCfg, enabled) {
|
|
126
|
+
const address = gmailAppPasswordAccount(accountCfg);
|
|
127
|
+
const oauth = address ? null : mcpClient.getMcpServerOAuthState?.(accountCfg);
|
|
128
|
+
const state = connectorAccountHealth(accountCfg.name);
|
|
129
|
+
const authRequired = Boolean(oauth && oauth.signedIn !== true) || state?.authRequired === true;
|
|
130
|
+
return {
|
|
131
|
+
name: accountCfg.name,
|
|
132
|
+
...(enabled ? {} : { enabled: false }),
|
|
133
|
+
email: address || oauth?.account || state?.email || '',
|
|
134
|
+
...(address ? { appPassword: { account: address } } : {}),
|
|
135
|
+
...(oauth ? { oauth } : {}),
|
|
136
|
+
...(typeof accountCfg.oauthClientId === 'string' && accountCfg.oauthClientId.trim() ? { ownClient: true } : {}),
|
|
137
|
+
...(authRequired ? { authRequired: true } : state?.error ? { error: state.error } : {}),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
115
141
|
function statusRows(catalog) {
|
|
116
142
|
const { servers: configured, sources, entries } = catalog;
|
|
117
143
|
const connected = new Map((mcpClient.getMcpServerStatus?.(getMcpScopeId()) || []).map((row) => [row.name, row]));
|
|
@@ -126,7 +152,19 @@ export function createMcpServerCatalog({
|
|
|
126
152
|
failures.get(name) || (dead ? { msg: live.error || live.lastError || 'MCP server is not alive' } : undefined);
|
|
127
153
|
const entry = entries[name] || {};
|
|
128
154
|
const loginPending = !(live && !dead) && mcpClient.isMcpLoginPending?.(name, getMcpScopeId()) === true;
|
|
129
|
-
const
|
|
155
|
+
const accounts = entry.owner
|
|
156
|
+
? []
|
|
157
|
+
: connectorAccountsOf(cfg).map((account) =>
|
|
158
|
+
accountRow(connectorAccountServer(cfg, account), connectorAccountEnabled(account))
|
|
159
|
+
);
|
|
160
|
+
// A connector server none of whose accounts is signed in needs a sign-in, not a repair.
|
|
161
|
+
const accountsSignIn = accounts.length > 0 && accounts.every((account) => account.authRequired === true);
|
|
162
|
+
const status = mcpServerStatus(
|
|
163
|
+
cfg,
|
|
164
|
+
live && !dead,
|
|
165
|
+
fail && accountsSignIn ? { ...fail, authRequired: true } : fail,
|
|
166
|
+
loginPending
|
|
167
|
+
);
|
|
130
168
|
// Needing an OAuth sign-in is a state, not an error.
|
|
131
169
|
const authRequired = status === 'sign-in required';
|
|
132
170
|
const row = {
|
|
@@ -156,6 +194,14 @@ export function createMcpServerCatalog({
|
|
|
156
194
|
if (appPasswordAccount) row.appPassword = { account: appPasswordAccount };
|
|
157
195
|
// A catalog connector running on the user's own Google client.
|
|
158
196
|
if (connector && typeof cfg?.oauthClientId === 'string' && cfg.oauthClientId.trim()) row.ownClient = true;
|
|
197
|
+
if (accounts.length) {
|
|
198
|
+
// A multi-account connector: its accounts, each with its own state.
|
|
199
|
+
row.accounts = accounts;
|
|
200
|
+
if (accounts.some((account) => account.ownClient)) row.ownClient = true;
|
|
201
|
+
// One account reads like the one-account server it replaces.
|
|
202
|
+
if (accounts.length === 1 && accounts[0].oauth) row.oauth = accounts[0].oauth;
|
|
203
|
+
if (accounts.length === 1 && accounts[0].appPassword) row.appPassword = accounts[0].appPassword;
|
|
204
|
+
}
|
|
159
205
|
if (entry.owner) {
|
|
160
206
|
row.owner = entry.owner;
|
|
161
207
|
row.pluginEnabled = entry.pluginEnabled;
|
|
@@ -175,7 +221,13 @@ export function createMcpServerCatalog({
|
|
|
175
221
|
|
|
176
222
|
function mcpStatus() {
|
|
177
223
|
if (envFlag('MIXDOG_DISABLE_MCP')) {
|
|
178
|
-
return {
|
|
224
|
+
return {
|
|
225
|
+
servers: [],
|
|
226
|
+
configuredCount: 0,
|
|
227
|
+
connectedCount: 0,
|
|
228
|
+
failedCount: 0,
|
|
229
|
+
googleClient: Boolean(googleOAuthClient()),
|
|
230
|
+
};
|
|
179
231
|
}
|
|
180
232
|
const catalog = resolveCatalog();
|
|
181
233
|
const servers = statusRows(catalog);
|
|
@@ -8,7 +8,7 @@ import { openInBrowser } from '../runtime/shared/open-url.mjs';
|
|
|
8
8
|
// Settled flows stay readable long enough for a poller to observe the result.
|
|
9
9
|
const SETTLED_FLOW_TTL_MS = 10 * 60_000;
|
|
10
10
|
const NOT_COMPLETED = 'MCP OAuth sign-in was not completed';
|
|
11
|
-
|
|
11
|
+
const MCP_OAUTH_LOGIN_TIMED_OUT = 'MCP OAuth sign-in timed out';
|
|
12
12
|
// A sign-in nobody finishes ends here, ahead of the OAuth layer's own 5-minute
|
|
13
13
|
// abort, so its failure is reported as the timeout it is.
|
|
14
14
|
const LOGIN_DEADLINE_MS = 5 * 60_000 - 10_000;
|
|
@@ -125,7 +125,9 @@ export function createMcpOAuthLogins({
|
|
|
125
125
|
Promise.all([...flows.values()].filter((flow) => flow.owner === owner && flow.name === name).map(cancelFlow));
|
|
126
126
|
|
|
127
127
|
async function begin(name, options = {}) {
|
|
128
|
-
|
|
128
|
+
// `beside`: run any mode through `switchAccount` (a sign-in beside the
|
|
129
|
+
// stored one, for an account that is not a server of its own).
|
|
130
|
+
const { openBrowser: hostBrowser, mode = 'connect', beside = false } = options || {};
|
|
129
131
|
if (hostBrowser !== undefined && typeof hostBrowser !== 'boolean') {
|
|
130
132
|
throw new TypeError('openBrowser must be a boolean');
|
|
131
133
|
}
|
|
@@ -178,7 +180,7 @@ export function createMcpOAuthLogins({
|
|
|
178
180
|
flow.done = (async () => {
|
|
179
181
|
try {
|
|
180
182
|
const outcome =
|
|
181
|
-
mode === 'switch'
|
|
183
|
+
mode === 'switch' || beside === true
|
|
182
184
|
? await switchAccount(name, launch, {
|
|
183
185
|
set abort(fn) {
|
|
184
186
|
flow.abort = fn;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Mixy's heartbeat:
|
|
3
|
-
*
|
|
2
|
+
* Mixy's heartbeat: at the user's chosen interval (heartbeatIntervalMinutes,
|
|
3
|
+
* 30 min / 1 h / 2 h / 4 h, default 1 h, read live at each tick), one check of
|
|
4
|
+
* what happened since the last one, in three stages that each stop as early as they can.
|
|
4
5
|
* 1. Collect (no model): a bounded digest of what happened in the interval:
|
|
5
6
|
* sessions the user talks in with new activity (Lead sessions, bot chats,
|
|
6
7
|
* group rooms; never Mixy's own chat, the heartbeat's hidden sessions,
|
|
@@ -13,11 +14,13 @@
|
|
|
13
14
|
* still fails (once when it switched itself off); a success closes it.
|
|
14
15
|
* 2. Gate: a digest equal to the last check's, or an empty one, ends the
|
|
15
16
|
* check. Otherwise the Maintainer model reviews each session and task
|
|
16
|
-
* line in its own call over that session's messages
|
|
17
|
-
* review (tool calls left out), given that review's note
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* line in its own call over the latest 12 of that session's messages
|
|
18
|
+
* since its last review (tool calls left out), given that review's note
|
|
19
|
+
* (a few at a time; the cursor then moves to the newest item and the line
|
|
20
|
+
* says how many older messages went unreviewed, or that its cursor was
|
|
21
|
+
* not found; a session with no new item keeps its note without a call; a
|
|
22
|
+
* line it finds nothing in is dropped unless it says that, its note is
|
|
23
|
+
* appended, a failed read or review keeps the line as collected), then answers once on the reviewed
|
|
21
24
|
* digest with Mixy's last delivered message of the past day
|
|
22
25
|
* (heartbeat-completion.mjs). Without one
|
|
23
26
|
* (it is off by default), after a
|
|
@@ -40,11 +43,17 @@
|
|
|
40
43
|
* for, or a wake whose reply was delivered); a failed collection (any
|
|
41
44
|
* source), Maintainer call or wake leaves them for the next check, and a
|
|
42
45
|
* routine-only wake after a failed Maintainer call commits just its routine
|
|
43
|
-
* warnings. A due check waits while the user is active
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
46
|
+
* warnings. A due check waits while the user is active: the user is idle only
|
|
47
|
+
* after 30 minutes with no operation, an operation being a turn they sent or
|
|
48
|
+
* an input (keyboard, mouse buttons, wheel, mouse movement) in the desktop
|
|
49
|
+
* app's own windows, which the app reports (noteUserInput), as this process
|
|
50
|
+
* saw it or the state file kept it. Input elsewhere on the machine, and
|
|
51
|
+
* routine and other runtime-made turns, are no user activity; without the
|
|
52
|
+
* desktop app only sent turns count. Missed checks run as one; two never run
|
|
53
|
+
* at once; the first one after a start is looked at after a minute. The setting `heartbeat: false` (setup
|
|
54
|
+
* set_heartbeat_enabled) stops it, and so does a representative bot that does
|
|
55
|
+
* not exist (mixy-presence.mjs, as the desktop shows her): no check runs
|
|
56
|
+
* and the watermark is cleared, so the first check once Mixy exists arms anew.
|
|
48
57
|
*
|
|
49
58
|
* Proposals Mixy makes (session action suggest) live in the same state file
|
|
50
59
|
* under a stable key (action:target): the same key is refreshed, a declined
|
|
@@ -63,6 +72,10 @@ import { roomIdOfSession, roomMemberOfSession } from '../runtime/agent/orchestra
|
|
|
63
72
|
import { isRootLeadSession } from '../runtime/agent/orchestrator/session/store-summary-visibility.mjs';
|
|
64
73
|
import { writeJsonAtomicSync } from '../runtime/shared/atomic-file.mjs';
|
|
65
74
|
import { resolvePluginData } from '../runtime/shared/plugin-paths.mjs';
|
|
75
|
+
import {
|
|
76
|
+
DEFAULT_HEARTBEAT_INTERVAL_MINUTES,
|
|
77
|
+
normalizeHeartbeatIntervalMinutes,
|
|
78
|
+
} from '../runtime/shared/heartbeat-interval.mjs';
|
|
66
79
|
import { ROUTINE_LIMITS } from '../runtime/shared/routine-limits.mjs';
|
|
67
80
|
import {
|
|
68
81
|
HEARTBEAT_QUIET,
|
|
@@ -74,10 +87,11 @@ import { activityOf, isWorking, quotedText, scanCatalog, sessionBotOf } from './
|
|
|
74
87
|
|
|
75
88
|
const HOUR = 60 * 60_000;
|
|
76
89
|
export const HEARTBEAT_LIMITS = Object.freeze({
|
|
77
|
-
intervalMs
|
|
90
|
+
// The default interval; the setting decides (see `intervalMs` in createMixyHeartbeat).
|
|
91
|
+
intervalMs: DEFAULT_HEARTBEAT_INTERVAL_MINUTES * 60_000,
|
|
78
92
|
firstTickMs: 60_000,
|
|
79
93
|
tickMs: 5 * 60_000,
|
|
80
|
-
idleMs:
|
|
94
|
+
idleMs: 30 * 60_000,
|
|
81
95
|
repeatMs: 6 * HOUR,
|
|
82
96
|
suggestionTtlMs: 72 * HOUR,
|
|
83
97
|
maxPending: 5,
|
|
@@ -90,14 +104,21 @@ const MAX_UNRELEASED = 20;
|
|
|
90
104
|
const MAX_LINES = { routine: 10, task: 8, session: 8 };
|
|
91
105
|
const TEXT_LIMIT = 120;
|
|
92
106
|
const DIGEST_LIMIT = 4000;
|
|
93
|
-
/** A review reads a session's latest TAIL_ITEMS transcript items and
|
|
94
|
-
*
|
|
95
|
-
* TAIL_TEXT_LIMIT; this many reviews run at once. */
|
|
107
|
+
/** A review reads a session's latest TAIL_ITEMS transcript items and takes
|
|
108
|
+
* the latest TAIL_MESSAGES user and assistant messages after its cursor, each
|
|
109
|
+
* cut to TAIL_TEXT_LIMIT, in one model call; this many reviews run at once. */
|
|
96
110
|
const TAIL_ITEMS = 40;
|
|
97
111
|
const TAIL_MESSAGES = 12;
|
|
98
112
|
const TAIL_TEXT_LIMIT = 400;
|
|
99
113
|
const REVIEWS_AT_ONCE = 4;
|
|
100
114
|
const NOTE_LIMIT = 300;
|
|
115
|
+
/** What a digest line says of the messages a review left out (readSessionTail). */
|
|
116
|
+
function skippedNote({ skipped = 0, exact = true } = {}) {
|
|
117
|
+
if (skipped < 0) return 'older messages since the last check could not be found, so some were not reviewed';
|
|
118
|
+
if (skipped === 0) return exact ? '' : 'older messages since the last check may not have been reviewed';
|
|
119
|
+
const count = `${exact ? '' : 'at least '}${skipped}`;
|
|
120
|
+
return `${count} older message${skipped === 1 && exact ? '' : 's'} since the last check ${skipped === 1 && exact ? 'was' : 'were'} not reviewed`;
|
|
121
|
+
}
|
|
101
122
|
/** Each reviewed session's cursor (its newest item) and note, kept this long
|
|
102
123
|
* and at most this many. */
|
|
103
124
|
const REVIEW_TTL_MS = 7 * 24 * HOUR;
|
|
@@ -130,6 +151,61 @@ export function noteUserTurn(at = Date.now(), { path = defaultStatePath() } = {}
|
|
|
130
151
|
});
|
|
131
152
|
}
|
|
132
153
|
|
|
154
|
+
let lastAppInputAt = 0;
|
|
155
|
+
/** Per state file: the app input time last written, when it was written and
|
|
156
|
+
* the trailing write waiting for the end of the window (if any). */
|
|
157
|
+
const appInputWrites = new Map();
|
|
158
|
+
const APP_INPUT_WRITE_MS = 60_000;
|
|
159
|
+
function writeAppInput(path, entry, current) {
|
|
160
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
161
|
+
entry.timer = null;
|
|
162
|
+
const value = lastAppInputAt;
|
|
163
|
+
updateState(path, (next) => {
|
|
164
|
+
next.lastAppInputAt = Math.max(next.lastAppInputAt, value);
|
|
165
|
+
});
|
|
166
|
+
entry.at = value;
|
|
167
|
+
entry.wroteAt = current;
|
|
168
|
+
}
|
|
169
|
+
/** The latest time the user operated the desktop app (keyboard, mouse buttons,
|
|
170
|
+
* wheel or mouse movement over its windows), as the app reports it (session
|
|
171
|
+
* action noteUserInput). Memory always takes the max (a time in the future
|
|
172
|
+
* counts as now). The state file (`lastAppInputAt`) is written only when the
|
|
173
|
+
* value advanced and at most once a minute, whoever calls. A note inside the
|
|
174
|
+
* window schedules one trailing write (an unref'd timer) of the newest value
|
|
175
|
+
* at the window's end, so after input stops the file is at most a minute
|
|
176
|
+
* behind: a crash loses at most the last minute of input, and a restart may
|
|
177
|
+
* see it up to a minute older than it was. The first note of a process
|
|
178
|
+
* writes at once. */
|
|
179
|
+
export function noteUserInput(
|
|
180
|
+
at = Date.now(),
|
|
181
|
+
{ path = defaultStatePath(), now = Date.now, schedule = setTimeout } = {}
|
|
182
|
+
) {
|
|
183
|
+
const current = now();
|
|
184
|
+
const time = Math.min(Number(at) || 0, current);
|
|
185
|
+
lastAppInputAt = Math.max(lastAppInputAt, time);
|
|
186
|
+
let entry = appInputWrites.get(path);
|
|
187
|
+
if (!entry) {
|
|
188
|
+
entry = { at: 0, wroteAt: 0, timer: null };
|
|
189
|
+
appInputWrites.set(path, entry);
|
|
190
|
+
}
|
|
191
|
+
if (lastAppInputAt <= entry.at) return;
|
|
192
|
+
const waited = current - entry.wroteAt;
|
|
193
|
+
if (entry.wroteAt && waited < APP_INPUT_WRITE_MS) {
|
|
194
|
+
if (entry.timer) return;
|
|
195
|
+
const held = entry;
|
|
196
|
+
held.timer = schedule(
|
|
197
|
+
() => {
|
|
198
|
+
held.timer = null;
|
|
199
|
+
if (lastAppInputAt > held.at) writeAppInput(path, held, now());
|
|
200
|
+
},
|
|
201
|
+
Math.min(APP_INPUT_WRITE_MS, APP_INPUT_WRITE_MS - waited)
|
|
202
|
+
);
|
|
203
|
+
held.timer?.unref?.();
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
writeAppInput(path, entry, current);
|
|
207
|
+
}
|
|
208
|
+
|
|
133
209
|
const defaultStatePath = () => join(resolvePluginData(), 'heartbeat.json');
|
|
134
210
|
|
|
135
211
|
function readState(path) {
|
|
@@ -144,6 +220,8 @@ function readState(path) {
|
|
|
144
220
|
lastAttemptAt: Number(value.lastAttemptAt) || 0,
|
|
145
221
|
// The user's latest accepted turn (noteUserTurn), for the idle check.
|
|
146
222
|
lastUserInputAt: Number(value.lastUserInputAt) || 0,
|
|
223
|
+
// The user's latest operation inside the desktop app (noteUserInput).
|
|
224
|
+
lastAppInputAt: Number(value.lastAppInputAt) || 0,
|
|
147
225
|
// Approvals waiting at the last handled check.
|
|
148
226
|
approvals: Number.isInteger(value.approvals) && value.approvals > 0 ? value.approvals : 0,
|
|
149
227
|
lastHash: typeof value.lastHash === 'string' ? value.lastHash : '',
|
|
@@ -418,24 +496,33 @@ export function isQuietReply(reply) {
|
|
|
418
496
|
}
|
|
419
497
|
|
|
420
498
|
/** Session `id`'s latest conversation for a review, oldest first:
|
|
421
|
-
* `{ rows, head
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
499
|
+
* `{ rows, head, skipped, exact }`. One read of the latest TAIL_ITEMS items
|
|
500
|
+
* (never more, however many tool calls they hold); `rows` is a line per
|
|
501
|
+
* user or assistant message (tool calls left out), the newest TAIL_MESSAGES
|
|
502
|
+
* after item `after` in that page. `skipped` is the number of older messages
|
|
503
|
+
* in the page left unreviewed: exact when the cursor is in the page, else a
|
|
504
|
+
* lower bound (`exact` false) when older items lie beyond the page; a
|
|
505
|
+
* supplied cursor absent from a page with nothing older is `-1` (it was
|
|
506
|
+
* compacted away: the gap is unknown). `head` is the id of the newest item
|
|
507
|
+
* ('' when the items carry none). Rejects when the session cannot be read. */
|
|
425
508
|
export async function readSessionTail(service, id, { after = '' } = {}) {
|
|
426
509
|
if (typeof service?.readSession !== 'function') throw new Error('the session service is not running');
|
|
427
510
|
const { range } = await service.readSession({ sessionId: id, transcriptRange: { offset: 0, limit: TAIL_ITEMS } });
|
|
428
511
|
const items = range?.items || [];
|
|
512
|
+
const hasOlder = range?.hasOlder === true;
|
|
429
513
|
const ids = items.map((item) => (item?.id == null ? '' : String(item.id)));
|
|
430
514
|
const head = ids.findLast(Boolean) || '';
|
|
431
515
|
const seen = after ? ids.lastIndexOf(after) : -1;
|
|
432
|
-
const
|
|
516
|
+
const all = [];
|
|
433
517
|
for (const item of items.slice(seen + 1)) {
|
|
434
518
|
if (item?.kind !== 'user' && item?.kind !== 'assistant') continue;
|
|
435
519
|
const text = quotedText(item.text, TAIL_TEXT_LIMIT);
|
|
436
|
-
if (text)
|
|
520
|
+
if (text) all.push(`${item.kind}: "${text}"`);
|
|
437
521
|
}
|
|
438
|
-
|
|
522
|
+
const rows = all.slice(-TAIL_MESSAGES);
|
|
523
|
+
const skipped = all.length - rows.length;
|
|
524
|
+
if (after && seen < 0 && !hasOlder) return { rows, head, skipped: -1, exact: false };
|
|
525
|
+
return { rows, head, skipped, exact: after ? seen >= 0 : !hasOlder };
|
|
439
526
|
}
|
|
440
527
|
|
|
441
528
|
/** Run `work` on every row, at most `limit` at once. */
|
|
@@ -549,7 +636,16 @@ export function createMixyHeartbeat({
|
|
|
549
636
|
path = defaultStatePath(),
|
|
550
637
|
isEnabled = async () =>
|
|
551
638
|
(await import('../runtime/agent/orchestrator/config.mjs')).loadConfig({ secrets: false }).heartbeat !== false,
|
|
639
|
+
// Whether the representative bot exists (mixy-presence.mjs, the rule the
|
|
640
|
+
// desktop and her routines follow): without it no check runs at all.
|
|
641
|
+
mixyExists = async () => (await import('./routine-owner.mjs')).readMixyExists(),
|
|
642
|
+
// Milliseconds between checks, read at every tick so a changed setting applies at once.
|
|
643
|
+
intervalMs = async () =>
|
|
644
|
+
normalizeHeartbeatIntervalMinutes(
|
|
645
|
+
(await import('../runtime/agent/orchestrator/config.mjs')).loadConfig({ secrets: false }).heartbeatIntervalMinutes
|
|
646
|
+
) * 60_000,
|
|
552
647
|
userTurnAt = () => lastUserTurnAt,
|
|
648
|
+
appInputAt = () => lastAppInputAt,
|
|
553
649
|
getSessionService = () => null,
|
|
554
650
|
log = defaultLog,
|
|
555
651
|
collect = (input) => collectHeartbeatFacts({ ...input, getSessionService }),
|
|
@@ -561,7 +657,7 @@ export function createMixyHeartbeat({
|
|
|
561
657
|
(await import('../runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs')).reviewHeartbeatSession(
|
|
562
658
|
input
|
|
563
659
|
),
|
|
564
|
-
readTail = (id) => readSessionTail(getSessionService(), id),
|
|
660
|
+
readTail = (id, options) => readSessionTail(getSessionService(), id, options),
|
|
565
661
|
release = closeHiddenSession,
|
|
566
662
|
// `hooks`: how the hidden session is closed, and where a failed close goes.
|
|
567
663
|
wake = (input, hooks) => wakeMixy(input, { getSessionService, log, ...hooks }),
|
|
@@ -642,9 +738,15 @@ export function createMixyHeartbeat({
|
|
|
642
738
|
const lines = [...digest.lines];
|
|
643
739
|
const dropped = new Set();
|
|
644
740
|
const cursors = {};
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
741
|
+
// A line whose older messages went unreviewed is never dropped as
|
|
742
|
+
// "nothing": it says so, as the overflow lines count what they leave out.
|
|
743
|
+
const apply = (index, note, skipped = '') => {
|
|
744
|
+
if (!note && !skipped) {
|
|
745
|
+
dropped.add(index);
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
const noted = note ? `${lines[index]}; reviewed: "${quotedText(note, NOTE_LIMIT)}"` : lines[index];
|
|
749
|
+
lines[index] = skipped ? `${noted}; ${skipped}` : noted;
|
|
648
750
|
};
|
|
649
751
|
await eachLimited(digest.subjects, REVIEWS_AT_ONCE, async ({ index, id }) => {
|
|
650
752
|
const prior = state.reviews[id];
|
|
@@ -656,6 +758,8 @@ export function createMixyHeartbeat({
|
|
|
656
758
|
apply(index, prior.note);
|
|
657
759
|
return;
|
|
658
760
|
}
|
|
761
|
+
// The latest messages since the cursor, in one call; the cursor then
|
|
762
|
+
// moves to the newest item, and what lay before them is said so.
|
|
659
763
|
result = await review({ line: digest.lines[index], transcript: tail.rows, previous: prior?.note || '' });
|
|
660
764
|
} catch (error) {
|
|
661
765
|
log(`review of ${id} failed: ${errorText(error)}`);
|
|
@@ -663,7 +767,7 @@ export function createMixyHeartbeat({
|
|
|
663
767
|
}
|
|
664
768
|
if (result?.action === 'nothing' || result?.action === 'note') {
|
|
665
769
|
const note = result.action === 'note' ? result.text : '';
|
|
666
|
-
apply(index, note);
|
|
770
|
+
apply(index, note, skippedNote(tail));
|
|
667
771
|
if (tail.head) cursors[id] = { head: tail.head, note };
|
|
668
772
|
} else if (result?.action !== 'unmanaged') log(`review of ${id}: unusable reply`);
|
|
669
773
|
});
|
|
@@ -759,6 +863,16 @@ export function createMixyHeartbeat({
|
|
|
759
863
|
try {
|
|
760
864
|
await retryReleases();
|
|
761
865
|
if (!(await isEnabled())) return 'off';
|
|
866
|
+
// No Maintainer call, hidden turn or queued report for a Mixy the user
|
|
867
|
+
// never created (issue #243); the first check after she is made arms anew.
|
|
868
|
+
if (!(await mixyExists())) {
|
|
869
|
+
if (readState(path).lastBeatAt) {
|
|
870
|
+
updateState(path, (next) => {
|
|
871
|
+
next.lastBeatAt = 0;
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
return 'no-mixy';
|
|
875
|
+
}
|
|
762
876
|
const at = now();
|
|
763
877
|
const state = readState(path);
|
|
764
878
|
if (!state.lastBeatAt) {
|
|
@@ -769,10 +883,16 @@ export function createMixyHeartbeat({
|
|
|
769
883
|
}
|
|
770
884
|
// Checks are due by the last one begun; a check left unhandled keeps
|
|
771
885
|
// its watermark, so the next one collects its changes again.
|
|
772
|
-
if (at - Math.max(state.lastBeatAt, state.lastAttemptAt) <
|
|
773
|
-
// The user's latest
|
|
774
|
-
//
|
|
775
|
-
|
|
886
|
+
if (at - Math.max(state.lastBeatAt, state.lastAttemptAt) < (await intervalMs())) return 'waiting';
|
|
887
|
+
// The user's latest operation: a turn they sent or an input in the
|
|
888
|
+
// desktop app, as this process saw it or the state file kept it (it
|
|
889
|
+
// survives a crash or restart).
|
|
890
|
+
const userAt = Math.max(
|
|
891
|
+
Number(userTurnAt()) || 0,
|
|
892
|
+
Number(appInputAt()) || 0,
|
|
893
|
+
state.lastUserInputAt,
|
|
894
|
+
state.lastAppInputAt
|
|
895
|
+
);
|
|
776
896
|
if (at - userAt < limits.idleMs) return 'deferred';
|
|
777
897
|
updateState(path, (next) => {
|
|
778
898
|
next.lastAttemptAt = at;
|
|
@@ -217,11 +217,20 @@ function switchSessionInPlace(deps, session) {
|
|
|
217
217
|
|
|
218
218
|
/** The Lead's fallback models after this selection, checked like an agent's
|
|
219
219
|
* chain (leaf routes, distinct providers): an explicit list replaces the
|
|
220
|
-
* stored one ([] clears it), a selection without one keeps it
|
|
220
|
+
* stored one ([] clears it), a selection without one keeps it as stored — a
|
|
221
|
+
* fallback on the new main model's provider stays saved and is inactive
|
|
222
|
+
* (executionFallbacks). */
|
|
221
223
|
async function leadFallbackChain(deps, next, primary) {
|
|
222
224
|
const storedPreset = findPreset(deps.getConfig(), workflowPresetId('lead'));
|
|
223
|
-
const
|
|
225
|
+
const explicit = hasOwn(next || {}, 'fallbacks');
|
|
226
|
+
const requested = explicit ? next.fallbacks : storedPreset?.fallbacks;
|
|
224
227
|
if (!Array.isArray(requested) || !requested.length) return [];
|
|
228
|
+
if (!explicit) {
|
|
229
|
+
return (
|
|
230
|
+
normalizeWorkflowRoute({ provider: primary.provider, model: primary.model, fallbacks: requested })?.fallbacks ||
|
|
231
|
+
[]
|
|
232
|
+
);
|
|
233
|
+
}
|
|
225
234
|
const chain = routeChain({ provider: primary.provider, model: primary.model, fallbacks: requested });
|
|
226
235
|
validateRouteChainProviders(chain);
|
|
227
236
|
const storedChain = routeChain(storedPreset || {});
|