@standardagents/builder 0.11.4 → 0.11.5
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/dist/built-in-routes.js +709 -6
- package/dist/built-in-routes.js.map +1 -1
- package/package.json +4 -4
package/dist/built-in-routes.js
CHANGED
|
@@ -20350,6 +20350,546 @@ async function fetchGenerationMetadata(apiKey, generationId, baseUrl = "https://
|
|
|
20350
20350
|
}
|
|
20351
20351
|
return null;
|
|
20352
20352
|
}
|
|
20353
|
+
function transformChatContentPart(part) {
|
|
20354
|
+
if (part.type === "text") {
|
|
20355
|
+
return { type: "text", text: part.text };
|
|
20356
|
+
}
|
|
20357
|
+
if (part.type === "image") {
|
|
20358
|
+
const data = part.data || "";
|
|
20359
|
+
const imageUrl = data.startsWith("data:") ? data : `data:${part.mediaType || "image/png"};base64,${data}`;
|
|
20360
|
+
return {
|
|
20361
|
+
type: "image_url",
|
|
20362
|
+
image_url: {
|
|
20363
|
+
url: imageUrl,
|
|
20364
|
+
detail: part.detail || "auto"
|
|
20365
|
+
}
|
|
20366
|
+
};
|
|
20367
|
+
}
|
|
20368
|
+
if (part.type === "image_url") {
|
|
20369
|
+
return {
|
|
20370
|
+
type: "image_url",
|
|
20371
|
+
image_url: {
|
|
20372
|
+
url: part.image_url?.url || "",
|
|
20373
|
+
detail: part.image_url?.detail || "auto"
|
|
20374
|
+
}
|
|
20375
|
+
};
|
|
20376
|
+
}
|
|
20377
|
+
return {
|
|
20378
|
+
type: "text",
|
|
20379
|
+
text: `[File: ${part.filename || "file"}]`
|
|
20380
|
+
};
|
|
20381
|
+
}
|
|
20382
|
+
function transformChatMessageContent(content) {
|
|
20383
|
+
if (typeof content === "string") {
|
|
20384
|
+
return content;
|
|
20385
|
+
}
|
|
20386
|
+
return content.map(transformChatContentPart);
|
|
20387
|
+
}
|
|
20388
|
+
function transformChatSystemMessage(msg) {
|
|
20389
|
+
return {
|
|
20390
|
+
role: "system",
|
|
20391
|
+
content: msg.content
|
|
20392
|
+
};
|
|
20393
|
+
}
|
|
20394
|
+
function transformChatUserMessage(msg) {
|
|
20395
|
+
return {
|
|
20396
|
+
role: "user",
|
|
20397
|
+
content: transformChatMessageContent(msg.content)
|
|
20398
|
+
};
|
|
20399
|
+
}
|
|
20400
|
+
function transformChatAssistantMessage(msg) {
|
|
20401
|
+
const message = {
|
|
20402
|
+
role: "assistant",
|
|
20403
|
+
content: msg.content || null
|
|
20404
|
+
};
|
|
20405
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
20406
|
+
message.tool_calls = msg.toolCalls.map((tc) => ({
|
|
20407
|
+
id: tc.id,
|
|
20408
|
+
type: "function",
|
|
20409
|
+
function: {
|
|
20410
|
+
name: tc.name,
|
|
20411
|
+
arguments: typeof tc.arguments === "string" ? tc.arguments : JSON.stringify(tc.arguments)
|
|
20412
|
+
}
|
|
20413
|
+
}));
|
|
20414
|
+
}
|
|
20415
|
+
return message;
|
|
20416
|
+
}
|
|
20417
|
+
function transformChatToolMessage(msg) {
|
|
20418
|
+
let output;
|
|
20419
|
+
if (typeof msg.content === "string") {
|
|
20420
|
+
output = msg.content;
|
|
20421
|
+
} else if ("type" in msg.content) {
|
|
20422
|
+
if (msg.content.type === "text") {
|
|
20423
|
+
output = msg.content.text;
|
|
20424
|
+
} else if (msg.content.type === "error") {
|
|
20425
|
+
output = `Error: ${msg.content.error}`;
|
|
20426
|
+
} else {
|
|
20427
|
+
output = JSON.stringify(msg.content);
|
|
20428
|
+
}
|
|
20429
|
+
} else {
|
|
20430
|
+
output = JSON.stringify(msg.content);
|
|
20431
|
+
}
|
|
20432
|
+
const imageAttachments = msg.attachments?.filter((a) => a.type === "image" && a.data) || [];
|
|
20433
|
+
const toolMessage = {
|
|
20434
|
+
role: "tool",
|
|
20435
|
+
tool_call_id: msg.toolCallId,
|
|
20436
|
+
content: output || (imageAttachments.length > 0 ? "Success" : "")
|
|
20437
|
+
};
|
|
20438
|
+
if (imageAttachments.length === 0) {
|
|
20439
|
+
return { toolMessage };
|
|
20440
|
+
}
|
|
20441
|
+
const imageContent = [];
|
|
20442
|
+
const toolName = msg.toolName || "the tool";
|
|
20443
|
+
const isSingle = imageAttachments.length === 1;
|
|
20444
|
+
const descriptor = isSingle ? "the file" : `${imageAttachments.length} files`;
|
|
20445
|
+
const verb = isSingle ? "is" : "are";
|
|
20446
|
+
imageContent.push({
|
|
20447
|
+
type: "text",
|
|
20448
|
+
text: `Here ${verb} ${descriptor} from ${toolName}:`
|
|
20449
|
+
});
|
|
20450
|
+
for (const attachment of imageAttachments) {
|
|
20451
|
+
const attachmentData = attachment.data || "";
|
|
20452
|
+
const imageData = attachmentData.startsWith("data:") ? attachmentData : `data:${attachment.mediaType || "image/png"};base64,${attachmentData}`;
|
|
20453
|
+
imageContent.push({
|
|
20454
|
+
type: "image_url",
|
|
20455
|
+
image_url: {
|
|
20456
|
+
url: imageData,
|
|
20457
|
+
detail: "auto"
|
|
20458
|
+
}
|
|
20459
|
+
});
|
|
20460
|
+
}
|
|
20461
|
+
const syntheticUserMessage = {
|
|
20462
|
+
role: "user",
|
|
20463
|
+
content: imageContent
|
|
20464
|
+
};
|
|
20465
|
+
return { toolMessage, syntheticUserMessage };
|
|
20466
|
+
}
|
|
20467
|
+
function transformChatMessages(messages) {
|
|
20468
|
+
const result = [];
|
|
20469
|
+
for (const msg of messages) {
|
|
20470
|
+
switch (msg.role) {
|
|
20471
|
+
case "system":
|
|
20472
|
+
result.push(transformChatSystemMessage(msg));
|
|
20473
|
+
break;
|
|
20474
|
+
case "user":
|
|
20475
|
+
result.push(transformChatUserMessage(msg));
|
|
20476
|
+
break;
|
|
20477
|
+
case "assistant":
|
|
20478
|
+
result.push(transformChatAssistantMessage(msg));
|
|
20479
|
+
break;
|
|
20480
|
+
case "tool": {
|
|
20481
|
+
const { toolMessage, syntheticUserMessage } = transformChatToolMessage(msg);
|
|
20482
|
+
result.push(toolMessage);
|
|
20483
|
+
if (syntheticUserMessage) {
|
|
20484
|
+
result.push(syntheticUserMessage);
|
|
20485
|
+
}
|
|
20486
|
+
break;
|
|
20487
|
+
}
|
|
20488
|
+
}
|
|
20489
|
+
}
|
|
20490
|
+
return result;
|
|
20491
|
+
}
|
|
20492
|
+
function transformChatTool(tool2) {
|
|
20493
|
+
const inputParams = tool2.function.parameters;
|
|
20494
|
+
let parameters;
|
|
20495
|
+
if (inputParams && typeof inputParams === "object") {
|
|
20496
|
+
parameters = {
|
|
20497
|
+
...inputParams,
|
|
20498
|
+
additionalProperties: false
|
|
20499
|
+
};
|
|
20500
|
+
} else {
|
|
20501
|
+
parameters = {
|
|
20502
|
+
type: "object",
|
|
20503
|
+
properties: {},
|
|
20504
|
+
required: [],
|
|
20505
|
+
additionalProperties: false
|
|
20506
|
+
};
|
|
20507
|
+
}
|
|
20508
|
+
return {
|
|
20509
|
+
type: "function",
|
|
20510
|
+
function: {
|
|
20511
|
+
name: tool2.function.name,
|
|
20512
|
+
description: tool2.function.description || void 0,
|
|
20513
|
+
parameters,
|
|
20514
|
+
strict: true
|
|
20515
|
+
}
|
|
20516
|
+
};
|
|
20517
|
+
}
|
|
20518
|
+
function transformChatTools(tools) {
|
|
20519
|
+
return tools.map(transformChatTool);
|
|
20520
|
+
}
|
|
20521
|
+
function transformChatToolChoice(choice) {
|
|
20522
|
+
if (choice === "auto") {
|
|
20523
|
+
return "auto";
|
|
20524
|
+
}
|
|
20525
|
+
if (choice === "none") {
|
|
20526
|
+
return "none";
|
|
20527
|
+
}
|
|
20528
|
+
if (choice === "required") {
|
|
20529
|
+
return "required";
|
|
20530
|
+
}
|
|
20531
|
+
if (typeof choice === "object" && "name" in choice) {
|
|
20532
|
+
return { type: "function", function: { name: choice.name } };
|
|
20533
|
+
}
|
|
20534
|
+
return void 0;
|
|
20535
|
+
}
|
|
20536
|
+
function mapChatFinishReason(finishReason) {
|
|
20537
|
+
switch (finishReason) {
|
|
20538
|
+
case "stop":
|
|
20539
|
+
return "stop";
|
|
20540
|
+
case "tool_calls":
|
|
20541
|
+
return "tool_calls";
|
|
20542
|
+
case "length":
|
|
20543
|
+
return "length";
|
|
20544
|
+
case "content_filter":
|
|
20545
|
+
return "content_filter";
|
|
20546
|
+
case "error":
|
|
20547
|
+
return "error";
|
|
20548
|
+
default:
|
|
20549
|
+
return "stop";
|
|
20550
|
+
}
|
|
20551
|
+
}
|
|
20552
|
+
function extractChatToolCalls(toolCalls) {
|
|
20553
|
+
if (!toolCalls || toolCalls.length === 0) {
|
|
20554
|
+
return void 0;
|
|
20555
|
+
}
|
|
20556
|
+
return toolCalls.map((tc) => {
|
|
20557
|
+
let parsedArgs = {};
|
|
20558
|
+
try {
|
|
20559
|
+
parsedArgs = tc.function.arguments ? JSON.parse(tc.function.arguments) : {};
|
|
20560
|
+
} catch {
|
|
20561
|
+
}
|
|
20562
|
+
return {
|
|
20563
|
+
id: tc.id,
|
|
20564
|
+
name: tc.function.name,
|
|
20565
|
+
arguments: parsedArgs
|
|
20566
|
+
};
|
|
20567
|
+
});
|
|
20568
|
+
}
|
|
20569
|
+
function transformChatUsage(usage, actualProvider) {
|
|
20570
|
+
if (!usage) {
|
|
20571
|
+
return {
|
|
20572
|
+
promptTokens: 0,
|
|
20573
|
+
completionTokens: 0,
|
|
20574
|
+
totalTokens: 0
|
|
20575
|
+
};
|
|
20576
|
+
}
|
|
20577
|
+
const promptTokens = usage.native_tokens_prompt || usage.prompt_tokens || 0;
|
|
20578
|
+
const completionTokens = usage.native_tokens_completion || usage.completion_tokens || 0;
|
|
20579
|
+
const totalTokens = usage.total_tokens || promptTokens + completionTokens;
|
|
20580
|
+
return {
|
|
20581
|
+
promptTokens,
|
|
20582
|
+
completionTokens,
|
|
20583
|
+
totalTokens,
|
|
20584
|
+
reasoningTokens: usage.completion_tokens_details?.reasoning_tokens,
|
|
20585
|
+
cachedTokens: usage.prompt_tokens_details?.cached_tokens,
|
|
20586
|
+
cost: usage.cost,
|
|
20587
|
+
provider: actualProvider
|
|
20588
|
+
};
|
|
20589
|
+
}
|
|
20590
|
+
function extractImageFromUrl(url, index) {
|
|
20591
|
+
if (url.startsWith("data:")) {
|
|
20592
|
+
const match2 = url.match(/^data:([^;]+);base64,(.+)$/);
|
|
20593
|
+
if (match2) {
|
|
20594
|
+
return {
|
|
20595
|
+
id: `image_${index}`,
|
|
20596
|
+
data: match2[2],
|
|
20597
|
+
// base64 data without prefix
|
|
20598
|
+
mediaType: match2[1]
|
|
20599
|
+
};
|
|
20600
|
+
}
|
|
20601
|
+
return {
|
|
20602
|
+
id: `image_${index}`,
|
|
20603
|
+
data: url,
|
|
20604
|
+
mediaType: "image/png"
|
|
20605
|
+
};
|
|
20606
|
+
}
|
|
20607
|
+
return {
|
|
20608
|
+
id: `image_${index}`,
|
|
20609
|
+
data: url,
|
|
20610
|
+
mediaType: "image/png"
|
|
20611
|
+
// Default; actual type unknown without fetching
|
|
20612
|
+
};
|
|
20613
|
+
}
|
|
20614
|
+
function extractChatImages(images) {
|
|
20615
|
+
if (!images || images.length === 0) {
|
|
20616
|
+
return void 0;
|
|
20617
|
+
}
|
|
20618
|
+
return images.map((img, index) => extractImageFromUrl(img.image_url.url, index));
|
|
20619
|
+
}
|
|
20620
|
+
function transformChatResponse(response) {
|
|
20621
|
+
const choice = response.choices?.[0];
|
|
20622
|
+
const message = choice?.message;
|
|
20623
|
+
const content = message?.content || null;
|
|
20624
|
+
const toolCalls = extractChatToolCalls(message?.tool_calls);
|
|
20625
|
+
const images = extractChatImages(message?.images);
|
|
20626
|
+
const actualProvider = response.model?.split("/")[0] || void 0;
|
|
20627
|
+
return {
|
|
20628
|
+
content,
|
|
20629
|
+
toolCalls,
|
|
20630
|
+
images,
|
|
20631
|
+
finishReason: mapChatFinishReason(choice?.finish_reason),
|
|
20632
|
+
usage: transformChatUsage(response.usage, actualProvider),
|
|
20633
|
+
metadata: {
|
|
20634
|
+
model: response.model,
|
|
20635
|
+
provider: "openrouter",
|
|
20636
|
+
actualProvider,
|
|
20637
|
+
requestId: response.id
|
|
20638
|
+
}
|
|
20639
|
+
};
|
|
20640
|
+
}
|
|
20641
|
+
function createChatStreamState() {
|
|
20642
|
+
return {
|
|
20643
|
+
content: "",
|
|
20644
|
+
toolCalls: /* @__PURE__ */ new Map(),
|
|
20645
|
+
images: [],
|
|
20646
|
+
reasoningContent: "",
|
|
20647
|
+
hasContent: false,
|
|
20648
|
+
hasReasoning: false,
|
|
20649
|
+
finishReason: null
|
|
20650
|
+
};
|
|
20651
|
+
}
|
|
20652
|
+
function processChatStreamChunk(chunk, state) {
|
|
20653
|
+
const chunks = [];
|
|
20654
|
+
const choice = chunk.choices?.[0];
|
|
20655
|
+
const delta = choice?.delta;
|
|
20656
|
+
if (!delta && !choice?.finish_reason && !chunk.usage) {
|
|
20657
|
+
return chunks;
|
|
20658
|
+
}
|
|
20659
|
+
if (delta?.content) {
|
|
20660
|
+
state.hasContent = true;
|
|
20661
|
+
state.content += delta.content;
|
|
20662
|
+
chunks.push({ type: "content-delta", delta: delta.content });
|
|
20663
|
+
}
|
|
20664
|
+
if (delta?.reasoning_content) {
|
|
20665
|
+
state.hasReasoning = true;
|
|
20666
|
+
state.reasoningContent += delta.reasoning_content;
|
|
20667
|
+
chunks.push({ type: "reasoning-delta", delta: delta.reasoning_content });
|
|
20668
|
+
}
|
|
20669
|
+
if (delta?.tool_calls) {
|
|
20670
|
+
for (const tc of delta.tool_calls) {
|
|
20671
|
+
const index = tc.index;
|
|
20672
|
+
const existing = state.toolCalls.get(index);
|
|
20673
|
+
if (tc.id && tc.function?.name) {
|
|
20674
|
+
state.toolCalls.set(index, {
|
|
20675
|
+
id: tc.id,
|
|
20676
|
+
name: tc.function.name,
|
|
20677
|
+
arguments: tc.function.arguments || ""
|
|
20678
|
+
});
|
|
20679
|
+
chunks.push({
|
|
20680
|
+
type: "tool-call-start",
|
|
20681
|
+
id: tc.id,
|
|
20682
|
+
name: tc.function.name
|
|
20683
|
+
});
|
|
20684
|
+
} else if (existing && tc.function?.arguments) {
|
|
20685
|
+
existing.arguments += tc.function.arguments;
|
|
20686
|
+
chunks.push({
|
|
20687
|
+
type: "tool-call-delta",
|
|
20688
|
+
id: existing.id,
|
|
20689
|
+
argumentsDelta: tc.function.arguments
|
|
20690
|
+
});
|
|
20691
|
+
}
|
|
20692
|
+
}
|
|
20693
|
+
}
|
|
20694
|
+
if (delta?.images && delta.images.length > 0) {
|
|
20695
|
+
for (const img of delta.images) {
|
|
20696
|
+
const index = state.images.length;
|
|
20697
|
+
const providerImage = extractImageFromUrl(img.image_url.url, index);
|
|
20698
|
+
state.images.push(providerImage);
|
|
20699
|
+
chunks.push({
|
|
20700
|
+
type: "image-done",
|
|
20701
|
+
index,
|
|
20702
|
+
image: providerImage
|
|
20703
|
+
});
|
|
20704
|
+
}
|
|
20705
|
+
}
|
|
20706
|
+
if (choice?.finish_reason) {
|
|
20707
|
+
state.finishReason = choice.finish_reason;
|
|
20708
|
+
if (state.hasContent) {
|
|
20709
|
+
chunks.push({ type: "content-done" });
|
|
20710
|
+
}
|
|
20711
|
+
if (state.hasReasoning) {
|
|
20712
|
+
chunks.push({ type: "reasoning-done" });
|
|
20713
|
+
}
|
|
20714
|
+
for (const tc of state.toolCalls.values()) {
|
|
20715
|
+
let parsedArgs = {};
|
|
20716
|
+
try {
|
|
20717
|
+
parsedArgs = tc.arguments ? JSON.parse(tc.arguments) : {};
|
|
20718
|
+
} catch {
|
|
20719
|
+
}
|
|
20720
|
+
chunks.push({
|
|
20721
|
+
type: "tool-call-done",
|
|
20722
|
+
id: tc.id,
|
|
20723
|
+
arguments: parsedArgs
|
|
20724
|
+
});
|
|
20725
|
+
}
|
|
20726
|
+
}
|
|
20727
|
+
if (chunk.usage) {
|
|
20728
|
+
const actualProvider = chunk.model?.split("/")[0] || void 0;
|
|
20729
|
+
chunks.push({
|
|
20730
|
+
type: "finish",
|
|
20731
|
+
finishReason: mapChatFinishReason(state.finishReason),
|
|
20732
|
+
usage: transformChatUsage(chunk.usage, actualProvider),
|
|
20733
|
+
responseId: chunk.id
|
|
20734
|
+
});
|
|
20735
|
+
}
|
|
20736
|
+
return chunks;
|
|
20737
|
+
}
|
|
20738
|
+
function parseChatStreamEvent(jsonStr) {
|
|
20739
|
+
try {
|
|
20740
|
+
return JSON.parse(jsonStr);
|
|
20741
|
+
} catch {
|
|
20742
|
+
return null;
|
|
20743
|
+
}
|
|
20744
|
+
}
|
|
20745
|
+
async function* parseChatSSEStream(response, state) {
|
|
20746
|
+
const reader = response.body?.getReader();
|
|
20747
|
+
if (!reader) {
|
|
20748
|
+
throw new Error("No response body");
|
|
20749
|
+
}
|
|
20750
|
+
const decoder = new TextDecoder();
|
|
20751
|
+
let buffer = "";
|
|
20752
|
+
try {
|
|
20753
|
+
while (true) {
|
|
20754
|
+
const { done, value } = await reader.read();
|
|
20755
|
+
if (done) break;
|
|
20756
|
+
buffer += decoder.decode(value, { stream: true });
|
|
20757
|
+
const lines = buffer.split("\n");
|
|
20758
|
+
buffer = lines.pop() || "";
|
|
20759
|
+
for (const line of lines) {
|
|
20760
|
+
const trimmed = line.trim();
|
|
20761
|
+
if (!trimmed || trimmed.startsWith(":")) continue;
|
|
20762
|
+
if (trimmed.startsWith("data: ")) {
|
|
20763
|
+
const data = trimmed.slice(6);
|
|
20764
|
+
if (data === "[DONE]") continue;
|
|
20765
|
+
const chunk = parseChatStreamEvent(data);
|
|
20766
|
+
if (chunk) {
|
|
20767
|
+
const providerChunks = processChatStreamChunk(chunk, state);
|
|
20768
|
+
for (const c of providerChunks) {
|
|
20769
|
+
yield c;
|
|
20770
|
+
}
|
|
20771
|
+
}
|
|
20772
|
+
}
|
|
20773
|
+
}
|
|
20774
|
+
}
|
|
20775
|
+
if (buffer.trim()) {
|
|
20776
|
+
const trimmed = buffer.trim();
|
|
20777
|
+
if (trimmed.startsWith("data: ")) {
|
|
20778
|
+
const data = trimmed.slice(6);
|
|
20779
|
+
if (data !== "[DONE]") {
|
|
20780
|
+
const chunk = parseChatStreamEvent(data);
|
|
20781
|
+
if (chunk) {
|
|
20782
|
+
const providerChunks = processChatStreamChunk(chunk, state);
|
|
20783
|
+
for (const c of providerChunks) {
|
|
20784
|
+
yield c;
|
|
20785
|
+
}
|
|
20786
|
+
}
|
|
20787
|
+
}
|
|
20788
|
+
}
|
|
20789
|
+
}
|
|
20790
|
+
if (state.finishReason && !state.toolCalls.size) {
|
|
20791
|
+
}
|
|
20792
|
+
} finally {
|
|
20793
|
+
reader.releaseLock();
|
|
20794
|
+
}
|
|
20795
|
+
}
|
|
20796
|
+
function buildChatParams(request) {
|
|
20797
|
+
const messages = transformChatMessages(request.messages);
|
|
20798
|
+
const params = {
|
|
20799
|
+
model: request.model,
|
|
20800
|
+
messages
|
|
20801
|
+
};
|
|
20802
|
+
if (request.tools && request.tools.length > 0) {
|
|
20803
|
+
params.tools = transformChatTools(request.tools);
|
|
20804
|
+
const toolChoice = transformChatToolChoice(request.toolChoice);
|
|
20805
|
+
if (toolChoice !== void 0) {
|
|
20806
|
+
params.tool_choice = toolChoice;
|
|
20807
|
+
}
|
|
20808
|
+
if (request.parallelToolCalls !== void 0) {
|
|
20809
|
+
params.parallel_tool_calls = request.parallelToolCalls;
|
|
20810
|
+
}
|
|
20811
|
+
}
|
|
20812
|
+
if (request.maxOutputTokens !== void 0) {
|
|
20813
|
+
params.max_tokens = request.maxOutputTokens;
|
|
20814
|
+
}
|
|
20815
|
+
if (request.temperature !== void 0) {
|
|
20816
|
+
params.temperature = request.temperature;
|
|
20817
|
+
}
|
|
20818
|
+
if (request.topP !== void 0) {
|
|
20819
|
+
params.top_p = request.topP;
|
|
20820
|
+
}
|
|
20821
|
+
if (request.reasoning?.level !== void 0) {
|
|
20822
|
+
const effortMap = {
|
|
20823
|
+
10: "minimal",
|
|
20824
|
+
33: "low",
|
|
20825
|
+
66: "medium",
|
|
20826
|
+
100: "high"
|
|
20827
|
+
};
|
|
20828
|
+
const effort = effortMap[request.reasoning.level];
|
|
20829
|
+
if (effort) {
|
|
20830
|
+
params.reasoning = { effort };
|
|
20831
|
+
}
|
|
20832
|
+
}
|
|
20833
|
+
if (request.responseFormat) {
|
|
20834
|
+
if (request.responseFormat.type === "json") {
|
|
20835
|
+
if (request.responseFormat.schema) {
|
|
20836
|
+
params.response_format = {
|
|
20837
|
+
type: "json_schema",
|
|
20838
|
+
json_schema: {
|
|
20839
|
+
name: "response",
|
|
20840
|
+
schema: request.responseFormat.schema,
|
|
20841
|
+
strict: true
|
|
20842
|
+
}
|
|
20843
|
+
};
|
|
20844
|
+
} else {
|
|
20845
|
+
params.response_format = { type: "json_object" };
|
|
20846
|
+
}
|
|
20847
|
+
}
|
|
20848
|
+
}
|
|
20849
|
+
if (request.providerOptions) {
|
|
20850
|
+
const { _metadata, ...safeOptions } = request.providerOptions;
|
|
20851
|
+
Object.assign(params, safeOptions);
|
|
20852
|
+
}
|
|
20853
|
+
return params;
|
|
20854
|
+
}
|
|
20855
|
+
function createChatErrorChunk(error, code) {
|
|
20856
|
+
return { type: "error", error, code };
|
|
20857
|
+
}
|
|
20858
|
+
function isBase64Like22(str) {
|
|
20859
|
+
if (str.startsWith("data:")) return true;
|
|
20860
|
+
if (str.length > 200) {
|
|
20861
|
+
const base64Pattern = /^[A-Za-z0-9+/]+=*$/;
|
|
20862
|
+
return base64Pattern.test(str.substring(0, 200));
|
|
20863
|
+
}
|
|
20864
|
+
return false;
|
|
20865
|
+
}
|
|
20866
|
+
function truncateBase64String22(str, maxLength = 50) {
|
|
20867
|
+
if (str.length <= maxLength) return str;
|
|
20868
|
+
const preview = str.substring(0, maxLength);
|
|
20869
|
+
return `${preview}...[truncated, ${str.length.toLocaleString()} chars]`;
|
|
20870
|
+
}
|
|
20871
|
+
function truncateChatBase64(obj, maxLength = 50) {
|
|
20872
|
+
if (obj === null || obj === void 0) {
|
|
20873
|
+
return obj;
|
|
20874
|
+
}
|
|
20875
|
+
if (typeof obj === "string") {
|
|
20876
|
+
if (isBase64Like22(obj)) {
|
|
20877
|
+
return truncateBase64String22(obj, maxLength);
|
|
20878
|
+
}
|
|
20879
|
+
return obj;
|
|
20880
|
+
}
|
|
20881
|
+
if (Array.isArray(obj)) {
|
|
20882
|
+
return obj.map((item) => truncateChatBase64(item, maxLength));
|
|
20883
|
+
}
|
|
20884
|
+
if (typeof obj === "object") {
|
|
20885
|
+
const result = {};
|
|
20886
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
20887
|
+
result[key] = truncateChatBase64(value, maxLength);
|
|
20888
|
+
}
|
|
20889
|
+
return result;
|
|
20890
|
+
}
|
|
20891
|
+
return obj;
|
|
20892
|
+
}
|
|
20353
20893
|
function svgToDataUri2(svg) {
|
|
20354
20894
|
const encoded = encodeURIComponent(svg).replace(/'/g, "%27").replace(/"/g, "%22");
|
|
20355
20895
|
return `data:image/svg+xml,${encoded}`;
|
|
@@ -20481,6 +21021,17 @@ var init_dist2 = __esm({
|
|
|
20481
21021
|
constructor(config) {
|
|
20482
21022
|
this.config = config;
|
|
20483
21023
|
}
|
|
21024
|
+
/**
|
|
21025
|
+
* Determine which API to use for a request.
|
|
21026
|
+
* Checks request-level providerOptions first, then falls back to config.
|
|
21027
|
+
* Defaults to Chat Completions (stable API).
|
|
21028
|
+
*/
|
|
21029
|
+
getApiMode(request) {
|
|
21030
|
+
if (request?.providerOptions?.useResponsesApi === true) {
|
|
21031
|
+
return "responses";
|
|
21032
|
+
}
|
|
21033
|
+
return "chat";
|
|
21034
|
+
}
|
|
20484
21035
|
async getClient() {
|
|
20485
21036
|
if (!this.client) {
|
|
20486
21037
|
const { OpenRouter: OpenRouter2 } = await Promise.resolve().then(() => (init_esm(), esm_exports));
|
|
@@ -20617,6 +21168,53 @@ var init_dist2 = __esm({
|
|
|
20617
21168
|
// Generation Methods
|
|
20618
21169
|
// ============================================================================
|
|
20619
21170
|
async generate(request) {
|
|
21171
|
+
const apiMode = this.getApiMode(request);
|
|
21172
|
+
if (apiMode === "responses") {
|
|
21173
|
+
return this.generateWithResponses(request);
|
|
21174
|
+
}
|
|
21175
|
+
return this.generateWithChat(request);
|
|
21176
|
+
}
|
|
21177
|
+
/**
|
|
21178
|
+
* Generate using the Chat Completions API (default).
|
|
21179
|
+
*/
|
|
21180
|
+
async generateWithChat(request) {
|
|
21181
|
+
const apiKey = this.config.apiKey;
|
|
21182
|
+
const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
|
|
21183
|
+
try {
|
|
21184
|
+
const params = buildChatParams(request);
|
|
21185
|
+
if (this.config.providers && this.config.providers.length > 0) {
|
|
21186
|
+
params.provider = { only: this.config.providers };
|
|
21187
|
+
}
|
|
21188
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
21189
|
+
method: "POST",
|
|
21190
|
+
headers: {
|
|
21191
|
+
"Content-Type": "application/json",
|
|
21192
|
+
"Authorization": `Bearer ${apiKey}`
|
|
21193
|
+
},
|
|
21194
|
+
body: JSON.stringify(params),
|
|
21195
|
+
signal: request.signal
|
|
21196
|
+
});
|
|
21197
|
+
if (!response.ok) {
|
|
21198
|
+
const errorText = await response.text();
|
|
21199
|
+
let errorMessage = `OpenRouter API error: ${response.status}`;
|
|
21200
|
+
try {
|
|
21201
|
+
const errorJson = JSON.parse(errorText);
|
|
21202
|
+
errorMessage = errorJson.error?.message || errorJson.message || errorMessage;
|
|
21203
|
+
} catch {
|
|
21204
|
+
errorMessage = errorText || errorMessage;
|
|
21205
|
+
}
|
|
21206
|
+
throw new ProviderError(errorMessage, "invalid_request", response.status);
|
|
21207
|
+
}
|
|
21208
|
+
const data = await response.json();
|
|
21209
|
+
return transformChatResponse(data);
|
|
21210
|
+
} catch (error) {
|
|
21211
|
+
throw this.toProviderError(error);
|
|
21212
|
+
}
|
|
21213
|
+
}
|
|
21214
|
+
/**
|
|
21215
|
+
* Generate using the Responses API (beta).
|
|
21216
|
+
*/
|
|
21217
|
+
async generateWithResponses(request) {
|
|
20620
21218
|
const client = await this.getClient();
|
|
20621
21219
|
try {
|
|
20622
21220
|
const params = buildCreateParams2(request);
|
|
@@ -20633,6 +21231,87 @@ var init_dist2 = __esm({
|
|
|
20633
21231
|
}
|
|
20634
21232
|
}
|
|
20635
21233
|
async stream(request) {
|
|
21234
|
+
const apiMode = this.getApiMode(request);
|
|
21235
|
+
if (apiMode === "responses") {
|
|
21236
|
+
return this.streamWithResponses(request);
|
|
21237
|
+
}
|
|
21238
|
+
return this.streamWithChat(request);
|
|
21239
|
+
}
|
|
21240
|
+
/**
|
|
21241
|
+
* Stream using the Chat Completions API (default).
|
|
21242
|
+
*/
|
|
21243
|
+
async streamWithChat(request) {
|
|
21244
|
+
const self = this;
|
|
21245
|
+
const apiKey = this.config.apiKey;
|
|
21246
|
+
const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
|
|
21247
|
+
try {
|
|
21248
|
+
const params = buildChatParams(request);
|
|
21249
|
+
if (this.config.providers && this.config.providers.length > 0) {
|
|
21250
|
+
params.provider = { only: this.config.providers };
|
|
21251
|
+
}
|
|
21252
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
21253
|
+
method: "POST",
|
|
21254
|
+
headers: {
|
|
21255
|
+
"Content-Type": "application/json",
|
|
21256
|
+
"Authorization": `Bearer ${apiKey}`
|
|
21257
|
+
},
|
|
21258
|
+
body: JSON.stringify({
|
|
21259
|
+
...params,
|
|
21260
|
+
stream: true,
|
|
21261
|
+
stream_options: { include_usage: true }
|
|
21262
|
+
}),
|
|
21263
|
+
signal: request.signal
|
|
21264
|
+
});
|
|
21265
|
+
if (!response.ok) {
|
|
21266
|
+
const errorText = await response.text();
|
|
21267
|
+
let errorMessage = `OpenRouter API error: ${response.status}`;
|
|
21268
|
+
try {
|
|
21269
|
+
const errorJson = JSON.parse(errorText);
|
|
21270
|
+
errorMessage = errorJson.error?.message || errorJson.message || errorMessage;
|
|
21271
|
+
} catch {
|
|
21272
|
+
errorMessage = errorText || errorMessage;
|
|
21273
|
+
}
|
|
21274
|
+
throw new ProviderError(errorMessage, "invalid_request", response.status);
|
|
21275
|
+
}
|
|
21276
|
+
return {
|
|
21277
|
+
async *[Symbol.asyncIterator]() {
|
|
21278
|
+
const state = createChatStreamState();
|
|
21279
|
+
let finishChunk = null;
|
|
21280
|
+
let responseId = null;
|
|
21281
|
+
try {
|
|
21282
|
+
for await (const chunk of parseChatSSEStream(response, state)) {
|
|
21283
|
+
if (chunk.type === "finish") {
|
|
21284
|
+
finishChunk = chunk;
|
|
21285
|
+
responseId = chunk.responseId || null;
|
|
21286
|
+
} else {
|
|
21287
|
+
yield chunk;
|
|
21288
|
+
}
|
|
21289
|
+
}
|
|
21290
|
+
if (finishChunk) {
|
|
21291
|
+
const finishWithMeta = {
|
|
21292
|
+
...finishChunk,
|
|
21293
|
+
_asyncMetadata: responseId ? {
|
|
21294
|
+
generationId: responseId,
|
|
21295
|
+
apiKey,
|
|
21296
|
+
baseUrl
|
|
21297
|
+
} : void 0
|
|
21298
|
+
};
|
|
21299
|
+
yield finishWithMeta;
|
|
21300
|
+
}
|
|
21301
|
+
} catch (error) {
|
|
21302
|
+
const providerError = self.toProviderError(error);
|
|
21303
|
+
yield createChatErrorChunk(providerError.message, providerError.code);
|
|
21304
|
+
}
|
|
21305
|
+
}
|
|
21306
|
+
};
|
|
21307
|
+
} catch (error) {
|
|
21308
|
+
throw this.toProviderError(error);
|
|
21309
|
+
}
|
|
21310
|
+
}
|
|
21311
|
+
/**
|
|
21312
|
+
* Stream using the Responses API (beta).
|
|
21313
|
+
*/
|
|
21314
|
+
async streamWithResponses(request) {
|
|
20636
21315
|
const self = this;
|
|
20637
21316
|
const apiKey = this.config.apiKey;
|
|
20638
21317
|
const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
|
|
@@ -20765,19 +21444,33 @@ var init_dist2 = __esm({
|
|
|
20765
21444
|
// Inspection
|
|
20766
21445
|
// ============================================================================
|
|
20767
21446
|
/**
|
|
20768
|
-
* Transform a ProviderRequest to
|
|
21447
|
+
* Transform a ProviderRequest to the appropriate API format for inspection.
|
|
20769
21448
|
* Returns the exact request body that would be sent to OpenRouter, with base64 data truncated.
|
|
20770
21449
|
*/
|
|
20771
21450
|
async inspectRequest(request) {
|
|
20772
|
-
const
|
|
21451
|
+
const apiMode = this.getApiMode(request);
|
|
21452
|
+
if (apiMode === "responses") {
|
|
21453
|
+
const params2 = buildCreateParams2(request);
|
|
21454
|
+
if (this.config.providers && this.config.providers.length > 0) {
|
|
21455
|
+
params2.provider = { only: this.config.providers };
|
|
21456
|
+
}
|
|
21457
|
+
return {
|
|
21458
|
+
body: truncateBase642(params2),
|
|
21459
|
+
messagesPath: "input",
|
|
21460
|
+
metadata: {
|
|
21461
|
+
endpoint: "https://openrouter.ai/api/v1/responses"
|
|
21462
|
+
}
|
|
21463
|
+
};
|
|
21464
|
+
}
|
|
21465
|
+
const params = buildChatParams(request);
|
|
20773
21466
|
if (this.config.providers && this.config.providers.length > 0) {
|
|
20774
21467
|
params.provider = { only: this.config.providers };
|
|
20775
21468
|
}
|
|
20776
21469
|
return {
|
|
20777
|
-
body:
|
|
20778
|
-
messagesPath: "
|
|
21470
|
+
body: truncateChatBase64(params),
|
|
21471
|
+
messagesPath: "messages",
|
|
20779
21472
|
metadata: {
|
|
20780
|
-
endpoint: "https://openrouter.ai/api/v1/
|
|
21473
|
+
endpoint: "https://openrouter.ai/api/v1/chat/completions"
|
|
20781
21474
|
}
|
|
20782
21475
|
};
|
|
20783
21476
|
}
|
|
@@ -20846,7 +21539,17 @@ var init_dist2 = __esm({
|
|
|
20846
21539
|
}).passthrough();
|
|
20847
21540
|
openrouterProviderOptions = z.object({
|
|
20848
21541
|
/** Provider routing configuration */
|
|
20849
|
-
provider: providerRoutingSchema.optional()
|
|
21542
|
+
provider: providerRoutingSchema.optional(),
|
|
21543
|
+
/**
|
|
21544
|
+
* Use OpenRouter's Responses API (beta) instead of the Chat Completions API.
|
|
21545
|
+
*
|
|
21546
|
+
* By default, the provider uses the stable Chat Completions API.
|
|
21547
|
+
* Set this to true to use the Responses API which has some additional
|
|
21548
|
+
* features but may be less stable.
|
|
21549
|
+
*
|
|
21550
|
+
* @default false
|
|
21551
|
+
*/
|
|
21552
|
+
useResponsesApi: z.boolean().optional()
|
|
20850
21553
|
}).passthrough();
|
|
20851
21554
|
openrouter = Object.assign(
|
|
20852
21555
|
(config) => new OpenRouterProvider(config),
|