@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091926.ebb2d62
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 +273 -121
- package/package.json +2 -2
- package/scripts/sync-llm-catalog.ts +2 -0
- 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__/build-persisted-content.test.ts +75 -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__/config-managed-gemini-defaults.test.ts +2 -46
- 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-execution-feature-gates.test.ts +5 -4
- 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__/embedding-managed-proxy-selection.test.ts +6 -40
- 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-catalog-parity.test.ts +4 -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__/persistence-secret-redaction.test.ts +78 -0
- 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__/retry-thinking-adaptive-only.test.ts +245 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +39 -0
- 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__/tool-start-timestamp.test.ts +218 -0
- 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/events/tool-result.ts +9 -0
- package/src/api/events/tool-use-start.ts +7 -0
- package/src/api/responses/conversation-message.ts +72 -13
- 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 -56
- package/src/config/llm-resolver.ts +39 -7
- package/src/config/loader.ts +5 -22
- 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 +120 -42
- 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/shared.ts +9 -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/embedding-backend.ts +5 -22
- 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 +57 -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 +57 -7
- 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
|
@@ -110,7 +110,7 @@ describe("memory-v3-live v2 suppression", () => {
|
|
|
110
110
|
];
|
|
111
111
|
|
|
112
112
|
const result = await applyRuntimeInjections(runMessages, {
|
|
113
|
-
|
|
113
|
+
...makeTurnContext(),
|
|
114
114
|
});
|
|
115
115
|
|
|
116
116
|
// Exactly one <memory> source across the WHOLE assembled context.
|
|
@@ -149,7 +149,7 @@ describe("memory-v3-live v2 suppression", () => {
|
|
|
149
149
|
];
|
|
150
150
|
|
|
151
151
|
const result = await applyRuntimeInjections(runMessages, {
|
|
152
|
-
|
|
152
|
+
...makeTurnContext(),
|
|
153
153
|
});
|
|
154
154
|
|
|
155
155
|
// v2's block survives — the turn still ships memory.
|
|
@@ -177,7 +177,7 @@ describe("memory-v3-live v2 suppression", () => {
|
|
|
177
177
|
// captures the exact pre-flag assembly behavior: v2 prefix stays, v3
|
|
178
178
|
// splices after it.
|
|
179
179
|
const offResult = await applyRuntimeInjections(runMessages, {
|
|
180
|
-
|
|
180
|
+
...makeTurnContext(),
|
|
181
181
|
});
|
|
182
182
|
|
|
183
183
|
// The tail keeps v2's block AND gains v3's (the historical double-injection
|
|
@@ -206,7 +206,7 @@ describe("memory-v3-live v2 suppression", () => {
|
|
|
206
206
|
];
|
|
207
207
|
|
|
208
208
|
const result = await applyRuntimeInjections(runMessages, {
|
|
209
|
-
|
|
209
|
+
...makeTurnContext(),
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
expect(result.messages).toEqual(runMessages);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for handleListMessages clientMessageId projection.
|
|
3
|
+
*
|
|
4
|
+
* Verifies that the persisted idempotency nonce is echoed back on the
|
|
5
|
+
* messages snapshot row so a client can correlate its optimistic row with
|
|
6
|
+
* the confirmed server row by identity instead of matching message text.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
10
|
+
|
|
11
|
+
mock.module("../util/logger.js", () => ({
|
|
12
|
+
getLogger: () =>
|
|
13
|
+
new Proxy({} as Record<string, unknown>, {
|
|
14
|
+
get: () => () => {},
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
mock.module("../config/loader.js", () => ({
|
|
19
|
+
getConfig: () => ({
|
|
20
|
+
ui: {},
|
|
21
|
+
model: "test",
|
|
22
|
+
provider: "test",
|
|
23
|
+
memory: { enabled: false },
|
|
24
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
25
|
+
}),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
import { addMessage, createConversation } from "../memory/conversation-crud.js";
|
|
29
|
+
import { getDb } from "../memory/db-connection.js";
|
|
30
|
+
import { initializeDb } from "../memory/db-init.js";
|
|
31
|
+
import { handleListMessages } from "../runtime/routes/conversation-routes.js";
|
|
32
|
+
|
|
33
|
+
initializeDb();
|
|
34
|
+
|
|
35
|
+
function resetTables() {
|
|
36
|
+
const db = getDb();
|
|
37
|
+
db.run("DELETE FROM messages");
|
|
38
|
+
db.run("DELETE FROM conversations");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface MessagePayload {
|
|
42
|
+
role: string;
|
|
43
|
+
clientMessageId?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe("handleListMessages clientMessageId", () => {
|
|
47
|
+
beforeEach(resetTables);
|
|
48
|
+
|
|
49
|
+
test("echoes the persisted clientMessageId onto the user row", async () => {
|
|
50
|
+
// GIVEN a user message persisted with a client-generated idempotency nonce
|
|
51
|
+
const conv = createConversation();
|
|
52
|
+
await addMessage(
|
|
53
|
+
conv.id,
|
|
54
|
+
"user",
|
|
55
|
+
JSON.stringify([{ type: "text", text: "hello" }]),
|
|
56
|
+
{ clientMessageId: "nonce-abc", skipIndexing: true },
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// WHEN the messages snapshot is built
|
|
60
|
+
const response = handleListMessages({
|
|
61
|
+
queryParams: { conversationId: conv.id },
|
|
62
|
+
});
|
|
63
|
+
const body = response as { messages: MessagePayload[] };
|
|
64
|
+
|
|
65
|
+
// THEN the snapshot row carries the nonce back for id-based correlation
|
|
66
|
+
expect(body.messages).toHaveLength(1);
|
|
67
|
+
expect(body.messages[0].role).toBe("user");
|
|
68
|
+
expect(body.messages[0].clientMessageId).toBe("nonce-abc");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("omits clientMessageId when the row was persisted without one", async () => {
|
|
72
|
+
// GIVEN a user message persisted without a client nonce (e.g. a channel send)
|
|
73
|
+
const conv = createConversation();
|
|
74
|
+
await addMessage(
|
|
75
|
+
conv.id,
|
|
76
|
+
"user",
|
|
77
|
+
JSON.stringify([{ type: "text", text: "hello" }]),
|
|
78
|
+
{ skipIndexing: true },
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// WHEN the messages snapshot is built
|
|
82
|
+
const response = handleListMessages({
|
|
83
|
+
queryParams: { conversationId: conv.id },
|
|
84
|
+
});
|
|
85
|
+
const body = response as { messages: MessagePayload[] };
|
|
86
|
+
|
|
87
|
+
// THEN the field is absent rather than emitted as null/empty
|
|
88
|
+
expect(body.messages).toHaveLength(1);
|
|
89
|
+
expect(body.messages[0].clientMessageId).toBeUndefined();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -96,6 +96,44 @@ describe("handleListMessages metadata.hidden filtering", () => {
|
|
|
96
96
|
expect(llmRows[1].metadata).toContain('"hidden":true');
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
+
test("UI serializer omits system rows but LLM-side getMessages includes them", async () => {
|
|
100
|
+
// GIVEN a conversation with a system row sandwiched between two
|
|
101
|
+
// renderable turns (e.g. a skill-authored context message)
|
|
102
|
+
const conv = createConversation();
|
|
103
|
+
await addMessage(
|
|
104
|
+
conv.id,
|
|
105
|
+
"user",
|
|
106
|
+
JSON.stringify([{ type: "text", text: "first visible" }]),
|
|
107
|
+
);
|
|
108
|
+
await addMessage(
|
|
109
|
+
conv.id,
|
|
110
|
+
"system",
|
|
111
|
+
JSON.stringify([{ type: "text", text: "system scaffolding" }]),
|
|
112
|
+
);
|
|
113
|
+
await addMessage(
|
|
114
|
+
conv.id,
|
|
115
|
+
"assistant",
|
|
116
|
+
JSON.stringify([{ type: "text", text: "second visible" }]),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// WHEN the UI history list is serialized
|
|
120
|
+
const response = handleListMessages({
|
|
121
|
+
queryParams: { conversationId: conv.id },
|
|
122
|
+
});
|
|
123
|
+
const body = response as { messages: MessagePayload[] };
|
|
124
|
+
|
|
125
|
+
// THEN only the user/assistant turns are returned, never the system row
|
|
126
|
+
expect(body.messages.map((m) => m.role)).toEqual(["user", "assistant"]);
|
|
127
|
+
expect(
|
|
128
|
+
body.messages.some((m) => plainText(m).includes("system scaffolding")),
|
|
129
|
+
).toBe(false);
|
|
130
|
+
|
|
131
|
+
// AND the LLM-side loader still includes the system row for agent context
|
|
132
|
+
const llmRows = getMessages(conv.id);
|
|
133
|
+
expect(llmRows).toHaveLength(3);
|
|
134
|
+
expect(llmRows[1].role).toBe("system");
|
|
135
|
+
});
|
|
136
|
+
|
|
99
137
|
test("messages without metadata or with hidden=false are returned", async () => {
|
|
100
138
|
const conv = createConversation();
|
|
101
139
|
await addMessage(
|
|
@@ -53,6 +53,7 @@ interface ClientCatalogModel {
|
|
|
53
53
|
longContextPricingThresholdTokens?: number;
|
|
54
54
|
longContextMode?: "native-model" | "provider-request-option" | "unsupported";
|
|
55
55
|
supportsThinking?: boolean;
|
|
56
|
+
adaptiveThinkingOnly?: boolean;
|
|
56
57
|
supportsCaching?: boolean;
|
|
57
58
|
supportsVision?: boolean;
|
|
58
59
|
supportsToolUse?: boolean;
|
|
@@ -194,6 +195,9 @@ describe("LLM catalog parity: daemon vs client", () => {
|
|
|
194
195
|
);
|
|
195
196
|
expect(clientModel.longContextMode).toBe(daemonModel.longContextMode);
|
|
196
197
|
expect(clientModel.supportsThinking).toBe(daemonModel.supportsThinking);
|
|
198
|
+
expect(clientModel.adaptiveThinkingOnly).toBe(
|
|
199
|
+
daemonModel.adaptiveThinkingOnly,
|
|
200
|
+
);
|
|
197
201
|
expect(clientModel.supportsCaching).toBe(daemonModel.supportsCaching);
|
|
198
202
|
expect(clientModel.supportsVision).toBe(daemonModel.supportsVision);
|
|
199
203
|
expect(clientModel.supportsToolUse).toBe(daemonModel.supportsToolUse);
|
|
@@ -1249,3 +1249,76 @@ describe("resolveDefaultProfileKey", () => {
|
|
|
1249
1249
|
expect(resolveDefaultProfileKey("mainAgent", llm)).toBe("balanced");
|
|
1250
1250
|
});
|
|
1251
1251
|
});
|
|
1252
|
+
|
|
1253
|
+
describe("resolveCallSiteConfig logitBias provenance", () => {
|
|
1254
|
+
const kimi = "accounts/fireworks/models/kimi-k2p6";
|
|
1255
|
+
|
|
1256
|
+
test("forwards logitBias from the active profile that opted in", () => {
|
|
1257
|
+
const llm = LLMSchema.parse({
|
|
1258
|
+
default: fullDefault,
|
|
1259
|
+
profiles: {
|
|
1260
|
+
"balanced-economy": {
|
|
1261
|
+
provider: "fireworks",
|
|
1262
|
+
model: kimi,
|
|
1263
|
+
logitBias: "suppress-cjk",
|
|
1264
|
+
},
|
|
1265
|
+
},
|
|
1266
|
+
activeProfile: "balanced-economy",
|
|
1267
|
+
});
|
|
1268
|
+
expect(resolveCallSiteConfig("mainAgent", llm).logitBias).toBe(
|
|
1269
|
+
"suppress-cjk",
|
|
1270
|
+
);
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
test("a higher-precedence override profile that omits logitBias clears it", () => {
|
|
1274
|
+
// Active profile opts in, but a pinned (override) Kimi profile did not —
|
|
1275
|
+
// the override must not inherit suppress-cjk just because it resolves to
|
|
1276
|
+
// Fireworks.
|
|
1277
|
+
const llm = LLMSchema.parse({
|
|
1278
|
+
default: fullDefault,
|
|
1279
|
+
profiles: {
|
|
1280
|
+
"balanced-economy": {
|
|
1281
|
+
provider: "fireworks",
|
|
1282
|
+
model: kimi,
|
|
1283
|
+
logitBias: "suppress-cjk",
|
|
1284
|
+
},
|
|
1285
|
+
"my-kimi": { provider: "fireworks", model: kimi },
|
|
1286
|
+
},
|
|
1287
|
+
activeProfile: "balanced-economy",
|
|
1288
|
+
});
|
|
1289
|
+
const resolved = resolveCallSiteConfig("mainAgent", llm, {
|
|
1290
|
+
overrideProfile: "my-kimi",
|
|
1291
|
+
});
|
|
1292
|
+
expect(resolved.logitBias).toBeUndefined();
|
|
1293
|
+
});
|
|
1294
|
+
|
|
1295
|
+
test("does not leak the active profile's logitBias into a call site's own profile", () => {
|
|
1296
|
+
// For non-main call sites the call-site profile wins; since it didn't opt
|
|
1297
|
+
// in, the active profile's preset must not bleed through.
|
|
1298
|
+
const llm = LLMSchema.parse({
|
|
1299
|
+
default: fullDefault,
|
|
1300
|
+
profiles: {
|
|
1301
|
+
"balanced-economy": {
|
|
1302
|
+
provider: "fireworks",
|
|
1303
|
+
model: kimi,
|
|
1304
|
+
logitBias: "suppress-cjk",
|
|
1305
|
+
},
|
|
1306
|
+
plain: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
1307
|
+
},
|
|
1308
|
+
activeProfile: "balanced-economy",
|
|
1309
|
+
callSites: { memoryExtraction: { profile: "plain" } },
|
|
1310
|
+
});
|
|
1311
|
+
expect(
|
|
1312
|
+
resolveCallSiteConfig("memoryExtraction", llm).logitBias,
|
|
1313
|
+
).toBeUndefined();
|
|
1314
|
+
});
|
|
1315
|
+
|
|
1316
|
+
test("a logitBias on a non-profile layer (llm.default) does not apply when the winning profile omits it", () => {
|
|
1317
|
+
const llm = LLMSchema.parse({
|
|
1318
|
+
default: { ...fullDefault, logitBias: "suppress-cjk" },
|
|
1319
|
+
profiles: { plain: { provider: "anthropic", model: "claude-opus-4-7" } },
|
|
1320
|
+
activeProfile: "plain",
|
|
1321
|
+
});
|
|
1322
|
+
expect(resolveCallSiteConfig("mainAgent", llm).logitBias).toBeUndefined();
|
|
1323
|
+
});
|
|
1324
|
+
});
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for the default `user-prompt-submit
|
|
2
|
+
* Tests for the default `user-prompt-submit` hook (memory retrieval +
|
|
3
|
+
* runtime injection).
|
|
3
4
|
*
|
|
4
5
|
* Covers the retrieval behavior, the side effects the hook owns (injected-block
|
|
5
|
-
* metadata, recall log, `memory_recalled` event), trust gating,
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* metadata, recall log, `memory_recalled` event), trust gating, the runtime
|
|
7
|
+
* injection the hook applies for every actor (and the assembled-block persist),
|
|
8
|
+
* error propagation, and abort-signal forwarding. Uses `mock.module` to stub
|
|
9
|
+
* the persistence helpers, `applyRuntimeInjections`, and the conversation
|
|
10
|
+
* registry / trust resolver so the test doesn't touch the developer's real
|
|
11
|
+
* `~/.vellum`, database, or live conversation state. The memory graph handle,
|
|
12
|
+
* abort signal, and trust class are self-resolved by the hook from a fake
|
|
13
|
+
* conversation installed in the registry mock.
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
@@ -23,13 +27,52 @@ mock.module("../memory/memory-recall-log-store.js", () => ({
|
|
|
23
27
|
recordMemoryRecallLog: recordMemoryRecallLogMock,
|
|
24
28
|
}));
|
|
25
29
|
|
|
30
|
+
// Pass-through injection stub: returns the input messages unchanged with no
|
|
31
|
+
// assembled blocks, so existing array-identity assertions hold. Individual
|
|
32
|
+
// tests override it via `mockImplementationOnce` to exercise injected blocks.
|
|
33
|
+
const applyRuntimeInjectionsMock = mock(async (messages: unknown) => ({
|
|
34
|
+
messages,
|
|
35
|
+
blocks: {},
|
|
36
|
+
}));
|
|
37
|
+
mock.module("../daemon/conversation-runtime-assembly.js", () => ({
|
|
38
|
+
applyRuntimeInjections: applyRuntimeInjectionsMock,
|
|
39
|
+
resolveTurnInboundActorContext: () => null,
|
|
40
|
+
resolveTurnModelProfileLabel: () => null,
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
// The hook self-resolves the live conversation and its trust class; both are
|
|
44
|
+
// driven from these refs so each test controls what the hook sees.
|
|
45
|
+
let currentConversation: Conversation | undefined;
|
|
46
|
+
let currentTrustClass: "guardian" | "unknown" = "guardian";
|
|
47
|
+
const findConversationOrSubagentMock = mock(
|
|
48
|
+
(_conversationId?: string) => currentConversation,
|
|
49
|
+
);
|
|
50
|
+
mock.module("../daemon/conversation-registry.js", () => ({
|
|
51
|
+
findConversationOrSubagent: findConversationOrSubagentMock,
|
|
52
|
+
}));
|
|
53
|
+
mock.module("../daemon/trust-context.js", () => ({
|
|
54
|
+
resolveTrustClass: () => currentTrustClass,
|
|
55
|
+
}));
|
|
56
|
+
mock.module("../config/loader.js", () => ({
|
|
57
|
+
getConfig: () => ({}) as AssistantConfig,
|
|
58
|
+
}));
|
|
59
|
+
|
|
60
|
+
// The hook publishes `memory_recalled` (and forwards the sink into
|
|
61
|
+
// `prepareMemory` for `memory_status`) through the shared `broadcastMessage`
|
|
62
|
+
// hub. Stub it so tests can assert what the hook emits.
|
|
63
|
+
const broadcastMessageMock = mock((_msg: unknown) => {});
|
|
64
|
+
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
65
|
+
broadcastMessage: broadcastMessageMock,
|
|
66
|
+
}));
|
|
67
|
+
|
|
68
|
+
import type { UserPromptSubmitContext } from "@vellumai/plugin-api";
|
|
69
|
+
|
|
26
70
|
import type { AssistantConfig } from "../config/schema.js";
|
|
71
|
+
import type { Conversation } from "../daemon/conversation.js";
|
|
27
72
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
28
73
|
import type { ConversationGraphMemory } from "../memory/graph/conversation-graph-memory.js";
|
|
29
74
|
import type { QdrantSparseVector } from "../memory/qdrant-client.js";
|
|
30
|
-
import userPromptSubmitMemoryRetrieval
|
|
31
|
-
type MemoryRetrievalHookContext,
|
|
32
|
-
} from "../plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.js";
|
|
75
|
+
import userPromptSubmitMemoryRetrieval from "../plugins/defaults/memory-retrieval/hooks/user-prompt-submit.js";
|
|
33
76
|
import type { Message } from "../providers/types.js";
|
|
34
77
|
|
|
35
78
|
/** Canonical metrics payload the graph retriever attaches to a real hit. */
|
|
@@ -102,31 +145,55 @@ function makeFakeGraphMemory(overrides?: {
|
|
|
102
145
|
}
|
|
103
146
|
|
|
104
147
|
function makeHookCtx(
|
|
105
|
-
overrides: Partial<
|
|
106
|
-
):
|
|
107
|
-
const { memory } = makeFakeGraphMemory();
|
|
148
|
+
overrides: Partial<UserPromptSubmitContext> = {},
|
|
149
|
+
): UserPromptSubmitContext {
|
|
108
150
|
return {
|
|
109
|
-
graphMemory: memory,
|
|
110
|
-
config: {} as AssistantConfig,
|
|
111
|
-
onEvent: () => {},
|
|
112
|
-
isTrustedActor: true,
|
|
113
151
|
conversationId: "conv-test",
|
|
114
152
|
userMessageId: "msg-test",
|
|
115
153
|
logger: {
|
|
116
154
|
warn: () => {},
|
|
117
|
-
} as unknown as
|
|
118
|
-
signal: new AbortController().signal,
|
|
155
|
+
} as unknown as UserPromptSubmitContext["logger"],
|
|
119
156
|
latestMessages: [],
|
|
157
|
+
requestId: "req-test",
|
|
158
|
+
isNonInteractive: false,
|
|
159
|
+
modelProfileKey: null,
|
|
160
|
+
prompt: "",
|
|
161
|
+
originalMessages: [],
|
|
120
162
|
...overrides,
|
|
121
163
|
};
|
|
122
164
|
}
|
|
123
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Install a fake live conversation for the hook to self-resolve by id: the
|
|
168
|
+
* graph handle, abort signal, and trust class all come from here rather than
|
|
169
|
+
* the hook context.
|
|
170
|
+
*/
|
|
171
|
+
function installConversation(
|
|
172
|
+
graphMemory: ConversationGraphMemory,
|
|
173
|
+
opts?: {
|
|
174
|
+
trusted?: boolean;
|
|
175
|
+
signal?: AbortSignal;
|
|
176
|
+
},
|
|
177
|
+
): void {
|
|
178
|
+
currentTrustClass = opts?.trusted === false ? "unknown" : "guardian";
|
|
179
|
+
currentConversation = {
|
|
180
|
+
graphMemory,
|
|
181
|
+
trustContext: undefined,
|
|
182
|
+
abortController: { signal: opts?.signal ?? new AbortController().signal },
|
|
183
|
+
} as unknown as Conversation;
|
|
184
|
+
}
|
|
185
|
+
|
|
124
186
|
beforeEach(() => {
|
|
125
187
|
updateMessageMetadataMock.mockReset();
|
|
126
188
|
recordMemoryRecallLogMock.mockReset();
|
|
189
|
+
applyRuntimeInjectionsMock.mockClear();
|
|
190
|
+
findConversationOrSubagentMock.mockClear();
|
|
191
|
+
broadcastMessageMock.mockReset();
|
|
192
|
+
currentConversation = undefined;
|
|
193
|
+
currentTrustClass = "guardian";
|
|
127
194
|
});
|
|
128
195
|
|
|
129
|
-
describe("user-prompt-submit
|
|
196
|
+
describe("user-prompt-submit hook (memory retrieval)", () => {
|
|
130
197
|
test("adopts the injected run messages when the actor is trusted", async () => {
|
|
131
198
|
const injected: Message[] = [
|
|
132
199
|
{ role: "user", content: [{ type: "text", text: "injected" }] },
|
|
@@ -134,7 +201,8 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
|
|
|
134
201
|
const { memory, prepareMemoryMock } = makeFakeGraphMemory({
|
|
135
202
|
messages: injected,
|
|
136
203
|
});
|
|
137
|
-
|
|
204
|
+
installConversation(memory, { trusted: true });
|
|
205
|
+
const ctx = makeHookCtx();
|
|
138
206
|
|
|
139
207
|
await userPromptSubmitMemoryRetrieval(ctx);
|
|
140
208
|
|
|
@@ -156,7 +224,8 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
|
|
|
156
224
|
userQueryVector: userDense,
|
|
157
225
|
userQuerySparseVector: userSparse,
|
|
158
226
|
});
|
|
159
|
-
|
|
227
|
+
installConversation(withUserQuery.memory, { trusted: true });
|
|
228
|
+
const userCtx = makeHookCtx();
|
|
160
229
|
await userPromptSubmitMemoryRetrieval(userCtx);
|
|
161
230
|
// User-query pair wins — never crossed with the summary signal — and is
|
|
162
231
|
// recorded back onto the graph handle for the PKB-reminder injector.
|
|
@@ -169,7 +238,8 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
|
|
|
169
238
|
queryVector: summaryDense,
|
|
170
239
|
sparseVector: summarySparse,
|
|
171
240
|
});
|
|
172
|
-
|
|
241
|
+
installConversation(summaryOnly.memory, { trusted: true });
|
|
242
|
+
const summaryCtx = makeHookCtx();
|
|
173
243
|
await userPromptSubmitMemoryRetrieval(summaryCtx);
|
|
174
244
|
expect(summaryOnly.recordPkbQueryVectorsMock).toHaveBeenCalledWith(
|
|
175
245
|
summaryDense,
|
|
@@ -177,17 +247,59 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
|
|
|
177
247
|
);
|
|
178
248
|
});
|
|
179
249
|
|
|
250
|
+
test("applies runtime injection on the retrieved history and persists the assembled blocks", async () => {
|
|
251
|
+
const retrieved: Message[] = [
|
|
252
|
+
{ role: "user", content: [{ type: "text", text: "retrieved" }] },
|
|
253
|
+
];
|
|
254
|
+
const injected: Message[] = [
|
|
255
|
+
{ role: "user", content: [{ type: "text", text: "injected" }] },
|
|
256
|
+
];
|
|
257
|
+
const { memory } = makeFakeGraphMemory({ messages: retrieved });
|
|
258
|
+
applyRuntimeInjectionsMock.mockImplementationOnce(async () => ({
|
|
259
|
+
messages: injected,
|
|
260
|
+
blocks: { unifiedTurnContext: "tc-block" },
|
|
261
|
+
}));
|
|
262
|
+
installConversation(memory, { trusted: true });
|
|
263
|
+
const ctx = makeHookCtx({ userMessageId: "msg-77" });
|
|
264
|
+
|
|
265
|
+
await userPromptSubmitMemoryRetrieval(ctx);
|
|
266
|
+
|
|
267
|
+
// Injection runs on the retrieved history; its result becomes the working
|
|
268
|
+
// list the loop reads back.
|
|
269
|
+
expect(applyRuntimeInjectionsMock).toHaveBeenCalledTimes(1);
|
|
270
|
+
expect(applyRuntimeInjectionsMock.mock.calls[0]?.[0]).toBe(retrieved);
|
|
271
|
+
expect(ctx.latestMessages).toBe(injected);
|
|
272
|
+
// The assembled blocks are persisted onto the user message metadata.
|
|
273
|
+
expect(updateMessageMetadataMock).toHaveBeenCalledWith("msg-77", {
|
|
274
|
+
turnContextBlock: "tc-block",
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test("applies runtime injection for untrusted actors despite skipping retrieval", async () => {
|
|
279
|
+
const { memory, prepareMemoryMock } = makeFakeGraphMemory();
|
|
280
|
+
const seeded: Message[] = [
|
|
281
|
+
{ role: "user", content: [{ type: "text", text: "seeded" }] },
|
|
282
|
+
];
|
|
283
|
+
installConversation(memory, { trusted: false });
|
|
284
|
+
const ctx = makeHookCtx({ latestMessages: seeded });
|
|
285
|
+
|
|
286
|
+
await userPromptSubmitMemoryRetrieval(ctx);
|
|
287
|
+
|
|
288
|
+
// The memory-graph step is gated on trust, but injection runs for everyone
|
|
289
|
+
// — on the seeded history, since no retrieval replaced it.
|
|
290
|
+
expect(prepareMemoryMock).not.toHaveBeenCalled();
|
|
291
|
+
expect(applyRuntimeInjectionsMock).toHaveBeenCalledTimes(1);
|
|
292
|
+
expect(applyRuntimeInjectionsMock.mock.calls[0]?.[0]).toBe(seeded);
|
|
293
|
+
});
|
|
294
|
+
|
|
180
295
|
test("skips graph retrieval and side effects for untrusted actors", async () => {
|
|
181
296
|
const { memory, prepareMemoryMock, recordPkbQueryVectorsMock } =
|
|
182
297
|
makeFakeGraphMemory();
|
|
183
298
|
const seeded: Message[] = [
|
|
184
299
|
{ role: "user", content: [{ type: "text", text: "seeded" }] },
|
|
185
300
|
];
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
isTrustedActor: false,
|
|
189
|
-
latestMessages: seeded,
|
|
190
|
-
});
|
|
301
|
+
installConversation(memory, { trusted: false });
|
|
302
|
+
const ctx = makeHookCtx({ latestMessages: seeded });
|
|
191
303
|
|
|
192
304
|
await userPromptSubmitMemoryRetrieval(ctx);
|
|
193
305
|
|
|
@@ -201,14 +313,12 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
|
|
|
201
313
|
});
|
|
202
314
|
|
|
203
315
|
test("persists injected block, recall log, and emits memory_recalled", async () => {
|
|
204
|
-
const received: ServerMessage[] = [];
|
|
205
316
|
const { memory } = makeFakeGraphMemory({
|
|
206
317
|
injectedBlockText: "injected-block",
|
|
207
318
|
metrics: makeMetrics(),
|
|
208
319
|
});
|
|
320
|
+
installConversation(memory, { trusted: true });
|
|
209
321
|
const ctx = makeHookCtx({
|
|
210
|
-
graphMemory: memory,
|
|
211
|
-
onEvent: (msg) => received.push(msg),
|
|
212
322
|
userMessageId: "msg-42",
|
|
213
323
|
conversationId: "conv-42",
|
|
214
324
|
});
|
|
@@ -225,13 +335,16 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
|
|
|
225
335
|
};
|
|
226
336
|
expect(logEntry.conversationId).toBe("conv-42");
|
|
227
337
|
expect(logEntry.reason).toBe("graph:none");
|
|
228
|
-
|
|
229
|
-
expect(
|
|
338
|
+
// The `memory_recalled` summary publishes through the shared broadcast hub.
|
|
339
|
+
expect(broadcastMessageMock).toHaveBeenCalledTimes(1);
|
|
340
|
+
const emitted = broadcastMessageMock.mock.calls[0]?.[0] as ServerMessage;
|
|
341
|
+
expect(emitted.type).toBe("memory_recalled");
|
|
230
342
|
});
|
|
231
343
|
|
|
232
344
|
test("skips metadata persist when no block text is injected", async () => {
|
|
233
345
|
const { memory } = makeFakeGraphMemory({ injectedBlockText: null });
|
|
234
|
-
|
|
346
|
+
installConversation(memory, { trusted: true });
|
|
347
|
+
const ctx = makeHookCtx();
|
|
235
348
|
|
|
236
349
|
await userPromptSubmitMemoryRetrieval(ctx);
|
|
237
350
|
|
|
@@ -254,16 +367,17 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
|
|
|
254
367
|
const graphMemory = {
|
|
255
368
|
prepareMemory: failingPrepare,
|
|
256
369
|
} as unknown as ConversationGraphMemory;
|
|
257
|
-
|
|
370
|
+
installConversation(graphMemory, { trusted: true });
|
|
371
|
+
const ctx = makeHookCtx();
|
|
258
372
|
|
|
259
373
|
await expect(userPromptSubmitMemoryRetrieval(ctx)).rejects.toThrow(
|
|
260
374
|
"retrieval failed",
|
|
261
375
|
);
|
|
262
376
|
});
|
|
263
377
|
|
|
264
|
-
test("forwards the
|
|
265
|
-
// The hook hands
|
|
266
|
-
// external cancel aborts the underlying retrieval.
|
|
378
|
+
test("forwards the conversation abort signal into prepareMemory", async () => {
|
|
379
|
+
// The hook hands the live conversation's abort signal straight to
|
|
380
|
+
// `prepareMemory` so an external cancel aborts the underlying retrieval.
|
|
267
381
|
let capturedSignal: AbortSignal | undefined;
|
|
268
382
|
const prepareMemoryMock = mock(
|
|
269
383
|
async (
|
|
@@ -288,7 +402,11 @@ describe("user-prompt-submit-temp hook (memory retrieval)", () => {
|
|
|
288
402
|
recordPkbQueryVectors: mock(() => {}),
|
|
289
403
|
} as unknown as ConversationGraphMemory;
|
|
290
404
|
const controller = new AbortController();
|
|
291
|
-
|
|
405
|
+
installConversation(graphMemory, {
|
|
406
|
+
trusted: true,
|
|
407
|
+
signal: controller.signal,
|
|
408
|
+
});
|
|
409
|
+
const ctx = makeHookCtx();
|
|
292
410
|
|
|
293
411
|
await userPromptSubmitMemoryRetrieval(ctx);
|
|
294
412
|
|