@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091853.fbaa2ae
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +6 -6
- package/bun.lock +2 -2
- package/docs/activation-funnel-telemetry.md +310 -0
- package/examples/plugins/echo/README.md +61 -60
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +263 -121
- package/package.json +2 -2
- package/src/__tests__/activation-early-marking.test.ts +120 -0
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
- package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
- package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
- package/src/__tests__/agent-loop-thinking.test.ts +36 -20
- package/src/__tests__/agent-loop.test.ts +441 -96
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
- package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
- package/src/__tests__/anthropic-provider.test.ts +23 -8
- package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +132 -0
- package/src/__tests__/approval-cascade.test.ts +6 -5
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +146 -0
- package/src/__tests__/compaction-events.test.ts +7 -7
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
- package/src/__tests__/context-overflow-reducer.test.ts +265 -125
- package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
- package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
- package/src/__tests__/conversation-agent-loop.test.ts +342 -623
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
- package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
- package/src/__tests__/conversation-error.test.ts +15 -1
- package/src/__tests__/conversation-history-web-search.test.ts +6 -1
- package/src/__tests__/conversation-media-retry.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
- package/src/__tests__/conversation-process-callsite.test.ts +15 -15
- package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
- package/src/__tests__/conversation-queue.test.ts +10 -10
- package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
- package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
- package/src/__tests__/conversation-slash-queue.test.ts +7 -5
- package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
- package/src/__tests__/conversation-speed-override.test.ts +11 -10
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
- package/src/__tests__/conversation-undo.test.ts +2 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
- package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/corrected-target.test.ts +93 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +36 -0
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +17 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/history-repair-hook.test.ts +5 -1
- package/src/__tests__/host-app-control-proxy.test.ts +45 -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__/inference-profile-reaper.test.ts +62 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
- package/src/__tests__/injector-background-turn.test.ts +13 -23
- package/src/__tests__/injector-chain.test.ts +268 -44
- package/src/__tests__/injector-disk-pressure.test.ts +210 -52
- package/src/__tests__/injector-document-comments.test.ts +97 -114
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-v3-suppression.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/llm-resolver.test.ts +73 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
- package/src/__tests__/notification-decision-strategy.test.ts +3 -3
- package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
- package/src/__tests__/persist-unsendable-image.test.ts +97 -1
- package/src/__tests__/plugin-api-shim.test.ts +6 -9
- package/src/__tests__/plugin-bootstrap.test.ts +91 -81
- package/src/__tests__/plugin-registry.test.ts +3 -49
- package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
- package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
- package/src/__tests__/plugin-types.test.ts +0 -70
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
- package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
- package/src/__tests__/published-app-updater.test.ts +138 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
- package/src/__tests__/steer-tool-repair.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-detail.test.ts +25 -7
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +5 -1
- package/src/__tests__/tool-error-hook.test.ts +1 -1
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/web-fetch.test.ts +45 -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-config-stub.ts +0 -2
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +280 -0
- package/src/acp/auto-install.ts +232 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/prepare-agent-env.ts +80 -27
- package/src/acp/resolve-agent.test.ts +188 -28
- package/src/acp/resolve-agent.ts +119 -42
- package/src/acp/resume-hint.ts +23 -0
- package/src/acp/session-manager.ts +507 -73
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +403 -251
- package/src/api/responses/conversation-message.ts +22 -2
- package/src/api/responses/memory-v3-selection-log.ts +19 -10
- package/src/approvals/guardian-request-resolvers.ts +27 -1
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
- package/src/cli/commands/memory-v3.ts +57 -199
- package/src/cli/commands/plugins.ts +43 -37
- package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
- package/src/cli/lib/install-from-github.ts +797 -60
- package/src/cli/lib/plugin-catalog-cache.ts +84 -0
- package/src/cli/lib/plugin-details.ts +416 -0
- package/src/cli/lib/plugin-marketplace.ts +215 -0
- package/src/cli/lib/search-plugins.ts +201 -29
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +9 -3
- package/src/config/acp-schema.ts +1 -7
- package/src/config/bundled-skills/acp/SKILL.md +80 -41
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
- package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +4 -0
- package/src/config/call-site-defaults.ts +0 -3
- package/src/config/feature-flag-registry.json +10 -16
- package/src/config/llm-resolver.ts +39 -7
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
- package/src/config/schemas/call-site-catalog.ts +0 -21
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +17 -3
- package/src/config/schemas/memory-v3.ts +58 -8
- package/src/config/seed-inference-profiles.ts +18 -0
- package/src/context/compactor.ts +22 -4
- package/src/context/post-turn-tool-result-truncation.ts +39 -1
- package/src/context/strip-injections.ts +8 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +18 -36
- package/src/daemon/conversation-agent-loop.ts +308 -1297
- package/src/daemon/conversation-error.ts +31 -4
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +11 -255
- package/src/daemon/conversation-media-retry.ts +19 -6
- package/src/daemon/conversation-messaging.ts +17 -0
- package/src/daemon/conversation-process.ts +22 -141
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +361 -393
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +165 -11
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +444 -62
- package/src/daemon/disk-pressure-policy.ts +0 -1
- package/src/daemon/external-plugins-bootstrap.ts +36 -46
- package/src/daemon/handlers/config-channels.ts +11 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +72 -57
- package/src/daemon/host-proxy-preactivation.ts +1 -3
- package/src/daemon/lifecycle.ts +21 -7
- package/src/daemon/persist-unsendable-image.ts +62 -25
- package/src/daemon/process-message.ts +1 -1
- package/src/daemon/server.ts +2 -0
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/daemon/wake-conversation-ops.ts +269 -0
- package/src/embedded/plugin-api.ts +2 -2
- package/src/export/__tests__/transcript-formatter.test.ts +5 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/memory/__tests__/activation-session-store.test.ts +41 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
- package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
- package/src/memory/activation-session-store.ts +43 -0
- package/src/memory/conversation-crud.ts +29 -19
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/db-init.ts +6 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
- package/src/memory/jobs-worker.ts +25 -1
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
- package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/onboarding-events-store.ts +66 -18
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +13 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
- package/src/memory/v2/__tests__/page-store.test.ts +22 -0
- package/src/memory/v2/consolidation-job.ts +2 -63
- package/src/memory/v2/types.ts +5 -0
- package/src/messaging/providers/telegram-bot/api.ts +14 -5
- package/src/notifications/__tests__/copy-composer.test.ts +244 -0
- package/src/notifications/access-request-copy.ts +298 -0
- package/src/notifications/adapters/slack.ts +3 -3
- package/src/notifications/adapters/telegram.ts +9 -2
- package/src/notifications/copy-composer.ts +49 -267
- package/src/notifications/decision-engine.ts +16 -35
- package/src/notifications/home-feed-side-effect.ts +1 -6
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +40 -11
- package/src/plugin-api/types.ts +108 -0
- package/src/plugins/defaults/compaction/compact.ts +106 -0
- package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
- package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
- package/src/plugins/defaults/compaction/manager-store.ts +57 -0
- package/src/plugins/defaults/compaction/package.json +1 -2
- package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
- package/src/plugins/defaults/empty-response/package.json +0 -1
- package/src/plugins/defaults/history-repair/package.json +0 -1
- package/src/plugins/defaults/index.ts +156 -26
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
- package/src/plugins/defaults/memory-retrieval/package.json +14 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
- package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
- package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -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 +76 -0
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
- package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
- package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
- package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
- package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
- package/src/plugins/defaults/title-generate/package.json +0 -1
- package/src/plugins/defaults/tool-error/package.json +0 -1
- package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
- package/src/plugins/external-api.ts +12 -2
- package/src/plugins/pipeline.ts +6 -293
- package/src/plugins/registry.ts +9 -37
- package/src/plugins/types.ts +76 -381
- package/src/plugins/user-loader.ts +30 -127
- package/src/prompts/__tests__/system-prompt.test.ts +6 -0
- package/src/prompts/system-prompt.ts +61 -10
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
- package/src/providers/anthropic/client.ts +9 -10
- package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
- package/src/providers/inference/logit-bias.ts +55 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -1
- package/src/providers/retry.ts +22 -0
- package/src/providers/types.ts +6 -0
- package/src/runtime/__tests__/agent-wake.test.ts +555 -691
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +108 -209
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
- package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/acp-routes.test.ts +185 -32
- package/src/runtime/routes/acp-routes.ts +328 -30
- package/src/runtime/routes/app-management-routes.ts +3 -0
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/channel-verification-routes.ts +14 -5
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +30 -2
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +18 -3
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
- package/src/runtime/routes/memory-v3-routes.ts +65 -305
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +337 -35
- package/src/runtime/routes/stt-routes.ts +45 -12
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +50 -15
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +147 -2
- package/src/runtime/verification-templates.ts +29 -3
- package/src/services/published-app-updater.ts +30 -8
- package/src/signals/cancel.ts +2 -4
- package/src/subagent/manager.ts +21 -5
- package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
- package/src/telemetry/activation-funnel.ts +167 -0
- package/src/telemetry/types.ts +13 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
- package/src/telemetry/usage-telemetry-reporter.ts +26 -1
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +9 -19
- package/src/tools/acp/list-agents.ts +3 -15
- package/src/tools/acp/spawn.test.ts +173 -202
- package/src/tools/acp/spawn.ts +37 -172
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +166 -50
- package/src/tools/browser/browser-execution.ts +12 -2
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/web-fetch.ts +65 -24
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/ui-surface/definitions.ts +32 -5
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
- package/docs/plugins.md +0 -832
- package/examples/plugins/echo/register.ts +0 -143
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
- package/src/__tests__/pipeline-runner.test.ts +0 -554
- package/src/daemon/wake-target-adapter.ts +0 -253
- package/src/memory/v3/__tests__/assign.test.ts +0 -242
- package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
- package/src/memory/v3/__tests__/core.test.ts +0 -39
- package/src/memory/v3/__tests__/health.test.ts +0 -219
- package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
- package/src/memory/v3/__tests__/needle.test.ts +0 -107
- package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
- package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
- package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
- package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
- package/src/memory/v3/__tests__/router.test.ts +0 -332
- package/src/memory/v3/__tests__/selector.test.ts +0 -470
- package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
- package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
- package/src/memory/v3/__tests__/tree.test.ts +0 -192
- package/src/memory/v3/assign.ts +0 -268
- package/src/memory/v3/capabilities.ts +0 -124
- package/src/memory/v3/core.ts +0 -26
- package/src/memory/v3/health.ts +0 -0
- package/src/memory/v3/maintain-job.ts +0 -314
- package/src/memory/v3/needle.ts +0 -115
- package/src/memory/v3/orchestrate.ts +0 -126
- package/src/memory/v3/page-content.ts +0 -34
- package/src/memory/v3/provider-blocks.ts +0 -26
- package/src/memory/v3/reconcile.ts +0 -523
- package/src/memory/v3/router.ts +0 -190
- package/src/memory/v3/selection-log-store.ts +0 -84
- package/src/memory/v3/selector.ts +0 -226
- package/src/memory/v3/shadow-plugin.ts +0 -411
- package/src/memory/v3/snapshot.ts +0 -209
- package/src/memory/v3/tree.ts +0 -174
- package/src/memory/v3/types.ts +0 -59
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/register.ts +0 -35
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/register.ts +0 -23
- package/src/plugins/defaults/history-repair/register.ts +0 -24
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/title-generate/register.ts +0 -35
- package/src/plugins/defaults/tool-error/register.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
- package/src/proactive-artifact/aux-message-injector.ts +0 -97
- package/src/proactive-artifact/decision.test.ts +0 -226
- package/src/proactive-artifact/decision.ts +0 -165
- package/src/proactive-artifact/index.ts +0 -7
- package/src/proactive-artifact/job.test.ts +0 -962
- package/src/proactive-artifact/job.ts +0 -372
- package/src/proactive-artifact/message-copy.ts +0 -58
- package/src/proactive-artifact/trigger-state.test.ts +0 -286
- package/src/proactive-artifact/trigger-state.ts +0 -123
- package/src/util/map-limit.ts +0 -27
- /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__/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}/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}/llm-retry.ts +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory v3 — synthetic capability rows (skills + `assistant` CLI commands).
|
|
3
|
+
*
|
|
4
|
+
* The assistant's invokable capabilities — installed/catalog skills and
|
|
5
|
+
* top-level CLI subcommands — are seeded as synthetic concept-collection rows
|
|
6
|
+
* (`skills/<id>`, `cli-commands/<name>`). The section-lane retrieval pipeline
|
|
7
|
+
* surfaces the relevant ones per turn, same as concept pages.
|
|
8
|
+
*
|
|
9
|
+
* Page summaries for synthetic slugs already resolve through the existing
|
|
10
|
+
* `pageSummary` lane (the v2 page index appends skill/CLI rows with a summary),
|
|
11
|
+
* so only full-content rendering for the live `<memory>` block needs a synthetic
|
|
12
|
+
* fallback — see {@link renderCapabilityContent}.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
getCliCommandCapability,
|
|
17
|
+
isCliCommandSlug,
|
|
18
|
+
} from "../../../memory/v2/cli-command-store.js";
|
|
19
|
+
import {
|
|
20
|
+
getSkillCapability,
|
|
21
|
+
isSkillSlug,
|
|
22
|
+
} from "../../../memory/v2/skill-store.js";
|
|
23
|
+
import type { Slug } from "./types.js";
|
|
24
|
+
|
|
25
|
+
/** True iff the slug is a synthetic skill or CLI-command capability row. */
|
|
26
|
+
export function isCapabilitySlug(slug: Slug): boolean {
|
|
27
|
+
return isSkillSlug(slug) || isCliCommandSlug(slug);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface CapabilityEntry {
|
|
31
|
+
id: string;
|
|
32
|
+
content: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface CapabilityResolvers {
|
|
36
|
+
skill: (idOrSlug: string) => CapabilityEntry | null;
|
|
37
|
+
cli: (idOrSlug: string) => CapabilityEntry | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const defaultResolvers: CapabilityResolvers = {
|
|
41
|
+
skill: getSkillCapability,
|
|
42
|
+
cli: getCliCommandCapability,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Render a synthetic skill/CLI slug's full capability content for the live
|
|
47
|
+
* `<memory>` block, mirroring {@link renderV3PageContent}'s `# header\n<content>`
|
|
48
|
+
* shape. Returns:
|
|
49
|
+
* - the rendered block when the slug is a capability slug and resolves;
|
|
50
|
+
* - `""` when it is a capability slug but the cache has no entry (degrade to a
|
|
51
|
+
* blank section rather than throwing or falling through to an on-disk read
|
|
52
|
+
* that would also miss);
|
|
53
|
+
* - `null` when the slug is NOT a capability slug, so the caller falls through
|
|
54
|
+
* to its normal on-disk page rendering.
|
|
55
|
+
*
|
|
56
|
+
* `resolvers` is injectable for tests; production uses the v2 store caches.
|
|
57
|
+
*/
|
|
58
|
+
export function renderCapabilityContent(
|
|
59
|
+
slug: Slug,
|
|
60
|
+
resolvers: CapabilityResolvers = defaultResolvers,
|
|
61
|
+
): string | null {
|
|
62
|
+
if (isSkillSlug(slug)) {
|
|
63
|
+
const entry = resolvers.skill(slug);
|
|
64
|
+
return entry ? `# Skill: ${entry.id}\n${entry.content}` : "";
|
|
65
|
+
}
|
|
66
|
+
if (isCliCommandSlug(slug)) {
|
|
67
|
+
const entry = resolvers.cli(slug);
|
|
68
|
+
return entry ? `# CLI command: ${entry.id}\n${entry.content}` : "";
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Resolve a slug's frontmatter-stripped body for the section index: synthetic
|
|
75
|
+
* skill/CLI capability slugs have no on-disk page, so they contribute their
|
|
76
|
+
* rendered capability content (exactly what `page-content.ts` injects for them),
|
|
77
|
+
* while real pages fall through to `readDiskBody`. Shared by `initLanes`'
|
|
78
|
+
* `pageBody` and the full-backfill body reader so the capability-or-disk dispatch
|
|
79
|
+
* lives in one place.
|
|
80
|
+
*
|
|
81
|
+
* `readDiskBody` is injected (rather than imported) so this helper does not pull
|
|
82
|
+
* the page store into `capabilities.ts` — each caller supplies its own cached or
|
|
83
|
+
* direct disk reader.
|
|
84
|
+
*/
|
|
85
|
+
export async function capabilityOrDiskBody(
|
|
86
|
+
slug: Slug,
|
|
87
|
+
readDiskBody: (slug: Slug) => Promise<string>,
|
|
88
|
+
): Promise<string> {
|
|
89
|
+
if (isCapabilitySlug(slug)) return renderCapabilityContent(slug) ?? "";
|
|
90
|
+
return readDiskBody(slug);
|
|
91
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory v3 — dense retrieval lane (section-grain)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Read counterpart to `section-dense-store.ts`. Embeds the turn query and runs
|
|
6
|
+
// a single cosine search against the `memory_v3_sections` collection, then
|
|
7
|
+
// dedupes the matched section points down to the top-`k` distinct articles —
|
|
8
|
+
// each carrying its best-scoring section ordinal. This is the dense lane of the
|
|
9
|
+
// section-grain retrieval design: where the v2 dense lane matches whole pages,
|
|
10
|
+
// this one matches the single most relevant section of a long article and hands
|
|
11
|
+
// the orchestrator both the article and which section matched (so the selector
|
|
12
|
+
// can show the matched section as the descriptor).
|
|
13
|
+
//
|
|
14
|
+
// Degrades safely: any embedding or Qdrant failure logs a warning and returns
|
|
15
|
+
// `[]`. The orchestrator unions the other lanes (needle, edge) plus carry-
|
|
16
|
+
// forward regardless, so a dense outage narrows recall but never breaks a turn.
|
|
17
|
+
|
|
18
|
+
import type { AssistantConfig } from "../../../config/types.js";
|
|
19
|
+
import { embedWithBackend } from "../../../memory/embedding-backend.js";
|
|
20
|
+
import { getLogger } from "../../../util/logger.js";
|
|
21
|
+
import {
|
|
22
|
+
getSectionDenseClient,
|
|
23
|
+
SECTION_COLLECTION,
|
|
24
|
+
} from "./section-dense-store.js";
|
|
25
|
+
import type { Slug } from "./types.js";
|
|
26
|
+
|
|
27
|
+
const log = getLogger("memory-v3-dense-lane");
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Multiplier applied to `k` when fetching section points from Qdrant. Several
|
|
31
|
+
* sections can belong to the same article, so we oversample the section hits to
|
|
32
|
+
* leave room for the article-level dedupe to still yield `k` distinct articles.
|
|
33
|
+
*/
|
|
34
|
+
export const OVERSAMPLE = 6;
|
|
35
|
+
|
|
36
|
+
/** A single dense-lane hit: an article plus the section ordinal that matched. */
|
|
37
|
+
export interface DenseHit {
|
|
38
|
+
article: Slug;
|
|
39
|
+
section: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Run the dense lane: embed `query`, search the section collection for the top
|
|
44
|
+
* `k * OVERSAMPLE` section points, then dedupe to the top-`k` distinct articles
|
|
45
|
+
* — each with its best-scoring section ordinal. Section points are returned by
|
|
46
|
+
* Qdrant in descending score order, so the first time an article is seen is its
|
|
47
|
+
* best section; subsequent sections of the same article are ignored.
|
|
48
|
+
*
|
|
49
|
+
* Returns `[]` on any embedding or Qdrant failure (logged at warn level).
|
|
50
|
+
*/
|
|
51
|
+
export async function denseLane(
|
|
52
|
+
config: AssistantConfig,
|
|
53
|
+
query: string,
|
|
54
|
+
k: number,
|
|
55
|
+
): Promise<DenseHit[]> {
|
|
56
|
+
if (k <= 0) return [];
|
|
57
|
+
|
|
58
|
+
let points: Array<{ payload?: unknown; score?: number }>;
|
|
59
|
+
try {
|
|
60
|
+
const { vectors } = await embedWithBackend(config, [query]);
|
|
61
|
+
const vector = vectors[0];
|
|
62
|
+
if (!vector || vector.length === 0) return [];
|
|
63
|
+
|
|
64
|
+
const result = await getSectionDenseClient(config).query(
|
|
65
|
+
SECTION_COLLECTION,
|
|
66
|
+
{
|
|
67
|
+
query: vector,
|
|
68
|
+
limit: k * OVERSAMPLE,
|
|
69
|
+
with_payload: true,
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
points = result.points;
|
|
73
|
+
} catch (err) {
|
|
74
|
+
log.warn({ err }, "memory v3 dense lane failed; degrading to no hits");
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Walk hits in score order, keeping the first (best) section per article and
|
|
79
|
+
// stopping once we have `k` distinct articles.
|
|
80
|
+
const seen = new Set<Slug>();
|
|
81
|
+
const hits: DenseHit[] = [];
|
|
82
|
+
for (const point of points) {
|
|
83
|
+
const payload = point.payload as
|
|
84
|
+
| { article?: unknown; ordinal?: unknown }
|
|
85
|
+
| null
|
|
86
|
+
| undefined;
|
|
87
|
+
const article = payload?.article;
|
|
88
|
+
const ordinal = payload?.ordinal;
|
|
89
|
+
if (typeof article !== "string" || typeof ordinal !== "number") continue;
|
|
90
|
+
if (seen.has(article)) continue;
|
|
91
|
+
seen.add(article);
|
|
92
|
+
hits.push({ article, section: ordinal });
|
|
93
|
+
if (hits.length >= k) break;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return hits;
|
|
97
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import type { PageIndexEntry } from "../../../memory/v2/page-index.js";
|
|
2
|
+
import { parseFrontmatterFields } from "../../../skills/frontmatter.js";
|
|
3
|
+
import type { Slug } from "./types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Edge lane for memory-v3 retrieval: a directed article link-graph used to
|
|
7
|
+
* expand a turn's lexical/dense seeds outward to their first-class neighbours.
|
|
8
|
+
*
|
|
9
|
+
* The graph unions THREE outbound-edge sources per article:
|
|
10
|
+
*
|
|
11
|
+
* (a) The optional `links:` frontmatter — a YAML list of
|
|
12
|
+
* `"<target-slug> — <description>"` strings (split on the first
|
|
13
|
+
* ` — `, space-emdash-space). This is the authored, first-class edge
|
|
14
|
+
* source: the curated description is carried through expansion so the
|
|
15
|
+
* orchestrator can use it directly as a select descriptor.
|
|
16
|
+
* (b) Inline `[[wikilink]]` targets parsed from the body.
|
|
17
|
+
* (c) `PageIndexEntry.edges` numeric ids resolved to slugs — the fallback
|
|
18
|
+
* for pages with no frontmatter `links`.
|
|
19
|
+
*
|
|
20
|
+
* All targets are resolved against the corpus slug set; unknown/dangling
|
|
21
|
+
* targets are dropped. A curated description is stored per (source → target)
|
|
22
|
+
* edge only when the `links` source supplied one; wikilink/numeric edges carry
|
|
23
|
+
* no description (the orchestrator falls back to a section descriptor).
|
|
24
|
+
*
|
|
25
|
+
* The build is pure given a `pageRaw` reader callback (no hard-coded I/O), so
|
|
26
|
+
* it is built once at lane-init and rebuilt by the maintain job, and is
|
|
27
|
+
* trivially unit-testable with a stub reader.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** Default in-degree above which an article is treated as a hub and excluded
|
|
31
|
+
* from expansion (a hub neighbour is too generic to be a useful surface). */
|
|
32
|
+
const DEFAULT_HUB_DEGREE = 30;
|
|
33
|
+
|
|
34
|
+
const DEFAULT_SEED_COUNT = 18;
|
|
35
|
+
const DEFAULT_PER_SEED = 6;
|
|
36
|
+
const DEFAULT_CAP = 45;
|
|
37
|
+
|
|
38
|
+
/** Matches the space-emdash-space separator in a `links:` entry. */
|
|
39
|
+
const LINK_SEPARATOR = " — ";
|
|
40
|
+
|
|
41
|
+
/** Matches `[[target]]` wikilinks; captures the raw target before any `|`
|
|
42
|
+
* display-text or `#section` anchor. */
|
|
43
|
+
const WIKILINK_REGEX = /\[\[([^\]]+)\]\]/g;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The directed link-graph. `adjacency` maps each source slug to its outbound
|
|
47
|
+
* edges (target slug → curated description, or `undefined` when the edge came
|
|
48
|
+
* from a wikilink/numeric source). `hubs` is the set of high-in-degree slugs
|
|
49
|
+
* excluded from expansion. `slugs` is the resolved corpus slug set.
|
|
50
|
+
*/
|
|
51
|
+
export interface EdgeGraph {
|
|
52
|
+
adjacency: Map<Slug, Map<Slug, string | undefined>>;
|
|
53
|
+
hubs: Set<Slug>;
|
|
54
|
+
slugs: Set<Slug>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** One article surfaced by {@link edgeExpand}, with the curated `links`
|
|
58
|
+
* description of the traversed edge when it carried one (else `undefined`). */
|
|
59
|
+
export interface EdgeNeighbor {
|
|
60
|
+
article: Slug;
|
|
61
|
+
description?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface EdgeExpandOptions {
|
|
65
|
+
/** Predicate gating which neighbours may be surfaced (e.g. liveness /
|
|
66
|
+
* not-already-selected). Neighbours failing `alive` are skipped. */
|
|
67
|
+
alive?: (slug: Slug) => boolean;
|
|
68
|
+
/** Only the top `seedCount` seeds (in input order) are expanded. */
|
|
69
|
+
seedCount?: number;
|
|
70
|
+
/** Up to `perSeed` neighbours are added per expanded seed. */
|
|
71
|
+
perSeed?: number;
|
|
72
|
+
/** Hard cap on the total number of distinct surfaced articles. */
|
|
73
|
+
cap?: number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface BuildEdgeGraphOptions {
|
|
77
|
+
/** In-degree above which an article is a hub. Defaults to
|
|
78
|
+
* {@link DEFAULT_HUB_DEGREE}. */
|
|
79
|
+
hubDegree?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Split one `links:` entry (`"<target-slug> — <description>"`) into its target
|
|
84
|
+
* slug and curated description on the FIRST ` — ` (space-emdash-space).
|
|
85
|
+
* Entries with no separator are bare target slugs and carry no description.
|
|
86
|
+
*/
|
|
87
|
+
function parseLinkEntry(entry: string): {
|
|
88
|
+
target: Slug;
|
|
89
|
+
description: string | undefined;
|
|
90
|
+
} {
|
|
91
|
+
const sep = entry.indexOf(LINK_SEPARATOR);
|
|
92
|
+
if (sep === -1) return { target: entry.trim(), description: undefined };
|
|
93
|
+
return {
|
|
94
|
+
target: entry.slice(0, sep).trim(),
|
|
95
|
+
description: entry.slice(sep + LINK_SEPARATOR.length).trim() || undefined,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Parse inline `[[wikilink]]` targets from a body. Strips `|display` and
|
|
100
|
+
* `#anchor` suffixes; returns trimmed target slugs (possibly with duplicates,
|
|
101
|
+
* deduped by the caller's map insertion). */
|
|
102
|
+
function parseWikilinks(body: string): string[] {
|
|
103
|
+
const targets: string[] = [];
|
|
104
|
+
for (const match of body.matchAll(WIKILINK_REGEX)) {
|
|
105
|
+
let target = match[1];
|
|
106
|
+
const pipe = target.indexOf("|");
|
|
107
|
+
if (pipe !== -1) target = target.slice(0, pipe);
|
|
108
|
+
const hash = target.indexOf("#");
|
|
109
|
+
if (hash !== -1) target = target.slice(0, hash);
|
|
110
|
+
target = target.trim();
|
|
111
|
+
if (target) targets.push(target);
|
|
112
|
+
}
|
|
113
|
+
return targets;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build the directed article link-graph from the page-index entries and a raw
|
|
118
|
+
* page reader. See the module docstring for the three unioned edge sources.
|
|
119
|
+
*
|
|
120
|
+
* Pure given `pageRaw`: the build performs no hard-coded I/O. A read that
|
|
121
|
+
* rejects drops that article's authored/wikilink edges but still keeps its
|
|
122
|
+
* numeric `PageIndexEntry.edges` fallback.
|
|
123
|
+
*/
|
|
124
|
+
export async function buildEdgeGraph(
|
|
125
|
+
articles: readonly PageIndexEntry[],
|
|
126
|
+
pageRaw: (slug: Slug) => Promise<string>,
|
|
127
|
+
opts: BuildEdgeGraphOptions = {},
|
|
128
|
+
): Promise<EdgeGraph> {
|
|
129
|
+
const hubDegree = opts.hubDegree ?? DEFAULT_HUB_DEGREE;
|
|
130
|
+
|
|
131
|
+
const slugs = new Set<Slug>(articles.map((a) => a.slug));
|
|
132
|
+
const byId = new Map<number, Slug>(articles.map((a) => [a.id, a.slug]));
|
|
133
|
+
|
|
134
|
+
const raws = await Promise.all(
|
|
135
|
+
articles.map((a) =>
|
|
136
|
+
pageRaw(a.slug).then(
|
|
137
|
+
(text) => text,
|
|
138
|
+
() => null, // read failed — fall back to numeric edges only
|
|
139
|
+
),
|
|
140
|
+
),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const adjacency = new Map<Slug, Map<Slug, string | undefined>>();
|
|
144
|
+
const inDegree = new Map<Slug, number>();
|
|
145
|
+
|
|
146
|
+
const addEdge = (
|
|
147
|
+
source: Slug,
|
|
148
|
+
target: Slug,
|
|
149
|
+
description: string | undefined,
|
|
150
|
+
): void => {
|
|
151
|
+
if (target === source) return; // no self-edges
|
|
152
|
+
if (!slugs.has(target)) return; // drop unknown/dangling targets
|
|
153
|
+
let out = adjacency.get(source);
|
|
154
|
+
if (!out) {
|
|
155
|
+
out = new Map();
|
|
156
|
+
adjacency.set(source, out);
|
|
157
|
+
}
|
|
158
|
+
if (!out.has(target)) {
|
|
159
|
+
out.set(target, description);
|
|
160
|
+
inDegree.set(target, (inDegree.get(target) ?? 0) + 1);
|
|
161
|
+
} else if (out.get(target) === undefined && description !== undefined) {
|
|
162
|
+
// A later source (the authored `links`) supplies a description for an
|
|
163
|
+
// edge first seen without one — upgrade it. In-degree already counted.
|
|
164
|
+
out.set(target, description);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
for (let i = 0; i < articles.length; i++) {
|
|
169
|
+
const article = articles[i];
|
|
170
|
+
const source = article.slug;
|
|
171
|
+
const raw = raws[i];
|
|
172
|
+
|
|
173
|
+
// (a) authored `links:` frontmatter — primary, carries descriptions.
|
|
174
|
+
const parsed = raw !== null ? parseFrontmatterFields(raw) : null;
|
|
175
|
+
const links = parsed?.fields.links;
|
|
176
|
+
if (Array.isArray(links)) {
|
|
177
|
+
for (const entry of links) {
|
|
178
|
+
if (typeof entry !== "string") continue;
|
|
179
|
+
const { target, description } = parseLinkEntry(entry);
|
|
180
|
+
addEdge(source, target, description);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// (b) inline `[[wikilink]]` targets from the body. `parsed.body` strips
|
|
185
|
+
// the frontmatter; a page without frontmatter has `parsed === null`, so
|
|
186
|
+
// the whole raw text is the body.
|
|
187
|
+
const body = parsed ? parsed.body : raw;
|
|
188
|
+
if (body !== null) {
|
|
189
|
+
for (const target of parseWikilinks(body)) {
|
|
190
|
+
addEdge(source, target, undefined);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// (c) numeric page-index edges resolved to slugs — fallback.
|
|
195
|
+
for (const targetId of article.edges) {
|
|
196
|
+
const target = byId.get(targetId);
|
|
197
|
+
if (target) addEdge(source, target, undefined);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const hubs = new Set<Slug>();
|
|
202
|
+
for (const [slug, degree] of inDegree) {
|
|
203
|
+
if (degree > hubDegree) hubs.add(slug);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return { adjacency, hubs, slugs };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Expand `seeds` outward along the graph. For each of the top `seedCount`
|
|
211
|
+
* seeds (in input order), surface up to `perSeed` non-hub, `alive`-passing
|
|
212
|
+
* neighbours, capped at `cap` total distinct articles. Seeds themselves are
|
|
213
|
+
* not surfaced (they are already in the pool). Each surfaced article carries
|
|
214
|
+
* the curated `links` description of the traversed edge when it had one.
|
|
215
|
+
*
|
|
216
|
+
* Deterministic given the input seed order and the graph's insertion order.
|
|
217
|
+
*/
|
|
218
|
+
export function edgeExpand(
|
|
219
|
+
graph: EdgeGraph,
|
|
220
|
+
seeds: readonly Slug[],
|
|
221
|
+
opts: EdgeExpandOptions = {},
|
|
222
|
+
): EdgeNeighbor[] {
|
|
223
|
+
const seedCount = opts.seedCount ?? DEFAULT_SEED_COUNT;
|
|
224
|
+
const perSeed = opts.perSeed ?? DEFAULT_PER_SEED;
|
|
225
|
+
const cap = opts.cap ?? DEFAULT_CAP;
|
|
226
|
+
const alive = opts.alive;
|
|
227
|
+
|
|
228
|
+
const seedSet = new Set<Slug>(seeds);
|
|
229
|
+
const surfaced = new Map<Slug, string | undefined>();
|
|
230
|
+
|
|
231
|
+
for (const seed of seeds.slice(0, seedCount)) {
|
|
232
|
+
if (surfaced.size >= cap) break;
|
|
233
|
+
const out = graph.adjacency.get(seed);
|
|
234
|
+
if (!out) continue;
|
|
235
|
+
let added = 0;
|
|
236
|
+
for (const [target, description] of out) {
|
|
237
|
+
if (added >= perSeed) break;
|
|
238
|
+
if (surfaced.size >= cap) break;
|
|
239
|
+
if (seedSet.has(target)) continue; // already in the pool
|
|
240
|
+
if (surfaced.has(target)) continue; // already surfaced via another seed
|
|
241
|
+
if (graph.hubs.has(target)) continue; // hubs excluded
|
|
242
|
+
if (alive && !alive(target)) continue;
|
|
243
|
+
surfaced.set(target, description);
|
|
244
|
+
added++;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return [...surfaced].map(([article, description]) => ({
|
|
249
|
+
article,
|
|
250
|
+
description,
|
|
251
|
+
}));
|
|
252
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No-op `post-compact` scaffolding for the memory-v3-shadow plugin.
|
|
3
|
+
*
|
|
4
|
+
* v3 re-injection after mid-turn compaction is not yet owned by this plugin —
|
|
5
|
+
* the active injector still runs through the static chain. Once the
|
|
6
|
+
* post-compaction hook API stabilizes we will import `memoryV3Injector` from
|
|
7
|
+
* `../injector.js` and re-apply it here. Until then this hook does nothing.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { PluginHookFn } from "@vellumai/plugin-api";
|
|
11
|
+
|
|
12
|
+
const postCompact: PluginHookFn = async () => {};
|
|
13
|
+
|
|
14
|
+
export default postCompact;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* No-op `user-prompt-submit` scaffolding for the memory-v3-shadow plugin.
|
|
3
|
+
*
|
|
4
|
+
* The v3 injector currently runs through the static injector chain
|
|
5
|
+
* (`memory-retrieval/injector-chain.ts`), not through this hook. Once the
|
|
6
|
+
* prompt-submit hook API stabilizes we will import `memoryV3Injector` from
|
|
7
|
+
* `../injector.js` and run it here, so v3 injection is owned by the plugin's
|
|
8
|
+
* own lifecycle rather than the loop-driven chain. Until then this hook
|
|
9
|
+
* intentionally does nothing.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type {
|
|
13
|
+
PluginHookFn,
|
|
14
|
+
UserPromptSubmitContext,
|
|
15
|
+
} from "@vellumai/plugin-api";
|
|
16
|
+
|
|
17
|
+
const userPromptSubmit: PluginHookFn<UserPromptSubmitContext> = async () => {};
|
|
18
|
+
|
|
19
|
+
export default userPromptSubmit;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The memory-v3 {@link Injector}. Reads both v3 flags:
|
|
3
|
+
* - `memory-v3-live` on → orchestrate, log, render the working-set selection
|
|
4
|
+
* into a `<memory>` block, and return it at v2's dynamic-memory placement.
|
|
5
|
+
* - `memory-v3-shadow` on (live off) → orchestrate + log only, return `null`.
|
|
6
|
+
* - both off → return `null` (no orchestration).
|
|
7
|
+
*
|
|
8
|
+
* Empty selection and any failure return `null` (no v3 injection). v2
|
|
9
|
+
* suppression keys off BOTH the flag AND this return value, so a `null` here
|
|
10
|
+
* (failure or empty selection) falls back to v2 memory rather than dropping all
|
|
11
|
+
* memory.
|
|
12
|
+
*
|
|
13
|
+
* Orchestration and telemetry live in {@link observeTurn}; this module is the
|
|
14
|
+
* thin injector wrapper that renders the result for live injection.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { isAssistantFeatureFlagEnabled } from "../../../config/assistant-feature-flags.js";
|
|
18
|
+
import { getConfig } from "../../../config/loader.js";
|
|
19
|
+
import { getLogger } from "../../../util/logger.js";
|
|
20
|
+
import {
|
|
21
|
+
type InjectionBlock,
|
|
22
|
+
type Injector,
|
|
23
|
+
type TurnContext,
|
|
24
|
+
} from "../../types.js";
|
|
25
|
+
import { renderV3SectionContent } from "./page-content.js";
|
|
26
|
+
import { renderMemoryBlock } from "./render-injection.js";
|
|
27
|
+
import {
|
|
28
|
+
MEMORY_V3_LIVE,
|
|
29
|
+
MEMORY_V3_SHADOW,
|
|
30
|
+
observeTurn,
|
|
31
|
+
} from "./shadow-plugin.js";
|
|
32
|
+
import { MEMORY_V3_BLOCK_ID } from "./types.js";
|
|
33
|
+
|
|
34
|
+
const log = getLogger("memory-v3-shadow");
|
|
35
|
+
|
|
36
|
+
export const memoryV3Injector: Injector = {
|
|
37
|
+
name: "memory-v3-shadow",
|
|
38
|
+
// High order so it sorts last; the live `<memory>` block uses the
|
|
39
|
+
// after-memory-prefix placement so it lands at the memory boundary regardless
|
|
40
|
+
// of this sort key, which only orders content-producing injectors.
|
|
41
|
+
order: 1000,
|
|
42
|
+
async produce(ctx: TurnContext): Promise<InjectionBlock | null> {
|
|
43
|
+
const config = getConfig();
|
|
44
|
+
const live = isAssistantFeatureFlagEnabled(MEMORY_V3_LIVE, config);
|
|
45
|
+
const shadow = isAssistantFeatureFlagEnabled(MEMORY_V3_SHADOW, config);
|
|
46
|
+
if (!live && !shadow) return null;
|
|
47
|
+
|
|
48
|
+
const result = await observeTurn(ctx.conversationId, ctx.turnIndex);
|
|
49
|
+
if (!live || !result) return null;
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// `renderMemoryBlock` returns "" for an empty selection; inject nothing.
|
|
53
|
+
const text = await renderMemoryBlock(
|
|
54
|
+
result.finalInjection,
|
|
55
|
+
result.sectionBySlug,
|
|
56
|
+
renderV3SectionContent,
|
|
57
|
+
);
|
|
58
|
+
if (text.length === 0) return null;
|
|
59
|
+
return {
|
|
60
|
+
id: MEMORY_V3_BLOCK_ID,
|
|
61
|
+
text,
|
|
62
|
+
// Mirror v2's dynamic `<memory>` block placement.
|
|
63
|
+
placement: "after-memory-prefix",
|
|
64
|
+
};
|
|
65
|
+
} catch (err) {
|
|
66
|
+
log.warn(
|
|
67
|
+
{
|
|
68
|
+
err: err instanceof Error ? err.message : String(err),
|
|
69
|
+
conversationId: ctx.conversationId,
|
|
70
|
+
},
|
|
71
|
+
"memory-v3 live render failed (non-fatal) — falling back to v2",
|
|
72
|
+
);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|