extrait 0.5.1 → 0.5.3
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 +113 -1
- package/dist/conversation.d.ts +8 -0
- package/dist/image.d.ts +8 -0
- package/dist/index.cjs +116 -7
- package/dist/index.d.ts +3 -1
- package/dist/index.js +119 -7
- package/dist/prompt.d.ts +3 -1
- package/dist/types.d.ts +19 -1
- package/package.json +31 -22
package/README.md
CHANGED
|
@@ -70,6 +70,7 @@ const llm = createLLM({
|
|
|
70
70
|
mode: "loose" | "strict", // loose allows repair
|
|
71
71
|
selfHeal: 0 | 1 | 2, // retry attempts
|
|
72
72
|
debug: false, // show repair logs
|
|
73
|
+
timeout: { request: 30_000 }, // optional default timeouts
|
|
73
74
|
},
|
|
74
75
|
});
|
|
75
76
|
```
|
|
@@ -159,11 +160,90 @@ const result = await llm.structured(
|
|
|
159
160
|
request: {
|
|
160
161
|
signal: abortController.signal, // optional AbortSignal
|
|
161
162
|
},
|
|
163
|
+
timeout: {
|
|
164
|
+
request: 30_000, // ms per LLM HTTP request
|
|
165
|
+
tool: 10_000, // ms per MCP tool call
|
|
166
|
+
},
|
|
162
167
|
}
|
|
163
168
|
);
|
|
164
169
|
```
|
|
165
170
|
|
|
166
|
-
`prompt()` builds an ordered `messages` payload. Use
|
|
171
|
+
`prompt()` builds an ordered `messages` payload. Use ``prompt`...` `` for a single string prompt, or the fluent builder for multi-turn conversations. The `LLMMessage` type is exported if you need to type your own message arrays.
|
|
172
|
+
|
|
173
|
+
### Images (multimodal)
|
|
174
|
+
|
|
175
|
+
Use `images()` to build base64 image content blocks for vision-capable models.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
import { images, prompt } from "extrait";
|
|
179
|
+
import { readFileSync } from "fs";
|
|
180
|
+
|
|
181
|
+
const base64 = readFileSync("photo.png").toString("base64");
|
|
182
|
+
const img = { base64, mimeType: "image/png" };
|
|
183
|
+
|
|
184
|
+
// With prompt() builder — pass LLMMessageContent array to .user() or .assistant()
|
|
185
|
+
const result = await llm.structured(Schema,
|
|
186
|
+
prompt()
|
|
187
|
+
.system`You are a vision assistant.`
|
|
188
|
+
.user([{ type: "text", text: "Describe this image." }, ...images(img)])
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
// With raw messages array
|
|
192
|
+
const result = await llm.structured(Schema, {
|
|
193
|
+
messages: [
|
|
194
|
+
{
|
|
195
|
+
role: "user",
|
|
196
|
+
content: [
|
|
197
|
+
{ type: "text", text: "Describe this image." },
|
|
198
|
+
...images(img),
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Multiple images
|
|
205
|
+
const content = [
|
|
206
|
+
{ type: "text", text: "Compare these two images." },
|
|
207
|
+
...images([
|
|
208
|
+
{ base64: base64A, mimeType: "image/png" },
|
|
209
|
+
{ base64: base64B, mimeType: "image/jpeg" },
|
|
210
|
+
]),
|
|
211
|
+
];
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`images()` accepts a single `{ base64, mimeType }` object or an array, and always returns an `LLMImageContent[]` that spreads directly into a content array.
|
|
215
|
+
|
|
216
|
+
### Conversations (multi-turn history)
|
|
217
|
+
|
|
218
|
+
Use `conversation()` to build a `LLMMessage[]` from an existing conversation history. This is the idiomatic way to pass prior turns to the LLM.
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { conversation } from "extrait";
|
|
222
|
+
|
|
223
|
+
const messages = conversation("You are a helpful assistant.", [
|
|
224
|
+
{ role: "user", text: "What is the speed of light?" },
|
|
225
|
+
{ role: "assistant", text: "Approximately 299,792 km/s in a vacuum." },
|
|
226
|
+
{ role: "user", text: "How long does light take to reach Earth from the Sun?" },
|
|
227
|
+
]);
|
|
228
|
+
|
|
229
|
+
// Pass to adapter directly
|
|
230
|
+
const response = await llm.adapter.complete({ messages });
|
|
231
|
+
|
|
232
|
+
// Or to structured extraction
|
|
233
|
+
const result = await llm.structured(Schema, { messages });
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Entries with `images` produce multimodal content automatically:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
const messages = conversation("You are a vision assistant.", [
|
|
240
|
+
{
|
|
241
|
+
role: "user",
|
|
242
|
+
text: "What is in this image?",
|
|
243
|
+
images: [{ base64, mimeType: "image/png" }],
|
|
244
|
+
},
|
|
245
|
+
]);
|
|
246
|
+
```
|
|
167
247
|
|
|
168
248
|
### Result Object
|
|
169
249
|
|
|
@@ -246,6 +326,34 @@ const result = await llm.structured(
|
|
|
246
326
|
await mcpClient.close?.();
|
|
247
327
|
```
|
|
248
328
|
|
|
329
|
+
### Timeouts
|
|
330
|
+
|
|
331
|
+
Use `timeout` to set per-request and per-tool-call time limits without managing `AbortSignal` manually.
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const result = await llm.structured(Schema, prompt`...`, {
|
|
335
|
+
timeout: {
|
|
336
|
+
request: 30_000, // abort the LLM HTTP request after 30s
|
|
337
|
+
tool: 5_000, // abort each MCP tool call after 5s
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Both fields are optional. `timeout.request` creates an `AbortSignal.timeout` internally; it is ignored if you also pass `request.signal` (your signal takes precedence). `timeout.tool` wraps each MCP client transparently.
|
|
343
|
+
|
|
344
|
+
You can also set defaults on the client:
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
const llm = createLLM({
|
|
348
|
+
provider: "openai-compatible",
|
|
349
|
+
model: "gpt-5-nano",
|
|
350
|
+
transport: { apiKey: process.env.LLM_API_KEY },
|
|
351
|
+
defaults: {
|
|
352
|
+
timeout: { request: 60_000 },
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
249
357
|
## Examples
|
|
250
358
|
|
|
251
359
|
Run examples with: `bun run dev <example-name>`
|
|
@@ -254,17 +362,21 @@ Available examples:
|
|
|
254
362
|
- `streaming` - Real LLM streaming + snapshot self-check ([streaming.ts](examples/streaming.ts))
|
|
255
363
|
- `streaming-with-tools` - Real text streaming with MCP tools + self-check ([streaming-with-tools.ts](examples/streaming-with-tools.ts))
|
|
256
364
|
- `abort-signal` - Start a generation then cancel quickly with `AbortSignal` ([abort-signal.ts](examples/abort-signal.ts))
|
|
365
|
+
- `timeout` - Set per-request and per-tool timeouts via the `timeout` option ([timeout.ts](examples/timeout.ts))
|
|
257
366
|
- `simple` - Basic structured output with streaming ([simple.ts](examples/simple.ts))
|
|
258
367
|
- `sentiment-analysis` - Enum validation, strict mode ([sentiment-analysis.ts](examples/sentiment-analysis.ts))
|
|
259
368
|
- `data-extraction` - Complex nested schemas, self-healing ([data-extraction.ts](examples/data-extraction.ts))
|
|
260
369
|
- `multi-step-reasoning` - Chained structured calls ([multi-step-reasoning.ts](examples/multi-step-reasoning.ts))
|
|
261
370
|
- `calculator-tool` - MCP tool integration ([calculator-tool.ts](examples/calculator-tool.ts))
|
|
371
|
+
- `image-analysis` - Multimodal structured extraction from an image file ([image-analysis.ts](examples/image-analysis.ts))
|
|
372
|
+
- `conversation` - Multi-turn conversation history and inline image messages ([conversation.ts](examples/conversation.ts))
|
|
262
373
|
|
|
263
374
|
Pass arguments after the example name:
|
|
264
375
|
```bash
|
|
265
376
|
bun run dev streaming
|
|
266
377
|
bun run dev streaming-with-tools
|
|
267
378
|
bun run dev abort-signal 120 "JSON cancellation demo"
|
|
379
|
+
bun run dev timeout 5000
|
|
268
380
|
bun run dev simple "Bun.js runtime"
|
|
269
381
|
bun run dev sentiment-analysis "I love this product."
|
|
270
382
|
bun run dev multi-step-reasoning "Why is the sky blue?"
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ImageInput } from "./image";
|
|
2
|
+
import type { LLMMessage } from "./types";
|
|
3
|
+
export interface ConversationEntry {
|
|
4
|
+
role: "user" | "assistant";
|
|
5
|
+
text: string;
|
|
6
|
+
images?: ImageInput[];
|
|
7
|
+
}
|
|
8
|
+
export declare function conversation(systemPrompt: string, entries: ConversationEntry[]): LLMMessage[];
|
package/dist/image.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LLMImageContent } from "./types";
|
|
2
|
+
export interface ImageInput {
|
|
3
|
+
base64: string;
|
|
4
|
+
mimeType: string;
|
|
5
|
+
}
|
|
6
|
+
export type ImageSize = "low" | "mid" | "high" | "xhigh" | "raw" | number;
|
|
7
|
+
export declare function images(input: ImageInput | ImageInput[]): LLMImageContent[];
|
|
8
|
+
export declare function resizeImage(source: string | Uint8Array | ArrayBuffer, size: ImageSize, mimeType?: string): Promise<ImageInput>;
|
package/dist/index.cjs
CHANGED
|
@@ -45,11 +45,13 @@ __export(exports_src, {
|
|
|
45
45
|
sanitizeThink: () => sanitizeThink,
|
|
46
46
|
s: () => s,
|
|
47
47
|
resolveSchemaInstruction: () => resolveSchemaInstruction,
|
|
48
|
+
resizeImage: () => resizeImage,
|
|
48
49
|
registerBuiltinProviders: () => registerBuiltinProviders,
|
|
49
50
|
prompt: () => prompt,
|
|
50
51
|
parseLLMOutput: () => parseLLMOutput,
|
|
51
52
|
inspectSchemaMetadata: () => inspectSchemaMetadata,
|
|
52
53
|
inferSchemaExample: () => inferSchemaExample,
|
|
54
|
+
images: () => images,
|
|
53
55
|
formatZodIssues: () => formatZodIssues,
|
|
54
56
|
formatPrompt: () => formatPrompt,
|
|
55
57
|
extractMarkdownCodeBlocks: () => extractMarkdownCodeBlocks,
|
|
@@ -62,6 +64,7 @@ __export(exports_src, {
|
|
|
62
64
|
createLLM: () => createLLM,
|
|
63
65
|
createDefaultProviderRegistry: () => createDefaultProviderRegistry,
|
|
64
66
|
createAnthropicCompatibleAdapter: () => createAnthropicCompatibleAdapter,
|
|
67
|
+
conversation: () => conversation,
|
|
65
68
|
buildSelfHealPrompt: () => buildSelfHealPrompt,
|
|
66
69
|
buildDefaultStructuredPrompt: () => buildDefaultStructuredPrompt,
|
|
67
70
|
StructuredParseError: () => StructuredParseError,
|
|
@@ -3927,19 +3930,24 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
|
|
|
3927
3930
|
const resolvedPrompt = applyPromptOutdent(resolvePrompt(normalized.prompt, { mode }), useOutdent);
|
|
3928
3931
|
const resolvedSystemPrompt = applyOutdentToOptionalPrompt(normalized.systemPrompt, useOutdent);
|
|
3929
3932
|
const preparedPrompt = prepareStructuredPromptPayload(resolvedPrompt, resolvedSystemPrompt, normalized.schema, normalized.schemaInstruction);
|
|
3933
|
+
const resolvedRequest = normalized.timeout?.tool !== undefined && normalized.request?.mcpClients !== undefined ? {
|
|
3934
|
+
...normalized.request,
|
|
3935
|
+
mcpClients: applyToolTimeout(normalized.request.mcpClients, normalized.timeout.tool)
|
|
3936
|
+
} : normalized.request;
|
|
3930
3937
|
const first = await executeAttempt(adapter, {
|
|
3931
3938
|
prompt: preparedPrompt.prompt,
|
|
3932
3939
|
messages: preparedPrompt.messages,
|
|
3933
3940
|
schema: normalized.schema,
|
|
3934
3941
|
parseOptions,
|
|
3935
3942
|
stream: streamConfig,
|
|
3936
|
-
request:
|
|
3943
|
+
request: resolvedRequest,
|
|
3937
3944
|
systemPrompt: preparedPrompt.systemPrompt,
|
|
3938
3945
|
observe: normalized.observe,
|
|
3939
3946
|
debug: debugConfig,
|
|
3940
3947
|
attemptNumber: 1,
|
|
3941
3948
|
selfHeal: false,
|
|
3942
|
-
selfHealEnabled: selfHealConfig.enabled
|
|
3949
|
+
selfHealEnabled: selfHealConfig.enabled,
|
|
3950
|
+
timeout: normalized.timeout
|
|
3943
3951
|
});
|
|
3944
3952
|
attempts.push(first.trace);
|
|
3945
3953
|
if (first.trace.success) {
|
|
@@ -3993,13 +4001,14 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
|
|
|
3993
4001
|
schema: normalized.schema,
|
|
3994
4002
|
parseOptions,
|
|
3995
4003
|
stream: streamConfig,
|
|
3996
|
-
request:
|
|
4004
|
+
request: resolvedRequest,
|
|
3997
4005
|
systemPrompt: preparedPrompt.systemPrompt,
|
|
3998
4006
|
observe: normalized.observe,
|
|
3999
4007
|
debug: debugConfig,
|
|
4000
4008
|
attemptNumber,
|
|
4001
4009
|
selfHeal: true,
|
|
4002
|
-
selfHealEnabled: selfHealConfig.enabled
|
|
4010
|
+
selfHealEnabled: selfHealConfig.enabled,
|
|
4011
|
+
timeout: normalized.timeout
|
|
4003
4012
|
});
|
|
4004
4013
|
attempts.push(healed.trace);
|
|
4005
4014
|
if (healed.trace.success) {
|
|
@@ -4131,6 +4140,19 @@ function injectStructuredFormatIntoMessages(messages, schema, schemaInstruction)
|
|
|
4131
4140
|
throw new Error("Structured prompts with messages must include at least one user message.");
|
|
4132
4141
|
}
|
|
4133
4142
|
const target = messages[lastUserIndex];
|
|
4143
|
+
if (Array.isArray(target?.content)) {
|
|
4144
|
+
const parts = target.content;
|
|
4145
|
+
const textIndex = parts.findIndex((p) => p.type === "text");
|
|
4146
|
+
const existingText = textIndex !== -1 ? (parts[textIndex]?.text ?? "").trim() : "";
|
|
4147
|
+
const formatted2 = shouldInjectFormat(existingText, schemaInstruction) ? formatPrompt(schema, existingText, { schemaInstruction }) : existingText;
|
|
4148
|
+
let newParts;
|
|
4149
|
+
if (textIndex !== -1) {
|
|
4150
|
+
newParts = parts.map((p, i) => i === textIndex ? { ...p, text: formatted2 } : p);
|
|
4151
|
+
} else {
|
|
4152
|
+
newParts = [{ type: "text", text: formatted2 }, ...parts];
|
|
4153
|
+
}
|
|
4154
|
+
return messages.map((message, index) => index === lastUserIndex ? { ...message, content: newParts } : message);
|
|
4155
|
+
}
|
|
4134
4156
|
const content = typeof target?.content === "string" ? target.content.trim() : stringifyPromptContent(target?.content);
|
|
4135
4157
|
const formatted = shouldInjectFormat(content, schemaInstruction) ? formatPrompt(schema, content, { schemaInstruction }) : content.trim();
|
|
4136
4158
|
return messages.map((message, index) => index === lastUserIndex ? {
|
|
@@ -4345,7 +4367,8 @@ async function executeAttempt(adapter, input) {
|
|
|
4345
4367
|
debug: input.debug,
|
|
4346
4368
|
attempt: input.attemptNumber,
|
|
4347
4369
|
selfHeal: input.selfHeal,
|
|
4348
|
-
selfHealEnabled: input.selfHealEnabled
|
|
4370
|
+
selfHealEnabled: input.selfHealEnabled,
|
|
4371
|
+
timeout: input.timeout
|
|
4349
4372
|
});
|
|
4350
4373
|
const parsed = parseWithObserve(response.text, input.schema, input.parseOptions, {
|
|
4351
4374
|
observe: input.observe,
|
|
@@ -4372,7 +4395,29 @@ async function executeAttempt(adapter, input) {
|
|
|
4372
4395
|
trace
|
|
4373
4396
|
};
|
|
4374
4397
|
}
|
|
4398
|
+
function withToolTimeout(client, toolTimeoutMs) {
|
|
4399
|
+
return {
|
|
4400
|
+
id: client.id,
|
|
4401
|
+
listTools: client.listTools.bind(client),
|
|
4402
|
+
close: client.close?.bind(client),
|
|
4403
|
+
async callTool(params) {
|
|
4404
|
+
let timeoutId;
|
|
4405
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
4406
|
+
timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
|
|
4407
|
+
});
|
|
4408
|
+
try {
|
|
4409
|
+
return await Promise.race([client.callTool(params), timeoutPromise]);
|
|
4410
|
+
} finally {
|
|
4411
|
+
clearTimeout(timeoutId);
|
|
4412
|
+
}
|
|
4413
|
+
}
|
|
4414
|
+
};
|
|
4415
|
+
}
|
|
4416
|
+
function applyToolTimeout(clients, toolTimeoutMs) {
|
|
4417
|
+
return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
|
|
4418
|
+
}
|
|
4375
4419
|
async function callModel(adapter, options) {
|
|
4420
|
+
const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
|
|
4376
4421
|
const requestPayload = {
|
|
4377
4422
|
prompt: options.prompt,
|
|
4378
4423
|
messages: options.messages,
|
|
@@ -4386,7 +4431,7 @@ async function callModel(adapter, options) {
|
|
|
4386
4431
|
onToolExecution: options.request?.onToolExecution,
|
|
4387
4432
|
toolDebug: options.request?.toolDebug,
|
|
4388
4433
|
body: options.request?.body,
|
|
4389
|
-
signal:
|
|
4434
|
+
signal: requestSignal
|
|
4390
4435
|
};
|
|
4391
4436
|
emitDebugRequest(options.debug, {
|
|
4392
4437
|
provider: adapter.provider,
|
|
@@ -4769,7 +4814,8 @@ function mergeStructuredOptions(defaults, overrides) {
|
|
|
4769
4814
|
},
|
|
4770
4815
|
stream: mergeObjectLike(defaults?.stream, overrides?.stream),
|
|
4771
4816
|
selfHeal: mergeObjectLike(defaults?.selfHeal, overrides?.selfHeal),
|
|
4772
|
-
debug: mergeObjectLike(defaults?.debug, overrides?.debug)
|
|
4817
|
+
debug: mergeObjectLike(defaults?.debug, overrides?.debug),
|
|
4818
|
+
timeout: mergeObjectLike(defaults?.timeout, overrides?.timeout)
|
|
4773
4819
|
};
|
|
4774
4820
|
}
|
|
4775
4821
|
function mergeObjectLike(defaults, overrides) {
|
|
@@ -4858,6 +4904,63 @@ function toImplementation(clientInfo) {
|
|
|
4858
4904
|
version: clientInfo?.version ?? "0.1.0"
|
|
4859
4905
|
};
|
|
4860
4906
|
}
|
|
4907
|
+
// src/image.ts
|
|
4908
|
+
var import_path = require("path");
|
|
4909
|
+
var IMAGE_SIZE_MAP = {
|
|
4910
|
+
low: 256,
|
|
4911
|
+
mid: 512,
|
|
4912
|
+
high: 1024,
|
|
4913
|
+
xhigh: 1280
|
|
4914
|
+
};
|
|
4915
|
+
var IMAGE_MIME_TYPES = {
|
|
4916
|
+
".png": "image/png",
|
|
4917
|
+
".jpg": "image/jpeg",
|
|
4918
|
+
".jpeg": "image/jpeg",
|
|
4919
|
+
".gif": "image/gif",
|
|
4920
|
+
".webp": "image/webp"
|
|
4921
|
+
};
|
|
4922
|
+
var MIME_TO_SHARP_FORMAT = {
|
|
4923
|
+
"image/jpeg": "jpeg",
|
|
4924
|
+
"image/png": "png",
|
|
4925
|
+
"image/webp": "webp",
|
|
4926
|
+
"image/gif": "gif"
|
|
4927
|
+
};
|
|
4928
|
+
function images(input) {
|
|
4929
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
4930
|
+
return inputs.map(({ base64, mimeType }) => ({
|
|
4931
|
+
type: "image_url",
|
|
4932
|
+
image_url: { url: `data:${mimeType};base64,${base64}` }
|
|
4933
|
+
}));
|
|
4934
|
+
}
|
|
4935
|
+
async function resizeImage(source, size, mimeType) {
|
|
4936
|
+
const resolvedMime = mimeType ?? (typeof source === "string" ? IMAGE_MIME_TYPES[import_path.extname(source).toLowerCase()] ?? "image/jpeg" : "image/jpeg");
|
|
4937
|
+
let sharp;
|
|
4938
|
+
try {
|
|
4939
|
+
sharp = (await import("sharp")).default;
|
|
4940
|
+
} catch {
|
|
4941
|
+
throw new Error('resizeImage() requires "sharp" to be installed. Run: bun add sharp');
|
|
4942
|
+
}
|
|
4943
|
+
const input = source instanceof ArrayBuffer ? Buffer.from(source) : source;
|
|
4944
|
+
let img = sharp(input);
|
|
4945
|
+
if (size !== "raw") {
|
|
4946
|
+
const targetPx = typeof size === "number" ? size : IMAGE_SIZE_MAP[size];
|
|
4947
|
+
img = img.resize(targetPx, targetPx, { fit: "inside", withoutEnlargement: true });
|
|
4948
|
+
}
|
|
4949
|
+
const sharpFormat = MIME_TO_SHARP_FORMAT[resolvedMime] ?? "jpeg";
|
|
4950
|
+
const outputMime = MIME_TO_SHARP_FORMAT[resolvedMime] ? resolvedMime : "image/jpeg";
|
|
4951
|
+
const buf = await img.toFormat(sharpFormat).toBuffer();
|
|
4952
|
+
return { base64: buf.toString("base64"), mimeType: outputMime };
|
|
4953
|
+
}
|
|
4954
|
+
// src/conversation.ts
|
|
4955
|
+
function conversation(systemPrompt, entries) {
|
|
4956
|
+
return [
|
|
4957
|
+
{ role: "system", content: systemPrompt },
|
|
4958
|
+
...entries.map((entry) => ({
|
|
4959
|
+
role: entry.role,
|
|
4960
|
+
content: entry.images && entry.images.length > 0 ? [{ type: "text", text: entry.text }, ...images(entry.images)] : entry.text
|
|
4961
|
+
}))
|
|
4962
|
+
];
|
|
4963
|
+
}
|
|
4861
4964
|
// src/prompt.ts
|
|
4862
4965
|
function toPromptString(value) {
|
|
4863
4966
|
if (value === null || value === undefined) {
|
|
@@ -4932,6 +5035,12 @@ class PromptMessageBuilderImpl {
|
|
|
4932
5035
|
return this.pushMessage("assistant", input, values);
|
|
4933
5036
|
}
|
|
4934
5037
|
pushMessage(role, input, values) {
|
|
5038
|
+
if (Array.isArray(input) && !isTemplateStringsArray(input)) {
|
|
5039
|
+
if (input.length > 0) {
|
|
5040
|
+
this.messages.push({ role, content: input });
|
|
5041
|
+
}
|
|
5042
|
+
return this;
|
|
5043
|
+
}
|
|
4935
5044
|
const message = toPromptMessage(input, values);
|
|
4936
5045
|
if (message.length > 0) {
|
|
4937
5046
|
this.messages.push({ role, content: message });
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export { sanitizeThink } from "./think";
|
|
|
5
5
|
export { createLLM, type CreateLLMOptions, type LLMClient } from "./llm";
|
|
6
6
|
export { formatZodIssues, parseLLMOutput } from "./parse";
|
|
7
7
|
export { createMCPClient, wrapMCPClient, type CreateMCPClientOptions, type MCPClientInfo, type MCPInMemoryTransportConfig, type MCPStdioTransportConfig, type MCPStreamableHTTPTransportConfig, type MCPTransportConfig, type ManagedMCPToolClient, } from "./mcp";
|
|
8
|
+
export { images, resizeImage, type ImageInput, type ImageSize } from "./image";
|
|
9
|
+
export { conversation, type ConversationEntry } from "./conversation";
|
|
8
10
|
export { prompt, type PromptMessageBuilder } from "./prompt";
|
|
9
11
|
export { s, inspectSchemaMetadata, inferSchemaExample } from "./schema-builder";
|
|
10
12
|
export { buildDefaultStructuredPrompt, DEFAULT_LOOSE_PARSE_OPTIONS, DEFAULT_SELF_HEAL_BY_MODE, DEFAULT_SELF_HEAL_CONTEXT_LABEL, DEFAULT_SELF_HEAL_FIX_INSTRUCTION, DEFAULT_SELF_HEAL_MAX_CONTEXT_CHARS, DEFAULT_SELF_HEAL_NO_ISSUES_MESSAGE, DEFAULT_SELF_HEAL_PROTOCOL, DEFAULT_SELF_HEAL_RAW_OUTPUT_LABEL, DEFAULT_SELF_HEAL_RETURN_INSTRUCTION, DEFAULT_SELF_HEAL_STOP_ON_NO_PROGRESS, DEFAULT_SELF_HEAL_VALIDATION_LABEL, DEFAULT_STRICT_PARSE_OPTIONS, DEFAULT_STRUCTURED_OBJECT_INSTRUCTION, DEFAULT_STRUCTURED_STYLE_INSTRUCTION, buildSelfHealPrompt, structured, StructuredParseError, type BuildDefaultStructuredPromptOptions, type SelfHealPromptTextOptions, } from "./structured";
|
|
@@ -12,4 +14,4 @@ export { createOpenAICompatibleAdapter, type OpenAICompatibleAdapterOptions, } f
|
|
|
12
14
|
export { createAnthropicCompatibleAdapter, DEFAULT_ANTHROPIC_MAX_TOKENS, DEFAULT_ANTHROPIC_VERSION, type AnthropicCompatibleAdapterOptions, } from "./providers/anthropic-compatible";
|
|
13
15
|
export { DEFAULT_MAX_TOOL_ROUNDS } from "./providers/mcp-runtime";
|
|
14
16
|
export { createDefaultProviderRegistry, createModelAdapter, createProviderRegistry, registerBuiltinProviders, type BuiltinProviderKind, type ModelAdapterConfig, type ProviderFactory, type ProviderRegistry, type ProviderTransportConfig, } from "./providers/registry";
|
|
15
|
-
export type { CandidateDiagnostics, ExtractJsonCandidatesOptions, ExtractionCandidate, ExtractionHeuristicsOptions, ExtractionParseHint, HTTPHeaders, LLMAdapter, LLMMessage, LLMRequest, LLMResponse, LLMStreamCallbacks, LLMStreamChunk, LLMToolCall, LLMToolDebugOptions, LLMToolExecution, LLMToolOutputTransformer, LLMToolArgumentsTransformer, LLMToolChoice, MCPCallToolParams, MCPListToolsResult, MCPToolClient, MCPToolDescriptor, MCPToolSchema, LLMUsage, MarkdownCodeBlock, MarkdownCodeOptions, ParseLLMOutputOptions, ParseLLMOutputResult, ParseTraceEvent, PipelineError, StructuredAttempt, StructuredCallOptions, StructuredDebugOptions, StructuredError, StructuredMode, StructuredOptions, StructuredPromptBuilder, StructuredPromptContext, StructuredPromptPayload, StructuredPromptResolver, StructuredPromptValue, StructuredResult, StructuredStreamData, StructuredStreamEvent, StructuredStreamInput, StructuredStreamOptions, StructuredSelfHealInput, ThinkDiagnostics, ThinkBlock, StructuredTraceEvent, } from "./types";
|
|
17
|
+
export type { CandidateDiagnostics, LLMImageContent, LLMMessageContent, LLMTextContent, ExtractJsonCandidatesOptions, ExtractionCandidate, ExtractionHeuristicsOptions, ExtractionParseHint, HTTPHeaders, LLMAdapter, LLMMessage, LLMRequest, LLMResponse, LLMStreamCallbacks, LLMStreamChunk, LLMToolCall, LLMToolDebugOptions, LLMToolExecution, LLMToolOutputTransformer, LLMToolArgumentsTransformer, LLMToolChoice, MCPCallToolParams, MCPListToolsResult, MCPToolClient, MCPToolDescriptor, MCPToolSchema, LLMUsage, MarkdownCodeBlock, MarkdownCodeOptions, ParseLLMOutputOptions, ParseLLMOutputResult, ParseTraceEvent, PipelineError, StructuredAttempt, StructuredCallOptions, StructuredDebugOptions, StructuredError, StructuredMode, StructuredOptions, StructuredPromptBuilder, StructuredPromptContext, StructuredPromptPayload, StructuredPromptResolver, StructuredPromptValue, StructuredResult, StructuredStreamData, StructuredStreamEvent, StructuredStreamInput, StructuredStreamOptions, StructuredSelfHealInput, StructuredTimeoutOptions, ThinkDiagnostics, ThinkBlock, StructuredTraceEvent, } from "./types";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
1
4
|
// src/extract.ts
|
|
2
5
|
import { jsonrepair } from "jsonrepair";
|
|
3
6
|
|
|
@@ -3838,19 +3841,24 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
|
|
|
3838
3841
|
const resolvedPrompt = applyPromptOutdent(resolvePrompt(normalized.prompt, { mode }), useOutdent);
|
|
3839
3842
|
const resolvedSystemPrompt = applyOutdentToOptionalPrompt(normalized.systemPrompt, useOutdent);
|
|
3840
3843
|
const preparedPrompt = prepareStructuredPromptPayload(resolvedPrompt, resolvedSystemPrompt, normalized.schema, normalized.schemaInstruction);
|
|
3844
|
+
const resolvedRequest = normalized.timeout?.tool !== undefined && normalized.request?.mcpClients !== undefined ? {
|
|
3845
|
+
...normalized.request,
|
|
3846
|
+
mcpClients: applyToolTimeout(normalized.request.mcpClients, normalized.timeout.tool)
|
|
3847
|
+
} : normalized.request;
|
|
3841
3848
|
const first = await executeAttempt(adapter, {
|
|
3842
3849
|
prompt: preparedPrompt.prompt,
|
|
3843
3850
|
messages: preparedPrompt.messages,
|
|
3844
3851
|
schema: normalized.schema,
|
|
3845
3852
|
parseOptions,
|
|
3846
3853
|
stream: streamConfig,
|
|
3847
|
-
request:
|
|
3854
|
+
request: resolvedRequest,
|
|
3848
3855
|
systemPrompt: preparedPrompt.systemPrompt,
|
|
3849
3856
|
observe: normalized.observe,
|
|
3850
3857
|
debug: debugConfig,
|
|
3851
3858
|
attemptNumber: 1,
|
|
3852
3859
|
selfHeal: false,
|
|
3853
|
-
selfHealEnabled: selfHealConfig.enabled
|
|
3860
|
+
selfHealEnabled: selfHealConfig.enabled,
|
|
3861
|
+
timeout: normalized.timeout
|
|
3854
3862
|
});
|
|
3855
3863
|
attempts.push(first.trace);
|
|
3856
3864
|
if (first.trace.success) {
|
|
@@ -3904,13 +3912,14 @@ async function structured(adapter, schemaOrOptions, promptInput, callOptions) {
|
|
|
3904
3912
|
schema: normalized.schema,
|
|
3905
3913
|
parseOptions,
|
|
3906
3914
|
stream: streamConfig,
|
|
3907
|
-
request:
|
|
3915
|
+
request: resolvedRequest,
|
|
3908
3916
|
systemPrompt: preparedPrompt.systemPrompt,
|
|
3909
3917
|
observe: normalized.observe,
|
|
3910
3918
|
debug: debugConfig,
|
|
3911
3919
|
attemptNumber,
|
|
3912
3920
|
selfHeal: true,
|
|
3913
|
-
selfHealEnabled: selfHealConfig.enabled
|
|
3921
|
+
selfHealEnabled: selfHealConfig.enabled,
|
|
3922
|
+
timeout: normalized.timeout
|
|
3914
3923
|
});
|
|
3915
3924
|
attempts.push(healed.trace);
|
|
3916
3925
|
if (healed.trace.success) {
|
|
@@ -4042,6 +4051,19 @@ function injectStructuredFormatIntoMessages(messages, schema, schemaInstruction)
|
|
|
4042
4051
|
throw new Error("Structured prompts with messages must include at least one user message.");
|
|
4043
4052
|
}
|
|
4044
4053
|
const target = messages[lastUserIndex];
|
|
4054
|
+
if (Array.isArray(target?.content)) {
|
|
4055
|
+
const parts = target.content;
|
|
4056
|
+
const textIndex = parts.findIndex((p) => p.type === "text");
|
|
4057
|
+
const existingText = textIndex !== -1 ? (parts[textIndex]?.text ?? "").trim() : "";
|
|
4058
|
+
const formatted2 = shouldInjectFormat(existingText, schemaInstruction) ? formatPrompt(schema, existingText, { schemaInstruction }) : existingText;
|
|
4059
|
+
let newParts;
|
|
4060
|
+
if (textIndex !== -1) {
|
|
4061
|
+
newParts = parts.map((p, i) => i === textIndex ? { ...p, text: formatted2 } : p);
|
|
4062
|
+
} else {
|
|
4063
|
+
newParts = [{ type: "text", text: formatted2 }, ...parts];
|
|
4064
|
+
}
|
|
4065
|
+
return messages.map((message, index) => index === lastUserIndex ? { ...message, content: newParts } : message);
|
|
4066
|
+
}
|
|
4045
4067
|
const content = typeof target?.content === "string" ? target.content.trim() : stringifyPromptContent(target?.content);
|
|
4046
4068
|
const formatted = shouldInjectFormat(content, schemaInstruction) ? formatPrompt(schema, content, { schemaInstruction }) : content.trim();
|
|
4047
4069
|
return messages.map((message, index) => index === lastUserIndex ? {
|
|
@@ -4256,7 +4278,8 @@ async function executeAttempt(adapter, input) {
|
|
|
4256
4278
|
debug: input.debug,
|
|
4257
4279
|
attempt: input.attemptNumber,
|
|
4258
4280
|
selfHeal: input.selfHeal,
|
|
4259
|
-
selfHealEnabled: input.selfHealEnabled
|
|
4281
|
+
selfHealEnabled: input.selfHealEnabled,
|
|
4282
|
+
timeout: input.timeout
|
|
4260
4283
|
});
|
|
4261
4284
|
const parsed = parseWithObserve(response.text, input.schema, input.parseOptions, {
|
|
4262
4285
|
observe: input.observe,
|
|
@@ -4283,7 +4306,29 @@ async function executeAttempt(adapter, input) {
|
|
|
4283
4306
|
trace
|
|
4284
4307
|
};
|
|
4285
4308
|
}
|
|
4309
|
+
function withToolTimeout(client, toolTimeoutMs) {
|
|
4310
|
+
return {
|
|
4311
|
+
id: client.id,
|
|
4312
|
+
listTools: client.listTools.bind(client),
|
|
4313
|
+
close: client.close?.bind(client),
|
|
4314
|
+
async callTool(params) {
|
|
4315
|
+
let timeoutId;
|
|
4316
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
4317
|
+
timeoutId = setTimeout(() => reject(new Error(`Tool call timed out after ${toolTimeoutMs}ms`)), toolTimeoutMs);
|
|
4318
|
+
});
|
|
4319
|
+
try {
|
|
4320
|
+
return await Promise.race([client.callTool(params), timeoutPromise]);
|
|
4321
|
+
} finally {
|
|
4322
|
+
clearTimeout(timeoutId);
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
};
|
|
4326
|
+
}
|
|
4327
|
+
function applyToolTimeout(clients, toolTimeoutMs) {
|
|
4328
|
+
return clients.map((client) => withToolTimeout(client, toolTimeoutMs));
|
|
4329
|
+
}
|
|
4286
4330
|
async function callModel(adapter, options) {
|
|
4331
|
+
const requestSignal = options.request?.signal ?? (options.timeout?.request !== undefined ? AbortSignal.timeout(options.timeout.request) : undefined);
|
|
4287
4332
|
const requestPayload = {
|
|
4288
4333
|
prompt: options.prompt,
|
|
4289
4334
|
messages: options.messages,
|
|
@@ -4297,7 +4342,7 @@ async function callModel(adapter, options) {
|
|
|
4297
4342
|
onToolExecution: options.request?.onToolExecution,
|
|
4298
4343
|
toolDebug: options.request?.toolDebug,
|
|
4299
4344
|
body: options.request?.body,
|
|
4300
|
-
signal:
|
|
4345
|
+
signal: requestSignal
|
|
4301
4346
|
};
|
|
4302
4347
|
emitDebugRequest(options.debug, {
|
|
4303
4348
|
provider: adapter.provider,
|
|
@@ -4680,7 +4725,8 @@ function mergeStructuredOptions(defaults, overrides) {
|
|
|
4680
4725
|
},
|
|
4681
4726
|
stream: mergeObjectLike(defaults?.stream, overrides?.stream),
|
|
4682
4727
|
selfHeal: mergeObjectLike(defaults?.selfHeal, overrides?.selfHeal),
|
|
4683
|
-
debug: mergeObjectLike(defaults?.debug, overrides?.debug)
|
|
4728
|
+
debug: mergeObjectLike(defaults?.debug, overrides?.debug),
|
|
4729
|
+
timeout: mergeObjectLike(defaults?.timeout, overrides?.timeout)
|
|
4684
4730
|
};
|
|
4685
4731
|
}
|
|
4686
4732
|
function mergeObjectLike(defaults, overrides) {
|
|
@@ -4773,6 +4819,63 @@ function toImplementation(clientInfo) {
|
|
|
4773
4819
|
version: clientInfo?.version ?? "0.1.0"
|
|
4774
4820
|
};
|
|
4775
4821
|
}
|
|
4822
|
+
// src/image.ts
|
|
4823
|
+
import { extname } from "path";
|
|
4824
|
+
var IMAGE_SIZE_MAP = {
|
|
4825
|
+
low: 256,
|
|
4826
|
+
mid: 512,
|
|
4827
|
+
high: 1024,
|
|
4828
|
+
xhigh: 1280
|
|
4829
|
+
};
|
|
4830
|
+
var IMAGE_MIME_TYPES = {
|
|
4831
|
+
".png": "image/png",
|
|
4832
|
+
".jpg": "image/jpeg",
|
|
4833
|
+
".jpeg": "image/jpeg",
|
|
4834
|
+
".gif": "image/gif",
|
|
4835
|
+
".webp": "image/webp"
|
|
4836
|
+
};
|
|
4837
|
+
var MIME_TO_SHARP_FORMAT = {
|
|
4838
|
+
"image/jpeg": "jpeg",
|
|
4839
|
+
"image/png": "png",
|
|
4840
|
+
"image/webp": "webp",
|
|
4841
|
+
"image/gif": "gif"
|
|
4842
|
+
};
|
|
4843
|
+
function images(input) {
|
|
4844
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
4845
|
+
return inputs.map(({ base64, mimeType }) => ({
|
|
4846
|
+
type: "image_url",
|
|
4847
|
+
image_url: { url: `data:${mimeType};base64,${base64}` }
|
|
4848
|
+
}));
|
|
4849
|
+
}
|
|
4850
|
+
async function resizeImage(source, size, mimeType) {
|
|
4851
|
+
const resolvedMime = mimeType ?? (typeof source === "string" ? IMAGE_MIME_TYPES[extname(source).toLowerCase()] ?? "image/jpeg" : "image/jpeg");
|
|
4852
|
+
let sharp;
|
|
4853
|
+
try {
|
|
4854
|
+
sharp = (await import("sharp")).default;
|
|
4855
|
+
} catch {
|
|
4856
|
+
throw new Error('resizeImage() requires "sharp" to be installed. Run: bun add sharp');
|
|
4857
|
+
}
|
|
4858
|
+
const input = source instanceof ArrayBuffer ? Buffer.from(source) : source;
|
|
4859
|
+
let img = sharp(input);
|
|
4860
|
+
if (size !== "raw") {
|
|
4861
|
+
const targetPx = typeof size === "number" ? size : IMAGE_SIZE_MAP[size];
|
|
4862
|
+
img = img.resize(targetPx, targetPx, { fit: "inside", withoutEnlargement: true });
|
|
4863
|
+
}
|
|
4864
|
+
const sharpFormat = MIME_TO_SHARP_FORMAT[resolvedMime] ?? "jpeg";
|
|
4865
|
+
const outputMime = MIME_TO_SHARP_FORMAT[resolvedMime] ? resolvedMime : "image/jpeg";
|
|
4866
|
+
const buf = await img.toFormat(sharpFormat).toBuffer();
|
|
4867
|
+
return { base64: buf.toString("base64"), mimeType: outputMime };
|
|
4868
|
+
}
|
|
4869
|
+
// src/conversation.ts
|
|
4870
|
+
function conversation(systemPrompt, entries) {
|
|
4871
|
+
return [
|
|
4872
|
+
{ role: "system", content: systemPrompt },
|
|
4873
|
+
...entries.map((entry) => ({
|
|
4874
|
+
role: entry.role,
|
|
4875
|
+
content: entry.images && entry.images.length > 0 ? [{ type: "text", text: entry.text }, ...images(entry.images)] : entry.text
|
|
4876
|
+
}))
|
|
4877
|
+
];
|
|
4878
|
+
}
|
|
4776
4879
|
// src/prompt.ts
|
|
4777
4880
|
function toPromptString(value) {
|
|
4778
4881
|
if (value === null || value === undefined) {
|
|
@@ -4847,6 +4950,12 @@ class PromptMessageBuilderImpl {
|
|
|
4847
4950
|
return this.pushMessage("assistant", input, values);
|
|
4848
4951
|
}
|
|
4849
4952
|
pushMessage(role, input, values) {
|
|
4953
|
+
if (Array.isArray(input) && !isTemplateStringsArray(input)) {
|
|
4954
|
+
if (input.length > 0) {
|
|
4955
|
+
this.messages.push({ role, content: input });
|
|
4956
|
+
}
|
|
4957
|
+
return this;
|
|
4958
|
+
}
|
|
4850
4959
|
const message = toPromptMessage(input, values);
|
|
4851
4960
|
if (message.length > 0) {
|
|
4852
4961
|
this.messages.push({ role, content: message });
|
|
@@ -5058,11 +5167,13 @@ export {
|
|
|
5058
5167
|
sanitizeThink,
|
|
5059
5168
|
s,
|
|
5060
5169
|
resolveSchemaInstruction,
|
|
5170
|
+
resizeImage,
|
|
5061
5171
|
registerBuiltinProviders,
|
|
5062
5172
|
prompt,
|
|
5063
5173
|
parseLLMOutput,
|
|
5064
5174
|
inspectSchemaMetadata,
|
|
5065
5175
|
inferSchemaExample,
|
|
5176
|
+
images,
|
|
5066
5177
|
formatZodIssues,
|
|
5067
5178
|
formatPrompt,
|
|
5068
5179
|
extractMarkdownCodeBlocks,
|
|
@@ -5075,6 +5186,7 @@ export {
|
|
|
5075
5186
|
createLLM,
|
|
5076
5187
|
createDefaultProviderRegistry,
|
|
5077
5188
|
createAnthropicCompatibleAdapter,
|
|
5189
|
+
conversation,
|
|
5078
5190
|
buildSelfHealPrompt,
|
|
5079
5191
|
buildDefaultStructuredPrompt,
|
|
5080
5192
|
StructuredParseError,
|
package/dist/prompt.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import type { StructuredPromptPayload, StructuredPromptResolver } from "./types";
|
|
1
|
+
import type { LLMMessageContent, StructuredPromptPayload, StructuredPromptResolver } from "./types";
|
|
2
2
|
export interface PromptMessageBuilder extends StructuredPromptResolver {
|
|
3
3
|
system(input: string): PromptMessageBuilder;
|
|
4
4
|
system(strings: TemplateStringsArray, ...values: unknown[]): PromptMessageBuilder;
|
|
5
5
|
user(input: string): PromptMessageBuilder;
|
|
6
6
|
user(strings: TemplateStringsArray, ...values: unknown[]): PromptMessageBuilder;
|
|
7
|
+
user(content: LLMMessageContent): PromptMessageBuilder;
|
|
7
8
|
assistant(input: string): PromptMessageBuilder;
|
|
8
9
|
assistant(strings: TemplateStringsArray, ...values: unknown[]): PromptMessageBuilder;
|
|
10
|
+
assistant(content: LLMMessageContent): PromptMessageBuilder;
|
|
9
11
|
build(): StructuredPromptPayload;
|
|
10
12
|
}
|
|
11
13
|
export declare function prompt(strings: TemplateStringsArray, ...values: unknown[]): string;
|
package/dist/types.d.ts
CHANGED
|
@@ -119,9 +119,20 @@ export interface MCPToolClient {
|
|
|
119
119
|
callTool(params: MCPCallToolParams): Promise<unknown>;
|
|
120
120
|
close?(): Promise<void>;
|
|
121
121
|
}
|
|
122
|
+
export interface LLMTextContent {
|
|
123
|
+
type: "text";
|
|
124
|
+
text: string;
|
|
125
|
+
}
|
|
126
|
+
export interface LLMImageContent {
|
|
127
|
+
type: "image_url";
|
|
128
|
+
image_url: {
|
|
129
|
+
url: string;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export type LLMMessageContent = string | (LLMTextContent | LLMImageContent)[];
|
|
122
133
|
export interface LLMMessage {
|
|
123
134
|
role: "system" | "user" | "assistant" | "tool";
|
|
124
|
-
content:
|
|
135
|
+
content: LLMMessageContent;
|
|
125
136
|
}
|
|
126
137
|
export interface LLMRequest {
|
|
127
138
|
prompt?: string;
|
|
@@ -250,6 +261,12 @@ export interface StructuredSelfHealOptions {
|
|
|
250
261
|
maxContextChars?: number;
|
|
251
262
|
}
|
|
252
263
|
export type StructuredSelfHealInput = boolean | number | StructuredSelfHealOptions;
|
|
264
|
+
export interface StructuredTimeoutOptions {
|
|
265
|
+
/** Timeout in ms for each LLM HTTP request. Creates an AbortSignal.timeout internally if no signal is already provided. */
|
|
266
|
+
request?: number;
|
|
267
|
+
/** Timeout in ms for each MCP tool call. */
|
|
268
|
+
tool?: number;
|
|
269
|
+
}
|
|
253
270
|
export type StructuredStreamData<T> = T extends Array<infer TItem> ? Array<StructuredStreamData<TItem>> : T extends object ? {
|
|
254
271
|
[K in keyof T]?: StructuredStreamData<T[K]> | null;
|
|
255
272
|
} : T | null;
|
|
@@ -277,6 +294,7 @@ export interface StructuredCallOptions<TSchema extends z.ZodTypeAny> {
|
|
|
277
294
|
systemPrompt?: string;
|
|
278
295
|
request?: Omit<LLMRequest, "prompt" | "systemPrompt" | "messages">;
|
|
279
296
|
schemaInstruction?: string;
|
|
297
|
+
timeout?: StructuredTimeoutOptions;
|
|
280
298
|
}
|
|
281
299
|
export interface StructuredOptions<TSchema extends z.ZodTypeAny> extends StructuredCallOptions<TSchema> {
|
|
282
300
|
schema: TSchema;
|
package/package.json
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "extrait",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"license": "MIT",
|
|
3
|
+
"version": "0.5.3",
|
|
5
4
|
"repository": {
|
|
6
5
|
"type": "git",
|
|
7
6
|
"url": "git+https://github.com/tterrasson/extrait.git"
|
|
8
7
|
},
|
|
9
|
-
"bugs": {
|
|
10
|
-
"url": "https://github.com/tterrasson/extrait/issues"
|
|
11
|
-
},
|
|
12
8
|
"main": "./dist/index.cjs",
|
|
13
9
|
"module": "./dist/index.js",
|
|
14
|
-
"
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
12
|
+
"jsonrepair": "^3.13.2",
|
|
13
|
+
"zod": "^4.3.6"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/bun": "^1.3.10",
|
|
17
|
+
"@types/sharp": "^0.32.0",
|
|
18
|
+
"typescript": "^5.9.3"
|
|
19
|
+
},
|
|
15
20
|
"exports": {
|
|
16
21
|
".": {
|
|
17
22
|
"types": "./dist/index.d.ts",
|
|
@@ -20,12 +25,29 @@
|
|
|
20
25
|
"default": "./dist/index.js"
|
|
21
26
|
}
|
|
22
27
|
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/tterrasson/extrait/issues"
|
|
30
|
+
},
|
|
23
31
|
"files": [
|
|
24
32
|
"dist",
|
|
25
33
|
"README.md",
|
|
26
34
|
"LICENSE"
|
|
27
35
|
],
|
|
28
|
-
"
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"overrides": {
|
|
38
|
+
"zod": "^4.3.6"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"sharp": "^0.34.5"
|
|
42
|
+
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"sharp": {
|
|
45
|
+
"optional": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"resolutions": {
|
|
49
|
+
"zod": "^4.3.6"
|
|
50
|
+
},
|
|
29
51
|
"scripts": {
|
|
30
52
|
"dev": "bun run examples/runner.ts",
|
|
31
53
|
"build": "bun run build:esm && bun run build:cjs",
|
|
@@ -38,19 +60,6 @@
|
|
|
38
60
|
"typecheck": "bunx tsc --noEmit",
|
|
39
61
|
"pack": "bun run build:types && bun run build && npm pack"
|
|
40
62
|
},
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
"jsonrepair": "^3.13.2",
|
|
44
|
-
"zod": "^4.3.6"
|
|
45
|
-
},
|
|
46
|
-
"devDependencies": {
|
|
47
|
-
"@types/bun": "^1.3.10",
|
|
48
|
-
"typescript": "^5.9.3"
|
|
49
|
-
},
|
|
50
|
-
"overrides": {
|
|
51
|
-
"zod": "^4.3.6"
|
|
52
|
-
},
|
|
53
|
-
"resolutions": {
|
|
54
|
-
"zod": "^4.3.6"
|
|
55
|
-
}
|
|
63
|
+
"type": "module",
|
|
64
|
+
"types": "./dist/index.d.ts"
|
|
56
65
|
}
|