nuabase 2.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +836 -82
- package/dist/esm/index.mjs +836 -82
- package/dist/types/backend/gateway.d.ts +1 -0
- package/dist/types/lib/auth.d.ts +1 -0
- package/package.json +1 -1
package/dist/esm/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import require$$0 from 'ajv';
|
|
2
|
-
import require$$1 from 'ajv/dist/2019';
|
|
3
|
-
import require$$2 from 'ajv/dist/2020';
|
|
2
|
+
import require$$1 from 'ajv/dist/2019.js';
|
|
3
|
+
import require$$2 from 'ajv/dist/2020.js';
|
|
4
4
|
import require$$3 from 'ajv/dist/refs/json-schema-draft-07.json';
|
|
5
5
|
import require$$4 from 'ajv/dist/refs/json-schema-draft-06.json';
|
|
6
6
|
import { z } from 'zod';
|
|
@@ -274,8 +274,8 @@ function requireAjvInstances() {
|
|
|
274
274
|
Object.defineProperty(ajvInstances, "__esModule", { value: true });
|
|
275
275
|
ajvInstances.ajvInstances = void 0;
|
|
276
276
|
const ajv_1 = __importDefault(require$$0);
|
|
277
|
-
const
|
|
278
|
-
const
|
|
277
|
+
const _2019_js_1 = __importDefault(require$$1);
|
|
278
|
+
const _2020_js_1 = __importDefault(require$$2);
|
|
279
279
|
const json_schema_draft_07_json_1 = __importDefault(require$$3);
|
|
280
280
|
const json_schema_draft_06_json_1 = __importDefault(require$$4);
|
|
281
281
|
const ajvOptions = {
|
|
@@ -288,10 +288,10 @@ function requireAjvInstances() {
|
|
|
288
288
|
class AjvInstances {
|
|
289
289
|
constructor() {
|
|
290
290
|
this.draft07 = new ajv_1.default(ajvOptions);
|
|
291
|
-
this.draft2019 = new
|
|
291
|
+
this.draft2019 = new _2019_js_1.default(ajvOptions);
|
|
292
292
|
this.draft2019.addMetaSchema(json_schema_draft_07_json_1.default);
|
|
293
293
|
this.draft2019.addMetaSchema(json_schema_draft_06_json_1.default);
|
|
294
|
-
this.draft2020 = new
|
|
294
|
+
this.draft2020 = new _2020_js_1.default(ajvOptions);
|
|
295
295
|
}
|
|
296
296
|
getInstanceForSchema(schema) {
|
|
297
297
|
const schemaVersion = schema.$schema;
|
|
@@ -355,17 +355,15 @@ function requireModelInfo() {
|
|
|
355
355
|
exports$1.parseCanonicalModelName = parseCanonicalModelName;
|
|
356
356
|
exports$1.CANONICAL_MODELS = [
|
|
357
357
|
"qwen3-30b-a3b-instruct-2507",
|
|
358
|
-
"claude-sonnet-4-
|
|
358
|
+
"claude-sonnet-4-6",
|
|
359
359
|
"qwen3-vl-235b-a22b-instruct",
|
|
360
360
|
"qwen3-max",
|
|
361
361
|
"gpt-5",
|
|
362
|
-
"gemini-2.5-flash-lite
|
|
362
|
+
"gemini-2.5-flash-lite",
|
|
363
|
+
"gemini-2.5-flash",
|
|
363
364
|
"qwen3-coder-flash",
|
|
364
365
|
"gpt-oss-120b",
|
|
365
|
-
"
|
|
366
|
-
"gpt-4o",
|
|
367
|
-
"llama-3.3-70b",
|
|
368
|
-
"gemini-2.0-flash"
|
|
366
|
+
"kimi-k2.5"
|
|
369
367
|
];
|
|
370
368
|
const CANONICAL_SET = new Set(exports$1.CANONICAL_MODELS);
|
|
371
369
|
exports$1.SUPPORTED_MODELS = {
|
|
@@ -374,6 +372,10 @@ function requireModelInfo() {
|
|
|
374
372
|
provider: "cerebras",
|
|
375
373
|
providerModelName: "gpt-oss-120b"
|
|
376
374
|
},
|
|
375
|
+
{
|
|
376
|
+
provider: "groq",
|
|
377
|
+
providerModelName: "openai/gpt-oss-120b"
|
|
378
|
+
},
|
|
377
379
|
{
|
|
378
380
|
provider: "openrouter",
|
|
379
381
|
providerModelName: "openai/gpt-oss-120b"
|
|
@@ -385,10 +387,10 @@ function requireModelInfo() {
|
|
|
385
387
|
providerModelName: "qwen/qwen3-30b-a3b-instruct-2507"
|
|
386
388
|
}
|
|
387
389
|
],
|
|
388
|
-
"claude-sonnet-4-
|
|
390
|
+
"claude-sonnet-4-6": [
|
|
389
391
|
{
|
|
390
392
|
provider: "openrouter",
|
|
391
|
-
providerModelName: "anthropic/claude-sonnet-4.
|
|
393
|
+
providerModelName: "anthropic/claude-sonnet-4.6"
|
|
392
394
|
}
|
|
393
395
|
],
|
|
394
396
|
"qwen3-vl-235b-a22b-instruct": [
|
|
@@ -409,40 +411,36 @@ function requireModelInfo() {
|
|
|
409
411
|
providerModelName: "openai/gpt-5"
|
|
410
412
|
}
|
|
411
413
|
],
|
|
412
|
-
"gemini-2.5-flash-lite
|
|
414
|
+
"gemini-2.5-flash-lite": [
|
|
413
415
|
{
|
|
414
|
-
provider: "
|
|
415
|
-
providerModelName: "
|
|
416
|
-
}
|
|
417
|
-
],
|
|
418
|
-
"qwen3-coder-flash": [
|
|
416
|
+
provider: "gemini",
|
|
417
|
+
providerModelName: "gemini-2.5-flash-lite"
|
|
418
|
+
},
|
|
419
419
|
{
|
|
420
420
|
provider: "openrouter",
|
|
421
|
-
providerModelName: "
|
|
421
|
+
providerModelName: "google/gemini-2.5-flash-lite"
|
|
422
422
|
}
|
|
423
423
|
],
|
|
424
|
-
"
|
|
424
|
+
"gemini-2.5-flash": [
|
|
425
425
|
{
|
|
426
|
-
provider: "
|
|
427
|
-
providerModelName: "
|
|
428
|
-
}
|
|
429
|
-
],
|
|
430
|
-
"gpt-4o": [
|
|
426
|
+
provider: "gemini",
|
|
427
|
+
providerModelName: "gemini-2.5-flash"
|
|
428
|
+
},
|
|
431
429
|
{
|
|
432
430
|
provider: "openrouter",
|
|
433
|
-
providerModelName: "
|
|
431
|
+
providerModelName: "google/gemini-2.5-flash"
|
|
434
432
|
}
|
|
435
433
|
],
|
|
436
|
-
"
|
|
434
|
+
"qwen3-coder-flash": [
|
|
437
435
|
{
|
|
438
|
-
provider: "
|
|
439
|
-
providerModelName: "
|
|
436
|
+
provider: "openrouter",
|
|
437
|
+
providerModelName: "qwen/qwen3-coder-flash"
|
|
440
438
|
}
|
|
441
439
|
],
|
|
442
|
-
"
|
|
440
|
+
"kimi-k2.5": [
|
|
443
441
|
{
|
|
444
|
-
provider: "
|
|
445
|
-
providerModelName: "
|
|
442
|
+
provider: "openrouter",
|
|
443
|
+
providerModelName: "moonshotai/kimi-k2.5"
|
|
446
444
|
}
|
|
447
445
|
]
|
|
448
446
|
};
|
|
@@ -455,11 +453,14 @@ function requireModelInfo() {
|
|
|
455
453
|
case "fast":
|
|
456
454
|
m2 = "gpt-oss-120b";
|
|
457
455
|
break;
|
|
456
|
+
case "gemini":
|
|
457
|
+
m2 = "gemini-2.5-flash";
|
|
458
|
+
break;
|
|
458
459
|
case "qwen":
|
|
459
460
|
m2 = "qwen3-vl-235b-a22b-instruct";
|
|
460
461
|
break;
|
|
461
462
|
case "sonnet":
|
|
462
|
-
m2 = "claude-sonnet-4-
|
|
463
|
+
m2 = "claude-sonnet-4-6";
|
|
463
464
|
break;
|
|
464
465
|
case "gpt":
|
|
465
466
|
m2 = "gpt-5";
|
|
@@ -484,7 +485,7 @@ function requireProviderConfig() {
|
|
|
484
485
|
hasRequiredProviderConfig = 1;
|
|
485
486
|
(function(exports$1) {
|
|
486
487
|
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
487
|
-
exports$1.providerConfigs = exports$1.normalizedUsageZero = void 0;
|
|
488
|
+
exports$1.providerConfigs = exports$1.extractOpenAiMessageText = exports$1.normalizeGeminiUsage = exports$1.normalizeOpenAiUsage = exports$1.normalizedUsageZero = void 0;
|
|
488
489
|
exports$1.normalizedUsageZero = {
|
|
489
490
|
promptTokens: 0,
|
|
490
491
|
completionTokens: 0,
|
|
@@ -503,6 +504,7 @@ function requireProviderConfig() {
|
|
|
503
504
|
totalTokens: usage.total_tokens
|
|
504
505
|
};
|
|
505
506
|
};
|
|
507
|
+
exports$1.normalizeOpenAiUsage = normalizeOpenAiUsage;
|
|
506
508
|
const normalizeGeminiUsage = (usage) => {
|
|
507
509
|
if (!usage) {
|
|
508
510
|
return exports$1.normalizedUsageZero;
|
|
@@ -516,6 +518,7 @@ function requireProviderConfig() {
|
|
|
516
518
|
totalTokens: usage.totalTokenCount
|
|
517
519
|
};
|
|
518
520
|
};
|
|
521
|
+
exports$1.normalizeGeminiUsage = normalizeGeminiUsage;
|
|
519
522
|
const buildOpenAiStyleRequest = (baseUrl) => ({ prompt, model, maxTokens, assistantPrefillPrompt }, apiKey) => {
|
|
520
523
|
const messages = [];
|
|
521
524
|
messages.push({ role: "user", content: prompt });
|
|
@@ -550,11 +553,11 @@ function requireProviderConfig() {
|
|
|
550
553
|
const parseOpenAiStyleResponse = (errorLabel) => async (response) => {
|
|
551
554
|
if (response.status === 200) {
|
|
552
555
|
const responseBody = await response.json();
|
|
553
|
-
const responseText = responseBody.choices?.[0]?.message
|
|
556
|
+
const responseText = (0, exports$1.extractOpenAiMessageText)(responseBody.choices?.[0]?.message);
|
|
554
557
|
if (responseText) {
|
|
555
558
|
return {
|
|
556
559
|
text: responseText,
|
|
557
|
-
usage: normalizeOpenAiUsage(responseBody.usage)
|
|
560
|
+
usage: (0, exports$1.normalizeOpenAiUsage)(responseBody.usage)
|
|
558
561
|
};
|
|
559
562
|
}
|
|
560
563
|
throw new Error(`${errorLabel} API error: Could not extract text from response. Body: ${JSON.stringify(responseBody)}`);
|
|
@@ -568,22 +571,28 @@ function requireProviderConfig() {
|
|
|
568
571
|
throw new Error(`${errorLabel} API error: ${response.status} - ${errorBody}`);
|
|
569
572
|
}
|
|
570
573
|
};
|
|
574
|
+
const normalizeOpenAiText = (value) => {
|
|
575
|
+
if (typeof value !== "string") {
|
|
576
|
+
return void 0;
|
|
577
|
+
}
|
|
578
|
+
const trimmed = value.trim();
|
|
579
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
580
|
+
};
|
|
581
|
+
const extractOpenAiMessageText = (message) => {
|
|
582
|
+
if (!message) {
|
|
583
|
+
return void 0;
|
|
584
|
+
}
|
|
585
|
+
return normalizeOpenAiText(message.content) ?? normalizeOpenAiText(message.reasoning) ?? normalizeOpenAiText(message.reasoning_details?.map((detail) => typeof detail === "object" && detail !== null ? "summary" in detail ? detail.summary : void 0 : void 0).find((summary) => summary !== void 0));
|
|
586
|
+
};
|
|
587
|
+
exports$1.extractOpenAiMessageText = extractOpenAiMessageText;
|
|
571
588
|
const parseOpenAiGPT5ThinkingStyleResponse = (errorLabel) => async (response) => {
|
|
572
|
-
const normalize = (value) => {
|
|
573
|
-
if (typeof value !== "string") {
|
|
574
|
-
return void 0;
|
|
575
|
-
}
|
|
576
|
-
const trimmed = value.trim();
|
|
577
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
578
|
-
};
|
|
579
589
|
if (response.status === 200) {
|
|
580
590
|
const responseBody = await response.json();
|
|
581
|
-
const
|
|
582
|
-
const content = normalize(message?.content) ?? normalize(message?.reasoning) ?? normalize(message?.reasoning_details?.map((detail) => typeof detail === "object" && detail !== null ? "summary" in detail ? detail.summary : void 0 : void 0).find((summary) => summary !== void 0));
|
|
591
|
+
const content = (0, exports$1.extractOpenAiMessageText)(responseBody.choices?.[0]?.message);
|
|
583
592
|
if (content) {
|
|
584
593
|
return {
|
|
585
594
|
text: content,
|
|
586
|
-
usage: normalizeOpenAiUsage(responseBody.usage)
|
|
595
|
+
usage: (0, exports$1.normalizeOpenAiUsage)(responseBody.usage)
|
|
587
596
|
};
|
|
588
597
|
}
|
|
589
598
|
throw new Error(`${errorLabel} API error: Could not extract text from thinking response. Body: ${JSON.stringify(responseBody)}`);
|
|
@@ -631,7 +640,7 @@ function requireProviderConfig() {
|
|
|
631
640
|
if (responseText) {
|
|
632
641
|
return {
|
|
633
642
|
text: responseText,
|
|
634
|
-
usage: normalizeGeminiUsage(responseBody.usageMetadata)
|
|
643
|
+
usage: (0, exports$1.normalizeGeminiUsage)(responseBody.usageMetadata)
|
|
635
644
|
};
|
|
636
645
|
}
|
|
637
646
|
throw new Error(`Gemini API error: Could not extract text from response. Body: ${JSON.stringify(responseBody)}`);
|
|
@@ -679,6 +688,496 @@ function requireProviderConfig() {
|
|
|
679
688
|
return providerConfig;
|
|
680
689
|
}
|
|
681
690
|
|
|
691
|
+
var providerFormatters = {};
|
|
692
|
+
|
|
693
|
+
var sseParser = {};
|
|
694
|
+
|
|
695
|
+
var hasRequiredSseParser;
|
|
696
|
+
function requireSseParser() {
|
|
697
|
+
if (hasRequiredSseParser) return sseParser;
|
|
698
|
+
hasRequiredSseParser = 1;
|
|
699
|
+
Object.defineProperty(sseParser, "__esModule", { value: true });
|
|
700
|
+
sseParser.parseSSEStream = parseSSEStream;
|
|
701
|
+
async function* parseSSEStream(stream) {
|
|
702
|
+
const reader = stream.getReader();
|
|
703
|
+
const decoder = new TextDecoder();
|
|
704
|
+
let buffer = "";
|
|
705
|
+
try {
|
|
706
|
+
while (true) {
|
|
707
|
+
const { done, value } = await reader.read();
|
|
708
|
+
if (done)
|
|
709
|
+
break;
|
|
710
|
+
buffer += decoder.decode(value, { stream: true });
|
|
711
|
+
const parts = buffer.split(/\r?\n\r?\n/);
|
|
712
|
+
buffer = parts.pop();
|
|
713
|
+
for (const part of parts) {
|
|
714
|
+
for (const line of part.split(/\r?\n/)) {
|
|
715
|
+
if (line.startsWith("data: ")) {
|
|
716
|
+
const data = line.slice(6);
|
|
717
|
+
if (data === "[DONE]") {
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
yield data;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
if (buffer.trim()) {
|
|
726
|
+
for (const line of buffer.split(/\r?\n/)) {
|
|
727
|
+
if (line.startsWith("data: ")) {
|
|
728
|
+
const data = line.slice(6);
|
|
729
|
+
if (data === "[DONE]") {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
yield data;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
} finally {
|
|
737
|
+
reader.releaseLock();
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
return sseParser;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
var hasRequiredProviderFormatters;
|
|
744
|
+
function requireProviderFormatters() {
|
|
745
|
+
if (hasRequiredProviderFormatters) return providerFormatters;
|
|
746
|
+
hasRequiredProviderFormatters = 1;
|
|
747
|
+
Object.defineProperty(providerFormatters, "__esModule", { value: true });
|
|
748
|
+
providerFormatters.buildOpenAiAgenticRequest = buildOpenAiAgenticRequest;
|
|
749
|
+
providerFormatters.parseOpenAiAgenticResponse = parseOpenAiAgenticResponse;
|
|
750
|
+
providerFormatters.buildGeminiAgenticRequest = buildGeminiAgenticRequest;
|
|
751
|
+
providerFormatters.parseGeminiAgenticResponse = parseGeminiAgenticResponse;
|
|
752
|
+
providerFormatters.streamOpenAiAgenticResponse = streamOpenAiAgenticResponse;
|
|
753
|
+
providerFormatters.streamGeminiAgenticResponse = streamGeminiAgenticResponse;
|
|
754
|
+
const provider_config_1 = requireProviderConfig();
|
|
755
|
+
const sse_parser_1 = requireSseParser();
|
|
756
|
+
function convertMessagesToOpenAi(messages, systemPrompt) {
|
|
757
|
+
const result = [];
|
|
758
|
+
if (systemPrompt) {
|
|
759
|
+
result.push({ role: "system", content: systemPrompt });
|
|
760
|
+
}
|
|
761
|
+
for (const msg of messages) {
|
|
762
|
+
switch (msg.role) {
|
|
763
|
+
case "user":
|
|
764
|
+
result.push({ role: "user", content: msg.content });
|
|
765
|
+
break;
|
|
766
|
+
case "assistant": {
|
|
767
|
+
const textParts = msg.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
768
|
+
const toolCalls = msg.content.filter((c) => c.type === "toolCall").map((c) => ({
|
|
769
|
+
id: c.id,
|
|
770
|
+
type: "function",
|
|
771
|
+
function: {
|
|
772
|
+
name: c.name,
|
|
773
|
+
arguments: JSON.stringify(c.arguments)
|
|
774
|
+
}
|
|
775
|
+
}));
|
|
776
|
+
const openAiMsg = {
|
|
777
|
+
role: "assistant",
|
|
778
|
+
content: textParts || null,
|
|
779
|
+
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
|
|
780
|
+
};
|
|
781
|
+
result.push(openAiMsg);
|
|
782
|
+
break;
|
|
783
|
+
}
|
|
784
|
+
case "toolResult":
|
|
785
|
+
result.push({
|
|
786
|
+
role: "tool",
|
|
787
|
+
tool_call_id: msg.toolCallId,
|
|
788
|
+
content: msg.content
|
|
789
|
+
});
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
return result;
|
|
794
|
+
}
|
|
795
|
+
function convertToolsToOpenAi(tools) {
|
|
796
|
+
return tools.map((t) => ({
|
|
797
|
+
type: "function",
|
|
798
|
+
function: {
|
|
799
|
+
name: t.name,
|
|
800
|
+
description: t.description,
|
|
801
|
+
parameters: t.parameters
|
|
802
|
+
}
|
|
803
|
+
}));
|
|
804
|
+
}
|
|
805
|
+
function buildOpenAiAgenticRequest(options, baseUrl, apiKey) {
|
|
806
|
+
const messages = convertMessagesToOpenAi(options.messages, options.systemPrompt);
|
|
807
|
+
const tools = convertToolsToOpenAi(options.tools);
|
|
808
|
+
const body = {
|
|
809
|
+
messages,
|
|
810
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
811
|
+
model: options.model,
|
|
812
|
+
max_completion_tokens: options.maxTokens,
|
|
813
|
+
stream: options.stream ?? false
|
|
814
|
+
};
|
|
815
|
+
if (options.stream) {
|
|
816
|
+
body.stream_options = { include_usage: true };
|
|
817
|
+
}
|
|
818
|
+
const headers = {
|
|
819
|
+
"Content-Type": "application/json",
|
|
820
|
+
Authorization: `Bearer ${apiKey}`
|
|
821
|
+
};
|
|
822
|
+
return {
|
|
823
|
+
url: baseUrl,
|
|
824
|
+
method: "POST",
|
|
825
|
+
headers,
|
|
826
|
+
body,
|
|
827
|
+
loggableHeaders: {
|
|
828
|
+
...headers,
|
|
829
|
+
Authorization: "Bearer [REDACTED]"
|
|
830
|
+
},
|
|
831
|
+
loggableBody: body
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
function parseOpenAiToolArguments(rawArguments, toolName, errorLabel) {
|
|
835
|
+
if (!rawArguments.trim()) {
|
|
836
|
+
return {};
|
|
837
|
+
}
|
|
838
|
+
let parsed;
|
|
839
|
+
try {
|
|
840
|
+
parsed = JSON.parse(rawArguments);
|
|
841
|
+
} catch {
|
|
842
|
+
const preview = rawArguments.length > 500 ? rawArguments.slice(0, 500) + "..." : rawArguments;
|
|
843
|
+
throw new Error(`${errorLabel} API error: Invalid JSON arguments for tool "${toolName}": ${preview}`);
|
|
844
|
+
}
|
|
845
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
846
|
+
throw new Error(`${errorLabel} API error: Tool "${toolName}" arguments must be a JSON object`);
|
|
847
|
+
}
|
|
848
|
+
return parsed;
|
|
849
|
+
}
|
|
850
|
+
async function parseOpenAiAgenticResponse(response, errorLabel) {
|
|
851
|
+
if (response.status !== 200) {
|
|
852
|
+
const errorBody = await response.text();
|
|
853
|
+
try {
|
|
854
|
+
const parsed = JSON.parse(errorBody);
|
|
855
|
+
const message = parsed?.error?.message || errorBody;
|
|
856
|
+
throw new Error(`${errorLabel} API error: ${response.status} - ${message}`);
|
|
857
|
+
} catch (e) {
|
|
858
|
+
if (e instanceof Error && e.message.startsWith(`${errorLabel} API error:`))
|
|
859
|
+
throw e;
|
|
860
|
+
throw new Error(`${errorLabel} API error: ${response.status} - ${errorBody}`);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
const responseBody = await response.json();
|
|
864
|
+
const choice = responseBody.choices?.[0];
|
|
865
|
+
if (!choice?.message) {
|
|
866
|
+
throw new Error(`${errorLabel} API error: No message in response. Body: ${JSON.stringify(responseBody)}`);
|
|
867
|
+
}
|
|
868
|
+
const contentBlocks = [];
|
|
869
|
+
const assistantText = (0, provider_config_1.extractOpenAiMessageText)(choice.message);
|
|
870
|
+
if (assistantText) {
|
|
871
|
+
contentBlocks.push({
|
|
872
|
+
type: "text",
|
|
873
|
+
text: assistantText
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
if (choice.message.tool_calls) {
|
|
877
|
+
for (const tc of choice.message.tool_calls) {
|
|
878
|
+
contentBlocks.push({
|
|
879
|
+
type: "toolCall",
|
|
880
|
+
id: tc.id,
|
|
881
|
+
name: tc.function.name,
|
|
882
|
+
arguments: parseOpenAiToolArguments(tc.function.arguments, tc.function.name, errorLabel)
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
const usage = (0, provider_config_1.normalizeOpenAiUsage)(responseBody.usage);
|
|
887
|
+
const stopReason = choice.finish_reason === "tool_calls" || choice.finish_reason === "stop" ? choice.finish_reason === "tool_calls" ? "tool_use" : "stop" : choice.message.tool_calls && choice.message.tool_calls.length > 0 ? "tool_use" : "stop";
|
|
888
|
+
return {
|
|
889
|
+
message: {
|
|
890
|
+
role: "assistant",
|
|
891
|
+
content: contentBlocks
|
|
892
|
+
},
|
|
893
|
+
usage,
|
|
894
|
+
stopReason
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
function convertMessagesToGemini(messages) {
|
|
898
|
+
const result = [];
|
|
899
|
+
for (const msg of messages) {
|
|
900
|
+
switch (msg.role) {
|
|
901
|
+
case "user":
|
|
902
|
+
result.push({
|
|
903
|
+
role: "user",
|
|
904
|
+
parts: [{ text: msg.content }]
|
|
905
|
+
});
|
|
906
|
+
break;
|
|
907
|
+
case "assistant": {
|
|
908
|
+
const parts = [];
|
|
909
|
+
for (const block of msg.content) {
|
|
910
|
+
if (block.type === "text") {
|
|
911
|
+
parts.push({ text: block.text });
|
|
912
|
+
} else if (block.type === "toolCall") {
|
|
913
|
+
parts.push({
|
|
914
|
+
functionCall: {
|
|
915
|
+
name: block.name,
|
|
916
|
+
args: block.arguments
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
result.push({ role: "model", parts });
|
|
922
|
+
break;
|
|
923
|
+
}
|
|
924
|
+
case "toolResult": {
|
|
925
|
+
result.push({
|
|
926
|
+
role: "user",
|
|
927
|
+
parts: [
|
|
928
|
+
{
|
|
929
|
+
functionResponse: {
|
|
930
|
+
name: msg.toolName,
|
|
931
|
+
response: { content: msg.content }
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
]
|
|
935
|
+
});
|
|
936
|
+
break;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return result;
|
|
941
|
+
}
|
|
942
|
+
function convertToolsToGemini(tools) {
|
|
943
|
+
if (tools.length === 0)
|
|
944
|
+
return [];
|
|
945
|
+
return [
|
|
946
|
+
{
|
|
947
|
+
functionDeclarations: tools.map((t) => ({
|
|
948
|
+
name: t.name,
|
|
949
|
+
description: t.description,
|
|
950
|
+
parameters: t.parameters
|
|
951
|
+
}))
|
|
952
|
+
}
|
|
953
|
+
];
|
|
954
|
+
}
|
|
955
|
+
function buildGeminiAgenticRequest(options, apiKey) {
|
|
956
|
+
const contents = convertMessagesToGemini(options.messages);
|
|
957
|
+
const tools = convertToolsToGemini(options.tools);
|
|
958
|
+
const body = {
|
|
959
|
+
contents,
|
|
960
|
+
generationConfig: {
|
|
961
|
+
maxOutputTokens: options.maxTokens
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
if (tools.length > 0) {
|
|
965
|
+
body.tools = tools;
|
|
966
|
+
}
|
|
967
|
+
if (options.systemPrompt) {
|
|
968
|
+
body.systemInstruction = {
|
|
969
|
+
parts: [{ text: options.systemPrompt }]
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
const action = options.stream ? "streamGenerateContent" : "generateContent";
|
|
973
|
+
const altParam = options.stream ? "&alt=sse" : "";
|
|
974
|
+
const url = `https://generativelanguage.googleapis.com/v1beta/models/${options.model}:${action}?key=${apiKey}${altParam}`;
|
|
975
|
+
return {
|
|
976
|
+
url,
|
|
977
|
+
method: "POST",
|
|
978
|
+
headers: {
|
|
979
|
+
"Content-Type": "application/json"
|
|
980
|
+
},
|
|
981
|
+
body,
|
|
982
|
+
loggableUrl: url.replace(/key=[^&]+/, "key=[REDACTED]"),
|
|
983
|
+
loggableBody: body
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
async function parseGeminiAgenticResponse(response) {
|
|
987
|
+
if (response.status !== 200) {
|
|
988
|
+
const errorBody = await response.text();
|
|
989
|
+
try {
|
|
990
|
+
const parsed = JSON.parse(errorBody);
|
|
991
|
+
const message = parsed?.error?.message || errorBody;
|
|
992
|
+
throw new Error(`Gemini API error: ${response.status} - ${message}`);
|
|
993
|
+
} catch (e) {
|
|
994
|
+
if (e instanceof Error && e.message.startsWith("Gemini API error:"))
|
|
995
|
+
throw e;
|
|
996
|
+
throw new Error(`Gemini API error: ${response.status} - ${errorBody}`);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
const responseBody = await response.json();
|
|
1000
|
+
const candidate = responseBody.candidates?.[0];
|
|
1001
|
+
if (!candidate?.content?.parts) {
|
|
1002
|
+
throw new Error(`Gemini API error: No content in response. Body: ${JSON.stringify(responseBody)}`);
|
|
1003
|
+
}
|
|
1004
|
+
const contentBlocks = [];
|
|
1005
|
+
let hasToolCalls = false;
|
|
1006
|
+
for (const part of candidate.content.parts) {
|
|
1007
|
+
if (part.text) {
|
|
1008
|
+
contentBlocks.push({ type: "text", text: part.text });
|
|
1009
|
+
}
|
|
1010
|
+
if (part.functionCall) {
|
|
1011
|
+
hasToolCalls = true;
|
|
1012
|
+
contentBlocks.push({
|
|
1013
|
+
type: "toolCall",
|
|
1014
|
+
id: crypto.randomUUID(),
|
|
1015
|
+
name: part.functionCall.name,
|
|
1016
|
+
arguments: part.functionCall.args
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
const usage = (0, provider_config_1.normalizeGeminiUsage)(responseBody.usageMetadata);
|
|
1021
|
+
const stopReason = hasToolCalls ? "tool_use" : "stop";
|
|
1022
|
+
return {
|
|
1023
|
+
message: {
|
|
1024
|
+
role: "assistant",
|
|
1025
|
+
content: contentBlocks
|
|
1026
|
+
},
|
|
1027
|
+
usage,
|
|
1028
|
+
stopReason
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
function safeEmit(onEvent, event) {
|
|
1032
|
+
if (!onEvent)
|
|
1033
|
+
return;
|
|
1034
|
+
try {
|
|
1035
|
+
onEvent(event);
|
|
1036
|
+
} catch {
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
async function streamOpenAiAgenticResponse(response, errorLabel, onEvent) {
|
|
1040
|
+
if (response.status !== 200) {
|
|
1041
|
+
const errorBody = await response.text();
|
|
1042
|
+
try {
|
|
1043
|
+
const parsed = JSON.parse(errorBody);
|
|
1044
|
+
const message = parsed?.error?.message || errorBody;
|
|
1045
|
+
throw new Error(`${errorLabel} API error: ${response.status} - ${message}`);
|
|
1046
|
+
} catch (e) {
|
|
1047
|
+
if (e instanceof Error && e.message.startsWith(`${errorLabel} API error:`))
|
|
1048
|
+
throw e;
|
|
1049
|
+
throw new Error(`${errorLabel} API error: ${response.status} - ${errorBody}`);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
if (!response.body) {
|
|
1053
|
+
throw new Error(`${errorLabel} API error: Response body is null`);
|
|
1054
|
+
}
|
|
1055
|
+
let textContent = "";
|
|
1056
|
+
const toolCallAccumulators = /* @__PURE__ */ new Map();
|
|
1057
|
+
let finishReason = null;
|
|
1058
|
+
let usage = { ...provider_config_1.normalizedUsageZero };
|
|
1059
|
+
for await (const data of (0, sse_parser_1.parseSSEStream)(response.body)) {
|
|
1060
|
+
let chunk;
|
|
1061
|
+
try {
|
|
1062
|
+
chunk = JSON.parse(data);
|
|
1063
|
+
} catch {
|
|
1064
|
+
continue;
|
|
1065
|
+
}
|
|
1066
|
+
if (chunk.usage) {
|
|
1067
|
+
usage = (0, provider_config_1.normalizeOpenAiUsage)(chunk.usage);
|
|
1068
|
+
}
|
|
1069
|
+
const choice = chunk.choices?.[0];
|
|
1070
|
+
if (!choice)
|
|
1071
|
+
continue;
|
|
1072
|
+
if (choice.finish_reason) {
|
|
1073
|
+
finishReason = choice.finish_reason;
|
|
1074
|
+
}
|
|
1075
|
+
const delta = choice.delta;
|
|
1076
|
+
if (!delta)
|
|
1077
|
+
continue;
|
|
1078
|
+
if (delta.content) {
|
|
1079
|
+
textContent += delta.content;
|
|
1080
|
+
safeEmit(onEvent, { type: "text_delta", text: delta.content });
|
|
1081
|
+
}
|
|
1082
|
+
if (delta.tool_calls) {
|
|
1083
|
+
for (const tc of delta.tool_calls) {
|
|
1084
|
+
const existing = toolCallAccumulators.get(tc.index);
|
|
1085
|
+
if (existing) {
|
|
1086
|
+
if (tc.function?.arguments) {
|
|
1087
|
+
existing.arguments += tc.function.arguments;
|
|
1088
|
+
}
|
|
1089
|
+
} else {
|
|
1090
|
+
toolCallAccumulators.set(tc.index, {
|
|
1091
|
+
id: tc.id ?? "",
|
|
1092
|
+
name: tc.function?.name ?? "",
|
|
1093
|
+
arguments: tc.function?.arguments ?? ""
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
const contentBlocks = [];
|
|
1100
|
+
if (textContent) {
|
|
1101
|
+
contentBlocks.push({ type: "text", text: textContent });
|
|
1102
|
+
}
|
|
1103
|
+
const sortedToolCalls = [...toolCallAccumulators.entries()].sort(([a], [b]) => a - b);
|
|
1104
|
+
for (const [, tc] of sortedToolCalls) {
|
|
1105
|
+
contentBlocks.push({
|
|
1106
|
+
type: "toolCall",
|
|
1107
|
+
id: tc.id,
|
|
1108
|
+
name: tc.name,
|
|
1109
|
+
arguments: parseOpenAiToolArguments(tc.arguments, tc.name, errorLabel)
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
const stopReason2 = finishReason === "tool_calls" || sortedToolCalls.length > 0 ? "tool_use" : "stop";
|
|
1113
|
+
return {
|
|
1114
|
+
message: { role: "assistant", content: contentBlocks },
|
|
1115
|
+
usage,
|
|
1116
|
+
stopReason: stopReason2
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
async function streamGeminiAgenticResponse(response, onEvent) {
|
|
1120
|
+
if (response.status !== 200) {
|
|
1121
|
+
const errorBody = await response.text();
|
|
1122
|
+
try {
|
|
1123
|
+
const parsed = JSON.parse(errorBody);
|
|
1124
|
+
const message = parsed?.error?.message || errorBody;
|
|
1125
|
+
throw new Error(`Gemini API error: ${response.status} - ${message}`);
|
|
1126
|
+
} catch (e) {
|
|
1127
|
+
if (e instanceof Error && e.message.startsWith("Gemini API error:"))
|
|
1128
|
+
throw e;
|
|
1129
|
+
throw new Error(`Gemini API error: ${response.status} - ${errorBody}`);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
if (!response.body) {
|
|
1133
|
+
throw new Error("Gemini API error: Response body is null");
|
|
1134
|
+
}
|
|
1135
|
+
const contentBlocks = [];
|
|
1136
|
+
let hasToolCalls2 = false;
|
|
1137
|
+
let textContent2 = "";
|
|
1138
|
+
let usage2 = { ...provider_config_1.normalizedUsageZero };
|
|
1139
|
+
for await (const data of (0, sse_parser_1.parseSSEStream)(response.body)) {
|
|
1140
|
+
let chunk;
|
|
1141
|
+
try {
|
|
1142
|
+
chunk = JSON.parse(data);
|
|
1143
|
+
} catch {
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
if (chunk.usageMetadata) {
|
|
1147
|
+
usage2 = (0, provider_config_1.normalizeGeminiUsage)(chunk.usageMetadata);
|
|
1148
|
+
}
|
|
1149
|
+
const candidate = chunk.candidates?.[0];
|
|
1150
|
+
if (!candidate?.content?.parts)
|
|
1151
|
+
continue;
|
|
1152
|
+
for (const part of candidate.content.parts) {
|
|
1153
|
+
if (part.text) {
|
|
1154
|
+
textContent2 += part.text;
|
|
1155
|
+
safeEmit(onEvent, { type: "text_delta", text: part.text });
|
|
1156
|
+
}
|
|
1157
|
+
if (part.functionCall) {
|
|
1158
|
+
hasToolCalls2 = true;
|
|
1159
|
+
contentBlocks.push({
|
|
1160
|
+
type: "toolCall",
|
|
1161
|
+
id: crypto.randomUUID(),
|
|
1162
|
+
name: part.functionCall.name,
|
|
1163
|
+
arguments: part.functionCall.args
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
if (textContent2) {
|
|
1169
|
+
contentBlocks.unshift({ type: "text", text: textContent2 });
|
|
1170
|
+
}
|
|
1171
|
+
const stopReason3 = hasToolCalls2 ? "tool_use" : "stop";
|
|
1172
|
+
return {
|
|
1173
|
+
message: { role: "assistant", content: contentBlocks },
|
|
1174
|
+
usage: usage2,
|
|
1175
|
+
stopReason: stopReason3
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
return providerFormatters;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
682
1181
|
var hasRequiredHttpLlmClient;
|
|
683
1182
|
function requireHttpLlmClient() {
|
|
684
1183
|
if (hasRequiredHttpLlmClient) return httpLlmClient;
|
|
@@ -688,6 +1187,7 @@ function requireHttpLlmClient() {
|
|
|
688
1187
|
const model_info_1 = requireModelInfo();
|
|
689
1188
|
const logger_1 = requireLogger();
|
|
690
1189
|
const provider_config_1 = requireProviderConfig();
|
|
1190
|
+
const provider_formatters_1 = requireProviderFormatters();
|
|
691
1191
|
class HttpLlmClient {
|
|
692
1192
|
constructor(providerId, apiKey, logger) {
|
|
693
1193
|
this.providerId = providerId;
|
|
@@ -695,51 +1195,133 @@ function requireHttpLlmClient() {
|
|
|
695
1195
|
this.logger = logger;
|
|
696
1196
|
}
|
|
697
1197
|
async sendRequest(prompt, model, maxTokens, assistantPrefillPrompt) {
|
|
1198
|
+
const provider = this.getProviderConfig();
|
|
1199
|
+
const providerModelName = this.getProviderModelName(model);
|
|
1200
|
+
const requestOptions = provider.buildRequest({
|
|
1201
|
+
prompt,
|
|
1202
|
+
model: providerModelName,
|
|
1203
|
+
maxTokens,
|
|
1204
|
+
assistantPrefillPrompt
|
|
1205
|
+
}, this.apiKey);
|
|
1206
|
+
return this.executeProviderCall({
|
|
1207
|
+
provider,
|
|
1208
|
+
model,
|
|
1209
|
+
maxTokens,
|
|
1210
|
+
apiOperation: provider.apiOperation,
|
|
1211
|
+
requestOptions,
|
|
1212
|
+
parseResponse: provider.parseResponse,
|
|
1213
|
+
getResponsePreview: (parsedResponse) => parsedResponse.text,
|
|
1214
|
+
getUsage: (parsedResponse) => parsedResponse.usage
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
async sendAgenticRequest(messages, tools, model, maxTokens, systemPrompt, onEvent) {
|
|
1218
|
+
const provider = this.getProviderConfig();
|
|
1219
|
+
const providerModelName = this.getProviderModelName(model);
|
|
1220
|
+
const codec = this.getAgenticProviderCodec(provider.errorLabel);
|
|
1221
|
+
const requestOptions = codec.buildRequest({
|
|
1222
|
+
messages,
|
|
1223
|
+
tools,
|
|
1224
|
+
model: providerModelName,
|
|
1225
|
+
maxTokens,
|
|
1226
|
+
systemPrompt,
|
|
1227
|
+
stream: !!onEvent
|
|
1228
|
+
});
|
|
1229
|
+
const parseResponse = onEvent ? (response) => codec.parseStreamingResponse(response, onEvent) : codec.parseResponse;
|
|
1230
|
+
return this.executeProviderCall({
|
|
1231
|
+
provider,
|
|
1232
|
+
model,
|
|
1233
|
+
maxTokens,
|
|
1234
|
+
apiOperation: "agentic",
|
|
1235
|
+
requestOptions,
|
|
1236
|
+
parseResponse,
|
|
1237
|
+
getResponsePreview: (parsedResponse) => parsedResponse.message.content.filter((content) => content.type === "text").map((content) => content.text).join(""),
|
|
1238
|
+
getUsage: (parsedResponse) => parsedResponse.usage
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
getProviderConfig() {
|
|
698
1242
|
const provider = provider_config_1.providerConfigs[this.providerId];
|
|
699
1243
|
if (!provider) {
|
|
700
1244
|
throw new Error(`Unknown LLM provider: ${this.providerId}`);
|
|
701
1245
|
}
|
|
1246
|
+
return provider;
|
|
1247
|
+
}
|
|
1248
|
+
getProviderModelName(model) {
|
|
702
1249
|
const providerSpecificModelName = model_info_1.SUPPORTED_MODELS[model].find((pm) => pm.provider === this.providerId);
|
|
703
1250
|
if (!providerSpecificModelName) {
|
|
704
1251
|
throw new Error(`LLM Provider ${this.providerId} does not support model ${model}. If this is an error and the provider does support this model, please contact us to fix it`);
|
|
705
1252
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
const method = requestOptions.method ?? "POST";
|
|
713
|
-
const headers = requestOptions.headers ?? {};
|
|
714
|
-
const bodyPayload = requestOptions.body;
|
|
715
|
-
const body = typeof bodyPayload === "string" ? bodyPayload : bodyPayload !== void 0 ? JSON.stringify(bodyPayload) : void 0;
|
|
1253
|
+
return providerSpecificModelName.providerModelName;
|
|
1254
|
+
}
|
|
1255
|
+
async executeProviderCall(params) {
|
|
1256
|
+
const method = params.requestOptions.method ?? "POST";
|
|
1257
|
+
const headers = params.requestOptions.headers ?? {};
|
|
1258
|
+
const body = this.toFetchableBody(params.requestOptions.body);
|
|
716
1259
|
const spanId = (0, logger_1.generateSpanId)();
|
|
717
1260
|
const startTime = Date.now();
|
|
718
|
-
(0, logger_1.logLlmCallStart)(this.logger, spanId, provider.providerId,
|
|
719
|
-
url: requestOptions.loggableUrl ?? requestOptions.url,
|
|
1261
|
+
(0, logger_1.logLlmCallStart)(this.logger, spanId, params.provider.providerId, params.apiOperation, {
|
|
1262
|
+
url: params.requestOptions.loggableUrl ?? params.requestOptions.url,
|
|
720
1263
|
httpMethod: method,
|
|
721
|
-
model,
|
|
722
|
-
maxTokens
|
|
1264
|
+
model: params.model,
|
|
1265
|
+
maxTokens: params.maxTokens
|
|
723
1266
|
});
|
|
724
1267
|
try {
|
|
725
|
-
const response = await fetch(requestOptions.url, {
|
|
1268
|
+
const response = await fetch(params.requestOptions.url, {
|
|
726
1269
|
method,
|
|
727
1270
|
headers,
|
|
728
1271
|
body
|
|
729
1272
|
});
|
|
730
|
-
const parsedResponse = await
|
|
1273
|
+
const parsedResponse = await params.parseResponse(response);
|
|
731
1274
|
const duration = Date.now() - startTime;
|
|
732
|
-
(0, logger_1.logLlmCallComplete)(this.logger, spanId, provider.providerId,
|
|
1275
|
+
(0, logger_1.logLlmCallComplete)(this.logger, spanId, params.provider.providerId, params.apiOperation, {
|
|
733
1276
|
status: response.status,
|
|
734
|
-
responseText: parsedResponse
|
|
1277
|
+
responseText: params.getResponsePreview(parsedResponse),
|
|
735
1278
|
headers: Object.fromEntries(response.headers.entries()),
|
|
736
|
-
usage: parsedResponse
|
|
1279
|
+
usage: params.getUsage(parsedResponse)
|
|
737
1280
|
}, duration);
|
|
738
1281
|
return parsedResponse;
|
|
739
1282
|
} catch (error) {
|
|
740
1283
|
const duration = Date.now() - startTime;
|
|
741
|
-
(0, logger_1.logLlmCallError)(this.logger, spanId, provider.providerId,
|
|
742
|
-
throw new Error(`${provider.errorLabel} API request failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1284
|
+
(0, logger_1.logLlmCallError)(this.logger, spanId, params.provider.providerId, params.apiOperation, error, duration);
|
|
1285
|
+
throw new Error(`${params.provider.errorLabel} API request failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
toFetchableBody(bodyPayload) {
|
|
1289
|
+
if (typeof bodyPayload === "string") {
|
|
1290
|
+
return bodyPayload;
|
|
1291
|
+
}
|
|
1292
|
+
if (bodyPayload === void 0) {
|
|
1293
|
+
return void 0;
|
|
1294
|
+
}
|
|
1295
|
+
return JSON.stringify(bodyPayload);
|
|
1296
|
+
}
|
|
1297
|
+
getAgenticProviderCodec(errorLabel) {
|
|
1298
|
+
switch (this.providerId) {
|
|
1299
|
+
case "groq":
|
|
1300
|
+
return {
|
|
1301
|
+
buildRequest: (options) => (0, provider_formatters_1.buildOpenAiAgenticRequest)(options, "https://api.groq.com/openai/v1/chat/completions", this.apiKey),
|
|
1302
|
+
parseResponse: (response) => (0, provider_formatters_1.parseOpenAiAgenticResponse)(response, errorLabel),
|
|
1303
|
+
parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamOpenAiAgenticResponse)(response, errorLabel, onEvent)
|
|
1304
|
+
};
|
|
1305
|
+
case "cerebras":
|
|
1306
|
+
return {
|
|
1307
|
+
buildRequest: (options) => (0, provider_formatters_1.buildOpenAiAgenticRequest)(options, "https://api.cerebras.ai/v1/chat/completions", this.apiKey),
|
|
1308
|
+
parseResponse: (response) => (0, provider_formatters_1.parseOpenAiAgenticResponse)(response, errorLabel),
|
|
1309
|
+
parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamOpenAiAgenticResponse)(response, errorLabel, onEvent)
|
|
1310
|
+
};
|
|
1311
|
+
case "openrouter":
|
|
1312
|
+
return {
|
|
1313
|
+
buildRequest: (options) => (0, provider_formatters_1.buildOpenAiAgenticRequest)(options, "https://openrouter.ai/api/v1/chat/completions", this.apiKey),
|
|
1314
|
+
parseResponse: (response) => (0, provider_formatters_1.parseOpenAiAgenticResponse)(response, errorLabel),
|
|
1315
|
+
parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamOpenAiAgenticResponse)(response, errorLabel, onEvent)
|
|
1316
|
+
};
|
|
1317
|
+
case "gemini":
|
|
1318
|
+
return {
|
|
1319
|
+
buildRequest: (options) => (0, provider_formatters_1.buildGeminiAgenticRequest)(options, this.apiKey),
|
|
1320
|
+
parseResponse: provider_formatters_1.parseGeminiAgenticResponse,
|
|
1321
|
+
parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamGeminiAgenticResponse)(response, onEvent)
|
|
1322
|
+
};
|
|
1323
|
+
default:
|
|
1324
|
+
throw new Error(`Unsupported provider for agentic requests: ${this.providerId}`);
|
|
743
1325
|
}
|
|
744
1326
|
}
|
|
745
1327
|
}
|
|
@@ -827,7 +1409,8 @@ function requireCastPromptBuilder() {
|
|
|
827
1409
|
`Your entire response should be just the value of '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}', as valid JSON.`,
|
|
828
1410
|
`And it should not be wrapped in any wrapper object -- return exactly what the JSON schema is expecting.`,
|
|
829
1411
|
`We will validate the result with the AJV Node library, using ajv.parse, against the given schema, and we expect`,
|
|
830
|
-
`it to validate correctly
|
|
1412
|
+
`it to validate correctly.`,
|
|
1413
|
+
`IMPORTANT: Output raw JSON only. No markdown code fences, no explanation, no commentary, no extra fields beyond the schema. Do not correct yourself -- produce the right answer on the first try.`
|
|
831
1414
|
].join(" ");
|
|
832
1415
|
const buildSystemPrompt = (reqParams) => {
|
|
833
1416
|
let a = BASE_SYSTEM_PROMPT_WHEN_OUTPUT_TYPE_NAME_PROVIDED;
|
|
@@ -879,6 +1462,145 @@ function requireNuaErrors() {
|
|
|
879
1462
|
return nuaErrors;
|
|
880
1463
|
}
|
|
881
1464
|
|
|
1465
|
+
var agentLoop = {};
|
|
1466
|
+
|
|
1467
|
+
var hasRequiredAgentLoop;
|
|
1468
|
+
function requireAgentLoop() {
|
|
1469
|
+
if (hasRequiredAgentLoop) return agentLoop;
|
|
1470
|
+
hasRequiredAgentLoop = 1;
|
|
1471
|
+
Object.defineProperty(agentLoop, "__esModule", { value: true });
|
|
1472
|
+
agentLoop.runAgentLoop = runAgentLoop;
|
|
1473
|
+
const provider_config_1 = requireProviderConfig();
|
|
1474
|
+
function safeEmit(onEvent, event) {
|
|
1475
|
+
if (!onEvent)
|
|
1476
|
+
return;
|
|
1477
|
+
try {
|
|
1478
|
+
onEvent(event);
|
|
1479
|
+
} catch {
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
async function runAgentLoop(params) {
|
|
1483
|
+
const messages = [...params.messages];
|
|
1484
|
+
let totalUsage = { ...provider_config_1.normalizedUsageZero };
|
|
1485
|
+
const toolsByName = new Map(params.tools.map((tool) => [tool.name, tool]));
|
|
1486
|
+
let completionReason = "max_turns";
|
|
1487
|
+
const onEvent = params.onEvent;
|
|
1488
|
+
for (let turn = 0; turn < params.maxTurns; turn++) {
|
|
1489
|
+
safeEmit(onEvent, { type: "turn_start", turn });
|
|
1490
|
+
let response;
|
|
1491
|
+
try {
|
|
1492
|
+
response = await params.sendRequest(messages, params.tools, params.systemPrompt);
|
|
1493
|
+
} catch (error) {
|
|
1494
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1495
|
+
safeEmit(onEvent, { type: "error", error: errorMessage });
|
|
1496
|
+
return buildAgentResult(messages, totalUsage, "error", errorMessage);
|
|
1497
|
+
}
|
|
1498
|
+
messages.push(response.message);
|
|
1499
|
+
totalUsage = addUsage(totalUsage, response.usage);
|
|
1500
|
+
safeEmit(onEvent, {
|
|
1501
|
+
type: "response_complete",
|
|
1502
|
+
message: response.message,
|
|
1503
|
+
usage: response.usage,
|
|
1504
|
+
stopReason: response.stopReason
|
|
1505
|
+
});
|
|
1506
|
+
const toolCalls = response.message.content.filter((c) => c.type === "toolCall");
|
|
1507
|
+
if (toolCalls.length === 0 || response.stopReason === "stop") {
|
|
1508
|
+
completionReason = "stop";
|
|
1509
|
+
return buildAgentResult(messages, totalUsage, completionReason);
|
|
1510
|
+
}
|
|
1511
|
+
for (const toolCall of toolCalls) {
|
|
1512
|
+
safeEmit(onEvent, {
|
|
1513
|
+
type: "tool_start",
|
|
1514
|
+
toolCallId: toolCall.id,
|
|
1515
|
+
toolName: toolCall.name,
|
|
1516
|
+
arguments: toolCall.arguments
|
|
1517
|
+
});
|
|
1518
|
+
const tool = toolsByName.get(toolCall.name);
|
|
1519
|
+
if (!tool) {
|
|
1520
|
+
const result = {
|
|
1521
|
+
content: `Tool "${toolCall.name}" not found`,
|
|
1522
|
+
isError: true
|
|
1523
|
+
};
|
|
1524
|
+
messages.push({
|
|
1525
|
+
role: "toolResult",
|
|
1526
|
+
toolCallId: toolCall.id,
|
|
1527
|
+
toolName: toolCall.name,
|
|
1528
|
+
content: result.content,
|
|
1529
|
+
isError: true
|
|
1530
|
+
});
|
|
1531
|
+
safeEmit(onEvent, {
|
|
1532
|
+
type: "tool_complete",
|
|
1533
|
+
toolCallId: toolCall.id,
|
|
1534
|
+
toolName: toolCall.name,
|
|
1535
|
+
result
|
|
1536
|
+
});
|
|
1537
|
+
continue;
|
|
1538
|
+
}
|
|
1539
|
+
try {
|
|
1540
|
+
const result = await tool.execute(toolCall.arguments);
|
|
1541
|
+
messages.push({
|
|
1542
|
+
role: "toolResult",
|
|
1543
|
+
toolCallId: toolCall.id,
|
|
1544
|
+
toolName: toolCall.name,
|
|
1545
|
+
content: result.content,
|
|
1546
|
+
isError: result.isError ?? false
|
|
1547
|
+
});
|
|
1548
|
+
safeEmit(onEvent, {
|
|
1549
|
+
type: "tool_complete",
|
|
1550
|
+
toolCallId: toolCall.id,
|
|
1551
|
+
toolName: toolCall.name,
|
|
1552
|
+
result
|
|
1553
|
+
});
|
|
1554
|
+
} catch (error) {
|
|
1555
|
+
const errorContent = `Tool execution error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
1556
|
+
const result = { content: errorContent, isError: true };
|
|
1557
|
+
messages.push({
|
|
1558
|
+
role: "toolResult",
|
|
1559
|
+
toolCallId: toolCall.id,
|
|
1560
|
+
toolName: toolCall.name,
|
|
1561
|
+
content: errorContent,
|
|
1562
|
+
isError: true
|
|
1563
|
+
});
|
|
1564
|
+
safeEmit(onEvent, {
|
|
1565
|
+
type: "tool_complete",
|
|
1566
|
+
toolCallId: toolCall.id,
|
|
1567
|
+
toolName: toolCall.name,
|
|
1568
|
+
result
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
return buildAgentResult(messages, totalUsage, completionReason, `Reached maxTurns limit (${params.maxTurns}) before receiving a final response`);
|
|
1574
|
+
}
|
|
1575
|
+
function addUsage(a, b) {
|
|
1576
|
+
return {
|
|
1577
|
+
promptTokens: a.promptTokens + b.promptTokens,
|
|
1578
|
+
completionTokens: a.completionTokens + b.completionTokens,
|
|
1579
|
+
totalTokens: a.totalTokens + b.totalTokens
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
function extractLastAssistantText(messages) {
|
|
1583
|
+
const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
|
|
1584
|
+
if (lastAssistant?.role !== "assistant") {
|
|
1585
|
+
return void 0;
|
|
1586
|
+
}
|
|
1587
|
+
const text = lastAssistant.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
1588
|
+
return text || void 0;
|
|
1589
|
+
}
|
|
1590
|
+
function buildAgentResult(messages, usage, completionReason, error) {
|
|
1591
|
+
const success = completionReason === "stop" && !error;
|
|
1592
|
+
return {
|
|
1593
|
+
success,
|
|
1594
|
+
completionReason,
|
|
1595
|
+
messages,
|
|
1596
|
+
textResponse: extractLastAssistantText(messages),
|
|
1597
|
+
usage,
|
|
1598
|
+
error
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
return agentLoop;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
882
1604
|
var hasRequiredNuaLlmClient;
|
|
883
1605
|
function requireNuaLlmClient() {
|
|
884
1606
|
if (hasRequiredNuaLlmClient) return nuaLlmClient;
|
|
@@ -893,10 +1615,12 @@ function requireNuaLlmClient() {
|
|
|
893
1615
|
const call_llm_service_1 = requireCallLlmService();
|
|
894
1616
|
const nua_json_schema_value_validation_1 = requireNuaJsonSchemaValueValidation();
|
|
895
1617
|
const http_llm_client_1 = requireHttpLlmClient();
|
|
1618
|
+
const provider_config_1 = requireProviderConfig();
|
|
896
1619
|
const model_info_1 = requireModelInfo();
|
|
897
1620
|
const cast_array_prompt_builder_1 = __importDefault(requireCastArrayPromptBuilder());
|
|
898
1621
|
const cast_prompt_builder_1 = __importDefault(requireCastPromptBuilder());
|
|
899
1622
|
const nua_errors_1 = requireNuaErrors();
|
|
1623
|
+
const agent_loop_1 = requireAgentLoop();
|
|
900
1624
|
class NuaLlmClient {
|
|
901
1625
|
constructor(config) {
|
|
902
1626
|
this.logger = config.logger || new logger_1.ConsoleLogger();
|
|
@@ -986,6 +1710,30 @@ function requireNuaLlmClient() {
|
|
|
986
1710
|
};
|
|
987
1711
|
}
|
|
988
1712
|
}
|
|
1713
|
+
async runAgent(params) {
|
|
1714
|
+
try {
|
|
1715
|
+
const model = this.resolveModel(params.model);
|
|
1716
|
+
const client = this.getClientForModel(model);
|
|
1717
|
+
const maxTokens = params.maxTokens ?? 4096;
|
|
1718
|
+
const maxTurns = params.maxTurns ?? 10;
|
|
1719
|
+
return (0, agent_loop_1.runAgentLoop)({
|
|
1720
|
+
messages: params.messages,
|
|
1721
|
+
tools: params.tools,
|
|
1722
|
+
systemPrompt: params.systemPrompt,
|
|
1723
|
+
maxTurns,
|
|
1724
|
+
onEvent: params.onEvent,
|
|
1725
|
+
sendRequest: (messages, tools, systemPrompt) => client.sendAgenticRequest(messages, tools, model, maxTokens, systemPrompt, params.onEvent)
|
|
1726
|
+
});
|
|
1727
|
+
} catch (e) {
|
|
1728
|
+
return {
|
|
1729
|
+
success: false,
|
|
1730
|
+
completionReason: "error",
|
|
1731
|
+
messages: params.messages,
|
|
1732
|
+
usage: provider_config_1.normalizedUsageZero,
|
|
1733
|
+
error: e instanceof Error ? e.message : String(e)
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
989
1737
|
}
|
|
990
1738
|
nuaLlmClient.NuaLlmClient = NuaLlmClient;
|
|
991
1739
|
return nuaLlmClient;
|
|
@@ -1159,7 +1907,7 @@ function requireDist() {
|
|
|
1159
1907
|
return mod && mod.__esModule ? mod : { "default": mod };
|
|
1160
1908
|
};
|
|
1161
1909
|
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
1162
|
-
exports$1.stableStringify = exports$1.validateJsonSchema = exports$1.providerConfigs = exports$1.normalizedUsageZero = exports$1.castArrayPromptBuilder = exports$1.castPromptBuilder = void 0;
|
|
1910
|
+
exports$1.runAgentLoop = exports$1.stableStringify = exports$1.validateJsonSchema = exports$1.providerConfigs = exports$1.normalizedUsageZero = exports$1.castArrayPromptBuilder = exports$1.castPromptBuilder = void 0;
|
|
1163
1911
|
__exportStar(requireNuaLlmClient(), exports$1);
|
|
1164
1912
|
__exportStar(requireLogger(), exports$1);
|
|
1165
1913
|
__exportStar(requireTypes(), exports$1);
|
|
@@ -1189,6 +1937,10 @@ function requireDist() {
|
|
|
1189
1937
|
} });
|
|
1190
1938
|
__exportStar(requireModelInfo(), exports$1);
|
|
1191
1939
|
__exportStar(requireSchemaUtils(), exports$1);
|
|
1940
|
+
var agent_loop_1 = requireAgentLoop();
|
|
1941
|
+
Object.defineProperty(exports$1, "runAgentLoop", { enumerable: true, get: function() {
|
|
1942
|
+
return agent_loop_1.runAgentLoop;
|
|
1943
|
+
} });
|
|
1192
1944
|
})(dist);
|
|
1193
1945
|
return dist;
|
|
1194
1946
|
}
|
|
@@ -1280,12 +2032,16 @@ function resolveConfigValue(config, key, envVar) {
|
|
|
1280
2032
|
}
|
|
1281
2033
|
|
|
1282
2034
|
const isBrowserEnvironment = () => typeof window !== "undefined" && !!window.document;
|
|
1283
|
-
const
|
|
1284
|
-
if (typeof window === "undefined"
|
|
1285
|
-
return false;
|
|
1286
|
-
}
|
|
2035
|
+
const isDevelopmentLikeBrowserEnvironment = () => {
|
|
2036
|
+
if (typeof window === "undefined") return false;
|
|
1287
2037
|
const host = window.location.hostname;
|
|
1288
|
-
|
|
2038
|
+
if (host === "localhost" || host === "127.0.0.1") return true;
|
|
2039
|
+
if (typeof process !== "undefined") {
|
|
2040
|
+
if (process.env?.NODE_ENV === "development") {
|
|
2041
|
+
return true;
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
return false;
|
|
1289
2045
|
};
|
|
1290
2046
|
class AuthTokenManager {
|
|
1291
2047
|
constructor(config) {
|
|
@@ -1300,12 +2056,10 @@ class AuthTokenManager {
|
|
|
1300
2056
|
);
|
|
1301
2057
|
}
|
|
1302
2058
|
if (this.apiKey && isBrowserEnvironment()) {
|
|
1303
|
-
|
|
1304
|
-
if (!allowedLocally) {
|
|
2059
|
+
if (!(config.dangerouslyAllowBrowserApiKeyInLocalhost && isDevelopmentLikeBrowserEnvironment()))
|
|
1305
2060
|
throw new Error(
|
|
1306
2061
|
"found config.apiKey. It is a private secret that must only be used in server environments."
|
|
1307
2062
|
);
|
|
1308
|
-
}
|
|
1309
2063
|
}
|
|
1310
2064
|
}
|
|
1311
2065
|
async getToken() {
|
|
@@ -1413,7 +2167,7 @@ class GatewayBackend {
|
|
|
1413
2167
|
success: true,
|
|
1414
2168
|
data: apiResponse.data,
|
|
1415
2169
|
usage,
|
|
1416
|
-
model: apiResponse.model
|
|
2170
|
+
model: apiResponse.model,
|
|
1417
2171
|
latencyMs,
|
|
1418
2172
|
source: "gateway",
|
|
1419
2173
|
meta: {
|
|
@@ -1445,7 +2199,7 @@ class GatewayBackend {
|
|
|
1445
2199
|
success: true,
|
|
1446
2200
|
data: apiResponse.data,
|
|
1447
2201
|
usage,
|
|
1448
|
-
model: apiResponse.model
|
|
2202
|
+
model: apiResponse.model,
|
|
1449
2203
|
latencyMs,
|
|
1450
2204
|
source: "gateway",
|
|
1451
2205
|
meta: {
|