@vellumai/assistant 0.8.5 → 0.8.6
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/AGENTS.md +33 -1
- package/ARCHITECTURE.md +1 -1
- package/bunfig.toml +6 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +1900 -166
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
- package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-risk-options.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +9 -13
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +3 -2
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +320 -3
- package/src/__tests__/checker.test.ts +12 -12
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +12 -14
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-token-estimator.test.ts +22 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
- package/src/__tests__/conversation-agent-loop.test.ts +488 -2
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +69 -8
- package/src/__tests__/conversation-fork-route.test.ts +3 -2
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
- package/src/__tests__/conversation-pairing.test.ts +53 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
- package/src/__tests__/conversation-process-callsite.test.ts +1 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-queue.test.ts +84 -32
- package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
- package/src/__tests__/conversation-speed-override.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
- package/src/__tests__/conversation-sync-tags.test.ts +128 -12
- package/src/__tests__/conversation-title-service.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
- package/src/__tests__/conversation-usage.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -5
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +56 -2
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +58 -41
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +0 -33
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +26 -40
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/filing-service.test.ts +1 -0
- package/src/__tests__/first-greeting.test.ts +62 -12
- package/src/__tests__/gateway-flag-listener.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +26 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-shell-tool.test.ts +5 -4
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +29 -7
- package/src/__tests__/identity-intro-cache.test.ts +133 -22
- package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/injector-disk-pressure.test.ts +3 -17
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-resolver.test.ts +331 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/messaging-send-tool.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/oauth-commands-routes.test.ts +37 -0
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +3 -2
- package/src/__tests__/openai-provider.test.ts +8 -9
- package/src/__tests__/openai-responses-provider.test.ts +70 -10
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/plugin-bootstrap.test.ts +9 -11
- package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
- package/src/__tests__/process-message-background-slack.test.ts +21 -16
- package/src/__tests__/process-message-display-content.test.ts +19 -22
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/schedule-store.test.ts +16 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +81 -42
- package/src/__tests__/server-history-render.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +14 -16
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
- package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
- package/src/__tests__/subagent-manager-notify.test.ts +20 -8
- package/src/__tests__/subagent-notify-parent.test.ts +5 -4
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +38 -0
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
- package/src/__tests__/voice-session-bridge.test.ts +37 -28
- package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
- package/src/acp/session-manager.ts +5 -6
- package/src/agent/loop.ts +80 -0
- package/src/api/README.md +124 -2
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +51 -0
- package/src/api/events/assistant-text-delta.ts +32 -0
- package/src/api/events/assistant-turn-start.ts +33 -0
- package/src/api/events/document-comment-created.ts +48 -0
- package/src/api/events/document-comment-deleted.ts +24 -0
- package/src/api/events/document-comment-reopened.ts +25 -0
- package/src/api/events/document-comment-resolved.ts +27 -0
- package/src/api/events/generation-cancelled.ts +24 -0
- package/src/api/events/generation-handoff.ts +41 -0
- package/src/api/events/message-complete.ts +42 -0
- package/src/api/events/open-url.ts +30 -0
- package/src/{events → api/events}/relationship-state-updated.ts +3 -3
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +128 -3
- package/src/api/responses/llm-context-response.ts +39 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/background-wake/background-wake-routes.test.ts +687 -52
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +2 -2
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/memory-v3-render.ts +147 -0
- package/src/cli/commands/memory-v3.ts +255 -4
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +23 -42
- package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/call-site-defaults.ts +1 -1
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +90 -1
- package/src/config/schemas/memory-v2.ts +26 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/token-estimator.ts +10 -5
- package/src/credential-execution/executable-discovery.ts +40 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
- package/src/daemon/conversation-agent-loop.ts +132 -28
- package/src/daemon/conversation-error.ts +33 -5
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +29 -9
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +33 -48
- package/src/daemon/conversation.ts +26 -46
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +27 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/lifecycle.ts +12 -12
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-types/conversations.ts +20 -22
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -2
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +23 -38
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/process-message.ts +9 -9
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +16 -0
- package/src/daemon/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- package/src/daemon/wake-target-adapter.ts +10 -0
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
- package/src/heartbeat/heartbeat-service.ts +63 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-writer.ts +146 -7
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
- package/src/ipc/skill-routes/memory.ts +4 -3
- package/src/ipc/skill-routes/registries.ts +28 -29
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +352 -112
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +4 -0
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/job-handlers/embedding.test.ts +3 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs-worker.ts +12 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
- package/src/memory/llm-request-log-source-local.ts +24 -0
- package/src/memory/llm-request-log-source.ts +31 -0
- package/src/memory/llm-request-log-store.ts +188 -3
- package/src/memory/memory-v2-activation-log-store.ts +95 -1
- package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edges.test.ts +144 -1
- package/src/memory/v3/__tests__/filter.test.ts +48 -0
- package/src/memory/v3/__tests__/gate.test.ts +96 -33
- package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
- package/src/memory/v3/__tests__/loop.test.ts +250 -5
- package/src/memory/v3/__tests__/scouts.test.ts +49 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
- package/src/memory/v3/__tests__/traversal.test.ts +39 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
- package/src/memory/v3/__tests__/validate.test.ts +32 -0
- package/src/memory/v3/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edges.ts +58 -21
- package/src/memory/v3/filter.ts +27 -22
- package/src/memory/v3/gate.ts +51 -36
- package/src/memory/v3/index-composition.ts +18 -5
- package/src/memory/v3/loop.ts +65 -17
- package/src/memory/v3/scouts.ts +15 -4
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +44 -2
- package/src/memory/v3/traversal.ts +6 -1
- package/src/memory/v3/tree-walk.ts +6 -1
- package/src/memory/v3/validate.ts +56 -33
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -3
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +11 -1
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- package/src/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugins/defaults/injectors.ts +2 -8
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/types.ts +57 -13
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +7 -11
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/call-site-routing.ts +33 -9
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +24 -3
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
- package/src/providers/openai/chat-completions-provider.ts +110 -12
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +53 -53
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +18 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -4
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +9 -0
- package/src/runtime/__tests__/agent-wake.test.ts +1 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/auth/route-policy.ts +10 -0
- package/src/runtime/channel-readiness-service.ts +68 -0
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +47 -14
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/background-wake-routes.ts +188 -20
- package/src/runtime/routes/btw-routes.ts +4 -4
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +147 -0
- package/src/runtime/routes/conversation-management-routes.ts +39 -14
- package/src/runtime/routes/conversation-query-routes.ts +60 -10
- package/src/runtime/routes/conversation-routes.ts +186 -140
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/documents-routes.ts +10 -1
- package/src/runtime/routes/group-routes.ts +11 -0
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/identity-intro-cache.ts +61 -16
- package/src/runtime/routes/identity-routes.ts +30 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
- package/src/runtime/routes/integrations/vercel.ts +15 -0
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-v3-routes.ts +160 -2
- package/src/runtime/routes/migration-routes.ts +20 -13
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- package/src/runtime/routes/surface-action-routes.ts +1 -38
- package/src/runtime/routes/surface-content-routes.ts +12 -5
- package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/schedule/schedule-store.ts +8 -1
- package/src/schedule/scheduler.ts +111 -15
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/user-message.ts +5 -8
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +13 -13
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/tools/apps/definitions.ts +35 -21
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +268 -266
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +2 -5
- package/src/tools/executor.ts +18 -55
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search.test.ts +211 -3
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-search.ts +199 -44
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +146 -103
- package/src/tools/schedule/create.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +17 -15
- package/src/tools/ui-surface/definitions.ts +98 -86
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/util/browser.ts +7 -2
- package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/registry.ts +4 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import { getDocumentById } from "../documents/document-store.js";
|
|
4
|
-
import { getSqlite
|
|
4
|
+
import { getSqlite } from "../memory/db-connection.js";
|
|
5
5
|
import {
|
|
6
6
|
executeDocumentDelete,
|
|
7
7
|
executeDocumentList,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
executeDocumentUpdate,
|
|
10
10
|
} from "../tools/document/document-tool.js";
|
|
11
11
|
import type { ToolContext, ToolExecutionResult } from "../tools/types.js";
|
|
12
|
+
import { resetDbForTesting } from "./db-test-helpers.js";
|
|
12
13
|
|
|
13
14
|
function makeContext(overrides: Partial<ToolContext> = {}): ToolContext {
|
|
14
15
|
return {
|
|
@@ -25,7 +26,7 @@ function parseResult<T>(result: ToolExecutionResult): T {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
function bootstrapDocumentTables(): void {
|
|
28
|
-
|
|
29
|
+
resetDbForTesting();
|
|
29
30
|
const raw = getSqlite();
|
|
30
31
|
raw.exec(/*sql*/ `
|
|
31
32
|
DROP TABLE IF EXISTS document_conversations;
|
|
@@ -256,3 +257,81 @@ describe("document tool security", () => {
|
|
|
256
257
|
expect(getDocumentById("doc-current")).toBeNull();
|
|
257
258
|
});
|
|
258
259
|
});
|
|
260
|
+
|
|
261
|
+
describe("executeDocumentUpdate — input validation", () => {
|
|
262
|
+
beforeEach(() => {
|
|
263
|
+
bootstrapDocumentTables();
|
|
264
|
+
seedFixtureDocuments();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test("returns Invalid input when surface_id is missing", () => {
|
|
268
|
+
const result = executeDocumentUpdate({}, makeContext());
|
|
269
|
+
expect(result.isError).toBe(true);
|
|
270
|
+
const body = parseResult<{ error: string }>(result);
|
|
271
|
+
expect(body.error).toContain("Invalid input: surface_id is required");
|
|
272
|
+
expect(body.error).not.toContain("Document not found");
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test("returns Invalid input when content is missing", () => {
|
|
276
|
+
const result = executeDocumentUpdate(
|
|
277
|
+
{ surface_id: "doc-x" },
|
|
278
|
+
makeContext(),
|
|
279
|
+
);
|
|
280
|
+
expect(result.isError).toBe(true);
|
|
281
|
+
const body = parseResult<{ error: string }>(result);
|
|
282
|
+
expect(body.error).toBe(
|
|
283
|
+
"Invalid input: content is required and must be a string",
|
|
284
|
+
);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test("allows empty string content (falls through to access check)", () => {
|
|
288
|
+
const result = executeDocumentUpdate(
|
|
289
|
+
{ surface_id: "doc-x", content: "" },
|
|
290
|
+
makeContext(),
|
|
291
|
+
);
|
|
292
|
+
expect(result.isError).toBe(true);
|
|
293
|
+
const body = parseResult<{ error: string }>(result);
|
|
294
|
+
// Did NOT fail input validation; fell through to access/not-found path.
|
|
295
|
+
expect(body.error).toBe("Document not found");
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("returns Invalid input when mode is not replace or append", () => {
|
|
299
|
+
const result = executeDocumentUpdate(
|
|
300
|
+
{ surface_id: "doc-x", content: "hi", mode: "bogus" },
|
|
301
|
+
makeContext(),
|
|
302
|
+
);
|
|
303
|
+
expect(result.isError).toBe(true);
|
|
304
|
+
const body = parseResult<{ error: string }>(result);
|
|
305
|
+
expect(body.error).toBe(
|
|
306
|
+
'Invalid input: mode must be "replace" or "append"',
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
test("treats mode: null the same as undefined (factory validator accepts both)", () => {
|
|
311
|
+
// validateInputAgainstSchema treats null as "absent" for enum checks, so
|
|
312
|
+
// the executor must agree — { mode: null } should fall through to the
|
|
313
|
+
// access check, not return a confusing 'mode must be ...' error.
|
|
314
|
+
const result = executeDocumentUpdate(
|
|
315
|
+
{ surface_id: "doc-x", content: "hi", mode: null },
|
|
316
|
+
makeContext(),
|
|
317
|
+
);
|
|
318
|
+
expect(result.isError).toBe(true);
|
|
319
|
+
const body = parseResult<{ error: string }>(result);
|
|
320
|
+
expect(body.error).not.toContain("Invalid input: mode");
|
|
321
|
+
expect(body.error).toBe("Document not found");
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test("executeDocumentRead returns Invalid input when surface_id is missing", () => {
|
|
325
|
+
const result = executeDocumentRead({}, makeContext());
|
|
326
|
+
expect(result.isError).toBe(true);
|
|
327
|
+
const body = parseResult<{ error: string }>(result);
|
|
328
|
+
expect(body.error).toContain("Invalid input: surface_id is required");
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
test("executeDocumentDelete returns Invalid input when surface_id is missing", () => {
|
|
332
|
+
const result = executeDocumentDelete({}, makeContext());
|
|
333
|
+
expect(result.isError).toBe(true);
|
|
334
|
+
const body = parseResult<{ error: string }>(result);
|
|
335
|
+
expect(body.error).toContain("Invalid input: surface_id is required");
|
|
336
|
+
});
|
|
337
|
+
});
|
|
@@ -46,18 +46,19 @@ mock.module("../config/loader.js", () => ({
|
|
|
46
46
|
}));
|
|
47
47
|
|
|
48
48
|
const { buildSystemPrompt } = await import("../prompts/system-prompt.js");
|
|
49
|
-
const {
|
|
50
|
-
|
|
49
|
+
const { setOverridesForTesting } = await import(
|
|
50
|
+
"./feature-flag-test-helpers.js"
|
|
51
|
+
);
|
|
51
52
|
|
|
52
53
|
describe("Dynamic Skill Authoring Workflow moved to tool descriptions", () => {
|
|
53
54
|
beforeEach(() => {
|
|
54
|
-
|
|
55
|
+
setOverridesForTesting({
|
|
55
56
|
browser: true,
|
|
56
57
|
});
|
|
57
58
|
});
|
|
58
59
|
|
|
59
60
|
afterEach(() => {
|
|
60
|
-
|
|
61
|
+
setOverridesForTesting({});
|
|
61
62
|
});
|
|
62
63
|
|
|
63
64
|
test("system prompt no longer contains Dynamic Skill Authoring section", () => {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test-only utilities for overriding the encrypted credential store paths.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the removed `_setStorePath` and `_setStoreKeyPath` exports
|
|
5
|
+
* from `encrypted-store.ts`. Lives here (not in the source module)
|
|
6
|
+
* because production modules should not expose test backdoors.
|
|
7
|
+
*
|
|
8
|
+
* No source-module imports
|
|
9
|
+
* ------------------------
|
|
10
|
+
* This file has ZERO imports from `src/`. It accesses the store-path
|
|
11
|
+
* override state via the shared `globalThis.vellumAssistant.storePathOverride`
|
|
12
|
+
* slot that `src/security/store-path-override.ts` also reads/writes. The
|
|
13
|
+
* slot shape is duplicated here on purpose: keeping this file off the
|
|
14
|
+
* production import graph is what protects the test preload from a
|
|
15
|
+
* broken `node_modules` symlink (DB ghost #3). The two declarations MUST
|
|
16
|
+
* stay in sync — if you change one, change the other.
|
|
17
|
+
*
|
|
18
|
+
* Most tests no longer need these overrides: the test preload places
|
|
19
|
+
* `VELLUM_WORKSPACE_DIR` at `<tmpRoot>/workspace`, so `getProtectedDir()`
|
|
20
|
+
* resolves to `<tmpRoot>/protected` per process. The setters here exist
|
|
21
|
+
* for the small set of tests that exercise specific path scenarios
|
|
22
|
+
* (env-var fallbacks, migration corner cases, etc.).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Mirrors `src/security/store-path-override.ts`. Duplicated by design — see
|
|
26
|
+
// the "No source-module imports" section above.
|
|
27
|
+
type PathSlot = {
|
|
28
|
+
storePath: string | null;
|
|
29
|
+
storeKeyPath: string | null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type VellumAssistantNamespace = {
|
|
33
|
+
storePathOverride?: PathSlot;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function pathSlot(): PathSlot {
|
|
37
|
+
const g = globalThis as { vellumAssistant?: VellumAssistantNamespace };
|
|
38
|
+
const ns = (g.vellumAssistant ??= {});
|
|
39
|
+
return (ns.storePathOverride ??= { storePath: null, storeKeyPath: null });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Override the encrypted store file path. Pass `null` to reset to the
|
|
44
|
+
* default (`<protectedDir>/keys.enc`).
|
|
45
|
+
*/
|
|
46
|
+
export function setStorePathForTesting(path: string | null): void {
|
|
47
|
+
pathSlot().storePath = path;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Override the store-key file path. Pass `null` to reset to the default
|
|
52
|
+
* (`<dirname(storePath)>/store.key`).
|
|
53
|
+
*/
|
|
54
|
+
export function setStoreKeyPathForTesting(path: string | null): void {
|
|
55
|
+
pathSlot().storeKeyPath = path;
|
|
56
|
+
}
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from "bun:test";
|
|
25
25
|
|
|
26
26
|
// ---------------------------------------------------------------------------
|
|
27
|
-
// Mock only the logger (not platform -- we use
|
|
27
|
+
// Mock only the logger (not platform -- we use setStorePathForTesting instead)
|
|
28
28
|
// ---------------------------------------------------------------------------
|
|
29
29
|
|
|
30
30
|
mock.module("../util/logger.js", () => ({
|
|
@@ -35,13 +35,15 @@ mock.module("../util/logger.js", () => ({
|
|
|
35
35
|
}));
|
|
36
36
|
|
|
37
37
|
import {
|
|
38
|
-
_setStoreKeyPath,
|
|
39
|
-
_setStorePath,
|
|
40
38
|
deleteKey,
|
|
41
39
|
getKey,
|
|
42
40
|
listKeys,
|
|
43
41
|
setKey,
|
|
44
42
|
} from "../security/encrypted-store.js";
|
|
43
|
+
import {
|
|
44
|
+
setStoreKeyPathForTesting,
|
|
45
|
+
setStorePathForTesting,
|
|
46
|
+
} from "./encrypted-store-test-helpers.js";
|
|
45
47
|
|
|
46
48
|
// ---------------------------------------------------------------------------
|
|
47
49
|
// Use a temp directory so tests don't touch the real ~/.vellum
|
|
@@ -141,13 +143,13 @@ describe("encrypted-store", () => {
|
|
|
141
143
|
for (const entry of readdirSync(TEST_DIR)) {
|
|
142
144
|
rmSync(join(TEST_DIR, entry), { recursive: true, force: true });
|
|
143
145
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
setStorePathForTesting(STORE_PATH);
|
|
147
|
+
setStoreKeyPathForTesting(STORE_KEY_PATH);
|
|
146
148
|
});
|
|
147
149
|
|
|
148
150
|
afterEach(() => {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
setStorePathForTesting(null);
|
|
152
|
+
setStoreKeyPathForTesting(null);
|
|
151
153
|
});
|
|
152
154
|
|
|
153
155
|
afterAll(() => {
|
|
@@ -508,8 +510,8 @@ describe("encrypted-store", () => {
|
|
|
508
510
|
// Point to a path in a non-existent subdirectory
|
|
509
511
|
const nestedPath = join(TEST_DIR, "sub", "dir", "keys.enc");
|
|
510
512
|
const nestedKeyPath = join(TEST_DIR, "sub", "dir", "store.key");
|
|
511
|
-
|
|
512
|
-
|
|
513
|
+
setStorePathForTesting(nestedPath);
|
|
514
|
+
setStoreKeyPathForTesting(nestedKeyPath);
|
|
513
515
|
const result = setKey("test", "value");
|
|
514
516
|
expect(result).toBe(true);
|
|
515
517
|
expect(getKey("test")).toBe("value");
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test-only utilities for seeding the feature flag override cache.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the removed `_setOverridesForTesting` export from
|
|
5
|
+
* `assistant-feature-flags.ts`. Lives here (not in the source module)
|
|
6
|
+
* because production modules should not expose test backdoors.
|
|
7
|
+
*
|
|
8
|
+
* No source-module imports
|
|
9
|
+
* ------------------------
|
|
10
|
+
* This file has ZERO imports from `src/`. It accesses the feature flag
|
|
11
|
+
* cache's state via the shared `globalThis.vellumAssistant.featureFlagCache`
|
|
12
|
+
* slot that `src/config/feature-flag-cache.ts` also reads/writes. The slot
|
|
13
|
+
* shape is duplicated here on purpose: keeping this file off the
|
|
14
|
+
* production import graph is what protects the test preload from a
|
|
15
|
+
* broken `node_modules` symlink (DB ghost #3). The two declarations MUST
|
|
16
|
+
* stay in sync — if you change one, change the other.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// Mirrors `src/config/feature-flag-cache.ts`. Duplicated by design — see
|
|
20
|
+
// the "No source-module imports" section above.
|
|
21
|
+
type FlagSlot = {
|
|
22
|
+
overrides: Record<string, boolean> | null;
|
|
23
|
+
fromGateway: boolean;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type VellumAssistantNamespace = {
|
|
27
|
+
featureFlagCache?: FlagSlot;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function flagSlot(): FlagSlot {
|
|
31
|
+
const g = globalThis as { vellumAssistant?: VellumAssistantNamespace };
|
|
32
|
+
const ns = (g.vellumAssistant ??= {});
|
|
33
|
+
return (ns.featureFlagCache ??= { overrides: null, fromGateway: false });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Synchronously seed the feature flag override cache for the current test.
|
|
38
|
+
*
|
|
39
|
+
* Sets the cache to a clone of `overrides` and marks it as
|
|
40
|
+
* gateway-populated, so subsequent `initFeatureFlagOverrides()` calls are
|
|
41
|
+
* no-ops (preventing the production retry loop from running during tests).
|
|
42
|
+
*
|
|
43
|
+
* Tests that want the gateway IPC retry path to actually run should not
|
|
44
|
+
* call this — they should leave the cache empty or call
|
|
45
|
+
* `clearFeatureFlagOverridesCache()` from `assistant-feature-flags.ts`.
|
|
46
|
+
*/
|
|
47
|
+
export function setOverridesForTesting(
|
|
48
|
+
overrides: Record<string, boolean>,
|
|
49
|
+
): void {
|
|
50
|
+
const s = flagSlot();
|
|
51
|
+
s.overrides = { ...overrides };
|
|
52
|
+
s.fromGateway = true;
|
|
53
|
+
}
|
|
@@ -96,7 +96,7 @@ describe("first-greeting", () => {
|
|
|
96
96
|
assistantName: "Pax",
|
|
97
97
|
});
|
|
98
98
|
expect(greeting).toBe(
|
|
99
|
-
"Hey Alice, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
99
|
+
"Hey Alice, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you. If you have context or workflows from another assistant or harness, bring them over early and I'll help port them.",
|
|
100
100
|
);
|
|
101
101
|
});
|
|
102
102
|
|
|
@@ -108,7 +108,7 @@ describe("first-greeting", () => {
|
|
|
108
108
|
assistantName: "Remy",
|
|
109
109
|
});
|
|
110
110
|
expect(greeting).toBe(
|
|
111
|
-
"Hey Alice, I'm Remy. Good to meet you.\n\nWe can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here.",
|
|
111
|
+
"Hey Alice, I'm Remy. Good to meet you.\n\nWe can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here. If you have context or workflows from another assistant or harness, bring them over early and I can help port them.",
|
|
112
112
|
);
|
|
113
113
|
});
|
|
114
114
|
|
|
@@ -119,7 +119,7 @@ describe("first-greeting", () => {
|
|
|
119
119
|
assistantName: "Pax",
|
|
120
120
|
});
|
|
121
121
|
expect(greeting).toBe(
|
|
122
|
-
"Hey, I'm Pax. Let's see what you've got.\n\nWe can jump straight into whatever you've got, or take a few minutes to just talk first. What sounds right?",
|
|
122
|
+
"Hey, I'm Pax. Let's see what you've got.\n\nWe can jump straight into whatever you've got, or take a few minutes to just talk first. If you've got context or workflows from another assistant or harness, bring them over early and I'll port them with you. What sounds right?",
|
|
123
123
|
);
|
|
124
124
|
});
|
|
125
125
|
|
|
@@ -131,7 +131,7 @@ describe("first-greeting", () => {
|
|
|
131
131
|
assistantName: "Pax",
|
|
132
132
|
});
|
|
133
133
|
expect(greeting).toBe(
|
|
134
|
-
"Hey Alice, I'm Pax.\n\nWe can start with whatever's in front of you, or just talk for a bit first. Either way.",
|
|
134
|
+
"Hey Alice, I'm Pax.\n\nWe can start with whatever's in front of you, or just talk for a bit first. Either way. If there's old context or workflows from another assistant or harness, bring them over early and I'll help port them.",
|
|
135
135
|
);
|
|
136
136
|
});
|
|
137
137
|
|
|
@@ -142,7 +142,7 @@ describe("first-greeting", () => {
|
|
|
142
142
|
userName: "Alice",
|
|
143
143
|
});
|
|
144
144
|
expect(greeting).toBe(
|
|
145
|
-
"Hey Alice,\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
145
|
+
"Hey Alice,\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you. If you have context or workflows from another assistant or harness, bring them over early and I'll help port them.",
|
|
146
146
|
);
|
|
147
147
|
});
|
|
148
148
|
|
|
@@ -153,7 +153,7 @@ describe("first-greeting", () => {
|
|
|
153
153
|
assistantName: "Pax",
|
|
154
154
|
});
|
|
155
155
|
expect(greeting).toBe(
|
|
156
|
-
"Hey, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
156
|
+
"Hey, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you. If you have context or workflows from another assistant or harness, bring them over early and I'll help port them.",
|
|
157
157
|
);
|
|
158
158
|
});
|
|
159
159
|
|
|
@@ -173,7 +173,7 @@ describe("first-greeting", () => {
|
|
|
173
173
|
tone: "warm",
|
|
174
174
|
});
|
|
175
175
|
expect(greeting).toBe(
|
|
176
|
-
"Hey,\n\nWe can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here.",
|
|
176
|
+
"Hey,\n\nWe can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here. If you have context or workflows from another assistant or harness, bring them over early and I can help port them.",
|
|
177
177
|
);
|
|
178
178
|
});
|
|
179
179
|
|
|
@@ -185,6 +185,17 @@ describe("first-greeting", () => {
|
|
|
185
185
|
expect(unique.size).toBe(4);
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
+
it("google-connected greeting points to Gmail only", () => {
|
|
189
|
+
const greeting = getCannedFirstGreeting({
|
|
190
|
+
...base,
|
|
191
|
+
tone: "grounded",
|
|
192
|
+
googleConnected: true,
|
|
193
|
+
});
|
|
194
|
+
expect(greeting).toContain("scan Gmail");
|
|
195
|
+
expect(greeting).not.toContain("calendar");
|
|
196
|
+
expect(greeting).not.toContain("drive");
|
|
197
|
+
});
|
|
198
|
+
|
|
188
199
|
it("unknown tone falls back to grounded defaults", () => {
|
|
189
200
|
const greeting = getCannedFirstGreeting({
|
|
190
201
|
...base,
|
|
@@ -193,7 +204,7 @@ describe("first-greeting", () => {
|
|
|
193
204
|
assistantName: "Pax",
|
|
194
205
|
});
|
|
195
206
|
expect(greeting).toBe(
|
|
196
|
-
"Hey Alice, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
207
|
+
"Hey Alice, I'm Pax.\n\nWe can get into whatever you've got, or just talk first — that tends to go better. Up to you. If you have context or workflows from another assistant or harness, bring them over early and I'll help port them.",
|
|
197
208
|
);
|
|
198
209
|
});
|
|
199
210
|
|
|
@@ -223,7 +234,7 @@ describe("first-greeting", () => {
|
|
|
223
234
|
const [intro, invite] = greeting.split("\n\n");
|
|
224
235
|
expect(intro).toBe("Hey Bob, I'm Pax.");
|
|
225
236
|
expect(invite).toBe(
|
|
226
|
-
"We can get into whatever you've got, or just talk first — that tends to go better. Up to you.",
|
|
237
|
+
"We can get into whatever you've got, or just talk first — that tends to go better. Up to you. If you have context or workflows from another assistant or harness, bring them over early and I'll help port them.",
|
|
227
238
|
);
|
|
228
239
|
});
|
|
229
240
|
|
|
@@ -232,7 +243,7 @@ describe("first-greeting", () => {
|
|
|
232
243
|
const [intro, invite] = greeting.split("\n\n");
|
|
233
244
|
expect(intro).toBe("Hey Bob, I'm Pax. Good to meet you.");
|
|
234
245
|
expect(invite).toBe(
|
|
235
|
-
"We can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here.",
|
|
246
|
+
"We can start on something specific, or just talk for a bit first — honestly that tends to work out better. Either way, I'm here. If you have context or workflows from another assistant or harness, bring them over early and I can help port them.",
|
|
236
247
|
);
|
|
237
248
|
});
|
|
238
249
|
|
|
@@ -241,7 +252,7 @@ describe("first-greeting", () => {
|
|
|
241
252
|
const [intro, invite] = greeting.split("\n\n");
|
|
242
253
|
expect(intro).toBe("Hey Bob, I'm Pax. Let's see what you've got.");
|
|
243
254
|
expect(invite).toBe(
|
|
244
|
-
"We can jump straight into whatever you've got, or take a few minutes to just talk first. What sounds right?",
|
|
255
|
+
"We can jump straight into whatever you've got, or take a few minutes to just talk first. If you've got context or workflows from another assistant or harness, bring them over early and I'll port them with you. What sounds right?",
|
|
245
256
|
);
|
|
246
257
|
});
|
|
247
258
|
|
|
@@ -250,7 +261,7 @@ describe("first-greeting", () => {
|
|
|
250
261
|
const [intro, invite] = greeting.split("\n\n");
|
|
251
262
|
expect(intro).toBe("Hey Bob, I'm Pax.");
|
|
252
263
|
expect(invite).toBe(
|
|
253
|
-
"We can start with whatever's in front of you, or just talk for a bit first. Either way.",
|
|
264
|
+
"We can start with whatever's in front of you, or just talk for a bit first. Either way. If there's old context or workflows from another assistant or harness, bring them over early and I'll help port them.",
|
|
254
265
|
);
|
|
255
266
|
});
|
|
256
267
|
|
|
@@ -274,6 +285,45 @@ describe("first-greeting", () => {
|
|
|
274
285
|
});
|
|
275
286
|
});
|
|
276
287
|
|
|
288
|
+
describe("migration offer is present in every variant", () => {
|
|
289
|
+
const MIGRATION_MARKER = "bring them over early";
|
|
290
|
+
|
|
291
|
+
it("no-onboarding greeting includes the migration offer", () => {
|
|
292
|
+
expect(getCannedFirstGreeting(undefined)).toContain(MIGRATION_MARKER);
|
|
293
|
+
expect(CANNED_FIRST_GREETING).toContain(MIGRATION_MARKER);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it("minimal onboarding (falls back to CANNED) includes the migration offer", () => {
|
|
297
|
+
expect(
|
|
298
|
+
getCannedFirstGreeting({ tools: [], tasks: [], tone: "" }),
|
|
299
|
+
).toContain(MIGRATION_MARKER);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("every tone variant includes the migration offer", () => {
|
|
303
|
+
for (const tone of ["grounded", "warm", "energetic", "poetic"]) {
|
|
304
|
+
const greeting = getCannedFirstGreeting({
|
|
305
|
+
tools: [],
|
|
306
|
+
tasks: [],
|
|
307
|
+
tone,
|
|
308
|
+
userName: "Alice",
|
|
309
|
+
assistantName: "Pax",
|
|
310
|
+
});
|
|
311
|
+
expect(greeting).toContain(MIGRATION_MARKER);
|
|
312
|
+
expect(greeting).toContain("port them");
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it("google-connected greeting still includes the migration offer", () => {
|
|
317
|
+
const greeting = getCannedFirstGreeting({
|
|
318
|
+
tools: [],
|
|
319
|
+
tasks: [],
|
|
320
|
+
tone: "warm",
|
|
321
|
+
googleConnected: true,
|
|
322
|
+
});
|
|
323
|
+
expect(greeting).toContain(MIGRATION_MARKER);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
277
327
|
describe("buildScanFirstMessage", () => {
|
|
278
328
|
it("website variant includes 'my website' and the URL", () => {
|
|
279
329
|
const msg = buildScanFirstMessage("https://acme.com", "website");
|
|
@@ -33,7 +33,6 @@ mock.module("../config/assistant-feature-flags.js", () => ({
|
|
|
33
33
|
initFeatureFlagOverrides: async () => {},
|
|
34
34
|
clearFeatureFlagOverridesCache: () => {},
|
|
35
35
|
isAssistantFeatureFlagEnabled: () => true,
|
|
36
|
-
_setOverridesForTesting: () => {},
|
|
37
36
|
}));
|
|
38
37
|
|
|
39
38
|
// ---------------------------------------------------------------------------
|
|
@@ -285,6 +285,32 @@ describe("GeminiProvider", () => {
|
|
|
285
285
|
});
|
|
286
286
|
});
|
|
287
287
|
|
|
288
|
+
test("omits thinkingConfig for models that do not support thinking", async () => {
|
|
289
|
+
fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
|
|
290
|
+
|
|
291
|
+
// gemini-2.5-flash-lite has supportsThinking: false in the catalog; the
|
|
292
|
+
// provider must not forward thinking params even when a thinking config is
|
|
293
|
+
// supplied (gemini is in THINKING_AWARE_PROVIDERS, so retry.ts no longer
|
|
294
|
+
// strips them).
|
|
295
|
+
const liteProvider = new GeminiProvider(
|
|
296
|
+
"test-api-key",
|
|
297
|
+
"gemini-2.5-flash-lite",
|
|
298
|
+
);
|
|
299
|
+
await liteProvider.sendMessage(
|
|
300
|
+
[{ role: "user", content: [{ type: "text", text: "Hi" }] }],
|
|
301
|
+
undefined,
|
|
302
|
+
undefined,
|
|
303
|
+
{
|
|
304
|
+
config: {
|
|
305
|
+
thinking: { type: "adaptive", level: "high", streamThinking: false },
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
const config = lastStreamParams!.config as Record<string, unknown>;
|
|
311
|
+
expect(config.thinkingConfig).toBeUndefined();
|
|
312
|
+
});
|
|
313
|
+
|
|
288
314
|
test("omits thinkingConfig when wire shape is adaptive with no extras", async () => {
|
|
289
315
|
fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
|
|
290
316
|
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
stopGuardianActionSweep,
|
|
29
29
|
sweepExpiredGuardianActions,
|
|
30
30
|
} from "../calls/guardian-action-sweep.js";
|
|
31
|
-
import { getDb
|
|
31
|
+
import { getDb } from "../memory/db-connection.js";
|
|
32
32
|
import { initializeDb } from "../memory/db-init.js";
|
|
33
33
|
import {
|
|
34
34
|
createGuardianActionDelivery,
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
updateDeliveryStatus,
|
|
39
39
|
} from "../memory/guardian-action-store.js";
|
|
40
40
|
import { conversations } from "../memory/schema.js";
|
|
41
|
+
import { resetDbForTesting } from "./db-test-helpers.js";
|
|
41
42
|
|
|
42
43
|
initializeDb();
|
|
43
44
|
|
|
@@ -73,7 +74,7 @@ describe("guardian-action-sweep", () => {
|
|
|
73
74
|
|
|
74
75
|
afterAll(() => {
|
|
75
76
|
stopGuardianActionSweep();
|
|
76
|
-
|
|
77
|
+
resetDbForTesting();
|
|
77
78
|
});
|
|
78
79
|
|
|
79
80
|
test("sweepExpiredGuardianActions expires requests past their expiresAt", async () => {
|
|
@@ -88,7 +88,7 @@ globalThis.fetch = (async (
|
|
|
88
88
|
// Now import modules under test (after mocks are in place)
|
|
89
89
|
// ---------------------------------------------------------------------------
|
|
90
90
|
|
|
91
|
-
import { getDb
|
|
91
|
+
import { getDb } from "../memory/db-connection.js";
|
|
92
92
|
import { initializeDb } from "../memory/db-init.js";
|
|
93
93
|
import { updateSessionDelivery } from "../runtime/channel-verification-service.js";
|
|
94
94
|
import {
|
|
@@ -102,13 +102,14 @@ import {
|
|
|
102
102
|
resendOutbound,
|
|
103
103
|
startOutbound,
|
|
104
104
|
} from "../runtime/verification-outbound-actions.js";
|
|
105
|
+
import { resetDbForTesting } from "./db-test-helpers.js";
|
|
105
106
|
|
|
106
107
|
// Initialize the database (creates all tables)
|
|
107
108
|
initializeDb();
|
|
108
109
|
|
|
109
110
|
afterAll(() => {
|
|
110
111
|
globalThis.fetch = originalFetch;
|
|
111
|
-
|
|
112
|
+
resetDbForTesting();
|
|
112
113
|
});
|
|
113
114
|
|
|
114
115
|
function resetTables(): void {
|
|
@@ -156,9 +156,54 @@ mock.module("../daemon/skill-memory-refresh.js", () => ({
|
|
|
156
156
|
refreshSkillCapabilityMemories: mockRefreshSkillCapabilityMemories,
|
|
157
157
|
}));
|
|
158
158
|
|
|
159
|
-
mock.module("../util/platform.js", () =>
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
mock.module("../util/platform.js", () => {
|
|
160
|
+
const stub = () => "/tmp/test-stub";
|
|
161
|
+
return {
|
|
162
|
+
getWorkspaceSkillsDir: () => "/tmp/test-skills",
|
|
163
|
+
vellumRoot: stub,
|
|
164
|
+
isMacOS: () => false,
|
|
165
|
+
isLinux: () => true,
|
|
166
|
+
isWindows: () => false,
|
|
167
|
+
getPlatformName: () => "linux",
|
|
168
|
+
normalizeAssistantId: (id: string) => id,
|
|
169
|
+
getDataDir: stub,
|
|
170
|
+
getEmbeddingModelsDir: stub,
|
|
171
|
+
getSandboxRootDir: stub,
|
|
172
|
+
getSandboxWorkingDir: stub,
|
|
173
|
+
getSoundsDir: stub,
|
|
174
|
+
getAvatarDir: stub,
|
|
175
|
+
AVATAR_IMAGE_FILENAME: "avatar-image.png",
|
|
176
|
+
getAvatarImagePath: stub,
|
|
177
|
+
getXdgVellumConfigDirName: () => ".vellum",
|
|
178
|
+
getPidPath: stub,
|
|
179
|
+
getDbPath: stub,
|
|
180
|
+
getLogsDir: stub,
|
|
181
|
+
getHistoryPath: stub,
|
|
182
|
+
getProtectedDir: stub,
|
|
183
|
+
getSignalsDir: stub,
|
|
184
|
+
getDaemonStderrLogPath: stub,
|
|
185
|
+
getDaemonStartupLockPath: stub,
|
|
186
|
+
getExternalDir: stub,
|
|
187
|
+
getBinDir: stub,
|
|
188
|
+
getDotEnvPath: stub,
|
|
189
|
+
getEmbedWorkerPidPath: stub,
|
|
190
|
+
getWorkspaceDir: stub,
|
|
191
|
+
getWorkspaceDirDisplay: stub,
|
|
192
|
+
getWorkspaceConfigPath: stub,
|
|
193
|
+
getWorkspaceHooksDir: stub,
|
|
194
|
+
getWorkspacePluginsDir: stub,
|
|
195
|
+
getWorkspaceRoutesDir: stub,
|
|
196
|
+
getDeprecatedDir: stub,
|
|
197
|
+
getConversationsDir: stub,
|
|
198
|
+
getWorkspacePromptPath: stub,
|
|
199
|
+
getProfilerRootDir: stub,
|
|
200
|
+
getProfilerRunsDir: stub,
|
|
201
|
+
getProfilerRunDir: stub,
|
|
202
|
+
getSkillRuntimePath: stub,
|
|
203
|
+
getBundledBunPath: () => undefined,
|
|
204
|
+
ensureDataDir: () => {},
|
|
205
|
+
};
|
|
206
|
+
});
|
|
162
207
|
|
|
163
208
|
mock.module("../daemon/handlers/shared.js", () => ({
|
|
164
209
|
CONFIG_RELOAD_DEBOUNCE_MS: 100,
|
|
@@ -92,6 +92,7 @@ mock.module("../runtime/pending-interactions.js", () => ({
|
|
|
92
92
|
|
|
93
93
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
94
94
|
addMessage: mock(async () => ({ id: "persisted-message-id" })),
|
|
95
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
95
96
|
}));
|
|
96
97
|
|
|
97
98
|
mock.module("../config/loader.js", () => ({
|
|
@@ -74,6 +74,7 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
74
74
|
// addMessage. Disk-pressure short-circuits before addMessage ever runs,
|
|
75
75
|
// but the mock module must still expose every name the real module does.
|
|
76
76
|
addMessage: () => Promise.resolve({ id: "mock-msg-id" }),
|
|
77
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
77
78
|
}));
|
|
78
79
|
|
|
79
80
|
const mockProcessMessage = mock(() => Promise.resolve({ messageId: "msg-1" }));
|
|
@@ -159,6 +159,7 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
159
159
|
createdConversations.push(opts);
|
|
160
160
|
return { id: `conv-${++conversationIdCounter}`, ...opts };
|
|
161
161
|
},
|
|
162
|
+
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
162
163
|
}));
|
|
163
164
|
|
|
164
165
|
// Mock logger — capture warn calls for unreachable-credential assertions
|