@vellumai/assistant 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +11 -12
- package/docker-entrypoint.sh +13 -1
- package/docker-init-apt-root.sh +79 -6
- package/openapi.yaml +336 -21
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +272 -0
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/context-token-estimator.test.ts +30 -65
- package/src/__tests__/conversation-agent-loop.test.ts +57 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-runtime-assembly.test.ts +26 -4
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -0
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +5 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +255 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +218 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +6 -73
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/loop.ts +167 -18
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/notifications.ts +65 -35
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/call-site-defaults.ts +105 -0
- package/src/config/feature-flag-registry.json +21 -29
- package/src/config/llm-resolver.ts +52 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +1 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +4 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +72 -12
- package/src/context/token-estimator.ts +32 -34
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/conversation-agent-loop-handlers.ts +78 -0
- package/src/daemon/conversation-agent-loop.ts +29 -2
- package/src/daemon/conversation-runtime-assembly.ts +9 -0
- package/src/daemon/conversation.ts +0 -7
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +289 -0
- package/src/daemon/handlers/conversations.ts +1 -0
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/lifecycle.ts +49 -61
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/process-message.ts +3 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -0
- package/src/heartbeat/heartbeat-service.ts +34 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/feed-types.ts +14 -2
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-enqueue.ts +1 -20
- package/src/memory/memory-retrospective-job.ts +33 -6
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection.test.ts +190 -3
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection.ts +49 -20
- package/src/memory/v2/page-index.ts +38 -13
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +11 -2
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +1 -0
- package/src/notifications/home-feed-side-effect.ts +85 -6
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/plugins/defaults/injectors.ts +38 -19
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +6 -51
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/system-prompt.ts +0 -8
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/system-sections.ts +0 -9
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +9 -20
- package/src/providers/inference/auth.ts +12 -0
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +2 -0
- package/src/providers/model-catalog.ts +199 -244
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +159 -6
- package/src/providers/openrouter/client.ts +42 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/runtime/agent-wake.ts +61 -1
- package/src/runtime/auth/route-policy.ts +13 -0
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +0 -47
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +66 -4
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/conversation-query-routes.ts +70 -11
- package/src/runtime/routes/conversation-routes.ts +7 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +134 -1
- package/src/runtime/routes/integrations/a2a.ts +235 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/subagent/manager.ts +2 -0
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/registry.ts +2 -2
- package/src/tools/types.ts +37 -2
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
|
@@ -21,6 +21,13 @@ interface FakeChunk {
|
|
|
21
21
|
choices: Array<{
|
|
22
22
|
delta: {
|
|
23
23
|
content?: string | null;
|
|
24
|
+
reasoning_content?: string | null;
|
|
25
|
+
reasoning?: string | null;
|
|
26
|
+
reasoning_details?: Array<{
|
|
27
|
+
type?: string;
|
|
28
|
+
summary?: string | null;
|
|
29
|
+
text?: string | null;
|
|
30
|
+
}> | null;
|
|
24
31
|
tool_calls?: Array<{
|
|
25
32
|
index: number;
|
|
26
33
|
id?: string;
|
|
@@ -209,6 +216,44 @@ function cachedUsageChunk(
|
|
|
209
216
|
};
|
|
210
217
|
}
|
|
211
218
|
|
|
219
|
+
function reasoningChunk(
|
|
220
|
+
reasoning: string,
|
|
221
|
+
finish: string | null = null,
|
|
222
|
+
): FakeChunk {
|
|
223
|
+
return {
|
|
224
|
+
choices: [
|
|
225
|
+
{ delta: { reasoning_content: reasoning }, finish_reason: finish },
|
|
226
|
+
],
|
|
227
|
+
usage: null,
|
|
228
|
+
model: "gpt-5.2",
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// OpenRouter spec uses `delta.reasoning` rather than `delta.reasoning_content`.
|
|
233
|
+
function openRouterReasoningChunk(
|
|
234
|
+
reasoning: string,
|
|
235
|
+
finish: string | null = null,
|
|
236
|
+
): FakeChunk {
|
|
237
|
+
return {
|
|
238
|
+
choices: [{ delta: { reasoning }, finish_reason: finish }],
|
|
239
|
+
usage: null,
|
|
240
|
+
model: "gpt-5.2",
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// OpenRouter's documented reasoning-summary shape: a `reasoning_details` array
|
|
245
|
+
// with entries tagged `reasoning.summary` / `reasoning.text` / `reasoning.encrypted`.
|
|
246
|
+
function reasoningDetailsChunk(
|
|
247
|
+
details: Array<{ type?: string; summary?: string; text?: string }>,
|
|
248
|
+
finish: string | null = null,
|
|
249
|
+
): FakeChunk {
|
|
250
|
+
return {
|
|
251
|
+
choices: [{ delta: { reasoning_details: details }, finish_reason: finish }],
|
|
252
|
+
usage: null,
|
|
253
|
+
model: "gpt-5.2",
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
212
257
|
// ---------------------------------------------------------------------------
|
|
213
258
|
// Class extraction sanity checks
|
|
214
259
|
// ---------------------------------------------------------------------------
|
|
@@ -339,6 +384,153 @@ describe("OpenAIProvider", () => {
|
|
|
339
384
|
expect(events[1]).toEqual({ type: "text_delta", text: ", world!" });
|
|
340
385
|
});
|
|
341
386
|
|
|
387
|
+
// -----------------------------------------------------------------------
|
|
388
|
+
// Reasoning content (MiniMax / DeepSeek extension)
|
|
389
|
+
// -----------------------------------------------------------------------
|
|
390
|
+
test("parses reasoning_content into thinking block", async () => {
|
|
391
|
+
fakeChunks = [
|
|
392
|
+
reasoningChunk("Let me think..."),
|
|
393
|
+
textChunk("The answer is 42."),
|
|
394
|
+
usageChunk(10, 20),
|
|
395
|
+
];
|
|
396
|
+
|
|
397
|
+
const result = await provider.sendMessage([userMsg("Hi")]);
|
|
398
|
+
|
|
399
|
+
expect(result.content).toHaveLength(2);
|
|
400
|
+
expect(result.content[0]).toEqual({
|
|
401
|
+
type: "thinking",
|
|
402
|
+
thinking: "Let me think...",
|
|
403
|
+
signature: "",
|
|
404
|
+
});
|
|
405
|
+
expect(result.content[1]).toEqual({
|
|
406
|
+
type: "text",
|
|
407
|
+
text: "The answer is 42.",
|
|
408
|
+
});
|
|
409
|
+
expect(result.usage).toEqual({ inputTokens: 10, outputTokens: 20 });
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("fires thinking_delta events during streaming", async () => {
|
|
413
|
+
fakeChunks = [
|
|
414
|
+
reasoningChunk("Let me think..."),
|
|
415
|
+
textChunk("The answer is 42."),
|
|
416
|
+
usageChunk(10, 20),
|
|
417
|
+
];
|
|
418
|
+
|
|
419
|
+
const events: ProviderEvent[] = [];
|
|
420
|
+
await provider.sendMessage([userMsg("Hi")], undefined, undefined, {
|
|
421
|
+
onEvent: (e) => events.push(e),
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
expect(events).toHaveLength(2);
|
|
425
|
+
expect(events[0]).toEqual({
|
|
426
|
+
type: "thinking_delta",
|
|
427
|
+
thinking: "Let me think...",
|
|
428
|
+
});
|
|
429
|
+
expect(events[1]).toEqual({
|
|
430
|
+
type: "text_delta",
|
|
431
|
+
text: "The answer is 42.",
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
test("reasoning + tool calls orders correctly (thinking → tool_use)", async () => {
|
|
436
|
+
fakeChunks = [
|
|
437
|
+
reasoningChunk("Planning..."),
|
|
438
|
+
...toolCallChunks([
|
|
439
|
+
{ id: "call_1", name: "file_read", args: '{"path":"/a"}' },
|
|
440
|
+
]),
|
|
441
|
+
usageChunk(10, 30),
|
|
442
|
+
];
|
|
443
|
+
|
|
444
|
+
const result = await provider.sendMessage([userMsg("Read /a")]);
|
|
445
|
+
|
|
446
|
+
expect(result.content).toHaveLength(2);
|
|
447
|
+
expect(result.content[0].type).toBe("thinking");
|
|
448
|
+
expect(result.content[1].type).toBe("tool_use");
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test("no thinking block when reasoning_content is absent", async () => {
|
|
452
|
+
fakeChunks = [textChunk("Just text"), usageChunk(10, 5)];
|
|
453
|
+
|
|
454
|
+
const result = await provider.sendMessage([userMsg("Hi")]);
|
|
455
|
+
|
|
456
|
+
expect(result.content).toHaveLength(1);
|
|
457
|
+
expect(result.content[0].type).toBe("text");
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
test("parses OpenRouter's `delta.reasoning` field into thinking block", async () => {
|
|
461
|
+
fakeChunks = [
|
|
462
|
+
openRouterReasoningChunk("Hmm, let me think..."),
|
|
463
|
+
textChunk("Final answer."),
|
|
464
|
+
usageChunk(10, 8),
|
|
465
|
+
];
|
|
466
|
+
|
|
467
|
+
const events: ProviderEvent[] = [];
|
|
468
|
+
const result = await provider.sendMessage(
|
|
469
|
+
[userMsg("Hi")],
|
|
470
|
+
undefined,
|
|
471
|
+
undefined,
|
|
472
|
+
{
|
|
473
|
+
onEvent: (e) => events.push(e),
|
|
474
|
+
},
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
expect(result.content).toHaveLength(2);
|
|
478
|
+
expect(result.content[0]).toEqual({
|
|
479
|
+
type: "thinking",
|
|
480
|
+
thinking: "Hmm, let me think...",
|
|
481
|
+
signature: "",
|
|
482
|
+
});
|
|
483
|
+
expect(result.content[1]).toEqual({ type: "text", text: "Final answer." });
|
|
484
|
+
expect(events).toContainEqual({
|
|
485
|
+
type: "thinking_delta",
|
|
486
|
+
thinking: "Hmm, let me think...",
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test("parses OpenRouter `delta.reasoning_details` summary/text entries and skips encrypted", async () => {
|
|
491
|
+
fakeChunks = [
|
|
492
|
+
reasoningDetailsChunk([
|
|
493
|
+
{ type: "reasoning.summary", summary: "Plan step one. " },
|
|
494
|
+
{ type: "reasoning.encrypted", text: "ENCRYPTED_BLOB" },
|
|
495
|
+
{ type: "reasoning.text", text: "Detailed thought." },
|
|
496
|
+
]),
|
|
497
|
+
textChunk("Done."),
|
|
498
|
+
usageChunk(10, 8),
|
|
499
|
+
];
|
|
500
|
+
|
|
501
|
+
const events: ProviderEvent[] = [];
|
|
502
|
+
const result = await provider.sendMessage(
|
|
503
|
+
[userMsg("Hi")],
|
|
504
|
+
undefined,
|
|
505
|
+
undefined,
|
|
506
|
+
{
|
|
507
|
+
onEvent: (e) => events.push(e),
|
|
508
|
+
},
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
expect(result.content).toHaveLength(2);
|
|
512
|
+
expect(result.content[0]).toEqual({
|
|
513
|
+
type: "thinking",
|
|
514
|
+
thinking: "Plan step one. Detailed thought.",
|
|
515
|
+
signature: "",
|
|
516
|
+
});
|
|
517
|
+
expect(result.content[1]).toEqual({ type: "text", text: "Done." });
|
|
518
|
+
expect(events).toContainEqual({
|
|
519
|
+
type: "thinking_delta",
|
|
520
|
+
thinking: "Plan step one. ",
|
|
521
|
+
});
|
|
522
|
+
expect(events).toContainEqual({
|
|
523
|
+
type: "thinking_delta",
|
|
524
|
+
thinking: "Detailed thought.",
|
|
525
|
+
});
|
|
526
|
+
// Encrypted blob must never surface as visible thinking.
|
|
527
|
+
for (const e of events) {
|
|
528
|
+
if (e.type === "thinking_delta") {
|
|
529
|
+
expect(e.thinking).not.toContain("ENCRYPTED_BLOB");
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
|
|
342
534
|
// -----------------------------------------------------------------------
|
|
343
535
|
// System prompt
|
|
344
536
|
// -----------------------------------------------------------------------
|
|
@@ -1306,14 +1498,17 @@ describe("OpenRouterProvider reasoning", () => {
|
|
|
1306
1498
|
shouldThrow = null;
|
|
1307
1499
|
});
|
|
1308
1500
|
|
|
1309
|
-
test("sends reasoning.enabled=true when thinking config is present", async () => {
|
|
1501
|
+
test("sends reasoning.enabled=true with default detailed summary when thinking config is present", async () => {
|
|
1310
1502
|
const provider = new OpenRouterProvider("or-key", "x-ai/grok-4");
|
|
1311
1503
|
await provider.sendMessage([userMsg("hi")], undefined, undefined, {
|
|
1312
1504
|
config: { thinking: { type: "adaptive" } },
|
|
1313
1505
|
});
|
|
1314
1506
|
|
|
1315
1507
|
expect(lastCreateParams).toBeTruthy();
|
|
1316
|
-
expect(lastCreateParams!.reasoning).toEqual({
|
|
1508
|
+
expect(lastCreateParams!.reasoning).toEqual({
|
|
1509
|
+
enabled: true,
|
|
1510
|
+
summary: "detailed",
|
|
1511
|
+
});
|
|
1317
1512
|
});
|
|
1318
1513
|
|
|
1319
1514
|
test("sends reasoning.enabled=false when thinking is explicitly disabled", async () => {
|
|
@@ -1376,7 +1571,10 @@ describe("OpenRouterProvider reasoning", () => {
|
|
|
1376
1571
|
await retry.sendMessage([userMsg("hi")], undefined, undefined, {
|
|
1377
1572
|
config: { thinking: { type: "adaptive" } },
|
|
1378
1573
|
});
|
|
1379
|
-
expect(lastCreateParams!.reasoning).toEqual({
|
|
1574
|
+
expect(lastCreateParams!.reasoning).toEqual({
|
|
1575
|
+
enabled: true,
|
|
1576
|
+
summary: "detailed",
|
|
1577
|
+
});
|
|
1380
1578
|
});
|
|
1381
1579
|
|
|
1382
1580
|
test("RetryProvider + OpenRouterProvider disables thinking end-to-end", async () => {
|
|
@@ -1389,6 +1587,23 @@ describe("OpenRouterProvider reasoning", () => {
|
|
|
1389
1587
|
});
|
|
1390
1588
|
expect(lastCreateParams!.reasoning).toEqual({ enabled: false });
|
|
1391
1589
|
});
|
|
1590
|
+
|
|
1591
|
+
test("nests effort under reasoning and omits top-level reasoning_effort", async () => {
|
|
1592
|
+
const provider = new OpenRouterProvider("or-key", "moonshotai/kimi-k2.6");
|
|
1593
|
+
await provider.sendMessage([userMsg("hi")], undefined, undefined, {
|
|
1594
|
+
config: { thinking: { enabled: true }, effort: "max" },
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
expect(lastCreateParams).toBeTruthy();
|
|
1598
|
+
expect(lastCreateParams!.reasoning).toEqual({
|
|
1599
|
+
enabled: true,
|
|
1600
|
+
effort: "xhigh",
|
|
1601
|
+
summary: "detailed",
|
|
1602
|
+
});
|
|
1603
|
+
// Critical: must NOT also send the OpenAI-native flat field — OpenRouter
|
|
1604
|
+
// rejects requests that carry both forms for reasoning models.
|
|
1605
|
+
expect(lastCreateParams).not.toHaveProperty("reasoning_effort");
|
|
1606
|
+
});
|
|
1392
1607
|
});
|
|
1393
1608
|
|
|
1394
1609
|
describe("OpenRouterProvider Anthropic-compatible errors", () => {
|
|
@@ -92,9 +92,9 @@ describe("OpenAI Responses API cutover guard", () => {
|
|
|
92
92
|
|
|
93
93
|
// The factory must NOT instantiate OpenAIChatCompletionsProvider or
|
|
94
94
|
// OpenAIProvider (the backward-compatible alias) inside the `openai:`
|
|
95
|
-
// factory entry. Other entries (e.g. `
|
|
96
|
-
//
|
|
97
|
-
//
|
|
95
|
+
// factory entry. Other entries (e.g. `openai-compatible:`) may legitimately
|
|
96
|
+
// use OpenAIChatCompletionsProvider since that's the OpenAI Chat Completions
|
|
97
|
+
// transport for third-party endpoints.
|
|
98
98
|
const openaiEntryRegion =
|
|
99
99
|
/(?:^|\s)openai\s*:\s*\([^)]*\)\s*=>\s*[\s\S]{0,400}?(?=\}\s*,\s*[a-z-]+\s*:|\}\s*;)/m.exec(
|
|
100
100
|
source,
|
|
@@ -116,7 +116,7 @@ describe("OpenRouter provider.only plumbing", () => {
|
|
|
116
116
|
expect(extras.provider).toBe(undefined);
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
-
test("
|
|
119
|
+
test("enables thinking with default detailed summary alongside provider.only", () => {
|
|
120
120
|
const provider = new ProbeOpenRouterProvider(
|
|
121
121
|
"fake-key",
|
|
122
122
|
"x-ai/grok-4.20-beta",
|
|
@@ -128,12 +128,12 @@ describe("OpenRouter provider.only plumbing", () => {
|
|
|
128
128
|
},
|
|
129
129
|
});
|
|
130
130
|
expect(extras).toEqual({
|
|
131
|
-
reasoning: { enabled: true },
|
|
131
|
+
reasoning: { enabled: true, summary: "detailed" },
|
|
132
132
|
provider: { only: ["xAI"] },
|
|
133
133
|
});
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
test("disabled thinking keeps reasoning disabled
|
|
136
|
+
test("disabled thinking keeps reasoning disabled and omits summary", () => {
|
|
137
137
|
const provider = new ProbeOpenRouterProvider(
|
|
138
138
|
"fake-key",
|
|
139
139
|
"x-ai/grok-4.20-beta",
|
|
@@ -149,5 +149,53 @@ describe("OpenRouter provider.only plumbing", () => {
|
|
|
149
149
|
provider: { only: ["xAI"] },
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
|
+
|
|
153
|
+
test("nests effort under reasoning and maps `max` to xhigh", () => {
|
|
154
|
+
const provider = new ProbeOpenRouterProvider(
|
|
155
|
+
"fake-key",
|
|
156
|
+
"moonshotai/kimi-k2.6",
|
|
157
|
+
);
|
|
158
|
+
const extras = provider.probeExtras({
|
|
159
|
+
config: {
|
|
160
|
+
thinking: { enabled: true },
|
|
161
|
+
effort: "max",
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
expect(extras).toEqual({
|
|
165
|
+
reasoning: { enabled: true, effort: "xhigh", summary: "detailed" },
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("honors a per-call summary override", () => {
|
|
170
|
+
const provider = new ProbeOpenRouterProvider(
|
|
171
|
+
"fake-key",
|
|
172
|
+
"moonshotai/kimi-k2.6",
|
|
173
|
+
);
|
|
174
|
+
const extras = provider.probeExtras({
|
|
175
|
+
config: {
|
|
176
|
+
thinking: { enabled: true },
|
|
177
|
+
openrouter: { reasoning: { summary: "concise" } },
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
expect(extras).toEqual({
|
|
181
|
+
reasoning: { enabled: true, summary: "concise" },
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("ignores an invalid summary override and falls back to detailed", () => {
|
|
186
|
+
const provider = new ProbeOpenRouterProvider(
|
|
187
|
+
"fake-key",
|
|
188
|
+
"moonshotai/kimi-k2.6",
|
|
189
|
+
);
|
|
190
|
+
const extras = provider.probeExtras({
|
|
191
|
+
config: {
|
|
192
|
+
thinking: { enabled: true },
|
|
193
|
+
openrouter: { reasoning: { summary: "verbose" } },
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
expect(extras).toEqual({
|
|
197
|
+
reasoning: { enabled: true, summary: "detailed" },
|
|
198
|
+
});
|
|
199
|
+
});
|
|
152
200
|
});
|
|
153
201
|
});
|
|
@@ -5,7 +5,11 @@ import { OpenRouterProvider } from "../providers/openrouter/client.js";
|
|
|
5
5
|
import type { Message } from "../providers/types.js";
|
|
6
6
|
|
|
7
7
|
/** Build a minimal valid PNG header encoding the given dimensions. */
|
|
8
|
-
function makePngBase64(
|
|
8
|
+
function makePngBase64(
|
|
9
|
+
width: number,
|
|
10
|
+
height: number,
|
|
11
|
+
paddingBytes = 0,
|
|
12
|
+
): string {
|
|
9
13
|
const header = Buffer.alloc(24);
|
|
10
14
|
header[0] = 0x89;
|
|
11
15
|
header[1] = 0x50;
|
|
@@ -41,13 +45,13 @@ describe("OpenRouterProvider token estimation routing", () => {
|
|
|
41
45
|
expect(provider.tokenEstimationProvider).toBe("openrouter");
|
|
42
46
|
});
|
|
43
47
|
|
|
44
|
-
test("estimatePromptTokens applies
|
|
48
|
+
test("estimatePromptTokens applies dimension-based image scaling when routed via OpenRouter to Anthropic", () => {
|
|
45
49
|
const provider = new OpenRouterProvider(
|
|
46
50
|
"fake-key",
|
|
47
51
|
"anthropic/claude-opus-4-6",
|
|
48
52
|
);
|
|
49
53
|
// 1920x1080 screenshot with ~200 KB of pixel data → base64/4 would be ~65k
|
|
50
|
-
// tokens; dimension-based
|
|
54
|
+
// tokens; dimension-based rules land around 1.6k tokens.
|
|
51
55
|
const messages: Message[] = [
|
|
52
56
|
{
|
|
53
57
|
role: "user",
|
|
@@ -68,33 +72,38 @@ describe("OpenRouterProvider token estimation routing", () => {
|
|
|
68
72
|
providerName: provider.tokenEstimationProvider,
|
|
69
73
|
});
|
|
70
74
|
|
|
71
|
-
// Dimension-based estimate should be well under 5k; base64/4 would exceed 50k.
|
|
72
75
|
expect(estimated).toBeLessThan(5_000);
|
|
73
76
|
});
|
|
74
77
|
|
|
75
|
-
test("estimatePromptTokens
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
test("estimatePromptTokens applies dimension-based image scaling for non-Anthropic OpenRouter models", () => {
|
|
79
|
+
// A naive base64/4 estimate on a 1920x1080 screenshot (~200 KB) lands near
|
|
80
|
+
// 65k tokens and trips spurious compaction long before the real context
|
|
81
|
+
// window fills. Vision models on OpenRouter — both anthropic/* and
|
|
82
|
+
// non-Anthropic (Kimi K2.6, Grok, etc.) — must use the dimension-based
|
|
83
|
+
// formula.
|
|
84
|
+
for (const model of ["moonshotai/kimi-k2.6", "x-ai/grok-4.20-beta"]) {
|
|
85
|
+
const provider = new OpenRouterProvider("fake-key", model);
|
|
86
|
+
const messages: Message[] = [
|
|
87
|
+
{
|
|
88
|
+
role: "user",
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "image",
|
|
92
|
+
source: {
|
|
93
|
+
type: "base64",
|
|
94
|
+
media_type: "image/png",
|
|
95
|
+
data: makePngBase64(1920, 1080, 200_000),
|
|
96
|
+
},
|
|
87
97
|
},
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
];
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
];
|
|
92
101
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
102
|
+
const estimated = estimatePromptTokens(messages, "system", {
|
|
103
|
+
providerName: provider.tokenEstimationProvider,
|
|
104
|
+
});
|
|
96
105
|
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
expect(estimated).toBeLessThan(5_000);
|
|
107
|
+
}
|
|
99
108
|
});
|
|
100
109
|
});
|
|
@@ -117,8 +117,13 @@ describe("buildManagedBaseUrl", () => {
|
|
|
117
117
|
);
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
test("returns managed URL for fireworks", async () => {
|
|
121
|
+
expect(await buildManagedBaseUrl("fireworks")).toBe(
|
|
122
|
+
"https://platform.example.com/v1/runtime-proxy/fireworks",
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
120
126
|
test("returns undefined for non-managed providers", async () => {
|
|
121
|
-
expect(await buildManagedBaseUrl("fireworks")).toBeUndefined();
|
|
122
127
|
expect(await buildManagedBaseUrl("openrouter")).toBeUndefined();
|
|
123
128
|
expect(await buildManagedBaseUrl("ollama")).toBeUndefined();
|
|
124
129
|
});
|
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
unregisterPluginTools,
|
|
60
60
|
} from "../tools/registry.js";
|
|
61
61
|
import type {
|
|
62
|
-
|
|
62
|
+
LoadedPluginTool,
|
|
63
63
|
ToolContext,
|
|
64
64
|
ToolExecutionResult,
|
|
65
65
|
} from "../tools/types.js";
|
|
@@ -81,8 +81,8 @@ const fakeCtx: DaemonContext = {
|
|
|
81
81
|
|
|
82
82
|
function makeFakeTool(
|
|
83
83
|
name: string,
|
|
84
|
-
extras: Partial<
|
|
85
|
-
):
|
|
84
|
+
extras: Partial<LoadedPluginTool> = {},
|
|
85
|
+
): LoadedPluginTool {
|
|
86
86
|
return {
|
|
87
87
|
name,
|
|
88
88
|
description: `Fake ${name}`,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
type ToolResultTruncateResult,
|
|
47
47
|
type TurnContext,
|
|
48
48
|
} from "../plugins/types.js";
|
|
49
|
-
import type {
|
|
49
|
+
import type { LoadedPluginTool } from "../tools/types.js";
|
|
50
50
|
|
|
51
51
|
const sampleTrust: TrustContext = {
|
|
52
52
|
sourceChannel: "vellum",
|
|
@@ -207,7 +207,7 @@ describe("plugin core types", () => {
|
|
|
207
207
|
},
|
|
208
208
|
};
|
|
209
209
|
|
|
210
|
-
const sampleTool:
|
|
210
|
+
const sampleTool: LoadedPluginTool = {
|
|
211
211
|
name: "sample-tool",
|
|
212
212
|
description: "Sample plugin tool",
|
|
213
213
|
defaultRiskLevel: RiskLevel.Low,
|
|
@@ -19,6 +19,22 @@ function makeConfig(): AssistantConfig {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
describe("getVisibleProviderCatalog", () => {
|
|
22
|
+
test("hides openai-compatible endpoints by default", () => {
|
|
23
|
+
_setOverridesForTesting({});
|
|
24
|
+
|
|
25
|
+
const visible = getVisibleProviderCatalog(makeConfig());
|
|
26
|
+
|
|
27
|
+
expect(visible.find((p) => p.id === "openai-compatible")).toBeUndefined();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("shows openai-compatible endpoints when its flag is enabled", () => {
|
|
31
|
+
_setOverridesForTesting({ "openai-compatible-endpoints": true });
|
|
32
|
+
|
|
33
|
+
const visible = getVisibleProviderCatalog(makeConfig());
|
|
34
|
+
|
|
35
|
+
expect(visible.find((p) => p.id === "openai-compatible")).toBeDefined();
|
|
36
|
+
});
|
|
37
|
+
|
|
22
38
|
test("returns the full catalog when all feature flags are enabled", () => {
|
|
23
39
|
const allFlags: Record<string, boolean> = {};
|
|
24
40
|
for (const entry of PROVIDER_CATALOG) {
|
|
@@ -113,7 +113,7 @@ const DIRECT_OR_MANAGED_PROVIDER_KEYS: string[] = [
|
|
|
113
113
|
"fireworks",
|
|
114
114
|
"openrouter",
|
|
115
115
|
];
|
|
116
|
-
const MANAGED_FALLBACK_PROVIDERS: string[] = ["anthropic", "gemini", "openai"];
|
|
116
|
+
const MANAGED_FALLBACK_PROVIDERS: string[] = ["anthropic", "gemini", "openai", "fireworks"];
|
|
117
117
|
|
|
118
118
|
function enableManagedProxy() {
|
|
119
119
|
mockPlatformBaseUrl = PLATFORM_BASE;
|
|
@@ -209,20 +209,19 @@ describe("managed proxy integration — credential precedence", () => {
|
|
|
209
209
|
},
|
|
210
210
|
);
|
|
211
211
|
|
|
212
|
-
test("managed bootstrap registers anthropic, openai, and
|
|
212
|
+
test("managed bootstrap registers anthropic, openai, gemini, and fireworks", async () => {
|
|
213
213
|
enableManagedProxy();
|
|
214
214
|
mockProviderKeys = {};
|
|
215
215
|
await initializeProviders(makeProvidersConfig("anthropic", "test-model"));
|
|
216
216
|
expect(listProviders()).toEqual(
|
|
217
|
-
expect.arrayContaining(["anthropic", "openai", "gemini"]),
|
|
217
|
+
expect.arrayContaining(["anthropic", "openai", "gemini", "fireworks"]),
|
|
218
218
|
);
|
|
219
|
-
expect(listProviders()).toHaveLength(
|
|
219
|
+
expect(listProviders()).toHaveLength(4);
|
|
220
220
|
expect(getProviderRoutingSource("anthropic")).toBe("managed-proxy");
|
|
221
221
|
expect(getProviderRoutingSource("openai")).toBe("managed-proxy");
|
|
222
222
|
expect(getProviderRoutingSource("gemini")).toBe("managed-proxy");
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
223
|
+
expect(getProviderRoutingSource("fireworks")).toBe("managed-proxy");
|
|
224
|
+
expect(getProviderRoutingSource("openrouter")).toBeUndefined();
|
|
226
225
|
});
|
|
227
226
|
|
|
228
227
|
test("managed anthropic uses anthropic proxy path", async () => {
|
|
@@ -376,7 +375,7 @@ describe("managed proxy integration — credential precedence", () => {
|
|
|
376
375
|
});
|
|
377
376
|
|
|
378
377
|
describe("mixed: some user keys + managed fallback fills gaps", () => {
|
|
379
|
-
test("user key for anthropic routes direct and managed fallback fills openai and
|
|
378
|
+
test("user key for anthropic routes direct and managed fallback fills openai, gemini, and fireworks", async () => {
|
|
380
379
|
enableManagedProxy();
|
|
381
380
|
setUserKeysFor("anthropic");
|
|
382
381
|
await initializeProviders(makeProvidersConfig("anthropic", "test-model"));
|
|
@@ -387,13 +386,13 @@ describe("managed proxy integration — credential precedence", () => {
|
|
|
387
386
|
expect(getProviderRoutingSource("openai")).toBe("managed-proxy");
|
|
388
387
|
expect(registered).toContain("gemini");
|
|
389
388
|
expect(getProviderRoutingSource("gemini")).toBe("managed-proxy");
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
389
|
+
expect(registered).toContain("fireworks");
|
|
390
|
+
expect(getProviderRoutingSource("fireworks")).toBe("managed-proxy");
|
|
391
|
+
expect(registered).not.toContain("openrouter");
|
|
392
|
+
expect(getProviderRoutingSource("openrouter")).toBeUndefined();
|
|
394
393
|
});
|
|
395
394
|
|
|
396
|
-
test("user key for openai routes direct while anthropic and
|
|
395
|
+
test("user key for openai routes direct while anthropic, gemini, and fireworks still bootstrap via managed proxy", async () => {
|
|
397
396
|
enableManagedProxy();
|
|
398
397
|
setUserKeysFor("openai");
|
|
399
398
|
await initializeProviders(makeProvidersConfig("openai", "test-model"));
|
|
@@ -404,11 +403,10 @@ describe("managed proxy integration — credential precedence", () => {
|
|
|
404
403
|
expect(getProviderRoutingSource("anthropic")).toBe("managed-proxy");
|
|
405
404
|
expect(registered).toContain("gemini");
|
|
406
405
|
expect(getProviderRoutingSource("gemini")).toBe("managed-proxy");
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
406
|
+
expect(registered).toContain("fireworks");
|
|
407
|
+
expect(getProviderRoutingSource("fireworks")).toBe("managed-proxy");
|
|
408
|
+
expect(registered).not.toContain("openrouter");
|
|
409
|
+
expect(getProviderRoutingSource("openrouter")).toBeUndefined();
|
|
412
410
|
});
|
|
413
411
|
});
|
|
414
412
|
});
|
|
@@ -476,8 +474,8 @@ describe("config mode flip → provider reinit", () => {
|
|
|
476
474
|
});
|
|
477
475
|
|
|
478
476
|
describe("managed proxy integration — constants integrity", () => {
|
|
479
|
-
test("anthropic, openai, and
|
|
480
|
-
for (const provider of ["anthropic", "openai", "gemini"]) {
|
|
477
|
+
test("anthropic, openai, gemini, and fireworks have metadata with managed=true and a proxyPath", () => {
|
|
478
|
+
for (const provider of ["anthropic", "openai", "gemini", "fireworks"]) {
|
|
481
479
|
const meta = PLATFORM_PROVIDER_META[provider];
|
|
482
480
|
expect(meta).toBeDefined();
|
|
483
481
|
expect(meta.managed).toBe(true);
|
|
@@ -504,10 +502,14 @@ describe("managed proxy integration — constants integrity", () => {
|
|
|
504
502
|
);
|
|
505
503
|
});
|
|
506
504
|
|
|
507
|
-
test("fireworks
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
505
|
+
test("fireworks routes through fireworks proxy path", () => {
|
|
506
|
+
expect(PLATFORM_PROVIDER_META.fireworks.proxyPath).toBe(
|
|
507
|
+
"/v1/runtime-proxy/fireworks",
|
|
508
|
+
);
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
test("openrouter is not managed proxy capable", () => {
|
|
512
|
+
expect(PLATFORM_PROVIDER_META.openrouter.managed).toBe(false);
|
|
513
|
+
expect(PLATFORM_PROVIDER_META.openrouter.proxyPath).toBeUndefined();
|
|
512
514
|
});
|
|
513
515
|
});
|
|
@@ -12,7 +12,7 @@ let providerRefreshCalls = 0;
|
|
|
12
12
|
const PLATFORM_BASE_URL = "https://platform.example.com";
|
|
13
13
|
const ASSISTANT_API_KEY_PATH = credentialKey("vellum", "assistant_api_key");
|
|
14
14
|
const PLATFORM_BASE_URL_PATH = credentialKey("vellum", "platform_base_url");
|
|
15
|
-
const MANAGED_PROVIDERS = ["anthropic", "openai", "gemini"] as const;
|
|
15
|
+
const MANAGED_PROVIDERS = ["anthropic", "openai", "gemini", "fireworks"] as const;
|
|
16
16
|
|
|
17
17
|
let platformBaseUrlOverride: string | undefined;
|
|
18
18
|
|