@vellumai/assistant 0.7.2 → 0.7.3
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 +16 -1
- package/docs/architecture/memory.md +5 -2
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/openapi.yaml +449 -22
- package/package.json +1 -1
- package/src/__tests__/app-control-flow.test.ts +21 -11
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/assistant-event.test.ts +0 -10
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +4 -2
- package/src/__tests__/config-loader-backfill.test.ts +379 -0
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
- package/src/__tests__/config-watcher.test.ts +140 -69
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credentials-cli.test.ts +7 -0
- package/src/__tests__/cu-unified-flow.test.ts +176 -10
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +260 -11
- package/src/__tests__/host-app-control-proxy.test.ts +195 -25
- package/src/__tests__/host-bash-proxy.test.ts +227 -34
- package/src/__tests__/host-bash-routes.test.ts +178 -13
- package/src/__tests__/host-cu-proxy.test.ts +210 -3
- package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
- package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
- package/src/__tests__/host-file-proxy.test.ts +268 -6
- package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
- package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
- package/src/__tests__/http-user-message-parity.test.ts +107 -1
- package/src/__tests__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- package/src/__tests__/runtime-events-sse.test.ts +4 -8
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -1
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/twilio-validation.test.ts +2 -2
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/contacts.ts +64 -25
- package/src/cli/commands/credentials.ts +56 -0
- package/src/cli/commands/memory-v2.ts +7 -6
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
- package/src/cli/commands/platform/index.ts +16 -7
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/program.ts +4 -2
- package/src/config/assistant-feature-flags.ts +13 -3
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/env.ts +0 -8
- package/src/config/feature-flag-registry.json +27 -3
- package/src/config/loader.ts +127 -8
- package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +13 -0
- package/src/config/schemas/memory-v2.ts +75 -11
- package/src/config/schemas/platform.ts +43 -3
- package/src/config/schemas/services.ts +28 -0
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -25
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/config-watcher.ts +85 -57
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +170 -33
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +1 -3
- package/src/daemon/conversation-process.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +26 -0
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +195 -15
- package/src/daemon/conversation-tool-setup.ts +57 -14
- package/src/daemon/conversation.ts +17 -22
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/handlers/shared.ts +0 -1
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +137 -41
- package/src/daemon/host-bash-proxy.ts +46 -21
- package/src/daemon/host-cu-proxy.ts +49 -3
- package/src/daemon/host-file-proxy.ts +43 -7
- package/src/daemon/host-transfer-proxy.ts +95 -4
- package/src/daemon/lifecycle.ts +79 -28
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +4 -0
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/tool-setup-types.ts +2 -2
- package/src/documents/document-store.ts +85 -0
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
- package/src/heartbeat/heartbeat-run-store.ts +13 -0
- package/src/heartbeat/heartbeat-service.ts +205 -31
- package/src/home/feed-scheduler.ts +18 -0
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/assistant-server.ts +56 -2
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/protocol.ts +5 -7
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/context-search/agent-runner.ts +19 -2
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +5 -4
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +4 -12
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
- package/src/memory/graph/conversation-graph-memory.ts +42 -54
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +1 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +6 -10
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs-store.ts +48 -0
- package/src/memory/jobs-worker.ts +81 -43
- package/src/memory/memory-v2-activation-log-store.ts +32 -14
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/qdrant-client.ts +0 -13
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/search/semantic.ts +6 -67
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +311 -250
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +157 -167
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +5 -199
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/static-context.test.ts +76 -1
- package/src/memory/v2/activation.ts +149 -156
- package/src/memory/v2/consolidation-job.ts +62 -12
- package/src/memory/v2/injection.ts +47 -60
- package/src/memory/v2/prompts/consolidation.ts +36 -1
- package/src/memory/v2/qdrant.ts +99 -0
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +10 -84
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +82 -59
- package/src/memory/v2/static-context.ts +22 -0
- package/src/memory/v2/types.ts +10 -10
- package/src/notifications/copy-composer.ts +13 -0
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +21 -7
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +36 -6
- package/src/runtime/assistant-event.ts +0 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/pending-interactions.ts +8 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/client-routes.ts +20 -2
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-routes.ts +35 -26
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +6 -2
- package/src/runtime/routes/documents-routes.ts +2 -75
- package/src/runtime/routes/events-routes.ts +41 -9
- package/src/runtime/routes/host-bash-routes.ts +23 -3
- package/src/runtime/routes/host-cu-routes.ts +33 -6
- package/src/runtime/routes/host-file-routes.ts +32 -6
- package/src/runtime/routes/host-transfer-routes.ts +79 -16
- package/src/runtime/routes/identity-routes.ts +7 -138
- package/src/runtime/routes/inbound-message-handler.ts +77 -12
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-v2-routes.ts +33 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/scheduler.ts +20 -1
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/skills/remote-skill-policy.ts +4 -10
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +43 -1
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +43 -1
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +56 -11
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +43 -1
- package/src/tools/host-terminal/host-shell.ts +13 -6
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +31 -6
- package/src/tools/types.ts +24 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -404
- package/src/signals/bash.ts +0 -198
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end test for `assistant clients list` over IPC.
|
|
3
|
+
*
|
|
4
|
+
* Regression test for the gap where the same-user filter on
|
|
5
|
+
* `GET /v1/clients` (which reads `headers["x-vellum-actor-principal-id"]`)
|
|
6
|
+
* silently returned an empty list over IPC because the IPC adapter did
|
|
7
|
+
* not inject the synthetic actor-principal header that the HTTP adapter
|
|
8
|
+
* populates from the verified `AuthContext`.
|
|
9
|
+
*
|
|
10
|
+
* Asserts that in non-dev-bypass mode (`isHttpAuthDisabled() === false`),
|
|
11
|
+
* the CLI sees same-user clients via the IPC path because the IPC server
|
|
12
|
+
* fills in the header from the local guardian principal.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
afterAll,
|
|
17
|
+
afterEach,
|
|
18
|
+
beforeEach,
|
|
19
|
+
describe,
|
|
20
|
+
expect,
|
|
21
|
+
mock,
|
|
22
|
+
test,
|
|
23
|
+
} from "bun:test";
|
|
24
|
+
|
|
25
|
+
import { runAssistantCommandFull } from "../../cli/__tests__/run-assistant-command.js";
|
|
26
|
+
import { AssistantIpcServer } from "../assistant-server.js";
|
|
27
|
+
|
|
28
|
+
// ── Module mocks (must be set up before importing the route) ──────────────
|
|
29
|
+
|
|
30
|
+
let fakeHttpAuthDisabled = false;
|
|
31
|
+
let fakeLocalPrincipalId: string | undefined = "guardian-local";
|
|
32
|
+
|
|
33
|
+
mock.module("../../config/env.js", () => ({
|
|
34
|
+
isHttpAuthDisabled: () => fakeHttpAuthDisabled,
|
|
35
|
+
hasUngatedHttpAuthDisabled: () => false,
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
mock.module("../../runtime/local-actor-identity.js", () => ({
|
|
39
|
+
findLocalGuardianPrincipalId: () => fakeLocalPrincipalId,
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
// ── Real imports (after mocks) ────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
import { assistantEventHub } from "../../runtime/assistant-event-hub.js";
|
|
45
|
+
|
|
46
|
+
// ── Fixtures ──────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
let server: AssistantIpcServer | null = null;
|
|
49
|
+
|
|
50
|
+
function registerClient(args: {
|
|
51
|
+
clientId: string;
|
|
52
|
+
actorPrincipalId?: string;
|
|
53
|
+
}): void {
|
|
54
|
+
assistantEventHub.subscribe({
|
|
55
|
+
type: "client",
|
|
56
|
+
clientId: args.clientId,
|
|
57
|
+
interfaceId: "macos",
|
|
58
|
+
capabilities: ["host_bash", "host_file", "host_cu"],
|
|
59
|
+
actorPrincipalId: args.actorPrincipalId,
|
|
60
|
+
callback: () => {},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function clearHub(): void {
|
|
65
|
+
const ids = assistantEventHub.listClients().map((c) => c.clientId);
|
|
66
|
+
for (const id of ids) {
|
|
67
|
+
assistantEventHub.disposeClient(id);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function startServer(): Promise<void> {
|
|
72
|
+
server = new AssistantIpcServer();
|
|
73
|
+
await server.start();
|
|
74
|
+
// Allow the listener to be ready before the CLI tries to connect.
|
|
75
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
fakeHttpAuthDisabled = false;
|
|
80
|
+
fakeLocalPrincipalId = "guardian-local";
|
|
81
|
+
clearHub();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
afterEach(() => {
|
|
85
|
+
server?.stop();
|
|
86
|
+
server = null;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
afterAll(() => {
|
|
90
|
+
mock.restore();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// ── Tests ────────────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
describe("assistant clients list over IPC — same-user filter", () => {
|
|
96
|
+
test("returns same-user clients in non-dev-bypass mode", async () => {
|
|
97
|
+
registerClient({
|
|
98
|
+
clientId: "client-self-1",
|
|
99
|
+
actorPrincipalId: "guardian-local",
|
|
100
|
+
});
|
|
101
|
+
registerClient({
|
|
102
|
+
clientId: "client-self-2",
|
|
103
|
+
actorPrincipalId: "guardian-local",
|
|
104
|
+
});
|
|
105
|
+
registerClient({
|
|
106
|
+
clientId: "client-other",
|
|
107
|
+
actorPrincipalId: "other-user",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
await startServer();
|
|
111
|
+
|
|
112
|
+
const { stdout } = await runAssistantCommandFull(
|
|
113
|
+
"clients",
|
|
114
|
+
"list",
|
|
115
|
+
"--json",
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const parsed = JSON.parse(stdout.trim()) as {
|
|
119
|
+
clients: Array<{ clientId: string }>;
|
|
120
|
+
};
|
|
121
|
+
const ids = parsed.clients.map((c) => c.clientId).sort();
|
|
122
|
+
expect(ids).toEqual(["client-self-1", "client-self-2"]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("returns empty when no local guardian principal is bound (fail-closed)", async () => {
|
|
126
|
+
fakeLocalPrincipalId = undefined;
|
|
127
|
+
registerClient({
|
|
128
|
+
clientId: "client-self",
|
|
129
|
+
actorPrincipalId: "guardian-local",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await startServer();
|
|
133
|
+
|
|
134
|
+
const { stdout } = await runAssistantCommandFull(
|
|
135
|
+
"clients",
|
|
136
|
+
"list",
|
|
137
|
+
"--json",
|
|
138
|
+
);
|
|
139
|
+
const parsed = JSON.parse(stdout.trim()) as {
|
|
140
|
+
clients: Array<{ clientId: string }>;
|
|
141
|
+
};
|
|
142
|
+
expect(parsed.clients).toEqual([]);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("dev-bypass mode returns all clients regardless of principal", async () => {
|
|
146
|
+
fakeHttpAuthDisabled = true;
|
|
147
|
+
registerClient({
|
|
148
|
+
clientId: "client-self",
|
|
149
|
+
actorPrincipalId: "guardian-local",
|
|
150
|
+
});
|
|
151
|
+
registerClient({
|
|
152
|
+
clientId: "client-other",
|
|
153
|
+
actorPrincipalId: "other-user",
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
await startServer();
|
|
157
|
+
|
|
158
|
+
const { stdout } = await runAssistantCommandFull(
|
|
159
|
+
"clients",
|
|
160
|
+
"list",
|
|
161
|
+
"--json",
|
|
162
|
+
);
|
|
163
|
+
const parsed = JSON.parse(stdout.trim()) as {
|
|
164
|
+
clients: Array<{ clientId: string }>;
|
|
165
|
+
};
|
|
166
|
+
const ids = parsed.clients.map((c) => c.clientId).sort();
|
|
167
|
+
expect(ids).toEqual(["client-other", "client-self"]);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -32,9 +32,13 @@ import { existsSync, mkdirSync, unlinkSync } from "node:fs";
|
|
|
32
32
|
import { createServer, type Server, type Socket } from "node:net";
|
|
33
33
|
import { dirname } from "node:path";
|
|
34
34
|
|
|
35
|
+
import { findLocalGuardianPrincipalId } from "../runtime/local-actor-identity.js";
|
|
35
36
|
import { RouteError } from "../runtime/routes/errors.js";
|
|
36
37
|
import { ROUTES } from "../runtime/routes/index.js";
|
|
37
|
-
import type {
|
|
38
|
+
import type {
|
|
39
|
+
RouteDefinition,
|
|
40
|
+
RouteHandlerArgs,
|
|
41
|
+
} from "../runtime/routes/types.js";
|
|
38
42
|
import { getLogger } from "../util/logger.js";
|
|
39
43
|
import {
|
|
40
44
|
type IpcEnvelope,
|
|
@@ -256,7 +260,8 @@ export class AssistantIpcServer {
|
|
|
256
260
|
void binary;
|
|
257
261
|
|
|
258
262
|
try {
|
|
259
|
-
const
|
|
263
|
+
const handlerArgs = injectLocalActorHeader(req.params);
|
|
264
|
+
const result = handler(handlerArgs);
|
|
260
265
|
|
|
261
266
|
if (result instanceof Promise) {
|
|
262
267
|
result
|
|
@@ -454,3 +459,52 @@ export class AssistantIpcServer {
|
|
|
454
459
|
// ---------------------------------------------------------------------------
|
|
455
460
|
// Helpers
|
|
456
461
|
// ---------------------------------------------------------------------------
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Inject a synthetic `x-vellum-actor-principal-id` header from the local
|
|
465
|
+
* guardian principal when the caller hasn't already provided one.
|
|
466
|
+
*
|
|
467
|
+
* Local IPC is intra-process and owned by the same user as the daemon, so
|
|
468
|
+
* routes that consume `headers["x-vellum-actor-principal-id"]` (e.g. the
|
|
469
|
+
* same-user filter on `GET /v1/clients`) need an actor identity to function
|
|
470
|
+
* over IPC. The HTTP adapter does this from the verified `AuthContext`
|
|
471
|
+
* (`http-adapter.ts`); this helper mirrors that convention for IPC.
|
|
472
|
+
*
|
|
473
|
+
* Existing headers from the caller (e.g. the gateway's IPC runtime proxy,
|
|
474
|
+
* which forwards real `x-vellum-*` headers from the authenticated HTTP
|
|
475
|
+
* request) are preserved — we only fill in the gap for direct CLI/local
|
|
476
|
+
* IPC callers.
|
|
477
|
+
*/
|
|
478
|
+
function injectLocalActorHeader(
|
|
479
|
+
params: Record<string, unknown> | undefined,
|
|
480
|
+
): RouteHandlerArgs {
|
|
481
|
+
const args = (params ?? {}) as RouteHandlerArgs;
|
|
482
|
+
const existingHeaders = args.headers;
|
|
483
|
+
if (existingHeaders?.["x-vellum-actor-principal-id"]) {
|
|
484
|
+
return args;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Defensive: the guardian lookup queries the contacts table, which may
|
|
488
|
+
// not yet exist on a very early boot path or in test fixtures that don't
|
|
489
|
+
// initialize the DB. A failure here must not block IPC dispatch — routes
|
|
490
|
+
// that require the header will fail-closed on their own.
|
|
491
|
+
let localActor: string | undefined;
|
|
492
|
+
try {
|
|
493
|
+
localActor = findLocalGuardianPrincipalId();
|
|
494
|
+
} catch (err) {
|
|
495
|
+
log.debug(
|
|
496
|
+
{ err },
|
|
497
|
+
"failed to resolve local actor principal for IPC header injection",
|
|
498
|
+
);
|
|
499
|
+
return args;
|
|
500
|
+
}
|
|
501
|
+
if (!localActor) return args;
|
|
502
|
+
|
|
503
|
+
return {
|
|
504
|
+
...args,
|
|
505
|
+
headers: {
|
|
506
|
+
...existingHeaders,
|
|
507
|
+
"x-vellum-actor-principal-id": localActor,
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
}
|
|
@@ -38,9 +38,10 @@ const log = getLogger("gateway-ipc-client");
|
|
|
38
38
|
export async function ipcCall(
|
|
39
39
|
method: string,
|
|
40
40
|
params?: Record<string, unknown>,
|
|
41
|
+
timeoutMs?: number,
|
|
41
42
|
): Promise<unknown> {
|
|
42
43
|
const socketPath = getGatewaySocketPath();
|
|
43
|
-
return packageIpcCall(socketPath, method, params, log);
|
|
44
|
+
return packageIpcCall(socketPath, method, params, log, timeoutMs);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
// ---------------------------------------------------------------------------
|
|
@@ -90,9 +91,15 @@ export function resetPersistentClient(): void {
|
|
|
90
91
|
/**
|
|
91
92
|
* Fetch all merged feature flags from the gateway via IPC.
|
|
92
93
|
* Returns an empty record on any failure.
|
|
94
|
+
*
|
|
95
|
+
* @param timeoutMs - Optional timeout override forwarded to the IPC
|
|
96
|
+
* transport. Pass a small value (e.g. 200) for CLI startup paths where
|
|
97
|
+
* a slow/absent gateway should fail fast.
|
|
93
98
|
*/
|
|
94
|
-
export async function ipcGetFeatureFlags(
|
|
95
|
-
|
|
99
|
+
export async function ipcGetFeatureFlags(
|
|
100
|
+
timeoutMs?: number,
|
|
101
|
+
): Promise<Record<string, boolean>> {
|
|
102
|
+
const result = await ipcCall("get_feature_flags", undefined, timeoutMs);
|
|
96
103
|
if (result && typeof result === "object" && !Array.isArray(result)) {
|
|
97
104
|
const filtered: Record<string, boolean> = {};
|
|
98
105
|
for (const [k, v] of Object.entries(result as Record<string, unknown>)) {
|
|
@@ -103,6 +110,33 @@ export async function ipcGetFeatureFlags(): Promise<Record<string, boolean>> {
|
|
|
103
110
|
return {};
|
|
104
111
|
}
|
|
105
112
|
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Velay tunnel status
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
export interface VelayTunnelStatus {
|
|
118
|
+
connected: boolean;
|
|
119
|
+
publicUrl: string | null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Fetch the current Velay tunnel status from the gateway via IPC.
|
|
124
|
+
* Returns `null` when the gateway is unreachable or returns an unexpected
|
|
125
|
+
* response — callers should treat `null` as "gateway not running".
|
|
126
|
+
*/
|
|
127
|
+
export async function ipcGetVelayStatus(): Promise<VelayTunnelStatus | null> {
|
|
128
|
+
const result = await ipcCall("get_velay_status");
|
|
129
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const obj = result as Record<string, unknown>;
|
|
133
|
+
if (typeof obj.connected !== "boolean") return null;
|
|
134
|
+
return {
|
|
135
|
+
connected: obj.connected,
|
|
136
|
+
publicUrl: typeof obj.publicUrl === "string" ? obj.publicUrl : null,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
106
140
|
/**
|
|
107
141
|
* Classify risk for a tool invocation via the gateway's persistent IPC
|
|
108
142
|
* connection.
|
|
@@ -17,7 +17,7 @@ const LIVE_VOICE_AUDIO_SOURCE = "live-voice";
|
|
|
17
17
|
|
|
18
18
|
export type LiveVoiceAudioArchiveRole = "user" | "assistant";
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
type LiveVoiceAudioSource =
|
|
21
21
|
| {
|
|
22
22
|
type: "base64";
|
|
23
23
|
dataBase64: string;
|
|
@@ -28,7 +28,7 @@ export type LiveVoiceAudioSource =
|
|
|
28
28
|
sizeBytes?: number;
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
interface ArchiveLiveVoiceAudioInput {
|
|
32
32
|
messageId: string;
|
|
33
33
|
sessionId: string;
|
|
34
34
|
turnId: string;
|
|
@@ -55,7 +55,7 @@ export interface LiveVoiceAudioArtifactMetadata {
|
|
|
55
55
|
archivedAt: number;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
type LiveVoiceAudioArchiveWarningCode =
|
|
59
59
|
| "archive_failed"
|
|
60
60
|
| "attachment_not_found"
|
|
61
61
|
| "invalid_audio_source"
|
|
@@ -591,7 +591,7 @@ type LinkLiveVoiceRolelessAudioInput = Omit<
|
|
|
591
591
|
messageId?: string | null;
|
|
592
592
|
};
|
|
593
593
|
|
|
594
|
-
|
|
594
|
+
interface LinkLiveVoiceAudioArtifactInput {
|
|
595
595
|
messageId?: string | null;
|
|
596
596
|
artifact: LiveVoiceAudioArtifactMetadata;
|
|
597
597
|
position?: number;
|
|
@@ -6,8 +6,7 @@ const LIVE_VOICE_CLIENT_FRAME_TYPES = [
|
|
|
6
6
|
"end",
|
|
7
7
|
] as const;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
(typeof LIVE_VOICE_CLIENT_FRAME_TYPES)[number];
|
|
9
|
+
type LiveVoiceClientFrameType = (typeof LIVE_VOICE_CLIENT_FRAME_TYPES)[number];
|
|
11
10
|
|
|
12
11
|
const _LIVE_VOICE_SERVER_FRAME_TYPES = [
|
|
13
12
|
"ready",
|
|
@@ -23,8 +22,7 @@ const _LIVE_VOICE_SERVER_FRAME_TYPES = [
|
|
|
23
22
|
"error",
|
|
24
23
|
] as const;
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
(typeof _LIVE_VOICE_SERVER_FRAME_TYPES)[number];
|
|
25
|
+
type LiveVoiceServerFrameType = (typeof _LIVE_VOICE_SERVER_FRAME_TYPES)[number];
|
|
28
26
|
|
|
29
27
|
export const LiveVoiceProtocolErrorCode = {
|
|
30
28
|
InvalidJson: "invalid_json",
|
|
@@ -45,7 +43,7 @@ export interface LiveVoiceProtocolError {
|
|
|
45
43
|
readonly frameType?: string;
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
|
|
46
|
+
type LiveVoiceParseResult<T> =
|
|
49
47
|
| { ok: true; frame: T }
|
|
50
48
|
| { ok: false; error: LiveVoiceProtocolError };
|
|
51
49
|
|
|
@@ -85,12 +83,12 @@ export type LiveVoiceClientFrame =
|
|
|
85
83
|
| LiveVoiceClientInterruptFrame
|
|
86
84
|
| LiveVoiceClientEndFrame;
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+
interface LiveVoiceBinaryAudioFrame {
|
|
89
87
|
readonly type: "binary_audio";
|
|
90
88
|
readonly data: Uint8Array;
|
|
91
89
|
}
|
|
92
90
|
|
|
93
|
-
|
|
91
|
+
interface LiveVoiceServerFrameBase {
|
|
94
92
|
readonly type: LiveVoiceServerFrameType;
|
|
95
93
|
readonly seq: number;
|
|
96
94
|
}
|
|
@@ -76,10 +76,4 @@ export function providerForModel(
|
|
|
76
76
|
return fallback;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
export type {
|
|
80
|
-
GeneratedImage,
|
|
81
|
-
ImageGenCredentials,
|
|
82
|
-
ImageGenerationRequest,
|
|
83
|
-
ImageGenerationResult,
|
|
84
|
-
ImageGenProvider,
|
|
85
|
-
} from "./types.js";
|
|
79
|
+
export type { ImageGenCredentials } from "./types.js";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
MemoryV2ConceptRowRecord,
|
|
3
3
|
MemoryV2ConfigSnapshot,
|
|
4
|
-
MemoryV2SkillRowRecord,
|
|
5
4
|
} from "../../memory-v2-activation-log-store.js";
|
|
6
5
|
|
|
7
6
|
export const sampleConcepts: MemoryV2ConceptRowRecord[] = [
|
|
@@ -13,10 +12,28 @@ export const sampleConcepts: MemoryV2ConceptRowRecord[] = [
|
|
|
13
12
|
simUser: 0.6,
|
|
14
13
|
simAssistant: 0.4,
|
|
15
14
|
simNow: 0.3,
|
|
15
|
+
simUserRerankBoost: 0,
|
|
16
|
+
simAssistantRerankBoost: 0,
|
|
17
|
+
inRerankPool: false,
|
|
16
18
|
spreadContribution: 0.2,
|
|
17
19
|
source: "both",
|
|
18
20
|
status: "injected",
|
|
19
21
|
},
|
|
22
|
+
{
|
|
23
|
+
slug: "skills/skill-1",
|
|
24
|
+
finalActivation: 0.8,
|
|
25
|
+
ownActivation: 0.8,
|
|
26
|
+
priorActivation: 0,
|
|
27
|
+
simUser: 0.5,
|
|
28
|
+
simAssistant: 0.4,
|
|
29
|
+
simNow: 0.3,
|
|
30
|
+
simUserRerankBoost: 0,
|
|
31
|
+
simAssistantRerankBoost: 0,
|
|
32
|
+
inRerankPool: false,
|
|
33
|
+
spreadContribution: 0,
|
|
34
|
+
source: "ann_top50",
|
|
35
|
+
status: "injected",
|
|
36
|
+
},
|
|
20
37
|
{
|
|
21
38
|
slug: "concept-b",
|
|
22
39
|
finalActivation: 0.4,
|
|
@@ -25,23 +42,15 @@ export const sampleConcepts: MemoryV2ConceptRowRecord[] = [
|
|
|
25
42
|
simUser: 0.2,
|
|
26
43
|
simAssistant: 0.1,
|
|
27
44
|
simNow: 0.05,
|
|
45
|
+
simUserRerankBoost: 0,
|
|
46
|
+
simAssistantRerankBoost: 0,
|
|
47
|
+
inRerankPool: false,
|
|
28
48
|
spreadContribution: 0.0,
|
|
29
49
|
source: "ann_top50",
|
|
30
50
|
status: "not_injected",
|
|
31
51
|
},
|
|
32
52
|
];
|
|
33
53
|
|
|
34
|
-
export const sampleSkills: MemoryV2SkillRowRecord[] = [
|
|
35
|
-
{
|
|
36
|
-
id: "skill-1",
|
|
37
|
-
activation: 0.8,
|
|
38
|
-
simUser: 0.5,
|
|
39
|
-
simAssistant: 0.4,
|
|
40
|
-
simNow: 0.3,
|
|
41
|
-
status: "injected",
|
|
42
|
-
},
|
|
43
|
-
];
|
|
44
|
-
|
|
45
54
|
export const sampleConfig: MemoryV2ConfigSnapshot = {
|
|
46
55
|
d: 0.85,
|
|
47
56
|
c_user: 1.0,
|
|
@@ -50,6 +59,5 @@ export const sampleConfig: MemoryV2ConfigSnapshot = {
|
|
|
50
59
|
k: 5,
|
|
51
60
|
hops: 2,
|
|
52
61
|
top_k: 10,
|
|
53
|
-
top_k_skills: 3,
|
|
54
62
|
epsilon: 0.001,
|
|
55
63
|
};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for
|
|
2
|
+
* Tests for v1/v2 mutual exclusion in `maybeEnqueueGraphMaintenanceJobs`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - Flag
|
|
11
|
-
*
|
|
12
|
-
* - Flag on + config on,
|
|
4
|
+
* The schedule is now mutually exclusive: when both the `memory-v2-enabled`
|
|
5
|
+
* flag and `memory.v2.enabled` config are on, only `memory_v2_consolidate`
|
|
6
|
+
* is scheduled; otherwise the four v1 entries (decay, consolidate,
|
|
7
|
+
* pattern_scan, narrative) fire and the v2 entry does not.
|
|
8
|
+
*
|
|
9
|
+
* Coverage:
|
|
10
|
+
* - Flag off → only v1 entries fire (no `memory_v2_consolidate`).
|
|
11
|
+
* - Flag on + config off → only v1 entries fire.
|
|
12
|
+
* - Flag on + config on, no prior checkpoint → only the v2 entry fires.
|
|
13
|
+
* - Flag on + config on, recent checkpoint → no v2 row (interval not
|
|
14
|
+
* yet elapsed).
|
|
15
|
+
* - Flag on + config on, stale checkpoint → v2 row enqueued, checkpoint
|
|
13
16
|
* refreshed.
|
|
14
|
-
* - The v1 maintenance entries (decay, consolidate, pattern_scan,
|
|
15
|
-
* narrative) still fire under the v2 path — adding the v2 entry must
|
|
16
|
-
* not regress v1 scheduling.
|
|
17
17
|
*
|
|
18
|
-
* The sweep job is intentionally NOT scheduled here:
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* The sweep job is intentionally NOT scheduled here: it is wired into the
|
|
19
|
+
* `graph_extract` debounce in `indexer.ts`. Those triggers are covered by
|
|
20
|
+
* the separate trigger-path tests; this file owns only the cron entries.
|
|
21
21
|
*
|
|
22
22
|
* Tests use a temp workspace pinned via `VELLUM_WORKSPACE_DIR` so the DB
|
|
23
23
|
* lives under `tmpdir()` and `~/.vellum/` is never touched.
|
|
@@ -145,6 +145,11 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
|
|
|
145
145
|
maybeEnqueueGraphMaintenanceJobs(config, Date.now());
|
|
146
146
|
|
|
147
147
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
148
|
+
// v1 entries are suppressed when v2 is active.
|
|
149
|
+
expect(countPendingJobs("graph_decay")).toBe(0);
|
|
150
|
+
expect(countPendingJobs("graph_consolidate")).toBe(0);
|
|
151
|
+
expect(countPendingJobs("graph_pattern_scan")).toBe(0);
|
|
152
|
+
expect(countPendingJobs("graph_narrative_refine")).toBe(0);
|
|
148
153
|
});
|
|
149
154
|
|
|
150
155
|
test("does not enqueue consolidate before the interval has elapsed", () => {
|
|
@@ -200,11 +205,30 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
|
|
|
200
205
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
201
206
|
});
|
|
202
207
|
|
|
203
|
-
test("v1
|
|
208
|
+
test("v1 maintenance entries are suppressed when v2 is active", () => {
|
|
204
209
|
_setOverridesForTesting({ "memory-v2-enabled": true });
|
|
205
210
|
const config = buildConfig({ v2Enabled: true, intervalHours: 1 });
|
|
206
211
|
|
|
207
|
-
// No checkpoints set — every entry
|
|
212
|
+
// No checkpoints set — every entry would be due if it were scheduled.
|
|
213
|
+
deleteMemoryCheckpoint("graph_maintenance:decay:last_run");
|
|
214
|
+
deleteMemoryCheckpoint("graph_maintenance:consolidate:last_run");
|
|
215
|
+
deleteMemoryCheckpoint("graph_maintenance:pattern_scan:last_run");
|
|
216
|
+
deleteMemoryCheckpoint("graph_maintenance:narrative:last_run");
|
|
217
|
+
deleteMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY);
|
|
218
|
+
|
|
219
|
+
maybeEnqueueGraphMaintenanceJobs(config, Date.now());
|
|
220
|
+
|
|
221
|
+
expect(countPendingJobs("graph_decay")).toBe(0);
|
|
222
|
+
expect(countPendingJobs("graph_consolidate")).toBe(0);
|
|
223
|
+
expect(countPendingJobs("graph_pattern_scan")).toBe(0);
|
|
224
|
+
expect(countPendingJobs("graph_narrative_refine")).toBe(0);
|
|
225
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(1);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("flag-off path fires v1 entries and does not enqueue v2", () => {
|
|
229
|
+
_setOverridesForTesting({ "memory-v2-enabled": false });
|
|
230
|
+
const config = buildConfig({ v2Enabled: true, intervalHours: 1 });
|
|
231
|
+
|
|
208
232
|
deleteMemoryCheckpoint("graph_maintenance:decay:last_run");
|
|
209
233
|
deleteMemoryCheckpoint("graph_maintenance:consolidate:last_run");
|
|
210
234
|
deleteMemoryCheckpoint("graph_maintenance:pattern_scan:last_run");
|
|
@@ -217,19 +241,25 @@ describe("maybeEnqueueGraphMaintenanceJobs — memory v2 consolidation", () => {
|
|
|
217
241
|
expect(countPendingJobs("graph_consolidate")).toBe(1);
|
|
218
242
|
expect(countPendingJobs("graph_pattern_scan")).toBe(1);
|
|
219
243
|
expect(countPendingJobs("graph_narrative_refine")).toBe(1);
|
|
220
|
-
expect(countPendingJobs("memory_v2_consolidate")).toBe(
|
|
244
|
+
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
221
245
|
});
|
|
222
246
|
|
|
223
|
-
test("
|
|
224
|
-
_setOverridesForTesting({ "memory-v2-enabled":
|
|
225
|
-
const config = buildConfig({ v2Enabled:
|
|
247
|
+
test("config-gate-off path fires v1 entries and does not enqueue v2", () => {
|
|
248
|
+
_setOverridesForTesting({ "memory-v2-enabled": true });
|
|
249
|
+
const config = buildConfig({ v2Enabled: false, intervalHours: 1 });
|
|
226
250
|
|
|
227
251
|
deleteMemoryCheckpoint("graph_maintenance:decay:last_run");
|
|
252
|
+
deleteMemoryCheckpoint("graph_maintenance:consolidate:last_run");
|
|
253
|
+
deleteMemoryCheckpoint("graph_maintenance:pattern_scan:last_run");
|
|
254
|
+
deleteMemoryCheckpoint("graph_maintenance:narrative:last_run");
|
|
228
255
|
deleteMemoryCheckpoint(CONSOLIDATE_CHECKPOINT_KEY);
|
|
229
256
|
|
|
230
257
|
maybeEnqueueGraphMaintenanceJobs(config, Date.now());
|
|
231
258
|
|
|
232
259
|
expect(countPendingJobs("graph_decay")).toBe(1);
|
|
260
|
+
expect(countPendingJobs("graph_consolidate")).toBe(1);
|
|
261
|
+
expect(countPendingJobs("graph_pattern_scan")).toBe(1);
|
|
262
|
+
expect(countPendingJobs("graph_narrative_refine")).toBe(1);
|
|
233
263
|
expect(countPendingJobs("memory_v2_consolidate")).toBe(0);
|
|
234
264
|
});
|
|
235
265
|
});
|
|
@@ -29,7 +29,6 @@ import { memoryV2ActivationLogs } from "../schema.js";
|
|
|
29
29
|
import {
|
|
30
30
|
sampleConcepts,
|
|
31
31
|
sampleConfig,
|
|
32
|
-
sampleSkills,
|
|
33
32
|
} from "./fixtures/memory-v2-activation-fixtures.js";
|
|
34
33
|
|
|
35
34
|
initializeDb();
|
|
@@ -53,7 +52,6 @@ describe("memory-v2-activation-log-store", () => {
|
|
|
53
52
|
turn: 3,
|
|
54
53
|
mode: "per-turn",
|
|
55
54
|
concepts: sampleConcepts,
|
|
56
|
-
skills: sampleSkills,
|
|
57
55
|
config: sampleConfig,
|
|
58
56
|
});
|
|
59
57
|
|
|
@@ -65,7 +63,6 @@ describe("memory-v2-activation-log-store", () => {
|
|
|
65
63
|
expect(result!.turn).toBe(3);
|
|
66
64
|
expect(result!.mode).toBe("per-turn");
|
|
67
65
|
expect(result!.concepts).toEqual(sampleConcepts);
|
|
68
|
-
expect(result!.skills).toEqual(sampleSkills);
|
|
69
66
|
expect(result!.config).toEqual(sampleConfig);
|
|
70
67
|
});
|
|
71
68
|
|
|
@@ -82,7 +79,6 @@ describe("memory-v2-activation-log-store", () => {
|
|
|
82
79
|
turn: 1,
|
|
83
80
|
mode: "context-load",
|
|
84
81
|
concepts: sampleConcepts,
|
|
85
|
-
skills: sampleSkills,
|
|
86
82
|
config: sampleConfig,
|
|
87
83
|
});
|
|
88
84
|
recordMemoryV2ActivationLog({
|
|
@@ -90,7 +86,6 @@ describe("memory-v2-activation-log-store", () => {
|
|
|
90
86
|
turn: 2,
|
|
91
87
|
mode: "per-turn",
|
|
92
88
|
concepts: sampleConcepts,
|
|
93
|
-
skills: sampleSkills,
|
|
94
89
|
config: sampleConfig,
|
|
95
90
|
});
|
|
96
91
|
|
|
@@ -110,7 +105,6 @@ describe("memory-v2-activation-log-store", () => {
|
|
|
110
105
|
turn: 3,
|
|
111
106
|
mode: "per-turn",
|
|
112
107
|
concepts: sampleConcepts,
|
|
113
|
-
skills: sampleSkills,
|
|
114
108
|
config: sampleConfig,
|
|
115
109
|
});
|
|
116
110
|
|