mixdog 1.3.4 → 1.4.0
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/LICENSES/oh-my-pi-MIT.txt +23 -0
- package/NOTICE.md +17 -2
- package/README.md +11 -0
- package/package.json +3 -11
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/embed-google-oauth-client.mjs +49 -0
- package/scripts/gate-local.mjs +4 -2
- package/scripts/lib/test-spawn-ledger.mjs +46 -1
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +10 -1
- package/scripts/test.mjs +12 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +25 -1
- package/src/defaults/skills/browser-use/SKILL.md +77 -17
- 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 +33 -9
- package/src/defaults/skills/setup/SKILL.md +29 -2
- package/src/defaults/skills/setup/references/actions.md +117 -28
- package/src/defaults/skills/setup/references/surfaces.md +77 -35
- package/src/defaults/skills/setup-guide/SKILL.md +3 -3
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/keychain-cjs.cjs +359 -29
- package/src/lib/rules-builder.cjs +10 -8
- package/src/rules/agent/AGENT.md +6 -6
- package/src/rules/agent-mode/AGENT_MODE.md +10 -2
- package/src/rules/agent-mode/MIXY.md +12 -0
- package/src/rules/lead/LEAD.md +18 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
- 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/config.mjs +34 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +177 -73
- package/src/runtime/agent/orchestrator/mcp/client.mjs +25 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +230 -137
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +64 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- 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.mjs +160 -69
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +142 -104
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
- package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
- package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -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 +19 -1
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
- 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/opencode-go-gemini.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
- 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 +43 -3
- 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/providers/wire-protobuf-codec.mjs +368 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- 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 +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +148 -25
- 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/eager-dispatch.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +47 -9
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +51 -3
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -2
- 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 +14 -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 +10 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +23 -5
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
- 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-commit.mjs +2 -0
- 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 +14 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -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 +23 -13
- 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 +129 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
- package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
- package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +47 -11
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
- 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-persistence-events.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +133 -18
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
- package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
- 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/tool-batch/state.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +25 -2
- 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/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/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.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- 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/schedule-errors.mjs +51 -0
- package/src/runtime/channels/lib/scheduler.mjs +135 -154
- package/src/runtime/channels/lib/schedules-db.mjs +83 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +14 -2
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- 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 +19 -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 +27 -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/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/com/com-adapter.mjs +17 -1
- package/src/runtime/office/com/office-com-host.ps1 +51 -1
- package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
- package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
- package/src/runtime/office/pdf/document-preview.mjs +326 -8
- package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
- package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
- package/src/runtime/office/portable/portable-soffice.mjs +45 -5
- 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-hops.mjs +62 -2
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +51 -35
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +33 -2
- package/src/runtime/shared/connector-catalog.mjs +166 -8
- package/src/runtime/shared/connector-triggers.mjs +22 -19
- package/src/runtime/shared/defaults-separation.mjs +2 -14
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/developer-options.mjs +32 -1
- package/src/runtime/shared/err-text.mjs +24 -15
- 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/google-oauth-client.generated.json +4 -0
- package/src/runtime/shared/google-oauth-client.mjs +34 -9
- 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 +104 -0
- package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/llm/well-formed.mjs +66 -0
- package/src/runtime/shared/mixy-presence.mjs +22 -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 +231 -59
- package/src/runtime/shared/provider-api-key.mjs +19 -8
- 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 +52 -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 +34 -1
- 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-execution-contract.mjs +2 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -14
- package/src/runtime/shared/transcript-metadata.mjs +38 -0
- package/src/runtime/shared/user-data-guard.mjs +30 -2
- package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
- package/src/runtime/shared/worktrees/test-support.mjs +9 -4
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +27 -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 +486 -179
- package/src/session-runtime/agent-room-delivery.mjs +28 -1
- package/src/session-runtime/agent-task-sessions.mjs +561 -199
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/begin.mjs +3 -2
- 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 +8 -1
- package/src/session-runtime/bot-chain.mjs +32 -0
- package/src/session-runtime/bot-status.mjs +7 -4
- package/src/session-runtime/channel-config-api.mjs +63 -17
- package/src/session-runtime/config-lifecycle.mjs +6 -0
- package/src/session-runtime/connector-merge-migration.mjs +305 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
- package/src/session-runtime/internal-tool-executor.mjs +4 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
- 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 +61 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +927 -0
- package/src/session-runtime/model-route/route-tuning.mjs +10 -6
- 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 +35 -13
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/provider-auth/login.mjs +7 -0
- package/src/session-runtime/provider-models/row-hydration.mjs +13 -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/routine-home-turn.mjs +33 -6
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/schedule-session-run.mjs +7 -3
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- 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 +73 -31
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/channel-worker.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +128 -25
- package/src/session-runtime/services/schedule-access.mjs +14 -0
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +8 -4
- 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 +28 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +187 -29
- package/src/session-runtime/setup-tool/extended-actions.mjs +33 -2
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +68 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +92 -6
- package/src/session-runtime/task-session-route.mjs +99 -0
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +21 -4
- package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
- package/src/session-runtime/tool-surface.mjs +4 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
- package/src/session-runtime/workspace/transitions.mjs +10 -2
- 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 +161 -157
- package/src/standalone/daemon.mjs +33 -2
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +10 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
- package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
- 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 +23 -2
- package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-service.mjs +13 -0
- package/src/standalone/session-tool-output.mjs +21 -10
- package/src/tui/app/model-options.mjs +4 -27
- package/src/tui/dist/index.mjs +81 -65
- 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 +23 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/integrations.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +8 -0
- 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 +30 -2
- 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 +5 -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 +36 -3
- package/src/tui/session/turn.mjs +23 -2
- 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
|
@@ -8,29 +8,73 @@ import {
|
|
|
8
8
|
} from '../../runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs';
|
|
9
9
|
import { createCallerContextResolvers } from './caller-context.mjs';
|
|
10
10
|
import { runAbortable } from '../../runtime/shared/abort-race.mjs';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
HANDOFF_OUTCOMES as AGENT_OUTCOMES,
|
|
13
|
+
SECRET_REQUEST_TIMEOUT_MS,
|
|
14
|
+
} from '../../runtime/agent/orchestrator/session/human-gate/requests.mjs';
|
|
12
15
|
import {
|
|
13
16
|
agentIdForSession,
|
|
14
17
|
recordHumanDecision,
|
|
15
18
|
unattendedApprovalPort,
|
|
16
19
|
} from '../../runtime/agent/orchestrator/session/human-gate/gate.mjs';
|
|
17
|
-
import { browserSecretInput } from '../../runtime/browser-bridge/client.mjs';
|
|
18
|
-
import { computerSecretInput } from '../../runtime/computer-bridge/client.mjs';
|
|
20
|
+
import { browserHandoffPage, browserSecretInput } from '../../runtime/browser-bridge/client.mjs';
|
|
21
|
+
import { computerSecretBind, computerSecretInput } from '../../runtime/computer-bridge/client.mjs';
|
|
22
|
+
|
|
23
|
+
/** The settle reason of a takeover that expired (desktop takeover-gate.ts
|
|
24
|
+
* TAKEOVER_EXPIRED_REASON). */
|
|
25
|
+
const TAKEOVER_EXPIRED_REASON = 'expired';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The agent's result of a secret request, from the card's answer and the
|
|
29
|
+
* desktop's fill: one of requests.mjs HANDOFF_OUTCOMES. `fill` runs only for a provided
|
|
30
|
+
* value and answers 'entered' / 'no_field' / 'page_changed' / 'blocked' /
|
|
31
|
+
* 'expired'.
|
|
32
|
+
*/
|
|
33
|
+
export async function secretOutcome(result, fill) {
|
|
34
|
+
if (result?.timedOut === true || result?.reason === TAKEOVER_EXPIRED_REASON) return 'expired';
|
|
35
|
+
if (result?.approved !== true || result.response !== 'provide-secret') return 'user_skipped';
|
|
36
|
+
const filled = await fill();
|
|
37
|
+
return AGENT_OUTCOMES.includes(filled) && filled !== 'user_skipped' ? filled : 'blocked';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** A page address as the agent may see it: origin and path, no query or
|
|
41
|
+
* fragment (a sign-in redirect can carry a code or token there). */
|
|
42
|
+
function factUrl(value) {
|
|
43
|
+
try {
|
|
44
|
+
const url = new URL(String(value || ''));
|
|
45
|
+
return url.protocol === 'http:' || url.protocol === 'https:' ? `${url.origin}${url.pathname}` : '';
|
|
46
|
+
} catch {
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The agent's result of a takeover: what the user did and where the page is
|
|
52
|
+
* now, never "signed in" (the agent checks the page). */
|
|
53
|
+
export function takeoverOutcome(result, pageUrl = '') {
|
|
54
|
+
if (result?.timedOut === true || result?.reason === TAKEOVER_EXPIRED_REASON) return 'expired';
|
|
55
|
+
if (result?.approved !== true) return 'user_skipped';
|
|
56
|
+
const url = factUrl(pageUrl);
|
|
57
|
+
const did = result.reason === 'saved_login' ? 'User chose a saved login; it was filled in' : 'User pressed Done';
|
|
58
|
+
return url ? `${did}; page now at ${url}` : did;
|
|
59
|
+
}
|
|
19
60
|
|
|
20
61
|
/**
|
|
21
|
-
* A secret or takeover handoff. Secret:
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* (
|
|
27
|
-
* main/takeover-gate.ts); the result is '
|
|
62
|
+
* A secret or takeover handoff. Secret: at request time the desktop binds the
|
|
63
|
+
* request to its page ({pageId, origin}) or, for computer use, it is bound to
|
|
64
|
+
* {window_id, ref}; the card collects the value on the desktop, which holds it
|
|
65
|
+
* for `requestId` and fills only that page, only while its origin is
|
|
66
|
+
* unchanged. Here only the outcome travels (secretOutcome). Takeover: the run
|
|
67
|
+
* waits until the user says done (that session's actions stay blocked
|
|
68
|
+
* meanwhile, desktop main/takeover-gate.ts); the result is takeoverOutcome's.
|
|
28
69
|
*/
|
|
29
70
|
export async function runAskUserHandoff(handoff, { hook, sessionId, toolCallId, signal, inputs = {} }) {
|
|
30
71
|
const secretInput = {
|
|
31
72
|
browser: inputs.browser || browserSecretInput,
|
|
32
73
|
computer: inputs.computer || computerSecretInput,
|
|
33
74
|
};
|
|
75
|
+
const page = inputs.page || browserHandoffPage;
|
|
76
|
+
const bindComputer = inputs.computerBind || computerSecretBind;
|
|
77
|
+
const identity = handoff.identity || {};
|
|
34
78
|
const gate = {
|
|
35
79
|
agentId: agentIdForSession(sessionId),
|
|
36
80
|
kind: handoff.kind,
|
|
@@ -47,32 +91,84 @@ export async function runAskUserHandoff(handoff, { hook, sessionId, toolCallId,
|
|
|
47
91
|
return UNATTENDED_TAKEOVER;
|
|
48
92
|
}
|
|
49
93
|
if (typeof hook !== 'function') {
|
|
50
|
-
// Nobody can take over here: blocked, never "proceed".
|
|
94
|
+
// Nobody can take over or type here: blocked, never "proceed".
|
|
51
95
|
if (handoff.kind === 'takeover') return NO_TAKEOVER;
|
|
52
|
-
await recordHumanDecision(gate, { response: '
|
|
53
|
-
return '
|
|
96
|
+
await recordHumanDecision(gate, { response: 'blocked' });
|
|
97
|
+
return 'blocked';
|
|
54
98
|
}
|
|
55
99
|
if (handoff.kind === 'secret') {
|
|
56
100
|
const requestId = `secret_${randomUUID()}`;
|
|
101
|
+
// Bound now: the page (and its origin) the value may go to, and what its
|
|
102
|
+
// field is. A browser page that cannot be bound, or has no such field,
|
|
103
|
+
// never asks the user for a value it could not place.
|
|
104
|
+
let bound = {};
|
|
105
|
+
if (handoff.surface === 'browser') {
|
|
106
|
+
const facts = await page(
|
|
107
|
+
sessionId,
|
|
108
|
+
'secret_bind',
|
|
109
|
+
{ request_id: requestId, ...(identity.tab ? { tab: identity.tab } : {}), field: handoff.field },
|
|
110
|
+
{ signal }
|
|
111
|
+
);
|
|
112
|
+
let outcome = '';
|
|
113
|
+
if (!facts?.origin) outcome = 'blocked';
|
|
114
|
+
else if (!facts.form) outcome = 'no_field';
|
|
115
|
+
if (outcome) {
|
|
116
|
+
await recordHumanDecision(gate, { response: outcome });
|
|
117
|
+
return outcome;
|
|
118
|
+
}
|
|
119
|
+
bound = { origin: facts.origin, form: facts.form, ...(facts.length ? { length: facts.length } : {}) };
|
|
120
|
+
} else {
|
|
121
|
+
// Computer Use: bound to the exact window and field ref the agent named
|
|
122
|
+
// (from snapshot/find). Without both there is no field to confirm, and
|
|
123
|
+
// none is made up (never the focused field or the front window).
|
|
124
|
+
const outcome =
|
|
125
|
+
identity.windowId && identity.ref
|
|
126
|
+
? await bindComputer(sessionId, requestId, { windowId: identity.windowId, ref: identity.ref, signal })
|
|
127
|
+
: 'no_field';
|
|
128
|
+
if (outcome !== 'bound') {
|
|
129
|
+
const refused = outcome === 'no_field' ? 'no_field' : 'blocked';
|
|
130
|
+
await recordHumanDecision(gate, { response: refused });
|
|
131
|
+
return refused;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
57
134
|
const result = await runAbortable(signal, () =>
|
|
58
135
|
hook({
|
|
59
136
|
name: 'ask_user',
|
|
60
137
|
kind: 'secret',
|
|
61
|
-
secret: { requestId, surface: handoff.surface, target: handoff.target, field: handoff.field },
|
|
138
|
+
secret: { requestId, surface: handoff.surface, target: handoff.target, field: handoff.field, ...bound },
|
|
62
139
|
reason: '',
|
|
63
140
|
timeoutMs: SECRET_REQUEST_TIMEOUT_MS,
|
|
64
141
|
sessionId,
|
|
65
142
|
toolCallId,
|
|
66
143
|
})
|
|
67
144
|
);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
145
|
+
const computerTarget = {
|
|
146
|
+
...(identity.ref ? { ref: identity.ref } : {}),
|
|
147
|
+
...(identity.windowId ? { windowId: identity.windowId } : {}),
|
|
148
|
+
};
|
|
149
|
+
const outcome = await secretOutcome(result, () =>
|
|
150
|
+
secretInput[handoff.surface](sessionId, requestId, {
|
|
151
|
+
signal,
|
|
152
|
+
...(handoff.surface === 'computer' ? computerTarget : {}),
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
await recordHumanDecision(gate, { response: outcome, device: result?.device });
|
|
156
|
+
return outcome;
|
|
75
157
|
}
|
|
158
|
+
// A sign-in page's saved logins (masked) let the card fill one for the
|
|
159
|
+
// user: the desktop offers them only for a page on that origin, bound now
|
|
160
|
+
// under `fillId` so the fill reaches that page alone (host-agent.ts fillBoundLogin).
|
|
161
|
+
const fillId = handoff.login ? `secret_${randomUUID()}` : '';
|
|
162
|
+
const accounts = handoff.login
|
|
163
|
+
? (
|
|
164
|
+
await page(
|
|
165
|
+
sessionId,
|
|
166
|
+
'login_accounts',
|
|
167
|
+
{ url: handoff.login.url, request_id: fillId, ...(identity.tab ? { tab: identity.tab } : {}) },
|
|
168
|
+
{ signal }
|
|
169
|
+
)
|
|
170
|
+
)?.accounts
|
|
171
|
+
: null;
|
|
76
172
|
const result = await runAbortable(signal, () =>
|
|
77
173
|
hook({
|
|
78
174
|
name: 'ask_user',
|
|
@@ -81,9 +177,10 @@ export async function runAskUserHandoff(handoff, { hook, sessionId, toolCallId,
|
|
|
81
177
|
surface: handoff.surface,
|
|
82
178
|
instructions: handoff.instructions,
|
|
83
179
|
target: handoff.target,
|
|
84
|
-
...
|
|
180
|
+
...identity,
|
|
85
181
|
// A login takeover: the desktop opens its sign-in window on this page.
|
|
86
182
|
...(handoff.login ? { purpose: 'login', url: handoff.login.url } : {}),
|
|
183
|
+
...(Array.isArray(accounts) && accounts.length ? { accounts, fillId } : {}),
|
|
87
184
|
},
|
|
88
185
|
args: { surface: handoff.surface, instructions: handoff.instructions },
|
|
89
186
|
reason: '',
|
|
@@ -92,8 +189,15 @@ export async function runAskUserHandoff(handoff, { hook, sessionId, toolCallId,
|
|
|
92
189
|
toolCallId,
|
|
93
190
|
})
|
|
94
191
|
);
|
|
95
|
-
const
|
|
96
|
-
|
|
192
|
+
const pageUrl =
|
|
193
|
+
result?.approved === true && handoff.surface === 'browser'
|
|
194
|
+
? (await page(sessionId, 'page_url', identity.tab ? { tab: identity.tab } : {}, { signal }))?.url
|
|
195
|
+
: '';
|
|
196
|
+
const answer = takeoverOutcome(result, pageUrl);
|
|
197
|
+
await recordHumanDecision(gate, {
|
|
198
|
+
response: answer.startsWith('User ') ? 'done' : answer,
|
|
199
|
+
device: result?.device,
|
|
200
|
+
});
|
|
97
201
|
return answer;
|
|
98
202
|
}
|
|
99
203
|
|
|
@@ -125,7 +229,7 @@ const DISMISSED =
|
|
|
125
229
|
'User closed the questions without answering. Proceed with your best judgment; ask again only if something new depends on it.';
|
|
126
230
|
|
|
127
231
|
/** Wire answers -> array aligned with questions; invalid entries become null. */
|
|
128
|
-
|
|
232
|
+
function normalizeAskUserAnswers(answers, questions) {
|
|
129
233
|
const list = Array.isArray(answers) ? answers.slice(0, 4) : [];
|
|
130
234
|
return questions.map((q, i) => {
|
|
131
235
|
const entry = list[i];
|
|
@@ -143,7 +247,7 @@ export function normalizeAskUserAnswers(answers, questions) {
|
|
|
143
247
|
|
|
144
248
|
// Strings are JSON-quoted so a quote inside one cannot end it early; typed
|
|
145
249
|
// text stays apart from the picked labels (`"picked" + "typed" (typed)`).
|
|
146
|
-
|
|
250
|
+
function formatAskUserAnswers(questions, answers) {
|
|
147
251
|
const quote = (text) => JSON.stringify(text);
|
|
148
252
|
const parts = questions.map((q, i) => {
|
|
149
253
|
const a = answers[i];
|
|
@@ -157,14 +261,14 @@ export function formatAskUserAnswers(questions, answers) {
|
|
|
157
261
|
|
|
158
262
|
/** A composer message sent instead of (or with) picking: kept when it is a
|
|
159
263
|
* non-empty string within the typed-answer limit, else dropped. */
|
|
160
|
-
|
|
264
|
+
function normalizeAskUserReply(reply) {
|
|
161
265
|
if (typeof reply !== 'string' || reply.length > ASK_USER_MAX_TEXT) return '';
|
|
162
266
|
return reply.trim();
|
|
163
267
|
}
|
|
164
268
|
|
|
165
269
|
// `User replied in chat: "<reply>". ` leads, then the usual picks sentence
|
|
166
270
|
// when any question was answered, else just the closing sentence.
|
|
167
|
-
|
|
271
|
+
function formatAskUserResult(questions, answers, reply) {
|
|
168
272
|
if (!reply) return formatAskUserAnswers(questions, answers);
|
|
169
273
|
const lead = `User replied in chat: ${JSON.stringify(reply)}. `;
|
|
170
274
|
if (answers.some(Boolean)) return `${lead}${formatAskUserAnswers(questions, answers)}`;
|
|
@@ -45,6 +45,8 @@ export function createBridgeToolHandlers({ rt }) {
|
|
|
45
45
|
cwd: callerCwd,
|
|
46
46
|
requestApproval: callerCtx?.toolApprovalHook,
|
|
47
47
|
toolCallId: callerCtx?.toolCallId || null,
|
|
48
|
+
// The agent turn, as for the browser: it scopes a saved-login fill's protection.
|
|
49
|
+
turnId: callerCtx?.turnId || rt.session?.usageMetricsTurnId,
|
|
48
50
|
signal: signalFor(callerCtx),
|
|
49
51
|
});
|
|
50
52
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// react: a bot's emoji reaction on the user's message (message-reactions.mjs).
|
|
2
|
+
// Only a bot's own chat with the user may react: its home chat, where the
|
|
3
|
+
// message is in the chat's own transcript, or its seat in a group room, where
|
|
4
|
+
// the message is the user's row in the room's log. Never a coding session, a
|
|
5
|
+
// delegated worker, or a run nobody attends.
|
|
6
|
+
import { isAgentOwner } from '../../runtime/agent/orchestrator/agent-owner.mjs';
|
|
7
|
+
import { noteReactionTarget, validateReactionArgs } from '../../runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs';
|
|
8
|
+
import { agentIdOfHomeSession } from '../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
9
|
+
import { roomMemberOfSession, roomSessionId } from '../../runtime/agent/orchestrator/session/agent-room.mjs';
|
|
10
|
+
import { reactInSession } from '../../runtime/agent/orchestrator/session/message-reactions.mjs';
|
|
11
|
+
import { agentHomeLiveSurface } from '../agent-home-delivery.mjs';
|
|
12
|
+
import { reactInRoom } from '../agent-room-delivery.mjs';
|
|
13
|
+
import { scheduleCallerScope } from '../services/schedule-access.mjs';
|
|
14
|
+
|
|
15
|
+
const DONE =
|
|
16
|
+
'The user sees it under their message. Say nothing about it; reply only if the message also needs an answer.';
|
|
17
|
+
|
|
18
|
+
export function createReactionToolHandlers({ rt, live = agentHomeLiveSurface, roomReact = reactInRoom }) {
|
|
19
|
+
return {
|
|
20
|
+
react: async (args, { callerCtx }) => {
|
|
21
|
+
const sessionId = callerCtx?.callerSessionId || rt.session?.id || '';
|
|
22
|
+
const session = rt.session?.id === sessionId ? rt.session : null;
|
|
23
|
+
const member = roomMemberOfSession(sessionId);
|
|
24
|
+
const agentId = member?.agentId || agentIdOfHomeSession(sessionId);
|
|
25
|
+
if (!session || !agentId || isAgentOwner(session)) {
|
|
26
|
+
throw new Error("react: reactions belong to a bot's own chat with the user");
|
|
27
|
+
}
|
|
28
|
+
if (scheduleCallerScope(session).unattended === true) {
|
|
29
|
+
throw new Error('react: nobody is in this run to see a reaction');
|
|
30
|
+
}
|
|
31
|
+
const { emoji, messagesBack } = validateReactionArgs(args);
|
|
32
|
+
const change = { agentId, emoji, messagesBack };
|
|
33
|
+
let result;
|
|
34
|
+
if (member) result = await roomReact(roomSessionId(member.roomId), change);
|
|
35
|
+
else {
|
|
36
|
+
result = reactInSession(session, change);
|
|
37
|
+
// The chat's own turn saves the transcript; its open views show it now.
|
|
38
|
+
if (result.changed) live()?.react?.(sessionId, result.messageId, result.reactions);
|
|
39
|
+
}
|
|
40
|
+
if (!emoji) return result.changed ? 'Removed your reaction.' : 'You had no reaction on that message.';
|
|
41
|
+
noteReactionTarget(sessionId, callerCtx?.toolCallId, { messageId: result.messageId, room: Boolean(member) });
|
|
42
|
+
return `Reacted ${emoji}. ${DONE}`;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -6,11 +6,17 @@ import { listProjects } from '../../runtime/shared/projects.mjs';
|
|
|
6
6
|
import { applySessionSidebarChange } from '../../runtime/shared/session-sidebar-host.mjs';
|
|
7
7
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
8
8
|
import { AGENT_MODE, resolveSessionMode } from '../../runtime/agent/orchestrator/session/agent-mode.mjs';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
MIXY_AGENT_ID,
|
|
11
|
+
agentHomeSessionId,
|
|
12
|
+
agentIdOfHomeSession,
|
|
13
|
+
} from '../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
10
14
|
import { turnHopOf } from '../../runtime/shared/bot-hops.mjs';
|
|
15
|
+
import { isHeartbeatSession } from '../../runtime/shared/routine-trigger.mjs';
|
|
11
16
|
import { scheduleCallerScope } from '../services/schedule-access.mjs';
|
|
12
17
|
import { worktreeCallerScope } from '../services/worktree-access.mjs';
|
|
13
18
|
import { resolveHandoffAttachments, sessionRoots } from '../handoff-attachments.mjs';
|
|
19
|
+
import { delegationChainOf } from '../bot-chain.mjs';
|
|
14
20
|
|
|
15
21
|
const USER_TITLE_ERROR = 'session: the user already titled this session; the title was not changed';
|
|
16
22
|
|
|
@@ -53,6 +59,14 @@ export function createWorkspaceToolHandlers({
|
|
|
53
59
|
return rt.session.id;
|
|
54
60
|
};
|
|
55
61
|
|
|
62
|
+
// Mixy's hidden heartbeat session (mixy-heartbeat.mjs), by the in-process
|
|
63
|
+
// mark on the calling session, never by tool input or stored fields.
|
|
64
|
+
const callerIsHeartbeat = (callerCtx) => isHeartbeatSession(callerCtx?.callerSessionId || rt.session?.id);
|
|
65
|
+
const HEARTBEAT_NO_HANDOFF =
|
|
66
|
+
'a heartbeat turn cannot hand work off: its result would reach nobody. Propose it to the user instead (session action suggest).';
|
|
67
|
+
// What a heartbeat turn does with sessions: read them and the bots, and record proposals.
|
|
68
|
+
const HEARTBEAT_SESSION_ACTIONS = new Set(['read', 'status', 'list', 'bots', 'suggest']);
|
|
69
|
+
|
|
56
70
|
const SIDEBAR_ACTIONS = new Set(['favorite', 'archive']);
|
|
57
71
|
|
|
58
72
|
// Sidebar flags only (the desktop's favorite/archive metadata).
|
|
@@ -71,12 +85,26 @@ export function createWorkspaceToolHandlers({
|
|
|
71
85
|
const session = async (args, { callerCtx, callerCwd }) => {
|
|
72
86
|
const action = clean(args?.action || (args?.path ? 'set-project' : 'status')).toLowerCase();
|
|
73
87
|
const target = clean(args?.session_id);
|
|
88
|
+
if (callerIsHeartbeat(callerCtx) && !HEARTBEAT_SESSION_ACTIONS.has(action)) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`session: ${
|
|
91
|
+
action === 'create' || action === 'send'
|
|
92
|
+
? HEARTBEAT_NO_HANDOFF
|
|
93
|
+
: `a heartbeat turn only reads sessions and bots and records proposals; action=${action} is refused`
|
|
94
|
+
}`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
74
97
|
if (
|
|
75
98
|
['list', 'bots', 'read', 'send', 'cancel', 'delete', 'create'].includes(action) ||
|
|
76
99
|
(action === 'status' && target)
|
|
77
100
|
) {
|
|
78
101
|
const callerSessionId = assertLead(action, callerCtx);
|
|
102
|
+
// `callerAgentId`: the bot whose conversation gets results reported
|
|
103
|
+
// back; `callerBotId`: the bot the caller acts as, attended or not,
|
|
104
|
+
// for what only a bot's own sessions allow (an effort change).
|
|
79
105
|
const callerAgentId = attendedAgentOf(rt.session);
|
|
106
|
+
const acting = resolveSessionMode({ session: rt.session });
|
|
107
|
+
const callerBotId = acting.mode === AGENT_MODE ? acting.agentId : '';
|
|
80
108
|
if (action === 'create' && !callerAgentId) {
|
|
81
109
|
throw new Error(
|
|
82
110
|
'session: create belongs to a bot conversation; delegated workers, agent task sessions and schedule/webhook runs cannot create agent task sessions'
|
|
@@ -105,8 +133,24 @@ export function createWorkspaceToolHandlers({
|
|
|
105
133
|
{
|
|
106
134
|
callerSessionId,
|
|
107
135
|
callerAgentId,
|
|
136
|
+
callerBotId,
|
|
108
137
|
callerCwd,
|
|
109
|
-
...(action === 'send' || action === 'create'
|
|
138
|
+
...(action === 'send' || action === 'create'
|
|
139
|
+
? {
|
|
140
|
+
callerHop: turnHopOf(rt.session),
|
|
141
|
+
// The bot chain this turn acts in (bot-chain.mjs), checked
|
|
142
|
+
// against the target and carried to the turn it starts —
|
|
143
|
+
// only when the sender is a bot conversation (a bot's chat,
|
|
144
|
+
// room seat or run); any other session hands work to any
|
|
145
|
+
// bot as before, whatever started its turn (the hop limit
|
|
146
|
+
// still bounds a loop).
|
|
147
|
+
callerBotChain: callerBotId
|
|
148
|
+
? delegationChainOf(callerSessionId, (id) =>
|
|
149
|
+
id === rt.session?.id ? rt.session : getSessionManager()?.getSession?.(id) || null
|
|
150
|
+
)
|
|
151
|
+
: [],
|
|
152
|
+
}
|
|
153
|
+
: {}),
|
|
110
154
|
// Whether a create may provision a worktree (worktree-access.mjs).
|
|
111
155
|
...(action === 'create' ? { callerScope: worktreeCallerScope(rt.session) } : {}),
|
|
112
156
|
// Which bots and sessions it may see (bot-status.mjs).
|
|
@@ -116,6 +160,16 @@ export function createWorkspaceToolHandlers({
|
|
|
116
160
|
)
|
|
117
161
|
);
|
|
118
162
|
}
|
|
163
|
+
// Mixy's proposals to the user (mixy-heartbeat.mjs): kept so none repeats.
|
|
164
|
+
if (action === 'suggest') {
|
|
165
|
+
const sessionId = assertLead(action, callerCtx);
|
|
166
|
+
if (sessionId !== agentHomeSessionId(MIXY_AGENT_ID) && !callerIsHeartbeat(callerCtx)) {
|
|
167
|
+
throw new Error("session: suggest belongs to Mixy's chat");
|
|
168
|
+
}
|
|
169
|
+
const { recordSuggestion } = await import('../mixy-heartbeat.mjs');
|
|
170
|
+
const receipt = recordSuggestion({ key: args?.key, text: args?.title, dismissed: args?.value === false });
|
|
171
|
+
return JSON.stringify({ action, ...receipt }, null, 2);
|
|
172
|
+
}
|
|
119
173
|
if (target && target !== assertLead(action, callerCtx)) {
|
|
120
174
|
throw new Error(`session: action=${action} only applies to the current session`);
|
|
121
175
|
}
|
|
@@ -184,6 +238,9 @@ export function createWorkspaceToolHandlers({
|
|
|
184
238
|
project: current?.workspace?.projectPath || current?.desktopSession?.projectPath || currentCwd,
|
|
185
239
|
provider: current?.provider || null,
|
|
186
240
|
model: current?.model || null,
|
|
241
|
+
effort: current?.effort || null,
|
|
242
|
+
autoEffort: current?.autoEffort !== false,
|
|
243
|
+
fast: current?.fast === true,
|
|
187
244
|
},
|
|
188
245
|
null,
|
|
189
246
|
2
|
|
@@ -229,12 +286,22 @@ export function createWorkspaceToolHandlers({
|
|
|
229
286
|
|
|
230
287
|
return {
|
|
231
288
|
session,
|
|
232
|
-
goal: async (args, { name, callerCtx }) =>
|
|
233
|
-
|
|
289
|
+
goal: async (args, { name, callerCtx }) => {
|
|
290
|
+
// A Goal keeps working in its session across turns: a heartbeat's would
|
|
291
|
+
// run on unseen in the hidden session.
|
|
292
|
+
if (['create', 'resume'].includes(clean(args?.action).toLowerCase()) && callerIsHeartbeat(callerCtx)) {
|
|
293
|
+
throw new Error(`goal: ${HEARTBEAT_NO_HANDOFF}`);
|
|
294
|
+
}
|
|
295
|
+
return await goalRuntime.executeTool(name, args || {}, {
|
|
234
296
|
callerSessionId: callerCtx?.callerSessionId || rt.session?.id || rt.reservedSessionId || null,
|
|
235
|
-
})
|
|
297
|
+
});
|
|
298
|
+
},
|
|
236
299
|
agent: async (args, { callerCtx, callerCwd }) => {
|
|
237
300
|
const callerSessionId = callerCtx?.callerSessionId || rt.session?.id || null;
|
|
301
|
+
// The agent tool's action is `type`, spawn when omitted (agent-tool/execute.mjs).
|
|
302
|
+
if (['spawn', 'send'].includes((clean(args?.type) || 'spawn').toLowerCase()) && callerIsHeartbeat(callerCtx)) {
|
|
303
|
+
throw new Error(`agent: ${HEARTBEAT_NO_HANDOFF}`);
|
|
304
|
+
}
|
|
238
305
|
// `attachmentParts` is never the model's to set: only the resolved
|
|
239
306
|
// `attachments` reach the agent's turn.
|
|
240
307
|
const { attachments, attachmentParts: _ignored, ...rest } = args || {};
|
|
@@ -10,6 +10,7 @@ import { createAskUserToolHandlers } from './internal-tool-executor/ask-user-too
|
|
|
10
10
|
import { createBridgeToolHandlers } from './internal-tool-executor/bridge-tools.mjs';
|
|
11
11
|
import { createFeatureToolHandlers } from './internal-tool-executor/feature-tools.mjs';
|
|
12
12
|
import { createKnowledgeToolHandlers } from './internal-tool-executor/knowledge-tools.mjs';
|
|
13
|
+
import { createReactionToolHandlers } from './internal-tool-executor/reaction-tool.mjs';
|
|
13
14
|
import { createWorkspaceToolHandlers } from './internal-tool-executor/workspace-tools.mjs';
|
|
14
15
|
|
|
15
16
|
export function createInternalToolExecutor({
|
|
@@ -40,6 +41,7 @@ export function createInternalToolExecutor({
|
|
|
40
41
|
const handlers = {
|
|
41
42
|
...createBridgeToolHandlers({ rt }),
|
|
42
43
|
...createAskUserToolHandlers({ rt }),
|
|
44
|
+
...createReactionToolHandlers({ rt }),
|
|
43
45
|
...createFeatureToolHandlers({ rt, setupTool, officeToolsEnabled, mediaToolEnabled, tidyToolEnabled }),
|
|
44
46
|
...createKnowledgeToolHandlers({
|
|
45
47
|
rt,
|
|
@@ -80,6 +82,8 @@ export function createInternalToolExecutor({
|
|
|
80
82
|
|
|
81
83
|
return async (name, args, callerCtx = {}) => {
|
|
82
84
|
const callerCwd = clean(callerCtx?.callerCwd) || rt.currentCwd;
|
|
85
|
+
// The Reactions setting gates the tool whoever calls it, not only the model.
|
|
86
|
+
if (name === 'react' && rt.config?.reactions === false) throw new Error('reactions are turned off in settings');
|
|
83
87
|
if (callerCtx?.invocationSource === 'model-tool') guardModelCall(name);
|
|
84
88
|
if (Object.hasOwn(handlers, name)) return handlers[name](args, { name, callerCtx, callerCwd });
|
|
85
89
|
if (channels.isChannelTool(name)) {
|
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
inheritanceRouteTarget,
|
|
16
16
|
} from '../inheritance-fit.mjs';
|
|
17
17
|
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
18
|
+
import {
|
|
19
|
+
rebindToChangedPrefix,
|
|
20
|
+
requestPrefixIdentity,
|
|
21
|
+
} from '../../runtime/agent/orchestrator/session/thinking-binding.mjs';
|
|
18
22
|
import { buildColdHeir, committedSource, persistColdHeir } from './cold-heir.mjs';
|
|
19
23
|
|
|
20
24
|
export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
@@ -155,8 +159,17 @@ export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
|
155
159
|
async function carryConversation(source, target, { compact = false } = {}) {
|
|
156
160
|
// System blocks belong to the session that BUILT them: the target's own
|
|
157
161
|
// prompt was composed for the current model, tool surface, and workflow.
|
|
158
|
-
// Only the conversation itself travels
|
|
159
|
-
|
|
162
|
+
// Only the conversation itself travels — without its thinking replay when
|
|
163
|
+
// the heir's prompt or tools differ from the source's: that replay is
|
|
164
|
+
// bound to the source's prefix, so the provider would drop it (and every
|
|
165
|
+
// thinking block after it) or refuse it, while the heir's context estimate
|
|
166
|
+
// kept counting it (thinking-binding.mjs); an open tool round the source
|
|
167
|
+
// stopped in is ended for the heir. An identical prefix keeps it all.
|
|
168
|
+
const carrySource =
|
|
169
|
+
requestPrefixIdentity(source) === requestPrefixIdentity(target)
|
|
170
|
+
? source
|
|
171
|
+
: { ...source, messages: rebindToChangedPrefix(source.messages) };
|
|
172
|
+
let carried = inheritableMessages(carrySource.messages);
|
|
160
173
|
if (!hasUserConversationMessage(carried)) {
|
|
161
174
|
throw new Error('inheritFrom: the source session has no conversation to carry');
|
|
162
175
|
}
|
|
@@ -169,7 +182,7 @@ export function createInheritance(deps, { compactConversation, saveSession }) {
|
|
|
169
182
|
// compact:true summarizes even a conversation that fits; otherwise only
|
|
170
183
|
// one that cannot fit is compacted.
|
|
171
184
|
if (compact || (fit.known && !fit.fits)) {
|
|
172
|
-
const next = await fitConversationForHeir(
|
|
185
|
+
const next = await fitConversationForHeir(carrySource, target, carried, fit, { required: compact });
|
|
173
186
|
compacted = next !== carried;
|
|
174
187
|
carried = next;
|
|
175
188
|
}
|
|
@@ -77,7 +77,9 @@ export function leadSessionRow(s, working = false) {
|
|
|
77
77
|
if (sourceType === 'exec') return null;
|
|
78
78
|
if (!agentSession && !isLeadShaped(s, owner, sourceType)) return null;
|
|
79
79
|
const { preview, messageCount, realTurnCount, incomingTail } = previewOf(s);
|
|
80
|
-
|
|
80
|
+
// A titled one is not scratch: its prompt was rewound away (Esc-Esc message
|
|
81
|
+
// selector), so it stays listed rather than vanishing with its open tab.
|
|
82
|
+
if (!preview && messageCount === 0 && !cleanSessionPreview(s.title || '', 100)) return null;
|
|
81
83
|
const lastMessageRoutine = normalizeRoutineProvenance(s.lastMessageRoutine);
|
|
82
84
|
return {
|
|
83
85
|
id: s.id,
|
|
@@ -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 {
|