@wrongstack/providers 0.1.4 → 0.1.7
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 +101 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +161 -172
- package/dist/index.js.map +1 -1
- package/package.json +7 -4
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# @wrongstack/providers
|
|
2
|
+
|
|
3
|
+
LLM provider adapters for WrongStack: Anthropic, OpenAI, Google, OpenAI-compatible (Mistral, Groq, DeepSeek, Together, Fireworks, OpenRouter, …).
|
|
4
|
+
|
|
5
|
+
Most providers ride a single declarative `WireFormatConfig` adapter; only the three majors (Anthropic / OpenAI / Google) have hand-written classes. Adding a new provider is usually a 20-line preset, not a new file.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @wrongstack/providers @wrongstack/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`@wrongstack/core` is a peer of every provider — providers depend on the core `Provider` interface, message types, and tool format.
|
|
14
|
+
|
|
15
|
+
## What's in here
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
src/
|
|
19
|
+
anthropic.ts native Anthropic Messages API
|
|
20
|
+
openai.ts native OpenAI Chat Completions API
|
|
21
|
+
google.ts native Google Gemini generateContent API
|
|
22
|
+
openai-compatible.ts drop-in for any /v1/chat/completions endpoint
|
|
23
|
+
wire-adapter.ts declarative adapter — pass a WireFormatConfig
|
|
24
|
+
presets/ wire configs for anthropic / openai / google / mistral
|
|
25
|
+
sse.ts SSE parser with 256 KB buffer cap
|
|
26
|
+
aggregate.ts tool_use stream-event aggregator
|
|
27
|
+
tool-format/ tools ↔ Anthropic / OpenAI converters
|
|
28
|
+
stop-reason.ts normalize provider stop_reason → canonical
|
|
29
|
+
error-parse.ts parse provider HTTP error envelopes
|
|
30
|
+
capabilities.ts map models.dev capability strings → bool flags
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick example
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { AnthropicProvider } from '@wrongstack/providers';
|
|
37
|
+
|
|
38
|
+
const provider = new AnthropicProvider({
|
|
39
|
+
apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
40
|
+
modelId: 'claude-sonnet-4-6',
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const stream = provider.stream({
|
|
44
|
+
messages: [{ role: 'user', content: 'hello' }],
|
|
45
|
+
tools: [],
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
for await (const event of stream) {
|
|
49
|
+
if (event.type === 'text_delta') process.stdout.write(event.text);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Using a preset (OpenAI-compatible service)
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { OpenAICompatibleProvider } from '@wrongstack/providers';
|
|
57
|
+
|
|
58
|
+
const groq = new OpenAICompatibleProvider({
|
|
59
|
+
id: 'groq',
|
|
60
|
+
apiKey: process.env.GROQ_API_KEY!,
|
|
61
|
+
baseURL: 'https://api.groq.com/openai/v1',
|
|
62
|
+
modelId: 'llama-3.3-70b-versatile',
|
|
63
|
+
capabilities: { tools: true, vision: false, maxContext: 128_000 },
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Wire-format adapter (declarative)
|
|
68
|
+
|
|
69
|
+
For a new provider that doesn't fit one of the existing presets, write a `WireFormatConfig` and plug it into `WireAdapter`. See [docs/provider-author-guide.md](../../docs/provider-author-guide.md) for the full spec.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { WireAdapter } from '@wrongstack/providers';
|
|
73
|
+
import type { WireFormatConfig } from '@wrongstack/core';
|
|
74
|
+
|
|
75
|
+
const myWire: WireFormatConfig = {
|
|
76
|
+
family: 'openai',
|
|
77
|
+
endpoint: 'https://api.myprovider.com/v1/chat/completions',
|
|
78
|
+
authHeader: (key) => ({ 'Authorization': `Bearer ${key}` }),
|
|
79
|
+
// tool format, message shape, stream parsing — see WireFormatConfig type
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const provider = new WireAdapter({
|
|
83
|
+
id: 'myprovider',
|
|
84
|
+
apiKey: '…',
|
|
85
|
+
modelId: 'my-model-1',
|
|
86
|
+
wire: myWire,
|
|
87
|
+
capabilities: { tools: true, maxContext: 32_000 },
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Tool input parsing (`parseToolInput`)
|
|
92
|
+
|
|
93
|
+
All four stream parsers (anthropic / openai / aggregate + the three OpenAI-compatible presets) run tool-call JSON through one canonical helper: [`_tool-input.ts`](src/_tool-input.ts). It guarantees the agent always receives a `Record<string, unknown>` for `tool_use.input`, never a parse-error or `null`. Invalid or non-object inputs are wrapped under `{ __raw: ... }` instead of crashing the provider runner.
|
|
94
|
+
|
|
95
|
+
## Capabilities
|
|
96
|
+
|
|
97
|
+
The capability flags on each provider come from [models.dev](https://models.dev) catalog data, mapped by `capabilitiesFor()`. The agent uses them to pick adaptive context-management thresholds, gate vision/reasoning features, and refuse tools on models that don't support tool calls.
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -360,6 +360,9 @@ declare const googleWireFormat: WireFormatConfig<GoogleStreamState>;
|
|
|
360
360
|
*/
|
|
361
361
|
declare function capabilitiesFor(registry: ModelsRegistry, providerId: string, modelId: string): Promise<Capabilities>;
|
|
362
362
|
|
|
363
|
+
declare const CAPABILITIES_BY_FAMILY: Record<WireFamily, Capabilities>;
|
|
364
|
+
declare function capabilitiesForFamily(family: WireFamily, overrides?: Partial<Capabilities>): Capabilities;
|
|
365
|
+
|
|
363
366
|
/**
|
|
364
367
|
* Provider HTTP error bodies come in three or four shapes depending on
|
|
365
368
|
* vendor. Rather than dump the raw JSON into the error message (which is
|
|
@@ -459,4 +462,4 @@ declare function buildProviderFactoriesFromRegistry(opts: BuildFactoriesOptions)
|
|
|
459
462
|
*/
|
|
460
463
|
declare function makeProviderFromConfig(id: string, cfg: ProviderConfig): Provider;
|
|
461
464
|
|
|
462
|
-
export { AnthropicProvider, type AnthropicProviderOptions, type BuildFactoriesOptions, type CompatibilityQuirks, type ConvertOptions, GoogleProvider, type GoogleProviderOptions, type OpenAIChoice, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OpenAIMessage, OpenAIProvider, type OpenAIProviderOptions, type OpenAIToolCall, WireAdapter, type WireFactoryOptions, type WireFormatConfig, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defineWireFormat, googleWireFormat, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
|
|
465
|
+
export { AnthropicProvider, type AnthropicProviderOptions, type BuildFactoriesOptions, CAPABILITIES_BY_FAMILY, type CompatibilityQuirks, type ConvertOptions, GoogleProvider, type GoogleProviderOptions, type OpenAIChoice, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OpenAIMessage, OpenAIProvider, type OpenAIProviderOptions, type OpenAIToolCall, WireAdapter, type WireFactoryOptions, type WireFormatConfig, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, capabilitiesForFamily, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defineWireFormat, googleWireFormat, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProviderError, safeParse, sanitizeJsonString } from '@wrongstack/core';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
2
3
|
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -9,6 +10,20 @@ var __export = (target, all) => {
|
|
|
9
10
|
for (var name in all)
|
|
10
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
12
|
};
|
|
13
|
+
function parseToolInput(raw) {
|
|
14
|
+
if (!raw) return {};
|
|
15
|
+
const parsed = safeParse(raw);
|
|
16
|
+
if (!parsed.ok) return { __raw: raw };
|
|
17
|
+
const v = parsed.value;
|
|
18
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
19
|
+
return v;
|
|
20
|
+
}
|
|
21
|
+
return { __raw: v ?? raw };
|
|
22
|
+
}
|
|
23
|
+
var init_tool_input = __esm({
|
|
24
|
+
"src/_tool-input.ts"() {
|
|
25
|
+
}
|
|
26
|
+
});
|
|
12
27
|
|
|
13
28
|
// src/aggregate.ts
|
|
14
29
|
var aggregate_exports = {};
|
|
@@ -50,13 +65,14 @@ async function aggregateStream(stream, onEvent) {
|
|
|
50
65
|
case "tool_use_stop": {
|
|
51
66
|
const b = toolBuffers.get(ev.id);
|
|
52
67
|
if (b) {
|
|
53
|
-
if (ev.input
|
|
68
|
+
if (ev.input === void 0) {
|
|
69
|
+
b.input = parseToolInput(b.partial);
|
|
70
|
+
} else if (typeof ev.input === "string") {
|
|
71
|
+
b.input = parseToolInput(ev.input);
|
|
72
|
+
} else if (ev.input && typeof ev.input === "object" && !Array.isArray(ev.input)) {
|
|
54
73
|
b.input = ev.input;
|
|
55
|
-
} else if (b.partial) {
|
|
56
|
-
const parsed = safeParse(b.partial);
|
|
57
|
-
b.input = parsed.ok ? parsed.value : { _raw: b.partial };
|
|
58
74
|
} else {
|
|
59
|
-
b.input = {};
|
|
75
|
+
b.input = { __raw: ev.input };
|
|
60
76
|
}
|
|
61
77
|
}
|
|
62
78
|
currentTextIndex = -1;
|
|
@@ -80,7 +96,7 @@ async function aggregateStream(stream, onEvent) {
|
|
|
80
96
|
type: "tool_use",
|
|
81
97
|
id: b.id,
|
|
82
98
|
name: tb.name,
|
|
83
|
-
input: tb.input
|
|
99
|
+
input: tb.input && typeof tb.input === "object" && !Array.isArray(tb.input) ? tb.input : {}
|
|
84
100
|
});
|
|
85
101
|
}
|
|
86
102
|
}
|
|
@@ -90,6 +106,7 @@ async function aggregateStream(stream, onEvent) {
|
|
|
90
106
|
}
|
|
91
107
|
var init_aggregate = __esm({
|
|
92
108
|
"src/aggregate.ts"() {
|
|
109
|
+
init_tool_input();
|
|
93
110
|
}
|
|
94
111
|
});
|
|
95
112
|
function parseProviderHttpError(providerId, status, rawText) {
|
|
@@ -98,9 +115,10 @@ function parseProviderHttpError(providerId, status, rawText) {
|
|
|
98
115
|
const message = `${providerId} HTTP ${status}`;
|
|
99
116
|
return new ProviderError(message, status, retryable, providerId, { body });
|
|
100
117
|
}
|
|
118
|
+
var RAW_TRUNCATE_AT = 2e3;
|
|
101
119
|
function parseBody(rawText) {
|
|
102
|
-
const raw = rawText.slice(0,
|
|
103
|
-
const body = { raw };
|
|
120
|
+
const raw = rawText.slice(0, RAW_TRUNCATE_AT);
|
|
121
|
+
const body = rawText.length > RAW_TRUNCATE_AT ? { raw, truncated: true, rawLength: rawText.length } : { raw };
|
|
104
122
|
if (!rawText.trim()) return body;
|
|
105
123
|
let parsed;
|
|
106
124
|
try {
|
|
@@ -144,6 +162,9 @@ function stringOf(v) {
|
|
|
144
162
|
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
145
163
|
}
|
|
146
164
|
|
|
165
|
+
// src/anthropic.ts
|
|
166
|
+
init_tool_input();
|
|
167
|
+
|
|
147
168
|
// src/tool-format/to-anthropic.ts
|
|
148
169
|
function toolsToAnthropic(tools) {
|
|
149
170
|
return tools.map((t) => ({
|
|
@@ -209,6 +230,7 @@ function normalizeGemini(stop) {
|
|
|
209
230
|
}
|
|
210
231
|
|
|
211
232
|
// src/sse.ts
|
|
233
|
+
var MAX_BUFFER_BYTES = 256 * 1024;
|
|
212
234
|
async function* parseSSE(body) {
|
|
213
235
|
if (!body) return;
|
|
214
236
|
const decoder = new TextDecoder("utf-8");
|
|
@@ -241,12 +263,23 @@ async function* parseSSE(body) {
|
|
|
241
263
|
else if (field === "data") dataLines.push(value);
|
|
242
264
|
return void 0;
|
|
243
265
|
};
|
|
266
|
+
const appendChunk = (chunkStr) => {
|
|
267
|
+
if (chunkStr.length === 0) return;
|
|
268
|
+
buffer += chunkStr;
|
|
269
|
+
if (buffer.length > MAX_BUFFER_BYTES) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
`SSE: pending line exceeds ${MAX_BUFFER_BYTES} bytes \u2014 upstream is not framing events`
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
244
275
|
if (isNodeReadable(body)) {
|
|
245
276
|
for await (const chunk of body) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
277
|
+
appendChunk(
|
|
278
|
+
typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true })
|
|
279
|
+
);
|
|
280
|
+
const split = splitBuffer(buffer);
|
|
281
|
+
buffer = split.tail;
|
|
282
|
+
for (const line of split.lines) {
|
|
250
283
|
const msg = processLine(line);
|
|
251
284
|
if (msg) yield msg;
|
|
252
285
|
}
|
|
@@ -257,10 +290,10 @@ async function* parseSSE(body) {
|
|
|
257
290
|
for (; ; ) {
|
|
258
291
|
const { done, value } = await reader.read();
|
|
259
292
|
if (done) break;
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
buffer =
|
|
263
|
-
for (const line of
|
|
293
|
+
appendChunk(decoder.decode(value, { stream: true }));
|
|
294
|
+
const split = splitBuffer(buffer);
|
|
295
|
+
buffer = split.tail;
|
|
296
|
+
for (const line of split.lines) {
|
|
264
297
|
const msg = processLine(line);
|
|
265
298
|
if (msg) yield msg;
|
|
266
299
|
}
|
|
@@ -270,17 +303,17 @@ async function* parseSSE(body) {
|
|
|
270
303
|
}
|
|
271
304
|
}
|
|
272
305
|
if (buffer.length > 0) {
|
|
273
|
-
const msg = processLine(buffer);
|
|
306
|
+
const msg = processLine(buffer.replace(/\r$/, ""));
|
|
274
307
|
if (msg) yield msg;
|
|
275
308
|
}
|
|
276
309
|
const final = flush();
|
|
277
310
|
if (final) yield final;
|
|
278
311
|
}
|
|
279
312
|
function splitBuffer(buf) {
|
|
280
|
-
const
|
|
281
|
-
const parts = norm.split("\n");
|
|
313
|
+
const parts = buf.split("\n");
|
|
282
314
|
const tail = parts.pop() ?? "";
|
|
283
|
-
|
|
315
|
+
const lines = parts.map((p) => p.endsWith("\r") ? p.slice(0, -1) : p);
|
|
316
|
+
return { lines, tail };
|
|
284
317
|
}
|
|
285
318
|
function isNodeReadable(b) {
|
|
286
319
|
return !!b && typeof b === "object" && typeof b.pipe === "function" && typeof b.on === "function";
|
|
@@ -347,12 +380,9 @@ var WireAdapter = class {
|
|
|
347
380
|
}
|
|
348
381
|
};
|
|
349
382
|
|
|
350
|
-
// src/
|
|
351
|
-
var
|
|
352
|
-
|
|
353
|
-
var AnthropicProvider = class extends WireAdapter {
|
|
354
|
-
id = "anthropic";
|
|
355
|
-
capabilities = {
|
|
383
|
+
// src/family-capabilities.ts
|
|
384
|
+
var CAPABILITIES_BY_FAMILY = {
|
|
385
|
+
anthropic: {
|
|
356
386
|
tools: true,
|
|
357
387
|
parallelTools: true,
|
|
358
388
|
vision: true,
|
|
@@ -362,7 +392,65 @@ var AnthropicProvider = class extends WireAdapter {
|
|
|
362
392
|
jsonMode: false,
|
|
363
393
|
maxContext: 2e5,
|
|
364
394
|
cacheControl: "native"
|
|
395
|
+
},
|
|
396
|
+
openai: {
|
|
397
|
+
tools: true,
|
|
398
|
+
parallelTools: true,
|
|
399
|
+
vision: true,
|
|
400
|
+
streaming: true,
|
|
401
|
+
promptCache: false,
|
|
402
|
+
systemPrompt: true,
|
|
403
|
+
jsonMode: true,
|
|
404
|
+
maxContext: 128e3,
|
|
405
|
+
cacheControl: "auto"
|
|
406
|
+
},
|
|
407
|
+
"openai-compatible": {
|
|
408
|
+
tools: true,
|
|
409
|
+
parallelTools: true,
|
|
410
|
+
vision: false,
|
|
411
|
+
streaming: true,
|
|
412
|
+
promptCache: false,
|
|
413
|
+
systemPrompt: true,
|
|
414
|
+
jsonMode: false,
|
|
415
|
+
maxContext: 32e3,
|
|
416
|
+
cacheControl: "none"
|
|
417
|
+
},
|
|
418
|
+
google: {
|
|
419
|
+
tools: true,
|
|
420
|
+
parallelTools: true,
|
|
421
|
+
vision: true,
|
|
422
|
+
streaming: true,
|
|
423
|
+
promptCache: false,
|
|
424
|
+
systemPrompt: true,
|
|
425
|
+
jsonMode: true,
|
|
426
|
+
maxContext: 1e6,
|
|
427
|
+
cacheControl: "none"
|
|
428
|
+
},
|
|
429
|
+
unsupported: {
|
|
430
|
+
tools: false,
|
|
431
|
+
parallelTools: false,
|
|
432
|
+
vision: false,
|
|
433
|
+
streaming: false,
|
|
434
|
+
promptCache: false,
|
|
435
|
+
systemPrompt: false,
|
|
436
|
+
jsonMode: false,
|
|
437
|
+
maxContext: 0,
|
|
438
|
+
cacheControl: "none"
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
function capabilitiesForFamily(family, overrides = {}) {
|
|
442
|
+
return {
|
|
443
|
+
...CAPABILITIES_BY_FAMILY[family] ?? CAPABILITIES_BY_FAMILY.unsupported,
|
|
444
|
+
...overrides
|
|
365
445
|
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// src/anthropic.ts
|
|
449
|
+
var DEFAULT_BASE = "https://api.anthropic.com";
|
|
450
|
+
var DEFAULT_VERSION = "2023-06-01";
|
|
451
|
+
var AnthropicProvider = class extends WireAdapter {
|
|
452
|
+
id = "anthropic";
|
|
453
|
+
capabilities = capabilitiesForFamily("anthropic");
|
|
366
454
|
opts;
|
|
367
455
|
constructor(opts) {
|
|
368
456
|
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE, opts.fetchImpl);
|
|
@@ -475,7 +563,7 @@ async function* parseAnthropicStream(body, fallbackModel) {
|
|
|
475
563
|
const index = Number(ev["index"] ?? 0);
|
|
476
564
|
const block = blocks.get(index);
|
|
477
565
|
if (block?.kind === "tool_use" && block.id) {
|
|
478
|
-
const input =
|
|
566
|
+
const input = parseToolInput(block.partial);
|
|
479
567
|
yield { type: "tool_use_stop", id: block.id, input };
|
|
480
568
|
}
|
|
481
569
|
break;
|
|
@@ -508,6 +596,7 @@ async function* parseAnthropicStream(body, fallbackModel) {
|
|
|
508
596
|
yield { type: "message_stop", stopReason, usage };
|
|
509
597
|
}
|
|
510
598
|
}
|
|
599
|
+
init_tool_input();
|
|
511
600
|
|
|
512
601
|
// src/tool-format/to-openai.ts
|
|
513
602
|
function toolsToOpenAI(tools) {
|
|
@@ -613,18 +702,11 @@ var OpenAIProvider = class extends WireAdapter {
|
|
|
613
702
|
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE2, opts.fetchImpl);
|
|
614
703
|
this.opts = opts;
|
|
615
704
|
this.id = opts.id ?? "openai";
|
|
616
|
-
this.capabilities = {
|
|
617
|
-
tools: true,
|
|
705
|
+
this.capabilities = capabilitiesForFamily("openai", {
|
|
618
706
|
parallelTools: !opts.quirks?.parallelToolsDisabled,
|
|
619
|
-
vision: true,
|
|
620
|
-
streaming: true,
|
|
621
|
-
promptCache: false,
|
|
622
707
|
systemPrompt: !opts.quirks?.systemAsMessage,
|
|
623
|
-
jsonMode: true,
|
|
624
|
-
maxContext: 128e3,
|
|
625
|
-
cacheControl: "auto",
|
|
626
708
|
...opts.capabilities
|
|
627
|
-
};
|
|
709
|
+
});
|
|
628
710
|
}
|
|
629
711
|
buildUrl(_req) {
|
|
630
712
|
const base = this.baseUrl.replace(/\/+$/, "");
|
|
@@ -737,7 +819,7 @@ async function* parseOpenAIStream(body, fallbackModel) {
|
|
|
737
819
|
}
|
|
738
820
|
}
|
|
739
821
|
for (const entry of toolByIndex.values()) {
|
|
740
|
-
const input =
|
|
822
|
+
const input = parseToolInput(entry.argBuf);
|
|
741
823
|
yield { type: "tool_use_stop", id: entry.id, input };
|
|
742
824
|
}
|
|
743
825
|
if (started) {
|
|
@@ -755,12 +837,12 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
|
|
|
755
837
|
baseUrl: opts.baseUrl,
|
|
756
838
|
fetchImpl: opts.fetchImpl,
|
|
757
839
|
id: opts.id,
|
|
758
|
-
capabilities:
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
840
|
+
capabilities: capabilitiesForFamily("openai-compatible", {
|
|
841
|
+
parallelTools: !opts.quirks?.parallelToolsDisabled,
|
|
842
|
+
systemPrompt: !opts.quirks?.systemAsMessage,
|
|
843
|
+
...opts.capabilities
|
|
844
|
+
}),
|
|
845
|
+
quirks: opts.quirks
|
|
764
846
|
});
|
|
765
847
|
this.extraHeaders = opts.headers;
|
|
766
848
|
this.urlOverride = opts.urlOverride;
|
|
@@ -787,18 +869,9 @@ var GoogleProvider = class extends WireAdapter {
|
|
|
787
869
|
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE3, opts.fetchImpl);
|
|
788
870
|
this.opts = opts;
|
|
789
871
|
this.id = opts.id ?? "google";
|
|
790
|
-
this.capabilities = {
|
|
791
|
-
tools: true,
|
|
792
|
-
parallelTools: true,
|
|
793
|
-
vision: true,
|
|
794
|
-
streaming: true,
|
|
795
|
-
promptCache: false,
|
|
796
|
-
systemPrompt: true,
|
|
797
|
-
jsonMode: true,
|
|
798
|
-
maxContext: 1e6,
|
|
799
|
-
cacheControl: "none",
|
|
872
|
+
this.capabilities = capabilitiesForFamily("google", {
|
|
800
873
|
...opts.capabilities
|
|
801
|
-
};
|
|
874
|
+
});
|
|
802
875
|
}
|
|
803
876
|
buildUrl(req) {
|
|
804
877
|
return `${this.baseUrl}/models/${encodeURIComponent(req.model)}:streamGenerateContent?alt=sse`;
|
|
@@ -945,8 +1018,9 @@ function messagesToGemini(messages) {
|
|
|
945
1018
|
});
|
|
946
1019
|
}
|
|
947
1020
|
}
|
|
948
|
-
|
|
949
|
-
if (functionParts.length > 0)
|
|
1021
|
+
const userParts = [...textParts];
|
|
1022
|
+
if (functionParts.length > 0) userParts.push(...functionParts);
|
|
1023
|
+
if (userParts.length > 0) out.push({ role: "user", parts: userParts });
|
|
950
1024
|
}
|
|
951
1025
|
return out;
|
|
952
1026
|
}
|
|
@@ -972,7 +1046,7 @@ async function* parseGoogleStream(body, fallbackModel) {
|
|
|
972
1046
|
yield { type: "text_delta", text: part.text };
|
|
973
1047
|
} else if (part.functionCall) {
|
|
974
1048
|
sawFunctionCall = true;
|
|
975
|
-
const id =
|
|
1049
|
+
const id = randomUUID();
|
|
976
1050
|
yield { type: "tool_use_start", id, name: part.functionCall.name };
|
|
977
1051
|
const providerMeta = typeof part.thoughtSignature === "string" ? { "google.thoughtSignature": part.thoughtSignature } : void 0;
|
|
978
1052
|
yield {
|
|
@@ -1064,20 +1138,16 @@ function createWireFormatFactory(cfg, opts = {}) {
|
|
|
1064
1138
|
}
|
|
1065
1139
|
};
|
|
1066
1140
|
}
|
|
1141
|
+
|
|
1142
|
+
// src/presets/mistral.ts
|
|
1143
|
+
init_tool_input();
|
|
1067
1144
|
var mistralWireFormat = defineWireFormat({
|
|
1068
1145
|
id: "mistral",
|
|
1069
1146
|
family: "openai-compatible",
|
|
1070
|
-
capabilities: {
|
|
1071
|
-
tools: true,
|
|
1072
|
-
parallelTools: true,
|
|
1073
|
-
vision: false,
|
|
1074
|
-
streaming: true,
|
|
1075
|
-
promptCache: false,
|
|
1076
|
-
systemPrompt: true,
|
|
1147
|
+
capabilities: capabilitiesForFamily("openai-compatible", {
|
|
1077
1148
|
jsonMode: true,
|
|
1078
|
-
maxContext: 128e3
|
|
1079
|
-
|
|
1080
|
-
},
|
|
1149
|
+
maxContext: 128e3
|
|
1150
|
+
}),
|
|
1081
1151
|
defaultBaseUrl: "https://api.mistral.ai/v1",
|
|
1082
1152
|
buildUrl: (base) => `${base.replace(/\/+$/, "")}/chat/completions`,
|
|
1083
1153
|
buildHeaders: (apiKey) => ({ authorization: `Bearer ${apiKey}` }),
|
|
@@ -1133,11 +1203,10 @@ var mistralWireFormat = defineWireFormat({
|
|
|
1133
1203
|
if (choice?.finish_reason) {
|
|
1134
1204
|
for (const block of state.toolCalls.values()) {
|
|
1135
1205
|
if (block.id) {
|
|
1136
|
-
const parsedInput = safeParse(block.partial || "{}");
|
|
1137
1206
|
out.push({
|
|
1138
1207
|
type: "tool_use_stop",
|
|
1139
1208
|
id: block.id,
|
|
1140
|
-
input:
|
|
1209
|
+
input: parseToolInput(block.partial)
|
|
1141
1210
|
});
|
|
1142
1211
|
}
|
|
1143
1212
|
}
|
|
@@ -1165,21 +1234,14 @@ function mapStopReason(reason) {
|
|
|
1165
1234
|
return "end_turn";
|
|
1166
1235
|
}
|
|
1167
1236
|
}
|
|
1237
|
+
|
|
1238
|
+
// src/presets/anthropic.ts
|
|
1239
|
+
init_tool_input();
|
|
1168
1240
|
var DEFAULT_VERSION2 = "2023-06-01";
|
|
1169
1241
|
var anthropicWireFormat = defineWireFormat({
|
|
1170
1242
|
id: "anthropic",
|
|
1171
1243
|
family: "anthropic",
|
|
1172
|
-
capabilities:
|
|
1173
|
-
tools: true,
|
|
1174
|
-
parallelTools: true,
|
|
1175
|
-
vision: true,
|
|
1176
|
-
streaming: true,
|
|
1177
|
-
promptCache: true,
|
|
1178
|
-
systemPrompt: true,
|
|
1179
|
-
jsonMode: false,
|
|
1180
|
-
maxContext: 2e5,
|
|
1181
|
-
cacheControl: "native"
|
|
1182
|
-
},
|
|
1244
|
+
capabilities: capabilitiesForFamily("anthropic"),
|
|
1183
1245
|
defaultBaseUrl: "https://api.anthropic.com",
|
|
1184
1246
|
buildUrl: (base) => {
|
|
1185
1247
|
const b = base.replace(/\/+$/, "");
|
|
@@ -1273,7 +1335,7 @@ var anthropicWireFormat = defineWireFormat({
|
|
|
1273
1335
|
const index = Number(ev["index"] ?? 0);
|
|
1274
1336
|
const block = state.blocks.get(index);
|
|
1275
1337
|
if (block?.kind === "tool_use" && block.id) {
|
|
1276
|
-
const input =
|
|
1338
|
+
const input = parseToolInput(block.partial);
|
|
1277
1339
|
out.push({ type: "tool_use_stop", id: block.id, input });
|
|
1278
1340
|
}
|
|
1279
1341
|
break;
|
|
@@ -1312,20 +1374,13 @@ var anthropicWireFormat = defineWireFormat({
|
|
|
1312
1374
|
return [];
|
|
1313
1375
|
}
|
|
1314
1376
|
});
|
|
1377
|
+
|
|
1378
|
+
// src/presets/openai.ts
|
|
1379
|
+
init_tool_input();
|
|
1315
1380
|
var openaiWireFormat = defineWireFormat({
|
|
1316
1381
|
id: "openai",
|
|
1317
1382
|
family: "openai",
|
|
1318
|
-
capabilities:
|
|
1319
|
-
tools: true,
|
|
1320
|
-
parallelTools: true,
|
|
1321
|
-
vision: true,
|
|
1322
|
-
streaming: true,
|
|
1323
|
-
promptCache: false,
|
|
1324
|
-
systemPrompt: true,
|
|
1325
|
-
jsonMode: true,
|
|
1326
|
-
maxContext: 128e3,
|
|
1327
|
-
cacheControl: "auto"
|
|
1328
|
-
},
|
|
1383
|
+
capabilities: capabilitiesForFamily("openai"),
|
|
1329
1384
|
defaultBaseUrl: "https://api.openai.com/v1",
|
|
1330
1385
|
buildUrl: (base) => {
|
|
1331
1386
|
const b = base.replace(/\/+$/, "");
|
|
@@ -1424,7 +1479,7 @@ var openaiWireFormat = defineWireFormat({
|
|
|
1424
1479
|
state.finalEmitted = true;
|
|
1425
1480
|
const out = [];
|
|
1426
1481
|
for (const entry of state.toolByIndex.values()) {
|
|
1427
|
-
const input =
|
|
1482
|
+
const input = parseToolInput(entry.argBuf);
|
|
1428
1483
|
out.push({ type: "tool_use_stop", id: entry.id, input });
|
|
1429
1484
|
}
|
|
1430
1485
|
if (state.started) {
|
|
@@ -1443,17 +1498,7 @@ function stripCacheControl(system) {
|
|
|
1443
1498
|
var googleWireFormat = defineWireFormat({
|
|
1444
1499
|
id: "google",
|
|
1445
1500
|
family: "google",
|
|
1446
|
-
capabilities:
|
|
1447
|
-
tools: true,
|
|
1448
|
-
parallelTools: true,
|
|
1449
|
-
vision: true,
|
|
1450
|
-
streaming: true,
|
|
1451
|
-
promptCache: false,
|
|
1452
|
-
systemPrompt: true,
|
|
1453
|
-
jsonMode: true,
|
|
1454
|
-
maxContext: 1e6,
|
|
1455
|
-
cacheControl: "none"
|
|
1456
|
-
},
|
|
1501
|
+
capabilities: capabilitiesForFamily("google"),
|
|
1457
1502
|
defaultBaseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
|
1458
1503
|
buildUrl: (base, req) => `${base}/models/${encodeURIComponent(req.model)}:streamGenerateContent?alt=sse`,
|
|
1459
1504
|
buildHeaders: (apiKey) => ({ "x-goog-api-key": apiKey }),
|
|
@@ -1650,74 +1695,15 @@ function messagesToGemini2(messages) {
|
|
|
1650
1695
|
}
|
|
1651
1696
|
|
|
1652
1697
|
// src/capabilities.ts
|
|
1653
|
-
var BASE_BY_FAMILY = {
|
|
1654
|
-
anthropic: {
|
|
1655
|
-
tools: true,
|
|
1656
|
-
parallelTools: true,
|
|
1657
|
-
vision: true,
|
|
1658
|
-
streaming: true,
|
|
1659
|
-
promptCache: true,
|
|
1660
|
-
systemPrompt: true,
|
|
1661
|
-
jsonMode: false,
|
|
1662
|
-
maxContext: 2e5,
|
|
1663
|
-
cacheControl: "native"
|
|
1664
|
-
},
|
|
1665
|
-
openai: {
|
|
1666
|
-
tools: true,
|
|
1667
|
-
parallelTools: true,
|
|
1668
|
-
vision: true,
|
|
1669
|
-
streaming: true,
|
|
1670
|
-
promptCache: false,
|
|
1671
|
-
systemPrompt: true,
|
|
1672
|
-
jsonMode: true,
|
|
1673
|
-
maxContext: 128e3,
|
|
1674
|
-
cacheControl: "auto"
|
|
1675
|
-
},
|
|
1676
|
-
"openai-compatible": {
|
|
1677
|
-
tools: true,
|
|
1678
|
-
parallelTools: true,
|
|
1679
|
-
vision: false,
|
|
1680
|
-
streaming: true,
|
|
1681
|
-
promptCache: false,
|
|
1682
|
-
systemPrompt: true,
|
|
1683
|
-
jsonMode: false,
|
|
1684
|
-
maxContext: 32e3,
|
|
1685
|
-
cacheControl: "none"
|
|
1686
|
-
},
|
|
1687
|
-
google: {
|
|
1688
|
-
tools: true,
|
|
1689
|
-
parallelTools: true,
|
|
1690
|
-
vision: true,
|
|
1691
|
-
streaming: true,
|
|
1692
|
-
promptCache: false,
|
|
1693
|
-
systemPrompt: true,
|
|
1694
|
-
jsonMode: true,
|
|
1695
|
-
maxContext: 1e6,
|
|
1696
|
-
cacheControl: "none"
|
|
1697
|
-
},
|
|
1698
|
-
unsupported: {
|
|
1699
|
-
tools: false,
|
|
1700
|
-
parallelTools: false,
|
|
1701
|
-
vision: false,
|
|
1702
|
-
streaming: false,
|
|
1703
|
-
promptCache: false,
|
|
1704
|
-
systemPrompt: false,
|
|
1705
|
-
jsonMode: false,
|
|
1706
|
-
maxContext: 0,
|
|
1707
|
-
cacheControl: "none"
|
|
1708
|
-
}
|
|
1709
|
-
};
|
|
1710
|
-
function baseFor(family) {
|
|
1711
|
-
return BASE_BY_FAMILY[family] ?? BASE_BY_FAMILY.unsupported;
|
|
1712
|
-
}
|
|
1713
1698
|
async function capabilitiesFor(registry, providerId, modelId) {
|
|
1714
1699
|
const provider = await registry.getProvider(providerId);
|
|
1715
|
-
const base =
|
|
1700
|
+
const base = capabilitiesForFamily(provider?.family ?? "unsupported");
|
|
1716
1701
|
const model = await registry.getModel(providerId, modelId);
|
|
1717
1702
|
if (!model) return { ...base };
|
|
1718
1703
|
return {
|
|
1719
1704
|
...base,
|
|
1720
1705
|
tools: model.capabilities.tools && base.tools,
|
|
1706
|
+
parallelTools: model.capabilities.tools && base.parallelTools,
|
|
1721
1707
|
vision: model.capabilities.vision && base.vision,
|
|
1722
1708
|
maxContext: model.capabilities.maxContext || base.maxContext
|
|
1723
1709
|
};
|
|
@@ -1800,12 +1786,15 @@ function parseToolArguments(raw, toolName, toolCallId, opts) {
|
|
|
1800
1786
|
opts.onParseFailure?.({ toolName, toolCallId, raw });
|
|
1801
1787
|
return { __raw_arguments: raw };
|
|
1802
1788
|
} catch {
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1789
|
+
const sanitized = sanitizeJsonString(raw);
|
|
1790
|
+
if (sanitized !== null) {
|
|
1791
|
+
try {
|
|
1792
|
+
const parsed = JSON.parse(sanitized);
|
|
1793
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1794
|
+
return parsed;
|
|
1795
|
+
}
|
|
1796
|
+
} catch {
|
|
1807
1797
|
}
|
|
1808
|
-
} catch {
|
|
1809
1798
|
}
|
|
1810
1799
|
opts.onParseFailure?.({ toolName, toolCallId, raw });
|
|
1811
1800
|
return { __raw_arguments: raw };
|
|
@@ -1916,6 +1905,6 @@ function requireKey(cfg) {
|
|
|
1916
1905
|
throw new Error("Provider config requires apiKey (or set the corresponding env var).");
|
|
1917
1906
|
}
|
|
1918
1907
|
|
|
1919
|
-
export { AnthropicProvider, GoogleProvider, OpenAICompatibleProvider, OpenAIProvider, WireAdapter, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defineWireFormat, googleWireFormat, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
|
|
1908
|
+
export { AnthropicProvider, CAPABILITIES_BY_FAMILY, GoogleProvider, OpenAICompatibleProvider, OpenAIProvider, WireAdapter, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, capabilitiesForFamily, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defineWireFormat, googleWireFormat, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
|
|
1920
1909
|
//# sourceMappingURL=index.js.map
|
|
1921
1910
|
//# sourceMappingURL=index.js.map
|