extrait 0.3.1 → 0.4.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 CHANGED
@@ -233,6 +233,7 @@ Run examples with: `bun run dev <example-name>`
233
233
  Available examples:
234
234
  - `streaming` - Real LLM streaming + snapshot self-check ([streaming.ts](examples/streaming.ts))
235
235
  - `streaming-with-tools` - Real text streaming with MCP tools + self-check ([streaming-with-tools.ts](examples/streaming-with-tools.ts))
236
+ - `abort-signal` - Start a generation then cancel quickly with `AbortSignal` ([abort-signal.ts](examples/abort-signal.ts))
236
237
  - `simple` - Basic structured output with streaming ([simple.ts](examples/simple.ts))
237
238
  - `sentiment-analysis` - Enum validation, strict mode ([sentiment-analysis.ts](examples/sentiment-analysis.ts))
238
239
  - `data-extraction` - Complex nested schemas, self-healing ([data-extraction.ts](examples/data-extraction.ts))
@@ -243,6 +244,7 @@ Pass arguments after the example name:
243
244
  ```bash
244
245
  bun run dev streaming
245
246
  bun run dev streaming-with-tools
247
+ bun run dev abort-signal 120 "JSON cancellation demo"
246
248
  bun run dev simple "Bun.js runtime"
247
249
  bun run dev sentiment-analysis "I love this product."
248
250
  bun run dev multi-step-reasoning "Why is the sky blue?"
package/dist/index.cjs CHANGED
@@ -1324,7 +1324,12 @@ async function executeMCPToolCalls(calls, toolset, context) {
1324
1324
  out.push({ call: metadata2, execution });
1325
1325
  continue;
1326
1326
  }
1327
- const args = isRecord(parsedArguments) ? parsedArguments : {};
1327
+ const rawArgs = isRecord(parsedArguments) ? parsedArguments : {};
1328
+ const args = context.request.transformToolArguments ? await context.request.transformToolArguments(rawArgs, {
1329
+ name: toolName,
1330
+ remoteName: tool.remoteName,
1331
+ clientId: tool.clientId
1332
+ }) : rawArgs;
1328
1333
  const metadata = {
1329
1334
  id: callId,
1330
1335
  type: call.type ?? "function",
@@ -1643,7 +1648,8 @@ function createOpenAICompatibleAdapter(options) {
1643
1648
  temperature: request.temperature,
1644
1649
  max_tokens: request.maxTokens,
1645
1650
  stream: true
1646
- }))
1651
+ })),
1652
+ signal: request.signal
1647
1653
  });
1648
1654
  if (!response.ok) {
1649
1655
  const message = await response.text();
@@ -1714,7 +1720,8 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
1714
1720
  temperature: request.temperature,
1715
1721
  max_tokens: request.maxTokens,
1716
1722
  stream: false
1717
- }))
1723
+ })),
1724
+ signal: request.signal
1718
1725
  });
1719
1726
  if (!response.ok) {
1720
1727
  const message = await response.text();
@@ -1758,7 +1765,8 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1758
1765
  tools: transportTools,
1759
1766
  tool_choice: request.toolChoice,
1760
1767
  parallel_tool_calls: request.parallelToolCalls
1761
- }))
1768
+ })),
1769
+ signal: request.signal
1762
1770
  });
1763
1771
  if (!response.ok) {
1764
1772
  const message = await response.text();
@@ -1823,7 +1831,8 @@ async function completeWithResponsesAPIPassThrough(options, fetcher, path, reque
1823
1831
  previous_response_id: pickString(body?.previous_response_id),
1824
1832
  temperature: request.temperature,
1825
1833
  max_output_tokens: request.maxTokens
1826
- }))
1834
+ })),
1835
+ signal: request.signal
1827
1836
  });
1828
1837
  if (!response.ok) {
1829
1838
  const message = await response.text();
@@ -1865,7 +1874,8 @@ async function completeWithResponsesAPIWithMCP(options, fetcher, path, request)
1865
1874
  tools: transportTools,
1866
1875
  tool_choice: request.toolChoice,
1867
1876
  parallel_tool_calls: request.parallelToolCalls
1868
- }))
1877
+ })),
1878
+ signal: request.signal
1869
1879
  });
1870
1880
  if (!response.ok) {
1871
1881
  const message = await response.text();
@@ -1941,7 +1951,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1941
1951
  tool_choice: request.toolChoice,
1942
1952
  parallel_tool_calls: request.parallelToolCalls,
1943
1953
  stream: true
1944
- }))
1954
+ })),
1955
+ signal: request.signal
1945
1956
  });
1946
1957
  if (!response.ok) {
1947
1958
  const message = await response.text();
@@ -2043,7 +2054,8 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
2043
2054
  temperature: request.temperature,
2044
2055
  max_output_tokens: request.maxTokens,
2045
2056
  stream: true
2046
- }))
2057
+ })),
2058
+ signal: request.signal
2047
2059
  });
2048
2060
  if (!response.ok) {
2049
2061
  const message = await response.text();
@@ -2125,7 +2137,8 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
2125
2137
  tool_choice: request.toolChoice,
2126
2138
  parallel_tool_calls: request.parallelToolCalls,
2127
2139
  stream: true
2128
- }))
2140
+ })),
2141
+ signal: request.signal
2129
2142
  });
2130
2143
  if (!response.ok) {
2131
2144
  const message = await response.text();
@@ -2689,7 +2702,8 @@ function createAnthropicCompatibleAdapter(options) {
2689
2702
  temperature: request.temperature,
2690
2703
  max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2691
2704
  stream: true
2692
- }))
2705
+ })),
2706
+ signal: request.signal
2693
2707
  });
2694
2708
  if (!response.ok) {
2695
2709
  const message = await response.text();
@@ -2747,7 +2761,8 @@ async function completePassThrough(options, fetcher, path, request) {
2747
2761
  temperature: request.temperature,
2748
2762
  max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2749
2763
  stream: false
2750
- }))
2764
+ })),
2765
+ signal: request.signal
2751
2766
  });
2752
2767
  if (!response.ok) {
2753
2768
  const message = await response.text();
@@ -2792,7 +2807,8 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
2792
2807
  tools,
2793
2808
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2794
2809
  stream: false
2795
- }))
2810
+ })),
2811
+ signal: request.signal
2796
2812
  });
2797
2813
  if (!response.ok) {
2798
2814
  const message = await response.text();
@@ -2875,7 +2891,8 @@ async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks)
2875
2891
  tools,
2876
2892
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2877
2893
  stream: true
2878
- }))
2894
+ })),
2895
+ signal: request.signal
2879
2896
  });
2880
2897
  if (!response.ok) {
2881
2898
  const message = await response.text();
@@ -4252,7 +4269,8 @@ async function callModel(adapter, options) {
4252
4269
  maxToolRounds: options.request?.maxToolRounds,
4253
4270
  onToolExecution: options.request?.onToolExecution,
4254
4271
  toolDebug: options.request?.toolDebug,
4255
- body: options.request?.body
4272
+ body: options.request?.body,
4273
+ signal: options.request?.signal
4256
4274
  };
4257
4275
  emitDebugRequest(options.debug, {
4258
4276
  provider: adapter.provider,
package/dist/index.d.ts CHANGED
@@ -12,4 +12,4 @@ export { createOpenAICompatibleAdapter, type OpenAICompatibleAdapterOptions, } f
12
12
  export { createAnthropicCompatibleAdapter, DEFAULT_ANTHROPIC_MAX_TOKENS, DEFAULT_ANTHROPIC_VERSION, type AnthropicCompatibleAdapterOptions, } from "./providers/anthropic-compatible";
13
13
  export { DEFAULT_MAX_TOOL_ROUNDS } from "./providers/mcp-runtime";
14
14
  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, LLMRequest, LLMResponse, LLMStreamCallbacks, LLMStreamChunk, LLMToolCall, LLMToolDebugOptions, LLMToolExecution, LLMToolOutputTransformer, 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";
15
+ export type { CandidateDiagnostics, ExtractJsonCandidatesOptions, ExtractionCandidate, ExtractionHeuristicsOptions, ExtractionParseHint, HTTPHeaders, LLMAdapter, 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";
package/dist/index.js CHANGED
@@ -1245,7 +1245,12 @@ async function executeMCPToolCalls(calls, toolset, context) {
1245
1245
  out.push({ call: metadata2, execution });
1246
1246
  continue;
1247
1247
  }
1248
- const args = isRecord(parsedArguments) ? parsedArguments : {};
1248
+ const rawArgs = isRecord(parsedArguments) ? parsedArguments : {};
1249
+ const args = context.request.transformToolArguments ? await context.request.transformToolArguments(rawArgs, {
1250
+ name: toolName,
1251
+ remoteName: tool.remoteName,
1252
+ clientId: tool.clientId
1253
+ }) : rawArgs;
1249
1254
  const metadata = {
1250
1255
  id: callId,
1251
1256
  type: call.type ?? "function",
@@ -1564,7 +1569,8 @@ function createOpenAICompatibleAdapter(options) {
1564
1569
  temperature: request.temperature,
1565
1570
  max_tokens: request.maxTokens,
1566
1571
  stream: true
1567
- }))
1572
+ })),
1573
+ signal: request.signal
1568
1574
  });
1569
1575
  if (!response.ok) {
1570
1576
  const message = await response.text();
@@ -1635,7 +1641,8 @@ async function completeWithChatCompletionsPassThrough(options, fetcher, path, re
1635
1641
  temperature: request.temperature,
1636
1642
  max_tokens: request.maxTokens,
1637
1643
  stream: false
1638
- }))
1644
+ })),
1645
+ signal: request.signal
1639
1646
  });
1640
1647
  if (!response.ok) {
1641
1648
  const message = await response.text();
@@ -1679,7 +1686,8 @@ async function completeWithChatCompletionsWithMCP(options, fetcher, path, reques
1679
1686
  tools: transportTools,
1680
1687
  tool_choice: request.toolChoice,
1681
1688
  parallel_tool_calls: request.parallelToolCalls
1682
- }))
1689
+ })),
1690
+ signal: request.signal
1683
1691
  });
1684
1692
  if (!response.ok) {
1685
1693
  const message = await response.text();
@@ -1744,7 +1752,8 @@ async function completeWithResponsesAPIPassThrough(options, fetcher, path, reque
1744
1752
  previous_response_id: pickString(body?.previous_response_id),
1745
1753
  temperature: request.temperature,
1746
1754
  max_output_tokens: request.maxTokens
1747
- }))
1755
+ })),
1756
+ signal: request.signal
1748
1757
  });
1749
1758
  if (!response.ok) {
1750
1759
  const message = await response.text();
@@ -1786,7 +1795,8 @@ async function completeWithResponsesAPIWithMCP(options, fetcher, path, request)
1786
1795
  tools: transportTools,
1787
1796
  tool_choice: request.toolChoice,
1788
1797
  parallel_tool_calls: request.parallelToolCalls
1789
- }))
1798
+ })),
1799
+ signal: request.signal
1790
1800
  });
1791
1801
  if (!response.ok) {
1792
1802
  const message = await response.text();
@@ -1862,7 +1872,8 @@ async function streamWithChatCompletionsWithMCP(options, fetcher, path, request,
1862
1872
  tool_choice: request.toolChoice,
1863
1873
  parallel_tool_calls: request.parallelToolCalls,
1864
1874
  stream: true
1865
- }))
1875
+ })),
1876
+ signal: request.signal
1866
1877
  });
1867
1878
  if (!response.ok) {
1868
1879
  const message = await response.text();
@@ -1964,7 +1975,8 @@ async function streamWithResponsesAPIPassThrough(options, fetcher, path, request
1964
1975
  temperature: request.temperature,
1965
1976
  max_output_tokens: request.maxTokens,
1966
1977
  stream: true
1967
- }))
1978
+ })),
1979
+ signal: request.signal
1968
1980
  });
1969
1981
  if (!response.ok) {
1970
1982
  const message = await response.text();
@@ -2046,7 +2058,8 @@ async function streamWithResponsesAPIWithMCP(options, fetcher, path, request, ca
2046
2058
  tool_choice: request.toolChoice,
2047
2059
  parallel_tool_calls: request.parallelToolCalls,
2048
2060
  stream: true
2049
- }))
2061
+ })),
2062
+ signal: request.signal
2050
2063
  });
2051
2064
  if (!response.ok) {
2052
2065
  const message = await response.text();
@@ -2610,7 +2623,8 @@ function createAnthropicCompatibleAdapter(options) {
2610
2623
  temperature: request.temperature,
2611
2624
  max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2612
2625
  stream: true
2613
- }))
2626
+ })),
2627
+ signal: request.signal
2614
2628
  });
2615
2629
  if (!response.ok) {
2616
2630
  const message = await response.text();
@@ -2668,7 +2682,8 @@ async function completePassThrough(options, fetcher, path, request) {
2668
2682
  temperature: request.temperature,
2669
2683
  max_tokens: resolveMaxTokens(request.maxTokens, options.defaultMaxTokens),
2670
2684
  stream: false
2671
- }))
2685
+ })),
2686
+ signal: request.signal
2672
2687
  });
2673
2688
  if (!response.ok) {
2674
2689
  const message = await response.text();
@@ -2713,7 +2728,8 @@ async function completeWithMCPToolLoop(options, fetcher, path, request) {
2713
2728
  tools,
2714
2729
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2715
2730
  stream: false
2716
- }))
2731
+ })),
2732
+ signal: request.signal
2717
2733
  });
2718
2734
  if (!response.ok) {
2719
2735
  const message = await response.text();
@@ -2796,7 +2812,8 @@ async function streamWithMCPToolLoop(options, fetcher, path, request, callbacks)
2796
2812
  tools,
2797
2813
  tool_choice: toAnthropicToolChoice(request.toolChoice),
2798
2814
  stream: true
2799
- }))
2815
+ })),
2816
+ signal: request.signal
2800
2817
  });
2801
2818
  if (!response.ok) {
2802
2819
  const message = await response.text();
@@ -4173,7 +4190,8 @@ async function callModel(adapter, options) {
4173
4190
  maxToolRounds: options.request?.maxToolRounds,
4174
4191
  onToolExecution: options.request?.onToolExecution,
4175
4192
  toolDebug: options.request?.toolDebug,
4176
- body: options.request?.body
4193
+ body: options.request?.body,
4194
+ signal: options.request?.signal
4177
4195
  };
4178
4196
  emitDebugRequest(options.debug, {
4179
4197
  provider: adapter.provider,
package/dist/types.d.ts CHANGED
@@ -130,9 +130,11 @@ export interface LLMRequest {
130
130
  maxToolRounds?: number;
131
131
  onToolExecution?: (execution: LLMToolExecution) => void;
132
132
  transformToolOutput?: LLMToolOutputTransformer;
133
+ transformToolArguments?: LLMToolArgumentsTransformer;
133
134
  unknownToolError?: (toolName: string) => string;
134
135
  toolDebug?: boolean | LLMToolDebugOptions;
135
136
  body?: Record<string, unknown>;
137
+ signal?: AbortSignal;
136
138
  }
137
139
  export interface LLMUsage {
138
140
  inputTokens?: number;
@@ -192,6 +194,11 @@ export interface LLMToolExecution {
192
194
  durationMs?: number;
193
195
  }
194
196
  export type LLMToolOutputTransformer = (output: unknown, execution: Omit<LLMToolExecution, "output" | "durationMs">) => unknown | Promise<unknown>;
197
+ export type LLMToolArgumentsTransformer = (args: Record<string, unknown>, context: {
198
+ name: string;
199
+ remoteName: string;
200
+ clientId: string;
201
+ }) => Record<string, unknown> | Promise<Record<string, unknown>>;
195
202
  export interface LLMToolDebugOptions {
196
203
  enabled?: boolean;
197
204
  logger?: (line: string) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extrait",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -36,10 +36,10 @@
36
36
  "prepublishOnly": "bun run lint && bun run build && bun run build:types",
37
37
  "test": "bun test tests/ --reporter=dots --only-failures",
38
38
  "typecheck": "bunx tsc --noEmit",
39
- "pack": "bun run build && npm pack"
39
+ "pack": "bun run build:types && bun run build && npm pack"
40
40
  },
41
41
  "dependencies": {
42
- "@modelcontextprotocol/sdk": "^1.26.0",
42
+ "@modelcontextprotocol/sdk": "^1.27.1",
43
43
  "jsonrepair": "^3.13.2",
44
44
  "zod": "^3.25.76"
45
45
  },