@vellumai/assistant 0.10.9 → 0.10.10-dev.202607162206.d08e98e
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 +1 -1
- package/Dockerfile +8 -0
- package/docs/activation-funnel-telemetry.md +13 -7
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
- package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
- package/openapi.yaml +530 -107
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +8 -0
- package/src/__tests__/activation-early-marking.test.ts +6 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
- package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
- package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
- package/src/__tests__/app-bundler.test.ts +4 -12
- package/src/__tests__/app-executors.test.ts +2 -49
- package/src/__tests__/app-routes-csp.test.ts +114 -146
- package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
- package/src/__tests__/build-persisted-content.test.ts +96 -0
- package/src/__tests__/bundle-scanner.test.ts +27 -1
- package/src/__tests__/call-controller.test.ts +291 -0
- package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
- package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
- package/src/__tests__/config-loader-backfill.test.ts +9 -4
- package/src/__tests__/config-schema-cmd.test.ts +10 -11
- package/src/__tests__/config-schema.test.ts +190 -257
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
- package/src/__tests__/conversation-agent-loop.test.ts +22 -9
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
- package/src/__tests__/conversation-process-callsite.test.ts +12 -19
- package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
- package/src/__tests__/conversation-summarize-route.test.ts +36 -44
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
- package/src/__tests__/conversation-usage.test.ts +4 -12
- package/src/__tests__/credential-routes.test.ts +250 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/db-migration-rollback.test.ts +22 -0
- package/src/__tests__/empty-response-hook.test.ts +186 -1
- package/src/__tests__/external-plugin-loader.test.ts +11 -5
- package/src/__tests__/heartbeat-service.test.ts +0 -28
- package/src/__tests__/host-shell-tool.test.ts +2 -0
- package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
- package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
- package/src/__tests__/invite-routes-http.test.ts +12 -16
- package/src/__tests__/list-all-apps.test.ts +0 -4
- package/src/__tests__/llm-context-resolution.test.ts +32 -56
- package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
- package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
- package/src/__tests__/llm-resolver.test.ts +342 -602
- package/src/__tests__/llm-schema.test.ts +79 -37
- package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
- package/src/__tests__/media-stream-output.test.ts +259 -3
- package/src/__tests__/media-stream-server-integration.test.ts +22 -1
- package/src/__tests__/media-stream-stt-session.test.ts +47 -0
- package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
- package/src/__tests__/memory-recall-log-store.test.ts +47 -13
- package/src/__tests__/mock-gateway-ipc.ts +46 -1
- package/src/__tests__/mtime-cache.test.ts +61 -0
- package/src/__tests__/navigate-settings-tab.test.ts +2 -0
- package/src/__tests__/normalize-onboarding.test.ts +33 -0
- package/src/__tests__/onboarding-persona-write.test.ts +26 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
- package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
- package/src/__tests__/provider-connections-backfill.test.ts +138 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
- package/src/__tests__/provider-registry-ollama.test.ts +8 -18
- package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
- package/src/__tests__/provider-usage-tracking.test.ts +9 -19
- package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
- package/src/__tests__/published-app-updater.test.ts +22 -16
- package/src/__tests__/registry.test.ts +5 -16
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
- package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
- package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
- package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
- package/src/__tests__/reveal-success-registry.test.ts +123 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
- package/src/__tests__/secret-fixtures.ts +9 -0
- package/src/__tests__/server-history-render.test.ts +28 -0
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/slack-share-routes.test.ts +0 -1
- package/src/__tests__/stt-stream-session.test.ts +6 -5
- package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
- package/src/__tests__/subagent-disposal.test.ts +2 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
- package/src/__tests__/subagent-manager-notify.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +37 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +50 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
- package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
- package/src/__tests__/telemetry-routes.test.ts +99 -19
- package/src/__tests__/tool-audit.test.ts +34 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-profiler.test.ts +72 -1
- package/src/__tests__/tool-result-spool.test.ts +49 -4
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
- package/src/__tests__/ui-channel-variants.test.ts +108 -0
- package/src/__tests__/ui-shape-teaching.test.ts +255 -0
- package/src/__tests__/usage-attribution.test.ts +18 -41
- package/src/__tests__/user-plugin-loader.test.ts +4 -4
- package/src/__tests__/voice-config-update.test.ts +46 -0
- package/src/__tests__/voice-session-bridge.test.ts +216 -84
- package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
- package/src/agent/loop.ts +4 -3
- package/src/api/events/open-conversation.test.ts +64 -0
- package/src/api/events/open-conversation.ts +33 -0
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +25 -35
- package/src/bundler/app-bundler.ts +34 -48
- package/src/bundler/app-compiler.ts +39 -4
- package/src/bundler/bundle-scanner.ts +13 -0
- package/src/bundler/manifest.ts +1 -1
- package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
- package/src/calls/call-constants.ts +5 -0
- package/src/calls/call-controller.ts +100 -32
- package/src/calls/call-transport.ts +9 -0
- package/src/calls/media-stream-output.ts +107 -4
- package/src/calls/media-stream-server.ts +29 -9
- package/src/calls/media-stream-stt-session.ts +7 -1
- package/src/calls/media-turn-detector.ts +11 -1
- package/src/calls/voice-session-bridge.ts +84 -63
- package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
- package/src/cli/commands/__tests__/notifications.test.ts +24 -3
- package/src/cli/commands/config.help.ts +6 -6
- package/src/cli/commands/credentials.help.ts +13 -0
- package/src/cli/commands/credentials.ts +6 -1
- package/src/cli/commands/email.help.ts +7 -0
- package/src/cli/commands/email.ts +35 -1
- package/src/cli/commands/inference-providers.ts +168 -107
- package/src/cli/commands/inference.help.ts +118 -46
- package/src/cli/commands/memory/index.help.ts +23 -0
- package/src/cli/commands/memory/nodes.ts +146 -0
- package/src/cli/commands/notifications.help.ts +10 -10
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
- package/src/cli/commands/oauth/connect.test.ts +126 -0
- package/src/cli/commands/oauth/connect.ts +29 -6
- package/src/cli/commands/oauth/index.help.ts +7 -1
- package/src/cli/commands/oauth/status.test.ts +69 -3
- package/src/cli/commands/oauth/status.ts +50 -12
- package/src/cli/commands/plugins.help.ts +13 -2
- package/src/cli/commands/plugins.ts +61 -7
- package/src/cli/commands/telemetry.help.ts +13 -0
- package/src/cli/commands/telemetry.ts +45 -5
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
- package/src/cli/lib/bundled-marketplace.json +93 -36
- package/src/cli/lib/inspect-plugin.ts +5 -1
- package/src/cli/lib/install-from-github.ts +68 -4
- package/src/cli/lib/plugin-catalog-local.ts +6 -2
- package/src/cli/lib/plugin-fingerprint.ts +3 -3
- package/src/cli/lib/upgrade-plugin.ts +236 -35
- package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
- package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
- package/src/config/__tests__/profile-materialization.test.ts +1 -88
- package/src/config/bundled-skills/AGENTS.md +3 -30
- package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
- package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
- package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -1
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/call-site-defaults.ts +3 -3
- package/src/config/feature-flag-registry.json +24 -39
- package/src/config/llm-resolver.ts +88 -475
- package/src/config/profile-materialization.ts +11 -11
- package/src/config/schema.ts +93 -127
- package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
- package/src/config/schemas/__tests__/stt.test.ts +31 -3
- package/src/config/schemas/live-voice.ts +10 -4
- package/src/config/schemas/llm.ts +52 -15
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +8 -0
- package/src/config/schemas/memory-v2.ts +2 -2
- package/src/config/schemas/memory-v3.ts +1 -1
- package/src/config/schemas/services.ts +6 -3
- package/src/config/schemas/stt.ts +38 -21
- package/src/config/schemas/tts.ts +13 -18
- package/src/config/skills.ts +31 -21
- package/src/context/compactor.ts +44 -7
- package/src/context/post-turn-tool-result-truncation.ts +4 -2
- package/src/context/tool-result-spool.ts +26 -5
- package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
- package/src/conversations/message-consolidation.ts +22 -2
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
- package/src/daemon/app-source-watcher.ts +17 -23
- package/src/daemon/chat-credential-redaction.ts +1365 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +627 -34
- package/src/daemon/conversation-agent-loop.ts +71 -31
- package/src/daemon/conversation-error.ts +36 -14
- package/src/daemon/conversation-process.ts +22 -0
- package/src/daemon/conversation-store.ts +35 -0
- package/src/daemon/conversation-surfaces.ts +25 -25
- package/src/daemon/conversation-tool-setup.ts +33 -7
- package/src/daemon/conversation.ts +55 -5
- package/src/daemon/handlers/shared.ts +33 -2
- package/src/daemon/lifecycle.ts +4 -4
- package/src/daemon/message-types/conversations.ts +6 -17
- package/src/daemon/providers-setup.ts +8 -0
- package/src/daemon/tool-setup-types.ts +7 -1
- package/src/daemon/wake-conversation-ops.ts +10 -1
- package/src/hooks/types.ts +9 -0
- package/src/ipc/__tests__/email-ipc.test.ts +90 -0
- package/src/ipc/gateway-client.test.ts +59 -0
- package/src/ipc/gateway-client.ts +70 -27
- package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
- package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
- package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
- package/src/live-voice/__tests__/protocol.test.ts +122 -0
- package/src/live-voice/live-voice-session.ts +443 -40
- package/src/live-voice/protocol.ts +143 -1
- package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
- package/src/monitoring/plugin-source-watch.ts +3 -62
- package/src/notifications/README.md +1 -1
- package/src/permissions/checker.ts +8 -4
- package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
- package/src/persistence/conversation-crud.ts +104 -2
- package/src/persistence/db-init.ts +14 -3
- package/src/persistence/job-handlers/cleanup.ts +15 -7
- package/src/persistence/llm-request-log-store.ts +88 -52
- package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
- package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
- package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
- package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
- package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
- package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
- package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
- package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
- package/src/persistence/migrations/helpers/relocation.ts +44 -1
- package/src/persistence/migrations/run-migrations.ts +25 -1
- package/src/persistence/schema/infrastructure.ts +9 -0
- package/src/persistence/schema/memory-core.ts +3 -0
- package/src/persistence/schema/memory-injection.ts +2 -0
- package/src/persistence/steps.ts +36 -0
- package/src/platform/client.test.ts +1 -44
- package/src/platform/client.ts +10 -20
- package/src/platform/consent-cache.test.ts +89 -23
- package/src/platform/consent-cache.ts +71 -33
- package/src/plugin-api/constants.ts +12 -0
- package/src/plugin-api/conversation-turn.ts +37 -14
- package/src/plugin-api/index.ts +11 -1
- package/src/plugin-api/resolve-credential.ts +75 -0
- package/src/plugin-api/vision-support.test.ts +8 -19
- package/src/plugin-api/vision-support.ts +26 -17
- package/src/plugins/collect-source-versions.ts +77 -0
- package/src/plugins/defaults/compaction/compact.ts +6 -0
- package/src/plugins/defaults/compaction/window-manager.ts +9 -0
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
- package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
- package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
- package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
- package/src/plugins/defaults/index.ts +8 -1
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
- package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
- package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
- package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
- package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
- package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
- package/src/plugins/defaults/memory/graph/store.ts +114 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
- package/src/plugins/defaults/memory/graph/tools.ts +47 -13
- package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
- package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
- package/src/plugins/defaults/memory/memory-db.ts +3 -2
- package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
- package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
- package/src/plugins/defaults/memory/path-containment.ts +21 -0
- package/src/plugins/defaults/memory/prompt-override.ts +51 -13
- package/src/plugins/defaults/memory/tools.test.ts +34 -0
- package/src/plugins/defaults/memory/tools.ts +12 -2
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
- package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
- package/src/plugins/defaults/memory/v2/migration.ts +46 -16
- package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
- package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
- package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
- package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
- package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
- package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
- package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
- package/src/plugins/defaults/memory/v3/prune.ts +17 -11
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
- package/src/plugins/external-plugin-loader.ts +15 -15
- package/src/plugins/mtime-cache.ts +47 -0
- package/src/plugins/pipeline.ts +9 -1
- package/src/plugins/plugin-execution-context.ts +44 -0
- package/src/plugins/plugin-tree-walk.ts +31 -24
- package/src/plugins/source-fingerprint.ts +3 -4
- package/src/prompts/normalize-onboarding.ts +12 -0
- package/src/prompts/persona-resolver.ts +8 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
- package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
- package/src/providers/__tests__/retry-callsite.test.ts +235 -215
- package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
- package/src/providers/atlascloud/client.ts +10 -49
- package/src/providers/baseten/client.ts +43 -0
- package/src/providers/call-site-routing.ts +26 -13
- package/src/providers/connection-resolution.ts +9 -11
- package/src/providers/fetch-provider-catalog.ts +4 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
- package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
- package/src/providers/inference/adapter-factory.ts +27 -6
- package/src/providers/inference/auth.ts +29 -1
- package/src/providers/inference/backfill.ts +61 -10
- package/src/providers/inference/connection-availability.ts +3 -2
- package/src/providers/inference/resolve-auth.ts +9 -1
- package/src/providers/model-catalog.ts +37 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
- package/src/providers/openai/api-key-validation.ts +70 -0
- package/src/providers/retry.ts +2 -0
- package/src/providers/types.ts +11 -4
- package/src/providers/vellum-model-routing.test.ts +26 -0
- package/src/providers/vellum-model-routing.ts +30 -0
- package/src/providers/voice-error-copy.ts +47 -0
- package/src/runtime/agent-wake.ts +40 -24
- package/src/runtime/for-chat-mint-registry.ts +118 -0
- package/src/runtime/reveal-nonce.ts +49 -0
- package/src/runtime/reveal-success-registry.ts +306 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
- package/src/runtime/routes/app-management-routes.ts +152 -45
- package/src/runtime/routes/app-routes.ts +16 -77
- package/src/runtime/routes/canned-message-complete.ts +16 -16
- package/src/runtime/routes/conversation-management-routes.ts +17 -14
- package/src/runtime/routes/conversation-query-routes.ts +54 -6
- package/src/runtime/routes/conversation-routes.ts +48 -2
- package/src/runtime/routes/credential-routes.ts +116 -3
- package/src/runtime/routes/email-routes.ts +17 -1
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
- package/src/runtime/routes/inference-send-routes.ts +1 -1
- package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
- package/src/runtime/routes/plugins-routes.ts +37 -6
- package/src/runtime/routes/publish-routes.ts +15 -18
- package/src/runtime/routes/schedule-worker-routes.ts +9 -0
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/telemetry-routes.ts +149 -45
- package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
- package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
- package/src/schedule/schedule-store.ts +12 -1
- package/src/schedule/schedule-timezone.ts +63 -0
- package/src/schedule/scheduler.ts +100 -6
- package/src/schedule/worker-control.ts +19 -0
- package/src/security/auth-fallback-events-store.ts +7 -6
- package/src/security/secret-scanner.ts +26 -1
- package/src/services/published-app-updater.ts +6 -11
- package/src/stt/stt-stream-session.ts +36 -16
- package/src/subagent/manager.ts +34 -8
- package/src/telemetry/AGENTS.md +30 -1
- package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
- package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
- package/src/telemetry/config-setting-snapshot.ts +44 -10
- package/src/telemetry/telemetry-event-sources.test.ts +124 -30
- package/src/telemetry/telemetry-event-sources.ts +137 -83
- package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
- package/src/telemetry/telemetry-events-outbox.ts +60 -9
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire-validation.ts +39 -2
- package/src/telemetry/telemetry-wire.generated.ts +8 -0
- package/src/telemetry/tool-audit.ts +15 -9
- package/src/telemetry/tool-executed-events-store.test.ts +1 -1
- package/src/telemetry/turn-events-store.ts +20 -0
- package/src/telemetry/types.ts +45 -12
- package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
- package/src/telemetry/usage-telemetry-reporter.ts +117 -18
- package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
- package/src/telemetry/watchdog-direct-emit.ts +11 -6
- package/src/tools/apps/executors.ts +11 -36
- package/src/tools/executor.ts +14 -1
- package/src/tools/host-terminal/host-shell.ts +6 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
- package/src/tools/network/web-fetch.ts +6 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/subagent/spawn.ts +7 -11
- package/src/tools/terminal/shell.ts +5 -2
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/tool-profiler.ts +37 -6
- package/src/tools/ui-surface/channel-variants.ts +101 -0
- package/src/tools/ui-surface/definitions.ts +23 -67
- package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
- package/src/tts/__tests__/provider-adapters.test.ts +18 -0
- package/src/tts/provider-catalog.ts +2 -4
- package/src/tts/providers/deepgram-provider.ts +10 -1
- package/src/types/onboarding-context.ts +8 -0
- package/src/usage/attribution.ts +18 -112
- package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
- package/src/util/provider-error-patterns.ts +7 -1
- package/src/util/worker-process.ts +105 -0
- package/src/watcher/__tests__/telemetry.test.ts +17 -4
- package/src/watcher/telemetry.ts +5 -5
- package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/workspace/provider-commit-message-generator.ts +6 -4
- package/src/__tests__/app-open-proxy.test.ts +0 -67
- package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
- package/src/onboarding/onboarding-research-events-store.ts +0 -104
- package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
- package/src/tools/apps/definitions.ts +0 -73
- package/src/tools/apps/open-proxy.ts +0 -43
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
3
|
+
|
|
4
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
2
5
|
|
|
3
6
|
let listPagesImpl: (workspaceDir: string) => Promise<string[]> = async () => [];
|
|
4
7
|
|
|
@@ -6,9 +9,12 @@ mock.module("../v2/page-store.js", () => ({
|
|
|
6
9
|
listPages: (workspaceDir: string) => listPagesImpl(workspaceDir),
|
|
7
10
|
}));
|
|
8
11
|
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
import {
|
|
13
|
+
clearStoredDb,
|
|
14
|
+
setStoredDb,
|
|
15
|
+
} from "../../../../persistence/db-singleton.js";
|
|
16
|
+
import { ensureActivationLogsSchema } from "../../../../persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.js";
|
|
17
|
+
import * as schema from "../../../../persistence/schema/index.js";
|
|
12
18
|
import {
|
|
13
19
|
type MemoryV2ConceptRowRecord,
|
|
14
20
|
recordMemoryV2ActivationLog,
|
|
@@ -16,7 +22,10 @@ import {
|
|
|
16
22
|
import { getConceptFrequencySummary } from "../memory-v2-concept-frequency.js";
|
|
17
23
|
import { sampleConfig } from "./fixtures/memory-v2-activation-fixtures.js";
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
// The store and aggregator resolve the dedicated memory connection through
|
|
26
|
+
// the `memory` singleton slot — install a fresh in-memory DB there with the
|
|
27
|
+
// relocated table's schema.
|
|
28
|
+
let memorySqlite: Database;
|
|
20
29
|
|
|
21
30
|
const WORKSPACE = "/tmp/memory-v2-concept-frequency-test";
|
|
22
31
|
|
|
@@ -41,16 +50,20 @@ function makeConcept(
|
|
|
41
50
|
};
|
|
42
51
|
}
|
|
43
52
|
|
|
44
|
-
function resetTables(): void {
|
|
45
|
-
getDb().delete(memoryV2ActivationLogs).run();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
53
|
describe("memory-v2-concept-frequency", () => {
|
|
49
54
|
beforeEach(() => {
|
|
50
|
-
|
|
55
|
+
memorySqlite = new Database(":memory:");
|
|
56
|
+
ensureActivationLogsSchema(memorySqlite);
|
|
57
|
+
setStoredDb("memory", drizzle(memorySqlite, { schema }), () =>
|
|
58
|
+
memorySqlite.close(),
|
|
59
|
+
);
|
|
51
60
|
listPagesImpl = async () => [];
|
|
52
61
|
});
|
|
53
62
|
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
clearStoredDb("memory");
|
|
65
|
+
});
|
|
66
|
+
|
|
54
67
|
test("aggregates per-status counts across multiple turns", async () => {
|
|
55
68
|
const conv = "conv-1";
|
|
56
69
|
recordMemoryV2ActivationLog({
|
|
@@ -185,7 +198,7 @@ describe("memory-v2-concept-frequency", () => {
|
|
|
185
198
|
config: sampleConfig,
|
|
186
199
|
});
|
|
187
200
|
// Backdate the just-written row — recordMemoryV2ActivationLog uses Date.now().
|
|
188
|
-
|
|
201
|
+
memorySqlite.exec(`UPDATE memory_v2_activation_logs SET created_at = 1000`);
|
|
189
202
|
|
|
190
203
|
recordMemoryV2ActivationLog({
|
|
191
204
|
conversationId: "conv-1",
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* (`assistant/src/memory/prompt-override.ts`) and the memory-v3
|
|
4
4
|
* `resolveSelectorPrompt` built on it. Mirrors the v2 router/consolidation
|
|
5
5
|
* prompt-path suites: a configured file replaces the bundled prompt, and any
|
|
6
|
-
* missing / empty / oversized / non-regular / unreadable
|
|
7
|
-
* bundled prompt with a diagnostic warning.
|
|
6
|
+
* out-of-workspace / missing / empty / oversized / non-regular / unreadable
|
|
7
|
+
* file degrades to the bundled prompt with a diagnostic warning.
|
|
8
8
|
*/
|
|
9
9
|
import { execFileSync } from "node:child_process";
|
|
10
10
|
import { mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { homedir, tmpdir } from "node:os";
|
|
12
|
-
import { join } from "node:path";
|
|
12
|
+
import { basename, join } from "node:path";
|
|
13
13
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
14
14
|
|
|
15
15
|
import {
|
|
@@ -50,6 +50,7 @@ const load = (
|
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
describe("resolveOverridePath", () => {
|
|
53
|
+
// Pure resolution — workspace containment is enforced by loadPromptOverride.
|
|
53
54
|
test("expands a leading ~/ to the home directory", () => {
|
|
54
55
|
expect(resolveOverridePath("~/sub/x.md", tmpDir)).toBe(
|
|
55
56
|
join(homedir(), "sub/x.md"),
|
|
@@ -91,17 +92,80 @@ describe("loadPromptOverride — usable override", () => {
|
|
|
91
92
|
expect(warnCalls).toHaveLength(0);
|
|
92
93
|
});
|
|
93
94
|
|
|
94
|
-
test("
|
|
95
|
+
test("honors a ~/ path that resolves inside the workspace", () => {
|
|
96
|
+
let wsUnderHome: string;
|
|
97
|
+
try {
|
|
98
|
+
wsUnderHome = mkdtempSync(join(homedir(), ".vellum-prompt-override-ws-"));
|
|
99
|
+
} catch {
|
|
100
|
+
// Home directory not writable on this platform — skip without failing.
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
writeFileSync(join(wsUnderHome, "x.md"), "home workspace body\n");
|
|
105
|
+
const out = loadPromptOverride({
|
|
106
|
+
overridePath: `~/${basename(wsUnderHome)}/x.md`,
|
|
107
|
+
workspaceDir: wsUnderHome,
|
|
108
|
+
log: recordingLogger,
|
|
109
|
+
label: "test prompt",
|
|
110
|
+
});
|
|
111
|
+
expect(out).toBe("home workspace body\n");
|
|
112
|
+
expect(warnCalls).toHaveLength(0);
|
|
113
|
+
} finally {
|
|
114
|
+
rmSync(wsUnderHome, { recursive: true, force: true });
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("loadPromptOverride — workspace containment", () => {
|
|
120
|
+
test("an absolute path outside the workspace is rejected", () => {
|
|
121
|
+
const outside = mkdtempSync(join(tmpdir(), "prompt-override-outside-"));
|
|
122
|
+
try {
|
|
123
|
+
const p = join(outside, "secret.md");
|
|
124
|
+
writeFileSync(p, "SENSITIVE CONTENTS\n");
|
|
125
|
+
expect(load(p)).toBeNull();
|
|
126
|
+
expect(warnCalls).toHaveLength(1);
|
|
127
|
+
expect(warnCalls[0].data.reason).toBe("outside_workspace");
|
|
128
|
+
expect(warnCalls[0].data.fallback).toBe("bundled");
|
|
129
|
+
} finally {
|
|
130
|
+
rmSync(outside, { recursive: true, force: true });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("a relative path escaping the workspace via .. is rejected", () => {
|
|
135
|
+
const name = `prompt-override-escape-${process.pid}.md`;
|
|
136
|
+
const target = join(tmpDir, "..", name);
|
|
137
|
+
writeFileSync(target, "escaped\n");
|
|
138
|
+
try {
|
|
139
|
+
expect(load(join("..", name))).toBeNull();
|
|
140
|
+
expect(warnCalls[0].data.reason).toBe("outside_workspace");
|
|
141
|
+
} finally {
|
|
142
|
+
rmSync(target, { force: true });
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("a ~/ path outside the workspace is rejected", () => {
|
|
95
147
|
const filename = `.vellum-prompt-override-test-${process.pid}.md`;
|
|
96
148
|
const p = join(homedir(), filename);
|
|
97
149
|
writeFileSync(p, "home body\n");
|
|
98
150
|
try {
|
|
99
|
-
expect(load(`~/${filename}`)).
|
|
100
|
-
expect(warnCalls).
|
|
151
|
+
expect(load(`~/${filename}`)).toBeNull();
|
|
152
|
+
expect(warnCalls[0].data.reason).toBe("outside_workspace");
|
|
101
153
|
} finally {
|
|
102
154
|
rmSync(p, { force: true });
|
|
103
155
|
}
|
|
104
156
|
});
|
|
157
|
+
|
|
158
|
+
test("a symlinked directory pointing outside the workspace is rejected", () => {
|
|
159
|
+
const outside = mkdtempSync(join(tmpdir(), "prompt-override-outside-"));
|
|
160
|
+
try {
|
|
161
|
+
writeFileSync(join(outside, "secret.md"), "SENSITIVE CONTENTS\n");
|
|
162
|
+
symlinkSync(outside, join(tmpDir, "linked-dir"));
|
|
163
|
+
expect(load(join("linked-dir", "secret.md"))).toBeNull();
|
|
164
|
+
expect(warnCalls[0].data.reason).toBe("outside_workspace");
|
|
165
|
+
} finally {
|
|
166
|
+
rmSync(outside, { recursive: true, force: true });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
105
169
|
});
|
|
106
170
|
|
|
107
171
|
describe("loadPromptOverride — fallback to null with a diagnostic warning", () => {
|
|
@@ -28,6 +28,14 @@ const { MEMORY_JOBS_RELOCATION } =
|
|
|
28
28
|
await import("../../../../persistence/migrations/298-move-memory-jobs-to-memory-db.js");
|
|
29
29
|
const { INJECTION_EVENTS_RELOCATION } =
|
|
30
30
|
await import("../../../../persistence/migrations/326-move-injection-events-to-memory-db.js");
|
|
31
|
+
const { ACTIVATION_LOGS_RELOCATION } =
|
|
32
|
+
await import("../../../../persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.js");
|
|
33
|
+
const { RECALL_LOGS_RELOCATION } =
|
|
34
|
+
await import("../../../../persistence/migrations/337-move-memory-recall-logs-to-memory-db.js");
|
|
35
|
+
const { MEMORY_V3_SELECTIONS_RELOCATION } =
|
|
36
|
+
await import("../../../../persistence/migrations/338-move-memory-v3-selections-to-memory-db.js");
|
|
37
|
+
const { ACTIVATION_SESSIONS_RELOCATION } =
|
|
38
|
+
await import("../../../../persistence/migrations/339-move-activation-sessions-to-memory-db.js");
|
|
31
39
|
|
|
32
40
|
await initializeDb();
|
|
33
41
|
|
|
@@ -177,3 +185,273 @@ describe("memory_v2_injection_events drain", () => {
|
|
|
177
185
|
]);
|
|
178
186
|
});
|
|
179
187
|
});
|
|
188
|
+
|
|
189
|
+
describe("memory_v3_selections drain", () => {
|
|
190
|
+
test("copies every row (full copy) and drops staging", async () => {
|
|
191
|
+
const sqlite = getSqlite();
|
|
192
|
+
const memory = getMemorySqlite()!;
|
|
193
|
+
|
|
194
|
+
// Clean slate: empty live table, fresh populated staging table with the
|
|
195
|
+
// full post-283 column set.
|
|
196
|
+
memory.exec(`DELETE FROM memory_v3_selections`);
|
|
197
|
+
sqlite.exec(`DROP TABLE IF EXISTS main."memory_v3_selections__relocating"`);
|
|
198
|
+
sqlite.exec(/*sql*/ `
|
|
199
|
+
CREATE TABLE main."memory_v3_selections__relocating" (
|
|
200
|
+
conversation_id TEXT NOT NULL,
|
|
201
|
+
turn INTEGER NOT NULL,
|
|
202
|
+
slug TEXT NOT NULL,
|
|
203
|
+
source TEXT NOT NULL,
|
|
204
|
+
pinned INTEGER NOT NULL DEFAULT 0,
|
|
205
|
+
created_at INTEGER NOT NULL,
|
|
206
|
+
message_id TEXT,
|
|
207
|
+
section_ordinal INTEGER,
|
|
208
|
+
section_title TEXT,
|
|
209
|
+
PRIMARY KEY (conversation_id, turn, slug)
|
|
210
|
+
)
|
|
211
|
+
`);
|
|
212
|
+
|
|
213
|
+
const insert = sqlite.prepare(
|
|
214
|
+
`INSERT INTO main."memory_v3_selections__relocating"
|
|
215
|
+
(conversation_id, turn, slug, source, pinned, created_at,
|
|
216
|
+
message_id, section_ordinal, section_title)
|
|
217
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
218
|
+
);
|
|
219
|
+
insert.run("conv-1", 1, "page-a", "needle", 0, 1_000, "msg-1", 2, "Head");
|
|
220
|
+
insert.run("conv-1", 2, "page-b", "core", 1, 2_000, null, null, null);
|
|
221
|
+
|
|
222
|
+
await drainStagedTable(sqlite, MEMORY_V3_SELECTIONS_RELOCATION);
|
|
223
|
+
|
|
224
|
+
expect(existsInMain("memory_v3_selections__relocating")).toBe(false);
|
|
225
|
+
|
|
226
|
+
// Both rows landed intact, secondary attributes included.
|
|
227
|
+
const kept = memory
|
|
228
|
+
.query(
|
|
229
|
+
`SELECT conversation_id, turn, slug, source, pinned, created_at,
|
|
230
|
+
message_id, section_ordinal, section_title
|
|
231
|
+
FROM memory_v3_selections WHERE conversation_id = 'conv-1'
|
|
232
|
+
ORDER BY turn`,
|
|
233
|
+
)
|
|
234
|
+
.all();
|
|
235
|
+
expect(kept).toEqual([
|
|
236
|
+
{
|
|
237
|
+
conversation_id: "conv-1",
|
|
238
|
+
turn: 1,
|
|
239
|
+
slug: "page-a",
|
|
240
|
+
source: "needle",
|
|
241
|
+
pinned: 0,
|
|
242
|
+
created_at: 1_000,
|
|
243
|
+
message_id: "msg-1",
|
|
244
|
+
section_ordinal: 2,
|
|
245
|
+
section_title: "Head",
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
conversation_id: "conv-1",
|
|
249
|
+
turn: 2,
|
|
250
|
+
slug: "page-b",
|
|
251
|
+
source: "core",
|
|
252
|
+
pinned: 1,
|
|
253
|
+
created_at: 2_000,
|
|
254
|
+
message_id: null,
|
|
255
|
+
section_ordinal: null,
|
|
256
|
+
section_title: null,
|
|
257
|
+
},
|
|
258
|
+
]);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("a pre-283 legacy source NULL-fills the missing columns", async () => {
|
|
262
|
+
const sqlite = getSqlite();
|
|
263
|
+
const memory = getMemorySqlite()!;
|
|
264
|
+
|
|
265
|
+
// Staging table shaped like migration 268's original schema — no
|
|
266
|
+
// message_id / section_ordinal / section_title columns.
|
|
267
|
+
memory.exec(`DELETE FROM memory_v3_selections`);
|
|
268
|
+
sqlite.exec(`DROP TABLE IF EXISTS main."memory_v3_selections__relocating"`);
|
|
269
|
+
sqlite.exec(/*sql*/ `
|
|
270
|
+
CREATE TABLE main."memory_v3_selections__relocating" (
|
|
271
|
+
conversation_id TEXT NOT NULL,
|
|
272
|
+
turn INTEGER NOT NULL,
|
|
273
|
+
slug TEXT NOT NULL,
|
|
274
|
+
source TEXT NOT NULL,
|
|
275
|
+
pinned INTEGER NOT NULL DEFAULT 0,
|
|
276
|
+
created_at INTEGER NOT NULL,
|
|
277
|
+
PRIMARY KEY (conversation_id, turn, slug)
|
|
278
|
+
)
|
|
279
|
+
`);
|
|
280
|
+
sqlite
|
|
281
|
+
.prepare(
|
|
282
|
+
`INSERT INTO main."memory_v3_selections__relocating"
|
|
283
|
+
(conversation_id, turn, slug, source, pinned, created_at)
|
|
284
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
285
|
+
)
|
|
286
|
+
.run("conv-legacy", 7, "page-old", "needle", 0, 5_000);
|
|
287
|
+
|
|
288
|
+
await drainStagedTable(sqlite, MEMORY_V3_SELECTIONS_RELOCATION);
|
|
289
|
+
|
|
290
|
+
expect(existsInMain("memory_v3_selections__relocating")).toBe(false);
|
|
291
|
+
|
|
292
|
+
const row = memory
|
|
293
|
+
.query(
|
|
294
|
+
`SELECT slug, created_at, message_id, section_ordinal, section_title
|
|
295
|
+
FROM memory_v3_selections WHERE conversation_id = 'conv-legacy'`,
|
|
296
|
+
)
|
|
297
|
+
.get();
|
|
298
|
+
expect(row).toEqual({
|
|
299
|
+
slug: "page-old",
|
|
300
|
+
created_at: 5_000,
|
|
301
|
+
message_id: null,
|
|
302
|
+
section_ordinal: null,
|
|
303
|
+
section_title: null,
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
describe("activation_sessions drain", () => {
|
|
309
|
+
test("copies every row and drops staging", async () => {
|
|
310
|
+
const sqlite = getSqlite();
|
|
311
|
+
const memory = getMemorySqlite()!;
|
|
312
|
+
|
|
313
|
+
memory.exec(`DELETE FROM activation_sessions`);
|
|
314
|
+
sqlite.exec(`DROP TABLE IF EXISTS main."activation_sessions__relocating"`);
|
|
315
|
+
sqlite.exec(/*sql*/ `
|
|
316
|
+
CREATE TABLE main."activation_sessions__relocating" (
|
|
317
|
+
conversation_id TEXT PRIMARY KEY,
|
|
318
|
+
created_at INTEGER NOT NULL
|
|
319
|
+
)
|
|
320
|
+
`);
|
|
321
|
+
const insert = sqlite.prepare(
|
|
322
|
+
`INSERT INTO main."activation_sessions__relocating"
|
|
323
|
+
(conversation_id, created_at) VALUES (?, ?)`,
|
|
324
|
+
);
|
|
325
|
+
insert.run("conv-a", 1_000);
|
|
326
|
+
insert.run("conv-b", 2_000);
|
|
327
|
+
|
|
328
|
+
await drainStagedTable(sqlite, ACTIVATION_SESSIONS_RELOCATION);
|
|
329
|
+
|
|
330
|
+
expect(existsInMain("activation_sessions__relocating")).toBe(false);
|
|
331
|
+
|
|
332
|
+
const kept = memory
|
|
333
|
+
.query(
|
|
334
|
+
`SELECT conversation_id, created_at FROM activation_sessions
|
|
335
|
+
ORDER BY conversation_id`,
|
|
336
|
+
)
|
|
337
|
+
.all();
|
|
338
|
+
expect(kept).toEqual([
|
|
339
|
+
{ conversation_id: "conv-a", created_at: 1_000 },
|
|
340
|
+
{ conversation_id: "conv-b", created_at: 2_000 },
|
|
341
|
+
]);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
describe("memory_v2_activation_logs drain", () => {
|
|
346
|
+
test("copies every row, drops staging", async () => {
|
|
347
|
+
const sqlite = getSqlite();
|
|
348
|
+
const memory = getMemorySqlite()!;
|
|
349
|
+
|
|
350
|
+
// Clean slate: empty live table, fresh populated staging table.
|
|
351
|
+
memory.exec(`DELETE FROM memory_v2_activation_logs`);
|
|
352
|
+
sqlite.exec(
|
|
353
|
+
`DROP TABLE IF EXISTS main."memory_v2_activation_logs__relocating"`,
|
|
354
|
+
);
|
|
355
|
+
sqlite.exec(/*sql*/ `
|
|
356
|
+
CREATE TABLE main."memory_v2_activation_logs__relocating" (
|
|
357
|
+
id TEXT PRIMARY KEY,
|
|
358
|
+
conversation_id TEXT NOT NULL,
|
|
359
|
+
message_id TEXT,
|
|
360
|
+
turn INTEGER NOT NULL,
|
|
361
|
+
mode TEXT NOT NULL,
|
|
362
|
+
concepts_json TEXT NOT NULL,
|
|
363
|
+
skills_json TEXT NOT NULL,
|
|
364
|
+
config_json TEXT NOT NULL,
|
|
365
|
+
created_at INTEGER NOT NULL
|
|
366
|
+
)
|
|
367
|
+
`);
|
|
368
|
+
|
|
369
|
+
const insert = sqlite.prepare(
|
|
370
|
+
`INSERT INTO main."memory_v2_activation_logs__relocating"
|
|
371
|
+
(id, conversation_id, message_id, turn, mode,
|
|
372
|
+
concepts_json, skills_json, config_json, created_at)
|
|
373
|
+
VALUES (?, 'conv-1', ?, ?, 'router', '[]', '[]', '{}', ?)`,
|
|
374
|
+
);
|
|
375
|
+
insert.run("act-1", "msg-1", 1, 1_000);
|
|
376
|
+
insert.run("act-2", null, 2, 2_000);
|
|
377
|
+
|
|
378
|
+
await drainStagedTable(sqlite, ACTIVATION_LOGS_RELOCATION);
|
|
379
|
+
|
|
380
|
+
// Staging dropped; the full-copy spec preserved every row and column.
|
|
381
|
+
expect(existsInMain("memory_v2_activation_logs__relocating")).toBe(false);
|
|
382
|
+
const kept = memory
|
|
383
|
+
.query<
|
|
384
|
+
{ id: string; message_id: string | null; turn: number },
|
|
385
|
+
[]
|
|
386
|
+
>(`SELECT id, message_id, turn FROM memory_v2_activation_logs ORDER BY id`)
|
|
387
|
+
.all();
|
|
388
|
+
expect(kept).toEqual([
|
|
389
|
+
{ id: "act-1", message_id: "msg-1", turn: 1 },
|
|
390
|
+
{ id: "act-2", message_id: null, turn: 2 },
|
|
391
|
+
]);
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
describe("memory_recall_logs drain", () => {
|
|
396
|
+
test("copies every row, NULL-fills query_context on a pre-211 source, drops staging", async () => {
|
|
397
|
+
const sqlite = getSqlite();
|
|
398
|
+
const memory = getMemorySqlite()!;
|
|
399
|
+
|
|
400
|
+
// Clean slate: empty live table, fresh populated staging table shaped
|
|
401
|
+
// like a legacy source that predates the query_context column.
|
|
402
|
+
memory.exec(`DELETE FROM memory_recall_logs`);
|
|
403
|
+
sqlite.exec(`DROP TABLE IF EXISTS main."memory_recall_logs__relocating"`);
|
|
404
|
+
sqlite.exec(/*sql*/ `
|
|
405
|
+
CREATE TABLE main."memory_recall_logs__relocating" (
|
|
406
|
+
id TEXT PRIMARY KEY,
|
|
407
|
+
conversation_id TEXT NOT NULL,
|
|
408
|
+
message_id TEXT,
|
|
409
|
+
enabled INTEGER NOT NULL,
|
|
410
|
+
degraded INTEGER NOT NULL,
|
|
411
|
+
provider TEXT,
|
|
412
|
+
model TEXT,
|
|
413
|
+
degradation_json TEXT,
|
|
414
|
+
semantic_hits INTEGER NOT NULL,
|
|
415
|
+
merged_count INTEGER NOT NULL,
|
|
416
|
+
selected_count INTEGER NOT NULL,
|
|
417
|
+
tier1_count INTEGER NOT NULL,
|
|
418
|
+
tier2_count INTEGER NOT NULL,
|
|
419
|
+
hybrid_search_latency_ms INTEGER NOT NULL,
|
|
420
|
+
sparse_vector_used INTEGER NOT NULL,
|
|
421
|
+
injected_tokens INTEGER NOT NULL,
|
|
422
|
+
latency_ms INTEGER NOT NULL,
|
|
423
|
+
top_candidates_json TEXT NOT NULL,
|
|
424
|
+
injected_text TEXT,
|
|
425
|
+
reason TEXT,
|
|
426
|
+
created_at INTEGER NOT NULL
|
|
427
|
+
)
|
|
428
|
+
`);
|
|
429
|
+
|
|
430
|
+
const insert = sqlite.prepare(
|
|
431
|
+
`INSERT INTO main."memory_recall_logs__relocating"
|
|
432
|
+
(id, conversation_id, message_id, enabled, degraded, semantic_hits,
|
|
433
|
+
merged_count, selected_count, tier1_count, tier2_count,
|
|
434
|
+
hybrid_search_latency_ms, sparse_vector_used, injected_tokens,
|
|
435
|
+
latency_ms, top_candidates_json, created_at)
|
|
436
|
+
VALUES (?, 'conv-1', ?, 1, 0, 3, 2, 1, 1, 0, 100, 0, 300, 150, '[]', ?)`,
|
|
437
|
+
);
|
|
438
|
+
insert.run("rec-1", "msg-1", 1_000);
|
|
439
|
+
insert.run("rec-2", null, 2_000);
|
|
440
|
+
|
|
441
|
+
await drainStagedTable(sqlite, RECALL_LOGS_RELOCATION);
|
|
442
|
+
|
|
443
|
+
// Staging dropped; both rows copied with the absent legacy column
|
|
444
|
+
// NULL-filled.
|
|
445
|
+
expect(existsInMain("memory_recall_logs__relocating")).toBe(false);
|
|
446
|
+
const kept = memory
|
|
447
|
+
.query<
|
|
448
|
+
{ id: string; message_id: string | null; query_context: string | null },
|
|
449
|
+
[]
|
|
450
|
+
>(`SELECT id, message_id, query_context FROM memory_recall_logs ORDER BY id`)
|
|
451
|
+
.all();
|
|
452
|
+
expect(kept).toEqual([
|
|
453
|
+
{ id: "rec-1", message_id: "msg-1", query_context: null },
|
|
454
|
+
{ id: "rec-2", message_id: null, query_context: null },
|
|
455
|
+
]);
|
|
456
|
+
});
|
|
457
|
+
});
|
|
@@ -1,41 +1,48 @@
|
|
|
1
|
-
import { eq } from "drizzle-orm";
|
|
2
|
-
|
|
3
|
-
import { getDb } from "../../../persistence/db-connection.js";
|
|
4
|
-
import { activationSessions } from "../../../persistence/schema/index.js";
|
|
5
1
|
import { getLogger } from "./logging.js";
|
|
2
|
+
import { memorySqliteOrNull } from "./memory-db.js";
|
|
6
3
|
|
|
7
4
|
const log = getLogger("activation-session-store");
|
|
8
5
|
|
|
9
6
|
/**
|
|
10
7
|
* Mark a conversation as an activation-rail session. Idempotent (the row's
|
|
11
|
-
* primary key is the conversation id) and best-effort:
|
|
12
|
-
* logged and swallowed so it never blocks the
|
|
8
|
+
* primary key is the conversation id) and best-effort: an unavailable memory
|
|
9
|
+
* database or a write failure is logged and swallowed so it never blocks the
|
|
10
|
+
* turn that triggered it.
|
|
13
11
|
*/
|
|
14
12
|
export function markActivationSession(conversationId: string): void {
|
|
15
13
|
try {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
const raw = memorySqliteOrNull("markActivationSession");
|
|
15
|
+
if (!raw) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
raw
|
|
19
|
+
.query(
|
|
20
|
+
/*sql*/ `INSERT OR IGNORE INTO activation_sessions (conversation_id, created_at) VALUES (?, ?)`,
|
|
21
|
+
)
|
|
22
|
+
.run(conversationId, Date.now());
|
|
21
23
|
} catch (err) {
|
|
22
24
|
log.warn({ err, conversationId }, "Failed to mark activation session");
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
|
-
* Whether the given conversation was started on the activation rail.
|
|
28
|
-
* a read failure is logged and
|
|
29
|
+
* Whether the given conversation was started on the activation rail.
|
|
30
|
+
* Best-effort: an unavailable memory database or a read failure is logged and
|
|
31
|
+
* treated as "not an activation session".
|
|
29
32
|
*/
|
|
30
33
|
export function isActivationSession(conversationId: string): boolean {
|
|
31
34
|
try {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
const raw = memorySqliteOrNull("isActivationSession");
|
|
36
|
+
if (!raw) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return (
|
|
40
|
+
raw
|
|
41
|
+
.query(
|
|
42
|
+
/*sql*/ `SELECT 1 FROM activation_sessions WHERE conversation_id = ?`,
|
|
43
|
+
)
|
|
44
|
+
.get(conversationId) != null
|
|
45
|
+
);
|
|
39
46
|
} catch (err) {
|
|
40
47
|
log.warn({ err, conversationId }, "Failed to read activation session");
|
|
41
48
|
return false;
|
|
@@ -24,10 +24,11 @@
|
|
|
24
24
|
// still surface lexical hits, and vice versa.
|
|
25
25
|
|
|
26
26
|
import { readdir, readFile, realpath, stat } from "node:fs/promises";
|
|
27
|
-
import { extname,
|
|
27
|
+
import { extname, join } from "node:path";
|
|
28
28
|
|
|
29
29
|
import { embedWithRetry } from "../../../../../persistence/embeddings/embed.js";
|
|
30
30
|
import { getLogger } from "../../logging.js";
|
|
31
|
+
import { isPathInsideRoot } from "../../path-containment.js";
|
|
31
32
|
import { spreadActivation } from "../../v2/activation.js";
|
|
32
33
|
import { getEdgeIndex } from "../../v2/edge-index.js";
|
|
33
34
|
import {
|
|
@@ -580,14 +581,6 @@ function normalizeExcerpt(excerpt: string): string {
|
|
|
580
581
|
return excerpt.trim().replace(/\s+/g, " ").toLowerCase();
|
|
581
582
|
}
|
|
582
583
|
|
|
583
|
-
function isPathInsideRoot(pathToCheck: string, rootRealPath: string): boolean {
|
|
584
|
-
const pathRelativeToRoot = relative(rootRealPath, pathToCheck);
|
|
585
|
-
return (
|
|
586
|
-
pathRelativeToRoot === "" ||
|
|
587
|
-
(!pathRelativeToRoot.startsWith("..") && !isAbsolute(pathRelativeToRoot))
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
584
|
function truncateExcerpt(text: string, maxChars: number): string {
|
|
592
585
|
if (text.length <= maxChars) return text;
|
|
593
586
|
return `${text.slice(0, maxChars - 3).trimEnd()}...`;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readdir, readFile, realpath, stat } from "node:fs/promises";
|
|
2
2
|
import { extname, isAbsolute, join, relative, sep } from "node:path";
|
|
3
3
|
|
|
4
|
+
import { isPathInsideRoot } from "../../path-containment.js";
|
|
4
5
|
import type {
|
|
5
6
|
RecallEvidence,
|
|
6
7
|
RecallSearchContext,
|
|
@@ -1208,14 +1209,6 @@ export function normalizeWorkspacePathLiteral(
|
|
|
1208
1209
|
return withoutLineSuffix.split(sep).join("/");
|
|
1209
1210
|
}
|
|
1210
1211
|
|
|
1211
|
-
function isPathInsideRoot(pathToCheck: string, rootRealPath: string): boolean {
|
|
1212
|
-
const pathRelativeToRoot = relative(rootRealPath, pathToCheck);
|
|
1213
|
-
return (
|
|
1214
|
-
pathRelativeToRoot === "" ||
|
|
1215
|
-
(!pathRelativeToRoot.startsWith("..") && !isAbsolute(pathRelativeToRoot))
|
|
1216
|
-
);
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
1212
|
function toWorkspaceRelativePath(
|
|
1220
1213
|
rootRealPath: string,
|
|
1221
1214
|
filePath: string,
|
|
@@ -126,7 +126,7 @@ function makeCapabilityNode(content: string, capId: string): NewNode {
|
|
|
126
126
|
describe("loadContextMemory — query/sparse vector surfacing", () => {
|
|
127
127
|
beforeAll(async () => {
|
|
128
128
|
await initializeDb();
|
|
129
|
-
});
|
|
129
|
+
}, 30_000);
|
|
130
130
|
|
|
131
131
|
beforeEach(async () => {
|
|
132
132
|
embedShouldThrow = false;
|
|
@@ -136,7 +136,7 @@ describe("loadContextMemory — query/sparse vector surfacing", () => {
|
|
|
136
136
|
searchRouter = null;
|
|
137
137
|
resetDbForTesting();
|
|
138
138
|
await initializeDb();
|
|
139
|
-
});
|
|
139
|
+
}, 30_000);
|
|
140
140
|
|
|
141
141
|
test("returns the dense queryVector when embedding succeeds", async () => {
|
|
142
142
|
embedVector = [0.42, 0.5, 0.7];
|
|
@@ -179,7 +179,7 @@ describe("loadContextMemory — query/sparse vector surfacing", () => {
|
|
|
179
179
|
describe("retrieveForTurn — query/sparse vector surfacing", () => {
|
|
180
180
|
beforeAll(async () => {
|
|
181
181
|
await initializeDb();
|
|
182
|
-
});
|
|
182
|
+
}, 30_000);
|
|
183
183
|
|
|
184
184
|
beforeEach(async () => {
|
|
185
185
|
embedShouldThrow = false;
|
|
@@ -189,7 +189,7 @@ describe("retrieveForTurn — query/sparse vector surfacing", () => {
|
|
|
189
189
|
searchRouter = null;
|
|
190
190
|
resetDbForTesting();
|
|
191
191
|
await initializeDb();
|
|
192
|
-
});
|
|
192
|
+
}, 30_000);
|
|
193
193
|
|
|
194
194
|
test("returns the dense queryVector when embedding succeeds", async () => {
|
|
195
195
|
embedVector = [0.9, 0.8, 0.7];
|
|
@@ -312,7 +312,7 @@ describe("retrieveForTurn — topic-pivot recovery", () => {
|
|
|
312
312
|
|
|
313
313
|
beforeAll(async () => {
|
|
314
314
|
await initializeDb();
|
|
315
|
-
});
|
|
315
|
+
}, 30_000);
|
|
316
316
|
|
|
317
317
|
beforeEach(() => {
|
|
318
318
|
embedShouldThrow = false;
|
|
@@ -462,7 +462,7 @@ describe("loadContextMemory — dual-query capability ranking", () => {
|
|
|
462
462
|
|
|
463
463
|
beforeAll(async () => {
|
|
464
464
|
await initializeDb();
|
|
465
|
-
});
|
|
465
|
+
}, 30_000);
|
|
466
466
|
|
|
467
467
|
beforeEach(() => {
|
|
468
468
|
embedShouldThrow = false;
|