@umituz/web-ai 1.0.11 → 1.2.0
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/README.md +29 -3
- package/dist/{cancellation-error-_39nYWwz.d.cts → cancellation-error-BWb59Wkj.d.cts} +1 -1
- package/dist/{cancellation-error-hYcE9AS9.d.ts → cancellation-error-D9LETLCD.d.ts} +1 -1
- package/dist/chat/index.cjs +1 -0
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.js +1 -0
- package/dist/chat/index.js.map +1 -1
- package/dist/content/index.cjs +622 -8
- package/dist/content/index.cjs.map +1 -1
- package/dist/content/index.d.cts +2 -2
- package/dist/content/index.d.ts +2 -2
- package/dist/content/index.js +622 -8
- package/dist/content/index.js.map +1 -1
- package/dist/context-manager-CuZz0vnC.d.cts +104 -0
- package/dist/context-manager-CuZz0vnC.d.ts +104 -0
- package/dist/core/index.cjs +147 -10
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +91 -73
- package/dist/core/index.d.ts +91 -73
- package/dist/core/index.js +141 -11
- package/dist/core/index.js.map +1 -1
- package/dist/{create-ai-D-oEWzf9.d.ts → create-ai-Cq3HkJxd.d.ts} +61 -1
- package/dist/{create-ai-DRysRImc.d.cts → create-ai-DDyTVzef.d.cts} +61 -1
- package/dist/hooks/index.cjs +747 -15
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +57 -4
- package/dist/hooks/index.d.ts +57 -4
- package/dist/hooks/index.js +746 -16
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +1180 -242
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +1140 -243
- package/dist/index.js.map +1 -1
- package/dist/providers/index.cjs +1212 -362
- package/dist/providers/index.cjs.map +1 -1
- package/dist/providers/index.d.cts +422 -10
- package/dist/providers/index.d.ts +422 -10
- package/dist/providers/index.js +1179 -363
- package/dist/providers/index.js.map +1 -1
- package/dist/remote-chat-client-LrNlew4n.d.cts +70 -0
- package/dist/remote-chat-client-LrNlew4n.d.ts +70 -0
- package/dist/{requestQueue-D89wx91Q.d.cts → requestQueue--h2uZ-Q3.d.cts} +1 -1
- package/dist/{requestQueue-AP6n_bRH.d.ts → requestQueue-BGeCy4Fd.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/tool-call-accumulator-C7KhaXZA.d.cts +0 -69
- package/dist/tool-call-accumulator-C7KhaXZA.d.ts +0 -69
package/dist/providers/index.cjs
CHANGED
|
@@ -1110,7 +1110,7 @@ var AnthropicProvider = class {
|
|
|
1110
1110
|
);
|
|
1111
1111
|
}
|
|
1112
1112
|
const structuredPrompt = new StructuredPromptBuilder(
|
|
1113
|
-
messages[lastUserIndex]
|
|
1113
|
+
messages[lastUserIndex]?.content ?? ""
|
|
1114
1114
|
).withSchema(request.schema).build();
|
|
1115
1115
|
messages[lastUserIndex] = { role: "user", content: structuredPrompt };
|
|
1116
1116
|
const wireRequest = new AnthropicRequestBuilder(model).withRequest({ ...request, messages }).withEffort(this.config.effort).build();
|
|
@@ -1190,7 +1190,8 @@ function mapAnthropicUsage(usage) {
|
|
|
1190
1190
|
}
|
|
1191
1191
|
function findLastIndex(items, predicate) {
|
|
1192
1192
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
1193
|
-
|
|
1193
|
+
const item = items[i];
|
|
1194
|
+
if (item !== void 0 && predicate(item)) return i;
|
|
1194
1195
|
}
|
|
1195
1196
|
return -1;
|
|
1196
1197
|
}
|
|
@@ -1513,6 +1514,26 @@ function validateApiKey(apiKey, rule = DEFAULT_API_KEY_RULE) {
|
|
|
1513
1514
|
return { valid: true };
|
|
1514
1515
|
}
|
|
1515
1516
|
|
|
1517
|
+
// src/core/utils/failover.ts
|
|
1518
|
+
var TRANSIENT_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
1519
|
+
"capacity",
|
|
1520
|
+
"rate_limited",
|
|
1521
|
+
"timeout",
|
|
1522
|
+
"network"
|
|
1523
|
+
]);
|
|
1524
|
+
function isTransientError(err) {
|
|
1525
|
+
if (!err || typeof err !== "object") return false;
|
|
1526
|
+
const candidate = err;
|
|
1527
|
+
if (candidate.code && TRANSIENT_ERROR_CODES.has(candidate.code)) return true;
|
|
1528
|
+
if (candidate.type && TRANSIENT_ERROR_CODES.has(candidate.type)) return true;
|
|
1529
|
+
if (candidate.status === 429 || candidate.status === 503 || candidate.status === 504) return true;
|
|
1530
|
+
return false;
|
|
1531
|
+
}
|
|
1532
|
+
function canFailover(err, streamedChars) {
|
|
1533
|
+
if (!isTransientError(err)) return false;
|
|
1534
|
+
return streamedChars === 0;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1516
1537
|
// src/providers/groq/groq.constants.ts
|
|
1517
1538
|
var GROQ_MODELS = {
|
|
1518
1539
|
LLAMA_3_1_8B_INSTANT: "llama-3.1-8b-instant",
|
|
@@ -2066,7 +2087,7 @@ var GroqProvider = class {
|
|
|
2066
2087
|
);
|
|
2067
2088
|
}
|
|
2068
2089
|
const structuredPrompt = new StructuredPromptBuilder(
|
|
2069
|
-
messages[lastUserIndex]
|
|
2090
|
+
messages[lastUserIndex]?.content ?? ""
|
|
2070
2091
|
).withSchema(request.schema).build();
|
|
2071
2092
|
messages[lastUserIndex] = { role: "user", content: structuredPrompt };
|
|
2072
2093
|
const wireRequest = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(this.generationConfig(request, STRUCTURED_TEMPERATURE)).withJsonResponse(true).build();
|
|
@@ -2163,7 +2184,8 @@ function createGroqProvider(config) {
|
|
|
2163
2184
|
}
|
|
2164
2185
|
function findLastIndex2(items, predicate) {
|
|
2165
2186
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
2166
|
-
|
|
2187
|
+
const item = items[i];
|
|
2188
|
+
if (item !== void 0 && predicate(item)) return i;
|
|
2167
2189
|
}
|
|
2168
2190
|
return -1;
|
|
2169
2191
|
}
|
|
@@ -2313,7 +2335,7 @@ var GeminiProvider = class extends BaseProvider {
|
|
|
2313
2335
|
}
|
|
2314
2336
|
messages[lastUserIndex] = {
|
|
2315
2337
|
role: "user",
|
|
2316
|
-
content: new StructuredPromptBuilder(messages[lastUserIndex]
|
|
2338
|
+
content: new StructuredPromptBuilder(messages[lastUserIndex]?.content ?? "").withSchema(request.schema).build()
|
|
2317
2339
|
};
|
|
2318
2340
|
const result = await this.generate({ ...request, messages, temperature: 0.1 });
|
|
2319
2341
|
return { value: this.jsonParser.parse(result.text), result };
|
|
@@ -2419,7 +2441,8 @@ function mapGeminiFinishReason(reason) {
|
|
|
2419
2441
|
}
|
|
2420
2442
|
function findLastIndex3(items, predicate) {
|
|
2421
2443
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
2422
|
-
|
|
2444
|
+
const item = items[i];
|
|
2445
|
+
if (item !== void 0 && predicate(item)) return i;
|
|
2423
2446
|
}
|
|
2424
2447
|
return -1;
|
|
2425
2448
|
}
|
|
@@ -3515,190 +3538,748 @@ function createPrunaProvider(config) {
|
|
|
3515
3538
|
return new PrunaProvider(config);
|
|
3516
3539
|
}
|
|
3517
3540
|
|
|
3518
|
-
// src/
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3541
|
+
// src/core/sse/tool-call-accumulator.ts
|
|
3542
|
+
var ToolCallAccumulator = class {
|
|
3543
|
+
slots = /* @__PURE__ */ new Map();
|
|
3544
|
+
push(delta) {
|
|
3545
|
+
const index = delta.index ?? 0;
|
|
3546
|
+
const slot = this.slots.get(index) ?? { id: "", name: "", args: "" };
|
|
3547
|
+
if (delta.id) slot.id = delta.id;
|
|
3548
|
+
if (delta.function?.name) slot.name = delta.function.name;
|
|
3549
|
+
if (delta.function?.arguments) slot.args += delta.function.arguments;
|
|
3550
|
+
this.slots.set(index, slot);
|
|
3527
3551
|
}
|
|
3528
|
-
|
|
3529
|
-
|
|
3552
|
+
finish() {
|
|
3553
|
+
return Array.from(this.slots.entries()).sort(([a], [b]) => a - b).map(([, slot]) => ({
|
|
3554
|
+
id: slot.id,
|
|
3555
|
+
name: slot.name,
|
|
3556
|
+
arguments: slot.args
|
|
3557
|
+
})).filter((call) => call.id.length > 0 || call.name.length > 0);
|
|
3530
3558
|
}
|
|
3531
|
-
|
|
3532
|
-
|
|
3559
|
+
};
|
|
3560
|
+
|
|
3561
|
+
// src/providers/adapters/openai-compatible.adapter.ts
|
|
3562
|
+
function toWireMessage(message) {
|
|
3563
|
+
if (message.role === "tool") {
|
|
3564
|
+
return { role: "tool", content: message.content, tool_call_id: message.toolCallId ?? "" };
|
|
3533
3565
|
}
|
|
3534
|
-
if (
|
|
3535
|
-
|
|
3566
|
+
if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
|
|
3567
|
+
return {
|
|
3568
|
+
role: "assistant",
|
|
3569
|
+
content: message.content,
|
|
3570
|
+
tool_calls: message.toolCalls.map((call) => ({
|
|
3571
|
+
id: call.id,
|
|
3572
|
+
type: "function",
|
|
3573
|
+
function: { name: call.name, arguments: call.arguments }
|
|
3574
|
+
}))
|
|
3575
|
+
};
|
|
3536
3576
|
}
|
|
3537
|
-
if (
|
|
3538
|
-
|
|
3577
|
+
if (message.role === "user") return { role: "user", content: message.content };
|
|
3578
|
+
return { role: message.role, content: message.content };
|
|
3579
|
+
}
|
|
3580
|
+
function mergeImages(messages, images) {
|
|
3581
|
+
if (images.length === 0) return [...messages];
|
|
3582
|
+
const parts = images.map((image) => ({
|
|
3583
|
+
type: "image_url",
|
|
3584
|
+
image_url: { url: `data:${image.mimeType};base64,${image.dataBase64}` }
|
|
3585
|
+
}));
|
|
3586
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
3587
|
+
const message = messages[index];
|
|
3588
|
+
if (!message || message.role !== "user") continue;
|
|
3589
|
+
const textParts = typeof message.content === "string" ? message.content.length > 0 ? [{ type: "text", text: message.content }] : [] : message.content;
|
|
3590
|
+
return [
|
|
3591
|
+
...messages.slice(0, index),
|
|
3592
|
+
{ role: "user", content: [...textParts, ...parts] },
|
|
3593
|
+
...messages.slice(index + 1)
|
|
3594
|
+
];
|
|
3539
3595
|
}
|
|
3540
|
-
return
|
|
3596
|
+
return [...messages, { role: "user", content: [...parts] }];
|
|
3541
3597
|
}
|
|
3542
|
-
|
|
3543
|
-
// src/providers/groq/groq-messages.ts
|
|
3544
|
-
var createUserMessage = (content) => ({
|
|
3545
|
-
role: "user",
|
|
3546
|
-
content
|
|
3547
|
-
});
|
|
3548
|
-
var createAssistantMessage = (content) => ({
|
|
3549
|
-
role: "assistant",
|
|
3550
|
-
content
|
|
3551
|
-
});
|
|
3552
|
-
var createSystemMessage = (content) => ({
|
|
3553
|
-
role: "system",
|
|
3554
|
-
content
|
|
3555
|
-
});
|
|
3556
|
-
var createMessage = (role, content) => ({
|
|
3557
|
-
role,
|
|
3558
|
-
content
|
|
3559
|
-
});
|
|
3560
|
-
var promptToMessages = (prompt) => [
|
|
3561
|
-
createUserMessage(prompt)
|
|
3562
|
-
];
|
|
3563
|
-
var extractTextFromMessages = (messages) => messages.map((m) => m.content).join("\n\n");
|
|
3564
|
-
var formatMessagesForDisplay = (messages) => messages.map((m) => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n---\n\n");
|
|
3565
|
-
|
|
3566
|
-
// src/providers/groq/groq-structured-json.ts
|
|
3567
|
-
async function requestStructuredJson(client, request) {
|
|
3568
|
-
const chatRequest = {
|
|
3569
|
-
model: request.model,
|
|
3570
|
-
messages: [createUserMessage(request.instructions)],
|
|
3571
|
-
temperature: request.temperature,
|
|
3572
|
-
max_tokens: request.maxTokens,
|
|
3573
|
-
response_format: { type: "json_object" },
|
|
3574
|
-
...request.reasoningEffort !== void 0 ? { reasoning_effort: request.reasoningEffort } : {}
|
|
3575
|
-
};
|
|
3576
|
-
const response = await client.postChatCompletion(chatRequest);
|
|
3577
|
-
const content = response.choices[0]?.message?.content ?? "";
|
|
3578
|
-
const candidate = extractJsonCandidate(content);
|
|
3598
|
+
async function extractErrorDetail(response) {
|
|
3579
3599
|
try {
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
"model response contained no parsable json object",
|
|
3585
|
-
err instanceof Error ? err : void 0
|
|
3586
|
-
);
|
|
3600
|
+
const body = await response.json();
|
|
3601
|
+
return body.error;
|
|
3602
|
+
} catch {
|
|
3603
|
+
return void 0;
|
|
3587
3604
|
}
|
|
3588
3605
|
}
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
cache;
|
|
3600
|
-
defaultModel;
|
|
3601
|
-
id = "groq-text-generation";
|
|
3602
|
-
name = "Groq Text Generation";
|
|
3603
|
-
capabilities = ["text"];
|
|
3604
|
-
jsonParser = new JsonResponseParser();
|
|
3605
|
-
generateCompletion(prompt, options = {}) {
|
|
3606
|
-
const model = options.model ?? this.defaultModel;
|
|
3607
|
-
return this.executeWithCache(
|
|
3608
|
-
{
|
|
3609
|
-
type: CACHE_KEY_TYPE_COMPLETION,
|
|
3610
|
-
model,
|
|
3611
|
-
prompt,
|
|
3612
|
-
config: options.generationConfig
|
|
3613
|
-
},
|
|
3614
|
-
async () => {
|
|
3615
|
-
const request = GroqChatRequestBuilder.for(model).withMessages([createUserMessage(prompt)]).withConfig(options.generationConfig).build();
|
|
3616
|
-
const response = await this.httpClient.postChatCompletion(request);
|
|
3617
|
-
return this.extractContent(response.choices[0]?.message?.content);
|
|
3618
|
-
}
|
|
3619
|
-
);
|
|
3620
|
-
}
|
|
3621
|
-
generateChatCompletion(messages, options = {}) {
|
|
3622
|
-
const model = options.model ?? this.defaultModel;
|
|
3623
|
-
return this.executeWithCache(
|
|
3624
|
-
{
|
|
3625
|
-
type: CACHE_KEY_TYPE_CHAT,
|
|
3626
|
-
model,
|
|
3627
|
-
messages: [...messages],
|
|
3628
|
-
config: options.generationConfig
|
|
3629
|
-
},
|
|
3630
|
-
async () => {
|
|
3631
|
-
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).build();
|
|
3632
|
-
const response = await this.httpClient.postChatCompletion(request);
|
|
3633
|
-
return this.extractContent(response.choices[0]?.message?.content);
|
|
3634
|
-
}
|
|
3635
|
-
);
|
|
3636
|
-
}
|
|
3637
|
-
generateStructured(promptOrRequest, options) {
|
|
3638
|
-
if (typeof promptOrRequest === "string") {
|
|
3639
|
-
const model2 = options?.model ?? this.defaultModel;
|
|
3640
|
-
const jsonPrompt = StructuredPromptBuilder.for(promptOrRequest).withSchema(options?.schema).build();
|
|
3641
|
-
const request = GroqChatRequestBuilder.for(model2).withMessages([createUserMessage(jsonPrompt)]).withConfig({
|
|
3642
|
-
...options?.generationConfig,
|
|
3643
|
-
temperature: STRUCTURED_OUTPUT_TEMPERATURE
|
|
3644
|
-
}).build();
|
|
3645
|
-
return this.httpClient.postChatCompletion(request).then((response) => {
|
|
3646
|
-
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
3647
|
-
return this.jsonParser.parse(content);
|
|
3648
|
-
});
|
|
3606
|
+
async function* parseSseEvent(rawEvent, toolCallAccumulator) {
|
|
3607
|
+
for (const line of rawEvent.split("\n")) {
|
|
3608
|
+
if (!line.startsWith("data:")) continue;
|
|
3609
|
+
const payload = line.slice(5).trim();
|
|
3610
|
+
if (payload.length === 0 || payload === "[DONE]") continue;
|
|
3611
|
+
let chunk;
|
|
3612
|
+
try {
|
|
3613
|
+
chunk = JSON.parse(payload);
|
|
3614
|
+
} catch {
|
|
3615
|
+
continue;
|
|
3649
3616
|
}
|
|
3650
|
-
const
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
const messages = [];
|
|
3654
|
-
if (req.systemPrompt) {
|
|
3655
|
-
messages.push({ role: "system", content: req.systemPrompt });
|
|
3617
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
3618
|
+
if (delta?.reasoning) {
|
|
3619
|
+
yield { type: "delta", channel: "reasoning", text: delta.reasoning };
|
|
3656
3620
|
}
|
|
3657
|
-
|
|
3658
|
-
|
|
3621
|
+
if (delta?.content) {
|
|
3622
|
+
yield { type: "delta", channel: "answer", text: delta.content };
|
|
3659
3623
|
}
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
const structuredPrompt = StructuredPromptBuilder.for(lastMsg.content).withSchema(schemaObj).build();
|
|
3663
|
-
messages[messages.length - 1] = { ...lastMsg, content: structuredPrompt };
|
|
3624
|
+
if (delta?.tool_calls) {
|
|
3625
|
+
for (const toolCallDelta of delta.tool_calls) toolCallAccumulator.push(toolCallDelta);
|
|
3664
3626
|
}
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
text: content,
|
|
3674
|
-
model: response.model,
|
|
3675
|
-
providerId: this.id,
|
|
3676
|
-
finishReason: response.choices[0]?.finish_reason ?? "stop",
|
|
3677
|
-
usage: response.usage ? {
|
|
3678
|
-
inputTokens: response.usage.prompt_tokens,
|
|
3679
|
-
outputTokens: response.usage.completion_tokens,
|
|
3680
|
-
totalTokens: response.usage.total_tokens
|
|
3681
|
-
} : void 0
|
|
3627
|
+
if (chunk.usage) {
|
|
3628
|
+
yield {
|
|
3629
|
+
type: "usage",
|
|
3630
|
+
usage: {
|
|
3631
|
+
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
3632
|
+
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
3633
|
+
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens
|
|
3634
|
+
}
|
|
3682
3635
|
};
|
|
3683
|
-
|
|
3684
|
-
});
|
|
3685
|
-
}
|
|
3686
|
-
streamCompletion(prompt, callbacks, options = {}) {
|
|
3687
|
-
return this.streamChatCompletion([createUserMessage(prompt)], callbacks, options);
|
|
3636
|
+
}
|
|
3688
3637
|
}
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3638
|
+
}
|
|
3639
|
+
async function* parseSseStream(body) {
|
|
3640
|
+
const reader = body.getReader();
|
|
3641
|
+
const decoder = new TextDecoder();
|
|
3642
|
+
const toolCallAccumulator = new ToolCallAccumulator();
|
|
3643
|
+
let buffer = "";
|
|
3644
|
+
try {
|
|
3645
|
+
while (true) {
|
|
3646
|
+
const { done, value } = await reader.read();
|
|
3647
|
+
if (done) break;
|
|
3648
|
+
buffer += decoder.decode(value, { stream: true });
|
|
3649
|
+
let separator = buffer.indexOf("\n\n");
|
|
3650
|
+
while (separator !== -1) {
|
|
3651
|
+
const rawEvent = buffer.slice(0, separator);
|
|
3652
|
+
buffer = buffer.slice(separator + 2);
|
|
3653
|
+
separator = buffer.indexOf("\n\n");
|
|
3654
|
+
yield* parseSseEvent(rawEvent, toolCallAccumulator);
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
} catch (err) {
|
|
3658
|
+
throw errorFromUnknown(err);
|
|
3659
|
+
} finally {
|
|
3660
|
+
reader.releaseLock();
|
|
3661
|
+
}
|
|
3662
|
+
const calls = toolCallAccumulator.finish();
|
|
3663
|
+
if (calls.length > 0) yield { type: "tool_calls", calls };
|
|
3664
|
+
}
|
|
3665
|
+
function createOpenAiCompatibleAdapter(config) {
|
|
3666
|
+
if (!config.baseUrl && !config.endpointUrl) {
|
|
3667
|
+
throw new Error("createOpenAiCompatibleAdapter requires baseUrl or endpointUrl");
|
|
3668
|
+
}
|
|
3669
|
+
const endpoint = config.endpointUrl ?? `${config.baseUrl}/chat/completions`;
|
|
3670
|
+
return {
|
|
3671
|
+
async *stream(req) {
|
|
3672
|
+
const timeout = AbortSignal.timeout(config.timeoutMs);
|
|
3673
|
+
const signal = req.signal ? AbortSignal.any([req.signal, timeout]) : timeout;
|
|
3674
|
+
let response;
|
|
3675
|
+
try {
|
|
3676
|
+
response = await fetch(endpoint, {
|
|
3677
|
+
method: "POST",
|
|
3678
|
+
headers: {
|
|
3679
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
3680
|
+
"Content-Type": "application/json"
|
|
3681
|
+
},
|
|
3682
|
+
body: JSON.stringify({
|
|
3683
|
+
model: req.externalModelId,
|
|
3684
|
+
messages: mergeImages(req.messages.map(toWireMessage), req.images ?? []),
|
|
3685
|
+
temperature: req.temperature,
|
|
3686
|
+
max_completion_tokens: req.maxOutputTokens,
|
|
3687
|
+
top_p: req.topP,
|
|
3688
|
+
stream: true,
|
|
3689
|
+
stream_options: { include_usage: true },
|
|
3690
|
+
...req.tools && req.tools.length > 0 ? {
|
|
3691
|
+
tools: req.tools.map((tool) => ({ type: "function", function: tool })),
|
|
3692
|
+
tool_choice: "auto"
|
|
3693
|
+
} : {}
|
|
3694
|
+
}),
|
|
3695
|
+
signal
|
|
3696
|
+
});
|
|
3697
|
+
} catch (err) {
|
|
3698
|
+
throw errorFromUnknown(err);
|
|
3699
|
+
}
|
|
3700
|
+
if (!response.ok || !response.body) {
|
|
3701
|
+
const detail = await extractErrorDetail(response);
|
|
3702
|
+
throw errorFromStatus(response.status, detail?.message, detail);
|
|
3703
|
+
}
|
|
3704
|
+
yield* parseSseStream(response.body);
|
|
3705
|
+
}
|
|
3706
|
+
};
|
|
3707
|
+
}
|
|
3708
|
+
|
|
3709
|
+
// src/providers/openai-compatible/openai-compatible.provider.ts
|
|
3710
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
3711
|
+
var STRUCTURED_TEMPERATURE2 = 0.1;
|
|
3712
|
+
var OpenAiCompatibleProvider = class {
|
|
3713
|
+
constructor(config) {
|
|
3714
|
+
this.config = config;
|
|
3715
|
+
if (!config.baseUrl && !config.endpointUrl) {
|
|
3716
|
+
throw new AIError(
|
|
3717
|
+
"MISSING_CONFIG" /* MISSING_CONFIG */,
|
|
3718
|
+
"OpenAiCompatibleProvider requires baseUrl or endpointUrl"
|
|
3719
|
+
);
|
|
3720
|
+
}
|
|
3721
|
+
this.adapter = createOpenAiCompatibleAdapter({
|
|
3722
|
+
baseUrl: config.baseUrl,
|
|
3723
|
+
endpointUrl: config.endpointUrl,
|
|
3724
|
+
apiKey: config.apiKey,
|
|
3725
|
+
timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS
|
|
3726
|
+
});
|
|
3727
|
+
this.tiers = mergeTierOverrides(
|
|
3728
|
+
config.model ? { fast: config.model, balanced: config.model, powerful: config.model } : {},
|
|
3729
|
+
config.models
|
|
3730
|
+
);
|
|
3731
|
+
}
|
|
3732
|
+
config;
|
|
3733
|
+
id = "openai-compatible";
|
|
3734
|
+
name = "OpenAI-compatible";
|
|
3735
|
+
capabilities = ["text"];
|
|
3736
|
+
adapter;
|
|
3737
|
+
tiers;
|
|
3738
|
+
jsonParser = new JsonResponseParser();
|
|
3739
|
+
resolveModel(tier) {
|
|
3740
|
+
return resolveModel(this.tiers, tier, this.id);
|
|
3741
|
+
}
|
|
3742
|
+
async healthCheck() {
|
|
3743
|
+
return this.config.apiKey && (this.config.baseUrl || this.config.endpointUrl) ? "healthy" : "unavailable";
|
|
3744
|
+
}
|
|
3745
|
+
async estimateCost() {
|
|
3746
|
+
return 0;
|
|
3747
|
+
}
|
|
3748
|
+
async generate(request) {
|
|
3749
|
+
const model = this.modelFor(request);
|
|
3750
|
+
const outcome = await this.consume(this.toAdapterRequest(model, request));
|
|
3751
|
+
if (outcome.text.length === 0) {
|
|
3752
|
+
throw this.noContentError(model);
|
|
3753
|
+
}
|
|
3754
|
+
return {
|
|
3755
|
+
text: outcome.text,
|
|
3756
|
+
usage: outcome.usage,
|
|
3757
|
+
model,
|
|
3758
|
+
providerId: this.id,
|
|
3759
|
+
finishReason: "stop"
|
|
3760
|
+
};
|
|
3761
|
+
}
|
|
3762
|
+
async generateStructured(request) {
|
|
3763
|
+
const model = this.modelFor(request);
|
|
3764
|
+
const messages = this.toWireMessages(request.messages, request.systemPrompt);
|
|
3765
|
+
const lastUserIndex = findLastIndex4(messages, (m) => m.role === "user");
|
|
3766
|
+
if (lastUserIndex === -1) {
|
|
3767
|
+
throw new AIError(
|
|
3768
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
3769
|
+
"generateStructured requires at least one user message"
|
|
3770
|
+
);
|
|
3771
|
+
}
|
|
3772
|
+
const structuredPrompt = new StructuredPromptBuilder(
|
|
3773
|
+
messages[lastUserIndex]?.content ?? ""
|
|
3774
|
+
).withSchema(request.schema).build();
|
|
3775
|
+
messages[lastUserIndex] = { role: "user", content: structuredPrompt };
|
|
3776
|
+
const outcome = await this.consume({
|
|
3777
|
+
externalModelId: model,
|
|
3778
|
+
messages,
|
|
3779
|
+
temperature: STRUCTURED_TEMPERATURE2,
|
|
3780
|
+
signal: request.signal
|
|
3781
|
+
});
|
|
3782
|
+
if (outcome.text.length === 0) {
|
|
3783
|
+
throw this.noContentError(model);
|
|
3784
|
+
}
|
|
3785
|
+
return {
|
|
3786
|
+
value: this.jsonParser.parse(outcome.text),
|
|
3787
|
+
result: {
|
|
3788
|
+
text: outcome.text,
|
|
3789
|
+
usage: outcome.usage,
|
|
3790
|
+
model,
|
|
3791
|
+
providerId: this.id,
|
|
3792
|
+
finishReason: "stop"
|
|
3793
|
+
}
|
|
3794
|
+
};
|
|
3795
|
+
}
|
|
3796
|
+
async stream(request, callbacks) {
|
|
3797
|
+
const model = this.modelFor(request);
|
|
3798
|
+
try {
|
|
3799
|
+
const outcome = await this.consume(this.toAdapterRequest(model, request), (text) => {
|
|
3800
|
+
callbacks.onChunk?.(text);
|
|
3801
|
+
});
|
|
3802
|
+
if (outcome.text.length === 0) {
|
|
3803
|
+
throw this.noContentError(model);
|
|
3804
|
+
}
|
|
3805
|
+
const result = {
|
|
3806
|
+
text: outcome.text,
|
|
3807
|
+
usage: outcome.usage,
|
|
3808
|
+
model,
|
|
3809
|
+
providerId: this.id,
|
|
3810
|
+
finishReason: "stop"
|
|
3811
|
+
};
|
|
3812
|
+
callbacks.onComplete?.(result);
|
|
3813
|
+
return result;
|
|
3814
|
+
} catch (error) {
|
|
3815
|
+
callbacks.onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
3816
|
+
throw error;
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
/* ---------- internals ---------- */
|
|
3820
|
+
/** Drain one adapter stream to its end. `onChunk`, when given, sees answer
|
|
3821
|
+
* deltas as they arrive — the streaming surface is this same drain. */
|
|
3822
|
+
async consume(req, onChunk) {
|
|
3823
|
+
let text = "";
|
|
3824
|
+
let usage;
|
|
3825
|
+
for await (const event of this.adapter.stream(req)) {
|
|
3826
|
+
if (event.type === "delta" && event.channel === "answer") {
|
|
3827
|
+
text += event.text;
|
|
3828
|
+
onChunk?.(event.text);
|
|
3829
|
+
} else if (event.type === "usage") {
|
|
3830
|
+
usage = event.usage;
|
|
3831
|
+
}
|
|
3832
|
+
}
|
|
3833
|
+
return { text, usage };
|
|
3834
|
+
}
|
|
3835
|
+
modelFor(request) {
|
|
3836
|
+
return request.model ?? this.resolveModel(request.tier ?? "balanced");
|
|
3837
|
+
}
|
|
3838
|
+
noContentError(model) {
|
|
3839
|
+
return new AIError(
|
|
3840
|
+
"SERVER_ERROR" /* SERVER_ERROR */,
|
|
3841
|
+
"No content generated from the OpenAI-compatible endpoint",
|
|
3842
|
+
void 0,
|
|
3843
|
+
{ model }
|
|
3844
|
+
);
|
|
3845
|
+
}
|
|
3846
|
+
toAdapterRequest(model, request) {
|
|
3847
|
+
return {
|
|
3848
|
+
externalModelId: model,
|
|
3849
|
+
messages: this.toWireMessages(request.messages, request.systemPrompt),
|
|
3850
|
+
...request.temperature !== void 0 ? { temperature: request.temperature } : {},
|
|
3851
|
+
...request.maxTokens !== void 0 ? { maxOutputTokens: request.maxTokens } : {},
|
|
3852
|
+
...request.topP !== void 0 ? { topP: request.topP } : {},
|
|
3853
|
+
...request.signal ? { signal: request.signal } : {}
|
|
3854
|
+
};
|
|
3855
|
+
}
|
|
3856
|
+
/** Neutral messages onto the adapter's shape; systemPrompt becomes the
|
|
3857
|
+
* leading system message (in-band, the OpenAI way). */
|
|
3858
|
+
toWireMessages(messages, systemPrompt) {
|
|
3859
|
+
const wire = [];
|
|
3860
|
+
if (systemPrompt && systemPrompt.length > 0) {
|
|
3861
|
+
wire.push({ role: "system", content: systemPrompt });
|
|
3862
|
+
}
|
|
3863
|
+
for (const message of messages) {
|
|
3864
|
+
wire.push({ role: message.role, content: message.content });
|
|
3865
|
+
}
|
|
3866
|
+
return wire;
|
|
3867
|
+
}
|
|
3868
|
+
};
|
|
3869
|
+
function createOpenAiCompatibleProvider(config) {
|
|
3870
|
+
return new OpenAiCompatibleProvider(config);
|
|
3871
|
+
}
|
|
3872
|
+
function findLastIndex4(items, predicate) {
|
|
3873
|
+
for (let index = items.length - 1; index >= 0; index -= 1) {
|
|
3874
|
+
if (predicate(items[index])) return index;
|
|
3875
|
+
}
|
|
3876
|
+
return -1;
|
|
3877
|
+
}
|
|
3878
|
+
|
|
3879
|
+
// src/providers/workers-ai/workers-ai.entities.ts
|
|
3880
|
+
var WorkersAIError = class extends Error {
|
|
3881
|
+
status;
|
|
3882
|
+
constructor(message, status) {
|
|
3883
|
+
super(message);
|
|
3884
|
+
this.name = "WorkersAIError";
|
|
3885
|
+
this.status = status;
|
|
3886
|
+
}
|
|
3887
|
+
};
|
|
3888
|
+
|
|
3889
|
+
// src/providers/workers-ai/workers-ai.text.ts
|
|
3890
|
+
var WORKERS_AI_LLM_MODEL = "@cf/meta/llama-3.3-70b-instruct-fp8-fast";
|
|
3891
|
+
var WORKERS_AI_TEXT_TIMEOUT_MS = 25e3;
|
|
3892
|
+
function workersAIConfigured(env) {
|
|
3893
|
+
return typeof env.AI?.run === "function";
|
|
3894
|
+
}
|
|
3895
|
+
function requireAi(env) {
|
|
3896
|
+
const ai = env.AI;
|
|
3897
|
+
if (!ai || typeof ai.run !== "function") throw new WorkersAIError("Workers AI is not configured");
|
|
3898
|
+
return ai;
|
|
3899
|
+
}
|
|
3900
|
+
async function runWorkersAIText(env, messages, opts = {}) {
|
|
3901
|
+
const ai = requireAi(env);
|
|
3902
|
+
const model = opts.model ?? WORKERS_AI_LLM_MODEL;
|
|
3903
|
+
let result;
|
|
3904
|
+
try {
|
|
3905
|
+
result = await Promise.race([
|
|
3906
|
+
ai.run(model, {
|
|
3907
|
+
messages: messages.map((m) => ({ role: m.role, content: m.content })),
|
|
3908
|
+
max_tokens: opts.maxTokens ?? 900,
|
|
3909
|
+
temperature: opts.temperature ?? 0.7
|
|
3910
|
+
}),
|
|
3911
|
+
new Promise(
|
|
3912
|
+
(_, reject) => setTimeout(() => reject(new WorkersAIError("Workers AI timed out")), WORKERS_AI_TEXT_TIMEOUT_MS)
|
|
3913
|
+
)
|
|
3914
|
+
]);
|
|
3915
|
+
} catch (err) {
|
|
3916
|
+
throw err instanceof WorkersAIError ? err : new WorkersAIError(err instanceof Error ? err.message : "Workers AI request failed");
|
|
3917
|
+
}
|
|
3918
|
+
const response = result ?? {};
|
|
3919
|
+
let text = response.response;
|
|
3920
|
+
if (typeof text !== "string" || text.length === 0) {
|
|
3921
|
+
text = response.choices?.[0]?.message?.content;
|
|
3922
|
+
}
|
|
3923
|
+
if (typeof text !== "string" || text.length === 0) {
|
|
3924
|
+
throw new WorkersAIError("Workers AI returned no text");
|
|
3925
|
+
}
|
|
3926
|
+
return text;
|
|
3927
|
+
}
|
|
3928
|
+
async function* streamWorkersAIText(env, messages, opts = {}) {
|
|
3929
|
+
const ai = requireAi(env);
|
|
3930
|
+
const model = opts.model ?? WORKERS_AI_LLM_MODEL;
|
|
3931
|
+
let body;
|
|
3932
|
+
try {
|
|
3933
|
+
body = await Promise.race([
|
|
3934
|
+
ai.run(model, {
|
|
3935
|
+
messages: messages.map((m) => ({ role: m.role, content: m.content })),
|
|
3936
|
+
stream: true,
|
|
3937
|
+
max_tokens: opts.maxTokens ?? 600,
|
|
3938
|
+
temperature: opts.temperature ?? 0.7
|
|
3939
|
+
}),
|
|
3940
|
+
new Promise(
|
|
3941
|
+
(_, reject) => setTimeout(() => reject(new WorkersAIError("Workers AI timed out")), WORKERS_AI_TEXT_TIMEOUT_MS)
|
|
3942
|
+
)
|
|
3943
|
+
]);
|
|
3944
|
+
} catch (err) {
|
|
3945
|
+
throw err instanceof WorkersAIError ? err : new WorkersAIError(err instanceof Error ? err.message : "Workers AI request failed");
|
|
3946
|
+
}
|
|
3947
|
+
const stream = body;
|
|
3948
|
+
const getReader = typeof stream === "object" && stream !== null && "getReader" in stream && typeof stream.getReader === "function" ? stream.getReader : void 0;
|
|
3949
|
+
if (!getReader) throw new WorkersAIError("Workers AI stream was not readable");
|
|
3950
|
+
const reader = getReader.call(stream);
|
|
3951
|
+
const decoder = new TextDecoder();
|
|
3952
|
+
let buffer = "";
|
|
3953
|
+
try {
|
|
3954
|
+
for (; ; ) {
|
|
3955
|
+
const { done, value } = await reader.read();
|
|
3956
|
+
if (done) break;
|
|
3957
|
+
buffer += decoder.decode(value, { stream: true });
|
|
3958
|
+
let newlineAt;
|
|
3959
|
+
while ((newlineAt = buffer.indexOf("\n")) !== -1) {
|
|
3960
|
+
let line = buffer.slice(0, newlineAt);
|
|
3961
|
+
buffer = buffer.slice(newlineAt + 1);
|
|
3962
|
+
if (line.endsWith("\r")) line = line.slice(0, -1);
|
|
3963
|
+
if (line.startsWith(":") || line.trim() === "") continue;
|
|
3964
|
+
if (!line.startsWith("data: ")) continue;
|
|
3965
|
+
const payload = line.slice(6).trim();
|
|
3966
|
+
if (payload === "[DONE]") return;
|
|
3967
|
+
try {
|
|
3968
|
+
const parsed = JSON.parse(payload);
|
|
3969
|
+
if (typeof parsed.response === "string" && parsed.response.length > 0) yield parsed.response;
|
|
3970
|
+
} catch {
|
|
3971
|
+
buffer = `${line}
|
|
3972
|
+
${buffer}`;
|
|
3973
|
+
break;
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
} finally {
|
|
3978
|
+
reader.releaseLock();
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
// src/providers/workers-ai/workers-ai.provider.ts
|
|
3983
|
+
var WORKERS_AI_TIERS = {
|
|
3984
|
+
fast: "@cf/meta/llama-3.1-8b-instruct-fp8-fast",
|
|
3985
|
+
balanced: WORKERS_AI_LLM_MODEL,
|
|
3986
|
+
powerful: WORKERS_AI_LLM_MODEL
|
|
3987
|
+
};
|
|
3988
|
+
var WorkersAIProvider = class {
|
|
3989
|
+
id = "workers-ai";
|
|
3990
|
+
name = "Cloudflare Workers AI";
|
|
3991
|
+
capabilities = ["text"];
|
|
3992
|
+
binding;
|
|
3993
|
+
tiers;
|
|
3994
|
+
jsonParser = new JsonResponseParser();
|
|
3995
|
+
constructor(config) {
|
|
3996
|
+
this.binding = config.binding;
|
|
3997
|
+
this.tiers = mergeTierOverrides(WORKERS_AI_TIERS, config.models);
|
|
3998
|
+
}
|
|
3999
|
+
resolveModel(tier) {
|
|
4000
|
+
return resolveModel(this.tiers, tier, this.id);
|
|
4001
|
+
}
|
|
4002
|
+
async healthCheck() {
|
|
4003
|
+
return typeof this.binding?.run === "function" ? "healthy" : "unavailable";
|
|
4004
|
+
}
|
|
4005
|
+
/** Workers AI is allocation-priced (neurons per deployment), not per
|
|
4006
|
+
* request — there is no per-call cost to estimate. */
|
|
4007
|
+
async estimateCost(_request) {
|
|
4008
|
+
return 0;
|
|
4009
|
+
}
|
|
4010
|
+
async generate(request) {
|
|
4011
|
+
const model = request.model ?? this.resolveModel(request.tier ?? "balanced");
|
|
4012
|
+
const messages = withSystemPrompt(request);
|
|
4013
|
+
try {
|
|
4014
|
+
const text = await runWorkersAIText(
|
|
4015
|
+
{ AI: this.binding },
|
|
4016
|
+
messages,
|
|
4017
|
+
{
|
|
4018
|
+
model,
|
|
4019
|
+
maxTokens: request.maxTokens,
|
|
4020
|
+
temperature: request.temperature
|
|
4021
|
+
}
|
|
4022
|
+
);
|
|
4023
|
+
return { text, model, providerId: this.id, finishReason: "stop" };
|
|
4024
|
+
} catch (error) {
|
|
4025
|
+
throw toAIError(error);
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
async generateStructured(request) {
|
|
4029
|
+
const messages = [...request.messages];
|
|
4030
|
+
const lastUserIndex = findLastIndex5(messages, (m) => m.role === "user");
|
|
4031
|
+
if (lastUserIndex === -1) {
|
|
4032
|
+
throw new AIError("UNKNOWN_ERROR" /* UNKNOWN_ERROR */, "generateStructured requires at least one user message");
|
|
4033
|
+
}
|
|
4034
|
+
messages[lastUserIndex] = {
|
|
4035
|
+
role: "user",
|
|
4036
|
+
content: new StructuredPromptBuilder(messages[lastUserIndex]?.content ?? "").withSchema(request.schema).build()
|
|
4037
|
+
};
|
|
4038
|
+
const result = await this.generate({ ...request, messages, temperature: 0.1 });
|
|
4039
|
+
return { value: this.jsonParser.parse(result.text), result };
|
|
4040
|
+
}
|
|
4041
|
+
async stream(request, callbacks) {
|
|
4042
|
+
const model = request.model ?? this.resolveModel(request.tier ?? "balanced");
|
|
4043
|
+
const messages = withSystemPrompt(request);
|
|
4044
|
+
let text = "";
|
|
4045
|
+
try {
|
|
4046
|
+
for await (const chunk of streamWorkersAIText({ AI: this.binding }, messages, {
|
|
4047
|
+
model,
|
|
4048
|
+
maxTokens: request.maxTokens,
|
|
4049
|
+
temperature: request.temperature
|
|
4050
|
+
})) {
|
|
4051
|
+
text += chunk;
|
|
4052
|
+
callbacks.onChunk?.(chunk);
|
|
4053
|
+
}
|
|
4054
|
+
} catch (error) {
|
|
4055
|
+
const aiError = toAIError(error);
|
|
4056
|
+
callbacks.onError?.(aiError);
|
|
4057
|
+
throw aiError;
|
|
4058
|
+
}
|
|
4059
|
+
const result = { text, model, providerId: this.id, finishReason: "stop" };
|
|
4060
|
+
callbacks.onComplete?.(result);
|
|
4061
|
+
return result;
|
|
4062
|
+
}
|
|
4063
|
+
};
|
|
4064
|
+
function withSystemPrompt(request) {
|
|
4065
|
+
if (request.systemPrompt && request.systemPrompt.length > 0) {
|
|
4066
|
+
return [
|
|
4067
|
+
{ role: "system", content: request.systemPrompt },
|
|
4068
|
+
...request.messages.filter((m) => m.role !== "system")
|
|
4069
|
+
];
|
|
4070
|
+
}
|
|
4071
|
+
return request.messages;
|
|
4072
|
+
}
|
|
4073
|
+
function toAIError(error) {
|
|
4074
|
+
if (error instanceof AIError) return error;
|
|
4075
|
+
const message = error instanceof Error ? error.message : "Workers AI request failed";
|
|
4076
|
+
const type = error instanceof WorkersAIError && error.message.includes("not configured") ? "INVALID_API_KEY" /* INVALID_API_KEY */ : "SERVER_ERROR" /* SERVER_ERROR */;
|
|
4077
|
+
return new AIError(type, message, error instanceof Error ? error : void 0);
|
|
4078
|
+
}
|
|
4079
|
+
function findLastIndex5(items, predicate) {
|
|
4080
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
4081
|
+
const item = items[i];
|
|
4082
|
+
if (item !== void 0 && predicate(item)) return i;
|
|
4083
|
+
}
|
|
4084
|
+
return -1;
|
|
4085
|
+
}
|
|
4086
|
+
function createWorkersAIProvider(config) {
|
|
4087
|
+
return new WorkersAIProvider(config);
|
|
4088
|
+
}
|
|
4089
|
+
|
|
4090
|
+
// src/providers/factory/create-ai.ts
|
|
4091
|
+
function createAI(config = {}) {
|
|
4092
|
+
const factory = new ProviderFactory({
|
|
4093
|
+
priority: config.priority,
|
|
4094
|
+
fallbackEnabled: config.fallbackEnabled,
|
|
4095
|
+
defaultTier: config.defaultTier
|
|
4096
|
+
});
|
|
4097
|
+
if (config.anthropic?.apiKey) {
|
|
4098
|
+
factory.register(new AnthropicProvider(config.anthropic));
|
|
4099
|
+
}
|
|
4100
|
+
if (config.groq?.apiKey) {
|
|
4101
|
+
factory.register(new GroqProvider(config.groq));
|
|
4102
|
+
}
|
|
4103
|
+
if (config.gemini?.apiKey) {
|
|
4104
|
+
factory.register(new GeminiProvider({ ...config.gemini, enabled: true }));
|
|
4105
|
+
}
|
|
4106
|
+
if (config.fal?.apiKey) {
|
|
4107
|
+
factory.register(new FalProvider({ ...config.fal, enabled: true }));
|
|
4108
|
+
}
|
|
4109
|
+
if (config.pruna?.apiKey) {
|
|
4110
|
+
factory.register(new PrunaProvider({ ...config.pruna, enabled: true }));
|
|
4111
|
+
}
|
|
4112
|
+
const openaiCompatible = config.openaiCompatible;
|
|
4113
|
+
if (openaiCompatible?.apiKey && (openaiCompatible.baseUrl || openaiCompatible.endpointUrl)) {
|
|
4114
|
+
factory.register(
|
|
4115
|
+
new OpenAiCompatibleProvider({ ...openaiCompatible, apiKey: openaiCompatible.apiKey })
|
|
4116
|
+
);
|
|
4117
|
+
}
|
|
4118
|
+
if (config.workersAI?.binding) {
|
|
4119
|
+
factory.register(new WorkersAIProvider(config.workersAI));
|
|
4120
|
+
}
|
|
4121
|
+
return factory;
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
// src/providers/groq/groq-messages.ts
|
|
4125
|
+
var createUserMessage = (content) => ({
|
|
4126
|
+
role: "user",
|
|
4127
|
+
content
|
|
4128
|
+
});
|
|
4129
|
+
var createAssistantMessage = (content) => ({
|
|
4130
|
+
role: "assistant",
|
|
4131
|
+
content
|
|
4132
|
+
});
|
|
4133
|
+
var createSystemMessage = (content) => ({
|
|
4134
|
+
role: "system",
|
|
4135
|
+
content
|
|
4136
|
+
});
|
|
4137
|
+
var createMessage = (role, content) => ({
|
|
4138
|
+
role,
|
|
4139
|
+
content
|
|
4140
|
+
});
|
|
4141
|
+
var promptToMessages = (prompt) => [
|
|
4142
|
+
createUserMessage(prompt)
|
|
4143
|
+
];
|
|
4144
|
+
var extractTextFromMessages = (messages) => messages.map((m) => m.content).join("\n\n");
|
|
4145
|
+
var formatMessagesForDisplay = (messages) => messages.map((m) => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n---\n\n");
|
|
4146
|
+
|
|
4147
|
+
// src/providers/groq/groq-structured-json.ts
|
|
4148
|
+
async function requestStructuredJson(client, request) {
|
|
4149
|
+
const chatRequest = {
|
|
4150
|
+
model: request.model,
|
|
4151
|
+
messages: [createUserMessage(request.instructions)],
|
|
4152
|
+
temperature: request.temperature,
|
|
4153
|
+
max_tokens: request.maxTokens,
|
|
4154
|
+
response_format: { type: "json_object" },
|
|
4155
|
+
...request.reasoningEffort !== void 0 ? { reasoning_effort: request.reasoningEffort } : {}
|
|
4156
|
+
};
|
|
4157
|
+
const response = await client.postChatCompletion(chatRequest);
|
|
4158
|
+
const content = response.choices[0]?.message?.content ?? "";
|
|
4159
|
+
const candidate = extractJsonCandidate(content);
|
|
4160
|
+
try {
|
|
4161
|
+
return JSON.parse(candidate);
|
|
4162
|
+
} catch (err) {
|
|
4163
|
+
throw new GroqError(
|
|
4164
|
+
"UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
|
|
4165
|
+
"model response contained no parsable json object",
|
|
4166
|
+
err instanceof Error ? err : void 0
|
|
4167
|
+
);
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
|
|
4171
|
+
// src/providers/groq/text-generation.service.ts
|
|
4172
|
+
var STRUCTURED_OUTPUT_TEMPERATURE = 0.1;
|
|
4173
|
+
var TextGenerationService = class {
|
|
4174
|
+
constructor(httpClient, cache = new CacheManager(), defaultModel = DEFAULT_MODELS.TEXT) {
|
|
4175
|
+
this.httpClient = httpClient;
|
|
4176
|
+
this.cache = cache;
|
|
4177
|
+
this.defaultModel = defaultModel;
|
|
4178
|
+
}
|
|
4179
|
+
httpClient;
|
|
4180
|
+
cache;
|
|
4181
|
+
defaultModel;
|
|
4182
|
+
id = "groq-text-generation";
|
|
4183
|
+
name = "Groq Text Generation";
|
|
4184
|
+
capabilities = ["text"];
|
|
4185
|
+
jsonParser = new JsonResponseParser();
|
|
4186
|
+
generateCompletion(prompt, options = {}) {
|
|
4187
|
+
const model = options.model ?? this.defaultModel;
|
|
4188
|
+
return this.executeWithCache(
|
|
4189
|
+
{
|
|
4190
|
+
type: CACHE_KEY_TYPE_COMPLETION,
|
|
4191
|
+
model,
|
|
4192
|
+
prompt,
|
|
4193
|
+
config: options.generationConfig
|
|
4194
|
+
},
|
|
4195
|
+
async () => {
|
|
4196
|
+
const request = GroqChatRequestBuilder.for(model).withMessages([createUserMessage(prompt)]).withConfig(options.generationConfig).build();
|
|
4197
|
+
const response = await this.httpClient.postChatCompletion(request);
|
|
4198
|
+
return this.extractContent(response.choices[0]?.message?.content);
|
|
4199
|
+
}
|
|
4200
|
+
);
|
|
4201
|
+
}
|
|
4202
|
+
generateChatCompletion(messages, options = {}) {
|
|
4203
|
+
const model = options.model ?? this.defaultModel;
|
|
4204
|
+
return this.executeWithCache(
|
|
4205
|
+
{
|
|
4206
|
+
type: CACHE_KEY_TYPE_CHAT,
|
|
4207
|
+
model,
|
|
4208
|
+
messages: [...messages],
|
|
4209
|
+
config: options.generationConfig
|
|
4210
|
+
},
|
|
4211
|
+
async () => {
|
|
4212
|
+
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).build();
|
|
4213
|
+
const response = await this.httpClient.postChatCompletion(request);
|
|
4214
|
+
return this.extractContent(response.choices[0]?.message?.content);
|
|
4215
|
+
}
|
|
4216
|
+
);
|
|
4217
|
+
}
|
|
4218
|
+
generateStructured(promptOrRequest, options) {
|
|
4219
|
+
if (typeof promptOrRequest === "string") {
|
|
4220
|
+
const model2 = options?.model ?? this.defaultModel;
|
|
4221
|
+
const jsonPrompt = StructuredPromptBuilder.for(promptOrRequest).withSchema(options?.schema).build();
|
|
4222
|
+
const request = GroqChatRequestBuilder.for(model2).withMessages([createUserMessage(jsonPrompt)]).withConfig({
|
|
4223
|
+
...options?.generationConfig,
|
|
4224
|
+
temperature: STRUCTURED_OUTPUT_TEMPERATURE
|
|
4225
|
+
}).build();
|
|
4226
|
+
return this.httpClient.postChatCompletion(request).then((response) => {
|
|
4227
|
+
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
4228
|
+
return this.jsonParser.parse(content);
|
|
4229
|
+
});
|
|
4230
|
+
}
|
|
4231
|
+
const req = promptOrRequest;
|
|
4232
|
+
const model = req.model ?? (req.tier ? this.resolveModel(req.tier) : this.defaultModel);
|
|
4233
|
+
const schemaObj = req.schema;
|
|
4234
|
+
const messages = [];
|
|
4235
|
+
if (req.systemPrompt) {
|
|
4236
|
+
messages.push({ role: "system", content: req.systemPrompt });
|
|
4237
|
+
}
|
|
4238
|
+
for (const m of req.messages) {
|
|
4239
|
+
messages.push({ role: m.role, content: m.content });
|
|
4240
|
+
}
|
|
4241
|
+
const lastMsg = messages[messages.length - 1];
|
|
4242
|
+
if (lastMsg) {
|
|
4243
|
+
const structuredPrompt = StructuredPromptBuilder.for(lastMsg.content).withSchema(schemaObj).build();
|
|
4244
|
+
messages[messages.length - 1] = { ...lastMsg, content: structuredPrompt };
|
|
4245
|
+
}
|
|
4246
|
+
const groqReq = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig({
|
|
4247
|
+
temperature: req.temperature ?? STRUCTURED_OUTPUT_TEMPERATURE,
|
|
4248
|
+
maxTokens: req.maxTokens
|
|
4249
|
+
}).build();
|
|
4250
|
+
return this.httpClient.postChatCompletion(groqReq).then((response) => {
|
|
4251
|
+
const content = this.extractContent(response.choices[0]?.message?.content);
|
|
4252
|
+
const parsed = this.jsonParser.parse(content);
|
|
4253
|
+
const genResult = {
|
|
4254
|
+
text: content,
|
|
4255
|
+
model: response.model,
|
|
4256
|
+
providerId: this.id,
|
|
4257
|
+
finishReason: response.choices[0]?.finish_reason ?? "stop",
|
|
4258
|
+
usage: response.usage ? {
|
|
4259
|
+
inputTokens: response.usage.prompt_tokens,
|
|
4260
|
+
outputTokens: response.usage.completion_tokens,
|
|
4261
|
+
totalTokens: response.usage.total_tokens
|
|
4262
|
+
} : void 0
|
|
4263
|
+
};
|
|
4264
|
+
return { value: parsed, result: genResult };
|
|
4265
|
+
});
|
|
4266
|
+
}
|
|
4267
|
+
streamCompletion(prompt, callbacks, options = {}) {
|
|
4268
|
+
return this.streamChatCompletion([createUserMessage(prompt)], callbacks, options);
|
|
4269
|
+
}
|
|
4270
|
+
async streamChatCompletion(messages, callbacks, options = {}) {
|
|
4271
|
+
const model = options.model ?? this.defaultModel;
|
|
4272
|
+
const request = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(options.generationConfig).withStream(true).build();
|
|
4273
|
+
const parser = new StreamingResponseParser(
|
|
4274
|
+
{
|
|
4275
|
+
onChunk: (chunk) => callbacks.onChunk?.(chunk)
|
|
4276
|
+
},
|
|
4277
|
+
extractContentFromSsePayload
|
|
4278
|
+
);
|
|
4279
|
+
try {
|
|
4280
|
+
const stream = await this.httpClient.streamChatCompletion(request, {
|
|
4281
|
+
signal: options.signal
|
|
4282
|
+
});
|
|
3702
4283
|
const fullText = await parser.parse(stream);
|
|
3703
4284
|
callbacks.onComplete?.(fullText);
|
|
3704
4285
|
return fullText;
|
|
@@ -3920,6 +4501,7 @@ var ChatService = class {
|
|
|
3920
4501
|
if (messages.length === 0) return null;
|
|
3921
4502
|
const last = messages[messages.length - 1];
|
|
3922
4503
|
const first = messages[0];
|
|
4504
|
+
if (!last || !first) return null;
|
|
3923
4505
|
const companionId = String(first.metadata?.["companionId"] ?? "unknown");
|
|
3924
4506
|
const companionName = String(first.metadata?.["companionName"] ?? "Unknown");
|
|
3925
4507
|
return {
|
|
@@ -4012,30 +4594,235 @@ var ChatService = class {
|
|
|
4012
4594
|
}
|
|
4013
4595
|
return this.storage;
|
|
4014
4596
|
}
|
|
4015
|
-
};
|
|
4597
|
+
};
|
|
4598
|
+
|
|
4599
|
+
// src/providers/groq/groq-container.ts
|
|
4600
|
+
var container = null;
|
|
4601
|
+
function configureProvider(config) {
|
|
4602
|
+
const configStore = new GroqConfigStore();
|
|
4603
|
+
const transport = new GroqHttpTransport(configStore);
|
|
4604
|
+
const httpClient = new GroqHttpClient({ configStore, transport });
|
|
4605
|
+
httpClient.initialize(config);
|
|
4606
|
+
const textGeneration = new TextGenerationService(
|
|
4607
|
+
httpClient,
|
|
4608
|
+
new CacheManager(),
|
|
4609
|
+
config.textModel
|
|
4610
|
+
);
|
|
4611
|
+
const chat = new ChatService(textGeneration);
|
|
4612
|
+
container = { groqHttpClient: httpClient, textGeneration, chat };
|
|
4613
|
+
return container;
|
|
4614
|
+
}
|
|
4615
|
+
function getProvider() {
|
|
4616
|
+
return container;
|
|
4617
|
+
}
|
|
4618
|
+
function resetProvider() {
|
|
4619
|
+
container?.groqHttpClient.reset();
|
|
4620
|
+
container = null;
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
// src/providers/workers-ai/workers-ai.speech.ts
|
|
4624
|
+
var WORKERS_AI_SPEECH_TIMEOUT_MS = 45e3;
|
|
4625
|
+
async function readAll(stream) {
|
|
4626
|
+
const reader = stream.getReader();
|
|
4627
|
+
const chunks = [];
|
|
4628
|
+
try {
|
|
4629
|
+
for (; ; ) {
|
|
4630
|
+
const { done, value } = await reader.read();
|
|
4631
|
+
if (done) break;
|
|
4632
|
+
if (value) chunks.push(value);
|
|
4633
|
+
}
|
|
4634
|
+
} finally {
|
|
4635
|
+
reader.releaseLock();
|
|
4636
|
+
}
|
|
4637
|
+
const combined = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0));
|
|
4638
|
+
let offset = 0;
|
|
4639
|
+
for (const chunk of chunks) {
|
|
4640
|
+
combined.set(chunk, offset);
|
|
4641
|
+
offset += chunk.length;
|
|
4642
|
+
}
|
|
4643
|
+
return combined;
|
|
4644
|
+
}
|
|
4645
|
+
function base64ToBytes2(base64) {
|
|
4646
|
+
const binary = atob(base64);
|
|
4647
|
+
const bytes = new Uint8Array(binary.length);
|
|
4648
|
+
for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);
|
|
4649
|
+
return bytes;
|
|
4650
|
+
}
|
|
4651
|
+
async function speakWithWorkersAI(env, engine, text) {
|
|
4652
|
+
const ai = env.AI;
|
|
4653
|
+
if (!ai || typeof ai.run !== "function") throw new WorkersAIError("Workers AI is not configured");
|
|
4654
|
+
const input = engine.langParam ? { prompt: text, lang: engine.langParam } : { text };
|
|
4655
|
+
let result;
|
|
4656
|
+
try {
|
|
4657
|
+
result = await Promise.race([
|
|
4658
|
+
ai.run(engine.model, input),
|
|
4659
|
+
new Promise(
|
|
4660
|
+
(_, reject) => setTimeout(() => reject(new WorkersAIError("The speech engine timed out")), WORKERS_AI_SPEECH_TIMEOUT_MS)
|
|
4661
|
+
)
|
|
4662
|
+
]);
|
|
4663
|
+
} catch (err) {
|
|
4664
|
+
throw err instanceof WorkersAIError ? err : new WorkersAIError(err instanceof Error ? err.message : "Workers AI speech request failed");
|
|
4665
|
+
}
|
|
4666
|
+
if (result instanceof ReadableStream) {
|
|
4667
|
+
const bytes = await readAll(result);
|
|
4668
|
+
if (bytes.length === 0) throw new WorkersAIError("The speech engine returned no audio");
|
|
4669
|
+
return { bytes };
|
|
4670
|
+
}
|
|
4671
|
+
const audio = result ?? {};
|
|
4672
|
+
if (typeof audio.audio === "string" && audio.audio.length > 0) {
|
|
4673
|
+
return { bytes: base64ToBytes2(audio.audio) };
|
|
4674
|
+
}
|
|
4675
|
+
throw new WorkersAIError("The speech engine returned no audio");
|
|
4676
|
+
}
|
|
4677
|
+
|
|
4678
|
+
// src/providers/fal/queue/fal-queue.entities.ts
|
|
4679
|
+
var FalQueueError = class extends Error {
|
|
4680
|
+
status;
|
|
4681
|
+
constructor(message, status) {
|
|
4682
|
+
super(message);
|
|
4683
|
+
this.name = "FalQueueError";
|
|
4684
|
+
this.status = status;
|
|
4685
|
+
}
|
|
4686
|
+
};
|
|
4687
|
+
var FAL_ASPECT_IMAGE_SIZES = {
|
|
4688
|
+
"1:1": "square_hd",
|
|
4689
|
+
"16:9": "landscape_16_9",
|
|
4690
|
+
"9:16": "portrait_16_9"
|
|
4691
|
+
};
|
|
4692
|
+
|
|
4693
|
+
// src/providers/fal/queue/fal-queue.client.ts
|
|
4694
|
+
var FAL_QUEUE_BASE = "https://queue.fal.run";
|
|
4695
|
+
var FAL_SUBMIT_TIMEOUT_MS = 15e3;
|
|
4696
|
+
var FAL_POLL_TIMEOUT_MS = 1e4;
|
|
4697
|
+
function falQueueConfigured(env) {
|
|
4698
|
+
return Boolean(env.FAL_KEY);
|
|
4699
|
+
}
|
|
4700
|
+
async function falFetch(env, url, timeoutMs, body) {
|
|
4701
|
+
if (!falQueueConfigured(env)) throw new FalQueueError("fal.ai is not configured");
|
|
4702
|
+
const request = async () => fetch(url, {
|
|
4703
|
+
method: body !== void 0 ? "POST" : "GET",
|
|
4704
|
+
headers: {
|
|
4705
|
+
Authorization: `Key ${env.FAL_KEY}`,
|
|
4706
|
+
...body !== void 0 ? { "Content-Type": "application/json" } : {}
|
|
4707
|
+
},
|
|
4708
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0,
|
|
4709
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
4710
|
+
});
|
|
4711
|
+
let res;
|
|
4712
|
+
try {
|
|
4713
|
+
res = await request();
|
|
4714
|
+
if (res.status >= 500) res = await request();
|
|
4715
|
+
} catch (err) {
|
|
4716
|
+
throw new FalQueueError(err instanceof Error ? err.message : "fal.ai request failed");
|
|
4717
|
+
}
|
|
4718
|
+
if (!res.ok) {
|
|
4719
|
+
const text = await res.text().catch(() => "");
|
|
4720
|
+
throw new FalQueueError(`fal ${res.status}: ${text.slice(0, 200)}`, res.status);
|
|
4721
|
+
}
|
|
4722
|
+
return await res.json();
|
|
4723
|
+
}
|
|
4724
|
+
function createFalQueue(env) {
|
|
4725
|
+
return {
|
|
4726
|
+
async submit(model, input) {
|
|
4727
|
+
const res = await falFetch(env, `${FAL_QUEUE_BASE}/${model}`, FAL_SUBMIT_TIMEOUT_MS, input);
|
|
4728
|
+
return { requestId: res.request_id, statusUrl: res.status_url, responseUrl: res.response_url };
|
|
4729
|
+
},
|
|
4730
|
+
async checkStatus(statusUrl) {
|
|
4731
|
+
const res = await falFetch(env, statusUrl, FAL_POLL_TIMEOUT_MS);
|
|
4732
|
+
return {
|
|
4733
|
+
status: res.status,
|
|
4734
|
+
queuePosition: res.queue_position,
|
|
4735
|
+
logs: res.logs?.map((l) => l.message ?? "").filter(Boolean)
|
|
4736
|
+
};
|
|
4737
|
+
},
|
|
4738
|
+
fetchResult(responseUrl) {
|
|
4739
|
+
return falFetch(env, responseUrl, FAL_POLL_TIMEOUT_MS);
|
|
4740
|
+
}
|
|
4741
|
+
};
|
|
4742
|
+
}
|
|
4016
4743
|
|
|
4017
|
-
// src/providers/
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
httpClient,
|
|
4026
|
-
new CacheManager(),
|
|
4027
|
-
config.textModel
|
|
4028
|
-
);
|
|
4029
|
-
const chat = new ChatService(textGeneration);
|
|
4030
|
-
container = { groqHttpClient: httpClient, textGeneration, chat };
|
|
4031
|
-
return container;
|
|
4744
|
+
// src/providers/fal/queue/fal-wire.ts
|
|
4745
|
+
function buildFalImageInput(model, input) {
|
|
4746
|
+
const base = { prompt: input.prompt, num_images: input.numImages };
|
|
4747
|
+
if (model.includes("flux")) {
|
|
4748
|
+
const imageSize = input.aspectRatio ? FAL_ASPECT_IMAGE_SIZES[input.aspectRatio] : void 0;
|
|
4749
|
+
if (imageSize) base.image_size = imageSize;
|
|
4750
|
+
}
|
|
4751
|
+
return base;
|
|
4032
4752
|
}
|
|
4033
|
-
function
|
|
4034
|
-
|
|
4753
|
+
function parseFalImageOutput(raw) {
|
|
4754
|
+
const obj = raw ?? {};
|
|
4755
|
+
const entries = Array.isArray(obj.images) ? obj.images : obj.image && typeof obj.image === "object" ? [obj.image] : [];
|
|
4756
|
+
const imageUrls = entries.map((e) => typeof e.url === "string" ? e.url : "").filter((url) => url.length > 0);
|
|
4757
|
+
const first = entries.find((e) => typeof e.width === "number" || typeof e.height === "number");
|
|
4758
|
+
return {
|
|
4759
|
+
imageUrls,
|
|
4760
|
+
...typeof obj.seed === "number" ? { seed: obj.seed } : {},
|
|
4761
|
+
...typeof first?.width === "number" ? { width: first.width } : {},
|
|
4762
|
+
...typeof first?.height === "number" ? { height: first.height } : {}
|
|
4763
|
+
};
|
|
4035
4764
|
}
|
|
4036
|
-
function
|
|
4037
|
-
|
|
4038
|
-
|
|
4765
|
+
function buildFalVideoInput(spec, input) {
|
|
4766
|
+
const base = { prompt: input.prompt };
|
|
4767
|
+
if (spec.durationFormat !== "none" && typeof input.durationSeconds === "number") {
|
|
4768
|
+
base.duration = spec.durationFormat === "s-suffix" ? `${input.durationSeconds}s` : String(input.durationSeconds);
|
|
4769
|
+
}
|
|
4770
|
+
if (spec.aspectRatios && input.aspectRatio) base.aspect_ratio = input.aspectRatio;
|
|
4771
|
+
if (spec.resolutions && input.resolution) base.resolution = input.resolution;
|
|
4772
|
+
if (input.imageUrl) base.image_url = input.imageUrl;
|
|
4773
|
+
if (spec.supportsNegativePrompt && input.negativePrompt) base.negative_prompt = input.negativePrompt;
|
|
4774
|
+
if (spec.generateAudio) base.generate_audio = true;
|
|
4775
|
+
return base;
|
|
4776
|
+
}
|
|
4777
|
+
function parseFalVideoOutput(raw) {
|
|
4778
|
+
const obj = raw ?? {};
|
|
4779
|
+
const video = obj.video && typeof obj.video === "object" ? obj.video : void 0;
|
|
4780
|
+
if (!video || typeof video.url !== "string" || video.url.length === 0) return null;
|
|
4781
|
+
return {
|
|
4782
|
+
videoUrl: video.url,
|
|
4783
|
+
...typeof video.content_type === "string" ? { contentType: video.content_type } : {},
|
|
4784
|
+
...typeof video.file_size === "number" ? { fileSize: video.file_size } : {}
|
|
4785
|
+
};
|
|
4786
|
+
}
|
|
4787
|
+
function buildFalTagPrompt(prompt) {
|
|
4788
|
+
return prompt.toLowerCase().split(/[,\s]+/).filter((word) => word.length > 3).slice(0, 5).join(", ");
|
|
4789
|
+
}
|
|
4790
|
+
function buildFalAudioLyrics(input) {
|
|
4791
|
+
if (input.instrumental) return "[inst]";
|
|
4792
|
+
const lyrics = input.lyrics?.trim();
|
|
4793
|
+
if (!lyrics) return void 0;
|
|
4794
|
+
if (lyrics.includes("[verse]") || lyrics.includes("[chorus]")) return lyrics;
|
|
4795
|
+
return `[verse]
|
|
4796
|
+
${lyrics}
|
|
4797
|
+
[/verse]`;
|
|
4798
|
+
}
|
|
4799
|
+
function buildFalAudioInput(spec, input) {
|
|
4800
|
+
const tags = buildFalTagPrompt(input.prompt);
|
|
4801
|
+
const base = { prompt: tags, duration: input.durationSeconds };
|
|
4802
|
+
if (spec.supportsLyrics) {
|
|
4803
|
+
const lyrics = buildFalAudioLyrics(input);
|
|
4804
|
+
if (lyrics) base.lyrics = lyrics;
|
|
4805
|
+
}
|
|
4806
|
+
if (spec.supportsInstrumental && input.instrumental !== void 0) {
|
|
4807
|
+
base.instrumental = input.instrumental;
|
|
4808
|
+
}
|
|
4809
|
+
return base;
|
|
4810
|
+
}
|
|
4811
|
+
function parseFalAudioOutput(raw) {
|
|
4812
|
+
const obj = raw ?? {};
|
|
4813
|
+
const nested = (key) => {
|
|
4814
|
+
const value = obj[key];
|
|
4815
|
+
if (!value || typeof value !== "object") return void 0;
|
|
4816
|
+
const url = value.url;
|
|
4817
|
+
return typeof url === "string" && url.length > 0 ? url : void 0;
|
|
4818
|
+
};
|
|
4819
|
+
const flat = (key) => {
|
|
4820
|
+
const value = obj[key];
|
|
4821
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
4822
|
+
};
|
|
4823
|
+
const audioUrl = nested("audio_url") ?? nested("audio_file") ?? nested("audio") ?? flat("audio_url") ?? flat("audio");
|
|
4824
|
+
if (!audioUrl) return null;
|
|
4825
|
+
return { audioUrl };
|
|
4039
4826
|
}
|
|
4040
4827
|
|
|
4041
4828
|
// src/providers/embeddings/openai-embeddings.ts
|
|
@@ -4225,170 +5012,6 @@ function createOpenAiImageAdapter(config) {
|
|
|
4225
5012
|
};
|
|
4226
5013
|
}
|
|
4227
5014
|
|
|
4228
|
-
// src/core/sse/tool-call-accumulator.ts
|
|
4229
|
-
var ToolCallAccumulator = class {
|
|
4230
|
-
slots = /* @__PURE__ */ new Map();
|
|
4231
|
-
push(delta) {
|
|
4232
|
-
const index = delta.index ?? 0;
|
|
4233
|
-
const slot = this.slots.get(index) ?? { id: "", name: "", args: "" };
|
|
4234
|
-
if (delta.id) slot.id = delta.id;
|
|
4235
|
-
if (delta.function?.name) slot.name = delta.function.name;
|
|
4236
|
-
if (delta.function?.arguments) slot.args += delta.function.arguments;
|
|
4237
|
-
this.slots.set(index, slot);
|
|
4238
|
-
}
|
|
4239
|
-
finish() {
|
|
4240
|
-
return Array.from(this.slots.entries()).sort(([a], [b]) => a - b).map(([, slot]) => ({
|
|
4241
|
-
id: slot.id,
|
|
4242
|
-
name: slot.name,
|
|
4243
|
-
arguments: slot.args
|
|
4244
|
-
})).filter((call) => call.id.length > 0 || call.name.length > 0);
|
|
4245
|
-
}
|
|
4246
|
-
};
|
|
4247
|
-
|
|
4248
|
-
// src/providers/adapters/openai-compatible.adapter.ts
|
|
4249
|
-
function toWireMessage(message) {
|
|
4250
|
-
if (message.role === "tool") {
|
|
4251
|
-
return { role: "tool", content: message.content, tool_call_id: message.toolCallId ?? "" };
|
|
4252
|
-
}
|
|
4253
|
-
if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
|
|
4254
|
-
return {
|
|
4255
|
-
role: "assistant",
|
|
4256
|
-
content: message.content,
|
|
4257
|
-
tool_calls: message.toolCalls.map((call) => ({
|
|
4258
|
-
id: call.id,
|
|
4259
|
-
type: "function",
|
|
4260
|
-
function: { name: call.name, arguments: call.arguments }
|
|
4261
|
-
}))
|
|
4262
|
-
};
|
|
4263
|
-
}
|
|
4264
|
-
if (message.role === "user") return { role: "user", content: message.content };
|
|
4265
|
-
return { role: message.role, content: message.content };
|
|
4266
|
-
}
|
|
4267
|
-
function mergeImages(messages, images) {
|
|
4268
|
-
if (images.length === 0) return [...messages];
|
|
4269
|
-
const parts = images.map((image) => ({
|
|
4270
|
-
type: "image_url",
|
|
4271
|
-
image_url: { url: `data:${image.mimeType};base64,${image.dataBase64}` }
|
|
4272
|
-
}));
|
|
4273
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
4274
|
-
const message = messages[index];
|
|
4275
|
-
if (message.role !== "user") continue;
|
|
4276
|
-
const textParts = typeof message.content === "string" ? message.content.length > 0 ? [{ type: "text", text: message.content }] : [] : message.content;
|
|
4277
|
-
return [
|
|
4278
|
-
...messages.slice(0, index),
|
|
4279
|
-
{ role: "user", content: [...textParts, ...parts] },
|
|
4280
|
-
...messages.slice(index + 1)
|
|
4281
|
-
];
|
|
4282
|
-
}
|
|
4283
|
-
return [...messages, { role: "user", content: [...parts] }];
|
|
4284
|
-
}
|
|
4285
|
-
async function extractErrorDetail(response) {
|
|
4286
|
-
try {
|
|
4287
|
-
const body = await response.json();
|
|
4288
|
-
return body.error;
|
|
4289
|
-
} catch {
|
|
4290
|
-
return void 0;
|
|
4291
|
-
}
|
|
4292
|
-
}
|
|
4293
|
-
async function* parseSseEvent(rawEvent, toolCallAccumulator) {
|
|
4294
|
-
for (const line of rawEvent.split("\n")) {
|
|
4295
|
-
if (!line.startsWith("data:")) continue;
|
|
4296
|
-
const payload = line.slice(5).trim();
|
|
4297
|
-
if (payload.length === 0 || payload === "[DONE]") continue;
|
|
4298
|
-
let chunk;
|
|
4299
|
-
try {
|
|
4300
|
-
chunk = JSON.parse(payload);
|
|
4301
|
-
} catch {
|
|
4302
|
-
continue;
|
|
4303
|
-
}
|
|
4304
|
-
const delta = chunk.choices?.[0]?.delta;
|
|
4305
|
-
if (delta?.reasoning) {
|
|
4306
|
-
yield { type: "delta", channel: "reasoning", text: delta.reasoning };
|
|
4307
|
-
}
|
|
4308
|
-
if (delta?.content) {
|
|
4309
|
-
yield { type: "delta", channel: "answer", text: delta.content };
|
|
4310
|
-
}
|
|
4311
|
-
if (delta?.tool_calls) {
|
|
4312
|
-
for (const toolCallDelta of delta.tool_calls) toolCallAccumulator.push(toolCallDelta);
|
|
4313
|
-
}
|
|
4314
|
-
if (chunk.usage) {
|
|
4315
|
-
yield {
|
|
4316
|
-
type: "usage",
|
|
4317
|
-
usage: {
|
|
4318
|
-
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
4319
|
-
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
4320
|
-
reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens
|
|
4321
|
-
}
|
|
4322
|
-
};
|
|
4323
|
-
}
|
|
4324
|
-
}
|
|
4325
|
-
}
|
|
4326
|
-
async function* parseSseStream(body) {
|
|
4327
|
-
const reader = body.getReader();
|
|
4328
|
-
const decoder = new TextDecoder();
|
|
4329
|
-
const toolCallAccumulator = new ToolCallAccumulator();
|
|
4330
|
-
let buffer = "";
|
|
4331
|
-
try {
|
|
4332
|
-
while (true) {
|
|
4333
|
-
const { done, value } = await reader.read();
|
|
4334
|
-
if (done) break;
|
|
4335
|
-
buffer += decoder.decode(value, { stream: true });
|
|
4336
|
-
let separator = buffer.indexOf("\n\n");
|
|
4337
|
-
while (separator !== -1) {
|
|
4338
|
-
const rawEvent = buffer.slice(0, separator);
|
|
4339
|
-
buffer = buffer.slice(separator + 2);
|
|
4340
|
-
separator = buffer.indexOf("\n\n");
|
|
4341
|
-
yield* parseSseEvent(rawEvent, toolCallAccumulator);
|
|
4342
|
-
}
|
|
4343
|
-
}
|
|
4344
|
-
} catch (err) {
|
|
4345
|
-
throw errorFromUnknown(err);
|
|
4346
|
-
} finally {
|
|
4347
|
-
reader.releaseLock();
|
|
4348
|
-
}
|
|
4349
|
-
const calls = toolCallAccumulator.finish();
|
|
4350
|
-
if (calls.length > 0) yield { type: "tool_calls", calls };
|
|
4351
|
-
}
|
|
4352
|
-
function createOpenAiCompatibleAdapter(config) {
|
|
4353
|
-
return {
|
|
4354
|
-
async *stream(req) {
|
|
4355
|
-
const timeout = AbortSignal.timeout(config.timeoutMs);
|
|
4356
|
-
const signal = req.signal ? AbortSignal.any([req.signal, timeout]) : timeout;
|
|
4357
|
-
let response;
|
|
4358
|
-
try {
|
|
4359
|
-
response = await fetch(`${config.baseUrl}/chat/completions`, {
|
|
4360
|
-
method: "POST",
|
|
4361
|
-
headers: {
|
|
4362
|
-
Authorization: `Bearer ${config.apiKey}`,
|
|
4363
|
-
"Content-Type": "application/json"
|
|
4364
|
-
},
|
|
4365
|
-
body: JSON.stringify({
|
|
4366
|
-
model: req.externalModelId,
|
|
4367
|
-
messages: mergeImages(req.messages.map(toWireMessage), req.images ?? []),
|
|
4368
|
-
temperature: req.temperature,
|
|
4369
|
-
max_completion_tokens: req.maxOutputTokens,
|
|
4370
|
-
top_p: req.topP,
|
|
4371
|
-
stream: true,
|
|
4372
|
-
stream_options: { include_usage: true },
|
|
4373
|
-
...req.tools && req.tools.length > 0 ? {
|
|
4374
|
-
tools: req.tools.map((tool) => ({ type: "function", function: tool })),
|
|
4375
|
-
tool_choice: "auto"
|
|
4376
|
-
} : {}
|
|
4377
|
-
}),
|
|
4378
|
-
signal
|
|
4379
|
-
});
|
|
4380
|
-
} catch (err) {
|
|
4381
|
-
throw errorFromUnknown(err);
|
|
4382
|
-
}
|
|
4383
|
-
if (!response.ok || !response.body) {
|
|
4384
|
-
const detail = await extractErrorDetail(response);
|
|
4385
|
-
throw errorFromStatus(response.status, detail?.message, detail);
|
|
4386
|
-
}
|
|
4387
|
-
yield* parseSseStream(response.body);
|
|
4388
|
-
}
|
|
4389
|
-
};
|
|
4390
|
-
}
|
|
4391
|
-
|
|
4392
5015
|
// src/providers/adapters/anthropic.adapter.ts
|
|
4393
5016
|
var ANTHROPIC_VERSION = "2023-06-01";
|
|
4394
5017
|
var ERROR_TYPE_TO_CODE = {
|
|
@@ -4409,7 +5032,7 @@ function mergeImages2(messages, images) {
|
|
|
4409
5032
|
}));
|
|
4410
5033
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
4411
5034
|
const message = messages[index];
|
|
4412
|
-
if (message.role !== "user") continue;
|
|
5035
|
+
if (!message || message.role !== "user") continue;
|
|
4413
5036
|
const textBlocks = typeof message.content === "string" ? message.content.length > 0 ? [{ type: "text", text: message.content }] : [] : message.content;
|
|
4414
5037
|
return [
|
|
4415
5038
|
...messages.slice(0, index),
|
|
@@ -4525,7 +5148,7 @@ function createAnthropicAdapter(config) {
|
|
|
4525
5148
|
model: req.externalModelId,
|
|
4526
5149
|
messages,
|
|
4527
5150
|
...system.length > 0 ? { system } : {},
|
|
4528
|
-
max_tokens: req.maxOutputTokens,
|
|
5151
|
+
max_tokens: req.maxOutputTokens ?? 4096,
|
|
4529
5152
|
stream: true
|
|
4530
5153
|
}),
|
|
4531
5154
|
signal
|
|
@@ -4542,6 +5165,201 @@ function createAnthropicAdapter(config) {
|
|
|
4542
5165
|
};
|
|
4543
5166
|
}
|
|
4544
5167
|
|
|
5168
|
+
// src/providers/adapters/adapter-resolver.ts
|
|
5169
|
+
var ADAPTER_TIMEOUT_MS = 6e4;
|
|
5170
|
+
var ADAPTER_MEDIA_TIMEOUT_MS = 12e4;
|
|
5171
|
+
function resolveApiKey(env, apiKeyEnv) {
|
|
5172
|
+
const value = env[apiKeyEnv];
|
|
5173
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
5174
|
+
throw new AiError("missing_key");
|
|
5175
|
+
}
|
|
5176
|
+
return value.trim();
|
|
5177
|
+
}
|
|
5178
|
+
function apiKeyAvailable(env, apiKeyEnv) {
|
|
5179
|
+
try {
|
|
5180
|
+
resolveApiKey(env, apiKeyEnv);
|
|
5181
|
+
return true;
|
|
5182
|
+
} catch {
|
|
5183
|
+
return false;
|
|
5184
|
+
}
|
|
5185
|
+
}
|
|
5186
|
+
function normalizeBaseUrl(url) {
|
|
5187
|
+
return url.replace(/\/$/, "");
|
|
5188
|
+
}
|
|
5189
|
+
function openAiApiKey(binding, capability) {
|
|
5190
|
+
if (binding.adapter !== "openai-compatible") {
|
|
5191
|
+
throw new AiError(
|
|
5192
|
+
"model_unavailable",
|
|
5193
|
+
`Adapter kind does not support ${capability}: ${binding.adapter}`
|
|
5194
|
+
);
|
|
5195
|
+
}
|
|
5196
|
+
return binding.apiKey;
|
|
5197
|
+
}
|
|
5198
|
+
function chatAdapterFor(binding, timing = {}) {
|
|
5199
|
+
const timeoutMs = timing.timeoutMs ?? ADAPTER_TIMEOUT_MS;
|
|
5200
|
+
if (binding.adapter === "openai-compatible") {
|
|
5201
|
+
return createOpenAiCompatibleAdapter({
|
|
5202
|
+
baseUrl: normalizeBaseUrl(binding.baseUrl),
|
|
5203
|
+
apiKey: binding.apiKey,
|
|
5204
|
+
timeoutMs
|
|
5205
|
+
});
|
|
5206
|
+
}
|
|
5207
|
+
if (binding.adapter === "anthropic") {
|
|
5208
|
+
return createAnthropicAdapter({
|
|
5209
|
+
baseUrl: normalizeBaseUrl(binding.baseUrl),
|
|
5210
|
+
apiKey: binding.apiKey,
|
|
5211
|
+
timeoutMs
|
|
5212
|
+
});
|
|
5213
|
+
}
|
|
5214
|
+
throw new AiError("model_unavailable", `Unsupported adapter kind: ${binding.adapter}`);
|
|
5215
|
+
}
|
|
5216
|
+
function imageAdapterFor(binding, timing = {}) {
|
|
5217
|
+
return createOpenAiImageAdapter({
|
|
5218
|
+
baseUrl: normalizeBaseUrl(binding.baseUrl),
|
|
5219
|
+
apiKey: openAiApiKey(binding, "images"),
|
|
5220
|
+
timeoutMs: timing.mediaTimeoutMs ?? ADAPTER_MEDIA_TIMEOUT_MS
|
|
5221
|
+
});
|
|
5222
|
+
}
|
|
5223
|
+
function embeddingsAdapterFor(binding, timing = {}) {
|
|
5224
|
+
return createOpenAiEmbeddingsAdapter({
|
|
5225
|
+
baseUrl: normalizeBaseUrl(binding.baseUrl),
|
|
5226
|
+
apiKey: openAiApiKey(binding, "embeddings"),
|
|
5227
|
+
timeoutMs: timing.timeoutMs ?? ADAPTER_TIMEOUT_MS
|
|
5228
|
+
});
|
|
5229
|
+
}
|
|
5230
|
+
function audioTranscriptionAdapterFor(binding, timing = {}) {
|
|
5231
|
+
return createOpenAiAudioTranscriptionAdapter({
|
|
5232
|
+
baseUrl: normalizeBaseUrl(binding.baseUrl),
|
|
5233
|
+
apiKey: openAiApiKey(binding, "audio transcription"),
|
|
5234
|
+
timeoutMs: timing.timeoutMs ?? ADAPTER_TIMEOUT_MS
|
|
5235
|
+
});
|
|
5236
|
+
}
|
|
5237
|
+
function speechAdapterFor(binding, timing = {}) {
|
|
5238
|
+
return createOpenAiSpeechAdapter({
|
|
5239
|
+
baseUrl: normalizeBaseUrl(binding.baseUrl),
|
|
5240
|
+
apiKey: openAiApiKey(binding, "speech synthesis"),
|
|
5241
|
+
timeoutMs: timing.mediaTimeoutMs ?? ADAPTER_MEDIA_TIMEOUT_MS
|
|
5242
|
+
});
|
|
5243
|
+
}
|
|
5244
|
+
function createAdapterResolver(env, timing = {}) {
|
|
5245
|
+
const toProviderBinding = (binding) => ({
|
|
5246
|
+
adapter: binding.adapter,
|
|
5247
|
+
baseUrl: binding.baseUrl,
|
|
5248
|
+
apiKey: resolveApiKey(env, binding.apiKeyEnv)
|
|
5249
|
+
});
|
|
5250
|
+
return {
|
|
5251
|
+
chat: (binding) => chatAdapterFor(toProviderBinding(binding), timing),
|
|
5252
|
+
image: (binding) => imageAdapterFor(toProviderBinding(binding), timing),
|
|
5253
|
+
embeddings: (binding) => embeddingsAdapterFor(toProviderBinding(binding), timing),
|
|
5254
|
+
audioTranscription: (binding) => audioTranscriptionAdapterFor(toProviderBinding(binding), timing),
|
|
5255
|
+
speech: (binding) => speechAdapterFor(toProviderBinding(binding), timing),
|
|
5256
|
+
available: (binding) => apiKeyAvailable(env, binding.apiKeyEnv)
|
|
5257
|
+
};
|
|
5258
|
+
}
|
|
5259
|
+
|
|
5260
|
+
// src/core/context/context-manager.ts
|
|
5261
|
+
var CHARS_PER_TOKEN = 4;
|
|
5262
|
+
var SAFETY_MARGIN_TOKENS = 256;
|
|
5263
|
+
function estimateTokens(text) {
|
|
5264
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
5265
|
+
}
|
|
5266
|
+
function estimateMessageTokens(message) {
|
|
5267
|
+
const toolStructure = message.toolCalls && message.toolCalls.length > 0 ? estimateTokens(JSON.stringify(message.toolCalls)) : 0;
|
|
5268
|
+
return estimateTokens(message.content) + toolStructure + 8;
|
|
5269
|
+
}
|
|
5270
|
+
function buildContext(history, systemPrompt, budget) {
|
|
5271
|
+
const available = budget.contextWindow - budget.maxOutputTokens - SAFETY_MARGIN_TOKENS;
|
|
5272
|
+
let used = estimateTokens(systemPrompt);
|
|
5273
|
+
const selected = [];
|
|
5274
|
+
for (let i = history.length - 1; i >= 0; i -= 1) {
|
|
5275
|
+
const message = history[i];
|
|
5276
|
+
if (!message) continue;
|
|
5277
|
+
const cost = estimateMessageTokens(message);
|
|
5278
|
+
if (used + cost > available && selected.length > 0) break;
|
|
5279
|
+
used += cost;
|
|
5280
|
+
selected.push(message);
|
|
5281
|
+
}
|
|
5282
|
+
selected.reverse();
|
|
5283
|
+
while (selected.length > 1 && (selected[0]?.role === "assistant" || selected[0]?.role === "tool")) {
|
|
5284
|
+
selected.shift();
|
|
5285
|
+
}
|
|
5286
|
+
return [{ role: "system", content: systemPrompt }, ...selected];
|
|
5287
|
+
}
|
|
5288
|
+
|
|
5289
|
+
// src/providers/execution/run-conversation.ts
|
|
5290
|
+
async function* runConversation(input) {
|
|
5291
|
+
const tools = input.tools && input.tools.length > 0 ? { tools: input.tools } : {};
|
|
5292
|
+
const images = input.images && input.images.length > 0 ? { images: input.images } : {};
|
|
5293
|
+
for (const [index, attempt] of input.attempts.entries()) {
|
|
5294
|
+
let answer = "";
|
|
5295
|
+
let reasoning = "";
|
|
5296
|
+
let usage = null;
|
|
5297
|
+
let toolCalls = [];
|
|
5298
|
+
const startedAt = Date.now();
|
|
5299
|
+
const context = buildContext(input.history, input.systemPrompt, {
|
|
5300
|
+
contextWindow: attempt.model.contextWindow,
|
|
5301
|
+
// No explicit output reservation → keep the whole window for input.
|
|
5302
|
+
maxOutputTokens: attempt.settings.maxOutputTokens ?? 0
|
|
5303
|
+
});
|
|
5304
|
+
yield { type: "attempt", index };
|
|
5305
|
+
try {
|
|
5306
|
+
for await (const event of attempt.adapter.stream({
|
|
5307
|
+
externalModelId: attempt.model.externalModelId,
|
|
5308
|
+
messages: context,
|
|
5309
|
+
temperature: attempt.settings.temperature,
|
|
5310
|
+
maxOutputTokens: attempt.settings.maxOutputTokens,
|
|
5311
|
+
topP: attempt.settings.topP,
|
|
5312
|
+
...tools,
|
|
5313
|
+
...images,
|
|
5314
|
+
signal: input.signal
|
|
5315
|
+
})) {
|
|
5316
|
+
if (event.type === "delta") {
|
|
5317
|
+
if (event.channel === "reasoning") reasoning += event.text;
|
|
5318
|
+
else answer += event.text;
|
|
5319
|
+
yield { type: "delta", channel: event.channel, text: event.text };
|
|
5320
|
+
} else if (event.type === "tool_calls") {
|
|
5321
|
+
toolCalls = [...event.calls];
|
|
5322
|
+
} else {
|
|
5323
|
+
usage = event.usage;
|
|
5324
|
+
}
|
|
5325
|
+
}
|
|
5326
|
+
} catch (err) {
|
|
5327
|
+
const result2 = {
|
|
5328
|
+
answer,
|
|
5329
|
+
reasoning,
|
|
5330
|
+
usage,
|
|
5331
|
+
toolCalls,
|
|
5332
|
+
durationMs: Date.now() - startedAt
|
|
5333
|
+
};
|
|
5334
|
+
if (input.signal?.aborted === true) {
|
|
5335
|
+
yield { type: "stopped", result: result2 };
|
|
5336
|
+
return;
|
|
5337
|
+
}
|
|
5338
|
+
if (index + 1 < input.attempts.length && canFailover(err, answer.length + reasoning.length)) {
|
|
5339
|
+
continue;
|
|
5340
|
+
}
|
|
5341
|
+
const aiError = err instanceof AiError ? err : errorFromUnknown(err);
|
|
5342
|
+
yield { type: "failed", code: aiError.code, message: aiError.userMessage, result: result2 };
|
|
5343
|
+
return;
|
|
5344
|
+
}
|
|
5345
|
+
const result = {
|
|
5346
|
+
answer,
|
|
5347
|
+
reasoning,
|
|
5348
|
+
usage,
|
|
5349
|
+
toolCalls,
|
|
5350
|
+
durationMs: Date.now() - startedAt
|
|
5351
|
+
};
|
|
5352
|
+
if (toolCalls.length > 0 && input.tools && input.tools.length > 0) {
|
|
5353
|
+
yield { type: "tool_calls", result };
|
|
5354
|
+
return;
|
|
5355
|
+
}
|
|
5356
|
+
yield { type: "done", result };
|
|
5357
|
+
return;
|
|
5358
|
+
}
|
|
5359
|
+
}
|
|
5360
|
+
|
|
5361
|
+
exports.ADAPTER_MEDIA_TIMEOUT_MS = ADAPTER_MEDIA_TIMEOUT_MS;
|
|
5362
|
+
exports.ADAPTER_TIMEOUT_MS = ADAPTER_TIMEOUT_MS;
|
|
4545
5363
|
exports.ANTHROPIC_API_VERSION = ANTHROPIC_API_VERSION;
|
|
4546
5364
|
exports.ANTHROPIC_DEFAULT_MAX_TOKENS = ANTHROPIC_DEFAULT_MAX_TOKENS;
|
|
4547
5365
|
exports.ANTHROPIC_MODELS = ANTHROPIC_MODELS;
|
|
@@ -4557,7 +5375,9 @@ exports.CancellationError = CancellationError;
|
|
|
4557
5375
|
exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
|
|
4558
5376
|
exports.DEFAULT_GENERATION_CONFIG = DEFAULT_GENERATION_CONFIG;
|
|
4559
5377
|
exports.DEFAULT_MODELS = DEFAULT_MODELS;
|
|
5378
|
+
exports.FAL_ASPECT_IMAGE_SIZES = FAL_ASPECT_IMAGE_SIZES;
|
|
4560
5379
|
exports.FalProvider = FalProvider;
|
|
5380
|
+
exports.FalQueueError = FalQueueError;
|
|
4561
5381
|
exports.GEMINI_TIERS = GEMINI_TIERS;
|
|
4562
5382
|
exports.GROQ_MODELS = GROQ_MODELS;
|
|
4563
5383
|
exports.GROQ_TIERS = GROQ_TIERS;
|
|
@@ -4571,6 +5391,7 @@ exports.GroqProvider = GroqProvider;
|
|
|
4571
5391
|
exports.IMAGE_B64_LIMIT = IMAGE_B64_LIMIT;
|
|
4572
5392
|
exports.IMAGE_QUALITIES = IMAGE_QUALITIES;
|
|
4573
5393
|
exports.IMAGE_SIZES = IMAGE_SIZES;
|
|
5394
|
+
exports.OpenAiCompatibleProvider = OpenAiCompatibleProvider;
|
|
4574
5395
|
exports.ProviderError = ProviderError;
|
|
4575
5396
|
exports.ProviderFactory = ProviderFactory;
|
|
4576
5397
|
exports.PrunaProvider = PrunaProvider;
|
|
@@ -4580,18 +5401,33 @@ exports.TIMEOUTS = TIMEOUTS;
|
|
|
4580
5401
|
exports.TextGenerationService = TextGenerationService;
|
|
4581
5402
|
exports.TimeoutError = TimeoutError;
|
|
4582
5403
|
exports.ValidationError = ValidationError;
|
|
5404
|
+
exports.WORKERS_AI_LLM_MODEL = WORKERS_AI_LLM_MODEL;
|
|
5405
|
+
exports.WORKERS_AI_TIERS = WORKERS_AI_TIERS;
|
|
5406
|
+
exports.WorkersAIError = WorkersAIError;
|
|
5407
|
+
exports.WorkersAIProvider = WorkersAIProvider;
|
|
5408
|
+
exports.apiKeyAvailable = apiKeyAvailable;
|
|
5409
|
+
exports.audioTranscriptionAdapterFor = audioTranscriptionAdapterFor;
|
|
5410
|
+
exports.buildFalAudioInput = buildFalAudioInput;
|
|
5411
|
+
exports.buildFalAudioLyrics = buildFalAudioLyrics;
|
|
5412
|
+
exports.buildFalImageInput = buildFalImageInput;
|
|
5413
|
+
exports.buildFalTagPrompt = buildFalTagPrompt;
|
|
5414
|
+
exports.buildFalVideoInput = buildFalVideoInput;
|
|
5415
|
+
exports.chatAdapterFor = chatAdapterFor;
|
|
4583
5416
|
exports.configureProvider = configureProvider;
|
|
4584
5417
|
exports.consumeAnthropicStream = consumeAnthropicStream;
|
|
4585
5418
|
exports.consumeGroqStream = consumeGroqStream;
|
|
4586
5419
|
exports.createAI = createAI;
|
|
5420
|
+
exports.createAdapterResolver = createAdapterResolver;
|
|
4587
5421
|
exports.createAnthropicAdapter = createAnthropicAdapter;
|
|
4588
5422
|
exports.createAssistantMessage = createAssistantMessage;
|
|
4589
5423
|
exports.createFalProvider = createFalProvider;
|
|
5424
|
+
exports.createFalQueue = createFalQueue;
|
|
4590
5425
|
exports.createGeminiProvider = createGeminiProvider;
|
|
4591
5426
|
exports.createGroqProvider = createGroqProvider;
|
|
4592
5427
|
exports.createMessage = createMessage;
|
|
4593
5428
|
exports.createOpenAiAudioTranscriptionAdapter = createOpenAiAudioTranscriptionAdapter;
|
|
4594
5429
|
exports.createOpenAiCompatibleAdapter = createOpenAiCompatibleAdapter;
|
|
5430
|
+
exports.createOpenAiCompatibleProvider = createOpenAiCompatibleProvider;
|
|
4595
5431
|
exports.createOpenAiEmbeddingsAdapter = createOpenAiEmbeddingsAdapter;
|
|
4596
5432
|
exports.createOpenAiImageAdapter = createOpenAiImageAdapter;
|
|
4597
5433
|
exports.createOpenAiSpeechAdapter = createOpenAiSpeechAdapter;
|
|
@@ -4599,23 +5435,37 @@ exports.createProviderFactory = createProviderFactory;
|
|
|
4599
5435
|
exports.createPrunaProvider = createPrunaProvider;
|
|
4600
5436
|
exports.createSystemMessage = createSystemMessage;
|
|
4601
5437
|
exports.createUserMessage = createUserMessage;
|
|
5438
|
+
exports.createWorkersAIProvider = createWorkersAIProvider;
|
|
4602
5439
|
exports.defaultEffortForModel = defaultEffortForModel;
|
|
5440
|
+
exports.embeddingsAdapterFor = embeddingsAdapterFor;
|
|
4603
5441
|
exports.extractContentFromSsePayload = extractContentFromSsePayload;
|
|
4604
5442
|
exports.extractTextFromMessages = extractTextFromMessages;
|
|
5443
|
+
exports.falQueueConfigured = falQueueConfigured;
|
|
4605
5444
|
exports.formatMessagesForDisplay = formatMessagesForDisplay;
|
|
4606
5445
|
exports.generateImageThenVideo = generateImageThenVideo;
|
|
4607
5446
|
exports.generatePruna = generate;
|
|
4608
5447
|
exports.generateWithPruna = generateWithPruna;
|
|
4609
5448
|
exports.getProvider = getProvider;
|
|
5449
|
+
exports.imageAdapterFor = imageAdapterFor;
|
|
4610
5450
|
exports.isMediaProvider = isMediaProvider;
|
|
4611
5451
|
exports.isTextProvider = isTextProvider;
|
|
4612
5452
|
exports.mapAnthropicStopReason = mapAnthropicStopReason;
|
|
5453
|
+
exports.parseFalAudioOutput = parseFalAudioOutput;
|
|
5454
|
+
exports.parseFalImageOutput = parseFalImageOutput;
|
|
5455
|
+
exports.parseFalVideoOutput = parseFalVideoOutput;
|
|
4613
5456
|
exports.pollForResult = pollForResult;
|
|
4614
5457
|
exports.promptToMessages = promptToMessages;
|
|
4615
5458
|
exports.requestStructuredJson = requestStructuredJson;
|
|
4616
5459
|
exports.resetProvider = resetProvider;
|
|
5460
|
+
exports.resolveApiKey = resolveApiKey;
|
|
5461
|
+
exports.runConversation = runConversation;
|
|
5462
|
+
exports.runWorkersAIText = runWorkersAIText;
|
|
5463
|
+
exports.speakWithWorkersAI = speakWithWorkersAI;
|
|
5464
|
+
exports.speechAdapterFor = speechAdapterFor;
|
|
5465
|
+
exports.streamWorkersAIText = streamWorkersAIText;
|
|
4617
5466
|
exports.submitPrediction = submitPrediction;
|
|
4618
5467
|
exports.toGroqMessages = toGroqMessages;
|
|
4619
5468
|
exports.uploadImage = uploadImage;
|
|
5469
|
+
exports.workersAIConfigured = workersAIConfigured;
|
|
4620
5470
|
//# sourceMappingURL=index.cjs.map
|
|
4621
5471
|
//# sourceMappingURL=index.cjs.map
|