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
|
@@ -509,6 +509,25 @@ export function providerInputExcludesCache(name) {
|
|
|
509
509
|
export function providerNativePdf(name) {
|
|
510
510
|
return providerTakesNativePdf(providers.get(String(name || '').toLowerCase()));
|
|
511
511
|
}
|
|
512
|
+
/**
|
|
513
|
+
* Whether the named provider sends image input to its models: false only for
|
|
514
|
+
* an adapter that declares `takesImages = false` (the text-only local
|
|
515
|
+
* runtime, which lowers every image to a placeholder). A pure lookup; an
|
|
516
|
+
* unknown provider is treated as taking images, as attachments are.
|
|
517
|
+
*/
|
|
518
|
+
export function providerReadsImages(name) {
|
|
519
|
+
return providers.get(String(name || '').toLowerCase())?.takesImages !== false;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* The user's image-input override for one model of a custom provider: true or
|
|
523
|
+
* false as set, undefined when unset (auto) or the provider is not a loaded
|
|
524
|
+
* custom one. A pure lookup; it never instantiates a provider.
|
|
525
|
+
*/
|
|
526
|
+
export function providerModelVisionOverride(name, model) {
|
|
527
|
+
const overrides = providers.get(String(name || '').toLowerCase())?.customConfig?.modelOverrides;
|
|
528
|
+
const value = overrides && Object.hasOwn(overrides, model) ? overrides[model]?.supportsVision : undefined;
|
|
529
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
530
|
+
}
|
|
512
531
|
/**
|
|
513
532
|
* Whether the named provider's adapter declares `consumesReadWindows`: it
|
|
514
533
|
* needs the structured clip report of read results. A pure lookup; a proxy
|
|
@@ -9,7 +9,7 @@ import { OpenAICompatProvider, OPENAI_COMPAT_PRESETS } from './openai-compat.mjs
|
|
|
9
9
|
import { originBoundFetch } from './lib/origin-bound-fetch.mjs';
|
|
10
10
|
import { withInclusiveUsage } from './lib/inclusive-usage.mjs';
|
|
11
11
|
import { getModelMetadataSync } from './model-catalog.mjs';
|
|
12
|
-
import { resolveWireRoute, sendOnRoute } from './wire-route.mjs';
|
|
12
|
+
import { resolveWireRoute, sendOnRoute, sendWireRoute } from './wire-route.mjs';
|
|
13
13
|
|
|
14
14
|
// A Files API file-ID image anywhere in the history (tool results nest content).
|
|
15
15
|
function hasFileIdImage(value, depth = 0) {
|
|
@@ -66,6 +66,10 @@ export class GatewayMessagesEngine extends AnthropicProvider {
|
|
|
66
66
|
_sendOnce(messages, model, tools, opts) {
|
|
67
67
|
return super._sendOnce(messages, model, tools, gatewayMessagesOpts(this.config, model, messages, opts));
|
|
68
68
|
}
|
|
69
|
+
// Same ceiling a send resolves, so a retry never asks above the gateway's limit.
|
|
70
|
+
escalatedMaxTokens(model, opts) {
|
|
71
|
+
return super.escalatedMaxTokens(model, gatewayMessagesOpts(this.config, model, [], opts));
|
|
72
|
+
}
|
|
69
73
|
_createClient(apiKey) {
|
|
70
74
|
const client = super._createClient(apiKey);
|
|
71
75
|
if (this.config.authScheme === 'bearer') {
|
|
@@ -138,6 +142,14 @@ export class WireGatewayProvider {
|
|
|
138
142
|
});
|
|
139
143
|
}
|
|
140
144
|
|
|
145
|
+
// A higher one-shot max_tokens exists only on the Messages wire; the
|
|
146
|
+
// route is the same one the send itself resolves. Other wires: null.
|
|
147
|
+
async escalatedMaxTokens(model, opts, tools) {
|
|
148
|
+
const useModel = model || this.openai.defaultModel;
|
|
149
|
+
const route = await sendWireRoute(this, useModel, tools, opts);
|
|
150
|
+
return route?.wire === 'messages' ? this.anthropic.escalatedMaxTokens(useModel, opts) : null;
|
|
151
|
+
}
|
|
152
|
+
|
|
141
153
|
reloadApiKey() {
|
|
142
154
|
this.openai.reloadApiKey();
|
|
143
155
|
this.anthropic.reloadApiKey();
|
|
@@ -4,6 +4,7 @@ import { clean, hasOwn } from './session-text.mjs';
|
|
|
4
4
|
import { normalizeEffortInput, normalizeSavedEffort } from './effort.mjs';
|
|
5
5
|
import { routeFastKey, fastPreferenceFor } from './model-capabilities.mjs';
|
|
6
6
|
import { normalizeContextTokens } from '../../../shared/llm/default-context-window.mjs';
|
|
7
|
+
import { normalizeCompactionSummaryMode } from '../session/compact/summary-mode.mjs';
|
|
7
8
|
|
|
8
9
|
const DEFAULT_PROVIDER = 'anthropic-oauth';
|
|
9
10
|
export const DEFAULT_MODEL = '';
|
|
@@ -191,12 +192,23 @@ const AUTO_CLEAR_DEFAULT_IDLE_MS = 60 * 60 * 1000;
|
|
|
191
192
|
// reusable. Gemini, xAI and Mistral
|
|
192
193
|
// caches run ~1h, Groq's implicit cache persists ~2h, and DeepSeek's
|
|
193
194
|
// implicit cache is evicted after "a few hours to a few days" (kept at 24h).
|
|
194
|
-
// OpenAI (
|
|
195
|
-
//
|
|
196
|
-
// matches
|
|
197
|
-
//
|
|
198
|
-
//
|
|
195
|
+
// OpenAI public API (GPT-5.6+ Responses, cache-strategy.mjs): the moving tail
|
|
196
|
+
// is written with ttl "30m" and only the Lead-class stable prefix with "12h",
|
|
197
|
+
// so the sweep matches the 30m tail — a clear after that costs nothing extra
|
|
198
|
+
// (the tail is cold anyway) and the cleared session restarts on the warm 12h
|
|
199
|
+
// prefix. Earlier OpenAI models (prompt_cache_retention, typically ~30 min)
|
|
200
|
+
// are not distinguished: these call sites only know the provider.
|
|
201
|
+
// OpenAI OAuth (Codex/ChatGPT login) keeps the cache of logged-in users
|
|
202
|
+
// indefinitely (2026-10-20), so its built-in window is unlimited: no idle
|
|
203
|
+
// clear; compaction happens only at the context limit or on request.
|
|
199
204
|
// Unknown/unrecognized providers fall back to the 'default' 1h entry.
|
|
205
|
+
//
|
|
206
|
+
// Unlimited ("never auto-clear") is stored as 0 in providerIdleMs — a value
|
|
207
|
+
// older builds dropped, so no older config carries it — and resolves to
|
|
208
|
+
// AUTO_CLEAR_UNLIMITED_MS, which every idle comparison treats as never
|
|
209
|
+
// reached. Input also accepts 'unlimited' / 'never'.
|
|
210
|
+
export const AUTO_CLEAR_UNLIMITED = 0;
|
|
211
|
+
export const AUTO_CLEAR_UNLIMITED_MS = Number.MAX_SAFE_INTEGER;
|
|
200
212
|
const AUTO_CLEAR_PROVIDER_IDLE_MS = Object.freeze({
|
|
201
213
|
anthropic: 60 * 60 * 1000,
|
|
202
214
|
'anthropic-oauth': 60 * 60 * 1000,
|
|
@@ -205,20 +217,48 @@ const AUTO_CLEAR_PROVIDER_IDLE_MS = Object.freeze({
|
|
|
205
217
|
openai: 30 * 60 * 1000,
|
|
206
218
|
deepseek: 24 * 60 * 60 * 1000,
|
|
207
219
|
xai: 60 * 60 * 1000,
|
|
208
|
-
'openai-oauth':
|
|
220
|
+
'openai-oauth': AUTO_CLEAR_UNLIMITED,
|
|
209
221
|
mistral: 60 * 60 * 1000,
|
|
210
222
|
default: AUTO_CLEAR_DEFAULT_IDLE_MS,
|
|
211
223
|
});
|
|
212
224
|
const AUTO_CLEAR_PROVIDER_IDS = Object.freeze(Object.keys(AUTO_CLEAR_PROVIDER_IDLE_MS));
|
|
213
225
|
|
|
226
|
+
// Completed-agent retention where it must differ from the idle window. Reap
|
|
227
|
+
// frees in-memory sessions and worker-index rows (resources), so it stays
|
|
228
|
+
// finite even where the cache is permanent: openai-oauth uses the 1h product
|
|
229
|
+
// default, which covers Lead follow-ups (24/25 Lead waits were 5–27 min).
|
|
230
|
+
const AGENT_TERMINAL_REAP_MS = Object.freeze({ 'openai-oauth': 60 * 60 * 1000 });
|
|
231
|
+
|
|
232
|
+
/** A stored/requested idle value: AUTO_CLEAR_UNLIMITED, a window ≥ 1 min, or
|
|
233
|
+
* null when absent or invalid. */
|
|
234
|
+
export function normalizeAutoClearIdleValue(value) {
|
|
235
|
+
if (value === null || value === undefined || typeof value === 'boolean') return null;
|
|
236
|
+
if (typeof value === 'string') {
|
|
237
|
+
const text = value.trim().toLowerCase();
|
|
238
|
+
if (!text) return null;
|
|
239
|
+
if (text === 'unlimited' || text === 'never') return AUTO_CLEAR_UNLIMITED;
|
|
240
|
+
}
|
|
241
|
+
const idleMs = Number(value);
|
|
242
|
+
if (!Number.isFinite(idleMs) || idleMs < 0) return null;
|
|
243
|
+
if (idleMs === 0) return AUTO_CLEAR_UNLIMITED;
|
|
244
|
+
return Math.max(60_000, Math.round(idleMs));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const resolvedIdleMs = (stored) => (stored === AUTO_CLEAR_UNLIMITED ? AUTO_CLEAR_UNLIMITED_MS : stored);
|
|
248
|
+
|
|
249
|
+
/** Whether a resolved idle window means "never auto-clear". */
|
|
250
|
+
export function isAutoClearUnlimited(idleMs) {
|
|
251
|
+
return Number(idleMs) >= AUTO_CLEAR_UNLIMITED_MS;
|
|
252
|
+
}
|
|
253
|
+
|
|
214
254
|
function normalizeAutoClearProviderIdleMs(value = {}) {
|
|
215
255
|
const raw = value && typeof value === 'object' ? value : {};
|
|
216
256
|
const out = {};
|
|
217
257
|
for (const [key, ms] of Object.entries(raw)) {
|
|
218
258
|
const provider = clean(key).toLowerCase();
|
|
219
|
-
const idleMs =
|
|
220
|
-
if (!provider ||
|
|
221
|
-
out[provider] =
|
|
259
|
+
const idleMs = normalizeAutoClearIdleValue(ms);
|
|
260
|
+
if (!provider || idleMs === null) continue;
|
|
261
|
+
out[provider] = idleMs;
|
|
222
262
|
}
|
|
223
263
|
return out;
|
|
224
264
|
}
|
|
@@ -228,49 +268,71 @@ function normalizeAutoClearProviderIdleMs(value = {}) {
|
|
|
228
268
|
export function autoClearIdleMsForProvider(provider, providerIdleMs = null) {
|
|
229
269
|
const overrides = normalizeAutoClearProviderIdleMs(providerIdleMs);
|
|
230
270
|
const key = clean(provider).toLowerCase();
|
|
231
|
-
if (overrides
|
|
232
|
-
if (key && AUTO_CLEAR_PROVIDER_IDLE_MS
|
|
233
|
-
if (overrides
|
|
271
|
+
if (key && Object.hasOwn(overrides, key)) return resolvedIdleMs(overrides[key]);
|
|
272
|
+
if (key && Object.hasOwn(AUTO_CLEAR_PROVIDER_IDLE_MS, key)) return resolvedIdleMs(AUTO_CLEAR_PROVIDER_IDLE_MS[key]);
|
|
273
|
+
if (Object.hasOwn(overrides, 'default')) return resolvedIdleMs(overrides.default);
|
|
234
274
|
return AUTO_CLEAR_PROVIDER_IDLE_MS.default;
|
|
235
275
|
}
|
|
236
276
|
|
|
237
|
-
|
|
277
|
+
// One row per built-in provider plus every provider in `extraProviders` (the
|
|
278
|
+
// providers the user has enabled or routes to), before the 'default' row.
|
|
279
|
+
// A provider without a built-in entry resolves like any unknown provider.
|
|
280
|
+
export function autoClearProviderDefaults(providerIdleMs = null, extraProviders = []) {
|
|
238
281
|
const overrides = normalizeAutoClearProviderIdleMs(providerIdleMs);
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const
|
|
282
|
+
const ids = AUTO_CLEAR_PROVIDER_IDS.filter((id) => id !== 'default');
|
|
283
|
+
for (const value of extraProviders || []) {
|
|
284
|
+
const id = clean(value).toLowerCase();
|
|
285
|
+
if (id && !ids.includes(id) && id !== 'default') ids.push(id);
|
|
286
|
+
}
|
|
287
|
+
for (const id of Object.keys(overrides)) if (!ids.includes(id) && id !== 'default') ids.push(id);
|
|
288
|
+
ids.push('default');
|
|
289
|
+
return ids.map((provider) => {
|
|
290
|
+
const builtIn = Object.hasOwn(AUTO_CLEAR_PROVIDER_IDLE_MS, provider)
|
|
291
|
+
? AUTO_CLEAR_PROVIDER_IDLE_MS[provider]
|
|
292
|
+
: AUTO_CLEAR_PROVIDER_IDLE_MS.default;
|
|
293
|
+
const idleMs = Object.hasOwn(overrides, provider)
|
|
294
|
+
? resolvedIdleMs(overrides[provider])
|
|
295
|
+
: provider === 'default' || Object.hasOwn(AUTO_CLEAR_PROVIDER_IDLE_MS, provider)
|
|
296
|
+
? resolvedIdleMs(builtIn)
|
|
297
|
+
: autoClearIdleMsForProvider(provider, overrides);
|
|
242
298
|
return {
|
|
243
299
|
provider,
|
|
244
300
|
idleMs,
|
|
245
|
-
builtInMs,
|
|
246
|
-
|
|
301
|
+
builtInMs: resolvedIdleMs(builtIn),
|
|
302
|
+
unlimited: isAutoClearUnlimited(idleMs),
|
|
303
|
+
builtInUnlimited: builtIn === AUTO_CLEAR_UNLIMITED,
|
|
304
|
+
custom: Object.hasOwn(overrides, provider),
|
|
247
305
|
};
|
|
248
306
|
});
|
|
249
307
|
}
|
|
250
308
|
|
|
251
309
|
// Agent terminal retention is deliberately narrower than Auto Clear's general
|
|
252
|
-
// resolution: listed providers use their provider cache lifetime
|
|
310
|
+
// resolution: listed providers use their provider cache lifetime, or the
|
|
311
|
+
// finite AGENT_TERMINAL_REAP_MS entry where that cache is permanent. Unlisted
|
|
253
312
|
// providers use the Advanced "default" row, or the built-in default when no
|
|
254
|
-
// override is configured, so completed agents are still eventually reclaimed
|
|
313
|
+
// override is configured, so completed agents are still eventually reclaimed;
|
|
314
|
+
// an unlimited override never disables reaping.
|
|
255
315
|
export function resolveAgentTerminalReapMs(config, provider) {
|
|
256
316
|
const key = clean(provider).toLowerCase();
|
|
257
317
|
const raw = config?.autoClear && typeof config.autoClear === 'object' ? config.autoClear : {};
|
|
258
318
|
const overrides = normalizeAutoClearProviderIdleMs(raw.providerIdleMs);
|
|
319
|
+
const finite = (value) => (value > 0 ? value : null);
|
|
259
320
|
if (!key || key === 'default' || !Object.hasOwn(AUTO_CLEAR_PROVIDER_IDLE_MS, key)) {
|
|
260
|
-
return overrides.default ?? AUTO_CLEAR_PROVIDER_IDLE_MS.default;
|
|
321
|
+
return finite(overrides.default) ?? AUTO_CLEAR_PROVIDER_IDLE_MS.default;
|
|
261
322
|
}
|
|
262
|
-
return overrides[key] ?? AUTO_CLEAR_PROVIDER_IDLE_MS[key];
|
|
323
|
+
return finite(overrides[key]) ?? AGENT_TERMINAL_REAP_MS[key] ?? AUTO_CLEAR_PROVIDER_IDLE_MS[key];
|
|
263
324
|
}
|
|
264
325
|
|
|
265
326
|
// Resolve the effective auto-clear idle window for a config + provider:
|
|
266
327
|
// a provider-specific override (autoClear.providerIdleMs[provider]) wins;
|
|
267
328
|
// else the global user-set idleMs (autoClear.idleMs); else the provider's
|
|
268
329
|
// built-in window, then providerIdleMs.default / the built-in 1h default.
|
|
330
|
+
// Unlimited resolves to AUTO_CLEAR_UNLIMITED_MS.
|
|
269
331
|
export function resolveAutoClearIdleMs(config, provider) {
|
|
270
332
|
const raw = config?.autoClear && typeof config.autoClear === 'object' ? config.autoClear : {};
|
|
271
333
|
const key = clean(provider).toLowerCase();
|
|
272
|
-
const
|
|
273
|
-
if (
|
|
334
|
+
const overrides = normalizeAutoClearProviderIdleMs(raw.providerIdleMs);
|
|
335
|
+
if (key && key !== 'default' && Object.hasOwn(overrides, key)) return resolvedIdleMs(overrides[key]);
|
|
274
336
|
const idleMs = Number(raw.idleMs);
|
|
275
337
|
if (Number.isFinite(idleMs) && idleMs > 0) return Math.max(60_000, Math.round(idleMs));
|
|
276
338
|
return autoClearIdleMsForProvider(provider, raw.providerIdleMs);
|
|
@@ -350,12 +412,16 @@ export function normalizeCompactionConfig(value = {}) {
|
|
|
350
412
|
delete next.recallConcurrency;
|
|
351
413
|
delete next.recallCycle1DeadlineMs;
|
|
352
414
|
delete next.enabled;
|
|
415
|
+
delete next.useMaintainer;
|
|
353
416
|
return {
|
|
354
417
|
...next,
|
|
355
418
|
auto: raw.auto !== false && raw.enabled !== false,
|
|
356
419
|
// Compact a conversation on its current model before switching it to
|
|
357
420
|
// another one in place (default on).
|
|
358
421
|
onModelChange: raw.onModelChange !== false,
|
|
422
|
+
// Which model writes compaction summaries (smart / maintainer / self);
|
|
423
|
+
// replaces the previous release's boolean useMaintainer.
|
|
424
|
+
summaryMode: normalizeCompactionSummaryMode(raw),
|
|
359
425
|
};
|
|
360
426
|
}
|
|
361
427
|
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
// Small filesystem read helpers used by session-runtime submodules.
|
|
2
2
|
import { readdirSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { holdsNoData } from '../../../shared/atomic-file.mjs';
|
|
3
4
|
|
|
4
5
|
export { readJsonSafe } from '../../../shared/json-file.mjs';
|
|
5
6
|
|
|
7
|
+
// The default data dir of a loader factory: a path, or a resolver read per
|
|
8
|
+
// call so a later runtime start's data dir is honored.
|
|
9
|
+
export const defaultDirResolver = (dataDir) => (typeof dataDir === 'function' ? dataDir : () => dataDir);
|
|
10
|
+
|
|
6
11
|
export function readTextSafe(path) {
|
|
7
12
|
try {
|
|
8
|
-
|
|
13
|
+
const text = readFileSync(path, 'utf8');
|
|
14
|
+
// A crash can leave NUL bytes (String.trim keeps them): no data is no text.
|
|
15
|
+
return holdsNoData(text) ? '' : text.trim();
|
|
9
16
|
} catch {
|
|
10
17
|
return '';
|
|
11
18
|
}
|
|
@@ -133,7 +133,7 @@ export function createGoalMutations(ctx) {
|
|
|
133
133
|
await write(
|
|
134
134
|
join(root, 'history', id, `${assertSessionId(goal.id)}.json`),
|
|
135
135
|
{ version: GOAL_FILE_VERSION, goal },
|
|
136
|
-
{ lock: true, secret: true,
|
|
136
|
+
{ lock: true, secret: true, timeoutMs: 2_000 }
|
|
137
137
|
);
|
|
138
138
|
};
|
|
139
139
|
|
|
@@ -65,6 +65,10 @@ export function createGoalRuntime({
|
|
|
65
65
|
// context still owes, from the rules and state already delivered into it.
|
|
66
66
|
// In memory on purpose: a restart is a fresh context that needs them again.
|
|
67
67
|
continuationTiers: new Map(),
|
|
68
|
+
// Session -> Goal id whose turn ended in a stop (failed, cancelled, usage
|
|
69
|
+
// limit) the record could not save. The record still reads active, so
|
|
70
|
+
// without this a full disk would start turn after turn into the same error.
|
|
71
|
+
unsavedStops: new Map(),
|
|
68
72
|
closed: false,
|
|
69
73
|
};
|
|
70
74
|
Object.assign(ctx, createGoalStore(ctx));
|
|
@@ -116,6 +120,7 @@ export function createGoalRuntime({
|
|
|
116
120
|
ctx.observedGoals.clear();
|
|
117
121
|
ctx.idleReviewTurns.clear();
|
|
118
122
|
ctx.continuationTiers.clear();
|
|
123
|
+
ctx.unsavedStops.clear();
|
|
119
124
|
listeners.clear();
|
|
120
125
|
// Accepted writes keep their ordering until they settle. Callers may
|
|
121
126
|
// await this barrier before releasing the session's backing resources.
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readdirSync, rmSync, statSync } from 'node:fs';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
2
3
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
parseJsonText,
|
|
6
|
+
readJsonStateSync,
|
|
7
|
+
unsupportedState,
|
|
8
|
+
withFileLock,
|
|
9
|
+
writeJsonAtomicAsync,
|
|
10
|
+
} from '../../../shared/atomic-file.mjs';
|
|
4
11
|
import { clean } from '../../../shared/clean.mjs';
|
|
5
12
|
import {
|
|
6
13
|
DEFAULT_COMPLETED_GOAL_TTL_MS,
|
|
@@ -87,31 +94,58 @@ export function reportGoalStorageError(error) {
|
|
|
87
94
|
process.emitWarning(error?.message || String(error), { code: 'GOAL_STORAGE_ERROR' });
|
|
88
95
|
}
|
|
89
96
|
|
|
97
|
+
// A damaged record (empty, NUL, torn, invalid) never blocks the Goal
|
|
98
|
+
// feature: readJsonStateSync keeps its bytes aside as `<file>.corrupt-<ts>`,
|
|
99
|
+
// restores the last good `.bak` when there is one, else the session has no
|
|
100
|
+
// Goal. A record from a newer build is left in place and reads as no Goal.
|
|
101
|
+
// Real I/O errors still throw.
|
|
90
102
|
function readGoalRecordFile(path, sessionId, normalizeGoal, at) {
|
|
103
|
+
const record = readJsonStateSync(path, {
|
|
104
|
+
secret: true,
|
|
105
|
+
fallback: null,
|
|
106
|
+
validate(parsed) {
|
|
107
|
+
if (Number.isSafeInteger(parsed?.version) && parsed.version > GOAL_FILE_VERSION) {
|
|
108
|
+
throw unsupportedState(`Goal record version ${parsed.version} is newer than this build`);
|
|
109
|
+
}
|
|
110
|
+
if (
|
|
111
|
+
!parsed ||
|
|
112
|
+
typeof parsed !== 'object' ||
|
|
113
|
+
!Object.hasOwn(parsed, 'goal') ||
|
|
114
|
+
parsed.version !== GOAL_FILE_VERSION
|
|
115
|
+
) {
|
|
116
|
+
throw new Error('unsupported or invalid Goal record');
|
|
117
|
+
}
|
|
118
|
+
if (parsed.goal !== null && (typeof parsed.goal !== 'object' || Array.isArray(parsed.goal)))
|
|
119
|
+
throw new Error('invalid Goal value');
|
|
120
|
+
return { version: GOAL_FILE_VERSION, goal: normalizeGoal(parsed.goal, sessionId, at) };
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
return record ?? { version: GOAL_FILE_VERSION, goal: null };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// A record written by a newer build reads as no Goal and stays in place; a
|
|
127
|
+
// write must not replace it (nor, through `.bak`, its backup). Caller holds the
|
|
128
|
+
// record's lock. Unreadable or unparsable content is damage, not a newer build.
|
|
129
|
+
async function refuseNewerRecord(path) {
|
|
91
130
|
let text;
|
|
92
131
|
try {
|
|
93
|
-
text =
|
|
132
|
+
text = await readFile(path, 'utf8');
|
|
94
133
|
} catch (error) {
|
|
95
|
-
if (error?.code === 'ENOENT') return
|
|
134
|
+
if (error?.code === 'ENOENT') return;
|
|
96
135
|
throw error;
|
|
97
136
|
}
|
|
137
|
+
let parsed;
|
|
98
138
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
throw new Error('invalid Goal value');
|
|
110
|
-
return { version: GOAL_FILE_VERSION, goal: normalizeGoal(parsed.goal, sessionId, at) };
|
|
111
|
-
} catch (cause) {
|
|
112
|
-
throw new Error(
|
|
113
|
-
`cannot read Goal record ${path}: ${cause.message}; original file preserved, repair or explicitly clear it before creating a Goal`,
|
|
114
|
-
{ cause }
|
|
139
|
+
parsed = parseJsonText(text);
|
|
140
|
+
} catch {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (Number.isSafeInteger(parsed?.version) && parsed.version > GOAL_FILE_VERSION) {
|
|
144
|
+
throw Object.assign(
|
|
145
|
+
new Error(
|
|
146
|
+
`Goal record ${path} was written by a newer build (version ${parsed.version} > ${GOAL_FILE_VERSION}); update Mixdog to change this Goal`
|
|
147
|
+
),
|
|
148
|
+
{ code: 'EGOALNEWERVERSION' }
|
|
115
149
|
);
|
|
116
150
|
}
|
|
117
151
|
}
|
|
@@ -149,7 +183,7 @@ export function createGoalStorage({ pathFor, normalizeGoal, now, writeRecord = w
|
|
|
149
183
|
try {
|
|
150
184
|
record = readGoalRecordFile(path, id, normalizeGoal, now());
|
|
151
185
|
} catch (error) {
|
|
152
|
-
if (cached && TRANSIENT_READ_CODES.has(error?.
|
|
186
|
+
if (cached && TRANSIENT_READ_CODES.has(error?.code)) {
|
|
153
187
|
return structuredClone(cached.record);
|
|
154
188
|
}
|
|
155
189
|
throw error;
|
|
@@ -166,7 +200,19 @@ export function createGoalStorage({ pathFor, normalizeGoal, now, writeRecord = w
|
|
|
166
200
|
const snapshot = structuredClone(record);
|
|
167
201
|
writing.add(id);
|
|
168
202
|
try {
|
|
169
|
-
|
|
203
|
+
const path = pathFor(id);
|
|
204
|
+
// The newer-build check and the write share one lock hold, so nothing
|
|
205
|
+
// can publish a newer record between them. The writer's own lock
|
|
206
|
+
// request re-enters this hold.
|
|
207
|
+
await withFileLock(
|
|
208
|
+
`${path}.lock`,
|
|
209
|
+
async () => {
|
|
210
|
+
await refuseNewerRecord(path);
|
|
211
|
+
// Durable, with the replaced version kept as `.bak` for damage recovery.
|
|
212
|
+
await writeRecord(path, snapshot, { lock: true, secret: true, backup: true, timeoutMs: 2_000 });
|
|
213
|
+
},
|
|
214
|
+
{ timeoutMs: 2_000 }
|
|
215
|
+
);
|
|
170
216
|
// The write lock has already been released. A subsequent stat could
|
|
171
217
|
// belong to another writer, so validate the file on the next read.
|
|
172
218
|
cache.set(id, { record: snapshot, stamp: null });
|
|
@@ -112,7 +112,7 @@ const GOAL_TOOL_ACTIONS = {
|
|
|
112
112
|
status(ctx, id) {
|
|
113
113
|
// Same view the user sees. Reading the stored record here showed the
|
|
114
114
|
// model Goals the user had already archived away.
|
|
115
|
-
ctx.readRecord(id); //
|
|
115
|
+
ctx.readRecord(id); // A real I/O error is an actionable error, not "no Goal".
|
|
116
116
|
return toolReply(ctx, id, ctx.visibleSnapshot(id), { full: true });
|
|
117
117
|
},
|
|
118
118
|
async create(ctx, id, args) {
|
|
@@ -114,6 +114,7 @@ export function createGoalTurnLifecycle(ctx) {
|
|
|
114
114
|
turnStartedAt,
|
|
115
115
|
idleReviewTurns,
|
|
116
116
|
continuationTiers,
|
|
117
|
+
unsavedStops,
|
|
117
118
|
withMutation,
|
|
118
119
|
readRecord,
|
|
119
120
|
commit,
|
|
@@ -163,7 +164,14 @@ export function createGoalTurnLifecycle(ctx) {
|
|
|
163
164
|
applyTurnOutcome(goal, detail, at);
|
|
164
165
|
}
|
|
165
166
|
goal.updatedAt = at;
|
|
166
|
-
|
|
167
|
+
let published;
|
|
168
|
+
try {
|
|
169
|
+
published = await commit(id, goal);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
if (goal.status !== 'active') unsavedStops.set(id, goal.id);
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
unsavedStops.delete(id);
|
|
167
175
|
if (automaticTurnWithoutActivity(detail, published)) idleReviewTurns.set(id, idleReviewKey(published));
|
|
168
176
|
return published;
|
|
169
177
|
});
|
|
@@ -189,6 +197,7 @@ export function createGoalTurnLifecycle(ctx) {
|
|
|
189
197
|
if (goal?.status !== 'active') return { run: false, reason: goal?.status || 'missing', goal };
|
|
190
198
|
if (runningAgentWork(agentStatus)) return { run: false, reason: 'agent-running', goal };
|
|
191
199
|
const id = assertSessionId(sessionId);
|
|
200
|
+
if (unsavedStops.get(id) === goal.id) return { run: false, reason: 'unsaved-stop', goal };
|
|
192
201
|
const answered = idleReviewTurns.get(id) === idleReviewKey(goal);
|
|
193
202
|
if (settledDurationWait(goal)) {
|
|
194
203
|
// The model already answered this exact list with no new work, so the
|
|
@@ -25,13 +25,11 @@ export const AGENT_MODE_DELEGATION = `# Delegation
|
|
|
25
25
|
Handle conversation yourself. Delegate specialised work to sub-agents. Hand
|
|
26
26
|
substantial coding to a new agent task session (\`session create\`) with
|
|
27
27
|
a self-contained brief: start it when already requested, otherwise suggest it. Then relay the
|
|
28
|
-
result in your own words.
|
|
29
|
-
reports back only when its result says reportsBack: true; promise to report
|
|
30
|
-
only then.`;
|
|
28
|
+
result in your own words. Promise a follow-up only when the session result allows it.`;
|
|
31
29
|
|
|
32
|
-
/** Mixy only:
|
|
33
|
-
export const MIXY_CONTACTS_INTRO = `
|
|
34
|
-
|
|
30
|
+
/** Mixy only: the user's other bots, its contact catalog's intro. */
|
|
31
|
+
export const MIXY_CONTACTS_INTRO = `The user's other bots. Hand one a request with \`session send\` to its chat and a
|
|
32
|
+
self-contained brief.`;
|
|
35
33
|
|
|
36
34
|
export function orchestrationInstructions(value) {
|
|
37
35
|
const mode = normalizeOrchestrationMode(value);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// A route's context-window selection against provider windows: the share and
|
|
2
|
+
// window a route names, and what a session is created with for it. Shared by
|
|
3
|
+
// every session builder (spawned agents, hidden-role dispatch, the Lead).
|
|
4
|
+
import { providerCachedModelMetadataSync } from '../providers/provider-catalog-cache.mjs';
|
|
5
|
+
import { contextWindowRange, normalizeContextTokens } from '../../../shared/llm/default-context-window.mjs';
|
|
6
|
+
import { clean } from './session-text.mjs';
|
|
7
|
+
|
|
8
|
+
// The persisted provider model rows are the SAME source the picker sized its
|
|
9
|
+
// slider against, so they carry both windows (openai-oauth: 272k default /
|
|
10
|
+
// 1M max). Reading them keeps a percentage saved against the picker's scale
|
|
11
|
+
// meaningful; anything that only knows a single window would silently rescale
|
|
12
|
+
// it (30% of 272k instead of 30% of 1M).
|
|
13
|
+
const clampPercent = (percent) => Math.max(10, Math.min(100, percent));
|
|
14
|
+
|
|
15
|
+
function cachedRouteWindows(provider, model) {
|
|
16
|
+
const row = providerCachedModelMetadataSync(provider, model)?.rawProviderModel || null;
|
|
17
|
+
if (!row) return null;
|
|
18
|
+
const contextWindow = Number(row.contextWindow ?? row.context_window ?? row.max_input_tokens) || 0;
|
|
19
|
+
const maxContextWindow = Number(row.maxContextWindow ?? row.max_context_window) || 0;
|
|
20
|
+
return contextWindow > 0 || maxContextWindow > 0 ? { contextWindow, maxContextWindow } : null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function resolveRouteContextState(targetRoute = {}, modelMeta = null, windowLookup = cachedRouteWindows) {
|
|
24
|
+
// Only providers that implement getCachedModelInfo (openai-oauth, cursor,
|
|
25
|
+
// openai-compat, opencode-go) hand lookupModelMeta a window; every other one
|
|
26
|
+
// (anthropic-oauth, grok-oauth, gemini, …) gets the bare `{ id, provider }`
|
|
27
|
+
// placeholder. Reading the window from that alone yields 0, which dropped the
|
|
28
|
+
// saved context percentage for the entire session — while resolveSessionContextMeta
|
|
29
|
+
// went on to size that session from the provider/catalog window (Claude Opus 5:
|
|
30
|
+
// a full 1M rather than the selected 500k). Read the cached provider row here so
|
|
31
|
+
// the percentage and the session boundary cannot disagree.
|
|
32
|
+
const windowMeta =
|
|
33
|
+
Number(modelMeta?.contextWindow) > 0 || Number(modelMeta?.maxContextWindow) > 0
|
|
34
|
+
? modelMeta
|
|
35
|
+
: windowLookup?.(clean(targetRoute?.provider), clean(targetRoute?.model)) || modelMeta;
|
|
36
|
+
const { defaultWindow, maxWindow } = contextWindowRange({
|
|
37
|
+
provider: clean(targetRoute?.provider),
|
|
38
|
+
contextWindow: windowMeta?.contextWindow,
|
|
39
|
+
maxContextWindow: windowMeta?.maxContextWindow,
|
|
40
|
+
});
|
|
41
|
+
if (!maxWindow) {
|
|
42
|
+
return { contextPercent: undefined, contextDefaultPercent: undefined, selectedContextWindow: undefined };
|
|
43
|
+
}
|
|
44
|
+
const contextDefaultPercent = clampPercent(Math.round((defaultWindow / maxWindow) * 10) * 10);
|
|
45
|
+
// An exact token selection overrides the 10% stops. It is clamped to the
|
|
46
|
+
// selectable range; one that lands on the default window is the default.
|
|
47
|
+
const requestedTokens = normalizeContextTokens(targetRoute?.contextTokens);
|
|
48
|
+
if (requestedTokens) {
|
|
49
|
+
const contextTokens = Math.max(Math.ceil(maxWindow * 0.1), Math.min(maxWindow, requestedTokens));
|
|
50
|
+
if (contextTokens === defaultWindow) {
|
|
51
|
+
return { contextPercent: contextDefaultPercent, contextDefaultPercent, selectedContextWindow: defaultWindow };
|
|
52
|
+
}
|
|
53
|
+
const contextPercent = clampPercent(Math.round((contextTokens / maxWindow) * 10) * 10);
|
|
54
|
+
return { contextPercent, contextDefaultPercent, selectedContextWindow: contextTokens, contextTokens };
|
|
55
|
+
}
|
|
56
|
+
const requested = Number(targetRoute?.contextPercent);
|
|
57
|
+
const contextPercent =
|
|
58
|
+
Number.isFinite(requested) && requested > 0 ? clampPercent(Math.round(requested / 10) * 10) : contextDefaultPercent;
|
|
59
|
+
const selectedContextWindow =
|
|
60
|
+
contextPercent === contextDefaultPercent
|
|
61
|
+
? defaultWindow
|
|
62
|
+
: Math.max(1, Math.floor((maxWindow * contextPercent) / 100));
|
|
63
|
+
return { contextPercent, contextDefaultPercent, selectedContextWindow };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The session fields (`contextPercent`, `selectedContextWindow`, `contextTokens`)
|
|
68
|
+
* a route's own context choice creates a session with, from its resolved
|
|
69
|
+
* `state`. A model whose window is not known resolves to nothing: the choice
|
|
70
|
+
* then travels as stored (the session sizes it from the provider's window)
|
|
71
|
+
* instead of being dropped for the model's default. Only set fields are returned.
|
|
72
|
+
*/
|
|
73
|
+
export function contextSelectionFromState(state, route) {
|
|
74
|
+
const windowKnown = state.contextDefaultPercent !== undefined;
|
|
75
|
+
const chosen = {
|
|
76
|
+
contextPercent: state.contextPercent ?? route.contextPercent,
|
|
77
|
+
selectedContextWindow: state.selectedContextWindow,
|
|
78
|
+
contextTokens: state.contextTokens ?? (windowKnown ? undefined : route.contextTokens),
|
|
79
|
+
};
|
|
80
|
+
return Object.fromEntries(Object.entries(chosen).filter(([, value]) => value));
|
|
81
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Session message/preview text helpers. Pure, no runtime-closure deps.
|
|
2
2
|
import { clean } from '../../../shared/clean.mjs';
|
|
3
3
|
import { stripInjectedBlocks } from '../../../shared/injected-display-text.mjs';
|
|
4
|
+
import { CONTROL_MARKER_RE } from '../../../shared/tool-execution-contract.mjs';
|
|
4
5
|
|
|
5
6
|
export function sessionMessageText(content) {
|
|
6
7
|
if (content == null) return '';
|
|
@@ -42,7 +43,7 @@ function messageContextText(message) {
|
|
|
42
43
|
const SYNTHETIC_SESSION_TEXT_PATTERNS = Object.freeze([
|
|
43
44
|
/^\[mixdog-runtime\]/i,
|
|
44
45
|
// User-cancel + process-restart control rows must never title/preview a session.
|
|
45
|
-
|
|
46
|
+
CONTROL_MARKER_RE,
|
|
46
47
|
/^a previous model worked on this task and produced the compacted handoff summary below\b/i,
|
|
47
48
|
// Compact/auto-clear re-seed handoff variants: these lead the FIRST user
|
|
48
49
|
// message of every post-compaction session, so titling from them painted
|