@vellumai/assistant 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -0
- package/Dockerfile +5 -4
- package/README.md +2 -2
- package/docker-entrypoint.sh +16 -0
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/knip.json +2 -1
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/openapi.yaml +4847 -1698
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +52 -4
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +107 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/anthropic-provider.test.ts +92 -2
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +14 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +198 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +42 -16
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-window-manager.test.ts +389 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +38 -0
- package/src/__tests__/conversation-fork-crud.test.ts +241 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
- package/src/__tests__/conversation-lifecycle.test.ts +124 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +21 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/external-plugin-loader.test.ts +458 -0
- package/src/__tests__/filing-service.test.ts +23 -3
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/history-repair.test.ts +89 -0
- package/src/__tests__/host-app-control-proxy.test.ts +109 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +154 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +2 -2
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +146 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/managed-profile-guard.test.ts +131 -2
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -2009
- package/src/__tests__/oauth-commands-routes.test.ts +711 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/plugin-bootstrap.test.ts +31 -2
- package/src/__tests__/plugin-route-contribution.test.ts +31 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
- package/src/__tests__/plugin-types.test.ts +13 -11
- package/src/__tests__/process-message-background-slack.test.ts +46 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +118 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +104 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +2 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +145 -0
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/approvals/guardian-request-resolvers.ts +32 -87
- package/src/calls/relay-server.ts +35 -0
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +23 -4
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +1 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +593 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +414 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +346 -436
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +162 -516
- package/src/cli/commands/notifications.ts +33 -7
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +176 -297
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/program.ts +2 -4
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +76 -14
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/llm-request-logs.ts +57 -0
- package/src/config/schemas/llm.ts +52 -2
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +32 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/window-manager.ts +191 -5
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +23 -29
- package/src/daemon/config-watcher.ts +2 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
- package/src/daemon/conversation-agent-loop.ts +127 -97
- package/src/daemon/conversation-error.ts +21 -0
- package/src/daemon/conversation-lifecycle.ts +46 -5
- package/src/daemon/conversation-process.ts +36 -19
- package/src/daemon/conversation-runtime-assembly.ts +14 -5
- package/src/daemon/conversation-slash.ts +175 -23
- package/src/daemon/conversation-store.ts +17 -10
- package/src/daemon/conversation-surfaces.ts +76 -12
- package/src/daemon/conversation-tool-setup.ts +24 -14
- package/src/daemon/conversation.ts +48 -9
- package/src/daemon/external-plugins-bootstrap.ts +18 -8
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +8 -126
- package/src/daemon/handlers/config-slack-channel.ts +10 -7
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/skills.ts +84 -5
- package/src/daemon/history-repair.ts +33 -6
- package/src/daemon/host-app-control-proxy.ts +44 -19
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +96 -35
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +42 -43
- package/src/daemon/meet-host-supervisor.ts +15 -15
- package/src/daemon/memory-v2-startup.ts +9 -2
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +12 -9
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/sync.ts +60 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/process-message.ts +56 -23
- package/src/daemon/server.ts +23 -18
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +40 -53
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +148 -127
- package/src/home/__tests__/feed-types.test.ts +63 -131
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +19 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +1 -3
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +55 -6
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/bookmark-crud.ts +179 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +18 -6
- package/src/memory/context-search/sources/memory-v2.ts +39 -14
- package/src/memory/context-search/sources/memory.ts +7 -0
- package/src/memory/context-search/sources/workspace.ts +13 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +312 -10
- package/src/memory/conversation-queries.ts +9 -5
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +2 -1
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +76 -5
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/tool-handlers.ts +17 -7
- package/src/memory/graph/tools.ts +44 -5
- package/src/memory/indexer.ts +17 -0
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
- package/src/memory/jobs/embed-concept-page.ts +45 -9
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +52 -3
- package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +97 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/schema/bookmarks.ts +38 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +29 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +1 -4
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +11 -4
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +628 -10
- package/src/memory/v2/__tests__/migration.test.ts +7 -3
- package/src/memory/v2/__tests__/page-index.test.ts +277 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +516 -0
- package/src/memory/v2/__tests__/sim.test.ts +45 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
- package/src/memory/v2/__tests__/static-context.test.ts +7 -22
- package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +85 -78
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +440 -109
- package/src/memory/v2/migration.ts +117 -20
- package/src/memory/v2/page-index.ts +191 -0
- package/src/memory/v2/page-store.ts +3 -0
- package/src/memory/v2/prompts/consolidation.ts +9 -7
- package/src/memory/v2/prompts/router.ts +192 -0
- package/src/memory/v2/qdrant.ts +100 -87
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +322 -0
- package/src/memory/v2/sim.ts +25 -12
- package/src/memory/v2/skill-store.ts +118 -29
- package/src/memory/v2/static-context.ts +16 -9
- package/src/memory/v2/sweep-job.ts +122 -96
- package/src/memory/v2/types.ts +10 -6
- package/src/memory/validation.ts +13 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +2 -2
- package/src/notifications/copy-composer.ts +15 -0
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +28 -1
- package/src/notifications/home-feed-side-effect.ts +111 -0
- package/src/notifications/signal.ts +5 -0
- package/src/permissions/checker.ts +12 -0
- package/src/permissions/ipc-risk-types.ts +2 -0
- package/src/plugin-api/index.ts +13 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +62 -0
- package/src/plugins/defaults/injectors.ts +19 -3
- package/src/plugins/external-plugin-loader.ts +294 -0
- package/src/plugins/types.ts +46 -30
- package/src/plugins/user-loader.ts +64 -41
- package/src/proactive-artifact/job.test.ts +12 -4
- package/src/proactive-artifact/job.ts +4 -0
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +105 -0
- package/src/prompts/system-prompt.ts +22 -1
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +288 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +95 -26
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +163 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +173 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +356 -0
- package/src/providers/inference/resolve-auth.ts +65 -0
- package/src/providers/model-catalog.ts +104 -6
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +143 -159
- package/src/providers/retry.ts +18 -10
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +35 -6
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +303 -8
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +1 -0
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.ts +10 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +0 -18
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +154 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +192 -0
- package/src/runtime/routes/conversation-management-routes.ts +30 -43
- package/src/runtime/routes/conversation-query-routes.ts +334 -86
- package/src/runtime/routes/conversation-routes.ts +31 -10
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
- package/src/runtime/routes/index.ts +36 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/twilio.ts +1 -0
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-v2-routes.ts +13 -398
- package/src/runtime/routes/notification-routes.ts +2 -0
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/schedule-routes.ts +82 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/tts-routes.ts +67 -0
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/scheduler.ts +200 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/secret-patterns.ts +3 -0
- package/src/sequence/engine.ts +38 -40
- package/src/subagent/manager.ts +20 -15
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +15 -4
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/memory/register.test.ts +3 -3
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +13 -5
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/terminal/shell.ts +44 -0
- package/src/usage/attribution.ts +3 -2
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +301 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +90 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/registry.ts +22 -0
- package/src/workspace/migrations/runner.ts +13 -2
- package/src/workspace/migrations/types.ts +13 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -498
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -476
- package/src/memory/graph/compaction.ts +0 -299
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
* without this wrapper a memoryRetrieval call configured to run on OpenAI
|
|
9
9
|
* but originating from an Anthropic-default conversation would still hit
|
|
10
10
|
* the Anthropic transport.
|
|
11
|
+
*
|
|
12
|
+
* Alternate-provider routing requires a `provider_connection`, and the
|
|
13
|
+
* wrapper takes a single async hook
|
|
14
|
+
* `(connectionName, expectedProvider) => Promise<Provider | null>`.
|
|
15
|
+
* Call-site profiles without a connection throw `ConnectionResolutionError`.
|
|
11
16
|
*/
|
|
12
17
|
|
|
13
18
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
@@ -26,6 +31,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
26
31
|
|
|
27
32
|
import { LLMSchema } from "../config/schemas/llm.js";
|
|
28
33
|
import { CallSiteRoutingProvider } from "../providers/call-site-routing.js";
|
|
34
|
+
import { ConnectionResolutionError } from "../providers/connection-resolution.js";
|
|
29
35
|
import type {
|
|
30
36
|
Message,
|
|
31
37
|
Provider,
|
|
@@ -63,6 +69,21 @@ function setLlmConfig(raw: unknown): void {
|
|
|
63
69
|
mockLlmConfig = LLMSchema.parse(raw) as Record<string, unknown>;
|
|
64
70
|
}
|
|
65
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Build a connection-resolution hook keyed by connection name. Returns the
|
|
74
|
+
* matching Provider (or null if not registered). Async to satisfy the new
|
|
75
|
+
* `resolveByConnection` signature.
|
|
76
|
+
*/
|
|
77
|
+
function makeConnectionHook(
|
|
78
|
+
byConnection: Record<string, Provider>,
|
|
79
|
+
): (
|
|
80
|
+
connectionName: string,
|
|
81
|
+
expectedProvider: string,
|
|
82
|
+
) => Promise<Provider | null> {
|
|
83
|
+
return async (connectionName, _expectedProvider) =>
|
|
84
|
+
byConnection[connectionName] ?? null;
|
|
85
|
+
}
|
|
86
|
+
|
|
66
87
|
beforeEach(() => {
|
|
67
88
|
mockLlmConfig = LLMSchema.parse({}) as Record<string, unknown>;
|
|
68
89
|
});
|
|
@@ -71,8 +92,15 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
71
92
|
test("routes to default provider when callSite is absent", async () => {
|
|
72
93
|
setLlmConfig({
|
|
73
94
|
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
95
|
+
profiles: {
|
|
96
|
+
altOpenai: {
|
|
97
|
+
provider: "openai",
|
|
98
|
+
provider_connection: "openai-conn",
|
|
99
|
+
model: "gpt-5.4",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
74
102
|
callSites: {
|
|
75
|
-
memoryRetrieval: {
|
|
103
|
+
memoryRetrieval: { profile: "altOpenai" },
|
|
76
104
|
},
|
|
77
105
|
});
|
|
78
106
|
|
|
@@ -84,8 +112,9 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
84
112
|
calls.alt++;
|
|
85
113
|
});
|
|
86
114
|
|
|
87
|
-
const wrapped = new CallSiteRoutingProvider(
|
|
88
|
-
|
|
115
|
+
const wrapped = new CallSiteRoutingProvider(
|
|
116
|
+
defaultProvider,
|
|
117
|
+
makeConnectionHook({ "openai-conn": altProvider }),
|
|
89
118
|
);
|
|
90
119
|
|
|
91
120
|
const response = await wrapped.sendMessage(
|
|
@@ -102,11 +131,12 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
102
131
|
expect(response.model).toBe("anthropic");
|
|
103
132
|
});
|
|
104
133
|
|
|
105
|
-
test("routes to default provider when callSite resolves to same provider name", async () => {
|
|
134
|
+
test("routes to default provider when callSite resolves to same provider name (no connection)", async () => {
|
|
106
135
|
setLlmConfig({
|
|
107
136
|
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
108
137
|
callSites: {
|
|
109
|
-
// Same provider as default —
|
|
138
|
+
// Same provider as default, no connection — should reuse default
|
|
139
|
+
// without doing any connection resolution work.
|
|
110
140
|
memoryRetrieval: { model: "claude-haiku-4-5-20251001" },
|
|
111
141
|
},
|
|
112
142
|
});
|
|
@@ -119,8 +149,9 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
119
149
|
calls.alt++;
|
|
120
150
|
});
|
|
121
151
|
|
|
122
|
-
const wrapped = new CallSiteRoutingProvider(
|
|
123
|
-
|
|
152
|
+
const wrapped = new CallSiteRoutingProvider(
|
|
153
|
+
defaultProvider,
|
|
154
|
+
makeConnectionHook({ "openai-conn": altProvider }),
|
|
124
155
|
);
|
|
125
156
|
|
|
126
157
|
await wrapped.sendMessage(DUMMY_MESSAGES, undefined, undefined, {
|
|
@@ -131,11 +162,18 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
131
162
|
expect(calls.alt).toBe(0);
|
|
132
163
|
});
|
|
133
164
|
|
|
134
|
-
test("routes to alternative provider when callSite resolves to a
|
|
165
|
+
test("routes to alternative provider when callSite resolves to a profile with provider_connection", async () => {
|
|
135
166
|
setLlmConfig({
|
|
136
167
|
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
168
|
+
profiles: {
|
|
169
|
+
altOpenai: {
|
|
170
|
+
provider: "openai",
|
|
171
|
+
provider_connection: "openai-conn",
|
|
172
|
+
model: "gpt-5.4",
|
|
173
|
+
},
|
|
174
|
+
},
|
|
137
175
|
callSites: {
|
|
138
|
-
memoryRetrieval: {
|
|
176
|
+
memoryRetrieval: { profile: "altOpenai" },
|
|
139
177
|
},
|
|
140
178
|
});
|
|
141
179
|
|
|
@@ -147,8 +185,9 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
147
185
|
calls.alt++;
|
|
148
186
|
});
|
|
149
187
|
|
|
150
|
-
const wrapped = new CallSiteRoutingProvider(
|
|
151
|
-
|
|
188
|
+
const wrapped = new CallSiteRoutingProvider(
|
|
189
|
+
defaultProvider,
|
|
190
|
+
makeConnectionHook({ "openai-conn": altProvider }),
|
|
152
191
|
);
|
|
153
192
|
|
|
154
193
|
const response = await wrapped.sendMessage(
|
|
@@ -163,11 +202,18 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
163
202
|
expect(response.model).toBe("openai");
|
|
164
203
|
});
|
|
165
204
|
|
|
166
|
-
test("falls back to default when
|
|
205
|
+
test("falls back to default when connection resolves to null (soft credential failure)", async () => {
|
|
167
206
|
setLlmConfig({
|
|
168
207
|
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
208
|
+
profiles: {
|
|
209
|
+
altOpenai: {
|
|
210
|
+
provider: "openai",
|
|
211
|
+
provider_connection: "openai-conn",
|
|
212
|
+
model: "gpt-5.4",
|
|
213
|
+
},
|
|
214
|
+
},
|
|
169
215
|
callSites: {
|
|
170
|
-
memoryRetrieval: {
|
|
216
|
+
memoryRetrieval: { profile: "altOpenai" },
|
|
171
217
|
},
|
|
172
218
|
});
|
|
173
219
|
|
|
@@ -176,11 +222,11 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
176
222
|
calls.default++;
|
|
177
223
|
});
|
|
178
224
|
|
|
179
|
-
//
|
|
180
|
-
//
|
|
225
|
+
// Hook always returns null — simulates a credential miss / transient
|
|
226
|
+
// auth failure inside the resolver.
|
|
181
227
|
const wrapped = new CallSiteRoutingProvider(
|
|
182
228
|
defaultProvider,
|
|
183
|
-
() =>
|
|
229
|
+
async () => null,
|
|
184
230
|
);
|
|
185
231
|
|
|
186
232
|
const response = await wrapped.sendMessage(
|
|
@@ -194,19 +240,65 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
194
240
|
expect(response.model).toBe("anthropic");
|
|
195
241
|
});
|
|
196
242
|
|
|
243
|
+
test("alternate-provider profile WITHOUT a connection throws ConnectionResolutionError", async () => {
|
|
244
|
+
setLlmConfig({
|
|
245
|
+
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
246
|
+
profiles: {
|
|
247
|
+
legacyOpenai: {
|
|
248
|
+
provider: "openai",
|
|
249
|
+
// No provider_connection — alternate-provider routing requires
|
|
250
|
+
// one, so this profile is expected to throw
|
|
251
|
+
// `ConnectionResolutionError(missing_connection)` below.
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
callSites: {
|
|
255
|
+
memoryRetrieval: { profile: "legacyOpenai" },
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const defaultProvider = makeProvider("anthropic", () => {});
|
|
260
|
+
|
|
261
|
+
const wrapped = new CallSiteRoutingProvider(
|
|
262
|
+
defaultProvider,
|
|
263
|
+
makeConnectionHook({}),
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
let caught: unknown;
|
|
267
|
+
try {
|
|
268
|
+
await wrapped.sendMessage(DUMMY_MESSAGES, undefined, undefined, {
|
|
269
|
+
config: { callSite: "memoryRetrieval" },
|
|
270
|
+
});
|
|
271
|
+
} catch (err) {
|
|
272
|
+
caught = err;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
expect(caught).toBeInstanceOf(ConnectionResolutionError);
|
|
276
|
+
expect((caught as ConnectionResolutionError).reason).toBe(
|
|
277
|
+
"missing_connection",
|
|
278
|
+
);
|
|
279
|
+
});
|
|
280
|
+
|
|
197
281
|
test("stamps actualProvider when routing to an alternative provider", async () => {
|
|
198
282
|
setLlmConfig({
|
|
199
283
|
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
284
|
+
profiles: {
|
|
285
|
+
altOpenai: {
|
|
286
|
+
provider: "openai",
|
|
287
|
+
provider_connection: "openai-conn",
|
|
288
|
+
model: "gpt-5.5",
|
|
289
|
+
},
|
|
290
|
+
},
|
|
200
291
|
callSites: {
|
|
201
|
-
memoryRetrieval: {
|
|
292
|
+
memoryRetrieval: { profile: "altOpenai" },
|
|
202
293
|
},
|
|
203
294
|
});
|
|
204
295
|
|
|
205
296
|
const defaultProvider = makeProvider("anthropic", () => {});
|
|
206
297
|
const altProvider = makeProvider("openai", () => {});
|
|
207
298
|
|
|
208
|
-
const wrapped = new CallSiteRoutingProvider(
|
|
209
|
-
|
|
299
|
+
const wrapped = new CallSiteRoutingProvider(
|
|
300
|
+
defaultProvider,
|
|
301
|
+
makeConnectionHook({ "openai-conn": altProvider }),
|
|
210
302
|
);
|
|
211
303
|
|
|
212
304
|
const response = await wrapped.sendMessage(
|
|
@@ -225,8 +317,15 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
225
317
|
test("does not overwrite actualProvider already set by the alternative provider", async () => {
|
|
226
318
|
setLlmConfig({
|
|
227
319
|
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
320
|
+
profiles: {
|
|
321
|
+
altOpenai: {
|
|
322
|
+
provider: "openai",
|
|
323
|
+
provider_connection: "openai-conn",
|
|
324
|
+
model: "gpt-5.5",
|
|
325
|
+
},
|
|
326
|
+
},
|
|
228
327
|
callSites: {
|
|
229
|
-
memoryRetrieval: {
|
|
328
|
+
memoryRetrieval: { profile: "altOpenai" },
|
|
230
329
|
},
|
|
231
330
|
});
|
|
232
331
|
|
|
@@ -242,8 +341,9 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
242
341
|
},
|
|
243
342
|
};
|
|
244
343
|
|
|
245
|
-
const wrapped = new CallSiteRoutingProvider(
|
|
246
|
-
|
|
344
|
+
const wrapped = new CallSiteRoutingProvider(
|
|
345
|
+
defaultProvider,
|
|
346
|
+
makeConnectionHook({ "openai-conn": altProvider }),
|
|
247
347
|
);
|
|
248
348
|
|
|
249
349
|
const response = await wrapped.sendMessage(
|
|
@@ -265,7 +365,7 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
265
365
|
|
|
266
366
|
const wrapped = new CallSiteRoutingProvider(
|
|
267
367
|
defaultProvider,
|
|
268
|
-
()
|
|
368
|
+
makeConnectionHook({}),
|
|
269
369
|
);
|
|
270
370
|
|
|
271
371
|
const response = await wrapped.sendMessage(
|
|
@@ -290,7 +390,7 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
290
390
|
|
|
291
391
|
const wrapped = new CallSiteRoutingProvider(
|
|
292
392
|
defaultProvider,
|
|
293
|
-
()
|
|
393
|
+
makeConnectionHook({}),
|
|
294
394
|
);
|
|
295
395
|
|
|
296
396
|
expect(wrapped.name).toBe("anthropic");
|
|
@@ -304,8 +404,15 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
304
404
|
// event says "LLM call to anthropic" even when the call went to openai.
|
|
305
405
|
setLlmConfig({
|
|
306
406
|
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
407
|
+
profiles: {
|
|
408
|
+
altOpenai: {
|
|
409
|
+
provider: "openai",
|
|
410
|
+
provider_connection: "openai-conn",
|
|
411
|
+
model: "gpt-5.5",
|
|
412
|
+
},
|
|
413
|
+
},
|
|
307
414
|
callSites: {
|
|
308
|
-
memoryRetrieval: {
|
|
415
|
+
memoryRetrieval: { profile: "altOpenai" },
|
|
309
416
|
},
|
|
310
417
|
});
|
|
311
418
|
|
|
@@ -321,8 +428,9 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
321
428
|
},
|
|
322
429
|
};
|
|
323
430
|
|
|
324
|
-
const wrapped = new CallSiteRoutingProvider(
|
|
325
|
-
|
|
431
|
+
const wrapped = new CallSiteRoutingProvider(
|
|
432
|
+
defaultProvider,
|
|
433
|
+
makeConnectionHook({ "openai-conn": altProvider }),
|
|
326
434
|
);
|
|
327
435
|
|
|
328
436
|
expect(wrapped.name).toBe("anthropic"); // idle → default
|
|
@@ -339,9 +447,21 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
339
447
|
// other. AsyncLocalStorage gives each call its own async-context slot.
|
|
340
448
|
setLlmConfig({
|
|
341
449
|
default: { provider: "anthropic", model: "claude-opus-4-7" },
|
|
450
|
+
profiles: {
|
|
451
|
+
altOpenai: {
|
|
452
|
+
provider: "openai",
|
|
453
|
+
provider_connection: "openai-conn",
|
|
454
|
+
model: "gpt-5.5",
|
|
455
|
+
},
|
|
456
|
+
altFireworks: {
|
|
457
|
+
provider: "fireworks",
|
|
458
|
+
provider_connection: "fireworks-conn",
|
|
459
|
+
model: "qwen3-235b",
|
|
460
|
+
},
|
|
461
|
+
},
|
|
342
462
|
callSites: {
|
|
343
|
-
memoryRetrieval: {
|
|
344
|
-
conversationTitle: {
|
|
463
|
+
memoryRetrieval: { profile: "altOpenai" },
|
|
464
|
+
conversationTitle: { profile: "altFireworks" },
|
|
345
465
|
},
|
|
346
466
|
});
|
|
347
467
|
|
|
@@ -349,18 +469,25 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
349
469
|
const nameSeenByOpenAI: string[] = [];
|
|
350
470
|
const nameSeenByFireworks: string[] = [];
|
|
351
471
|
|
|
352
|
-
// Shared resolve handles
|
|
353
|
-
//
|
|
472
|
+
// Shared resolve handles, pre-bound via Deferred-style promises so they
|
|
473
|
+
// exist before either provider's sendMessage executes. The connection-
|
|
474
|
+
// aware dispatch path awaits an extra tick to resolve the connection
|
|
475
|
+
// before invoking sendMessage, so any late-binding via
|
|
476
|
+
// `new Promise((r) => { resolveOpenAI = r })` would race with the
|
|
477
|
+
// microtask queue — these handles must be assigned synchronously.
|
|
354
478
|
let resolveOpenAI!: () => void;
|
|
355
479
|
let resolveFireworks!: () => void;
|
|
480
|
+
const openAIBlocked = new Promise<void>((r) => {
|
|
481
|
+
resolveOpenAI = r;
|
|
482
|
+
});
|
|
483
|
+
const fireworksBlocked = new Promise<void>((r) => {
|
|
484
|
+
resolveFireworks = r;
|
|
485
|
+
});
|
|
356
486
|
|
|
357
487
|
const openAIProvider: Provider = {
|
|
358
488
|
name: "openai",
|
|
359
489
|
async sendMessage() {
|
|
360
|
-
|
|
361
|
-
await new Promise<void>((r) => {
|
|
362
|
-
resolveOpenAI = r;
|
|
363
|
-
});
|
|
490
|
+
await openAIBlocked;
|
|
364
491
|
nameSeenByOpenAI.push(wrapped.name);
|
|
365
492
|
return makeResponse("openai");
|
|
366
493
|
},
|
|
@@ -369,19 +496,19 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
369
496
|
const fireworksProvider: Provider = {
|
|
370
497
|
name: "fireworks",
|
|
371
498
|
async sendMessage() {
|
|
372
|
-
await
|
|
373
|
-
resolveFireworks = r;
|
|
374
|
-
});
|
|
499
|
+
await fireworksBlocked;
|
|
375
500
|
nameSeenByFireworks.push(wrapped.name);
|
|
376
501
|
return makeResponse("fireworks");
|
|
377
502
|
},
|
|
378
503
|
};
|
|
379
504
|
|
|
380
|
-
const wrapped = new CallSiteRoutingProvider(
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
505
|
+
const wrapped = new CallSiteRoutingProvider(
|
|
506
|
+
defaultProvider,
|
|
507
|
+
makeConnectionHook({
|
|
508
|
+
"openai-conn": openAIProvider,
|
|
509
|
+
"fireworks-conn": fireworksProvider,
|
|
510
|
+
}),
|
|
511
|
+
);
|
|
385
512
|
|
|
386
513
|
// Start both calls concurrently (do not await yet).
|
|
387
514
|
const callA = wrapped.sendMessage(DUMMY_MESSAGES, undefined, undefined, {
|
|
@@ -391,8 +518,8 @@ describe("CallSiteRoutingProvider", () => {
|
|
|
391
518
|
config: { callSite: "conversationTitle" }, // → fireworks
|
|
392
519
|
});
|
|
393
520
|
|
|
394
|
-
//
|
|
395
|
-
|
|
521
|
+
// Resolve both — the awaits above guarantee these handles fire even if
|
|
522
|
+
// the providers' sendMessage hasn't executed yet.
|
|
396
523
|
resolveOpenAI();
|
|
397
524
|
resolveFireworks();
|
|
398
525
|
|
|
@@ -57,6 +57,7 @@ mock.module("../daemon/handlers/conversations.js", () => ({
|
|
|
57
57
|
import { getOrCreateConversation } from "../memory/conversation-key-store.js";
|
|
58
58
|
import { initializeDb } from "../memory/db-init.js";
|
|
59
59
|
import { ROUTES } from "../runtime/routes/conversation-management-routes.js";
|
|
60
|
+
import { routeDefinitionsToHTTPRoutes } from "../runtime/routes/http-adapter.js";
|
|
60
61
|
|
|
61
62
|
initializeDb();
|
|
62
63
|
|
|
@@ -73,27 +74,67 @@ describe("POST /v1/conversations/:id/cancel", () => {
|
|
|
73
74
|
|
|
74
75
|
expect(internalId).not.toBe(conversationKey);
|
|
75
76
|
|
|
76
|
-
cancelRoute.handler({
|
|
77
|
+
const result = cancelRoute.handler({
|
|
77
78
|
pathParams: { id: conversationKey },
|
|
78
79
|
body: {},
|
|
79
80
|
headers: {},
|
|
80
|
-
|
|
81
81
|
});
|
|
82
82
|
|
|
83
83
|
expect(cancelledId!).toBe(internalId);
|
|
84
|
+
expect(result).toEqual({
|
|
85
|
+
ok: true,
|
|
86
|
+
cancelled: true,
|
|
87
|
+
conversationId: internalId,
|
|
88
|
+
});
|
|
84
89
|
});
|
|
85
90
|
|
|
86
91
|
test("falls back to raw ID when key is not in the mapping", () => {
|
|
87
92
|
cancelledId = undefined;
|
|
88
93
|
const directId = "direct-conversation-id";
|
|
89
94
|
|
|
90
|
-
cancelRoute.handler({
|
|
95
|
+
const result = cancelRoute.handler({
|
|
91
96
|
pathParams: { id: directId },
|
|
92
97
|
body: {},
|
|
93
98
|
headers: {},
|
|
99
|
+
});
|
|
94
100
|
|
|
101
|
+
expect(cancelledId!).toBe(directId);
|
|
102
|
+
expect(result).toEqual({
|
|
103
|
+
ok: true,
|
|
104
|
+
cancelled: true,
|
|
105
|
+
conversationId: directId,
|
|
95
106
|
});
|
|
107
|
+
});
|
|
96
108
|
|
|
109
|
+
test("HTTP adapter returns a serializable 202 response", async () => {
|
|
110
|
+
cancelledId = undefined;
|
|
111
|
+
const directId = "direct-http-conversation-id";
|
|
112
|
+
const [httpRoute] = routeDefinitionsToHTTPRoutes([cancelRoute]);
|
|
113
|
+
const url = new URL(`http://localhost/v1/conversations/${directId}/cancel`);
|
|
114
|
+
|
|
115
|
+
const response = await httpRoute.handler({
|
|
116
|
+
req: new Request(url, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: { "content-type": "application/json" },
|
|
119
|
+
body: "{}",
|
|
120
|
+
}),
|
|
121
|
+
url,
|
|
122
|
+
params: { id: directId },
|
|
123
|
+
authContext: {} as never,
|
|
124
|
+
server: {} as never,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(response.status).toBe(202);
|
|
128
|
+
expect(await response.json()).toEqual({
|
|
129
|
+
ok: true,
|
|
130
|
+
cancelled: true,
|
|
131
|
+
conversationId: directId,
|
|
132
|
+
});
|
|
97
133
|
expect(cancelledId!).toBe(directId);
|
|
98
134
|
});
|
|
135
|
+
|
|
136
|
+
test("route definition advertises the cancellation response body", () => {
|
|
137
|
+
expect(cancelRoute.responseStatus).toBe("202");
|
|
138
|
+
expect(cancelRoute.responseBody).toBeDefined();
|
|
139
|
+
});
|
|
99
140
|
});
|
|
@@ -71,6 +71,7 @@ describe("channel policy registry", () => {
|
|
|
71
71
|
"start_new_conversation",
|
|
72
72
|
"continue_existing_conversation",
|
|
73
73
|
"not_deliverable",
|
|
74
|
+
"push_only",
|
|
74
75
|
]);
|
|
75
76
|
|
|
76
77
|
for (const channelId of CHANNEL_IDS) {
|
|
@@ -101,6 +102,7 @@ describe("channel policy registry", () => {
|
|
|
101
102
|
["telegram", "continue_existing_conversation"],
|
|
102
103
|
["slack", "continue_existing_conversation"],
|
|
103
104
|
["phone", "not_deliverable"],
|
|
105
|
+
["platform", "push_only"],
|
|
104
106
|
];
|
|
105
107
|
|
|
106
108
|
for (const [channelId, expected] of expectedStrategies) {
|
|
@@ -113,6 +115,7 @@ describe("channel policy registry", () => {
|
|
|
113
115
|
"start_new_conversation",
|
|
114
116
|
"continue_existing_conversation",
|
|
115
117
|
"not_deliverable",
|
|
118
|
+
"push_only",
|
|
116
119
|
]);
|
|
117
120
|
|
|
118
121
|
for (const channelId of CHANNEL_IDS) {
|
|
@@ -148,4 +151,13 @@ describe("channel policy registry", () => {
|
|
|
148
151
|
}
|
|
149
152
|
}
|
|
150
153
|
});
|
|
154
|
+
|
|
155
|
+
test("channels with push_only strategy have deliveryEnabled: true", () => {
|
|
156
|
+
for (const channelId of CHANNEL_IDS) {
|
|
157
|
+
const policy = getChannelPolicy(channelId);
|
|
158
|
+
if (policy.notification.conversationStrategy === "push_only") {
|
|
159
|
+
expect(policy.notification.deliveryEnabled).toBe(true);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
151
163
|
});
|
|
@@ -1597,6 +1597,95 @@ describe("bash network_mode=proxied — risk capped at medium", () => {
|
|
|
1597
1597
|
});
|
|
1598
1598
|
});
|
|
1599
1599
|
|
|
1600
|
+
describe("credentialed proxied bash — high risk escalation", () => {
|
|
1601
|
+
beforeEach(() => {
|
|
1602
|
+
mockRisk("low");
|
|
1603
|
+
mockIpcResponse("get_global_thresholds", DEFAULT_GATEWAY_THRESHOLDS);
|
|
1604
|
+
_clearGlobalCacheForTesting();
|
|
1605
|
+
clearRiskCache();
|
|
1606
|
+
testConfig.skills = { load: { extraDirs: [] } };
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
test("proxied bash with credential_ids sends credentialRefCount in IPC params", async () => {
|
|
1610
|
+
mockRisk("high", {
|
|
1611
|
+
reason:
|
|
1612
|
+
"Proxied credential session — shell has access to injected credentials",
|
|
1613
|
+
});
|
|
1614
|
+
const result = await check(
|
|
1615
|
+
"bash",
|
|
1616
|
+
{
|
|
1617
|
+
command: "curl https://api.example.com",
|
|
1618
|
+
network_mode: "proxied",
|
|
1619
|
+
credential_ids: ["cred-abc-123"],
|
|
1620
|
+
},
|
|
1621
|
+
"/tmp",
|
|
1622
|
+
);
|
|
1623
|
+
expect(result.decision).toBe("prompt");
|
|
1624
|
+
expect(result.reason).toContain("credential");
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
test("proxied bash with multiple credential_ids prompts with high risk", async () => {
|
|
1628
|
+
mockRisk("high", {
|
|
1629
|
+
reason:
|
|
1630
|
+
"Proxied credential session — shell has access to injected credentials",
|
|
1631
|
+
});
|
|
1632
|
+
const result = await check(
|
|
1633
|
+
"bash",
|
|
1634
|
+
{
|
|
1635
|
+
command: "ls",
|
|
1636
|
+
network_mode: "proxied",
|
|
1637
|
+
credential_ids: ["cred-1", "cred-2"],
|
|
1638
|
+
},
|
|
1639
|
+
"/tmp",
|
|
1640
|
+
);
|
|
1641
|
+
expect(result.decision).toBe("prompt");
|
|
1642
|
+
});
|
|
1643
|
+
|
|
1644
|
+
test("proxied bash with empty credential_ids array does not escalate risk", async () => {
|
|
1645
|
+
mockRisk("low");
|
|
1646
|
+
const result = await check(
|
|
1647
|
+
"bash",
|
|
1648
|
+
{
|
|
1649
|
+
command: "ls",
|
|
1650
|
+
network_mode: "proxied",
|
|
1651
|
+
credential_ids: [],
|
|
1652
|
+
},
|
|
1653
|
+
"/tmp",
|
|
1654
|
+
);
|
|
1655
|
+
// Empty array means no credential refs — follows normal proxied behavior
|
|
1656
|
+
expect(result.decision).toBe("allow");
|
|
1657
|
+
});
|
|
1658
|
+
|
|
1659
|
+
test("proxied bash with credential_ids containing empty strings does not escalate", async () => {
|
|
1660
|
+
mockRisk("low");
|
|
1661
|
+
const result = await check(
|
|
1662
|
+
"bash",
|
|
1663
|
+
{
|
|
1664
|
+
command: "ls",
|
|
1665
|
+
network_mode: "proxied",
|
|
1666
|
+
credential_ids: ["", ""],
|
|
1667
|
+
},
|
|
1668
|
+
"/tmp",
|
|
1669
|
+
);
|
|
1670
|
+
// Empty strings are filtered out, so no credential refs
|
|
1671
|
+
expect(result.decision).toBe("allow");
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1674
|
+
test("non-proxied bash with credential_ids follows normal flow", async () => {
|
|
1675
|
+
mockRisk("low");
|
|
1676
|
+
const result = await check(
|
|
1677
|
+
"bash",
|
|
1678
|
+
{
|
|
1679
|
+
command: "ls",
|
|
1680
|
+
credential_ids: ["cred-abc-123"],
|
|
1681
|
+
},
|
|
1682
|
+
"/tmp",
|
|
1683
|
+
);
|
|
1684
|
+
// Without proxied mode, credential refs don't affect IPC classification
|
|
1685
|
+
expect(result.decision).toBe("allow");
|
|
1686
|
+
});
|
|
1687
|
+
});
|
|
1688
|
+
|
|
1600
1689
|
describe("workspace mode — auto-allow workspace-scoped operations", () => {
|
|
1601
1690
|
const workspaceDir = "/home/user/my-project";
|
|
1602
1691
|
|
|
@@ -61,14 +61,15 @@ const { RouteError } = await import("../runtime/routes/errors.js");
|
|
|
61
61
|
// Helpers
|
|
62
62
|
// ---------------------------------------------------------------------------
|
|
63
63
|
|
|
64
|
-
function
|
|
64
|
+
function buildProgram(): Command {
|
|
65
65
|
const program = new Command();
|
|
66
66
|
program.exitOverride();
|
|
67
67
|
program.configureOutput({
|
|
68
68
|
writeErr: () => {},
|
|
69
69
|
writeOut: () => {},
|
|
70
70
|
});
|
|
71
|
-
|
|
71
|
+
// The registrar creates the `memory` parent itself, so callers don't
|
|
72
|
+
// need to stub one.
|
|
72
73
|
registerMemoryV2Command(program);
|
|
73
74
|
return program;
|
|
74
75
|
}
|
|
@@ -82,7 +83,7 @@ async function runCommand(args: string[]): Promise<{ exitCode: number }> {
|
|
|
82
83
|
|
|
83
84
|
process.exitCode = 0;
|
|
84
85
|
try {
|
|
85
|
-
const program =
|
|
86
|
+
const program = buildProgram();
|
|
86
87
|
await program.parseAsync(["node", "assistant", ...args]);
|
|
87
88
|
} catch {
|
|
88
89
|
if (process.exitCode === 0) process.exitCode = 1;
|
|
@@ -198,15 +199,15 @@ describe("all memory v2 routes — MEMORY_V2_DISABLED gate", () => {
|
|
|
198
199
|
// schema validation so any body would surface the gate error, but using
|
|
199
200
|
// valid shapes keeps the assertion precise: we're confirming the gate
|
|
200
201
|
// (not zod) is what blocks the call.
|
|
202
|
+
//
|
|
203
|
+
// NOTE: `memory_v2_validate` is intentionally absent — validate is a
|
|
204
|
+
// read-only diagnostic walk that must be runnable before the flag is
|
|
205
|
+
// flipped (see the dedicated coverage further down).
|
|
201
206
|
const MINIMAL_BODIES: Record<string, Record<string, unknown>> = {
|
|
202
207
|
memory_v2_backfill: { op: "migrate" },
|
|
203
|
-
memory_v2_validate: {},
|
|
204
208
|
memory_v2_get_concept_page: { slug: "any" },
|
|
205
209
|
memory_v2_list_concept_pages: {},
|
|
206
|
-
memory_v2_rebuild_corpus_stats: {},
|
|
207
|
-
memory_v2_explain_similarity: { userText: "hello" },
|
|
208
210
|
memory_v2_concept_frequency: {},
|
|
209
|
-
memory_v2_fit_anisotropy: {},
|
|
210
211
|
};
|
|
211
212
|
|
|
212
213
|
const GATE_OFF_CASES = [
|
|
@@ -235,4 +236,31 @@ describe("all memory v2 routes — MEMORY_V2_DISABLED gate", () => {
|
|
|
235
236
|
});
|
|
236
237
|
}
|
|
237
238
|
}
|
|
239
|
+
|
|
240
|
+
// memory_v2_validate is the one read-only diagnostic that must work
|
|
241
|
+
// before the operator flips memory.v2.enabled — the
|
|
242
|
+
// vellum-memory-v2-migration skill's pre-flip dry-run depends on it.
|
|
243
|
+
test("memory_v2_validate runs when memory.v2.enabled is false", async () => {
|
|
244
|
+
writeWorkspaceConfig({ memory: { v2: { enabled: false } } });
|
|
245
|
+
const route = memoryV2Routes.find(
|
|
246
|
+
(r) => r.operationId === "memory_v2_validate",
|
|
247
|
+
);
|
|
248
|
+
expect(route).toBeDefined();
|
|
249
|
+
|
|
250
|
+
const result = (await route!.handler({ body: {} })) as {
|
|
251
|
+
pageCount: number;
|
|
252
|
+
edgeCount: number;
|
|
253
|
+
missingEdgeEndpoints: unknown[];
|
|
254
|
+
oversizedPages: unknown[];
|
|
255
|
+
parseFailures: unknown[];
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// Empty workspace → zero-violation report. The point is that the call
|
|
259
|
+
// returned at all (no MEMORY_V2_DISABLED throw).
|
|
260
|
+
expect(result.pageCount).toBe(0);
|
|
261
|
+
expect(result.edgeCount).toBe(0);
|
|
262
|
+
expect(result.missingEdgeEndpoints).toEqual([]);
|
|
263
|
+
expect(result.oversizedPages).toEqual([]);
|
|
264
|
+
expect(result.parseFailures).toEqual([]);
|
|
265
|
+
});
|
|
238
266
|
});
|