@vellumai/assistant 0.12.2 → 0.12.3-staging.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/.env.example +2 -0
- package/AGENTS.md +1 -1
- package/docs/architecture/integrations.md +7 -0
- package/docs/architecture/memory.md +17 -2
- package/docs/credential-execution-service.md +1 -1
- package/docs/desktop-browser-cli.md +7 -3
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
- package/node_modules/@vellumai/environments/src/shell.ts +24 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
- package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/openapi.yaml +54 -5
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +1 -0
- package/scripts/sync-llm-catalog.ts +3 -0
- package/scripts/voice-ttft-spike.ts +2 -2
- package/src/__tests__/agent-loop.test.ts +259 -0
- package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
- package/src/__tests__/anthropic-provider.test.ts +55 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
- package/src/__tests__/attachments-store.test.ts +22 -3
- package/src/__tests__/channel-approval.test.ts +9 -14
- package/src/__tests__/channel-reply-delivery.test.ts +56 -0
- package/src/__tests__/chat-credential-redaction.test.ts +23 -0
- package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
- package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +257 -6
- package/src/__tests__/conversation-attachments.test.ts +106 -0
- package/src/__tests__/conversation-fork-crud.test.ts +191 -0
- package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
- package/src/__tests__/credential-execution-client.test.ts +70 -53
- package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
- package/src/__tests__/events-tail-route.test.ts +33 -0
- package/src/__tests__/history-repair.test.ts +53 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
- package/src/__tests__/llm-catalog-parity.test.ts +27 -4
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-commands-routes.test.ts +114 -101
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/persist-media-references.test.ts +50 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
- package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
- package/src/__tests__/schedule-routes.test.ts +20 -0
- package/src/__tests__/scheduler-result-notification.test.ts +23 -4
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
- package/src/__tests__/secret-routes-scrub.test.ts +22 -27
- package/src/__tests__/secret-scanner.test.ts +20 -0
- package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
- package/src/__tests__/secure-keys.test.ts +7 -3
- package/src/__tests__/server-tool-pairing.test.ts +107 -0
- package/src/__tests__/skills.test.ts +5 -4
- package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/tool-result-follow-up.test.ts +99 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +63 -0
- package/src/__tests__/unicode.test.ts +36 -0
- package/src/agent/loop.ts +37 -12
- package/src/agent/tool-result-follow-up.ts +70 -0
- package/src/api/attachment-provenance.test.ts +68 -0
- package/src/api/computer-use-tool.test.ts +55 -0
- package/src/api/computer-use-tool.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +3 -0
- package/src/api/events/desktop-activity-changed.ts +10 -0
- package/src/api/events/question-request.ts +1 -0
- package/src/api/index.ts +11 -0
- package/src/api/responses/conversation-message.ts +3 -0
- package/src/approvals/approval-primitive.ts +5 -2
- package/src/approvals/scoped-approval-grants.ts +6 -2
- package/src/browser/virtual-desktop-target.ts +1 -2
- package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
- package/src/cli/commands/__tests__/plugins.test.ts +20 -1
- package/src/cli/commands/__tests__/schedules.test.ts +14 -0
- package/src/cli/commands/bash.help.ts +4 -3
- package/src/cli/commands/browser.help.ts +5 -1
- package/src/cli/commands/credentials.help.ts +3 -3
- package/src/cli/commands/oauth/index.help.ts +10 -0
- package/src/cli/commands/oauth/providers.ts +12 -0
- package/src/cli/commands/oauth/request.test.ts +179 -2
- package/src/cli/commands/oauth/request.ts +41 -10
- package/src/cli/commands/plugins.ts +12 -5
- package/src/cli/commands/schedules.ts +2 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
- package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
- package/src/cli/lib/bundled-marketplace.json +855 -0
- package/src/cli/lib/bundled-plugin-packages.json +783 -1
- package/src/cli/lib/inspect-plugin.ts +11 -4
- package/src/cli/lib/upgrade-plugin.ts +19 -11
- package/src/cli/output.ts +18 -4
- package/src/config/__tests__/default-provider.test.ts +4 -0
- package/src/config/bundled-skills/schedule/SKILL.md +6 -6
- package/src/config/loader.ts +9 -17
- package/src/config/platform-identity.ts +8 -8
- package/src/config/profile-text-generation.test.ts +51 -0
- package/src/config/profile-text-generation.ts +51 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
- package/src/config/schemas/llm.ts +7 -2
- package/src/config/schemas/mcp.ts +5 -1
- package/src/config/schemas/memory-v3.ts +12 -0
- package/src/credential-execution/ces-runtime.ts +2 -2
- package/src/credential-execution/executable-discovery.ts +36 -134
- package/src/credential-execution/process-manager.test.ts +20 -24
- package/src/credential-execution/process-manager.ts +24 -19
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
- package/src/daemon/assistant-attachments.ts +20 -12
- package/src/daemon/chat-credential-redaction.ts +16 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +74 -3
- package/src/daemon/conversation-agent-loop.ts +12 -0
- package/src/daemon/conversation-attachments.ts +93 -12
- package/src/daemon/conversation-tool-setup.ts +71 -3
- package/src/daemon/conversation-turn-finalize.ts +26 -13
- package/src/daemon/conversation.ts +72 -17
- package/src/daemon/daemon-control.ts +3 -7
- package/src/daemon/lifecycle.ts +4 -4
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/message-types/shared.ts +1 -0
- package/src/daemon/orphan-reaper.ts +4 -3
- package/src/daemon/persist-media-references.ts +20 -3
- package/src/daemon/tool-setup-types.ts +6 -0
- package/src/daemon/wake-conversation-ops.ts +50 -15
- package/src/desktop/desktop-automation-lease.test.ts +230 -0
- package/src/desktop/desktop-automation-lease.ts +90 -6
- package/src/desktop/desktop-help.ts +15 -0
- package/src/desktop/desktop-stream-bridge.test.ts +65 -10
- package/src/desktop/desktop-stream-bridge.ts +3 -3
- package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
- package/src/desktop/desktop-wallpaper-worker.ts +17 -0
- package/src/desktop/desktop-wallpaper.test.ts +48 -7
- package/src/desktop/desktop-wallpaper.ts +34 -102
- package/src/desktop/virtual-desktop-feature.ts +1 -1
- package/src/mcp/__tests__/manager-tool-caps.test.ts +111 -0
- package/src/mcp/__tests__/startup.test.ts +30 -7
- package/src/mcp/__tests__/tool-caps.test.ts +107 -0
- package/src/mcp/manager.ts +168 -101
- package/src/mcp/startup.ts +33 -13
- package/src/mcp/tool-caps.ts +176 -0
- package/src/messaging/provider-message-metadata.ts +3 -3
- package/src/notifications/__tests__/copy-composer.test.ts +70 -0
- package/src/notifications/copy-composer.ts +11 -3
- package/src/notifications/schedule-result-producer.ts +4 -6
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
- package/src/oauth/identity-verifier.ts +24 -0
- package/src/oauth/oauth-store.ts +11 -1
- package/src/oauth/provider-serializer.ts +1 -0
- package/src/oauth/seed-providers.ts +12 -0
- package/src/permissions/confirmation-guardian-request.test.ts +16 -0
- package/src/permissions/confirmation-guardian-request.ts +2 -3
- package/src/permissions/question-prompter.test.ts +31 -0
- package/src/permissions/question-prompter.ts +2 -0
- package/src/persistence/attachments-store.ts +84 -44
- package/src/persistence/conversation-crud.ts +111 -20
- package/src/persistence/conversation-plugin-facade.ts +30 -0
- package/src/persistence/conversation-tool-surface.ts +135 -0
- package/src/persistence/conversation-types.test.ts +32 -0
- package/src/persistence/conversation-types.ts +26 -4
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
- package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
- package/src/persistence/schema/index.ts +1 -0
- package/src/persistence/schema/oauth.ts +1 -0
- package/src/persistence/steps.ts +24 -3
- package/src/plugin-api/conversation-turn.ts +31 -7
- package/src/plugin-api/index.ts +11 -1
- package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
- package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
- package/src/plugins/defaults/memory/AGENTS.md +39 -5
- package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
- package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
- package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
- package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
- package/src/plugins/defaults/memory/buffer-file.ts +354 -0
- package/src/plugins/defaults/memory/buffer-format.ts +40 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -2
- package/src/plugins/defaults/memory/context-search/format.ts +2 -1
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
- package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
- package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -42
- package/src/plugins/defaults/memory/host-utils.ts +0 -10
- package/src/plugins/defaults/memory/injectors.ts +4 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
- package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +1 -1
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
- package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +89 -49
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
- package/src/plugins/defaults/memory/tools.ts +1 -1
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
- package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
- package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +183 -4
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +103 -2
- package/src/plugins/defaults/memory/v3/card.ts +2 -1
- package/src/plugins/defaults/memory/v3/injector.ts +212 -178
- package/src/plugins/defaults/memory/v3/orchestrate.ts +112 -25
- package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +253 -1
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +35 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +31 -19
- package/src/plugins/defaults/memory/v3/sections.ts +2 -1
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
- package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
- package/src/prompts/delegation-gate.ts +57 -0
- package/src/prompts/system-prompt.ts +14 -32
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/jev/client.test.ts +260 -0
- package/src/providers/jev/client.ts +518 -0
- package/src/providers/model-catalog.ts +58 -3
- package/src/providers/server-tool-pairing.ts +16 -7
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +94 -1
- package/src/runtime/agent-wake.ts +31 -4
- package/src/runtime/guardian-action-service.ts +2 -17
- package/src/runtime/guardian-reply-router.ts +1 -8
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
- package/src/runtime/migrations/vbundle-import-policy.ts +33 -11
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
- package/src/runtime/routes/channel-route-shared.ts +1 -9
- package/src/runtime/routes/conversation-routes.ts +29 -4
- package/src/runtime/routes/desktop-setup-routes.test.ts +2 -2
- package/src/runtime/routes/desktop-setup-routes.ts +8 -5
- package/src/runtime/routes/guardian-approval-interception.ts +24 -0
- package/src/runtime/routes/inbound-message-handler.ts +2 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +1 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +7 -4
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
- package/src/runtime/routes/inference-profiles-routes.ts +9 -0
- package/src/runtime/routes/oauth-commands-routes.ts +57 -54
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
- package/src/runtime/routes/oauth-request-hints.ts +149 -0
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/secret-routes.ts +99 -119
- package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
- package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
- package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
- package/src/schedule/run-script.ts +2 -2
- package/src/schedule/scheduler.ts +47 -11
- package/src/schedule/tool-surface-readiness.ts +65 -0
- package/src/schedule/worker-mcp.ts +85 -0
- package/src/schedule/worker.ts +9 -31
- package/src/security/secure-keys.ts +60 -48
- package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
- package/src/tools/ask-question/ask-question-tool.ts +119 -23
- package/src/tools/browser/browser-execution.ts +7 -1
- package/src/tools/host-terminal/host-shell.ts +12 -6
- package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
- package/src/tools/shared/shell-output.test.ts +10 -0
- package/src/tools/shared/shell-output.ts +14 -2
- package/src/tools/skills/sandbox-runner.ts +13 -2
- package/src/tools/skills/scaffold-managed.ts +2 -1
- package/src/tools/terminal/__tests__/safe-env.test.ts +33 -4
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
- package/src/tools/terminal/safe-env.ts +35 -24
- package/src/tools/terminal/sanitized-bash.ts +15 -2
- package/src/tools/terminal/shell-launch.test.ts +162 -0
- package/src/tools/terminal/shell.test.ts +29 -0
- package/src/tools/terminal/shell.ts +13 -7
- package/src/util/browser-human-verification.ts +14 -0
- package/src/util/host-process.test.ts +17 -1
- package/src/util/host-process.ts +24 -0
- package/src/util/unicode.ts +29 -0
|
@@ -28,6 +28,9 @@ const MANAGED_PROVIDERS = [
|
|
|
28
28
|
] as const;
|
|
29
29
|
|
|
30
30
|
let platformBaseUrlOverride: string | undefined;
|
|
31
|
+
let platformAssistantIdOverride: string | undefined;
|
|
32
|
+
let platformOrganizationIdOverride: string | undefined;
|
|
33
|
+
let platformUserIdOverride: string | undefined;
|
|
31
34
|
|
|
32
35
|
mock.module("@google/genai", () => ({
|
|
33
36
|
GoogleGenAI: class MockGoogleGenAI {
|
|
@@ -54,9 +57,19 @@ mock.module("@google/genai", () => ({
|
|
|
54
57
|
|
|
55
58
|
mock.module("../config/env.js", () => ({
|
|
56
59
|
getPlatformBaseUrl: () => PLATFORM_BASE_URL,
|
|
60
|
+
getPlatformAssistantId: () => platformAssistantIdOverride,
|
|
57
61
|
setPlatformBaseUrl: (value: string | undefined) => {
|
|
58
62
|
platformBaseUrlOverride = value;
|
|
59
63
|
},
|
|
64
|
+
setPlatformAssistantId: (value: string | undefined) => {
|
|
65
|
+
platformAssistantIdOverride = value;
|
|
66
|
+
},
|
|
67
|
+
setPlatformOrganizationId: (value: string | undefined) => {
|
|
68
|
+
platformOrganizationIdOverride = value;
|
|
69
|
+
},
|
|
70
|
+
setPlatformUserId: (value: string | undefined) => {
|
|
71
|
+
platformUserIdOverride = value;
|
|
72
|
+
},
|
|
60
73
|
}));
|
|
61
74
|
|
|
62
75
|
mock.module("../providers/provider-secret-catalog.js", () => ({
|
|
@@ -182,6 +195,9 @@ describe("secret routes managed proxy registry sync", () => {
|
|
|
182
195
|
metadataDeletes.length = 0;
|
|
183
196
|
lastGeminiConstructorOpts = null;
|
|
184
197
|
platformBaseUrlOverride = undefined;
|
|
198
|
+
platformAssistantIdOverride = undefined;
|
|
199
|
+
platformOrganizationIdOverride = undefined;
|
|
200
|
+
platformUserIdOverride = undefined;
|
|
185
201
|
providerRefreshCalls = 0;
|
|
186
202
|
identitySyncCalls = 0;
|
|
187
203
|
avatarSyncCalls = 0;
|
|
@@ -254,32 +270,38 @@ describe("secret routes managed proxy registry sync", () => {
|
|
|
254
270
|
expect(providerRefreshCalls).toBe(2);
|
|
255
271
|
});
|
|
256
272
|
|
|
257
|
-
test("deleting vellum
|
|
273
|
+
test("deleting a vellum credential is rejected without touching the vault", async () => {
|
|
258
274
|
secureKeyStore[ASSISTANT_API_KEY_PATH] = "ast-managed-key";
|
|
275
|
+
secureKeyStore[PLATFORM_BASE_URL_PATH] = "https://managed.example.com";
|
|
276
|
+
platformBaseUrlOverride = "https://managed.example.com";
|
|
277
|
+
platformAssistantIdOverride = "asst-1";
|
|
259
278
|
await initializeProviders(getConfig());
|
|
260
279
|
|
|
261
|
-
for (const
|
|
262
|
-
|
|
263
|
-
|
|
280
|
+
for (const name of [
|
|
281
|
+
"vellum:assistant_api_key",
|
|
282
|
+
"vellum:platform_base_url",
|
|
283
|
+
"vellum:webhook_secret",
|
|
284
|
+
"vellum:platform_assistant_id",
|
|
285
|
+
]) {
|
|
286
|
+
await expect(deleteCredential(name)).rejects.toThrow(
|
|
287
|
+
"Vellum credentials cannot be deleted",
|
|
288
|
+
);
|
|
264
289
|
}
|
|
265
290
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
expect(
|
|
291
|
+
expect(secureKeyStore[ASSISTANT_API_KEY_PATH]).toBe("ast-managed-key");
|
|
292
|
+
expect(secureKeyStore[PLATFORM_BASE_URL_PATH]).toBe(
|
|
293
|
+
"https://managed.example.com",
|
|
294
|
+
);
|
|
295
|
+
expect(platformBaseUrlOverride).toBe("https://managed.example.com");
|
|
296
|
+
expect(platformAssistantIdOverride).toBe("asst-1");
|
|
297
|
+
expect(metadataDeletes).toEqual([]);
|
|
298
|
+
expect(providerRefreshCalls).toBe(0);
|
|
273
299
|
});
|
|
274
300
|
|
|
275
301
|
test("managed proxy credential writes notify live-conversation refresh listeners", async () => {
|
|
276
302
|
await addCredential("vellum:assistant_api_key", "ast-managed-key");
|
|
277
303
|
|
|
278
304
|
expect(providerRefreshCalls).toBe(1);
|
|
279
|
-
|
|
280
|
-
await deleteCredential("vellum:assistant_api_key");
|
|
281
|
-
|
|
282
|
-
expect(providerRefreshCalls).toBe(2);
|
|
283
305
|
});
|
|
284
306
|
|
|
285
307
|
/**
|
|
@@ -326,7 +348,6 @@ describe("secret routes managed proxy registry sync", () => {
|
|
|
326
348
|
test("storing a platform registration credential enqueues name and avatar syncs", async () => {
|
|
327
349
|
for (const name of [
|
|
328
350
|
"vellum:assistant_api_key",
|
|
329
|
-
"vellum:platform_assistant_id",
|
|
330
351
|
"vellum:platform_base_url",
|
|
331
352
|
]) {
|
|
332
353
|
identitySyncCalls = 0;
|
|
@@ -339,7 +360,6 @@ describe("secret routes managed proxy registry sync", () => {
|
|
|
339
360
|
|
|
340
361
|
test("unrelated credentials do not enqueue platform syncs", async () => {
|
|
341
362
|
await addCredential("openrouter:api_key", "openrouter-key");
|
|
342
|
-
await addCredential("vellum:platform_user_id", "user-1");
|
|
343
363
|
|
|
344
364
|
expect(identitySyncCalls).toBe(0);
|
|
345
365
|
expect(avatarSyncCalls).toBe(0);
|
|
@@ -349,13 +369,61 @@ describe("secret routes managed proxy registry sync", () => {
|
|
|
349
369
|
failSecureKeyWrites = true;
|
|
350
370
|
|
|
351
371
|
await expect(
|
|
352
|
-
addCredential("vellum:
|
|
372
|
+
addCredential("vellum:platform_base_url", "https://managed.example.com"),
|
|
353
373
|
).rejects.toThrow("Failed to store credential");
|
|
354
374
|
|
|
355
375
|
expect(identitySyncCalls).toBe(0);
|
|
356
376
|
expect(avatarSyncCalls).toBe(0);
|
|
357
377
|
});
|
|
358
378
|
|
|
379
|
+
test("unknown vellum credentials are rejected without persisting or binding identity", async () => {
|
|
380
|
+
platformAssistantIdOverride = "existing-asst";
|
|
381
|
+
platformOrganizationIdOverride = "existing-org";
|
|
382
|
+
platformUserIdOverride = "existing-user";
|
|
383
|
+
|
|
384
|
+
await expect(
|
|
385
|
+
addCredential("vellum:platform_assistant_id", "asst-1"),
|
|
386
|
+
).rejects.toThrow("Unknown vellum credential: platform_assistant_id");
|
|
387
|
+
await expect(
|
|
388
|
+
addCredential("vellum:platform_organization_id", "org-1"),
|
|
389
|
+
).rejects.toThrow("Unknown vellum credential: platform_organization_id");
|
|
390
|
+
await expect(
|
|
391
|
+
addCredential("vellum:platform_user_id", "user-1"),
|
|
392
|
+
).rejects.toThrow("Unknown vellum credential: platform_user_id");
|
|
393
|
+
|
|
394
|
+
expect(
|
|
395
|
+
secureKeyStore[credentialKey("vellum", "platform_assistant_id")],
|
|
396
|
+
).toBeUndefined();
|
|
397
|
+
expect(
|
|
398
|
+
secureKeyStore[credentialKey("vellum", "platform_organization_id")],
|
|
399
|
+
).toBeUndefined();
|
|
400
|
+
expect(
|
|
401
|
+
secureKeyStore[credentialKey("vellum", "platform_user_id")],
|
|
402
|
+
).toBeUndefined();
|
|
403
|
+
expect(metadataUpserts).toEqual([]);
|
|
404
|
+
expect(platformAssistantIdOverride).toBe("existing-asst");
|
|
405
|
+
expect(platformOrganizationIdOverride).toBe("existing-org");
|
|
406
|
+
expect(platformUserIdOverride).toBe("existing-user");
|
|
407
|
+
expect(identitySyncCalls).toBe(0);
|
|
408
|
+
expect(avatarSyncCalls).toBe(0);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
test("an unknown vellum credential does not delete leftover vault copies", async () => {
|
|
412
|
+
const key = credentialKey("vellum", "platform_assistant_id");
|
|
413
|
+
secureKeyStore[key] = "leftover-asst";
|
|
414
|
+
platformAssistantIdOverride = "asst-1";
|
|
415
|
+
|
|
416
|
+
await expect(
|
|
417
|
+
addCredential("vellum:platform_assistant_id", " "),
|
|
418
|
+
).rejects.toThrow("Unknown vellum credential: platform_assistant_id");
|
|
419
|
+
|
|
420
|
+
expect(secureKeyStore[key]).toBe("leftover-asst");
|
|
421
|
+
expect(platformAssistantIdOverride).toBe("asst-1");
|
|
422
|
+
expect(metadataDeletes).toEqual([]);
|
|
423
|
+
expect(identitySyncCalls).toBe(0);
|
|
424
|
+
expect(avatarSyncCalls).toBe(0);
|
|
425
|
+
});
|
|
426
|
+
|
|
359
427
|
test("storing vellum:platform_base_url sets override and triggers initializeProviders", async () => {
|
|
360
428
|
await addCredential(
|
|
361
429
|
"vellum:platform_base_url",
|
|
@@ -389,17 +457,4 @@ describe("secret routes managed proxy registry sync", () => {
|
|
|
389
457
|
expect(getProviderRoutingSource(provider)).toBe("managed-proxy");
|
|
390
458
|
}
|
|
391
459
|
});
|
|
392
|
-
|
|
393
|
-
test("deleting vellum:platform_base_url clears override and re-initializes providers", async () => {
|
|
394
|
-
secureKeyStore[PLATFORM_BASE_URL_PATH] = "https://managed.example.com";
|
|
395
|
-
platformBaseUrlOverride = "https://managed.example.com";
|
|
396
|
-
|
|
397
|
-
await deleteCredential("vellum:platform_base_url");
|
|
398
|
-
|
|
399
|
-
expect(secureKeyStore[PLATFORM_BASE_URL_PATH]).toBeUndefined();
|
|
400
|
-
expect(platformBaseUrlOverride).toBeUndefined();
|
|
401
|
-
expect(metadataDeletes).toEqual([
|
|
402
|
-
{ service: "vellum", field: "platform_base_url" },
|
|
403
|
-
]);
|
|
404
|
-
});
|
|
405
460
|
});
|
|
@@ -222,39 +222,34 @@ describe("secrets_add credential transcript scrub", () => {
|
|
|
222
222
|
expect(scrubbedValues).toEqual([CREDENTIAL_VALUE]);
|
|
223
223
|
});
|
|
224
224
|
|
|
225
|
-
test("non-secret platform fields are
|
|
226
|
-
for (const field of [
|
|
227
|
-
"platform_assistant_id",
|
|
228
|
-
"platform_organization_id",
|
|
229
|
-
"platform_user_id",
|
|
230
|
-
"platform_base_url",
|
|
231
|
-
]) {
|
|
232
|
-
const result = await addRoute.handler({
|
|
233
|
-
body: {
|
|
234
|
-
type: "credential",
|
|
235
|
-
name: `vellum:${field}`,
|
|
236
|
-
value: "0198f4c2-1111-2222-3333-444455556666",
|
|
237
|
-
},
|
|
238
|
-
});
|
|
239
|
-
expect(result).toEqual(expect.objectContaining({ success: true }));
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// All four stored, none scrubbed — they are benign UUIDs/URLs that
|
|
243
|
-
// legitimately appear in transcripts.
|
|
244
|
-
expect(secureStore.size).toBe(4);
|
|
245
|
-
expect(scrubbedValues).toEqual([]);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
test("an identity-field delete stores nothing and never scrubs", async () => {
|
|
225
|
+
test("non-secret platform fields are not scrubbed", async () => {
|
|
249
226
|
const result = await addRoute.handler({
|
|
250
227
|
body: {
|
|
251
228
|
type: "credential",
|
|
252
|
-
name: "vellum:
|
|
253
|
-
value: "
|
|
229
|
+
name: "vellum:platform_base_url",
|
|
230
|
+
value: "0198f4c2-1111-2222-3333-444455556666",
|
|
254
231
|
},
|
|
255
232
|
});
|
|
256
|
-
|
|
257
233
|
expect(result).toEqual(expect.objectContaining({ success: true }));
|
|
234
|
+
|
|
235
|
+
expect(secureStore.size).toBe(1);
|
|
236
|
+
expect(secureStore.get(credentialKey("vellum", "platform_base_url"))).toBe(
|
|
237
|
+
"0198f4c2-1111-2222-3333-444455556666",
|
|
238
|
+
);
|
|
239
|
+
expect(scrubbedValues).toEqual([]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
test("an unknown vellum credential is rejected and never triggers a scrub", async () => {
|
|
243
|
+
await expect(
|
|
244
|
+
addRoute.handler({
|
|
245
|
+
body: {
|
|
246
|
+
type: "credential",
|
|
247
|
+
name: "vellum:platform_assistant_id",
|
|
248
|
+
value: " ",
|
|
249
|
+
},
|
|
250
|
+
}),
|
|
251
|
+
).rejects.toBeInstanceOf(BadRequestError);
|
|
252
|
+
|
|
258
253
|
expect(secureStore.size).toBe(0);
|
|
259
254
|
expect(scrubbedValues).toEqual([]);
|
|
260
255
|
});
|
|
@@ -187,6 +187,26 @@ describe("Anthropic keys", () => {
|
|
|
187
187
|
});
|
|
188
188
|
});
|
|
189
189
|
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// Resend
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
describe("Resend keys", () => {
|
|
194
|
+
const key = `re_${"a".repeat(8)}_${"b".repeat(24)}`;
|
|
195
|
+
|
|
196
|
+
test("detects re_ key", () => {
|
|
197
|
+
expectMatch(key, "Resend API Key");
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("redacts a key echoed from shell output", () => {
|
|
201
|
+
const out = redactSecrets(`$ cat .env\nRESEND=${key}\n`);
|
|
202
|
+
expect(out).not.toContain(key);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("ignores re_ identifiers that are not key-shaped", () => {
|
|
206
|
+
expectNoMatch("re_0_of_1_is_deprecated_6387");
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
190
210
|
// ---------------------------------------------------------------------------
|
|
191
211
|
// OpenAI
|
|
192
212
|
// ---------------------------------------------------------------------------
|
|
@@ -63,4 +63,12 @@ describe("secure-keys managed CES failover", () => {
|
|
|
63
63
|
expect(rpcCall).toHaveBeenCalledTimes(1);
|
|
64
64
|
expect(globalThis.fetch).toHaveBeenCalledTimes(1);
|
|
65
65
|
});
|
|
66
|
+
|
|
67
|
+
test("uses CES HTTP only after lazy IPC finds no socket", async () => {
|
|
68
|
+
const start = Date.now();
|
|
69
|
+
expect(await getSecureKeyAsync("openai")).toBe("http-secret");
|
|
70
|
+
expect(Date.now() - start).toBeLessThan(1_000);
|
|
71
|
+
expect(getActiveBackendName()).toBe("ces-http");
|
|
72
|
+
expect(globalThis.fetch).toHaveBeenCalledTimes(1);
|
|
73
|
+
});
|
|
66
74
|
});
|
|
@@ -61,7 +61,6 @@ describe("secure-keys", () => {
|
|
|
61
61
|
delete process.env.VELLUM_DESKTOP_APP;
|
|
62
62
|
delete process.env.IS_CONTAINERIZED;
|
|
63
63
|
delete process.env.CES_CREDENTIAL_URL;
|
|
64
|
-
delete process.env.CES_LOCAL_SOCKET;
|
|
65
64
|
});
|
|
66
65
|
|
|
67
66
|
afterAll(() => {
|
|
@@ -79,6 +78,13 @@ describe("secure-keys", () => {
|
|
|
79
78
|
expect(await getSecureKeyAsync("openai")).toBe("sk-openai-789");
|
|
80
79
|
});
|
|
81
80
|
|
|
81
|
+
test("does not poll for a CES socket when none is present", async () => {
|
|
82
|
+
const start = Date.now();
|
|
83
|
+
await getSecureKeyAsync("openai");
|
|
84
|
+
expect(Date.now() - start).toBeLessThan(1_000);
|
|
85
|
+
expect(getActiveBackendName()).toBe("encrypted-store");
|
|
86
|
+
});
|
|
87
|
+
|
|
82
88
|
test("get returns undefined for nonexistent key", async () => {
|
|
83
89
|
expect(await getSecureKeyAsync("nonexistent")).toBeUndefined();
|
|
84
90
|
});
|
|
@@ -552,7 +558,6 @@ describe("secure-keys", () => {
|
|
|
552
558
|
test("reads report unreachable (indeterminate), never absent", async () => {
|
|
553
559
|
process.env.IS_CONTAINERIZED = "1";
|
|
554
560
|
delete process.env.CES_CREDENTIAL_URL;
|
|
555
|
-
delete process.env.CES_LOCAL_SOCKET;
|
|
556
561
|
_resetBackend();
|
|
557
562
|
|
|
558
563
|
const result = await getSecureKeyResultAsync("openai");
|
|
@@ -564,7 +569,6 @@ describe("secure-keys", () => {
|
|
|
564
569
|
test("does not pin the unreachable result: a ready CES client wins the next read", async () => {
|
|
565
570
|
process.env.IS_CONTAINERIZED = "1";
|
|
566
571
|
delete process.env.CES_CREDENTIAL_URL;
|
|
567
|
-
delete process.env.CES_LOCAL_SOCKET;
|
|
568
572
|
_resetBackend();
|
|
569
573
|
|
|
570
574
|
expect((await getSecureKeyResultAsync("openai")).unreachable).toBe(true);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { analyzeServerToolPairing } from "../providers/server-tool-pairing.js";
|
|
4
|
+
import type { ContentBlock, Message } from "../providers/types.js";
|
|
5
|
+
|
|
6
|
+
const DEFERRED_ID = "srvtoolu_deferred";
|
|
7
|
+
|
|
8
|
+
const opener: Message = {
|
|
9
|
+
role: "user",
|
|
10
|
+
content: [{ type: "text", text: "Check both" }],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** Assistant turn calling a client tool and a native web search together. */
|
|
14
|
+
const mixedTail: Message = {
|
|
15
|
+
role: "assistant",
|
|
16
|
+
content: [
|
|
17
|
+
{ type: "tool_use", id: "tu_a", name: "web_fetch", input: {} },
|
|
18
|
+
{
|
|
19
|
+
type: "server_tool_use",
|
|
20
|
+
id: DEFERRED_ID,
|
|
21
|
+
name: "web_search",
|
|
22
|
+
input: { query: "news" },
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const clientResult: ContentBlock = {
|
|
28
|
+
type: "tool_result",
|
|
29
|
+
tool_use_id: "tu_a",
|
|
30
|
+
content: "Error: HTTP 404",
|
|
31
|
+
is_error: true,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const guidance: ContentBlock = {
|
|
35
|
+
type: "text",
|
|
36
|
+
text: "<system_notice>retry</system_notice>",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
describe("analyzeServerToolPairing", () => {
|
|
40
|
+
test("an unanswered use with nothing after it is deferred", () => {
|
|
41
|
+
const pairing = analyzeServerToolPairing([opener, mixedTail]);
|
|
42
|
+
|
|
43
|
+
expect(pairing.deferredUseIds).toEqual(new Set([DEFERRED_ID]));
|
|
44
|
+
expect(pairing.resolvedPairIds.size).toBe(0);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("an unanswered use answered by tool_result blocks alone is deferred", () => {
|
|
48
|
+
const pairing = analyzeServerToolPairing([
|
|
49
|
+
opener,
|
|
50
|
+
mixedTail,
|
|
51
|
+
{ role: "user", content: [clientResult] },
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
expect(pairing.deferredUseIds).toEqual(new Set([DEFERRED_ID]));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("guidance text after the tool_result makes the use an orphan, not a deferral", () => {
|
|
58
|
+
// The trailing text closes the assistant turn on the provider side, which
|
|
59
|
+
// then rejects the unanswered use as unpaired; the repair passes stamp a
|
|
60
|
+
// synthetic result instead of preserving it.
|
|
61
|
+
const pairing = analyzeServerToolPairing([
|
|
62
|
+
opener,
|
|
63
|
+
mixedTail,
|
|
64
|
+
{ role: "user", content: [clientResult, guidance] },
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
expect(pairing.deferredUseIds.size).toBe(0);
|
|
68
|
+
expect(pairing.resolvedPairIds.size).toBe(0);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("a user text message after the tool_result message makes the use an orphan", () => {
|
|
72
|
+
const pairing = analyzeServerToolPairing([
|
|
73
|
+
opener,
|
|
74
|
+
mixedTail,
|
|
75
|
+
{ role: "user", content: [clientResult] },
|
|
76
|
+
{ role: "user", content: [{ type: "text", text: "also do this" }] },
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
expect(pairing.deferredUseIds.size).toBe(0);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("a use answered in its own message is resolved and never deferred", () => {
|
|
83
|
+
const pairing = analyzeServerToolPairing([
|
|
84
|
+
opener,
|
|
85
|
+
{
|
|
86
|
+
role: "assistant",
|
|
87
|
+
content: [
|
|
88
|
+
{
|
|
89
|
+
type: "server_tool_use",
|
|
90
|
+
id: "srvtoolu_done",
|
|
91
|
+
name: "web_search",
|
|
92
|
+
input: { query: "news" },
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: "web_search_tool_result",
|
|
96
|
+
tool_use_id: "srvtoolu_done",
|
|
97
|
+
content: [],
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
{ role: "user", content: [guidance] },
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
expect(pairing.resolvedPairIds).toEqual(new Set(["srvtoolu_done"]));
|
|
105
|
+
expect(pairing.deferredUseIds.size).toBe(0);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -1054,14 +1054,15 @@ describe("ingress-dependent setup skills declare public-ingress intentionally",
|
|
|
1054
1054
|
expect(includes ?? []).not.toContain("public-ingress");
|
|
1055
1055
|
});
|
|
1056
1056
|
|
|
1057
|
-
test("telegram-setup documents
|
|
1057
|
+
test("telegram-setup documents which chats are supported and how a group is addressed", () => {
|
|
1058
1058
|
const content = readFileSync(
|
|
1059
1059
|
join(FIRST_PARTY_SKILLS_DIR, "telegram-setup", "SKILL.md"),
|
|
1060
1060
|
"utf-8",
|
|
1061
1061
|
);
|
|
1062
|
-
expect(content).toMatch(/private
|
|
1063
|
-
expect(content).toMatch(
|
|
1064
|
-
expect(content).toMatch(/
|
|
1062
|
+
expect(content).toMatch(/private chats and in groups and supergroups/i);
|
|
1063
|
+
expect(content).toMatch(/@mention of the bot's username/i);
|
|
1064
|
+
expect(content).toMatch(/reply to one of its posts/i);
|
|
1065
|
+
expect(content).toMatch(/Broadcast channels are not supported/i);
|
|
1065
1066
|
});
|
|
1066
1067
|
|
|
1067
1068
|
test("twilio-setup includes public-ingress", () => {
|