@wrongstack/providers 0.1.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/LICENSE +17 -0
- package/dist/index.d.ts +311 -0
- package/dist/index.js +1206 -0
- package/dist/index.js.map +1 -0
- package/package.json +29 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2026 ECOSTACK TECHNOLOGY OÜ
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { Provider, Capabilities, Request, Response, StreamEvent, ProviderError, TextBlock, Message, Tool, ModelsRegistry, StopReason, ContentBlock, Logger, ProviderFactory, ProviderConfig } from '@wrongstack/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal Server-Sent Events parser for HTTP streaming responses.
|
|
5
|
+
*
|
|
6
|
+
* Yields parsed events as `{ event, data }` pairs. Per spec:
|
|
7
|
+
* - Each event is separated by a blank line
|
|
8
|
+
* - `event: foo` sets the event name (defaults to "message")
|
|
9
|
+
* - `data: ...` lines accumulate into the data buffer
|
|
10
|
+
* - `:` lines are comments and ignored
|
|
11
|
+
* - `id` / `retry` fields are accepted and ignored
|
|
12
|
+
*
|
|
13
|
+
* For Anthropic the wire format is canonical SSE with explicit `event:` lines.
|
|
14
|
+
* For OpenAI / OpenAI-compatible the format omits `event:` and just emits
|
|
15
|
+
* `data: <json>` chunks, with a final `data: [DONE]`. Both work with this
|
|
16
|
+
* parser; consumers branch on event name or just on `data`.
|
|
17
|
+
*/
|
|
18
|
+
interface SSEMessage {
|
|
19
|
+
event: string;
|
|
20
|
+
data: string;
|
|
21
|
+
}
|
|
22
|
+
declare function parseSSE(body: ReadableStream<Uint8Array> | NodeJS.ReadableStream | null): AsyncIterable<SSEMessage>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Shared HTTP mechanics for streaming providers.
|
|
26
|
+
* Providers extend this to get:
|
|
27
|
+
* - canonical error handling (ProviderError with retryable flag)
|
|
28
|
+
* - SSE body parsing via parseSSE()
|
|
29
|
+
* - abort signal wiring
|
|
30
|
+
*
|
|
31
|
+
* Subclasses implement the abstract members to provide their specific wire format.
|
|
32
|
+
*/
|
|
33
|
+
declare abstract class WireAdapter implements Provider {
|
|
34
|
+
protected readonly apiKey: string;
|
|
35
|
+
protected readonly baseUrl: string;
|
|
36
|
+
readonly fetchImpl: typeof fetch;
|
|
37
|
+
abstract readonly id: string;
|
|
38
|
+
abstract readonly capabilities: Capabilities;
|
|
39
|
+
constructor(apiKey: string, baseUrl: string, fetchImpl?: typeof fetch);
|
|
40
|
+
complete(req: Request, opts: {
|
|
41
|
+
signal: AbortSignal;
|
|
42
|
+
}): Promise<Response>;
|
|
43
|
+
stream(req: Request, opts: {
|
|
44
|
+
signal: AbortSignal;
|
|
45
|
+
}): AsyncIterable<StreamEvent>;
|
|
46
|
+
/** HTTP endpoint for this provider's chat completions / messages API. */
|
|
47
|
+
protected abstract buildUrl(req: Request): string;
|
|
48
|
+
/** Per-request headers. `apiKey` is already in scope — call `super.buildHeaders` first. */
|
|
49
|
+
protected buildHeaders(_req: Request): Record<string, string>;
|
|
50
|
+
/** Map Request fields to the wire request body. */
|
|
51
|
+
protected abstract buildBody(req: Request): Record<string, unknown>;
|
|
52
|
+
/** Translate wire SSE events into canonical StreamEvent[]. */
|
|
53
|
+
protected abstract parseStream(body: ReadableStream<Uint8Array> | NodeJS.ReadableStream | null, fallbackModel: string): AsyncIterable<StreamEvent>;
|
|
54
|
+
/** Build a ProviderError from an HTTP failure response. */
|
|
55
|
+
protected translateError(status: number, body: string): ProviderError;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface AnthropicProviderOptions {
|
|
59
|
+
apiKey: string;
|
|
60
|
+
baseUrl?: string;
|
|
61
|
+
apiVersion?: string;
|
|
62
|
+
beta?: string[];
|
|
63
|
+
fetchImpl?: typeof fetch;
|
|
64
|
+
}
|
|
65
|
+
declare class AnthropicProvider extends WireAdapter {
|
|
66
|
+
readonly id = "anthropic";
|
|
67
|
+
readonly capabilities: Capabilities;
|
|
68
|
+
private readonly opts;
|
|
69
|
+
constructor(opts: AnthropicProviderOptions);
|
|
70
|
+
protected buildUrl(_req: Request): string;
|
|
71
|
+
protected buildHeaders(req: Request): Record<string, string>;
|
|
72
|
+
protected buildBody(req: Request): Record<string, unknown>;
|
|
73
|
+
protected parseStream(body: Parameters<typeof parseSSE>[0], fallbackModel: string): AsyncIterable<StreamEvent>;
|
|
74
|
+
protected translateError(status: number, text: string): ProviderError;
|
|
75
|
+
private normalizeMessage;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface OpenAIToolSchema {
|
|
79
|
+
type: 'function';
|
|
80
|
+
function: {
|
|
81
|
+
name: string;
|
|
82
|
+
description: string;
|
|
83
|
+
parameters: Record<string, unknown>;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
declare function toolsToOpenAI(tools: Tool[]): OpenAIToolSchema[];
|
|
87
|
+
interface OpenAIMessage {
|
|
88
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
89
|
+
content?: string | OpenAIContent[];
|
|
90
|
+
tool_calls?: OpenAIToolCall[];
|
|
91
|
+
tool_call_id?: string;
|
|
92
|
+
name?: string;
|
|
93
|
+
}
|
|
94
|
+
interface OpenAIContent {
|
|
95
|
+
type: 'text' | 'image_url';
|
|
96
|
+
text?: string;
|
|
97
|
+
image_url?: {
|
|
98
|
+
url: string;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
interface OpenAIToolCall {
|
|
102
|
+
id: string;
|
|
103
|
+
type: 'function';
|
|
104
|
+
function: {
|
|
105
|
+
name: string;
|
|
106
|
+
arguments: string;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
interface ConvertOptions {
|
|
110
|
+
flattenContentToString?: boolean;
|
|
111
|
+
stripCacheControl?: boolean;
|
|
112
|
+
systemAsMessage?: boolean;
|
|
113
|
+
emptyToolCallContent?: 'null' | 'empty_string';
|
|
114
|
+
}
|
|
115
|
+
declare function messagesToOpenAI(system: TextBlock[] | undefined, messages: Message[], opts?: ConvertOptions): OpenAIMessage[];
|
|
116
|
+
|
|
117
|
+
interface OpenAIProviderOptions {
|
|
118
|
+
apiKey: string;
|
|
119
|
+
baseUrl?: string;
|
|
120
|
+
organization?: string;
|
|
121
|
+
fetchImpl?: typeof fetch;
|
|
122
|
+
quirks?: ConvertOptions & {
|
|
123
|
+
parallelToolsDisabled?: boolean;
|
|
124
|
+
jsonArgumentsBuggy?: boolean;
|
|
125
|
+
};
|
|
126
|
+
id?: string;
|
|
127
|
+
capabilities?: Partial<Capabilities>;
|
|
128
|
+
}
|
|
129
|
+
declare class OpenAIProvider extends WireAdapter {
|
|
130
|
+
readonly id: string;
|
|
131
|
+
readonly capabilities: Capabilities;
|
|
132
|
+
protected readonly opts: OpenAIProviderOptions;
|
|
133
|
+
constructor(opts: OpenAIProviderOptions);
|
|
134
|
+
protected buildUrl(_req: Request): string;
|
|
135
|
+
protected buildHeaders(req: Request): Record<string, string>;
|
|
136
|
+
protected buildBody(req: Request): Record<string, unknown>;
|
|
137
|
+
protected parseStream(body: Parameters<typeof parseSSE>[0], fallbackModel: string): AsyncIterable<StreamEvent>;
|
|
138
|
+
protected translateError(status: number, text: string): ProviderError;
|
|
139
|
+
private stripCacheControl;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface CompatibilityQuirks {
|
|
143
|
+
stripCacheControl?: boolean;
|
|
144
|
+
systemAsMessage?: boolean;
|
|
145
|
+
flattenContentToString?: boolean;
|
|
146
|
+
preserveToolCallIds?: boolean;
|
|
147
|
+
parallelToolsDisabled?: boolean;
|
|
148
|
+
jsonArgumentsBuggy?: boolean;
|
|
149
|
+
emptyToolCallContent?: 'null' | 'empty_string';
|
|
150
|
+
}
|
|
151
|
+
interface OpenAICompatibleOptions {
|
|
152
|
+
id: string;
|
|
153
|
+
apiKey: string;
|
|
154
|
+
baseUrl: string;
|
|
155
|
+
headers?: Record<string, string>;
|
|
156
|
+
quirks?: CompatibilityQuirks;
|
|
157
|
+
capabilities?: Partial<Capabilities>;
|
|
158
|
+
fetchImpl?: typeof fetch;
|
|
159
|
+
/**
|
|
160
|
+
* Optional override for URL construction. Receives the base URL and request,
|
|
161
|
+
* returns the full URL to use. Allows custom providers with non-standard
|
|
162
|
+
* URL structures (e.g. Google with model-in-path, Anthropic with /v1/messages).
|
|
163
|
+
*/
|
|
164
|
+
urlOverride?: (baseUrl: string, req: Request) => string;
|
|
165
|
+
}
|
|
166
|
+
declare class OpenAICompatibleProvider extends OpenAIProvider {
|
|
167
|
+
private readonly extraHeaders?;
|
|
168
|
+
private readonly urlOverride?;
|
|
169
|
+
constructor(opts: OpenAICompatibleOptions);
|
|
170
|
+
protected buildUrl(req: Request): string;
|
|
171
|
+
protected buildHeaders(req: Request): Record<string, string>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Google Gemini wire format (generativelanguage.googleapis.com).
|
|
176
|
+
*
|
|
177
|
+
* Differences vs OpenAI:
|
|
178
|
+
* - Endpoint includes the model in the path: /v1beta/models/{model}:generateContent
|
|
179
|
+
* - Messages → `contents: [{ role: 'user'|'model', parts: [...] }]`
|
|
180
|
+
* - System prompt → `systemInstruction: { parts: [{ text }] }`
|
|
181
|
+
* - Tools → `tools: [{ functionDeclarations: [...] }]`
|
|
182
|
+
* - Tool call → `parts: [{ functionCall: { name, args } }]`
|
|
183
|
+
* - Tool result → `parts: [{ functionResponse: { name, response } }]`
|
|
184
|
+
* - Auth via `?key=` query param or `x-goog-api-key` header
|
|
185
|
+
*/
|
|
186
|
+
interface GoogleProviderOptions {
|
|
187
|
+
apiKey: string;
|
|
188
|
+
baseUrl?: string;
|
|
189
|
+
fetchImpl?: typeof fetch;
|
|
190
|
+
id?: string;
|
|
191
|
+
capabilities?: Partial<Capabilities>;
|
|
192
|
+
}
|
|
193
|
+
declare class GoogleProvider extends WireAdapter {
|
|
194
|
+
readonly id: string;
|
|
195
|
+
readonly capabilities: Capabilities;
|
|
196
|
+
private readonly opts;
|
|
197
|
+
constructor(opts: GoogleProviderOptions);
|
|
198
|
+
protected buildUrl(req: Request): string;
|
|
199
|
+
protected buildHeaders(req: Request): Record<string, string>;
|
|
200
|
+
protected buildBody(req: Request): Record<string, unknown>;
|
|
201
|
+
protected parseStream(body: Parameters<typeof parseSSE>[0], fallbackModel: string): AsyncIterable<StreamEvent>;
|
|
202
|
+
protected translateError(status: number, text: string): ProviderError;
|
|
203
|
+
private buildGenConfig;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Resolve capabilities for a (provider, model) pair using the family default
|
|
208
|
+
* as a baseline and overlaying per-model facts from the ModelsRegistry.
|
|
209
|
+
*/
|
|
210
|
+
declare function capabilitiesFor(registry: ModelsRegistry, providerId: string, modelId: string): Promise<Capabilities>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Provider HTTP error bodies come in three or four shapes depending on
|
|
214
|
+
* vendor. Rather than dump the raw JSON into the error message (which is
|
|
215
|
+
* what was shipped to the user log before this module existed), we parse
|
|
216
|
+
* out the fields we care about — `type`, `message`, `requestId` — and put
|
|
217
|
+
* them on `ProviderError.body` for `describe()` and downstream rendering.
|
|
218
|
+
*
|
|
219
|
+
* The function is intentionally tolerant: anything we can't parse falls
|
|
220
|
+
* back to a truncated raw string, never throws.
|
|
221
|
+
*/
|
|
222
|
+
declare function parseProviderHttpError(providerId: string, status: number, rawText: string): ProviderError;
|
|
223
|
+
|
|
224
|
+
declare function normalizeAnthropic(stop: string | null | undefined): StopReason;
|
|
225
|
+
declare function normalizeOpenAI(stop: string | null | undefined): StopReason;
|
|
226
|
+
|
|
227
|
+
interface AnthropicToolSchema {
|
|
228
|
+
name: string;
|
|
229
|
+
description: string;
|
|
230
|
+
input_schema: Record<string, unknown>;
|
|
231
|
+
}
|
|
232
|
+
declare function toolsToAnthropic(tools: Tool[]): AnthropicToolSchema[];
|
|
233
|
+
|
|
234
|
+
interface AnthropicBlock {
|
|
235
|
+
type: string;
|
|
236
|
+
text?: string;
|
|
237
|
+
id?: string;
|
|
238
|
+
name?: string;
|
|
239
|
+
input?: unknown;
|
|
240
|
+
content?: unknown;
|
|
241
|
+
tool_use_id?: string;
|
|
242
|
+
is_error?: boolean;
|
|
243
|
+
source?: {
|
|
244
|
+
type?: 'base64' | 'url';
|
|
245
|
+
media_type?: string;
|
|
246
|
+
data?: string;
|
|
247
|
+
url?: string;
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
interface FromAnthropicOptions {
|
|
251
|
+
/**
|
|
252
|
+
* Called once for each block whose `type` the converter doesn't recognize.
|
|
253
|
+
* The block is still dropped — this hook only exists so callers can wire
|
|
254
|
+
* it into observability (event bus, logger) instead of silently losing
|
|
255
|
+
* data. Anthropic ships new block types over time (`thinking`,
|
|
256
|
+
* `server_tool_use`, etc.) and we want a way to find out without
|
|
257
|
+
* inflating the conversion logic itself.
|
|
258
|
+
*/
|
|
259
|
+
onUnsupported?: (type: string, block: AnthropicBlock) => void;
|
|
260
|
+
}
|
|
261
|
+
declare function contentFromAnthropic(blocks: AnthropicBlock[], opts?: FromAnthropicOptions): ContentBlock[];
|
|
262
|
+
|
|
263
|
+
interface OpenAIChoice {
|
|
264
|
+
message: {
|
|
265
|
+
role: string;
|
|
266
|
+
content: string | null;
|
|
267
|
+
tool_calls?: OpenAIToolCall[];
|
|
268
|
+
};
|
|
269
|
+
finish_reason: string | null;
|
|
270
|
+
}
|
|
271
|
+
interface FromOpenAIOptions {
|
|
272
|
+
/**
|
|
273
|
+
* Deprecated: the sanitizer fallback is now always attempted. Kept for
|
|
274
|
+
* backward compatibility; the value is ignored.
|
|
275
|
+
*/
|
|
276
|
+
jsonArgumentsBuggy?: boolean;
|
|
277
|
+
/**
|
|
278
|
+
* Called when a tool call's `arguments` field can't be parsed even after
|
|
279
|
+
* the sanitizer pass. Callers can use this to emit a structured event,
|
|
280
|
+
* log it, or surface it in a UI. The block is still appended with
|
|
281
|
+
* `{ __raw_arguments }` so the tool gets *something* to fail on, but
|
|
282
|
+
* silently producing garbage input is the kind of bug that wastes
|
|
283
|
+
* debugging hours — this is the hook to find out.
|
|
284
|
+
*/
|
|
285
|
+
onParseFailure?: (info: {
|
|
286
|
+
toolName: string;
|
|
287
|
+
toolCallId: string;
|
|
288
|
+
raw: string;
|
|
289
|
+
}) => void;
|
|
290
|
+
}
|
|
291
|
+
declare function contentFromOpenAI(choice: OpenAIChoice, opts?: FromOpenAIOptions): ContentBlock[];
|
|
292
|
+
|
|
293
|
+
interface BuildFactoriesOptions {
|
|
294
|
+
registry: ModelsRegistry;
|
|
295
|
+
/** Used to log unsupported families during boot. */
|
|
296
|
+
log?: Logger;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Build one ProviderFactory per provider known to models.dev. The factory's
|
|
300
|
+
* `create(cfg)` resolves the wire-family at construction time and returns the
|
|
301
|
+
* matching transport. Unsupported families return a stub that throws when
|
|
302
|
+
* complete() is called, so the system can still boot.
|
|
303
|
+
*/
|
|
304
|
+
declare function buildProviderFactoriesFromRegistry(opts: BuildFactoriesOptions): Promise<ProviderFactory[]>;
|
|
305
|
+
/**
|
|
306
|
+
* Build a Provider purely from config — no models.dev lookup at all.
|
|
307
|
+
* Used for user-defined providers and offline operation.
|
|
308
|
+
*/
|
|
309
|
+
declare function makeProviderFromConfig(id: string, cfg: ProviderConfig): Provider;
|
|
310
|
+
|
|
311
|
+
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, buildProviderFactoriesFromRegistry, capabilitiesFor, contentFromAnthropic, contentFromOpenAI, makeProviderFromConfig, messagesToOpenAI, normalizeAnthropic, normalizeOpenAI, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
|