@vellumai/assistant 0.8.8 → 0.8.9-staging.1
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/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 +236 -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 +185 -140
- 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-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -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__/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 +59 -103
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +94 -189
- package/src/__tests__/conversation-agent-loop.test.ts +249 -490
- 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-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 +18 -16
- 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 +73 -6
- 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__/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 +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -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 +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +390 -240
- 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 +83 -31
- 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 +29 -0
- 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/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-registry.json +14 -5
- package/src/config/schemas/heartbeat.ts +9 -0
- 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 +167 -1005
- 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 +383 -56
- 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 -0
- 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/plugins/defaults/compaction/manager-store.ts +44 -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 +103 -38
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +167 -56
- 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/proactive-artifact/aux-message-injector.ts +1 -1
- package/src/proactive-artifact/job.test.ts +1 -1
- 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 +283 -55
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +398 -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 +336 -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 +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- 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/{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,16 @@ 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 { createContextWindowManager } from "../plugins/defaults/compaction/manager-store.js";
|
|
67
|
+
import { repairHistory } from "../plugins/defaults/history-repair/terminal.js";
|
|
63
68
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
64
|
-
import type { Message } from "../providers/types.js";
|
|
69
|
+
import type { ContentBlock, Message } from "../providers/types.js";
|
|
65
70
|
import type { Provider } from "../providers/types.js";
|
|
66
|
-
import
|
|
71
|
+
import {
|
|
72
|
+
isUntrustedTrustClass,
|
|
73
|
+
type TrustClass,
|
|
74
|
+
} from "../runtime/actor-trust-resolver.js";
|
|
67
75
|
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
68
76
|
import type { AuthContext } from "../runtime/auth/types.js";
|
|
69
77
|
import type { InteractiveUiResult } from "../runtime/interactive-ui.js";
|
|
@@ -74,6 +82,8 @@ import type { ToolLifecycleEvent } from "../tools/types.js";
|
|
|
74
82
|
import type { OnboardingContext } from "../types/onboarding-context.js";
|
|
75
83
|
import type { AbortReason } from "../util/abort-reasons.js";
|
|
76
84
|
import { getLogger } from "../util/logger.js";
|
|
85
|
+
import type { WorkspaceGitService } from "../workspace/git-service.js";
|
|
86
|
+
import type { commitTurnChanges } from "../workspace/turn-commit.js";
|
|
77
87
|
import type { AssistantAttachmentDraft } from "./assistant-attachments.js";
|
|
78
88
|
import type { AssistantSurface } from "./conversation-agent-loop.js";
|
|
79
89
|
import {
|
|
@@ -85,7 +95,7 @@ import { undo as undoImpl } from "./conversation-history.js";
|
|
|
85
95
|
import {
|
|
86
96
|
abortConversation,
|
|
87
97
|
disposeConversation,
|
|
88
|
-
|
|
98
|
+
reinjectImageSourcePaths,
|
|
89
99
|
} from "./conversation-lifecycle.js";
|
|
90
100
|
import type {
|
|
91
101
|
EnqueueMessageOptions,
|
|
@@ -99,10 +109,7 @@ import {
|
|
|
99
109
|
} from "./conversation-messaging.js";
|
|
100
110
|
// Extracted modules
|
|
101
111
|
import { registerConversationNotifiers } from "./conversation-notifiers.js";
|
|
102
|
-
import type {
|
|
103
|
-
ProcessConversationContext,
|
|
104
|
-
ProcessMessageOptions,
|
|
105
|
-
} from "./conversation-process.js";
|
|
112
|
+
import type { ProcessMessageOptions } from "./conversation-process.js";
|
|
106
113
|
import {
|
|
107
114
|
drainQueue as drainQueueImpl,
|
|
108
115
|
processMessage as processMessageImpl,
|
|
@@ -128,7 +135,6 @@ import {
|
|
|
128
135
|
createResolveToolsCallback,
|
|
129
136
|
createToolExecutor,
|
|
130
137
|
} from "./conversation-tool-setup.js";
|
|
131
|
-
import { refreshWorkspaceTopLevelContextIfNeeded as refreshWorkspaceImpl } from "./conversation-workspace.js";
|
|
132
138
|
import { canonicalizeTimeZone } from "./date-context.js";
|
|
133
139
|
import { HostAppControlProxy } from "./host-app-control-proxy.js";
|
|
134
140
|
import { HostCuProxy } from "./host-cu-proxy.js";
|
|
@@ -139,6 +145,7 @@ import type {
|
|
|
139
145
|
SurfaceType,
|
|
140
146
|
UsageStats,
|
|
141
147
|
} from "./message-protocol.js";
|
|
148
|
+
import { filterMessagesForUntrustedActor } from "./message-provenance.js";
|
|
142
149
|
import type { ConversationTransportMetadata } from "./message-types/conversations.js";
|
|
143
150
|
import { isHostProxyTransport } from "./message-types/conversations.js";
|
|
144
151
|
import type { ConfirmationStateChanged } from "./message-types/messages.js";
|
|
@@ -201,18 +208,31 @@ export class Conversation {
|
|
|
201
208
|
/** @internal */ contextWindowManager: ContextWindowManager;
|
|
202
209
|
/** @internal */ contextCompactedMessageCount = 0;
|
|
203
210
|
/** @internal */ contextCompactedAt: number | null = null;
|
|
211
|
+
/** @internal */ contextSummary: string | null = null;
|
|
212
|
+
/** @internal */ slackContextCompactionWatermarkTs: string | null = null;
|
|
213
|
+
/** @internal */ lastNotifiedInferenceProfile: string | null = null;
|
|
204
214
|
/**
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
* stripped and never re-emits them.
|
|
215
|
+
* Per-conversation inference-profile override mirrored from the DB row.
|
|
216
|
+
* `inferenceProfileSessionId`/`inferenceProfileExpiresAt` are set when the
|
|
217
|
+
* override is session-backed (expiring); both are null for a sticky
|
|
218
|
+
* override or when no override is active. Hydrated on load and kept in sync
|
|
219
|
+
* by the HTTP setters and the background expiry reaper so the live instance
|
|
220
|
+
* is the single source of truth for the per-turn override derivation.
|
|
221
|
+
* @internal
|
|
213
222
|
*/
|
|
214
|
-
|
|
223
|
+
inferenceProfile: string | null = null;
|
|
224
|
+
/** @internal */ inferenceProfileSessionId: string | null = null;
|
|
225
|
+
/** @internal */ inferenceProfileExpiresAt: number | null = null;
|
|
215
226
|
/** @internal */ currentRequestId?: string;
|
|
227
|
+
/**
|
|
228
|
+
* The {@link LLMCallSite} of the in-flight turn, set at turn start from
|
|
229
|
+
* `options?.callSite ?? "mainAgent"`. Lets the per-turn plugin context tell
|
|
230
|
+
* the main reply apart from background agent-loop work (compaction,
|
|
231
|
+
* subagents, …) on this same conversation. Per-turn mutable, mirroring
|
|
232
|
+
* {@link currentRequestId}.
|
|
233
|
+
* @internal
|
|
234
|
+
*/
|
|
235
|
+
currentCallSite?: LLMCallSite;
|
|
216
236
|
/** @internal */ hasNoClient = false;
|
|
217
237
|
/** @internal */ isSubagent = false;
|
|
218
238
|
/** @internal */ headlessLock = false;
|
|
@@ -242,11 +262,37 @@ export class Conversation {
|
|
|
242
262
|
/** @internal */ currentTurnTrustContext?: TrustContext;
|
|
243
263
|
/** @internal */ currentTurnChannelCapabilities?: ChannelCapabilities;
|
|
244
264
|
/** @internal */ currentTurnOverrideProfile?: string;
|
|
265
|
+
/** @internal */ toolRoutedProfile?: string;
|
|
245
266
|
/** @internal */ authContext?: AuthContext;
|
|
246
267
|
/** @internal */ loadedHistoryTrustClass?: TrustClass;
|
|
247
268
|
/** @internal */ loadedHistoryPersonalMemoryAllowed?: boolean;
|
|
248
269
|
/** @internal */ voiceCallControlPrompt?: string;
|
|
249
270
|
/** @internal */ transportHints?: string[];
|
|
271
|
+
/**
|
|
272
|
+
* Optional workspace-git seams, overridable in tests to stub the git
|
|
273
|
+
* initializer and turn-commit behavior. Default to the real
|
|
274
|
+
* implementations in the agent loop when unset.
|
|
275
|
+
* @internal
|
|
276
|
+
*/
|
|
277
|
+
getWorkspaceGitService?: (
|
|
278
|
+
workspaceDir: string,
|
|
279
|
+
) => Pick<WorkspaceGitService, "ensureInitialized">;
|
|
280
|
+
/** @internal */ commitTurnChanges?: typeof commitTurnChanges;
|
|
281
|
+
/**
|
|
282
|
+
* The conversation's immutable creation type (`interactive`, `background`,
|
|
283
|
+
* `scheduled`, …) as stored on the DB row. Cached on load (and set directly
|
|
284
|
+
* for subagent conversations) so the runtime-assembly path can derive the
|
|
285
|
+
* background-turn flag from live state without a per-injection DB read.
|
|
286
|
+
* @internal
|
|
287
|
+
*/
|
|
288
|
+
conversationType?: string;
|
|
289
|
+
/**
|
|
290
|
+
* The conversation's creation source (`user`, …) as stored on the DB row,
|
|
291
|
+
* cached on load so the runtime-assembly and disk-pressure paths can read it
|
|
292
|
+
* from live state without a per-turn DB row read.
|
|
293
|
+
* @internal
|
|
294
|
+
*/
|
|
295
|
+
source?: string;
|
|
250
296
|
/** @internal */ assistantId?: string;
|
|
251
297
|
/** @internal */ commandIntent?: {
|
|
252
298
|
type: string;
|
|
@@ -340,6 +386,26 @@ export class Conversation {
|
|
|
340
386
|
*/
|
|
341
387
|
hostUsername?: string;
|
|
342
388
|
/** @internal */ clientTimezone?: string;
|
|
389
|
+
/**
|
|
390
|
+
* Per-turn temporal snapshot frozen by the agent loop and read by
|
|
391
|
+
* `applyRuntimeInjections` to build the `<turn_context>` timezone-mismatch
|
|
392
|
+
* affordance and `time_since_last_message` line. Holds the client-reported
|
|
393
|
+
* timezone captured at turn start and the human-readable gap since the
|
|
394
|
+
* previous user message (null unless it exceeds the long-absence threshold).
|
|
395
|
+
*
|
|
396
|
+
* Frozen here rather than read live in assembly so the client timezone is not
|
|
397
|
+
* clobbered when a newer message for the same conversation overwrites the
|
|
398
|
+
* live {@link clientTimezone} mid-turn (every inbound message re-applies
|
|
399
|
+
* transport metadata before it is enqueued). Its presence also gates the
|
|
400
|
+
* `<turn_context>` block: assembly emits the block only for turns the loop has
|
|
401
|
+
* frozen a snapshot for. The `current_time` value is computed fresh at each
|
|
402
|
+
* injection so post-compaction re-injections reflect the current wall clock.
|
|
403
|
+
* @internal
|
|
404
|
+
*/
|
|
405
|
+
currentTurnTemporalSnapshot?: {
|
|
406
|
+
clientTimezone: string | null;
|
|
407
|
+
timeSinceLastMessage: string | null;
|
|
408
|
+
};
|
|
343
409
|
public readonly traceEmitter: TraceEmitter;
|
|
344
410
|
/** @internal */ hasSystemPromptOverride: boolean;
|
|
345
411
|
/** @internal */ readonly graphMemory: ConversationGraphMemory;
|
|
@@ -359,6 +425,22 @@ export class Conversation {
|
|
|
359
425
|
/** @internal */ currentTurnChannelContext: TurnChannelContext | null = null;
|
|
360
426
|
/** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null =
|
|
361
427
|
null;
|
|
428
|
+
/**
|
|
429
|
+
* The conversation's recorded origin interface, cached from the DB row at
|
|
430
|
+
* load time. It is immutable once recorded, so it backs the `<turn_context>`
|
|
431
|
+
* interface fallback for turns that don't set a per-turn interface context
|
|
432
|
+
* (regenerate, wake, subagent) without a per-injection DB lookup.
|
|
433
|
+
* @internal
|
|
434
|
+
*/
|
|
435
|
+
originInterface: InterfaceId | undefined = undefined;
|
|
436
|
+
/**
|
|
437
|
+
* The conversation's recorded origin channel, cached from the DB row at load
|
|
438
|
+
* time. It is immutable once recorded, so it backs the `<turn_context>`
|
|
439
|
+
* channel fallback for turns that don't set a per-turn channel context
|
|
440
|
+
* (regenerate, wake, subagent) without a per-injection DB lookup.
|
|
441
|
+
* @internal
|
|
442
|
+
*/
|
|
443
|
+
originChannel: ChannelId | undefined = undefined;
|
|
362
444
|
/** @internal */ activityVersion = 0;
|
|
363
445
|
/** Last emitted activity state message, retained for replay on SSE reconnection. */
|
|
364
446
|
/** @internal */ lastActivityStateMsg: ServerMessage | null = null;
|
|
@@ -518,7 +600,9 @@ export class Conversation {
|
|
|
518
600
|
agentLoopConfig.maxTokens = configuredMaxTokens;
|
|
519
601
|
}
|
|
520
602
|
|
|
521
|
-
this.agentLoop = new AgentLoop(
|
|
603
|
+
this.agentLoop = new AgentLoop({
|
|
604
|
+
provider,
|
|
605
|
+
systemPrompt,
|
|
522
606
|
conversationId: this.conversationId,
|
|
523
607
|
config: agentLoopConfig,
|
|
524
608
|
tools: toolDefs.length > 0 ? toolDefs : undefined,
|
|
@@ -526,7 +610,7 @@ export class Conversation {
|
|
|
526
610
|
resolveTools,
|
|
527
611
|
resolveSystemPrompt: resolveSystemPromptCallback,
|
|
528
612
|
});
|
|
529
|
-
this.contextWindowManager =
|
|
613
|
+
this.contextWindowManager = createContextWindowManager({
|
|
530
614
|
provider,
|
|
531
615
|
systemPrompt: () => resolveSystemPromptCallback([]).systemPrompt,
|
|
532
616
|
config: initialContextWindowConfig,
|
|
@@ -548,6 +632,22 @@ export class Conversation {
|
|
|
548
632
|
return this.onboardingContext;
|
|
549
633
|
}
|
|
550
634
|
|
|
635
|
+
/**
|
|
636
|
+
* Mirror an inference-profile override write onto the live instance so the
|
|
637
|
+
* per-turn override derivation reads current state without re-fetching the
|
|
638
|
+
* DB row. Called alongside the corresponding DB write by the HTTP setters
|
|
639
|
+
* and the background expiry reaper.
|
|
640
|
+
*/
|
|
641
|
+
applyInferenceProfileState(state: {
|
|
642
|
+
profile: string | null;
|
|
643
|
+
sessionId: string | null;
|
|
644
|
+
expiresAt: number | null;
|
|
645
|
+
}): void {
|
|
646
|
+
this.inferenceProfile = state.profile;
|
|
647
|
+
this.inferenceProfileSessionId = state.sessionId;
|
|
648
|
+
this.inferenceProfileExpiresAt = state.expiresAt;
|
|
649
|
+
}
|
|
650
|
+
|
|
551
651
|
// ── Prompt Cache Warming ─────────────────────────────────────────
|
|
552
652
|
|
|
553
653
|
/**
|
|
@@ -605,7 +705,250 @@ export class Conversation {
|
|
|
605
705
|
// ── Lifecycle ────────────────────────────────────────────────────
|
|
606
706
|
|
|
607
707
|
async loadFromDb(): Promise<void> {
|
|
608
|
-
|
|
708
|
+
const trustClass = this.trustContext?.trustClass;
|
|
709
|
+
const allDbMessages = getMessages(this.conversationId);
|
|
710
|
+
const dbMessages = isUntrustedTrustClass(trustClass)
|
|
711
|
+
? filterMessagesForUntrustedActor(allDbMessages)
|
|
712
|
+
: allDbMessages;
|
|
713
|
+
|
|
714
|
+
const conv = getConversation(this.conversationId);
|
|
715
|
+
this.conversationType = conv?.conversationType ?? undefined;
|
|
716
|
+
this.originInterface = parseInterfaceId(conv?.originInterface) ?? undefined;
|
|
717
|
+
this.originChannel = parseChannelId(conv?.originChannel) ?? undefined;
|
|
718
|
+
this.source = conv?.source ?? undefined;
|
|
719
|
+
this.contextSummary = conv?.contextSummary ?? null;
|
|
720
|
+
this.slackContextCompactionWatermarkTs =
|
|
721
|
+
conv?.slackContextCompactionWatermarkTs ?? null;
|
|
722
|
+
this.lastNotifiedInferenceProfile =
|
|
723
|
+
conv?.lastNotifiedInferenceProfile ?? null;
|
|
724
|
+
this.inferenceProfile = conv?.inferenceProfile ?? null;
|
|
725
|
+
this.inferenceProfileSessionId = conv?.inferenceProfileSessionId ?? null;
|
|
726
|
+
this.inferenceProfileExpiresAt = conv?.inferenceProfileExpiresAt ?? null;
|
|
727
|
+
this.contextCompactedMessageCount = Math.max(
|
|
728
|
+
0,
|
|
729
|
+
conv?.contextCompactedMessageCount ?? 0,
|
|
730
|
+
);
|
|
731
|
+
this.contextCompactedAt = conv?.contextCompactedAt ?? null;
|
|
732
|
+
|
|
733
|
+
// Untrusted actor views never receive summary-based compaction: a
|
|
734
|
+
// compacted summary can embed trusted/guardian-only detail, so the
|
|
735
|
+
// summary message is suppressed and the persisted history is rendered
|
|
736
|
+
// unsliced. The slice boundary is clamped so it can never drop more rows
|
|
737
|
+
// than exist. Slack chronological context is a separate consumer that
|
|
738
|
+
// applies its own trust filtering downstream, so it reads the raw
|
|
739
|
+
// mirrored count rather than this in-context boundary.
|
|
740
|
+
const inContextCompactedCount = isUntrustedTrustClass(trustClass)
|
|
741
|
+
? 0
|
|
742
|
+
: Math.min(this.contextCompactedMessageCount, dbMessages.length);
|
|
743
|
+
const contextSummaryForHistory = isUntrustedTrustClass(trustClass)
|
|
744
|
+
? null
|
|
745
|
+
: this.contextSummary?.trim() || null;
|
|
746
|
+
|
|
747
|
+
// Every injection-strip event (`/clean` or compaction) updates
|
|
748
|
+
// `historyStrippedAt`. Messages older than this should skip metadata
|
|
749
|
+
// rehydration and have any injection prefixes still embedded in their
|
|
750
|
+
// content stripped, so the post-strip view survives reload and forks.
|
|
751
|
+
const historyStrippedAt = conv?.historyStrippedAt ?? null;
|
|
752
|
+
const slicedDbMessages = dbMessages.slice(inContextCompactedCount);
|
|
753
|
+
let preStrippedCount = 0;
|
|
754
|
+
if (historyStrippedAt != null) {
|
|
755
|
+
const boundary = slicedDbMessages.findIndex(
|
|
756
|
+
(m) => m.createdAt >= historyStrippedAt,
|
|
757
|
+
);
|
|
758
|
+
preStrippedCount = boundary === -1 ? slicedDbMessages.length : boundary;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Mirror the injection-time gate (`shouldExposePersonalMemory` in
|
|
762
|
+
// `conversation-agent-loop.ts`) so background/local conversations
|
|
763
|
+
// (sourceChannel `undefined` or `"vellum"`) can rehydrate the persisted
|
|
764
|
+
// v2 static memory block. Use `resolveTrustClass` for parity with the
|
|
765
|
+
// agent loop — it folds in the HTTP-auth-disabled dev bypass so
|
|
766
|
+
// rehydration and injection agree on the effective trust class.
|
|
767
|
+
const personalMemoryAllowed = shouldExposePersonalMemory({
|
|
768
|
+
sourceChannel: this.trustContext?.sourceChannel,
|
|
769
|
+
isTrustedActor: resolveTrustClass(this.trustContext) === "guardian",
|
|
770
|
+
});
|
|
771
|
+
const parsedMessages: Message[] = slicedDbMessages.map((m, index, arr) => {
|
|
772
|
+
const isPreStripped = index < preStrippedCount;
|
|
773
|
+
const role = m.role as "user" | "assistant";
|
|
774
|
+
let content: ContentBlock[];
|
|
775
|
+
try {
|
|
776
|
+
const parsed = JSON.parse(m.content);
|
|
777
|
+
content = Array.isArray(parsed)
|
|
778
|
+
? parsed
|
|
779
|
+
: [{ type: "text", text: m.content }];
|
|
780
|
+
} catch {
|
|
781
|
+
log.warn(
|
|
782
|
+
{ conversationId: this.conversationId, messageId: m.id },
|
|
783
|
+
"Invalid JSON in persisted message content, replacing with safe text block",
|
|
784
|
+
);
|
|
785
|
+
content = [{ type: "text", text: m.content }];
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
content = reinjectImageSourcePaths(content, role, m.metadata);
|
|
789
|
+
|
|
790
|
+
// Re-inject persisted injection blocks from metadata so it survives
|
|
791
|
+
// conversation reloads (eviction, restart, fork).
|
|
792
|
+
if (role === "user" && m.metadata && !isPreStripped) {
|
|
793
|
+
try {
|
|
794
|
+
const meta = JSON.parse(m.metadata);
|
|
795
|
+
const isTail = index === arr.length - 1;
|
|
796
|
+
|
|
797
|
+
// Rehydrate in reverse injection order (innermost block first)
|
|
798
|
+
// so the resulting layout matches `applyRuntimeInjections`'s
|
|
799
|
+
// after-memory-prefix splices in ascending injector order
|
|
800
|
+
// (pkb-context 30, pkb-reminder 35, memory-v2-static 38,
|
|
801
|
+
// now-md 40 — the v2 static block lands inside the memory
|
|
802
|
+
// prefix, so now-md splices *after* it):
|
|
803
|
+
// [<workspace>, <turn_context>, <memory>dynamic</memory>,
|
|
804
|
+
// <info>v2static</info>, <NOW.md>, <system_reminder>,
|
|
805
|
+
// <knowledge_base>, ...original]
|
|
806
|
+
// The v2 static block is replayed verbatim from stored metadata,
|
|
807
|
+
// so rows may carry either `<info>…</info>` or `<memory>…</memory>`
|
|
808
|
+
// depending on when they were persisted.
|
|
809
|
+
// Required so Anthropic's prefix cache keeps matching msg[0]
|
|
810
|
+
// across daemon restart and conversation eviction. The tail
|
|
811
|
+
// row only rehydrates `memoryInjectedBlock` — the next turn
|
|
812
|
+
// re-injects the rest fresh.
|
|
813
|
+
if (!isTail && typeof meta.pkbContextBlock === "string") {
|
|
814
|
+
content = [
|
|
815
|
+
{ type: "text" as const, text: meta.pkbContextBlock },
|
|
816
|
+
...content,
|
|
817
|
+
];
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
if (!isTail && typeof meta.pkbSystemReminderBlock === "string") {
|
|
821
|
+
content = [
|
|
822
|
+
{ type: "text" as const, text: meta.pkbSystemReminderBlock },
|
|
823
|
+
...content,
|
|
824
|
+
];
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (!isTail && typeof meta.nowScratchpadBlock === "string") {
|
|
828
|
+
content = [
|
|
829
|
+
{ type: "text" as const, text: meta.nowScratchpadBlock },
|
|
830
|
+
...content,
|
|
831
|
+
];
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// The v2 static memory block (essentials/threads/recent/buffer
|
|
835
|
+
// wrapped in either `<info>…</info>` or `<memory>…</memory>`)
|
|
836
|
+
// carries personal user memory. Trust-gated to mirror
|
|
837
|
+
// `shouldExposePersonalMemory` at injection time — untrusted-actor
|
|
838
|
+
// views must not read persisted personal memory back through
|
|
839
|
+
// metadata. Skipped on the tail row because the next turn
|
|
840
|
+
// re-injects fresh content on full-mode turns.
|
|
841
|
+
if (
|
|
842
|
+
!isTail &&
|
|
843
|
+
personalMemoryAllowed &&
|
|
844
|
+
typeof meta.memoryV2StaticBlock === "string"
|
|
845
|
+
) {
|
|
846
|
+
content = [
|
|
847
|
+
{ type: "text" as const, text: meta.memoryV2StaticBlock },
|
|
848
|
+
...content,
|
|
849
|
+
];
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// Memory remains rehydrated on all rows (existing behavior).
|
|
853
|
+
// Strip any pre-existing wrapper before re-wrapping so historical
|
|
854
|
+
// rows persisted with the wrapper (v2 path before the
|
|
855
|
+
// injectedBlockText contract was unified with v1's unwrapped form)
|
|
856
|
+
// don't render double-wrapped after rehydrate. Only unwrap when
|
|
857
|
+
// the full <memory>...</memory> pair is present so we don't mutate
|
|
858
|
+
// legitimate unwrapped payloads that happen to start with
|
|
859
|
+
// "<memory>\n" or end with "\n</memory>".
|
|
860
|
+
if (typeof meta.memoryInjectedBlock === "string") {
|
|
861
|
+
const block = meta.memoryInjectedBlock;
|
|
862
|
+
const inner =
|
|
863
|
+
block.startsWith("<memory>\n") && block.endsWith("\n</memory>")
|
|
864
|
+
? block.slice("<memory>\n".length, -"\n</memory>".length)
|
|
865
|
+
: block;
|
|
866
|
+
content = [
|
|
867
|
+
{
|
|
868
|
+
type: "text" as const,
|
|
869
|
+
text: `<memory>\n${inner}\n</memory>`,
|
|
870
|
+
},
|
|
871
|
+
...content,
|
|
872
|
+
];
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
if (!isTail && typeof meta.turnContextBlock === "string") {
|
|
876
|
+
content = [
|
|
877
|
+
{ type: "text" as const, text: meta.turnContextBlock },
|
|
878
|
+
...content,
|
|
879
|
+
];
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if (!isTail && typeof meta.workspaceBlock === "string") {
|
|
883
|
+
content = [
|
|
884
|
+
{ type: "text" as const, text: meta.workspaceBlock },
|
|
885
|
+
...content,
|
|
886
|
+
];
|
|
887
|
+
}
|
|
888
|
+
} catch {
|
|
889
|
+
/* ignore parse errors — metadata may be malformed */
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
return { role, content };
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
// Strip pre-clean messages only; post-clean messages keep the fresh
|
|
897
|
+
// injections they were generated with.
|
|
898
|
+
const messagesBeforeRepair =
|
|
899
|
+
preStrippedCount === 0
|
|
900
|
+
? parsedMessages
|
|
901
|
+
: [
|
|
902
|
+
...stripInjectionsForCompaction(
|
|
903
|
+
parsedMessages.slice(0, preStrippedCount),
|
|
904
|
+
),
|
|
905
|
+
...parsedMessages.slice(preStrippedCount),
|
|
906
|
+
];
|
|
907
|
+
|
|
908
|
+
// Normalize the canonical persisted history once at load. Every consumer
|
|
909
|
+
// of `this.messages` outside the agent loop (history edit/undo, PKB context
|
|
910
|
+
// tracking, surfaces) reads this list directly, so it must satisfy the
|
|
911
|
+
// provider pairing/alternation rules before any of them run. The agent
|
|
912
|
+
// loop's pre-run repair only repairs the transient per-turn message list it
|
|
913
|
+
// sends to the provider and never writes back here, so this pass is not
|
|
914
|
+
// redundant with it.
|
|
915
|
+
const { messages: repairedMessages, stats } =
|
|
916
|
+
repairHistory(messagesBeforeRepair);
|
|
917
|
+
if (
|
|
918
|
+
stats.assistantToolResultsMigrated > 0 ||
|
|
919
|
+
stats.missingToolResultsInserted > 0 ||
|
|
920
|
+
stats.orphanToolResultsDowngraded > 0 ||
|
|
921
|
+
stats.consecutiveSameRoleMerged > 0
|
|
922
|
+
) {
|
|
923
|
+
log.warn(
|
|
924
|
+
{ conversationId: this.conversationId, phase: "load", ...stats },
|
|
925
|
+
"Repaired persisted history",
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
this.messages = repairedMessages;
|
|
929
|
+
|
|
930
|
+
if (contextSummaryForHistory) {
|
|
931
|
+
this.messages.unshift(
|
|
932
|
+
createContextSummaryMessage(contextSummaryForHistory),
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if (conv) {
|
|
937
|
+
this.usageStats = {
|
|
938
|
+
inputTokens: conv.totalInputTokens,
|
|
939
|
+
outputTokens: conv.totalOutputTokens,
|
|
940
|
+
estimatedCost: conv.totalEstimatedCost,
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
this.loadedHistoryTrustClass = trustClass;
|
|
945
|
+
this.loadedHistoryPersonalMemoryAllowed = personalMemoryAllowed;
|
|
946
|
+
|
|
947
|
+
log.info(
|
|
948
|
+
{ conversationId: this.conversationId, count: this.messages.length },
|
|
949
|
+
"Loaded messages from DB",
|
|
950
|
+
);
|
|
951
|
+
|
|
609
952
|
this.restoreSurfaceStateFromHistory();
|
|
610
953
|
this.graphMemory.restoreState();
|
|
611
954
|
}
|
|
@@ -719,9 +1062,7 @@ export class Conversation {
|
|
|
719
1062
|
);
|
|
720
1063
|
}
|
|
721
1064
|
this.messages = [...messages];
|
|
722
|
-
this.contextWindowManager.
|
|
723
|
-
this.contextWindowManager.summaryIsInjected =
|
|
724
|
-
getSummaryFromContextMessage(messages[0]) != null;
|
|
1065
|
+
this.contextWindowManager.seedNonPersistedPrefix(messages.length);
|
|
725
1066
|
}
|
|
726
1067
|
|
|
727
1068
|
/**
|
|
@@ -1045,20 +1386,14 @@ export class Conversation {
|
|
|
1045
1386
|
}
|
|
1046
1387
|
|
|
1047
1388
|
async forceCompact(): Promise<ContextWindowResult> {
|
|
1048
|
-
const
|
|
1049
|
-
const overrideProfile =
|
|
1050
|
-
getConversationOverrideProfileFromRow(conversationRow) ?? null;
|
|
1389
|
+
const overrideProfile = resolveOverrideProfile(this) ?? null;
|
|
1051
1390
|
const config = getConfig();
|
|
1052
1391
|
const effectiveContextWindow = resolveEffectiveContextWindow({
|
|
1053
1392
|
llm: config.llm,
|
|
1054
1393
|
callSite: "mainAgent",
|
|
1055
1394
|
overrideProfile: overrideProfile ?? undefined,
|
|
1056
1395
|
});
|
|
1057
|
-
(
|
|
1058
|
-
this.contextWindowManager as ContextWindowManager & {
|
|
1059
|
-
updateConfig?: (config: ContextWindowConfig) => void;
|
|
1060
|
-
}
|
|
1061
|
-
).updateConfig?.(
|
|
1396
|
+
this.contextWindowManager.updateConfig(
|
|
1062
1397
|
contextWindowConfigFromEffective(
|
|
1063
1398
|
resolveCallSiteConfig("mainAgent", config.llm, {
|
|
1064
1399
|
overrideProfile: overrideProfile ?? undefined,
|
|
@@ -1073,25 +1408,23 @@ export class Conversation {
|
|
|
1073
1408
|
this.channelCapabilities,
|
|
1074
1409
|
{
|
|
1075
1410
|
trustClass: this.trustContext?.trustClass,
|
|
1076
|
-
contextSummary:
|
|
1077
|
-
contextCompactedMessageCount:
|
|
1078
|
-
conversationRow?.contextCompactedMessageCount,
|
|
1411
|
+
contextSummary: this.contextSummary,
|
|
1412
|
+
contextCompactedMessageCount: this.contextCompactedMessageCount,
|
|
1079
1413
|
slackContextCompactionWatermarkTs:
|
|
1080
|
-
|
|
1414
|
+
this.slackContextCompactionWatermarkTs,
|
|
1081
1415
|
},
|
|
1082
1416
|
)
|
|
1083
1417
|
: null;
|
|
1084
1418
|
const messagesToCompact =
|
|
1085
1419
|
slackChronologicalContext?.messages ?? this.messages;
|
|
1086
|
-
const result = await
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
);
|
|
1420
|
+
const result = await defaultCompact({
|
|
1421
|
+
manager: this.contextWindowManager,
|
|
1422
|
+
messages: messagesToCompact,
|
|
1423
|
+
signal: this.abortController?.signal ?? undefined,
|
|
1424
|
+
force: true,
|
|
1425
|
+
overrideProfile,
|
|
1426
|
+
actorTrustClass: this.trustContext?.trustClass,
|
|
1427
|
+
});
|
|
1095
1428
|
// Track circuit-breaker state for user-initiated `/compact` and other
|
|
1096
1429
|
// forced paths so a successful forced compaction clears a stuck counter
|
|
1097
1430
|
// and a run of forced failures still trips the breaker. `summaryFailed`
|
|
@@ -1099,7 +1432,6 @@ export class Conversation {
|
|
|
1099
1432
|
// etc.) — skip those so they don't silently reset the counter.
|
|
1100
1433
|
if (result.summaryFailed !== undefined) {
|
|
1101
1434
|
await this.agentLoop.compactionCircuit.recordOutcome(
|
|
1102
|
-
this,
|
|
1103
1435
|
result.summaryFailed,
|
|
1104
1436
|
this.sendToClient,
|
|
1105
1437
|
);
|
|
@@ -1128,7 +1460,6 @@ export class Conversation {
|
|
|
1128
1460
|
const stripped = stripInjectionsForCompaction(this.messages);
|
|
1129
1461
|
this.messages = stripped;
|
|
1130
1462
|
await this.graphMemory.onCompacted(0);
|
|
1131
|
-
this.pendingPostCompactReinject = true;
|
|
1132
1463
|
setConversationHistoryStrippedAt(this.conversationId, Date.now());
|
|
1133
1464
|
const estimatedInputTokens = this.contextWindowManager.estimateInputTokens(
|
|
1134
1465
|
this.messages,
|
|
@@ -1308,13 +1639,13 @@ export class Conversation {
|
|
|
1308
1639
|
}
|
|
1309
1640
|
|
|
1310
1641
|
drainQueue(reason: QueueDrainReason = "loop_complete"): Promise<void> {
|
|
1311
|
-
return drainQueueImpl(this
|
|
1642
|
+
return drainQueueImpl(this, reason);
|
|
1312
1643
|
}
|
|
1313
1644
|
|
|
1314
1645
|
async processMessage(options: ProcessMessageOptions): Promise<string> {
|
|
1315
1646
|
this.cacheWarmAbort?.abort();
|
|
1316
1647
|
this.cacheWarmAbort = undefined;
|
|
1317
|
-
return processMessageImpl(this
|
|
1648
|
+
return processMessageImpl(this, {
|
|
1318
1649
|
...options,
|
|
1319
1650
|
onEvent: options.onEvent ?? this.sendToClient,
|
|
1320
1651
|
});
|
|
@@ -1346,10 +1677,6 @@ export class Conversation {
|
|
|
1346
1677
|
|
|
1347
1678
|
// ── Workspace ────────────────────────────────────────────────────
|
|
1348
1679
|
|
|
1349
|
-
refreshWorkspaceTopLevelContextIfNeeded(): void {
|
|
1350
|
-
refreshWorkspaceImpl(this);
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
1680
|
markWorkspaceTopLevelDirty(): void {
|
|
1354
1681
|
this.workspaceTopLevelDirty = true;
|
|
1355
1682
|
}
|