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