@jterrazz/intelligence 3.0.1 → 4.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 +259 -55
- package/dist/index.cjs +594 -783
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +352 -5
- package/dist/index.js +620 -5
- package/dist/index.js.map +1 -1
- package/package.json +26 -20
- package/dist/middleware/__tests__/logging.middleware.test.d.ts +0 -1
- package/dist/middleware/__tests__/logging.middleware.test.js +0 -390
- package/dist/middleware/__tests__/logging.middleware.test.js.map +0 -1
- package/dist/middleware/logging.middleware.d.ts +0 -21
- package/dist/middleware/logging.middleware.js +0 -296
- package/dist/middleware/logging.middleware.js.map +0 -1
- package/dist/parsing/__tests__/create-schema-prompt.test.d.ts +0 -1
- package/dist/parsing/__tests__/create-schema-prompt.test.js +0 -53
- package/dist/parsing/__tests__/create-schema-prompt.test.js.map +0 -1
- package/dist/parsing/__tests__/parse-object.test.d.ts +0 -1
- package/dist/parsing/__tests__/parse-object.test.js +0 -193
- package/dist/parsing/__tests__/parse-object.test.js.map +0 -1
- package/dist/parsing/__tests__/parse-text.test.d.ts +0 -1
- package/dist/parsing/__tests__/parse-text.test.js +0 -167
- package/dist/parsing/__tests__/parse-text.test.js.map +0 -1
- package/dist/parsing/create-schema-prompt.d.ts +0 -28
- package/dist/parsing/create-schema-prompt.js +0 -42
- package/dist/parsing/create-schema-prompt.js.map +0 -1
- package/dist/parsing/parse-object.d.ts +0 -33
- package/dist/parsing/parse-object.js +0 -360
- package/dist/parsing/parse-object.js.map +0 -1
- package/dist/parsing/parse-text.d.ts +0 -14
- package/dist/parsing/parse-text.js +0 -76
- package/dist/parsing/parse-text.js.map +0 -1
- package/dist/providers/openrouter.provider.d.ts +0 -36
- package/dist/providers/openrouter.provider.js +0 -58
- package/dist/providers/openrouter.provider.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,829 +1,640 @@
|
|
|
1
|
-
|
|
1
|
+
let langfuse = require("langfuse");
|
|
2
|
+
let ai = require("ai");
|
|
3
|
+
let jsonrepair = require("jsonrepair");
|
|
4
|
+
let zod_v4 = require("zod/v4");
|
|
5
|
+
let _openrouter_ai_sdk_provider = require("@openrouter/ai-sdk-provider");
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
keys.push.apply(keys, symbols);
|
|
76
|
-
}
|
|
77
|
-
return keys;
|
|
78
|
-
}
|
|
79
|
-
function _object_spread_props(target, source) {
|
|
80
|
-
source = source != null ? source : {};
|
|
81
|
-
if (Object.getOwnPropertyDescriptors) {
|
|
82
|
-
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
83
|
-
} else {
|
|
84
|
-
ownKeys(Object(source)).forEach(function(key) {
|
|
85
|
-
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
return target;
|
|
7
|
+
//#region src/logging/logging.middleware.ts
|
|
8
|
+
/**
|
|
9
|
+
* Creates middleware that logs AI SDK requests and responses.
|
|
10
|
+
*/
|
|
11
|
+
function createLoggingMiddleware(options) {
|
|
12
|
+
const { logger, include = {} } = options;
|
|
13
|
+
const { params: includeParams, content: includeContent, usage: includeUsage = true } = include;
|
|
14
|
+
return {
|
|
15
|
+
specificationVersion: "v3",
|
|
16
|
+
wrapGenerate: async ({ doGenerate, params, model }) => {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
logger.debug("ai.generate.start", {
|
|
19
|
+
model: model.modelId,
|
|
20
|
+
...includeParams && { params }
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
const result = await doGenerate();
|
|
24
|
+
const textContent = result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
25
|
+
logger.debug("ai.generate.complete", {
|
|
26
|
+
model: model.modelId,
|
|
27
|
+
durationMs: Date.now() - startTime,
|
|
28
|
+
finishReason: result.finishReason,
|
|
29
|
+
...includeUsage && { usage: result.usage },
|
|
30
|
+
...includeContent && { content: textContent }
|
|
31
|
+
});
|
|
32
|
+
return result;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
logger.error("ai.generate.error", {
|
|
35
|
+
model: model.modelId,
|
|
36
|
+
durationMs: Date.now() - startTime,
|
|
37
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
38
|
+
});
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
wrapStream: async ({ doStream, params, model }) => {
|
|
43
|
+
const startTime = Date.now();
|
|
44
|
+
logger.debug("ai.stream.start", {
|
|
45
|
+
model: model.modelId,
|
|
46
|
+
...includeParams && { params }
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
const result = await doStream();
|
|
50
|
+
const chunks = [];
|
|
51
|
+
const transformStream = new TransformStream({
|
|
52
|
+
transform(chunk, controller) {
|
|
53
|
+
if (includeContent && chunk.type === "text-delta") chunks.push(chunk.delta);
|
|
54
|
+
controller.enqueue(chunk);
|
|
55
|
+
},
|
|
56
|
+
flush() {
|
|
57
|
+
logger.debug("ai.stream.complete", {
|
|
58
|
+
model: model.modelId,
|
|
59
|
+
durationMs: Date.now() - startTime,
|
|
60
|
+
...includeContent && { content: chunks.join("") }
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
specificationVersion: "v3",
|
|
66
|
+
...result,
|
|
67
|
+
stream: result.stream.pipeThrough(transformStream)
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
logger.error("ai.stream.error", {
|
|
71
|
+
model: model.modelId,
|
|
72
|
+
durationMs: Date.now() - startTime,
|
|
73
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
74
|
+
});
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
89
79
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
ops: []
|
|
99
|
-
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
100
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
|
|
101
|
-
return this;
|
|
102
|
-
}), g;
|
|
103
|
-
function verb(n) {
|
|
104
|
-
return function(v) {
|
|
105
|
-
return step([
|
|
106
|
-
n,
|
|
107
|
-
v
|
|
108
|
-
]);
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
function step(op) {
|
|
112
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
113
|
-
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
114
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
115
|
-
if (y = 0, t) op = [
|
|
116
|
-
op[0] & 2,
|
|
117
|
-
t.value
|
|
118
|
-
];
|
|
119
|
-
switch(op[0]){
|
|
120
|
-
case 0:
|
|
121
|
-
case 1:
|
|
122
|
-
t = op;
|
|
123
|
-
break;
|
|
124
|
-
case 4:
|
|
125
|
-
_.label++;
|
|
126
|
-
return {
|
|
127
|
-
value: op[1],
|
|
128
|
-
done: false
|
|
129
|
-
};
|
|
130
|
-
case 5:
|
|
131
|
-
_.label++;
|
|
132
|
-
y = op[1];
|
|
133
|
-
op = [
|
|
134
|
-
0
|
|
135
|
-
];
|
|
136
|
-
continue;
|
|
137
|
-
case 7:
|
|
138
|
-
op = _.ops.pop();
|
|
139
|
-
_.trys.pop();
|
|
140
|
-
continue;
|
|
141
|
-
default:
|
|
142
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
143
|
-
_ = 0;
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
147
|
-
_.label = op[1];
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
if (op[0] === 6 && _.label < t[1]) {
|
|
151
|
-
_.label = t[1];
|
|
152
|
-
t = op;
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
if (t && _.label < t[2]) {
|
|
156
|
-
_.label = t[2];
|
|
157
|
-
_.ops.push(op);
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
if (t[2]) _.ops.pop();
|
|
161
|
-
_.trys.pop();
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
op = body.call(thisArg, _);
|
|
165
|
-
} catch (e) {
|
|
166
|
-
op = [
|
|
167
|
-
6,
|
|
168
|
-
e
|
|
169
|
-
];
|
|
170
|
-
y = 0;
|
|
171
|
-
} finally{
|
|
172
|
-
f = t = 0;
|
|
173
|
-
}
|
|
174
|
-
if (op[0] & 5) throw op[1];
|
|
175
|
-
return {
|
|
176
|
-
value: op[0] ? op[1] : void 0,
|
|
177
|
-
done: true
|
|
178
|
-
};
|
|
179
|
-
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/observability/observability.middleware.ts
|
|
83
|
+
/**
|
|
84
|
+
* Helper to create type-safe observability metadata for providerOptions
|
|
85
|
+
*/
|
|
86
|
+
function withObservability(meta) {
|
|
87
|
+
return { observability: meta };
|
|
180
88
|
}
|
|
181
89
|
/**
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
];
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
})();
|
|
247
|
-
},
|
|
248
|
-
wrapStream: function(param) {
|
|
249
|
-
var doStream = param.doStream, params = param.params;
|
|
250
|
-
return _async_to_generator(function() {
|
|
251
|
-
var startTime, result, error;
|
|
252
|
-
return _ts_generator(this, function(_state) {
|
|
253
|
-
switch(_state.label){
|
|
254
|
-
case 0:
|
|
255
|
-
startTime = Date.now();
|
|
256
|
-
logger.debug('Model stream started', _object_spread$1({}, verbose && {
|
|
257
|
-
params: params
|
|
258
|
-
}));
|
|
259
|
-
_state.label = 1;
|
|
260
|
-
case 1:
|
|
261
|
-
_state.trys.push([
|
|
262
|
-
1,
|
|
263
|
-
3,
|
|
264
|
-
,
|
|
265
|
-
4
|
|
266
|
-
]);
|
|
267
|
-
return [
|
|
268
|
-
4,
|
|
269
|
-
doStream()
|
|
270
|
-
];
|
|
271
|
-
case 2:
|
|
272
|
-
result = _state.sent();
|
|
273
|
-
return [
|
|
274
|
-
2,
|
|
275
|
-
_object_spread_props(_object_spread$1({}, result), {
|
|
276
|
-
stream: result.stream
|
|
277
|
-
})
|
|
278
|
-
];
|
|
279
|
-
case 3:
|
|
280
|
-
error = _state.sent();
|
|
281
|
-
logger.error('Model stream failed', {
|
|
282
|
-
durationMs: Date.now() - startTime,
|
|
283
|
-
error: _instanceof$1(error, Error) ? error.message : 'Unknown error'
|
|
284
|
-
});
|
|
285
|
-
throw error;
|
|
286
|
-
case 4:
|
|
287
|
-
return [
|
|
288
|
-
2
|
|
289
|
-
];
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
})();
|
|
293
|
-
}
|
|
294
|
-
};
|
|
90
|
+
* Creates middleware that sends generation data to an observability platform.
|
|
91
|
+
*/
|
|
92
|
+
function createObservabilityMiddleware(options) {
|
|
93
|
+
const { observability, providerMetadata } = options;
|
|
94
|
+
return {
|
|
95
|
+
specificationVersion: "v3",
|
|
96
|
+
wrapGenerate: async ({ doGenerate, params, model }) => {
|
|
97
|
+
const startTime = /* @__PURE__ */ new Date();
|
|
98
|
+
const meta = params.providerOptions?.observability;
|
|
99
|
+
const result = await doGenerate();
|
|
100
|
+
const endTime = /* @__PURE__ */ new Date();
|
|
101
|
+
if (meta?.traceId) {
|
|
102
|
+
const extracted = providerMetadata?.extract(result.providerMetadata);
|
|
103
|
+
const outputText = result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
104
|
+
observability.generation({
|
|
105
|
+
traceId: meta.traceId,
|
|
106
|
+
name: meta.name ?? "generation",
|
|
107
|
+
model: model.modelId,
|
|
108
|
+
input: params.prompt,
|
|
109
|
+
output: outputText,
|
|
110
|
+
startTime,
|
|
111
|
+
endTime,
|
|
112
|
+
usage: extracted?.usage,
|
|
113
|
+
cost: extracted?.cost,
|
|
114
|
+
metadata: meta.metadata
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
},
|
|
119
|
+
wrapStream: async ({ doStream, params, model }) => {
|
|
120
|
+
const startTime = /* @__PURE__ */ new Date();
|
|
121
|
+
const meta = params.providerOptions?.observability;
|
|
122
|
+
const result = await doStream();
|
|
123
|
+
if (!meta?.traceId) return result;
|
|
124
|
+
const chunks = [];
|
|
125
|
+
const transformStream = new TransformStream({
|
|
126
|
+
transform(chunk, controller) {
|
|
127
|
+
if (chunk.type === "text-delta") chunks.push(chunk.delta);
|
|
128
|
+
controller.enqueue(chunk);
|
|
129
|
+
},
|
|
130
|
+
flush() {
|
|
131
|
+
const endTime = /* @__PURE__ */ new Date();
|
|
132
|
+
observability.generation({
|
|
133
|
+
traceId: meta.traceId,
|
|
134
|
+
name: meta.name ?? "generation",
|
|
135
|
+
model: model.modelId,
|
|
136
|
+
input: params.prompt,
|
|
137
|
+
output: chunks.join(""),
|
|
138
|
+
startTime,
|
|
139
|
+
endTime,
|
|
140
|
+
metadata: meta.metadata
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
specificationVersion: "v3",
|
|
146
|
+
...result,
|
|
147
|
+
stream: result.stream.pipeThrough(transformStream)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
};
|
|
295
151
|
}
|
|
296
152
|
|
|
153
|
+
//#endregion
|
|
154
|
+
//#region src/observability/langfuse.adapter.ts
|
|
297
155
|
/**
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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
|
+
});
|
|
168
|
+
}
|
|
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
|
+
});
|
|
198
|
+
}
|
|
199
|
+
async shutdown() {
|
|
200
|
+
await this.client.shutdownAsync();
|
|
201
|
+
}
|
|
202
|
+
trace(params) {
|
|
203
|
+
this.client.trace({
|
|
204
|
+
id: params.id,
|
|
205
|
+
name: params.name,
|
|
206
|
+
metadata: params.metadata
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
};
|
|
336
210
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
function
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
function _construct(Parent, args, Class) {
|
|
361
|
-
if (_is_native_reflect_construct()) {
|
|
362
|
-
_construct = Reflect.construct;
|
|
363
|
-
} else {
|
|
364
|
-
_construct = function construct(Parent, args, Class) {
|
|
365
|
-
var a = [
|
|
366
|
-
null
|
|
367
|
-
];
|
|
368
|
-
a.push.apply(a, args);
|
|
369
|
-
var Constructor = Function.bind.apply(Parent, a);
|
|
370
|
-
var instance = new Constructor();
|
|
371
|
-
if (Class) _set_prototype_of(instance, Class.prototype);
|
|
372
|
-
return instance;
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
return _construct.apply(null, arguments);
|
|
376
|
-
}
|
|
377
|
-
function _define_property$1(obj, key, value) {
|
|
378
|
-
if (key in obj) {
|
|
379
|
-
Object.defineProperty(obj, key, {
|
|
380
|
-
value: value,
|
|
381
|
-
enumerable: true,
|
|
382
|
-
configurable: true,
|
|
383
|
-
writable: true
|
|
384
|
-
});
|
|
385
|
-
} else {
|
|
386
|
-
obj[key] = value;
|
|
387
|
-
}
|
|
388
|
-
return obj;
|
|
389
|
-
}
|
|
390
|
-
function _get_prototype_of(o) {
|
|
391
|
-
_get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
|
|
392
|
-
return o.__proto__ || Object.getPrototypeOf(o);
|
|
393
|
-
};
|
|
394
|
-
return _get_prototype_of(o);
|
|
395
|
-
}
|
|
396
|
-
function _inherits(subClass, superClass) {
|
|
397
|
-
if (typeof superClass !== "function" && superClass !== null) {
|
|
398
|
-
throw new TypeError("Super expression must either be null or a function");
|
|
399
|
-
}
|
|
400
|
-
subClass.prototype = Object.create(superClass && superClass.prototype, {
|
|
401
|
-
constructor: {
|
|
402
|
-
value: subClass,
|
|
403
|
-
writable: true,
|
|
404
|
-
configurable: true
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
if (superClass) _set_prototype_of(subClass, superClass);
|
|
408
|
-
}
|
|
409
|
-
function _instanceof(left, right) {
|
|
410
|
-
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
411
|
-
return !!right[Symbol.hasInstance](left);
|
|
412
|
-
} else {
|
|
413
|
-
return left instanceof right;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
function _is_native_function(fn) {
|
|
417
|
-
return Function.toString.call(fn).indexOf("[native code]") !== -1;
|
|
418
|
-
}
|
|
419
|
-
function _iterable_to_array_limit(arr, i) {
|
|
420
|
-
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
421
|
-
if (_i == null) return;
|
|
422
|
-
var _arr = [];
|
|
423
|
-
var _n = true;
|
|
424
|
-
var _d = false;
|
|
425
|
-
var _s, _e;
|
|
426
|
-
try {
|
|
427
|
-
for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
|
|
428
|
-
_arr.push(_s.value);
|
|
429
|
-
if (i && _arr.length === i) break;
|
|
430
|
-
}
|
|
431
|
-
} catch (err) {
|
|
432
|
-
_d = true;
|
|
433
|
-
_e = err;
|
|
434
|
-
} finally{
|
|
435
|
-
try {
|
|
436
|
-
if (!_n && _i["return"] != null) _i["return"]();
|
|
437
|
-
} finally{
|
|
438
|
-
if (_d) throw _e;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
return _arr;
|
|
442
|
-
}
|
|
443
|
-
function _non_iterable_rest() {
|
|
444
|
-
throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
445
|
-
}
|
|
446
|
-
function _possible_constructor_return(self, call) {
|
|
447
|
-
if (call && (_type_of(call) === "object" || typeof call === "function")) {
|
|
448
|
-
return call;
|
|
449
|
-
}
|
|
450
|
-
return _assert_this_initialized(self);
|
|
451
|
-
}
|
|
452
|
-
function _set_prototype_of(o, p) {
|
|
453
|
-
_set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
|
|
454
|
-
o.__proto__ = p;
|
|
455
|
-
return o;
|
|
456
|
-
};
|
|
457
|
-
return _set_prototype_of(o, p);
|
|
458
|
-
}
|
|
459
|
-
function _sliced_to_array(arr, i) {
|
|
460
|
-
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/observability/noop.adapter.ts
|
|
213
|
+
/**
|
|
214
|
+
* No-op adapter that silently discards all observability data.
|
|
215
|
+
* Useful for testing, development, or when observability is disabled.
|
|
216
|
+
*/
|
|
217
|
+
var NoopObservabilityAdapter = class {
|
|
218
|
+
async flush() {}
|
|
219
|
+
generation(_params) {}
|
|
220
|
+
async shutdown() {}
|
|
221
|
+
trace(_params) {}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/result/result.ts
|
|
226
|
+
/**
|
|
227
|
+
* Create a successful result
|
|
228
|
+
*/
|
|
229
|
+
function generationSuccess(data) {
|
|
230
|
+
return {
|
|
231
|
+
success: true,
|
|
232
|
+
data
|
|
233
|
+
};
|
|
461
234
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
235
|
+
/**
|
|
236
|
+
* Create a failed result
|
|
237
|
+
*/
|
|
238
|
+
function generationFailure(code, message, cause) {
|
|
239
|
+
return {
|
|
240
|
+
success: false,
|
|
241
|
+
error: {
|
|
242
|
+
code,
|
|
243
|
+
message,
|
|
244
|
+
cause
|
|
245
|
+
}
|
|
246
|
+
};
|
|
465
247
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Classify an error into a GenerationErrorCode
|
|
250
|
+
*/
|
|
251
|
+
function classifyError(error) {
|
|
252
|
+
if (error instanceof Error) {
|
|
253
|
+
const message = error.message.toLowerCase();
|
|
254
|
+
if (message.includes("timeout") || message.includes("timed out")) return "TIMEOUT";
|
|
255
|
+
if (message.includes("rate limit") || message.includes("429")) return "RATE_LIMITED";
|
|
256
|
+
if (message.includes("parse") || message.includes("json") || message.includes("unexpected token")) return "PARSING_FAILED";
|
|
257
|
+
if (message.includes("valid") || message.includes("schema") || message.includes("zod")) return "VALIDATION_FAILED";
|
|
258
|
+
}
|
|
259
|
+
return "AI_GENERATION_FAILED";
|
|
473
260
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
throw new TypeError("Super expression must either be null or a function");
|
|
480
|
-
}
|
|
481
|
-
if (typeof _cache !== "undefined") {
|
|
482
|
-
if (_cache.has(Class)) return _cache.get(Class);
|
|
483
|
-
_cache.set(Class, Wrapper);
|
|
484
|
-
}
|
|
485
|
-
function Wrapper() {
|
|
486
|
-
return _construct(Class, arguments, _get_prototype_of(this).constructor);
|
|
487
|
-
}
|
|
488
|
-
Wrapper.prototype = Object.create(Class.prototype, {
|
|
489
|
-
constructor: {
|
|
490
|
-
value: Wrapper,
|
|
491
|
-
enumerable: false,
|
|
492
|
-
writable: true,
|
|
493
|
-
configurable: true
|
|
494
|
-
}
|
|
495
|
-
});
|
|
496
|
-
return _set_prototype_of(Wrapper, Class);
|
|
497
|
-
};
|
|
498
|
-
return _wrap_native_super(Class);
|
|
261
|
+
/**
|
|
262
|
+
* Check if a result is successful (type guard)
|
|
263
|
+
*/
|
|
264
|
+
function isSuccess(result) {
|
|
265
|
+
return result.success;
|
|
499
266
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
return !!result;
|
|
506
|
-
})();
|
|
267
|
+
/**
|
|
268
|
+
* Check if a result is a failure (type guard)
|
|
269
|
+
*/
|
|
270
|
+
function isFailure(result) {
|
|
271
|
+
return !result.success;
|
|
507
272
|
}
|
|
508
273
|
/**
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
var _this;
|
|
516
|
-
_this = _call_super(this, ParseObjectError, [
|
|
517
|
-
message
|
|
518
|
-
]), _define_property$1(_this, "cause", void 0), _define_property$1(_this, "text", void 0), _define_property$1(_this, "name", void 0), _this.cause = cause, _this.text = text, _this.name = 'ParseObjectError';
|
|
519
|
-
return _this;
|
|
520
|
-
}
|
|
521
|
-
return ParseObjectError;
|
|
522
|
-
}(_wrap_native_super(Error));
|
|
274
|
+
* Unwrap a result, throwing if it fails
|
|
275
|
+
*/
|
|
276
|
+
function unwrap(result) {
|
|
277
|
+
if (result.success) return result.data;
|
|
278
|
+
throw new Error(`${result.error.code}: ${result.error.message}`);
|
|
279
|
+
}
|
|
523
280
|
/**
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
* - JSON embedded in prose text
|
|
529
|
-
* - Malformed JSON (auto-repaired)
|
|
530
|
-
* - Escaped unicode and special characters
|
|
531
|
-
*
|
|
532
|
-
* @param text - The raw AI response text
|
|
533
|
-
* @param schema - A Zod schema to validate and type the result
|
|
534
|
-
* @returns The parsed and validated data
|
|
535
|
-
* @throws {ParseObjectError} When parsing or validation fails
|
|
536
|
-
*
|
|
537
|
-
* @example
|
|
538
|
-
* ```ts
|
|
539
|
-
* const schema = z.object({ title: z.string(), tags: z.array(z.string()) });
|
|
540
|
-
* const result = parseObject(aiResponse, schema);
|
|
541
|
-
* // result is typed as { title: string; tags: string[] }
|
|
542
|
-
* ```
|
|
543
|
-
*/ function parseObject(text, schema) {
|
|
544
|
-
try {
|
|
545
|
-
var jsonString = extractJsonString(text);
|
|
546
|
-
var extracted = extractBySchemaType(jsonString, schema, text);
|
|
547
|
-
var unescaped = unescapeJsonValues(extracted);
|
|
548
|
-
return schema.parse(unescaped);
|
|
549
|
-
} catch (error) {
|
|
550
|
-
if (_instanceof(error, ParseObjectError)) {
|
|
551
|
-
throw error;
|
|
552
|
-
}
|
|
553
|
-
if (_instanceof(error, v4.z.ZodError)) {
|
|
554
|
-
throw new ParseObjectError('Failed to validate response against schema', error, text);
|
|
555
|
-
}
|
|
556
|
-
throw error;
|
|
557
|
-
}
|
|
281
|
+
* Unwrap a result with a default value for failures
|
|
282
|
+
*/
|
|
283
|
+
function unwrapOr(result, defaultValue) {
|
|
284
|
+
return result.success ? result.data : defaultValue;
|
|
558
285
|
}
|
|
559
|
-
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
//#region src/parsing/parse-object.ts
|
|
289
|
+
const MARKDOWN_CODE_BLOCK_RE = /```(?:json)?\r?\n([^`]*?)\r?\n```/g;
|
|
290
|
+
/**
|
|
291
|
+
* Error thrown when object parsing fails.
|
|
292
|
+
* Contains the original text for debugging purposes.
|
|
293
|
+
*/
|
|
294
|
+
var ParseObjectError = class extends Error {
|
|
295
|
+
name = "ParseObjectError";
|
|
296
|
+
constructor(message, cause, text) {
|
|
297
|
+
super(message);
|
|
298
|
+
this.cause = cause;
|
|
299
|
+
this.text = text;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
560
302
|
function convertToPrimitive(value, schema) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
303
|
+
if (schema instanceof zod_v4.z.ZodBoolean) return Boolean(value);
|
|
304
|
+
if (schema instanceof zod_v4.z.ZodNull) return null;
|
|
305
|
+
if (schema instanceof zod_v4.z.ZodNumber) return Number(value);
|
|
306
|
+
if (schema instanceof zod_v4.z.ZodString) return String(value);
|
|
307
|
+
return value;
|
|
566
308
|
}
|
|
567
309
|
function extractArray(text, originalText) {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
throw new ParseObjectError('Failed to parse array JSON', error, originalText);
|
|
578
|
-
}
|
|
310
|
+
const start = text.indexOf("[");
|
|
311
|
+
const end = text.lastIndexOf("]");
|
|
312
|
+
if (start === -1 || end === -1) throw new ParseObjectError("No array found in response", void 0, originalText);
|
|
313
|
+
try {
|
|
314
|
+
const raw = text.slice(start, end + 1);
|
|
315
|
+
return JSON.parse((0, jsonrepair.jsonrepair)(raw));
|
|
316
|
+
} catch (error) {
|
|
317
|
+
throw new ParseObjectError("Failed to parse array JSON", error, originalText);
|
|
318
|
+
}
|
|
579
319
|
}
|
|
580
|
-
function
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
throw new ParseObjectError('Unsupported schema type', undefined, originalText);
|
|
320
|
+
function extractObject(text, originalText) {
|
|
321
|
+
const start = text.indexOf("{");
|
|
322
|
+
const end = text.lastIndexOf("}");
|
|
323
|
+
if (start === -1 || end === -1) throw new ParseObjectError("No object found in response", void 0, originalText);
|
|
324
|
+
try {
|
|
325
|
+
const raw = text.slice(start, end + 1);
|
|
326
|
+
return JSON.parse((0, jsonrepair.jsonrepair)(raw));
|
|
327
|
+
} catch (error) {
|
|
328
|
+
throw new ParseObjectError("Failed to parse object JSON", error, originalText);
|
|
329
|
+
}
|
|
591
330
|
}
|
|
592
|
-
function
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
331
|
+
function extractPrimitive(text, schema) {
|
|
332
|
+
const trimmed = text.trim();
|
|
333
|
+
try {
|
|
334
|
+
return convertToPrimitive(JSON.parse(trimmed), schema);
|
|
335
|
+
} catch {
|
|
336
|
+
return convertToPrimitive(trimmed, schema);
|
|
337
|
+
}
|
|
600
338
|
}
|
|
601
|
-
function
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
if (structures.length > 0) {
|
|
615
|
-
return findLongestString(structures);
|
|
616
|
-
}
|
|
617
|
-
return text.replace(/\s+/g, ' ').trim();
|
|
339
|
+
function extractBySchemaType(text, schema, originalText) {
|
|
340
|
+
if (schema instanceof zod_v4.z.ZodArray) return extractArray(text, originalText);
|
|
341
|
+
if (schema instanceof zod_v4.z.ZodObject) return extractObject(text, originalText);
|
|
342
|
+
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);
|
|
343
|
+
if (schema instanceof zod_v4.z.ZodUnion || schema instanceof zod_v4.z.ZodDiscriminatedUnion) {
|
|
344
|
+
if (text.indexOf("{") !== -1) return extractObject(text, originalText);
|
|
345
|
+
if (text.indexOf("[") !== -1) return extractArray(text, originalText);
|
|
346
|
+
throw new ParseObjectError("No object or array found for union type", void 0, originalText);
|
|
347
|
+
}
|
|
348
|
+
if (schema instanceof zod_v4.z.ZodOptional || schema instanceof zod_v4.z.ZodNullable) return extractBySchemaType(text, schema.unwrap(), originalText);
|
|
349
|
+
if (schema instanceof zod_v4.z.ZodDefault) return extractBySchemaType(text, schema.def.innerType, originalText);
|
|
350
|
+
if (schema instanceof zod_v4.z.ZodPipe) return extractBySchemaType(text, schema.def.in, originalText);
|
|
351
|
+
throw new ParseObjectError("Unsupported schema type", void 0, originalText);
|
|
618
352
|
}
|
|
619
|
-
function
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
return JSON.parse(jsonrepair.jsonrepair(raw));
|
|
628
|
-
} catch (error) {
|
|
629
|
-
throw new ParseObjectError('Failed to parse object JSON', error, originalText);
|
|
630
|
-
}
|
|
353
|
+
function extractJsonFromCodeBlock(block) {
|
|
354
|
+
const content = block.replace(/```(?:json)?\r?\n([^`]*?)\r?\n```/, "$1").trim();
|
|
355
|
+
try {
|
|
356
|
+
JSON.parse(content);
|
|
357
|
+
return content;
|
|
358
|
+
} catch {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
631
361
|
}
|
|
632
|
-
function
|
|
633
|
-
|
|
634
|
-
try {
|
|
635
|
-
return convertToPrimitive(JSON.parse(trimmed), schema);
|
|
636
|
-
} catch (e) {
|
|
637
|
-
return convertToPrimitive(trimmed, schema);
|
|
638
|
-
}
|
|
362
|
+
function findLongestString(strings) {
|
|
363
|
+
return strings.reduce((longest, current) => current.length > longest.length ? current : longest);
|
|
639
364
|
}
|
|
640
365
|
function findJsonStructures(text) {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
return matches;
|
|
366
|
+
const matches = [];
|
|
367
|
+
let depth = 0;
|
|
368
|
+
let start = -1;
|
|
369
|
+
for (let i = 0; i < text.length; i++) {
|
|
370
|
+
const char = text[i];
|
|
371
|
+
if (char === "{" || char === "[") {
|
|
372
|
+
if (depth === 0) start = i;
|
|
373
|
+
depth++;
|
|
374
|
+
} else if (char === "}" || char === "]") {
|
|
375
|
+
depth--;
|
|
376
|
+
if (depth === 0 && start !== -1) {
|
|
377
|
+
const candidate = text.slice(start, i + 1);
|
|
378
|
+
try {
|
|
379
|
+
JSON.parse(candidate);
|
|
380
|
+
matches.push(candidate);
|
|
381
|
+
} catch {}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return matches;
|
|
663
386
|
}
|
|
664
|
-
function
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
387
|
+
function extractJsonString(text) {
|
|
388
|
+
const codeBlocks = text.match(MARKDOWN_CODE_BLOCK_RE);
|
|
389
|
+
if (codeBlocks && codeBlocks.length > 0) {
|
|
390
|
+
const validBlocks = codeBlocks.map((block) => extractJsonFromCodeBlock(block)).filter((block) => block !== null);
|
|
391
|
+
if (validBlocks.length > 0) return findLongestString(validBlocks);
|
|
392
|
+
}
|
|
393
|
+
const structures = findJsonStructures(text);
|
|
394
|
+
if (structures.length > 0) return findLongestString(structures);
|
|
395
|
+
return text.replace(/\s+/g, " ").trim();
|
|
396
|
+
}
|
|
397
|
+
function unescapeString(text) {
|
|
398
|
+
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)));
|
|
668
399
|
}
|
|
669
400
|
function unescapeJsonValues(json) {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
return json.map(unescapeJsonValues);
|
|
675
|
-
}
|
|
676
|
-
if ((typeof json === "undefined" ? "undefined" : _type_of(json)) === 'object' && json !== null) {
|
|
677
|
-
return Object.fromEntries(Object.entries(json).map(function(param) {
|
|
678
|
-
var _param = _sliced_to_array(param, 2), key = _param[0], value = _param[1];
|
|
679
|
-
return [
|
|
680
|
-
key,
|
|
681
|
-
unescapeJsonValues(value)
|
|
682
|
-
];
|
|
683
|
-
}));
|
|
684
|
-
}
|
|
685
|
-
return json;
|
|
401
|
+
if (typeof json === "string") return unescapeString(json);
|
|
402
|
+
if (Array.isArray(json)) return json.map(unescapeJsonValues);
|
|
403
|
+
if (typeof json === "object" && json !== null) return Object.fromEntries(Object.entries(json).map(([key, value]) => [key, unescapeJsonValues(value)]));
|
|
404
|
+
return json;
|
|
686
405
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
406
|
+
/**
|
|
407
|
+
* Parses AI-generated text into structured data validated against a Zod schema.
|
|
408
|
+
*
|
|
409
|
+
* Handles common AI response formats:
|
|
410
|
+
* - JSON wrapped in markdown code blocks
|
|
411
|
+
* - JSON embedded in prose text
|
|
412
|
+
* - Malformed JSON (auto-repaired)
|
|
413
|
+
* - Escaped unicode and special characters
|
|
414
|
+
*
|
|
415
|
+
* @param text - The raw AI response text
|
|
416
|
+
* @param schema - A Zod schema to validate and type the result
|
|
417
|
+
* @returns The parsed and validated data
|
|
418
|
+
* @throws {ParseObjectError} When parsing or validation fails
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```ts
|
|
422
|
+
* const schema = z.object({ title: z.string(), tags: z.array(z.string()) });
|
|
423
|
+
* const result = parseObject(aiResponse, schema);
|
|
424
|
+
* // result is typed as { title: string; tags: string[] }
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
function parseObject(text, schema) {
|
|
428
|
+
try {
|
|
429
|
+
const unescaped = unescapeJsonValues(extractBySchemaType(extractJsonString(text), schema, text));
|
|
430
|
+
return schema.parse(unescaped);
|
|
431
|
+
} catch (error) {
|
|
432
|
+
if (error instanceof ParseObjectError) throw error;
|
|
433
|
+
if (error instanceof zod_v4.z.ZodError) throw new ParseObjectError("Failed to validate response against schema", error, text);
|
|
434
|
+
throw error;
|
|
435
|
+
}
|
|
691
436
|
}
|
|
692
437
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
var ASCII_CTRL_RE = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
|
|
696
|
-
/* eslint-enable no-control-regex */ var SPACE_LIKE_RE = /[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
697
|
-
var MULTIPLE_SPACES_RE = / {2,}/g;
|
|
698
|
-
var CR_RE = /\r\n?/g;
|
|
699
|
-
var CITATION_RE = / *\(oaicite:\d+\)\{index=\d+\}/g;
|
|
700
|
-
var EM_DASH_SEPARATOR_RE = /\s*[—–―‒]\s*/g;
|
|
701
|
-
var TYPOGRAPHY_REPLACEMENTS = [
|
|
702
|
-
{
|
|
703
|
-
pattern: /[\u2018\u2019\u201A]/g,
|
|
704
|
-
replacement: "'"
|
|
705
|
-
},
|
|
706
|
-
{
|
|
707
|
-
pattern: /[\u201C\u201D\u201E]/g,
|
|
708
|
-
replacement: '"'
|
|
709
|
-
},
|
|
710
|
-
{
|
|
711
|
-
pattern: /\u2026/g,
|
|
712
|
-
replacement: '...'
|
|
713
|
-
},
|
|
714
|
-
{
|
|
715
|
-
pattern: /[\u2022\u25AA-\u25AB\u25B8-\u25B9\u25CF]/g,
|
|
716
|
-
replacement: '-'
|
|
717
|
-
}
|
|
718
|
-
];
|
|
438
|
+
//#endregion
|
|
439
|
+
//#region src/generation/generate-structured.ts
|
|
719
440
|
/**
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
var _step_value = _step.value, pattern = _step_value.pattern, replacement = _step_value.replacement;
|
|
746
|
-
result = result.replace(pattern, replacement);
|
|
747
|
-
}
|
|
748
|
-
} catch (err) {
|
|
749
|
-
_didIteratorError = true;
|
|
750
|
-
_iteratorError = err;
|
|
751
|
-
} finally{
|
|
752
|
-
try {
|
|
753
|
-
if (!_iteratorNormalCompletion && _iterator["return"] != null) {
|
|
754
|
-
_iterator["return"]();
|
|
755
|
-
}
|
|
756
|
-
} finally{
|
|
757
|
-
if (_didIteratorError) {
|
|
758
|
-
throw _iteratorError;
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
if (collapseSpaces) {
|
|
763
|
-
result = result.replace(MULTIPLE_SPACES_RE, ' ').trim();
|
|
764
|
-
}
|
|
765
|
-
return result;
|
|
441
|
+
* Generate structured data from an AI model with automatic parsing and error handling.
|
|
442
|
+
* Observability is handled by middleware - no metadata exposed to caller.
|
|
443
|
+
*/
|
|
444
|
+
async function generateStructured(options) {
|
|
445
|
+
const { model, prompt, system, schema, providerOptions, abortSignal, maxOutputTokens, temperature } = options;
|
|
446
|
+
try {
|
|
447
|
+
const response = await (0, ai.generateText)({
|
|
448
|
+
model,
|
|
449
|
+
prompt,
|
|
450
|
+
system,
|
|
451
|
+
providerOptions,
|
|
452
|
+
abortSignal,
|
|
453
|
+
maxOutputTokens,
|
|
454
|
+
temperature
|
|
455
|
+
});
|
|
456
|
+
if (!response.text || response.text.trim() === "") return generationFailure("EMPTY_RESULT", "AI returned empty response");
|
|
457
|
+
try {
|
|
458
|
+
return generationSuccess(parseObject(response.text, schema));
|
|
459
|
+
} catch (error) {
|
|
460
|
+
if (error instanceof ParseObjectError) return generationFailure("PARSING_FAILED", error.message, error);
|
|
461
|
+
return generationFailure("VALIDATION_FAILED", "Schema validation failed", error);
|
|
462
|
+
}
|
|
463
|
+
} catch (error) {
|
|
464
|
+
return generationFailure(classifyError(error), error instanceof Error ? error.message : "Unknown error", error);
|
|
465
|
+
}
|
|
766
466
|
}
|
|
767
467
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
468
|
+
//#endregion
|
|
469
|
+
//#region src/parsing/create-schema-prompt.ts
|
|
470
|
+
/**
|
|
471
|
+
* Creates a system prompt that instructs the model to output structured data
|
|
472
|
+
* matching the provided Zod schema.
|
|
473
|
+
*
|
|
474
|
+
* Use this with `generateText` when the provider doesn't support native
|
|
475
|
+
* structured outputs, then parse the response with `parseObject`.
|
|
476
|
+
*
|
|
477
|
+
* @param schema - A Zod schema defining the expected output structure
|
|
478
|
+
* @returns A system prompt string with JSON schema instructions
|
|
479
|
+
*
|
|
480
|
+
* @example
|
|
481
|
+
* ```ts
|
|
482
|
+
* import { generateText } from 'ai';
|
|
483
|
+
* import { createSchemaPrompt, parseObject } from '@jterrazz/intelligence';
|
|
484
|
+
*
|
|
485
|
+
* const schema = z.object({ title: z.string(), tags: z.array(z.string()) });
|
|
486
|
+
*
|
|
487
|
+
* const { text } = await generateText({
|
|
488
|
+
* model,
|
|
489
|
+
* prompt: 'Generate an article about TypeScript',
|
|
490
|
+
* system: createSchemaPrompt(schema),
|
|
491
|
+
* });
|
|
492
|
+
*
|
|
493
|
+
* const result = parseObject(text, schema);
|
|
494
|
+
* ```
|
|
495
|
+
*/
|
|
496
|
+
function createSchemaPrompt(schema) {
|
|
497
|
+
const jsonSchema = zod_v4.z.toJSONSchema(schema);
|
|
498
|
+
const schemaJson = JSON.stringify(jsonSchema, null, 2);
|
|
499
|
+
if ([
|
|
500
|
+
"boolean",
|
|
501
|
+
"integer",
|
|
502
|
+
"number",
|
|
503
|
+
"string"
|
|
504
|
+
].includes(jsonSchema.type)) return `<OUTPUT_FORMAT>
|
|
505
|
+
You must respond with a ${jsonSchema.type} value that matches this schema:
|
|
506
|
+
|
|
507
|
+
\`\`\`json
|
|
508
|
+
${schemaJson}
|
|
509
|
+
\`\`\`
|
|
510
|
+
|
|
511
|
+
Your response should be only the ${jsonSchema.type} value, without any JSON wrapping or additional text.
|
|
512
|
+
</OUTPUT_FORMAT>`;
|
|
513
|
+
return `<OUTPUT_FORMAT>
|
|
514
|
+
You must respond with valid JSON that matches this JSON schema:
|
|
515
|
+
|
|
516
|
+
\`\`\`json
|
|
517
|
+
${schemaJson}
|
|
518
|
+
\`\`\`
|
|
519
|
+
|
|
520
|
+
Your response must be parseable JSON that validates against this schema. Do not include any text outside the JSON.
|
|
521
|
+
</OUTPUT_FORMAT>`;
|
|
780
522
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
523
|
+
|
|
524
|
+
//#endregion
|
|
525
|
+
//#region src/parsing/parse-text.ts
|
|
526
|
+
const INVISIBLE_CHARS_RE = /[\u00AD\u180E\u200B-\u200C\u200E-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u2069\uFEFF]/g;
|
|
527
|
+
const ASCII_CTRL_RE = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g;
|
|
528
|
+
const SPACE_LIKE_RE = /[\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
529
|
+
const MULTIPLE_SPACES_RE = / {2,}/g;
|
|
530
|
+
const CR_RE = /\r\n?/g;
|
|
531
|
+
const CITATION_RE = / *\(oaicite:\d+\)\{index=\d+\}/g;
|
|
532
|
+
const EM_DASH_SEPARATOR_RE = /\s*[—–―‒]\s*/g;
|
|
533
|
+
const TYPOGRAPHY_REPLACEMENTS = [
|
|
534
|
+
{
|
|
535
|
+
pattern: /[\u2018\u2019\u201A]/g,
|
|
536
|
+
replacement: "'"
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
pattern: /[\u201C\u201D\u201E]/g,
|
|
540
|
+
replacement: "\""
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
pattern: /\u2026/g,
|
|
544
|
+
replacement: "..."
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
pattern: /[\u2022\u25AA-\u25AB\u25B8-\u25B9\u25CF]/g,
|
|
548
|
+
replacement: "-"
|
|
549
|
+
}
|
|
550
|
+
];
|
|
551
|
+
/**
|
|
552
|
+
* Parses and sanitizes text by removing AI artifacts and normalizing typography.
|
|
553
|
+
*
|
|
554
|
+
* @param text - The text to parse
|
|
555
|
+
* @param options - Parsing options
|
|
556
|
+
* @returns The cleaned text
|
|
557
|
+
*/
|
|
558
|
+
function parseText(text, options = {}) {
|
|
559
|
+
const { normalizeEmDashesToCommas = true, collapseSpaces = true } = options;
|
|
560
|
+
if (!text) return "";
|
|
561
|
+
let result = text;
|
|
562
|
+
result = result.replace(CR_RE, "\n");
|
|
563
|
+
result = result.replace(CITATION_RE, "");
|
|
564
|
+
result = result.normalize("NFKC");
|
|
565
|
+
result = result.replace(INVISIBLE_CHARS_RE, "");
|
|
566
|
+
result = result.replace(ASCII_CTRL_RE, "");
|
|
567
|
+
if (normalizeEmDashesToCommas) result = result.replace(EM_DASH_SEPARATOR_RE, ", ");
|
|
568
|
+
result = result.replace(SPACE_LIKE_RE, " ");
|
|
569
|
+
for (const { pattern, replacement } of TYPOGRAPHY_REPLACEMENTS) result = result.replace(pattern, replacement);
|
|
570
|
+
if (collapseSpaces) result = result.replace(MULTIPLE_SPACES_RE, " ").trim();
|
|
571
|
+
return result;
|
|
795
572
|
}
|
|
573
|
+
|
|
574
|
+
//#endregion
|
|
575
|
+
//#region src/provider/openrouter.provider.ts
|
|
796
576
|
/**
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
}, options.reasoning && {
|
|
816
|
-
extraBody: {
|
|
817
|
-
reasoning: options.reasoning
|
|
818
|
-
}
|
|
819
|
-
}));
|
|
820
|
-
}
|
|
821
|
-
};
|
|
577
|
+
* Creates an OpenRouter provider for AI SDK models.
|
|
578
|
+
*
|
|
579
|
+
* @example
|
|
580
|
+
* ```ts
|
|
581
|
+
* const provider = createOpenRouterProvider({ apiKey: process.env.OPENROUTER_API_KEY });
|
|
582
|
+
* const model = provider.model('anthropic/claude-sonnet-4-20250514');
|
|
583
|
+
*
|
|
584
|
+
* const { text } = await generateText({ model, prompt: 'Hello!' });
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
function createOpenRouterProvider(config) {
|
|
588
|
+
const openrouter = (0, _openrouter_ai_sdk_provider.createOpenRouter)({ apiKey: config.apiKey });
|
|
589
|
+
return { model(name, options = {}) {
|
|
590
|
+
return openrouter(name, {
|
|
591
|
+
...options.maxTokens !== void 0 && { maxTokens: options.maxTokens },
|
|
592
|
+
...options.reasoning && { extraBody: { reasoning: options.reasoning } }
|
|
593
|
+
});
|
|
594
|
+
} };
|
|
822
595
|
}
|
|
823
596
|
|
|
597
|
+
//#endregion
|
|
598
|
+
//#region src/provider/openrouter-metadata.adapter.ts
|
|
599
|
+
/**
|
|
600
|
+
* OpenRouter adapter for extracting usage and cost from provider metadata
|
|
601
|
+
*/
|
|
602
|
+
var OpenRouterMetadataAdapter = class {
|
|
603
|
+
extract(providerMetadata) {
|
|
604
|
+
const meta = providerMetadata?.openrouter;
|
|
605
|
+
if (!meta?.usage) return {};
|
|
606
|
+
const usage = meta.usage;
|
|
607
|
+
return {
|
|
608
|
+
usage: {
|
|
609
|
+
input: usage.promptTokens ?? 0,
|
|
610
|
+
output: usage.completionTokens ?? 0,
|
|
611
|
+
total: usage.totalTokens,
|
|
612
|
+
reasoning: usage.completionTokensDetails?.reasoningTokens,
|
|
613
|
+
cacheRead: usage.promptTokensDetails?.cachedTokens
|
|
614
|
+
},
|
|
615
|
+
cost: usage.cost !== void 0 ? { total: usage.cost } : void 0
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
//#endregion
|
|
621
|
+
exports.LangfuseAdapter = LangfuseAdapter;
|
|
622
|
+
exports.NoopObservabilityAdapter = NoopObservabilityAdapter;
|
|
623
|
+
exports.OpenRouterMetadataAdapter = OpenRouterMetadataAdapter;
|
|
824
624
|
exports.ParseObjectError = ParseObjectError;
|
|
625
|
+
exports.classifyError = classifyError;
|
|
825
626
|
exports.createLoggingMiddleware = createLoggingMiddleware;
|
|
627
|
+
exports.createObservabilityMiddleware = createObservabilityMiddleware;
|
|
826
628
|
exports.createOpenRouterProvider = createOpenRouterProvider;
|
|
827
629
|
exports.createSchemaPrompt = createSchemaPrompt;
|
|
630
|
+
exports.generateStructured = generateStructured;
|
|
631
|
+
exports.generationFailure = generationFailure;
|
|
632
|
+
exports.generationSuccess = generationSuccess;
|
|
633
|
+
exports.isFailure = isFailure;
|
|
634
|
+
exports.isSuccess = isSuccess;
|
|
828
635
|
exports.parseObject = parseObject;
|
|
829
636
|
exports.parseText = parseText;
|
|
637
|
+
exports.unwrap = unwrap;
|
|
638
|
+
exports.unwrapOr = unwrapOr;
|
|
639
|
+
exports.withObservability = withObservability;
|
|
640
|
+
//# sourceMappingURL=index.cjs.map
|