nuabase 2.3.3 → 2.3.4

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.
package/README.md CHANGED
@@ -146,33 +146,33 @@ Every call returns a discriminated union. When `success` is `false`, you get an
146
146
 
147
147
  **Success**
148
148
 
149
- | Field | Type | Description |
150
- | ----------- | --------------------------------------------------------- | ------------------------------------------------------- |
151
- | `success` | `true` | Indicates that the request completed successfully. |
152
- | `data` | `T` (for `get`) or `Array<{ [pk]: value; [output]: T }>` (for `list`) | The typed result matching your schema. |
153
- | `usage` | `{ promptTokens, completionTokens, totalTokens }` | Token usage statistics for the LLM request. |
154
- | `model` | `string` | The LLM model used for this request. |
155
- | `latencyMs` | `number` | Request latency in milliseconds. |
156
- | `source` | `'gateway'` \| `'direct'` | Which backend processed the request. |
157
- | `meta` | `object` | Additional metadata (varies by source). |
149
+ | Field | Type | Description |
150
+ | ----------- | --------------------------------------------------------------------- | -------------------------------------------------- |
151
+ | `success` | `true` | Indicates that the request completed successfully. |
152
+ | `data` | `T` (for `get`) or `Array<{ [pk]: value; [output]: T }>` (for `list`) | The typed result matching your schema. |
153
+ | `usage` | `{ promptTokens, completionTokens, totalTokens }` | Token usage statistics for the LLM request. |
154
+ | `model` | `string` | The LLM model used for this request. |
155
+ | `latencyMs` | `number` | Request latency in milliseconds. |
156
+ | `source` | `'gateway'` \| `'direct'` | Which backend processed the request. |
157
+ | `meta` | `object` | Additional metadata (varies by source). |
158
158
 
159
159
  **Gateway-specific metadata** (`meta` when `source` is `'gateway'`):
160
160
 
161
- | Field | Type | Description |
162
- | ------------ | --------- | ---------------------------------------------- |
163
- | `requestId` | `string` | Unique identifier for tracing. |
164
- | `cached` | `boolean` | Whether the result was served from cache. |
165
- | `llmUsage` | `object` | Token usage from LLM calls. |
166
- | `cacheUsage` | `object` | Token usage served from cache. |
161
+ | Field | Type | Description |
162
+ | ------------ | --------- | ----------------------------------------- |
163
+ | `requestId` | `string` | Unique identifier for tracing. |
164
+ | `cached` | `boolean` | Whether the result was served from cache. |
165
+ | `llmUsage` | `object` | Token usage from LLM calls. |
166
+ | `cacheUsage` | `object` | Token usage served from cache. |
167
167
 
168
168
  **Error**
169
169
 
170
- | Field | Type | Description |
171
- | ----------- | ----------------------------- | -------------------------------------------------------- |
172
- | `success` | `false` | Indicates the request failed. |
173
- | `error` | `string` | Message describing the error. |
174
- | `source` | `'gateway'` \| `'direct'` | Which backend returned the error. |
175
- | `latencyMs` | `number` | Time until failure in milliseconds. |
170
+ | Field | Type | Description |
171
+ | ----------- | ------------------------- | ----------------------------------- |
172
+ | `success` | `false` | Indicates the request failed. |
173
+ | `error` | `string` | Message describing the error. |
174
+ | `source` | `'gateway'` \| `'direct'` | Which backend returned the error. |
175
+ | `latencyMs` | `number` | Time until failure in milliseconds. |
176
176
 
177
177
  ## SDK API
178
178
 
@@ -187,8 +187,22 @@ Creates a client that connects to the Nuabase API gateway. Use this for producti
187
187
  **`Nua.direct(config)`**
188
188
  Creates a client that calls LLM providers directly (in-process). Use this for serverless, edge functions, or CLI tools where you don't need the gateway infrastructure.
189
189
 
190
- - `model: string` – The model to use (e.g., `'gpt-4o-mini'`).
191
- - `providers: { openai?: { apiKey: string }, ... }` – Provider credentials.
190
+ - `model?: ModelInput` – Optional default model. Omit it to use `{ alias: 'fast' }`.
191
+ - `providers: { groq?: { apiKey: string }, cerebras?: { apiKey: string }, gemini?: { apiKey: string }, openrouter?: { apiKey: string } }` – Provider credentials.
192
+
193
+ Model inputs are objects, not provider-prefixed strings:
194
+
195
+ ```ts
196
+ await nua.get('Extract the company name', {
197
+ output: { name: 'companyName', schema: z.string() },
198
+ model: { provider: 'openrouter', model: 'z-ai/glm-5.2' },
199
+ });
200
+
201
+ await nua.get('Extract the company name', {
202
+ output: { name: 'companyName', schema: z.string() },
203
+ model: { alias: 'fast' },
204
+ });
205
+ ```
192
206
 
193
207
  ### Methods
194
208
 
@@ -196,7 +210,7 @@ Creates a client that calls LLM providers directly (in-process). Use this for se
196
210
  Returns a simple string response from the LLM.
197
211
 
198
212
  ```ts
199
- const result = await nua.get("Tell me a joke");
213
+ const result = await nua.get('Tell me a joke');
200
214
  if (result.success) console.log(result.data); // string
201
215
  ```
202
216
 
@@ -208,8 +222,8 @@ Returns a typed single value. Parameters:
208
222
  - `options.output: { name: string; schema: ZodSchema }` – Output name and Zod schema.
209
223
 
210
224
  ```ts
211
- const result = await nua.get("Extract the address", {
212
- input: "123 Main St, Springfield, IL 62701",
225
+ const result = await nua.get('Extract the address', {
226
+ input: '123 Main St, Springfield, IL 62701',
213
227
  output: { name: 'address', schema: AddressSchema },
214
228
  });
215
229
  if (result.success) console.log(result.data); // typed as z.infer<typeof AddressSchema>
@@ -224,20 +238,20 @@ Processes an array of items. Parameters:
224
238
  - `options.output: { name: string; schema: ZodSchema }` – Output configuration.
225
239
 
226
240
  ```ts
227
- const result = await nua.list("Classify each lead", {
241
+ const result = await nua.list('Classify each lead', {
228
242
  input: leads,
229
243
  primaryKey: 'id',
230
244
  output: { name: 'classification', schema: ClassificationSchema },
231
245
  });
232
246
  if (result.success) {
233
- result.data.forEach(row => console.log(row.id, row.classification));
247
+ result.data.forEach((row) => console.log(row.id, row.classification));
234
248
  }
235
249
  ```
236
250
 
237
- **`nua.queueGet(prompt, options?)`** *(Gateway mode only)*
251
+ **`nua.queueGet(prompt, options?)`** _(Gateway mode only)_
238
252
  Submits an async job for single-value operations. Returns `{ success: true, jobId }`.
239
253
 
240
- **`nua.queueList(prompt, options)`** *(Gateway mode only)*
254
+ **`nua.queueList(prompt, options)`** _(Gateway mode only)_
241
255
  Submits an async job for array operations. Returns `{ success: true, jobId }`.
242
256
 
243
257
  ## Next Steps
@@ -14,7 +14,6 @@ function requireLogger() {
14
14
  hasRequiredLogger = 1;
15
15
  Object.defineProperty(logger, "__esModule", { value: true });
16
16
  logger.logLlmCallError = logger.logLlmCallComplete = logger.logLlmCallStart = logger.generateSpanId = logger.ConsoleLogger = void 0;
17
- logger.truncateText = truncateText;
18
17
  logger.pickHeaders = pickHeaders;
19
18
  logger.normalizeError = normalizeError;
20
19
  class ConsoleLogger {
@@ -34,13 +33,6 @@ function requireLogger() {
34
33
  logger.ConsoleLogger = ConsoleLogger;
35
34
  const generateSpanId = () => crypto.randomUUID();
36
35
  logger.generateSpanId = generateSpanId;
37
- function truncateText(text, limit = 500) {
38
- const length = text.length;
39
- if (length <= limit) {
40
- return { preview: text, length };
41
- }
42
- return { preview: text.slice(0, limit), length };
43
- }
44
36
  function pickHeaders(headers, allowlist, redactSet) {
45
37
  const result = {};
46
38
  for (const [key, value] of Object.entries(headers)) {
@@ -75,16 +67,13 @@ function requireLogger() {
75
67
  };
76
68
  logger.logLlmCallStart = logLlmCallStart;
77
69
  const logLlmCallComplete = (logger2, spanId, service, method, response, duration) => {
78
- const { headers, responseText, ...rest } = response;
79
- const { preview: responsePreview, length: responseLength } = truncateText(responseText);
70
+ const { headers, ...rest } = response;
80
71
  logger2.info("LLM call completed", {
81
72
  type: "llm_call_complete",
82
73
  span_id: spanId,
83
74
  service,
84
75
  method,
85
76
  ...rest,
86
- responsePreview,
87
- responseLength,
88
77
  ...pickHeaders(headers, LLM_RESPONSE_HEADER_ALLOWLIST),
89
78
  duration_ms: duration
90
79
  });
@@ -9510,170 +9499,6 @@ function requireNuaJsonSchemaValueValidation() {
9510
9499
 
9511
9500
  var httpLlmClient = {};
9512
9501
 
9513
- var modelInfo = {};
9514
-
9515
- var hasRequiredModelInfo;
9516
- function requireModelInfo() {
9517
- if (hasRequiredModelInfo) return modelInfo;
9518
- hasRequiredModelInfo = 1;
9519
- (function(exports$1) {
9520
- Object.defineProperty(exports$1, "__esModule", { value: true });
9521
- exports$1.SUPPORTED_MODELS = exports$1.CANONICAL_MODELS = void 0;
9522
- exports$1.parseCanonicalModelName = parseCanonicalModelName;
9523
- exports$1.CANONICAL_MODELS = [
9524
- "qwen3-30b-a3b-instruct-2507",
9525
- "claude-opus-4-7",
9526
- "claude-sonnet-4-6",
9527
- "claude-haiku-4-5",
9528
- "qwen3-vl-235b-a22b-instruct",
9529
- "qwen3-max",
9530
- "gpt-5",
9531
- "gemini-2.5-flash-lite",
9532
- "gemini-2.5-flash",
9533
- "qwen3-coder-flash",
9534
- "gpt-oss-120b",
9535
- "kimi-k2.5",
9536
- "kimi-k2.6"
9537
- ];
9538
- const CANONICAL_SET = new Set(exports$1.CANONICAL_MODELS);
9539
- exports$1.SUPPORTED_MODELS = {
9540
- "gpt-oss-120b": [
9541
- {
9542
- provider: "cerebras",
9543
- providerModelName: "gpt-oss-120b"
9544
- },
9545
- {
9546
- provider: "groq",
9547
- providerModelName: "openai/gpt-oss-120b"
9548
- },
9549
- {
9550
- provider: "openrouter",
9551
- providerModelName: "openai/gpt-oss-120b"
9552
- }
9553
- ],
9554
- "qwen3-30b-a3b-instruct-2507": [
9555
- {
9556
- provider: "openrouter",
9557
- providerModelName: "qwen/qwen3-30b-a3b-instruct-2507"
9558
- }
9559
- ],
9560
- "claude-opus-4-7": [
9561
- {
9562
- provider: "openrouter",
9563
- providerModelName: "anthropic/claude-opus-4.7"
9564
- }
9565
- ],
9566
- "claude-sonnet-4-6": [
9567
- {
9568
- provider: "openrouter",
9569
- providerModelName: "anthropic/claude-sonnet-4.6"
9570
- }
9571
- ],
9572
- "claude-haiku-4-5": [
9573
- {
9574
- provider: "openrouter",
9575
- providerModelName: "anthropic/claude-haiku-4.5"
9576
- }
9577
- ],
9578
- "qwen3-vl-235b-a22b-instruct": [
9579
- {
9580
- provider: "openrouter",
9581
- providerModelName: "qwen/qwen3-vl-235b-a22b-instruct"
9582
- }
9583
- ],
9584
- "qwen3-max": [
9585
- {
9586
- provider: "openrouter",
9587
- providerModelName: "qwen/qwen3-max"
9588
- }
9589
- ],
9590
- "gpt-5": [
9591
- {
9592
- provider: "openrouter",
9593
- providerModelName: "openai/gpt-5"
9594
- }
9595
- ],
9596
- "gemini-2.5-flash-lite": [
9597
- {
9598
- provider: "gemini",
9599
- providerModelName: "gemini-2.5-flash-lite"
9600
- },
9601
- {
9602
- provider: "openrouter",
9603
- providerModelName: "google/gemini-2.5-flash-lite"
9604
- }
9605
- ],
9606
- "gemini-2.5-flash": [
9607
- {
9608
- provider: "gemini",
9609
- providerModelName: "gemini-2.5-flash"
9610
- },
9611
- {
9612
- provider: "openrouter",
9613
- providerModelName: "google/gemini-2.5-flash"
9614
- }
9615
- ],
9616
- "qwen3-coder-flash": [
9617
- {
9618
- provider: "openrouter",
9619
- providerModelName: "qwen/qwen3-coder-flash"
9620
- }
9621
- ],
9622
- "kimi-k2.5": [
9623
- {
9624
- provider: "openrouter",
9625
- providerModelName: "moonshotai/kimi-k2.5"
9626
- }
9627
- ],
9628
- "kimi-k2.6": [
9629
- {
9630
- provider: "openrouter",
9631
- providerModelName: "moonshotai/kimi-k2.6"
9632
- }
9633
- ]
9634
- };
9635
- function parseCanonicalModelName(requestedModel) {
9636
- let m = requestedModel || "fast";
9637
- if (CANONICAL_SET.has(m))
9638
- return m;
9639
- let m2;
9640
- switch (m) {
9641
- case "fast":
9642
- m2 = "gpt-oss-120b";
9643
- break;
9644
- case "gemini":
9645
- m2 = "gemini-2.5-flash";
9646
- break;
9647
- case "qwen":
9648
- m2 = "qwen3-vl-235b-a22b-instruct";
9649
- break;
9650
- case "sonnet":
9651
- m2 = "claude-sonnet-4-6";
9652
- break;
9653
- case "opus":
9654
- m2 = "claude-opus-4-7";
9655
- break;
9656
- case "haiku":
9657
- m2 = "claude-haiku-4-5";
9658
- break;
9659
- case "kimi":
9660
- m2 = "kimi-k2.6";
9661
- break;
9662
- case "gpt":
9663
- m2 = "gpt-5";
9664
- break;
9665
- }
9666
- if (m2)
9667
- return m2;
9668
- return {
9669
- kind: "validation-error",
9670
- message: `Invalid model name: ${m ?? "null/undefined"}`
9671
- };
9672
- }
9673
- })(modelInfo);
9674
- return modelInfo;
9675
- }
9676
-
9677
9502
  var providerConfig = {};
9678
9503
 
9679
9504
  var hasRequiredProviderConfig;
@@ -9682,7 +9507,13 @@ function requireProviderConfig() {
9682
9507
  hasRequiredProviderConfig = 1;
9683
9508
  (function(exports$1) {
9684
9509
  Object.defineProperty(exports$1, "__esModule", { value: true });
9685
- exports$1.providerConfigs = exports$1.extractOpenAiMessageText = exports$1.normalizeGeminiUsage = exports$1.normalizeOpenAiUsage = exports$1.normalizedUsageZero = void 0;
9510
+ exports$1.providerConfigs = exports$1.extractOpenAiMessageText = exports$1.normalizeGeminiUsage = exports$1.normalizeOpenAiUsage = exports$1.normalizedUsageZero = exports$1.LLM_PROVIDER_IDS = void 0;
9511
+ exports$1.LLM_PROVIDER_IDS = [
9512
+ "groq",
9513
+ "cerebras",
9514
+ "gemini",
9515
+ "openrouter"
9516
+ ];
9686
9517
  exports$1.normalizedUsageZero = {
9687
9518
  promptTokens: 0,
9688
9519
  completionTokens: 0,
@@ -10381,7 +10212,6 @@ function requireHttpLlmClient() {
10381
10212
  hasRequiredHttpLlmClient = 1;
10382
10213
  Object.defineProperty(httpLlmClient, "__esModule", { value: true });
10383
10214
  httpLlmClient.HttpLlmClient = void 0;
10384
- const model_info_1 = requireModelInfo();
10385
10215
  const logger_1 = requireLogger();
10386
10216
  const provider_config_1 = requireProviderConfig();
10387
10217
  const provider_formatters_1 = requireProviderFormatters();
@@ -10393,10 +10223,9 @@ function requireHttpLlmClient() {
10393
10223
  }
10394
10224
  async sendRequest(prompt, model, maxTokens, assistantPrefillPrompt) {
10395
10225
  const provider = this.getProviderConfig();
10396
- const providerModelName = this.getProviderModelName(model);
10397
10226
  const requestOptions = provider.buildRequest({
10398
10227
  prompt,
10399
- model: providerModelName,
10228
+ model,
10400
10229
  maxTokens,
10401
10230
  assistantPrefillPrompt
10402
10231
  }, this.apiKey);
@@ -10407,18 +10236,17 @@ function requireHttpLlmClient() {
10407
10236
  apiOperation: provider.apiOperation,
10408
10237
  requestOptions,
10409
10238
  parseResponse: provider.parseResponse,
10410
- getResponsePreview: (parsedResponse) => parsedResponse.text,
10239
+ getResponseLength: (parsedResponse) => parsedResponse.text.length,
10411
10240
  getUsage: (parsedResponse) => parsedResponse.usage
10412
10241
  });
10413
10242
  }
10414
10243
  async sendAgenticRequest(messages, tools, model, maxTokens, systemPrompt, onEvent) {
10415
10244
  const provider = this.getProviderConfig();
10416
- const providerModelName = this.getProviderModelName(model);
10417
10245
  const codec = this.getAgenticProviderCodec(provider.errorLabel);
10418
10246
  const requestOptions = codec.buildRequest({
10419
10247
  messages,
10420
10248
  tools,
10421
- model: providerModelName,
10249
+ model,
10422
10250
  maxTokens,
10423
10251
  systemPrompt,
10424
10252
  stream: !!onEvent
@@ -10431,7 +10259,7 @@ function requireHttpLlmClient() {
10431
10259
  apiOperation: "agentic",
10432
10260
  requestOptions,
10433
10261
  parseResponse,
10434
- getResponsePreview: (parsedResponse) => parsedResponse.message.content.filter((content) => content.type === "text").map((content) => content.text).join(""),
10262
+ getResponseLength: (parsedResponse) => parsedResponse.message.content.reduce((total, content) => total + (content.type === "text" ? content.text.length : 0), 0),
10435
10263
  getUsage: (parsedResponse) => parsedResponse.usage
10436
10264
  });
10437
10265
  }
@@ -10442,13 +10270,6 @@ function requireHttpLlmClient() {
10442
10270
  }
10443
10271
  return provider;
10444
10272
  }
10445
- getProviderModelName(model) {
10446
- const providerSpecificModelName = model_info_1.SUPPORTED_MODELS[model].find((pm) => pm.provider === this.providerId);
10447
- if (!providerSpecificModelName) {
10448
- throw new Error(`LLM Provider ${this.providerId} does not support model ${model}. If this is an error and the provider does support this model, please contact us to fix it`);
10449
- }
10450
- return providerSpecificModelName.providerModelName;
10451
- }
10452
10273
  async executeProviderCall(params) {
10453
10274
  const method = params.requestOptions.method ?? "POST";
10454
10275
  const headers = params.requestOptions.headers ?? {};
@@ -10471,7 +10292,7 @@ function requireHttpLlmClient() {
10471
10292
  const duration = Date.now() - startTime;
10472
10293
  (0, logger_1.logLlmCallComplete)(this.logger, spanId, params.provider.providerId, params.apiOperation, {
10473
10294
  status: response.status,
10474
- responseText: params.getResponsePreview(parsedResponse),
10295
+ responseLength: params.getResponseLength(parsedResponse),
10475
10296
  headers: Object.fromEntries(response.headers.entries()),
10476
10297
  usage: params.getUsage(parsedResponse)
10477
10298
  }, duration);
@@ -10526,6 +10347,112 @@ function requireHttpLlmClient() {
10526
10347
  return httpLlmClient;
10527
10348
  }
10528
10349
 
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.`);
10447
+ }
10448
+ return configuredTarget;
10449
+ }
10450
+ return validationError("model must include either alias or provider/model fields");
10451
+ }
10452
+ })(modelInfo);
10453
+ return modelInfo;
10454
+ }
10455
+
10529
10456
  var castArrayPromptBuilder = {};
10530
10457
 
10531
10458
  var promptTemplateUtils = {};
@@ -10828,28 +10755,26 @@ function requireNuaLlmClient() {
10828
10755
  }
10829
10756
  });
10830
10757
  }
10831
- getClientForModel(model) {
10832
- const supported = model_info_1.SUPPORTED_MODELS[model];
10833
- if (!supported || supported.length === 0) {
10834
- throw new Error(`Model ${model} is not supported or configuration is missing.`);
10835
- }
10836
- for (const option of supported) {
10837
- if (this.clients.has(option.provider)) {
10838
- return this.clients.get(option.provider);
10839
- }
10840
- }
10841
- throw new Error(`No configured provider found for model ${model}. Please check your API keys.`);
10758
+ getConfiguredProviderIds() {
10759
+ return new Set(this.clients.keys());
10842
10760
  }
10843
- resolveModel(modelName) {
10844
- const result = (0, model_info_1.parseCanonicalModelName)(modelName);
10761
+ resolveModel(model) {
10762
+ const result = (0, model_info_1.resolveModelInput)(model, this.getConfiguredProviderIds());
10845
10763
  if ((0, nua_errors_1.isNuaValidationError)(result)) {
10846
10764
  throw new Error(result.message);
10847
10765
  }
10848
10766
  return result;
10849
10767
  }
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;
10774
+ }
10850
10775
  async castValue(params) {
10851
- const model = this.resolveModel(params.model);
10852
- const client = this.getClientForModel(model);
10776
+ const providerModel = this.resolveModel(params.model);
10777
+ const client = this.getClientForProvider(providerModel.provider);
10853
10778
  const maxTokens = params.maxTokens || 4096;
10854
10779
  const temperature = params.temperature ?? 0;
10855
10780
  const prompt = cast_prompt_builder_1.default.buildFullPrompt(params);
@@ -10858,7 +10783,7 @@ function requireNuaLlmClient() {
10858
10783
  const result = await (0, call_llm_service_1.callLLM)(
10859
10784
  client,
10860
10785
  prompt,
10861
- model,
10786
+ providerModel.model,
10862
10787
  maxTokens,
10863
10788
  temperature,
10864
10789
  3,
@@ -10880,8 +10805,8 @@ function requireNuaLlmClient() {
10880
10805
  }
10881
10806
  }
10882
10807
  async castArray(params) {
10883
- const model = this.resolveModel(params.model);
10884
- const client = this.getClientForModel(model);
10808
+ const providerModel = this.resolveModel(params.model);
10809
+ const client = this.getClientForProvider(providerModel.provider);
10885
10810
  const maxTokens = params.maxTokens || 4096;
10886
10811
  const temperature = params.temperature ?? 0;
10887
10812
  const validData = (0, validate_mappable_input_data_1.validateMappableInputData)(params.data, params.input.primaryKey);
@@ -10894,7 +10819,7 @@ function requireNuaLlmClient() {
10894
10819
  const prompt = cast_array_prompt_builder_1.default.buildFullPrompt(params, validData);
10895
10820
  const validationFn = (0, nua_json_schema_value_validation_1.buildNuaJsonSchemaValueValidation)("library-req", params.output.effectiveSchema);
10896
10821
  try {
10897
- const result = await (0, call_llm_service_1.callLLM)(client, prompt, model, maxTokens, temperature, 3, validationFn);
10822
+ const result = await (0, call_llm_service_1.callLLM)(client, prompt, providerModel.model, maxTokens, temperature, 3, validationFn);
10898
10823
  return {
10899
10824
  success: true,
10900
10825
  data: result.data,
@@ -10911,8 +10836,8 @@ function requireNuaLlmClient() {
10911
10836
  }
10912
10837
  async runAgent(params) {
10913
10838
  try {
10914
- const model = this.resolveModel(params.model);
10915
- const client = this.getClientForModel(model);
10839
+ const providerModel = this.resolveModel(params.model);
10840
+ const client = this.getClientForProvider(providerModel.provider);
10916
10841
  const maxTokens = params.maxTokens ?? 4096;
10917
10842
  const maxTurns = params.maxTurns ?? 10;
10918
10843
  return (0, agent_loop_1.runAgentLoop)({
@@ -10921,7 +10846,7 @@ function requireNuaLlmClient() {
10921
10846
  systemPrompt: params.systemPrompt,
10922
10847
  maxTurns,
10923
10848
  onEvent: params.onEvent,
10924
- sendRequest: (messages, tools, systemPrompt) => client.sendAgenticRequest(messages, tools, model, maxTokens, systemPrompt, params.onEvent)
10849
+ sendRequest: (messages, tools, systemPrompt) => client.sendAgenticRequest(messages, tools, providerModel.model, maxTokens, systemPrompt, params.onEvent)
10925
10850
  });
10926
10851
  } catch (e) {
10927
10852
  return {
@@ -11106,7 +11031,7 @@ function requireDist() {
11106
11031
  return mod && mod.__esModule ? mod : { "default": mod };
11107
11032
  };
11108
11033
  Object.defineProperty(exports$1, "__esModule", { value: true });
11109
- exports$1.runAgentLoop = exports$1.stableStringify = exports$1.validateJsonSchema = exports$1.providerConfigs = exports$1.normalizedUsageZero = exports$1.castArrayPromptBuilder = exports$1.castPromptBuilder = void 0;
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;
11110
11035
  __exportStar(requireNuaLlmClient(), exports$1);
11111
11036
  __exportStar(requireLogger(), exports$1);
11112
11037
  __exportStar(requireTypes(), exports$1);
@@ -11120,6 +11045,9 @@ function requireDist() {
11120
11045
  return __importDefault(cast_array_prompt_builder_1).default;
11121
11046
  } });
11122
11047
  var provider_config_1 = requireProviderConfig();
11048
+ Object.defineProperty(exports$1, "LLM_PROVIDER_IDS", { enumerable: true, get: function() {
11049
+ return provider_config_1.LLM_PROVIDER_IDS;
11050
+ } });
11123
11051
  Object.defineProperty(exports$1, "normalizedUsageZero", { enumerable: true, get: function() {
11124
11052
  return provider_config_1.normalizedUsageZero;
11125
11053
  } });
@@ -11153,9 +11081,6 @@ const normalizedUsageZero = {
11153
11081
  };
11154
11082
  class DirectBackend {
11155
11083
  constructor(config) {
11156
- if (!config.model) {
11157
- throw new Error("model is required for direct mode");
11158
- }
11159
11084
  this.model = config.model;
11160
11085
  this.client = new distExports.NuaLlmClient({ providers: config.providers });
11161
11086
  }
@@ -11180,7 +11105,7 @@ class DirectBackend {
11180
11105
  success: true,
11181
11106
  data: result.data,
11182
11107
  usage: result.usage || normalizedUsageZero,
11183
- model,
11108
+ model: formatModelInput(model),
11184
11109
  latencyMs,
11185
11110
  source: "direct",
11186
11111
  meta: {}
@@ -11212,13 +11137,18 @@ class DirectBackend {
11212
11137
  success: true,
11213
11138
  data: result.data,
11214
11139
  usage: result.usage || normalizedUsageZero,
11215
- model,
11140
+ model: formatModelInput(model),
11216
11141
  latencyMs,
11217
11142
  source: "direct",
11218
11143
  meta: {}
11219
11144
  };
11220
11145
  }
11221
11146
  }
11147
+ function formatModelInput(model) {
11148
+ if (!model) return "fast";
11149
+ if ("alias" in model) return model.alias;
11150
+ return `${model.provider}:${model.model}`;
11151
+ }
11222
11152
 
11223
11153
  function resolveConfigValue(config, key, envVar) {
11224
11154
  if (config[key]) return config[key];
@@ -13,7 +13,6 @@ function requireLogger() {
13
13
  hasRequiredLogger = 1;
14
14
  Object.defineProperty(logger, "__esModule", { value: true });
15
15
  logger.logLlmCallError = logger.logLlmCallComplete = logger.logLlmCallStart = logger.generateSpanId = logger.ConsoleLogger = void 0;
16
- logger.truncateText = truncateText;
17
16
  logger.pickHeaders = pickHeaders;
18
17
  logger.normalizeError = normalizeError;
19
18
  class ConsoleLogger {
@@ -33,13 +32,6 @@ function requireLogger() {
33
32
  logger.ConsoleLogger = ConsoleLogger;
34
33
  const generateSpanId = () => crypto.randomUUID();
35
34
  logger.generateSpanId = generateSpanId;
36
- function truncateText(text, limit = 500) {
37
- const length = text.length;
38
- if (length <= limit) {
39
- return { preview: text, length };
40
- }
41
- return { preview: text.slice(0, limit), length };
42
- }
43
35
  function pickHeaders(headers, allowlist, redactSet) {
44
36
  const result = {};
45
37
  for (const [key, value] of Object.entries(headers)) {
@@ -74,16 +66,13 @@ function requireLogger() {
74
66
  };
75
67
  logger.logLlmCallStart = logLlmCallStart;
76
68
  const logLlmCallComplete = (logger2, spanId, service, method, response, duration) => {
77
- const { headers, responseText, ...rest } = response;
78
- const { preview: responsePreview, length: responseLength } = truncateText(responseText);
69
+ const { headers, ...rest } = response;
79
70
  logger2.info("LLM call completed", {
80
71
  type: "llm_call_complete",
81
72
  span_id: spanId,
82
73
  service,
83
74
  method,
84
75
  ...rest,
85
- responsePreview,
86
- responseLength,
87
76
  ...pickHeaders(headers, LLM_RESPONSE_HEADER_ALLOWLIST),
88
77
  duration_ms: duration
89
78
  });
@@ -9509,170 +9498,6 @@ function requireNuaJsonSchemaValueValidation() {
9509
9498
 
9510
9499
  var httpLlmClient = {};
9511
9500
 
9512
- var modelInfo = {};
9513
-
9514
- var hasRequiredModelInfo;
9515
- function requireModelInfo() {
9516
- if (hasRequiredModelInfo) return modelInfo;
9517
- hasRequiredModelInfo = 1;
9518
- (function(exports$1) {
9519
- Object.defineProperty(exports$1, "__esModule", { value: true });
9520
- exports$1.SUPPORTED_MODELS = exports$1.CANONICAL_MODELS = void 0;
9521
- exports$1.parseCanonicalModelName = parseCanonicalModelName;
9522
- exports$1.CANONICAL_MODELS = [
9523
- "qwen3-30b-a3b-instruct-2507",
9524
- "claude-opus-4-7",
9525
- "claude-sonnet-4-6",
9526
- "claude-haiku-4-5",
9527
- "qwen3-vl-235b-a22b-instruct",
9528
- "qwen3-max",
9529
- "gpt-5",
9530
- "gemini-2.5-flash-lite",
9531
- "gemini-2.5-flash",
9532
- "qwen3-coder-flash",
9533
- "gpt-oss-120b",
9534
- "kimi-k2.5",
9535
- "kimi-k2.6"
9536
- ];
9537
- const CANONICAL_SET = new Set(exports$1.CANONICAL_MODELS);
9538
- exports$1.SUPPORTED_MODELS = {
9539
- "gpt-oss-120b": [
9540
- {
9541
- provider: "cerebras",
9542
- providerModelName: "gpt-oss-120b"
9543
- },
9544
- {
9545
- provider: "groq",
9546
- providerModelName: "openai/gpt-oss-120b"
9547
- },
9548
- {
9549
- provider: "openrouter",
9550
- providerModelName: "openai/gpt-oss-120b"
9551
- }
9552
- ],
9553
- "qwen3-30b-a3b-instruct-2507": [
9554
- {
9555
- provider: "openrouter",
9556
- providerModelName: "qwen/qwen3-30b-a3b-instruct-2507"
9557
- }
9558
- ],
9559
- "claude-opus-4-7": [
9560
- {
9561
- provider: "openrouter",
9562
- providerModelName: "anthropic/claude-opus-4.7"
9563
- }
9564
- ],
9565
- "claude-sonnet-4-6": [
9566
- {
9567
- provider: "openrouter",
9568
- providerModelName: "anthropic/claude-sonnet-4.6"
9569
- }
9570
- ],
9571
- "claude-haiku-4-5": [
9572
- {
9573
- provider: "openrouter",
9574
- providerModelName: "anthropic/claude-haiku-4.5"
9575
- }
9576
- ],
9577
- "qwen3-vl-235b-a22b-instruct": [
9578
- {
9579
- provider: "openrouter",
9580
- providerModelName: "qwen/qwen3-vl-235b-a22b-instruct"
9581
- }
9582
- ],
9583
- "qwen3-max": [
9584
- {
9585
- provider: "openrouter",
9586
- providerModelName: "qwen/qwen3-max"
9587
- }
9588
- ],
9589
- "gpt-5": [
9590
- {
9591
- provider: "openrouter",
9592
- providerModelName: "openai/gpt-5"
9593
- }
9594
- ],
9595
- "gemini-2.5-flash-lite": [
9596
- {
9597
- provider: "gemini",
9598
- providerModelName: "gemini-2.5-flash-lite"
9599
- },
9600
- {
9601
- provider: "openrouter",
9602
- providerModelName: "google/gemini-2.5-flash-lite"
9603
- }
9604
- ],
9605
- "gemini-2.5-flash": [
9606
- {
9607
- provider: "gemini",
9608
- providerModelName: "gemini-2.5-flash"
9609
- },
9610
- {
9611
- provider: "openrouter",
9612
- providerModelName: "google/gemini-2.5-flash"
9613
- }
9614
- ],
9615
- "qwen3-coder-flash": [
9616
- {
9617
- provider: "openrouter",
9618
- providerModelName: "qwen/qwen3-coder-flash"
9619
- }
9620
- ],
9621
- "kimi-k2.5": [
9622
- {
9623
- provider: "openrouter",
9624
- providerModelName: "moonshotai/kimi-k2.5"
9625
- }
9626
- ],
9627
- "kimi-k2.6": [
9628
- {
9629
- provider: "openrouter",
9630
- providerModelName: "moonshotai/kimi-k2.6"
9631
- }
9632
- ]
9633
- };
9634
- function parseCanonicalModelName(requestedModel) {
9635
- let m = requestedModel || "fast";
9636
- if (CANONICAL_SET.has(m))
9637
- return m;
9638
- let m2;
9639
- switch (m) {
9640
- case "fast":
9641
- m2 = "gpt-oss-120b";
9642
- break;
9643
- case "gemini":
9644
- m2 = "gemini-2.5-flash";
9645
- break;
9646
- case "qwen":
9647
- m2 = "qwen3-vl-235b-a22b-instruct";
9648
- break;
9649
- case "sonnet":
9650
- m2 = "claude-sonnet-4-6";
9651
- break;
9652
- case "opus":
9653
- m2 = "claude-opus-4-7";
9654
- break;
9655
- case "haiku":
9656
- m2 = "claude-haiku-4-5";
9657
- break;
9658
- case "kimi":
9659
- m2 = "kimi-k2.6";
9660
- break;
9661
- case "gpt":
9662
- m2 = "gpt-5";
9663
- break;
9664
- }
9665
- if (m2)
9666
- return m2;
9667
- return {
9668
- kind: "validation-error",
9669
- message: `Invalid model name: ${m ?? "null/undefined"}`
9670
- };
9671
- }
9672
- })(modelInfo);
9673
- return modelInfo;
9674
- }
9675
-
9676
9501
  var providerConfig = {};
9677
9502
 
9678
9503
  var hasRequiredProviderConfig;
@@ -9681,7 +9506,13 @@ function requireProviderConfig() {
9681
9506
  hasRequiredProviderConfig = 1;
9682
9507
  (function(exports$1) {
9683
9508
  Object.defineProperty(exports$1, "__esModule", { value: true });
9684
- exports$1.providerConfigs = exports$1.extractOpenAiMessageText = exports$1.normalizeGeminiUsage = exports$1.normalizeOpenAiUsage = exports$1.normalizedUsageZero = void 0;
9509
+ exports$1.providerConfigs = exports$1.extractOpenAiMessageText = exports$1.normalizeGeminiUsage = exports$1.normalizeOpenAiUsage = exports$1.normalizedUsageZero = exports$1.LLM_PROVIDER_IDS = void 0;
9510
+ exports$1.LLM_PROVIDER_IDS = [
9511
+ "groq",
9512
+ "cerebras",
9513
+ "gemini",
9514
+ "openrouter"
9515
+ ];
9685
9516
  exports$1.normalizedUsageZero = {
9686
9517
  promptTokens: 0,
9687
9518
  completionTokens: 0,
@@ -10380,7 +10211,6 @@ function requireHttpLlmClient() {
10380
10211
  hasRequiredHttpLlmClient = 1;
10381
10212
  Object.defineProperty(httpLlmClient, "__esModule", { value: true });
10382
10213
  httpLlmClient.HttpLlmClient = void 0;
10383
- const model_info_1 = requireModelInfo();
10384
10214
  const logger_1 = requireLogger();
10385
10215
  const provider_config_1 = requireProviderConfig();
10386
10216
  const provider_formatters_1 = requireProviderFormatters();
@@ -10392,10 +10222,9 @@ function requireHttpLlmClient() {
10392
10222
  }
10393
10223
  async sendRequest(prompt, model, maxTokens, assistantPrefillPrompt) {
10394
10224
  const provider = this.getProviderConfig();
10395
- const providerModelName = this.getProviderModelName(model);
10396
10225
  const requestOptions = provider.buildRequest({
10397
10226
  prompt,
10398
- model: providerModelName,
10227
+ model,
10399
10228
  maxTokens,
10400
10229
  assistantPrefillPrompt
10401
10230
  }, this.apiKey);
@@ -10406,18 +10235,17 @@ function requireHttpLlmClient() {
10406
10235
  apiOperation: provider.apiOperation,
10407
10236
  requestOptions,
10408
10237
  parseResponse: provider.parseResponse,
10409
- getResponsePreview: (parsedResponse) => parsedResponse.text,
10238
+ getResponseLength: (parsedResponse) => parsedResponse.text.length,
10410
10239
  getUsage: (parsedResponse) => parsedResponse.usage
10411
10240
  });
10412
10241
  }
10413
10242
  async sendAgenticRequest(messages, tools, model, maxTokens, systemPrompt, onEvent) {
10414
10243
  const provider = this.getProviderConfig();
10415
- const providerModelName = this.getProviderModelName(model);
10416
10244
  const codec = this.getAgenticProviderCodec(provider.errorLabel);
10417
10245
  const requestOptions = codec.buildRequest({
10418
10246
  messages,
10419
10247
  tools,
10420
- model: providerModelName,
10248
+ model,
10421
10249
  maxTokens,
10422
10250
  systemPrompt,
10423
10251
  stream: !!onEvent
@@ -10430,7 +10258,7 @@ function requireHttpLlmClient() {
10430
10258
  apiOperation: "agentic",
10431
10259
  requestOptions,
10432
10260
  parseResponse,
10433
- getResponsePreview: (parsedResponse) => parsedResponse.message.content.filter((content) => content.type === "text").map((content) => content.text).join(""),
10261
+ getResponseLength: (parsedResponse) => parsedResponse.message.content.reduce((total, content) => total + (content.type === "text" ? content.text.length : 0), 0),
10434
10262
  getUsage: (parsedResponse) => parsedResponse.usage
10435
10263
  });
10436
10264
  }
@@ -10441,13 +10269,6 @@ function requireHttpLlmClient() {
10441
10269
  }
10442
10270
  return provider;
10443
10271
  }
10444
- getProviderModelName(model) {
10445
- const providerSpecificModelName = model_info_1.SUPPORTED_MODELS[model].find((pm) => pm.provider === this.providerId);
10446
- if (!providerSpecificModelName) {
10447
- throw new Error(`LLM Provider ${this.providerId} does not support model ${model}. If this is an error and the provider does support this model, please contact us to fix it`);
10448
- }
10449
- return providerSpecificModelName.providerModelName;
10450
- }
10451
10272
  async executeProviderCall(params) {
10452
10273
  const method = params.requestOptions.method ?? "POST";
10453
10274
  const headers = params.requestOptions.headers ?? {};
@@ -10470,7 +10291,7 @@ function requireHttpLlmClient() {
10470
10291
  const duration = Date.now() - startTime;
10471
10292
  (0, logger_1.logLlmCallComplete)(this.logger, spanId, params.provider.providerId, params.apiOperation, {
10472
10293
  status: response.status,
10473
- responseText: params.getResponsePreview(parsedResponse),
10294
+ responseLength: params.getResponseLength(parsedResponse),
10474
10295
  headers: Object.fromEntries(response.headers.entries()),
10475
10296
  usage: params.getUsage(parsedResponse)
10476
10297
  }, duration);
@@ -10525,6 +10346,112 @@ function requireHttpLlmClient() {
10525
10346
  return httpLlmClient;
10526
10347
  }
10527
10348
 
10349
+ var modelInfo = {};
10350
+
10351
+ var hasRequiredModelInfo;
10352
+ function requireModelInfo() {
10353
+ if (hasRequiredModelInfo) return modelInfo;
10354
+ hasRequiredModelInfo = 1;
10355
+ (function(exports$1) {
10356
+ Object.defineProperty(exports$1, "__esModule", { value: true });
10357
+ exports$1.MODEL_ALIAS_NAMES = exports$1.MODEL_ALIASES = void 0;
10358
+ exports$1.isLlmProviderId = isLlmProviderId;
10359
+ exports$1.isModelAliasName = isModelAliasName;
10360
+ exports$1.resolveModelInput = resolveModelInput;
10361
+ const provider_config_1 = requireProviderConfig();
10362
+ exports$1.MODEL_ALIASES = {
10363
+ fast: [
10364
+ { provider: "cerebras", model: "gpt-oss-120b" },
10365
+ { provider: "groq", model: "openai/gpt-oss-120b" },
10366
+ { provider: "openrouter", model: "openai/gpt-oss-120b" }
10367
+ ],
10368
+ gemini: [
10369
+ { provider: "gemini", model: "gemini-2.5-flash" },
10370
+ { provider: "openrouter", model: "google/gemini-2.5-flash" }
10371
+ ],
10372
+ qwen: [
10373
+ { provider: "openrouter", model: "qwen/qwen3-vl-235b-a22b-instruct" }
10374
+ ],
10375
+ sonnet: [
10376
+ { provider: "openrouter", model: "anthropic/claude-sonnet-4.6" }
10377
+ ],
10378
+ opus: [
10379
+ { provider: "openrouter", model: "anthropic/claude-opus-4.7" }
10380
+ ],
10381
+ haiku: [
10382
+ { provider: "openrouter", model: "anthropic/claude-haiku-4.5" }
10383
+ ],
10384
+ kimi: [
10385
+ { provider: "openrouter", model: "moonshotai/kimi-k2.6" }
10386
+ ],
10387
+ gpt: [
10388
+ { provider: "openrouter", model: "openai/gpt-5" }
10389
+ ]
10390
+ };
10391
+ exports$1.MODEL_ALIAS_NAMES = Object.keys(exports$1.MODEL_ALIASES);
10392
+ const MODEL_ALIAS_SET = new Set(exports$1.MODEL_ALIAS_NAMES);
10393
+ const LLM_PROVIDER_ID_SET = new Set(provider_config_1.LLM_PROVIDER_IDS);
10394
+ function isLlmProviderId(value) {
10395
+ return typeof value === "string" && LLM_PROVIDER_ID_SET.has(value);
10396
+ }
10397
+ function isModelAliasName(value) {
10398
+ return typeof value === "string" && MODEL_ALIAS_SET.has(value);
10399
+ }
10400
+ function validationError(message) {
10401
+ return {
10402
+ kind: "validation-error",
10403
+ message
10404
+ };
10405
+ }
10406
+ function validateProviderModel(input, configuredProviders) {
10407
+ if (!isLlmProviderId(input.provider)) {
10408
+ return validationError(`Invalid LLM provider: ${String(input.provider)}`);
10409
+ }
10410
+ if (!configuredProviders.has(input.provider)) {
10411
+ return validationError(`LLM provider ${input.provider} is not configured. Please check your API keys.`);
10412
+ }
10413
+ if (typeof input.model !== "string") {
10414
+ return validationError("model.model must be a string");
10415
+ }
10416
+ const model = input.model.trim();
10417
+ if (!model) {
10418
+ return validationError("model.model must be a non-empty string");
10419
+ }
10420
+ if (input.provider === "gemini" && model.startsWith("models/")) {
10421
+ return validationError('Gemini model names must use bare model IDs, for example "gemini-2.5-flash", not "models/gemini-2.5-flash".');
10422
+ }
10423
+ return {
10424
+ provider: input.provider,
10425
+ model
10426
+ };
10427
+ }
10428
+ function resolveModelInput(input, configuredProviders) {
10429
+ if (input == null) {
10430
+ return resolveModelInput({ alias: "fast" }, configuredProviders);
10431
+ }
10432
+ if (typeof input !== "object") {
10433
+ return validationError("model must be an object with either alias or provider/model fields");
10434
+ }
10435
+ if ("provider" in input || "model" in input) {
10436
+ return validateProviderModel(input, configuredProviders);
10437
+ }
10438
+ if ("alias" in input) {
10439
+ const alias = input.alias;
10440
+ if (!isModelAliasName(alias)) {
10441
+ return validationError(`Invalid model alias: ${String(alias)}`);
10442
+ }
10443
+ const configuredTarget = exports$1.MODEL_ALIASES[alias].find((target) => configuredProviders.has(target.provider));
10444
+ if (!configuredTarget) {
10445
+ return validationError(`No configured provider found for model alias ${alias}. Please check your API keys.`);
10446
+ }
10447
+ return configuredTarget;
10448
+ }
10449
+ return validationError("model must include either alias or provider/model fields");
10450
+ }
10451
+ })(modelInfo);
10452
+ return modelInfo;
10453
+ }
10454
+
10528
10455
  var castArrayPromptBuilder = {};
10529
10456
 
10530
10457
  var promptTemplateUtils = {};
@@ -10827,28 +10754,26 @@ function requireNuaLlmClient() {
10827
10754
  }
10828
10755
  });
10829
10756
  }
10830
- getClientForModel(model) {
10831
- const supported = model_info_1.SUPPORTED_MODELS[model];
10832
- if (!supported || supported.length === 0) {
10833
- throw new Error(`Model ${model} is not supported or configuration is missing.`);
10834
- }
10835
- for (const option of supported) {
10836
- if (this.clients.has(option.provider)) {
10837
- return this.clients.get(option.provider);
10838
- }
10839
- }
10840
- throw new Error(`No configured provider found for model ${model}. Please check your API keys.`);
10757
+ getConfiguredProviderIds() {
10758
+ return new Set(this.clients.keys());
10841
10759
  }
10842
- resolveModel(modelName) {
10843
- const result = (0, model_info_1.parseCanonicalModelName)(modelName);
10760
+ resolveModel(model) {
10761
+ const result = (0, model_info_1.resolveModelInput)(model, this.getConfiguredProviderIds());
10844
10762
  if ((0, nua_errors_1.isNuaValidationError)(result)) {
10845
10763
  throw new Error(result.message);
10846
10764
  }
10847
10765
  return result;
10848
10766
  }
10767
+ getClientForProvider(provider) {
10768
+ const client = this.clients.get(provider);
10769
+ if (!client) {
10770
+ throw new Error(`LLM provider ${provider} is not configured. Please check your API keys.`);
10771
+ }
10772
+ return client;
10773
+ }
10849
10774
  async castValue(params) {
10850
- const model = this.resolveModel(params.model);
10851
- const client = this.getClientForModel(model);
10775
+ const providerModel = this.resolveModel(params.model);
10776
+ const client = this.getClientForProvider(providerModel.provider);
10852
10777
  const maxTokens = params.maxTokens || 4096;
10853
10778
  const temperature = params.temperature ?? 0;
10854
10779
  const prompt = cast_prompt_builder_1.default.buildFullPrompt(params);
@@ -10857,7 +10782,7 @@ function requireNuaLlmClient() {
10857
10782
  const result = await (0, call_llm_service_1.callLLM)(
10858
10783
  client,
10859
10784
  prompt,
10860
- model,
10785
+ providerModel.model,
10861
10786
  maxTokens,
10862
10787
  temperature,
10863
10788
  3,
@@ -10879,8 +10804,8 @@ function requireNuaLlmClient() {
10879
10804
  }
10880
10805
  }
10881
10806
  async castArray(params) {
10882
- const model = this.resolveModel(params.model);
10883
- const client = this.getClientForModel(model);
10807
+ const providerModel = this.resolveModel(params.model);
10808
+ const client = this.getClientForProvider(providerModel.provider);
10884
10809
  const maxTokens = params.maxTokens || 4096;
10885
10810
  const temperature = params.temperature ?? 0;
10886
10811
  const validData = (0, validate_mappable_input_data_1.validateMappableInputData)(params.data, params.input.primaryKey);
@@ -10893,7 +10818,7 @@ function requireNuaLlmClient() {
10893
10818
  const prompt = cast_array_prompt_builder_1.default.buildFullPrompt(params, validData);
10894
10819
  const validationFn = (0, nua_json_schema_value_validation_1.buildNuaJsonSchemaValueValidation)("library-req", params.output.effectiveSchema);
10895
10820
  try {
10896
- const result = await (0, call_llm_service_1.callLLM)(client, prompt, model, maxTokens, temperature, 3, validationFn);
10821
+ const result = await (0, call_llm_service_1.callLLM)(client, prompt, providerModel.model, maxTokens, temperature, 3, validationFn);
10897
10822
  return {
10898
10823
  success: true,
10899
10824
  data: result.data,
@@ -10910,8 +10835,8 @@ function requireNuaLlmClient() {
10910
10835
  }
10911
10836
  async runAgent(params) {
10912
10837
  try {
10913
- const model = this.resolveModel(params.model);
10914
- const client = this.getClientForModel(model);
10838
+ const providerModel = this.resolveModel(params.model);
10839
+ const client = this.getClientForProvider(providerModel.provider);
10915
10840
  const maxTokens = params.maxTokens ?? 4096;
10916
10841
  const maxTurns = params.maxTurns ?? 10;
10917
10842
  return (0, agent_loop_1.runAgentLoop)({
@@ -10920,7 +10845,7 @@ function requireNuaLlmClient() {
10920
10845
  systemPrompt: params.systemPrompt,
10921
10846
  maxTurns,
10922
10847
  onEvent: params.onEvent,
10923
- sendRequest: (messages, tools, systemPrompt) => client.sendAgenticRequest(messages, tools, model, maxTokens, systemPrompt, params.onEvent)
10848
+ sendRequest: (messages, tools, systemPrompt) => client.sendAgenticRequest(messages, tools, providerModel.model, maxTokens, systemPrompt, params.onEvent)
10924
10849
  });
10925
10850
  } catch (e) {
10926
10851
  return {
@@ -11105,7 +11030,7 @@ function requireDist() {
11105
11030
  return mod && mod.__esModule ? mod : { "default": mod };
11106
11031
  };
11107
11032
  Object.defineProperty(exports$1, "__esModule", { value: true });
11108
- exports$1.runAgentLoop = exports$1.stableStringify = exports$1.validateJsonSchema = exports$1.providerConfigs = exports$1.normalizedUsageZero = exports$1.castArrayPromptBuilder = exports$1.castPromptBuilder = void 0;
11033
+ 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;
11109
11034
  __exportStar(requireNuaLlmClient(), exports$1);
11110
11035
  __exportStar(requireLogger(), exports$1);
11111
11036
  __exportStar(requireTypes(), exports$1);
@@ -11119,6 +11044,9 @@ function requireDist() {
11119
11044
  return __importDefault(cast_array_prompt_builder_1).default;
11120
11045
  } });
11121
11046
  var provider_config_1 = requireProviderConfig();
11047
+ Object.defineProperty(exports$1, "LLM_PROVIDER_IDS", { enumerable: true, get: function() {
11048
+ return provider_config_1.LLM_PROVIDER_IDS;
11049
+ } });
11122
11050
  Object.defineProperty(exports$1, "normalizedUsageZero", { enumerable: true, get: function() {
11123
11051
  return provider_config_1.normalizedUsageZero;
11124
11052
  } });
@@ -11152,9 +11080,6 @@ const normalizedUsageZero = {
11152
11080
  };
11153
11081
  class DirectBackend {
11154
11082
  constructor(config) {
11155
- if (!config.model) {
11156
- throw new Error("model is required for direct mode");
11157
- }
11158
11083
  this.model = config.model;
11159
11084
  this.client = new distExports.NuaLlmClient({ providers: config.providers });
11160
11085
  }
@@ -11179,7 +11104,7 @@ class DirectBackend {
11179
11104
  success: true,
11180
11105
  data: result.data,
11181
11106
  usage: result.usage || normalizedUsageZero,
11182
- model,
11107
+ model: formatModelInput(model),
11183
11108
  latencyMs,
11184
11109
  source: "direct",
11185
11110
  meta: {}
@@ -11211,13 +11136,18 @@ class DirectBackend {
11211
11136
  success: true,
11212
11137
  data: result.data,
11213
11138
  usage: result.usage || normalizedUsageZero,
11214
- model,
11139
+ model: formatModelInput(model),
11215
11140
  latencyMs,
11216
11141
  source: "direct",
11217
11142
  meta: {}
11218
11143
  };
11219
11144
  }
11220
11145
  }
11146
+ function formatModelInput(model) {
11147
+ if (!model) return "fast";
11148
+ if ("alias" in model) return model.alias;
11149
+ return `${model.provider}:${model.model}`;
11150
+ }
11221
11151
 
11222
11152
  function resolveConfigValue(config, key, envVar) {
11223
11153
  if (config[key]) return config[key];
@@ -1,7 +1,7 @@
1
1
  import { CastArrayParams, CastResult, CastValueParams, LlmBackend } from './types';
2
- import { LlmProviderId } from 'nua-llm-core';
2
+ import type { LlmProviderId, ModelInput } from 'nua-llm-core';
3
3
  export type DirectConfig = {
4
- model: string;
4
+ model?: ModelInput;
5
5
  providers: {
6
6
  [key in LlmProviderId]?: {
7
7
  apiKey: string;
@@ -1,9 +1,10 @@
1
+ import type { ModelInput } from 'nua-llm-core';
1
2
  export type CastValueParams = {
2
3
  prompt: string;
3
4
  data: unknown;
4
5
  outputName: string;
5
6
  outputSchema: object;
6
- model?: string;
7
+ model?: ModelInput;
7
8
  };
8
9
  export type CastArrayParams = {
9
10
  prompt: string;
@@ -11,7 +12,7 @@ export type CastArrayParams = {
11
12
  primaryKey: string;
12
13
  outputName: string;
13
14
  outputSchema: object;
14
- model?: string;
15
+ model?: ModelInput;
15
16
  };
16
17
  export type NormalizedUsage = {
17
18
  promptTokens: number;
@@ -1,6 +1,7 @@
1
1
  import { DirectConfig } from './backend/direct';
2
2
  import { GatewayConfig } from './backend/gateway';
3
3
  import { CastResult, QueueResult } from './backend/types';
4
+ import type { ModelInput } from 'nua-llm-core';
4
5
  import { z } from 'zod';
5
6
  export type OutputDef<TSchema extends z.ZodTypeAny> = {
6
7
  name: string;
@@ -9,13 +10,13 @@ export type OutputDef<TSchema extends z.ZodTypeAny> = {
9
10
  export type GetOptions<TSchema extends z.ZodTypeAny> = {
10
11
  input?: unknown;
11
12
  output: OutputDef<TSchema>;
12
- model?: string;
13
+ model?: ModelInput;
13
14
  };
14
15
  export type ListOptions<TSchema extends z.ZodTypeAny, TData extends Record<string, unknown>, PrimaryKey extends keyof TData & string> = {
15
16
  input: TData[];
16
17
  primaryKey: PrimaryKey;
17
18
  output: OutputDef<TSchema>;
18
- model?: string;
19
+ model?: ModelInput;
19
20
  };
20
21
  export type ListResultRow<TSchema extends z.ZodTypeAny, PrimaryKey extends string> = {
21
22
  [K in PrimaryKey]: string | number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuabase",
3
3
  "description": "Nuabase TypeScript client to create typed functions from LLM prompts",
4
- "version": "2.3.3",
4
+ "version": "2.3.4",
5
5
  "type": "module",
6
6
  "author": "Jasim A Basheer <jasim@nuabase.com>",
7
7
  "engines": {