nuabase 2.3.3 → 2.3.5

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.
Files changed (65) hide show
  1. package/README.md +96 -31
  2. package/dist/cjs/chunks/logger-Co5uZG0A.cjs +90 -0
  3. package/dist/cjs/index.cjs +1510 -1444
  4. package/dist/cjs/local-agent.cjs +886 -0
  5. package/dist/esm/chunks/logger-DnkHzkX_.mjs +88 -0
  6. package/dist/esm/index.mjs +1511 -1445
  7. package/dist/esm/local-agent.mjs +884 -0
  8. package/dist/types/__tests__/helpers/client-factory.d.ts +33 -11
  9. package/dist/types/__tests__/helpers/index.d.ts +2 -1
  10. package/dist/types/backend/direct.d.ts +20 -8
  11. package/dist/types/backend/types.d.ts +9 -4
  12. package/dist/types/index.d.cts +3 -2
  13. package/dist/types/index.d.mts +3 -2
  14. package/dist/types/local-agent.d.cts +2 -0
  15. package/dist/types/local-agent.d.mts +2 -0
  16. package/dist/types/nua-llm-core/index.d.ts +23 -0
  17. package/dist/types/nua-llm-core/lib/error-utils.d.ts +6 -0
  18. package/dist/types/nua-llm-core/lib/logger.d.ts +44 -0
  19. package/dist/types/nua-llm-core/lib/nua-errors.d.ts +12 -0
  20. package/dist/types/nua-llm-core/lib/prompt-template-utils.d.ts +2 -0
  21. package/dist/types/nua-llm-core/lib/schema-utils.d.ts +1 -0
  22. package/dist/types/nua-llm-core/lib/stable-stringify.d.ts +1 -0
  23. package/dist/types/nua-llm-core/lib/strict-json-schema.d.ts +7 -0
  24. package/dist/types/nua-llm-core/lib/types.d.ts +8 -0
  25. package/dist/types/nua-llm-core/lib/validate-mappable-input-data.d.ts +4 -0
  26. package/dist/types/nua-llm-core/local-agent.d.ts +7 -0
  27. package/dist/types/nua-llm-core/modules/agent/agent-loop.d.ts +10 -0
  28. package/dist/types/nua-llm-core/modules/agent/agent-turn.d.ts +17 -0
  29. package/dist/types/nua-llm-core/modules/agent/provider-formatters.d.ts +22 -0
  30. package/dist/types/nua-llm-core/modules/agent/run-agent.d.ts +7 -0
  31. package/dist/types/nua-llm-core/modules/agent/types.d.ts +90 -0
  32. package/dist/types/nua-llm-core/modules/cast/cast-request.d.ts +32 -0
  33. package/dist/types/nua-llm-core/modules/cast/envelope.d.ts +9 -0
  34. package/dist/types/nua-llm-core/modules/cast/list-schema.d.ts +32 -0
  35. package/dist/types/nua-llm-core/modules/cast/prompts/list-prompt.d.ts +3 -0
  36. package/dist/types/nua-llm-core/modules/cast/prompts/render-prompt.d.ts +7 -0
  37. package/dist/types/nua-llm-core/modules/cast/prompts/value-prompt.d.ts +3 -0
  38. package/dist/types/nua-llm-core/modules/cast/run-cast.d.ts +44 -0
  39. package/dist/types/nua-llm-core/modules/engine/engine-router.d.ts +23 -0
  40. package/dist/types/nua-llm-core/modules/engine/http/http-engine.d.ts +12 -0
  41. package/dist/types/nua-llm-core/modules/engine/http/provider-call.d.ts +33 -0
  42. package/dist/types/nua-llm-core/modules/engine/http/provider-config.d.ts +65 -0
  43. package/dist/types/nua-llm-core/modules/engine/http/provider-engines.d.ts +35 -0
  44. package/dist/types/nua-llm-core/modules/engine/llm-engine.d.ts +73 -0
  45. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/claude-code.d.ts +2 -0
  46. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/codex.d.ts +2 -0
  47. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/failure-classification.d.ts +4 -0
  48. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/index.d.ts +3 -0
  49. package/dist/types/nua-llm-core/modules/engine/local-agent/adapters/types.d.ts +61 -0
  50. package/dist/types/nua-llm-core/modules/engine/local-agent/agent-id.d.ts +4 -0
  51. package/dist/types/nua-llm-core/modules/engine/local-agent/create-local-agent.d.ts +36 -0
  52. package/dist/types/nua-llm-core/modules/engine/local-agent/detect.d.ts +20 -0
  53. package/dist/types/nua-llm-core/modules/engine/local-agent/local-agent-engine.d.ts +32 -0
  54. package/dist/types/nua-llm-core/modules/engine/local-agent/local-agent.d.ts +25 -0
  55. package/dist/types/nua-llm-core/modules/engine/local-agent/process-runner.d.ts +16 -0
  56. package/dist/types/nua-llm-core/modules/engine/local-agent/semaphore.d.ts +8 -0
  57. package/dist/types/nua-llm-core/modules/execution/llm-response-extraction.d.ts +5 -0
  58. package/dist/types/nua-llm-core/modules/json-schema-validation/ajv-instances.d.ts +12 -0
  59. package/dist/types/nua-llm-core/modules/json-schema-validation/nua-json-schema-value-validation.d.ts +10 -0
  60. package/dist/types/nua-llm-core/modules/json-schema-validation/validate-json-schema.d.ts +2 -0
  61. package/dist/types/nua-llm-core/modules/model-info/index.d.ts +15 -0
  62. package/dist/types/nua-llm-core/modules/streaming/sse-parser.d.ts +7 -0
  63. package/dist/types/nua-llm-core/nua-llm-client.d.ts +37 -0
  64. package/dist/types/nua.d.ts +8 -2
  65. package/package.json +19 -2
@@ -1,107 +1,33 @@
1
1
  'use strict';
2
2
 
3
+ var logger = require('./chunks/logger-Co5uZG0A.cjs');
3
4
  var zod = require('zod');
4
5
 
5
6
  var dist = {};
6
7
 
7
8
  var nuaLlmClient = {};
8
9
 
9
- var logger = {};
10
-
11
- var hasRequiredLogger;
12
- function requireLogger() {
13
- if (hasRequiredLogger) return logger;
14
- hasRequiredLogger = 1;
15
- Object.defineProperty(logger, "__esModule", { value: true });
16
- logger.logLlmCallError = logger.logLlmCallComplete = logger.logLlmCallStart = logger.generateSpanId = logger.ConsoleLogger = void 0;
17
- logger.truncateText = truncateText;
18
- logger.pickHeaders = pickHeaders;
19
- logger.normalizeError = normalizeError;
20
- class ConsoleLogger {
21
- debug(message, context) {
22
- console.debug(`[DEBUG] ${message}`, context || "");
23
- }
24
- info(message, context) {
25
- console.info(`[INFO] ${message}`, context || "");
26
- }
27
- warn(message, context) {
28
- console.warn(`[WARN] ${message}`, context || "");
29
- }
30
- error(message, context) {
31
- console.error(`[ERROR] ${message}`, context || "");
32
- }
33
- }
34
- logger.ConsoleLogger = ConsoleLogger;
35
- const generateSpanId = () => crypto.randomUUID();
36
- logger.generateSpanId = generateSpanId;
37
- function truncateText(text, limit = 500) {
38
- const length = text.length;
39
- if (length <= limit) {
40
- return { preview: text, length };
41
- }
42
- return { preview: text.slice(0, limit), length };
43
- }
44
- function pickHeaders(headers, allowlist, redactSet) {
45
- const result = {};
46
- for (const [key, value] of Object.entries(headers)) {
47
- const lowerKey = key.toLowerCase();
48
- if (redactSet?.has(lowerKey)) {
49
- result[key] = "[REDACTED]";
50
- } else if (allowlist.has(lowerKey)) {
51
- result[key] = Array.isArray(value) ? value.join(", ") : value ?? "";
52
- }
53
- }
54
- return result;
55
- }
56
- function normalizeError(error) {
57
- return error instanceof Error ? { message: error.message, stack: error.stack } : String(error);
58
- }
59
- const LLM_RESPONSE_HEADER_ALLOWLIST = /* @__PURE__ */ new Set([
60
- "x-request-id",
61
- "x-ratelimit-limit-requests",
62
- "x-ratelimit-limit-tokens",
63
- "x-ratelimit-remaining-requests",
64
- "x-ratelimit-remaining-tokens",
65
- "x-groq-region"
66
- ]);
67
- const logLlmCallStart = (logger2, spanId, service, method, request) => {
68
- logger2.info("LLM call started", {
69
- type: "llm_call_start",
70
- span_id: spanId,
71
- service,
72
- method,
73
- ...request
74
- });
10
+ var nuaErrors = {};
11
+
12
+ var hasRequiredNuaErrors;
13
+ function requireNuaErrors() {
14
+ if (hasRequiredNuaErrors) return nuaErrors;
15
+ hasRequiredNuaErrors = 1;
16
+ Object.defineProperty(nuaErrors, "__esModule", { value: true });
17
+ nuaErrors.isNuaError = nuaErrors.isNuaInternalError = nuaErrors.isNuaValidationError = void 0;
18
+ const isNuaValidationError = (a) => {
19
+ return typeof a == "object" && a != null && "kind" in a && a.kind == "validation-error";
75
20
  };
76
- logger.logLlmCallStart = logLlmCallStart;
77
- const logLlmCallComplete = (logger2, spanId, service, method, response, duration) => {
78
- const { headers, responseText, ...rest } = response;
79
- const { preview: responsePreview, length: responseLength } = truncateText(responseText);
80
- logger2.info("LLM call completed", {
81
- type: "llm_call_complete",
82
- span_id: spanId,
83
- service,
84
- method,
85
- ...rest,
86
- responsePreview,
87
- responseLength,
88
- ...pickHeaders(headers, LLM_RESPONSE_HEADER_ALLOWLIST),
89
- duration_ms: duration
90
- });
21
+ nuaErrors.isNuaValidationError = isNuaValidationError;
22
+ const isNuaInternalError = (a) => {
23
+ return typeof a == "object" && a != null && "kind" in a && a.kind == "internal-error";
91
24
  };
92
- logger.logLlmCallComplete = logLlmCallComplete;
93
- const logLlmCallError = (logger2, spanId, service, method, error, duration) => {
94
- logger2.error("LLM call failed", {
95
- type: "llm_call_error",
96
- span_id: spanId,
97
- service,
98
- method,
99
- error: normalizeError(error),
100
- duration_ms: duration
101
- });
25
+ nuaErrors.isNuaInternalError = isNuaInternalError;
26
+ const isNuaError = (a) => {
27
+ return typeof a == "object" && a != null && "kind" in a && (a.kind == "internal-error" || a.kind == "validation-error");
102
28
  };
103
- logger.logLlmCallError = logLlmCallError;
104
- return logger;
29
+ nuaErrors.isNuaError = isNuaError;
30
+ return nuaErrors;
105
31
  }
106
32
 
107
33
  var validateMappableInputData = {};
@@ -144,7 +70,7 @@ function requireValidateMappableInputData() {
144
70
  return validateMappableInputData;
145
71
  }
146
72
 
147
- var callLlmService = {};
73
+ var runCast = {};
148
74
 
149
75
  var llmResponseExtraction = {};
150
76
 
@@ -253,60 +179,6 @@ function requireLlmResponseExtraction() {
253
179
  return llmResponseExtraction;
254
180
  }
255
181
 
256
- var hasRequiredCallLlmService;
257
- function requireCallLlmService() {
258
- if (hasRequiredCallLlmService) return callLlmService;
259
- hasRequiredCallLlmService = 1;
260
- Object.defineProperty(callLlmService, "__esModule", { value: true });
261
- callLlmService.callLLM = callLLM;
262
- const llm_response_extraction_1 = requireLlmResponseExtraction();
263
- const delay = (ms) => {
264
- return new Promise((resolve) => setTimeout(resolve, ms));
265
- };
266
- async function callLLM(llmClient, prompt, model, maxTokens, temperature, maxRetries, validationFunction) {
267
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
268
- try {
269
- const providerResponse = await llmClient.sendRequest(prompt, model, maxTokens);
270
- const response = providerResponse.text;
271
- let parsedResponse;
272
- try {
273
- const { cleanedResponse } = (0, llm_response_extraction_1.extractThinkingFromResponse)(response);
274
- parsedResponse = (0, llm_response_extraction_1.parseJsonFromLlmResponse)(cleanedResponse);
275
- } catch (parseError) {
276
- const errorMessage2 = `Failed to parse LLM response as JSON: ${parseError instanceof Error ? parseError.message : "Unknown parsing error"}`;
277
- throw new Error(`${errorMessage2}
278
-
279
- Raw LLM response:
280
- ${response}`);
281
- }
282
- const validationResult = validationFunction(parsedResponse);
283
- if (validationResult.success && validationResult.data) {
284
- return {
285
- data: validationResult.data,
286
- usage: providerResponse.usage
287
- };
288
- }
289
- const errorMessage = `Validation failed: ${validationResult.error || "Unknown validation error"}`;
290
- throw new Error(`${errorMessage}
291
-
292
- Raw LLM response:
293
- ${response}`);
294
- } catch (error) {
295
- const isLastAttempt = attempt === maxRetries;
296
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
297
- if (isLastAttempt) {
298
- throw new Error(`LLM call failed after ${maxRetries} attempts. Last error: ${errorMessage}`);
299
- }
300
- const backoffDelay = Math.pow(2, attempt - 1) * 1e3;
301
- console.warn(`LLM call attempt ${attempt} failed: ${errorMessage}. Retrying in ${backoffDelay}ms...`);
302
- await delay(backoffDelay);
303
- }
304
- }
305
- throw new Error("Unexpected error: retry loop completed without success or failure");
306
- }
307
- return callLlmService;
308
- }
309
-
310
182
  var nuaJsonSchemaValueValidation = {};
311
183
 
312
184
  var ajvInstances = {};
@@ -9508,170 +9380,417 @@ function requireNuaJsonSchemaValueValidation() {
9508
9380
  return nuaJsonSchemaValueValidation;
9509
9381
  }
9510
9382
 
9511
- var httpLlmClient = {};
9512
-
9513
- var modelInfo = {};
9383
+ var envelope = {};
9514
9384
 
9515
- var hasRequiredModelInfo;
9516
- function requireModelInfo() {
9517
- if (hasRequiredModelInfo) return modelInfo;
9518
- hasRequiredModelInfo = 1;
9385
+ var hasRequiredEnvelope;
9386
+ function requireEnvelope() {
9387
+ if (hasRequiredEnvelope) return envelope;
9388
+ hasRequiredEnvelope = 1;
9519
9389
  (function(exports$1) {
9520
9390
  Object.defineProperty(exports$1, "__esModule", { value: true });
9521
- exports$1.SUPPORTED_MODELS = exports$1.CANONICAL_MODELS = void 0;
9522
- exports$1.parseCanonicalModelName = parseCanonicalModelName;
9523
- exports$1.CANONICAL_MODELS = [
9524
- "qwen3-30b-a3b-instruct-2507",
9525
- "claude-opus-4-7",
9526
- "claude-sonnet-4-6",
9527
- "claude-haiku-4-5",
9528
- "qwen3-vl-235b-a22b-instruct",
9529
- "qwen3-max",
9530
- "gpt-5",
9531
- "gemini-2.5-flash-lite",
9532
- "gemini-2.5-flash",
9533
- "qwen3-coder-flash",
9534
- "gpt-oss-120b",
9535
- "kimi-k2.5",
9536
- "kimi-k2.6"
9537
- ];
9538
- const CANONICAL_SET = new Set(exports$1.CANONICAL_MODELS);
9539
- exports$1.SUPPORTED_MODELS = {
9540
- "gpt-oss-120b": [
9541
- {
9542
- provider: "cerebras",
9543
- providerModelName: "gpt-oss-120b"
9544
- },
9545
- {
9546
- provider: "groq",
9547
- providerModelName: "openai/gpt-oss-120b"
9548
- },
9549
- {
9550
- provider: "openrouter",
9551
- providerModelName: "openai/gpt-oss-120b"
9552
- }
9553
- ],
9554
- "qwen3-30b-a3b-instruct-2507": [
9555
- {
9556
- provider: "openrouter",
9557
- providerModelName: "qwen/qwen3-30b-a3b-instruct-2507"
9558
- }
9559
- ],
9560
- "claude-opus-4-7": [
9561
- {
9562
- provider: "openrouter",
9563
- providerModelName: "anthropic/claude-opus-4.7"
9564
- }
9565
- ],
9566
- "claude-sonnet-4-6": [
9567
- {
9568
- provider: "openrouter",
9569
- providerModelName: "anthropic/claude-sonnet-4.6"
9570
- }
9571
- ],
9572
- "claude-haiku-4-5": [
9573
- {
9574
- provider: "openrouter",
9575
- providerModelName: "anthropic/claude-haiku-4.5"
9576
- }
9577
- ],
9578
- "qwen3-vl-235b-a22b-instruct": [
9579
- {
9580
- provider: "openrouter",
9581
- providerModelName: "qwen/qwen3-vl-235b-a22b-instruct"
9582
- }
9583
- ],
9584
- "qwen3-max": [
9585
- {
9586
- provider: "openrouter",
9587
- providerModelName: "qwen/qwen3-max"
9588
- }
9589
- ],
9590
- "gpt-5": [
9591
- {
9592
- provider: "openrouter",
9593
- providerModelName: "openai/gpt-5"
9594
- }
9595
- ],
9596
- "gemini-2.5-flash-lite": [
9597
- {
9598
- provider: "gemini",
9599
- providerModelName: "gemini-2.5-flash-lite"
9600
- },
9601
- {
9602
- provider: "openrouter",
9603
- providerModelName: "google/gemini-2.5-flash-lite"
9604
- }
9605
- ],
9606
- "gemini-2.5-flash": [
9607
- {
9608
- provider: "gemini",
9609
- providerModelName: "gemini-2.5-flash"
9610
- },
9611
- {
9612
- provider: "openrouter",
9613
- providerModelName: "google/gemini-2.5-flash"
9614
- }
9615
- ],
9616
- "qwen3-coder-flash": [
9617
- {
9618
- provider: "openrouter",
9619
- providerModelName: "qwen/qwen3-coder-flash"
9620
- }
9621
- ],
9622
- "kimi-k2.5": [
9623
- {
9624
- provider: "openrouter",
9625
- providerModelName: "moonshotai/kimi-k2.5"
9626
- }
9627
- ],
9628
- "kimi-k2.6": [
9629
- {
9630
- provider: "openrouter",
9631
- providerModelName: "moonshotai/kimi-k2.6"
9391
+ exports$1.ENVELOPE_KEY = void 0;
9392
+ exports$1.wrapInEnvelope = wrapInEnvelope;
9393
+ exports$1.unwrapEnvelope = unwrapEnvelope;
9394
+ exports$1.ENVELOPE_KEY = "value";
9395
+ function wrapInEnvelope(schema) {
9396
+ return {
9397
+ type: "object",
9398
+ properties: { [exports$1.ENVELOPE_KEY]: withoutSchemaKeyword(schema) },
9399
+ required: [exports$1.ENVELOPE_KEY],
9400
+ additionalProperties: false
9401
+ };
9402
+ }
9403
+ function unwrapEnvelope(envelope2) {
9404
+ if (typeof envelope2 !== "object" || envelope2 === null || !(exports$1.ENVELOPE_KEY in envelope2)) {
9405
+ return { found: false };
9406
+ }
9407
+ return { found: true, value: envelope2[exports$1.ENVELOPE_KEY] };
9408
+ }
9409
+ const SUBSCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
9410
+ "items",
9411
+ "additionalItems",
9412
+ "prefixItems",
9413
+ "contains",
9414
+ "additionalProperties",
9415
+ "propertyNames",
9416
+ "unevaluatedItems",
9417
+ "unevaluatedProperties",
9418
+ "not",
9419
+ "if",
9420
+ "then",
9421
+ "else",
9422
+ "allOf",
9423
+ "anyOf",
9424
+ "oneOf"
9425
+ ]);
9426
+ const SUBSCHEMA_MAP_KEYWORDS = /* @__PURE__ */ new Set([
9427
+ "properties",
9428
+ "patternProperties",
9429
+ "dependentSchemas",
9430
+ "dependencies",
9431
+ "$defs",
9432
+ "definitions"
9433
+ ]);
9434
+ function withoutSchemaKeyword(schema) {
9435
+ const result = {};
9436
+ for (const [keyword, value] of Object.entries(schema)) {
9437
+ if (keyword === "$schema")
9438
+ continue;
9439
+ if (SUBSCHEMA_KEYWORDS.has(keyword)) {
9440
+ result[keyword] = Array.isArray(value) ? value.map(subschema) : subschema(value);
9441
+ } else if (SUBSCHEMA_MAP_KEYWORDS.has(keyword) && isObject(value)) {
9442
+ result[keyword] = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, subschema(child)]));
9443
+ } else {
9444
+ result[keyword] = value;
9632
9445
  }
9633
- ]
9634
- };
9635
- function parseCanonicalModelName(requestedModel) {
9636
- let m = requestedModel || "fast";
9637
- if (CANONICAL_SET.has(m))
9638
- return m;
9639
- let m2;
9640
- switch (m) {
9641
- case "fast":
9642
- m2 = "gpt-oss-120b";
9643
- break;
9644
- case "gemini":
9645
- m2 = "gemini-2.5-flash";
9646
- break;
9647
- case "qwen":
9648
- m2 = "qwen3-vl-235b-a22b-instruct";
9649
- break;
9650
- case "sonnet":
9651
- m2 = "claude-sonnet-4-6";
9652
- break;
9653
- case "opus":
9654
- m2 = "claude-opus-4-7";
9655
- break;
9656
- case "haiku":
9657
- m2 = "claude-haiku-4-5";
9658
- break;
9659
- case "kimi":
9660
- m2 = "kimi-k2.6";
9661
- break;
9662
- case "gpt":
9663
- m2 = "gpt-5";
9664
- break;
9665
9446
  }
9666
- if (m2)
9667
- return m2;
9447
+ return result;
9448
+ }
9449
+ function subschema(value) {
9450
+ return isObject(value) ? withoutSchemaKeyword(value) : value;
9451
+ }
9452
+ function isObject(value) {
9453
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9454
+ }
9455
+ })(envelope);
9456
+ return envelope;
9457
+ }
9458
+
9459
+ var renderPrompt = {};
9460
+
9461
+ var listPrompt = {};
9462
+
9463
+ var promptTemplateUtils = {};
9464
+
9465
+ var hasRequiredPromptTemplateUtils;
9466
+ function requirePromptTemplateUtils() {
9467
+ if (hasRequiredPromptTemplateUtils) return promptTemplateUtils;
9468
+ hasRequiredPromptTemplateUtils = 1;
9469
+ (function(exports$1) {
9470
+ Object.defineProperty(exports$1, "__esModule", { value: true });
9471
+ exports$1.replaceTemplateVarName = exports$1.templateVarName = void 0;
9472
+ const templateVarName = (varName) => `<<{${varName}}>>`;
9473
+ exports$1.templateVarName = templateVarName;
9474
+ const replaceTemplateVarName = (str, varName, value) => str.replaceAll((0, exports$1.templateVarName)(varName), value);
9475
+ exports$1.replaceTemplateVarName = replaceTemplateVarName;
9476
+ })(promptTemplateUtils);
9477
+ return promptTemplateUtils;
9478
+ }
9479
+
9480
+ var hasRequiredListPrompt;
9481
+ function requireListPrompt() {
9482
+ if (hasRequiredListPrompt) return listPrompt;
9483
+ hasRequiredListPrompt = 1;
9484
+ Object.defineProperty(listPrompt, "__esModule", { value: true });
9485
+ listPrompt.renderListPrompt = renderListPrompt;
9486
+ const prompt_template_utils_1 = requirePromptTemplateUtils();
9487
+ const envelope_1 = requireEnvelope();
9488
+ const DESCRIBE_OUTPUT = [
9489
+ `Your task is to transform the provided <input-data> into a JSON array, that represents a list of`,
9490
+ `${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}. The schema for this JSON array is defined below in <json-schema-spec> for you reference.`,
9491
+ `It uses the JSON Schema spec.`
9492
+ ];
9493
+ const MATCH_PRIMARY_KEYS = [
9494
+ `Note that the primary key of each element in the input-data is '${(0, prompt_template_utils_1.templateVarName)("PRIMARY_KEY")}'. In the output JSON array,`,
9495
+ `each object should have the same key with the same value of the original data, so we can map the input element against the output element.`
9496
+ ];
9497
+ const SYSTEM_PROMPTS = {
9498
+ "in-prompt": [
9499
+ ...DESCRIBE_OUTPUT,
9500
+ `Respond with only the instance, not the schema. It should not be wrapped in any wrapper object -- return exactly what the JSON schema is expecting.`,
9501
+ `Your entire response should be just the value of the JSON array containing objects with '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}'`,
9502
+ `and its primary key '${(0, prompt_template_utils_1.templateVarName)("PRIMARY_KEY")}', as valid JSON.`,
9503
+ `We will validate the result with the AJV Node library, using ajv.parse, against the JSON schema, and we expect it to validate correctly.`,
9504
+ ...MATCH_PRIMARY_KEYS
9505
+ ].join(" "),
9506
+ native: [
9507
+ ...DESCRIBE_OUTPUT,
9508
+ `Respond with only the instance, not the schema. Your reply is enforced by a JSON schema that wraps the result in an object:`,
9509
+ `put the JSON array, containing objects with '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}' and its primary key '${(0, prompt_template_utils_1.templateVarName)("PRIMARY_KEY")}', in its "${envelope_1.ENVELOPE_KEY}" field.`,
9510
+ `We will validate the "${envelope_1.ENVELOPE_KEY}" field with the AJV Node library against the JSON schema, and we expect it to validate correctly.`,
9511
+ ...MATCH_PRIMARY_KEYS
9512
+ ].join(" ")
9513
+ };
9514
+ function renderListPrompt(cast, enforcement) {
9515
+ const withPrimaryKey = (0, prompt_template_utils_1.replaceTemplateVarName)(SYSTEM_PROMPTS[enforcement], "PRIMARY_KEY", cast.primaryKey);
9516
+ const system = (0, prompt_template_utils_1.replaceTemplateVarName)(withPrimaryKey, "OUTPUT_TYPE_NAME", cast.outputName);
9517
+ const full = [
9518
+ cast.prompt || "Transform the provided data according to the schema.",
9519
+ system,
9520
+ `<json-schema-spec> ${JSON.stringify(cast.schema)} </json-schema-spec>`,
9521
+ `<input-data>${JSON.stringify(cast.rows)}</input-data>`
9522
+ ].join("\n");
9523
+ return { system, full };
9524
+ }
9525
+ return listPrompt;
9526
+ }
9527
+
9528
+ var valuePrompt = {};
9529
+
9530
+ var hasRequiredValuePrompt;
9531
+ function requireValuePrompt() {
9532
+ if (hasRequiredValuePrompt) return valuePrompt;
9533
+ hasRequiredValuePrompt = 1;
9534
+ Object.defineProperty(valuePrompt, "__esModule", { value: true });
9535
+ valuePrompt.renderValuePrompt = renderValuePrompt;
9536
+ const prompt_template_utils_1 = requirePromptTemplateUtils();
9537
+ const envelope_1 = requireEnvelope();
9538
+ const DESCRIBE_OUTPUT = [
9539
+ `Please respond with a single JSON object that represents '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}'.`,
9540
+ `The schema for this object (which uses the JSON Schema spec), is defined below for your reference.`,
9541
+ `Your task is to create an instance of this object. Respond with only the instance, not the schema.`
9542
+ ];
9543
+ const SYSTEM_PROMPTS = {
9544
+ "in-prompt": [
9545
+ ...DESCRIBE_OUTPUT,
9546
+ `Your entire response should be just the value of '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}', as valid JSON.`,
9547
+ `And it should not be wrapped in any wrapper object -- return exactly what the JSON schema is expecting.`,
9548
+ `We will validate the result with the AJV Node library, using ajv.parse, against the given schema, and we expect`,
9549
+ `it to validate correctly.`,
9550
+ `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.`
9551
+ ].join(" "),
9552
+ native: [
9553
+ ...DESCRIBE_OUTPUT,
9554
+ `Your reply is enforced by a JSON schema that wraps the result in an object:`,
9555
+ `put the value of '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}' in its "${envelope_1.ENVELOPE_KEY}" field.`,
9556
+ `We will validate the "${envelope_1.ENVELOPE_KEY}" field with the AJV Node library against the schema below, and we expect`,
9557
+ `it to validate correctly.`
9558
+ ].join(" ")
9559
+ };
9560
+ function renderValuePrompt(cast, enforcement) {
9561
+ const system = (0, prompt_template_utils_1.replaceTemplateVarName)(SYSTEM_PROMPTS[enforcement], "OUTPUT_TYPE_NAME", cast.outputName);
9562
+ const full = [
9563
+ cast.prompt || "Transform the provided data according to the schema.",
9564
+ system,
9565
+ `<json-schema-spec> ${JSON.stringify(cast.schema)} </json-schema-spec>`,
9566
+ cast.data ? `<input-data>${JSON.stringify(cast.data)}</input-data>` : ""
9567
+ ].join("\n");
9568
+ return { system, full };
9569
+ }
9570
+ return valuePrompt;
9571
+ }
9572
+
9573
+ var hasRequiredRenderPrompt;
9574
+ function requireRenderPrompt() {
9575
+ if (hasRequiredRenderPrompt) return renderPrompt;
9576
+ hasRequiredRenderPrompt = 1;
9577
+ Object.defineProperty(renderPrompt, "__esModule", { value: true });
9578
+ renderPrompt.renderPrompt = renderPrompt$1;
9579
+ const list_prompt_1 = requireListPrompt();
9580
+ const value_prompt_1 = requireValuePrompt();
9581
+ function renderPrompt$1(cast, enforcement) {
9582
+ switch (cast.kind) {
9583
+ case "value":
9584
+ return (0, value_prompt_1.renderValuePrompt)(cast, enforcement);
9585
+ case "list":
9586
+ return (0, list_prompt_1.renderListPrompt)(cast, enforcement);
9587
+ }
9588
+ }
9589
+ return renderPrompt;
9590
+ }
9591
+
9592
+ var hasRequiredRunCast;
9593
+ function requireRunCast() {
9594
+ if (hasRequiredRunCast) return runCast;
9595
+ hasRequiredRunCast = 1;
9596
+ Object.defineProperty(runCast, "__esModule", { value: true });
9597
+ runCast.runCast = runCast$1;
9598
+ runCast.judgeOutcome = judgeOutcome;
9599
+ const llm_response_extraction_1 = requireLlmResponseExtraction();
9600
+ const nua_json_schema_value_validation_1 = requireNuaJsonSchemaValueValidation();
9601
+ const envelope_1 = requireEnvelope();
9602
+ const render_prompt_1 = requireRenderPrompt();
9603
+ const RETRY_DELAYS_MS = [1e3, 2e3];
9604
+ const MAX_ATTEMPTS = RETRY_DELAYS_MS.length + 1;
9605
+ async function runCast$1(engine, request, logger) {
9606
+ let validate;
9607
+ try {
9608
+ validate = (0, nua_json_schema_value_validation_1.buildNuaJsonSchemaValueValidation)("library-req", request.schema);
9609
+ } catch (error) {
9610
+ return { success: false, error: `Invalid output schema: ${errorMessage(error)}` };
9611
+ }
9612
+ let plan = planAttempt(request, chooseEnforcement(engine, request.schema));
9613
+ let lastFailure = { error: "", prompt: plan.prompt };
9614
+ for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
9615
+ const outcome = await engine.attempt({
9616
+ prompt: plan.prompt.full,
9617
+ maxTokens: request.maxTokens,
9618
+ enforcement: plan.enforcement
9619
+ });
9620
+ const verdict = judgeOutcome(outcome, validate);
9621
+ if (verdict.kind === "accept") {
9622
+ return {
9623
+ success: true,
9624
+ data: verdict.data,
9625
+ usage: verdict.usage,
9626
+ prompt: plan.prompt,
9627
+ origin: verdict.origin,
9628
+ schemaEnforcement: plan.enforcement.kind
9629
+ };
9630
+ }
9631
+ if (verdict.kind === "give-up") {
9632
+ return { success: false, error: verdict.error, prompt: plan.prompt };
9633
+ }
9634
+ lastFailure = { error: verdict.error, prompt: plan.prompt };
9635
+ if (verdict.kind === "retry-in-prompt") {
9636
+ logger.warn("Engine rejected the native output schema; retrying with the schema in the prompt", {
9637
+ attempt,
9638
+ error: verdict.error
9639
+ });
9640
+ plan = planAttempt(request, { kind: "in-prompt" });
9641
+ continue;
9642
+ }
9643
+ if (attempt < MAX_ATTEMPTS) {
9644
+ const delayMs = RETRY_DELAYS_MS[attempt - 1];
9645
+ logger.warn("LLM call attempt failed; retrying", { attempt, delayMs, error: verdict.error });
9646
+ await delay(delayMs);
9647
+ }
9648
+ }
9649
+ return {
9650
+ success: false,
9651
+ error: `LLM call failed after ${MAX_ATTEMPTS} attempts. Last error: ${lastFailure.error}`,
9652
+ prompt: lastFailure.prompt
9653
+ };
9654
+ }
9655
+ function chooseEnforcement(engine, schema) {
9656
+ const nativeSchema = engine.nativeSchema((0, envelope_1.wrapInEnvelope)(schema));
9657
+ return nativeSchema ? { kind: "native", schema: nativeSchema } : { kind: "in-prompt" };
9658
+ }
9659
+ function planAttempt(request, enforcement) {
9660
+ return { enforcement, prompt: (0, render_prompt_1.renderPrompt)(request, enforcement.kind) };
9661
+ }
9662
+ function judgeOutcome(outcome, validate) {
9663
+ if (outcome.kind === "failed") {
9664
+ return verdictForFailure(outcome.failure);
9665
+ }
9666
+ const candidate = readAnswer(outcome.answer);
9667
+ if (!candidate.ok) {
9668
+ return { kind: "retry", error: candidate.error };
9669
+ }
9670
+ const validation = validate(candidate.value);
9671
+ if (!validation.success) {
9668
9672
  return {
9669
- kind: "validation-error",
9670
- message: `Invalid model name: ${m ?? "null/undefined"}`
9673
+ kind: "retry",
9674
+ error: `Validation failed: ${validation.error || "Unknown validation error"}
9675
+
9676
+ Raw LLM response:
9677
+ ${candidate.raw}`
9671
9678
  };
9672
9679
  }
9673
- })(modelInfo);
9674
- return modelInfo;
9680
+ return { kind: "accept", data: candidate.value, usage: outcome.usage, origin: outcome.origin };
9681
+ }
9682
+ function verdictForFailure(failure) {
9683
+ switch (failure.kind) {
9684
+ case "transient":
9685
+ return { kind: "retry", error: failure.message };
9686
+ case "schema-rejected":
9687
+ return { kind: "retry-in-prompt", error: failure.message };
9688
+ case "fatal":
9689
+ return { kind: "give-up", error: failure.message };
9690
+ }
9691
+ }
9692
+ function readAnswer(answer) {
9693
+ switch (answer.kind) {
9694
+ case "text":
9695
+ return readTextAnswer(answer.text);
9696
+ case "structured":
9697
+ return readStructuredAnswer(answer.envelope);
9698
+ }
9699
+ }
9700
+ function readTextAnswer(text) {
9701
+ try {
9702
+ const { cleanedResponse } = (0, llm_response_extraction_1.extractThinkingFromResponse)(text);
9703
+ return { ok: true, value: (0, llm_response_extraction_1.parseJsonFromLlmResponse)(cleanedResponse), raw: text };
9704
+ } catch (error) {
9705
+ return {
9706
+ ok: false,
9707
+ error: `Failed to parse LLM response as JSON: ${errorMessage(error)}
9708
+
9709
+ Raw LLM response:
9710
+ ${text}`
9711
+ };
9712
+ }
9713
+ }
9714
+ function readStructuredAnswer(envelope) {
9715
+ const raw = JSON.stringify(envelope);
9716
+ const unwrapped = (0, envelope_1.unwrapEnvelope)(envelope);
9717
+ if (!unwrapped.found) {
9718
+ return { ok: false, error: `Structured output has no "${envelope_1.ENVELOPE_KEY}" field: ${raw}` };
9719
+ }
9720
+ return { ok: true, value: unwrapped.value, raw };
9721
+ }
9722
+ function errorMessage(error) {
9723
+ return error instanceof Error ? error.message : String(error);
9724
+ }
9725
+ function delay(ms) {
9726
+ return new Promise((resolve) => setTimeout(resolve, ms));
9727
+ }
9728
+ return runCast;
9729
+ }
9730
+
9731
+ var hasRequiredNuaLlmClient;
9732
+ function requireNuaLlmClient() {
9733
+ if (hasRequiredNuaLlmClient) return nuaLlmClient;
9734
+ hasRequiredNuaLlmClient = 1;
9735
+ Object.defineProperty(nuaLlmClient, "__esModule", { value: true });
9736
+ nuaLlmClient.NuaLlmClient = void 0;
9737
+ const nua_errors_1 = requireNuaErrors();
9738
+ const validate_mappable_input_data_1 = requireValidateMappableInputData();
9739
+ const run_cast_1 = requireRunCast();
9740
+ const DEFAULT_MAX_TOKENS = 4096;
9741
+ class NuaLlmClient {
9742
+ constructor(engines) {
9743
+ this.engines = engines;
9744
+ }
9745
+ async castValue(params) {
9746
+ const route = this.engines.route(params.model);
9747
+ if (route.kind === "unroutable") {
9748
+ return { success: false, error: route.message };
9749
+ }
9750
+ const request = {
9751
+ kind: "value",
9752
+ prompt: params.input.prompt,
9753
+ data: params.input.data,
9754
+ outputName: params.output.name,
9755
+ schema: params.output.schema,
9756
+ maxTokens: params.maxTokens ?? DEFAULT_MAX_TOKENS
9757
+ };
9758
+ return (0, run_cast_1.runCast)(route.engine, request, this.engines.logger);
9759
+ }
9760
+ async castArray(params) {
9761
+ const { primaryKey, outputName, jsonSchema } = params.output;
9762
+ const rows = (0, validate_mappable_input_data_1.validateMappableInputData)(params.input.data, primaryKey);
9763
+ if ((0, nua_errors_1.isNuaValidationError)(rows)) {
9764
+ return { success: false, error: rows.message };
9765
+ }
9766
+ const route = this.engines.route(params.model);
9767
+ if (route.kind === "unroutable") {
9768
+ return { success: false, error: route.message };
9769
+ }
9770
+ const request = {
9771
+ kind: "list",
9772
+ prompt: params.input.prompt,
9773
+ rows,
9774
+ primaryKey,
9775
+ outputName,
9776
+ schema: jsonSchema,
9777
+ maxTokens: params.maxTokens ?? DEFAULT_MAX_TOKENS
9778
+ };
9779
+ return (0, run_cast_1.runCast)(route.engine, request, this.engines.logger);
9780
+ }
9781
+ }
9782
+ nuaLlmClient.NuaLlmClient = NuaLlmClient;
9783
+ return nuaLlmClient;
9784
+ }
9785
+
9786
+ var types = {};
9787
+
9788
+ var hasRequiredTypes;
9789
+ function requireTypes() {
9790
+ if (hasRequiredTypes) return types;
9791
+ hasRequiredTypes = 1;
9792
+ Object.defineProperty(types, "__esModule", { value: true });
9793
+ return types;
9675
9794
  }
9676
9795
 
9677
9796
  var providerConfig = {};
@@ -9682,7 +9801,13 @@ function requireProviderConfig() {
9682
9801
  hasRequiredProviderConfig = 1;
9683
9802
  (function(exports$1) {
9684
9803
  Object.defineProperty(exports$1, "__esModule", { value: true });
9685
- exports$1.providerConfigs = exports$1.extractOpenAiMessageText = exports$1.normalizeGeminiUsage = exports$1.normalizeOpenAiUsage = exports$1.normalizedUsageZero = void 0;
9804
+ exports$1.providerConfigs = exports$1.extractOpenAiMessageText = exports$1.normalizeGeminiUsage = exports$1.normalizeOpenAiUsage = exports$1.normalizedUsageZero = exports$1.LLM_PROVIDER_IDS = void 0;
9805
+ exports$1.LLM_PROVIDER_IDS = [
9806
+ "groq",
9807
+ "cerebras",
9808
+ "gemini",
9809
+ "openrouter"
9810
+ ];
9686
9811
  exports$1.normalizedUsageZero = {
9687
9812
  promptTokens: 0,
9688
9813
  completionTokens: 0,
@@ -9885,346 +10010,433 @@ function requireProviderConfig() {
9885
10010
  return providerConfig;
9886
10011
  }
9887
10012
 
9888
- var providerFormatters = {};
10013
+ var providerEngines = {};
9889
10014
 
9890
- var sseParser = {};
10015
+ var modelInfo = {};
9891
10016
 
9892
- var hasRequiredSseParser;
9893
- function requireSseParser() {
9894
- if (hasRequiredSseParser) return sseParser;
9895
- hasRequiredSseParser = 1;
9896
- Object.defineProperty(sseParser, "__esModule", { value: true });
9897
- sseParser.parseSSEStream = parseSSEStream;
9898
- async function* parseSSEStream(stream) {
9899
- const reader = stream.getReader();
9900
- const decoder = new TextDecoder();
9901
- let buffer = "";
9902
- try {
9903
- while (true) {
9904
- const { done, value } = await reader.read();
9905
- if (done)
9906
- break;
9907
- buffer += decoder.decode(value, { stream: true });
9908
- const parts = buffer.split(/\r?\n\r?\n/);
9909
- buffer = parts.pop();
9910
- for (const part of parts) {
9911
- for (const line of part.split(/\r?\n/)) {
9912
- if (line.startsWith("data: ")) {
9913
- const data = line.slice(6);
9914
- if (data === "[DONE]") {
9915
- return;
9916
- }
9917
- yield data;
9918
- }
9919
- }
9920
- }
10017
+ var hasRequiredModelInfo;
10018
+ function requireModelInfo() {
10019
+ if (hasRequiredModelInfo) return modelInfo;
10020
+ hasRequiredModelInfo = 1;
10021
+ (function(exports$1) {
10022
+ Object.defineProperty(exports$1, "__esModule", { value: true });
10023
+ exports$1.MODEL_ALIAS_NAMES = exports$1.MODEL_ALIASES = void 0;
10024
+ exports$1.isLlmProviderId = isLlmProviderId;
10025
+ exports$1.isModelAliasName = isModelAliasName;
10026
+ exports$1.resolveModelInput = resolveModelInput;
10027
+ const provider_config_1 = requireProviderConfig();
10028
+ exports$1.MODEL_ALIASES = {
10029
+ fast: [
10030
+ { provider: "cerebras", model: "qwen-3.8-27b" },
10031
+ { provider: "groq", model: "qwen/qwen3.8-27b" },
10032
+ { provider: "openrouter", model: "z-ai/glm-5.2" }
10033
+ ],
10034
+ gemini: [
10035
+ { provider: "gemini", model: "gemini-2.5-flash" },
10036
+ { provider: "openrouter", model: "google/gemini-2.5-flash" }
10037
+ ],
10038
+ qwen: [
10039
+ { provider: "openrouter", model: "qwen/qwen3-vl-235b-a22b-instruct" }
10040
+ ],
10041
+ sonnet: [
10042
+ { provider: "openrouter", model: "anthropic/claude-sonnet-4.6" }
10043
+ ],
10044
+ opus: [
10045
+ { provider: "openrouter", model: "anthropic/claude-opus-4.7" }
10046
+ ],
10047
+ haiku: [
10048
+ { provider: "openrouter", model: "anthropic/claude-haiku-4.5" }
10049
+ ],
10050
+ kimi: [
10051
+ { provider: "openrouter", model: "moonshotai/kimi-k2.7-code" }
10052
+ ],
10053
+ gpt: [
10054
+ { provider: "openrouter", model: "openai/gpt-5" }
10055
+ ]
10056
+ };
10057
+ exports$1.MODEL_ALIAS_NAMES = Object.keys(exports$1.MODEL_ALIASES);
10058
+ const MODEL_ALIAS_SET = new Set(exports$1.MODEL_ALIAS_NAMES);
10059
+ const LLM_PROVIDER_ID_SET = new Set(provider_config_1.LLM_PROVIDER_IDS);
10060
+ function isLlmProviderId(value) {
10061
+ return typeof value === "string" && LLM_PROVIDER_ID_SET.has(value);
10062
+ }
10063
+ function isModelAliasName(value) {
10064
+ return typeof value === "string" && MODEL_ALIAS_SET.has(value);
10065
+ }
10066
+ function validationError(message) {
10067
+ return {
10068
+ kind: "validation-error",
10069
+ message
10070
+ };
10071
+ }
10072
+ function validateProviderModel(input, configuredProviders) {
10073
+ if (!isLlmProviderId(input.provider)) {
10074
+ return validationError(`Invalid LLM provider: ${String(input.provider)}`);
9921
10075
  }
9922
- if (buffer.trim()) {
9923
- for (const line of buffer.split(/\r?\n/)) {
9924
- if (line.startsWith("data: ")) {
9925
- const data = line.slice(6);
9926
- if (data === "[DONE]") {
9927
- return;
9928
- }
9929
- yield data;
9930
- }
10076
+ if (!configuredProviders.has(input.provider)) {
10077
+ return validationError(`LLM provider ${input.provider} is not configured. Please check your API keys.`);
10078
+ }
10079
+ if (typeof input.model !== "string") {
10080
+ return validationError("model.model must be a string");
10081
+ }
10082
+ const model = input.model.trim();
10083
+ if (!model) {
10084
+ return validationError("model.model must be a non-empty string");
10085
+ }
10086
+ if (input.provider === "gemini" && model.startsWith("models/")) {
10087
+ return validationError('Gemini model names must use bare model IDs, for example "gemini-2.5-flash", not "models/gemini-2.5-flash".');
10088
+ }
10089
+ return {
10090
+ provider: input.provider,
10091
+ model
10092
+ };
10093
+ }
10094
+ function resolveModelInput(input, configuredProviders) {
10095
+ if (input == null) {
10096
+ return resolveModelInput({ alias: "fast" }, configuredProviders);
10097
+ }
10098
+ if (typeof input !== "object") {
10099
+ return validationError("model must be an object with either alias or provider/model fields");
10100
+ }
10101
+ if ("provider" in input || "model" in input) {
10102
+ return validateProviderModel(input, configuredProviders);
10103
+ }
10104
+ if ("alias" in input) {
10105
+ const alias = input.alias;
10106
+ if (!isModelAliasName(alias)) {
10107
+ return validationError(`Invalid model alias: ${String(alias)}`);
10108
+ }
10109
+ const configuredTarget = exports$1.MODEL_ALIASES[alias].find((target) => configuredProviders.has(target.provider));
10110
+ if (!configuredTarget) {
10111
+ return validationError(`No configured provider found for model alias ${alias}. Please check your API keys.`);
9931
10112
  }
10113
+ return configuredTarget;
9932
10114
  }
9933
- } finally {
9934
- reader.releaseLock();
10115
+ return validationError("model must include either alias or provider/model fields");
10116
+ }
10117
+ })(modelInfo);
10118
+ return modelInfo;
10119
+ }
10120
+
10121
+ var httpEngine = {};
10122
+
10123
+ var providerCall = {};
10124
+
10125
+ var hasRequiredProviderCall;
10126
+ function requireProviderCall() {
10127
+ if (hasRequiredProviderCall) return providerCall;
10128
+ hasRequiredProviderCall = 1;
10129
+ Object.defineProperty(providerCall, "__esModule", { value: true });
10130
+ providerCall.callProvider = callProvider;
10131
+ const logger_1 = logger.requireLogger();
10132
+ const provider_config_1 = requireProviderConfig();
10133
+ async function callProvider(call, logger) {
10134
+ const { target, apiOperation, request } = call;
10135
+ const method = request.method ?? "POST";
10136
+ const spanId = (0, logger_1.generateSpanId)();
10137
+ const startTime = Date.now();
10138
+ let status;
10139
+ (0, logger_1.logLlmCallStart)(logger, spanId, target.provider, apiOperation, {
10140
+ url: request.loggableUrl ?? request.url,
10141
+ httpMethod: method,
10142
+ model: target.model,
10143
+ maxTokens: call.maxTokens
10144
+ });
10145
+ try {
10146
+ const response = await fetch(request.url, {
10147
+ method,
10148
+ headers: request.headers ?? {},
10149
+ body: toFetchableBody(request.body)
10150
+ });
10151
+ status = response.status;
10152
+ const reply = await call.parseResponse(response);
10153
+ (0, logger_1.logLlmCallComplete)(logger, spanId, target.provider, apiOperation, {
10154
+ status: response.status,
10155
+ responseLength: call.responseLength(reply),
10156
+ headers: Object.fromEntries(response.headers.entries()),
10157
+ usage: call.usage(reply)
10158
+ }, Date.now() - startTime);
10159
+ return { kind: "ok", reply };
10160
+ } catch (error) {
10161
+ (0, logger_1.logLlmCallError)(logger, spanId, target.provider, apiOperation, error, Date.now() - startTime);
10162
+ return {
10163
+ kind: "failed",
10164
+ status,
10165
+ message: `${provider_config_1.providerConfigs[target.provider].errorLabel} API request failed: ${error instanceof Error ? error.message : "Unknown error"}`
10166
+ };
9935
10167
  }
9936
10168
  }
9937
- return sseParser;
10169
+ function toFetchableBody(body) {
10170
+ if (typeof body === "string" || body === void 0) {
10171
+ return body;
10172
+ }
10173
+ return JSON.stringify(body);
10174
+ }
10175
+ return providerCall;
9938
10176
  }
9939
10177
 
9940
- var hasRequiredProviderFormatters;
9941
- function requireProviderFormatters() {
9942
- if (hasRequiredProviderFormatters) return providerFormatters;
9943
- hasRequiredProviderFormatters = 1;
9944
- Object.defineProperty(providerFormatters, "__esModule", { value: true });
9945
- providerFormatters.buildOpenAiAgenticRequest = buildOpenAiAgenticRequest;
9946
- providerFormatters.parseOpenAiAgenticResponse = parseOpenAiAgenticResponse;
9947
- providerFormatters.buildGeminiAgenticRequest = buildGeminiAgenticRequest;
9948
- providerFormatters.parseGeminiAgenticResponse = parseGeminiAgenticResponse;
9949
- providerFormatters.streamOpenAiAgenticResponse = streamOpenAiAgenticResponse;
9950
- providerFormatters.streamGeminiAgenticResponse = streamGeminiAgenticResponse;
10178
+ var hasRequiredHttpEngine;
10179
+ function requireHttpEngine() {
10180
+ if (hasRequiredHttpEngine) return httpEngine;
10181
+ hasRequiredHttpEngine = 1;
10182
+ Object.defineProperty(httpEngine, "__esModule", { value: true });
10183
+ httpEngine.HttpEngine = void 0;
10184
+ const provider_call_1 = requireProviderCall();
9951
10185
  const provider_config_1 = requireProviderConfig();
9952
- const sse_parser_1 = requireSseParser();
9953
- function convertMessagesToOpenAi(messages, systemPrompt) {
9954
- const result = [];
9955
- if (systemPrompt) {
9956
- result.push({ role: "system", content: systemPrompt });
10186
+ const FATAL_HTTP_STATUSES = /* @__PURE__ */ new Set([401, 403, 404]);
10187
+ class HttpEngine {
10188
+ constructor(target, logger) {
10189
+ this.target = target;
10190
+ this.logger = logger;
9957
10191
  }
9958
- for (const msg of messages) {
9959
- switch (msg.role) {
9960
- case "user":
9961
- result.push({ role: "user", content: msg.content });
9962
- break;
9963
- case "assistant": {
9964
- const textParts = msg.content.filter((c) => c.type === "text").map((c) => c.text).join("");
9965
- const toolCalls = msg.content.filter((c) => c.type === "toolCall").map((c) => ({
9966
- id: c.id,
9967
- type: "function",
9968
- function: {
9969
- name: c.name,
9970
- arguments: JSON.stringify(c.arguments)
9971
- }
9972
- }));
9973
- const openAiMsg = {
9974
- role: "assistant",
9975
- content: textParts || null,
9976
- ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
9977
- };
9978
- result.push(openAiMsg);
9979
- break;
9980
- }
9981
- case "toolResult":
9982
- result.push({
9983
- role: "tool",
9984
- tool_call_id: msg.toolCallId,
9985
- content: msg.content
9986
- });
9987
- break;
10192
+ /** Provider APIs are given the schema in the prompt; none is enforced natively yet. */
10193
+ nativeSchema() {
10194
+ return null;
10195
+ }
10196
+ async attempt(request) {
10197
+ const { provider, model, apiKey } = this.target;
10198
+ const config = provider_config_1.providerConfigs[provider];
10199
+ const call = await (0, provider_call_1.callProvider)({
10200
+ target: this.target,
10201
+ apiOperation: config.apiOperation,
10202
+ maxTokens: request.maxTokens,
10203
+ request: config.buildRequest({ prompt: request.prompt, model, maxTokens: request.maxTokens }, apiKey),
10204
+ parseResponse: config.parseResponse,
10205
+ responseLength: (reply) => reply.text.length,
10206
+ usage: (reply) => reply.usage
10207
+ }, this.logger);
10208
+ if (call.kind === "failed") {
10209
+ return { kind: "failed", failure: failureForStatus(call.status, call.message) };
9988
10210
  }
10211
+ return {
10212
+ kind: "answered",
10213
+ answer: { kind: "text", text: call.reply.text },
10214
+ usage: call.reply.usage,
10215
+ origin: { engine: "http", provider, model }
10216
+ };
9989
10217
  }
9990
- return result;
9991
10218
  }
9992
- function convertToolsToOpenAi(tools) {
9993
- return tools.map((t) => ({
9994
- type: "function",
9995
- function: {
9996
- name: t.name,
9997
- description: t.description,
9998
- parameters: t.parameters
9999
- }
10000
- }));
10219
+ httpEngine.HttpEngine = HttpEngine;
10220
+ function failureForStatus(status, message) {
10221
+ const fatal = status !== void 0 && FATAL_HTTP_STATUSES.has(status);
10222
+ return { kind: fatal ? "fatal" : "transient", message };
10001
10223
  }
10002
- function buildOpenAiAgenticRequest(options, baseUrl, apiKey) {
10003
- const messages = convertMessagesToOpenAi(options.messages, options.systemPrompt);
10004
- const tools = convertToolsToOpenAi(options.tools);
10005
- const body = {
10006
- messages,
10007
- tools: tools.length > 0 ? tools : void 0,
10008
- model: options.model,
10009
- max_completion_tokens: options.maxTokens,
10010
- stream: options.stream ?? false
10011
- };
10012
- if (options.stream) {
10013
- body.stream_options = { include_usage: true };
10014
- }
10015
- const headers = {
10016
- "Content-Type": "application/json",
10017
- Authorization: `Bearer ${apiKey}`
10018
- };
10019
- return {
10020
- url: baseUrl,
10021
- method: "POST",
10022
- headers,
10023
- body,
10024
- loggableHeaders: {
10025
- ...headers,
10026
- Authorization: "Bearer [REDACTED]"
10027
- },
10028
- loggableBody: body
10029
- };
10224
+ return httpEngine;
10225
+ }
10226
+
10227
+ var hasRequiredProviderEngines;
10228
+ function requireProviderEngines() {
10229
+ if (hasRequiredProviderEngines) return providerEngines;
10230
+ hasRequiredProviderEngines = 1;
10231
+ Object.defineProperty(providerEngines, "__esModule", { value: true });
10232
+ providerEngines.ProviderEngines = void 0;
10233
+ providerEngines.providerEngines = providerEngines$1;
10234
+ const logger_1 = logger.requireLogger();
10235
+ const nua_errors_1 = requireNuaErrors();
10236
+ const model_info_1 = requireModelInfo();
10237
+ const http_engine_1 = requireHttpEngine();
10238
+ function providerEngines$1(config) {
10239
+ return new ProviderEngines(config);
10030
10240
  }
10031
- function parseOpenAiToolArguments(rawArguments, toolName, errorLabel) {
10032
- if (!rawArguments.trim()) {
10033
- return {};
10241
+ class ProviderEngines {
10242
+ constructor(config) {
10243
+ this.logger = config.logger ?? new logger_1.ConsoleLogger();
10244
+ this.defaultModel = config.model;
10245
+ const apiKeys = /* @__PURE__ */ new Map();
10246
+ for (const [id, provider] of Object.entries(config.providers)) {
10247
+ if (provider?.apiKey) {
10248
+ apiKeys.set(id, provider.apiKey);
10249
+ }
10250
+ }
10251
+ this.apiKeys = apiKeys;
10034
10252
  }
10035
- let parsed;
10036
- try {
10037
- parsed = JSON.parse(rawArguments);
10038
- } catch {
10039
- const preview = rawArguments.length > 500 ? rawArguments.slice(0, 500) + "..." : rawArguments;
10040
- throw new Error(`${errorLabel} API error: Invalid JSON arguments for tool "${toolName}": ${preview}`);
10253
+ route(model) {
10254
+ const resolved = this.resolve(model);
10255
+ if (resolved.kind === "unroutable") {
10256
+ return resolved;
10257
+ }
10258
+ return { kind: "routed", engine: new http_engine_1.HttpEngine(resolved.target, this.logger) };
10041
10259
  }
10042
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
10043
- throw new Error(`${errorLabel} API error: Tool "${toolName}" arguments must be a JSON object`);
10260
+ /** The provider model, with its API key, that a model choice runs on. */
10261
+ resolve(model) {
10262
+ const providerModel = (0, model_info_1.resolveModelInput)(model ?? this.defaultModel, new Set(this.apiKeys.keys()));
10263
+ if ((0, nua_errors_1.isNuaValidationError)(providerModel)) {
10264
+ return { kind: "unroutable", message: providerModel.message };
10265
+ }
10266
+ const apiKey = this.apiKeys.get(providerModel.provider);
10267
+ if (apiKey === void 0) {
10268
+ return { kind: "unroutable", message: `LLM provider ${providerModel.provider} is not configured.` };
10269
+ }
10270
+ return { kind: "resolved", target: { ...providerModel, apiKey } };
10044
10271
  }
10045
- return parsed;
10046
10272
  }
10047
- async function parseOpenAiAgenticResponse(response, errorLabel) {
10048
- if (response.status !== 200) {
10049
- const errorBody = await response.text();
10273
+ providerEngines.ProviderEngines = ProviderEngines;
10274
+ return providerEngines;
10275
+ }
10276
+
10277
+ var validateJsonSchema = {};
10278
+
10279
+ var errorUtils = {};
10280
+
10281
+ var hasRequiredErrorUtils;
10282
+ function requireErrorUtils() {
10283
+ if (hasRequiredErrorUtils) return errorUtils;
10284
+ hasRequiredErrorUtils = 1;
10285
+ Object.defineProperty(errorUtils, "__esModule", { value: true });
10286
+ errorUtils.getErrorMessageFromException = getErrorMessageFromException;
10287
+ function isErrorWithMessage(error) {
10288
+ return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
10289
+ }
10290
+ function getErrorMessageFromException(error) {
10291
+ if (isErrorWithMessage(error)) {
10292
+ return error.message;
10293
+ }
10294
+ return String(error);
10295
+ }
10296
+ return errorUtils;
10297
+ }
10298
+
10299
+ var hasRequiredValidateJsonSchema;
10300
+ function requireValidateJsonSchema() {
10301
+ if (hasRequiredValidateJsonSchema) return validateJsonSchema;
10302
+ hasRequiredValidateJsonSchema = 1;
10303
+ Object.defineProperty(validateJsonSchema, "__esModule", { value: true });
10304
+ validateJsonSchema.validateJsonSchema = void 0;
10305
+ const error_utils_1 = requireErrorUtils();
10306
+ const ajv_instances_1 = requireAjvInstances();
10307
+ const validateJsonSchema$1 = (schema) => {
10308
+ if (!schema || typeof schema !== "object") {
10309
+ return {
10310
+ kind: "validation-error",
10311
+ message: "Schema must be a valid object"
10312
+ };
10313
+ }
10314
+ const ajvInstance = ajv_instances_1.ajvInstances.getInstanceForSchema(schema);
10315
+ const isValidSchema = ajvInstance.validateSchema(schema);
10316
+ let errors = "";
10317
+ if (ajvInstance.errors) {
10318
+ errors = ajvInstance.errors.map((e) => JSON.stringify(e, null, 2)).join("; ");
10319
+ } else if (isValidSchema) {
10050
10320
  try {
10051
- const parsed = JSON.parse(errorBody);
10052
- const message = parsed?.error?.message || errorBody;
10053
- throw new Error(`${errorLabel} API error: ${response.status} - ${message}`);
10321
+ ajvInstance.compile(schema);
10322
+ return true;
10054
10323
  } catch (e) {
10055
- if (e instanceof Error && e.message.startsWith(`${errorLabel} API error:`))
10056
- throw e;
10057
- throw new Error(`${errorLabel} API error: ${response.status} - ${errorBody}`);
10324
+ errors = (0, error_utils_1.getErrorMessageFromException)(e);
10058
10325
  }
10326
+ } else {
10327
+ errors = "unexpected-situation-no-errors-found-for-invalid-schema";
10059
10328
  }
10060
- const responseBody = await response.json();
10061
- const choice = responseBody.choices?.[0];
10062
- if (!choice?.message) {
10063
- throw new Error(`${errorLabel} API error: No message in response. Body: ${JSON.stringify(responseBody)}`);
10064
- }
10065
- const contentBlocks = [];
10066
- const assistantText = (0, provider_config_1.extractOpenAiMessageText)(choice.message);
10067
- if (assistantText) {
10068
- contentBlocks.push({
10069
- type: "text",
10070
- text: assistantText
10071
- });
10072
- }
10073
- if (choice.message.tool_calls) {
10074
- for (const tc of choice.message.tool_calls) {
10075
- contentBlocks.push({
10076
- type: "toolCall",
10077
- id: tc.id,
10078
- name: tc.function.name,
10079
- arguments: parseOpenAiToolArguments(tc.function.arguments, tc.function.name, errorLabel)
10080
- });
10081
- }
10082
- }
10083
- const usage = (0, provider_config_1.normalizeOpenAiUsage)(responseBody.usage);
10084
- 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";
10085
10329
  return {
10086
- message: {
10087
- role: "assistant",
10088
- content: contentBlocks
10089
- },
10090
- usage,
10091
- stopReason
10330
+ kind: "validation-error",
10331
+ message: `Unable to validate JSON schema: ${errors}`
10092
10332
  };
10093
- }
10094
- function convertMessagesToGemini(messages) {
10095
- const result = [];
10096
- for (const msg of messages) {
10097
- switch (msg.role) {
10098
- case "user":
10099
- result.push({
10100
- role: "user",
10101
- parts: [{ text: msg.content }]
10102
- });
10103
- break;
10104
- case "assistant": {
10105
- const parts = [];
10106
- for (const block of msg.content) {
10107
- if (block.type === "text") {
10108
- parts.push({ text: block.text });
10109
- } else if (block.type === "toolCall") {
10110
- parts.push({
10111
- functionCall: {
10112
- name: block.name,
10113
- args: block.arguments
10114
- }
10115
- });
10116
- }
10117
- }
10118
- result.push({ role: "model", parts });
10119
- break;
10120
- }
10121
- case "toolResult": {
10122
- result.push({
10123
- role: "user",
10124
- parts: [
10125
- {
10126
- functionResponse: {
10127
- name: msg.toolName,
10128
- response: { content: msg.content }
10129
- }
10130
- }
10131
- ]
10132
- });
10133
- break;
10333
+ };
10334
+ validateJsonSchema.validateJsonSchema = validateJsonSchema$1;
10335
+ return validateJsonSchema;
10336
+ }
10337
+
10338
+ var stableStringify = {};
10339
+
10340
+ var hasRequiredStableStringify;
10341
+ function requireStableStringify() {
10342
+ if (hasRequiredStableStringify) return stableStringify;
10343
+ hasRequiredStableStringify = 1;
10344
+ Object.defineProperty(stableStringify, "__esModule", { value: true });
10345
+ stableStringify.stableStringify = stableStringify$1;
10346
+ function stableStringify$1(value) {
10347
+ const seen = /* @__PURE__ */ new WeakSet();
10348
+ const sorter = (_key, currentValue) => {
10349
+ if (currentValue && typeof currentValue === "object" && !Array.isArray(currentValue)) {
10350
+ if (seen.has(currentValue)) {
10351
+ return currentValue;
10134
10352
  }
10353
+ seen.add(currentValue);
10354
+ return Object.keys(currentValue).sort().reduce((acc, key) => {
10355
+ acc[key] = currentValue[key];
10356
+ return acc;
10357
+ }, {});
10135
10358
  }
10136
- }
10137
- return result;
10138
- }
10139
- function convertToolsToGemini(tools) {
10140
- if (tools.length === 0)
10141
- return [];
10142
- return [
10143
- {
10144
- functionDeclarations: tools.map((t) => ({
10145
- name: t.name,
10146
- description: t.description,
10147
- parameters: t.parameters
10148
- }))
10149
- }
10150
- ];
10359
+ return currentValue;
10360
+ };
10361
+ return JSON.stringify(value, sorter) ?? "";
10151
10362
  }
10152
- function buildGeminiAgenticRequest(options, apiKey) {
10153
- const contents = convertMessagesToGemini(options.messages);
10154
- const tools = convertToolsToGemini(options.tools);
10155
- const body = {
10156
- contents,
10157
- generationConfig: {
10158
- maxOutputTokens: options.maxTokens
10363
+ return stableStringify;
10364
+ }
10365
+
10366
+ var schemaUtils = {};
10367
+
10368
+ var hasRequiredSchemaUtils;
10369
+ function requireSchemaUtils() {
10370
+ if (hasRequiredSchemaUtils) return schemaUtils;
10371
+ hasRequiredSchemaUtils = 1;
10372
+ Object.defineProperty(schemaUtils, "__esModule", { value: true });
10373
+ return schemaUtils;
10374
+ }
10375
+
10376
+ var listSchema = {};
10377
+
10378
+ var hasRequiredListSchema;
10379
+ function requireListSchema() {
10380
+ if (hasRequiredListSchema) return listSchema;
10381
+ hasRequiredListSchema = 1;
10382
+ Object.defineProperty(listSchema, "__esModule", { value: true });
10383
+ listSchema.listSchema = listSchema$1;
10384
+ listSchema.parseListSchema = parseListSchema;
10385
+ function listSchema$1(itemSchema, keys) {
10386
+ const jsonSchema = {
10387
+ type: "array",
10388
+ items: {
10389
+ type: "object",
10390
+ required: [keys.primaryKey, keys.outputName],
10391
+ properties: {
10392
+ [keys.primaryKey]: {
10393
+ anyOf: [{ type: "string" }, { type: "number" }, { type: "integer" }]
10394
+ },
10395
+ [keys.outputName]: itemSchema
10396
+ }
10159
10397
  }
10160
10398
  };
10161
- if (tools.length > 0) {
10162
- body.tools = tools;
10399
+ if (typeof itemSchema.$schema === "string") {
10400
+ jsonSchema.$schema = itemSchema.$schema;
10163
10401
  }
10164
- if (options.systemPrompt) {
10165
- body.systemInstruction = {
10166
- parts: [{ text: options.systemPrompt }]
10167
- };
10402
+ return brand(keys, jsonSchema);
10403
+ }
10404
+ function parseListSchema(jsonSchema, keys) {
10405
+ if (isObject(jsonSchema) && jsonSchema.type === "array" && rowsHoldKeys(jsonSchema.items, keys)) {
10406
+ return brand(keys, jsonSchema);
10168
10407
  }
10169
- const action = options.stream ? "streamGenerateContent" : "generateContent";
10170
- const altParam = options.stream ? "&alt=sse" : "";
10171
- const url = `https://generativelanguage.googleapis.com/v1beta/models/${options.model}:${action}?key=${apiKey}${altParam}`;
10172
10408
  return {
10173
- url,
10174
- method: "POST",
10175
- headers: {
10176
- "Content-Type": "application/json"
10177
- },
10178
- body,
10179
- loggableUrl: url.replace(/key=[^&]+/, "key=[REDACTED]"),
10180
- loggableBody: body
10409
+ kind: "validation-error",
10410
+ message: `Not a list schema with rows keyed by "${keys.primaryKey}" holding "${keys.outputName}"`
10181
10411
  };
10182
10412
  }
10183
- async function parseGeminiAgenticResponse(response) {
10184
- if (response.status !== 200) {
10185
- const errorBody = await response.text();
10186
- try {
10187
- const parsed = JSON.parse(errorBody);
10188
- const message = parsed?.error?.message || errorBody;
10189
- throw new Error(`Gemini API error: ${response.status} - ${message}`);
10190
- } catch (e) {
10191
- if (e instanceof Error && e.message.startsWith("Gemini API error:"))
10192
- throw e;
10193
- throw new Error(`Gemini API error: ${response.status} - ${errorBody}`);
10194
- }
10195
- }
10196
- const responseBody = await response.json();
10197
- const candidate = responseBody.candidates?.[0];
10198
- if (!candidate?.content?.parts) {
10199
- throw new Error(`Gemini API error: No content in response. Body: ${JSON.stringify(responseBody)}`);
10200
- }
10201
- const contentBlocks = [];
10202
- let hasToolCalls = false;
10203
- for (const part of candidate.content.parts) {
10204
- if (part.text) {
10205
- contentBlocks.push({ type: "text", text: part.text });
10206
- }
10207
- if (part.functionCall) {
10208
- hasToolCalls = true;
10209
- contentBlocks.push({
10210
- type: "toolCall",
10211
- id: crypto.randomUUID(),
10212
- name: part.functionCall.name,
10213
- arguments: part.functionCall.args
10214
- });
10215
- }
10413
+ function rowsHoldKeys(items, keys) {
10414
+ if (!isObject(items) || !isObject(items.properties) || !Array.isArray(items.required)) {
10415
+ return false;
10216
10416
  }
10217
- const usage = (0, provider_config_1.normalizeGeminiUsage)(responseBody.usageMetadata);
10218
- const stopReason = hasToolCalls ? "tool_use" : "stop";
10219
- return {
10220
- message: {
10221
- role: "assistant",
10222
- content: contentBlocks
10223
- },
10224
- usage,
10225
- stopReason
10226
- };
10417
+ const { properties, required } = items;
10418
+ return [keys.primaryKey, keys.outputName].every((key) => key in properties && required.includes(key));
10419
+ }
10420
+ function brand(keys, jsonSchema) {
10421
+ return { primaryKey: keys.primaryKey, outputName: keys.outputName, jsonSchema };
10422
+ }
10423
+ function isObject(value) {
10424
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10227
10425
  }
10426
+ return listSchema;
10427
+ }
10428
+
10429
+ var runAgent = {};
10430
+
10431
+ var agentLoop = {};
10432
+
10433
+ var hasRequiredAgentLoop;
10434
+ function requireAgentLoop() {
10435
+ if (hasRequiredAgentLoop) return agentLoop;
10436
+ hasRequiredAgentLoop = 1;
10437
+ Object.defineProperty(agentLoop, "__esModule", { value: true });
10438
+ agentLoop.runAgentLoop = runAgentLoop;
10439
+ const provider_config_1 = requireProviderConfig();
10228
10440
  function safeEmit(onEvent, event) {
10229
10441
  if (!onEvent)
10230
10442
  return;
@@ -10233,441 +10445,470 @@ function requireProviderFormatters() {
10233
10445
  } catch {
10234
10446
  }
10235
10447
  }
10236
- async function streamOpenAiAgenticResponse(response, errorLabel, onEvent) {
10237
- if (response.status !== 200) {
10238
- const errorBody = await response.text();
10448
+ async function runAgentLoop(params) {
10449
+ const messages = [...params.messages];
10450
+ let totalUsage = { ...provider_config_1.normalizedUsageZero };
10451
+ const toolsByName = new Map(params.tools.map((tool) => [tool.name, tool]));
10452
+ let completionReason = "max_turns";
10453
+ const onEvent = params.onEvent;
10454
+ for (let turn = 0; turn < params.maxTurns; turn++) {
10455
+ safeEmit(onEvent, { type: "turn_start", turn });
10456
+ let response;
10239
10457
  try {
10240
- const parsed = JSON.parse(errorBody);
10241
- const message = parsed?.error?.message || errorBody;
10242
- throw new Error(`${errorLabel} API error: ${response.status} - ${message}`);
10243
- } catch (e) {
10244
- if (e instanceof Error && e.message.startsWith(`${errorLabel} API error:`))
10245
- throw e;
10246
- throw new Error(`${errorLabel} API error: ${response.status} - ${errorBody}`);
10458
+ response = await params.sendRequest(messages, params.tools, params.systemPrompt);
10459
+ } catch (error) {
10460
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
10461
+ safeEmit(onEvent, { type: "error", error: errorMessage });
10462
+ return buildAgentResult(messages, totalUsage, "error", errorMessage);
10247
10463
  }
10248
- }
10249
- if (!response.body) {
10250
- throw new Error(`${errorLabel} API error: Response body is null`);
10251
- }
10252
- let textContent = "";
10253
- const toolCallAccumulators = /* @__PURE__ */ new Map();
10254
- let finishReason = null;
10255
- let usage = { ...provider_config_1.normalizedUsageZero };
10256
- for await (const data of (0, sse_parser_1.parseSSEStream)(response.body)) {
10257
- let chunk;
10258
- try {
10259
- chunk = JSON.parse(data);
10260
- } catch {
10261
- continue;
10464
+ messages.push(response.message);
10465
+ totalUsage = addUsage(totalUsage, response.usage);
10466
+ safeEmit(onEvent, {
10467
+ type: "response_complete",
10468
+ message: response.message,
10469
+ usage: response.usage,
10470
+ stopReason: response.stopReason
10471
+ });
10472
+ const toolCalls = response.message.content.filter((c) => c.type === "toolCall");
10473
+ if (toolCalls.length === 0 || response.stopReason === "stop") {
10474
+ completionReason = "stop";
10475
+ return buildAgentResult(messages, totalUsage, completionReason);
10262
10476
  }
10263
- if (chunk.usage) {
10264
- usage = (0, provider_config_1.normalizeOpenAiUsage)(chunk.usage);
10265
- }
10266
- const choice = chunk.choices?.[0];
10267
- if (!choice)
10268
- continue;
10269
- if (choice.finish_reason) {
10270
- finishReason = choice.finish_reason;
10477
+ for (const toolCall of toolCalls) {
10478
+ safeEmit(onEvent, {
10479
+ type: "tool_start",
10480
+ toolCallId: toolCall.id,
10481
+ toolName: toolCall.name,
10482
+ arguments: toolCall.arguments
10483
+ });
10484
+ const tool = toolsByName.get(toolCall.name);
10485
+ if (!tool) {
10486
+ const result = {
10487
+ content: `Tool "${toolCall.name}" not found`,
10488
+ isError: true
10489
+ };
10490
+ messages.push({
10491
+ role: "toolResult",
10492
+ toolCallId: toolCall.id,
10493
+ toolName: toolCall.name,
10494
+ content: result.content,
10495
+ isError: true
10496
+ });
10497
+ safeEmit(onEvent, {
10498
+ type: "tool_complete",
10499
+ toolCallId: toolCall.id,
10500
+ toolName: toolCall.name,
10501
+ result
10502
+ });
10503
+ continue;
10504
+ }
10505
+ try {
10506
+ const result = await tool.execute(toolCall.arguments);
10507
+ messages.push({
10508
+ role: "toolResult",
10509
+ toolCallId: toolCall.id,
10510
+ toolName: toolCall.name,
10511
+ content: result.content,
10512
+ isError: result.isError ?? false
10513
+ });
10514
+ safeEmit(onEvent, {
10515
+ type: "tool_complete",
10516
+ toolCallId: toolCall.id,
10517
+ toolName: toolCall.name,
10518
+ result
10519
+ });
10520
+ } catch (error) {
10521
+ const errorContent = `Tool execution error: ${error instanceof Error ? error.message : "Unknown error"}`;
10522
+ const result = { content: errorContent, isError: true };
10523
+ messages.push({
10524
+ role: "toolResult",
10525
+ toolCallId: toolCall.id,
10526
+ toolName: toolCall.name,
10527
+ content: errorContent,
10528
+ isError: true
10529
+ });
10530
+ safeEmit(onEvent, {
10531
+ type: "tool_complete",
10532
+ toolCallId: toolCall.id,
10533
+ toolName: toolCall.name,
10534
+ result
10535
+ });
10536
+ }
10271
10537
  }
10272
- const delta = choice.delta;
10273
- if (!delta)
10274
- continue;
10275
- if (delta.content) {
10276
- textContent += delta.content;
10277
- safeEmit(onEvent, { type: "text_delta", text: delta.content });
10538
+ }
10539
+ return buildAgentResult(messages, totalUsage, completionReason, `Reached maxTurns limit (${params.maxTurns}) before receiving a final response`);
10540
+ }
10541
+ function addUsage(a, b) {
10542
+ return {
10543
+ promptTokens: a.promptTokens + b.promptTokens,
10544
+ completionTokens: a.completionTokens + b.completionTokens,
10545
+ totalTokens: a.totalTokens + b.totalTokens
10546
+ };
10547
+ }
10548
+ function extractLastAssistantText(messages) {
10549
+ const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
10550
+ if (lastAssistant?.role !== "assistant") {
10551
+ return void 0;
10552
+ }
10553
+ const text = lastAssistant.content.filter((c) => c.type === "text").map((c) => c.text).join("");
10554
+ return text || void 0;
10555
+ }
10556
+ function buildAgentResult(messages, usage, completionReason, error) {
10557
+ const success = completionReason === "stop" && !error;
10558
+ return {
10559
+ success,
10560
+ completionReason,
10561
+ messages,
10562
+ textResponse: extractLastAssistantText(messages),
10563
+ usage,
10564
+ error
10565
+ };
10566
+ }
10567
+ return agentLoop;
10568
+ }
10569
+
10570
+ var agentTurn = {};
10571
+
10572
+ var providerFormatters = {};
10573
+
10574
+ var sseParser = {};
10575
+
10576
+ var hasRequiredSseParser;
10577
+ function requireSseParser() {
10578
+ if (hasRequiredSseParser) return sseParser;
10579
+ hasRequiredSseParser = 1;
10580
+ Object.defineProperty(sseParser, "__esModule", { value: true });
10581
+ sseParser.parseSSEStream = parseSSEStream;
10582
+ async function* parseSSEStream(stream) {
10583
+ const reader = stream.getReader();
10584
+ const decoder = new TextDecoder();
10585
+ let buffer = "";
10586
+ try {
10587
+ while (true) {
10588
+ const { done, value } = await reader.read();
10589
+ if (done)
10590
+ break;
10591
+ buffer += decoder.decode(value, { stream: true });
10592
+ const parts = buffer.split(/\r?\n\r?\n/);
10593
+ buffer = parts.pop();
10594
+ for (const part of parts) {
10595
+ for (const line of part.split(/\r?\n/)) {
10596
+ if (line.startsWith("data: ")) {
10597
+ const data = line.slice(6);
10598
+ if (data === "[DONE]") {
10599
+ return;
10600
+ }
10601
+ yield data;
10602
+ }
10603
+ }
10604
+ }
10278
10605
  }
10279
- if (delta.tool_calls) {
10280
- for (const tc of delta.tool_calls) {
10281
- const existing = toolCallAccumulators.get(tc.index);
10282
- if (existing) {
10283
- if (tc.function?.arguments) {
10284
- existing.arguments += tc.function.arguments;
10606
+ if (buffer.trim()) {
10607
+ for (const line of buffer.split(/\r?\n/)) {
10608
+ if (line.startsWith("data: ")) {
10609
+ const data = line.slice(6);
10610
+ if (data === "[DONE]") {
10611
+ return;
10285
10612
  }
10286
- } else {
10287
- toolCallAccumulators.set(tc.index, {
10288
- id: tc.id ?? "",
10289
- name: tc.function?.name ?? "",
10290
- arguments: tc.function?.arguments ?? ""
10291
- });
10613
+ yield data;
10292
10614
  }
10293
10615
  }
10294
10616
  }
10617
+ } finally {
10618
+ reader.releaseLock();
10295
10619
  }
10296
- const contentBlocks = [];
10297
- if (textContent) {
10298
- contentBlocks.push({ type: "text", text: textContent });
10620
+ }
10621
+ return sseParser;
10622
+ }
10623
+
10624
+ var hasRequiredProviderFormatters;
10625
+ function requireProviderFormatters() {
10626
+ if (hasRequiredProviderFormatters) return providerFormatters;
10627
+ hasRequiredProviderFormatters = 1;
10628
+ Object.defineProperty(providerFormatters, "__esModule", { value: true });
10629
+ providerFormatters.buildOpenAiAgenticRequest = buildOpenAiAgenticRequest;
10630
+ providerFormatters.parseOpenAiAgenticResponse = parseOpenAiAgenticResponse;
10631
+ providerFormatters.buildGeminiAgenticRequest = buildGeminiAgenticRequest;
10632
+ providerFormatters.parseGeminiAgenticResponse = parseGeminiAgenticResponse;
10633
+ providerFormatters.streamOpenAiAgenticResponse = streamOpenAiAgenticResponse;
10634
+ providerFormatters.streamGeminiAgenticResponse = streamGeminiAgenticResponse;
10635
+ const provider_config_1 = requireProviderConfig();
10636
+ const sse_parser_1 = requireSseParser();
10637
+ function convertMessagesToOpenAi(messages, systemPrompt) {
10638
+ const result = [];
10639
+ if (systemPrompt) {
10640
+ result.push({ role: "system", content: systemPrompt });
10299
10641
  }
10300
- const sortedToolCalls = [...toolCallAccumulators.entries()].sort(([a], [b]) => a - b);
10301
- for (const [, tc] of sortedToolCalls) {
10302
- contentBlocks.push({
10303
- type: "toolCall",
10304
- id: tc.id,
10305
- name: tc.name,
10306
- arguments: parseOpenAiToolArguments(tc.arguments, tc.name, errorLabel)
10307
- });
10642
+ for (const msg of messages) {
10643
+ switch (msg.role) {
10644
+ case "user":
10645
+ result.push({ role: "user", content: msg.content });
10646
+ break;
10647
+ case "assistant": {
10648
+ const textParts = msg.content.filter((c) => c.type === "text").map((c) => c.text).join("");
10649
+ const toolCalls = msg.content.filter((c) => c.type === "toolCall").map((c) => ({
10650
+ id: c.id,
10651
+ type: "function",
10652
+ function: {
10653
+ name: c.name,
10654
+ arguments: JSON.stringify(c.arguments)
10655
+ }
10656
+ }));
10657
+ const openAiMsg = {
10658
+ role: "assistant",
10659
+ content: textParts || null,
10660
+ ...toolCalls.length > 0 ? { tool_calls: toolCalls } : {}
10661
+ };
10662
+ result.push(openAiMsg);
10663
+ break;
10664
+ }
10665
+ case "toolResult":
10666
+ result.push({
10667
+ role: "tool",
10668
+ tool_call_id: msg.toolCallId,
10669
+ content: msg.content
10670
+ });
10671
+ break;
10672
+ }
10308
10673
  }
10309
- const stopReason2 = finishReason === "tool_calls" || sortedToolCalls.length > 0 ? "tool_use" : "stop";
10674
+ return result;
10675
+ }
10676
+ function convertToolsToOpenAi(tools) {
10677
+ return tools.map((t) => ({
10678
+ type: "function",
10679
+ function: {
10680
+ name: t.name,
10681
+ description: t.description,
10682
+ parameters: t.parameters
10683
+ }
10684
+ }));
10685
+ }
10686
+ function buildOpenAiAgenticRequest(options, baseUrl, apiKey) {
10687
+ const messages = convertMessagesToOpenAi(options.messages, options.systemPrompt);
10688
+ const tools = convertToolsToOpenAi(options.tools);
10689
+ const body = {
10690
+ messages,
10691
+ tools: tools.length > 0 ? tools : void 0,
10692
+ model: options.model,
10693
+ max_completion_tokens: options.maxTokens,
10694
+ stream: options.stream ?? false
10695
+ };
10696
+ if (options.stream) {
10697
+ body.stream_options = { include_usage: true };
10698
+ }
10699
+ const headers = {
10700
+ "Content-Type": "application/json",
10701
+ Authorization: `Bearer ${apiKey}`
10702
+ };
10310
10703
  return {
10311
- message: { role: "assistant", content: contentBlocks },
10312
- usage,
10313
- stopReason: stopReason2
10704
+ url: baseUrl,
10705
+ method: "POST",
10706
+ headers,
10707
+ body,
10708
+ loggableHeaders: {
10709
+ ...headers,
10710
+ Authorization: "Bearer [REDACTED]"
10711
+ },
10712
+ loggableBody: body
10314
10713
  };
10315
10714
  }
10316
- async function streamGeminiAgenticResponse(response, onEvent) {
10715
+ function parseOpenAiToolArguments(rawArguments, toolName, errorLabel) {
10716
+ if (!rawArguments.trim()) {
10717
+ return {};
10718
+ }
10719
+ let parsed;
10720
+ try {
10721
+ parsed = JSON.parse(rawArguments);
10722
+ } catch {
10723
+ const preview = rawArguments.length > 500 ? rawArguments.slice(0, 500) + "..." : rawArguments;
10724
+ throw new Error(`${errorLabel} API error: Invalid JSON arguments for tool "${toolName}": ${preview}`);
10725
+ }
10726
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
10727
+ throw new Error(`${errorLabel} API error: Tool "${toolName}" arguments must be a JSON object`);
10728
+ }
10729
+ return parsed;
10730
+ }
10731
+ async function parseOpenAiAgenticResponse(response, errorLabel) {
10317
10732
  if (response.status !== 200) {
10318
10733
  const errorBody = await response.text();
10319
10734
  try {
10320
10735
  const parsed = JSON.parse(errorBody);
10321
10736
  const message = parsed?.error?.message || errorBody;
10322
- throw new Error(`Gemini API error: ${response.status} - ${message}`);
10737
+ throw new Error(`${errorLabel} API error: ${response.status} - ${message}`);
10323
10738
  } catch (e) {
10324
- if (e instanceof Error && e.message.startsWith("Gemini API error:"))
10739
+ if (e instanceof Error && e.message.startsWith(`${errorLabel} API error:`))
10325
10740
  throw e;
10326
- throw new Error(`Gemini API error: ${response.status} - ${errorBody}`);
10741
+ throw new Error(`${errorLabel} API error: ${response.status} - ${errorBody}`);
10327
10742
  }
10328
10743
  }
10329
- if (!response.body) {
10330
- throw new Error("Gemini API error: Response body is null");
10744
+ const responseBody = await response.json();
10745
+ const choice = responseBody.choices?.[0];
10746
+ if (!choice?.message) {
10747
+ throw new Error(`${errorLabel} API error: No message in response. Body: ${JSON.stringify(responseBody)}`);
10331
10748
  }
10332
10749
  const contentBlocks = [];
10333
- let hasToolCalls2 = false;
10334
- let textContent2 = "";
10335
- let usage2 = { ...provider_config_1.normalizedUsageZero };
10336
- for await (const data of (0, sse_parser_1.parseSSEStream)(response.body)) {
10337
- let chunk;
10338
- try {
10339
- chunk = JSON.parse(data);
10340
- } catch {
10341
- continue;
10342
- }
10343
- if (chunk.usageMetadata) {
10344
- usage2 = (0, provider_config_1.normalizeGeminiUsage)(chunk.usageMetadata);
10345
- }
10346
- const candidate = chunk.candidates?.[0];
10347
- if (!candidate?.content?.parts)
10348
- continue;
10349
- for (const part of candidate.content.parts) {
10350
- if (part.text) {
10351
- textContent2 += part.text;
10352
- safeEmit(onEvent, { type: "text_delta", text: part.text });
10353
- }
10354
- if (part.functionCall) {
10355
- hasToolCalls2 = true;
10356
- contentBlocks.push({
10357
- type: "toolCall",
10358
- id: crypto.randomUUID(),
10359
- name: part.functionCall.name,
10360
- arguments: part.functionCall.args
10361
- });
10362
- }
10363
- }
10750
+ const assistantText = (0, provider_config_1.extractOpenAiMessageText)(choice.message);
10751
+ if (assistantText) {
10752
+ contentBlocks.push({
10753
+ type: "text",
10754
+ text: assistantText
10755
+ });
10364
10756
  }
10365
- if (textContent2) {
10366
- contentBlocks.unshift({ type: "text", text: textContent2 });
10757
+ if (choice.message.tool_calls) {
10758
+ for (const tc of choice.message.tool_calls) {
10759
+ contentBlocks.push({
10760
+ type: "toolCall",
10761
+ id: tc.id,
10762
+ name: tc.function.name,
10763
+ arguments: parseOpenAiToolArguments(tc.function.arguments, tc.function.name, errorLabel)
10764
+ });
10765
+ }
10367
10766
  }
10368
- const stopReason3 = hasToolCalls2 ? "tool_use" : "stop";
10767
+ const usage = (0, provider_config_1.normalizeOpenAiUsage)(responseBody.usage);
10768
+ 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";
10369
10769
  return {
10370
- message: { role: "assistant", content: contentBlocks },
10371
- usage: usage2,
10372
- stopReason: stopReason3
10770
+ message: {
10771
+ role: "assistant",
10772
+ content: contentBlocks
10773
+ },
10774
+ usage,
10775
+ stopReason
10373
10776
  };
10374
10777
  }
10375
- return providerFormatters;
10376
- }
10377
-
10378
- var hasRequiredHttpLlmClient;
10379
- function requireHttpLlmClient() {
10380
- if (hasRequiredHttpLlmClient) return httpLlmClient;
10381
- hasRequiredHttpLlmClient = 1;
10382
- Object.defineProperty(httpLlmClient, "__esModule", { value: true });
10383
- httpLlmClient.HttpLlmClient = void 0;
10384
- const model_info_1 = requireModelInfo();
10385
- const logger_1 = requireLogger();
10386
- const provider_config_1 = requireProviderConfig();
10387
- const provider_formatters_1 = requireProviderFormatters();
10388
- class HttpLlmClient {
10389
- constructor(providerId, apiKey, logger) {
10390
- this.providerId = providerId;
10391
- this.apiKey = apiKey;
10392
- this.logger = logger;
10393
- }
10394
- async sendRequest(prompt, model, maxTokens, assistantPrefillPrompt) {
10395
- const provider = this.getProviderConfig();
10396
- const providerModelName = this.getProviderModelName(model);
10397
- const requestOptions = provider.buildRequest({
10398
- prompt,
10399
- model: providerModelName,
10400
- maxTokens,
10401
- assistantPrefillPrompt
10402
- }, this.apiKey);
10403
- return this.executeProviderCall({
10404
- provider,
10405
- model,
10406
- maxTokens,
10407
- apiOperation: provider.apiOperation,
10408
- requestOptions,
10409
- parseResponse: provider.parseResponse,
10410
- getResponsePreview: (parsedResponse) => parsedResponse.text,
10411
- getUsage: (parsedResponse) => parsedResponse.usage
10412
- });
10413
- }
10414
- async sendAgenticRequest(messages, tools, model, maxTokens, systemPrompt, onEvent) {
10415
- const provider = this.getProviderConfig();
10416
- const providerModelName = this.getProviderModelName(model);
10417
- const codec = this.getAgenticProviderCodec(provider.errorLabel);
10418
- const requestOptions = codec.buildRequest({
10419
- messages,
10420
- tools,
10421
- model: providerModelName,
10422
- maxTokens,
10423
- systemPrompt,
10424
- stream: !!onEvent
10425
- });
10426
- const parseResponse = onEvent ? (response) => codec.parseStreamingResponse(response, onEvent) : codec.parseResponse;
10427
- return this.executeProviderCall({
10428
- provider,
10429
- model,
10430
- maxTokens,
10431
- apiOperation: "agentic",
10432
- requestOptions,
10433
- parseResponse,
10434
- getResponsePreview: (parsedResponse) => parsedResponse.message.content.filter((content) => content.type === "text").map((content) => content.text).join(""),
10435
- getUsage: (parsedResponse) => parsedResponse.usage
10436
- });
10437
- }
10438
- getProviderConfig() {
10439
- const provider = provider_config_1.providerConfigs[this.providerId];
10440
- if (!provider) {
10441
- throw new Error(`Unknown LLM provider: ${this.providerId}`);
10442
- }
10443
- return provider;
10444
- }
10445
- getProviderModelName(model) {
10446
- const providerSpecificModelName = model_info_1.SUPPORTED_MODELS[model].find((pm) => pm.provider === this.providerId);
10447
- if (!providerSpecificModelName) {
10448
- 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`);
10449
- }
10450
- return providerSpecificModelName.providerModelName;
10451
- }
10452
- async executeProviderCall(params) {
10453
- const method = params.requestOptions.method ?? "POST";
10454
- const headers = params.requestOptions.headers ?? {};
10455
- const body = this.toFetchableBody(params.requestOptions.body);
10456
- const spanId = (0, logger_1.generateSpanId)();
10457
- const startTime = Date.now();
10458
- (0, logger_1.logLlmCallStart)(this.logger, spanId, params.provider.providerId, params.apiOperation, {
10459
- url: params.requestOptions.loggableUrl ?? params.requestOptions.url,
10460
- httpMethod: method,
10461
- model: params.model,
10462
- maxTokens: params.maxTokens
10463
- });
10464
- try {
10465
- const response = await fetch(params.requestOptions.url, {
10466
- method,
10467
- headers,
10468
- body
10469
- });
10470
- const parsedResponse = await params.parseResponse(response);
10471
- const duration = Date.now() - startTime;
10472
- (0, logger_1.logLlmCallComplete)(this.logger, spanId, params.provider.providerId, params.apiOperation, {
10473
- status: response.status,
10474
- responseText: params.getResponsePreview(parsedResponse),
10475
- headers: Object.fromEntries(response.headers.entries()),
10476
- usage: params.getUsage(parsedResponse)
10477
- }, duration);
10478
- return parsedResponse;
10479
- } catch (error) {
10480
- const duration = Date.now() - startTime;
10481
- (0, logger_1.logLlmCallError)(this.logger, spanId, params.provider.providerId, params.apiOperation, error, duration);
10482
- throw new Error(`${params.provider.errorLabel} API request failed: ${error instanceof Error ? error.message : "Unknown error"}`);
10778
+ function convertMessagesToGemini(messages) {
10779
+ const result = [];
10780
+ for (const msg of messages) {
10781
+ switch (msg.role) {
10782
+ case "user":
10783
+ result.push({
10784
+ role: "user",
10785
+ parts: [{ text: msg.content }]
10786
+ });
10787
+ break;
10788
+ case "assistant": {
10789
+ const parts = [];
10790
+ for (const block of msg.content) {
10791
+ if (block.type === "text") {
10792
+ parts.push({ text: block.text });
10793
+ } else if (block.type === "toolCall") {
10794
+ parts.push({
10795
+ functionCall: {
10796
+ name: block.name,
10797
+ args: block.arguments
10798
+ }
10799
+ });
10800
+ }
10801
+ }
10802
+ result.push({ role: "model", parts });
10803
+ break;
10804
+ }
10805
+ case "toolResult": {
10806
+ result.push({
10807
+ role: "user",
10808
+ parts: [
10809
+ {
10810
+ functionResponse: {
10811
+ name: msg.toolName,
10812
+ response: { content: msg.content }
10813
+ }
10814
+ }
10815
+ ]
10816
+ });
10817
+ break;
10818
+ }
10483
10819
  }
10484
10820
  }
10485
- toFetchableBody(bodyPayload) {
10486
- if (typeof bodyPayload === "string") {
10487
- return bodyPayload;
10821
+ return result;
10822
+ }
10823
+ function convertToolsToGemini(tools) {
10824
+ if (tools.length === 0)
10825
+ return [];
10826
+ return [
10827
+ {
10828
+ functionDeclarations: tools.map((t) => ({
10829
+ name: t.name,
10830
+ description: t.description,
10831
+ parameters: t.parameters
10832
+ }))
10488
10833
  }
10489
- if (bodyPayload === void 0) {
10490
- return void 0;
10834
+ ];
10835
+ }
10836
+ function buildGeminiAgenticRequest(options, apiKey) {
10837
+ const contents = convertMessagesToGemini(options.messages);
10838
+ const tools = convertToolsToGemini(options.tools);
10839
+ const body = {
10840
+ contents,
10841
+ generationConfig: {
10842
+ maxOutputTokens: options.maxTokens
10491
10843
  }
10492
- return JSON.stringify(bodyPayload);
10844
+ };
10845
+ if (tools.length > 0) {
10846
+ body.tools = tools;
10493
10847
  }
10494
- getAgenticProviderCodec(errorLabel) {
10495
- switch (this.providerId) {
10496
- case "groq":
10497
- return {
10498
- buildRequest: (options) => (0, provider_formatters_1.buildOpenAiAgenticRequest)(options, "https://api.groq.com/openai/v1/chat/completions", this.apiKey),
10499
- parseResponse: (response) => (0, provider_formatters_1.parseOpenAiAgenticResponse)(response, errorLabel),
10500
- parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamOpenAiAgenticResponse)(response, errorLabel, onEvent)
10501
- };
10502
- case "cerebras":
10503
- return {
10504
- buildRequest: (options) => (0, provider_formatters_1.buildOpenAiAgenticRequest)(options, "https://api.cerebras.ai/v1/chat/completions", this.apiKey),
10505
- parseResponse: (response) => (0, provider_formatters_1.parseOpenAiAgenticResponse)(response, errorLabel),
10506
- parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamOpenAiAgenticResponse)(response, errorLabel, onEvent)
10507
- };
10508
- case "openrouter":
10509
- return {
10510
- buildRequest: (options) => (0, provider_formatters_1.buildOpenAiAgenticRequest)(options, "https://openrouter.ai/api/v1/chat/completions", this.apiKey),
10511
- parseResponse: (response) => (0, provider_formatters_1.parseOpenAiAgenticResponse)(response, errorLabel),
10512
- parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamOpenAiAgenticResponse)(response, errorLabel, onEvent)
10513
- };
10514
- case "gemini":
10515
- return {
10516
- buildRequest: (options) => (0, provider_formatters_1.buildGeminiAgenticRequest)(options, this.apiKey),
10517
- parseResponse: provider_formatters_1.parseGeminiAgenticResponse,
10518
- parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamGeminiAgenticResponse)(response, onEvent)
10519
- };
10520
- default:
10521
- throw new Error(`Unsupported provider for agentic requests: ${this.providerId}`);
10522
- }
10848
+ if (options.systemPrompt) {
10849
+ body.systemInstruction = {
10850
+ parts: [{ text: options.systemPrompt }]
10851
+ };
10523
10852
  }
10524
- }
10525
- httpLlmClient.HttpLlmClient = HttpLlmClient;
10526
- return httpLlmClient;
10527
- }
10528
-
10529
- var castArrayPromptBuilder = {};
10530
-
10531
- var promptTemplateUtils = {};
10532
-
10533
- var hasRequiredPromptTemplateUtils;
10534
- function requirePromptTemplateUtils() {
10535
- if (hasRequiredPromptTemplateUtils) return promptTemplateUtils;
10536
- hasRequiredPromptTemplateUtils = 1;
10537
- (function(exports$1) {
10538
- Object.defineProperty(exports$1, "__esModule", { value: true });
10539
- exports$1.replaceTemplateVarName = exports$1.templateVarName = void 0;
10540
- const templateVarName = (varName) => `<<{${varName}}>>`;
10541
- exports$1.templateVarName = templateVarName;
10542
- const replaceTemplateVarName = (str, varName, value) => str.replaceAll((0, exports$1.templateVarName)(varName), value);
10543
- exports$1.replaceTemplateVarName = replaceTemplateVarName;
10544
- })(promptTemplateUtils);
10545
- return promptTemplateUtils;
10546
- }
10547
-
10548
- var hasRequiredCastArrayPromptBuilder;
10549
- function requireCastArrayPromptBuilder() {
10550
- if (hasRequiredCastArrayPromptBuilder) return castArrayPromptBuilder;
10551
- hasRequiredCastArrayPromptBuilder = 1;
10552
- Object.defineProperty(castArrayPromptBuilder, "__esModule", { value: true });
10553
- const prompt_template_utils_1 = requirePromptTemplateUtils();
10554
- const builder = () => {
10555
- const BASE_SYSTEM_PROMPT_WHEN_OUTPUT_TYPE_NAME_PROVIDED = [
10556
- `Your task is to transform the provided <input-data> into a JSON array, that represents a list of`,
10557
- `${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}. The schema for this JSON array is defined below in <json-schema-spec> for you reference.`,
10558
- `It uses the JSON Schema spec.`,
10559
- `Respond with only the instance, not the schema. It should not be wrapped in any wrapper object -- return exactly what the JSON schema is expecting.`,
10560
- `Your entire response should be just the value of the JSON array containing objects with '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}'`,
10561
- `and its primary key '${(0, prompt_template_utils_1.templateVarName)("PRIMARY_KEY")}', as valid JSON.`,
10562
- `We will validate the result with the AJV Node library, using ajv.parse, against the JSON schema, and we expect it to validate correctly.`,
10563
- `Note that the primary key of each element in the input-data is '${(0, prompt_template_utils_1.templateVarName)("PRIMARY_KEY")}'. In the output JSON array,`,
10564
- `each object should have the same key with the same value of the original data, so we can map the input element against the output element.`
10565
- ].join(" ");
10566
- const buildSystemPrompt = (primaryKey, outputName) => {
10567
- let a = BASE_SYSTEM_PROMPT_WHEN_OUTPUT_TYPE_NAME_PROVIDED;
10568
- a = (0, prompt_template_utils_1.replaceTemplateVarName)(a, "PRIMARY_KEY", primaryKey);
10569
- a = (0, prompt_template_utils_1.replaceTemplateVarName)(a, "OUTPUT_TYPE_NAME", outputName);
10570
- return a;
10571
- };
10572
- const buildFullPrompt = (req, uncachedInputDataRows) => {
10573
- const prompt = req.input.prompt;
10574
- const fullPrompt = [
10575
- prompt || "Transform the provided data according to the schema.",
10576
- // user prompt
10577
- buildSystemPrompt(req.input.primaryKey, req.output.name),
10578
- `<json-schema-spec> ${JSON.stringify(req.output.effectiveSchema)} </json-schema-spec>`,
10579
- `<input-data>${JSON.stringify(uncachedInputDataRows)}</input-data>`
10580
- ].join("\n");
10581
- return fullPrompt;
10582
- };
10853
+ const action = options.stream ? "streamGenerateContent" : "generateContent";
10854
+ const altParam = options.stream ? "&alt=sse" : "";
10855
+ const url = `https://generativelanguage.googleapis.com/v1beta/models/${options.model}:${action}?key=${apiKey}${altParam}`;
10583
10856
  return {
10584
- buildSystemPrompt,
10585
- buildFullPrompt
10586
- };
10587
- };
10588
- const castArrayPromptBuilder$1 = builder();
10589
- castArrayPromptBuilder.default = castArrayPromptBuilder$1;
10590
- return castArrayPromptBuilder;
10591
- }
10592
-
10593
- var castPromptBuilder = {};
10594
-
10595
- var hasRequiredCastPromptBuilder;
10596
- function requireCastPromptBuilder() {
10597
- if (hasRequiredCastPromptBuilder) return castPromptBuilder;
10598
- hasRequiredCastPromptBuilder = 1;
10599
- Object.defineProperty(castPromptBuilder, "__esModule", { value: true });
10600
- const prompt_template_utils_1 = requirePromptTemplateUtils();
10601
- const builder = () => {
10602
- const BASE_SYSTEM_PROMPT_WHEN_OUTPUT_TYPE_NAME_PROVIDED = [
10603
- `Please respond with a single JSON object that represents '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}'.`,
10604
- `The schema for this object (which uses the JSON Schema spec), is defined below for your reference.`,
10605
- `Your task is to create an instance of this object. Respond with only the instance, not the schema.`,
10606
- `Your entire response should be just the value of '${(0, prompt_template_utils_1.templateVarName)("OUTPUT_TYPE_NAME")}', as valid JSON.`,
10607
- `And it should not be wrapped in any wrapper object -- return exactly what the JSON schema is expecting.`,
10608
- `We will validate the result with the AJV Node library, using ajv.parse, against the given schema, and we expect`,
10609
- `it to validate correctly.`,
10610
- `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.`
10611
- ].join(" ");
10612
- const buildSystemPrompt = (reqParams) => {
10613
- let a = BASE_SYSTEM_PROMPT_WHEN_OUTPUT_TYPE_NAME_PROVIDED;
10614
- a = (0, prompt_template_utils_1.replaceTemplateVarName)(a, "OUTPUT_TYPE_NAME", reqParams.output.name);
10615
- return a;
10616
- };
10617
- const buildFullPrompt = (reqParams) => {
10618
- const { prompt, data } = reqParams.input;
10619
- const { effectiveSchema } = reqParams.output;
10620
- const fullPrompt = [
10621
- prompt || "Transform the provided data according to the schema.",
10622
- // user prompt
10623
- buildSystemPrompt(reqParams),
10624
- `<json-schema-spec> ${JSON.stringify(effectiveSchema)} </json-schema-spec>`,
10625
- data ? `<input-data>${JSON.stringify(data)}</input-data>` : ""
10626
- ].join("\n");
10627
- return fullPrompt;
10857
+ url,
10858
+ method: "POST",
10859
+ headers: {
10860
+ "Content-Type": "application/json"
10861
+ },
10862
+ body,
10863
+ loggableUrl: url.replace(/key=[^&]+/, "key=[REDACTED]"),
10864
+ loggableBody: body
10628
10865
  };
10866
+ }
10867
+ async function parseGeminiAgenticResponse(response) {
10868
+ if (response.status !== 200) {
10869
+ const errorBody = await response.text();
10870
+ try {
10871
+ const parsed = JSON.parse(errorBody);
10872
+ const message = parsed?.error?.message || errorBody;
10873
+ throw new Error(`Gemini API error: ${response.status} - ${message}`);
10874
+ } catch (e) {
10875
+ if (e instanceof Error && e.message.startsWith("Gemini API error:"))
10876
+ throw e;
10877
+ throw new Error(`Gemini API error: ${response.status} - ${errorBody}`);
10878
+ }
10879
+ }
10880
+ const responseBody = await response.json();
10881
+ const candidate = responseBody.candidates?.[0];
10882
+ if (!candidate?.content?.parts) {
10883
+ throw new Error(`Gemini API error: No content in response. Body: ${JSON.stringify(responseBody)}`);
10884
+ }
10885
+ const contentBlocks = [];
10886
+ let hasToolCalls = false;
10887
+ for (const part of candidate.content.parts) {
10888
+ if (part.text) {
10889
+ contentBlocks.push({ type: "text", text: part.text });
10890
+ }
10891
+ if (part.functionCall) {
10892
+ hasToolCalls = true;
10893
+ contentBlocks.push({
10894
+ type: "toolCall",
10895
+ id: crypto.randomUUID(),
10896
+ name: part.functionCall.name,
10897
+ arguments: part.functionCall.args
10898
+ });
10899
+ }
10900
+ }
10901
+ const usage = (0, provider_config_1.normalizeGeminiUsage)(responseBody.usageMetadata);
10902
+ const stopReason = hasToolCalls ? "tool_use" : "stop";
10629
10903
  return {
10630
- buildSystemPrompt,
10631
- buildFullPrompt
10904
+ message: {
10905
+ role: "assistant",
10906
+ content: contentBlocks
10907
+ },
10908
+ usage,
10909
+ stopReason
10632
10910
  };
10633
- };
10634
- const castPromptBuilder$1 = builder();
10635
- castPromptBuilder.default = castPromptBuilder$1;
10636
- return castPromptBuilder;
10637
- }
10638
-
10639
- var nuaErrors = {};
10640
-
10641
- var hasRequiredNuaErrors;
10642
- function requireNuaErrors() {
10643
- if (hasRequiredNuaErrors) return nuaErrors;
10644
- hasRequiredNuaErrors = 1;
10645
- Object.defineProperty(nuaErrors, "__esModule", { value: true });
10646
- nuaErrors.isNuaError = nuaErrors.isNuaInternalError = nuaErrors.isNuaValidationError = void 0;
10647
- const isNuaValidationError = (a) => {
10648
- return typeof a == "object" && a != null && "kind" in a && a.kind == "validation-error";
10649
- };
10650
- nuaErrors.isNuaValidationError = isNuaValidationError;
10651
- const isNuaInternalError = (a) => {
10652
- return typeof a == "object" && a != null && "kind" in a && a.kind == "internal-error";
10653
- };
10654
- nuaErrors.isNuaInternalError = isNuaInternalError;
10655
- const isNuaError = (a) => {
10656
- return typeof a == "object" && a != null && "kind" in a && (a.kind == "internal-error" || a.kind == "validation-error");
10657
- };
10658
- nuaErrors.isNuaError = isNuaError;
10659
- return nuaErrors;
10660
- }
10661
-
10662
- var agentLoop = {};
10663
-
10664
- var hasRequiredAgentLoop;
10665
- function requireAgentLoop() {
10666
- if (hasRequiredAgentLoop) return agentLoop;
10667
- hasRequiredAgentLoop = 1;
10668
- Object.defineProperty(agentLoop, "__esModule", { value: true });
10669
- agentLoop.runAgentLoop = runAgentLoop;
10670
- const provider_config_1 = requireProviderConfig();
10911
+ }
10671
10912
  function safeEmit(onEvent, event) {
10672
10913
  if (!onEvent)
10673
10914
  return;
@@ -10676,409 +10917,241 @@ function requireAgentLoop() {
10676
10917
  } catch {
10677
10918
  }
10678
10919
  }
10679
- async function runAgentLoop(params) {
10680
- const messages = [...params.messages];
10681
- let totalUsage = { ...provider_config_1.normalizedUsageZero };
10682
- const toolsByName = new Map(params.tools.map((tool) => [tool.name, tool]));
10683
- let completionReason = "max_turns";
10684
- const onEvent = params.onEvent;
10685
- for (let turn = 0; turn < params.maxTurns; turn++) {
10686
- safeEmit(onEvent, { type: "turn_start", turn });
10687
- let response;
10920
+ async function streamOpenAiAgenticResponse(response, errorLabel, onEvent) {
10921
+ if (response.status !== 200) {
10922
+ const errorBody = await response.text();
10688
10923
  try {
10689
- response = await params.sendRequest(messages, params.tools, params.systemPrompt);
10690
- } catch (error) {
10691
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
10692
- safeEmit(onEvent, { type: "error", error: errorMessage });
10693
- return buildAgentResult(messages, totalUsage, "error", errorMessage);
10924
+ const parsed = JSON.parse(errorBody);
10925
+ const message = parsed?.error?.message || errorBody;
10926
+ throw new Error(`${errorLabel} API error: ${response.status} - ${message}`);
10927
+ } catch (e) {
10928
+ if (e instanceof Error && e.message.startsWith(`${errorLabel} API error:`))
10929
+ throw e;
10930
+ throw new Error(`${errorLabel} API error: ${response.status} - ${errorBody}`);
10694
10931
  }
10695
- messages.push(response.message);
10696
- totalUsage = addUsage(totalUsage, response.usage);
10697
- safeEmit(onEvent, {
10698
- type: "response_complete",
10699
- message: response.message,
10700
- usage: response.usage,
10701
- stopReason: response.stopReason
10702
- });
10703
- const toolCalls = response.message.content.filter((c) => c.type === "toolCall");
10704
- if (toolCalls.length === 0 || response.stopReason === "stop") {
10705
- completionReason = "stop";
10706
- return buildAgentResult(messages, totalUsage, completionReason);
10932
+ }
10933
+ if (!response.body) {
10934
+ throw new Error(`${errorLabel} API error: Response body is null`);
10935
+ }
10936
+ let textContent = "";
10937
+ const toolCallAccumulators = /* @__PURE__ */ new Map();
10938
+ let finishReason = null;
10939
+ let usage = { ...provider_config_1.normalizedUsageZero };
10940
+ for await (const data of (0, sse_parser_1.parseSSEStream)(response.body)) {
10941
+ let chunk;
10942
+ try {
10943
+ chunk = JSON.parse(data);
10944
+ } catch {
10945
+ continue;
10707
10946
  }
10708
- for (const toolCall of toolCalls) {
10709
- safeEmit(onEvent, {
10710
- type: "tool_start",
10711
- toolCallId: toolCall.id,
10712
- toolName: toolCall.name,
10713
- arguments: toolCall.arguments
10714
- });
10715
- const tool = toolsByName.get(toolCall.name);
10716
- if (!tool) {
10717
- const result = {
10718
- content: `Tool "${toolCall.name}" not found`,
10719
- isError: true
10720
- };
10721
- messages.push({
10722
- role: "toolResult",
10723
- toolCallId: toolCall.id,
10724
- toolName: toolCall.name,
10725
- content: result.content,
10726
- isError: true
10727
- });
10728
- safeEmit(onEvent, {
10729
- type: "tool_complete",
10730
- toolCallId: toolCall.id,
10731
- toolName: toolCall.name,
10732
- result
10733
- });
10734
- continue;
10735
- }
10736
- try {
10737
- const result = await tool.execute(toolCall.arguments);
10738
- messages.push({
10739
- role: "toolResult",
10740
- toolCallId: toolCall.id,
10741
- toolName: toolCall.name,
10742
- content: result.content,
10743
- isError: result.isError ?? false
10744
- });
10745
- safeEmit(onEvent, {
10746
- type: "tool_complete",
10747
- toolCallId: toolCall.id,
10748
- toolName: toolCall.name,
10749
- result
10750
- });
10751
- } catch (error) {
10752
- const errorContent = `Tool execution error: ${error instanceof Error ? error.message : "Unknown error"}`;
10753
- const result = { content: errorContent, isError: true };
10754
- messages.push({
10755
- role: "toolResult",
10756
- toolCallId: toolCall.id,
10757
- toolName: toolCall.name,
10758
- content: errorContent,
10759
- isError: true
10760
- });
10761
- safeEmit(onEvent, {
10762
- type: "tool_complete",
10763
- toolCallId: toolCall.id,
10764
- toolName: toolCall.name,
10765
- result
10766
- });
10947
+ if (chunk.usage) {
10948
+ usage = (0, provider_config_1.normalizeOpenAiUsage)(chunk.usage);
10949
+ }
10950
+ const choice = chunk.choices?.[0];
10951
+ if (!choice)
10952
+ continue;
10953
+ if (choice.finish_reason) {
10954
+ finishReason = choice.finish_reason;
10955
+ }
10956
+ const delta = choice.delta;
10957
+ if (!delta)
10958
+ continue;
10959
+ if (delta.content) {
10960
+ textContent += delta.content;
10961
+ safeEmit(onEvent, { type: "text_delta", text: delta.content });
10962
+ }
10963
+ if (delta.tool_calls) {
10964
+ for (const tc of delta.tool_calls) {
10965
+ const existing = toolCallAccumulators.get(tc.index);
10966
+ if (existing) {
10967
+ if (tc.function?.arguments) {
10968
+ existing.arguments += tc.function.arguments;
10969
+ }
10970
+ } else {
10971
+ toolCallAccumulators.set(tc.index, {
10972
+ id: tc.id ?? "",
10973
+ name: tc.function?.name ?? "",
10974
+ arguments: tc.function?.arguments ?? ""
10975
+ });
10976
+ }
10767
10977
  }
10768
10978
  }
10769
10979
  }
10770
- return buildAgentResult(messages, totalUsage, completionReason, `Reached maxTurns limit (${params.maxTurns}) before receiving a final response`);
10771
- }
10772
- function addUsage(a, b) {
10773
- return {
10774
- promptTokens: a.promptTokens + b.promptTokens,
10775
- completionTokens: a.completionTokens + b.completionTokens,
10776
- totalTokens: a.totalTokens + b.totalTokens
10777
- };
10778
- }
10779
- function extractLastAssistantText(messages) {
10780
- const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
10781
- if (lastAssistant?.role !== "assistant") {
10782
- return void 0;
10980
+ const contentBlocks = [];
10981
+ if (textContent) {
10982
+ contentBlocks.push({ type: "text", text: textContent });
10783
10983
  }
10784
- const text = lastAssistant.content.filter((c) => c.type === "text").map((c) => c.text).join("");
10785
- return text || void 0;
10786
- }
10787
- function buildAgentResult(messages, usage, completionReason, error) {
10788
- const success = completionReason === "stop" && !error;
10789
- return {
10790
- success,
10791
- completionReason,
10792
- messages,
10793
- textResponse: extractLastAssistantText(messages),
10794
- usage,
10795
- error
10796
- };
10797
- }
10798
- return agentLoop;
10799
- }
10800
-
10801
- var hasRequiredNuaLlmClient;
10802
- function requireNuaLlmClient() {
10803
- if (hasRequiredNuaLlmClient) return nuaLlmClient;
10804
- hasRequiredNuaLlmClient = 1;
10805
- var __importDefault = nuaLlmClient && nuaLlmClient.__importDefault || function(mod) {
10806
- return mod && mod.__esModule ? mod : { "default": mod };
10807
- };
10808
- Object.defineProperty(nuaLlmClient, "__esModule", { value: true });
10809
- nuaLlmClient.NuaLlmClient = void 0;
10810
- const logger_1 = requireLogger();
10811
- const validate_mappable_input_data_1 = requireValidateMappableInputData();
10812
- const call_llm_service_1 = requireCallLlmService();
10813
- const nua_json_schema_value_validation_1 = requireNuaJsonSchemaValueValidation();
10814
- const http_llm_client_1 = requireHttpLlmClient();
10815
- const provider_config_1 = requireProviderConfig();
10816
- const model_info_1 = requireModelInfo();
10817
- const cast_array_prompt_builder_1 = __importDefault(requireCastArrayPromptBuilder());
10818
- const cast_prompt_builder_1 = __importDefault(requireCastPromptBuilder());
10819
- const nua_errors_1 = requireNuaErrors();
10820
- const agent_loop_1 = requireAgentLoop();
10821
- class NuaLlmClient {
10822
- constructor(config) {
10823
- this.logger = config.logger || new logger_1.ConsoleLogger();
10824
- this.clients = /* @__PURE__ */ new Map();
10825
- Object.entries(config.providers).forEach(([providerId, providerConfig]) => {
10826
- if (providerConfig?.apiKey) {
10827
- this.clients.set(providerId, new http_llm_client_1.HttpLlmClient(providerId, providerConfig.apiKey, this.logger));
10828
- }
10984
+ const sortedToolCalls = [...toolCallAccumulators.entries()].sort(([a], [b]) => a - b);
10985
+ for (const [, tc] of sortedToolCalls) {
10986
+ contentBlocks.push({
10987
+ type: "toolCall",
10988
+ id: tc.id,
10989
+ name: tc.name,
10990
+ arguments: parseOpenAiToolArguments(tc.arguments, tc.name, errorLabel)
10829
10991
  });
10830
10992
  }
10831
- getClientForModel(model) {
10832
- const supported = model_info_1.SUPPORTED_MODELS[model];
10833
- if (!supported || supported.length === 0) {
10834
- throw new Error(`Model ${model} is not supported or configuration is missing.`);
10835
- }
10836
- for (const option of supported) {
10837
- if (this.clients.has(option.provider)) {
10838
- return this.clients.get(option.provider);
10839
- }
10993
+ const stopReason2 = finishReason === "tool_calls" || sortedToolCalls.length > 0 ? "tool_use" : "stop";
10994
+ return {
10995
+ message: { role: "assistant", content: contentBlocks },
10996
+ usage,
10997
+ stopReason: stopReason2
10998
+ };
10999
+ }
11000
+ async function streamGeminiAgenticResponse(response, onEvent) {
11001
+ if (response.status !== 200) {
11002
+ const errorBody = await response.text();
11003
+ try {
11004
+ const parsed = JSON.parse(errorBody);
11005
+ const message = parsed?.error?.message || errorBody;
11006
+ throw new Error(`Gemini API error: ${response.status} - ${message}`);
11007
+ } catch (e) {
11008
+ if (e instanceof Error && e.message.startsWith("Gemini API error:"))
11009
+ throw e;
11010
+ throw new Error(`Gemini API error: ${response.status} - ${errorBody}`);
10840
11011
  }
10841
- throw new Error(`No configured provider found for model ${model}. Please check your API keys.`);
10842
11012
  }
10843
- resolveModel(modelName) {
10844
- const result = (0, model_info_1.parseCanonicalModelName)(modelName);
10845
- if ((0, nua_errors_1.isNuaValidationError)(result)) {
10846
- throw new Error(result.message);
10847
- }
10848
- return result;
11013
+ if (!response.body) {
11014
+ throw new Error("Gemini API error: Response body is null");
10849
11015
  }
10850
- async castValue(params) {
10851
- const model = this.resolveModel(params.model);
10852
- const client = this.getClientForModel(model);
10853
- const maxTokens = params.maxTokens || 4096;
10854
- const temperature = params.temperature ?? 0;
10855
- const prompt = cast_prompt_builder_1.default.buildFullPrompt(params);
10856
- const validationFn = (0, nua_json_schema_value_validation_1.buildNuaJsonSchemaValueValidation)("library-req", params.output.effectiveSchema);
11016
+ const contentBlocks = [];
11017
+ let hasToolCalls2 = false;
11018
+ let textContent2 = "";
11019
+ let usage2 = { ...provider_config_1.normalizedUsageZero };
11020
+ for await (const data of (0, sse_parser_1.parseSSEStream)(response.body)) {
11021
+ let chunk;
10857
11022
  try {
10858
- const result = await (0, call_llm_service_1.callLLM)(
10859
- client,
10860
- prompt,
10861
- model,
10862
- maxTokens,
10863
- temperature,
10864
- 3,
10865
- // default retries
10866
- validationFn
10867
- );
10868
- return {
10869
- success: true,
10870
- data: result.data,
10871
- usage: result.usage,
10872
- prompt
10873
- };
10874
- } catch (e) {
10875
- return {
10876
- success: false,
10877
- error: e instanceof Error ? e.message : String(e),
10878
- prompt
10879
- };
11023
+ chunk = JSON.parse(data);
11024
+ } catch {
11025
+ continue;
10880
11026
  }
10881
- }
10882
- async castArray(params) {
10883
- const model = this.resolveModel(params.model);
10884
- const client = this.getClientForModel(model);
10885
- const maxTokens = params.maxTokens || 4096;
10886
- const temperature = params.temperature ?? 0;
10887
- const validData = (0, validate_mappable_input_data_1.validateMappableInputData)(params.data, params.input.primaryKey);
10888
- if ((0, nua_errors_1.isNuaValidationError)(validData)) {
10889
- return {
10890
- success: false,
10891
- error: validData.message
10892
- };
11027
+ if (chunk.usageMetadata) {
11028
+ usage2 = (0, provider_config_1.normalizeGeminiUsage)(chunk.usageMetadata);
10893
11029
  }
10894
- const prompt = cast_array_prompt_builder_1.default.buildFullPrompt(params, validData);
10895
- const validationFn = (0, nua_json_schema_value_validation_1.buildNuaJsonSchemaValueValidation)("library-req", params.output.effectiveSchema);
10896
- try {
10897
- const result = await (0, call_llm_service_1.callLLM)(client, prompt, model, maxTokens, temperature, 3, validationFn);
10898
- return {
10899
- success: true,
10900
- data: result.data,
10901
- usage: result.usage,
10902
- prompt
10903
- };
10904
- } catch (e) {
10905
- return {
10906
- success: false,
10907
- error: e instanceof Error ? e.message : String(e),
10908
- prompt
10909
- };
11030
+ const candidate = chunk.candidates?.[0];
11031
+ if (!candidate?.content?.parts)
11032
+ continue;
11033
+ for (const part of candidate.content.parts) {
11034
+ if (part.text) {
11035
+ textContent2 += part.text;
11036
+ safeEmit(onEvent, { type: "text_delta", text: part.text });
11037
+ }
11038
+ if (part.functionCall) {
11039
+ hasToolCalls2 = true;
11040
+ contentBlocks.push({
11041
+ type: "toolCall",
11042
+ id: crypto.randomUUID(),
11043
+ name: part.functionCall.name,
11044
+ arguments: part.functionCall.args
11045
+ });
11046
+ }
10910
11047
  }
10911
11048
  }
10912
- async runAgent(params) {
10913
- try {
10914
- const model = this.resolveModel(params.model);
10915
- const client = this.getClientForModel(model);
10916
- const maxTokens = params.maxTokens ?? 4096;
10917
- const maxTurns = params.maxTurns ?? 10;
10918
- return (0, agent_loop_1.runAgentLoop)({
10919
- messages: params.messages,
10920
- tools: params.tools,
10921
- systemPrompt: params.systemPrompt,
10922
- maxTurns,
10923
- onEvent: params.onEvent,
10924
- sendRequest: (messages, tools, systemPrompt) => client.sendAgenticRequest(messages, tools, model, maxTokens, systemPrompt, params.onEvent)
10925
- });
10926
- } catch (e) {
10927
- return {
10928
- success: false,
10929
- completionReason: "error",
10930
- messages: params.messages,
10931
- usage: provider_config_1.normalizedUsageZero,
10932
- error: e instanceof Error ? e.message : String(e)
10933
- };
10934
- }
11049
+ if (textContent2) {
11050
+ contentBlocks.unshift({ type: "text", text: textContent2 });
10935
11051
  }
11052
+ const stopReason3 = hasToolCalls2 ? "tool_use" : "stop";
11053
+ return {
11054
+ message: { role: "assistant", content: contentBlocks },
11055
+ usage: usage2,
11056
+ stopReason: stopReason3
11057
+ };
10936
11058
  }
10937
- nuaLlmClient.NuaLlmClient = NuaLlmClient;
10938
- return nuaLlmClient;
10939
- }
10940
-
10941
- var types = {};
10942
-
10943
- var hasRequiredTypes;
10944
- function requireTypes() {
10945
- if (hasRequiredTypes) return types;
10946
- hasRequiredTypes = 1;
10947
- Object.defineProperty(types, "__esModule", { value: true });
10948
- return types;
11059
+ return providerFormatters;
10949
11060
  }
10950
11061
 
10951
- var validateJsonSchema = {};
10952
-
10953
- var errorUtils = {};
10954
-
10955
- var hasRequiredErrorUtils;
10956
- function requireErrorUtils() {
10957
- if (hasRequiredErrorUtils) return errorUtils;
10958
- hasRequiredErrorUtils = 1;
10959
- Object.defineProperty(errorUtils, "__esModule", { value: true });
10960
- errorUtils.getErrorMessageFromException = getErrorMessageFromException;
10961
- function isErrorWithMessage(error) {
10962
- return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
10963
- }
10964
- function getErrorMessageFromException(error) {
10965
- if (isErrorWithMessage(error)) {
10966
- return error.message;
11062
+ var hasRequiredAgentTurn;
11063
+ function requireAgentTurn() {
11064
+ if (hasRequiredAgentTurn) return agentTurn;
11065
+ hasRequiredAgentTurn = 1;
11066
+ Object.defineProperty(agentTurn, "__esModule", { value: true });
11067
+ agentTurn.sendAgentTurn = sendAgentTurn;
11068
+ const provider_call_1 = requireProviderCall();
11069
+ const provider_config_1 = requireProviderConfig();
11070
+ const provider_formatters_1 = requireProviderFormatters();
11071
+ async function sendAgentTurn(turn, logger) {
11072
+ const codec = agentCodec(turn.target);
11073
+ const onEvent = turn.onEvent;
11074
+ const call = await (0, provider_call_1.callProvider)({
11075
+ target: turn.target,
11076
+ apiOperation: "agentic",
11077
+ maxTokens: turn.maxTokens,
11078
+ request: codec.buildRequest({
11079
+ messages: turn.messages,
11080
+ tools: turn.tools,
11081
+ model: turn.target.model,
11082
+ maxTokens: turn.maxTokens,
11083
+ systemPrompt: turn.systemPrompt,
11084
+ stream: onEvent !== void 0
11085
+ }),
11086
+ parseResponse: onEvent ? (response) => codec.parseStreamingResponse(response, onEvent) : codec.parseResponse,
11087
+ responseLength: (reply) => reply.message.content.reduce((total, content) => total + (content.type === "text" ? content.text.length : 0), 0),
11088
+ usage: (reply) => reply.usage
11089
+ }, logger);
11090
+ if (call.kind === "failed") {
11091
+ throw new Error(call.message);
10967
11092
  }
10968
- return String(error);
11093
+ return call.reply;
10969
11094
  }
10970
- return errorUtils;
10971
- }
10972
-
10973
- var hasRequiredValidateJsonSchema;
10974
- function requireValidateJsonSchema() {
10975
- if (hasRequiredValidateJsonSchema) return validateJsonSchema;
10976
- hasRequiredValidateJsonSchema = 1;
10977
- Object.defineProperty(validateJsonSchema, "__esModule", { value: true });
10978
- validateJsonSchema.validateJsonSchema = void 0;
10979
- const error_utils_1 = requireErrorUtils();
10980
- const ajv_instances_1 = requireAjvInstances();
10981
- const validateJsonSchema$1 = (schema) => {
10982
- if (!schema || typeof schema !== "object") {
10983
- return {
10984
- kind: "validation-error",
10985
- message: "Schema must be a valid object"
10986
- };
10987
- }
10988
- const ajvInstance = ajv_instances_1.ajvInstances.getInstanceForSchema(schema);
10989
- const isValidSchema = ajvInstance.validateSchema(schema);
10990
- let errors = "";
10991
- if (ajvInstance.errors) {
10992
- errors = ajvInstance.errors.map((e) => JSON.stringify(e, null, 2)).join("; ");
10993
- } else if (isValidSchema) {
10994
- try {
10995
- ajvInstance.compile(schema);
10996
- return true;
10997
- } catch (e) {
10998
- errors = (0, error_utils_1.getErrorMessageFromException)(e);
10999
- }
11000
- } else {
11001
- errors = "unexpected-situation-no-errors-found-for-invalid-schema";
11095
+ function agentCodec({ provider, apiKey }) {
11096
+ const errorLabel = provider_config_1.providerConfigs[provider].errorLabel;
11097
+ switch (provider) {
11098
+ case "groq":
11099
+ return openAiStyleCodec("https://api.groq.com/openai/v1/chat/completions", apiKey, errorLabel);
11100
+ case "cerebras":
11101
+ return openAiStyleCodec("https://api.cerebras.ai/v1/chat/completions", apiKey, errorLabel);
11102
+ case "openrouter":
11103
+ return openAiStyleCodec("https://openrouter.ai/api/v1/chat/completions", apiKey, errorLabel);
11104
+ case "gemini":
11105
+ return {
11106
+ buildRequest: (options) => (0, provider_formatters_1.buildGeminiAgenticRequest)(options, apiKey),
11107
+ parseResponse: provider_formatters_1.parseGeminiAgenticResponse,
11108
+ parseStreamingResponse: provider_formatters_1.streamGeminiAgenticResponse
11109
+ };
11002
11110
  }
11111
+ }
11112
+ function openAiStyleCodec(url, apiKey, errorLabel) {
11003
11113
  return {
11004
- kind: "validation-error",
11005
- message: `Unable to validate JSON schema: ${errors}`
11006
- };
11007
- };
11008
- validateJsonSchema.validateJsonSchema = validateJsonSchema$1;
11009
- return validateJsonSchema;
11010
- }
11011
-
11012
- var stableStringify = {};
11013
-
11014
- var hasRequiredStableStringify;
11015
- function requireStableStringify() {
11016
- if (hasRequiredStableStringify) return stableStringify;
11017
- hasRequiredStableStringify = 1;
11018
- Object.defineProperty(stableStringify, "__esModule", { value: true });
11019
- stableStringify.stableStringify = stableStringify$1;
11020
- function stableStringify$1(value) {
11021
- const seen = /* @__PURE__ */ new WeakSet();
11022
- const sorter = (_key, currentValue) => {
11023
- if (currentValue && typeof currentValue === "object" && !Array.isArray(currentValue)) {
11024
- if (seen.has(currentValue)) {
11025
- return currentValue;
11026
- }
11027
- seen.add(currentValue);
11028
- return Object.keys(currentValue).sort().reduce((acc, key) => {
11029
- acc[key] = currentValue[key];
11030
- return acc;
11031
- }, {});
11032
- }
11033
- return currentValue;
11114
+ buildRequest: (options) => (0, provider_formatters_1.buildOpenAiAgenticRequest)(options, url, apiKey),
11115
+ parseResponse: (response) => (0, provider_formatters_1.parseOpenAiAgenticResponse)(response, errorLabel),
11116
+ parseStreamingResponse: (response, onEvent) => (0, provider_formatters_1.streamOpenAiAgenticResponse)(response, errorLabel, onEvent)
11034
11117
  };
11035
- return JSON.stringify(value, sorter) ?? "";
11036
11118
  }
11037
- return stableStringify;
11119
+ return agentTurn;
11038
11120
  }
11039
11121
 
11040
- var schemaUtils = {};
11041
-
11042
- var hasRequiredSchemaUtils;
11043
- function requireSchemaUtils() {
11044
- if (hasRequiredSchemaUtils) return schemaUtils;
11045
- hasRequiredSchemaUtils = 1;
11046
- Object.defineProperty(schemaUtils, "__esModule", { value: true });
11047
- schemaUtils.wrapArraySchema = wrapArraySchema;
11048
- schemaUtils.unwrapArraySchema = unwrapArraySchema;
11049
- function wrapArraySchema(schema, options) {
11050
- const { primaryKey, outputName } = options;
11051
- const schemaVersion = typeof schema.$schema === "string" ? schema.$schema : void 0;
11052
- const wrappedSchema = {
11053
- type: "array",
11054
- items: {
11055
- type: "object",
11056
- required: [primaryKey, outputName],
11057
- properties: {
11058
- [primaryKey]: {
11059
- anyOf: [{ type: "string" }, { type: "number" }, { type: "integer" }]
11060
- },
11061
- [outputName]: schema
11062
- }
11063
- }
11064
- };
11065
- if (schemaVersion) {
11066
- wrappedSchema.$schema = schemaVersion;
11067
- }
11068
- return wrappedSchema;
11069
- }
11070
- function unwrapArraySchema(wrappedSchema, outputName) {
11071
- const items = wrappedSchema.items;
11072
- if (!items || typeof items !== "object") {
11073
- return null;
11074
- }
11075
- const properties = items.properties;
11076
- if (!properties || typeof properties !== "object") {
11077
- return null;
11122
+ var hasRequiredRunAgent;
11123
+ function requireRunAgent() {
11124
+ if (hasRequiredRunAgent) return runAgent;
11125
+ hasRequiredRunAgent = 1;
11126
+ Object.defineProperty(runAgent, "__esModule", { value: true });
11127
+ runAgent.runAgent = runAgent$1;
11128
+ const provider_config_1 = requireProviderConfig();
11129
+ const agent_loop_1 = requireAgentLoop();
11130
+ const agent_turn_1 = requireAgentTurn();
11131
+ const DEFAULT_MAX_TOKENS = 4096;
11132
+ const DEFAULT_MAX_TURNS = 10;
11133
+ async function runAgent$1(providers, params) {
11134
+ const resolved = providers.resolve(params.model);
11135
+ if (resolved.kind === "unroutable") {
11136
+ return {
11137
+ success: false,
11138
+ completionReason: "error",
11139
+ messages: params.messages,
11140
+ usage: provider_config_1.normalizedUsageZero,
11141
+ error: resolved.message
11142
+ };
11078
11143
  }
11079
- return properties[outputName] ?? null;
11144
+ const maxTokens = params.maxTokens ?? DEFAULT_MAX_TOKENS;
11145
+ return (0, agent_loop_1.runAgentLoop)({
11146
+ messages: params.messages,
11147
+ tools: params.tools,
11148
+ systemPrompt: params.systemPrompt,
11149
+ maxTurns: params.maxTurns ?? DEFAULT_MAX_TURNS,
11150
+ onEvent: params.onEvent,
11151
+ sendRequest: (messages, tools, systemPrompt) => (0, agent_turn_1.sendAgentTurn)({ target: resolved.target, maxTokens, messages, tools, systemPrompt, onEvent: params.onEvent }, providers.logger)
11152
+ });
11080
11153
  }
11081
- return schemaUtils;
11154
+ return runAgent;
11082
11155
  }
11083
11156
 
11084
11157
  var hasRequiredDist;
@@ -11102,30 +11175,26 @@ function requireDist() {
11102
11175
  var __exportStar = dist && dist.__exportStar || function(m, exports2) {
11103
11176
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
11104
11177
  };
11105
- var __importDefault = dist && dist.__importDefault || function(mod) {
11106
- return mod && mod.__esModule ? mod : { "default": mod };
11107
- };
11108
11178
  Object.defineProperty(exports$1, "__esModule", { value: true });
11109
- exports$1.runAgentLoop = exports$1.stableStringify = exports$1.validateJsonSchema = exports$1.providerConfigs = exports$1.normalizedUsageZero = exports$1.castArrayPromptBuilder = exports$1.castPromptBuilder = void 0;
11179
+ exports$1.runAgentLoop = exports$1.runAgent = exports$1.parseListSchema = exports$1.listSchema = exports$1.stableStringify = exports$1.validateJsonSchema = exports$1.providerEngines = exports$1.providerConfigs = exports$1.normalizedUsageZero = exports$1.LLM_PROVIDER_IDS = void 0;
11110
11180
  __exportStar(requireNuaLlmClient(), exports$1);
11111
- __exportStar(requireLogger(), exports$1);
11181
+ __exportStar(logger.requireLogger(), exports$1);
11112
11182
  __exportStar(requireTypes(), exports$1);
11113
11183
  __exportStar(requireNuaErrors(), exports$1);
11114
- var cast_prompt_builder_1 = requireCastPromptBuilder();
11115
- Object.defineProperty(exports$1, "castPromptBuilder", { enumerable: true, get: function() {
11116
- return __importDefault(cast_prompt_builder_1).default;
11117
- } });
11118
- var cast_array_prompt_builder_1 = requireCastArrayPromptBuilder();
11119
- Object.defineProperty(exports$1, "castArrayPromptBuilder", { enumerable: true, get: function() {
11120
- return __importDefault(cast_array_prompt_builder_1).default;
11121
- } });
11122
11184
  var provider_config_1 = requireProviderConfig();
11185
+ Object.defineProperty(exports$1, "LLM_PROVIDER_IDS", { enumerable: true, get: function() {
11186
+ return provider_config_1.LLM_PROVIDER_IDS;
11187
+ } });
11123
11188
  Object.defineProperty(exports$1, "normalizedUsageZero", { enumerable: true, get: function() {
11124
11189
  return provider_config_1.normalizedUsageZero;
11125
11190
  } });
11126
11191
  Object.defineProperty(exports$1, "providerConfigs", { enumerable: true, get: function() {
11127
11192
  return provider_config_1.providerConfigs;
11128
11193
  } });
11194
+ var provider_engines_1 = requireProviderEngines();
11195
+ Object.defineProperty(exports$1, "providerEngines", { enumerable: true, get: function() {
11196
+ return provider_engines_1.providerEngines;
11197
+ } });
11129
11198
  var validate_json_schema_1 = requireValidateJsonSchema();
11130
11199
  Object.defineProperty(exports$1, "validateJsonSchema", { enumerable: true, get: function() {
11131
11200
  return validate_json_schema_1.validateJsonSchema;
@@ -11136,6 +11205,17 @@ function requireDist() {
11136
11205
  } });
11137
11206
  __exportStar(requireModelInfo(), exports$1);
11138
11207
  __exportStar(requireSchemaUtils(), exports$1);
11208
+ var list_schema_1 = requireListSchema();
11209
+ Object.defineProperty(exports$1, "listSchema", { enumerable: true, get: function() {
11210
+ return list_schema_1.listSchema;
11211
+ } });
11212
+ Object.defineProperty(exports$1, "parseListSchema", { enumerable: true, get: function() {
11213
+ return list_schema_1.parseListSchema;
11214
+ } });
11215
+ var run_agent_1 = requireRunAgent();
11216
+ Object.defineProperty(exports$1, "runAgent", { enumerable: true, get: function() {
11217
+ return run_agent_1.runAgent;
11218
+ } });
11139
11219
  var agent_loop_1 = requireAgentLoop();
11140
11220
  Object.defineProperty(exports$1, "runAgentLoop", { enumerable: true, get: function() {
11141
11221
  return agent_loop_1.runAgentLoop;
@@ -11146,77 +11226,58 @@ function requireDist() {
11146
11226
 
11147
11227
  var distExports = requireDist();
11148
11228
 
11149
- const normalizedUsageZero = {
11150
- promptTokens: 0,
11151
- completionTokens: 0,
11152
- totalTokens: 0
11153
- };
11154
11229
  class DirectBackend {
11155
11230
  constructor(config) {
11156
- if (!config.model) {
11157
- throw new Error("model is required for direct mode");
11158
- }
11159
- this.model = config.model;
11160
- this.client = new distExports.NuaLlmClient({ providers: config.providers });
11231
+ this.client = new distExports.NuaLlmClient(enginesFor(config));
11161
11232
  }
11162
11233
  async castValue(params) {
11163
- const model = params.model ?? this.model;
11164
11234
  const startTime = Date.now();
11165
11235
  const result = await this.client.castValue({
11166
- model,
11236
+ model: params.model,
11167
11237
  input: { prompt: params.prompt, data: params.data },
11168
- output: { name: params.outputName, effectiveSchema: params.outputSchema }
11238
+ output: { name: params.outputName, schema: params.outputSchema }
11169
11239
  });
11170
- const latencyMs = Date.now() - startTime;
11171
- if (!result.success) {
11172
- return {
11173
- success: false,
11174
- error: result.error || "Unknown error",
11175
- source: "direct",
11176
- latencyMs
11177
- };
11178
- }
11179
- return {
11180
- success: true,
11181
- data: result.data,
11182
- usage: result.usage || normalizedUsageZero,
11183
- model,
11184
- latencyMs,
11185
- source: "direct",
11186
- meta: {}
11187
- };
11240
+ return toDirectResult(result, Date.now() - startTime);
11188
11241
  }
11189
11242
  async castArray(params) {
11190
- const model = params.model ?? this.model;
11191
11243
  const startTime = Date.now();
11192
- const wrappedSchema = distExports.wrapArraySchema(params.outputSchema, {
11193
- primaryKey: params.primaryKey,
11194
- outputName: params.outputName
11195
- });
11196
11244
  const result = await this.client.castArray({
11197
- model,
11198
- data: params.data,
11199
- input: { prompt: params.prompt, primaryKey: params.primaryKey },
11200
- output: { name: params.outputName, effectiveSchema: wrappedSchema }
11245
+ model: params.model,
11246
+ input: { prompt: params.prompt, data: params.data },
11247
+ output: distExports.listSchema(params.outputSchema, {
11248
+ primaryKey: params.primaryKey,
11249
+ outputName: params.outputName
11250
+ })
11201
11251
  });
11202
- const latencyMs = Date.now() - startTime;
11203
- if (!result.success) {
11204
- return {
11205
- success: false,
11206
- error: result.error || "Unknown error",
11207
- source: "direct",
11208
- latencyMs
11209
- };
11210
- }
11211
- return {
11212
- success: true,
11213
- data: result.data,
11214
- usage: result.usage || normalizedUsageZero,
11215
- model,
11216
- latencyMs,
11217
- source: "direct",
11218
- meta: {}
11219
- };
11252
+ return toDirectResult(result, Date.now() - startTime);
11253
+ }
11254
+ }
11255
+ function enginesFor(config) {
11256
+ if (config.localAgent) {
11257
+ return config.localAgent;
11258
+ }
11259
+ return distExports.providerEngines({ providers: config.providers, model: config.model });
11260
+ }
11261
+ function toDirectResult(result, latencyMs) {
11262
+ if (!result.success) {
11263
+ return { success: false, error: result.error, source: "direct", latencyMs };
11264
+ }
11265
+ return {
11266
+ success: true,
11267
+ data: result.data,
11268
+ usage: result.usage,
11269
+ model: describeModel(result.origin),
11270
+ latencyMs,
11271
+ source: "direct",
11272
+ meta: { ...result.origin, schemaEnforcement: result.schemaEnforcement }
11273
+ };
11274
+ }
11275
+ function describeModel(origin) {
11276
+ switch (origin.engine) {
11277
+ case "http":
11278
+ return `${origin.provider}:${origin.model}`;
11279
+ case "local-agent":
11280
+ return `${origin.agent}:${origin.model ?? "default"}`;
11220
11281
  }
11221
11282
  }
11222
11283
 
@@ -11467,6 +11528,11 @@ class Nua {
11467
11528
  static gateway(config) {
11468
11529
  return new Nua(new GatewayBackend(config));
11469
11530
  }
11531
+ /**
11532
+ * Runs casts in this process: on LLM providers' APIs with your API keys (`providers`), or
11533
+ * on a coding-agent CLI installed on this machine (`localAgent`, set up with `localAgent()` or
11534
+ * `findLocalAgent()` from "nuabase/local-agent").
11535
+ */
11470
11536
  static direct(config) {
11471
11537
  return new Nua(new DirectBackend(config));
11472
11538
  }