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
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* enqueue adds nothing and a crash between posting and dequeuing never posts
|
|
11
11
|
* twice (the posted message id is derived from the run id). One drainer per
|
|
12
12
|
* home appends every queued result FIFO once the thread is idle; posting never
|
|
13
|
-
* starts a turn.
|
|
13
|
+
* starts a turn. Rows that wake nobody (a task session's progress updates,
|
|
14
|
+
* among others) also post right before any turn of the thread starts
|
|
15
|
+
* (postBeforeTurn), so that turn reads them ahead of its prompt. A home thread that does not exist yet keeps its results
|
|
14
16
|
* queued until it does; a deleted owner's results move to Mixy's home. Each
|
|
15
17
|
* home keeps at most ROUTINE_LIMITS.homeQueueLimit results (the oldest drop
|
|
16
18
|
* behind one "n omitted" notice), and posted run ids stay in a ledger so a
|
|
@@ -58,6 +60,7 @@ import {
|
|
|
58
60
|
routineSummary,
|
|
59
61
|
} from '../runtime/agent/orchestrator/session/routine-result.mjs';
|
|
60
62
|
import { readJsonState, updateJsonAtomic } from '../runtime/shared/atomic-file.mjs';
|
|
63
|
+
import { endHandoff, noteHandoff } from '../runtime/shared/delegated-approval-host.mjs';
|
|
61
64
|
import { ROUTINE_LIMITS } from '../runtime/shared/routine-limits.mjs';
|
|
62
65
|
import { submissionIdsOf, submissionOutcome } from './agent-task-sessions.mjs';
|
|
63
66
|
import {
|
|
@@ -65,9 +68,36 @@ import {
|
|
|
65
68
|
heldRequestNotice,
|
|
66
69
|
} from '../runtime/agent/orchestrator/session/human-gate/held-message.mjs';
|
|
67
70
|
|
|
71
|
+
/** `message` marked as posted outside any turn (`meta.transcript.posted`):
|
|
72
|
+
* its row is a turn of its own, never part of the rows around it
|
|
73
|
+
* (transcript-turn-keys.mjs). */
|
|
74
|
+
function postedMessage(message) {
|
|
75
|
+
return { ...message, meta: { ...message.meta, transcript: { ...message.meta?.transcript, posted: true } } };
|
|
76
|
+
}
|
|
77
|
+
|
|
68
78
|
/** A queued item's stored message and live notice: a routine result, or a
|
|
69
79
|
* held request of an unattended run (session-runtime/held-requests.mjs). */
|
|
70
80
|
function deliveredRow(item, messageId) {
|
|
81
|
+
const row = queuedRow(item, messageId);
|
|
82
|
+
return { ...row, message: postedMessage(row.message) };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** A task report past the round-trip cap with another agent's own thread:
|
|
86
|
+
* each wake could answer the other agent again without end. */
|
|
87
|
+
const taskWakeCapped = (item) =>
|
|
88
|
+
(isAgentHomeSessionId(item.taskSessionId) || isRoomThreadSessionId(item.taskSessionId)) &&
|
|
89
|
+
(item.round || 0) > TASK_LOOP_CAP;
|
|
90
|
+
|
|
91
|
+
/** Whether queued `item` wakes the agent once posted: a task turn's end (not
|
|
92
|
+
* its start, a wait for the user or a progress update), unless capped. */
|
|
93
|
+
const wakesAgent = (item) => item.kind === 'agent-task' && item.roundTrip === true && !taskWakeCapped(item);
|
|
94
|
+
|
|
95
|
+
const MIXY_HOME = agentHomeSessionId(MIXY_AGENT_ID);
|
|
96
|
+
/** A heartbeat report: Mixy's own reply from a check turn (mixy-heartbeat.mjs
|
|
97
|
+
* wakeMixy, its only sender of agent messages). */
|
|
98
|
+
const isHeartbeatReport = (item) => item?.kind === 'agent-message';
|
|
99
|
+
|
|
100
|
+
function queuedRow(item, messageId) {
|
|
71
101
|
// The agent's own words from a turn it ran elsewhere (mixy-heartbeat.mjs):
|
|
72
102
|
// one ordinary reply of the agent in its thread.
|
|
73
103
|
if (item.kind === 'agent-message') {
|
|
@@ -79,14 +109,9 @@ function deliveredRow(item, messageId) {
|
|
|
79
109
|
return { message, notice: heldRequestNotice(message) };
|
|
80
110
|
}
|
|
81
111
|
if (item.kind === 'agent-task') {
|
|
82
|
-
|
|
83
|
-
// except past the round-trip cap with another agent's own thread, where
|
|
84
|
-
// each wake could answer the other agent again without end.
|
|
85
|
-
const capped =
|
|
86
|
-
(isAgentHomeSessionId(item.taskSessionId) || isRoomThreadSessionId(item.taskSessionId)) &&
|
|
87
|
-
(item.round || 0) > TASK_LOOP_CAP;
|
|
112
|
+
const capped = taskWakeCapped(item);
|
|
88
113
|
const message = agentTaskMessage({ ...item, messageId, ...(capped ? { woken: false } : {}) });
|
|
89
|
-
return { message, notice: routineResultNotice(message), wake: item
|
|
114
|
+
return { message, notice: routineResultNotice(message), wake: wakesAgent(item) };
|
|
90
115
|
}
|
|
91
116
|
const message = routineResultMessage({ ...item, messageId });
|
|
92
117
|
return { message, notice: routineResultNotice(message) };
|
|
@@ -152,14 +177,14 @@ export function agentHomeLiveSurface() {
|
|
|
152
177
|
// even into a thread that was reset ("대화 새로 시작") since.
|
|
153
178
|
const DELIVERED_LEDGER = 500;
|
|
154
179
|
// A target's round-trip count left idle this long starts over.
|
|
155
|
-
|
|
180
|
+
const ROUND_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
156
181
|
// Per home: round-trip targets counted (least recently counted drop first),
|
|
157
182
|
// reporting turns watched at once, and posted results owed a wake.
|
|
158
183
|
export const QUEUE_CAPS = Object.freeze({ roundTargets: 100, watches: 200, wakeRunIds: 100 });
|
|
159
184
|
// Waits before the 2nd, 3rd and 4th try of a relay (wake) turn that did not finish.
|
|
160
|
-
|
|
185
|
+
const WAKE_RETRY_DELAYS_MS = Object.freeze([30_000, 120_000, 600_000]);
|
|
161
186
|
// Refused wake submissions of one batch, a minute apart, before it is given up.
|
|
162
|
-
|
|
187
|
+
const WAKE_REFUSAL_LIMIT = 10;
|
|
163
188
|
|
|
164
189
|
/** `homeId`'s wake obligations in `wakes`: posted task results not in a batch
|
|
165
190
|
* yet (`owed`), those past the cap collapsed into one marker (`overflow`:
|
|
@@ -264,6 +289,25 @@ function withDequeued(doc, homeId, runIds, omitted) {
|
|
|
264
289
|
return { ...doc, homes, omitted: omittedNow, delivered };
|
|
265
290
|
}
|
|
266
291
|
|
|
292
|
+
/** `{ doc, item }`: task report `item` for `homeId` and the `doc` it joins,
|
|
293
|
+
* so that a final report never repeats progress update `progressRunId` that
|
|
294
|
+
* carried the same answer. Posted (`posted`: the thread holds it, or the
|
|
295
|
+
* ledger says so), the final report points to it instead of repeating its
|
|
296
|
+
* text (the row's one-line summary stays); only queued, that update is
|
|
297
|
+
* dropped and the final report carries the answer in its place. */
|
|
298
|
+
function withoutRepeatedProgress(doc, homeId, item, posted) {
|
|
299
|
+
const { progressRunId, ...report } = item;
|
|
300
|
+
if (!progressRunId) return { doc, item };
|
|
301
|
+
if (posted || (doc.delivered[homeId] || []).includes(progressRunId)) {
|
|
302
|
+
const { text: _text, textChars: _textChars, ...rest } = report;
|
|
303
|
+
return { doc, item: { ...rest, text: '', answerAbove: true } };
|
|
304
|
+
}
|
|
305
|
+
const queued = doc.homes[homeId] || [];
|
|
306
|
+
if (!queued.some((row) => row.runId === progressRunId)) return { doc, item: report };
|
|
307
|
+
const homes = { ...doc.homes, [homeId]: queued.filter((row) => row.runId !== progressRunId) };
|
|
308
|
+
return { doc: { ...doc, homes }, item: report };
|
|
309
|
+
}
|
|
310
|
+
|
|
267
311
|
/** The persisted queue at `filePath`: `{ homes: { [homeSessionId]: item[] },
|
|
268
312
|
* omitted: { [homeSessionId]: { id, count } }, delivered: { [homeSessionId]:
|
|
269
313
|
* runId[] } }`. A home keeps at most `limit` items: past it the oldest drop,
|
|
@@ -288,6 +332,9 @@ export function createRoutineResultQueue(
|
|
|
288
332
|
rounds: section(doc, 'rounds'),
|
|
289
333
|
// Reporting turns not yet queued, by submission id (agent-task-sessions.mjs).
|
|
290
334
|
watches: section(doc, 'watches'),
|
|
335
|
+
// The bot-sent turns that hold no watch (reports off, or a watch that could
|
|
336
|
+
// not be stored), by submission id: work a restart re-attaches.
|
|
337
|
+
owned: section(doc, 'owned'),
|
|
291
338
|
// Posted task results whose wake turn was not taken yet, per home.
|
|
292
339
|
wakes: section(doc, 'wakes'),
|
|
293
340
|
});
|
|
@@ -299,16 +346,23 @@ export function createRoutineResultQueue(
|
|
|
299
346
|
}
|
|
300
347
|
/** Read-modify-write under the file lock (`mutator(doc)` returns the next
|
|
301
348
|
* doc, or nothing to keep the file); every write also retires stale and
|
|
302
|
-
* surplus round counts.
|
|
303
|
-
|
|
304
|
-
|
|
349
|
+
* surplus round counts. The watches a write added or removed, by any path
|
|
350
|
+
* (a report, a turn never taken, a cap eviction, a pruned home), start or
|
|
351
|
+
* end their hand-offs (delegated-approval-host.mjs). */
|
|
352
|
+
async function update(mutator) {
|
|
353
|
+
let watches = null;
|
|
354
|
+
const result = await updateJsonAtomic(
|
|
305
355
|
filePath,
|
|
306
356
|
(raw) => {
|
|
307
|
-
const
|
|
357
|
+
const doc = parts(raw);
|
|
358
|
+
const next = mutator(doc);
|
|
359
|
+
watches = { before: doc.watches, after: next ? section(next, 'watches') : doc.watches };
|
|
308
360
|
return next ? { ...next, rounds: tidyRounds(next.rounds) } : undefined;
|
|
309
361
|
},
|
|
310
362
|
{ backup: true }
|
|
311
363
|
);
|
|
364
|
+
if (watches) syncHandoffs(watches.before, watches.after);
|
|
365
|
+
return result;
|
|
312
366
|
}
|
|
313
367
|
const appended = (doc, homeId, items, omittedCount = 0) => appendedItems(doc, homeId, items, limit, omittedCount);
|
|
314
368
|
return {
|
|
@@ -423,9 +477,14 @@ export function createRoutineResultQueue(
|
|
|
423
477
|
return (await read()).omitted[homeId] || null;
|
|
424
478
|
},
|
|
425
479
|
/** Queue `item` for `homeId`; `unwatch` (run ids) drops those watches in the
|
|
426
|
-
* same write, also when the item was queued or posted before.
|
|
427
|
-
|
|
428
|
-
|
|
480
|
+
* same write, also when the item was queued or posted before.
|
|
481
|
+
* `progressPosted`: the thread holds the progress update a final report
|
|
482
|
+
* names (withoutRepeatedProgress). `progressed` (`{ runId, turnId }`):
|
|
483
|
+
* watch `runId` reported turn `turnId` as progress — its durable mark,
|
|
484
|
+
* stored in the same write (agent-task-sessions.mjs progressedThrough). */
|
|
485
|
+
async add(homeId, queued, { unwatch = [], progressPosted = false, progressed = null } = {}) {
|
|
486
|
+
await update((stored) => {
|
|
487
|
+
const { doc, item } = withoutRepeatedProgress(stored, homeId, queued, progressPosted);
|
|
429
488
|
let next = null;
|
|
430
489
|
if (item.roundTrip !== true) next = appended(doc, homeId, [item]);
|
|
431
490
|
else {
|
|
@@ -443,11 +502,19 @@ export function createRoutineResultQueue(
|
|
|
443
502
|
next = { ...next, rounds: { ...doc.rounds, [homeId]: counted } };
|
|
444
503
|
}
|
|
445
504
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
505
|
+
let watches = doc.watches;
|
|
506
|
+
const marked = progressed?.turnId && watches[progressed.runId];
|
|
507
|
+
if (marked && marked.progressed !== progressed.turnId) {
|
|
508
|
+
watches = { ...watches, [progressed.runId]: { ...marked, progressed: progressed.turnId } };
|
|
509
|
+
}
|
|
510
|
+
const dropped = unwatch.filter((runId) => watches[runId]);
|
|
511
|
+
if (dropped.length) {
|
|
512
|
+
watches = { ...watches };
|
|
513
|
+
for (const runId of dropped) delete watches[runId];
|
|
514
|
+
}
|
|
515
|
+
const base = next || doc;
|
|
516
|
+
if (watches === doc.watches) return base === stored ? undefined : base;
|
|
517
|
+
return { ...base, watches };
|
|
451
518
|
});
|
|
452
519
|
},
|
|
453
520
|
/** Keep `watch` ({ runId, agentId, homeSessionId, taskSessionId, title,
|
|
@@ -469,9 +536,12 @@ export function createRoutineResultQueue(
|
|
|
469
536
|
});
|
|
470
537
|
},
|
|
471
538
|
watchCap: caps.watches,
|
|
472
|
-
/** Every stored watch, oldest first
|
|
539
|
+
/** Every stored watch, oldest first; each is a live hand-off (after a
|
|
540
|
+
* restart, this read brings them back). */
|
|
473
541
|
async watches() {
|
|
474
|
-
|
|
542
|
+
const watches = Object.values((await read()).watches);
|
|
543
|
+
for (const watch of watches) noteHandoff(watch ?? {});
|
|
544
|
+
return watches;
|
|
475
545
|
},
|
|
476
546
|
/** The watch of `runId` follows the turn submitted as `submissionId`: a
|
|
477
547
|
* room member's one turn answering several sends, or a fresh turn
|
|
@@ -492,6 +562,26 @@ export function createRoutineResultQueue(
|
|
|
492
562
|
return { ...doc, watches };
|
|
493
563
|
});
|
|
494
564
|
},
|
|
565
|
+
/** Keep `work` ({ runId, agentId, taskSessionId, owner, at }): a bot-sent
|
|
566
|
+
* turn that reports nothing, until its work ends. It is no watch: it
|
|
567
|
+
* owes no report, starts no hand-off and takes no part in a watch cap. */
|
|
568
|
+
async own(work) {
|
|
569
|
+
await update((doc) => ({ ...doc, owned: { ...doc.owned, [work.runId]: work } }));
|
|
570
|
+
},
|
|
571
|
+
/** Every stored record of bot-sent work that reports nothing, oldest first. */
|
|
572
|
+
async owned() {
|
|
573
|
+
return Object.values((await read()).owned);
|
|
574
|
+
},
|
|
575
|
+
/** Drop the records of `runIds` (a run id or a list; their work ended), in one write. */
|
|
576
|
+
async disown(runIds) {
|
|
577
|
+
const ids = [runIds].flat();
|
|
578
|
+
await update((doc) => {
|
|
579
|
+
if (!ids.some((runId) => doc.owned[runId])) return undefined;
|
|
580
|
+
const owned = { ...doc.owned };
|
|
581
|
+
for (const runId of ids) delete owned[runId];
|
|
582
|
+
return { ...doc, owned };
|
|
583
|
+
});
|
|
584
|
+
},
|
|
495
585
|
/** The user spoke in `homeId`: its round trips count from zero again. */
|
|
496
586
|
async resetRounds(homeId) {
|
|
497
587
|
await update((doc) => {
|
|
@@ -537,7 +627,7 @@ const messageIdOf = (runId) => `routine_${runId}`;
|
|
|
537
627
|
* or false (logged) when the surface threw. */
|
|
538
628
|
function noticeLive(live, log, homeId, notice) {
|
|
539
629
|
try {
|
|
540
|
-
return live()?.notice?.(homeId, notice);
|
|
630
|
+
return live()?.notice?.(homeId, { ...notice, posted: true });
|
|
541
631
|
} catch (error) {
|
|
542
632
|
log(`live notice in ${homeId} failed: ${error?.message || error}`);
|
|
543
633
|
return false;
|
|
@@ -571,6 +661,13 @@ function routineResultItem(row, result) {
|
|
|
571
661
|
};
|
|
572
662
|
}
|
|
573
663
|
|
|
664
|
+
/** End the hand-off of each watch in `before` and not `after`, and start
|
|
665
|
+
* each one `after` added (both keyed by run id). */
|
|
666
|
+
function syncHandoffs(before, after) {
|
|
667
|
+
for (const runId of Object.keys(before)) if (!after[runId]) endHandoff(runId);
|
|
668
|
+
for (const [runId, watch] of Object.entries(after)) if (!before[runId]) noteHandoff(watch ?? {});
|
|
669
|
+
}
|
|
670
|
+
|
|
574
671
|
/** The run ids of `watches` a home at its watch `cap` gives up before
|
|
575
672
|
* storing `watch`: its oldest whose target sessions are proven deleted. */
|
|
576
673
|
function watchesToDrop(watches, watch, cap, sessionDeleted) {
|
|
@@ -594,6 +691,9 @@ function homeProvenDeleted(homeId, agentPresence, roomPresence) {
|
|
|
594
691
|
return Boolean(roomId) && roomPresence(roomId) === 'deleted';
|
|
595
692
|
}
|
|
596
693
|
|
|
694
|
+
// Task report statuses that post a row and wake nobody.
|
|
695
|
+
const QUIET_TASK_STATUSES = new Set(['started', 'blocked', 'working']);
|
|
696
|
+
|
|
597
697
|
/** The queued item of one task report (enqueueTask). */
|
|
598
698
|
function taskReportItem({
|
|
599
699
|
runId,
|
|
@@ -607,6 +707,7 @@ function taskReportItem({
|
|
|
607
707
|
hop = 0,
|
|
608
708
|
watchId = '',
|
|
609
709
|
watchIds = [],
|
|
710
|
+
progressRunId = '',
|
|
610
711
|
}) {
|
|
611
712
|
// The model-facing reply keeps its lines up to REPLY_LIMIT; the row's
|
|
612
713
|
// one-line summary is derived from it (agentTaskMessage).
|
|
@@ -630,7 +731,12 @@ function taskReportItem({
|
|
|
630
731
|
...(watchIds.length > 1 ? { sendIds: watchIds.map(String) } : {}),
|
|
631
732
|
// The files the turn produced (handoff-attachments.mjs collectTurnArtifacts).
|
|
632
733
|
...(Array.isArray(files) && files.length ? { files, ...(omitted > 0 ? { omitted } : {}) } : {}),
|
|
633
|
-
|
|
734
|
+
// The progress update that carried this final report's answer, if one
|
|
735
|
+
// did: the queue keeps the answer from being repeated (withoutRepeatedProgress).
|
|
736
|
+
...(progressRunId ? { progressRunId: String(progressRunId) } : {}),
|
|
737
|
+
// Only a turn's end wakes the agent and counts a round trip: not its
|
|
738
|
+
// start, a wait for the user, or a progress update (status 'working').
|
|
739
|
+
roundTrip: !QUIET_TASK_STATUSES.has(status),
|
|
634
740
|
...(hop > 0 ? { hop } : {}),
|
|
635
741
|
at: Date.now(),
|
|
636
742
|
};
|
|
@@ -644,7 +750,7 @@ function postQueuedRows(session, items, omitted) {
|
|
|
644
750
|
const fresh = [];
|
|
645
751
|
const omittedId = omitted ? messageIdOf(omitted.id) : '';
|
|
646
752
|
if (omitted && !posted.has(omittedId)) {
|
|
647
|
-
const message = routineOmittedMessage({ count: omitted.count, messageId: omittedId });
|
|
753
|
+
const message = postedMessage(routineOmittedMessage({ count: omitted.count, messageId: omittedId }));
|
|
648
754
|
session.messages.push(message);
|
|
649
755
|
fresh.push({ message, notice: routineResultNotice(message) });
|
|
650
756
|
}
|
|
@@ -716,15 +822,17 @@ function createHomeRelay({
|
|
|
716
822
|
log(`the relay turn in ${homeId} ${why}; its results stay posted unrelayed`);
|
|
717
823
|
const messageId = messageIdOf(`relay_${batch.id}`);
|
|
718
824
|
if (!session.messages.some((message) => message?.meta?.transcript?.messageId === messageId)) {
|
|
719
|
-
const message =
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
825
|
+
const message = postedMessage(
|
|
826
|
+
agentTaskRelayFailedMessage({
|
|
827
|
+
count: batch.runIds.length + (batch.overflow?.count || 0),
|
|
828
|
+
tries,
|
|
829
|
+
messageId,
|
|
830
|
+
})
|
|
831
|
+
);
|
|
724
832
|
session.messages.push(message);
|
|
725
833
|
session.updatedAt = Date.now();
|
|
726
834
|
await saveSession(session);
|
|
727
|
-
noticeLive(live, log, homeId, { ...routineResultNotice(message), messageId });
|
|
835
|
+
noticeLive(live, log, homeId, { ...routineResultNotice(message), messageId, at: message.meta.transcript.at });
|
|
728
836
|
}
|
|
729
837
|
await queue.woke(homeId, batch.id);
|
|
730
838
|
return true;
|
|
@@ -807,6 +915,200 @@ function createHomeRelay({
|
|
|
807
915
|
return { wakeOwed };
|
|
808
916
|
}
|
|
809
917
|
|
|
918
|
+
/** Whether home thread `sessionId` is busy: a turn in flight in this process,
|
|
919
|
+
* or the `live()` surface says so (false when it threw). */
|
|
920
|
+
const homeBusy = (turnInFlight, live) => (sessionId) => {
|
|
921
|
+
if (turnInFlight(sessionId)) return true;
|
|
922
|
+
try {
|
|
923
|
+
return live()?.busy?.(sessionId) === true;
|
|
924
|
+
} catch {
|
|
925
|
+
return false;
|
|
926
|
+
}
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
/** `later(homeId, ms)`: drain `homeId` again after `ms`, one retry timer per
|
|
930
|
+
* home armed at a time. */
|
|
931
|
+
function createRetryTimer(retryLater, drain) {
|
|
932
|
+
const waiting = new Set(); // homes with a retry timer armed
|
|
933
|
+
return function later(homeId, ms) {
|
|
934
|
+
if (waiting.has(homeId)) return;
|
|
935
|
+
waiting.add(homeId);
|
|
936
|
+
retryLater(() => {
|
|
937
|
+
waiting.delete(homeId);
|
|
938
|
+
void drain(homeId);
|
|
939
|
+
}, ms);
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/** The held requests shown live in a busy thread. A held request waits on the
|
|
944
|
+
* user, possibly raised by the very turn that keeps its thread busy (a
|
|
945
|
+
* routine turn): `show` shows it live at once; the stored row (same
|
|
946
|
+
* messageId) replaces it once the thread is idle, and `forget` lets a later
|
|
947
|
+
* one show again. */
|
|
948
|
+
function createHeldLiveDisplay(live, log) {
|
|
949
|
+
const shownLive = new Set(); // held-request message ids shown live in a busy thread
|
|
950
|
+
return {
|
|
951
|
+
show(homeId, items) {
|
|
952
|
+
for (const item of items) {
|
|
953
|
+
if (item.kind !== 'held-request') continue;
|
|
954
|
+
const messageId = messageIdOf(item.runId);
|
|
955
|
+
if (shownLive.has(messageId)) continue;
|
|
956
|
+
shownLive.add(messageId);
|
|
957
|
+
noticeLive(live, log, homeId, { ...deliveredRow(item, messageId).notice, messageId, at: item.at });
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
forget(items) {
|
|
961
|
+
for (const item of items) shownLive.delete(messageIdOf(item.runId));
|
|
962
|
+
},
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/** The queues a drain drops unposted instead of retrying them. */
|
|
967
|
+
function createQueueDrops({ queue, log, homeAgent, homeDeleted, sessionDeleted }) {
|
|
968
|
+
/** A room thread proven gone: its queued rows are dropped, never retried. */
|
|
969
|
+
async function dropGoneRoomThread(homeId, items, omitted) {
|
|
970
|
+
if (!isRoomThreadSessionId(homeId) || !(homeDeleted(homeId) || sessionDeleted(homeId))) return false;
|
|
971
|
+
log(`${items.length} task report(s) for the deleted ${homeId} are dropped`);
|
|
972
|
+
await dropQueued(queue, homeId, items, omitted);
|
|
973
|
+
return true;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/** A room log's queued rows: task reports go to member sessions now, so what
|
|
977
|
+
* an earlier version left under the log's id is dropped, never posted. */
|
|
978
|
+
async function dropRoomLogQueue(logId, items, omitted) {
|
|
979
|
+
log(`${items.length} legacy task report(s) queued for the room log ${logId} are dropped`);
|
|
980
|
+
await dropQueued(queue, logId, items, omitted);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/** A missing home of an agent that can never have one (no bot): its queued
|
|
984
|
+
* rows are dropped with a log line, never retried. */
|
|
985
|
+
async function dropHomeless(homeId, items, omitted) {
|
|
986
|
+
const agentId = agentIdOfHomeSession(homeId);
|
|
987
|
+
if (!agentId || agentId === MIXY_AGENT_ID || homeAgent(agentId) !== 'none') return false;
|
|
988
|
+
log(`${items.length} result(s) for ${homeId} are dropped: ${agentId} is not a bot, so it has no chat`);
|
|
989
|
+
await dropQueued(queue, homeId, items, omitted);
|
|
990
|
+
return true;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
return { dropGoneRoomThread, dropRoomLogQueue, dropHomeless };
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/** The durable intake of a home: each enqueue persists its row for the home
|
|
997
|
+
* thread, then starts draining it, and resolves once it is queued. */
|
|
998
|
+
function createHomeEnqueue(queue, drain, { postingFor, postedIn }) {
|
|
999
|
+
/** Persist `result` ({ runId, kind, ok, text, runSessionId }) of a schedule
|
|
1000
|
+
* or webhook `row` for its owner's home, then start draining it. Resolves
|
|
1001
|
+
* once it is queued. */
|
|
1002
|
+
async function enqueue(row, result) {
|
|
1003
|
+
const homeId = agentHomeSessionId(scheduleOwnerAgentId(row));
|
|
1004
|
+
if (!result?.runId) throw new Error('routine result: runId required');
|
|
1005
|
+
await queue.add(homeId, routineResultItem(row, result));
|
|
1006
|
+
void drain(homeId);
|
|
1007
|
+
return homeId;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
/** Persist one held-request row (`held`: normalizeHeldRequest fields) for
|
|
1011
|
+
* `agentId`'s home thread, then start draining it. Each status posts once. */
|
|
1012
|
+
async function enqueueHeld(agentId, held) {
|
|
1013
|
+
const homeId = agentHomeSessionId(agentId) || agentHomeSessionId(MIXY_AGENT_ID);
|
|
1014
|
+
if (!held?.id) throw new Error('held request: id required');
|
|
1015
|
+
await queue.add(homeId, {
|
|
1016
|
+
runId: `${held.id}_${held.status || 'pending'}`,
|
|
1017
|
+
kind: 'held-request',
|
|
1018
|
+
held,
|
|
1019
|
+
at: Date.now(),
|
|
1020
|
+
});
|
|
1021
|
+
void drain(homeId);
|
|
1022
|
+
return homeId;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/** Persist one report of a coding task session `agentId` created (session
|
|
1026
|
+
* create) for its home thread, then start draining it. `status` 'started'
|
|
1027
|
+
* and 'blocked' only post a line; a turn's end also wakes the agent. */
|
|
1028
|
+
async function enqueueTask(agentId, report) {
|
|
1029
|
+
const { runId, taskSessionId, watchId = '', watchIds = [], from = '' } = report;
|
|
1030
|
+
const homeId = agentHomeSessionId(agentId) || agentHomeSessionId(MIXY_AGENT_ID);
|
|
1031
|
+
if (!runId || !taskSessionId) throw new Error('task report: runId and taskSessionId required');
|
|
1032
|
+
const item = taskReportItem(report);
|
|
1033
|
+
const unwatch = [...new Set([watchId, ...watchIds].filter(Boolean).map(String))];
|
|
1034
|
+
// A room member's own work reports to its member session, never its home.
|
|
1035
|
+
const target = roomMemberOfSession(from)?.agentId === agentId ? from : homeId;
|
|
1036
|
+
if (item.progressRunId) {
|
|
1037
|
+
// Whether its answer already went out as that progress update is
|
|
1038
|
+
// decided in the thread's posting turn, against the thread itself: a
|
|
1039
|
+
// row being posted (or posted before a crash, not dequeued yet) counts
|
|
1040
|
+
// as posted, never as still queued.
|
|
1041
|
+
await postingFor(target, async () =>
|
|
1042
|
+
queue.add(target, item, { unwatch, progressPosted: postedIn(target, item.progressRunId) })
|
|
1043
|
+
);
|
|
1044
|
+
} else {
|
|
1045
|
+
// A progress update moves its send's watch mark (`progressed`) to the
|
|
1046
|
+
// turn it carries, in the same write: a restart never reports it again.
|
|
1047
|
+
const progressed = report.progressWatchId
|
|
1048
|
+
? { runId: String(report.progressWatchId), turnId: String(report.answerId || '') }
|
|
1049
|
+
: null;
|
|
1050
|
+
await queue.add(target, item, { unwatch, progressed });
|
|
1051
|
+
}
|
|
1052
|
+
void drain(target);
|
|
1053
|
+
return target;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
/** Persist `text`, the agent's own reply from turn `runId` it ran outside
|
|
1057
|
+
* its thread, for `agentId`'s home thread, then start draining it. It posts
|
|
1058
|
+
* once, as the agent's message; no turn follows. */
|
|
1059
|
+
async function enqueueMessage(agentId, { runId, text }) {
|
|
1060
|
+
const homeId = agentHomeSessionId(agentId) || agentHomeSessionId(MIXY_AGENT_ID);
|
|
1061
|
+
if (!runId || !String(text || '').trim()) throw new Error('agent message: runId and text required');
|
|
1062
|
+
await queue.add(homeId, { runId: String(runId), kind: 'agent-message', text: String(text).trim(), at: Date.now() });
|
|
1063
|
+
void drain(homeId);
|
|
1064
|
+
return homeId;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
return { enqueue, enqueueHeld, enqueueTask, enqueueMessage };
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
/** The queue's bookkeeping across processes: report watches and the restart
|
|
1071
|
+
* recovery that retires deleted homes and drains what was left queued. */
|
|
1072
|
+
function createHomeBookkeeping({ queue, log, homeDeleted, sessionDeleted, drain }) {
|
|
1073
|
+
/** Retire the bookkeeping of deleted homes (and stale round counts). */
|
|
1074
|
+
async function prune() {
|
|
1075
|
+
await queue.prune((await queue.bookkeptHomes()).filter(homeDeleted));
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/** Store `watch`; a home at its watch cap first gives up its oldest watches
|
|
1079
|
+
* whose target sessions are proven deleted, and refuses the watch (so the
|
|
1080
|
+
* send claims no report) when that frees too few. */
|
|
1081
|
+
async function watchTask(watch) {
|
|
1082
|
+
const drop = watchesToDrop(await queue.watches(), watch, queue.watchCap, sessionDeleted);
|
|
1083
|
+
if (drop.length) {
|
|
1084
|
+
log(`${watch.homeSessionId} is at its watch cap: dropped ${drop.length} watch(es) of deleted sessions`);
|
|
1085
|
+
}
|
|
1086
|
+
await queue.watch(watch, { drop });
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/** Drain every queue left by an earlier process, after retiring stale bookkeeping. */
|
|
1090
|
+
async function recover() {
|
|
1091
|
+
try {
|
|
1092
|
+
await prune();
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
log(`pruning the routine results failed: ${error?.message || error}`);
|
|
1095
|
+
}
|
|
1096
|
+
// The stored watches name the hand-offs an earlier process left open:
|
|
1097
|
+
// reading them notes each one now, so a target that asks again after the
|
|
1098
|
+
// restart reaches the chat that handed it the work.
|
|
1099
|
+
try {
|
|
1100
|
+
await queue.watches();
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
log(`reading the report watches failed: ${error?.message || error}`);
|
|
1103
|
+
}
|
|
1104
|
+
const homes = await queue.pendingHomes();
|
|
1105
|
+
for (const homeId of homes) void drain(homeId);
|
|
1106
|
+
return homes;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
return { watchTask, recover };
|
|
1110
|
+
}
|
|
1111
|
+
|
|
810
1112
|
export function createAgentHomeDelivery({
|
|
811
1113
|
loadSession,
|
|
812
1114
|
saveSession,
|
|
@@ -828,6 +1130,9 @@ export function createAgentHomeDelivery({
|
|
|
828
1130
|
// at all. 'none' (proven: a workflow agent such as Reviewer) drops the rows
|
|
829
1131
|
// queued for its missing home instead of waiting on it forever.
|
|
830
1132
|
homeAgent = () => 'unknown',
|
|
1133
|
+
// Whether the representative bot exists (mixy-presence.mjs): while it does
|
|
1134
|
+
// not, heartbeat reports queued for its home are dropped.
|
|
1135
|
+
mixyExists = async () => true,
|
|
831
1136
|
// Waits before each new try of a relay turn that did not finish; past the
|
|
832
1137
|
// last one the results stay posted with a note and nobody is woken.
|
|
833
1138
|
wakeRetryDelaysMs = WAKE_RETRY_DELAYS_MS,
|
|
@@ -840,19 +1145,20 @@ export function createAgentHomeDelivery({
|
|
|
840
1145
|
roomRelay = (sessionId, prompt, options) => agentRoomHost().relay(sessionId, prompt, options),
|
|
841
1146
|
log = (line) => process.stderr.write(`mixdog routines: ${line}\n`),
|
|
842
1147
|
}) {
|
|
843
|
-
const busy = (
|
|
844
|
-
if (turnInFlight(sessionId)) return true;
|
|
845
|
-
try {
|
|
846
|
-
return live()?.busy?.(sessionId) === true;
|
|
847
|
-
} catch {
|
|
848
|
-
return false;
|
|
849
|
-
}
|
|
850
|
-
};
|
|
1148
|
+
const busy = homeBusy(turnInFlight, live);
|
|
851
1149
|
const draining = new Map(); // home → the running pass
|
|
852
1150
|
const again = new Set(); // homes enqueued to while their pass ran
|
|
853
|
-
const waiting = new Set(); // homes with a retry timer armed
|
|
854
|
-
const shownLive = new Set(); // held-request message ids shown live in a busy thread
|
|
855
1151
|
const waitLogged = new Set(); // missing homes whose wait was logged
|
|
1152
|
+
const later = createRetryTimer(retryLater, drain);
|
|
1153
|
+
const heldLive = createHeldLiveDisplay(live, log);
|
|
1154
|
+
const homeDeleted = (homeId) => homeProvenDeleted(homeId, agentPresence, roomPresence);
|
|
1155
|
+
const { dropGoneRoomThread, dropRoomLogQueue, dropHomeless } = createQueueDrops({
|
|
1156
|
+
queue,
|
|
1157
|
+
log,
|
|
1158
|
+
homeAgent,
|
|
1159
|
+
homeDeleted,
|
|
1160
|
+
sessionDeleted,
|
|
1161
|
+
});
|
|
856
1162
|
const relay = createHomeRelay({
|
|
857
1163
|
queue,
|
|
858
1164
|
saveSession,
|
|
@@ -867,61 +1173,123 @@ export function createAgentHomeDelivery({
|
|
|
867
1173
|
busyRetryMs,
|
|
868
1174
|
missingRetryMs,
|
|
869
1175
|
});
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
1176
|
+
// Per thread, one posting turn at a time: push queued rows, save the
|
|
1177
|
+
// thread, dequeue them (the drain, the turn prelude), and a final report's
|
|
1178
|
+
// check whether its answer already went out as a progress update. No pass
|
|
1179
|
+
// ever dequeues rows another pushed but has not saved yet, and a row being
|
|
1180
|
+
// posted is never mistaken for one still queued.
|
|
1181
|
+
const postingChains = new Map();
|
|
1182
|
+
function postingFor(homeId, fn) {
|
|
1183
|
+
const run = (postingChains.get(homeId) || Promise.resolve()).then(fn);
|
|
1184
|
+
const tail = run.then(
|
|
1185
|
+
() => {},
|
|
1186
|
+
() => {}
|
|
1187
|
+
);
|
|
1188
|
+
postingChains.set(homeId, tail);
|
|
1189
|
+
void tail.then(() => {
|
|
1190
|
+
if (postingChains.get(homeId) === tail) postingChains.delete(homeId);
|
|
1191
|
+
});
|
|
1192
|
+
return run;
|
|
882
1193
|
}
|
|
1194
|
+
/** Whether queued row `runId` is in thread `homeId` (posted, saved or not). */
|
|
1195
|
+
const postedIn = (homeId, runId) => {
|
|
1196
|
+
const messages = loadSession(homeId)?.messages;
|
|
1197
|
+
const messageId = messageIdOf(runId);
|
|
1198
|
+
return Array.isArray(messages) && messages.some((message) => message?.meta?.transcript?.messageId === messageId);
|
|
1199
|
+
};
|
|
1200
|
+
const intake = createHomeEnqueue(queue, drain, { postingFor, postedIn });
|
|
1201
|
+
const { watchTask, recover } = createHomeBookkeeping({ queue, log, homeDeleted, sessionDeleted, drain });
|
|
883
1202
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
},
|
|
1203
|
+
/** Append `items` (and the omission notice `omitted`) not posted before to
|
|
1204
|
+
* `homeId`'s thread `session`, store it and show the new rows live.
|
|
1205
|
+
* Returns the run ids owed a wake (postQueuedRows). Nothing awaits before
|
|
1206
|
+
* the push, so no turn can start in between. */
|
|
1207
|
+
async function postRows(homeId, session, items, omitted) {
|
|
1208
|
+
if (!Array.isArray(session.messages)) session.messages = [];
|
|
1209
|
+
const { fresh, toWake } = postQueuedRows(session, items, omitted);
|
|
1210
|
+
heldLive.forget(items);
|
|
1211
|
+
// The caller dequeues `items` (and `omitted`) next: the thread holding
|
|
1212
|
+
// them is saved first, also when an earlier pass pushed them but its save
|
|
1213
|
+
// failed (they are in the thread in memory, not on disk).
|
|
1214
|
+
if (items.length || omitted) {
|
|
1215
|
+
if (fresh.length) session.updatedAt = Date.now();
|
|
1216
|
+
await saveSession(session);
|
|
1217
|
+
}
|
|
1218
|
+
for (const { message, notice } of fresh) {
|
|
1219
|
+
const { messageId, at } = message.meta.transcript;
|
|
1220
|
+
noticeLive(live, log, homeId, { ...notice, messageId, at });
|
|
1221
|
+
}
|
|
1222
|
+
return toWake;
|
|
891
1223
|
}
|
|
892
1224
|
|
|
893
|
-
/**
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1225
|
+
/** Right before a turn of thread `homeId` takes its prompt (whatever started
|
|
1226
|
+
* it: the user, a routine, a wake): post its queued rows that wake nobody —
|
|
1227
|
+
* progress updates of the sessions its agent handed work to, start and wait
|
|
1228
|
+
* lines, held requests, routine results — in queue order, so the turn reads
|
|
1229
|
+
* them before its prompt. Rows that wake the agent stay for the drain after
|
|
1230
|
+
* the turn, which posts them and wakes it as before. The caller starts the
|
|
1231
|
+
* turn, so the thread's busy state is its own. Rows the queue dropped past
|
|
1232
|
+
* its limit are announced first by the "n omitted" notice, retired in the
|
|
1233
|
+
* same write that dequeues the posted rows (as the drain does). It runs
|
|
1234
|
+
* in the thread's posting turn (postingFor), never beside the drain's. A
|
|
1235
|
+
* failure is logged; the turn goes on and the drain posts the rows later. */
|
|
1236
|
+
async function postBeforeTurn(homeId) {
|
|
1237
|
+
try {
|
|
1238
|
+
await postingFor(homeId, async () => {
|
|
1239
|
+
const items = (await queue.items(homeId)).filter((item) => !wakesAgent(item));
|
|
1240
|
+
const omitted = await queue.omitted(homeId);
|
|
1241
|
+
if (!items.length && !omitted) return;
|
|
1242
|
+
const session = loadSession(homeId);
|
|
1243
|
+
if (!session || session.closed === true) return;
|
|
1244
|
+
await postRows(homeId, session, items, omitted);
|
|
1245
|
+
await queue.remove(
|
|
1246
|
+
homeId,
|
|
1247
|
+
items.map((item) => item.runId),
|
|
1248
|
+
omitted
|
|
1249
|
+
);
|
|
1250
|
+
});
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
log(`posting the rows owed before a turn of ${homeId} failed: ${error?.message || error}`);
|
|
1253
|
+
}
|
|
899
1254
|
}
|
|
900
1255
|
|
|
901
|
-
/**
|
|
902
|
-
*
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1256
|
+
/** Mixy's heartbeat reports queued for her home while she does not exist
|
|
1257
|
+
* are dropped, never posted once she is created (issue #243); so is the
|
|
1258
|
+
* omission notice when nothing else waits (the rows it counts were these
|
|
1259
|
+
* reports too). Returns what is left to post. */
|
|
1260
|
+
async function dropHeartbeatReports(homeId, items, omitted) {
|
|
1261
|
+
const kept = items.filter((item) => !isHeartbeatReport(item));
|
|
1262
|
+
const retired = kept.length ? null : omitted;
|
|
1263
|
+
log(`${items.length - kept.length} heartbeat report(s) for ${homeId} are dropped: Mixy was never created`);
|
|
1264
|
+
await queue.remove(
|
|
1265
|
+
homeId,
|
|
1266
|
+
items.filter(isHeartbeatReport).map((item) => item.runId),
|
|
1267
|
+
retired
|
|
1268
|
+
);
|
|
1269
|
+
return { items: kept, omitted: retired ? null : omitted };
|
|
906
1270
|
}
|
|
907
1271
|
|
|
908
|
-
/**
|
|
909
|
-
*
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
await
|
|
915
|
-
return true;
|
|
1272
|
+
/** Post every queued result of `homeId` if its thread is idle, in its
|
|
1273
|
+
* posting turn, then wake the agent for what it owes; else retry later.
|
|
1274
|
+
* The wake runs outside the posting turn: the turn it starts posts first
|
|
1275
|
+
* (postBeforeTurn). */
|
|
1276
|
+
async function drainOnce(homeId) {
|
|
1277
|
+
const session = await postingFor(homeId, () => postIdle(homeId));
|
|
1278
|
+
if (session) await relay.wakeOwed(homeId, session);
|
|
916
1279
|
}
|
|
917
1280
|
|
|
918
|
-
/**
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1281
|
+
/** drainOnce's posting: the thread it posted to; nothing when nothing is
|
|
1282
|
+
* owed or the pass ends here (moved, busy, missing, dropped). */
|
|
1283
|
+
async function postIdle(homeId) {
|
|
1284
|
+
let items = await queue.items(homeId);
|
|
1285
|
+
let omitted = await queue.omitted(homeId);
|
|
922
1286
|
const owed = owesWake(await queue.wakes(homeId));
|
|
923
1287
|
if (!items.length && !omitted && !owed) return;
|
|
924
1288
|
if (roomIdOfSession(homeId)) return dropRoomLogQueue(homeId, items, omitted);
|
|
1289
|
+
if (homeId === MIXY_HOME && items.some(isHeartbeatReport) && !(await mixyExists())) {
|
|
1290
|
+
({ items, omitted } = await dropHeartbeatReports(homeId, items, omitted));
|
|
1291
|
+
if (!items.length && !omitted && !owed) return;
|
|
1292
|
+
}
|
|
925
1293
|
const agentId = agentIdOfHomeSession(homeId);
|
|
926
1294
|
if (agentId && agentId !== MIXY_AGENT_ID && agentPresence(agentId) === 'deleted') {
|
|
927
1295
|
// The owner is gone (its home archived): Mixy, the default owner, gets them.
|
|
@@ -933,7 +1301,7 @@ export function createAgentHomeDelivery({
|
|
|
933
1301
|
return;
|
|
934
1302
|
}
|
|
935
1303
|
if (busy(homeId)) {
|
|
936
|
-
|
|
1304
|
+
heldLive.show(homeId, items);
|
|
937
1305
|
return later(homeId, busyRetryMs);
|
|
938
1306
|
}
|
|
939
1307
|
// From here to the push nothing awaits, so no turn can start in between.
|
|
@@ -948,16 +1316,7 @@ export function createAgentHomeDelivery({
|
|
|
948
1316
|
}
|
|
949
1317
|
return later(homeId, missingRetryMs);
|
|
950
1318
|
}
|
|
951
|
-
|
|
952
|
-
const { fresh, toWake } = postQueuedRows(session, items, omitted);
|
|
953
|
-
for (const item of items) shownLive.delete(messageIdOf(item.runId));
|
|
954
|
-
if (fresh.length) {
|
|
955
|
-
session.updatedAt = Date.now();
|
|
956
|
-
await saveSession(session);
|
|
957
|
-
for (const { message, notice } of fresh) {
|
|
958
|
-
noticeLive(live, log, homeId, { ...notice, messageId: message.meta.transcript.messageId });
|
|
959
|
-
}
|
|
960
|
-
}
|
|
1319
|
+
const toWake = await postRows(homeId, session, items, omitted);
|
|
961
1320
|
// Dequeuing and owing the wake are one write: no restart between posting
|
|
962
1321
|
// and waking loses the wake.
|
|
963
1322
|
const { overflowed } = await queue.remove(
|
|
@@ -967,7 +1326,7 @@ export function createAgentHomeDelivery({
|
|
|
967
1326
|
{ wake: toWake }
|
|
968
1327
|
);
|
|
969
1328
|
if (overflowed) log(`${homeId} is at its wake cap: ${overflowed} result(s) ride the next wake as a count`);
|
|
970
|
-
|
|
1329
|
+
return session;
|
|
971
1330
|
}
|
|
972
1331
|
|
|
973
1332
|
/** The single drainer of `homeId`; a call during a pass runs one more pass. */
|
|
@@ -994,59 +1353,6 @@ export function createAgentHomeDelivery({
|
|
|
994
1353
|
return pass;
|
|
995
1354
|
}
|
|
996
1355
|
|
|
997
|
-
/** Persist `result` ({ runId, kind, ok, text, runSessionId }) of a schedule
|
|
998
|
-
* or webhook `row` for its owner's home, then start draining it. Resolves
|
|
999
|
-
* once it is queued. */
|
|
1000
|
-
async function enqueue(row, result) {
|
|
1001
|
-
const homeId = agentHomeSessionId(scheduleOwnerAgentId(row));
|
|
1002
|
-
if (!result?.runId) throw new Error('routine result: runId required');
|
|
1003
|
-
await queue.add(homeId, routineResultItem(row, result));
|
|
1004
|
-
void drain(homeId);
|
|
1005
|
-
return homeId;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
/** Persist one held-request row (`held`: normalizeHeldRequest fields) for
|
|
1009
|
-
* `agentId`'s home thread, then start draining it. Each status posts once. */
|
|
1010
|
-
async function enqueueHeld(agentId, held) {
|
|
1011
|
-
const homeId = agentHomeSessionId(agentId) || agentHomeSessionId(MIXY_AGENT_ID);
|
|
1012
|
-
if (!held?.id) throw new Error('held request: id required');
|
|
1013
|
-
await queue.add(homeId, {
|
|
1014
|
-
runId: `${held.id}_${held.status || 'pending'}`,
|
|
1015
|
-
kind: 'held-request',
|
|
1016
|
-
held,
|
|
1017
|
-
at: Date.now(),
|
|
1018
|
-
});
|
|
1019
|
-
void drain(homeId);
|
|
1020
|
-
return homeId;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
/** Persist one report of a coding task session `agentId` created (session
|
|
1024
|
-
* create) for its home thread, then start draining it. `status` 'started'
|
|
1025
|
-
* and 'blocked' only post a line; a turn's end also wakes the agent. */
|
|
1026
|
-
async function enqueueTask(agentId, report) {
|
|
1027
|
-
const { runId, taskSessionId, watchId = '', watchIds = [], from = '' } = report;
|
|
1028
|
-
const homeId = agentHomeSessionId(agentId) || agentHomeSessionId(MIXY_AGENT_ID);
|
|
1029
|
-
if (!runId || !taskSessionId) throw new Error('task report: runId and taskSessionId required');
|
|
1030
|
-
const item = taskReportItem(report);
|
|
1031
|
-
const unwatch = [...new Set([watchId, ...watchIds].filter(Boolean).map(String))];
|
|
1032
|
-
// A room member's own work reports to its member session, never its home.
|
|
1033
|
-
const target = roomMemberOfSession(from)?.agentId === agentId ? from : homeId;
|
|
1034
|
-
await queue.add(target, item, { unwatch });
|
|
1035
|
-
void drain(target);
|
|
1036
|
-
return target;
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
/** Persist `text`, the agent's own reply from turn `runId` it ran outside
|
|
1040
|
-
* its thread, for `agentId`'s home thread, then start draining it. It posts
|
|
1041
|
-
* once, as the agent's message; no turn follows. */
|
|
1042
|
-
async function enqueueMessage(agentId, { runId, text }) {
|
|
1043
|
-
const homeId = agentHomeSessionId(agentId) || agentHomeSessionId(MIXY_AGENT_ID);
|
|
1044
|
-
if (!runId || !String(text || '').trim()) throw new Error('agent message: runId and text required');
|
|
1045
|
-
await queue.add(homeId, { runId: String(runId), kind: 'agent-message', text: String(text).trim(), at: Date.now() });
|
|
1046
|
-
void drain(homeId);
|
|
1047
|
-
return homeId;
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
1356
|
/** Show `run`'s live-only row (routineRunNotice: `running`, or a result whose
|
|
1051
1357
|
* delivery failed) in `row`'s owner home when it is open and idle. Nothing
|
|
1052
1358
|
* is stored and no turn or unread mark follows; the posted result (same
|
|
@@ -1058,48 +1364,19 @@ export function createAgentHomeDelivery({
|
|
|
1058
1364
|
return noticeLive(live, log, homeId, notice) === true;
|
|
1059
1365
|
}
|
|
1060
1366
|
|
|
1061
|
-
const homeDeleted = (homeId) => homeProvenDeleted(homeId, agentPresence, roomPresence);
|
|
1062
|
-
|
|
1063
|
-
/** Retire the bookkeeping of deleted homes (and stale round counts). */
|
|
1064
|
-
async function prune() {
|
|
1065
|
-
await queue.prune((await queue.bookkeptHomes()).filter(homeDeleted));
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
/** Store `watch`; a home at its watch cap first gives up its oldest watches
|
|
1069
|
-
* whose target sessions are proven deleted, and refuses the watch (so the
|
|
1070
|
-
* send claims no report) when that frees too few. */
|
|
1071
|
-
async function watchTask(watch) {
|
|
1072
|
-
const drop = watchesToDrop(await queue.watches(), watch, queue.watchCap, sessionDeleted);
|
|
1073
|
-
if (drop.length) {
|
|
1074
|
-
log(`${watch.homeSessionId} is at its watch cap: dropped ${drop.length} watch(es) of deleted sessions`);
|
|
1075
|
-
}
|
|
1076
|
-
await queue.watch(watch, { drop });
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
/** Drain every queue left by an earlier process, after retiring stale bookkeeping. */
|
|
1080
|
-
async function recover() {
|
|
1081
|
-
try {
|
|
1082
|
-
await prune();
|
|
1083
|
-
} catch (error) {
|
|
1084
|
-
log(`pruning the routine results failed: ${error?.message || error}`);
|
|
1085
|
-
}
|
|
1086
|
-
const homes = await queue.pendingHomes();
|
|
1087
|
-
for (const homeId of homes) void drain(homeId);
|
|
1088
|
-
return homes;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
1367
|
return {
|
|
1092
|
-
|
|
1093
|
-
enqueueHeld,
|
|
1094
|
-
enqueueTask,
|
|
1095
|
-
enqueueMessage,
|
|
1368
|
+
...intake,
|
|
1096
1369
|
announce,
|
|
1097
1370
|
drain,
|
|
1371
|
+
postBeforeTurn,
|
|
1098
1372
|
recover,
|
|
1099
1373
|
watchTask,
|
|
1100
1374
|
unwatchTask: (runId) => queue.unwatch(runId),
|
|
1101
1375
|
followTask: (runId, submissionId) => queue.followWatch(runId, submissionId),
|
|
1102
1376
|
taskWatches: () => queue.watches(),
|
|
1377
|
+
ownTask: (work) => queue.own(work),
|
|
1378
|
+
disownTask: (runId) => queue.disown(runId),
|
|
1379
|
+
ownedTasks: () => queue.owned(),
|
|
1103
1380
|
resetRounds: (homeId) => queue.resetRounds(homeId),
|
|
1104
1381
|
};
|
|
1105
1382
|
}
|
|
@@ -1136,6 +1413,9 @@ async function processDelivery() {
|
|
|
1136
1413
|
// A home chat exists only for bots; only a definition read successfully
|
|
1137
1414
|
// can prove an agent is none (readHomeAgent).
|
|
1138
1415
|
homeAgent: (agentId) => readHomeAgent({ dataDir: getPluginData(), shippedRoot: mixdogRoot(), id: agentId }),
|
|
1416
|
+
// The one rule (mixy-presence.mjs; routine-owner.mjs imports this
|
|
1417
|
+
// module, hence late).
|
|
1418
|
+
mixyExists: async () => (await import('./routine-owner.mjs')).readMixyExists(),
|
|
1139
1419
|
// Deleting a session unlinks its record (session-delete.mjs) and leaves
|
|
1140
1420
|
// no tombstone: only an absent file with no in-memory copy proves it.
|
|
1141
1421
|
// An unreadable file probes 'unreadable' and stays.
|
|
@@ -1192,6 +1472,21 @@ export async function followAgentTask(runId, submissionId) {
|
|
|
1192
1472
|
return (await processDelivery()).followTask(runId, submissionId);
|
|
1193
1473
|
}
|
|
1194
1474
|
|
|
1475
|
+
/** Keep the record of one bot-sent turn that reports nothing until its work ends. */
|
|
1476
|
+
export async function ownAgentTask(work) {
|
|
1477
|
+
return (await processDelivery()).ownTask(work);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
/** Drop the record of one bot-sent turn that reports nothing (its work ended). */
|
|
1481
|
+
export async function disownAgentTask(runId) {
|
|
1482
|
+
return (await processDelivery()).disownTask(runId);
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
/** The bot-sent turns that report nothing and whose work was not seen to end. */
|
|
1486
|
+
export async function agentOwnedTasks() {
|
|
1487
|
+
return (await processDelivery()).ownedTasks();
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1195
1490
|
/** A user's own message in `homeId`: its round trips with every target restart. */
|
|
1196
1491
|
export async function resetAgentTaskRounds(homeId) {
|
|
1197
1492
|
return (await processDelivery()).resetRounds(homeId);
|
|
@@ -1202,6 +1497,15 @@ export async function agentTaskWatches() {
|
|
|
1202
1497
|
return (await processDelivery()).taskWatches();
|
|
1203
1498
|
}
|
|
1204
1499
|
|
|
1500
|
+
/** The session turn prelude (session-turn-prelude.mjs) of the daemon: before a
|
|
1501
|
+
* turn of an agent's home thread or a room member session starts, its queued
|
|
1502
|
+
* rows that wake nobody post first (postBeforeTurn). Null for any other
|
|
1503
|
+
* session: nothing to wait for. */
|
|
1504
|
+
export function postBeforeAgentTurn(sessionId) {
|
|
1505
|
+
if (!isAgentHomeSessionId(sessionId) && !roomMemberOfSession(sessionId)) return null;
|
|
1506
|
+
return processDelivery().then((delivery) => delivery.postBeforeTurn(sessionId));
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1205
1509
|
/** Daemon start: post the results an earlier process left queued. */
|
|
1206
1510
|
export async function recoverScheduleResults() {
|
|
1207
1511
|
return (await processDelivery()).recover();
|