@jterrazz/intelligence 5.0.0 → 7.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/README.md +239 -217
- package/dist/formatting.cjs +2845 -0
- package/dist/formatting.cjs.map +1 -0
- package/dist/formatting.d.cts +105 -0
- package/dist/formatting.d.ts +105 -0
- package/dist/formatting.js +2819 -0
- package/dist/formatting.js.map +1 -0
- package/dist/index.cjs +709 -475
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +203 -1512
- package/dist/index.d.ts +203 -1512
- package/dist/index.js +705 -458
- package/dist/index.js.map +1 -1
- package/dist/oxlint.cjs +629 -0
- package/dist/oxlint.cjs.map +1 -0
- package/dist/oxlint.d.cts +132 -0
- package/dist/oxlint.d.ts +132 -0
- package/dist/oxlint.js +623 -0
- package/dist/oxlint.js.map +1 -0
- package/package.json +21 -15
- package/dist/parse-text.cjs +0 -57
- package/dist/parse-text.cjs.map +0 -1
- package/dist/parse-text.d.cts +0 -18
- package/dist/parse-text.d.ts +0 -18
- package/dist/parse-text.js +0 -52
- package/dist/parse-text.js.map +0 -1
- package/dist/text.cjs +0 -3
- package/dist/text.d.cts +0 -2
- package/dist/text.d.ts +0 -2
- package/dist/text.js +0 -2
package/dist/index.cjs
CHANGED
|
@@ -1,12 +1,127 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
3
|
-
let langfuse = require("langfuse");
|
|
2
|
+
let _ai_sdk_otel = require("@ai-sdk/otel");
|
|
4
3
|
let ai = require("ai");
|
|
5
|
-
let
|
|
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
|
-
|
|
6
|
+
let _openrouter_ai_sdk_provider = require("@openrouter/ai-sdk-provider");
|
|
7
|
+
//#region src/middleware/agent.middleware.ts
|
|
8
|
+
const AGENT_ATTRIBUTE = "gen_ai.agent.name";
|
|
9
|
+
/**
|
|
10
|
+
* Creates middleware that names the AI SDK's inference span after the agent.
|
|
11
|
+
*
|
|
12
|
+
* The AI SDK names that span `chat <model>` and only puts the agent identity
|
|
13
|
+
* (`gen_ai.agent.name`, from `experimental_telemetry.functionId`) on the
|
|
14
|
+
* parent `invoke_agent` span. Langfuse extracts model, usage and cost from
|
|
15
|
+
* the inference span alone, so a pipeline that forwards only that span would
|
|
16
|
+
* otherwise show every agent as "chat <model>". This runs inside the
|
|
17
|
+
* inference span's context (the AI SDK activates it for the provider call),
|
|
18
|
+
* so the active span is the right one.
|
|
19
|
+
*
|
|
20
|
+
* Never throws: all enrichment is best-effort.
|
|
21
|
+
*/
|
|
22
|
+
function createAgentMiddleware(options) {
|
|
23
|
+
const { agentName } = options;
|
|
24
|
+
const nameActiveSpan = () => {
|
|
25
|
+
try {
|
|
26
|
+
const span = _opentelemetry_api.trace.getActiveSpan();
|
|
27
|
+
if (!span) return;
|
|
28
|
+
span.updateName(agentName);
|
|
29
|
+
span.setAttribute(AGENT_ATTRIBUTE, agentName);
|
|
30
|
+
} catch {}
|
|
31
|
+
};
|
|
32
|
+
return {
|
|
33
|
+
specificationVersion: "v4",
|
|
34
|
+
wrapGenerate: async ({ doGenerate }) => {
|
|
35
|
+
nameActiveSpan();
|
|
36
|
+
return doGenerate();
|
|
37
|
+
},
|
|
38
|
+
wrapStream: async ({ doStream }) => {
|
|
39
|
+
nameActiveSpan();
|
|
40
|
+
return doStream();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/middleware/cost.middleware.ts
|
|
46
|
+
const COST_ATTRIBUTE = "gen_ai.usage.cost";
|
|
47
|
+
function resolveCost(providerMetadata, usage, pricing) {
|
|
48
|
+
const actualCost = providerMetadata?.openrouter?.usage?.cost;
|
|
49
|
+
if (typeof actualCost === "number" && actualCost > 0) return actualCost;
|
|
50
|
+
if (pricing) {
|
|
51
|
+
const inputTokens = usage?.inputTokens?.total ?? 0;
|
|
52
|
+
const outputTokens = usage?.outputTokens?.total ?? 0;
|
|
53
|
+
return inputTokens / 1e6 * pricing.input + outputTokens / 1e6 * pricing.output;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function recordCost(cost) {
|
|
57
|
+
if (cost === void 0) return;
|
|
58
|
+
_opentelemetry_api.trace.getActiveSpan()?.setAttribute(COST_ATTRIBUTE, cost);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Creates middleware that records the USD cost of a generation as
|
|
62
|
+
* `gen_ai.usage.cost` on the active OpenTelemetry span — the AI SDK's own
|
|
63
|
+
* inference span (`gen_ai.operation.name = chat`), which is what Langfuse
|
|
64
|
+
* ingests as a generation.
|
|
65
|
+
*
|
|
66
|
+
* Resolution order:
|
|
67
|
+
* 1. Actual cost reported by the provider (currently: OpenRouter's
|
|
68
|
+
* `providerMetadata.openrouter.usage.cost`).
|
|
69
|
+
* 2. Estimated cost from `pricing` (USD per million input/output tokens),
|
|
70
|
+
* computed from the reported token usage.
|
|
71
|
+
*
|
|
72
|
+
* When neither is available nothing is written: `gen_ai.request.model` is
|
|
73
|
+
* left to the AI SDK (the bare model id), so Langfuse can still price the
|
|
74
|
+
* generation from its own model catalogue. Langfuse prioritizes
|
|
75
|
+
* `gen_ai.usage.cost` over that inference when both exist.
|
|
76
|
+
*
|
|
77
|
+
* Never throws: all enrichment is best-effort.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const model = wrapLanguageModel({
|
|
82
|
+
* model: provider.model('google/gemini-2.5-flash-lite'),
|
|
83
|
+
* middleware: [createCostMiddleware({ pricing: { input: 0.1, output: 0.4 } })],
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
function createCostMiddleware(options = {}) {
|
|
88
|
+
const { pricing } = options;
|
|
89
|
+
return {
|
|
90
|
+
specificationVersion: "v4",
|
|
91
|
+
wrapGenerate: async ({ doGenerate }) => {
|
|
92
|
+
const result = await doGenerate();
|
|
93
|
+
try {
|
|
94
|
+
recordCost(resolveCost(result.providerMetadata, result.usage, pricing));
|
|
95
|
+
} catch {}
|
|
96
|
+
return result;
|
|
97
|
+
},
|
|
98
|
+
wrapStream: async ({ doStream }) => {
|
|
99
|
+
const result = await doStream();
|
|
100
|
+
let finishUsage;
|
|
101
|
+
let finishProviderMetadata;
|
|
102
|
+
const transformStream = new TransformStream({
|
|
103
|
+
transform(chunk, controller) {
|
|
104
|
+
if (chunk.type === "finish") {
|
|
105
|
+
finishUsage = chunk.usage;
|
|
106
|
+
finishProviderMetadata = chunk.providerMetadata;
|
|
107
|
+
}
|
|
108
|
+
controller.enqueue(chunk);
|
|
109
|
+
},
|
|
110
|
+
flush() {
|
|
111
|
+
try {
|
|
112
|
+
recordCost(resolveCost(finishProviderMetadata, finishUsage, pricing));
|
|
113
|
+
} catch {}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
...result,
|
|
118
|
+
stream: result.stream.pipeThrough(transformStream)
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/middleware/logging.middleware.ts
|
|
10
125
|
/**
|
|
11
126
|
* Creates middleware that logs AI SDK requests and responses.
|
|
12
127
|
*/
|
|
@@ -80,542 +195,661 @@ function createLoggingMiddleware(options) {
|
|
|
80
195
|
};
|
|
81
196
|
}
|
|
82
197
|
//#endregion
|
|
83
|
-
//#region
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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: "v4",
|
|
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
|
-
});
|
|
198
|
+
//#region node_modules/@ai-sdk/provider/dist/index.js
|
|
199
|
+
var marker = "vercel.ai.error";
|
|
200
|
+
var symbol = Symbol.for(marker);
|
|
201
|
+
var _a;
|
|
202
|
+
var _b;
|
|
203
|
+
var AISDKError = class _AISDKError extends (_b = Error, _a = symbol, _b) {
|
|
204
|
+
/**
|
|
205
|
+
* Creates an AI SDK Error.
|
|
206
|
+
*
|
|
207
|
+
* @param {Object} params - The parameters for creating the error.
|
|
208
|
+
* @param {string} params.name - The name of the error.
|
|
209
|
+
* @param {string} params.message - The error message.
|
|
210
|
+
* @param {unknown} [params.cause] - The underlying cause of the error.
|
|
211
|
+
*/
|
|
212
|
+
constructor({ name: name15, message, cause }) {
|
|
213
|
+
super(message);
|
|
214
|
+
this[_a] = true;
|
|
215
|
+
this.name = name15;
|
|
216
|
+
this.cause = cause;
|
|
168
217
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
});
|
|
218
|
+
/**
|
|
219
|
+
* Checks if the given error is an AI SDK Error.
|
|
220
|
+
* @param {unknown} error - The error to check.
|
|
221
|
+
* @returns {boolean} True if the error is an AI SDK Error, false otherwise.
|
|
222
|
+
*/
|
|
223
|
+
static isInstance(error) {
|
|
224
|
+
return _AISDKError.hasMarker(error, marker);
|
|
198
225
|
}
|
|
199
|
-
|
|
200
|
-
|
|
226
|
+
static hasMarker(error, marker16) {
|
|
227
|
+
const markerSymbol = Symbol.for(marker16);
|
|
228
|
+
return error != null && typeof error === "object" && markerSymbol in error && typeof error[markerSymbol] === "boolean" && error[markerSymbol] === true;
|
|
201
229
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
230
|
+
};
|
|
231
|
+
var name = "AI_APICallError";
|
|
232
|
+
var marker2 = `vercel.ai.error.${name}`;
|
|
233
|
+
var symbol2 = Symbol.for(marker2);
|
|
234
|
+
var _a2;
|
|
235
|
+
var _b2;
|
|
236
|
+
var APICallError = class extends (_b2 = AISDKError, _a2 = symbol2, _b2) {
|
|
237
|
+
constructor({ message, url, requestBodyValues, statusCode, responseHeaders, responseBody, cause, isRetryable = statusCode != null && (statusCode === 408 || statusCode === 409 || statusCode === 429 || statusCode >= 500), data }) {
|
|
238
|
+
super({
|
|
239
|
+
name,
|
|
240
|
+
message,
|
|
241
|
+
cause
|
|
207
242
|
});
|
|
243
|
+
this[_a2] = true;
|
|
244
|
+
this.url = url;
|
|
245
|
+
this.requestBodyValues = requestBodyValues;
|
|
246
|
+
this.statusCode = statusCode;
|
|
247
|
+
this.responseHeaders = responseHeaders;
|
|
248
|
+
this.responseBody = responseBody;
|
|
249
|
+
this.isRetryable = isRetryable;
|
|
250
|
+
this.data = data;
|
|
251
|
+
}
|
|
252
|
+
static isInstance(error) {
|
|
253
|
+
return AISDKError.hasMarker(error, marker2);
|
|
208
254
|
}
|
|
209
255
|
};
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
function
|
|
228
|
-
return
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
256
|
+
var name2 = "AI_EmptyResponseBodyError";
|
|
257
|
+
var marker3 = `vercel.ai.error.${name2}`;
|
|
258
|
+
var symbol3 = Symbol.for(marker3);
|
|
259
|
+
var _a3;
|
|
260
|
+
var _b3;
|
|
261
|
+
(class extends (_b3 = AISDKError, _a3 = symbol3, _b3) {
|
|
262
|
+
constructor({ message = "Empty response body" } = {}) {
|
|
263
|
+
super({
|
|
264
|
+
name: name2,
|
|
265
|
+
message
|
|
266
|
+
});
|
|
267
|
+
this[_a3] = true;
|
|
268
|
+
}
|
|
269
|
+
static isInstance(error) {
|
|
270
|
+
return AISDKError.hasMarker(error, marker3);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
function getErrorMessage(error) {
|
|
274
|
+
if (error == null) return "unknown error";
|
|
275
|
+
if (typeof error === "string") return error;
|
|
276
|
+
if (error instanceof Error) return error.toString();
|
|
277
|
+
return JSON.stringify(error);
|
|
232
278
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
279
|
+
var name3 = "AI_InvalidArgumentError";
|
|
280
|
+
var marker4 = `vercel.ai.error.${name3}`;
|
|
281
|
+
var symbol4 = Symbol.for(marker4);
|
|
282
|
+
var _a4;
|
|
283
|
+
var _b4;
|
|
284
|
+
(class extends (_b4 = AISDKError, _a4 = symbol4, _b4) {
|
|
285
|
+
constructor({ message, cause, argument }) {
|
|
286
|
+
super({
|
|
287
|
+
name: name3,
|
|
241
288
|
message,
|
|
242
289
|
cause
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
var
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
text
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
290
|
+
});
|
|
291
|
+
this[_a4] = true;
|
|
292
|
+
this.argument = argument;
|
|
293
|
+
}
|
|
294
|
+
static isInstance(error) {
|
|
295
|
+
return AISDKError.hasMarker(error, marker4);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
var name4 = "AI_InvalidPromptError";
|
|
299
|
+
var marker5 = `vercel.ai.error.${name4}`;
|
|
300
|
+
var symbol5 = Symbol.for(marker5);
|
|
301
|
+
var _a5;
|
|
302
|
+
var _b5;
|
|
303
|
+
(class extends (_b5 = AISDKError, _a5 = symbol5, _b5) {
|
|
304
|
+
constructor({ prompt, message, cause }) {
|
|
305
|
+
super({
|
|
306
|
+
name: name4,
|
|
307
|
+
message: `Invalid prompt: ${message}`,
|
|
308
|
+
cause
|
|
309
|
+
});
|
|
310
|
+
this[_a5] = true;
|
|
311
|
+
this.prompt = prompt;
|
|
312
|
+
}
|
|
313
|
+
static isInstance(error) {
|
|
314
|
+
return AISDKError.hasMarker(error, marker5);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
var name5 = "AI_InvalidResponseDataError";
|
|
318
|
+
var marker6 = `vercel.ai.error.${name5}`;
|
|
319
|
+
var symbol6 = Symbol.for(marker6);
|
|
320
|
+
var _a6;
|
|
321
|
+
var _b6;
|
|
322
|
+
(class extends (_b6 = AISDKError, _a6 = symbol6, _b6) {
|
|
323
|
+
constructor({ data, message = `Invalid response data: ${JSON.stringify(data)}.` }) {
|
|
324
|
+
super({
|
|
325
|
+
name: name5,
|
|
326
|
+
message
|
|
327
|
+
});
|
|
328
|
+
this[_a6] = true;
|
|
329
|
+
this.data = data;
|
|
330
|
+
}
|
|
331
|
+
static isInstance(error) {
|
|
332
|
+
return AISDKError.hasMarker(error, marker6);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
var name6 = "AI_JSONParseError";
|
|
336
|
+
var marker7 = `vercel.ai.error.${name6}`;
|
|
337
|
+
var symbol7 = Symbol.for(marker7);
|
|
338
|
+
var _a7;
|
|
339
|
+
var _b7;
|
|
340
|
+
(class extends (_b7 = AISDKError, _a7 = symbol7, _b7) {
|
|
341
|
+
constructor({ text, cause }) {
|
|
342
|
+
super({
|
|
343
|
+
name: name6,
|
|
344
|
+
message: `JSON parsing failed: Text: ${text}.
|
|
345
|
+
Error message: ${getErrorMessage(cause)}`,
|
|
346
|
+
cause
|
|
347
|
+
});
|
|
348
|
+
this[_a7] = true;
|
|
298
349
|
this.text = text;
|
|
299
350
|
}
|
|
300
|
-
|
|
301
|
-
|
|
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);
|
|
351
|
+
static isInstance(error) {
|
|
352
|
+
return AISDKError.hasMarker(error, marker7);
|
|
317
353
|
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
354
|
+
});
|
|
355
|
+
var name7 = "AI_LoadAPIKeyError";
|
|
356
|
+
var marker8 = `vercel.ai.error.${name7}`;
|
|
357
|
+
var symbol8 = Symbol.for(marker8);
|
|
358
|
+
var _a8;
|
|
359
|
+
var _b8;
|
|
360
|
+
(class extends (_b8 = AISDKError, _a8 = symbol8, _b8) {
|
|
361
|
+
constructor({ message }) {
|
|
362
|
+
super({
|
|
363
|
+
name: name7,
|
|
364
|
+
message
|
|
365
|
+
});
|
|
366
|
+
this[_a8] = true;
|
|
328
367
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const trimmed = text.trim();
|
|
332
|
-
try {
|
|
333
|
-
return convertToPrimitive(JSON.parse(trimmed), schema);
|
|
334
|
-
} catch {
|
|
335
|
-
return convertToPrimitive(trimmed, schema);
|
|
368
|
+
static isInstance(error) {
|
|
369
|
+
return AISDKError.hasMarker(error, marker8);
|
|
336
370
|
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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;
|
|
371
|
+
});
|
|
372
|
+
var name8 = "AI_LoadSettingError";
|
|
373
|
+
var marker9 = `vercel.ai.error.${name8}`;
|
|
374
|
+
var symbol9 = Symbol.for(marker9);
|
|
375
|
+
var _a9;
|
|
376
|
+
var _b9;
|
|
377
|
+
(class extends (_b9 = AISDKError, _a9 = symbol9, _b9) {
|
|
378
|
+
constructor({ message }) {
|
|
379
|
+
super({
|
|
380
|
+
name: name8,
|
|
381
|
+
message
|
|
382
|
+
});
|
|
383
|
+
this[_a9] = true;
|
|
359
384
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
385
|
+
static isInstance(error) {
|
|
386
|
+
return AISDKError.hasMarker(error, marker9);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
var name9 = "AI_NoContentGeneratedError";
|
|
390
|
+
var marker10 = `vercel.ai.error.${name9}`;
|
|
391
|
+
var symbol10 = Symbol.for(marker10);
|
|
392
|
+
var _a10;
|
|
393
|
+
var _b10;
|
|
394
|
+
(class extends (_b10 = AISDKError, _a10 = symbol10, _b10) {
|
|
395
|
+
constructor({ message = "No content generated." } = {}) {
|
|
396
|
+
super({
|
|
397
|
+
name: name9,
|
|
398
|
+
message
|
|
399
|
+
});
|
|
400
|
+
this[_a10] = true;
|
|
401
|
+
}
|
|
402
|
+
static isInstance(error) {
|
|
403
|
+
return AISDKError.hasMarker(error, marker10);
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
var name10 = "AI_NoSuchModelError";
|
|
407
|
+
var marker11 = `vercel.ai.error.${name10}`;
|
|
408
|
+
var symbol11 = Symbol.for(marker11);
|
|
409
|
+
var _a11;
|
|
410
|
+
var _b11;
|
|
411
|
+
(class extends (_b11 = AISDKError, _a11 = symbol11, _b11) {
|
|
412
|
+
constructor({ errorName = name10, modelId, modelType, message = `No such ${modelType}: ${modelId}` }) {
|
|
413
|
+
super({
|
|
414
|
+
name: errorName,
|
|
415
|
+
message
|
|
416
|
+
});
|
|
417
|
+
this[_a11] = true;
|
|
418
|
+
this.modelId = modelId;
|
|
419
|
+
this.modelType = modelType;
|
|
420
|
+
}
|
|
421
|
+
static isInstance(error) {
|
|
422
|
+
return AISDKError.hasMarker(error, marker11);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
var name11 = "AI_NoSuchProviderReferenceError";
|
|
426
|
+
var marker12 = `vercel.ai.error.${name11}`;
|
|
427
|
+
var symbol12 = Symbol.for(marker12);
|
|
428
|
+
var _a12;
|
|
429
|
+
var _b12;
|
|
430
|
+
(class extends (_b12 = AISDKError, _a12 = symbol12, _b12) {
|
|
431
|
+
constructor({ provider, reference, message = `No provider reference found for provider '${provider}'. Available providers: ${Object.keys(reference).join(", ")}` }) {
|
|
432
|
+
super({
|
|
433
|
+
name: name11,
|
|
434
|
+
message
|
|
435
|
+
});
|
|
436
|
+
this[_a12] = true;
|
|
437
|
+
this.provider = provider;
|
|
438
|
+
this.reference = reference;
|
|
439
|
+
}
|
|
440
|
+
static isInstance(error) {
|
|
441
|
+
return AISDKError.hasMarker(error, marker12);
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
var name12 = "AI_TooManyEmbeddingValuesForCallError";
|
|
445
|
+
var marker13 = `vercel.ai.error.${name12}`;
|
|
446
|
+
var symbol13 = Symbol.for(marker13);
|
|
447
|
+
var _a13;
|
|
448
|
+
var _b13;
|
|
449
|
+
(class extends (_b13 = AISDKError, _a13 = symbol13, _b13) {
|
|
450
|
+
constructor(options) {
|
|
451
|
+
super({
|
|
452
|
+
name: name12,
|
|
453
|
+
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.`
|
|
454
|
+
});
|
|
455
|
+
this[_a13] = true;
|
|
456
|
+
this.provider = options.provider;
|
|
457
|
+
this.modelId = options.modelId;
|
|
458
|
+
this.maxEmbeddingsPerCall = options.maxEmbeddingsPerCall;
|
|
459
|
+
this.values = options.values;
|
|
460
|
+
}
|
|
461
|
+
static isInstance(error) {
|
|
462
|
+
return AISDKError.hasMarker(error, marker13);
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
var name13 = "AI_TypeValidationError";
|
|
466
|
+
var marker14 = `vercel.ai.error.${name13}`;
|
|
467
|
+
var symbol14 = Symbol.for(marker14);
|
|
468
|
+
var _a14;
|
|
469
|
+
var _b14;
|
|
470
|
+
(class _TypeValidationError extends (_b14 = AISDKError, _a14 = symbol14, _b14) {
|
|
471
|
+
constructor({ value, cause, context }) {
|
|
472
|
+
let contextPrefix = "Type validation failed";
|
|
473
|
+
if (context == null ? void 0 : context.field) contextPrefix += ` for ${context.field}`;
|
|
474
|
+
if ((context == null ? void 0 : context.entityName) || (context == null ? void 0 : context.entityId)) {
|
|
475
|
+
contextPrefix += " (";
|
|
476
|
+
const parts = [];
|
|
477
|
+
if (context.entityName) parts.push(context.entityName);
|
|
478
|
+
if (context.entityId) parts.push(`id: "${context.entityId}"`);
|
|
479
|
+
contextPrefix += parts.join(", ");
|
|
480
|
+
contextPrefix += ")";
|
|
382
481
|
}
|
|
482
|
+
super({
|
|
483
|
+
name: name13,
|
|
484
|
+
message: `${contextPrefix}: Value: ${JSON.stringify(value)}.
|
|
485
|
+
Error message: ${getErrorMessage(cause)}`,
|
|
486
|
+
cause
|
|
487
|
+
});
|
|
488
|
+
this[_a14] = true;
|
|
489
|
+
this.value = value;
|
|
490
|
+
this.context = context;
|
|
383
491
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
492
|
+
static isInstance(error) {
|
|
493
|
+
return AISDKError.hasMarker(error, marker14);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Wraps an error into a TypeValidationError.
|
|
497
|
+
* If the cause is already a TypeValidationError with the same value and context, it returns the cause.
|
|
498
|
+
* Otherwise, it creates a new TypeValidationError.
|
|
499
|
+
*
|
|
500
|
+
* @param {Object} params - The parameters for wrapping the error.
|
|
501
|
+
* @param {unknown} params.value - The value that failed validation.
|
|
502
|
+
* @param {unknown} params.cause - The original error or cause of the validation failure.
|
|
503
|
+
* @param {TypeValidationContext} params.context - Optional context about what is being validated.
|
|
504
|
+
* @returns {TypeValidationError} A TypeValidationError instance.
|
|
505
|
+
*/
|
|
506
|
+
static wrap({ value, cause, context }) {
|
|
507
|
+
var _a16, _b16, _c;
|
|
508
|
+
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;
|
|
509
|
+
return new _TypeValidationError({
|
|
510
|
+
value,
|
|
511
|
+
cause,
|
|
512
|
+
context
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
var name14 = "AI_UnsupportedFunctionalityError";
|
|
517
|
+
var marker15 = `vercel.ai.error.${name14}`;
|
|
518
|
+
var symbol15 = Symbol.for(marker15);
|
|
519
|
+
var _a15;
|
|
520
|
+
var _b15;
|
|
521
|
+
(class extends (_b15 = AISDKError, _a15 = symbol15, _b15) {
|
|
522
|
+
constructor({ functionality, message = `'${functionality}' functionality not supported.` }) {
|
|
523
|
+
super({
|
|
524
|
+
name: name14,
|
|
525
|
+
message
|
|
526
|
+
});
|
|
527
|
+
this[_a15] = true;
|
|
528
|
+
this.functionality = functionality;
|
|
529
|
+
}
|
|
530
|
+
static isInstance(error) {
|
|
531
|
+
return AISDKError.hasMarker(error, marker15);
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
//#endregion
|
|
535
|
+
//#region src/model/fallback-model.ts
|
|
536
|
+
const RETRYABLE_MESSAGE_PATTERNS = [
|
|
537
|
+
/ECONNREFUSED/i,
|
|
538
|
+
/ECONNRESET/i,
|
|
539
|
+
/ETIMEDOUT/i,
|
|
540
|
+
/EAI_AGAIN/i,
|
|
541
|
+
/ENOTFOUND/i,
|
|
542
|
+
/timed?\s*out/i,
|
|
543
|
+
/network/i,
|
|
544
|
+
/fetch failed/i
|
|
545
|
+
];
|
|
546
|
+
function isRetryableError(error) {
|
|
547
|
+
if (APICallError.isInstance(error)) {
|
|
548
|
+
if (typeof error.statusCode === "number") return error.statusCode === 429 || error.statusCode >= 500;
|
|
549
|
+
return error.isRetryable;
|
|
550
|
+
}
|
|
551
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
552
|
+
return RETRYABLE_MESSAGE_PATTERNS.some((pattern) => pattern.test(message));
|
|
404
553
|
}
|
|
405
554
|
/**
|
|
406
|
-
*
|
|
555
|
+
* Creates a `LanguageModelV4` that transparently falls back to a secondary
|
|
556
|
+
* model when the primary model fails with a retryable error (HTTP 429, 5xx,
|
|
557
|
+
* network errors/timeouts). Non-retryable errors (400s, validation, abort)
|
|
558
|
+
* propagate unchanged.
|
|
407
559
|
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
* - JSON embedded in prose text
|
|
411
|
-
* - Malformed JSON (auto-repaired)
|
|
412
|
-
* - Escaped unicode and special characters
|
|
413
|
-
*
|
|
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
|
|
560
|
+
* This is a model, not a middleware — middleware cannot switch the
|
|
561
|
+
* underlying model, only transform a single model's behavior.
|
|
418
562
|
*
|
|
419
563
|
* @example
|
|
420
564
|
* ```ts
|
|
421
|
-
* const
|
|
422
|
-
*
|
|
423
|
-
*
|
|
565
|
+
* const model = createFallbackModel({
|
|
566
|
+
* primary: provider.model('anthropic/claude-sonnet-4'),
|
|
567
|
+
* fallback: provider.model('openai/gpt-4o-mini'),
|
|
568
|
+
* logger,
|
|
569
|
+
* });
|
|
424
570
|
* ```
|
|
425
571
|
*/
|
|
426
|
-
function
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
572
|
+
function createFallbackModel(options) {
|
|
573
|
+
const { primary, fallback, logger } = options;
|
|
574
|
+
const primaryModel = primary;
|
|
575
|
+
const fallbackModel = fallback;
|
|
576
|
+
function logFallback(error) {
|
|
577
|
+
logger?.warn("ai.fallback.triggered", {
|
|
578
|
+
modelIds: [primaryModel.modelId, fallbackModel.modelId],
|
|
579
|
+
error: error instanceof Error ? error.message : String(error)
|
|
580
|
+
});
|
|
434
581
|
}
|
|
582
|
+
return {
|
|
583
|
+
specificationVersion: "v4",
|
|
584
|
+
provider: primaryModel.provider,
|
|
585
|
+
modelId: primaryModel.modelId,
|
|
586
|
+
supportedUrls: primaryModel.supportedUrls,
|
|
587
|
+
async doGenerate(callOptions) {
|
|
588
|
+
try {
|
|
589
|
+
return await primaryModel.doGenerate(callOptions);
|
|
590
|
+
} catch (error) {
|
|
591
|
+
if (!isRetryableError(error)) throw error;
|
|
592
|
+
logFallback(error);
|
|
593
|
+
return fallbackModel.doGenerate(callOptions);
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
async doStream(callOptions) {
|
|
597
|
+
try {
|
|
598
|
+
return await primaryModel.doStream(callOptions);
|
|
599
|
+
} catch (error) {
|
|
600
|
+
if (!isRetryableError(error)) throw error;
|
|
601
|
+
logFallback(error);
|
|
602
|
+
return fallbackModel.doStream(callOptions);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
};
|
|
435
606
|
}
|
|
436
607
|
//#endregion
|
|
437
|
-
//#region src/
|
|
608
|
+
//#region src/middleware/schema-instruction.middleware.ts
|
|
609
|
+
function buildInstruction(responseFormat) {
|
|
610
|
+
if (responseFormat?.type !== "json") return "";
|
|
611
|
+
const lines = ["You must respond with valid JSON only — no prose, no markdown code fences."];
|
|
612
|
+
if (responseFormat.schema) lines.push("The JSON must strictly conform to this JSON schema:", JSON.stringify(responseFormat.schema));
|
|
613
|
+
return lines.join("\n");
|
|
614
|
+
}
|
|
615
|
+
function appendToLastUserMessage(prompt, instruction) {
|
|
616
|
+
const lastUserIndex = prompt.findLastIndex((message) => message.role === "user");
|
|
617
|
+
if (lastUserIndex === -1) return [...prompt, {
|
|
618
|
+
content: [{
|
|
619
|
+
text: instruction,
|
|
620
|
+
type: "text"
|
|
621
|
+
}],
|
|
622
|
+
role: "user"
|
|
623
|
+
}];
|
|
624
|
+
return prompt.map((message, index) => {
|
|
625
|
+
if (index !== lastUserIndex || message.role !== "user") return message;
|
|
626
|
+
const lastTextIndex = message.content.findLastIndex((part) => part.type === "text");
|
|
627
|
+
if (lastTextIndex === -1) return {
|
|
628
|
+
...message,
|
|
629
|
+
content: [...message.content, {
|
|
630
|
+
text: instruction,
|
|
631
|
+
type: "text"
|
|
632
|
+
}]
|
|
633
|
+
};
|
|
634
|
+
return {
|
|
635
|
+
...message,
|
|
636
|
+
content: message.content.map((part, partIndex) => {
|
|
637
|
+
if (partIndex !== lastTextIndex || part.type !== "text") return part;
|
|
638
|
+
return {
|
|
639
|
+
...part,
|
|
640
|
+
text: `${part.text}\n\n${instruction}`
|
|
641
|
+
};
|
|
642
|
+
})
|
|
643
|
+
};
|
|
644
|
+
});
|
|
645
|
+
}
|
|
438
646
|
/**
|
|
439
|
-
*
|
|
440
|
-
*
|
|
647
|
+
* Creates middleware that injects the JSON schema of a structured-output
|
|
648
|
+
* request into the last user message.
|
|
649
|
+
*
|
|
650
|
+
* Some gateways silently drop the native structured-output field when
|
|
651
|
+
* translating to their backend, so the model never sees the schema and
|
|
652
|
+
* answers in free prose. This middleware re-states the schema as part of the
|
|
653
|
+
* user message so structured output works regardless. It targets the user
|
|
654
|
+
* message rather than a system message because gateways backed by cloaked
|
|
655
|
+
* CLI agents bury injected system messages under their own persona prompt and
|
|
656
|
+
* ignore them. The original `responseFormat` is left untouched: backends that
|
|
657
|
+
* honor it get the native signal too.
|
|
658
|
+
*
|
|
659
|
+
* No-op for text generations (no `responseFormat`, or `type: 'text'`).
|
|
441
660
|
*/
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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);
|
|
661
|
+
function createSchemaInstructionMiddleware() {
|
|
662
|
+
return {
|
|
663
|
+
specificationVersion: "v4",
|
|
664
|
+
transformParams: ({ params }) => {
|
|
665
|
+
const instruction = buildInstruction(params.responseFormat);
|
|
666
|
+
if (!instruction) return Promise.resolve(params);
|
|
667
|
+
return Promise.resolve({
|
|
668
|
+
...params,
|
|
669
|
+
prompt: appendToLastUserMessage(params.prompt, instruction)
|
|
670
|
+
});
|
|
460
671
|
}
|
|
461
|
-
}
|
|
462
|
-
return generationFailure(classifyError(error), error instanceof Error ? error.message : "Unknown error", error);
|
|
463
|
-
}
|
|
672
|
+
};
|
|
464
673
|
}
|
|
465
674
|
//#endregion
|
|
466
|
-
//#region src/
|
|
675
|
+
//#region src/provider/gateway.provider.ts
|
|
467
676
|
/**
|
|
468
|
-
* Creates a
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
* Use this with `generateText` when the provider doesn't support native
|
|
472
|
-
* structured outputs, then parse the response with `parseObject`.
|
|
677
|
+
* Creates a provider for gateways exposing a chat-completions API — any API
|
|
678
|
+
* implementing the OpenAI chat completions spec.
|
|
473
679
|
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
680
|
+
* Every model returned is automatically wrapped with two safety nets for
|
|
681
|
+
* gateways that don't support native structured output:
|
|
682
|
+
* - `createSchemaInstructionMiddleware` injects the JSON schema into the
|
|
683
|
+
* system prompt (some gateways silently drop `response_format`);
|
|
684
|
+
* - `extractJsonMiddleware` strips markdown code fences from JSON responses.
|
|
476
685
|
*
|
|
477
686
|
* @example
|
|
478
687
|
* ```ts
|
|
479
|
-
*
|
|
480
|
-
*
|
|
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
|
-
* });
|
|
688
|
+
* const provider = createGatewayProvider({ baseURL: 'https://gateway.example.com/v1' });
|
|
689
|
+
* const model = provider.model('gpt-4o-mini');
|
|
489
690
|
*
|
|
490
|
-
* const
|
|
691
|
+
* const { text } = await generateText({ model, prompt: 'Hello!' });
|
|
491
692
|
* ```
|
|
492
693
|
*/
|
|
493
|
-
function
|
|
494
|
-
const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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>`;
|
|
694
|
+
function createGatewayProvider(config) {
|
|
695
|
+
const openai = (0, _ai_sdk_openai.createOpenAI)({
|
|
696
|
+
apiKey: config.apiKey,
|
|
697
|
+
baseURL: config.baseURL
|
|
698
|
+
});
|
|
699
|
+
return { model(id) {
|
|
700
|
+
return (0, ai.wrapLanguageModel)({
|
|
701
|
+
model: openai.chat(id),
|
|
702
|
+
middleware: [createSchemaInstructionMiddleware(), (0, ai.extractJsonMiddleware)()]
|
|
703
|
+
});
|
|
704
|
+
} };
|
|
519
705
|
}
|
|
520
706
|
//#endregion
|
|
521
707
|
//#region src/provider/openrouter.provider.ts
|
|
522
708
|
/**
|
|
523
709
|
* Creates an OpenRouter provider for AI SDK models.
|
|
524
710
|
*
|
|
711
|
+
* Per-call options (reasoning effort, max tokens, etc.) are no longer
|
|
712
|
+
* configured here — pass them at the call site via `providerOptions.openrouter`
|
|
713
|
+
* on `generateText`/`streamText`.
|
|
714
|
+
*
|
|
525
715
|
* @example
|
|
526
716
|
* ```ts
|
|
527
717
|
* const provider = createOpenRouterProvider({ apiKey: process.env.OPENROUTER_API_KEY });
|
|
528
718
|
* const model = provider.model('anthropic/claude-sonnet-4-20250514');
|
|
529
719
|
*
|
|
530
|
-
* const { text } = await generateText({
|
|
720
|
+
* const { text } = await generateText({
|
|
721
|
+
* model,
|
|
722
|
+
* prompt: 'Hello!',
|
|
723
|
+
* providerOptions: { openrouter: { reasoning: { effort: 'high' } } },
|
|
724
|
+
* });
|
|
531
725
|
* ```
|
|
532
726
|
*/
|
|
533
727
|
function createOpenRouterProvider(config) {
|
|
534
|
-
const openrouter = (0, _openrouter_ai_sdk_provider.createOpenRouter)({
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
728
|
+
const openrouter = (0, _openrouter_ai_sdk_provider.createOpenRouter)({
|
|
729
|
+
apiKey: config.apiKey,
|
|
730
|
+
appName: config.metadata?.application,
|
|
731
|
+
appUrl: config.metadata?.website
|
|
732
|
+
});
|
|
733
|
+
return { model(id) {
|
|
734
|
+
return openrouter(id);
|
|
540
735
|
} };
|
|
541
736
|
}
|
|
542
737
|
//#endregion
|
|
543
|
-
//#region src/
|
|
738
|
+
//#region src/factory/create-intelligence.ts
|
|
739
|
+
let telemetryRegistered = false;
|
|
544
740
|
/**
|
|
545
|
-
*
|
|
741
|
+
* Registers the AI SDK OpenTelemetry integration, once per process. Best
|
|
742
|
+
* effort — if the host app has no OTel SDK configured, `@ai-sdk/otel` spans
|
|
743
|
+
* are simply dropped rather than throwing.
|
|
546
744
|
*/
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
cacheRead: usage.promptTokensDetails?.cachedTokens
|
|
559
|
-
},
|
|
560
|
-
cost: usage.cost !== void 0 ? { total: usage.cost } : void 0
|
|
561
|
-
};
|
|
745
|
+
function ensureTelemetryRegistered() {
|
|
746
|
+
if (telemetryRegistered) return;
|
|
747
|
+
telemetryRegistered = true;
|
|
748
|
+
try {
|
|
749
|
+
(0, ai.registerTelemetry)(new _ai_sdk_otel.OpenTelemetry());
|
|
750
|
+
} catch {}
|
|
751
|
+
}
|
|
752
|
+
function createProvider(config) {
|
|
753
|
+
switch (config.type) {
|
|
754
|
+
case "gateway": return createGatewayProvider(config);
|
|
755
|
+
case "openrouter": return createOpenRouterProvider(config);
|
|
562
756
|
}
|
|
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
|
-
const modelName = config.modelMapping?.[name] ?? name;
|
|
577
|
-
return openai(modelName);
|
|
578
|
-
} };
|
|
579
757
|
}
|
|
580
|
-
|
|
581
|
-
|
|
758
|
+
function assertProviderExists(providerKey, providers) {
|
|
759
|
+
if (providers[providerKey]) return;
|
|
760
|
+
const available = Object.keys(providers).join(", ") || "(none configured)";
|
|
761
|
+
throw new Error(`Unknown provider "${providerKey}". Available providers: ${available}.`);
|
|
762
|
+
}
|
|
582
763
|
/**
|
|
583
|
-
*
|
|
584
|
-
*
|
|
764
|
+
* Creates a composition root over AI SDK v7: resolves each agent's
|
|
765
|
+
* `provider`/`model` pair into a fully instrumented `LanguageModel` — cost
|
|
766
|
+
* tracking, optional fallback, and optional logging — cached per agent name.
|
|
767
|
+
*
|
|
768
|
+
* Registers the `@ai-sdk/otel` telemetry integration on first use (idempotent,
|
|
769
|
+
* best-effort). The host app is expected to have already registered an
|
|
770
|
+
* OpenTelemetry Node SDK (e.g. via `@jterrazz/telemetry`).
|
|
771
|
+
*
|
|
772
|
+
* @example
|
|
773
|
+
* ```ts
|
|
774
|
+
* const intelligence = createIntelligence({
|
|
775
|
+
* providers: {
|
|
776
|
+
* openrouter: { type: 'openrouter', apiKey: process.env.OPENROUTER_API_KEY },
|
|
777
|
+
* },
|
|
778
|
+
* agents: {
|
|
779
|
+
* summarizer: {
|
|
780
|
+
* provider: 'openrouter',
|
|
781
|
+
* model: 'google/gemini-2.5-flash-lite',
|
|
782
|
+
* fallback: { provider: 'openrouter', model: 'openai/gpt-4o-mini' },
|
|
783
|
+
* },
|
|
784
|
+
* },
|
|
785
|
+
* pricing: {
|
|
786
|
+
* 'openrouter/google/gemini-2.5-flash-lite': { input: 0.1, output: 0.4 },
|
|
787
|
+
* },
|
|
788
|
+
* logger,
|
|
789
|
+
* });
|
|
790
|
+
*
|
|
791
|
+
* const model = intelligence.model('summarizer');
|
|
792
|
+
* const { text } = await generateText({ model, prompt: 'Hello!' });
|
|
793
|
+
* ```
|
|
585
794
|
*/
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
795
|
+
function createIntelligence(config) {
|
|
796
|
+
ensureTelemetryRegistered();
|
|
797
|
+
const { agents, logger, pricing, providers } = config;
|
|
798
|
+
const providerCache = /* @__PURE__ */ new Map();
|
|
799
|
+
const modelCache = /* @__PURE__ */ new Map();
|
|
800
|
+
function resolveProvider(providerKey) {
|
|
801
|
+
let provider = providerCache.get(providerKey);
|
|
802
|
+
if (!provider) {
|
|
803
|
+
provider = createProvider(providers[providerKey]);
|
|
804
|
+
providerCache.set(providerKey, provider);
|
|
805
|
+
}
|
|
806
|
+
return provider;
|
|
596
807
|
}
|
|
597
|
-
|
|
808
|
+
function buildModel(ref, agentName) {
|
|
809
|
+
assertProviderExists(ref.provider, providers);
|
|
810
|
+
return (0, ai.wrapLanguageModel)({
|
|
811
|
+
model: resolveProvider(ref.provider).model(ref.model),
|
|
812
|
+
middleware: [createAgentMiddleware({ agentName }), createCostMiddleware({ pricing: pricing?.[`${ref.provider}/${ref.model}`] })]
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
function buildAgentModel(agentName) {
|
|
816
|
+
const agentConfig = agents[agentName];
|
|
817
|
+
if (!agentConfig) {
|
|
818
|
+
const available = Object.keys(agents).join(", ") || "(none configured)";
|
|
819
|
+
throw new Error(`Unknown agent "${agentName}". Available agents: ${available}.`);
|
|
820
|
+
}
|
|
821
|
+
const primary = buildModel({
|
|
822
|
+
model: agentConfig.model,
|
|
823
|
+
provider: agentConfig.provider
|
|
824
|
+
}, agentName);
|
|
825
|
+
const composed = agentConfig.fallback ? createFallbackModel({
|
|
826
|
+
fallback: buildModel(agentConfig.fallback, agentName),
|
|
827
|
+
logger,
|
|
828
|
+
primary
|
|
829
|
+
}) : primary;
|
|
830
|
+
if (!logger) return composed;
|
|
831
|
+
return (0, ai.wrapLanguageModel)({
|
|
832
|
+
model: composed,
|
|
833
|
+
middleware: [createLoggingMiddleware({ logger })]
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
return { model(agentName) {
|
|
837
|
+
let model = modelCache.get(agentName);
|
|
838
|
+
if (!model) {
|
|
839
|
+
model = buildAgentModel(agentName);
|
|
840
|
+
modelCache.set(agentName, model);
|
|
841
|
+
}
|
|
842
|
+
return model;
|
|
843
|
+
} };
|
|
844
|
+
}
|
|
598
845
|
//#endregion
|
|
599
|
-
exports.
|
|
600
|
-
exports.
|
|
601
|
-
exports.
|
|
602
|
-
exports.
|
|
603
|
-
exports.
|
|
604
|
-
exports.classifyError = classifyError;
|
|
846
|
+
exports.createAgentMiddleware = createAgentMiddleware;
|
|
847
|
+
exports.createCostMiddleware = createCostMiddleware;
|
|
848
|
+
exports.createFallbackModel = createFallbackModel;
|
|
849
|
+
exports.createGatewayProvider = createGatewayProvider;
|
|
850
|
+
exports.createIntelligence = createIntelligence;
|
|
605
851
|
exports.createLoggingMiddleware = createLoggingMiddleware;
|
|
606
|
-
exports.createObservabilityMiddleware = createObservabilityMiddleware;
|
|
607
|
-
exports.createOpenAICompatibleProvider = createOpenAICompatibleProvider;
|
|
608
852
|
exports.createOpenRouterProvider = createOpenRouterProvider;
|
|
609
|
-
exports.
|
|
610
|
-
exports.generateStructured = generateStructured;
|
|
611
|
-
exports.generationFailure = generationFailure;
|
|
612
|
-
exports.generationSuccess = generationSuccess;
|
|
613
|
-
exports.isFailure = isFailure;
|
|
614
|
-
exports.isSuccess = isSuccess;
|
|
615
|
-
exports.parseObject = parseObject;
|
|
616
|
-
exports.parseText = require_parse_text.parseText;
|
|
617
|
-
exports.unwrap = unwrap;
|
|
618
|
-
exports.unwrapOr = unwrapOr;
|
|
619
|
-
exports.withObservability = withObservability;
|
|
853
|
+
exports.createSchemaInstructionMiddleware = createSchemaInstructionMiddleware;
|
|
620
854
|
|
|
621
855
|
//# sourceMappingURL=index.cjs.map
|