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
|
@@ -3,9 +3,12 @@ import { estimateMessagesTokens } from '../context-utils.mjs';
|
|
|
3
3
|
import { estimateTokens } from '../token-estimate.mjs';
|
|
4
4
|
import { persistToolResultArtifactSync, previewToolResultArtifact } from '../tool-result-offload.mjs';
|
|
5
5
|
import {
|
|
6
|
+
EXECUTION_TEXT_SOURCE,
|
|
6
7
|
isActualUserInstructionMessage,
|
|
8
|
+
isCompactConversationRow,
|
|
7
9
|
isProtectedContextAckMessage,
|
|
8
10
|
latestActualUserInstructionIndex,
|
|
11
|
+
pendingTaskNotificationIndexes,
|
|
9
12
|
} from './messages.mjs';
|
|
10
13
|
import { staleObservations, supersedeObservation } from './observation-supersession.mjs';
|
|
11
14
|
import { carryMessageId, withoutMessageIdsReplacer } from '../message-ids.mjs';
|
|
@@ -168,9 +171,10 @@ function shrinkGroup(group, archive, level) {
|
|
|
168
171
|
});
|
|
169
172
|
}
|
|
170
173
|
|
|
171
|
-
// Walk from the anchor: kept groups verbatim, user instructions,
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
+
// Walk from the anchor: kept groups verbatim, user instructions, unanswered
|
|
175
|
+
// task notifications, and the conversation the mode allows (rule-only:
|
|
176
|
+
// assistant text and runtime conversation rows).
|
|
177
|
+
function assembleTail(messages, kept, { anchor, firstKept, preserveConversation, pending }) {
|
|
174
178
|
const tail = [];
|
|
175
179
|
for (let i = Math.max(0, anchor); i < messages.length; i += 1) {
|
|
176
180
|
const group = kept.get(i);
|
|
@@ -184,8 +188,16 @@ function assembleTail(messages, kept, { anchor, firstKept, preserveConversation
|
|
|
184
188
|
// Omitted execution stays in the archive; its conversational text
|
|
185
189
|
// remains verbatim without replaying an orphaned call or reasoning.
|
|
186
190
|
if (message.toolCalls?.length) {
|
|
187
|
-
// The text-only copy is this message's rewrite: it keeps its id
|
|
188
|
-
|
|
191
|
+
// The text-only copy is this message's rewrite: it keeps its id, and
|
|
192
|
+
// its marker keeps it from reading as a final reply.
|
|
193
|
+
if (message.content) {
|
|
194
|
+
tail.push(
|
|
195
|
+
carryMessageId(
|
|
196
|
+
{ role: 'assistant', content: message.content, meta: { source: EXECUTION_TEXT_SOURCE } },
|
|
197
|
+
message
|
|
198
|
+
)
|
|
199
|
+
);
|
|
200
|
+
}
|
|
189
201
|
} else {
|
|
190
202
|
tail.push(message);
|
|
191
203
|
}
|
|
@@ -193,6 +205,8 @@ function assembleTail(messages, kept, { anchor, firstKept, preserveConversation
|
|
|
193
205
|
}
|
|
194
206
|
if (
|
|
195
207
|
isActualUserInstructionMessage(message) ||
|
|
208
|
+
pending.has(i) ||
|
|
209
|
+
(preserveConversation && isCompactConversationRow(message)) ||
|
|
196
210
|
(i >= firstKept && message?.role === 'assistant' && !message.toolCalls?.length)
|
|
197
211
|
) {
|
|
198
212
|
tail.push(message);
|
|
@@ -201,6 +215,19 @@ function assembleTail(messages, kept, { anchor, firstKept, preserveConversation
|
|
|
201
215
|
return tail;
|
|
202
216
|
}
|
|
203
217
|
|
|
218
|
+
// The reminder naming the new dump and the earlier ones it supersedes.
|
|
219
|
+
function recoveryReminder(archive, previousRecovery) {
|
|
220
|
+
const earlier = [...new Set(previousRecovery.flatMap(recoveryArchivePaths))]
|
|
221
|
+
.filter((path) => path !== archive.path)
|
|
222
|
+
.slice(-MAX_EARLIER_DUMPS);
|
|
223
|
+
const earlierLine = earlier.length ? `\nEarlier dumps (older first): ${earlier.join(EARLIER_DUMPS_SEPARATOR)}` : '';
|
|
224
|
+
return {
|
|
225
|
+
role: 'user',
|
|
226
|
+
meta: { source: EXECUTION_RECOVERY_SOURCE, synthetic: true },
|
|
227
|
+
content: `<system-reminder>\nSome execution history was omitted or shortened to fit the tool-history budget. This is not an instruction to repeat those calls. The original calls, outcomes, and earlier recovery references are available at ${archive.path} (sha256:${archive.sha256}). The dump is JSONL: line N+1 is message index N; an "archivedMessage" line names the file holding that message, so search its directory too. Read only missing evidence when needed.${earlierLine}\n</system-reminder>`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
204
231
|
export function buildExecutionTail(
|
|
205
232
|
transcript,
|
|
206
233
|
{ contextWindow, sessionId, preserveConversation = false, preview = false } = {}
|
|
@@ -225,17 +252,7 @@ export function buildExecutionTail(
|
|
|
225
252
|
const dump = persist({ sessionId, toolCallId: 'compact-execution', channel: 'compact-execution', content: text });
|
|
226
253
|
if (!dump) throw new Error('compact: execution history could not be archived; original context preserved');
|
|
227
254
|
archive = dump;
|
|
228
|
-
|
|
229
|
-
.filter((path) => path !== archive.path)
|
|
230
|
-
.slice(-MAX_EARLIER_DUMPS);
|
|
231
|
-
const earlierLine = earlier.length ? `\nEarlier dumps (older first): ${earlier.join(EARLIER_DUMPS_SEPARATOR)}` : '';
|
|
232
|
-
recovery = [
|
|
233
|
-
{
|
|
234
|
-
role: 'user',
|
|
235
|
-
meta: { source: EXECUTION_RECOVERY_SOURCE, synthetic: true },
|
|
236
|
-
content: `<system-reminder>\nSome execution history was omitted or shortened to fit the tool-history budget. This is not an instruction to repeat those calls. The original calls, outcomes, and earlier recovery references are available at ${archive.path} (sha256:${archive.sha256}). The dump is JSONL: line N+1 is message index N; an "archivedMessage" line names the file holding that message, so search its directory too. Read only missing evidence when needed.${earlierLine}\n</system-reminder>`,
|
|
237
|
-
},
|
|
238
|
-
];
|
|
255
|
+
recovery = [recoveryReminder(archive, previousRecovery)];
|
|
239
256
|
};
|
|
240
257
|
// An observation a later one of the same page or window replaced keeps only
|
|
241
258
|
// its outcome and a reference to the archived original.
|
|
@@ -294,13 +311,22 @@ export function buildExecutionTail(
|
|
|
294
311
|
throw new Error('compact: latest execution group cannot fit the tool-history budget; original context preserved');
|
|
295
312
|
}
|
|
296
313
|
const latest = latestActualUserInstructionIndex(messages);
|
|
314
|
+
const pendingIndexes = pendingTaskNotificationIndexes(messages);
|
|
315
|
+
const pending = new Set(pendingIndexes);
|
|
297
316
|
const firstKept = kept.size ? Math.min(...kept.keys()) : messages.length;
|
|
298
317
|
const latestKept = latest < 0 ? firstKept : latest;
|
|
299
|
-
const anchor = preserveConversation
|
|
300
|
-
|
|
318
|
+
const anchor = preserveConversation
|
|
319
|
+
? 0
|
|
320
|
+
: Math.min(requestStart(messages, Math.min(firstKept, latestKept)), ...pendingIndexes);
|
|
321
|
+
const tail = assembleTail(messages, kept, { anchor, firstKept, preserveConversation, pending });
|
|
301
322
|
// With no execution to retain, keep the existing latest-request contract.
|
|
302
323
|
if (!preserveConversation && !groups.length && !previousRecovery.length) {
|
|
303
|
-
return {
|
|
324
|
+
return {
|
|
325
|
+
messages: messages.filter((_message, index) => index === latest || pending.has(index)),
|
|
326
|
+
toolTokens: 0,
|
|
327
|
+
toolBudget: budget,
|
|
328
|
+
retainedGroups: 0,
|
|
329
|
+
};
|
|
304
330
|
}
|
|
305
331
|
return {
|
|
306
332
|
messages: [...recovery, ...tail],
|
|
@@ -65,6 +65,9 @@ export async function summarizeOnSharedPrefix({ sessionId, route, conversationIn
|
|
|
65
65
|
try {
|
|
66
66
|
response = await route.provider.send(messages, request.model, request.tools.length ? request.tools : undefined, {
|
|
67
67
|
...opts,
|
|
68
|
+
// Usage-ledger source, as on the isolated request (a background
|
|
69
|
+
// session's own sourceType in `opts.session` still wins there).
|
|
70
|
+
requestKind: 'compaction',
|
|
68
71
|
transportScope,
|
|
69
72
|
admissionOwner: sessionId,
|
|
70
73
|
signal: requestSignal,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
isProtectedContextUserMessage,
|
|
11
11
|
isSummaryMessage,
|
|
12
12
|
} from './user-message-kind.mjs';
|
|
13
|
+
import { CONTROL_MARKER_RE } from '../../../../shared/tool-execution-contract.mjs';
|
|
13
14
|
|
|
14
15
|
export function compactHeader(oldHistory) {
|
|
15
16
|
// Stable display ids are bookkeeping, not conversation: the header names
|
|
@@ -53,6 +54,49 @@ export function isProtectedContextAckMessage(m) {
|
|
|
53
54
|
);
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
// The text-only copy rule-only Compact keeps of an omitted tool-call turn.
|
|
58
|
+
// It is execution, not a final reply, though it no longer carries its calls.
|
|
59
|
+
export const EXECUTION_TEXT_SOURCE = 'compact-execution-text';
|
|
60
|
+
|
|
61
|
+
// Delivered task notifications (a background agent's or task's completion,
|
|
62
|
+
// stored as a role:'user' turn with source 'task-notification') the model has
|
|
63
|
+
// not answered yet: every one after the latest final assistant reply. They
|
|
64
|
+
// are turn input but neither a user instruction nor summarized conversation,
|
|
65
|
+
// so a Compact must carry them verbatim or the report is lost.
|
|
66
|
+
export function pendingTaskNotificationIndexes(messages) {
|
|
67
|
+
const list = Array.isArray(messages) ? messages : [];
|
|
68
|
+
const pending = [];
|
|
69
|
+
for (let index = list.length - 1; index >= 0; index -= 1) {
|
|
70
|
+
const message = list[index];
|
|
71
|
+
if (
|
|
72
|
+
message?.role === 'assistant' &&
|
|
73
|
+
!message.toolCalls?.length &&
|
|
74
|
+
!isProtectedContextAckMessage(message) &&
|
|
75
|
+
message.meta?.source !== EXECUTION_TEXT_SOURCE
|
|
76
|
+
) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
if (message?.role === 'user' && message.meta?.source === 'task-notification') pending.unshift(index);
|
|
80
|
+
}
|
|
81
|
+
return pending;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Runtime rows that are conversation, not instructions: task and channel
|
|
85
|
+
// notifications (answered or not), routine and task results posted into a
|
|
86
|
+
// home thread, and turn interruption markers. Rule-only Compact keeps them
|
|
87
|
+
// with the dialogue; the summary reads them as data.
|
|
88
|
+
const CONVERSATION_RUNTIME_SOURCES = new Set(['task-notification', 'schedule-result']);
|
|
89
|
+
|
|
90
|
+
export function isCompactConversationRow(message) {
|
|
91
|
+
if (message?.role !== 'user') return false;
|
|
92
|
+
if (CONVERSATION_RUNTIME_SOURCES.has(String(message.meta?.source || ''))) return true;
|
|
93
|
+
return (
|
|
94
|
+
typeof message.content === 'string' &&
|
|
95
|
+
CONTROL_MARKER_RE.test(message.content.trim()) &&
|
|
96
|
+
!isActualUserInstructionMessage(message)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
56
100
|
function referenceFilesManifestMessage(message) {
|
|
57
101
|
if (message?.role !== 'user' || typeof message.content !== 'string') return null;
|
|
58
102
|
const text = message.content.trimStart();
|
|
@@ -5,16 +5,19 @@ import { estimateMessagesTokens, reconcileDedupStubs, sanitizeToolPairs } from '
|
|
|
5
5
|
import { HANDOFF_TIMEOUT_MAX_MS, SUMMARY_OUTPUT_TOKENS, compactDebugLog } from './constants.mjs';
|
|
6
6
|
import {
|
|
7
7
|
contentText,
|
|
8
|
+
redactRawSecretString,
|
|
8
9
|
redactToolCallSecretsInMessages,
|
|
9
10
|
safeEstimateMessagesTokens,
|
|
10
11
|
textByteLength,
|
|
11
12
|
} from './text-utils.mjs';
|
|
12
13
|
import {
|
|
13
14
|
contextAckMessage,
|
|
15
|
+
isCompactConversationRow,
|
|
14
16
|
isProtectedContextAckMessage,
|
|
15
17
|
isSummaryMessage,
|
|
16
18
|
latestActualUserInstructionIndex,
|
|
17
19
|
latestActualUserInstructionMessage,
|
|
20
|
+
pendingTaskNotificationIndexes,
|
|
18
21
|
splitProtectedContext,
|
|
19
22
|
} from './messages.mjs';
|
|
20
23
|
import { activeTurnContinuationMessage } from './continuation.mjs';
|
|
@@ -25,6 +28,8 @@ import { stripRuntimeUserContext, withRuntimeUserContext } from '../runtime-user
|
|
|
25
28
|
import { carryMessageId, messageIdOf } from '../message-ids.mjs';
|
|
26
29
|
import { normalizeIngestRole, shouldExcludeIngestMessage } from '../../../../memory/lib/session-ingest.mjs';
|
|
27
30
|
import { codexWireSendOpts } from '../manager/session-id.mjs';
|
|
31
|
+
import { messageHasReferencableMedia, referenceMessageMedia } from '../../../../attachments/attachment-reference.mjs';
|
|
32
|
+
import { messageAttachmentTokens } from '../attachment-preflight.mjs';
|
|
28
33
|
import { rebaseCompactedEffortConfiguration } from '../../providers/effort-configuration.mjs';
|
|
29
34
|
import {
|
|
30
35
|
COMPACTION_SYSTEM_PROMPT,
|
|
@@ -73,8 +78,13 @@ function splitFreshSource(messages) {
|
|
|
73
78
|
// Budgeting, AI input and rule-only retention use this same projection.
|
|
74
79
|
// Keep current-turn reminders; remove only proven runtime additions from
|
|
75
80
|
// older requests. Unmarked legacy text remains part of the summary budget.
|
|
81
|
+
// Older requests also carry their attachments by reference from here on:
|
|
82
|
+
// the file stays on disk under the path the reference names, so the
|
|
83
|
+
// compacted context keeps the pointer instead of the whole document.
|
|
76
84
|
live: conversation
|
|
77
|
-
.map((message, index) =>
|
|
85
|
+
.map((message, index) =>
|
|
86
|
+
index === latestUserIndex ? message : referenceMessageMedia(stripRuntimeUserContext(message))
|
|
87
|
+
)
|
|
78
88
|
.filter((message) => !isSummaryMessage(message)),
|
|
79
89
|
sanitized,
|
|
80
90
|
};
|
|
@@ -95,28 +105,76 @@ function chunkConversationMessage(role, content, source = {}) {
|
|
|
95
105
|
return out;
|
|
96
106
|
}
|
|
97
107
|
|
|
98
|
-
|
|
108
|
+
// What the summary reads of runtime conversation rows and tool calls. The
|
|
109
|
+
// rows stay whole in rule-only Compact; the calls stay in the execution tail
|
|
110
|
+
// and archive.
|
|
111
|
+
const SUMMARY_RUNTIME_ROW_CHARS = 4_000;
|
|
112
|
+
const SUMMARY_TOOL_ARGS_CHARS = 200;
|
|
113
|
+
const SUMMARY_TOOL_OUTCOME_CHARS = 300;
|
|
114
|
+
|
|
115
|
+
function boundedSummaryText(text, limit) {
|
|
116
|
+
return text.length > limit ? `${text.slice(0, limit)}… [${text.length - limit} more chars]` : text;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function toolCallSummaryLine(call, result) {
|
|
120
|
+
const rawArgs = typeof call.arguments === 'string' ? call.arguments : JSON.stringify(call.arguments ?? {});
|
|
121
|
+
const args = boundedSummaryText(rawArgs.replace(/\s+/g, ' '), SUMMARY_TOOL_ARGS_CHARS);
|
|
122
|
+
// Arguments arrive redacted (splitFreshSource); the outcome is redacted
|
|
123
|
+
// here, before any cut can split a secret from its key.
|
|
124
|
+
const outcome = redactRawSecretString(contentText(result?.content)).trim();
|
|
125
|
+
// An ask_user result is the user's own answer: never cut.
|
|
126
|
+
const shown =
|
|
127
|
+
call.name === 'ask_user' ? outcome : boundedSummaryText(outcome.replace(/\s+/g, ' '), SUMMARY_TOOL_OUTCOME_CHARS);
|
|
128
|
+
return `[tool call] ${call.name}(${args}) → ${result ? shown || '(empty result)' : '(no result)'}`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// The conversation Compact measures and summarizes: user and assistant text
|
|
132
|
+
// (the memory-ingest projection) plus runtime conversation rows. `summary`
|
|
133
|
+
// bounds those rows and adds one line per tool call with its outcome.
|
|
134
|
+
function compactionConversationRows(messages, { summary = false } = {}) {
|
|
135
|
+
const list = messages || [];
|
|
136
|
+
const results = new Map(list.filter((m) => m?.role === 'tool').map((m) => [m.toolCallId, m]));
|
|
99
137
|
const out = [];
|
|
100
|
-
for (const message of
|
|
138
|
+
for (const message of list) {
|
|
101
139
|
if (!message || typeof message !== 'object') continue;
|
|
102
|
-
const role = normalizeIngestRole(message.role);
|
|
103
|
-
if (!role || shouldExcludeIngestMessage(message)) continue;
|
|
104
140
|
const content = contentText(message.content).trim();
|
|
105
|
-
if (
|
|
106
|
-
|
|
141
|
+
if (isCompactConversationRow(message)) {
|
|
142
|
+
// A notification can carry a background command's output: the summary
|
|
143
|
+
// reads it redacted like a tool outcome.
|
|
144
|
+
const text = summary ? boundedSummaryText(redactRawSecretString(content), SUMMARY_RUNTIME_ROW_CHARS) : content;
|
|
145
|
+
if (text) out.push(...chunkConversationMessage('user', text, message));
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const role = normalizeIngestRole(message.role);
|
|
149
|
+
if (role && content && !shouldExcludeIngestMessage(message)) {
|
|
150
|
+
out.push(...chunkConversationMessage(role, content, message));
|
|
151
|
+
}
|
|
152
|
+
if (summary && message.role === 'assistant' && message.toolCalls?.length) {
|
|
153
|
+
const lines = message.toolCalls.map((call) => toolCallSummaryLine(call, results.get(call.id)));
|
|
154
|
+
out.push(...chunkConversationMessage('assistant', lines.join('\n'), message));
|
|
155
|
+
}
|
|
107
156
|
}
|
|
108
157
|
return out;
|
|
109
158
|
}
|
|
110
159
|
|
|
111
|
-
|
|
160
|
+
/** The conversation Compact measures against its summary threshold, or with
|
|
161
|
+
* `summary`, the input the summary is written from. */
|
|
162
|
+
export function conversationCompactionInput(messages, { summary = false } = {}) {
|
|
112
163
|
const source = splitFreshSource(messages);
|
|
113
|
-
|
|
164
|
+
// The turn input (the latest actual request and unanswered notifications)
|
|
165
|
+
// is mandatory and must never be replaced by a summary. Skills and runtime
|
|
166
|
+
// injections are excluded by the same conversation projection used by
|
|
167
|
+
// summary generation.
|
|
168
|
+
const turnInput = new Set([
|
|
169
|
+
latestActualUserInstructionIndex(source.live),
|
|
170
|
+
...pendingTaskNotificationIndexes(source.live),
|
|
171
|
+
]);
|
|
114
172
|
return [
|
|
115
173
|
...(source.previousSummaryMessage ? [source.previousSummaryMessage] : []),
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
174
|
+
...compactionConversationRows(
|
|
175
|
+
source.live.filter((_, index) => !turnInput.has(index)),
|
|
176
|
+
{ summary }
|
|
177
|
+
),
|
|
120
178
|
];
|
|
121
179
|
}
|
|
122
180
|
|
|
@@ -135,6 +193,9 @@ function summarySendOpts(opts) {
|
|
|
135
193
|
// Fast mode is opt-in (it needs separate account credits); the summary
|
|
136
194
|
// follows the route/session choice and never enables it on its own.
|
|
137
195
|
fast: opts.fast ?? opts.sendOpts?.fast ?? false,
|
|
196
|
+
// Usage-ledger source for a foreground session's summary call (a
|
|
197
|
+
// background session's own sourceType still wins there).
|
|
198
|
+
requestKind: 'compaction',
|
|
138
199
|
maxOutputTokens: opts.maxOutputTokens || SUMMARY_OUTPUT_TOKENS,
|
|
139
200
|
providerState: undefined,
|
|
140
201
|
onToolCall: undefined,
|
|
@@ -219,7 +280,8 @@ export async function generateFreshHandoffSummary(provider, messages, model, bud
|
|
|
219
280
|
const startedAt = Date.now();
|
|
220
281
|
const budget = effectiveBudget(budgetTokens, opts);
|
|
221
282
|
const source = splitFreshSource(messages);
|
|
222
|
-
let head =
|
|
283
|
+
let head =
|
|
284
|
+
opts.filterOldHistoryForIngest === true ? compactionConversationRows(source.live, { summary: true }) : source.live;
|
|
223
285
|
if (head.length === 0 && !source.previousSummary) {
|
|
224
286
|
throw new Error('generateFreshHandoffSummary: no compactable session history');
|
|
225
287
|
}
|
|
@@ -331,7 +393,12 @@ function prependLatestUserContext(message, prefix) {
|
|
|
331
393
|
if (replacesGoalState) {
|
|
332
394
|
suffix = suffix.replace(/<system-reminder>\s*<goal_state>[\s\S]*?<\/goal_state>\s*<\/system-reminder>\s*/gi, '');
|
|
333
395
|
}
|
|
334
|
-
|
|
396
|
+
// The kept suffix still carries the turn's agent list reminder: it stays told.
|
|
397
|
+
const told = bare !== message && message.meta.agentListing ? { agentListing: message.meta.agentListing } : null;
|
|
398
|
+
return withRuntimeUserContext(told ? { ...bare, meta: { ...bare.meta, ...told } } : bare, {
|
|
399
|
+
prefix: `${text}\n\n`,
|
|
400
|
+
suffix,
|
|
401
|
+
});
|
|
335
402
|
}
|
|
336
403
|
|
|
337
404
|
// The retained execution tail plus the current-turn messages that must
|
|
@@ -350,8 +417,11 @@ function freshContextTail(source, budgetTokens, preserveConversation, opts) {
|
|
|
350
417
|
const retainedTail = execution.messages.map((message, index) =>
|
|
351
418
|
index === latestIndex ? prependLatestUserContext(message, opts.latestUserPrefix) : message
|
|
352
419
|
);
|
|
420
|
+
// The turn's input: the latest real request or an unanswered notification
|
|
421
|
+
// (a bot home thread may hold no human request at all).
|
|
422
|
+
const turnInput = !!latestUser || pendingTaskNotificationIndexes(source.live).length > 0;
|
|
353
423
|
const activeTurnContinuation =
|
|
354
|
-
|
|
424
|
+
turnInput && opts.activeTurn === true ? activeTurnContinuationMessage(source.live) : null;
|
|
355
425
|
// Older compacted sessions may have only synthetic Goal turns left.
|
|
356
426
|
// Preserve the current snapshot without inventing a human instruction
|
|
357
427
|
// to attach it to or resurrecting every historical Goal reminder.
|
|
@@ -366,6 +436,7 @@ function freshContextTail(source, budgetTokens, preserveConversation, opts) {
|
|
|
366
436
|
return {
|
|
367
437
|
execution,
|
|
368
438
|
latestUser,
|
|
439
|
+
turnInput,
|
|
369
440
|
retainedTail,
|
|
370
441
|
activeTurnContinuation,
|
|
371
442
|
volatileTail: [
|
|
@@ -398,20 +469,57 @@ function skillLoaderPair(live, bodyIndex, name, retainedCallIds) {
|
|
|
398
469
|
return [];
|
|
399
470
|
}
|
|
400
471
|
|
|
472
|
+
const SKILL_RELOAD_SOURCE = 'compact-skill-reload';
|
|
473
|
+
|
|
474
|
+
function skillReloadReminder(name) {
|
|
475
|
+
return {
|
|
476
|
+
role: 'user',
|
|
477
|
+
content: `[mixdog-runtime] Skill "${name}" was active, but its instructions did not fit after Compact. Reload it with the Skill tool before relying on them.`,
|
|
478
|
+
meta: { source: SKILL_RELOAD_SOURCE, synthetic: true, skill: name },
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
401
482
|
// Preserve complete, most-recent skill bodies from the durable transcript.
|
|
402
483
|
// Never summarize/truncate operating instructions or displace the handoff
|
|
403
|
-
// and current task. An omitted body
|
|
484
|
+
// and current task. An omitted body leaves a one-line reload reminder, which
|
|
485
|
+
// stands through later Compacts until the skill is loaded again. Reminders
|
|
486
|
+
// are charged to the same budget: every skill's reminder is reserved before
|
|
487
|
+
// any body is restored, and restoring a body releases its own reminder.
|
|
404
488
|
function restoreSkillBodies(live, skillBudget, retainedTail) {
|
|
405
489
|
const retainedCallIds = new Set(retainedTail.filter((m) => m?.role === 'tool').map((m) => m.toolCallId));
|
|
490
|
+
const bodies = latestSkillBodies(live);
|
|
491
|
+
const loaded = new Set(bodies.map((body) => body.name));
|
|
492
|
+
const reload = live
|
|
493
|
+
.filter((m) => m?.meta?.source === SKILL_RELOAD_SOURCE && !loaded.has(m.meta.skill))
|
|
494
|
+
.map((m) => m.meta.skill);
|
|
495
|
+
const reminderCost = (name) => estimateMessagesTokens([skillReloadReminder(name)]);
|
|
496
|
+
let reserved = [...new Set([...reload, ...loaded])].reduce((sum, name) => sum + reminderCost(name), 0);
|
|
497
|
+
const dropped = [];
|
|
406
498
|
const restoredSkills = [];
|
|
407
499
|
let skillTokens = 0;
|
|
408
|
-
for (const { name, message } of
|
|
500
|
+
for (const { name, message } of bodies.reverse()) {
|
|
409
501
|
const restored = [...skillLoaderPair(live, live.lastIndexOf(message), name, retainedCallIds), message];
|
|
410
502
|
const cost = estimateMessagesTokens(restored);
|
|
411
|
-
|
|
503
|
+
const own = reminderCost(name);
|
|
504
|
+
if (skillTokens + cost + reserved - own > skillBudget) {
|
|
505
|
+
dropped.unshift(name);
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
412
508
|
restoredSkills.unshift(...restored);
|
|
413
509
|
skillTokens += cost;
|
|
510
|
+
reserved -= own;
|
|
414
511
|
}
|
|
512
|
+
// Newest skill first; only a budget too small for the reminders themselves
|
|
513
|
+
// leaves one out.
|
|
514
|
+
const pending = [...new Set([...reload, ...dropped])];
|
|
515
|
+
const reminded = new Set();
|
|
516
|
+
for (const name of pending.toReversed()) {
|
|
517
|
+
const cost = reminderCost(name);
|
|
518
|
+
if (skillTokens + cost > skillBudget) continue;
|
|
519
|
+
reminded.add(name);
|
|
520
|
+
skillTokens += cost;
|
|
521
|
+
}
|
|
522
|
+
restoredSkills.push(...pending.filter((name) => reminded.has(name)).map(skillReloadReminder));
|
|
415
523
|
return { restoredSkills, skillTokens };
|
|
416
524
|
}
|
|
417
525
|
|
|
@@ -538,7 +646,7 @@ function freshContextLayout(source, budgetTokens, opts) {
|
|
|
538
646
|
? fitFreshContextSummaryMessage(source.live, handoffText, Number.MAX_SAFE_INTEGER)
|
|
539
647
|
: source.previousSummaryMessage;
|
|
540
648
|
const tail = freshContextTail(source, budgetTokens, !replaceConversation, opts);
|
|
541
|
-
const stableAck = tail.
|
|
649
|
+
const stableAck = tail.turnInput && summaryMessage ? stableAckMessage(source.previousAck, tail.volatileTail) : null;
|
|
542
650
|
const stableHead = [
|
|
543
651
|
...source.protectedPrefix,
|
|
544
652
|
...(summaryMessage ? [summaryMessage] : []),
|
|
@@ -548,15 +656,43 @@ function freshContextLayout(source, budgetTokens, opts) {
|
|
|
548
656
|
return { handoffText, summaryMessage, tail, stableHead, mandatory, mandatoryCost: estimateMessagesTokens(mandatory) };
|
|
549
657
|
}
|
|
550
658
|
|
|
551
|
-
function
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
659
|
+
function mandatoryOverflows(budget, mandatoryCost, summaryMessage) {
|
|
660
|
+
return mandatoryCost > budget || (summaryMessage && mandatoryCost === budget);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export const LATEST_TURN_EXCEEDS_CONTEXT = 'LATEST_TURN_EXCEEDS_CONTEXT';
|
|
664
|
+
|
|
665
|
+
// Says what does not fit and what would make it fit. A larger window is only
|
|
666
|
+
// offered when one would actually hold the required size.
|
|
667
|
+
function assertMandatoryFits(budget, mandatoryCost, summaryMessage, contextWindow, latestUser) {
|
|
668
|
+
if (!mandatoryOverflows(budget, mandatoryCost, summaryMessage)) return;
|
|
669
|
+
// Fixed sentences with the sizes inline: the desktop re-speaks each one
|
|
670
|
+
// through its catalog (error-notice-copy / transcript-failure-text).
|
|
671
|
+
const count = (value) => Number(value).toLocaleString('en-US');
|
|
672
|
+
const window = Number(contextWindow) > 0 ? `${count(contextWindow)}-token` : 'current';
|
|
673
|
+
const attachments = messageAttachmentTokens(latestUser);
|
|
674
|
+
const cause =
|
|
675
|
+
attachments > 0
|
|
676
|
+
? `Its attachments alone are about ${count(attachments)} tokens.`
|
|
677
|
+
: 'The latest message and protected session context (system rules, tool definitions) are that large.';
|
|
678
|
+
const error = new Error(
|
|
679
|
+
`The latest message cannot fit this model (${LATEST_TURN_EXCEEDS_CONTEXT}): it needs about ` +
|
|
680
|
+
`${count(mandatoryCost)} tokens, but the ${window} window leaves ${count(budget)} for it. ${cause} ` +
|
|
681
|
+
'Shorten the message or move large pasted text into a file the model can read. ' +
|
|
682
|
+
`A larger context window helps only if it holds ${count(mandatoryCost)} tokens plus room for the answer.`
|
|
683
|
+
);
|
|
684
|
+
error.code = LATEST_TURN_EXCEEDS_CONTEXT;
|
|
685
|
+
throw error;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// The source with the latest request's attachments sent by reference. Same
|
|
689
|
+
// source when it carries none.
|
|
690
|
+
function withLatestAttachmentsReferenced(source) {
|
|
691
|
+
const latest = latestActualUserInstructionIndex(source.live);
|
|
692
|
+
if (latest < 0 || !messageHasReferencableMedia(source.live[latest])) return source;
|
|
693
|
+
const live = source.live.slice();
|
|
694
|
+
live[latest] = referenceMessageMedia(live[latest]);
|
|
695
|
+
return { ...source, live };
|
|
560
696
|
}
|
|
561
697
|
|
|
562
698
|
function assertHandoffFits(summaryMessage, room) {
|
|
@@ -584,14 +720,26 @@ export function freshContextCompactMessages(messages, budgetTokens, opts = {}) {
|
|
|
584
720
|
});
|
|
585
721
|
}
|
|
586
722
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
)
|
|
593
|
-
|
|
594
|
-
|
|
723
|
+
let source = splitFreshSource(baseSanitized);
|
|
724
|
+
let layout = freshContextLayout(source, budgetTokens, opts);
|
|
725
|
+
let budget = freshContextBudget({ targetBudget, budgetTokens, ...layout, opts });
|
|
726
|
+
// The latest request is mandatory and kept verbatim — except its
|
|
727
|
+
// attachments: when they are what does not fit (or the provider already
|
|
728
|
+
// refused this request as too long), they travel by reference instead of
|
|
729
|
+
// failing the turn, and every later turn, forever.
|
|
730
|
+
if (
|
|
731
|
+
opts.referenceLatestAttachments === true ||
|
|
732
|
+
mandatoryOverflows(budget, layout.mandatoryCost, layout.summaryMessage)
|
|
733
|
+
) {
|
|
734
|
+
const referenced = withLatestAttachmentsReferenced(source);
|
|
735
|
+
if (referenced !== source) {
|
|
736
|
+
source = referenced;
|
|
737
|
+
layout = freshContextLayout(source, budgetTokens, opts);
|
|
738
|
+
budget = freshContextBudget({ targetBudget, budgetTokens, ...layout, opts });
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const { handoffText, summaryMessage, tail, stableHead, mandatory, mandatoryCost } = layout;
|
|
742
|
+
assertMandatoryFits(budget, mandatoryCost, summaryMessage, opts.contextWindow, tail.latestUser);
|
|
595
743
|
const handoff = handoffRoomFor(budget, mandatoryCost, opts);
|
|
596
744
|
const summaryContent = String(summaryMessage?.content || '');
|
|
597
745
|
assertHandoffFits(summaryMessage, handoff.room);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// compaction.summaryMode — which model writes a compaction summary
|
|
2
|
+
// (loop/fresh-context.mjs compactionSummaryPlan):
|
|
3
|
+
// smart warm prompt cache: fork the conversation's own cached request;
|
|
4
|
+
// cold: the Maintainer, else the subscription provider's lighter
|
|
5
|
+
// model, else the conversation's own model (isolated)
|
|
6
|
+
// maintainer the Maintainer (isolated), else the conversation's own model
|
|
7
|
+
// self the conversation's own model: fork when warm, isolated when cold
|
|
8
|
+
export const COMPACTION_SUMMARY_MODES = Object.freeze(['smart', 'maintainer', 'self']);
|
|
9
|
+
|
|
10
|
+
/** The saved mode; the previous release's boolean `useMaintainer:false`
|
|
11
|
+
* reads as 'self', true or absent as the 'smart' default. */
|
|
12
|
+
export function normalizeCompactionSummaryMode(compaction) {
|
|
13
|
+
const mode = compaction?.summaryMode;
|
|
14
|
+
if (COMPACTION_SUMMARY_MODES.includes(mode)) return mode;
|
|
15
|
+
return compaction?.useMaintainer === false ? 'self' : 'smart';
|
|
16
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// What the compaction summary route choice reads: whether the session's
|
|
2
|
+
// prompt cache is still warm (a fork of its last request would read it), and
|
|
3
|
+
// the lighter model of a subscription provider.
|
|
4
|
+
import { cacheCapabilityForProvider, providerTailCacheLifetimeMs } from '../../agent-runtime/cache-strategy.mjs';
|
|
5
|
+
import { getModelMetadataSync } from '../../../../shared/llm/model-catalog.mjs';
|
|
6
|
+
import {
|
|
7
|
+
_compareVersion as compareAnthropicVersion,
|
|
8
|
+
_loadModelCache as loadAnthropicCatalogCache,
|
|
9
|
+
} from '../../providers/anthropic-model-resolve.mjs';
|
|
10
|
+
import { gptVersion } from '../../providers/openai-model-capabilities.mjs';
|
|
11
|
+
import { loadSavedCodexCatalog } from '../../providers/openai-oauth-catalog-store.mjs';
|
|
12
|
+
import { compactionForkRequest } from '../side-question-store.mjs';
|
|
13
|
+
|
|
14
|
+
// A provider outside the Anthropic/OpenAI lifetimes whose catalog marks prompt
|
|
15
|
+
// caching: the shortest common cache lifetime (Gemini's default TTL).
|
|
16
|
+
const CATALOG_PROMPT_CACHE_LIFETIME_MS = 5 * 60_000;
|
|
17
|
+
// The cache is read when the fork is sent, after the route choice: a request
|
|
18
|
+
// this close to its lifetime counts as cold.
|
|
19
|
+
const WARM_MARGIN_MIN_MS = 30_000;
|
|
20
|
+
const WARM_MARGIN_RATIO = 0.1;
|
|
21
|
+
|
|
22
|
+
/** How long the cache a saved request wrote or read stays readable, in ms:
|
|
23
|
+
* Infinity when it does not expire (openai-oauth), 0 when it is not cached.
|
|
24
|
+
* Anthropic: the request's message-tail tier (5m / 1h); OpenAI: the 30m tail
|
|
25
|
+
* that holds the conversation (the Lead's 12h breakpoint covers only the
|
|
26
|
+
* stable tools/instructions prefix). */
|
|
27
|
+
function requestCacheLifetimeMs(request) {
|
|
28
|
+
const name = request?.provider?.name;
|
|
29
|
+
if (name === 'openai-oauth') return Infinity;
|
|
30
|
+
if (name === 'openai' || cacheCapabilityForProvider(name) === 'explicit-breakpoint') {
|
|
31
|
+
return providerTailCacheLifetimeMs(name, request.opts?.cacheStrategy) ?? 0;
|
|
32
|
+
}
|
|
33
|
+
const info = request.provider.getCachedModelInfo?.(request.model) || getModelMetadataSync(request.model, name);
|
|
34
|
+
return info?.supportsPromptCaching ? CATALOG_PROMPT_CACHE_LIFETIME_MS : 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Whether the session's last settled request is still inside the cache
|
|
38
|
+
* lifetime it used, with a safety margin. No forkable request = cold. */
|
|
39
|
+
export function compactionCacheWarm(sessionId, now = Date.now()) {
|
|
40
|
+
const request = compactionForkRequest(sessionId);
|
|
41
|
+
if (!request) return false;
|
|
42
|
+
const lifetime = requestCacheLifetimeMs(request);
|
|
43
|
+
if (lifetime === Infinity) return true;
|
|
44
|
+
const margin = Math.max(WARM_MARGIN_MIN_MS, lifetime * WARM_MARGIN_RATIO);
|
|
45
|
+
return now - Number(request.sentAt) < lifetime - margin;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function compareGptVersion(a, b) {
|
|
49
|
+
const [aMajor, aMinor] = gptVersion(a);
|
|
50
|
+
const [bMajor, bMinor] = gptVersion(b);
|
|
51
|
+
// Same version: the undated alias over a dated snapshot.
|
|
52
|
+
return aMajor - bMajor || aMinor - bMinor || b.length - a.length;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The lighter family per subscription provider: its newest catalog model.
|
|
56
|
+
// API-key providers bill per token and get no lighter step. `catalog` reads
|
|
57
|
+
// the provider's saved catalog only (disk cache, no auth or network on the
|
|
58
|
+
// compaction path): Anthropic's within its 24h TTL, Codex's stale or not.
|
|
59
|
+
const LIGHTER_FAMILY = Object.freeze({
|
|
60
|
+
'anthropic-oauth': {
|
|
61
|
+
catalog: loadAnthropicCatalogCache,
|
|
62
|
+
matches: (row) => row.family === 'haiku',
|
|
63
|
+
compare: compareAnthropicVersion,
|
|
64
|
+
},
|
|
65
|
+
'openai-oauth': {
|
|
66
|
+
catalog: loadSavedCodexCatalog,
|
|
67
|
+
matches: (row, id) => id.includes('-luna') && gptVersion(id) !== null,
|
|
68
|
+
compare: compareGptVersion,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/** The newest lighter-family model the saved catalog of `providerName` lists
|
|
73
|
+
* for this account, or null (not a subscription provider, no saved catalog,
|
|
74
|
+
* none listed). */
|
|
75
|
+
export async function lighterSubscriptionModel(providerName) {
|
|
76
|
+
const family = LIGHTER_FAMILY[providerName];
|
|
77
|
+
if (!family) return null;
|
|
78
|
+
const catalog = await family.catalog();
|
|
79
|
+
if (!Array.isArray(catalog)) return null;
|
|
80
|
+
let best = null;
|
|
81
|
+
for (const row of catalog) {
|
|
82
|
+
const id = String(row?.id || '');
|
|
83
|
+
if (!id || !family.matches(row, id)) continue;
|
|
84
|
+
if (!best || family.compare(id, best) > 0) best = id;
|
|
85
|
+
}
|
|
86
|
+
return best;
|
|
87
|
+
}
|
|
@@ -59,6 +59,8 @@ Rules:
|
|
|
59
59
|
- Use terse bullets, not prose paragraphs.
|
|
60
60
|
- Preserve exact file paths, commands, error strings, and identifiers when known.
|
|
61
61
|
- Use the same language as the active user thread when it is clear.
|
|
62
|
+
- Record work as Done or In Progress only when a tool call and its result in the history show it (an agent spawn/send result, an edit, a command outcome). An assistant's stated intent with no matching tool call is not started: list it under Next Steps as "announced, not started".
|
|
63
|
+
- Attribute every decision, answer, and version/choice to its source: the user (message or ask_user answer), a named agent's report, or the assistant. Never credit an agent or the assistant with a user's answer.
|
|
62
64
|
- Do not mention the summary process or that context was compacted.`;
|
|
63
65
|
|
|
64
66
|
// The final user turn of a summary forked from the session's own cached
|