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