mixdog 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/package.json +8 -8
- package/scripts/native-release-status.mjs +238 -0
- package/scripts/verify-runtime-dependency-versions.mjs +158 -0
- package/src/agents/reviewer/AGENT.md +5 -7
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +9 -1
- package/src/defaults/skills/browser-use/SKILL.md +6 -3
- package/src/defaults/skills/local-provider/SKILL.md +33 -6
- package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
- package/src/defaults/skills/setup/SKILL.md +23 -1
- package/src/defaults/skills/setup/references/actions.md +50 -3
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +7 -3
- package/src/defaults/skills/visualize/SKILL.md +9 -6
- package/src/defaults/skills/visualize/references/craft.md +8 -1
- package/src/help.mjs +1 -1
- package/src/lib/keychain-cjs.cjs +4 -1
- package/src/lib/rules-builder.cjs +14 -7
- package/src/rules/agent-mode/AGENT_MODE.md +8 -5
- package/src/rules/agent-mode/MIXY.md +6 -8
- package/src/rules/lead/LEAD.md +7 -10
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- package/src/rules/shared/45-destructive.md +5 -1
- package/src/rules/shared/60-verification.md +6 -4
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
- package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
- package/src/runtime/agent/orchestrator/config.mjs +11 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
- package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +84 -32
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +84 -42
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
- package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
- package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
- package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +52 -6
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +35 -13
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +196 -45
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +45 -19
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +185 -37
- package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +240 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +102 -35
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +19 -9
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +199 -109
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +33 -8
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +27 -14
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +115 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +4 -9
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +14 -1
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +52 -11
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +126 -12
- package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +16 -3
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
- package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +15 -5
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +49 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +80 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +47 -14
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +10 -12
- package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +42 -23
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
- package/src/runtime/attachments/attachment-reference.mjs +155 -0
- package/src/runtime/attachments/legacy-office.mjs +110 -0
- package/src/runtime/attachments/limits.mjs +5 -1
- package/src/runtime/attachments/office-extract.mjs +3 -6
- package/src/runtime/attachments/pdf-extract.mjs +84 -10
- package/src/runtime/attachments/prompt-restore.mjs +70 -0
- package/src/runtime/attachments/store.mjs +109 -33
- package/src/runtime/browser-bridge/client.mjs +73 -20
- package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
- package/src/runtime/channels/lib/scheduler.mjs +14 -7
- package/src/runtime/channels/lib/state-file.mjs +15 -15
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
- package/src/runtime/channels/lib/worker-main.mjs +3 -2
- package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
- package/src/runtime/effort-judge/judge-client.mjs +66 -16
- package/src/runtime/effort-judge/model-install.mjs +47 -7
- package/src/runtime/local-provider/asset-installer.mjs +10 -4
- package/src/runtime/local-provider/catalog.mjs +5 -2
- package/src/runtime/local-provider/registered-models.mjs +64 -27
- package/src/runtime/local-provider/server.mjs +2 -3
- package/src/runtime/media/adapters/image-api.mjs +89 -0
- package/src/runtime/media/auth.mjs +64 -1
- package/src/runtime/media/catalog.mjs +66 -4
- package/src/runtime/media/jobs.mjs +4 -0
- package/src/runtime/media/lanes.mjs +46 -5
- package/src/runtime/media/media-usage.mjs +17 -0
- package/src/runtime/media/renditions.mjs +15 -15
- package/src/runtime/media/store.mjs +36 -35
- package/src/runtime/media/tool.mjs +8 -1
- package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
- package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
- package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
- package/src/runtime/memory/lib/pg/process.mjs +8 -4
- package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
- package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
- package/src/runtime/office/core/journal.mjs +7 -14
- package/src/runtime/office/design/library/design-library-core.mjs +4 -16
- package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
- package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
- package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
- package/src/runtime/office/pdf/pdf-render.mjs +30 -18
- package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +135 -29
- package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
- package/src/runtime/shared/agent-avatar.mjs +3 -2
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
- package/src/runtime/shared/agent-message-envelope.mjs +44 -0
- package/src/runtime/shared/agent-reap-state.d.mts +4 -0
- package/src/runtime/shared/agent-room-host.d.mts +31 -0
- package/src/runtime/shared/agent-room-host.mjs +58 -0
- package/src/runtime/shared/agent-store.mjs +24 -7
- package/src/runtime/shared/agent-task-starts.mjs +27 -0
- package/src/runtime/shared/atomic-file.d.mts +50 -0
- package/src/runtime/shared/atomic-file.mjs +394 -132
- package/src/runtime/shared/background-tasks.mjs +7 -4
- package/src/runtime/shared/bot-hops.mjs +35 -0
- package/src/runtime/shared/bot-split-migration.mjs +1 -1
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/defaults-separation.mjs +6 -2
- package/src/runtime/shared/delegated-approval-host.mjs +74 -0
- package/src/runtime/shared/err-text.mjs +4 -0
- package/src/runtime/shared/error-presentation.mjs +22 -4
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/process-lifecycle.mjs +8 -12
- package/src/runtime/shared/projects.mjs +50 -41
- package/src/runtime/shared/provider-accounts.mjs +17 -12
- package/src/runtime/shared/redact-directories.mjs +18 -0
- package/src/runtime/shared/remove-directory.mjs +28 -0
- package/src/runtime/shared/routine-trigger.d.mts +6 -1
- package/src/runtime/shared/routine-trigger.mjs +14 -6
- package/src/runtime/shared/run-child.d.mts +3 -0
- package/src/runtime/shared/run-child.mjs +24 -3
- package/src/runtime/shared/session-baseline-store.mjs +8 -2
- package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
- package/src/runtime/shared/session-sidebar-host.mjs +16 -3
- package/src/runtime/shared/singleton-owner.mjs +7 -6
- package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
- package/src/runtime/shared/staged-update.mjs +4 -2
- package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
- package/src/runtime/shared/tool-execution-contract.mjs +10 -0
- package/src/runtime/shared/tool-work-units.mjs +12 -9
- package/src/runtime/shared/transcript-metadata.mjs +28 -3
- package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
- package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
- package/src/runtime/shared/turn-snapshot.mjs +277 -124
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +92 -61
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +251 -61
- package/src/runtime/shared/worktrees/contract.mjs +11 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
- package/src/runtime/shared/worktrees/manager.mjs +419 -52
- package/src/runtime/shared/worktrees/registry.mjs +29 -27
- package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/tidy/process.mjs +41 -8
- package/src/runtime/tidy/resolve.mjs +10 -7
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +542 -204
- package/src/session-runtime/agent-profile-changes.mjs +16 -0
- package/src/session-runtime/agent-room-delivery.mjs +81 -35
- package/src/session-runtime/agent-task-sessions.mjs +811 -179
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +48 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +16 -7
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +2 -2
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +23 -3
- package/src/session-runtime/bot-status.mjs +432 -0
- package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
- package/src/session-runtime/config-lifecycle.mjs +60 -55
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/held-requests.mjs +31 -33
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +24 -26
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown.mjs +11 -3
- package/src/session-runtime/mcp-glue/connect.mjs +100 -186
- package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
- package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
- package/src/session-runtime/media-api.mjs +5 -2
- package/src/session-runtime/model-recency.mjs +1 -0
- package/src/session-runtime/model-route/route-tuning.mjs +4 -1
- package/src/session-runtime/model-route/set-route.mjs +61 -1
- package/src/session-runtime/owned-automation-run.mjs +8 -1
- package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
- package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
- package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
- package/src/session-runtime/route-resolution.mjs +16 -8
- package/src/session-runtime/route-state.mjs +1 -59
- package/src/session-runtime/routine-home-turn.mjs +5 -3
- package/src/session-runtime/runtime-bootstrap.mjs +5 -3
- package/src/session-runtime/runtime-paths.mjs +11 -5
- package/src/session-runtime/runtime-review-api.mjs +4 -1
- package/src/session-runtime/runtime-tunables.mjs +6 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
- package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
- package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +34 -19
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +7 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
- package/src/session-runtime/services/agent-tool.mjs +6 -0
- package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
- package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
- package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
- package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
- package/src/session-runtime/services/plugin-admin.mjs +26 -26
- package/src/session-runtime/services/provider-admin.mjs +26 -6
- package/src/session-runtime/services/schedule-access.mjs +33 -4
- package/src/session-runtime/services/seeds.mjs +4 -3
- package/src/session-runtime/services/usage-dashboard.mjs +1 -1
- package/src/session-runtime/services/usage-stats-model.mjs +2 -1
- package/src/session-runtime/services/worktree-access.mjs +27 -0
- package/src/session-runtime/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/session-hooks.mjs +9 -17
- package/src/session-runtime/settings-builtin-tools-api.mjs +65 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +12 -2
- package/src/session-runtime/setup-tool/settings-contract.mjs +34 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
- package/src/session-runtime/skills-api.mjs +12 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +349 -0
- package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
- package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +183 -0
- package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
- package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
- package/src/session-runtime/tool-policy-refresh.mjs +48 -369
- package/src/session-runtime/tool-surface.mjs +10 -4
- package/src/session-runtime/turn/session-ops.mjs +8 -0
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +7 -2
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +527 -333
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +85 -63
- package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
- package/src/session-runtime/workspace/transition-steps.mjs +1 -18
- package/src/session-runtime/workspace/transitions.mjs +279 -67
- package/src/session-runtime/workspace/workspace-state.mjs +7 -6
- package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-lag-profiler.mjs +3 -1
- package/src/standalone/daemon-session-control.mjs +173 -15
- package/src/standalone/daemon-telemetry.mjs +9 -0
- package/src/standalone/daemon.mjs +33 -10
- package/src/standalone/local-session-runtime.mjs +33 -16
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +8 -0
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
- package/src/standalone/session-service/agent-route-follow.mjs +69 -0
- package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
- package/src/standalone/session-service.mjs +21 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +36 -9
- package/src/standalone/staged-import.mjs +47 -0
- package/src/tui/App.jsx +2 -0
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- package/src/tui/app/message-selector.mjs +15 -2
- package/src/tui/app/model-options.mjs +16 -2
- package/src/tui/app/model-picker.mjs +2 -1
- package/src/tui/app/route-pickers.mjs +3 -1
- package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
- package/src/tui/dist/index.mjs +617 -369
- package/src/tui/paste-attachments.mjs +0 -1
- package/src/tui/paste-text-policy.mjs +4 -5
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/notice-surface.mjs +3 -0
- package/src/tui/session/session-api/intake/abort.mjs +52 -18
- package/src/tui/session/session-api/intake/rewind.mjs +39 -4
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +76 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -247
- package/src/tui/session/session-api/settings.mjs +14 -1
- package/src/tui/session/session-flow/drain.mjs +28 -3
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
- package/src/tui/session/session-flow/steering.mjs +8 -3
- package/src/tui/session/tool-approval.mjs +142 -14
- package/src/tui/session/transcript-intake.mjs +2 -0
- package/src/tui/session/turn.mjs +23 -14
- package/src/tui/transcript-tool-failures.mjs +8 -2
- package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
- package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
- package/src/rules/agent-mode/ROUTINE.md +0 -6
- package/src/session-runtime/room-member-gate.mjs +0 -48
|
@@ -5,7 +5,6 @@ import { getProvider, initProviders } from '../../providers/registry.mjs';
|
|
|
5
5
|
import { resolveMaintenanceRoute } from '../../agent-runtime/maintenance-route.mjs';
|
|
6
6
|
import { resolveSessionContextMeta } from '../manager/context-meta.mjs';
|
|
7
7
|
import { isAccountQuotaError } from '../../providers/account-pool.mjs';
|
|
8
|
-
import { builtinFeatureActive } from '../../runtime-core/builtin-features.mjs';
|
|
9
8
|
import { positiveInt } from '../../../../shared/numbers.mjs';
|
|
10
9
|
import { estimateMessagesTokens, providerTokenCalibration } from '../context-utils.mjs';
|
|
11
10
|
import {
|
|
@@ -16,6 +15,8 @@ import {
|
|
|
16
15
|
COMPACT_TARGET_MIN_TOKENS,
|
|
17
16
|
} from '../compact.mjs';
|
|
18
17
|
import { summarizeOnSharedPrefix } from '../compact/forked-summary.mjs';
|
|
18
|
+
import { normalizeCompactionSummaryMode } from '../compact/summary-mode.mjs';
|
|
19
|
+
import { compactionCacheWarm, lighterSubscriptionModel } from '../compact/summary-route.mjs';
|
|
19
20
|
import { retireCompactionFork } from '../side-question-store.mjs';
|
|
20
21
|
|
|
21
22
|
// Conversation summarization triggers independently of the post-compact target:
|
|
@@ -24,52 +25,103 @@ import { retireCompactionFork } from '../side-question-store.mjs';
|
|
|
24
25
|
const CONVERSATION_COMPACT_TRIGGER_RATIO = 0.05;
|
|
25
26
|
const CONVERSATION_COMPACT_TRIGGER_MAX_TOKENS = 20_000;
|
|
26
27
|
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
|
|
28
|
+
// One summary route: the provider, its model and the window the summary
|
|
29
|
+
// request must fit. `source` names the step: 'session' (the conversation's
|
|
30
|
+
// own model), 'maintenance' (the Maintainer) or 'lighter' (the subscription
|
|
31
|
+
// provider's lighter model).
|
|
32
|
+
function summaryRoute({ sessionRef, provider, providerName, model, fast, source }) {
|
|
33
|
+
if (!provider || typeof provider.send !== 'function' || !model) {
|
|
34
|
+
throw new Error(`compact summary route unavailable: ${providerName || 'unknown'}/${model || 'unknown'}`);
|
|
35
|
+
}
|
|
36
|
+
const sameModel = providerName === sessionRef?.provider && model === sessionRef?.model;
|
|
37
|
+
const contextWindow =
|
|
38
|
+
sameModel && positiveInt(sessionRef?.contextWindow)
|
|
39
|
+
? positiveInt(sessionRef.contextWindow)
|
|
40
|
+
: resolveSessionContextMeta(provider, model, {}, { wholeWindow: true }).contextWindow;
|
|
41
|
+
return { provider, providerName, model, contextWindow, fast, source };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// The Maintainer's own model when one is set and enabled, whatever the memory
|
|
45
|
+
// or recap settings; null otherwise (an unrelated global default is never
|
|
46
|
+
// borrowed). Provider failures/cancellation are not absence and propagate.
|
|
47
|
+
async function resolveMaintainerRoute({ sessionRef, config, signal, getProviderFn, initProvidersFn }) {
|
|
48
|
+
const route = resolveMaintenanceRoute({ agent: 'cycle1-agent', config, includeDefault: false });
|
|
49
|
+
if (!(route?.provider && route?.model && config.providers?.[route.provider]?.enabled !== false)) return null;
|
|
50
|
+
await initProvidersFn(config.providers || {}, { signal });
|
|
51
|
+
signal?.throwIfAborted();
|
|
52
|
+
return summaryRoute({
|
|
53
|
+
sessionRef,
|
|
54
|
+
provider: getProviderFn(route.provider),
|
|
55
|
+
providerName: route.provider,
|
|
56
|
+
model: route.model,
|
|
57
|
+
fast: route.fast === true,
|
|
58
|
+
source: 'maintenance',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function resolveSessionRoute({ sessionRef, provider, model, getProviderFn }) {
|
|
63
|
+
const providerName = sessionRef?.provider || provider?.name;
|
|
64
|
+
return summaryRoute({
|
|
65
|
+
sessionRef,
|
|
66
|
+
provider: provider || getProviderFn(providerName),
|
|
67
|
+
providerName,
|
|
68
|
+
model: model || sessionRef?.model,
|
|
69
|
+
source: 'session',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// The newest lighter model of a subscription provider's saved account
|
|
74
|
+
// catalog; null on any other provider, without a saved catalog, when none is
|
|
75
|
+
// listed, or when the conversation already runs on it.
|
|
76
|
+
async function resolveLighterRoute(input) {
|
|
77
|
+
const session = resolveSessionRoute(input);
|
|
78
|
+
const lighter = await lighterSubscriptionModel(session.providerName);
|
|
79
|
+
input.signal?.throwIfAborted();
|
|
80
|
+
if (!lighter || lighter === session.model) return null;
|
|
81
|
+
return summaryRoute({
|
|
82
|
+
sessionRef: input.sessionRef,
|
|
83
|
+
provider: session.provider,
|
|
84
|
+
providerName: session.providerName,
|
|
85
|
+
model: lighter,
|
|
86
|
+
source: 'lighter',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The compaction summary plan (compact/summary-mode.mjs): the saved mode,
|
|
92
|
+
* whether the session's prompt cache is warm, and the routes in the order
|
|
93
|
+
* they are tried, each resolved only when reached (null = unavailable, the
|
|
94
|
+
* next one runs). The conversation's own model is always the last step.
|
|
95
|
+
*/
|
|
96
|
+
export function compactionSummaryPlan({
|
|
32
97
|
sessionRef,
|
|
98
|
+
sessionId = sessionRef?.id,
|
|
33
99
|
provider,
|
|
34
100
|
model,
|
|
35
101
|
config = loadConfig(),
|
|
36
102
|
signal,
|
|
37
103
|
getProviderFn = getProvider,
|
|
38
104
|
initProvidersFn = initProviders,
|
|
39
|
-
|
|
105
|
+
now = Date.now(),
|
|
40
106
|
} = {}) {
|
|
41
107
|
signal?.throwIfAborted();
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (!selectedProvider || typeof selectedProvider.send !== 'function' || !selectedModel) {
|
|
53
|
-
throw new Error(`compact summary route unavailable: ${providerName || 'unknown'}/${selectedModel || 'unknown'}`);
|
|
54
|
-
}
|
|
55
|
-
const sameModel = providerName === sessionRef?.provider && selectedModel === sessionRef?.model;
|
|
56
|
-
const contextWindow =
|
|
57
|
-
sameModel && positiveInt(sessionRef?.contextWindow)
|
|
58
|
-
? positiveInt(sessionRef.contextWindow)
|
|
59
|
-
: resolveSessionContextMeta(selectedProvider, selectedModel, {}, { wholeWindow: true }).contextWindow;
|
|
60
|
-
return {
|
|
61
|
-
provider: selectedProvider,
|
|
62
|
-
providerName,
|
|
63
|
-
model: selectedModel,
|
|
64
|
-
contextWindow,
|
|
65
|
-
fast: useMaintenance ? route.fast === true : undefined,
|
|
66
|
-
source: useMaintenance ? 'maintenance' : 'session',
|
|
67
|
-
};
|
|
108
|
+
const input = { sessionRef, provider, model, config, signal, getProviderFn, initProvidersFn };
|
|
109
|
+
const mode = normalizeCompactionSummaryMode(config.compaction);
|
|
110
|
+
const warm = compactionCacheWarm(sessionId, now);
|
|
111
|
+
const session = async () => resolveSessionRoute(input);
|
|
112
|
+
const maintainer = () => resolveMaintainerRoute(input);
|
|
113
|
+
const lighter = () => resolveLighterRoute(input);
|
|
114
|
+
let steps = [session];
|
|
115
|
+
if (mode === 'maintainer') steps = [maintainer, session];
|
|
116
|
+
else if (mode === 'smart' && !warm) steps = [maintainer, lighter, session];
|
|
117
|
+
return { mode, warm, steps };
|
|
68
118
|
}
|
|
69
119
|
|
|
70
|
-
// The
|
|
71
|
-
//
|
|
72
|
-
//
|
|
120
|
+
// The summary request on one route: the conversation alone (earlier summary,
|
|
121
|
+
// dialogue, runtime conversation rows and one bounded line per tool call;
|
|
122
|
+
// skills and injections excluded), never the cached context. Its input budget belongs to its OWN model, split into
|
|
123
|
+
// batches when the conversation is larger, whereas the rebuilt conversation
|
|
124
|
+
// must fit the original session's target/window.
|
|
73
125
|
function summarizeConversation(target, ctx) {
|
|
74
126
|
const { sessionRef, sessionId, signal, sendOpts, compactPolicy } = ctx;
|
|
75
127
|
const summaryWindow = positiveInt(target.contextWindow) || ctx.contextWindow;
|
|
@@ -107,7 +159,6 @@ function summarizeConversation(target, ctx) {
|
|
|
107
159
|
fast: target.fast,
|
|
108
160
|
timeoutMs: compactPolicy.handoffTimeoutMs,
|
|
109
161
|
force: true,
|
|
110
|
-
filterOldHistoryForIngest: true,
|
|
111
162
|
}
|
|
112
163
|
);
|
|
113
164
|
}
|
|
@@ -117,24 +168,24 @@ function sumUsage(a, b) {
|
|
|
117
168
|
return Object.fromEntries(Object.keys(a).map((key) => [key, (a[key] || 0) + (Number(b[key]) || 0)]));
|
|
118
169
|
}
|
|
119
170
|
|
|
120
|
-
//
|
|
121
|
-
// the latest cached request
|
|
122
|
-
//
|
|
123
|
-
// sending the text-only transcript uncached, and the summary
|
|
124
|
-
// execution context. A
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
171
|
+
// The summary on one route. While the session's prompt cache is warm, the
|
|
172
|
+
// summary forks the latest cached request on the conversation's own model
|
|
173
|
+
// (compact/forked-summary.mjs): reading the cached context costs a tenth to a
|
|
174
|
+
// twentieth of sending the text-only transcript uncached, and the summary
|
|
175
|
+
// sees the full execution context. A cold cache would be rewritten in full,
|
|
176
|
+
// so the isolated text-only request runs instead; so does any other route
|
|
177
|
+
// (a cache is never shared across models). A fork that cannot run or fails
|
|
178
|
+
// falls back to the isolated request on the same route.
|
|
179
|
+
async function summarizeOnRoute(route, ctx, warm) {
|
|
180
|
+
const shared = warm
|
|
181
|
+
? await summarizeOnSharedPrefix({
|
|
182
|
+
sessionId: ctx.sessionId,
|
|
183
|
+
route,
|
|
184
|
+
conversationInput: ctx.conversationInput,
|
|
185
|
+
signal: ctx.signal,
|
|
186
|
+
timeoutMs: ctx.compactPolicy.handoffTimeoutMs,
|
|
187
|
+
})
|
|
188
|
+
: { fallback: 'cold_cache' };
|
|
138
189
|
if (shared.generated) return shared.generated;
|
|
139
190
|
ctx.signal?.throwIfAborted();
|
|
140
191
|
const generated = await summarizeConversation(route, ctx);
|
|
@@ -145,34 +196,45 @@ async function summarizeOnRoute(route, ctx) {
|
|
|
145
196
|
};
|
|
146
197
|
}
|
|
147
198
|
|
|
148
|
-
// A
|
|
149
|
-
// turn down: the
|
|
150
|
-
// summarize.
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
199
|
+
// A Maintainer or lighter model that is out of quota or not available to the
|
|
200
|
+
// account must not take the whole turn down: the next route still can
|
|
201
|
+
// summarize. Every other compaction failure (overflow, malformed summary,
|
|
202
|
+
// transport) keeps its existing handling, and an aborted turn stays aborted.
|
|
203
|
+
function fallsToNextRoute(error) {
|
|
204
|
+
const status = Number(error?.status || error?.httpStatus || error?.response?.status || 0);
|
|
205
|
+
return (
|
|
206
|
+
error?.code === 'provider_accounts_exhausted' ||
|
|
207
|
+
error?.code === 'model_not_found' ||
|
|
208
|
+
status === 429 ||
|
|
209
|
+
status === 404 ||
|
|
210
|
+
isAccountQuotaError(error)
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Resolving a route (provider init, catalog lookup) is part of its step: a
|
|
215
|
+
// quota or availability failure there moves to the next route like one from
|
|
216
|
+
// the summary request. The conversation's own model is the last step, so its
|
|
217
|
+
// failure always ends the compaction.
|
|
218
|
+
async function summarizeOnPlan(ctx, plan) {
|
|
219
|
+
const tried = new Set();
|
|
220
|
+
let failure = null;
|
|
221
|
+
for (const step of plan.steps) {
|
|
222
|
+
let route = null;
|
|
169
223
|
try {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
224
|
+
route = await step();
|
|
225
|
+
ctx.signal?.throwIfAborted();
|
|
226
|
+
const key = route && `${route.providerName}\u0000${route.model}`;
|
|
227
|
+
if (!route || tried.has(key)) continue;
|
|
228
|
+
tried.add(key);
|
|
229
|
+
return { route, generated: await summarizeOnRoute(route, ctx, plan.warm) };
|
|
230
|
+
} catch (error) {
|
|
231
|
+
ctx.signal?.throwIfAborted();
|
|
232
|
+
if (route) error.compactRoute = { provider: route.providerName, model: route.model };
|
|
233
|
+
if (route?.source === 'session' || !fallsToNextRoute(error)) throw error;
|
|
234
|
+
failure = error;
|
|
174
235
|
}
|
|
175
236
|
}
|
|
237
|
+
throw failure;
|
|
176
238
|
}
|
|
177
239
|
|
|
178
240
|
// The window this compaction must fit (calibrated to the provider's token
|
|
@@ -200,7 +262,10 @@ function freshContextBudget({ compactPolicy, sessionRef, provider, compactBudget
|
|
|
200
262
|
return { contextWindow, hardBudget, conversationInput, conversationTokens, conversationThresholdTokens };
|
|
201
263
|
}
|
|
202
264
|
|
|
203
|
-
function freshContextBuildOptions(
|
|
265
|
+
function freshContextBuildOptions(
|
|
266
|
+
{ compactPolicy = {}, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
267
|
+
budget
|
|
268
|
+
) {
|
|
204
269
|
return {
|
|
205
270
|
reserveTokens: compactPolicy.reserveTokens,
|
|
206
271
|
maxBudgetTokens: budget.hardBudget,
|
|
@@ -209,6 +274,7 @@ function freshContextBuildOptions({ compactPolicy = {}, sessionId, goalReminderT
|
|
|
209
274
|
sessionId,
|
|
210
275
|
latestUserPrefix: goalReminderText,
|
|
211
276
|
activeTurn,
|
|
277
|
+
referenceLatestAttachments: referenceLatestAttachments === true,
|
|
212
278
|
};
|
|
213
279
|
}
|
|
214
280
|
|
|
@@ -230,6 +296,27 @@ export function previewFreshContextCompaction(input) {
|
|
|
230
296
|
return { beforeTokens, afterTokens, reducesTokens: afterTokens < beforeTokens, summaryTriggered };
|
|
231
297
|
}
|
|
232
298
|
|
|
299
|
+
function buildFreshContextResult(
|
|
300
|
+
{ messages, compactBudgetTokens, buildOptions, requireReduction, sessionId },
|
|
301
|
+
handoffText
|
|
302
|
+
) {
|
|
303
|
+
const result = freshContextCompactMessages(messages, compactBudgetTokens, { ...buildOptions, handoffText });
|
|
304
|
+
// A generated summary can differ from its prediction. Never replace the
|
|
305
|
+
// original with an automatic result that is equal-sized or larger.
|
|
306
|
+
if (requireReduction && estimateMessagesTokens(result.messages) >= estimateMessagesTokens(messages)) {
|
|
307
|
+
return {
|
|
308
|
+
...result,
|
|
309
|
+
messages,
|
|
310
|
+
freshContext: false,
|
|
311
|
+
skipped: true,
|
|
312
|
+
diagnostics: { ...result.diagnostics, noOp: true, reason: 'no_token_reduction' },
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
// The rewritten transcript is no longer what the saved request carried.
|
|
316
|
+
if (result.freshContext) retireCompactionFork(sessionId);
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
|
|
233
320
|
export async function runFreshContextCompact({
|
|
234
321
|
sessionRef,
|
|
235
322
|
messages,
|
|
@@ -246,35 +333,24 @@ export async function runFreshContextCompact({
|
|
|
246
333
|
getProviderFn,
|
|
247
334
|
initProvidersFn,
|
|
248
335
|
requireReduction = false,
|
|
336
|
+
referenceLatestAttachments = false,
|
|
249
337
|
} = {}) {
|
|
250
338
|
const startedAt = Date.now();
|
|
251
339
|
signal?.throwIfAborted();
|
|
252
|
-
const { contextWindow, hardBudget,
|
|
253
|
-
|
|
340
|
+
const { contextWindow, hardBudget, conversationTokens, conversationThresholdTokens } = freshContextBudget({
|
|
341
|
+
compactPolicy,
|
|
342
|
+
sessionRef,
|
|
343
|
+
provider,
|
|
344
|
+
compactBudgetTokens,
|
|
345
|
+
messages,
|
|
346
|
+
});
|
|
254
347
|
const summaryTriggered = conversationTokens >= conversationThresholdTokens;
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
handoffText,
|
|
262
|
-
});
|
|
263
|
-
// A generated summary can differ from its prediction. Never replace the
|
|
264
|
-
// original with an automatic result that is equal-sized or larger.
|
|
265
|
-
if (requireReduction && estimateMessagesTokens(result.messages) >= estimateMessagesTokens(messages)) {
|
|
266
|
-
return {
|
|
267
|
-
...result,
|
|
268
|
-
messages,
|
|
269
|
-
freshContext: false,
|
|
270
|
-
skipped: true,
|
|
271
|
-
diagnostics: { ...result.diagnostics, noOp: true, reason: 'no_token_reduction' },
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
// The rewritten transcript is no longer what the saved request carried.
|
|
275
|
-
if (result.freshContext) retireCompactionFork(sessionId);
|
|
276
|
-
return result;
|
|
277
|
-
};
|
|
348
|
+
const buildOptions = freshContextBuildOptions(
|
|
349
|
+
{ compactPolicy, sessionId, goalReminderText, activeTurn, referenceLatestAttachments },
|
|
350
|
+
{ contextWindow, hardBudget }
|
|
351
|
+
);
|
|
352
|
+
const build = (handoffText) =>
|
|
353
|
+
buildFreshContextResult({ messages, compactBudgetTokens, buildOptions, requireReduction, sessionId }, handoffText);
|
|
278
354
|
const pipeline = {
|
|
279
355
|
mode: summaryTriggered ? 'conversation-summary' : 'rules',
|
|
280
356
|
conversationTokens,
|
|
@@ -291,7 +367,17 @@ export async function runFreshContextCompact({
|
|
|
291
367
|
pipeline: { ...pipeline, totalMs: Date.now() - startedAt },
|
|
292
368
|
});
|
|
293
369
|
}
|
|
294
|
-
const
|
|
370
|
+
const plan = compactionSummaryPlan({
|
|
371
|
+
sessionRef,
|
|
372
|
+
sessionId,
|
|
373
|
+
provider,
|
|
374
|
+
model,
|
|
375
|
+
config,
|
|
376
|
+
signal,
|
|
377
|
+
getProviderFn,
|
|
378
|
+
initProvidersFn,
|
|
379
|
+
});
|
|
380
|
+
const { route, generated } = await summarizeOnPlan(
|
|
295
381
|
{
|
|
296
382
|
sessionRef,
|
|
297
383
|
sessionId,
|
|
@@ -301,9 +387,11 @@ export async function runFreshContextCompact({
|
|
|
301
387
|
compactBudgetTokens,
|
|
302
388
|
hardBudget,
|
|
303
389
|
contextWindow,
|
|
304
|
-
|
|
390
|
+
// What the summary is written from: the measured conversation plus one
|
|
391
|
+
// bounded line per tool call (conversationCompactionInput).
|
|
392
|
+
conversationInput: conversationCompactionInput(messages, { summary: true }),
|
|
305
393
|
},
|
|
306
|
-
|
|
394
|
+
plan
|
|
307
395
|
);
|
|
308
396
|
signal?.throwIfAborted();
|
|
309
397
|
const result = build(generated.summary);
|
|
@@ -315,6 +403,8 @@ export async function runFreshContextCompact({
|
|
|
315
403
|
pipeline: {
|
|
316
404
|
...pipeline,
|
|
317
405
|
handoffSource: 'session-local',
|
|
406
|
+
summaryMode: plan.mode,
|
|
407
|
+
cacheWarm: plan.warm,
|
|
318
408
|
summaryRoute: route.source,
|
|
319
409
|
summaryProvider: route.providerName,
|
|
320
410
|
summaryModel: route.model,
|
|
@@ -58,6 +58,7 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
58
58
|
lastUsage: undefined,
|
|
59
59
|
firstTurnUsage: undefined,
|
|
60
60
|
response: undefined,
|
|
61
|
+
lastStreamedChars: 0,
|
|
61
62
|
lastSendTools: tools,
|
|
62
63
|
contextOverflowRetryUsed: false,
|
|
63
64
|
// Set when a provider context-overflow refusal triggers the in-turn
|
|
@@ -133,6 +134,10 @@ export function createLoopState({ provider, messages, model, tools, cwd, sendOpt
|
|
|
133
134
|
sessionId,
|
|
134
135
|
sessionAgent: state.sessionAgent,
|
|
135
136
|
drainSteering: state.drainSteering,
|
|
137
|
+
// Only a provider that can offer a higher max_tokens implements this.
|
|
138
|
+
escalateMaxTokens: () => state.provider?.escalatedMaxTokens?.(state.model, state.opts, state.lastSendTools) ?? null,
|
|
139
|
+
// Characters the latest send put on screen through the live text stream.
|
|
140
|
+
streamedChars: () => state.lastStreamedChars,
|
|
136
141
|
});
|
|
137
142
|
return state;
|
|
138
143
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// continuations with no intervening tool batch, the current text is accepted
|
|
7
7
|
// as the final answer.
|
|
8
8
|
import { writeLoopDiagnostic } from './diagnostic.mjs';
|
|
9
|
+
import { resetOutputLimitRecovery } from './output-limit.mjs';
|
|
9
10
|
|
|
10
11
|
const PROVIDER_CONTINUATION_NO_TOOL_LIMIT = Math.max(
|
|
11
12
|
1,
|
|
@@ -38,6 +39,7 @@ export function resumeContinuation(
|
|
|
38
39
|
state.providerContinuationCount += 1;
|
|
39
40
|
state.continuationsSinceToolBatch += 1;
|
|
40
41
|
state.emptyNudgeStreak = 0;
|
|
42
|
+
resetOutputLimitRecovery(state);
|
|
41
43
|
trace(iteration, 'provider_continuation', {
|
|
42
44
|
signal,
|
|
43
45
|
stop_reason: stopReason,
|
|
@@ -25,7 +25,7 @@ export function nudgeEmptyTurn(response, { stopReason, isIncompleteStop }, { sta
|
|
|
25
25
|
messages.push({
|
|
26
26
|
role: 'user',
|
|
27
27
|
content: isIncompleteStop
|
|
28
|
-
? `[mixdog-runtime] Empty
|
|
28
|
+
? `[mixdog-runtime] Empty incomplete turn (stopReason=${stopReason}). Return the remaining final handoff; use tools only for required evidence still missing.`
|
|
29
29
|
: `[mixdog-runtime] Empty response (${state.emptyNudgeStreak}/${EMPTY_NUDGE_MAX}). Return final text, or use tools only for required evidence still missing.`,
|
|
30
30
|
});
|
|
31
31
|
return { action: 'continue', response };
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
// Max-output
|
|
1
|
+
// Max-output recovery — the single rule for every turn the provider cut at its
|
|
2
|
+
// output ceiling, with or without visible text.
|
|
2
3
|
//
|
|
3
|
-
// A
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// A max-output stop is not a completed assistant turn. A turn that spent its
|
|
5
|
+
// whole budget (typically on thinking) would repeat identically if re-sent
|
|
6
|
+
// unchanged, so recovery changes the request each time:
|
|
7
|
+
// 1. Escalation, once per progress window: re-send the same transcript with
|
|
8
|
+
// a higher max_tokens when the provider has one to offer (no message
|
|
9
|
+
// added; the cut partial is discarded and regenerated).
|
|
10
|
+
// 2. Up to MAX_OUTPUT_RECOVERY_LIMIT resume prompts at the normal
|
|
11
|
+
// max_tokens, preserving any partial text in the transcript.
|
|
12
|
+
// 3. Then the turn ends with a visible notice that the output limit was hit.
|
|
13
|
+
// Real progress (a tool-call turn, a continued text turn) resets both steps.
|
|
14
|
+
import { isOutputLimitStopReason } from '../termination.mjs';
|
|
15
|
+
|
|
7
16
|
const MAX_OUTPUT_RECOVERY_LIMIT = 3;
|
|
8
|
-
const MAX_OUTPUT_EXHAUSTED_NOTICE = `[mixdog-runtime]
|
|
17
|
+
const MAX_OUTPUT_EXHAUSTED_NOTICE = `[mixdog-runtime] The model hit its output limit and the response stayed truncated after ${MAX_OUTPUT_RECOVERY_LIMIT} recovery attempts.`;
|
|
9
18
|
const MAX_OUTPUT_RESUME_PROMPT =
|
|
10
|
-
'Output token limit hit. Resume directly — no apology, no recap. Pick up exactly where the
|
|
19
|
+
'[mixdog-runtime] Output token limit hit. Resume directly — no apology, no recap. Pick up exactly where you left off, and break the remaining work into smaller pieces.';
|
|
11
20
|
// A response whose stream was cut mid-text (and could not be withdrawn from
|
|
12
21
|
// the screen) resumes through the same ladder with its own reason.
|
|
13
22
|
const STREAM_CUT_RESUME_PROMPT =
|
|
@@ -19,25 +28,65 @@ function resumePrompt(response, attempt) {
|
|
|
19
28
|
: { role: 'user', content: MAX_OUTPUT_RESUME_PROMPT, meta: { source: 'max-output-recovery', attempt } };
|
|
20
29
|
}
|
|
21
30
|
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
// Real progress ends the recovery window: the next cut starts a fresh ladder.
|
|
32
|
+
export function resetOutputLimitRecovery(state) {
|
|
33
|
+
state.maxOutputRecoveryCount = 0;
|
|
34
|
+
state.outputEscalationUsed = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The escalation discards the cut response, so whatever it already put on the
|
|
38
|
+
// live stream must be withdrawn through the owner's retraction channel — the
|
|
39
|
+
// same one transport replays use. Text the owner cannot withdraw would be
|
|
40
|
+
// shown twice, so that case does not escalate.
|
|
41
|
+
async function withdrawStreamedText(opts, chars) {
|
|
42
|
+
if (!(chars > 0)) return true;
|
|
43
|
+
if (typeof opts?.onTextReset !== 'function') return false;
|
|
44
|
+
try {
|
|
45
|
+
return (await opts.onTextReset({ chars, reasoning: false, reason: 'output-limit-escalation' })) === true;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function resolveOutputLimit(
|
|
52
|
+
response,
|
|
53
|
+
{ state, segments, messages, opts, escalateMaxTokens, streamedChars }
|
|
54
|
+
) {
|
|
55
|
+
const hasContent = typeof response.content === 'string' && response.content.trim().length > 0;
|
|
56
|
+
if (!state.outputEscalationUsed && isOutputLimitStopReason(response.stopReason ?? response.stop_reason)) {
|
|
57
|
+
state.outputEscalationUsed = true;
|
|
58
|
+
// A provider may resolve the higher limit asynchronously (route lookup);
|
|
59
|
+
// failing to find one only skips the escalation.
|
|
60
|
+
const limit = await Promise.resolve()
|
|
61
|
+
.then(escalateMaxTokens)
|
|
62
|
+
.catch(() => null);
|
|
63
|
+
if (limit > 0 && (await withdrawStreamedText(opts, streamedChars()))) {
|
|
64
|
+
// Taken off the shared options by the very next send (sendProviderRequest).
|
|
65
|
+
opts.maxOutputTokensOverride = limit;
|
|
66
|
+
return { action: 'continue', response };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (hasContent) segments.record(response.content);
|
|
24
70
|
if (state.maxOutputRecoveryCount < MAX_OUTPUT_RECOVERY_LIMIT) {
|
|
25
71
|
// The partial assistant turn must be visible to the model so it can
|
|
26
72
|
// resume at the exact cutoff instead of reconstructing or repeating
|
|
27
73
|
// it. askSession persists this natural recovery chain;
|
|
28
74
|
// historyContent below prevents the aggregate returned to callers
|
|
29
|
-
// from being persisted a second time.
|
|
30
|
-
segments.commitIntermediate(response);
|
|
75
|
+
// from being persisted a second time. An empty cut has no output to keep.
|
|
76
|
+
if (hasContent) segments.commitIntermediate(response);
|
|
31
77
|
state.maxOutputRecoveryCount += 1;
|
|
32
78
|
messages.push(resumePrompt(response, state.maxOutputRecoveryCount));
|
|
33
79
|
return { action: 'continue', response };
|
|
34
80
|
}
|
|
35
|
-
const terminalSegment =
|
|
81
|
+
const terminalSegment = hasContent
|
|
82
|
+
? `${response.content}\n\n${MAX_OUTPUT_EXHAUSTED_NOTICE}`
|
|
83
|
+
: MAX_OUTPUT_EXHAUSTED_NOTICE;
|
|
84
|
+
const earlier = (hasContent ? segments.parts.slice(0, -1) : segments.parts).join('');
|
|
36
85
|
return {
|
|
37
86
|
action: 'break',
|
|
38
87
|
response: {
|
|
39
88
|
...response,
|
|
40
|
-
content: `${
|
|
89
|
+
content: `${earlier}${earlier && !hasContent ? '\n\n' : ''}${terminalSegment}`,
|
|
41
90
|
historyContent: terminalSegment,
|
|
42
91
|
maxOutputRecoveryAttempts: state.maxOutputRecoveryCount,
|
|
43
92
|
},
|
|
@@ -14,16 +14,27 @@ import { HIDDEN_AGENT_NAMES } from './hidden-agents.mjs';
|
|
|
14
14
|
import { INCOMPLETE_STOP_REASONS, isOutputLimitStopReason, providerContinuationSignal } from './termination.mjs';
|
|
15
15
|
import { appendAgentTrace } from '../../agent-trace.mjs';
|
|
16
16
|
import { createTurnSegments } from './no-tool-turn/segments.mjs';
|
|
17
|
-
import { resolveOutputLimit } from './no-tool-turn/output-limit.mjs';
|
|
17
|
+
import { resetOutputLimitRecovery, resolveOutputLimit } from './no-tool-turn/output-limit.mjs';
|
|
18
18
|
import { resolveRefusal } from './no-tool-turn/refusal.mjs';
|
|
19
19
|
import { resumeContinuation } from './no-tool-turn/continuation.mjs';
|
|
20
20
|
import { nudgeEmptyTurn } from './no-tool-turn/empty-nudge.mjs';
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// `escalateMaxTokens()` asks the live provider for a higher one-shot max_tokens
|
|
23
|
+
// (number) or reports none (null/undefined) — the loop stays provider-agnostic.
|
|
24
|
+
export function createNoToolTurnResolver({
|
|
25
|
+
messages,
|
|
26
|
+
opts,
|
|
27
|
+
sessionId,
|
|
28
|
+
sessionAgent,
|
|
29
|
+
drainSteering,
|
|
30
|
+
escalateMaxTokens = () => null,
|
|
31
|
+
streamedChars = () => 0,
|
|
32
|
+
}) {
|
|
23
33
|
const segments = createTurnSegments({ messages, opts });
|
|
24
34
|
// Per-turn recovery counters shared by the ladders.
|
|
25
35
|
const state = {
|
|
26
36
|
maxOutputRecoveryCount: 0,
|
|
37
|
+
outputEscalationUsed: false,
|
|
27
38
|
refusalRetryUsed: false,
|
|
28
39
|
emptyNudgeStreak: 0,
|
|
29
40
|
// Structured provider continuation signals honored this turn. Diagnostic
|
|
@@ -42,7 +53,7 @@ export function createNoToolTurnResolver({ messages, opts, sessionId, sessionAge
|
|
|
42
53
|
/* best-effort telemetry */
|
|
43
54
|
}
|
|
44
55
|
};
|
|
45
|
-
const ladder = { state, segments, messages, sessionId, trace };
|
|
56
|
+
const ladder = { state, segments, messages, opts, sessionId, trace, escalateMaxTokens, streamedChars };
|
|
46
57
|
|
|
47
58
|
// A no-tool message ends the turn. Unresolved tool failures remain visible
|
|
48
59
|
// in history and can be reported directly without a synthetic continuation
|
|
@@ -66,11 +77,13 @@ export function createNoToolTurnResolver({ messages, opts, sessionId, sessionAge
|
|
|
66
77
|
// { action: 'continue' | 'break', response }. 'continue' means the
|
|
67
78
|
// recovery appended to the transcript and the loop must re-send;
|
|
68
79
|
// 'break' returns the (possibly aggregated) terminal response.
|
|
69
|
-
resolve(response, iteration) {
|
|
80
|
+
async resolve(response, iteration) {
|
|
70
81
|
const hasContent = typeof response.content === 'string' && response.content.trim().length > 0;
|
|
71
82
|
const stopReason = response.stopReason ?? response.stop_reason ?? null;
|
|
72
83
|
const isOutputLimitStop = isOutputLimitStopReason(stopReason);
|
|
73
|
-
if (
|
|
84
|
+
if (isOutputLimitStop || (hasContent && response.streamCut === true)) {
|
|
85
|
+
return resolveOutputLimit(response, ladder);
|
|
86
|
+
}
|
|
74
87
|
if (stopReason === 'refusal') return resolveRefusal(response, hasContent, ladder);
|
|
75
88
|
// Output-limit stops keep the bounded max-output ladder above and
|
|
76
89
|
// refusals (already returned) keep the bounded refusal retry; both
|
|
@@ -108,13 +121,16 @@ export function createNoToolTurnResolver({ messages, opts, sessionId, sessionAge
|
|
|
108
121
|
})
|
|
109
122
|
) {
|
|
110
123
|
state.emptyNudgeStreak = 0;
|
|
124
|
+
resetOutputLimitRecovery(state);
|
|
111
125
|
return { action: 'continue', response };
|
|
112
126
|
}
|
|
113
127
|
return finishTurn(response);
|
|
114
128
|
},
|
|
115
|
-
// A turn that produced tool calls is never an empty contract violation
|
|
129
|
+
// A turn that produced tool calls is never an empty contract violation,
|
|
130
|
+
// and it is real progress: a later output-limit cut starts a fresh ladder.
|
|
116
131
|
noteToolCallTurn() {
|
|
117
132
|
state.emptyNudgeStreak = 0;
|
|
133
|
+
resetOutputLimitRecovery(state);
|
|
118
134
|
},
|
|
119
135
|
noteToolBatchCompleted() {
|
|
120
136
|
state.continuationsSinceToolBatch = 0;
|