nuabase 2.2.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.
@@ -1,23 +1,18 @@
1
1
  'use strict';
2
2
 
3
- var node_module = require('node:module');
4
3
  var require$$0 = require('ajv');
5
- var require$$1 = require('ajv/dist/2019');
6
- 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');
7
6
  var require$$3 = require('ajv/dist/refs/json-schema-draft-07.json');
8
7
  var require$$4 = require('ajv/dist/refs/json-schema-draft-06.json');
9
8
  var zod = require('zod');
10
9
 
11
- var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
12
10
  var dist = {};
13
11
 
14
12
  var nuaLlmClient = {};
15
13
 
16
14
  var logger = {};
17
15
 
18
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
19
- function __require() { return require$1("node:crypto"); }
20
-
21
16
  var hasRequiredLogger;
22
17
  function requireLogger() {
23
18
  if (hasRequiredLogger) return logger;
@@ -27,7 +22,6 @@ function requireLogger() {
27
22
  logger.truncateText = truncateText;
28
23
  logger.pickHeaders = pickHeaders;
29
24
  logger.normalizeError = normalizeError;
30
- const node_crypto_1 = __require();
31
25
  class ConsoleLogger {
32
26
  debug(message, context) {
33
27
  console.debug(`[DEBUG] ${message}`, context || "");
@@ -43,7 +37,7 @@ function requireLogger() {
43
37
  }
44
38
  }
45
39
  logger.ConsoleLogger = ConsoleLogger;
46
- const generateSpanId = () => (0, node_crypto_1.randomUUID)();
40
+ const generateSpanId = () => crypto.randomUUID();
47
41
  logger.generateSpanId = generateSpanId;
48
42
  function truncateText(text, limit = 500) {
49
43
  const length = text.length;
@@ -281,8 +275,8 @@ function requireAjvInstances() {
281
275
  Object.defineProperty(ajvInstances, "__esModule", { value: true });
282
276
  ajvInstances.ajvInstances = void 0;
283
277
  const ajv_1 = __importDefault(require$$0);
284
- const _2019_1 = __importDefault(require$$1);
285
- const _2020_1 = __importDefault(require$$2);
278
+ const _2019_js_1 = __importDefault(require$$1);
279
+ const _2020_js_1 = __importDefault(require$$2);
286
280
  const json_schema_draft_07_json_1 = __importDefault(require$$3);
287
281
  const json_schema_draft_06_json_1 = __importDefault(require$$4);
288
282
  const ajvOptions = {
@@ -295,10 +289,10 @@ function requireAjvInstances() {
295
289
  class AjvInstances {
296
290
  constructor() {
297
291
  this.draft07 = new ajv_1.default(ajvOptions);
298
- this.draft2019 = new _2019_1.default(ajvOptions);
292
+ this.draft2019 = new _2019_js_1.default(ajvOptions);
299
293
  this.draft2019.addMetaSchema(json_schema_draft_07_json_1.default);
300
294
  this.draft2019.addMetaSchema(json_schema_draft_06_json_1.default);
301
- this.draft2020 = new _2020_1.default(ajvOptions);
295
+ this.draft2020 = new _2020_js_1.default(ajvOptions);
302
296
  }
303
297
  getInstanceForSchema(schema) {
304
298
  const schemaVersion = schema.$schema;
@@ -362,17 +356,15 @@ function requireModelInfo() {
362
356
  exports$1.parseCanonicalModelName = parseCanonicalModelName;
363
357
  exports$1.CANONICAL_MODELS = [
364
358
  "qwen3-30b-a3b-instruct-2507",
365
- "claude-sonnet-4-5",
359
+ "claude-sonnet-4-6",
366
360
  "qwen3-vl-235b-a22b-instruct",
367
361
  "qwen3-max",
368
362
  "gpt-5",
369
- "gemini-2.5-flash-lite-preview-09-2025",
363
+ "gemini-2.5-flash-lite",
364
+ "gemini-2.5-flash",
370
365
  "qwen3-coder-flash",
371
366
  "gpt-oss-120b",
372
- "llama-3.3-70b-versatile",
373
- "gpt-4o",
374
- "llama-3.3-70b",
375
- "gemini-2.0-flash"
367
+ "kimi-k2.5"
376
368
  ];
377
369
  const CANONICAL_SET = new Set(exports$1.CANONICAL_MODELS);
378
370
  exports$1.SUPPORTED_MODELS = {
@@ -381,6 +373,10 @@ function requireModelInfo() {
381
373
  provider: "cerebras",
382
374
  providerModelName: "gpt-oss-120b"
383
375
  },
376
+ {
377
+ provider: "groq",
378
+ providerModelName: "openai/gpt-oss-120b"
379
+ },
384
380
  {
385
381
  provider: "openrouter",
386
382
  providerModelName: "openai/gpt-oss-120b"
@@ -392,10 +388,10 @@ function requireModelInfo() {
392
388
  providerModelName: "qwen/qwen3-30b-a3b-instruct-2507"
393
389
  }
394
390
  ],
395
- "claude-sonnet-4-5": [
391
+ "claude-sonnet-4-6": [
396
392
  {
397
393
  provider: "openrouter",
398
- providerModelName: "anthropic/claude-sonnet-4.5"
394
+ providerModelName: "anthropic/claude-sonnet-4.6"
399
395
  }
400
396
  ],
401
397
  "qwen3-vl-235b-a22b-instruct": [
@@ -416,40 +412,36 @@ function requireModelInfo() {
416
412
  providerModelName: "openai/gpt-5"
417
413
  }
418
414
  ],
419
- "gemini-2.5-flash-lite-preview-09-2025": [
415
+ "gemini-2.5-flash-lite": [
420
416
  {
421
- provider: "openrouter",
422
- providerModelName: "google/gemini-2.5-flash-lite-preview-09-2025"
423
- }
424
- ],
425
- "qwen3-coder-flash": [
417
+ provider: "gemini",
418
+ providerModelName: "gemini-2.5-flash-lite"
419
+ },
426
420
  {
427
421
  provider: "openrouter",
428
- providerModelName: "qwen/qwen3-coder-flash"
422
+ providerModelName: "google/gemini-2.5-flash-lite"
429
423
  }
430
424
  ],
431
- "llama-3.3-70b-versatile": [
425
+ "gemini-2.5-flash": [
432
426
  {
433
- provider: "groq",
434
- providerModelName: "llama-3.3-70b-versatile"
435
- }
436
- ],
437
- "gpt-4o": [
427
+ provider: "gemini",
428
+ providerModelName: "gemini-2.5-flash"
429
+ },
438
430
  {
439
431
  provider: "openrouter",
440
- providerModelName: "openai/gpt-4o"
432
+ providerModelName: "google/gemini-2.5-flash"
441
433
  }
442
434
  ],
443
- "llama-3.3-70b": [
435
+ "qwen3-coder-flash": [
444
436
  {
445
- provider: "cerebras",
446
- providerModelName: "llama-3.3-70b"
437
+ provider: "openrouter",
438
+ providerModelName: "qwen/qwen3-coder-flash"
447
439
  }
448
440
  ],
449
- "gemini-2.0-flash": [
441
+ "kimi-k2.5": [
450
442
  {
451
- provider: "gemini",
452
- providerModelName: "gemini-2.0-flash"
443
+ provider: "openrouter",
444
+ providerModelName: "moonshotai/kimi-k2.5"
453
445
  }
454
446
  ]
455
447
  };
@@ -462,11 +454,14 @@ function requireModelInfo() {
462
454
  case "fast":
463
455
  m2 = "gpt-oss-120b";
464
456
  break;
457
+ case "gemini":
458
+ m2 = "gemini-2.5-flash";
459
+ break;
465
460
  case "qwen":
466
461
  m2 = "qwen3-vl-235b-a22b-instruct";
467
462
  break;
468
463
  case "sonnet":
469
- m2 = "claude-sonnet-4-5";
464
+ m2 = "claude-sonnet-4-6";
470
465
  break;
471
466
  case "gpt":
472
467
  m2 = "gpt-5";
@@ -491,7 +486,7 @@ function requireProviderConfig() {
491
486
  hasRequiredProviderConfig = 1;
492
487
  (function(exports$1) {
493
488
  Object.defineProperty(exports$1, "__esModule", { value: true });
494
- 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;
495
490
  exports$1.normalizedUsageZero = {
496
491
  promptTokens: 0,
497
492
  completionTokens: 0,
@@ -510,6 +505,7 @@ function requireProviderConfig() {
510
505
  totalTokens: usage.total_tokens
511
506
  };
512
507
  };
508
+ exports$1.normalizeOpenAiUsage = normalizeOpenAiUsage;
513
509
  const normalizeGeminiUsage = (usage) => {
514
510
  if (!usage) {
515
511
  return exports$1.normalizedUsageZero;
@@ -523,6 +519,7 @@ function requireProviderConfig() {
523
519
  totalTokens: usage.totalTokenCount
524
520
  };
525
521
  };
522
+ exports$1.normalizeGeminiUsage = normalizeGeminiUsage;
526
523
  const buildOpenAiStyleRequest = (baseUrl) => ({ prompt, model, maxTokens, assistantPrefillPrompt }, apiKey) => {
527
524
  const messages = [];
528
525
  messages.push({ role: "user", content: prompt });
@@ -557,11 +554,11 @@ function requireProviderConfig() {
557
554
  const parseOpenAiStyleResponse = (errorLabel) => async (response) => {
558
555
  if (response.status === 200) {
559
556
  const responseBody = await response.json();
560
- const responseText = responseBody.choices?.[0]?.message?.content;
557
+ const responseText = (0, exports$1.extractOpenAiMessageText)(responseBody.choices?.[0]?.message);
561
558
  if (responseText) {
562
559
  return {
563
560
  text: responseText,
564
- usage: normalizeOpenAiUsage(responseBody.usage)
561
+ usage: (0, exports$1.normalizeOpenAiUsage)(responseBody.usage)
565
562
  };
566
563
  }
567
564
  throw new Error(`${errorLabel} API error: Could not extract text from response. Body: ${JSON.stringify(responseBody)}`);
@@ -575,22 +572,28 @@ function requireProviderConfig() {
575
572
  throw new Error(`${errorLabel} API error: ${response.status} - ${errorBody}`);
576
573
  }
577
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;
578
589
  const parseOpenAiGPT5ThinkingStyleResponse = (errorLabel) => async (response) => {
579
- const normalize = (value) => {
580
- if (typeof value !== "string") {
581
- return void 0;
582
- }
583
- const trimmed = value.trim();
584
- return trimmed.length > 0 ? trimmed : void 0;
585
- };
586
590
  if (response.status === 200) {
587
591
  const responseBody = await response.json();
588
- const message = responseBody.choices?.[0]?.message;
589
- 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);
590
593
  if (content) {
591
594
  return {
592
595
  text: content,
593
- usage: normalizeOpenAiUsage(responseBody.usage)
596
+ usage: (0, exports$1.normalizeOpenAiUsage)(responseBody.usage)
594
597
  };
595
598
  }
596
599
  throw new Error(`${errorLabel} API error: Could not extract text from thinking response. Body: ${JSON.stringify(responseBody)}`);
@@ -638,7 +641,7 @@ function requireProviderConfig() {
638
641
  if (responseText) {
639
642
  return {
640
643
  text: responseText,
641
- usage: normalizeGeminiUsage(responseBody.usageMetadata)
644
+ usage: (0, exports$1.normalizeGeminiUsage)(responseBody.usageMetadata)
642
645
  };
643
646
  }
644
647
  throw new Error(`Gemini API error: Could not extract text from response. Body: ${JSON.stringify(responseBody)}`);
@@ -686,6 +689,496 @@ function requireProviderConfig() {
686
689
  return providerConfig;
687
690
  }
688
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
+
689
1182
  var hasRequiredHttpLlmClient;
690
1183
  function requireHttpLlmClient() {
691
1184
  if (hasRequiredHttpLlmClient) return httpLlmClient;
@@ -695,6 +1188,7 @@ function requireHttpLlmClient() {
695
1188
  const model_info_1 = requireModelInfo();
696
1189
  const logger_1 = requireLogger();
697
1190
  const provider_config_1 = requireProviderConfig();
1191
+ const provider_formatters_1 = requireProviderFormatters();
698
1192
  class HttpLlmClient {
699
1193
  constructor(providerId, apiKey, logger) {
700
1194
  this.providerId = providerId;
@@ -702,51 +1196,133 @@ function requireHttpLlmClient() {
702
1196
  this.logger = logger;
703
1197
  }
704
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() {
705
1243
  const provider = provider_config_1.providerConfigs[this.providerId];
706
1244
  if (!provider) {
707
1245
  throw new Error(`Unknown LLM provider: ${this.providerId}`);
708
1246
  }
1247
+ return provider;
1248
+ }
1249
+ getProviderModelName(model) {
709
1250
  const providerSpecificModelName = model_info_1.SUPPORTED_MODELS[model].find((pm) => pm.provider === this.providerId);
710
1251
  if (!providerSpecificModelName) {
711
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`);
712
1253
  }
713
- const requestOptions = provider.buildRequest({
714
- prompt,
715
- model: providerSpecificModelName.providerModelName,
716
- maxTokens,
717
- assistantPrefillPrompt
718
- }, this.apiKey);
719
- const method = requestOptions.method ?? "POST";
720
- const headers = requestOptions.headers ?? {};
721
- const bodyPayload = requestOptions.body;
722
- 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);
723
1260
  const spanId = (0, logger_1.generateSpanId)();
724
1261
  const startTime = Date.now();
725
- (0, logger_1.logLlmCallStart)(this.logger, spanId, provider.providerId, provider.apiOperation, {
726
- 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,
727
1264
  httpMethod: method,
728
- model,
729
- maxTokens
1265
+ model: params.model,
1266
+ maxTokens: params.maxTokens
730
1267
  });
731
1268
  try {
732
- const response = await fetch(requestOptions.url, {
1269
+ const response = await fetch(params.requestOptions.url, {
733
1270
  method,
734
1271
  headers,
735
1272
  body
736
1273
  });
737
- const parsedResponse = await provider.parseResponse(response);
1274
+ const parsedResponse = await params.parseResponse(response);
738
1275
  const duration = Date.now() - startTime;
739
- (0, logger_1.logLlmCallComplete)(this.logger, spanId, provider.providerId, provider.apiOperation, {
1276
+ (0, logger_1.logLlmCallComplete)(this.logger, spanId, params.provider.providerId, params.apiOperation, {
740
1277
  status: response.status,
741
- responseText: parsedResponse.text,
1278
+ responseText: params.getResponsePreview(parsedResponse),
742
1279
  headers: Object.fromEntries(response.headers.entries()),
743
- usage: parsedResponse.usage
1280
+ usage: params.getUsage(parsedResponse)
744
1281
  }, duration);
745
1282
  return parsedResponse;
746
1283
  } catch (error) {
747
1284
  const duration = Date.now() - startTime;
748
- (0, logger_1.logLlmCallError)(this.logger, spanId, provider.providerId, provider.apiOperation, error, duration);
749
- 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}`);
750
1326
  }
751
1327
  }
752
1328
  }
@@ -834,7 +1410,8 @@ function requireCastPromptBuilder() {
834
1410
  `Your entire response should be just the value of '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}', as valid JSON.`,
835
1411
  `And it should not be wrapped in any wrapper object -- return exactly what the JSON schema is expecting.`,
836
1412
  `We will validate the result with the AJV Node library, using ajv.parse, against the given schema, and we expect`,
837
- `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.`
838
1415
  ].join(" ");
839
1416
  const buildSystemPrompt = (reqParams) => {
840
1417
  let a = BASE_SYSTEM_PROMPT_WHEN_OUTPUT_TYPE_NAME_PROVIDED;
@@ -886,6 +1463,145 @@ function requireNuaErrors() {
886
1463
  return nuaErrors;
887
1464
  }
888
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
+
889
1605
  var hasRequiredNuaLlmClient;
890
1606
  function requireNuaLlmClient() {
891
1607
  if (hasRequiredNuaLlmClient) return nuaLlmClient;
@@ -900,10 +1616,12 @@ function requireNuaLlmClient() {
900
1616
  const call_llm_service_1 = requireCallLlmService();
901
1617
  const nua_json_schema_value_validation_1 = requireNuaJsonSchemaValueValidation();
902
1618
  const http_llm_client_1 = requireHttpLlmClient();
1619
+ const provider_config_1 = requireProviderConfig();
903
1620
  const model_info_1 = requireModelInfo();
904
1621
  const cast_array_prompt_builder_1 = __importDefault(requireCastArrayPromptBuilder());
905
1622
  const cast_prompt_builder_1 = __importDefault(requireCastPromptBuilder());
906
1623
  const nua_errors_1 = requireNuaErrors();
1624
+ const agent_loop_1 = requireAgentLoop();
907
1625
  class NuaLlmClient {
908
1626
  constructor(config) {
909
1627
  this.logger = config.logger || new logger_1.ConsoleLogger();
@@ -993,6 +1711,30 @@ function requireNuaLlmClient() {
993
1711
  };
994
1712
  }
995
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
+ }
996
1738
  }
997
1739
  nuaLlmClient.NuaLlmClient = NuaLlmClient;
998
1740
  return nuaLlmClient;
@@ -1166,7 +1908,7 @@ function requireDist() {
1166
1908
  return mod && mod.__esModule ? mod : { "default": mod };
1167
1909
  };
1168
1910
  Object.defineProperty(exports$1, "__esModule", { value: true });
1169
- 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;
1170
1912
  __exportStar(requireNuaLlmClient(), exports$1);
1171
1913
  __exportStar(requireLogger(), exports$1);
1172
1914
  __exportStar(requireTypes(), exports$1);
@@ -1196,6 +1938,10 @@ function requireDist() {
1196
1938
  } });
1197
1939
  __exportStar(requireModelInfo(), exports$1);
1198
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
+ } });
1199
1945
  })(dist);
1200
1946
  return dist;
1201
1947
  }
@@ -1216,9 +1962,10 @@ class DirectBackend {
1216
1962
  this.client = new distExports.NuaLlmClient({ providers: config.providers });
1217
1963
  }
1218
1964
  async castValue(params) {
1965
+ const model = params.model ?? this.model;
1219
1966
  const startTime = Date.now();
1220
1967
  const result = await this.client.castValue({
1221
- model: this.model,
1968
+ model,
1222
1969
  input: { prompt: params.prompt, data: params.data },
1223
1970
  output: { name: params.outputName, effectiveSchema: params.outputSchema }
1224
1971
  });
@@ -1235,20 +1982,21 @@ class DirectBackend {
1235
1982
  success: true,
1236
1983
  data: result.data,
1237
1984
  usage: result.usage || normalizedUsageZero,
1238
- model: this.model,
1985
+ model,
1239
1986
  latencyMs,
1240
1987
  source: "direct",
1241
1988
  meta: {}
1242
1989
  };
1243
1990
  }
1244
1991
  async castArray(params) {
1992
+ const model = params.model ?? this.model;
1245
1993
  const startTime = Date.now();
1246
1994
  const wrappedSchema = distExports.wrapArraySchema(params.outputSchema, {
1247
1995
  primaryKey: params.primaryKey,
1248
1996
  outputName: params.outputName
1249
1997
  });
1250
1998
  const result = await this.client.castArray({
1251
- model: this.model,
1999
+ model,
1252
2000
  data: params.data,
1253
2001
  input: { prompt: params.prompt, primaryKey: params.primaryKey },
1254
2002
  output: { name: params.outputName, effectiveSchema: wrappedSchema }
@@ -1266,7 +2014,7 @@ class DirectBackend {
1266
2014
  success: true,
1267
2015
  data: result.data,
1268
2016
  usage: result.usage || normalizedUsageZero,
1269
- model: this.model,
2017
+ model,
1270
2018
  latencyMs,
1271
2019
  source: "direct",
1272
2020
  meta: {}
@@ -1285,6 +2033,17 @@ function resolveConfigValue(config, key, envVar) {
1285
2033
  }
1286
2034
 
1287
2035
  const isBrowserEnvironment = () => typeof window !== "undefined" && !!window.document;
2036
+ const isDevelopmentLikeBrowserEnvironment = () => {
2037
+ if (typeof window === "undefined") return false;
2038
+ const host = window.location.hostname;
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;
2046
+ };
1288
2047
  class AuthTokenManager {
1289
2048
  constructor(config) {
1290
2049
  this.apiKey = resolveConfigValue(config, "apiKey", "NUABASE_API_KEY") || void 0;
@@ -1298,9 +2057,10 @@ class AuthTokenManager {
1298
2057
  );
1299
2058
  }
1300
2059
  if (this.apiKey && isBrowserEnvironment()) {
1301
- throw new Error(
1302
- "found config.apiKey. It is a private secret that must only be used in server environments."
1303
- );
2060
+ if (!(config.dangerouslyAllowBrowserApiKeyInLocalhost && isDevelopmentLikeBrowserEnvironment()))
2061
+ throw new Error(
2062
+ "found config.apiKey. It is a private secret that must only be used in server environments."
2063
+ );
1304
2064
  }
1305
2065
  }
1306
2066
  async getToken() {
@@ -1391,7 +2151,8 @@ class GatewayBackend {
1391
2151
  const startTime = Date.now();
1392
2152
  const response = await this.post("cast/value/now", {
1393
2153
  input: { prompt: params.prompt, data: params.data },
1394
- output: { name: params.outputName, schema: params.outputSchema }
2154
+ output: { name: params.outputName, schema: params.outputSchema },
2155
+ ...params.model && { model: params.model }
1395
2156
  });
1396
2157
  const latencyMs = Date.now() - startTime;
1397
2158
  if (isErrorResponse(response)) {
@@ -1407,7 +2168,7 @@ class GatewayBackend {
1407
2168
  success: true,
1408
2169
  data: apiResponse.data,
1409
2170
  usage,
1410
- model: apiResponse.model ?? "unknown",
2171
+ model: apiResponse.model,
1411
2172
  latencyMs,
1412
2173
  source: "gateway",
1413
2174
  meta: {
@@ -1422,7 +2183,8 @@ class GatewayBackend {
1422
2183
  const startTime = Date.now();
1423
2184
  const response = await this.post("cast/array/now", {
1424
2185
  input: { prompt: params.prompt, data: params.data, primaryKey: params.primaryKey },
1425
- output: { name: params.outputName, schema: params.outputSchema }
2186
+ output: { name: params.outputName, schema: params.outputSchema },
2187
+ ...params.model && { model: params.model }
1426
2188
  });
1427
2189
  const latencyMs = Date.now() - startTime;
1428
2190
  if (isErrorResponse(response)) {
@@ -1438,7 +2200,7 @@ class GatewayBackend {
1438
2200
  success: true,
1439
2201
  data: apiResponse.data,
1440
2202
  usage,
1441
- model: apiResponse.model ?? "unknown",
2203
+ model: apiResponse.model,
1442
2204
  latencyMs,
1443
2205
  source: "gateway",
1444
2206
  meta: {
@@ -1452,7 +2214,8 @@ class GatewayBackend {
1452
2214
  async queueCastValue(params) {
1453
2215
  const response = await this.post("cast/value", {
1454
2216
  input: { prompt: params.prompt, data: params.data },
1455
- output: { name: params.outputName, schema: params.outputSchema }
2217
+ output: { name: params.outputName, schema: params.outputSchema },
2218
+ ...params.model && { model: params.model }
1456
2219
  });
1457
2220
  if (isErrorResponse(response)) {
1458
2221
  return { success: false, error: response.error, source: "gateway" };
@@ -1463,7 +2226,8 @@ class GatewayBackend {
1463
2226
  async queueCastArray(params) {
1464
2227
  const response = await this.post("cast/array", {
1465
2228
  input: { prompt: params.prompt, data: params.data, primaryKey: params.primaryKey },
1466
- output: { name: params.outputName, schema: params.outputSchema }
2229
+ output: { name: params.outputName, schema: params.outputSchema },
2230
+ ...params.model && { model: params.model }
1467
2231
  });
1468
2232
  if (isErrorResponse(response)) {
1469
2233
  return { success: false, error: response.error, source: "gateway" };
@@ -1520,7 +2284,8 @@ class Nua {
1520
2284
  prompt,
1521
2285
  data: options?.input ?? null,
1522
2286
  outputName,
1523
- outputSchema: jsonSchema
2287
+ outputSchema: jsonSchema,
2288
+ model: options?.model
1524
2289
  });
1525
2290
  }
1526
2291
  // ========== list() - Array Operations ==========
@@ -1540,7 +2305,8 @@ class Nua {
1540
2305
  data: options.input,
1541
2306
  primaryKey: options.primaryKey,
1542
2307
  outputName: options.output.name,
1543
- outputSchema: jsonSchema
2308
+ outputSchema: jsonSchema,
2309
+ model: options.model
1544
2310
  });
1545
2311
  }
1546
2312
  // Implementation
@@ -1558,7 +2324,8 @@ class Nua {
1558
2324
  prompt,
1559
2325
  data: options?.input ?? null,
1560
2326
  outputName,
1561
- outputSchema: jsonSchema
2327
+ outputSchema: jsonSchema,
2328
+ model: options?.model
1562
2329
  });
1563
2330
  }
1564
2331
  // ========== queueList() - Async Array Operations ==========
@@ -1581,7 +2348,8 @@ class Nua {
1581
2348
  data: options.input,
1582
2349
  primaryKey: options.primaryKey,
1583
2350
  outputName: options.output.name,
1584
- outputSchema: jsonSchema
2351
+ outputSchema: jsonSchema,
2352
+ model: options.model
1585
2353
  });
1586
2354
  }
1587
2355
  }