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