@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
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for `assistant/src/memory/v2/skill-store.ts`.
|
|
3
3
|
*
|
|
4
|
-
* Coverage matrix
|
|
4
|
+
* Coverage matrix:
|
|
5
5
|
* - `seedV2SkillEntries` enumerates the catalog and calls
|
|
6
|
-
* `
|
|
6
|
+
* `upsertConceptPageEmbedding` with `slug: "skills/<id>"` for each
|
|
7
|
+
* enabled skill in the unified `memory_v2_concept_pages` collection.
|
|
7
8
|
* - It skips skills whose declared feature flag is disabled.
|
|
8
|
-
* - It calls `
|
|
9
|
-
*
|
|
9
|
+
* - It calls `pruneSlugsWithPrefixExcept("skills/", ...)` with the active
|
|
10
|
+
* id list as suffixes, so stale skill slugs in the unified collection
|
|
11
|
+
* get pruned without touching concept-page slugs.
|
|
12
|
+
* - It populates the `entries` cache so `getSkillCapability` returns each
|
|
13
|
+
* entry — accepting both bare ids (`"example-skill"`) and unified-collection
|
|
14
|
+
* slugs (`"skills/example-skill"`).
|
|
10
15
|
* - It swallows errors from the embedding backend — the function resolves
|
|
11
16
|
* and the cache is unchanged from prior state.
|
|
12
17
|
*
|
|
@@ -29,6 +34,18 @@ mock.module("../../../util/logger.js", () => ({
|
|
|
29
34
|
// Programmable test state — drives every mocked dependency below.
|
|
30
35
|
// ---------------------------------------------------------------------------
|
|
31
36
|
|
|
37
|
+
interface UpsertCall {
|
|
38
|
+
slug: string;
|
|
39
|
+
dense: number[];
|
|
40
|
+
sparse: { indices: number[]; values: number[] };
|
|
41
|
+
updatedAt: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface PruneCall {
|
|
45
|
+
prefix: string;
|
|
46
|
+
activeSuffixes: readonly string[];
|
|
47
|
+
}
|
|
48
|
+
|
|
32
49
|
interface TestState {
|
|
33
50
|
catalog: SkillSummary[];
|
|
34
51
|
resolved: ResolvedSkill[];
|
|
@@ -38,14 +55,8 @@ interface TestState {
|
|
|
38
55
|
embedThrows: Error | null;
|
|
39
56
|
embedReturn: number[][];
|
|
40
57
|
sparseReturn: { indices: number[]; values: number[] };
|
|
41
|
-
upsertCalls:
|
|
42
|
-
|
|
43
|
-
content: string;
|
|
44
|
-
dense: number[];
|
|
45
|
-
sparse: { indices: number[]; values: number[] };
|
|
46
|
-
updatedAt: number;
|
|
47
|
-
}>;
|
|
48
|
-
pruneCalls: Array<readonly string[]>;
|
|
58
|
+
upsertCalls: UpsertCall[];
|
|
59
|
+
pruneCalls: PruneCall[];
|
|
49
60
|
upsertThrows: Error | null;
|
|
50
61
|
}
|
|
51
62
|
|
|
@@ -99,13 +110,16 @@ mock.module("../../embedding-backend.js", () => ({
|
|
|
99
110
|
generateSparseEmbedding: () => state.sparseReturn,
|
|
100
111
|
}));
|
|
101
112
|
|
|
102
|
-
mock.module("../
|
|
103
|
-
|
|
113
|
+
mock.module("../qdrant.js", () => ({
|
|
114
|
+
upsertConceptPageEmbedding: async (params: UpsertCall) => {
|
|
104
115
|
if (state.upsertThrows) throw state.upsertThrows;
|
|
105
116
|
state.upsertCalls.push(params);
|
|
106
117
|
},
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
pruneSlugsWithPrefixExcept: async (
|
|
119
|
+
prefix: string,
|
|
120
|
+
activeSuffixes: readonly string[],
|
|
121
|
+
) => {
|
|
122
|
+
state.pruneCalls.push({ prefix, activeSuffixes });
|
|
109
123
|
},
|
|
110
124
|
}));
|
|
111
125
|
|
|
@@ -160,7 +174,7 @@ afterEach(resetState);
|
|
|
160
174
|
// ---------------------------------------------------------------------------
|
|
161
175
|
|
|
162
176
|
describe("seedV2SkillEntries", () => {
|
|
163
|
-
test("
|
|
177
|
+
test("upserts each enabled skill into the unified collection under skills/<id>", async () => {
|
|
164
178
|
const skillA = makeSummary({
|
|
165
179
|
id: "example-skill-a",
|
|
166
180
|
displayName: "Skill A",
|
|
@@ -182,15 +196,16 @@ describe("seedV2SkillEntries", () => {
|
|
|
182
196
|
await seedV2SkillEntries();
|
|
183
197
|
|
|
184
198
|
expect(state.upsertCalls).toHaveLength(2);
|
|
185
|
-
const
|
|
186
|
-
expect(
|
|
187
|
-
|
|
188
|
-
// Each upsert carries the per-skill dense + sparse +
|
|
189
|
-
|
|
199
|
+
const slugs = state.upsertCalls.map((c) => c.slug).sort();
|
|
200
|
+
expect(slugs).toEqual(["skills/example-skill-a", "skills/example-skill-b"]);
|
|
201
|
+
|
|
202
|
+
// Each upsert carries the per-skill dense + sparse + updatedAt payload,
|
|
203
|
+
// keyed under the unified `skills/<id>` slug.
|
|
204
|
+
const callA = state.upsertCalls.find(
|
|
205
|
+
(c) => c.slug === "skills/example-skill-a",
|
|
206
|
+
)!;
|
|
190
207
|
expect(callA.dense).toEqual([0.1, 0.2, 0.3]);
|
|
191
208
|
expect(callA.sparse).toEqual(state.sparseReturn);
|
|
192
|
-
expect(callA.content).toContain("Skill A");
|
|
193
|
-
expect(callA.content).toContain("(example-skill-a)");
|
|
194
209
|
expect(callA.updatedAt).toBeGreaterThan(0);
|
|
195
210
|
});
|
|
196
211
|
|
|
@@ -207,12 +222,11 @@ describe("seedV2SkillEntries", () => {
|
|
|
207
222
|
await seedV2SkillEntries();
|
|
208
223
|
|
|
209
224
|
expect(state.upsertCalls).toHaveLength(1);
|
|
210
|
-
expect(state.upsertCalls[0].
|
|
225
|
+
expect(state.upsertCalls[0].slug).toBe("skills/example-skill-a");
|
|
211
226
|
});
|
|
212
227
|
|
|
213
228
|
test("does not re-seed an installed-but-disabled skill from the remote catalog", async () => {
|
|
214
|
-
// Regression
|
|
215
|
-
// (Codex P1): if `seenIds` is built only from enabled skills, a locally
|
|
229
|
+
// Regression: if `seenIds` is built only from enabled skills, a locally
|
|
216
230
|
// installed-but-disabled skill falls through to the catalog loop and gets
|
|
217
231
|
// embedded as if it were a discoverable uninstalled skill — contradicting
|
|
218
232
|
// the user's explicit disablement.
|
|
@@ -223,8 +237,6 @@ describe("seedV2SkillEntries", () => {
|
|
|
223
237
|
{ summary: enabledSkill, state: "enabled" },
|
|
224
238
|
{ summary: disabledSkill, state: "disabled" },
|
|
225
239
|
];
|
|
226
|
-
// The remote catalog also contains the disabled skill (same id) — the
|
|
227
|
-
// seed function must NOT pull it back in via `getCatalog()`.
|
|
228
240
|
state.fullCatalog = [
|
|
229
241
|
{
|
|
230
242
|
id: "example-skill-b",
|
|
@@ -237,7 +249,7 @@ describe("seedV2SkillEntries", () => {
|
|
|
237
249
|
await seedV2SkillEntries();
|
|
238
250
|
|
|
239
251
|
expect(state.upsertCalls).toHaveLength(1);
|
|
240
|
-
expect(state.upsertCalls[0].
|
|
252
|
+
expect(state.upsertCalls[0].slug).toBe("skills/example-skill-a");
|
|
241
253
|
});
|
|
242
254
|
|
|
243
255
|
test("seeds genuinely uninstalled catalog skills alongside enabled installed skills", async () => {
|
|
@@ -263,8 +275,11 @@ describe("seedV2SkillEntries", () => {
|
|
|
263
275
|
|
|
264
276
|
await seedV2SkillEntries();
|
|
265
277
|
|
|
266
|
-
const
|
|
267
|
-
expect(
|
|
278
|
+
const slugs = state.upsertCalls.map((c) => c.slug).sort();
|
|
279
|
+
expect(slugs).toEqual([
|
|
280
|
+
"skills/example-skill-a",
|
|
281
|
+
"skills/uninstalled-skill",
|
|
282
|
+
]);
|
|
268
283
|
});
|
|
269
284
|
|
|
270
285
|
test("skips skills whose declared feature flag is disabled", async () => {
|
|
@@ -284,10 +299,10 @@ describe("seedV2SkillEntries", () => {
|
|
|
284
299
|
await seedV2SkillEntries();
|
|
285
300
|
|
|
286
301
|
expect(state.upsertCalls).toHaveLength(1);
|
|
287
|
-
expect(state.upsertCalls[0].
|
|
302
|
+
expect(state.upsertCalls[0].slug).toBe("skills/example-skill-b");
|
|
288
303
|
});
|
|
289
304
|
|
|
290
|
-
test("calls
|
|
305
|
+
test("calls pruneSlugsWithPrefixExcept with the active id list and the skills/ prefix", async () => {
|
|
291
306
|
const skillA = makeSummary({ id: "example-skill-a" });
|
|
292
307
|
const skillB = makeSummary({ id: "example-skill-b" });
|
|
293
308
|
state.catalog = [skillA, skillB];
|
|
@@ -309,13 +324,14 @@ describe("seedV2SkillEntries", () => {
|
|
|
309
324
|
await seedV2SkillEntries();
|
|
310
325
|
|
|
311
326
|
expect(state.pruneCalls).toHaveLength(1);
|
|
312
|
-
expect(
|
|
327
|
+
expect(state.pruneCalls[0].prefix).toBe("skills/");
|
|
328
|
+
expect([...state.pruneCalls[0].activeSuffixes].sort()).toEqual([
|
|
313
329
|
"example-skill-a",
|
|
314
330
|
"example-skill-b",
|
|
315
331
|
]);
|
|
316
332
|
});
|
|
317
333
|
|
|
318
|
-
test("passes only the active (post-flag-filter) ids to
|
|
334
|
+
test("passes only the active (post-flag-filter) ids to pruneSlugsWithPrefixExcept", async () => {
|
|
319
335
|
const flagged = makeSummary({
|
|
320
336
|
id: "example-skill-a",
|
|
321
337
|
featureFlag: "off-flag",
|
|
@@ -327,8 +343,6 @@ describe("seedV2SkillEntries", () => {
|
|
|
327
343
|
{ summary: unflagged, state: "enabled" },
|
|
328
344
|
];
|
|
329
345
|
state.flagsEnabled = { "off-flag": false };
|
|
330
|
-
// Remote catalog must be non-empty so catalogAvailable is true and
|
|
331
|
-
// pruning is not skipped.
|
|
332
346
|
state.fullCatalog = [
|
|
333
347
|
{ id: "example-skill-a", name: "example-skill-a", description: "A" },
|
|
334
348
|
{ id: "example-skill-b", name: "example-skill-b", description: "B" },
|
|
@@ -338,44 +352,35 @@ describe("seedV2SkillEntries", () => {
|
|
|
338
352
|
await seedV2SkillEntries();
|
|
339
353
|
|
|
340
354
|
expect(state.pruneCalls).toHaveLength(1);
|
|
341
|
-
expect(
|
|
355
|
+
expect(state.pruneCalls[0].prefix).toBe("skills/");
|
|
356
|
+
expect([...state.pruneCalls[0].activeSuffixes]).toEqual([
|
|
357
|
+
"example-skill-b",
|
|
358
|
+
]);
|
|
342
359
|
});
|
|
343
360
|
|
|
344
|
-
test("populates the entries cache so getSkillCapability
|
|
361
|
+
test("populates the entries cache so getSkillCapability resolves both bare id and unified slug", async () => {
|
|
345
362
|
const skillA = makeSummary({
|
|
346
363
|
id: "example-skill-a",
|
|
347
364
|
displayName: "Skill A",
|
|
348
365
|
});
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
});
|
|
353
|
-
state.catalog = [skillA, skillB];
|
|
354
|
-
state.resolved = [
|
|
355
|
-
{ summary: skillA, state: "enabled" },
|
|
356
|
-
{ summary: skillB, state: "enabled" },
|
|
357
|
-
];
|
|
358
|
-
state.embedReturn = [
|
|
359
|
-
[0.1, 0.2, 0.3],
|
|
360
|
-
[0.4, 0.5, 0.6],
|
|
361
|
-
];
|
|
366
|
+
state.catalog = [skillA];
|
|
367
|
+
state.resolved = [{ summary: skillA, state: "enabled" }];
|
|
368
|
+
state.embedReturn = [[0.1, 0.2, 0.3]];
|
|
362
369
|
|
|
363
370
|
expect(getSkillCapability("example-skill-a")).toBeNull();
|
|
364
371
|
|
|
365
372
|
await seedV2SkillEntries();
|
|
366
373
|
|
|
367
|
-
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
expect(
|
|
371
|
-
expect(
|
|
372
|
-
|
|
373
|
-
expect(
|
|
374
|
-
expect(entryB?.id).toBe("example-skill-b");
|
|
375
|
-
expect(entryB?.content).toContain("Skill B");
|
|
374
|
+
// Bare id and unified-slug forms both resolve to the same entry.
|
|
375
|
+
const byId = getSkillCapability("example-skill-a");
|
|
376
|
+
const bySlug = getSkillCapability("skills/example-skill-a");
|
|
377
|
+
expect(byId).not.toBeNull();
|
|
378
|
+
expect(byId?.id).toBe("example-skill-a");
|
|
379
|
+
expect(byId?.content).toContain("Skill A");
|
|
380
|
+
expect(bySlug).toEqual(byId);
|
|
376
381
|
|
|
377
|
-
// Unknown ids return null even when the cache is populated.
|
|
378
382
|
expect(getSkillCapability("unknown-skill")).toBeNull();
|
|
383
|
+
expect(getSkillCapability("skills/unknown-skill")).toBeNull();
|
|
379
384
|
});
|
|
380
385
|
|
|
381
386
|
test("swallows errors from embedWithBackend and leaves prior cache intact", async () => {
|
|
@@ -426,9 +431,10 @@ describe("seedV2SkillEntries", () => {
|
|
|
426
431
|
await seedV2SkillEntries();
|
|
427
432
|
|
|
428
433
|
expect(state.upsertCalls).toHaveLength(1);
|
|
429
|
-
expect(state.upsertCalls[0].
|
|
434
|
+
expect(state.upsertCalls[0].slug).toBe("skills/remote-only");
|
|
430
435
|
expect(state.pruneCalls).toHaveLength(1);
|
|
431
|
-
expect(
|
|
436
|
+
expect(state.pruneCalls[0].prefix).toBe("skills/");
|
|
437
|
+
expect([...state.pruneCalls[0].activeSuffixes]).toEqual(["remote-only"]);
|
|
432
438
|
});
|
|
433
439
|
|
|
434
440
|
test("skips pruning when catalog fetch returns empty (network failure guard)", async () => {
|
|
@@ -49,7 +49,8 @@ mock.module("../../../config/loader.js", () => ({
|
|
|
49
49
|
|
|
50
50
|
const { _setOverridesForTesting } =
|
|
51
51
|
await import("../../../config/assistant-feature-flags.js");
|
|
52
|
-
const { readMemoryV2StaticContent } =
|
|
52
|
+
const { readMemoryV2StaticContent, shouldLoadMemoryV2Static } =
|
|
53
|
+
await import("../static-context.js");
|
|
53
54
|
|
|
54
55
|
const MEMORY_FILES = [
|
|
55
56
|
"essentials.md",
|
|
@@ -150,3 +151,77 @@ describe("readMemoryV2StaticContent", () => {
|
|
|
150
151
|
expect(readMemoryV2StaticContent()).toBeNull();
|
|
151
152
|
});
|
|
152
153
|
});
|
|
154
|
+
|
|
155
|
+
describe("shouldLoadMemoryV2Static", () => {
|
|
156
|
+
test("blocks all turns until the cadence gate fires", () => {
|
|
157
|
+
expect(
|
|
158
|
+
shouldLoadMemoryV2Static({
|
|
159
|
+
shouldInjectNowAndPkb: false,
|
|
160
|
+
sourceChannel: "vellum",
|
|
161
|
+
isTrustedActor: true,
|
|
162
|
+
}),
|
|
163
|
+
).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("allows guardian-trusted local conversations", () => {
|
|
167
|
+
expect(
|
|
168
|
+
shouldLoadMemoryV2Static({
|
|
169
|
+
shouldInjectNowAndPkb: true,
|
|
170
|
+
sourceChannel: "vellum",
|
|
171
|
+
isTrustedActor: true,
|
|
172
|
+
}),
|
|
173
|
+
).toBe(true);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("allows local-channel conversations even when trust class is unknown (analyze runs, dev)", () => {
|
|
177
|
+
expect(
|
|
178
|
+
shouldLoadMemoryV2Static({
|
|
179
|
+
shouldInjectNowAndPkb: true,
|
|
180
|
+
sourceChannel: "vellum",
|
|
181
|
+
isTrustedActor: false,
|
|
182
|
+
}),
|
|
183
|
+
).toBe(true);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("allows turns with no trust context (work-item task runs, internal background)", () => {
|
|
187
|
+
expect(
|
|
188
|
+
shouldLoadMemoryV2Static({
|
|
189
|
+
shouldInjectNowAndPkb: true,
|
|
190
|
+
sourceChannel: undefined,
|
|
191
|
+
isTrustedActor: false,
|
|
192
|
+
}),
|
|
193
|
+
).toBe(true);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const REMOTE_CHANNELS = [
|
|
197
|
+
"phone",
|
|
198
|
+
"slack",
|
|
199
|
+
"telegram",
|
|
200
|
+
"whatsapp",
|
|
201
|
+
"email",
|
|
202
|
+
] as const;
|
|
203
|
+
|
|
204
|
+
test("allows guardian-trusted remote channels (user's own phone/Slack)", () => {
|
|
205
|
+
for (const channel of REMOTE_CHANNELS) {
|
|
206
|
+
expect(
|
|
207
|
+
shouldLoadMemoryV2Static({
|
|
208
|
+
shouldInjectNowAndPkb: true,
|
|
209
|
+
sourceChannel: channel,
|
|
210
|
+
isTrustedActor: true,
|
|
211
|
+
}),
|
|
212
|
+
).toBe(true);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("blocks non-guardian remote-channel actors (the leak this gate exists to prevent)", () => {
|
|
217
|
+
for (const channel of REMOTE_CHANNELS) {
|
|
218
|
+
expect(
|
|
219
|
+
shouldLoadMemoryV2Static({
|
|
220
|
+
shouldInjectNowAndPkb: true,
|
|
221
|
+
sourceChannel: channel,
|
|
222
|
+
isTrustedActor: false,
|
|
223
|
+
}),
|
|
224
|
+
).toBe(false);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
});
|