mixdog 1.3.0 → 1.3.2
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/NOTICE.md +52 -9
- package/README.md +8 -4
- package/package.json +2 -2
- package/scripts/native-release-status.mjs +238 -0
- package/src/defaults/shipped-history.json +8 -1
- 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 +54 -4
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +17 -10
- 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/output-styles/common.md +13 -8
- package/src/rules/agent-mode/AGENT_MODE.md +9 -6
- package/src/rules/agent-mode/MIXY.md +11 -6
- package/src/rules/lead/LEAD.md +2 -2
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- 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 +81 -16
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -4
- 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 +80 -31
- 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 +67 -38
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +34 -16
- 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.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +19 -1
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -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-retry-profile.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +10 -2
- 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-responses-input.mjs +3 -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/provider-error-kind.mjs +14 -2
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
- 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-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +5 -5
- 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 +12 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +17 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +41 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +6 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +2 -0
- 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 +21 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +149 -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/execution-tail.mjs +14 -11
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +68 -18
- 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 +5 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +1 -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 +230 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +156 -25
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +21 -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 +189 -105
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +111 -9
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +11 -14
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +38 -5
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +21 -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/loop/usage.mjs +46 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +99 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -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/provider-replay.mjs +50 -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-lifecycle.mjs +62 -47
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +6 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +42 -10
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +35 -4
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +179 -16
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -1
- 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/sweep-record.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +36 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -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/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 +49 -14
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +134 -17
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +35 -13
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -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/lib/shell-job-records.mjs +6 -14
- 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 +34 -21
- 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/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/store.mjs +55 -30
- 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 +6 -3
- package/src/runtime/effort-judge/model-install.mjs +16 -8
- package/src/runtime/effort-judge/model-manifest.json +7 -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/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 +4 -0
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-kind.mjs +152 -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-route-config.d.mts +1 -0
- package/src/runtime/shared/agent-route-config.mjs +22 -8
- package/src/runtime/shared/agent-store.mjs +149 -0
- 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 +30 -0
- package/src/runtime/shared/bot-split-migration.mjs +457 -0
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config-patch.mjs +20 -1
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/connector-catalog.d.mts +1 -2
- package/src/runtime/shared/connector-catalog.mjs +2 -4
- package/src/runtime/shared/connector-triggers.mjs +2 -0
- 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 +7 -1
- package/src/runtime/shared/error-presentation.mjs +113 -10
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
- package/src/runtime/shared/handoff-artifacts.mjs +61 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +6 -1
- package/src/runtime/shared/llm/usage-accounting.mjs +7 -1
- package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/model-route-fallback.mjs +79 -7
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/plain-preview.mjs +22 -17
- 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/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/sensitive-path-rules.d.mts +15 -0
- package/src/runtime/shared/sensitive-path-rules.mjs +256 -0
- package/src/runtime/shared/session-baseline-store.mjs +8 -2
- 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 +6 -0
- 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 +44 -2
- package/src/runtime/shared/usage-readout-totals.mjs +15 -13
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +46 -44
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +269 -61
- package/src/runtime/shared/worktrees/registry.mjs +26 -26
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +859 -136
- package/src/session-runtime/agent-room-delivery.mjs +167 -19
- package/src/session-runtime/agent-task-sessions.mjs +831 -69
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +58 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +11 -1
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +16 -6
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +2 -2
- 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 +78 -32
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/handoff-attachments.mjs +593 -0
- package/src/session-runtime/held-requests.mjs +36 -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 +45 -6
- 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-route/route-persist.mjs +2 -2
- package/src/session-runtime/model-route/route-tuning.mjs +11 -2
- package/src/session-runtime/model-route/set-route.mjs +82 -2
- package/src/session-runtime/native-web-search.mjs +2 -2
- package/src/session-runtime/new-session-config.mjs +6 -1
- package/src/session-runtime/owned-automation-run.mjs +8 -1
- package/src/session-runtime/room-member-gate.mjs +16 -3
- package/src/session-runtime/route-resolution.mjs +21 -19
- 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-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/helpers.mjs +24 -5
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +36 -24
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -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 +12 -6
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +5 -8
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- 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 +14 -4
- 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/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +63 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +20 -3
- package/src/session-runtime/setup-tool/extended-actions.mjs +19 -7
- package/src/session-runtime/setup-tool/settings-contract.mjs +37 -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 +265 -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 +165 -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 +47 -358
- package/src/session-runtime/tool-surface.mjs +5 -3
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +99 -81
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +2 -1
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +578 -301
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +113 -53
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
- 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/workspace-state.mjs +7 -6
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-session-control.mjs +60 -11
- package/src/standalone/daemon.mjs +34 -4
- package/src/standalone/local-session-runtime.mjs +22 -14
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +46 -3
- package/src/standalone/session-service/agent-tree.mjs +4 -3
- package/src/standalone/session-service/session-calls/session-turns.mjs +19 -0
- package/src/standalone/session-service.mjs +11 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +35 -9
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- 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 +599 -342
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/notice-surface.mjs +3 -4
- package/src/tui/session/session-api/intake/abort.mjs +19 -1
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +75 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -236
- 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 +185 -20
- package/src/tui/session/transcript-intake.mjs +4 -0
- package/src/tui/session/turn-live-call.mjs +11 -3
- package/src/tui/session/turn.mjs +36 -17
- 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
|
@@ -29,7 +29,15 @@ import {
|
|
|
29
29
|
} from './store-summary-fields.mjs';
|
|
30
30
|
import { isRealTurnMessage } from './compact/user-message-kind.mjs';
|
|
31
31
|
import { isRoutineResultMessage, normalizeRoutineProvenance, routineProvenance } from './routine-result.mjs';
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
INCOMING_TAIL_MAX,
|
|
34
|
+
LAST_MESSAGE_PREVIEW_MAX,
|
|
35
|
+
cleanSummaryPreview,
|
|
36
|
+
isIncomingKind,
|
|
37
|
+
normalizedIncomingTail,
|
|
38
|
+
lastMessageRawText,
|
|
39
|
+
wantsIncomingTail,
|
|
40
|
+
} from './store-summary-last-message.mjs';
|
|
33
41
|
|
|
34
42
|
export const SESSION_SUMMARY_INDEX_VERSION = 2;
|
|
35
43
|
|
|
@@ -111,6 +119,13 @@ function _sessionMessageProjection(session) {
|
|
|
111
119
|
let real = 0;
|
|
112
120
|
let preview = '';
|
|
113
121
|
let previewMessage = null;
|
|
122
|
+
// Where the incoming messages with text sit among the counted ones (see
|
|
123
|
+
// incomingTailOf), kept only for the threads that show an unread count.
|
|
124
|
+
const wantsIncoming = wantsIncomingTail(session?.id);
|
|
125
|
+
let incoming = [];
|
|
126
|
+
// The totals ahead of the newest message, which a streamed reply fills in
|
|
127
|
+
// place after it was counted: an append redoes that message from here.
|
|
128
|
+
let ahead = null;
|
|
114
129
|
const canAppend =
|
|
115
130
|
cached &&
|
|
116
131
|
messages.length >= cached.length &&
|
|
@@ -119,6 +134,12 @@ function _sessionMessageProjection(session) {
|
|
|
119
134
|
start = cached.length;
|
|
120
135
|
count = cached.count;
|
|
121
136
|
real = cached.real;
|
|
137
|
+
incoming = cached.incoming.slice();
|
|
138
|
+
if (cached.ahead) {
|
|
139
|
+
start = cached.length - 1;
|
|
140
|
+
({ count, real } = cached.ahead);
|
|
141
|
+
incoming = cached.ahead.incoming.slice();
|
|
142
|
+
}
|
|
122
143
|
preview = cached.preview;
|
|
123
144
|
previewMessage = cached.previewMessage;
|
|
124
145
|
// The first real user message is stable in normal append-only session
|
|
@@ -131,6 +152,7 @@ function _sessionMessageProjection(session) {
|
|
|
131
152
|
start = 0;
|
|
132
153
|
count = 0;
|
|
133
154
|
real = 0;
|
|
155
|
+
incoming = [];
|
|
134
156
|
preview = '';
|
|
135
157
|
previewMessage = null;
|
|
136
158
|
}
|
|
@@ -138,7 +160,14 @@ function _sessionMessageProjection(session) {
|
|
|
138
160
|
}
|
|
139
161
|
for (let index = start; index < messages.length; index += 1) {
|
|
140
162
|
const message = messages[index];
|
|
141
|
-
if (
|
|
163
|
+
if (index === messages.length - 1) ahead = { count, real, incoming: incoming.slice() };
|
|
164
|
+
if (message && (message.role === 'user' || message.role === 'assistant')) {
|
|
165
|
+
count += 1;
|
|
166
|
+
if (wantsIncoming && isIncomingKind(message) && _lastPreviewFromMessage(message)) {
|
|
167
|
+
incoming.push(count);
|
|
168
|
+
if (incoming.length > INCOMING_TAIL_MAX) incoming.shift();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
142
171
|
if (isRealTurnMessage(message)) real += 1;
|
|
143
172
|
if (!preview) {
|
|
144
173
|
const candidate = _previewFromMessage(message);
|
|
@@ -165,11 +194,13 @@ function _sessionMessageProjection(session) {
|
|
|
165
194
|
lastMessage: messages[messages.length - 1] || null,
|
|
166
195
|
count,
|
|
167
196
|
real,
|
|
197
|
+
incoming,
|
|
198
|
+
ahead,
|
|
168
199
|
preview,
|
|
169
200
|
previewMessage,
|
|
170
201
|
});
|
|
171
202
|
}
|
|
172
|
-
return { count, real, preview, last, lastRoutine };
|
|
203
|
+
return { count, real, incoming: wantsIncoming ? incoming : null, preview, last, lastRoutine };
|
|
173
204
|
}
|
|
174
205
|
|
|
175
206
|
function _desktopSessionSummary(value, cwd = null) {
|
|
@@ -233,6 +264,7 @@ export function _sessionSummary(session) {
|
|
|
233
264
|
: null,
|
|
234
265
|
taskType: session.taskType || null,
|
|
235
266
|
messageCount: messageProjection.count,
|
|
267
|
+
...(messageProjection.incoming ? { incomingTail: messageProjection.incoming.slice() } : {}),
|
|
236
268
|
realTurnCount: messageProjection.real,
|
|
237
269
|
title: _cleanPreview(session.title || '', 100),
|
|
238
270
|
preview: messageProjection.preview,
|
|
@@ -291,6 +323,7 @@ function _normalizeSummaryRow(row) {
|
|
|
291
323
|
: null,
|
|
292
324
|
taskType: row.taskType || null,
|
|
293
325
|
messageCount: Math.max(0, Math.floor(Number(row.messageCount) || 0)),
|
|
326
|
+
...(Array.isArray(row.incomingTail) ? { incomingTail: normalizedIncomingTail(row.incomingTail) } : {}),
|
|
294
327
|
realTurnCount: realTurnCount(row),
|
|
295
328
|
title: _cleanPreview(row.title || '', 100),
|
|
296
329
|
preview: _cleanPreview(row.preview || ''),
|
|
@@ -561,12 +594,14 @@ export function summaryLockFailureStats() {
|
|
|
561
594
|
|
|
562
595
|
// ── Stale temp sweep ────────────────────────────────────────────────────────
|
|
563
596
|
// A crash between an atomic write's temp file and its rename orphans
|
|
564
|
-
//
|
|
597
|
+
// `session-summaries.json.mixdog-tmp-<16 hex>` (multi-MB each; before the
|
|
598
|
+
// cloud-sync fix `.session-summaries.json.<24 hex>.tmp`). Only this store's
|
|
565
599
|
// pattern is touched. Deleted only when older than SUMMARY_TMP_MIN_AGE_MS and
|
|
566
600
|
// while holding the index lock: every writer of these temps (full rewrite,
|
|
567
601
|
// compaction) holds that lock for the whole write, so no live writer can own a
|
|
568
602
|
// temp file the sweep sees.
|
|
569
|
-
const SUMMARY_TMP_PATTERN =
|
|
603
|
+
const SUMMARY_TMP_PATTERN =
|
|
604
|
+
/^(?:\.session-summaries\.json\.[0-9a-f]{24}\.tmp|session-summaries\.json\.mixdog-tmp-[0-9a-f]{16,24})$/;
|
|
570
605
|
const SUMMARY_TMP_MIN_AGE_MS = 10 * 60 * 1000;
|
|
571
606
|
let _sweptSummaryDir = '';
|
|
572
607
|
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import { cleanSessionPreview, isSessionPreviewNoise, sessionMessageText } from '../runtime-core/session-text.mjs';
|
|
8
8
|
import { plainPreviewText } from '../../../shared/plain-preview.mjs';
|
|
9
9
|
import { isRoutineResultMessage, routineProvenance, routineResultNotice } from './routine-result.mjs';
|
|
10
|
+
import { agentIdOfHomeSession } from './agent-home.mjs';
|
|
11
|
+
import { roomIdOfSession } from './agent-room.mjs';
|
|
10
12
|
|
|
11
13
|
export const LAST_MESSAGE_PREVIEW_MAX = 160;
|
|
12
14
|
|
|
@@ -28,13 +30,56 @@ export function lastMessageRawText(message) {
|
|
|
28
30
|
return isRoutineResultMessage(message) ? routineResultNotice(message).text : sessionMessageText(message.content);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
/** The message's last-message line, '' when it has none (tool-only, synthetic
|
|
33
|
+
/** The message's last-message line, '' when it has none (tool-only, synthetic,
|
|
34
|
+
* or the runtime's own task-notification envelopes). */
|
|
32
35
|
export function lastMessageLine(message) {
|
|
33
36
|
const raw = lastMessageRawText(message);
|
|
34
|
-
if (raw === null || isSessionPreviewNoise(raw)) return '';
|
|
37
|
+
if (raw === null || isSessionPreviewNoise(raw) || raw.trimStart().startsWith('<task-notification>\n')) return '';
|
|
35
38
|
return cleanSummaryPreview(plainPreviewText(raw), LAST_MESSAGE_PREVIEW_MAX);
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
/** Most unseen messages a row can report: one past the pill's 99, so a full
|
|
42
|
+
* tail still reads as "99+". */
|
|
43
|
+
export const INCOMING_TAIL_MAX = 100;
|
|
44
|
+
|
|
45
|
+
/** Only a bot's home thread or a group room's log shows an unread count, so
|
|
46
|
+
* only their summaries carry the incoming tail. */
|
|
47
|
+
export function wantsIncomingTail(sessionId) {
|
|
48
|
+
return Boolean(agentIdOfHomeSession(sessionId) || roomIdOfSession(sessionId));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Whether `message` is of a kind that arrives as a chat message the user did
|
|
52
|
+
* not write: an assistant turn that is not a tool call, or a posted result
|
|
53
|
+
* (routine, task report, bot-to-bot). A user prompt, a tool-call turn and a
|
|
54
|
+
* tool result are not. Text is checked separately (lastMessageLine). */
|
|
55
|
+
export function isIncomingKind(message) {
|
|
56
|
+
if (isRoutineResultMessage(message)) return true;
|
|
57
|
+
if (message?.role !== 'assistant') return false;
|
|
58
|
+
const content = Array.isArray(message.content) ? message.content : [];
|
|
59
|
+
return !(message.toolCalls?.length > 0) && !content.some((part) => part?.type === 'tool_use');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The incoming messages with text among the last of a transcript, each as
|
|
63
|
+
* its 1-based place among the user/assistant messages (the numbering of
|
|
64
|
+
* `messageCount` and of the read cursor), oldest first, at most
|
|
65
|
+
* INCOMING_TAIL_MAX of them. */
|
|
66
|
+
export function incomingTailOf(messages) {
|
|
67
|
+
const tail = [];
|
|
68
|
+
let ordinal = 0;
|
|
69
|
+
for (const message of Array.isArray(messages) ? messages : []) {
|
|
70
|
+
if (message?.role !== 'user' && message?.role !== 'assistant') continue;
|
|
71
|
+
ordinal += 1;
|
|
72
|
+
if (isIncomingKind(message) && lastMessageLine(message)) tail.push(ordinal);
|
|
73
|
+
}
|
|
74
|
+
return tail.slice(-INCOMING_TAIL_MAX);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** A stored incoming tail as a clean ascending list of whole places. */
|
|
78
|
+
export function normalizedIncomingTail(value) {
|
|
79
|
+
const places = (Array.isArray(value) ? value : []).filter((place) => Number.isSafeInteger(place) && place > 0);
|
|
80
|
+
return places.slice(-INCOMING_TAIL_MAX);
|
|
81
|
+
}
|
|
82
|
+
|
|
38
83
|
/** `{ lastMessagePreview, lastMessageRoutine }` of a transcript. */
|
|
39
84
|
export function lastMessageSummary(messages) {
|
|
40
85
|
const list = Array.isArray(messages) ? messages : [];
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Tail reminders: short per-model/per-language nudges appended to the very end
|
|
2
|
+
// of an outgoing request (after the last tool result), fresh on every request.
|
|
3
|
+
// They are never stored in session history or transcripts, and the Anthropic
|
|
4
|
+
// builders place their last cache breakpoint BEFORE them, so the cached prefix
|
|
5
|
+
// stays byte-identical from one request to the next.
|
|
6
|
+
//
|
|
7
|
+
// HOW TO ADD A RULE (a new per-model/per-language fix needs nothing else):
|
|
8
|
+
// 1. Append {id, when, text} to TAIL_REMINDER_RULES. `when` holds any of
|
|
9
|
+
// provider / model / language / role, each a list of accepted values; ALL
|
|
10
|
+
// given tags must match, an omitted tag matches anything.
|
|
11
|
+
// 2. `text` may use `{language}` (the language block's name, e.g. "Korean").
|
|
12
|
+
// 3. Add a positive and a negative case to tail-reminder-rules.test.mjs.
|
|
13
|
+
// Values: provider = provider id or family ('anthropic'); model = normalized
|
|
14
|
+
// family id ('claude-opus-5-5', route prefix/dots/date folded); language = id
|
|
15
|
+
// ('ko'); role = 'lead' | 'bot' | 'worker'. Unknown tags throw at load.
|
|
16
|
+
import { AGENT_MODE } from './agent-mode.mjs';
|
|
17
|
+
import { _buildLeadLanguage } from './manager/rules-cache.mjs';
|
|
18
|
+
import { TAIL_REMINDER_META } from '../providers/lib/tail-reminder-split.mjs';
|
|
19
|
+
|
|
20
|
+
export const TAIL_REMINDER_TAGS = Object.freeze(['provider', 'model', 'language', 'role']);
|
|
21
|
+
const ROLES = ['lead', 'bot', 'worker'];
|
|
22
|
+
|
|
23
|
+
const PROVIDER_FAMILIES = Object.freeze({
|
|
24
|
+
'anthropic-oauth': 'anthropic',
|
|
25
|
+
anthropic: 'anthropic',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const TAIL_REMINDER_RULES = Object.freeze([
|
|
29
|
+
// Claude Opus 5.5 keeps answering Korean users in English in long agentic
|
|
30
|
+
// turns, where many English tool results sit between the user message and
|
|
31
|
+
// the final answer.
|
|
32
|
+
{
|
|
33
|
+
id: 'opus-5-5-korean',
|
|
34
|
+
when: { model: ['claude-opus-5-5'], language: ['ko'], role: ['lead', 'bot'] },
|
|
35
|
+
text: 'Write all user-facing text in {language}.',
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
export function validateTailReminderRules(rules) {
|
|
40
|
+
if (!Array.isArray(rules)) throw new Error('tail reminder rules must be an array');
|
|
41
|
+
const ids = new Set();
|
|
42
|
+
for (const rule of rules) {
|
|
43
|
+
if (!rule?.id || ids.has(rule.id)) throw new Error(`tail reminder rule: missing or duplicate id "${rule?.id}"`);
|
|
44
|
+
ids.add(rule.id);
|
|
45
|
+
for (const key of Object.keys(rule)) {
|
|
46
|
+
if (!['id', 'when', 'text'].includes(key))
|
|
47
|
+
throw new Error(`tail reminder rule ${rule.id}: unknown field "${key}"`);
|
|
48
|
+
}
|
|
49
|
+
if (typeof rule.text !== 'string' || !rule.text.trim())
|
|
50
|
+
throw new Error(`tail reminder rule ${rule.id}: text required`);
|
|
51
|
+
for (const [tag, values] of Object.entries(rule.when || {})) {
|
|
52
|
+
if (!TAIL_REMINDER_TAGS.includes(tag)) throw new Error(`tail reminder rule ${rule.id}: unknown tag "${tag}"`);
|
|
53
|
+
if (!Array.isArray(values) || !values.length || values.some((v) => typeof v !== 'string' || !v)) {
|
|
54
|
+
throw new Error(`tail reminder rule ${rule.id}: "${tag}" must be a non-empty string list`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const role of rule.when?.role || []) {
|
|
58
|
+
if (!ROLES.includes(role)) throw new Error(`tail reminder rule ${rule.id}: unknown role "${role}"`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return rules;
|
|
62
|
+
}
|
|
63
|
+
validateTailReminderRules(TAIL_REMINDER_RULES);
|
|
64
|
+
|
|
65
|
+
/** `anthropic/claude-opus-5.5`, `claude-opus-5-5-20260101`, `us.anthropic.claude-opus-5-5-v1:0`,
|
|
66
|
+
* `claude-opus-5-5-thinking` → `claude-opus-5-5`. */
|
|
67
|
+
export function modelFamilyId(model) {
|
|
68
|
+
let id = String(model || '')
|
|
69
|
+
.trim()
|
|
70
|
+
.toLowerCase()
|
|
71
|
+
.replace(/\./g, '-');
|
|
72
|
+
const at = id.indexOf('claude-');
|
|
73
|
+
if (at >= 0) id = id.slice(at);
|
|
74
|
+
else id = id.slice(id.lastIndexOf('/') + 1);
|
|
75
|
+
// `@date`, Bedrock `-v1:0`, a gateway `:variant` (`:thinking`), `-v1`,
|
|
76
|
+
// `-YYYYMMDD`, and the `-thinking` alias of the same model.
|
|
77
|
+
return id
|
|
78
|
+
.replace(/@.*$/, '')
|
|
79
|
+
.replace(/-v\d+:\d+$/, '')
|
|
80
|
+
.replace(/:[^/]*$/, '')
|
|
81
|
+
.replace(/-v\d+$/, '')
|
|
82
|
+
.replace(/-\d{8}$/, '')
|
|
83
|
+
.replace(/-thinking$/, '');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The session's role: 'worker' (agent-owned), 'bot' (agent mode) or 'lead'. */
|
|
87
|
+
export function tailReminderRole(session) {
|
|
88
|
+
if (session?.owner === 'agent') return 'worker';
|
|
89
|
+
return session?.sessionMode === AGENT_MODE ? 'bot' : 'lead';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// All given conditions must hold (AND); an omitted condition matches anything.
|
|
93
|
+
function ruleMatches({ when = {} }, { provider, model, languageId, role }) {
|
|
94
|
+
const family = PROVIDER_FAMILIES[provider];
|
|
95
|
+
if (when.provider && !when.provider.some((p) => p === provider || (family && p === family))) return false;
|
|
96
|
+
if (when.model && !when.model.includes(modelFamilyId(model))) return false;
|
|
97
|
+
if (when.language && !when.language.includes(languageId)) return false;
|
|
98
|
+
if (when.role && !when.role.includes(role)) return false;
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The joined text of every matching rule wrapped as one system-reminder, or ''.
|
|
104
|
+
* context = {provider, model, language: {id, name}|null, role}.
|
|
105
|
+
*/
|
|
106
|
+
export function matchTailReminder(context, rules = TAIL_REMINDER_RULES) {
|
|
107
|
+
const language = context.language || null;
|
|
108
|
+
const facts = { ...context, languageId: language?.id };
|
|
109
|
+
const texts = rules
|
|
110
|
+
.filter((rule) => ruleMatches(rule, facts))
|
|
111
|
+
.map((rule) => rule.text.replaceAll('{language}', language?.name || ''));
|
|
112
|
+
return texts.length ? `<system-reminder>${texts.join('\n')}</system-reminder>` : '';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** `messages` plus the tail reminder for this request (a copy; the input is untouched). */
|
|
116
|
+
export function withTailReminder(messages, { session, provider, model }, language = _buildLeadLanguage()) {
|
|
117
|
+
const text = matchTailReminder({
|
|
118
|
+
provider: session?.provider || provider?.name || '',
|
|
119
|
+
model,
|
|
120
|
+
language,
|
|
121
|
+
role: tailReminderRole(session),
|
|
122
|
+
});
|
|
123
|
+
if (!text) return messages;
|
|
124
|
+
return [...messages, { role: 'user', content: text, meta: { source: TAIL_REMINDER_META } }];
|
|
125
|
+
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import { isOffloadedToolResultText, maybeOffloadToolResultBatch } from '../tool-result-offload.mjs';
|
|
12
12
|
import { setReadCached, setScopedToolCached } from '../read-dedup.mjs';
|
|
13
13
|
import { _stripMcpPrefix, _isReadTool, _isScopedCacheableTool, _isShellTool } from '../loop/tool-classify.mjs';
|
|
14
|
+
import { takeAgentTaskStarts } from '../../../../shared/agent-task-starts.mjs';
|
|
14
15
|
import { crossTurnSignature, isEditProgressTool } from '../loop/completion-guards.mjs';
|
|
15
16
|
import { isEagerDispatchable, isToolCallDedupEligible, parseNativeToolSearchPayload } from '../loop/tool-helpers.mjs';
|
|
16
17
|
import { restoreToolCallBodyForId } from '../loop/stored-tool-args.mjs';
|
|
@@ -307,6 +308,9 @@ function completedToolResult(completed, result, postprocessStartedAt) {
|
|
|
307
308
|
...(completed.readWindow ? { readWindow: completed.readWindow } : {}),
|
|
308
309
|
...(uiDiff !== null ? { uiDiff } : {}),
|
|
309
310
|
...toolMetaPatchFromMessage(completed.result),
|
|
311
|
+
// Every agent call's result names the jobs it started (none: []), so a
|
|
312
|
+
// task session's report follows exactly its own agents' results.
|
|
313
|
+
...(_stripMcpPrefix(call.name) === 'agent' ? { agentTaskIds: takeAgentTaskStarts(call.id) } : {}),
|
|
310
314
|
};
|
|
311
315
|
}
|
|
312
316
|
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
readdirSync,
|
|
11
11
|
rmdirSync,
|
|
12
12
|
unlinkSync,
|
|
13
|
-
writeFileSync,
|
|
14
13
|
} from 'node:fs';
|
|
15
|
-
import { lstat, open, readdir, readFile, stat, unlink
|
|
14
|
+
import { lstat, open, readdir, readFile, stat, unlink } from 'node:fs/promises';
|
|
16
15
|
import { createHash } from 'node:crypto';
|
|
17
16
|
import { join } from 'node:path';
|
|
17
|
+
import { holdsNoData, writeFileAtomicAsync, writeFileAtomicSync } from '../../../shared/atomic-file.mjs';
|
|
18
18
|
import { getPluginData } from '../config.mjs';
|
|
19
19
|
import { countSplitLines, normalizeOutputPath } from '../tools/builtin/path-utils.mjs';
|
|
20
20
|
import { classifyResultKind } from './result-classification.mjs';
|
|
@@ -236,28 +236,76 @@ export function persistToolResultArtifactSync({ sessionId, toolCallId, channel =
|
|
|
236
236
|
}
|
|
237
237
|
if (!meta) return null;
|
|
238
238
|
try {
|
|
239
|
-
|
|
239
|
+
const state = existingArtifactStateSync(meta);
|
|
240
|
+
if (state === ARTIFACT_INTACT) return meta;
|
|
241
|
+
if (state === ARTIFACT_FOREIGN) return null;
|
|
242
|
+
// Whole-file publication (fsynced temp, then link or rename): a crash never
|
|
243
|
+
// leaves a torn artifact. Data-free damage is replaced whole.
|
|
244
|
+
if (state === ARTIFACT_DAMAGED) {
|
|
245
|
+
writeFileAtomicSync(meta.path, content, { mode: 0o600 });
|
|
246
|
+
return meta;
|
|
247
|
+
}
|
|
248
|
+
if (writeFileAtomicSync(meta.path, content, { mode: 0o600, createOnly: true })) return meta;
|
|
249
|
+
// Lost the create race: the winner's file is whole; verify it like any other.
|
|
250
|
+
return existingArtifactStateSync(meta) === ARTIFACT_INTACT ? meta : null;
|
|
251
|
+
} catch {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// What sits at an artifact's content-addressed path: nothing, the verified
|
|
257
|
+
// bytes, a file a crash left without data (empty or NUL — replaced whole), or
|
|
258
|
+
// anything else (mismatched bytes, a link, a directory, an unreadable file),
|
|
259
|
+
// which is evidence that is never touched or trusted.
|
|
260
|
+
const ARTIFACT_ABSENT = 'absent';
|
|
261
|
+
const ARTIFACT_INTACT = 'intact';
|
|
262
|
+
const ARTIFACT_DAMAGED = 'damaged';
|
|
263
|
+
const ARTIFACT_FOREIGN = 'foreign';
|
|
264
|
+
|
|
265
|
+
function artifactVerdict(meta, info, readBytes) {
|
|
266
|
+
if (!info.isFile()) return ARTIFACT_FOREIGN;
|
|
267
|
+
if (!artifactShapeMatches(meta, info)) return info.size === 0 ? ARTIFACT_DAMAGED : ARTIFACT_FOREIGN;
|
|
268
|
+
const bytes = readBytes();
|
|
269
|
+
if (createHash('sha256').update(bytes).digest('hex') === meta.sha256) return ARTIFACT_INTACT;
|
|
270
|
+
return holdsNoData(bytes) ? ARTIFACT_DAMAGED : ARTIFACT_FOREIGN;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function existingArtifactStateSync(meta) {
|
|
274
|
+
let fd;
|
|
275
|
+
try {
|
|
276
|
+
lstatSync(meta.path);
|
|
277
|
+
fd = openSync(meta.path, ARTIFACT_READ_FLAGS);
|
|
278
|
+
const info = fstatSync(fd);
|
|
279
|
+
return artifactVerdict(meta, info, () => readFileSync(fd));
|
|
240
280
|
} catch (error) {
|
|
241
|
-
|
|
242
|
-
|
|
281
|
+
return error?.code === 'ENOENT' ? ARTIFACT_ABSENT : ARTIFACT_FOREIGN;
|
|
282
|
+
} finally {
|
|
243
283
|
try {
|
|
244
|
-
if (
|
|
245
|
-
fd = openSync(meta.path, ARTIFACT_READ_FLAGS);
|
|
246
|
-
if (!artifactShapeMatches(meta, fstatSync(fd))) return null;
|
|
247
|
-
if (createHash('sha256').update(readFileSync(fd)).digest('hex') !== meta.sha256) return null;
|
|
284
|
+
if (fd !== undefined) closeSync(fd);
|
|
248
285
|
} catch {
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
286
|
+
// A failed descriptor close is cleanup, not a failed persist.
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function existingArtifactState(meta) {
|
|
292
|
+
let handle;
|
|
293
|
+
try {
|
|
294
|
+
await lstat(meta.path);
|
|
295
|
+
handle = await open(meta.path, ARTIFACT_READ_FLAGS);
|
|
296
|
+
const info = await handle.stat();
|
|
297
|
+
// The verdict needs the bytes only when the size matches: read them first.
|
|
298
|
+
const bytes = info.isFile() && artifactShapeMatches(meta, info) ? await handle.readFile() : null;
|
|
299
|
+
return artifactVerdict(meta, info, () => bytes);
|
|
300
|
+
} catch (error) {
|
|
301
|
+
return error?.code === 'ENOENT' ? ARTIFACT_ABSENT : ARTIFACT_FOREIGN;
|
|
302
|
+
} finally {
|
|
303
|
+
try {
|
|
304
|
+
await handle?.close();
|
|
305
|
+
} catch {
|
|
306
|
+
// A failed handle close is cleanup, not a failed persist.
|
|
258
307
|
}
|
|
259
308
|
}
|
|
260
|
-
return meta;
|
|
261
309
|
}
|
|
262
310
|
|
|
263
311
|
async function persistToolResultArtifact({ sessionId, toolCallId, channel = 'result', content } = {}) {
|
|
@@ -269,32 +317,19 @@ async function persistToolResultArtifact({ sessionId, toolCallId, channel = 'res
|
|
|
269
317
|
}
|
|
270
318
|
if (!meta) return null;
|
|
271
319
|
try {
|
|
272
|
-
await
|
|
273
|
-
|
|
274
|
-
if (
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
if (!artifactShapeMatches(meta, await handle.stat())) return null;
|
|
280
|
-
if (
|
|
281
|
-
createHash('sha256')
|
|
282
|
-
.update(await handle.readFile())
|
|
283
|
-
.digest('hex') !== meta.sha256
|
|
284
|
-
)
|
|
285
|
-
return null;
|
|
286
|
-
} catch {
|
|
287
|
-
return null;
|
|
288
|
-
} finally {
|
|
289
|
-
try {
|
|
290
|
-
await handle?.close();
|
|
291
|
-
} catch {
|
|
292
|
-
// See persistToolResultArtifactSync: the verified artifact stands even
|
|
293
|
-
// when releasing the handle fails, so cleanup never nulls the result.
|
|
294
|
-
}
|
|
320
|
+
const state = await existingArtifactState(meta);
|
|
321
|
+
if (state === ARTIFACT_INTACT) return meta;
|
|
322
|
+
if (state === ARTIFACT_FOREIGN) return null;
|
|
323
|
+
// See persistToolResultArtifactSync.
|
|
324
|
+
if (state === ARTIFACT_DAMAGED) {
|
|
325
|
+
await writeFileAtomicAsync(meta.path, content, { mode: 0o600 });
|
|
326
|
+
return meta;
|
|
295
327
|
}
|
|
328
|
+
if (await writeFileAtomicAsync(meta.path, content, { mode: 0o600, createOnly: true })) return meta;
|
|
329
|
+
return (await existingArtifactState(meta)) === ARTIFACT_INTACT ? meta : null;
|
|
330
|
+
} catch {
|
|
331
|
+
return null;
|
|
296
332
|
}
|
|
297
|
-
return meta;
|
|
298
333
|
}
|
|
299
334
|
|
|
300
335
|
export async function maybeOffloadToolResult(sessionId, toolCallId, toolName, result, options = {}) {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { contextMeasurementStats } from '../../../../shared/context-measurement.mjs';
|
|
8
8
|
import { toolResultText } from './tool-result-text.mjs';
|
|
9
|
-
import {
|
|
9
|
+
import { createUserTextRestore } from './user-text.mjs';
|
|
10
10
|
import {
|
|
11
11
|
completionCardFromExecution,
|
|
12
12
|
parseModelVisibleCompletionWrapper,
|
|
@@ -86,6 +86,7 @@ function restoredTranscriptMetadata(message) {
|
|
|
86
86
|
...transcriptRouteMetadataFields(value),
|
|
87
87
|
...(typeof value.sender === 'string' && value.sender ? { sender: value.sender } : {}),
|
|
88
88
|
...(typeof value.device === 'string' && value.device ? { device: value.device } : {}),
|
|
89
|
+
...(typeof value.fromAgent === 'string' && value.fromAgent ? { fromAgent: value.fromAgent } : {}),
|
|
89
90
|
...(typeof value.checkpointId === 'string' && value.checkpointId ? { checkpointId: value.checkpointId } : {}),
|
|
90
91
|
// The attachments this prompt carried, by content hash: a restored row
|
|
91
92
|
// opens/downloads them by id from the attachment store.
|
|
@@ -112,8 +113,13 @@ function restoredTurnDoneItem(completion, metadata, nextId, finalAssistantId = '
|
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
115
|
|
|
116
|
+
// A stored message's plain text: string content as is, block content flattened.
|
|
117
|
+
function restoredContentText(message) {
|
|
118
|
+
return typeof message?.content === 'string' ? message.content : toolResultText(message?.content);
|
|
119
|
+
}
|
|
120
|
+
|
|
115
121
|
function restoredAssistantTranscriptItems(message, nextId) {
|
|
116
|
-
const text = (
|
|
122
|
+
const text = restoredContentText(message).trim();
|
|
117
123
|
if (!text) return [];
|
|
118
124
|
const { completion, ...metadata } = restoredTranscriptMetadata(message);
|
|
119
125
|
const items = [{ kind: 'assistant', id: nextId(), text, ...metadata }];
|
|
@@ -198,7 +204,7 @@ function attachRestoredToolResult(message, pendingByCallId) {
|
|
|
198
204
|
const target = callId ? pendingByCallId.get(callId) : null;
|
|
199
205
|
if (!target) return;
|
|
200
206
|
pendingByCallId.delete(callId);
|
|
201
|
-
const text = (
|
|
207
|
+
const text = restoredContentText(message) || '';
|
|
202
208
|
target.result = text;
|
|
203
209
|
assignUiDiffFromMessage(target, message);
|
|
204
210
|
assignToolMetaFromMessage(target, message);
|
|
@@ -339,7 +345,8 @@ function restoredMessageItemUpperBound(message) {
|
|
|
339
345
|
const boundaries =
|
|
340
346
|
(Array.isArray(message?.meta?.sessionInheritances) ? message.meta.sessionInheritances.length : 0) +
|
|
341
347
|
(Array.isArray(message?.meta?.modelSwitches) ? message.meta.modelSwitches.length : 0) +
|
|
342
|
-
(Array.isArray(message?.meta?.workflowSwitches) ? message.meta.workflowSwitches.length : 0)
|
|
348
|
+
(Array.isArray(message?.meta?.workflowSwitches) ? message.meta.workflowSwitches.length : 0) +
|
|
349
|
+
(Array.isArray(message?.meta?.orchestrationModeSwitches) ? message.meta.orchestrationModeSwitches.length : 0);
|
|
343
350
|
const completionCount =
|
|
344
351
|
Number(Boolean(message?.meta?.transcript?.completion)) +
|
|
345
352
|
(Array.isArray(message?.meta?.transcript?.previousCompletions)
|
|
@@ -379,7 +386,7 @@ function restoredNotificationToolItem(parsed, text, message, nextId, errorLabel)
|
|
|
379
386
|
};
|
|
380
387
|
}
|
|
381
388
|
|
|
382
|
-
function restoredUserTranscriptItems(message, nextId) {
|
|
389
|
+
function restoredUserTranscriptItems(message, nextId, userText) {
|
|
383
390
|
// Injected model-context payloads are model-visible but never user-authored:
|
|
384
391
|
// skill bodies (meta:'skill'), hook/system reminders, and tag-wrapped context
|
|
385
392
|
// blocks must not restore as user bubbles in any client.
|
|
@@ -400,10 +407,10 @@ function restoredUserTranscriptItems(message, nextId) {
|
|
|
400
407
|
}
|
|
401
408
|
// Imported prose renders verbatim: never a control row, card or display rewrite.
|
|
402
409
|
if (isImportedMessage(message)) {
|
|
403
|
-
const text = (
|
|
410
|
+
const text = restoredContentText(message).trim();
|
|
404
411
|
return text ? [{ kind: 'user', id: nextId(), text, ...restoredTranscriptMetadata(message) }] : [];
|
|
405
412
|
}
|
|
406
|
-
const text =
|
|
413
|
+
const text = userText.text(message?.content).trim();
|
|
407
414
|
// Persisted async-completion wrappers ("Async shell task ... finished. Result:
|
|
408
415
|
// > ...") are the only durable record of a background completion — the live
|
|
409
416
|
// Response card is an event-time push that does not survive a transcript
|
|
@@ -434,7 +441,7 @@ function restoredUserTranscriptItems(message, nextId) {
|
|
|
434
441
|
}
|
|
435
442
|
const synthetic = parseSyntheticAgentMessage(text);
|
|
436
443
|
if (!synthetic) {
|
|
437
|
-
const imageRefs =
|
|
444
|
+
const imageRefs = userText.imageRefs(message?.content);
|
|
438
445
|
return [
|
|
439
446
|
{
|
|
440
447
|
kind: 'user',
|
|
@@ -442,6 +449,8 @@ function restoredUserTranscriptItems(message, nextId) {
|
|
|
442
449
|
text,
|
|
443
450
|
...restoredTranscriptMetadata(message),
|
|
444
451
|
...(imageRefs.length ? { imageRefs } : {}),
|
|
452
|
+
// Read by the model inside its running turn, as the live row says.
|
|
453
|
+
...(message?.meta?.source === 'steering' ? { steered: true } : {}),
|
|
445
454
|
},
|
|
446
455
|
];
|
|
447
456
|
}
|
|
@@ -461,7 +470,9 @@ export function modelSwitchItem(id, boundary) {
|
|
|
461
470
|
};
|
|
462
471
|
}
|
|
463
472
|
|
|
464
|
-
/** The transcript row of a mid-conversation workflow switch (live and
|
|
473
|
+
/** The transcript row of a mid-conversation workflow switch (live and
|
|
474
|
+
* restored); `unavailable`: the chosen workflow was gone when it was due and
|
|
475
|
+
* the conversation kept `from`. */
|
|
465
476
|
export function workflowSwitchItem(id, boundary) {
|
|
466
477
|
return {
|
|
467
478
|
kind: 'statusdone',
|
|
@@ -470,11 +481,26 @@ export function workflowSwitchItem(id, boundary) {
|
|
|
470
481
|
label: 'Workflow switched',
|
|
471
482
|
from: boundary.from,
|
|
472
483
|
to: boundary.to,
|
|
484
|
+
...(boundary.unavailable === true ? { unavailable: true } : {}),
|
|
473
485
|
at: boundary.at,
|
|
474
486
|
};
|
|
475
487
|
}
|
|
476
488
|
|
|
477
|
-
|
|
489
|
+
/** The transcript row of a mid-conversation orchestration (delegation) mode
|
|
490
|
+
* switch (live and restored); `from`/`to` are mode ids. */
|
|
491
|
+
export function orchestrationModeSwitchItem(id, boundary) {
|
|
492
|
+
return {
|
|
493
|
+
kind: 'statusdone',
|
|
494
|
+
id,
|
|
495
|
+
status: 'orchestration-mode-switched',
|
|
496
|
+
label: 'Delegation mode switched',
|
|
497
|
+
from: boundary.from,
|
|
498
|
+
to: boundary.to,
|
|
499
|
+
at: boundary.at,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function restoreTranscriptRange(messages, start, sessionId, userText) {
|
|
478
504
|
const items = [];
|
|
479
505
|
const pendingToolCalls = new Map();
|
|
480
506
|
for (let index = start; index < messages.length; index += 1) {
|
|
@@ -490,7 +516,7 @@ function restoreTranscriptRange(messages, start, sessionId) {
|
|
|
490
516
|
continue;
|
|
491
517
|
}
|
|
492
518
|
if (message?.role === 'user') {
|
|
493
|
-
items.push(...restoredUserTranscriptItems(message, restoredId));
|
|
519
|
+
items.push(...restoredUserTranscriptItems(message, restoredId, userText));
|
|
494
520
|
} else if (message?.role === 'assistant' && !isContextAckMessage(message, messages[index - 1])) {
|
|
495
521
|
items.push(...restoredAssistantTranscriptItems(message, restoredId));
|
|
496
522
|
items.push(...restoredToolCallItems(message, restoredId, pendingToolCalls));
|
|
@@ -520,6 +546,12 @@ function restoreTranscriptRange(messages, start, sessionId) {
|
|
|
520
546
|
if (!boundary?.to) continue;
|
|
521
547
|
items.push(workflowSwitchItem(restoredId(), boundary));
|
|
522
548
|
}
|
|
549
|
+
for (const boundary of Array.isArray(message?.meta?.orchestrationModeSwitches)
|
|
550
|
+
? message.meta.orchestrationModeSwitches
|
|
551
|
+
: []) {
|
|
552
|
+
if (!boundary?.to) continue;
|
|
553
|
+
items.push(orchestrationModeSwitchItem(restoredId(), boundary));
|
|
554
|
+
}
|
|
523
555
|
if (message?.meta?.transcript?.previousCompletions?.length) {
|
|
524
556
|
const events = items.slice(eventStart);
|
|
525
557
|
if (events.every((item) => Number.isFinite(item.at))) {
|
|
@@ -533,9 +565,12 @@ function restoreTranscriptRange(messages, start, sessionId) {
|
|
|
533
565
|
|
|
534
566
|
export function restoreTranscriptItems(messages, { sessionId = 'session', itemLimit = Number.POSITIVE_INFINITY } = {}) {
|
|
535
567
|
const source = Array.isArray(messages) ? messages : [];
|
|
568
|
+
// One projection per load: a widened range reuses each prompt's parts and
|
|
569
|
+
// the paste-line reads share one budget.
|
|
570
|
+
const userText = createUserTextRestore();
|
|
536
571
|
const numericLimit = Number(itemLimit);
|
|
537
572
|
const limited = Number.isFinite(numericLimit) && numericLimit > 0;
|
|
538
|
-
if (!limited) return restoreTranscriptRange(source, 0, sessionId);
|
|
573
|
+
if (!limited) return restoreTranscriptRange(source, 0, sessionId, userText);
|
|
539
574
|
|
|
540
575
|
const limit = Math.max(1, Math.floor(numericLimit));
|
|
541
576
|
// Restore beyond the visible cap so a boundary tool run can merge exactly
|
|
@@ -549,7 +584,7 @@ export function restoreTranscriptItems(messages, { sessionId = 'session', itemLi
|
|
|
549
584
|
upperBound += restoredMessageItemUpperBound(source[start]);
|
|
550
585
|
}
|
|
551
586
|
|
|
552
|
-
let restored = restoreTranscriptRange(source, start, sessionId);
|
|
587
|
+
let restored = restoreTranscriptRange(source, start, sessionId, userText);
|
|
553
588
|
// Hidden/context messages and aggregate tool runs can make the cheap upper
|
|
554
589
|
// bound optimistic. Expand backward exponentially only when necessary.
|
|
555
590
|
let expansionTarget = Math.max(64, limit - restored.length);
|
|
@@ -559,7 +594,7 @@ export function restoreTranscriptItems(messages, { sessionId = 'session', itemLi
|
|
|
559
594
|
start -= 1;
|
|
560
595
|
expansion += restoredMessageItemUpperBound(source[start]);
|
|
561
596
|
}
|
|
562
|
-
restored = restoreTranscriptRange(source, start, sessionId);
|
|
597
|
+
restored = restoreTranscriptRange(source, start, sessionId, userText);
|
|
563
598
|
expansionTarget *= 2;
|
|
564
599
|
}
|
|
565
600
|
return restored.length > limit ? restored.slice(-limit) : restored;
|