@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea
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/Dockerfile +20 -4
- package/bun.lock +2 -2
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/examples/plugins/echo/README.md +61 -66
- 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/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +3378 -335
- package/package.json +2 -2
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- 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-routes-http.test.ts +4 -1
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.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__/clawhub-files.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.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
- package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
- package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
- package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- 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__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -0
- 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__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-api-shim.test.ts +3 -6
- package/src/__tests__/plugin-bootstrap.test.ts +14 -40
- package/src/__tests__/plugin-registry.test.ts +3 -76
- package/src/__tests__/plugin-types.test.ts +0 -193
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- 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__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -0
- 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 +362 -485
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- 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/assistant-feature-flags.ts +22 -11
- 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 -398
- 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/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -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-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +48 -7
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +5 -7
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
- package/src/daemon/conversation-agent-loop.ts +301 -997
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +218 -398
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +32 -20
- package/src/daemon/external-plugins-bootstrap.ts +17 -18
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +42 -10
- package/src/daemon/lifecycle.ts +25 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/server.ts +2 -0
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- 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/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.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/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +32 -5
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
- package/src/memory/v2/consolidation-job.ts +14 -5
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +7 -5
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +8 -19
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +2 -18
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
- 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__/health.test.ts +16 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
- 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 +48 -12
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- 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 +104 -32
- 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 +96 -30
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- 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/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
- package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- 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 +51 -45
- 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 +61 -46
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +6 -305
- package/src/plugins/registry.ts +10 -55
- package/src/plugins/types.ts +62 -797
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +4 -4
- package/src/proactive-artifact/job.test.ts +8 -13
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +10 -6
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +2 -5
- package/src/runtime/assistant-event-hub.ts +37 -7
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- 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/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- 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 +3 -1
- package/src/runtime/routes/conversation-routes.ts +372 -185
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- 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-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +224 -18
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +66 -34
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/signals/cancel.ts +2 -4
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/subagent/manager.ts +17 -5
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- 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/executor.ts +1 -53
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +34 -5
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/docs/plugins.md +0 -836
- package/examples/plugins/echo/register.ts +0 -184
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- 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__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/pipeline-runner.test.ts +0 -564
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/memory/v3/provider-blocks.ts +0 -16
- 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/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- 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/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
- /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__/needle.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__/types.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}/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
|
@@ -1,35 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Default `compaction` plugin.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (defaults load first in `bootstrapPlugins()`), which puts it at the
|
|
10
|
-
* OUTERMOST position of the onion chain. If the default middleware were to
|
|
11
|
-
* invoke the terminal directly without calling `next`, it would shadow every
|
|
12
|
-
* later-registered plugin. Routing through `next(args)` lets user middleware
|
|
13
|
-
* participate normally.
|
|
14
|
-
*
|
|
15
|
-
* Design doc: `.private/plans/agent-plugin-system.md` (PR 25).
|
|
4
|
+
* Compaction is implemented in `./compact.ts` as {@link defaultCompact}, which
|
|
5
|
+
* the agent loop calls directly with a {@link CompactionContext}. The plugin
|
|
6
|
+
* stays registered as a placeholder so it keeps a presence in the defaults
|
|
7
|
+
* list while we decide how plugins should surface compaction; it contributes
|
|
8
|
+
* no contract slot today.
|
|
16
9
|
*/
|
|
17
10
|
|
|
18
11
|
import { type Plugin } from "../../types.js";
|
|
19
|
-
import defaultCompactionMiddleware from "./middlewares/compaction.js";
|
|
20
12
|
import pkg from "./package.json" with { type: "json" };
|
|
21
13
|
|
|
22
14
|
/**
|
|
23
|
-
* Manifest
|
|
24
|
-
*
|
|
25
|
-
*
|
|
15
|
+
* Manifest for the default compaction plugin. The registration happens in
|
|
16
|
+
* `daemon/external-plugins-bootstrap.ts` before {@link bootstrapPlugins} fires
|
|
17
|
+
* plugin `init()` hooks.
|
|
26
18
|
*/
|
|
27
19
|
export const defaultCompactionPlugin: Plugin = {
|
|
28
20
|
manifest: {
|
|
29
21
|
name: pkg.name,
|
|
30
22
|
version: pkg.version,
|
|
31
23
|
},
|
|
32
|
-
middleware: {
|
|
33
|
-
compaction: defaultCompactionMiddleware,
|
|
34
|
-
},
|
|
35
24
|
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default `stop` hook: when the model yields a turn with no tool calls, decide
|
|
3
|
+
* whether to let the turn end or re-query the model with a nudge.
|
|
4
|
+
*
|
|
5
|
+
* Two cases warrant a nudge:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Refusal stop.** The provider returned `stopReason === "refusal"` with no
|
|
8
|
+
* visible text (Anthropic's safety classifier zeroed the response). Nudged
|
|
9
|
+
* even on the first model call of the run — a refusal there guarantees no
|
|
10
|
+
* organic text exists yet, so without intervening the loop would persist an
|
|
11
|
+
* empty assistant bubble to the user. Uses `REFUSAL_NUDGE_TEXT`.
|
|
12
|
+
* 2. **Empty turn after tool use.** The turn produced no visible text, follows
|
|
13
|
+
* at least one prior assistant turn this run, and no earlier turn this run
|
|
14
|
+
* already delivered visible text. Uses `NUDGE_TEXT`.
|
|
15
|
+
*
|
|
16
|
+
* Every other case leaves the decision at `"stop"` (the model said its piece,
|
|
17
|
+
* or there is nothing to nudge about). The retry cap is owned by the agent
|
|
18
|
+
* loop: this hook always asks to continue when a nudge is warranted, and the
|
|
19
|
+
* loop stops anyway once the run's nudge budget is spent.
|
|
20
|
+
*
|
|
21
|
+
* Both prior-turn signals are derived from the current response cycle — the
|
|
22
|
+
* messages after the last genuine user prompt (a user turn that isn't purely
|
|
23
|
+
* tool results). Scoping this way keeps prior conversation turns from polluting
|
|
24
|
+
* the signals, and deriving the boundary from history content rather than an
|
|
25
|
+
* index means mid-run compaction (which rewrites the array in place) can't
|
|
26
|
+
* invalidate it. A prior assistant turn this cycle implies a completed tool-use
|
|
27
|
+
* iteration (an empty turn nudges-and-continues without pushing an assistant
|
|
28
|
+
* message), so "a prior assistant turn exists" is the equivalent of "this is
|
|
29
|
+
* not the first model call".
|
|
30
|
+
*
|
|
31
|
+
* Defaults register before any user plugin, so this hook runs at the front of
|
|
32
|
+
* the `stop` chain — later hooks see (and may override) its decision.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import type { PluginHookFn, StopContext } from "@vellumai/plugin-api";
|
|
36
|
+
|
|
37
|
+
import type { ContentBlock, Message } from "../../../../providers/types.js";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Canonical nudge text for an empty turn after tool use. Must stay verbatim so
|
|
41
|
+
* a plugin that wraps the default sees a stable string.
|
|
42
|
+
*
|
|
43
|
+
* Wire-compat note: this is shown to the LLM, not the user. Edits here affect
|
|
44
|
+
* model behavior but not end-user UX directly.
|
|
45
|
+
*/
|
|
46
|
+
export const NUDGE_TEXT =
|
|
47
|
+
"<system_notice>Your previous response was empty. You must respond to the user with a summary of what you found or did. Do not use any tools — just respond with text.</system_notice>";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Refusal-specific nudge. Used when the provider stops with `"refusal"` and no
|
|
51
|
+
* visible text — i.e. the safety classifier zeroed the response. Kept distinct
|
|
52
|
+
* from `NUDGE_TEXT` so the model gets context-appropriate guidance (no "summary
|
|
53
|
+
* of what you found or did" — there is no tool trail to summarize on a refusal).
|
|
54
|
+
*
|
|
55
|
+
* Wire-compat note: this is shown to the LLM, not the user. Edits here affect
|
|
56
|
+
* retry behavior but not end-user UX directly.
|
|
57
|
+
*/
|
|
58
|
+
export const REFUSAL_NUDGE_TEXT =
|
|
59
|
+
'<system_notice>Your previous response was empty because the upstream provider returned stop_reason="refusal". Please answer the user\'s last message directly with a plain-text response. Do not use any tools — just respond with text.</system_notice>';
|
|
60
|
+
|
|
61
|
+
function hasVisibleText(content: ReadonlyArray<ContentBlock>): boolean {
|
|
62
|
+
return content.some(
|
|
63
|
+
(block) => block.type === "text" && block.text.trim().length > 0,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isAssistantTurn(message: Message): boolean {
|
|
68
|
+
return message.role === "assistant";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** A user-role message carrying only tool results, not a fresh prompt. */
|
|
72
|
+
function isToolResultMessage(message: Message): boolean {
|
|
73
|
+
return (
|
|
74
|
+
message.role === "user" &&
|
|
75
|
+
message.content.length > 0 &&
|
|
76
|
+
message.content.every((block) => block.type === "tool_result")
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Messages belonging to the current response cycle: everything after the last
|
|
82
|
+
* genuine user prompt. Falls back to the whole history when none is found.
|
|
83
|
+
*/
|
|
84
|
+
function currentCycleMessages(
|
|
85
|
+
messages: ReadonlyArray<Message>,
|
|
86
|
+
): ReadonlyArray<Message> {
|
|
87
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
88
|
+
const message = messages[i];
|
|
89
|
+
if (message.role === "user" && !isToolResultMessage(message)) {
|
|
90
|
+
return messages.slice(i + 1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return messages;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const stop: PluginHookFn<StopContext> = async (ctx) => {
|
|
97
|
+
const turnHasVisibleText = hasVisibleText(ctx.responseContent);
|
|
98
|
+
|
|
99
|
+
const appendNudge = (text: string): void => {
|
|
100
|
+
ctx.messages.push({ role: "user", content: [{ type: "text", text }] });
|
|
101
|
+
ctx.decision = "continue";
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (ctx.stopReason === "refusal" && !turnHasVisibleText) {
|
|
105
|
+
appendNudge(REFUSAL_NUDGE_TEXT);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const cycleMessages = currentCycleMessages(ctx.messages);
|
|
110
|
+
const priorAssistantTurns = cycleMessages.filter(isAssistantTurn);
|
|
111
|
+
const hadPriorAssistantTurn = priorAssistantTurns.length > 0;
|
|
112
|
+
const priorAssistantHadVisibleText = priorAssistantTurns.some((message) =>
|
|
113
|
+
hasVisibleText(message.content),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const isEmptyTurnAfterTools =
|
|
117
|
+
!turnHasVisibleText &&
|
|
118
|
+
hadPriorAssistantTurn &&
|
|
119
|
+
!priorAssistantHadVisibleText;
|
|
120
|
+
|
|
121
|
+
if (isEmptyTurnAfterTools) {
|
|
122
|
+
appendNudge(NUDGE_TEXT);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default stop;
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Default `
|
|
2
|
+
* Default `empty-response` plugin.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `./
|
|
7
|
-
*
|
|
8
|
-
* default plugin is registered before any user plugin (defaults load first in
|
|
9
|
-
* `bootstrapPlugins()`), which puts it at the OUTERMOST position of the onion
|
|
10
|
-
* chain. If the default middleware were to decide directly without calling
|
|
11
|
-
* `next`, it would shadow every later-registered plugin. Routing through
|
|
12
|
-
* `next(args)` lets user middleware participate normally.
|
|
4
|
+
* Contributes a `stop` hook that re-queries the model when a turn yields with
|
|
5
|
+
* no tool calls but came back empty (or as a provider refusal). The decision
|
|
6
|
+
* logic lives in `./hooks/stop.ts`. Defaults register before user plugins, so
|
|
7
|
+
* this runs at the front of the `stop` hook chain.
|
|
13
8
|
*/
|
|
14
9
|
|
|
15
10
|
import { type Plugin } from "../../types.js";
|
|
16
|
-
import
|
|
11
|
+
import stop from "./hooks/stop.js";
|
|
17
12
|
import pkg from "./package.json" with { type: "json" };
|
|
18
13
|
|
|
19
14
|
/** Singleton plugin — the registry rejects duplicate registrations by name. */
|
|
@@ -22,7 +17,7 @@ export const defaultEmptyResponsePlugin: Plugin = {
|
|
|
22
17
|
name: pkg.name,
|
|
23
18
|
version: pkg.version,
|
|
24
19
|
},
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
hooks: {
|
|
21
|
+
stop,
|
|
27
22
|
},
|
|
28
23
|
};
|
|
@@ -23,22 +23,14 @@
|
|
|
23
23
|
* registration work.
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { memoryV3ShadowPlugin } from "../../memory/v3/shadow-plugin.js";
|
|
27
26
|
import { registerPlugin, resetPluginRegistryForTests } from "../registry.js";
|
|
28
27
|
import { type Plugin, PluginExecutionError } from "../types.js";
|
|
29
|
-
import { defaultCircuitBreakerPlugin } from "./circuit-breaker/register.js";
|
|
30
28
|
import { defaultCompactionPlugin } from "./compaction/register.js";
|
|
31
29
|
import { defaultEmptyResponsePlugin } from "./empty-response/register.js";
|
|
32
30
|
import { defaultHistoryRepairPlugin } from "./history-repair/register.js";
|
|
33
|
-
import {
|
|
34
|
-
import { defaultLlmCallPlugin } from "./llm-call/register.js";
|
|
35
|
-
import { defaultMemoryRetrievalPlugin } from "./memory-retrieval/register.js";
|
|
36
|
-
import { defaultOverflowReducePlugin } from "./overflow-reduce/register.js";
|
|
37
|
-
import { defaultPersistencePlugin } from "./persistence/register.js";
|
|
31
|
+
import { memoryV3ShadowPlugin } from "./memory-v3-shadow/register.js";
|
|
38
32
|
import { defaultTitleGeneratePlugin } from "./title-generate/register.js";
|
|
39
|
-
import { defaultTokenEstimatePlugin } from "./token-estimate/register.js";
|
|
40
33
|
import { defaultToolErrorPlugin } from "./tool-error/register.js";
|
|
41
|
-
import { defaultToolExecutePlugin } from "./tool-execute/register.js";
|
|
42
34
|
import { defaultToolResultTruncatePlugin } from "./tool-result-truncate/register.js";
|
|
43
35
|
|
|
44
36
|
/**
|
|
@@ -53,19 +45,11 @@ import { defaultToolResultTruncatePlugin } from "./tool-result-truncate/register
|
|
|
53
45
|
*/
|
|
54
46
|
function getAllDefaultPlugins(): readonly Plugin[] {
|
|
55
47
|
return [
|
|
56
|
-
defaultLlmCallPlugin,
|
|
57
|
-
defaultToolExecutePlugin,
|
|
58
48
|
defaultToolResultTruncatePlugin,
|
|
59
49
|
defaultEmptyResponsePlugin,
|
|
60
50
|
defaultToolErrorPlugin,
|
|
61
|
-
defaultMemoryRetrievalPlugin,
|
|
62
|
-
defaultInjectorsPlugin,
|
|
63
|
-
defaultTokenEstimatePlugin,
|
|
64
|
-
defaultOverflowReducePlugin,
|
|
65
51
|
defaultHistoryRepairPlugin,
|
|
66
52
|
defaultCompactionPlugin,
|
|
67
|
-
defaultCircuitBreakerPlugin,
|
|
68
|
-
defaultPersistencePlugin,
|
|
69
53
|
defaultTitleGeneratePlugin,
|
|
70
54
|
memoryV3ShadowPlugin,
|
|
71
55
|
];
|
|
@@ -99,7 +83,7 @@ export function registerDefaultPlugins(): void {
|
|
|
99
83
|
* so integration tests that exercise the full agent loop have a
|
|
100
84
|
* production-parity plugin stack. Use this in `beforeEach` of tests that
|
|
101
85
|
* dispatch through pipelines with a terminal that assumes the default
|
|
102
|
-
* plugin handles every op (e.g.
|
|
86
|
+
* plugin handles every op (e.g. compaction).
|
|
103
87
|
*
|
|
104
88
|
* Tests that specifically need an empty registry (pipeline-unit tests, the
|
|
105
89
|
* plugin-registry tests themselves) should continue to call
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default `memoryRetrieval` post-compaction hook.
|
|
3
|
+
*
|
|
4
|
+
* After the agent loop compacts a conversation mid-turn it must re-apply the
|
|
5
|
+
* runtime injections compaction stripped — the NOW.md scratchpad, PKB context,
|
|
6
|
+
* memory-v2 static block, workspace top-level context, and Slack chronological
|
|
7
|
+
* snapshot — onto the compacted history before the turn continues. This hook
|
|
8
|
+
* is the memory system's home for that transform: it receives the message
|
|
9
|
+
* history plus the resolved runtime-injection options and returns the edited
|
|
10
|
+
* history (and the blocks it captured), with no dependency on the agent loop's
|
|
11
|
+
* closure state.
|
|
12
|
+
*
|
|
13
|
+
* It re-applies the runtime injections via {@link applyRuntimeInjections},
|
|
14
|
+
* re-tracks the memory graph's cached nodes against the re-injected history,
|
|
15
|
+
* and converts now-historical `web_search_tool_result` blocks to text so their
|
|
16
|
+
* expired `encrypted_content` tokens are not replayed. The remaining
|
|
17
|
+
* orchestrator-side step (the post-injection bookkeeping the loop records) is
|
|
18
|
+
* expected to migrate here as the hook subsumes the loop's re-injection
|
|
19
|
+
* ceremony.
|
|
20
|
+
*
|
|
21
|
+
* The memory graph handle is sourced internally from the plugin's own
|
|
22
|
+
* conversation-keyed registry ({@link getLiveGraphMemory}) rather than being
|
|
23
|
+
* threaded in by the loop — it is memory-retrieval-specific state, not
|
|
24
|
+
* something the generic loop or the shared {@link TurnContext} should carry.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
applyRuntimeInjections,
|
|
29
|
+
type RuntimeInjectionOptions,
|
|
30
|
+
type RuntimeInjectionResult,
|
|
31
|
+
} from "../../../../daemon/conversation-runtime-assembly.js";
|
|
32
|
+
import { resolveTrustClass } from "../../../../daemon/trust-context.js";
|
|
33
|
+
import { stripHistoricalWebSearchResults } from "../../../../daemon/web-search-history.js";
|
|
34
|
+
import { getLiveGraphMemory } from "../../../../memory/graph/conversation-graph-memory.js";
|
|
35
|
+
import type { PluginLogger } from "../../../../plugin-api/types.js";
|
|
36
|
+
import type { Message } from "../../../../providers/types.js";
|
|
37
|
+
import type { TurnContext } from "../../../types.js";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The slice of the hook's context the agent loop supplies from its own working
|
|
41
|
+
* state. Re-injection inputs migrate loop-ward by growing this type; the loop
|
|
42
|
+
* hands the hook an object of this shape via
|
|
43
|
+
* {@link MidLoopCompaction.postCompactionHook}.
|
|
44
|
+
*/
|
|
45
|
+
export interface PostCompactionHookInput {
|
|
46
|
+
/** Compacted message history to re-inject onto. */
|
|
47
|
+
history: Message[];
|
|
48
|
+
/** Per-turn conversation context forwarded to the injector chain. */
|
|
49
|
+
turnContext?: TurnContext;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Everything the hook needs in a single context: the loop-supplied
|
|
54
|
+
* {@link PostCompactionHookInput}, the resolved {@link RuntimeInjectionOptions}
|
|
55
|
+
* (spread top-level so each field stays individually addressable), and a
|
|
56
|
+
* turn-scoped logger. The memory graph handle is not part of this context —
|
|
57
|
+
* the hook sources it internally via {@link getLiveGraphMemory} — and the
|
|
58
|
+
* actor's trust class is derived from {@link PostCompactionHookInput.turnContext}
|
|
59
|
+
* rather than threaded in.
|
|
60
|
+
*/
|
|
61
|
+
export interface PostCompactContext
|
|
62
|
+
extends RuntimeInjectionOptions, PostCompactionHookInput {
|
|
63
|
+
/** Turn-scoped logger for diagnostics emitted while re-injecting. */
|
|
64
|
+
logger: PluginLogger;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default async function postCompactReinject(
|
|
68
|
+
ctx: PostCompactContext,
|
|
69
|
+
): Promise<RuntimeInjectionResult> {
|
|
70
|
+
const { history, logger, ...options } = ctx;
|
|
71
|
+
const result = await applyRuntimeInjections(history, options);
|
|
72
|
+
// Re-track the nodes the memory graph last injected so they survive against
|
|
73
|
+
// the re-injected history. Untrusted actors and minimal-mode turns never
|
|
74
|
+
// received a memory-graph injection, so there is nothing to re-track. The
|
|
75
|
+
// actor's trust class is derived from the turn's own trust context (the same
|
|
76
|
+
// value the injector chain resolves), not threaded in from the loop. The
|
|
77
|
+
// live graph handle is looked up from the plugin's own registry by the
|
|
78
|
+
// turn's conversation id — the same instance the turn's retrieval mutated,
|
|
79
|
+
// so re-tracking sees the real cached-node state.
|
|
80
|
+
const isTrustedActor =
|
|
81
|
+
resolveTrustClass(options.turnContext?.trust) === "guardian";
|
|
82
|
+
if (isTrustedActor && options.mode !== "minimal") {
|
|
83
|
+
getLiveGraphMemory(
|
|
84
|
+
options.turnContext?.conversationId,
|
|
85
|
+
)?.retrackCachedNodes();
|
|
86
|
+
}
|
|
87
|
+
const strip = stripHistoricalWebSearchResults(result.messages);
|
|
88
|
+
if (strip.stats.blocksStripped > 0) {
|
|
89
|
+
logger.info(
|
|
90
|
+
{ phase: "mid-loop-compact", ...strip.stats },
|
|
91
|
+
"Converted historical web_search_tool_result blocks to text summaries",
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return { ...result, messages: strip.messages };
|
|
95
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default `user-prompt-submit-temp` hook: runs the memory-graph retrieval the
|
|
3
|
+
* agent loop needs before building a turn's runtime-injection block.
|
|
4
|
+
*
|
|
5
|
+
* **Memory graph** via {@link ConversationGraphMemory.prepareMemory} —
|
|
6
|
+
* dispatches to context-load or per-turn retrieval depending on initialization
|
|
7
|
+
* state; gated on the actor being trusted (guardian).
|
|
8
|
+
*
|
|
9
|
+
* The hook also owns the retrieval's side effects — persisting the injected
|
|
10
|
+
* block onto the user message's metadata, writing the recall log, and emitting
|
|
11
|
+
* the `memory_recalled` event — so the loop only consumes the turn-scoped
|
|
12
|
+
* `latestMessages` written back onto the context. The PKB query-vector pair is
|
|
13
|
+
* recorded on the conversation's graph handle for the PKB-reminder injector to
|
|
14
|
+
* read back. PKB context and NOW.md are sourced directly by their injectors
|
|
15
|
+
* (gated on block presence), not produced here.
|
|
16
|
+
*
|
|
17
|
+
* This fires at the early "prompt submitted, before context assembly" moment,
|
|
18
|
+
* distinct from the canonical late `user-prompt-submit` hook (history repair,
|
|
19
|
+
* title): memory's outputs feed the injection and overflow-reduction transforms
|
|
20
|
+
* that run between the two moments. The `-temp` suffix marks this as a
|
|
21
|
+
* transitional staging point that folds into `user-prompt-submit` once
|
|
22
|
+
* compaction is cleared from the gap between the two call sites.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import type { PluginHookFn } from "@vellumai/plugin-api";
|
|
26
|
+
import type { Logger } from "pino";
|
|
27
|
+
|
|
28
|
+
import type { AssistantConfig } from "../../../../config/schema.js";
|
|
29
|
+
import type { ServerMessage } from "../../../../daemon/message-protocol.js";
|
|
30
|
+
import type { MemoryRecalled } from "../../../../daemon/message-types/memory.js";
|
|
31
|
+
import { updateMessageMetadata } from "../../../../memory/conversation-crud.js";
|
|
32
|
+
import type { ConversationGraphMemory } from "../../../../memory/graph/conversation-graph-memory.js";
|
|
33
|
+
import { recordMemoryRecallLog } from "../../../../memory/memory-recall-log-store.js";
|
|
34
|
+
import type { Message } from "../../../../providers/types.js";
|
|
35
|
+
import type { GraphMemoryResult } from "../../../types.js";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Context threaded through the `user-prompt-submit-temp` hook. The readonly
|
|
39
|
+
* fields carry the conversation-scoped state the retriever needs (graph
|
|
40
|
+
* handle, event sink, abort signal); the output fields are populated by the
|
|
41
|
+
* hook and read back by the agent loop. `latestMessages` straddles both: the
|
|
42
|
+
* loop seeds it with the pre-injection array and the hook overwrites it with
|
|
43
|
+
* the injected result.
|
|
44
|
+
*/
|
|
45
|
+
export interface MemoryRetrievalHookContext {
|
|
46
|
+
/** Per-conversation memory graph handle. */
|
|
47
|
+
readonly graphMemory: ConversationGraphMemory;
|
|
48
|
+
/** Assistant config snapshot. */
|
|
49
|
+
readonly config: AssistantConfig;
|
|
50
|
+
/** Event sink used by the graph retriever and `memory_recalled` emission. */
|
|
51
|
+
readonly onEvent: (msg: ServerMessage) => void;
|
|
52
|
+
/** True when the actor for this turn is trusted (guardian-class). */
|
|
53
|
+
readonly isTrustedActor: boolean;
|
|
54
|
+
/** Conversation the turn belongs to — keys the recall-log row. */
|
|
55
|
+
readonly conversationId: string;
|
|
56
|
+
/** User message the injected memory block is persisted onto. */
|
|
57
|
+
readonly userMessageId: string;
|
|
58
|
+
/** Turn-scoped logger for non-fatal persistence warnings. */
|
|
59
|
+
readonly logger: Logger;
|
|
60
|
+
/**
|
|
61
|
+
* Per-turn abort signal forwarded to `prepareMemory`. An external cancel
|
|
62
|
+
* aborts the underlying retrieval instead of letting it run to completion.
|
|
63
|
+
*/
|
|
64
|
+
readonly signal: AbortSignal;
|
|
65
|
+
/**
|
|
66
|
+
* Working message list for the turn. Seeded by the loop with the
|
|
67
|
+
* pre-injection messages and consumed as the retrieval input; the hook
|
|
68
|
+
* overwrites it with the memory-graph block injected, or leaves it
|
|
69
|
+
* unchanged when no graph retrieval ran (untrusted actor, or a no-op
|
|
70
|
+
* retrieval). Read back by the loop.
|
|
71
|
+
*/
|
|
72
|
+
latestMessages: Message[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Persist and broadcast the retrieval's side effects: the injected block on
|
|
77
|
+
* the user message's metadata (so it survives reloads), a recall-log row, and
|
|
78
|
+
* the `memory_recalled` debug event. All three are best-effort — a failure to
|
|
79
|
+
* persist must not abort the turn.
|
|
80
|
+
*/
|
|
81
|
+
function recordRecallSideEffects(
|
|
82
|
+
graphResult: GraphMemoryResult,
|
|
83
|
+
ctx: MemoryRetrievalHookContext,
|
|
84
|
+
): void {
|
|
85
|
+
// Persist the injected block text in message metadata so it survives
|
|
86
|
+
// conversation reloads (eviction, restart, fork). loadFromDb re-injects
|
|
87
|
+
// from metadata.
|
|
88
|
+
if (graphResult.injectedBlockText) {
|
|
89
|
+
try {
|
|
90
|
+
updateMessageMetadata(ctx.userMessageId, {
|
|
91
|
+
memoryInjectedBlock: graphResult.injectedBlockText,
|
|
92
|
+
});
|
|
93
|
+
} catch (err) {
|
|
94
|
+
ctx.logger.warn(
|
|
95
|
+
{ err },
|
|
96
|
+
"Failed to persist memory injection to metadata (non-fatal)",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const m = graphResult.metrics;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
recordMemoryRecallLog({
|
|
105
|
+
conversationId: ctx.conversationId,
|
|
106
|
+
enabled: true,
|
|
107
|
+
degraded: false,
|
|
108
|
+
provider: m?.embeddingProvider ?? undefined,
|
|
109
|
+
model: m?.embeddingModel ?? undefined,
|
|
110
|
+
semanticHits: m?.semanticHits ?? 0,
|
|
111
|
+
mergedCount: m?.mergedCount ?? 0,
|
|
112
|
+
selectedCount: m?.selectedCount ?? 0,
|
|
113
|
+
tier1Count: m?.tier1Count ?? 0,
|
|
114
|
+
tier2Count: m?.tier2Count ?? 0,
|
|
115
|
+
hybridSearchLatencyMs: m?.hybridSearchLatencyMs ?? 0,
|
|
116
|
+
sparseVectorUsed: m?.sparseVectorUsed ?? false,
|
|
117
|
+
injectedTokens: graphResult.injectedTokens,
|
|
118
|
+
latencyMs: graphResult.latencyMs,
|
|
119
|
+
topCandidatesJson: (m?.topCandidates ?? []).map((c) => ({
|
|
120
|
+
key: c.nodeId,
|
|
121
|
+
type: c.type,
|
|
122
|
+
kind: "graph",
|
|
123
|
+
finalScore: c.score,
|
|
124
|
+
semantic: c.semanticSimilarity,
|
|
125
|
+
recency: c.recencyBoost,
|
|
126
|
+
})),
|
|
127
|
+
injectedText: graphResult.injectedBlockText ?? undefined,
|
|
128
|
+
reason: `graph:${graphResult.mode}`,
|
|
129
|
+
queryContext: m?.queryContext ?? undefined,
|
|
130
|
+
});
|
|
131
|
+
} catch (err) {
|
|
132
|
+
ctx.logger.warn({ err }, "Failed to persist memory recall log (non-fatal)");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (m) {
|
|
136
|
+
const memoryRecalledEvent: MemoryRecalled = {
|
|
137
|
+
type: "memory_recalled",
|
|
138
|
+
provider: m.embeddingProvider ?? "unknown",
|
|
139
|
+
model: m.embeddingModel ?? "unknown",
|
|
140
|
+
semanticHits: m.semanticHits,
|
|
141
|
+
mergedCount: m.mergedCount,
|
|
142
|
+
selectedCount: m.selectedCount,
|
|
143
|
+
tier1Count: m.tier1Count,
|
|
144
|
+
tier2Count: m.tier2Count,
|
|
145
|
+
hybridSearchLatencyMs: m.hybridSearchLatencyMs,
|
|
146
|
+
sparseVectorUsed: m.sparseVectorUsed,
|
|
147
|
+
injectedTokens: graphResult.injectedTokens,
|
|
148
|
+
latencyMs: graphResult.latencyMs,
|
|
149
|
+
topCandidates: m.topCandidates.map((c) => ({
|
|
150
|
+
key: c.nodeId,
|
|
151
|
+
type: c.type,
|
|
152
|
+
kind: "graph",
|
|
153
|
+
finalScore: c.score,
|
|
154
|
+
semantic: c.semanticSimilarity,
|
|
155
|
+
recency: c.recencyBoost,
|
|
156
|
+
})),
|
|
157
|
+
};
|
|
158
|
+
ctx.onEvent(memoryRecalledEvent);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Run the default retrieval, writing `latestMessages` back onto the context and
|
|
164
|
+
* recording the PKB query-vector pair on the graph handle. Skips the
|
|
165
|
+
* memory-graph call entirely (leaving `latestMessages` as the seeded input
|
|
166
|
+
* messages and no query pair recorded) when the actor is not trusted.
|
|
167
|
+
*
|
|
168
|
+
* Memory retrieval blocks the turn — there is no soft timeout here. Memory is
|
|
169
|
+
* critical context, and silently dropping it produces a worse outcome than a
|
|
170
|
+
* slower turn. Cancellation still works via `ctx.signal`, which is threaded
|
|
171
|
+
* into `prepareMemory`.
|
|
172
|
+
*/
|
|
173
|
+
const userPromptSubmitMemoryRetrieval: PluginHookFn<
|
|
174
|
+
MemoryRetrievalHookContext
|
|
175
|
+
> = async (ctx) => {
|
|
176
|
+
if (!ctx.isTrustedActor) {
|
|
177
|
+
// Untrusted actors skip memory-graph retrieval entirely.
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const graphResult = await ctx.graphMemory.prepareMemory(
|
|
182
|
+
ctx.latestMessages,
|
|
183
|
+
ctx.config,
|
|
184
|
+
ctx.signal,
|
|
185
|
+
ctx.onEvent,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
recordRecallSideEffects(graphResult, ctx);
|
|
189
|
+
|
|
190
|
+
ctx.latestMessages = graphResult.runMessages;
|
|
191
|
+
// Select dense+sparse as a matched pair so RRF fusion combines two signals
|
|
192
|
+
// aligned to the same query text:
|
|
193
|
+
// 1. Context-load with a user query: user-query dense + user-query sparse
|
|
194
|
+
// — the cleanest pairing.
|
|
195
|
+
// 2. Otherwise (context-load without a user query, or per-turn): whatever
|
|
196
|
+
// `queryVector` / `sparseVector` the retriever produced, which are
|
|
197
|
+
// themselves co-aligned (both summary-derived in context-load, both
|
|
198
|
+
// user-last-message-derived in per-turn).
|
|
199
|
+
// Never pair a user-query dense with a summary-aligned sparse.
|
|
200
|
+
// The PKB-reminder injector reads this pair back off the same graph handle
|
|
201
|
+
// (looked up by conversation id) rather than receiving it threaded through
|
|
202
|
+
// the agent loop.
|
|
203
|
+
if (graphResult.userQueryVector) {
|
|
204
|
+
ctx.graphMemory.recordPkbQueryVectors(
|
|
205
|
+
graphResult.userQueryVector,
|
|
206
|
+
graphResult.userQuerySparseVector,
|
|
207
|
+
);
|
|
208
|
+
} else {
|
|
209
|
+
ctx.graphMemory.recordPkbQueryVectors(
|
|
210
|
+
graphResult.queryVector,
|
|
211
|
+
graphResult.sparseVector,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export default userPromptSubmitMemoryRetrieval;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The assembled runtime injector chain.
|
|
3
|
+
*
|
|
4
|
+
* Injection is not a plugin contribution: the first-party injectors are
|
|
5
|
+
* imported directly and sorted once, by ascending `order`, into the single
|
|
6
|
+
* sequence `applyRuntimeInjections` walks each turn. This co-locates the
|
|
7
|
+
* chain with the memory-retrieval domain it serves, rather than aggregating
|
|
8
|
+
* injectors out of the plugin registry.
|
|
9
|
+
*
|
|
10
|
+
* The chain combines the default injectors ({@link defaultInjectors}) with the
|
|
11
|
+
* memory-v3 injector ({@link memoryV3Injector}). The sort mirrors the previous
|
|
12
|
+
* registry aggregation (`Array.prototype.sort` is stable, so injectors sharing
|
|
13
|
+
* an `order` keep their listed order), so the produced sequence — and therefore
|
|
14
|
+
* the injected content — is identical.
|
|
15
|
+
*
|
|
16
|
+
* The chain is assembled lazily on first access and memoized, so the sort runs
|
|
17
|
+
* once per process rather than per turn and module evaluation stays free of any
|
|
18
|
+
* ordering assumptions about when `defaultInjectors` finishes initializing.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { Injector } from "../../types.js";
|
|
22
|
+
import { memoryV3Injector } from "../memory-v3-shadow/injector.js";
|
|
23
|
+
import { defaultInjectors } from "./injectors.js";
|
|
24
|
+
|
|
25
|
+
let cachedChain: Injector[] | null = null;
|
|
26
|
+
|
|
27
|
+
/** The order-sorted runtime injector chain, assembled once and memoized. */
|
|
28
|
+
export function getInjectorChain(): Injector[] {
|
|
29
|
+
if (cachedChain === null) {
|
|
30
|
+
cachedChain = [...defaultInjectors, memoryV3Injector].sort(
|
|
31
|
+
(a, b) => a.order - b.order,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return cachedChain;
|
|
35
|
+
}
|