@vellumai/assistant 0.8.8 → 0.8.9-staging.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/ARCHITECTURE.md +6 -6
- package/bun.lock +2 -2
- package/examples/plugins/echo/README.md +61 -60
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +235 -6
- package/package.json +2 -2
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
- package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
- package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
- package/src/__tests__/agent-loop-thinking.test.ts +36 -20
- package/src/__tests__/agent-loop.test.ts +441 -96
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
- package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
- package/src/__tests__/anthropic-provider.test.ts +1 -1
- package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +132 -0
- package/src/__tests__/approval-cascade.test.ts +5 -4
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction-events.test.ts +5 -5
- package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
- package/src/__tests__/context-overflow-reducer.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -4
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +142 -218
- package/src/__tests__/conversation-agent-loop.test.ts +297 -586
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -4
- package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -4
- package/src/__tests__/conversation-process-callsite.test.ts +14 -14
- package/src/__tests__/conversation-provider-retry-repair.test.ts +70 -65
- package/src/__tests__/conversation-queue.test.ts +9 -9
- package/src/__tests__/conversation-runtime-assembly.test.ts +923 -231
- package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
- package/src/__tests__/conversation-slash-queue.test.ts +6 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -4
- package/src/__tests__/conversation-speed-override.test.ts +10 -9
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-workspace-cache-state.test.ts +23 -20
- package/src/__tests__/conversation-workspace-injection.test.ts +68 -6
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +14 -11
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -1
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/inference-profile-reaper.test.ts +62 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
- package/src/__tests__/injector-background-turn.test.ts +13 -23
- package/src/__tests__/injector-chain.test.ts +268 -44
- package/src/__tests__/injector-disk-pressure.test.ts +210 -52
- package/src/__tests__/injector-document-comments.test.ts +97 -114
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-v3-suppression.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +131 -26
- package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
- package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
- package/src/__tests__/plugin-api-shim.test.ts +6 -9
- package/src/__tests__/plugin-bootstrap.test.ts +12 -23
- package/src/__tests__/plugin-registry.test.ts +3 -49
- package/src/__tests__/plugin-types.test.ts +0 -70
- package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/steer-tool-repair.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-detail.test.ts +25 -7
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +1 -1
- package/src/__tests__/tool-error-hook.test.ts +1 -1
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +280 -0
- package/src/acp/auto-install.ts +232 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +80 -27
- package/src/acp/resolve-agent.test.ts +225 -9
- package/src/acp/resolve-agent.ts +122 -17
- package/src/acp/resume-hint.ts +23 -0
- package/src/acp/session-manager.ts +507 -73
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +414 -248
- package/src/api/responses/conversation-message.ts +14 -1
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
- package/src/cli/commands/plugins.ts +43 -37
- package/src/cli/lib/__tests__/install-from-github.test.ts +429 -111
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +372 -0
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +220 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +226 -32
- package/src/cli/lib/install-from-github.ts +464 -55
- package/src/cli/lib/plugin-catalog-cache.ts +84 -0
- package/src/cli/lib/plugin-details.ts +409 -0
- package/src/cli/lib/plugin-marketplace.ts +197 -0
- package/src/cli/lib/search-plugins.ts +195 -29
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/bundled-skills/acp/SKILL.md +85 -33
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
- package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +4 -0
- package/src/config/call-site-defaults.ts +0 -2
- package/src/config/feature-flag-registry.json +15 -6
- package/src/config/schemas/call-site-catalog.ts +0 -14
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +0 -2
- package/src/context/compactor.ts +22 -4
- package/src/context/strip-injections.ts +8 -2
- package/src/context/window-manager.ts +27 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +10 -35
- package/src/daemon/conversation-agent-loop.ts +175 -1055
- package/src/daemon/conversation-lifecycle.ts +11 -255
- package/src/daemon/conversation-process.ts +8 -136
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +293 -392
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +24 -8
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +404 -57
- package/src/daemon/disk-pressure-policy.ts +0 -1
- package/src/daemon/external-plugins-bootstrap.ts +14 -19
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-proxy-preactivation.ts +1 -3
- package/src/daemon/lifecycle.ts +21 -7
- package/src/daemon/server.ts +2 -0
- package/src/daemon/wake-conversation-ops.ts +269 -0
- package/src/embedded/plugin-api.ts +2 -2
- package/src/export/__tests__/transcript-formatter.test.ts +5 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
- package/src/memory/conversation-crud.ts +29 -19
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/db-init.ts +2 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
- package/src/memory/jobs-worker.ts +25 -1
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
- package/src/memory/v2/consolidation-job.ts +13 -4
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +6 -5
- package/src/plugin-api/types.ts +75 -0
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +7 -7
- package/src/plugins/defaults/compaction/manager-store.ts +57 -0
- package/src/plugins/defaults/compaction/package.json +1 -2
- package/src/plugins/defaults/empty-response/package.json +0 -1
- package/src/plugins/defaults/history-repair/package.json +0 -1
- package/src/plugins/defaults/index.ts +135 -26
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +184 -74
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +9 -6
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +8 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +10 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +16 -17
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +9 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +5 -2
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +15 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/provider-blocks.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +7 -3
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +7 -7
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +32 -94
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +1 -1
- package/src/plugins/defaults/title-generate/package.json +0 -1
- package/src/plugins/defaults/tool-error/package.json +0 -1
- package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
- package/src/plugins/pipeline.ts +6 -293
- package/src/plugins/registry.ts +9 -37
- package/src/plugins/types.ts +76 -381
- package/src/plugins/user-loader.ts +30 -127
- package/src/prompts/__tests__/system-prompt.test.ts +6 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +35 -3
- package/src/runtime/__tests__/agent-wake.test.ts +555 -691
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +108 -209
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +315 -55
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +28 -2
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +18 -3
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
- package/src/runtime/routes/memory-v3-routes.ts +16 -6
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +337 -35
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/signals/cancel.ts +2 -4
- package/src/subagent/manager.ts +21 -5
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +8 -2
- package/src/tools/acp/spawn.test.ts +176 -195
- package/src/tools/acp/spawn.ts +37 -172
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +166 -50
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/ui-surface/definitions.ts +25 -5
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
- package/docs/plugins.md +0 -832
- package/examples/plugins/echo/register.ts +0 -143
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
- package/src/__tests__/pipeline-runner.test.ts +0 -554
- package/src/__tests__/plugin-external-api.test.ts +0 -68
- package/src/daemon/wake-target-adapter.ts +0 -253
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/register.ts +0 -35
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/register.ts +0 -23
- package/src/plugins/defaults/history-repair/register.ts +0 -24
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/title-generate/register.ts +0 -35
- package/src/plugins/defaults/tool-error/register.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
- package/src/plugins/external-api.ts +0 -104
- package/src/proactive-artifact/aux-message-injector.ts +0 -97
- package/src/proactive-artifact/decision.test.ts +0 -226
- package/src/proactive-artifact/decision.ts +0 -165
- package/src/proactive-artifact/index.ts +0 -7
- package/src/proactive-artifact/job.test.ts +0 -962
- package/src/proactive-artifact/job.ts +0 -372
- package/src/proactive-artifact/message-copy.ts +0 -58
- package/src/proactive-artifact/trigger-state.test.ts +0 -286
- package/src/proactive-artifact/trigger-state.ts +0 -123
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/provider-blocks.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -19,10 +19,12 @@ import type { AgentLoopConfig, ResolvedSystemPrompt } from "../agent/loop.js";
|
|
|
19
19
|
import { AgentLoop } from "../agent/loop.js";
|
|
20
20
|
import type { AssistantActivityStateEvent } from "../api/events/assistant-activity-state.js";
|
|
21
21
|
import type {
|
|
22
|
+
ChannelId,
|
|
22
23
|
InterfaceId,
|
|
23
24
|
TurnChannelContext,
|
|
24
25
|
TurnInterfaceContext,
|
|
25
26
|
} from "../channels/types.js";
|
|
27
|
+
import { parseChannelId, parseInterfaceId } from "../channels/types.js";
|
|
26
28
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
27
29
|
import {
|
|
28
30
|
contextWindowConfigFromEffective,
|
|
@@ -31,11 +33,10 @@ import {
|
|
|
31
33
|
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
32
34
|
import { getConfig } from "../config/loader.js";
|
|
33
35
|
import type { LLMCallSite, Speed } from "../config/schemas/llm.js";
|
|
34
|
-
import type { ContextWindowConfig } from "../config/types.js";
|
|
35
36
|
import {
|
|
36
|
-
ContextWindowManager,
|
|
37
|
+
type ContextWindowManager,
|
|
37
38
|
type ContextWindowResult,
|
|
38
|
-
|
|
39
|
+
createContextSummaryMessage,
|
|
39
40
|
} from "../context/window-manager.js";
|
|
40
41
|
import type { CesClient } from "../credential-execution/client.js";
|
|
41
42
|
import { EventBus } from "../events/bus.js";
|
|
@@ -52,7 +53,8 @@ import { registerToolTraceListener } from "../events/tool-trace-listener.js";
|
|
|
52
53
|
import { resolveCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
|
|
53
54
|
import {
|
|
54
55
|
getConversation,
|
|
55
|
-
|
|
56
|
+
getMessages,
|
|
57
|
+
resolveOverrideProfile,
|
|
56
58
|
setConversationHistoryStrippedAt,
|
|
57
59
|
} from "../memory/conversation-crud.js";
|
|
58
60
|
import { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
|
|
@@ -60,10 +62,19 @@ import { shouldExposePersonalMemory } from "../memory/v2/static-context.js";
|
|
|
60
62
|
import { PermissionPrompter } from "../permissions/prompter.js";
|
|
61
63
|
import { SecretPrompter } from "../permissions/secret-prompter.js";
|
|
62
64
|
import type { UserDecision } from "../permissions/types.js";
|
|
65
|
+
import { defaultCompact } from "../plugins/defaults/compaction/compact.js";
|
|
66
|
+
import {
|
|
67
|
+
createContextWindowManager,
|
|
68
|
+
getContextWindowManager,
|
|
69
|
+
} from "../plugins/defaults/compaction/manager-store.js";
|
|
70
|
+
import { repairHistory } from "../plugins/defaults/history-repair/terminal.js";
|
|
63
71
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
64
|
-
import type { Message } from "../providers/types.js";
|
|
72
|
+
import type { ContentBlock, Message } from "../providers/types.js";
|
|
65
73
|
import type { Provider } from "../providers/types.js";
|
|
66
|
-
import
|
|
74
|
+
import {
|
|
75
|
+
isUntrustedTrustClass,
|
|
76
|
+
type TrustClass,
|
|
77
|
+
} from "../runtime/actor-trust-resolver.js";
|
|
67
78
|
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
68
79
|
import type { AuthContext } from "../runtime/auth/types.js";
|
|
69
80
|
import type { InteractiveUiResult } from "../runtime/interactive-ui.js";
|
|
@@ -74,6 +85,8 @@ import type { ToolLifecycleEvent } from "../tools/types.js";
|
|
|
74
85
|
import type { OnboardingContext } from "../types/onboarding-context.js";
|
|
75
86
|
import type { AbortReason } from "../util/abort-reasons.js";
|
|
76
87
|
import { getLogger } from "../util/logger.js";
|
|
88
|
+
import type { WorkspaceGitService } from "../workspace/git-service.js";
|
|
89
|
+
import type { commitTurnChanges } from "../workspace/turn-commit.js";
|
|
77
90
|
import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
|
|
78
91
|
import type { AssistantSurface } from "./conversation-agent-loop.js";
|
|
79
92
|
import {
|
|
@@ -85,7 +98,7 @@ import { undo as undoImpl } from "./conversation-history.js";
|
|
|
85
98
|
import {
|
|
86
99
|
abortConversation,
|
|
87
100
|
disposeConversation,
|
|
88
|
-
|
|
101
|
+
reinjectImageSourcePaths,
|
|
89
102
|
} from "./conversation-lifecycle.js";
|
|
90
103
|
import type {
|
|
91
104
|
EnqueueMessageOptions,
|
|
@@ -99,10 +112,7 @@ import {
|
|
|
99
112
|
} from "./conversation-messaging.js";
|
|
100
113
|
// Extracted modules
|
|
101
114
|
import { registerConversationNotifiers } from "./conversation-notifiers.js";
|
|
102
|
-
import type {
|
|
103
|
-
ProcessConversationContext,
|
|
104
|
-
ProcessMessageOptions,
|
|
105
|
-
} from "./conversation-process.js";
|
|
115
|
+
import type { ProcessMessageOptions } from "./conversation-process.js";
|
|
106
116
|
import {
|
|
107
117
|
drainQueue as drainQueueImpl,
|
|
108
118
|
processMessage as processMessageImpl,
|
|
@@ -128,7 +138,6 @@ import {
|
|
|
128
138
|
createResolveToolsCallback,
|
|
129
139
|
createToolExecutor,
|
|
130
140
|
} from "./conversation-tool-setup.js";
|
|
131
|
-
import { refreshWorkspaceTopLevelContextIfNeeded as refreshWorkspaceImpl } from "./conversation-workspace.js";
|
|
132
141
|
import { canonicalizeTimeZone } from "./date-context.js";
|
|
133
142
|
import { HostAppControlProxy } from "./host-app-control-proxy.js";
|
|
134
143
|
import { HostCuProxy } from "./host-cu-proxy.js";
|
|
@@ -139,6 +148,7 @@ import type {
|
|
|
139
148
|
SurfaceType,
|
|
140
149
|
UsageStats,
|
|
141
150
|
} from "./message-protocol.js";
|
|
151
|
+
import { filterMessagesForUntrustedActor } from "./message-provenance.js";
|
|
142
152
|
import type { ConversationTransportMetadata } from "./message-types/conversations.js";
|
|
143
153
|
import { isHostProxyTransport } from "./message-types/conversations.js";
|
|
144
154
|
import type { ConfirmationStateChanged } from "./message-types/messages.js";
|
|
@@ -198,21 +208,33 @@ export class Conversation {
|
|
|
198
208
|
estimatedCost: 0,
|
|
199
209
|
};
|
|
200
210
|
/** @internal */ readonly systemPrompt: string;
|
|
201
|
-
/** @internal */ contextWindowManager: ContextWindowManager;
|
|
202
211
|
/** @internal */ contextCompactedMessageCount = 0;
|
|
203
212
|
/** @internal */ contextCompactedAt: number | null = null;
|
|
213
|
+
/** @internal */ contextSummary: string | null = null;
|
|
214
|
+
/** @internal */ slackContextCompactionWatermarkTs: string | null = null;
|
|
215
|
+
/** @internal */ lastNotifiedInferenceProfile: string | null = null;
|
|
204
216
|
/**
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* stripped and never re-emits them.
|
|
217
|
+
* Per-conversation inference-profile override mirrored from the DB row.
|
|
218
|
+
* `inferenceProfileSessionId`/`inferenceProfileExpiresAt` are set when the
|
|
219
|
+
* override is session-backed (expiring); both are null for a sticky
|
|
220
|
+
* override or when no override is active. Hydrated on load and kept in sync
|
|
221
|
+
* by the HTTP setters and the background expiry reaper so the live instance
|
|
222
|
+
* is the single source of truth for the per-turn override derivation.
|
|
223
|
+
* @internal
|
|
213
224
|
*/
|
|
214
|
-
|
|
225
|
+
inferenceProfile: string | null = null;
|
|
226
|
+
/** @internal */ inferenceProfileSessionId: string | null = null;
|
|
227
|
+
/** @internal */ inferenceProfileExpiresAt: number | null = null;
|
|
215
228
|
/** @internal */ currentRequestId?: string;
|
|
229
|
+
/**
|
|
230
|
+
* The {@link LLMCallSite} of the in-flight turn, set at turn start from
|
|
231
|
+
* `options?.callSite ?? "mainAgent"`. Lets the per-turn plugin context tell
|
|
232
|
+
* the main reply apart from background agent-loop work (compaction,
|
|
233
|
+
* subagents, …) on this same conversation. Per-turn mutable, mirroring
|
|
234
|
+
* {@link currentRequestId}.
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
currentCallSite?: LLMCallSite;
|
|
216
238
|
/** @internal */ hasNoClient = false;
|
|
217
239
|
/** @internal */ isSubagent = false;
|
|
218
240
|
/** @internal */ headlessLock = false;
|
|
@@ -242,11 +264,37 @@ export class Conversation {
|
|
|
242
264
|
/** @internal */ currentTurnTrustContext?: TrustContext;
|
|
243
265
|
/** @internal */ currentTurnChannelCapabilities?: ChannelCapabilities;
|
|
244
266
|
/** @internal */ currentTurnOverrideProfile?: string;
|
|
267
|
+
/** @internal */ toolRoutedProfile?: string;
|
|
245
268
|
/** @internal */ authContext?: AuthContext;
|
|
246
269
|
/** @internal */ loadedHistoryTrustClass?: TrustClass;
|
|
247
270
|
/** @internal */ loadedHistoryPersonalMemoryAllowed?: boolean;
|
|
248
271
|
/** @internal */ voiceCallControlPrompt?: string;
|
|
249
272
|
/** @internal */ transportHints?: string[];
|
|
273
|
+
/**
|
|
274
|
+
* Optional workspace-git seams, overridable in tests to stub the git
|
|
275
|
+
* initializer and turn-commit behavior. Default to the real
|
|
276
|
+
* implementations in the agent loop when unset.
|
|
277
|
+
* @internal
|
|
278
|
+
*/
|
|
279
|
+
getWorkspaceGitService?: (
|
|
280
|
+
workspaceDir: string,
|
|
281
|
+
) => Pick<WorkspaceGitService, "ensureInitialized">;
|
|
282
|
+
/** @internal */ commitTurnChanges?: typeof commitTurnChanges;
|
|
283
|
+
/**
|
|
284
|
+
* The conversation's immutable creation type (`interactive`, `background`,
|
|
285
|
+
* `scheduled`, …) as stored on the DB row. Cached on load (and set directly
|
|
286
|
+
* for subagent conversations) so the runtime-assembly path can derive the
|
|
287
|
+
* background-turn flag from live state without a per-injection DB read.
|
|
288
|
+
* @internal
|
|
289
|
+
*/
|
|
290
|
+
conversationType?: string;
|
|
291
|
+
/**
|
|
292
|
+
* The conversation's creation source (`user`, …) as stored on the DB row,
|
|
293
|
+
* cached on load so the runtime-assembly and disk-pressure paths can read it
|
|
294
|
+
* from live state without a per-turn DB row read.
|
|
295
|
+
* @internal
|
|
296
|
+
*/
|
|
297
|
+
source?: string;
|
|
250
298
|
/** @internal */ assistantId?: string;
|
|
251
299
|
/** @internal */ commandIntent?: {
|
|
252
300
|
type: string;
|
|
@@ -340,6 +388,26 @@ export class Conversation {
|
|
|
340
388
|
*/
|
|
341
389
|
hostUsername?: string;
|
|
342
390
|
/** @internal */ clientTimezone?: string;
|
|
391
|
+
/**
|
|
392
|
+
* Per-turn temporal snapshot frozen by the agent loop and read by
|
|
393
|
+
* `applyRuntimeInjections` to build the `<turn_context>` timezone-mismatch
|
|
394
|
+
* affordance and `time_since_last_message` line. Holds the client-reported
|
|
395
|
+
* timezone captured at turn start and the human-readable gap since the
|
|
396
|
+
* previous user message (null unless it exceeds the long-absence threshold).
|
|
397
|
+
*
|
|
398
|
+
* Frozen here rather than read live in assembly so the client timezone is not
|
|
399
|
+
* clobbered when a newer message for the same conversation overwrites the
|
|
400
|
+
* live {@link clientTimezone} mid-turn (every inbound message re-applies
|
|
401
|
+
* transport metadata before it is enqueued). Its presence also gates the
|
|
402
|
+
* `<turn_context>` block: assembly emits the block only for turns the loop has
|
|
403
|
+
* frozen a snapshot for. The `current_time` value is computed fresh at each
|
|
404
|
+
* injection so post-compaction re-injections reflect the current wall clock.
|
|
405
|
+
* @internal
|
|
406
|
+
*/
|
|
407
|
+
currentTurnTemporalSnapshot?: {
|
|
408
|
+
clientTimezone: string | null;
|
|
409
|
+
timeSinceLastMessage: string | null;
|
|
410
|
+
};
|
|
343
411
|
public readonly traceEmitter: TraceEmitter;
|
|
344
412
|
/** @internal */ hasSystemPromptOverride: boolean;
|
|
345
413
|
/** @internal */ readonly graphMemory: ConversationGraphMemory;
|
|
@@ -359,6 +427,22 @@ export class Conversation {
|
|
|
359
427
|
/** @internal */ currentTurnChannelContext: TurnChannelContext | null = null;
|
|
360
428
|
/** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null =
|
|
361
429
|
null;
|
|
430
|
+
/**
|
|
431
|
+
* The conversation's recorded origin interface, cached from the DB row at
|
|
432
|
+
* load time. It is immutable once recorded, so it backs the `<turn_context>`
|
|
433
|
+
* interface fallback for turns that don't set a per-turn interface context
|
|
434
|
+
* (regenerate, wake, subagent) without a per-injection DB lookup.
|
|
435
|
+
* @internal
|
|
436
|
+
*/
|
|
437
|
+
originInterface: InterfaceId | undefined = undefined;
|
|
438
|
+
/**
|
|
439
|
+
* The conversation's recorded origin channel, cached from the DB row at load
|
|
440
|
+
* time. It is immutable once recorded, so it backs the `<turn_context>`
|
|
441
|
+
* channel fallback for turns that don't set a per-turn channel context
|
|
442
|
+
* (regenerate, wake, subagent) without a per-injection DB lookup.
|
|
443
|
+
* @internal
|
|
444
|
+
*/
|
|
445
|
+
originChannel: ChannelId | undefined = undefined;
|
|
362
446
|
/** @internal */ activityVersion = 0;
|
|
363
447
|
/** Last emitted activity state message, retained for replay on SSE reconnection. */
|
|
364
448
|
/** @internal */ lastActivityStateMsg: ServerMessage | null = null;
|
|
@@ -518,7 +602,9 @@ export class Conversation {
|
|
|
518
602
|
agentLoopConfig.maxTokens = configuredMaxTokens;
|
|
519
603
|
}
|
|
520
604
|
|
|
521
|
-
this.agentLoop = new AgentLoop(
|
|
605
|
+
this.agentLoop = new AgentLoop({
|
|
606
|
+
provider,
|
|
607
|
+
systemPrompt,
|
|
522
608
|
conversationId: this.conversationId,
|
|
523
609
|
config: agentLoopConfig,
|
|
524
610
|
tools: toolDefs.length > 0 ? toolDefs : undefined,
|
|
@@ -526,7 +612,7 @@ export class Conversation {
|
|
|
526
612
|
resolveTools,
|
|
527
613
|
resolveSystemPrompt: resolveSystemPromptCallback,
|
|
528
614
|
});
|
|
529
|
-
|
|
615
|
+
createContextWindowManager({
|
|
530
616
|
provider,
|
|
531
617
|
systemPrompt: () => resolveSystemPromptCallback([]).systemPrompt,
|
|
532
618
|
config: initialContextWindowConfig,
|
|
@@ -538,6 +624,24 @@ export class Conversation {
|
|
|
538
624
|
});
|
|
539
625
|
}
|
|
540
626
|
|
|
627
|
+
/**
|
|
628
|
+
* The conversation's {@link ContextWindowManager}, owned by the compaction
|
|
629
|
+
* module's per-conversation store. The constructor registers it there; this
|
|
630
|
+
* accessor resolves it on demand so the conversation holds no separate
|
|
631
|
+
* handle. Present for the conversation's whole in-memory lifetime (registered
|
|
632
|
+
* at construction, released on teardown), so a live conversation always
|
|
633
|
+
* resolves an instance.
|
|
634
|
+
*/
|
|
635
|
+
/** @internal */ get contextWindowManager(): ContextWindowManager {
|
|
636
|
+
const manager = getContextWindowManager(this.conversationId);
|
|
637
|
+
if (manager == null) {
|
|
638
|
+
throw new Error(
|
|
639
|
+
`ContextWindowManager missing for conversation ${this.conversationId} — the compaction store entry was released while the conversation is still live`,
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
return manager;
|
|
643
|
+
}
|
|
644
|
+
|
|
541
645
|
// ── Onboarding context ───────────────────────────────────────────
|
|
542
646
|
|
|
543
647
|
setOnboardingContext(ctx: OnboardingContext): void {
|
|
@@ -548,6 +652,22 @@ export class Conversation {
|
|
|
548
652
|
return this.onboardingContext;
|
|
549
653
|
}
|
|
550
654
|
|
|
655
|
+
/**
|
|
656
|
+
* Mirror an inference-profile override write onto the live instance so the
|
|
657
|
+
* per-turn override derivation reads current state without re-fetching the
|
|
658
|
+
* DB row. Called alongside the corresponding DB write by the HTTP setters
|
|
659
|
+
* and the background expiry reaper.
|
|
660
|
+
*/
|
|
661
|
+
applyInferenceProfileState(state: {
|
|
662
|
+
profile: string | null;
|
|
663
|
+
sessionId: string | null;
|
|
664
|
+
expiresAt: number | null;
|
|
665
|
+
}): void {
|
|
666
|
+
this.inferenceProfile = state.profile;
|
|
667
|
+
this.inferenceProfileSessionId = state.sessionId;
|
|
668
|
+
this.inferenceProfileExpiresAt = state.expiresAt;
|
|
669
|
+
}
|
|
670
|
+
|
|
551
671
|
// ── Prompt Cache Warming ─────────────────────────────────────────
|
|
552
672
|
|
|
553
673
|
/**
|
|
@@ -605,7 +725,250 @@ export class Conversation {
|
|
|
605
725
|
// ── Lifecycle ────────────────────────────────────────────────────
|
|
606
726
|
|
|
607
727
|
async loadFromDb(): Promise<void> {
|
|
608
|
-
|
|
728
|
+
const trustClass = this.trustContext?.trustClass;
|
|
729
|
+
const allDbMessages = getMessages(this.conversationId);
|
|
730
|
+
const dbMessages = isUntrustedTrustClass(trustClass)
|
|
731
|
+
? filterMessagesForUntrustedActor(allDbMessages)
|
|
732
|
+
: allDbMessages;
|
|
733
|
+
|
|
734
|
+
const conv = getConversation(this.conversationId);
|
|
735
|
+
this.conversationType = conv?.conversationType ?? undefined;
|
|
736
|
+
this.originInterface = parseInterfaceId(conv?.originInterface) ?? undefined;
|
|
737
|
+
this.originChannel = parseChannelId(conv?.originChannel) ?? undefined;
|
|
738
|
+
this.source = conv?.source ?? undefined;
|
|
739
|
+
this.contextSummary = conv?.contextSummary ?? null;
|
|
740
|
+
this.slackContextCompactionWatermarkTs =
|
|
741
|
+
conv?.slackContextCompactionWatermarkTs ?? null;
|
|
742
|
+
this.lastNotifiedInferenceProfile =
|
|
743
|
+
conv?.lastNotifiedInferenceProfile ?? null;
|
|
744
|
+
this.inferenceProfile = conv?.inferenceProfile ?? null;
|
|
745
|
+
this.inferenceProfileSessionId = conv?.inferenceProfileSessionId ?? null;
|
|
746
|
+
this.inferenceProfileExpiresAt = conv?.inferenceProfileExpiresAt ?? null;
|
|
747
|
+
this.contextCompactedMessageCount = Math.max(
|
|
748
|
+
0,
|
|
749
|
+
conv?.contextCompactedMessageCount ?? 0,
|
|
750
|
+
);
|
|
751
|
+
this.contextCompactedAt = conv?.contextCompactedAt ?? null;
|
|
752
|
+
|
|
753
|
+
// Untrusted actor views never receive summary-based compaction: a
|
|
754
|
+
// compacted summary can embed trusted/guardian-only detail, so the
|
|
755
|
+
// summary message is suppressed and the persisted history is rendered
|
|
756
|
+
// unsliced. The slice boundary is clamped so it can never drop more rows
|
|
757
|
+
// than exist. Slack chronological context is a separate consumer that
|
|
758
|
+
// applies its own trust filtering downstream, so it reads the raw
|
|
759
|
+
// mirrored count rather than this in-context boundary.
|
|
760
|
+
const inContextCompactedCount = isUntrustedTrustClass(trustClass)
|
|
761
|
+
? 0
|
|
762
|
+
: Math.min(this.contextCompactedMessageCount, dbMessages.length);
|
|
763
|
+
const contextSummaryForHistory = isUntrustedTrustClass(trustClass)
|
|
764
|
+
? null
|
|
765
|
+
: this.contextSummary?.trim() || null;
|
|
766
|
+
|
|
767
|
+
// Every injection-strip event (`/clean` or compaction) updates
|
|
768
|
+
// `historyStrippedAt`. Messages older than this should skip metadata
|
|
769
|
+
// rehydration and have any injection prefixes still embedded in their
|
|
770
|
+
// content stripped, so the post-strip view survives reload and forks.
|
|
771
|
+
const historyStrippedAt = conv?.historyStrippedAt ?? null;
|
|
772
|
+
const slicedDbMessages = dbMessages.slice(inContextCompactedCount);
|
|
773
|
+
let preStrippedCount = 0;
|
|
774
|
+
if (historyStrippedAt != null) {
|
|
775
|
+
const boundary = slicedDbMessages.findIndex(
|
|
776
|
+
(m) => m.createdAt >= historyStrippedAt,
|
|
777
|
+
);
|
|
778
|
+
preStrippedCount = boundary === -1 ? slicedDbMessages.length : boundary;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// Mirror the injection-time gate (`shouldExposePersonalMemory` in
|
|
782
|
+
// `conversation-agent-loop.ts`) so background/local conversations
|
|
783
|
+
// (sourceChannel `undefined` or `"vellum"`) can rehydrate the persisted
|
|
784
|
+
// v2 static memory block. Use `resolveTrustClass` for parity with the
|
|
785
|
+
// agent loop — it folds in the HTTP-auth-disabled dev bypass so
|
|
786
|
+
// rehydration and injection agree on the effective trust class.
|
|
787
|
+
const personalMemoryAllowed = shouldExposePersonalMemory({
|
|
788
|
+
sourceChannel: this.trustContext?.sourceChannel,
|
|
789
|
+
isTrustedActor: resolveTrustClass(this.trustContext) === "guardian",
|
|
790
|
+
});
|
|
791
|
+
const parsedMessages: Message[] = slicedDbMessages.map((m, index, arr) => {
|
|
792
|
+
const isPreStripped = index < preStrippedCount;
|
|
793
|
+
const role = m.role as "user" | "assistant";
|
|
794
|
+
let content: ContentBlock[];
|
|
795
|
+
try {
|
|
796
|
+
const parsed = JSON.parse(m.content);
|
|
797
|
+
content = Array.isArray(parsed)
|
|
798
|
+
? parsed
|
|
799
|
+
: [{ type: "text", text: m.content }];
|
|
800
|
+
} catch {
|
|
801
|
+
log.warn(
|
|
802
|
+
{ conversationId: this.conversationId, messageId: m.id },
|
|
803
|
+
"Invalid JSON in persisted message content, replacing with safe text block",
|
|
804
|
+
);
|
|
805
|
+
content = [{ type: "text", text: m.content }];
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
content = reinjectImageSourcePaths(content, role, m.metadata);
|
|
809
|
+
|
|
810
|
+
// Re-inject persisted injection blocks from metadata so it survives
|
|
811
|
+
// conversation reloads (eviction, restart, fork).
|
|
812
|
+
if (role === "user" && m.metadata && !isPreStripped) {
|
|
813
|
+
try {
|
|
814
|
+
const meta = JSON.parse(m.metadata);
|
|
815
|
+
const isTail = index === arr.length - 1;
|
|
816
|
+
|
|
817
|
+
// Rehydrate in reverse injection order (innermost block first)
|
|
818
|
+
// so the resulting layout matches `applyRuntimeInjections`'s
|
|
819
|
+
// after-memory-prefix splices in ascending injector order
|
|
820
|
+
// (pkb-context 30, pkb-reminder 35, memory-v2-static 38,
|
|
821
|
+
// now-md 40 — the v2 static block lands inside the memory
|
|
822
|
+
// prefix, so now-md splices *after* it):
|
|
823
|
+
// [<workspace>, <turn_context>, <memory>dynamic</memory>,
|
|
824
|
+
// <info>v2static</info>, <NOW.md>, <system_reminder>,
|
|
825
|
+
// <knowledge_base>, ...original]
|
|
826
|
+
// The v2 static block is replayed verbatim from stored metadata,
|
|
827
|
+
// so rows may carry either `<info>…</info>` or `<memory>…</memory>`
|
|
828
|
+
// depending on when they were persisted.
|
|
829
|
+
// Required so Anthropic's prefix cache keeps matching msg[0]
|
|
830
|
+
// across daemon restart and conversation eviction. The tail
|
|
831
|
+
// row only rehydrates `memoryInjectedBlock` — the next turn
|
|
832
|
+
// re-injects the rest fresh.
|
|
833
|
+
if (!isTail && typeof meta.pkbContextBlock === "string") {
|
|
834
|
+
content = [
|
|
835
|
+
{ type: "text" as const, text: meta.pkbContextBlock },
|
|
836
|
+
...content,
|
|
837
|
+
];
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
if (!isTail && typeof meta.pkbSystemReminderBlock === "string") {
|
|
841
|
+
content = [
|
|
842
|
+
{ type: "text" as const, text: meta.pkbSystemReminderBlock },
|
|
843
|
+
...content,
|
|
844
|
+
];
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (!isTail && typeof meta.nowScratchpadBlock === "string") {
|
|
848
|
+
content = [
|
|
849
|
+
{ type: "text" as const, text: meta.nowScratchpadBlock },
|
|
850
|
+
...content,
|
|
851
|
+
];
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// The v2 static memory block (essentials/threads/recent/buffer
|
|
855
|
+
// wrapped in either `<info>…</info>` or `<memory>…</memory>`)
|
|
856
|
+
// carries personal user memory. Trust-gated to mirror
|
|
857
|
+
// `shouldExposePersonalMemory` at injection time — untrusted-actor
|
|
858
|
+
// views must not read persisted personal memory back through
|
|
859
|
+
// metadata. Skipped on the tail row because the next turn
|
|
860
|
+
// re-injects fresh content on full-mode turns.
|
|
861
|
+
if (
|
|
862
|
+
!isTail &&
|
|
863
|
+
personalMemoryAllowed &&
|
|
864
|
+
typeof meta.memoryV2StaticBlock === "string"
|
|
865
|
+
) {
|
|
866
|
+
content = [
|
|
867
|
+
{ type: "text" as const, text: meta.memoryV2StaticBlock },
|
|
868
|
+
...content,
|
|
869
|
+
];
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// Memory remains rehydrated on all rows (existing behavior).
|
|
873
|
+
// Strip any pre-existing wrapper before re-wrapping so historical
|
|
874
|
+
// rows persisted with the wrapper (v2 path before the
|
|
875
|
+
// injectedBlockText contract was unified with v1's unwrapped form)
|
|
876
|
+
// don't render double-wrapped after rehydrate. Only unwrap when
|
|
877
|
+
// the full <memory>...</memory> pair is present so we don't mutate
|
|
878
|
+
// legitimate unwrapped payloads that happen to start with
|
|
879
|
+
// "<memory>\n" or end with "\n</memory>".
|
|
880
|
+
if (typeof meta.memoryInjectedBlock === "string") {
|
|
881
|
+
const block = meta.memoryInjectedBlock;
|
|
882
|
+
const inner =
|
|
883
|
+
block.startsWith("<memory>\n") && block.endsWith("\n</memory>")
|
|
884
|
+
? block.slice("<memory>\n".length, -"\n</memory>".length)
|
|
885
|
+
: block;
|
|
886
|
+
content = [
|
|
887
|
+
{
|
|
888
|
+
type: "text" as const,
|
|
889
|
+
text: `<memory>\n${inner}\n</memory>`,
|
|
890
|
+
},
|
|
891
|
+
...content,
|
|
892
|
+
];
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
if (!isTail && typeof meta.turnContextBlock === "string") {
|
|
896
|
+
content = [
|
|
897
|
+
{ type: "text" as const, text: meta.turnContextBlock },
|
|
898
|
+
...content,
|
|
899
|
+
];
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
if (!isTail && typeof meta.workspaceBlock === "string") {
|
|
903
|
+
content = [
|
|
904
|
+
{ type: "text" as const, text: meta.workspaceBlock },
|
|
905
|
+
...content,
|
|
906
|
+
];
|
|
907
|
+
}
|
|
908
|
+
} catch {
|
|
909
|
+
/* ignore parse errors — metadata may be malformed */
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return { role, content };
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
// Strip pre-clean messages only; post-clean messages keep the fresh
|
|
917
|
+
// injections they were generated with.
|
|
918
|
+
const messagesBeforeRepair =
|
|
919
|
+
preStrippedCount === 0
|
|
920
|
+
? parsedMessages
|
|
921
|
+
: [
|
|
922
|
+
...stripInjectionsForCompaction(
|
|
923
|
+
parsedMessages.slice(0, preStrippedCount),
|
|
924
|
+
),
|
|
925
|
+
...parsedMessages.slice(preStrippedCount),
|
|
926
|
+
];
|
|
927
|
+
|
|
928
|
+
// Normalize the canonical persisted history once at load. Every consumer
|
|
929
|
+
// of `this.messages` outside the agent loop (history edit/undo, PKB context
|
|
930
|
+
// tracking, surfaces) reads this list directly, so it must satisfy the
|
|
931
|
+
// provider pairing/alternation rules before any of them run. The agent
|
|
932
|
+
// loop's pre-run repair only repairs the transient per-turn message list it
|
|
933
|
+
// sends to the provider and never writes back here, so this pass is not
|
|
934
|
+
// redundant with it.
|
|
935
|
+
const { messages: repairedMessages, stats } =
|
|
936
|
+
repairHistory(messagesBeforeRepair);
|
|
937
|
+
if (
|
|
938
|
+
stats.assistantToolResultsMigrated > 0 ||
|
|
939
|
+
stats.missingToolResultsInserted > 0 ||
|
|
940
|
+
stats.orphanToolResultsDowngraded > 0 ||
|
|
941
|
+
stats.consecutiveSameRoleMerged > 0
|
|
942
|
+
) {
|
|
943
|
+
log.warn(
|
|
944
|
+
{ conversationId: this.conversationId, phase: "load", ...stats },
|
|
945
|
+
"Repaired persisted history",
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
this.messages = repairedMessages;
|
|
949
|
+
|
|
950
|
+
if (contextSummaryForHistory) {
|
|
951
|
+
this.messages.unshift(
|
|
952
|
+
createContextSummaryMessage(contextSummaryForHistory),
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
if (conv) {
|
|
957
|
+
this.usageStats = {
|
|
958
|
+
inputTokens: conv.totalInputTokens,
|
|
959
|
+
outputTokens: conv.totalOutputTokens,
|
|
960
|
+
estimatedCost: conv.totalEstimatedCost,
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
this.loadedHistoryTrustClass = trustClass;
|
|
965
|
+
this.loadedHistoryPersonalMemoryAllowed = personalMemoryAllowed;
|
|
966
|
+
|
|
967
|
+
log.info(
|
|
968
|
+
{ conversationId: this.conversationId, count: this.messages.length },
|
|
969
|
+
"Loaded messages from DB",
|
|
970
|
+
);
|
|
971
|
+
|
|
609
972
|
this.restoreSurfaceStateFromHistory();
|
|
610
973
|
this.graphMemory.restoreState();
|
|
611
974
|
}
|
|
@@ -719,9 +1082,7 @@ export class Conversation {
|
|
|
719
1082
|
);
|
|
720
1083
|
}
|
|
721
1084
|
this.messages = [...messages];
|
|
722
|
-
this.contextWindowManager.
|
|
723
|
-
this.contextWindowManager.summaryIsInjected =
|
|
724
|
-
getSummaryFromContextMessage(messages[0]) != null;
|
|
1085
|
+
this.contextWindowManager.seedNonPersistedPrefix(messages.length);
|
|
725
1086
|
}
|
|
726
1087
|
|
|
727
1088
|
/**
|
|
@@ -1045,20 +1406,14 @@ export class Conversation {
|
|
|
1045
1406
|
}
|
|
1046
1407
|
|
|
1047
1408
|
async forceCompact(): Promise<ContextWindowResult> {
|
|
1048
|
-
const
|
|
1049
|
-
const overrideProfile =
|
|
1050
|
-
getConversationOverrideProfileFromRow(conversationRow) ?? null;
|
|
1409
|
+
const overrideProfile = resolveOverrideProfile(this) ?? null;
|
|
1051
1410
|
const config = getConfig();
|
|
1052
1411
|
const effectiveContextWindow = resolveEffectiveContextWindow({
|
|
1053
1412
|
llm: config.llm,
|
|
1054
1413
|
callSite: "mainAgent",
|
|
1055
1414
|
overrideProfile: overrideProfile ?? undefined,
|
|
1056
1415
|
});
|
|
1057
|
-
(
|
|
1058
|
-
this.contextWindowManager as ContextWindowManager & {
|
|
1059
|
-
updateConfig?: (config: ContextWindowConfig) => void;
|
|
1060
|
-
}
|
|
1061
|
-
).updateConfig?.(
|
|
1416
|
+
this.contextWindowManager.updateConfig(
|
|
1062
1417
|
contextWindowConfigFromEffective(
|
|
1063
1418
|
resolveCallSiteConfig("mainAgent", config.llm, {
|
|
1064
1419
|
overrideProfile: overrideProfile ?? undefined,
|
|
@@ -1073,25 +1428,23 @@ export class Conversation {
|
|
|
1073
1428
|
this.channelCapabilities,
|
|
1074
1429
|
{
|
|
1075
1430
|
trustClass: this.trustContext?.trustClass,
|
|
1076
|
-
contextSummary:
|
|
1077
|
-
contextCompactedMessageCount:
|
|
1078
|
-
conversationRow?.contextCompactedMessageCount,
|
|
1431
|
+
contextSummary: this.contextSummary,
|
|
1432
|
+
contextCompactedMessageCount: this.contextCompactedMessageCount,
|
|
1079
1433
|
slackContextCompactionWatermarkTs:
|
|
1080
|
-
|
|
1434
|
+
this.slackContextCompactionWatermarkTs,
|
|
1081
1435
|
},
|
|
1082
1436
|
)
|
|
1083
1437
|
: null;
|
|
1084
1438
|
const messagesToCompact =
|
|
1085
1439
|
slackChronologicalContext?.messages ?? this.messages;
|
|
1086
|
-
const result = await
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
);
|
|
1440
|
+
const result = await defaultCompact({
|
|
1441
|
+
manager: this.contextWindowManager,
|
|
1442
|
+
messages: messagesToCompact,
|
|
1443
|
+
signal: this.abortController?.signal ?? undefined,
|
|
1444
|
+
force: true,
|
|
1445
|
+
overrideProfile,
|
|
1446
|
+
actorTrustClass: this.trustContext?.trustClass,
|
|
1447
|
+
});
|
|
1095
1448
|
// Track circuit-breaker state for user-initiated `/compact` and other
|
|
1096
1449
|
// forced paths so a successful forced compaction clears a stuck counter
|
|
1097
1450
|
// and a run of forced failures still trips the breaker. `summaryFailed`
|
|
@@ -1099,7 +1452,6 @@ export class Conversation {
|
|
|
1099
1452
|
// etc.) — skip those so they don't silently reset the counter.
|
|
1100
1453
|
if (result.summaryFailed !== undefined) {
|
|
1101
1454
|
await this.agentLoop.compactionCircuit.recordOutcome(
|
|
1102
|
-
this,
|
|
1103
1455
|
result.summaryFailed,
|
|
1104
1456
|
this.sendToClient,
|
|
1105
1457
|
);
|
|
@@ -1128,7 +1480,6 @@ export class Conversation {
|
|
|
1128
1480
|
const stripped = stripInjectionsForCompaction(this.messages);
|
|
1129
1481
|
this.messages = stripped;
|
|
1130
1482
|
await this.graphMemory.onCompacted(0);
|
|
1131
|
-
this.pendingPostCompactReinject = true;
|
|
1132
1483
|
setConversationHistoryStrippedAt(this.conversationId, Date.now());
|
|
1133
1484
|
const estimatedInputTokens = this.contextWindowManager.estimateInputTokens(
|
|
1134
1485
|
this.messages,
|
|
@@ -1308,13 +1659,13 @@ export class Conversation {
|
|
|
1308
1659
|
}
|
|
1309
1660
|
|
|
1310
1661
|
drainQueue(reason: QueueDrainReason = "loop_complete"): Promise<void> {
|
|
1311
|
-
return drainQueueImpl(this
|
|
1662
|
+
return drainQueueImpl(this, reason);
|
|
1312
1663
|
}
|
|
1313
1664
|
|
|
1314
1665
|
async processMessage(options: ProcessMessageOptions): Promise<string> {
|
|
1315
1666
|
this.cacheWarmAbort?.abort();
|
|
1316
1667
|
this.cacheWarmAbort = undefined;
|
|
1317
|
-
return processMessageImpl(this
|
|
1668
|
+
return processMessageImpl(this, {
|
|
1318
1669
|
...options,
|
|
1319
1670
|
onEvent: options.onEvent ?? this.sendToClient,
|
|
1320
1671
|
});
|
|
@@ -1346,10 +1697,6 @@ export class Conversation {
|
|
|
1346
1697
|
|
|
1347
1698
|
// ── Workspace ────────────────────────────────────────────────────
|
|
1348
1699
|
|
|
1349
|
-
refreshWorkspaceTopLevelContextIfNeeded(): void {
|
|
1350
|
-
refreshWorkspaceImpl(this);
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
1700
|
markWorkspaceTopLevelDirty(): void {
|
|
1354
1701
|
this.workspaceTopLevelDirty = true;
|
|
1355
1702
|
}
|