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
|
@@ -194,38 +194,63 @@ async function archiveIndexFor(path, handle) {
|
|
|
194
194
|
return entries;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
/**
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
|
|
197
|
+
/** Runs `use(entries, load)` over a session's archive sidecar: its segment
|
|
198
|
+
* index and a loader of one segment's items. The open handle pins the file
|
|
199
|
+
* a concurrent atomic replace may swap out, so the index and the segment
|
|
200
|
+
* reads describe the same bytes. `fallback` when the archive is absent or
|
|
201
|
+
* unreadable (display-only history: it shows nothing then). */
|
|
202
|
+
async function withArchive(storeDir, sessionId, fallback, use) {
|
|
201
203
|
const path = compactionArchivePath(storeDir, sessionId);
|
|
202
|
-
if (!path) return
|
|
204
|
+
if (!path) return fallback;
|
|
203
205
|
let handle;
|
|
204
206
|
try {
|
|
205
207
|
handle = await open(path, 'r');
|
|
206
208
|
} catch {
|
|
207
|
-
// Display-only history: an absent or unreadable archive shows nothing.
|
|
208
209
|
archiveIndexes.delete(path);
|
|
209
|
-
return
|
|
210
|
+
return fallback;
|
|
210
211
|
}
|
|
211
212
|
try {
|
|
212
213
|
const entries = await archiveIndexFor(path, handle);
|
|
213
|
-
return await
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return segmentItems(buffer.toString('utf8'));
|
|
219
|
-
},
|
|
220
|
-
range
|
|
221
|
-
);
|
|
214
|
+
return await use(entries, async (entry) => {
|
|
215
|
+
const buffer = Buffer.alloc(entry.length);
|
|
216
|
+
await handle.read(buffer, 0, entry.length, entry.start);
|
|
217
|
+
return segmentItems(buffer.toString('utf8'));
|
|
218
|
+
});
|
|
222
219
|
} catch {
|
|
223
|
-
return
|
|
220
|
+
return fallback;
|
|
224
221
|
} finally {
|
|
225
222
|
await handle.close().catch(() => {});
|
|
226
223
|
}
|
|
227
224
|
}
|
|
228
225
|
|
|
226
|
+
/** One page of a session's archive sidecar (see pageFromSegments). */
|
|
227
|
+
export function readCompactionArchivePage(storeDir, sessionId, range = {}) {
|
|
228
|
+
return withArchive(storeDir, sessionId, { items: [], hasOlder: false }, (entries, load) =>
|
|
229
|
+
pageFromSegments(entries, load, range)
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Hands every visible segment of the archive (numbered in (after, before),
|
|
234
|
+
* oldest first) to `visit` as its items, one segment at a time, so a whole
|
|
235
|
+
* walk never holds more than one segment. True when the walk completed;
|
|
236
|
+
* false when the archive was absent or unreadable (the visits made so far
|
|
237
|
+
* are then incomplete). */
|
|
238
|
+
export function visitCompactionArchive(
|
|
239
|
+
storeDir,
|
|
240
|
+
sessionId,
|
|
241
|
+
{ after = 0, before = Number.POSITIVE_INFINITY } = {},
|
|
242
|
+
visit
|
|
243
|
+
) {
|
|
244
|
+
return withArchive(storeDir, sessionId, false, async (entries, load) => {
|
|
245
|
+
for (const entry of entries) {
|
|
246
|
+
const { seq, count } = entry.head;
|
|
247
|
+
if (seq <= after || seq >= before || count < 1) continue;
|
|
248
|
+
visit(await load(entry));
|
|
249
|
+
}
|
|
250
|
+
return true;
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
229
254
|
// Delete fence: every deletion bumps the session's epoch. A writer captures
|
|
230
255
|
// the epoch before it starts and publishes only if it is unchanged at the
|
|
231
256
|
// (synchronous) rename, so a delete that lands while a segment is being
|
|
@@ -11,6 +11,7 @@ import { createEagerEntry, runEagerEntry } from './eager-dispatch/entry.mjs';
|
|
|
11
11
|
import { executeTool } from './loop/tool-exec.mjs';
|
|
12
12
|
import { isParallelDispatchable } from './loop/tool-helpers.mjs';
|
|
13
13
|
import { resolveExecutionToolCall } from './loop/tool-call-resolution.mjs';
|
|
14
|
+
import { turnLimitsOf } from './loop/turn-limits.mjs';
|
|
14
15
|
|
|
15
16
|
export function createEagerDispatcher({
|
|
16
17
|
tools,
|
|
@@ -23,6 +24,7 @@ export function createEagerDispatcher({
|
|
|
23
24
|
getIterations,
|
|
24
25
|
getNextIteration,
|
|
25
26
|
repeatFailLimit,
|
|
27
|
+
isTurnLimitNoticed = () => false,
|
|
26
28
|
executeToolFn = executeTool,
|
|
27
29
|
}) {
|
|
28
30
|
const pending = new Map();
|
|
@@ -37,6 +39,9 @@ export function createEagerDispatcher({
|
|
|
37
39
|
repeatFailLimit,
|
|
38
40
|
});
|
|
39
41
|
const barriers = createEagerBarriers({ cwd });
|
|
42
|
+
// A capped turn runs its calls in order, so none past its cap starts early
|
|
43
|
+
// (loop/turn-limits.mjs).
|
|
44
|
+
const capped = turnLimitsOf(opts) !== null;
|
|
40
45
|
const execute = (call, entry) =>
|
|
41
46
|
executeToolFn(call.name, call.arguments, cwd, sessionId, sessionRef, {
|
|
42
47
|
toolCallId: call.id,
|
|
@@ -52,6 +57,9 @@ export function createEagerDispatcher({
|
|
|
52
57
|
const startEagerTool = (wireCall) => {
|
|
53
58
|
// Streamed call_tool requests are admitted, ordered and executed as their
|
|
54
59
|
// targets; a projection error is answered by the serial batch instead.
|
|
60
|
+
// Once the turn was told to reply (any limit), no call runs: the batch
|
|
61
|
+
// refuses them, so none may start while the wrap-up response streams.
|
|
62
|
+
if (capped || isTurnLimitNoticed()) return null;
|
|
55
63
|
const call = resolveExecutionToolCall(wireCall, sessionRef);
|
|
56
64
|
if (!call?.id || pending.has(call.id) || !isParallelDispatchable(call.name)) return null;
|
|
57
65
|
const admitted = admission.admit(call);
|
|
@@ -14,17 +14,22 @@
|
|
|
14
14
|
// allowed, payments and permanent deletes denied. Group-room members register
|
|
15
15
|
// a port here (session-runtime/held-requests.mjs) that turns their asks into
|
|
16
16
|
// held requests when no approval card is attached.
|
|
17
|
+
// The "Allow all actions" developer option (shared/developer-options.mjs)
|
|
18
|
+
// skips every ask below, the bot's per-action `ask` mode and a hook `ask`
|
|
19
|
+
// included, except a payment or permanent delete; a `block` and a hook `deny`
|
|
20
|
+
// still deny.
|
|
17
21
|
import { MIXY_AGENT_ID, agentIdOfHomeSession } from '../agent-home.mjs';
|
|
18
22
|
import { serverConnector } from '../../mcp/server-connectors.mjs';
|
|
19
23
|
import { readAgentDefinitionKind } from '../../../../shared/agent-kind.mjs';
|
|
20
24
|
import { isContactAgentId } from '../../../../shared/agent-route-config.mjs';
|
|
25
|
+
import { developerOptionEnabledStrict } from '../../../../shared/developer-options.mjs';
|
|
21
26
|
import { mixdogRoot, resolvePluginData } from '../../../../shared/plugin-paths.mjs';
|
|
22
27
|
import { roomMemberOfSession } from '../agent-room.mjs';
|
|
23
28
|
import { agentDisplayName } from '../../context/role-instructions.mjs';
|
|
24
29
|
import { delegationOf } from './delegation.mjs';
|
|
25
30
|
import { setUnattendedApprovalPort, unattendedApprovalPort } from './unattended-port.mjs';
|
|
26
|
-
import { classifyAsDelete, classifyOutboundCall, isRememberableAction } from './outbound-policy.mjs';
|
|
27
|
-
import { humanGateStore } from './store.mjs';
|
|
31
|
+
import { classifyAsDelete, classifyOutboundCall, isAlwaysAskAction, isRememberableAction } from './outbound-policy.mjs';
|
|
32
|
+
import { DEV_ALLOW_ALL_DECISION, humanGateStore } from './store.mjs';
|
|
28
33
|
import {
|
|
29
34
|
AUTOMATION_GRANT_REASON,
|
|
30
35
|
RUN_FORBIDDEN_REASON,
|
|
@@ -33,7 +38,7 @@ import {
|
|
|
33
38
|
savesAutomation,
|
|
34
39
|
} from './run-policy.mjs';
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
const OUTBOUND_APPROVAL_REASON = 'This sends or posts outside Mixdog; it needs your approval.';
|
|
37
42
|
export const BLOCKED_ACTION_REASON = "This agent's permission blocks this action.";
|
|
38
43
|
/** Outbound grants may be remembered for this agent, never for every agent;
|
|
39
44
|
* payments and deletes never. */
|
|
@@ -93,7 +98,8 @@ const LEAD_NAME = 'Lead';
|
|
|
93
98
|
* bot-created task session, a bot's home chat or room member session) and
|
|
94
99
|
* the names from there down to the asker ("Lead › Reviewer", "사무관 ›
|
|
95
100
|
* Worker"). Only where the card shows: no bot identity, grant or remember
|
|
96
|
-
* scope follows from it. Null for a top-level session
|
|
101
|
+
* scope follows from it. Null for a top-level session (whose requests show
|
|
102
|
+
* in the chats handing it work instead: tui/session/tool-approval.mjs). */
|
|
97
103
|
export function approvalSurface(sessionId) {
|
|
98
104
|
const delegation = delegationOf(sessionId);
|
|
99
105
|
if (delegation.state !== 'resolved') return null;
|
|
@@ -105,6 +111,22 @@ export function approvalSurface(sessionId) {
|
|
|
105
111
|
|
|
106
112
|
const actionOf = (decision) => String(decision?.action || decision?.decision || '').toLowerCase();
|
|
107
113
|
|
|
114
|
+
/** Whether the "Allow all actions" developer option is on (default off).
|
|
115
|
+
* Fail-closed: an unreadable, missing or malformed config is off (the call
|
|
116
|
+
* asks), and a value restored from a backup never counts. */
|
|
117
|
+
export const allowAllActionsEnabled = () => developerOptionEnabledStrict('allowAllActions');
|
|
118
|
+
|
|
119
|
+
/** Whether the option lets a call of this classification (or none) run without
|
|
120
|
+
* a card: every ask, never a classified payment or permanent delete. */
|
|
121
|
+
const skipsApproval = (classified) => !isAlwaysAskAction(classified?.category) && allowAllActionsEnabled();
|
|
122
|
+
|
|
123
|
+
/** The hook decision once its card is skipped: an `ask` runs as an allow,
|
|
124
|
+
* keeping any rewrite it carried. */
|
|
125
|
+
function withoutAsk(decision) {
|
|
126
|
+
if (actionOf(decision) !== 'ask') return decision;
|
|
127
|
+
return { ...decision, action: decision.name || decision.args ? 'modify' : 'allow' };
|
|
128
|
+
}
|
|
129
|
+
|
|
108
130
|
async function mcpAnnotations(name, scopeId) {
|
|
109
131
|
if (!String(name).startsWith('mcp__')) return undefined;
|
|
110
132
|
try {
|
|
@@ -135,7 +157,13 @@ async function describeEmails(call, outbound, ctx) {
|
|
|
135
157
|
const { executeMcpTool } = await import('../../mcp/client.mjs');
|
|
136
158
|
const ids = outbound.category === 'trash' && Array.isArray(call.args?.ids) ? call.args.ids.map(String) : [];
|
|
137
159
|
const shown = ids.slice(0, PREVIEW_MESSAGES);
|
|
138
|
-
|
|
160
|
+
// The account the call acts as (one server holds every Gmail account).
|
|
161
|
+
const chosen = typeof call.args?.account === 'string' ? call.args.account.trim() : '';
|
|
162
|
+
const raw = await executeMcpTool(
|
|
163
|
+
name,
|
|
164
|
+
{ ids: shown, ...(chosen ? { account: chosen } : {}) },
|
|
165
|
+
{ scopeId: ctx.mcpScopeId }
|
|
166
|
+
);
|
|
139
167
|
const { account, emails } = JSON.parse(raw);
|
|
140
168
|
const messages = (Array.isArray(emails) ? emails : []).map((mail) =>
|
|
141
169
|
[mail.from, mail.subject, String(mail.date || '').slice(0, 10)].filter(Boolean).join(' · ')
|
|
@@ -185,11 +213,17 @@ export async function humanGateDecision(call, decision, ctx = {}) {
|
|
|
185
213
|
const outbound = classified && actingBotId(ctx.sessionId) ? classified : null;
|
|
186
214
|
if (!outbound) {
|
|
187
215
|
if (action !== 'ask') return { decision, request: null, gate: null };
|
|
216
|
+
const gate = { agentId, kind: 'approval', tool: String(call?.name || ''), target: '' };
|
|
217
|
+
if (skipsApproval(classified)) {
|
|
218
|
+
const store = ctx.store || (await humanGateStore());
|
|
219
|
+
await store.recordAudit({ ...gate, decision: DEV_ALLOW_ALL_DECISION, device: '' });
|
|
220
|
+
return { decision: withoutAsk(decision), request: null, gate: null };
|
|
221
|
+
}
|
|
188
222
|
return {
|
|
189
223
|
// Saving a schedule or webhook says plainly what the approval grants.
|
|
190
224
|
decision: savesAutomation(call) ? { ...decision, reason: AUTOMATION_GRANT_REASON } : decision,
|
|
191
225
|
request: { kind: 'approval', agentId, remember: ['once'] },
|
|
192
|
-
gate
|
|
226
|
+
gate,
|
|
193
227
|
};
|
|
194
228
|
}
|
|
195
229
|
const gate = { agentId, kind: 'outbound', action: outbound.category, tool: outbound.tool, target: outbound.target };
|
|
@@ -204,10 +238,9 @@ export async function humanGateDecision(call, decision, ctx = {}) {
|
|
|
204
238
|
editable: outbound.editable,
|
|
205
239
|
details: outbound.details,
|
|
206
240
|
},
|
|
207
|
-
|
|
241
|
+
// "Don't ask again" is the bot's permission.
|
|
242
|
+
remember: outboundRemember(outbound.category),
|
|
208
243
|
};
|
|
209
|
-
// "Don't ask again" is the bot's permission.
|
|
210
|
-
request.remember = outboundRemember(outbound.category);
|
|
211
244
|
const store = ctx.store || (await humanGateStore());
|
|
212
245
|
const mode = await store.modeFor({ agentId, action: outbound.category });
|
|
213
246
|
const base = decision && typeof decision === 'object' ? decision : {};
|
|
@@ -215,6 +248,11 @@ export async function humanGateDecision(call, decision, ctx = {}) {
|
|
|
215
248
|
await store.recordAudit({ ...gate, decision: 'blocked', device: '' });
|
|
216
249
|
return { decision: { ...base, action: 'deny', reason: BLOCKED_ACTION_REASON }, request: null, gate: null };
|
|
217
250
|
}
|
|
251
|
+
// The bot's `ask` mode (and a hook's `ask`) is bypassed; a payment or delete is not.
|
|
252
|
+
if (skipsApproval(outbound)) {
|
|
253
|
+
await store.recordAudit({ ...gate, decision: DEV_ALLOW_ALL_DECISION, device: '' });
|
|
254
|
+
return { decision: withoutAsk(decision), request: null, gate: null };
|
|
255
|
+
}
|
|
218
256
|
if (action !== 'ask' && mode === 'allow') {
|
|
219
257
|
await store.recordAudit({ ...gate, decision: 'remembered', device: '' });
|
|
220
258
|
// The remembered grant answers this call: no later layer asks it again.
|
|
@@ -39,6 +39,12 @@ export function isRememberableAction(kind) {
|
|
|
39
39
|
return ACTION_KINDS.includes(kind) && !UNREMEMBERED_ACTIONS.has(kind);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/** Whether `kind` is a payment or permanent delete: it asks every time,
|
|
43
|
+
* whatever else is allowed (also by the "Allow all actions" developer option). */
|
|
44
|
+
export function isAlwaysAskAction(kind) {
|
|
45
|
+
return UNREMEMBERED_ACTIONS.has(kind);
|
|
46
|
+
}
|
|
47
|
+
|
|
42
48
|
const GITHUB_OUTBOUND = new Map([
|
|
43
49
|
['issue.comment', 'comment'],
|
|
44
50
|
['pr.comment', 'comment'],
|
|
@@ -68,8 +74,6 @@ const MCP_OUTBOUND = new Map([
|
|
|
68
74
|
'slack_post_message',
|
|
69
75
|
'slack_reply_to_thread',
|
|
70
76
|
'chat_post_message',
|
|
71
|
-
'discord_send_message',
|
|
72
|
-
'telegram_send_message',
|
|
73
77
|
].map((name) => [name, 'message']),
|
|
74
78
|
...['create_post', 'publish_post', 'create_tweet', 'post_tweet', 'send_tweet'].map((name) => [name, 'publish']),
|
|
75
79
|
['submit_form', 'form'],
|
|
@@ -12,10 +12,23 @@
|
|
|
12
12
|
// the scopes it allows and can leave out `always`. Nothing here ever carries a
|
|
13
13
|
// secret value: a decision that names one is stripped to its verdict.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const HUMAN_REQUEST_KINDS = Object.freeze(['approval', 'outbound', 'secret', 'takeover', 'permission']);
|
|
16
|
+
const HUMAN_RESPONSES = Object.freeze(['approve', 'deny', 'edit-and-approve', 'provide-secret', 'skip', 'done']);
|
|
17
|
+
const REMEMBER_SCOPES = Object.freeze(['once', 'agent', 'always']);
|
|
18
18
|
export const SECRET_REQUEST_TIMEOUT_MS = 120_000;
|
|
19
|
+
/** What a secret's bound field is: a sign-in form (아이디 + 비밀번호), a lone
|
|
20
|
+
* password, a new password, or a one-time code; '' when unknown (computer). */
|
|
21
|
+
export const SECRET_FORMS = Object.freeze(['login', 'password', 'new-password', 'otp']);
|
|
22
|
+
/** Every result a secret handoff (and a declined or expired takeover) gives
|
|
23
|
+
* the agent: facts, never a verdict about the site. */
|
|
24
|
+
export const HANDOFF_OUTCOMES = Object.freeze([
|
|
25
|
+
'entered',
|
|
26
|
+
'user_skipped',
|
|
27
|
+
'no_field',
|
|
28
|
+
'page_changed',
|
|
29
|
+
'blocked',
|
|
30
|
+
'expired',
|
|
31
|
+
]);
|
|
19
32
|
|
|
20
33
|
const RESPONSES_BY_KIND = Object.freeze({
|
|
21
34
|
approval: ['approve', 'deny'],
|
|
@@ -49,7 +62,7 @@ const text = (value, limit = TEXT_LIMIT) => (typeof value === 'string' ? value.t
|
|
|
49
62
|
|
|
50
63
|
/** The human kind of a request; anything else (ask_user's 'question', a
|
|
51
64
|
* hook's bare ask) is an ordinary approval for responses. */
|
|
52
|
-
|
|
65
|
+
function humanRequestKind(request) {
|
|
53
66
|
return HUMAN_REQUEST_KINDS.includes(request?.kind) ? request.kind : 'approval';
|
|
54
67
|
}
|
|
55
68
|
|
|
@@ -103,11 +116,21 @@ export function humanRequestFields(input = {}) {
|
|
|
103
116
|
}
|
|
104
117
|
if (kind === 'secret') {
|
|
105
118
|
const secret = isRecord(input.secret) ? input.secret : {};
|
|
119
|
+
// The bound page's origin and what its field is (the desktop read it at
|
|
120
|
+
// request time, ask-user-tool.mjs): the card's title and inputs; no value.
|
|
121
|
+
const origin = loginPageUrl(secret.origin)?.origin || '';
|
|
122
|
+
const form = SECRET_FORMS.includes(secret.form) ? secret.form : '';
|
|
123
|
+
// A code's length is the bound field's own (credential-autofill.ts
|
|
124
|
+
// codeLength); absent, it stays unspecified.
|
|
125
|
+
const length = Number.isInteger(secret.length) && secret.length > 0 ? secret.length : 0;
|
|
106
126
|
fields.secret = {
|
|
107
127
|
requestId: text(secret.requestId),
|
|
108
128
|
surface: secret.surface === 'computer' ? 'computer' : 'browser',
|
|
109
129
|
target: text(secret.target),
|
|
110
130
|
field: text(secret.field),
|
|
131
|
+
...(origin ? { origin } : {}),
|
|
132
|
+
...(form ? { form } : {}),
|
|
133
|
+
...(form === 'otp' && length ? { length } : {}),
|
|
111
134
|
};
|
|
112
135
|
fields.args = { surface: fields.secret.surface, target: fields.secret.target, field: fields.secret.field };
|
|
113
136
|
fields.remember = ['once'];
|
|
@@ -132,12 +155,21 @@ export function humanRequestFields(input = {}) {
|
|
|
132
155
|
// A login takeover (purpose 'login') opens the desktop's sign-in window on
|
|
133
156
|
// its validated page instead of handing over the side panel.
|
|
134
157
|
const login = surface === 'browser' && takeover.purpose === 'login' ? loginPageUrl(takeover.url) : null;
|
|
158
|
+
// The saved logins of the sign-in page's origin: opaque ids and masked
|
|
159
|
+
// labels only (profile-import.ts credentialSuggestions), never a password.
|
|
160
|
+
const accounts = (login && Array.isArray(takeover.accounts) ? takeover.accounts : [])
|
|
161
|
+
.filter((account) => isRecord(account) && token(account.id, 128) && text(account.label, 120))
|
|
162
|
+
.map((account) => ({ id: token(account.id, 128), label: text(account.label, 120) }));
|
|
163
|
+
// The page those logins may be filled into, bound by the desktop at
|
|
164
|
+
// request time (ask-user-tool.mjs fillId): without it none is offered.
|
|
165
|
+
const fillId = /^secret_[A-Za-z0-9-]{8,80}$/.test(text(takeover.fillId, 100)) ? text(takeover.fillId, 100) : '';
|
|
135
166
|
fields.takeover = {
|
|
136
167
|
surface,
|
|
137
168
|
instructions: text(takeover.instructions, 2_000),
|
|
138
169
|
...(text(takeover.target) ? { target: text(takeover.target) } : {}),
|
|
139
170
|
...identity,
|
|
140
171
|
...(login ? { purpose: 'login', url: login.url, origin: login.origin } : {}),
|
|
172
|
+
...(accounts.length && fillId ? { accounts, fillId } : {}),
|
|
141
173
|
};
|
|
142
174
|
fields.remember = ['once'];
|
|
143
175
|
}
|
|
@@ -173,12 +173,24 @@ export async function setAgentPermission(agentId, action, mode, options) {
|
|
|
173
173
|
return store.permissions(agent);
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
/** The audit decision of a call the "Allow all actions" developer option let through unasked. */
|
|
177
|
+
export const DEV_ALLOW_ALL_DECISION = 'dev-allow-all';
|
|
178
|
+
|
|
179
|
+
const BROWSER_AUDIT_DECISIONS = Object.freeze([
|
|
180
|
+
'approve',
|
|
181
|
+
'deny',
|
|
182
|
+
'granted',
|
|
183
|
+
'remembered',
|
|
184
|
+
'run-allowed',
|
|
185
|
+
'blocked',
|
|
186
|
+
DEV_ALLOW_ALL_DECISION,
|
|
187
|
+
]);
|
|
177
188
|
|
|
178
189
|
/** Audit one Browser Use approval of a bot (capability recordAgentApprovalAudit):
|
|
179
190
|
* the bot, the action kind and what happened — `approve` / `deny` for the card,
|
|
180
191
|
* `granted` when "always allow" was saved, `remembered` when a saved allow let
|
|
181
|
-
* a step run unasked
|
|
192
|
+
* a step run unasked, `dev-allow-all` when the developer option did. Never a
|
|
193
|
+
* page address, target or value. */
|
|
182
194
|
export async function recordAgentApprovalAudit(agentId, action, decision) {
|
|
183
195
|
const agent = requiredAgentId(agentId);
|
|
184
196
|
if (!ACTION_KINDS.includes(action)) throw new Error(`action must be one of ${ACTION_KINDS.join(', ')}`);
|
|
@@ -62,6 +62,12 @@ function assistantEchoFields(payloads) {
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
// The tail reminder the response was generated under (send-with-recovery.mjs),
|
|
66
|
+
// kept verbatim so a turn-scoped provider replays it byte-identically.
|
|
67
|
+
export function turnReminderField(resp) {
|
|
68
|
+
return typeof resp?.turnReminder === 'string' && resp.turnReminder ? { turnReminder: resp.turnReminder } : {};
|
|
69
|
+
}
|
|
70
|
+
|
|
65
71
|
// Intermediate (non-tool) assistant turn: max-output partials, refusal
|
|
66
72
|
// narration, provider continuations, and the terminal turn committed before a
|
|
67
73
|
// steering drain. Returns null when the turn carries nothing committable — a
|
|
@@ -89,6 +95,7 @@ export function buildIntermediateAssistantMessage(resp, opts) {
|
|
|
89
95
|
role: 'assistant',
|
|
90
96
|
content,
|
|
91
97
|
...assistantEchoFields(payloads),
|
|
98
|
+
...turnReminderField(resp),
|
|
92
99
|
...(stopReason ? { stopReason } : {}),
|
|
93
100
|
...(terminationReason ? { terminationReason } : {}),
|
|
94
101
|
},
|
|
@@ -108,6 +115,7 @@ export function buildToolCallAssistantMessage(response, { calls, opts }) {
|
|
|
108
115
|
content: response.content || '',
|
|
109
116
|
toolCalls: compactToolCallsForHistory(calls, { deferBodies: true }),
|
|
110
117
|
...assistantEchoFields(assistantEchoPayloads(response, { keepAssistantBlocks: true })),
|
|
118
|
+
...turnReminderField(response),
|
|
111
119
|
},
|
|
112
120
|
opts
|
|
113
121
|
);
|
|
@@ -21,6 +21,7 @@ import { isAgentModeSession } from '../agent-mode.mjs';
|
|
|
21
21
|
import { providerInputExcludesCache, providerNativePdf } from '../../providers/registry.mjs';
|
|
22
22
|
import { contentMediaBytes, contentMediaCount } from '../../providers/media-normalization.mjs';
|
|
23
23
|
import { splitProtectedContext } from '../compact/messages.mjs';
|
|
24
|
+
import { withLiveCompactionConfig } from '../../runtime-core/compaction-config-keys.mjs';
|
|
24
25
|
|
|
25
26
|
// Unified context-share rule (compact/constants.mjs CONTEXT_SHARE_RATIO): the
|
|
26
27
|
// post-compaction target is 25% of the boundary/context window. One
|
|
@@ -394,13 +395,6 @@ export function invalidateProviderContextBaseline(sessionRef) {
|
|
|
394
395
|
delete sessionRef.contextPressureUnanchoredReason;
|
|
395
396
|
}
|
|
396
397
|
|
|
397
|
-
// A baseline is refreshed on every provider_send/turn-end. When the transcript
|
|
398
|
-
// has grown but no fresh recording landed for this long, recording is failing
|
|
399
|
-
// (zero/absent usage keeps the OLD baseline because record() only returns
|
|
400
|
-
// false) — distrust it and fall back to the estimate. An idle session whose
|
|
401
|
-
// transcript did NOT grow keeps its baseline regardless of age.
|
|
402
|
-
const BASELINE_MAX_STALE_GROWTH_MS = 30 * 60 * 1000;
|
|
403
|
-
|
|
404
398
|
/**
|
|
405
399
|
* Does this anchor still describe this message prefix?
|
|
406
400
|
*
|
|
@@ -480,17 +474,19 @@ function providerBaselinePressureTokens(messages, sessionRef, policy, { includeC
|
|
|
480
474
|
? Math.max(0, tokens - Math.round(storedRequestReserve) + currentRequestReserve)
|
|
481
475
|
: tokens + currentRequestReserve;
|
|
482
476
|
}
|
|
483
|
-
// Staleness means
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
|
|
493
|
-
|
|
477
|
+
// Staleness means usage recording is failing: a provider request completed
|
|
478
|
+
// AFTER this reading without replacing it (every send records its usage
|
|
479
|
+
// after it starts, so a working recorder always leaves the reading newer
|
|
480
|
+
// than the last send) — zero/absent usage keeps the OLD baseline because
|
|
481
|
+
// record() only returns false. Never age on a clock: measured against `now`
|
|
482
|
+
// it discarded the reading of every session that sat unopened for a while
|
|
483
|
+
// (88 of 983 stored sessions), and measured against the session's last
|
|
484
|
+
// activity it discarded it whenever anything was appended more than half an
|
|
485
|
+
// hour after the last request — a user back from a break, an agent's result
|
|
486
|
+
// posted to a waiting Lead — so the next send compacted on the
|
|
487
|
+
// whole-transcript estimate, far above the provider's own count.
|
|
488
|
+
const lastSendAt = Number(sessionRef.lastProviderSendAt) || 0;
|
|
489
|
+
if (messages.length > count && baselineAt > 0 && lastSendAt > baselineAt) return null;
|
|
494
490
|
try {
|
|
495
491
|
// Baseline tokens are authoritative provider billing; only the growth
|
|
496
492
|
// after the baseline is a local estimate and needs billing calibration.
|
|
@@ -795,9 +791,9 @@ function compactionTelemetryRecord(sessionRef, policy, meta, prev) {
|
|
|
795
791
|
if (terminalSuccess) return null;
|
|
796
792
|
return present ? (next ?? null) : (previous ?? null);
|
|
797
793
|
};
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
794
|
+
// Config-owned fields stay the live ones (withLiveCompactionConfig): `policy`
|
|
795
|
+
// was resolved before a compaction that a reload may have outlived.
|
|
796
|
+
return withLiveCompactionConfig(prev, {
|
|
801
797
|
requestReserveTokens: policy.requestReserveTokens || 0,
|
|
802
798
|
reserveTokens: policy.reserveTokens || 0,
|
|
803
799
|
boundaryTokens: policy.boundaryTokens || null,
|
|
@@ -848,7 +844,7 @@ function compactionTelemetryRecord(sessionRef, policy, meta, prev) {
|
|
|
848
844
|
compactCount: (prev.compactCount || 0) + (changed ? 1 : 0),
|
|
849
845
|
singleShotConsumed:
|
|
850
846
|
policy.singleShot === true && meta.stage === 'compacting' ? true : prev.singleShotConsumed === true,
|
|
851
|
-
};
|
|
847
|
+
});
|
|
852
848
|
}
|
|
853
849
|
|
|
854
850
|
// Postmortem ring buffer: the per-check telemetry record is overwritten on
|
|
@@ -18,6 +18,9 @@ import { summarizeOnSharedPrefix } from '../compact/forked-summary.mjs';
|
|
|
18
18
|
import { normalizeCompactionSummaryMode } from '../compact/summary-mode.mjs';
|
|
19
19
|
import { compactionCacheWarm, lighterSubscriptionModel } from '../compact/summary-route.mjs';
|
|
20
20
|
import { retireCompactionFork } from '../side-question-store.mjs';
|
|
21
|
+
import { buildSkillToolEnvelope, collectSkillsCached, currentSkillDelivery } from '../../context/collect.mjs';
|
|
22
|
+
import { loadSkillToolDependencies } from '../../runtime-core/skill-tool-loading.mjs';
|
|
23
|
+
import { parseNativeToolSearchPayload } from './tool-helpers.mjs';
|
|
21
24
|
|
|
22
25
|
// Conversation summarization triggers independently of the post-compact target:
|
|
23
26
|
// at 5% of the window, capped so a large window does not carry tens of
|
|
@@ -262,11 +265,37 @@ function freshContextBudget({ compactPolicy, sessionRef, provider, compactBudget
|
|
|
262
265
|
return { contextWindow, hardBudget, conversationInput, conversationTokens, conversationThresholdTokens };
|
|
263
266
|
}
|
|
264
267
|
|
|
268
|
+
// Compact restores each active skill from its current source, as the Skill
|
|
269
|
+
// tool would deliver it in this session now (null: it no longer loads). The
|
|
270
|
+
// real pass also re-arms the skill's current tool dependencies on the session
|
|
271
|
+
// surface and answers the native tool-search payload they produce (or, with
|
|
272
|
+
// none, the Skill result summary); a preview never touches the surface and
|
|
273
|
+
// keeps the transcript's loader pairs.
|
|
274
|
+
function currentSkillResolver(sessionRef, { preview = false } = {}) {
|
|
275
|
+
const cwd = sessionRef?.cwd || null;
|
|
276
|
+
const config = loadConfig({ secrets: false });
|
|
277
|
+
const skills = collectSkillsCached(cwd);
|
|
278
|
+
return (name) => {
|
|
279
|
+
const delivery = currentSkillDelivery(name, cwd, config, skills);
|
|
280
|
+
if (!delivery) return null;
|
|
281
|
+
if (preview) return { body: delivery.body, native: undefined };
|
|
282
|
+
const { resource } = delivery;
|
|
283
|
+
const envelope = loadSkillToolDependencies(
|
|
284
|
+
buildSkillToolEnvelope(name, resource.content, resource.dir, resource),
|
|
285
|
+
sessionRef
|
|
286
|
+
);
|
|
287
|
+
const native = parseNativeToolSearchPayload('Skill', envelope.result);
|
|
288
|
+
return { body: delivery.body, native, summary: native?.summary ?? envelope.result };
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
265
292
|
function freshContextBuildOptions(
|
|
266
|
-
{ compactPolicy = {}, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
293
|
+
{ sessionRef, compactPolicy = {}, sessionId, goalReminderText, activeTurn, referenceLatestAttachments, preview },
|
|
267
294
|
budget
|
|
268
295
|
) {
|
|
269
296
|
return {
|
|
297
|
+
// A sessionless call (no session gates to apply) keeps the transcript copies.
|
|
298
|
+
currentSkill: sessionRef ? currentSkillResolver(sessionRef, { preview }) : null,
|
|
270
299
|
reserveTokens: compactPolicy.reserveTokens,
|
|
271
300
|
maxBudgetTokens: budget.hardBudget,
|
|
272
301
|
force: true,
|
|
@@ -287,7 +316,7 @@ export function previewFreshContextCompaction(input) {
|
|
|
287
316
|
const budget = freshContextBudget(input);
|
|
288
317
|
const summaryTriggered = budget.conversationTokens >= budget.conversationThresholdTokens;
|
|
289
318
|
const result = freshContextCompactMessages(input.messages, input.compactBudgetTokens, {
|
|
290
|
-
...freshContextBuildOptions(input, budget),
|
|
319
|
+
...freshContextBuildOptions({ ...input, preview: true }, budget),
|
|
291
320
|
preview: true,
|
|
292
321
|
previewSummary: summaryTriggered,
|
|
293
322
|
});
|
|
@@ -346,7 +375,7 @@ export async function runFreshContextCompact({
|
|
|
346
375
|
});
|
|
347
376
|
const summaryTriggered = conversationTokens >= conversationThresholdTokens;
|
|
348
377
|
const buildOptions = freshContextBuildOptions(
|
|
349
|
-
{ compactPolicy, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
378
|
+
{ sessionRef, compactPolicy, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
350
379
|
{ contextWindow, hardBudget }
|
|
351
380
|
);
|
|
352
381
|
const build = (handoffText) =>
|
|
@@ -55,6 +55,9 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
55
55
|
cwd: resolveLiveToolCwd(cwd, sessionRef),
|
|
56
56
|
iterations: 0,
|
|
57
57
|
toolCallsTotal: 0,
|
|
58
|
+
// A capped turn (turn-limits.mjs): told to reply, and ended by calling tools anyway.
|
|
59
|
+
turnLimitNoticed: false,
|
|
60
|
+
turnLimitEnded: false,
|
|
58
61
|
lastUsage: undefined,
|
|
59
62
|
firstTurnUsage: undefined,
|
|
60
63
|
response: undefined,
|
|
@@ -117,7 +120,9 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
117
120
|
messages.push(message);
|
|
118
121
|
try {
|
|
119
122
|
opts.onToolResult?.(message);
|
|
120
|
-
} catch {
|
|
123
|
+
} catch {
|
|
124
|
+
// the tool-result observer is advisory
|
|
125
|
+
}
|
|
121
126
|
};
|
|
122
127
|
state.drainSteering = createSteeringDrain({
|
|
123
128
|
messages,
|
|
@@ -147,6 +152,9 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
147
152
|
* promote an empty/abnormal finish to an explicit Lead-facing error). */
|
|
148
153
|
export function finishLoop(state) {
|
|
149
154
|
const { response } = state;
|
|
155
|
+
// A reaction-only turn is a successful completion, never an empty finish.
|
|
156
|
+
const terminationReason = classifyTerminationReason(response, { sessionAgent: state.sessionAgent });
|
|
157
|
+
const reactionCompleted = terminationReason === 'empty' && state.noToolTurn.reactionCompleted;
|
|
150
158
|
return {
|
|
151
159
|
...response,
|
|
152
160
|
usage: state.lastUsage || response.usage,
|
|
@@ -157,7 +165,8 @@ export function finishLoop(state) {
|
|
|
157
165
|
toolCallsTotal: state.toolCallsTotal,
|
|
158
166
|
providerState: state.providerState,
|
|
159
167
|
providerStateUpdated: state.providerStateUpdated,
|
|
160
|
-
terminationReason:
|
|
168
|
+
terminationReason: reactionCompleted ? undefined : terminationReason,
|
|
169
|
+
...(reactionCompleted ? { reactionCompleted: true } : {}),
|
|
161
170
|
providerContinuations: state.noToolTurn.providerContinuations,
|
|
162
171
|
...(state.routeUsageHops?.length
|
|
163
172
|
? {
|
|
@@ -20,8 +20,11 @@ export function createTurnSegments({ messages, opts }) {
|
|
|
20
20
|
// Record a mid-turn segment for the caller-facing aggregate and surface it
|
|
21
21
|
// live for every session.
|
|
22
22
|
// `committed: true` marks text that is the just-committed message's own.
|
|
23
|
+
// A committed message is whole, so the text after it is another message
|
|
24
|
+
// and a break keeps the aggregate from running the two together; a part
|
|
25
|
+
// that was cut off (max-output recovery) resumes right where it stopped.
|
|
23
26
|
record(text, { committed = false } = {}) {
|
|
24
|
-
parts.push(text);
|
|
27
|
+
parts.push(committed ? `${text.trimEnd()}\n\n` : text);
|
|
25
28
|
try {
|
|
26
29
|
opts.onAssistantText?.(text, { committed });
|
|
27
30
|
} catch {
|