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