@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
|
@@ -15,12 +15,17 @@
|
|
|
15
15
|
* cache turn after turn. The trailing recent-context / current-message block
|
|
16
16
|
* changes every turn, so it carries no breakpoint.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* -
|
|
21
|
-
* -
|
|
22
|
-
*
|
|
23
|
-
*
|
|
18
|
+
* Failure handling. A *model-call* failure is not the same as the model
|
|
19
|
+
* choosing to open everything, so the two no longer share an outcome:
|
|
20
|
+
* - explicit `ids` → open exactly those leaves,
|
|
21
|
+
* - explicit empty array (`ids: []`) → open nothing (deliberate abstention),
|
|
22
|
+
* - omitted `ids` → open nothing: the router must name the leaves it wants,
|
|
23
|
+
* never the whole tree (~137 leaves would fan out a full L2 pass per turn),
|
|
24
|
+
* - infrastructure failure (provider unavailable, a throw that survived the
|
|
25
|
+
* provider's own retries, no usable `tool_use`, or a schema mismatch) →
|
|
26
|
+
* open nothing after a short re-prompt retry, degrading to the deterministic
|
|
27
|
+
* recall lanes (always-on core, the BM25 needle, the carry-forward working
|
|
28
|
+
* set) that the orchestrator unions in regardless.
|
|
24
29
|
*/
|
|
25
30
|
|
|
26
31
|
import { z } from "zod";
|
|
@@ -28,9 +33,10 @@ import { z } from "zod";
|
|
|
28
33
|
import {
|
|
29
34
|
extractToolUse,
|
|
30
35
|
getConfiguredProvider,
|
|
31
|
-
} from "
|
|
32
|
-
import type { Message, ToolDefinition } from "
|
|
33
|
-
import { getLogger } from "
|
|
36
|
+
} from "../../../providers/provider-send-message.js";
|
|
37
|
+
import type { Message, ToolDefinition } from "../../../providers/types.js";
|
|
38
|
+
import { getLogger } from "../../../util/logger.js";
|
|
39
|
+
import { retryForResult } from "./llm-retry.js";
|
|
34
40
|
import { cachedTextBlock } from "./provider-blocks.js";
|
|
35
41
|
import type { LeafPath, LeafTree, TurnContext } from "./types.js";
|
|
36
42
|
|
|
@@ -40,8 +46,8 @@ const log = getLogger("memory-v3-router");
|
|
|
40
46
|
const OPEN_LEAVES_TOOL_NAME = "open_leaves";
|
|
41
47
|
|
|
42
48
|
const OpenLeavesSchema = z.object({
|
|
43
|
-
// Optional
|
|
44
|
-
//
|
|
49
|
+
// Optional so the field can be absent on the wire, but an omitted `ids` opens
|
|
50
|
+
// nothing — the router must name the leaves it wants, never the whole tree.
|
|
45
51
|
ids: z.array(z.number().int()).optional(),
|
|
46
52
|
});
|
|
47
53
|
|
|
@@ -50,8 +56,8 @@ const OPEN_LEAVES_TOOL: ToolDefinition = {
|
|
|
50
56
|
description:
|
|
51
57
|
"Open the leaves whose contents could plausibly bear on the next reply. " +
|
|
52
58
|
"Lean toward inclusion — a missed relevant leaf is a worse error than an " +
|
|
53
|
-
"unused one.
|
|
54
|
-
"
|
|
59
|
+
"unused one. Pass the chosen IDs explicitly; return `[]` only when nothing " +
|
|
60
|
+
"in the tree could possibly help.",
|
|
55
61
|
input_schema: {
|
|
56
62
|
type: "object",
|
|
57
63
|
properties: {
|
|
@@ -65,13 +71,14 @@ const OPEN_LEAVES_TOOL: ToolDefinition = {
|
|
|
65
71
|
|
|
66
72
|
const SYSTEM_PROMPT = `You route a conversation turn to the leaves of a topic tree that should be opened for the next reply.
|
|
67
73
|
|
|
68
|
-
Each leaf has a numbered ID, a path, and a description of what it holds. Decide which leaves to open by weighing
|
|
74
|
+
Each leaf has a numbered ID, a path, and a description of what it holds. Decide which leaves to open by weighing four signals:
|
|
69
75
|
|
|
70
76
|
- Topic — entities, projects, and events named or implied by the turn.
|
|
71
77
|
- Register — the affect and mode of the message (e.g. playful, distressed, formal). A register signal is enough to open a leaf even when no entity is named.
|
|
72
78
|
- Recent context — the immediately preceding exchange, which resolves references like "this", "that", or "the same thing" to concrete topics.
|
|
79
|
+
- Situation — the current date and a live scratchpad of what is salient right now. A date or state cue can make a leaf relevant even when the message never names it (e.g. a person whose anniversary is today, an active thread).
|
|
73
80
|
|
|
74
|
-
Include on doubt: open every leaf that could plausibly hold something useful. Missing a relevant leaf is a worse error than opening an unused one. Call \`open_leaves\` with the chosen IDs
|
|
81
|
+
Include on doubt: open every leaf that could plausibly hold something useful. Missing a relevant leaf is a worse error than opening an unused one. Call \`open_leaves\` with the chosen IDs explicitly; return \`[]\` only when nothing in the tree could possibly help.`;
|
|
75
82
|
|
|
76
83
|
/** Leaves sorted deterministically by path so the numbered block is stable. */
|
|
77
84
|
function sortedLeaves(tree: LeafTree): LeafPath[] {
|
|
@@ -104,10 +111,10 @@ export function renderLeafBlock(tree: LeafTree): string {
|
|
|
104
111
|
}
|
|
105
112
|
|
|
106
113
|
/**
|
|
107
|
-
* Run the L1 router for one turn. Returns the leaf paths to open
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
114
|
+
* Run the L1 router for one turn. Returns the leaf paths to open — only ever the
|
|
115
|
+
* leaves the model names explicitly. An omitted `ids`, an explicit `[]`, or an
|
|
116
|
+
* infrastructure failure (after a short re-prompt retry) all open nothing,
|
|
117
|
+
* degrading to the deterministic recall lanes the orchestrator unions in.
|
|
111
118
|
*/
|
|
112
119
|
export async function routeL1(
|
|
113
120
|
turn: TurnContext,
|
|
@@ -118,8 +125,10 @@ export async function routeL1(
|
|
|
118
125
|
|
|
119
126
|
const provider = await getConfiguredProvider("memoryV3RouteL1");
|
|
120
127
|
if (!provider) {
|
|
121
|
-
log.warn(
|
|
122
|
-
|
|
128
|
+
log.warn(
|
|
129
|
+
"L1 router provider unavailable; degrading to deterministic lanes",
|
|
130
|
+
);
|
|
131
|
+
return [];
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
const userMsg: Message = {
|
|
@@ -129,15 +138,21 @@ export async function routeL1(
|
|
|
129
138
|
{
|
|
130
139
|
type: "text",
|
|
131
140
|
text:
|
|
141
|
+
(turn.situationalContext
|
|
142
|
+
? `<situation>${turn.situationalContext}</situation>\n`
|
|
143
|
+
: "") +
|
|
132
144
|
`<recent_context>${turn.recentContext}</recent_context>\n` +
|
|
133
145
|
`<current_message>${turn.currentMessage}</current_message>`,
|
|
134
146
|
},
|
|
135
147
|
],
|
|
136
148
|
};
|
|
137
149
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
150
|
+
// One forced-tool call, retried a few times so a transient malformed response
|
|
151
|
+
// (no usable tool_use, or tool input that fails the schema) re-prompts before
|
|
152
|
+
// we give up. `null` from an attempt means "unusable, retry"; the provider
|
|
153
|
+
// layer already backs off transient throws, so this loop adds no delay.
|
|
154
|
+
const parsed = await retryForResult(async () => {
|
|
155
|
+
const response = await provider.sendMessage([userMsg], {
|
|
141
156
|
tools: [OPEN_LEAVES_TOOL],
|
|
142
157
|
systemPrompt: SYSTEM_PROMPT,
|
|
143
158
|
config: {
|
|
@@ -145,37 +160,28 @@ export async function routeL1(
|
|
|
145
160
|
tool_choice: { type: "tool" as const, name: OPEN_LEAVES_TOOL_NAME },
|
|
146
161
|
},
|
|
147
162
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const toolBlock = extractToolUse(response);
|
|
154
|
-
if (!toolBlock || toolBlock.name !== OPEN_LEAVES_TOOL_NAME) {
|
|
155
|
-
log.warn(
|
|
156
|
-
{ stopReason: response.stopReason },
|
|
157
|
-
"L1 router returned no open_leaves tool_use; opening all leaves",
|
|
158
|
-
);
|
|
159
|
-
return paths;
|
|
160
|
-
}
|
|
163
|
+
const toolBlock = extractToolUse(response);
|
|
164
|
+
if (!toolBlock || toolBlock.name !== OPEN_LEAVES_TOOL_NAME) return null;
|
|
165
|
+
const result = OpenLeavesSchema.safeParse(toolBlock.input);
|
|
166
|
+
return result.success ? result.data : null;
|
|
167
|
+
});
|
|
161
168
|
|
|
162
|
-
|
|
163
|
-
if (!parsed.success) {
|
|
169
|
+
if (parsed === null) {
|
|
164
170
|
log.warn(
|
|
165
|
-
|
|
166
|
-
"L1 router tool input did not match schema; opening all leaves",
|
|
171
|
+
"L1 router could not obtain a selection after retries; degrading to deterministic lanes",
|
|
167
172
|
);
|
|
168
|
-
return
|
|
173
|
+
return [];
|
|
169
174
|
}
|
|
170
175
|
|
|
171
|
-
//
|
|
172
|
-
|
|
176
|
+
// An omitted `ids` field means the model named no leaves — open nothing rather
|
|
177
|
+
// than the whole tree. Only explicitly listed IDs open leaves.
|
|
178
|
+
if (parsed.ids === undefined) return [];
|
|
173
179
|
|
|
174
180
|
// Map 1-based IDs back to leaf paths, dropping out-of-range IDs without
|
|
175
181
|
// throwing. De-duplicate while preserving model-returned order.
|
|
176
182
|
const seen = new Set<number>();
|
|
177
183
|
const selected: LeafPath[] = [];
|
|
178
|
-
for (const id of parsed.
|
|
184
|
+
for (const id of parsed.ids) {
|
|
179
185
|
if (id < 1 || id > paths.length || seen.has(id)) continue;
|
|
180
186
|
seen.add(id);
|
|
181
187
|
selected.push(paths[id - 1]);
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* across turns) and can't be reproduced after the fact.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { MemoryV3SelectionLog } from "
|
|
11
|
-
import { isAssistantFeatureFlagEnabled } from "
|
|
12
|
-
import { getConfig } from "
|
|
13
|
-
import { getDb, getSqliteFrom } from "
|
|
10
|
+
import type { MemoryV3SelectionLog } from "../../../api/responses/memory-v3-selection-log.js";
|
|
11
|
+
import { isAssistantFeatureFlagEnabled } from "../../../config/assistant-feature-flags.js";
|
|
12
|
+
import { getConfig } from "../../../config/loader.js";
|
|
13
|
+
import { getDb, getSqliteFrom } from "../../../memory/db-connection.js";
|
|
14
14
|
import { renderV3PageContent } from "./page-content.js";
|
|
15
15
|
import { renderMemoryBlock } from "./render-injection.js";
|
|
16
16
|
import type { Slug } from "./types.js";
|
|
@@ -14,11 +14,18 @@
|
|
|
14
14
|
* turn after turn. The trailing recent-context / current-message block changes
|
|
15
15
|
* every turn and carries no breakpoint. This mirrors `./router.ts`.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* -
|
|
20
|
-
* -
|
|
21
|
-
*
|
|
17
|
+
* Failure handling. A deliberate "select everything" and a model-call failure
|
|
18
|
+
* are different events with different outcomes:
|
|
19
|
+
* - explicit `ids` → select exactly those pages,
|
|
20
|
+
* - explicit empty `ids: []` → select nothing (deliberate abstention),
|
|
21
|
+
* - omitted `ids` → select ALL members of the leaf (the recall-safe "this
|
|
22
|
+
* whole leaf is relevant" signal, e.g. "give me all of X"); bounded to one
|
|
23
|
+
* leaf, so unlike the router this stays a select-all,
|
|
24
|
+
* - infrastructure failure (provider unavailable, a throw that survived the
|
|
25
|
+
* provider's own retries, no usable `tool_use`, or a schema mismatch) →
|
|
26
|
+
* select nothing after a short re-prompt retry, degrading to the
|
|
27
|
+
* deterministic recall lanes (core, needle, carry-forward working set) the
|
|
28
|
+
* orchestrator unions in regardless.
|
|
22
29
|
*/
|
|
23
30
|
|
|
24
31
|
import { z } from "zod";
|
|
@@ -26,10 +33,11 @@ import { z } from "zod";
|
|
|
26
33
|
import {
|
|
27
34
|
extractToolUse,
|
|
28
35
|
getConfiguredProvider,
|
|
29
|
-
} from "
|
|
30
|
-
import type { Message, ToolDefinition } from "
|
|
31
|
-
import { getLogger } from "
|
|
32
|
-
import { mapLimit } from "
|
|
36
|
+
} from "../../../providers/provider-send-message.js";
|
|
37
|
+
import type { Message, ToolDefinition } from "../../../providers/types.js";
|
|
38
|
+
import { getLogger } from "../../../util/logger.js";
|
|
39
|
+
import { mapLimit } from "../../../util/map-limit.js";
|
|
40
|
+
import { retryForResult } from "./llm-retry.js";
|
|
33
41
|
import { cachedTextBlock } from "./provider-blocks.js";
|
|
34
42
|
import { membersOf } from "./tree.js";
|
|
35
43
|
import type { LeafPath, LeafTree, Slug, TurnContext } from "./types.js";
|
|
@@ -55,11 +63,13 @@ const SelectPagesSchema = z.object({
|
|
|
55
63
|
const SELECT_PAGES_TOOL: ToolDefinition = {
|
|
56
64
|
name: SELECT_PAGES_TOOL_NAME,
|
|
57
65
|
description:
|
|
58
|
-
"Select the pages in this leaf whose content
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"conversation is centrally about. Omit
|
|
62
|
-
"
|
|
66
|
+
"Select the pages in this leaf whose content the reply would directly " +
|
|
67
|
+
"draw on. Be selective — prefer a few precisely-relevant pages over many " +
|
|
68
|
+
"loosely-related ones; a leaf opened on a weak signal may yield none. " +
|
|
69
|
+
"Pass `pinned_ids` for pages the conversation is centrally about. Omit " +
|
|
70
|
+
"`ids` only as a recall-safe fallback when you cannot judge the leaf " +
|
|
71
|
+
"(selects every page); return `[]` when pages are present but none are " +
|
|
72
|
+
"directly relevant.",
|
|
63
73
|
input_schema: {
|
|
64
74
|
type: "object",
|
|
65
75
|
properties: {
|
|
@@ -75,11 +85,13 @@ const SELECT_PAGES_TOOL: ToolDefinition = {
|
|
|
75
85
|
},
|
|
76
86
|
};
|
|
77
87
|
|
|
78
|
-
const SYSTEM_PROMPT = `This leaf of the topic tree is potentially relevant to the conversation. Select the pages whose content
|
|
88
|
+
const SYSTEM_PROMPT = `This leaf of the topic tree is potentially relevant to the conversation. Select ONLY the pages whose content the reply to THIS message would directly draw on.
|
|
79
89
|
|
|
80
|
-
Be
|
|
90
|
+
Be selective: exclude pages that are merely topically adjacent, part of the ever-present background, or only loosely related. Most opened leaves should contribute a few precisely-relevant pages, not most of their contents — a leaf opened on a weak signal may yield none.
|
|
81
91
|
|
|
82
|
-
|
|
92
|
+
A page can also be directly relevant because of the current situation — the date or the live scratchpad — not only the message: keep a page the situation makes pertinent (e.g. a person whose anniversary is today).
|
|
93
|
+
|
|
94
|
+
If the conversation is centrally ABOUT a page (rather than only peripherally relevant to it), mark that page as pinned. Call \`select_pages\` with the chosen IDs. Omit \`ids\` only as a recall-safe fallback when you cannot judge the leaf (selects every page); return \`[]\` when the pages are present but none are directly relevant.`;
|
|
83
95
|
|
|
84
96
|
/**
|
|
85
97
|
* Render the STATIC numbered `<pages>` block for a leaf from its member slugs.
|
|
@@ -103,8 +115,10 @@ async function renderPagesBlock(
|
|
|
103
115
|
/**
|
|
104
116
|
* Run the L2 selector for a single opened leaf. Returns the pages to inject.
|
|
105
117
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
118
|
+
* An omitted `ids` selects ALL members (the recall-safe "whole leaf is
|
|
119
|
+
* relevant" signal); an explicit `[]` selects none; an infrastructure failure
|
|
120
|
+
* (after a short re-prompt retry) selects none, degrading to the deterministic
|
|
121
|
+
* recall lanes the orchestrator unions in.
|
|
108
122
|
*/
|
|
109
123
|
export async function selectFromLeaf(
|
|
110
124
|
leaf: LeafPath,
|
|
@@ -120,8 +134,11 @@ export async function selectFromLeaf(
|
|
|
120
134
|
|
|
121
135
|
const provider = await getConfiguredProvider("memoryV3SelectL2");
|
|
122
136
|
if (!provider) {
|
|
123
|
-
log.warn(
|
|
124
|
-
|
|
137
|
+
log.warn(
|
|
138
|
+
{ leaf },
|
|
139
|
+
"L2 selector provider unavailable; degrading to deterministic lanes",
|
|
140
|
+
);
|
|
141
|
+
return [];
|
|
125
142
|
}
|
|
126
143
|
|
|
127
144
|
const userMsg: Message = {
|
|
@@ -134,15 +151,21 @@ export async function selectFromLeaf(
|
|
|
134
151
|
{
|
|
135
152
|
type: "text",
|
|
136
153
|
text:
|
|
154
|
+
(turn.situationalContext
|
|
155
|
+
? `<situation>${turn.situationalContext}</situation>\n`
|
|
156
|
+
: "") +
|
|
137
157
|
`<recent_context>${turn.recentContext}</recent_context>\n` +
|
|
138
158
|
`<current_message>${turn.currentMessage}</current_message>`,
|
|
139
159
|
},
|
|
140
160
|
],
|
|
141
161
|
};
|
|
142
162
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
// One forced-tool call, retried a few times so a transient malformed response
|
|
164
|
+
// (no usable tool_use, or tool input that fails the schema) re-prompts before
|
|
165
|
+
// we give up. `null` from an attempt means "unusable, retry"; the provider
|
|
166
|
+
// layer already backs off transient throws, so this loop adds no delay.
|
|
167
|
+
const parsed = await retryForResult(async () => {
|
|
168
|
+
const response = await provider.sendMessage([userMsg], {
|
|
146
169
|
tools: [SELECT_PAGES_TOOL],
|
|
147
170
|
systemPrompt: SYSTEM_PROMPT,
|
|
148
171
|
config: {
|
|
@@ -150,39 +173,31 @@ export async function selectFromLeaf(
|
|
|
150
173
|
tool_choice: { type: "tool" as const, name: SELECT_PAGES_TOOL_NAME },
|
|
151
174
|
},
|
|
152
175
|
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const toolBlock = extractToolUse(response);
|
|
159
|
-
if (!toolBlock || toolBlock.name !== SELECT_PAGES_TOOL_NAME) {
|
|
160
|
-
log.warn(
|
|
161
|
-
{ stopReason: response.stopReason, leaf },
|
|
162
|
-
"L2 selector returned no select_pages tool_use; selecting all",
|
|
163
|
-
);
|
|
164
|
-
return allMembers();
|
|
165
|
-
}
|
|
176
|
+
const toolBlock = extractToolUse(response);
|
|
177
|
+
if (!toolBlock || toolBlock.name !== SELECT_PAGES_TOOL_NAME) return null;
|
|
178
|
+
const result = SelectPagesSchema.safeParse(toolBlock.input);
|
|
179
|
+
return result.success ? result.data : null;
|
|
180
|
+
});
|
|
166
181
|
|
|
167
|
-
|
|
168
|
-
if (!parsed.success) {
|
|
182
|
+
if (parsed === null) {
|
|
169
183
|
log.warn(
|
|
170
|
-
{
|
|
171
|
-
"L2 selector
|
|
184
|
+
{ leaf },
|
|
185
|
+
"L2 selector could not obtain a selection after retries; degrading to deterministic lanes",
|
|
172
186
|
);
|
|
173
|
-
return
|
|
187
|
+
return [];
|
|
174
188
|
}
|
|
175
189
|
|
|
176
|
-
// Omitted `ids` is the recall-safe "
|
|
177
|
-
|
|
190
|
+
// Omitted `ids` is the recall-safe "this whole leaf is relevant" signal.
|
|
191
|
+
// Bounded to one leaf, so it stays a select-all (unlike the L1 router).
|
|
192
|
+
if (parsed.ids === undefined) return allMembers();
|
|
178
193
|
|
|
179
|
-
const pinned = new Set(parsed.
|
|
194
|
+
const pinned = new Set(parsed.pinned_ids ?? []);
|
|
180
195
|
|
|
181
196
|
// Map 1-based IDs back to member slugs, dropping out-of-range IDs without
|
|
182
197
|
// throwing. De-duplicate while preserving model-returned order.
|
|
183
198
|
const seen = new Set<number>();
|
|
184
199
|
const selected: SelectedPage[] = [];
|
|
185
|
-
for (const id of parsed.
|
|
200
|
+
for (const id of parsed.ids) {
|
|
186
201
|
if (id < 1 || id > members.length || seen.has(id)) continue;
|
|
187
202
|
seen.add(id);
|
|
188
203
|
selected.push({ slug: members[id - 1]!, pinned: pinned.has(id) });
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Memory v3 — flag-gated shadow/live
|
|
2
|
+
* Memory v3 — flag-gated shadow/live orchestration engine.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* injection behavior:
|
|
4
|
+
* Runs the v3 orchestrator each turn and records its selection set to
|
|
5
|
+
* `memory_v3_selections`. Two flags gate behavior:
|
|
7
6
|
*
|
|
8
|
-
* - `memory-v3-shadow` (
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
7
|
+
* - `memory-v3-shadow` (live OFF): observation-only. {@link observeTurn}
|
|
8
|
+
* orchestrates and logs the selection set; no injection is produced, so v2
|
|
9
|
+
* injection is bit-for-bit identical — the only difference is the
|
|
10
|
+
* side-effect telemetry write.
|
|
11
|
+
* - `memory-v3-live`: live injection. The injector (`memoryV3Injector` in
|
|
12
|
+
* `./injector.ts`) additionally renders the working-set selection into a
|
|
13
|
+
* `<memory>` block and returns it at v2's dynamic-memory placement
|
|
14
14
|
* (`after-memory-prefix`). Selections are still logged.
|
|
15
|
-
* - both OFF:
|
|
15
|
+
* - both OFF: orchestration is skipped entirely.
|
|
16
16
|
*
|
|
17
17
|
* On each turn (either flag on):
|
|
18
18
|
* 1. Lazy-init the v3 lanes ONCE across the whole process (leaf tree, core
|
|
@@ -22,49 +22,45 @@
|
|
|
22
22
|
* 3. Run {@link orchestrate} and record its selection set to
|
|
23
23
|
* `memory_v3_selections` with a best-effort lane attribution.
|
|
24
24
|
*
|
|
25
|
-
*
|
|
26
|
-
* logged and swallowed so it can never affect the live turn.
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* empty selection) falls back to v2 memory rather than dropping all memory.
|
|
25
|
+
* {@link observeTurn} wraps everything after the flag read in try/catch — any
|
|
26
|
+
* failure is logged and swallowed so it can never affect the live turn. The
|
|
27
|
+
* injector treats a `null`/empty result as "no v3 injection", so v2 memory
|
|
28
|
+
* remains the fallback rather than dropping all memory.
|
|
30
29
|
*/
|
|
31
30
|
|
|
32
|
-
import {
|
|
33
|
-
|
|
34
|
-
import
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
31
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
32
|
+
|
|
33
|
+
import { isAssistantFeatureFlagEnabled } from "../../../config/assistant-feature-flags.js";
|
|
34
|
+
import { getConfig } from "../../../config/loader.js";
|
|
35
|
+
import type { AssistantConfig } from "../../../config/schema.js";
|
|
36
|
+
import { getMessages } from "../../../memory/conversation-crud.js";
|
|
37
|
+
import { getDb, getSqliteFrom } from "../../../memory/db-connection.js";
|
|
38
|
+
import { stringifyMessageContent } from "../../../memory/message-content.js";
|
|
39
|
+
import { getPageIndex } from "../../../memory/v2/page-index.js";
|
|
40
|
+
import { getLogger } from "../../../util/logger.js";
|
|
38
41
|
import {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
} from "../../plugins/types.js";
|
|
44
|
-
import { getLogger } from "../../util/logger.js";
|
|
45
|
-
import { getWorkspaceDir } from "../../util/platform.js";
|
|
46
|
-
import { getPageIndex } from "../v2/page-index.js";
|
|
42
|
+
getWorkspaceDir,
|
|
43
|
+
getWorkspacePromptPath,
|
|
44
|
+
} from "../../../util/platform.js";
|
|
45
|
+
import { stripCommentLines } from "../../../util/strip-comment-lines.js";
|
|
47
46
|
import { injectCapabilitiesLeaf, isCapabilitySlug } from "./capabilities.js";
|
|
48
47
|
import { loadCore } from "./core.js";
|
|
49
48
|
import type { NeedleIndex } from "./needle.js";
|
|
50
49
|
import { buildNeedleIndex } from "./needle.js";
|
|
51
50
|
import type { OrchestrateResult } from "./orchestrate.js";
|
|
52
51
|
import { orchestrate } from "./orchestrate.js";
|
|
53
|
-
import { renderV3PageContent } from "./page-content.js";
|
|
54
|
-
import { renderMemoryBlock } from "./render-injection.js";
|
|
55
52
|
import { coreSlugs, loadLeafTree, resolveDataDir } from "./tree.js";
|
|
56
53
|
import {
|
|
57
54
|
type LeafPath,
|
|
58
55
|
type LeafTree,
|
|
59
|
-
MEMORY_V3_BLOCK_ID,
|
|
60
56
|
type SelectionSource,
|
|
61
57
|
type Slug,
|
|
62
58
|
type TurnContext,
|
|
63
59
|
} from "./types.js";
|
|
64
60
|
import { WorkingSet } from "./working-set.js";
|
|
65
61
|
|
|
66
|
-
const MEMORY_V3_SHADOW = "memory-v3-shadow" as const;
|
|
67
|
-
const MEMORY_V3_LIVE = "memory-v3-live" as const;
|
|
62
|
+
export const MEMORY_V3_SHADOW = "memory-v3-shadow" as const;
|
|
63
|
+
export const MEMORY_V3_LIVE = "memory-v3-live" as const;
|
|
68
64
|
|
|
69
65
|
const log = getLogger("memory-v3-shadow");
|
|
70
66
|
|
|
@@ -165,10 +161,42 @@ function getLanes(config: AssistantConfig): Promise<ShadowLanes> {
|
|
|
165
161
|
return lanesPromise;
|
|
166
162
|
}
|
|
167
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Read the live NOW.md scratchpad (the user's short "what's salient right now"
|
|
166
|
+
* file), stripped of its comment lines. Mirrors `readNowScratchpad` but reads
|
|
167
|
+
* through the light platform / strip utilities directly, keeping the v3
|
|
168
|
+
* plugin's load (and its test) free of heavier module graphs. Returns `null`
|
|
169
|
+
* when absent, empty, or unreadable.
|
|
170
|
+
*/
|
|
171
|
+
function readNowContext(): string | null {
|
|
172
|
+
const nowPath = getWorkspacePromptPath("NOW.md");
|
|
173
|
+
if (!existsSync(nowPath)) return null;
|
|
174
|
+
try {
|
|
175
|
+
const stripped = stripCommentLines(readFileSync(nowPath, "utf-8")).trim();
|
|
176
|
+
return stripped.length > 0 ? stripped : null;
|
|
177
|
+
} catch {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Compose the situational signal threaded into L1 routing and L2 selection: the
|
|
184
|
+
* current date plus the live NOW.md scratchpad. The date alone is a weak signal,
|
|
185
|
+
* but together with the scratchpad it lets retrieval surface a leaf the message
|
|
186
|
+
* never names (e.g. an anniversary that falls today). Always returns at least
|
|
187
|
+
* the date line — this mirrors the `c_now`/NOW.md signal the v2 retriever uses.
|
|
188
|
+
*/
|
|
189
|
+
function buildSituationalContext(): string {
|
|
190
|
+
const now = readNowContext();
|
|
191
|
+
const today = `Today is ${new Date().toDateString()}.`;
|
|
192
|
+
return now ? `${today}\n\n${now}` : today;
|
|
193
|
+
}
|
|
194
|
+
|
|
168
195
|
/**
|
|
169
196
|
* Build a v3 {@link TurnContext} from the conversation's persisted messages.
|
|
170
197
|
* `currentMessage` is the latest user message; `recentContext` is the tail of
|
|
171
|
-
* the recent transcript
|
|
198
|
+
* the recent transcript; `situationalContext` carries the current date and the
|
|
199
|
+
* live NOW.md scratchpad. Returns `null` when there is no user message to route
|
|
172
200
|
* on (nothing to shadow this turn).
|
|
173
201
|
*/
|
|
174
202
|
function buildShadowTurn(
|
|
@@ -198,6 +226,7 @@ function buildShadowTurn(
|
|
|
198
226
|
turnNumber: turnIndex,
|
|
199
227
|
currentMessage,
|
|
200
228
|
recentContext,
|
|
229
|
+
situationalContext: buildSituationalContext(),
|
|
201
230
|
};
|
|
202
231
|
}
|
|
203
232
|
|
|
@@ -272,7 +301,7 @@ function writeSelections(
|
|
|
272
301
|
* failures are logged and swallowed (returning `null`) so the live turn is
|
|
273
302
|
* unaffected. Returns `null` when there is no user message to route on.
|
|
274
303
|
*/
|
|
275
|
-
async function observeTurn(
|
|
304
|
+
export async function observeTurn(
|
|
276
305
|
conversationId: string,
|
|
277
306
|
turnIndex: number,
|
|
278
307
|
): Promise<OrchestrateResult | null> {
|
|
@@ -280,13 +309,15 @@ async function observeTurn(
|
|
|
280
309
|
const turn = buildShadowTurn(conversationId, turnIndex);
|
|
281
310
|
if (!turn) return null;
|
|
282
311
|
|
|
283
|
-
const
|
|
312
|
+
const cfg = getConfig();
|
|
313
|
+
const lanes = await getLanes(cfg);
|
|
284
314
|
const result = await orchestrate(turn, {
|
|
285
315
|
tree: lanes.tree,
|
|
286
316
|
core: lanes.core,
|
|
287
317
|
needle: lanes.needle,
|
|
288
318
|
workingSet: lanes.workingSet,
|
|
289
319
|
pageSummary,
|
|
320
|
+
l2Concurrency: cfg.memory.v3.l2Concurrency,
|
|
290
321
|
});
|
|
291
322
|
|
|
292
323
|
const rows = attributeSelections(lanes.tree, lanes.core, result);
|
|
@@ -316,64 +347,3 @@ export async function runShadowObservation(
|
|
|
316
347
|
if (!isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, getConfig())) return;
|
|
317
348
|
await observeTurn(conversationId, turnIndex);
|
|
318
349
|
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* The v3 injector. Reads both flags:
|
|
322
|
-
* - `memory-v3-live` on → orchestrate, log, render the working-set selection
|
|
323
|
-
* into a `<memory>` block, and return it at v2's dynamic-memory placement.
|
|
324
|
-
* - `memory-v3-shadow` on (live off) → orchestrate + log only, return `null`.
|
|
325
|
-
* - both off → return `null` (no orchestration).
|
|
326
|
-
*
|
|
327
|
-
* Empty selection and any failure return `null` (no v3 injection). v2
|
|
328
|
-
* suppression keys off BOTH the flag AND this return value, so a `null` here
|
|
329
|
-
* (failure or empty selection) falls back to v2 memory rather than dropping all
|
|
330
|
-
* memory.
|
|
331
|
-
*/
|
|
332
|
-
const memoryV3Injector: Injector = {
|
|
333
|
-
name: "memory-v3-shadow",
|
|
334
|
-
// High order so it sorts last; the live `<memory>` block uses the
|
|
335
|
-
// after-memory-prefix placement so it lands at the memory boundary regardless
|
|
336
|
-
// of this sort key, which only orders content-producing injectors.
|
|
337
|
-
order: 1000,
|
|
338
|
-
async produce(ctx: PluginTurnContext): Promise<InjectionBlock | null> {
|
|
339
|
-
const config = getConfig();
|
|
340
|
-
const live = isAssistantFeatureFlagEnabled(MEMORY_V3_LIVE, config);
|
|
341
|
-
const shadow = isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, config);
|
|
342
|
-
if (!live && !shadow) return null;
|
|
343
|
-
|
|
344
|
-
const result = await observeTurn(ctx.conversationId, ctx.turnIndex);
|
|
345
|
-
if (!live || !result) return null;
|
|
346
|
-
|
|
347
|
-
try {
|
|
348
|
-
// `renderMemoryBlock` returns "" for an empty selection; inject nothing.
|
|
349
|
-
const text = await renderMemoryBlock(
|
|
350
|
-
result.finalInjection,
|
|
351
|
-
renderV3PageContent,
|
|
352
|
-
);
|
|
353
|
-
if (text.length === 0) return null;
|
|
354
|
-
return {
|
|
355
|
-
id: MEMORY_V3_BLOCK_ID,
|
|
356
|
-
text,
|
|
357
|
-
// Mirror v2's dynamic `<memory>` block placement.
|
|
358
|
-
placement: "after-memory-prefix",
|
|
359
|
-
};
|
|
360
|
-
} catch (err) {
|
|
361
|
-
log.warn(
|
|
362
|
-
{
|
|
363
|
-
err: err instanceof Error ? err.message : String(err),
|
|
364
|
-
conversationId: ctx.conversationId,
|
|
365
|
-
},
|
|
366
|
-
"memory-v3 live render failed (non-fatal) — falling back to v2",
|
|
367
|
-
);
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
},
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
export const memoryV3ShadowPlugin: Plugin = {
|
|
374
|
-
manifest: {
|
|
375
|
-
name: "memory-v3-shadow",
|
|
376
|
-
version: "0.0.1",
|
|
377
|
-
},
|
|
378
|
-
injectors: [memoryV3Injector],
|
|
379
|
-
};
|