@jterrazz/intelligence 4.2.0 → 6.0.0

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/dist/index.cjs CHANGED
@@ -1,12 +1,95 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_parse_text = require("./parse-text.cjs");
3
- let langfuse = require("langfuse");
2
+ let _ai_sdk_otel = require("@ai-sdk/otel");
4
3
  let ai = require("ai");
5
- let jsonrepair = require("jsonrepair");
6
- let zod_v4 = require("zod/v4");
7
- let _openrouter_ai_sdk_provider = require("@openrouter/ai-sdk-provider");
4
+ let _opentelemetry_api = require("@opentelemetry/api");
8
5
  let _ai_sdk_openai = require("@ai-sdk/openai");
9
- //#region src/logging/logging.middleware.ts
6
+ let _openrouter_ai_sdk_provider = require("@openrouter/ai-sdk-provider");
7
+ //#region src/middleware/cost.middleware.ts
8
+ const COST_ATTRIBUTE = "gen_ai.usage.cost";
9
+ const MODEL_ATTRIBUTE = "gen_ai.request.model";
10
+ function resolveCost(providerMetadata, usage, pricing) {
11
+ const actualCost = providerMetadata?.openrouter?.usage?.cost;
12
+ if (typeof actualCost === "number" && actualCost > 0) return actualCost;
13
+ if (pricing) {
14
+ const inputTokens = usage?.inputTokens?.total ?? 0;
15
+ const outputTokens = usage?.outputTokens?.total ?? 0;
16
+ return inputTokens / 1e6 * pricing.input + outputTokens / 1e6 * pricing.output;
17
+ }
18
+ }
19
+ function recordGeneration(modelRef, cost) {
20
+ const span = _opentelemetry_api.trace.getActiveSpan();
21
+ if (!span) return;
22
+ span.setAttribute(MODEL_ATTRIBUTE, modelRef);
23
+ if (cost !== void 0) span.setAttribute(COST_ATTRIBUTE, cost);
24
+ }
25
+ /**
26
+ * Creates middleware that enriches the active OpenTelemetry span with the
27
+ * model reference (`gen_ai.request.model`) and the USD cost
28
+ * (`gen_ai.usage.cost`) of a generation.
29
+ *
30
+ * Resolution order:
31
+ * 1. Actual cost reported by the provider (currently: OpenRouter's
32
+ * `providerMetadata.openrouter.usage.cost`).
33
+ * 2. Estimated cost from `pricing` (USD per million input/output tokens),
34
+ * computed from the reported token usage.
35
+ *
36
+ * The `gen_ai.usage.cost` attribute is set on `trace.getActiveSpan()` because
37
+ * that's the attribute Langfuse's OTel ingestion prioritizes over its own
38
+ * cost inference (`langfuse.observation.cost_details` is buggy on ingestion).
39
+ *
40
+ * Never throws: all enrichment is best-effort.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const model = wrapLanguageModel({
45
+ * model: provider.model('google/gemini-2.5-flash-lite'),
46
+ * middleware: [
47
+ * createCostMiddleware({
48
+ * modelRef: 'openrouter/google/gemini-2.5-flash-lite',
49
+ * pricing: { input: 0.1, output: 0.4 },
50
+ * }),
51
+ * ],
52
+ * });
53
+ * ```
54
+ */
55
+ function createCostMiddleware(options) {
56
+ const { modelRef, pricing } = options;
57
+ return {
58
+ specificationVersion: "v4",
59
+ wrapGenerate: async ({ doGenerate }) => {
60
+ const result = await doGenerate();
61
+ try {
62
+ recordGeneration(modelRef, resolveCost(result.providerMetadata, result.usage, pricing));
63
+ } catch {}
64
+ return result;
65
+ },
66
+ wrapStream: async ({ doStream }) => {
67
+ const result = await doStream();
68
+ let finishUsage;
69
+ let finishProviderMetadata;
70
+ const transformStream = new TransformStream({
71
+ transform(chunk, controller) {
72
+ if (chunk.type === "finish") {
73
+ finishUsage = chunk.usage;
74
+ finishProviderMetadata = chunk.providerMetadata;
75
+ }
76
+ controller.enqueue(chunk);
77
+ },
78
+ flush() {
79
+ try {
80
+ recordGeneration(modelRef, resolveCost(finishProviderMetadata, finishUsage, pricing));
81
+ } catch {}
82
+ }
83
+ });
84
+ return {
85
+ ...result,
86
+ stream: result.stream.pipeThrough(transformStream)
87
+ };
88
+ }
89
+ };
90
+ }
91
+ //#endregion
92
+ //#region src/middleware/logging.middleware.ts
10
93
  /**
11
94
  * Creates middleware that logs AI SDK requests and responses.
12
95
  */
@@ -14,7 +97,7 @@ function createLoggingMiddleware(options) {
14
97
  const { logger, include = {} } = options;
15
98
  const { params: includeParams, content: includeContent, usage: includeUsage = true } = include;
16
99
  return {
17
- specificationVersion: "v3",
100
+ specificationVersion: "v4",
18
101
  wrapGenerate: async ({ doGenerate, params, model }) => {
19
102
  const startTime = Date.now();
20
103
  logger.debug("ai.generate.start", {
@@ -64,7 +147,7 @@ function createLoggingMiddleware(options) {
64
147
  }
65
148
  });
66
149
  return {
67
- specificationVersion: "v3",
150
+ specificationVersion: "v4",
68
151
  ...result,
69
152
  stream: result.stream.pipeThrough(transformStream)
70
153
  };
@@ -80,541 +163,665 @@ function createLoggingMiddleware(options) {
80
163
  };
81
164
  }
82
165
  //#endregion
83
- //#region src/observability/observability.middleware.ts
84
- /**
85
- * Helper to create type-safe observability metadata for providerOptions
86
- */
87
- function withObservability(meta) {
88
- return { observability: meta };
89
- }
90
- /**
91
- * Creates middleware that sends generation data to an observability platform.
92
- */
93
- function createObservabilityMiddleware(options) {
94
- const { observability, providerMetadata } = options;
95
- return {
96
- specificationVersion: "v3",
97
- wrapGenerate: async ({ doGenerate, params, model }) => {
98
- const startTime = /* @__PURE__ */ new Date();
99
- const meta = params.providerOptions?.observability;
100
- const result = await doGenerate();
101
- const endTime = /* @__PURE__ */ new Date();
102
- if (meta?.traceId) {
103
- const extracted = providerMetadata?.extract(result.providerMetadata);
104
- const outputText = result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
105
- observability.generation({
106
- traceId: meta.traceId,
107
- name: meta.name ?? "generation",
108
- model: model.modelId,
109
- input: params.prompt,
110
- output: outputText,
111
- startTime,
112
- endTime,
113
- usage: extracted?.usage,
114
- cost: extracted?.cost,
115
- metadata: meta.metadata
116
- });
117
- }
118
- return result;
119
- },
120
- wrapStream: async ({ doStream, params, model }) => {
121
- const startTime = /* @__PURE__ */ new Date();
122
- const meta = params.providerOptions?.observability;
123
- const result = await doStream();
124
- if (!meta?.traceId) return result;
125
- const chunks = [];
126
- const transformStream = new TransformStream({
127
- transform(chunk, controller) {
128
- if (chunk.type === "text-delta") chunks.push(chunk.delta);
129
- controller.enqueue(chunk);
130
- },
131
- flush() {
132
- const endTime = /* @__PURE__ */ new Date();
133
- observability.generation({
134
- traceId: meta.traceId,
135
- name: meta.name ?? "generation",
136
- model: model.modelId,
137
- input: params.prompt,
138
- output: chunks.join(""),
139
- startTime,
140
- endTime,
141
- metadata: meta.metadata
142
- });
143
- }
144
- });
145
- return {
146
- specificationVersion: "v3",
147
- ...result,
148
- stream: result.stream.pipeThrough(transformStream)
149
- };
150
- }
151
- };
152
- }
153
- //#endregion
154
- //#region src/observability/langfuse.adapter.ts
155
- /**
156
- * Langfuse adapter implementing ObservabilityPort
157
- */
158
- var LangfuseAdapter = class {
159
- client;
160
- constructor(config) {
161
- this.client = new langfuse.Langfuse({
162
- secretKey: config.secretKey,
163
- publicKey: config.publicKey,
164
- baseUrl: config.baseUrl,
165
- environment: config.environment,
166
- release: config.release
167
- });
166
+ //#region node_modules/@ai-sdk/provider/dist/index.js
167
+ var marker = "vercel.ai.error";
168
+ var symbol = Symbol.for(marker);
169
+ var _a;
170
+ var _b;
171
+ var AISDKError = class _AISDKError extends (_b = Error, _a = symbol, _b) {
172
+ /**
173
+ * Creates an AI SDK Error.
174
+ *
175
+ * @param {Object} params - The parameters for creating the error.
176
+ * @param {string} params.name - The name of the error.
177
+ * @param {string} params.message - The error message.
178
+ * @param {unknown} [params.cause] - The underlying cause of the error.
179
+ */
180
+ constructor({ name: name15, message, cause }) {
181
+ super(message);
182
+ this[_a] = true;
183
+ this.name = name15;
184
+ this.cause = cause;
168
185
  }
169
- async flush() {
170
- await this.client.flushAsync();
171
- }
172
- generation(params) {
173
- const usageDetails = params.usage ? {
174
- input: params.usage.input,
175
- output: params.usage.output,
176
- total: params.usage.total ?? params.usage.input + params.usage.output,
177
- ...params.usage.reasoning !== void 0 && { reasoning: params.usage.reasoning },
178
- ...params.usage.cacheRead !== void 0 && { cache_read: params.usage.cacheRead },
179
- ...params.usage.cacheWrite !== void 0 && { cache_write: params.usage.cacheWrite }
180
- } : void 0;
181
- const costDetails = params.cost ? {
182
- total: params.cost.total,
183
- ...params.cost.input !== void 0 && { input: params.cost.input },
184
- ...params.cost.output !== void 0 && { output: params.cost.output }
185
- } : void 0;
186
- this.client.generation({
187
- traceId: params.traceId,
188
- name: params.name,
189
- model: params.model,
190
- input: params.input,
191
- output: params.output,
192
- startTime: params.startTime,
193
- endTime: params.endTime,
194
- usageDetails,
195
- costDetails,
196
- metadata: params.metadata
197
- });
186
+ /**
187
+ * Checks if the given error is an AI SDK Error.
188
+ * @param {unknown} error - The error to check.
189
+ * @returns {boolean} True if the error is an AI SDK Error, false otherwise.
190
+ */
191
+ static isInstance(error) {
192
+ return _AISDKError.hasMarker(error, marker);
198
193
  }
199
- async shutdown() {
200
- await this.client.shutdownAsync();
194
+ static hasMarker(error, marker16) {
195
+ const markerSymbol = Symbol.for(marker16);
196
+ return error != null && typeof error === "object" && markerSymbol in error && typeof error[markerSymbol] === "boolean" && error[markerSymbol] === true;
201
197
  }
202
- trace(params) {
203
- this.client.trace({
204
- id: params.id,
205
- name: params.name,
206
- metadata: params.metadata
198
+ };
199
+ var name = "AI_APICallError";
200
+ var marker2 = `vercel.ai.error.${name}`;
201
+ var symbol2 = Symbol.for(marker2);
202
+ var _a2;
203
+ var _b2;
204
+ var APICallError = class extends (_b2 = AISDKError, _a2 = symbol2, _b2) {
205
+ constructor({ message, url, requestBodyValues, statusCode, responseHeaders, responseBody, cause, isRetryable = statusCode != null && (statusCode === 408 || statusCode === 409 || statusCode === 429 || statusCode >= 500), data }) {
206
+ super({
207
+ name,
208
+ message,
209
+ cause
207
210
  });
211
+ this[_a2] = true;
212
+ this.url = url;
213
+ this.requestBodyValues = requestBodyValues;
214
+ this.statusCode = statusCode;
215
+ this.responseHeaders = responseHeaders;
216
+ this.responseBody = responseBody;
217
+ this.isRetryable = isRetryable;
218
+ this.data = data;
219
+ }
220
+ static isInstance(error) {
221
+ return AISDKError.hasMarker(error, marker2);
208
222
  }
209
223
  };
210
- //#endregion
211
- //#region src/observability/noop.adapter.ts
212
- /**
213
- * No-op adapter that silently discards all observability data.
214
- * Useful for testing, development, or when observability is disabled.
215
- */
216
- var NoopObservabilityAdapter = class {
217
- async flush() {}
218
- generation(_params) {}
219
- async shutdown() {}
220
- trace(_params) {}
221
- };
222
- //#endregion
223
- //#region src/result/result.ts
224
- /**
225
- * Create a successful result
226
- */
227
- function generationSuccess(data) {
228
- return {
229
- success: true,
230
- data
231
- };
224
+ var name2 = "AI_EmptyResponseBodyError";
225
+ var marker3 = `vercel.ai.error.${name2}`;
226
+ var symbol3 = Symbol.for(marker3);
227
+ var _a3;
228
+ var _b3;
229
+ (class extends (_b3 = AISDKError, _a3 = symbol3, _b3) {
230
+ constructor({ message = "Empty response body" } = {}) {
231
+ super({
232
+ name: name2,
233
+ message
234
+ });
235
+ this[_a3] = true;
236
+ }
237
+ static isInstance(error) {
238
+ return AISDKError.hasMarker(error, marker3);
239
+ }
240
+ });
241
+ function getErrorMessage(error) {
242
+ if (error == null) return "unknown error";
243
+ if (typeof error === "string") return error;
244
+ if (error instanceof Error) return error.toString();
245
+ return JSON.stringify(error);
232
246
  }
233
- /**
234
- * Create a failed result
235
- */
236
- function generationFailure(code, message, cause) {
237
- return {
238
- success: false,
239
- error: {
240
- code,
247
+ var name3 = "AI_InvalidArgumentError";
248
+ var marker4 = `vercel.ai.error.${name3}`;
249
+ var symbol4 = Symbol.for(marker4);
250
+ var _a4;
251
+ var _b4;
252
+ (class extends (_b4 = AISDKError, _a4 = symbol4, _b4) {
253
+ constructor({ message, cause, argument }) {
254
+ super({
255
+ name: name3,
241
256
  message,
242
257
  cause
243
- }
244
- };
245
- }
246
- /**
247
- * Classify an error into a GenerationErrorCode
248
- */
249
- function classifyError(error) {
250
- if (error instanceof Error) {
251
- const message = error.message.toLowerCase();
252
- if (message.includes("timeout") || message.includes("timed out")) return "TIMEOUT";
253
- if (message.includes("rate limit") || message.includes("429")) return "RATE_LIMITED";
254
- if (message.includes("parse") || message.includes("json") || message.includes("unexpected token")) return "PARSING_FAILED";
255
- if (message.includes("valid") || message.includes("schema") || message.includes("zod")) return "VALIDATION_FAILED";
256
- }
257
- return "AI_GENERATION_FAILED";
258
- }
259
- /**
260
- * Check if a result is successful (type guard)
261
- */
262
- function isSuccess(result) {
263
- return result.success;
264
- }
265
- /**
266
- * Check if a result is a failure (type guard)
267
- */
268
- function isFailure(result) {
269
- return !result.success;
270
- }
271
- /**
272
- * Unwrap a result, throwing if it fails
273
- */
274
- function unwrap(result) {
275
- if (result.success) return result.data;
276
- throw new Error(`${result.error.code}: ${result.error.message}`);
277
- }
278
- /**
279
- * Unwrap a result with a default value for failures
280
- */
281
- function unwrapOr(result, defaultValue) {
282
- return result.success ? result.data : defaultValue;
283
- }
284
- //#endregion
285
- //#region src/parsing/parse-object.ts
286
- const MARKDOWN_CODE_BLOCK_RE = /```(?:json)?\r?\n([^`]*?)\r?\n```/g;
287
- /**
288
- * Error thrown when object parsing fails.
289
- * Contains the original text for debugging purposes.
290
- */
291
- var ParseObjectError = class extends Error {
292
- name = "ParseObjectError";
293
- cause;
294
- text;
295
- constructor(message, cause, text) {
296
- super(message);
297
- this.cause = cause;
258
+ });
259
+ this[_a4] = true;
260
+ this.argument = argument;
261
+ }
262
+ static isInstance(error) {
263
+ return AISDKError.hasMarker(error, marker4);
264
+ }
265
+ });
266
+ var name4 = "AI_InvalidPromptError";
267
+ var marker5 = `vercel.ai.error.${name4}`;
268
+ var symbol5 = Symbol.for(marker5);
269
+ var _a5;
270
+ var _b5;
271
+ (class extends (_b5 = AISDKError, _a5 = symbol5, _b5) {
272
+ constructor({ prompt, message, cause }) {
273
+ super({
274
+ name: name4,
275
+ message: `Invalid prompt: ${message}`,
276
+ cause
277
+ });
278
+ this[_a5] = true;
279
+ this.prompt = prompt;
280
+ }
281
+ static isInstance(error) {
282
+ return AISDKError.hasMarker(error, marker5);
283
+ }
284
+ });
285
+ var name5 = "AI_InvalidResponseDataError";
286
+ var marker6 = `vercel.ai.error.${name5}`;
287
+ var symbol6 = Symbol.for(marker6);
288
+ var _a6;
289
+ var _b6;
290
+ (class extends (_b6 = AISDKError, _a6 = symbol6, _b6) {
291
+ constructor({ data, message = `Invalid response data: ${JSON.stringify(data)}.` }) {
292
+ super({
293
+ name: name5,
294
+ message
295
+ });
296
+ this[_a6] = true;
297
+ this.data = data;
298
+ }
299
+ static isInstance(error) {
300
+ return AISDKError.hasMarker(error, marker6);
301
+ }
302
+ });
303
+ var name6 = "AI_JSONParseError";
304
+ var marker7 = `vercel.ai.error.${name6}`;
305
+ var symbol7 = Symbol.for(marker7);
306
+ var _a7;
307
+ var _b7;
308
+ (class extends (_b7 = AISDKError, _a7 = symbol7, _b7) {
309
+ constructor({ text, cause }) {
310
+ super({
311
+ name: name6,
312
+ message: `JSON parsing failed: Text: ${text}.
313
+ Error message: ${getErrorMessage(cause)}`,
314
+ cause
315
+ });
316
+ this[_a7] = true;
298
317
  this.text = text;
299
318
  }
300
- };
301
- function convertToPrimitive(value, schema) {
302
- if (schema instanceof zod_v4.z.ZodBoolean) return Boolean(value);
303
- if (schema instanceof zod_v4.z.ZodNull) return null;
304
- if (schema instanceof zod_v4.z.ZodNumber) return Number(value);
305
- if (schema instanceof zod_v4.z.ZodString) return String(value);
306
- return value;
307
- }
308
- function extractArray(text, originalText) {
309
- const start = text.indexOf("[");
310
- const end = text.lastIndexOf("]");
311
- if (start === -1 || end === -1) throw new ParseObjectError("No array found in response", void 0, originalText);
312
- try {
313
- const raw = text.slice(start, end + 1);
314
- return JSON.parse((0, jsonrepair.jsonrepair)(raw));
315
- } catch (error) {
316
- throw new ParseObjectError("Failed to parse array JSON", error, originalText);
319
+ static isInstance(error) {
320
+ return AISDKError.hasMarker(error, marker7);
317
321
  }
318
- }
319
- function extractObject(text, originalText) {
320
- const start = text.indexOf("{");
321
- const end = text.lastIndexOf("}");
322
- if (start === -1 || end === -1) throw new ParseObjectError("No object found in response", void 0, originalText);
323
- try {
324
- const raw = text.slice(start, end + 1);
325
- return JSON.parse((0, jsonrepair.jsonrepair)(raw));
326
- } catch (error) {
327
- throw new ParseObjectError("Failed to parse object JSON", error, originalText);
322
+ });
323
+ var name7 = "AI_LoadAPIKeyError";
324
+ var marker8 = `vercel.ai.error.${name7}`;
325
+ var symbol8 = Symbol.for(marker8);
326
+ var _a8;
327
+ var _b8;
328
+ (class extends (_b8 = AISDKError, _a8 = symbol8, _b8) {
329
+ constructor({ message }) {
330
+ super({
331
+ name: name7,
332
+ message
333
+ });
334
+ this[_a8] = true;
328
335
  }
329
- }
330
- function extractPrimitive(text, schema) {
331
- const trimmed = text.trim();
332
- try {
333
- return convertToPrimitive(JSON.parse(trimmed), schema);
334
- } catch {
335
- return convertToPrimitive(trimmed, schema);
336
+ static isInstance(error) {
337
+ return AISDKError.hasMarker(error, marker8);
336
338
  }
337
- }
338
- function extractBySchemaType(text, schema, originalText) {
339
- if (schema instanceof zod_v4.z.ZodArray) return extractArray(text, originalText);
340
- if (schema instanceof zod_v4.z.ZodObject) return extractObject(text, originalText);
341
- if (schema instanceof zod_v4.z.ZodBoolean || schema instanceof zod_v4.z.ZodNull || schema instanceof zod_v4.z.ZodNumber || schema instanceof zod_v4.z.ZodString) return extractPrimitive(text, schema);
342
- if (schema instanceof zod_v4.z.ZodUnion || schema instanceof zod_v4.z.ZodDiscriminatedUnion) {
343
- if (text.indexOf("{") !== -1) return extractObject(text, originalText);
344
- if (text.indexOf("[") !== -1) return extractArray(text, originalText);
345
- throw new ParseObjectError("No object or array found for union type", void 0, originalText);
346
- }
347
- if (schema instanceof zod_v4.z.ZodOptional || schema instanceof zod_v4.z.ZodNullable) return extractBySchemaType(text, schema.unwrap(), originalText);
348
- if (schema instanceof zod_v4.z.ZodDefault) return extractBySchemaType(text, schema.def.innerType, originalText);
349
- if (schema instanceof zod_v4.z.ZodPipe) return extractBySchemaType(text, schema.def.in, originalText);
350
- throw new ParseObjectError("Unsupported schema type", void 0, originalText);
351
- }
352
- function extractJsonFromCodeBlock(block) {
353
- const content = block.replace(/```(?:json)?\r?\n([^`]*?)\r?\n```/, "$1").trim();
354
- try {
355
- JSON.parse(content);
356
- return content;
357
- } catch {
358
- return null;
339
+ });
340
+ var name8 = "AI_LoadSettingError";
341
+ var marker9 = `vercel.ai.error.${name8}`;
342
+ var symbol9 = Symbol.for(marker9);
343
+ var _a9;
344
+ var _b9;
345
+ (class extends (_b9 = AISDKError, _a9 = symbol9, _b9) {
346
+ constructor({ message }) {
347
+ super({
348
+ name: name8,
349
+ message
350
+ });
351
+ this[_a9] = true;
359
352
  }
360
- }
361
- function findLongestString(strings) {
362
- return strings.reduce((longest, current) => current.length > longest.length ? current : longest);
363
- }
364
- function findJsonStructures(text) {
365
- const matches = [];
366
- let depth = 0;
367
- let start = -1;
368
- for (let i = 0; i < text.length; i++) {
369
- const char = text[i];
370
- if (char === "{" || char === "[") {
371
- if (depth === 0) start = i;
372
- depth++;
373
- } else if (char === "}" || char === "]") {
374
- depth--;
375
- if (depth === 0 && start !== -1) {
376
- const candidate = text.slice(start, i + 1);
377
- try {
378
- JSON.parse(candidate);
379
- matches.push(candidate);
380
- } catch {}
381
- }
353
+ static isInstance(error) {
354
+ return AISDKError.hasMarker(error, marker9);
355
+ }
356
+ });
357
+ var name9 = "AI_NoContentGeneratedError";
358
+ var marker10 = `vercel.ai.error.${name9}`;
359
+ var symbol10 = Symbol.for(marker10);
360
+ var _a10;
361
+ var _b10;
362
+ (class extends (_b10 = AISDKError, _a10 = symbol10, _b10) {
363
+ constructor({ message = "No content generated." } = {}) {
364
+ super({
365
+ name: name9,
366
+ message
367
+ });
368
+ this[_a10] = true;
369
+ }
370
+ static isInstance(error) {
371
+ return AISDKError.hasMarker(error, marker10);
372
+ }
373
+ });
374
+ var name10 = "AI_NoSuchModelError";
375
+ var marker11 = `vercel.ai.error.${name10}`;
376
+ var symbol11 = Symbol.for(marker11);
377
+ var _a11;
378
+ var _b11;
379
+ (class extends (_b11 = AISDKError, _a11 = symbol11, _b11) {
380
+ constructor({ errorName = name10, modelId, modelType, message = `No such ${modelType}: ${modelId}` }) {
381
+ super({
382
+ name: errorName,
383
+ message
384
+ });
385
+ this[_a11] = true;
386
+ this.modelId = modelId;
387
+ this.modelType = modelType;
388
+ }
389
+ static isInstance(error) {
390
+ return AISDKError.hasMarker(error, marker11);
391
+ }
392
+ });
393
+ var name11 = "AI_NoSuchProviderReferenceError";
394
+ var marker12 = `vercel.ai.error.${name11}`;
395
+ var symbol12 = Symbol.for(marker12);
396
+ var _a12;
397
+ var _b12;
398
+ (class extends (_b12 = AISDKError, _a12 = symbol12, _b12) {
399
+ constructor({ provider, reference, message = `No provider reference found for provider '${provider}'. Available providers: ${Object.keys(reference).join(", ")}` }) {
400
+ super({
401
+ name: name11,
402
+ message
403
+ });
404
+ this[_a12] = true;
405
+ this.provider = provider;
406
+ this.reference = reference;
407
+ }
408
+ static isInstance(error) {
409
+ return AISDKError.hasMarker(error, marker12);
410
+ }
411
+ });
412
+ var name12 = "AI_TooManyEmbeddingValuesForCallError";
413
+ var marker13 = `vercel.ai.error.${name12}`;
414
+ var symbol13 = Symbol.for(marker13);
415
+ var _a13;
416
+ var _b13;
417
+ (class extends (_b13 = AISDKError, _a13 = symbol13, _b13) {
418
+ constructor(options) {
419
+ super({
420
+ name: name12,
421
+ message: `Too many values for a single embedding call. The ${options.provider} model "${options.modelId}" can only embed up to ${options.maxEmbeddingsPerCall} values per call, but ${options.values.length} values were provided.`
422
+ });
423
+ this[_a13] = true;
424
+ this.provider = options.provider;
425
+ this.modelId = options.modelId;
426
+ this.maxEmbeddingsPerCall = options.maxEmbeddingsPerCall;
427
+ this.values = options.values;
428
+ }
429
+ static isInstance(error) {
430
+ return AISDKError.hasMarker(error, marker13);
431
+ }
432
+ });
433
+ var name13 = "AI_TypeValidationError";
434
+ var marker14 = `vercel.ai.error.${name13}`;
435
+ var symbol14 = Symbol.for(marker14);
436
+ var _a14;
437
+ var _b14;
438
+ (class _TypeValidationError extends (_b14 = AISDKError, _a14 = symbol14, _b14) {
439
+ constructor({ value, cause, context }) {
440
+ let contextPrefix = "Type validation failed";
441
+ if (context == null ? void 0 : context.field) contextPrefix += ` for ${context.field}`;
442
+ if ((context == null ? void 0 : context.entityName) || (context == null ? void 0 : context.entityId)) {
443
+ contextPrefix += " (";
444
+ const parts = [];
445
+ if (context.entityName) parts.push(context.entityName);
446
+ if (context.entityId) parts.push(`id: "${context.entityId}"`);
447
+ contextPrefix += parts.join(", ");
448
+ contextPrefix += ")";
382
449
  }
450
+ super({
451
+ name: name13,
452
+ message: `${contextPrefix}: Value: ${JSON.stringify(value)}.
453
+ Error message: ${getErrorMessage(cause)}`,
454
+ cause
455
+ });
456
+ this[_a14] = true;
457
+ this.value = value;
458
+ this.context = context;
383
459
  }
384
- return matches;
385
- }
386
- function extractJsonString(text) {
387
- const codeBlocks = text.match(MARKDOWN_CODE_BLOCK_RE);
388
- if (codeBlocks && codeBlocks.length > 0) {
389
- const validBlocks = codeBlocks.map((block) => extractJsonFromCodeBlock(block)).filter((block) => block !== null);
390
- if (validBlocks.length > 0) return findLongestString(validBlocks);
391
- }
392
- const structures = findJsonStructures(text);
393
- if (structures.length > 0) return findLongestString(structures);
394
- return text.replace(/\s+/g, " ").trim();
395
- }
396
- function unescapeString(text) {
397
- return text.replace(/\\"/g, "\"").replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\\\/g, "\\").replace(/\\u([0-9a-fA-F]{4})/g, (_, code) => String.fromCharCode(Number.parseInt(code, 16)));
398
- }
399
- function unescapeJsonValues(json) {
400
- if (typeof json === "string") return unescapeString(json);
401
- if (Array.isArray(json)) return json.map(unescapeJsonValues);
402
- if (typeof json === "object" && json !== null) return Object.fromEntries(Object.entries(json).map(([key, value]) => [key, unescapeJsonValues(value)]));
403
- return json;
460
+ static isInstance(error) {
461
+ return AISDKError.hasMarker(error, marker14);
462
+ }
463
+ /**
464
+ * Wraps an error into a TypeValidationError.
465
+ * If the cause is already a TypeValidationError with the same value and context, it returns the cause.
466
+ * Otherwise, it creates a new TypeValidationError.
467
+ *
468
+ * @param {Object} params - The parameters for wrapping the error.
469
+ * @param {unknown} params.value - The value that failed validation.
470
+ * @param {unknown} params.cause - The original error or cause of the validation failure.
471
+ * @param {TypeValidationContext} params.context - Optional context about what is being validated.
472
+ * @returns {TypeValidationError} A TypeValidationError instance.
473
+ */
474
+ static wrap({ value, cause, context }) {
475
+ var _a16, _b16, _c;
476
+ if (_TypeValidationError.isInstance(cause) && cause.value === value && ((_a16 = cause.context) == null ? void 0 : _a16.field) === (context == null ? void 0 : context.field) && ((_b16 = cause.context) == null ? void 0 : _b16.entityName) === (context == null ? void 0 : context.entityName) && ((_c = cause.context) == null ? void 0 : _c.entityId) === (context == null ? void 0 : context.entityId)) return cause;
477
+ return new _TypeValidationError({
478
+ value,
479
+ cause,
480
+ context
481
+ });
482
+ }
483
+ });
484
+ var name14 = "AI_UnsupportedFunctionalityError";
485
+ var marker15 = `vercel.ai.error.${name14}`;
486
+ var symbol15 = Symbol.for(marker15);
487
+ var _a15;
488
+ var _b15;
489
+ (class extends (_b15 = AISDKError, _a15 = symbol15, _b15) {
490
+ constructor({ functionality, message = `'${functionality}' functionality not supported.` }) {
491
+ super({
492
+ name: name14,
493
+ message
494
+ });
495
+ this[_a15] = true;
496
+ this.functionality = functionality;
497
+ }
498
+ static isInstance(error) {
499
+ return AISDKError.hasMarker(error, marker15);
500
+ }
501
+ });
502
+ //#endregion
503
+ //#region src/model/fallback-model.ts
504
+ const RETRYABLE_MESSAGE_PATTERNS = [
505
+ /ECONNREFUSED/i,
506
+ /ECONNRESET/i,
507
+ /ETIMEDOUT/i,
508
+ /EAI_AGAIN/i,
509
+ /ENOTFOUND/i,
510
+ /timed?\s*out/i,
511
+ /network/i,
512
+ /fetch failed/i
513
+ ];
514
+ function isRetryableError(error) {
515
+ if (APICallError.isInstance(error)) {
516
+ if (typeof error.statusCode === "number") return error.statusCode === 429 || error.statusCode >= 500;
517
+ return error.isRetryable;
518
+ }
519
+ const message = error instanceof Error ? error.message : String(error);
520
+ return RETRYABLE_MESSAGE_PATTERNS.some((pattern) => pattern.test(message));
404
521
  }
405
522
  /**
406
- * Parses AI-generated text into structured data validated against a Zod schema.
407
- *
408
- * Handles common AI response formats:
409
- * - JSON wrapped in markdown code blocks
410
- * - JSON embedded in prose text
411
- * - Malformed JSON (auto-repaired)
412
- * - Escaped unicode and special characters
523
+ * Creates a `LanguageModelV4` that transparently falls back to a secondary
524
+ * model when the primary model fails with a retryable error (HTTP 429, 5xx,
525
+ * network errors/timeouts). Non-retryable errors (400s, validation, abort)
526
+ * propagate unchanged.
413
527
  *
414
- * @param text - The raw AI response text
415
- * @param schema - A Zod schema to validate and type the result
416
- * @returns The parsed and validated data
417
- * @throws {ParseObjectError} When parsing or validation fails
528
+ * This is a model, not a middleware — middleware cannot switch the
529
+ * underlying model, only transform a single model's behavior.
418
530
  *
419
531
  * @example
420
532
  * ```ts
421
- * const schema = z.object({ title: z.string(), tags: z.array(z.string()) });
422
- * const result = parseObject(aiResponse, schema);
423
- * // result is typed as { title: string; tags: string[] }
533
+ * const model = createFallbackModel({
534
+ * primary: provider.model('anthropic/claude-sonnet-4'),
535
+ * fallback: provider.model('openai/gpt-4o-mini'),
536
+ * logger,
537
+ * });
424
538
  * ```
425
539
  */
426
- function parseObject(text, schema) {
427
- try {
428
- const unescaped = unescapeJsonValues(extractBySchemaType(extractJsonString(text), schema, text));
429
- return schema.parse(unescaped);
430
- } catch (error) {
431
- if (error instanceof ParseObjectError) throw error;
432
- if (error instanceof zod_v4.z.ZodError) throw new ParseObjectError("Failed to validate response against schema", error, text);
433
- throw error;
540
+ function createFallbackModel(options) {
541
+ const { primary, fallback, logger } = options;
542
+ const primaryModel = primary;
543
+ const fallbackModel = fallback;
544
+ function logFallback(error) {
545
+ logger?.warn("ai.fallback.triggered", {
546
+ modelIds: [primaryModel.modelId, fallbackModel.modelId],
547
+ error: error instanceof Error ? error.message : String(error)
548
+ });
434
549
  }
550
+ return {
551
+ specificationVersion: "v4",
552
+ provider: primaryModel.provider,
553
+ modelId: primaryModel.modelId,
554
+ supportedUrls: primaryModel.supportedUrls,
555
+ async doGenerate(callOptions) {
556
+ try {
557
+ return await primaryModel.doGenerate(callOptions);
558
+ } catch (error) {
559
+ if (!isRetryableError(error)) throw error;
560
+ logFallback(error);
561
+ return fallbackModel.doGenerate(callOptions);
562
+ }
563
+ },
564
+ async doStream(callOptions) {
565
+ try {
566
+ return await primaryModel.doStream(callOptions);
567
+ } catch (error) {
568
+ if (!isRetryableError(error)) throw error;
569
+ logFallback(error);
570
+ return fallbackModel.doStream(callOptions);
571
+ }
572
+ }
573
+ };
435
574
  }
436
575
  //#endregion
437
- //#region src/generation/generate-structured.ts
576
+ //#region src/middleware/schema-instruction.middleware.ts
577
+ function buildInstruction(responseFormat) {
578
+ if (responseFormat?.type !== "json") return "";
579
+ const lines = ["You must respond with valid JSON only — no prose, no markdown code fences."];
580
+ if (responseFormat.schema) lines.push("The JSON must strictly conform to this JSON schema:", JSON.stringify(responseFormat.schema));
581
+ return lines.join("\n");
582
+ }
583
+ function appendToLastUserMessage(prompt, instruction) {
584
+ const lastUserIndex = prompt.findLastIndex((message) => message.role === "user");
585
+ if (lastUserIndex === -1) return [...prompt, {
586
+ content: [{
587
+ text: instruction,
588
+ type: "text"
589
+ }],
590
+ role: "user"
591
+ }];
592
+ return prompt.map((message, index) => {
593
+ if (index !== lastUserIndex || message.role !== "user") return message;
594
+ const lastTextIndex = message.content.findLastIndex((part) => part.type === "text");
595
+ if (lastTextIndex === -1) return {
596
+ ...message,
597
+ content: [...message.content, {
598
+ text: instruction,
599
+ type: "text"
600
+ }]
601
+ };
602
+ return {
603
+ ...message,
604
+ content: message.content.map((part, partIndex) => {
605
+ if (partIndex !== lastTextIndex || part.type !== "text") return part;
606
+ return {
607
+ ...part,
608
+ text: `${part.text}\n\n${instruction}`
609
+ };
610
+ })
611
+ };
612
+ });
613
+ }
438
614
  /**
439
- * Generate structured data from an AI model with automatic parsing and error handling.
440
- * Observability is handled by middleware - no metadata exposed to caller.
615
+ * Creates middleware that injects the JSON schema of a structured-output
616
+ * request into the last user message.
617
+ *
618
+ * Some gateways silently drop the native structured-output field when
619
+ * translating to their backend, so the model never sees the schema and
620
+ * answers in free prose. This middleware re-states the schema as part of the
621
+ * user message so structured output works regardless. It targets the user
622
+ * message rather than a system message because gateways backed by cloaked
623
+ * CLI agents bury injected system messages under their own persona prompt and
624
+ * ignore them. The original `responseFormat` is left untouched: backends that
625
+ * honor it get the native signal too.
626
+ *
627
+ * No-op for text generations (no `responseFormat`, or `type: 'text'`).
441
628
  */
442
- async function generateStructured(options) {
443
- const { model, prompt, system, schema, providerOptions, abortSignal, maxOutputTokens, temperature } = options;
444
- try {
445
- const response = await (0, ai.generateText)({
446
- model,
447
- prompt,
448
- system,
449
- providerOptions,
450
- abortSignal,
451
- maxOutputTokens,
452
- temperature
453
- });
454
- if (!response.text || response.text.trim() === "") return generationFailure("EMPTY_RESULT", "AI returned empty response");
455
- try {
456
- return generationSuccess(parseObject(response.text, schema));
457
- } catch (error) {
458
- if (error instanceof ParseObjectError) return generationFailure("PARSING_FAILED", error.message, error);
459
- return generationFailure("VALIDATION_FAILED", "Schema validation failed", error);
629
+ function createSchemaInstructionMiddleware() {
630
+ return {
631
+ specificationVersion: "v4",
632
+ transformParams: ({ params }) => {
633
+ const instruction = buildInstruction(params.responseFormat);
634
+ if (!instruction) return Promise.resolve(params);
635
+ return Promise.resolve({
636
+ ...params,
637
+ prompt: appendToLastUserMessage(params.prompt, instruction)
638
+ });
460
639
  }
461
- } catch (error) {
462
- return generationFailure(classifyError(error), error instanceof Error ? error.message : "Unknown error", error);
463
- }
640
+ };
464
641
  }
465
642
  //#endregion
466
- //#region src/parsing/create-schema-prompt.ts
643
+ //#region src/provider/gateway.provider.ts
467
644
  /**
468
- * Creates a system prompt that instructs the model to output structured data
469
- * matching the provided Zod schema.
470
- *
471
- * Use this with `generateText` when the provider doesn't support native
472
- * structured outputs, then parse the response with `parseObject`.
645
+ * Creates a provider for gateways exposing a chat-completions API any API
646
+ * implementing the OpenAI chat completions spec.
473
647
  *
474
- * @param schema - A Zod schema defining the expected output structure
475
- * @returns A system prompt string with JSON schema instructions
648
+ * Every model returned is automatically wrapped with two safety nets for
649
+ * gateways that don't support native structured output:
650
+ * - `createSchemaInstructionMiddleware` injects the JSON schema into the
651
+ * system prompt (some gateways silently drop `response_format`);
652
+ * - `extractJsonMiddleware` strips markdown code fences from JSON responses.
476
653
  *
477
654
  * @example
478
655
  * ```ts
479
- * import { generateText } from 'ai';
480
- * import { createSchemaPrompt, parseObject } from '@jterrazz/intelligence';
481
- *
482
- * const schema = z.object({ title: z.string(), tags: z.array(z.string()) });
483
- *
484
- * const { text } = await generateText({
485
- * model,
486
- * prompt: 'Generate an article about TypeScript',
487
- * system: createSchemaPrompt(schema),
488
- * });
656
+ * const provider = createGatewayProvider({ baseURL: 'https://gateway.example.com/v1' });
657
+ * const model = provider.model('gpt-4o-mini');
489
658
  *
490
- * const result = parseObject(text, schema);
659
+ * const { text } = await generateText({ model, prompt: 'Hello!' });
491
660
  * ```
492
661
  */
493
- function createSchemaPrompt(schema) {
494
- const jsonSchema = zod_v4.z.toJSONSchema(schema);
495
- const schemaJson = JSON.stringify(jsonSchema, null, 2);
496
- if ([
497
- "boolean",
498
- "integer",
499
- "number",
500
- "string"
501
- ].includes(jsonSchema.type)) return `<OUTPUT_FORMAT>
502
- You must respond with a ${jsonSchema.type} value that matches this schema:
503
-
504
- \`\`\`json
505
- ${schemaJson}
506
- \`\`\`
507
-
508
- Your response should be only the ${jsonSchema.type} value, without any JSON wrapping or additional text.
509
- </OUTPUT_FORMAT>`;
510
- return `<OUTPUT_FORMAT>
511
- You must respond with valid JSON that matches this JSON schema:
512
-
513
- \`\`\`json
514
- ${schemaJson}
515
- \`\`\`
516
-
517
- Your response must be parseable JSON that validates against this schema. Do not include any text outside the JSON.
518
- </OUTPUT_FORMAT>`;
662
+ function createGatewayProvider(config) {
663
+ const openai = (0, _ai_sdk_openai.createOpenAI)({
664
+ apiKey: config.apiKey,
665
+ baseURL: config.baseURL
666
+ });
667
+ return { model(id) {
668
+ return (0, ai.wrapLanguageModel)({
669
+ model: openai.chat(id),
670
+ middleware: [createSchemaInstructionMiddleware(), (0, ai.extractJsonMiddleware)()]
671
+ });
672
+ } };
519
673
  }
520
674
  //#endregion
521
675
  //#region src/provider/openrouter.provider.ts
522
676
  /**
523
677
  * Creates an OpenRouter provider for AI SDK models.
524
678
  *
679
+ * Per-call options (reasoning effort, max tokens, etc.) are no longer
680
+ * configured here — pass them at the call site via `providerOptions.openrouter`
681
+ * on `generateText`/`streamText`.
682
+ *
525
683
  * @example
526
684
  * ```ts
527
685
  * const provider = createOpenRouterProvider({ apiKey: process.env.OPENROUTER_API_KEY });
528
686
  * const model = provider.model('anthropic/claude-sonnet-4-20250514');
529
687
  *
530
- * const { text } = await generateText({ model, prompt: 'Hello!' });
688
+ * const { text } = await generateText({
689
+ * model,
690
+ * prompt: 'Hello!',
691
+ * providerOptions: { openrouter: { reasoning: { effort: 'high' } } },
692
+ * });
531
693
  * ```
532
694
  */
533
695
  function createOpenRouterProvider(config) {
534
- const openrouter = (0, _openrouter_ai_sdk_provider.createOpenRouter)({ apiKey: config.apiKey });
535
- return { model(name, options = {}) {
536
- return openrouter(name, {
537
- ...options.maxTokens !== void 0 && { maxTokens: options.maxTokens },
538
- ...options.reasoning && { extraBody: { reasoning: options.reasoning } }
539
- });
696
+ const openrouter = (0, _openrouter_ai_sdk_provider.createOpenRouter)({
697
+ apiKey: config.apiKey,
698
+ appName: config.metadata?.application,
699
+ appUrl: config.metadata?.website
700
+ });
701
+ return { model(id) {
702
+ return openrouter(id);
540
703
  } };
541
704
  }
542
705
  //#endregion
543
- //#region src/provider/openrouter-metadata.adapter.ts
706
+ //#region src/factory/create-intelligence.ts
707
+ let telemetryRegistered = false;
544
708
  /**
545
- * OpenRouter adapter for extracting usage and cost from provider metadata
709
+ * Registers the AI SDK OpenTelemetry integration, once per process. Best
710
+ * effort — if the host app has no OTel SDK configured, `@ai-sdk/otel` spans
711
+ * are simply dropped rather than throwing.
546
712
  */
547
- var OpenRouterMetadataAdapter = class {
548
- extract(providerMetadata) {
549
- const meta = providerMetadata?.openrouter;
550
- if (!meta?.usage) return {};
551
- const usage = meta.usage;
552
- return {
553
- usage: {
554
- input: usage.promptTokens ?? 0,
555
- output: usage.completionTokens ?? 0,
556
- total: usage.totalTokens,
557
- reasoning: usage.completionTokensDetails?.reasoningTokens,
558
- cacheRead: usage.promptTokensDetails?.cachedTokens
559
- },
560
- cost: usage.cost !== void 0 ? { total: usage.cost } : void 0
561
- };
713
+ function ensureTelemetryRegistered() {
714
+ if (telemetryRegistered) return;
715
+ telemetryRegistered = true;
716
+ try {
717
+ (0, ai.registerTelemetry)(new _ai_sdk_otel.OpenTelemetry());
718
+ } catch {}
719
+ }
720
+ function createProvider(config) {
721
+ switch (config.type) {
722
+ case "gateway": return createGatewayProvider(config);
723
+ case "openrouter": return createOpenRouterProvider(config);
562
724
  }
563
- };
564
- //#endregion
565
- //#region src/provider/openai-compatible.provider.ts
566
- /**
567
- * Creates a provider for OpenAI-compatible APIs.
568
- * Works with any API implementing the OpenAI chat completions spec.
569
- */
570
- function createOpenAICompatibleProvider(config) {
571
- const openai = (0, _ai_sdk_openai.createOpenAI)({
572
- apiKey: config.apiKey,
573
- baseURL: config.baseURL
574
- });
575
- return { model(name, _options = {}) {
576
- return openai(config.modelMapping?.[name] ?? name);
577
- } };
578
725
  }
579
- //#endregion
580
- //#region src/provider/openai-compatible-metadata.adapter.ts
726
+ function assertProviderExists(providerKey, providers) {
727
+ if (providers[providerKey]) return;
728
+ const available = Object.keys(providers).join(", ") || "(none configured)";
729
+ throw new Error(`Unknown provider "${providerKey}". Available providers: ${available}.`);
730
+ }
581
731
  /**
582
- * Metadata adapter for OpenAI-compatible APIs (including gateway-intelligence).
583
- * Extracts usage data from the standardized OpenAI response format.
732
+ * Creates a composition root over AI SDK v7: resolves each agent's
733
+ * `provider`/`model` pair into a fully instrumented `LanguageModel` cost
734
+ * tracking, optional fallback, and optional logging — cached per agent name.
735
+ *
736
+ * Registers the `@ai-sdk/otel` telemetry integration on first use (idempotent,
737
+ * best-effort). The host app is expected to have already registered an
738
+ * OpenTelemetry Node SDK (e.g. via `@jterrazz/telemetry`).
739
+ *
740
+ * @example
741
+ * ```ts
742
+ * const intelligence = createIntelligence({
743
+ * providers: {
744
+ * openrouter: { type: 'openrouter', apiKey: process.env.OPENROUTER_API_KEY },
745
+ * },
746
+ * agents: {
747
+ * summarizer: {
748
+ * provider: 'openrouter',
749
+ * model: 'google/gemini-2.5-flash-lite',
750
+ * fallback: { provider: 'openrouter', model: 'openai/gpt-4o-mini' },
751
+ * },
752
+ * },
753
+ * pricing: {
754
+ * 'openrouter/google/gemini-2.5-flash-lite': { input: 0.1, output: 0.4 },
755
+ * },
756
+ * logger,
757
+ * });
758
+ *
759
+ * const model = intelligence.model('summarizer');
760
+ * const { text } = await generateText({ model, prompt: 'Hello!' });
761
+ * ```
584
762
  */
585
- var OpenAICompatibleMetadataAdapter = class {
586
- extract(providerMetadata) {
587
- const meta = providerMetadata?.openai;
588
- if (!meta?.usage) return {};
589
- const usage = meta.usage;
590
- return { usage: {
591
- input: usage.promptTokens ?? 0,
592
- output: usage.completionTokens ?? 0,
593
- total: usage.totalTokens
594
- } };
763
+ function createIntelligence(config) {
764
+ ensureTelemetryRegistered();
765
+ const { agents, logger, pricing, providers } = config;
766
+ const providerCache = /* @__PURE__ */ new Map();
767
+ const modelCache = /* @__PURE__ */ new Map();
768
+ function resolveProvider(providerKey) {
769
+ let provider = providerCache.get(providerKey);
770
+ if (!provider) {
771
+ provider = createProvider(providers[providerKey]);
772
+ providerCache.set(providerKey, provider);
773
+ }
774
+ return provider;
595
775
  }
596
- };
776
+ function buildModel(ref) {
777
+ assertProviderExists(ref.provider, providers);
778
+ const baseModel = resolveProvider(ref.provider).model(ref.model);
779
+ const pricingKey = `${ref.provider}/${ref.model}`;
780
+ return (0, ai.wrapLanguageModel)({
781
+ model: baseModel,
782
+ middleware: [createCostMiddleware({
783
+ modelRef: pricingKey,
784
+ pricing: pricing?.[pricingKey]
785
+ })]
786
+ });
787
+ }
788
+ function buildAgentModel(agentName) {
789
+ const agentConfig = agents[agentName];
790
+ if (!agentConfig) {
791
+ const available = Object.keys(agents).join(", ") || "(none configured)";
792
+ throw new Error(`Unknown agent "${agentName}". Available agents: ${available}.`);
793
+ }
794
+ const primary = buildModel({
795
+ model: agentConfig.model,
796
+ provider: agentConfig.provider
797
+ });
798
+ const composed = agentConfig.fallback ? createFallbackModel({
799
+ fallback: buildModel(agentConfig.fallback),
800
+ logger,
801
+ primary
802
+ }) : primary;
803
+ if (!logger) return composed;
804
+ return (0, ai.wrapLanguageModel)({
805
+ model: composed,
806
+ middleware: [createLoggingMiddleware({ logger })]
807
+ });
808
+ }
809
+ return { model(agentName) {
810
+ let model = modelCache.get(agentName);
811
+ if (!model) {
812
+ model = buildAgentModel(agentName);
813
+ modelCache.set(agentName, model);
814
+ }
815
+ return model;
816
+ } };
817
+ }
597
818
  //#endregion
598
- exports.LangfuseAdapter = LangfuseAdapter;
599
- exports.NoopObservabilityAdapter = NoopObservabilityAdapter;
600
- exports.OpenAICompatibleMetadataAdapter = OpenAICompatibleMetadataAdapter;
601
- exports.OpenRouterMetadataAdapter = OpenRouterMetadataAdapter;
602
- exports.ParseObjectError = ParseObjectError;
603
- exports.classifyError = classifyError;
819
+ exports.createCostMiddleware = createCostMiddleware;
820
+ exports.createFallbackModel = createFallbackModel;
821
+ exports.createGatewayProvider = createGatewayProvider;
822
+ exports.createIntelligence = createIntelligence;
604
823
  exports.createLoggingMiddleware = createLoggingMiddleware;
605
- exports.createObservabilityMiddleware = createObservabilityMiddleware;
606
- exports.createOpenAICompatibleProvider = createOpenAICompatibleProvider;
607
824
  exports.createOpenRouterProvider = createOpenRouterProvider;
608
- exports.createSchemaPrompt = createSchemaPrompt;
609
- exports.generateStructured = generateStructured;
610
- exports.generationFailure = generationFailure;
611
- exports.generationSuccess = generationSuccess;
612
- exports.isFailure = isFailure;
613
- exports.isSuccess = isSuccess;
614
- exports.parseObject = parseObject;
615
- exports.parseText = require_parse_text.parseText;
616
- exports.unwrap = unwrap;
617
- exports.unwrapOr = unwrapOr;
618
- exports.withObservability = withObservability;
825
+ exports.createSchemaInstructionMiddleware = createSchemaInstructionMiddleware;
619
826
 
620
827
  //# sourceMappingURL=index.cjs.map