@vellumai/assistant 0.4.45 → 0.4.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +6 -6
- package/docs/architecture/memory.md +1 -1
- package/docs/architecture/scheduling.md +2 -3
- package/docs/architecture/security.md +5 -5
- package/docs/trusted-contact-access.md +5 -6
- package/package.json +4 -1
- package/src/__tests__/avatar-e2e.test.ts +18 -219
- package/src/__tests__/avatar-generator.test.ts +5 -57
- package/src/__tests__/browser-fill-credential.test.ts +5 -2
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -1
- package/src/__tests__/channel-readiness-routes.test.ts +20 -19
- package/src/__tests__/cli.test.ts +23 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +23 -22
- package/src/__tests__/credential-broker-server-use.test.ts +22 -21
- package/src/__tests__/credential-broker.test.ts +2 -1
- package/src/__tests__/credential-metadata-store.test.ts +240 -18
- package/src/__tests__/credential-resolve.test.ts +5 -4
- package/src/__tests__/credential-security-e2e.test.ts +8 -8
- package/src/__tests__/credential-security-invariants.test.ts +104 -7
- package/src/__tests__/credential-vault-unit.test.ts +22 -20
- package/src/__tests__/credential-vault.test.ts +284 -12
- package/src/__tests__/credentials-cli.test.ts +11 -6
- package/src/__tests__/gateway-only-enforcement.test.ts +4 -2
- package/src/__tests__/gemini-image-service.test.ts +75 -45
- package/src/__tests__/gemini-provider.test.ts +9 -6
- package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -33
- package/src/__tests__/guardian-action-copy-generator.test.ts +0 -20
- package/src/__tests__/guardian-action-followup-executor.test.ts +1 -28
- package/src/__tests__/guardian-action-followup-store.test.ts +1 -1
- package/src/__tests__/guardian-grant-minting.test.ts +35 -0
- package/src/__tests__/integration-status.test.ts +53 -21
- package/src/__tests__/managed-proxy-context.test.ts +5 -3
- package/src/__tests__/media-generate-image.test.ts +63 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -3
- package/src/__tests__/messaging-send-tool.test.ts +4 -6
- package/src/__tests__/provider-fail-open-selection.test.ts +3 -1
- package/src/__tests__/provider-managed-proxy-integration.test.ts +70 -6
- package/src/__tests__/schedule-store.test.ts +1 -1
- package/src/__tests__/schema-transforms.test.ts +226 -0
- package/src/__tests__/script-proxy-injection-runtime.test.ts +23 -13
- package/src/__tests__/script-proxy-policy-runtime.test.ts +1 -1
- package/src/__tests__/script-proxy-session-manager.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +5 -3
- package/src/__tests__/session-messaging-secret-redirect.test.ts +5 -4
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +0 -9
- package/src/__tests__/slack-channel-config.test.ts +9 -8
- package/src/__tests__/slack-share-routes.test.ts +11 -6
- package/src/__tests__/telegram-bot-username-resolution.test.ts +3 -0
- package/src/__tests__/twilio-config.test.ts +2 -1
- package/src/__tests__/twilio-provider.test.ts +4 -2
- package/src/__tests__/twilio-routes.test.ts +5 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
- package/src/approvals/AGENTS.md +1 -1
- package/src/calls/call-domain.ts +7 -4
- package/src/calls/twilio-config.ts +2 -1
- package/src/calls/twilio-provider.ts +2 -1
- package/src/calls/twilio-rest.ts +2 -2
- package/src/cli/commands/browser-relay.ts +40 -15
- package/src/cli/commands/credentials.ts +9 -8
- package/src/cli/commands/oauth.ts +1 -1
- package/src/cli.ts +3 -2
- package/src/config/bundled-skills/claude-code/TOOLS.json +0 -4
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +29 -32
- package/src/config/bundled-skills/gmail/SKILL.md +4 -4
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +54 -61
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +25 -28
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +14 -17
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +39 -44
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +61 -58
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +50 -49
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +11 -13
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +148 -146
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +4 -7
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +175 -173
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +4 -7
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +71 -76
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +32 -38
- package/src/config/bundled-skills/google-calendar/SKILL.md +2 -2
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +70 -29
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +9 -10
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +5 -6
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +4 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +14 -15
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +37 -37
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +4 -9
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +24 -3
- package/src/config/bundled-skills/messaging/SKILL.md +6 -6
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +62 -63
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +15 -16
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +6 -7
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +14 -15
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +4 -5
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +128 -128
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +33 -34
- package/src/config/bundled-skills/messaging/tools/shared.ts +11 -11
- package/src/config/bundled-skills/notifications/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +5 -5
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/skill-management/SKILL.md +1 -1
- package/src/config/bundled-skills/slack/tools/shared.ts +4 -10
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +15 -16
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +4 -5
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +95 -92
- package/src/config/loader.ts +6 -0
- package/src/daemon/computer-use-session.ts +7 -1
- package/src/daemon/guardian-action-generators.ts +4 -5
- package/src/daemon/handlers/config-slack-channel.ts +37 -20
- package/src/daemon/handlers/config-telegram.ts +33 -20
- package/src/daemon/lifecycle.ts +9 -1
- package/src/daemon/message-types/integrations.ts +1 -0
- package/src/daemon/ride-shotgun-handler.ts +3 -1
- package/src/daemon/session-messaging.ts +3 -1
- package/src/daemon/session-tool-setup.ts +18 -2
- package/src/daemon/session.ts +1 -1
- package/src/email/providers/index.ts +2 -1
- package/src/instrument.ts +15 -1
- package/src/media/app-icon-generator.ts +30 -4
- package/src/media/avatar-router.ts +28 -62
- package/src/media/gemini-image-service.ts +28 -2
- package/src/memory/canonical-guardian-store.ts +1 -1
- package/src/memory/guardian-action-store.ts +1 -1
- package/src/memory/schema/guardian.ts +1 -1
- package/src/messaging/provider.ts +16 -10
- package/src/messaging/providers/gmail/adapter.ts +40 -23
- package/src/messaging/providers/gmail/client.ts +203 -122
- package/src/messaging/providers/gmail/people-client.ts +26 -18
- package/src/messaging/providers/slack/adapter.ts +29 -19
- package/src/messaging/providers/slack/client.ts +265 -78
- package/src/messaging/providers/telegram-bot/adapter.ts +5 -4
- package/src/messaging/providers/whatsapp/adapter.ts +6 -3
- package/src/messaging/registry.ts +2 -1
- package/src/oauth/byo-connection.test.ts +436 -0
- package/src/oauth/byo-connection.ts +112 -0
- package/src/oauth/connect-orchestrator.ts +27 -0
- package/src/oauth/connection-resolver.ts +34 -0
- package/src/oauth/connection.ts +38 -0
- package/src/oauth/platform-connection.test.ts +163 -0
- package/src/oauth/platform-connection.ts +110 -0
- package/src/oauth/provider-base-urls.ts +21 -0
- package/src/oauth/provider-profiles.ts +1 -1
- package/src/oauth/token-persistence.ts +20 -20
- package/src/permissions/checker.ts +6 -1
- package/src/prompts/system-prompt.ts +52 -15
- package/src/prompts/templates/BOOTSTRAP.md +1 -1
- package/src/providers/gemini/client.ts +15 -6
- package/src/providers/managed-proxy/constants.ts +2 -2
- package/src/providers/managed-proxy/context.ts +5 -1
- package/src/providers/ratelimit.ts +17 -0
- package/src/providers/registry.ts +2 -2
- package/src/runtime/AGENTS.md +18 -1
- package/src/runtime/auth/route-policy.ts +1 -0
- package/src/runtime/channel-invite-transports/telegram.ts +2 -1
- package/src/runtime/channel-readiness-service.ts +168 -195
- package/src/runtime/channel-readiness-types.ts +4 -0
- package/src/runtime/guardian-action-conversation-turn.ts +1 -3
- package/src/runtime/guardian-action-followup-executor.ts +1 -2
- package/src/runtime/guardian-action-message-composer.ts +3 -23
- package/src/runtime/http-server.ts +9 -4
- package/src/runtime/http-types.ts +0 -1
- package/src/runtime/middleware/rate-limiter.ts +74 -20
- package/src/runtime/middleware/twilio-validation.ts +1 -3
- package/src/runtime/routes/channel-readiness-routes.ts +2 -0
- package/src/runtime/routes/diagnostics-routes.ts +11 -9
- package/src/runtime/routes/guardian-approval-interception.ts +20 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +71 -25
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -5
- package/src/runtime/routes/integrations/slack/share.ts +3 -2
- package/src/runtime/routes/integrations/twilio.ts +6 -5
- package/src/runtime/routes/secret-routes.ts +3 -2
- package/src/runtime/routes/settings-routes.ts +75 -17
- package/src/runtime/telegram-streaming-delivery.test.ts +132 -0
- package/src/runtime/telegram-streaming-delivery.ts +11 -1
- package/src/schedule/integration-status.ts +5 -4
- package/src/security/credential-key.ts +170 -0
- package/src/security/token-manager.ts +36 -7
- package/src/tools/apps/definitions.ts +0 -5
- package/src/tools/assets/materialize.ts +0 -5
- package/src/tools/assets/search.ts +0 -5
- package/src/tools/browser/headless-browser.ts +1 -67
- package/src/tools/claude-code/claude-code.ts +0 -5
- package/src/tools/computer-use/request-computer-control.ts +0 -5
- package/src/tools/credentials/broker.ts +6 -4
- package/src/tools/credentials/metadata-store.ts +72 -20
- package/src/tools/credentials/resolve.ts +2 -1
- package/src/tools/credentials/vault.ts +77 -16
- package/src/tools/filesystem/edit.ts +1 -6
- package/src/tools/filesystem/read.ts +0 -5
- package/src/tools/filesystem/write.ts +1 -6
- package/src/tools/host-filesystem/edit.ts +1 -6
- package/src/tools/host-filesystem/read.ts +1 -6
- package/src/tools/host-filesystem/write.ts +1 -6
- package/src/tools/mcp/mcp-tool-factory.ts +18 -1
- package/src/tools/memory/definitions.ts +0 -5
- package/src/tools/network/web-fetch.ts +0 -5
- package/src/tools/network/web-search.ts +0 -5
- package/src/tools/schema-transforms.ts +99 -0
- package/src/tools/skills/load.ts +0 -5
- package/src/tools/swarm/delegate.ts +0 -5
- package/src/tools/system/avatar-generator.ts +3 -44
- package/src/tools/ui-surface/definitions.ts +0 -15
- package/src/tools/watch/screen-watch.ts +0 -5
- package/src/version.ts +10 -0
- package/src/watcher/providers/github.ts +51 -52
- package/src/watcher/providers/gmail.ts +88 -80
- package/src/watcher/providers/google-calendar.ts +93 -86
- package/src/watcher/providers/linear.ts +87 -93
- package/src/__tests__/avatar-router.test.ts +0 -149
- package/src/__tests__/managed-avatar-client.test.ts +0 -337
- package/src/config/bundled-skills/doordash/SKILL.md +0 -170
- package/src/config/bundled-skills/doordash/__tests__/doordash-client.test.ts +0 -205
- package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +0 -74
- package/src/config/bundled-skills/doordash/doordash-cli.ts +0 -1081
- package/src/config/bundled-skills/doordash/doordash-entry.ts +0 -22
- package/src/config/bundled-skills/doordash/lib/cart-queries.ts +0 -787
- package/src/config/bundled-skills/doordash/lib/client.ts +0 -1069
- package/src/config/bundled-skills/doordash/lib/order-queries.ts +0 -85
- package/src/config/bundled-skills/doordash/lib/queries.ts +0 -28
- package/src/config/bundled-skills/doordash/lib/query-extractor.ts +0 -94
- package/src/config/bundled-skills/doordash/lib/search-queries.ts +0 -203
- package/src/config/bundled-skills/doordash/lib/session.ts +0 -96
- package/src/config/bundled-skills/doordash/lib/shared/errors.ts +0 -61
- package/src/config/bundled-skills/doordash/lib/shared/network-recorder.ts +0 -380
- package/src/config/bundled-skills/doordash/lib/shared/platform.ts +0 -55
- package/src/config/bundled-skills/doordash/lib/shared/recording-store.ts +0 -43
- package/src/config/bundled-skills/doordash/lib/shared/recording-types.ts +0 -49
- package/src/config/bundled-skills/doordash/lib/shared/truncate.ts +0 -6
- package/src/config/bundled-skills/doordash/lib/store-queries.ts +0 -246
- package/src/config/bundled-skills/doordash/lib/types.ts +0 -367
- package/src/media/avatar-types.ts +0 -53
- package/src/media/managed-avatar-client.ts +0 -225
|
@@ -17,6 +17,7 @@ let mockGenerateResult = {
|
|
|
17
17
|
resolvedModel: "gemini-2.5-flash-image",
|
|
18
18
|
};
|
|
19
19
|
let mockGenerateError: Error | null = null;
|
|
20
|
+
let lastGenerateCredentials: unknown = null;
|
|
20
21
|
|
|
21
22
|
mock.module("../config/loader.js", () => ({
|
|
22
23
|
getConfig: () => ({
|
|
@@ -27,7 +28,11 @@ mock.module("../config/loader.js", () => ({
|
|
|
27
28
|
}));
|
|
28
29
|
|
|
29
30
|
mock.module("../media/gemini-image-service.js", () => ({
|
|
30
|
-
generateImage: async (
|
|
31
|
+
generateImage: async (
|
|
32
|
+
credentials: unknown,
|
|
33
|
+
_request: Record<string, unknown>,
|
|
34
|
+
) => {
|
|
35
|
+
lastGenerateCredentials = credentials;
|
|
31
36
|
if (mockGenerateError) throw mockGenerateError;
|
|
32
37
|
return mockGenerateResult;
|
|
33
38
|
},
|
|
@@ -37,6 +42,18 @@ mock.module("../media/gemini-image-service.js", () => ({
|
|
|
37
42
|
},
|
|
38
43
|
}));
|
|
39
44
|
|
|
45
|
+
let mockManagedBaseUrl: string | undefined;
|
|
46
|
+
let mockManagedProxyContext = {
|
|
47
|
+
enabled: false,
|
|
48
|
+
platformBaseUrl: "",
|
|
49
|
+
assistantApiKey: "",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
mock.module("../providers/managed-proxy/context.js", () => ({
|
|
53
|
+
buildManagedBaseUrl: () => mockManagedBaseUrl,
|
|
54
|
+
resolveManagedProxyContext: () => mockManagedProxyContext,
|
|
55
|
+
}));
|
|
56
|
+
|
|
40
57
|
let mockAttachments: Array<{
|
|
41
58
|
id: string;
|
|
42
59
|
assistantId: string;
|
|
@@ -138,6 +155,13 @@ beforeEach(() => {
|
|
|
138
155
|
};
|
|
139
156
|
mockGenerateError = null;
|
|
140
157
|
mockAttachments = [];
|
|
158
|
+
lastGenerateCredentials = null;
|
|
159
|
+
mockManagedBaseUrl = undefined;
|
|
160
|
+
mockManagedProxyContext = {
|
|
161
|
+
enabled: false,
|
|
162
|
+
platformBaseUrl: "",
|
|
163
|
+
assistantApiKey: "",
|
|
164
|
+
};
|
|
141
165
|
});
|
|
142
166
|
|
|
143
167
|
const fakeContext = {
|
|
@@ -153,7 +177,7 @@ describe("image-studio skill script wrapper", () => {
|
|
|
153
177
|
expect(getTool("media_generate_image")).toBeUndefined();
|
|
154
178
|
});
|
|
155
179
|
|
|
156
|
-
test("returns error when no API key
|
|
180
|
+
test("returns error when no API key and no managed proxy", async () => {
|
|
157
181
|
mockApiKey = undefined;
|
|
158
182
|
|
|
159
183
|
const result = await run({ prompt: "a cat" }, fakeContext);
|
|
@@ -162,6 +186,43 @@ describe("image-studio skill script wrapper", () => {
|
|
|
162
186
|
expect(result.content).toContain("No Gemini API key");
|
|
163
187
|
});
|
|
164
188
|
|
|
189
|
+
test("falls back to managed proxy when no API key is configured", async () => {
|
|
190
|
+
mockApiKey = undefined;
|
|
191
|
+
mockManagedBaseUrl = "https://platform.example.com/v1/runtime-proxy/vertex";
|
|
192
|
+
mockManagedProxyContext = {
|
|
193
|
+
enabled: true,
|
|
194
|
+
platformBaseUrl: "https://platform.example.com",
|
|
195
|
+
assistantApiKey: "managed-key-123",
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const result = await run({ prompt: "a hippo" }, fakeContext);
|
|
199
|
+
|
|
200
|
+
expect(result.isError).toBe(false);
|
|
201
|
+
expect(result.content).toContain("Generated 1 image");
|
|
202
|
+
expect(lastGenerateCredentials).toEqual({
|
|
203
|
+
type: "managed-proxy",
|
|
204
|
+
assistantApiKey: "managed-key-123",
|
|
205
|
+
baseUrl: "https://platform.example.com/v1/runtime-proxy/vertex",
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("prefers direct API key over managed proxy", async () => {
|
|
210
|
+
mockApiKey = "direct-key";
|
|
211
|
+
mockManagedBaseUrl = "https://platform.example.com/v1/runtime-proxy/vertex";
|
|
212
|
+
mockManagedProxyContext = {
|
|
213
|
+
enabled: true,
|
|
214
|
+
platformBaseUrl: "https://platform.example.com",
|
|
215
|
+
assistantApiKey: "managed-key-123",
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
await run({ prompt: "a cat" }, fakeContext);
|
|
219
|
+
|
|
220
|
+
expect(lastGenerateCredentials).toEqual({
|
|
221
|
+
type: "direct",
|
|
222
|
+
apiKey: "direct-key",
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
165
226
|
test("returns generated image with contentBlocks", async () => {
|
|
166
227
|
const result = await run({ prompt: "a sunset" }, fakeContext);
|
|
167
228
|
|
|
@@ -62,6 +62,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
62
62
|
|
|
63
63
|
// Credential resolver and secure key mocks — must be set up before
|
|
64
64
|
// session-manager is imported so the proxy uses our test data.
|
|
65
|
+
import { credentialKey } from "../security/credential-key.js";
|
|
65
66
|
import type { ResolvedCredential } from "../tools/credentials/resolve.js";
|
|
66
67
|
|
|
67
68
|
let resolveByIdResults = new Map<string, ResolvedCredential | undefined>();
|
|
@@ -154,7 +155,7 @@ function makeResolved(
|
|
|
154
155
|
credentialId,
|
|
155
156
|
service,
|
|
156
157
|
field,
|
|
157
|
-
storageKey:
|
|
158
|
+
storageKey: credentialKey(service, field),
|
|
158
159
|
injectionTemplates: templates,
|
|
159
160
|
metadata: {
|
|
160
161
|
credentialId,
|
|
@@ -357,7 +358,10 @@ describe("Story E2E: selfie yesterday -> generated image today", () => {
|
|
|
357
358
|
};
|
|
358
359
|
const resolved = makeResolved("cred-story", [tpl]);
|
|
359
360
|
resolveByIdResults.set("cred-story", resolved);
|
|
360
|
-
secureKeyValues.set(
|
|
361
|
+
secureKeyValues.set(
|
|
362
|
+
credentialKey("test-service", "api-key"),
|
|
363
|
+
"fal_test_secret",
|
|
364
|
+
);
|
|
361
365
|
|
|
362
366
|
// Drive the proxy step through the bash tool — the actual integration path.
|
|
363
367
|
// -x "$HTTP_PROXY" forces curl to use the proxy explicitly (macOS curl
|
|
@@ -381,7 +385,7 @@ describe("Story E2E: selfie yesterday -> generated image today", () => {
|
|
|
381
385
|
|
|
382
386
|
await stopAllSessions();
|
|
383
387
|
resolveByIdResults.delete("cred-story");
|
|
384
|
-
secureKeyValues.delete("
|
|
388
|
+
secureKeyValues.delete(credentialKey("test-service", "api-key"));
|
|
385
389
|
} finally {
|
|
386
390
|
echo.server.close();
|
|
387
391
|
}
|
|
@@ -2,6 +2,7 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import type { MessagingProvider } from "../messaging/provider.js";
|
|
4
4
|
import type { SendOptions } from "../messaging/provider-types.js";
|
|
5
|
+
import type { OAuthConnection } from "../oauth/connection.js";
|
|
5
6
|
|
|
6
7
|
const sendMessageMock = mock(async (..._args: unknown[]) => ({
|
|
7
8
|
id: "msg-1",
|
|
@@ -23,19 +24,16 @@ const provider: MessagingProvider = {
|
|
|
23
24
|
getHistory: async () => [],
|
|
24
25
|
search: async () => ({ total: 0, messages: [], hasMore: false }),
|
|
25
26
|
sendMessage: (
|
|
26
|
-
|
|
27
|
+
connectionOrToken: OAuthConnection | string,
|
|
27
28
|
conversationId: string,
|
|
28
29
|
text: string,
|
|
29
30
|
options?: SendOptions,
|
|
30
|
-
) => sendMessageMock(
|
|
31
|
+
) => sendMessageMock(connectionOrToken, conversationId, text, options),
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
mock.module("../config/bundled-skills/messaging/tools/shared.js", () => ({
|
|
34
35
|
resolveProvider: () => provider,
|
|
35
|
-
|
|
36
|
-
_provider: MessagingProvider,
|
|
37
|
-
fn: (token: string) => Promise<unknown>,
|
|
38
|
-
) => fn("provider-token"),
|
|
36
|
+
getProviderConnection: () => "provider-token",
|
|
39
37
|
ok: (content: string) => ({ content, isError: false }),
|
|
40
38
|
err: (content: string) => ({ content, isError: true }),
|
|
41
39
|
extractHeader: () => "",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import { credentialKey } from "../security/credential-key.js";
|
|
4
|
+
|
|
3
5
|
// ---------------------------------------------------------------------------
|
|
4
6
|
// Mock the underlying dependencies of managed-proxy/context.js rather than
|
|
5
7
|
// the context module itself. This avoids global mock bleed: other test files
|
|
@@ -19,7 +21,7 @@ const actualSecureKeys = await import("../security/secure-keys.js");
|
|
|
19
21
|
mock.module("../security/secure-keys.js", () => ({
|
|
20
22
|
...actualSecureKeys,
|
|
21
23
|
getSecureKey: (key: string) => {
|
|
22
|
-
if (key === "
|
|
24
|
+
if (key === credentialKey("vellum", "assistant_api_key")) {
|
|
23
25
|
return mockAssistantApiKey || null;
|
|
24
26
|
}
|
|
25
27
|
return null;
|
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import { MANAGED_PROVIDER_META } from "../providers/managed-proxy/constants.js";
|
|
4
|
+
import { credentialKey } from "../security/credential-key.js";
|
|
5
|
+
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Mock @google/genai to capture constructor arguments for Gemini base URL
|
|
8
|
+
// assertions. Must be before importing the registry.
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
let lastGeminiConstructorOpts: Record<string, unknown> | null = null;
|
|
11
|
+
|
|
12
|
+
mock.module("@google/genai", () => ({
|
|
13
|
+
GoogleGenAI: class MockGoogleGenAI {
|
|
14
|
+
constructor(opts: Record<string, unknown>) {
|
|
15
|
+
lastGeminiConstructorOpts = opts;
|
|
16
|
+
}
|
|
17
|
+
models = {
|
|
18
|
+
generateContentStream: async () => ({
|
|
19
|
+
[Symbol.asyncIterator]: async function* () {
|
|
20
|
+
/* no chunks */
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
ApiError: class FakeApiError extends Error {
|
|
26
|
+
status: number;
|
|
27
|
+
constructor(status: number, message: string) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.status = status;
|
|
30
|
+
this.name = "ApiError";
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
4
34
|
|
|
5
35
|
// ---------------------------------------------------------------------------
|
|
6
36
|
// Mock the underlying dependencies that the real context module relies on.
|
|
@@ -16,7 +46,7 @@ mock.module("../config/env.js", () => ({
|
|
|
16
46
|
|
|
17
47
|
mock.module("../security/secure-keys.js", () => ({
|
|
18
48
|
getSecureKey: (key: string) => {
|
|
19
|
-
if (key === "
|
|
49
|
+
if (key === credentialKey("vellum", "assistant_api_key")) {
|
|
20
50
|
return mockAssistantApiKey;
|
|
21
51
|
}
|
|
22
52
|
return null;
|
|
@@ -72,6 +102,7 @@ function userKeysFor(...names: string[]): Record<string, string> {
|
|
|
72
102
|
|
|
73
103
|
beforeEach(() => {
|
|
74
104
|
disableManagedProxy();
|
|
105
|
+
lastGeminiConstructorOpts = null;
|
|
75
106
|
});
|
|
76
107
|
|
|
77
108
|
describe("managed proxy integration — credential precedence", () => {
|
|
@@ -172,6 +203,25 @@ describe("managed proxy integration — credential precedence", () => {
|
|
|
172
203
|
expect(baseURL).toContain("/v1/runtime-proxy/vertex");
|
|
173
204
|
expect(baseURL).not.toContain("/v1/runtime-proxy/anthropic");
|
|
174
205
|
});
|
|
206
|
+
|
|
207
|
+
test("managed gemini uses vertex proxy path instead of gemini proxy path", () => {
|
|
208
|
+
enableManagedProxy();
|
|
209
|
+
initializeProviders({
|
|
210
|
+
apiKeys: {},
|
|
211
|
+
provider: "anthropic",
|
|
212
|
+
model: "test-model",
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// The GoogleGenAI constructor was captured by the mock — verify it
|
|
216
|
+
// received httpOptions.baseUrl pointing at the vertex proxy path.
|
|
217
|
+
expect(lastGeminiConstructorOpts).toBeDefined();
|
|
218
|
+
const httpOptions = lastGeminiConstructorOpts!.httpOptions as
|
|
219
|
+
| { baseUrl?: string }
|
|
220
|
+
| undefined;
|
|
221
|
+
expect(httpOptions).toBeDefined();
|
|
222
|
+
expect(httpOptions!.baseUrl).toContain("/v1/runtime-proxy/vertex");
|
|
223
|
+
expect(httpOptions!.baseUrl).not.toContain("/v1/runtime-proxy/gemini");
|
|
224
|
+
});
|
|
175
225
|
});
|
|
176
226
|
|
|
177
227
|
describe("neither user keys nor managed context → providers not initialized", () => {
|
|
@@ -285,10 +335,24 @@ describe("managed proxy integration — constants integrity", () => {
|
|
|
285
335
|
}
|
|
286
336
|
});
|
|
287
337
|
|
|
288
|
-
test("
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
expect(
|
|
338
|
+
test("anthropic and gemini route through vertex proxy path", () => {
|
|
339
|
+
expect(MANAGED_PROVIDER_META.anthropic.proxyPath).toBe(
|
|
340
|
+
"/v1/runtime-proxy/vertex",
|
|
341
|
+
);
|
|
342
|
+
expect(MANAGED_PROVIDER_META.gemini.proxyPath).toBe(
|
|
343
|
+
"/v1/runtime-proxy/vertex",
|
|
344
|
+
);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("other providers use their own proxy paths", () => {
|
|
348
|
+
expect(MANAGED_PROVIDER_META.openai.proxyPath).toBe(
|
|
349
|
+
"/v1/runtime-proxy/openai",
|
|
350
|
+
);
|
|
351
|
+
expect(MANAGED_PROVIDER_META.fireworks.proxyPath).toBe(
|
|
352
|
+
"/v1/runtime-proxy/fireworks",
|
|
353
|
+
);
|
|
354
|
+
expect(MANAGED_PROVIDER_META.openrouter.proxyPath).toBe(
|
|
355
|
+
"/v1/runtime-proxy/openrouter",
|
|
356
|
+
);
|
|
293
357
|
});
|
|
294
358
|
});
|
|
@@ -903,7 +903,7 @@ describe("routing and mode fields", () => {
|
|
|
903
903
|
});
|
|
904
904
|
|
|
905
905
|
test("routing hints round-trip through DB raw query", () => {
|
|
906
|
-
const hints = { target: "
|
|
906
|
+
const hints = { target: "telegram" };
|
|
907
907
|
const job = createSchedule({
|
|
908
908
|
name: "Raw round-trip",
|
|
909
909
|
message: "check raw",
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import type { ToolDefinition } from "../providers/types.js";
|
|
4
|
+
import {
|
|
5
|
+
injectReasonField,
|
|
6
|
+
REASON_SKIP_SET,
|
|
7
|
+
schemaDefinesProperty,
|
|
8
|
+
} from "../tools/schema-transforms.js";
|
|
9
|
+
|
|
10
|
+
function makeDef(
|
|
11
|
+
name: string,
|
|
12
|
+
schema: object = { type: "object", properties: {}, required: [] },
|
|
13
|
+
): ToolDefinition {
|
|
14
|
+
return { name, description: `Tool ${name}`, input_schema: schema };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("REASON_SKIP_SET", () => {
|
|
18
|
+
test("contains expected tool names", () => {
|
|
19
|
+
expect(REASON_SKIP_SET.has("skill_execute")).toBe(true);
|
|
20
|
+
expect(REASON_SKIP_SET.has("bash")).toBe(true);
|
|
21
|
+
expect(REASON_SKIP_SET.has("host_bash")).toBe(true);
|
|
22
|
+
expect(REASON_SKIP_SET.has("request_system_permission")).toBe(true);
|
|
23
|
+
expect(REASON_SKIP_SET.size).toBe(4);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("injectReasonField", () => {
|
|
28
|
+
test("injects reason on a tool without it", () => {
|
|
29
|
+
const defs = [makeDef("my_tool")];
|
|
30
|
+
const result = injectReasonField(defs);
|
|
31
|
+
const schema = result[0].input_schema as Record<string, unknown>;
|
|
32
|
+
const props = schema.properties as Record<string, unknown>;
|
|
33
|
+
expect(props.reason).toEqual({ type: "string" });
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("adds reason to required array", () => {
|
|
37
|
+
const defs = [
|
|
38
|
+
makeDef("my_tool", {
|
|
39
|
+
type: "object",
|
|
40
|
+
properties: { foo: { type: "string" } },
|
|
41
|
+
required: ["foo"],
|
|
42
|
+
}),
|
|
43
|
+
];
|
|
44
|
+
const result = injectReasonField(defs);
|
|
45
|
+
const schema = result[0].input_schema as Record<string, unknown>;
|
|
46
|
+
expect(schema.required).toEqual(["foo", "reason"]);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("creates required array if missing", () => {
|
|
50
|
+
const defs = [
|
|
51
|
+
makeDef("my_tool", {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: { foo: { type: "string" } },
|
|
54
|
+
}),
|
|
55
|
+
];
|
|
56
|
+
const result = injectReasonField(defs);
|
|
57
|
+
const schema = result[0].input_schema as Record<string, unknown>;
|
|
58
|
+
expect(schema.required).toEqual(["reason"]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("skips tools in skip set (returns unchanged)", () => {
|
|
62
|
+
const defs = [makeDef("bash"), makeDef("host_bash")];
|
|
63
|
+
const result = injectReasonField(defs);
|
|
64
|
+
// Should be the exact same object references
|
|
65
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
66
|
+
expect(Object.is(result[1], defs[1])).toBe(true);
|
|
67
|
+
// No reason injected
|
|
68
|
+
const schema0 = result[0].input_schema as Record<string, unknown>;
|
|
69
|
+
const props0 = schema0.properties as Record<string, unknown>;
|
|
70
|
+
expect("reason" in props0).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("skips tools that already have reason in properties", () => {
|
|
74
|
+
const defs = [
|
|
75
|
+
makeDef("my_tool", {
|
|
76
|
+
type: "object",
|
|
77
|
+
properties: { reason: { type: "number" } },
|
|
78
|
+
required: [],
|
|
79
|
+
}),
|
|
80
|
+
];
|
|
81
|
+
const result = injectReasonField(defs);
|
|
82
|
+
// Should be the exact same object reference (no clone needed)
|
|
83
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
84
|
+
const schema = result[0].input_schema as Record<string, unknown>;
|
|
85
|
+
const props = schema.properties as Record<string, unknown>;
|
|
86
|
+
// Original reason type preserved
|
|
87
|
+
expect(props.reason).toEqual({ type: "number" });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("does NOT mutate original definition objects", () => {
|
|
91
|
+
const originalProps = { foo: { type: "string" } };
|
|
92
|
+
const originalRequired = ["foo"];
|
|
93
|
+
const originalSchema = {
|
|
94
|
+
type: "object",
|
|
95
|
+
properties: originalProps,
|
|
96
|
+
required: originalRequired,
|
|
97
|
+
};
|
|
98
|
+
const defs = [makeDef("my_tool", originalSchema)];
|
|
99
|
+
|
|
100
|
+
const result = injectReasonField(defs);
|
|
101
|
+
|
|
102
|
+
// Original properties object is untouched
|
|
103
|
+
expect("reason" in originalProps).toBe(false);
|
|
104
|
+
// Original required array is untouched
|
|
105
|
+
expect(originalRequired).toEqual(["foo"]);
|
|
106
|
+
// Original schema properties ref is the same object
|
|
107
|
+
expect(Object.is(originalSchema.properties, originalProps)).toBe(true);
|
|
108
|
+
|
|
109
|
+
// Result has different object refs
|
|
110
|
+
const resultSchema = result[0].input_schema as Record<string, unknown>;
|
|
111
|
+
expect(Object.is(resultSchema, originalSchema)).toBe(false);
|
|
112
|
+
expect(Object.is(resultSchema.properties, originalProps)).toBe(false);
|
|
113
|
+
expect(Object.is(resultSchema.required, originalRequired)).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("passes through non-object schemas unchanged", () => {
|
|
117
|
+
const defs = [makeDef("my_tool", { type: "string" })];
|
|
118
|
+
const result = injectReasonField(defs);
|
|
119
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("passes through schemas without properties unchanged", () => {
|
|
123
|
+
const defs = [makeDef("my_tool", { type: "object" })];
|
|
124
|
+
const result = injectReasonField(defs);
|
|
125
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("skips tools with reason defined inside allOf member (composite schema)", () => {
|
|
129
|
+
const defs = [
|
|
130
|
+
makeDef("my_tool", {
|
|
131
|
+
type: "object",
|
|
132
|
+
properties: { foo: { type: "string" } },
|
|
133
|
+
allOf: [
|
|
134
|
+
{
|
|
135
|
+
properties: { reason: { type: "string" } },
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
required: [],
|
|
139
|
+
}),
|
|
140
|
+
];
|
|
141
|
+
const result = injectReasonField(defs);
|
|
142
|
+
// Should be the exact same object reference (no injection)
|
|
143
|
+
expect(Object.is(result[0], defs[0])).toBe(true);
|
|
144
|
+
const schema = result[0].input_schema as Record<string, unknown>;
|
|
145
|
+
const props = schema.properties as Record<string, unknown>;
|
|
146
|
+
// Top-level properties should NOT have reason injected
|
|
147
|
+
expect("reason" in props).toBe(false);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("handles empty definitions array", () => {
|
|
151
|
+
const result = injectReasonField([]);
|
|
152
|
+
expect(result).toEqual([]);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe("schemaDefinesProperty", () => {
|
|
157
|
+
test("returns true for direct properties match", () => {
|
|
158
|
+
const schema = {
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: { reason: { type: "string" } },
|
|
161
|
+
};
|
|
162
|
+
expect(schemaDefinesProperty(schema, "reason")).toBe(true);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("returns true for property in allOf member", () => {
|
|
166
|
+
const schema = {
|
|
167
|
+
allOf: [{ properties: { reason: { type: "string" } } }],
|
|
168
|
+
};
|
|
169
|
+
expect(schemaDefinesProperty(schema, "reason")).toBe(true);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("returns true for property in oneOf member", () => {
|
|
173
|
+
const schema = {
|
|
174
|
+
oneOf: [
|
|
175
|
+
{ properties: { foo: { type: "string" } } },
|
|
176
|
+
{ properties: { reason: { type: "string" } } },
|
|
177
|
+
],
|
|
178
|
+
};
|
|
179
|
+
expect(schemaDefinesProperty(schema, "reason")).toBe(true);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("returns true for property in anyOf member", () => {
|
|
183
|
+
const schema = {
|
|
184
|
+
anyOf: [{ properties: { reason: { type: "string" } } }],
|
|
185
|
+
};
|
|
186
|
+
expect(schemaDefinesProperty(schema, "reason")).toBe(true);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test("returns true for nested allOf within oneOf", () => {
|
|
190
|
+
const schema = {
|
|
191
|
+
oneOf: [
|
|
192
|
+
{
|
|
193
|
+
allOf: [{ properties: { reason: { type: "string" } } }],
|
|
194
|
+
},
|
|
195
|
+
],
|
|
196
|
+
};
|
|
197
|
+
expect(schemaDefinesProperty(schema, "reason")).toBe(true);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("returns false when property not defined", () => {
|
|
201
|
+
const schema = {
|
|
202
|
+
type: "object",
|
|
203
|
+
properties: { foo: { type: "string" } },
|
|
204
|
+
};
|
|
205
|
+
expect(schemaDefinesProperty(schema, "reason")).toBe(false);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("returns false for $ref (fail-closed)", () => {
|
|
209
|
+
const schema = { $ref: "#/definitions/Foo" };
|
|
210
|
+
expect(schemaDefinesProperty(schema, "reason")).toBe(false);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("returns false for null schema", () => {
|
|
214
|
+
expect(schemaDefinesProperty(null, "reason")).toBe(false);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("returns false for undefined schema", () => {
|
|
218
|
+
expect(schemaDefinesProperty(undefined, "reason")).toBe(false);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("returns false for non-object schema", () => {
|
|
222
|
+
expect(schemaDefinesProperty("not-an-object", "reason")).toBe(false);
|
|
223
|
+
expect(schemaDefinesProperty(42, "reason")).toBe(false);
|
|
224
|
+
expect(schemaDefinesProperty(true, "reason")).toBe(false);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as http from "node:http";
|
|
2
2
|
import { afterEach, describe, expect, mock, test } from "bun:test";
|
|
3
3
|
|
|
4
|
+
import { credentialKey } from "../security/credential-key.js";
|
|
4
5
|
import type { CredentialMetadata } from "../tools/credentials/metadata-store.js";
|
|
5
6
|
import type { CredentialInjectionTemplate } from "../tools/credentials/policy-types.js";
|
|
6
7
|
import type { ResolvedCredential } from "../tools/credentials/resolve.js";
|
|
@@ -82,7 +83,7 @@ function makeResolved(
|
|
|
82
83
|
credentialId,
|
|
83
84
|
service,
|
|
84
85
|
field,
|
|
85
|
-
storageKey:
|
|
86
|
+
storageKey: credentialKey(service, field),
|
|
86
87
|
injectionTemplates: templates,
|
|
87
88
|
metadata: {
|
|
88
89
|
credentialId,
|
|
@@ -154,7 +155,7 @@ describe("policyCallback credential injection", () => {
|
|
|
154
155
|
resolveByIdResults.set("cred-local", resolved);
|
|
155
156
|
credentialMetadataList.push(resolved.metadata);
|
|
156
157
|
secureKeyValues.set(
|
|
157
|
-
"
|
|
158
|
+
credentialKey("test-service", "api-key"),
|
|
158
159
|
"fal_secretvalue123",
|
|
159
160
|
);
|
|
160
161
|
|
|
@@ -194,7 +195,10 @@ describe("policyCallback credential injection", () => {
|
|
|
194
195
|
const resolved = makeResolved("cred-bearer", [tpl]);
|
|
195
196
|
resolveByIdResults.set("cred-bearer", resolved);
|
|
196
197
|
credentialMetadataList.push(resolved.metadata);
|
|
197
|
-
secureKeyValues.set(
|
|
198
|
+
secureKeyValues.set(
|
|
199
|
+
credentialKey("test-service", "api-key"),
|
|
200
|
+
"tok_abc123",
|
|
201
|
+
);
|
|
198
202
|
|
|
199
203
|
const session = createSession(
|
|
200
204
|
CONV_ID,
|
|
@@ -311,7 +315,7 @@ describe("MITM rewriteCallback credential injection", () => {
|
|
|
311
315
|
const tpl = makeTemplate("*.fal.ai", "authorization", "Key ");
|
|
312
316
|
const resolved = makeResolved("cred-fal", [tpl]);
|
|
313
317
|
resolveByIdResults.set("cred-fal", resolved);
|
|
314
|
-
secureKeyValues.set("
|
|
318
|
+
secureKeyValues.set(credentialKey("test-service", "api-key"), "fal_secret");
|
|
315
319
|
|
|
316
320
|
const templates = new Map([["cred-fal", [tpl]]]);
|
|
317
321
|
const headers: Record<string, string> = {
|
|
@@ -350,7 +354,7 @@ describe("MITM rewriteCallback credential injection", () => {
|
|
|
350
354
|
|
|
351
355
|
const tpl = makeTemplate("*.fal.ai", "authorization", "Key ");
|
|
352
356
|
resolveByIdResults.set("cred-fal", makeResolved("cred-fal", [tpl]));
|
|
353
|
-
secureKeyValues.set("
|
|
357
|
+
secureKeyValues.set(credentialKey("test-service", "api-key"), "fal_secret");
|
|
354
358
|
|
|
355
359
|
const templates = new Map([["cred-fal", [tpl]]]);
|
|
356
360
|
const headers: Record<string, string> = {
|
|
@@ -479,8 +483,8 @@ describe("composeWith injection", () => {
|
|
|
479
483
|
);
|
|
480
484
|
resolveByServiceFieldResults.set("twilio:auth_token", composedResolved);
|
|
481
485
|
|
|
482
|
-
secureKeyValues.set("
|
|
483
|
-
secureKeyValues.set("
|
|
486
|
+
secureKeyValues.set(credentialKey("twilio", "account_sid"), "ACtest123");
|
|
487
|
+
secureKeyValues.set(credentialKey("twilio", "auth_token"), "secret456");
|
|
484
488
|
|
|
485
489
|
const session = createSession(
|
|
486
490
|
CONV_ID,
|
|
@@ -531,7 +535,7 @@ describe("composeWith injection", () => {
|
|
|
531
535
|
);
|
|
532
536
|
resolveByIdResults.set("cred-primary", primaryResolved);
|
|
533
537
|
credentialMetadataList.push(primaryResolved.metadata);
|
|
534
|
-
secureKeyValues.set("
|
|
538
|
+
secureKeyValues.set(credentialKey("twilio", "account_sid"), "ACtest123");
|
|
535
539
|
|
|
536
540
|
// Do NOT register the composed credential in resolveByServiceFieldResults
|
|
537
541
|
|
|
@@ -578,7 +582,10 @@ describe("composeWith injection", () => {
|
|
|
578
582
|
const resolved = makeResolved("cred-b64", [tpl]);
|
|
579
583
|
resolveByIdResults.set("cred-b64", resolved);
|
|
580
584
|
credentialMetadataList.push(resolved.metadata);
|
|
581
|
-
secureKeyValues.set(
|
|
585
|
+
secureKeyValues.set(
|
|
586
|
+
credentialKey("test-service", "api-key"),
|
|
587
|
+
"plaintext",
|
|
588
|
+
);
|
|
582
589
|
|
|
583
590
|
const session = createSession(CONV_ID, ["cred-b64"], undefined, DATA_DIR);
|
|
584
591
|
const started = await startSession(session.id);
|
|
@@ -624,7 +631,7 @@ describe("composeWith injection", () => {
|
|
|
624
631
|
);
|
|
625
632
|
resolveByIdResults.set("cred-primary", primaryResolved);
|
|
626
633
|
credentialMetadataList.push(primaryResolved.metadata);
|
|
627
|
-
secureKeyValues.set("
|
|
634
|
+
secureKeyValues.set(credentialKey("twilio", "account_sid"), "ACtest123");
|
|
628
635
|
|
|
629
636
|
// Composed credential metadata resolves, but no secret value stored
|
|
630
637
|
const composedResolved = makeResolved(
|
|
@@ -634,7 +641,7 @@ describe("composeWith injection", () => {
|
|
|
634
641
|
"auth_token",
|
|
635
642
|
);
|
|
636
643
|
resolveByServiceFieldResults.set("twilio:auth_token", composedResolved);
|
|
637
|
-
// Do NOT set secureKeyValues for "
|
|
644
|
+
// Do NOT set secureKeyValues for credentialKey("twilio", "auth_token")
|
|
638
645
|
|
|
639
646
|
const session = createSession(
|
|
640
647
|
CONV_ID,
|
|
@@ -700,8 +707,11 @@ describe("composeWith injection", () => {
|
|
|
700
707
|
composedResolved,
|
|
701
708
|
);
|
|
702
709
|
|
|
703
|
-
secureKeyValues.set("
|
|
704
|
-
secureKeyValues.set(
|
|
710
|
+
secureKeyValues.set(credentialKey("my-service", "primary-key"), "value1");
|
|
711
|
+
secureKeyValues.set(
|
|
712
|
+
credentialKey("my-service", "secondary-key"),
|
|
713
|
+
"value2",
|
|
714
|
+
);
|
|
705
715
|
|
|
706
716
|
const session = createSession(
|
|
707
717
|
CONV_ID,
|