@agentskit/adapters 0.12.2 → 0.13.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/dist/catalog/index.cjs +153745 -0
- package/dist/catalog/index.cjs.map +1 -0
- package/dist/catalog/index.d.cts +205 -0
- package/dist/catalog/index.d.ts +205 -0
- package/dist/catalog/index.js +153479 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/chunk-6FPLWOVE.js +26 -0
- package/dist/chunk-6FPLWOVE.js.map +1 -0
- package/dist/chunk-726IKNNR.js +486 -0
- package/dist/chunk-726IKNNR.js.map +1 -0
- package/dist/createAdapter-Dfnf3Iio.d.cts +14 -0
- package/dist/createAdapter-Dfnf3Iio.d.ts +14 -0
- package/dist/createAdapter.cjs +28 -0
- package/dist/createAdapter.cjs.map +1 -0
- package/dist/createAdapter.d.cts +2 -0
- package/dist/createAdapter.d.ts +2 -0
- package/dist/createAdapter.js +3 -0
- package/dist/createAdapter.js.map +1 -0
- package/dist/index.cjs +212 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +202 -77
- package/dist/index.d.ts +202 -77
- package/dist/index.js +193 -527
- package/dist/index.js.map +1 -1
- package/dist/utils-ddwu4MN4.d.cts +66 -0
- package/dist/utils-ddwu4MN4.d.ts +66 -0
- package/package.json +19 -6
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/createAdapter.ts
|
|
2
|
+
function createAdapter(config) {
|
|
3
|
+
return {
|
|
4
|
+
createSource: (request) => ({
|
|
5
|
+
stream: async function* () {
|
|
6
|
+
try {
|
|
7
|
+
const result = await config.send(request);
|
|
8
|
+
const stream = result instanceof Response ? result.body : result;
|
|
9
|
+
yield* config.parse(stream);
|
|
10
|
+
} catch (err) {
|
|
11
|
+
yield {
|
|
12
|
+
type: "error",
|
|
13
|
+
content: err instanceof Error ? err.message : String(err)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
abort: () => {
|
|
18
|
+
config.abort?.();
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { createAdapter };
|
|
25
|
+
//# sourceMappingURL=chunk-6FPLWOVE.js.map
|
|
26
|
+
//# sourceMappingURL=chunk-6FPLWOVE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/createAdapter.ts"],"names":[],"mappings":";AAGO,SAAS,cAAc,MAAA,EAA6C;AACzE,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,CAAC,OAAA,MAA2C;AAAA,MACxD,QAAQ,mBAAuD;AAC7D,QAAA,IAAI;AACF,UAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AACxC,UAAA,MAAM,MAAA,GAAS,MAAA,YAAkB,QAAA,GAC7B,MAAA,CAAO,IAAA,GACP,MAAA;AACJ,UAAA,OAAO,MAAA,CAAO,MAAM,MAAM,CAAA;AAAA,QAC5B,SAAS,GAAA,EAAK;AACZ,UAAA,MAAM;AAAA,YACJ,IAAA,EAAM,OAAA;AAAA,YACN,SAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,WAC1D;AAAA,QACF;AAAA,MACF,CAAA;AAAA,MACA,OAAO,MAAM;AACX,QAAA,MAAA,CAAO,KAAA,IAAQ;AAAA,MACjB;AAAA,KACF;AAAA,GACF;AACF","file":"chunk-6FPLWOVE.js","sourcesContent":["import type { AdapterFactory, AdapterRequest, StreamChunk, StreamSource } from '@agentskit/core'\nimport type { CreateAdapterConfig } from './types'\n\nexport function createAdapter(config: CreateAdapterConfig): AdapterFactory {\n return {\n createSource: (request: AdapterRequest): StreamSource => ({\n stream: async function* (): AsyncIterableIterator<StreamChunk> {\n try {\n const result = await config.send(request)\n const stream = result instanceof Response\n ? result.body!\n : result\n yield* config.parse(stream)\n } catch (err) {\n yield {\n type: 'error',\n content: err instanceof Error ? err.message : String(err),\n }\n }\n },\n abort: () => {\n config.abort?.()\n },\n }),\n }\n}\n"]}
|
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
function toProviderMessages(messages) {
|
|
3
|
+
const knownToolCallIds = /* @__PURE__ */ new Set();
|
|
4
|
+
const output = [];
|
|
5
|
+
for (const message of messages) {
|
|
6
|
+
if (message.role === "tool") {
|
|
7
|
+
const id = message.toolCallId;
|
|
8
|
+
if (!id || !knownToolCallIds.has(id)) continue;
|
|
9
|
+
output.push({
|
|
10
|
+
role: "tool",
|
|
11
|
+
content: message.content,
|
|
12
|
+
tool_call_id: id
|
|
13
|
+
});
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
|
|
17
|
+
for (const tc of message.toolCalls) knownToolCallIds.add(tc.id);
|
|
18
|
+
output.push({
|
|
19
|
+
role: "assistant",
|
|
20
|
+
content: message.content || null,
|
|
21
|
+
tool_calls: message.toolCalls.map((tc) => ({
|
|
22
|
+
id: tc.id,
|
|
23
|
+
type: "function",
|
|
24
|
+
function: {
|
|
25
|
+
name: tc.name,
|
|
26
|
+
arguments: typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args ?? {})
|
|
27
|
+
}
|
|
28
|
+
}))
|
|
29
|
+
});
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (message.role === "assistant" && !message.content) continue;
|
|
33
|
+
output.push({ role: message.role, content: message.content });
|
|
34
|
+
}
|
|
35
|
+
return output;
|
|
36
|
+
}
|
|
37
|
+
async function* readSSELines(stream) {
|
|
38
|
+
const reader = stream.getReader();
|
|
39
|
+
const decoder = new TextDecoder();
|
|
40
|
+
let buffer = "";
|
|
41
|
+
try {
|
|
42
|
+
while (true) {
|
|
43
|
+
const { done, value } = await reader.read();
|
|
44
|
+
if (done) break;
|
|
45
|
+
buffer += decoder.decode(value, { stream: true });
|
|
46
|
+
const lines = buffer.split("\n");
|
|
47
|
+
buffer = lines.pop() ?? "";
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
if (!line.startsWith("data: ")) continue;
|
|
50
|
+
const data = line.slice(6).trim();
|
|
51
|
+
if (data) yield data;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} finally {
|
|
55
|
+
reader.releaseLock();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function* readNDJSONLines(stream) {
|
|
59
|
+
const reader = stream.getReader();
|
|
60
|
+
const decoder = new TextDecoder();
|
|
61
|
+
let buffer = "";
|
|
62
|
+
try {
|
|
63
|
+
while (true) {
|
|
64
|
+
const { done, value } = await reader.read();
|
|
65
|
+
if (done) break;
|
|
66
|
+
buffer += decoder.decode(value, { stream: true });
|
|
67
|
+
const lines = buffer.split("\n");
|
|
68
|
+
buffer = lines.pop() ?? "";
|
|
69
|
+
for (const line of lines) {
|
|
70
|
+
const trimmed = line.trim();
|
|
71
|
+
if (trimmed) yield trimmed;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
} finally {
|
|
75
|
+
reader.releaseLock();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function* parseOpenAIStream(stream) {
|
|
79
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
80
|
+
for await (const data of readSSELines(stream)) {
|
|
81
|
+
if (data === "[DONE]") {
|
|
82
|
+
for (const [, tc] of pendingToolCalls) {
|
|
83
|
+
yield { type: "tool_call", toolCall: { id: tc.id, name: tc.name, args: tc.args || "{}" } };
|
|
84
|
+
}
|
|
85
|
+
pendingToolCalls.clear();
|
|
86
|
+
yield { type: "done" };
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const event = JSON.parse(data);
|
|
91
|
+
const delta = event.choices?.[0]?.delta;
|
|
92
|
+
if (typeof delta?.content === "string") {
|
|
93
|
+
yield { type: "text", content: delta.content };
|
|
94
|
+
}
|
|
95
|
+
if (Array.isArray(delta?.tool_calls)) {
|
|
96
|
+
for (const toolCall of delta.tool_calls) {
|
|
97
|
+
const index = toolCall.index ?? 0;
|
|
98
|
+
const existing = pendingToolCalls.get(index);
|
|
99
|
+
if (toolCall?.function?.name) {
|
|
100
|
+
pendingToolCalls.set(index, {
|
|
101
|
+
id: toolCall.id ?? existing?.id ?? `tool-${index}-${Date.now()}`,
|
|
102
|
+
name: toolCall.function.name,
|
|
103
|
+
args: (existing?.args ?? "") + (toolCall.function.arguments ?? "")
|
|
104
|
+
});
|
|
105
|
+
} else if (existing && toolCall?.function?.arguments) {
|
|
106
|
+
existing.args += toolCall.function.arguments;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (event.usage) {
|
|
111
|
+
yield {
|
|
112
|
+
type: "usage",
|
|
113
|
+
usage: {
|
|
114
|
+
promptTokens: event.usage.prompt_tokens ?? 0,
|
|
115
|
+
completionTokens: event.usage.completion_tokens ?? 0,
|
|
116
|
+
totalTokens: event.usage.total_tokens ?? 0
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const [, tc] of pendingToolCalls) {
|
|
124
|
+
yield { type: "tool_call", toolCall: { id: tc.id, name: tc.name, args: tc.args || "{}" } };
|
|
125
|
+
}
|
|
126
|
+
pendingToolCalls.clear();
|
|
127
|
+
yield { type: "done" };
|
|
128
|
+
}
|
|
129
|
+
async function* parseAnthropicStream(stream) {
|
|
130
|
+
const pendingToolCalls = /* @__PURE__ */ new Map();
|
|
131
|
+
for await (const data of readSSELines(stream)) {
|
|
132
|
+
if (data === "[DONE]") continue;
|
|
133
|
+
try {
|
|
134
|
+
const event = JSON.parse(data);
|
|
135
|
+
if (event.type === "content_block_delta" && event.delta?.type === "text_delta" && event.delta?.text) {
|
|
136
|
+
yield { type: "text", content: event.delta.text };
|
|
137
|
+
} else if (event.type === "content_block_delta" && event.delta?.type === "input_json_delta") {
|
|
138
|
+
const index = event.index ?? 0;
|
|
139
|
+
const existing = pendingToolCalls.get(index);
|
|
140
|
+
if (existing) {
|
|
141
|
+
existing.args += event.delta.partial_json ?? "";
|
|
142
|
+
}
|
|
143
|
+
} else if (event.type === "content_block_start" && event.content_block?.type === "tool_use") {
|
|
144
|
+
const index = event.index ?? 0;
|
|
145
|
+
pendingToolCalls.set(index, {
|
|
146
|
+
id: event.content_block.id,
|
|
147
|
+
name: event.content_block.name,
|
|
148
|
+
args: ""
|
|
149
|
+
});
|
|
150
|
+
} else if (event.type === "content_block_stop") {
|
|
151
|
+
const index = event.index ?? 0;
|
|
152
|
+
const tc = pendingToolCalls.get(index);
|
|
153
|
+
if (tc) {
|
|
154
|
+
yield {
|
|
155
|
+
type: "tool_call",
|
|
156
|
+
toolCall: {
|
|
157
|
+
id: tc.id,
|
|
158
|
+
name: tc.name,
|
|
159
|
+
args: tc.args || "{}"
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
pendingToolCalls.delete(index);
|
|
163
|
+
}
|
|
164
|
+
} else if (event.type === "message_delta" && event.usage) {
|
|
165
|
+
yield {
|
|
166
|
+
type: "usage",
|
|
167
|
+
usage: {
|
|
168
|
+
promptTokens: event.usage.input_tokens ?? 0,
|
|
169
|
+
completionTokens: event.usage.output_tokens ?? 0,
|
|
170
|
+
totalTokens: (event.usage.input_tokens ?? 0) + (event.usage.output_tokens ?? 0)
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
} else if (event.type === "message_start" && event.message?.usage) {
|
|
174
|
+
yield {
|
|
175
|
+
type: "usage",
|
|
176
|
+
usage: {
|
|
177
|
+
promptTokens: event.message.usage.input_tokens ?? 0,
|
|
178
|
+
completionTokens: 0,
|
|
179
|
+
totalTokens: event.message.usage.input_tokens ?? 0
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
} else if (event.type === "message_stop") {
|
|
183
|
+
for (const [, tc] of pendingToolCalls) {
|
|
184
|
+
yield { type: "tool_call", toolCall: { id: tc.id, name: tc.name, args: tc.args || "{}" } };
|
|
185
|
+
}
|
|
186
|
+
pendingToolCalls.clear();
|
|
187
|
+
yield { type: "done" };
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
for (const [, tc] of pendingToolCalls) {
|
|
194
|
+
yield { type: "tool_call", toolCall: { id: tc.id, name: tc.name, args: tc.args || "{}" } };
|
|
195
|
+
}
|
|
196
|
+
pendingToolCalls.clear();
|
|
197
|
+
yield { type: "done" };
|
|
198
|
+
}
|
|
199
|
+
async function* parseGeminiStream(stream) {
|
|
200
|
+
for await (const data of readSSELines(stream)) {
|
|
201
|
+
try {
|
|
202
|
+
const event = JSON.parse(data);
|
|
203
|
+
if (event.usageMetadata) {
|
|
204
|
+
yield {
|
|
205
|
+
type: "usage",
|
|
206
|
+
usage: {
|
|
207
|
+
promptTokens: event.usageMetadata.promptTokenCount ?? 0,
|
|
208
|
+
completionTokens: event.usageMetadata.candidatesTokenCount ?? 0,
|
|
209
|
+
totalTokens: event.usageMetadata.totalTokenCount ?? 0
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const parts = event.candidates?.[0]?.content?.parts;
|
|
214
|
+
if (!Array.isArray(parts)) continue;
|
|
215
|
+
for (const part of parts) {
|
|
216
|
+
if (typeof part.text === "string" && part.text) {
|
|
217
|
+
yield { type: "text", content: part.text };
|
|
218
|
+
} else if (part.functionCall) {
|
|
219
|
+
const fc = part.functionCall;
|
|
220
|
+
yield {
|
|
221
|
+
type: "tool_call",
|
|
222
|
+
toolCall: {
|
|
223
|
+
id: fc.id ?? `${fc.name}-${Date.now()}`,
|
|
224
|
+
name: fc.name,
|
|
225
|
+
args: JSON.stringify(fc.args ?? {})
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
yield { type: "done" };
|
|
234
|
+
}
|
|
235
|
+
async function* parseOllamaStream(stream) {
|
|
236
|
+
for await (const data of readNDJSONLines(stream)) {
|
|
237
|
+
try {
|
|
238
|
+
const event = JSON.parse(data);
|
|
239
|
+
if (event.message?.content) {
|
|
240
|
+
yield { type: "text", content: event.message.content };
|
|
241
|
+
}
|
|
242
|
+
if (Array.isArray(event.message?.tool_calls)) {
|
|
243
|
+
for (const tc of event.message.tool_calls) {
|
|
244
|
+
if (tc?.function?.name) {
|
|
245
|
+
yield {
|
|
246
|
+
type: "tool_call",
|
|
247
|
+
toolCall: {
|
|
248
|
+
id: tc.id ?? `${tc.function.name}-${Date.now()}`,
|
|
249
|
+
name: tc.function.name,
|
|
250
|
+
args: typeof tc.function.arguments === "string" ? tc.function.arguments : JSON.stringify(tc.function.arguments ?? {})
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (event.done) {
|
|
257
|
+
if (typeof event.prompt_eval_count === "number" || typeof event.eval_count === "number") {
|
|
258
|
+
const promptTokens = event.prompt_eval_count ?? 0;
|
|
259
|
+
const completionTokens = event.eval_count ?? 0;
|
|
260
|
+
yield {
|
|
261
|
+
type: "usage",
|
|
262
|
+
usage: {
|
|
263
|
+
promptTokens,
|
|
264
|
+
completionTokens,
|
|
265
|
+
totalTokens: promptTokens + completionTokens
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
yield { type: "done" };
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
} catch {
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
yield { type: "done" };
|
|
276
|
+
}
|
|
277
|
+
var DEFAULT_RETRY = {
|
|
278
|
+
maxAttempts: 3,
|
|
279
|
+
baseDelayMs: 500,
|
|
280
|
+
maxDelayMs: 8e3,
|
|
281
|
+
jitter: true,
|
|
282
|
+
retryOn: ({ error, response }) => {
|
|
283
|
+
if (response) {
|
|
284
|
+
return [408, 429, 500, 502, 503, 504].includes(response.status);
|
|
285
|
+
}
|
|
286
|
+
if (error instanceof DOMException && error.name === "AbortError") return false;
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
function defaultSleep(ms) {
|
|
291
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
292
|
+
}
|
|
293
|
+
function computeDelay(attempt, opts) {
|
|
294
|
+
const exp = Math.min(opts.maxDelayMs, opts.baseDelayMs * Math.pow(2, attempt - 1));
|
|
295
|
+
if (!opts.jitter) return exp;
|
|
296
|
+
return Math.floor(Math.random() * exp);
|
|
297
|
+
}
|
|
298
|
+
function parseRetryAfter(value) {
|
|
299
|
+
if (!value) return void 0;
|
|
300
|
+
const n = Number(value);
|
|
301
|
+
if (!Number.isNaN(n)) return n * 1e3;
|
|
302
|
+
const date = Date.parse(value);
|
|
303
|
+
if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
|
|
304
|
+
return void 0;
|
|
305
|
+
}
|
|
306
|
+
async function fetchWithRetry(doFetch, signal, retryOpt = {}) {
|
|
307
|
+
const opts = {
|
|
308
|
+
...DEFAULT_RETRY,
|
|
309
|
+
...retryOpt
|
|
310
|
+
};
|
|
311
|
+
const sleep = retryOpt.sleep ?? defaultSleep;
|
|
312
|
+
let lastError;
|
|
313
|
+
for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
|
|
314
|
+
if (signal.aborted) throw new DOMException("Aborted", "AbortError");
|
|
315
|
+
try {
|
|
316
|
+
const response = await doFetch(signal);
|
|
317
|
+
if (response.ok) return response;
|
|
318
|
+
if (attempt >= opts.maxAttempts || !opts.retryOn({ response, attempt })) {
|
|
319
|
+
return response;
|
|
320
|
+
}
|
|
321
|
+
const retryAfterMs = parseRetryAfter(response.headers.get("retry-after"));
|
|
322
|
+
const delay = retryAfterMs ?? computeDelay(attempt, opts);
|
|
323
|
+
retryOpt.onRetry?.({ attempt, delayMs: delay, reason: `HTTP ${response.status}` });
|
|
324
|
+
await sleep(delay);
|
|
325
|
+
response.body?.cancel().catch(() => {
|
|
326
|
+
});
|
|
327
|
+
} catch (err) {
|
|
328
|
+
lastError = err;
|
|
329
|
+
if (err instanceof DOMException && err.name === "AbortError") throw err;
|
|
330
|
+
if (attempt >= opts.maxAttempts || !opts.retryOn({ error: err, attempt })) throw err;
|
|
331
|
+
const delay = computeDelay(attempt, opts);
|
|
332
|
+
retryOpt.onRetry?.({ attempt, delayMs: delay, reason: err.message });
|
|
333
|
+
await sleep(delay);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
throw lastError ?? new Error("fetchWithRetry: exhausted attempts");
|
|
337
|
+
}
|
|
338
|
+
function createStreamSource(doFetch, parse, errorLabel, retry) {
|
|
339
|
+
let abortController = new AbortController();
|
|
340
|
+
return {
|
|
341
|
+
stream: async function* () {
|
|
342
|
+
const controller = abortController;
|
|
343
|
+
if (!controller) return;
|
|
344
|
+
try {
|
|
345
|
+
const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {});
|
|
346
|
+
if (!response.ok || !response.body) {
|
|
347
|
+
yield { type: "error", content: `${errorLabel} error: ${response.status}` };
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
yield* parse(response.body);
|
|
351
|
+
} catch (err) {
|
|
352
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
353
|
+
yield {
|
|
354
|
+
type: "error",
|
|
355
|
+
content: err instanceof Error ? err.message : String(err)
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
abort: () => {
|
|
360
|
+
abortController?.abort();
|
|
361
|
+
abortController = null;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function chunkText(text, targetSize = 32) {
|
|
366
|
+
if (text.length <= targetSize) return [text];
|
|
367
|
+
const out = [];
|
|
368
|
+
let i = 0;
|
|
369
|
+
while (i < text.length) {
|
|
370
|
+
let end = Math.min(text.length, i + targetSize);
|
|
371
|
+
if (end < text.length) {
|
|
372
|
+
const nextSpace = text.indexOf(" ", end);
|
|
373
|
+
if (nextSpace !== -1 && nextSpace - end <= 8) end = nextSpace + 1;
|
|
374
|
+
}
|
|
375
|
+
out.push(text.slice(i, end));
|
|
376
|
+
i = end;
|
|
377
|
+
}
|
|
378
|
+
return out;
|
|
379
|
+
}
|
|
380
|
+
function simulateStream(doFetch, extractText, errorLabel, options = {}) {
|
|
381
|
+
const { chunkSize = 32, delayMs = 8, retry } = options;
|
|
382
|
+
let abortController = new AbortController();
|
|
383
|
+
return {
|
|
384
|
+
stream: async function* () {
|
|
385
|
+
const controller = abortController;
|
|
386
|
+
if (!controller) return;
|
|
387
|
+
try {
|
|
388
|
+
const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {});
|
|
389
|
+
if (!response.ok) {
|
|
390
|
+
yield { type: "error", content: `${errorLabel} error: ${response.status}` };
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const text = await extractText(response);
|
|
394
|
+
const chunks = chunkText(text, chunkSize);
|
|
395
|
+
for (const chunk of chunks) {
|
|
396
|
+
if (abortController === null) return;
|
|
397
|
+
if (delayMs > 0) {
|
|
398
|
+
await new Promise((resolve, reject) => {
|
|
399
|
+
const timer = setTimeout(resolve, delayMs);
|
|
400
|
+
controller.signal.addEventListener(
|
|
401
|
+
"abort",
|
|
402
|
+
() => {
|
|
403
|
+
clearTimeout(timer);
|
|
404
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
405
|
+
},
|
|
406
|
+
{ once: true }
|
|
407
|
+
);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
yield { type: "text", content: chunk };
|
|
411
|
+
}
|
|
412
|
+
yield { type: "done" };
|
|
413
|
+
} catch (err) {
|
|
414
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
415
|
+
yield {
|
|
416
|
+
type: "error",
|
|
417
|
+
content: err instanceof Error ? err.message : String(err)
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
abort: () => {
|
|
422
|
+
abortController?.abort();
|
|
423
|
+
abortController = null;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// src/openai.ts
|
|
429
|
+
function openai(config) {
|
|
430
|
+
const { apiKey, model, baseUrl = "https://api.openai.com", retry } = config;
|
|
431
|
+
const isCanonicalOpenAI = (() => {
|
|
432
|
+
try {
|
|
433
|
+
return new URL(baseUrl).host === "api.openai.com";
|
|
434
|
+
} catch {
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
})();
|
|
438
|
+
const includeUsage = config.includeUsage ?? isCanonicalOpenAI;
|
|
439
|
+
return {
|
|
440
|
+
capabilities: {
|
|
441
|
+
streaming: true,
|
|
442
|
+
tools: true,
|
|
443
|
+
// o1 / o3 models emit reasoning; older models don't. Accurate per-model
|
|
444
|
+
// detection would need a model registry; 'true' is the safer default here.
|
|
445
|
+
reasoning: model.startsWith("o1") || model.startsWith("o3"),
|
|
446
|
+
multiModal: model.startsWith("gpt-4") || model.startsWith("o"),
|
|
447
|
+
usage: true
|
|
448
|
+
},
|
|
449
|
+
createSource: (request) => {
|
|
450
|
+
const body = {
|
|
451
|
+
model,
|
|
452
|
+
messages: toProviderMessages(request.messages),
|
|
453
|
+
tools: request.context?.tools?.map((tool) => ({
|
|
454
|
+
type: "function",
|
|
455
|
+
function: {
|
|
456
|
+
name: tool.name,
|
|
457
|
+
description: tool.description,
|
|
458
|
+
parameters: tool.schema
|
|
459
|
+
}
|
|
460
|
+
})),
|
|
461
|
+
temperature: request.context?.temperature,
|
|
462
|
+
max_tokens: request.context?.maxTokens,
|
|
463
|
+
stream: true
|
|
464
|
+
};
|
|
465
|
+
if (includeUsage) body.stream_options = { include_usage: true };
|
|
466
|
+
return createStreamSource(
|
|
467
|
+
(signal) => fetch(`${baseUrl}/v1/chat/completions`, {
|
|
468
|
+
method: "POST",
|
|
469
|
+
headers: {
|
|
470
|
+
"Content-Type": "application/json",
|
|
471
|
+
"Authorization": `Bearer ${apiKey}`
|
|
472
|
+
},
|
|
473
|
+
body: JSON.stringify(body),
|
|
474
|
+
signal
|
|
475
|
+
}),
|
|
476
|
+
parseOpenAIStream,
|
|
477
|
+
"OpenAI API",
|
|
478
|
+
retry
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export { chunkText, createStreamSource, fetchWithRetry, openai, parseAnthropicStream, parseGeminiStream, parseOllamaStream, parseOpenAIStream, simulateStream, toProviderMessages };
|
|
485
|
+
//# sourceMappingURL=chunk-726IKNNR.js.map
|
|
486
|
+
//# sourceMappingURL=chunk-726IKNNR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/openai.ts"],"names":[],"mappings":"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","file":"chunk-726IKNNR.js","sourcesContent":["import type { AdapterRequest, Message, StreamChunk, StreamSource } from '@agentskit/core'\n\nexport function toProviderMessages(messages: Message[]) {\n // Track which tool_call ids were declared by preceding assistant turns so\n // we can drop orphan tool messages — the OpenAI Chat Completions API\n // rejects a tool message whose tool_call_id isn't bound to a previous\n // assistant message.\n const knownToolCallIds = new Set<string>()\n const output: Array<Record<string, unknown>> = []\n\n for (const message of messages) {\n if (message.role === 'tool') {\n const id = message.toolCallId\n // Orphan (no id, or id not declared) — skip; it would 400 the API.\n if (!id || !knownToolCallIds.has(id)) continue\n output.push({\n role: 'tool' as const,\n content: message.content,\n tool_call_id: id,\n })\n continue\n }\n\n if (message.role === 'assistant' && message.toolCalls && message.toolCalls.length > 0) {\n for (const tc of message.toolCalls) knownToolCallIds.add(tc.id)\n output.push({\n role: 'assistant' as const,\n content: message.content || null,\n tool_calls: message.toolCalls.map(tc => ({\n id: tc.id,\n type: 'function' as const,\n function: {\n name: tc.name,\n arguments: typeof tc.args === 'string' ? tc.args : JSON.stringify(tc.args ?? {}),\n },\n })),\n })\n continue\n }\n\n // Skip assistant messages with no content AND no tool calls. These\n // happen when a turn was interrupted (Ctrl+C, crashed adapter, etc.)\n // and the placeholder assistant message never received content —\n // sending `{role:'assistant', content:''}` back to the provider either\n // 400s or confuses the model into silence on the next turn.\n if (message.role === 'assistant' && !message.content) continue\n\n output.push({ role: message.role, content: message.content })\n }\n\n return output\n}\n\nexport async function* readSSELines(stream: ReadableStream): AsyncIterableIterator<string> {\n const reader = stream.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue\n const data = line.slice(6).trim()\n if (data) yield data\n }\n }\n } finally {\n reader.releaseLock()\n }\n}\n\nexport async function* readNDJSONLines(stream: ReadableStream): AsyncIterableIterator<string> {\n const reader = stream.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n\n for (const line of lines) {\n const trimmed = line.trim()\n if (trimmed) yield trimmed\n }\n }\n } finally {\n reader.releaseLock()\n }\n}\n\nexport async function* parseOpenAIStream(stream: ReadableStream): AsyncIterableIterator<StreamChunk> {\n const pendingToolCalls = new Map<number, { id: string; name: string; args: string }>()\n\n for await (const data of readSSELines(stream)) {\n if (data === '[DONE]') {\n for (const [, tc] of pendingToolCalls) {\n yield { type: 'tool_call', toolCall: { id: tc.id, name: tc.name, args: tc.args || '{}' } }\n }\n pendingToolCalls.clear()\n yield { type: 'done' }\n return\n }\n\n try {\n const event = JSON.parse(data)\n const delta = event.choices?.[0]?.delta\n\n if (typeof delta?.content === 'string') {\n yield { type: 'text', content: delta.content }\n }\n\n if (Array.isArray(delta?.tool_calls)) {\n for (const toolCall of delta.tool_calls) {\n const index: number = toolCall.index ?? 0\n const existing = pendingToolCalls.get(index)\n\n if (toolCall?.function?.name) {\n // First chunk for this tool call — store it\n pendingToolCalls.set(index, {\n id: toolCall.id ?? existing?.id ?? `tool-${index}-${Date.now()}`,\n name: toolCall.function.name,\n args: (existing?.args ?? '') + (toolCall.function.arguments ?? ''),\n })\n } else if (existing && toolCall?.function?.arguments) {\n // Subsequent chunk — accumulate arguments\n existing.args += toolCall.function.arguments\n }\n }\n }\n\n // Final usage chunk — emitted when `stream_options.include_usage` is set.\n if (event.usage) {\n yield {\n type: 'usage',\n usage: {\n promptTokens: event.usage.prompt_tokens ?? 0,\n completionTokens: event.usage.completion_tokens ?? 0,\n totalTokens: event.usage.total_tokens ?? 0,\n },\n }\n }\n } catch {\n // Ignore malformed events.\n }\n }\n\n // Flush any remaining tool calls if stream ends without [DONE]\n for (const [, tc] of pendingToolCalls) {\n yield { type: 'tool_call', toolCall: { id: tc.id, name: tc.name, args: tc.args || '{}' } }\n }\n pendingToolCalls.clear()\n\n yield { type: 'done' }\n}\n\nexport async function* parseAnthropicStream(stream: ReadableStream): AsyncIterableIterator<StreamChunk> {\n const pendingToolCalls = new Map<number, { id: string; name: string; args: string }>()\n\n for await (const data of readSSELines(stream)) {\n if (data === '[DONE]') continue\n\n try {\n const event = JSON.parse(data)\n if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta' && event.delta?.text) {\n yield { type: 'text', content: event.delta.text }\n } else if (event.type === 'content_block_delta' && event.delta?.type === 'input_json_delta') {\n const index: number = event.index ?? 0\n const existing = pendingToolCalls.get(index)\n if (existing) {\n existing.args += event.delta.partial_json ?? ''\n }\n } else if (event.type === 'content_block_start' && event.content_block?.type === 'tool_use') {\n const index: number = event.index ?? 0\n pendingToolCalls.set(index, {\n id: event.content_block.id,\n name: event.content_block.name,\n args: '',\n })\n } else if (event.type === 'content_block_stop') {\n const index: number = event.index ?? 0\n const tc = pendingToolCalls.get(index)\n if (tc) {\n yield {\n type: 'tool_call',\n toolCall: {\n id: tc.id,\n name: tc.name,\n args: tc.args || '{}',\n },\n }\n pendingToolCalls.delete(index)\n }\n } else if (event.type === 'message_delta' && event.usage) {\n // Anthropic emits output_tokens on `message_delta`, input_tokens on\n // `message_start`. We publish whatever we have on the delta — the\n // consumer accumulates across turns.\n yield {\n type: 'usage',\n usage: {\n promptTokens: event.usage.input_tokens ?? 0,\n completionTokens: event.usage.output_tokens ?? 0,\n totalTokens: (event.usage.input_tokens ?? 0) + (event.usage.output_tokens ?? 0),\n },\n }\n } else if (event.type === 'message_start' && event.message?.usage) {\n yield {\n type: 'usage',\n usage: {\n promptTokens: event.message.usage.input_tokens ?? 0,\n completionTokens: 0,\n totalTokens: event.message.usage.input_tokens ?? 0,\n },\n }\n } else if (event.type === 'message_stop') {\n // Flush any remaining tool calls\n for (const [, tc] of pendingToolCalls) {\n yield { type: 'tool_call', toolCall: { id: tc.id, name: tc.name, args: tc.args || '{}' } }\n }\n pendingToolCalls.clear()\n yield { type: 'done' }\n return\n }\n } catch {\n // Ignore malformed events.\n }\n }\n\n // Flush remaining if stream ends without message_stop\n for (const [, tc] of pendingToolCalls) {\n yield { type: 'tool_call', toolCall: { id: tc.id, name: tc.name, args: tc.args || '{}' } }\n }\n pendingToolCalls.clear()\n\n yield { type: 'done' }\n}\n\nexport async function* parseGeminiStream(stream: ReadableStream): AsyncIterableIterator<StreamChunk> {\n for await (const data of readSSELines(stream)) {\n try {\n const event = JSON.parse(data)\n\n if (event.usageMetadata) {\n yield {\n type: 'usage',\n usage: {\n promptTokens: event.usageMetadata.promptTokenCount ?? 0,\n completionTokens: event.usageMetadata.candidatesTokenCount ?? 0,\n totalTokens: event.usageMetadata.totalTokenCount ?? 0,\n },\n }\n }\n\n const parts = event.candidates?.[0]?.content?.parts\n if (!Array.isArray(parts)) continue\n\n for (const part of parts) {\n if (typeof part.text === 'string' && part.text) {\n yield { type: 'text', content: part.text }\n } else if (part.functionCall) {\n const fc = part.functionCall\n yield {\n type: 'tool_call',\n toolCall: {\n id: fc.id ?? `${fc.name}-${Date.now()}`,\n name: fc.name,\n args: JSON.stringify(fc.args ?? {}),\n },\n }\n }\n }\n } catch {\n // Ignore malformed events.\n }\n }\n\n yield { type: 'done' }\n}\n\nexport async function* parseOllamaStream(stream: ReadableStream): AsyncIterableIterator<StreamChunk> {\n for await (const data of readNDJSONLines(stream)) {\n try {\n const event = JSON.parse(data)\n if (event.message?.content) {\n yield { type: 'text', content: event.message.content }\n }\n if (Array.isArray(event.message?.tool_calls)) {\n for (const tc of event.message.tool_calls) {\n if (tc?.function?.name) {\n yield {\n type: 'tool_call',\n toolCall: {\n id: tc.id ?? `${tc.function.name}-${Date.now()}`,\n name: tc.function.name,\n args: typeof tc.function.arguments === 'string'\n ? tc.function.arguments\n : JSON.stringify(tc.function.arguments ?? {}),\n },\n }\n }\n }\n }\n if (event.done) {\n if (typeof event.prompt_eval_count === 'number' || typeof event.eval_count === 'number') {\n const promptTokens = event.prompt_eval_count ?? 0\n const completionTokens = event.eval_count ?? 0\n yield {\n type: 'usage',\n usage: {\n promptTokens,\n completionTokens,\n totalTokens: promptTokens + completionTokens,\n },\n }\n }\n yield { type: 'done' }\n return\n }\n } catch {\n // Ignore malformed events.\n }\n }\n\n yield { type: 'done' }\n}\n\n/**\n * Retry knobs for adapter fetches. Tunable per call to createStreamSource.\n *\n * Default behavior:\n * - 3 attempts total (1 initial + 2 retries)\n * - exponential backoff: 500ms, 1000ms, 2000ms ... (capped at maxDelayMs)\n * - full jitter on each delay\n * - retry on HTTP 408, 429, 500, 502, 503, 504\n * - retry on network errors (fetch throws)\n * - DO NOT retry on 4xx other than 408/429 (those are bad requests / auth)\n * - retries only the initial fetch — never mid-stream\n * - respects Retry-After header when present\n */\nexport interface RetryOptions {\n maxAttempts?: number\n baseDelayMs?: number\n maxDelayMs?: number\n jitter?: boolean\n retryOn?: (info: { error?: unknown; response?: Response; attempt: number }) => boolean\n /** Hook for tests + logging. Called after every failed attempt. */\n onRetry?: (info: { attempt: number; delayMs: number; reason: string }) => void\n /** Sleep override for tests. Defaults to setTimeout. */\n sleep?: (ms: number) => Promise<void>\n}\n\nconst DEFAULT_RETRY: Required<Omit<RetryOptions, 'onRetry' | 'sleep' | 'retryOn'>> & {\n retryOn: NonNullable<RetryOptions['retryOn']>\n} = {\n maxAttempts: 3,\n baseDelayMs: 500,\n maxDelayMs: 8000,\n jitter: true,\n retryOn: ({ error, response }) => {\n if (response) {\n return [408, 429, 500, 502, 503, 504].includes(response.status)\n }\n if (error instanceof DOMException && error.name === 'AbortError') return false\n // Network error: TypeError from fetch, AbortError from upstream timeout, etc.\n return true\n },\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\nfunction computeDelay(attempt: number, opts: Required<Pick<RetryOptions, 'baseDelayMs' | 'maxDelayMs' | 'jitter'>>): number {\n const exp = Math.min(opts.maxDelayMs, opts.baseDelayMs * Math.pow(2, attempt - 1))\n if (!opts.jitter) return exp\n return Math.floor(Math.random() * exp)\n}\n\nfunction parseRetryAfter(value: string | null): number | undefined {\n if (!value) return undefined\n const n = Number(value)\n if (!Number.isNaN(n)) return n * 1000\n const date = Date.parse(value)\n if (!Number.isNaN(date)) return Math.max(0, date - Date.now())\n return undefined\n}\n\n/**\n * Run a fetch with retries on transient failures. Returns the final\n * Response (whether successful or not — caller decides), or throws if\n * the AbortSignal fires or all attempts fail with a thrown error.\n */\nexport async function fetchWithRetry(\n doFetch: (signal: AbortSignal) => Promise<Response>,\n signal: AbortSignal,\n retryOpt: RetryOptions = {},\n): Promise<Response> {\n const opts = {\n ...DEFAULT_RETRY,\n ...retryOpt,\n }\n const sleep = retryOpt.sleep ?? defaultSleep\n let lastError: unknown\n\n for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\n if (signal.aborted) throw new DOMException('Aborted', 'AbortError')\n\n try {\n const response = await doFetch(signal)\n\n // Success or non-retryable failure → return.\n if (response.ok) return response\n if (attempt >= opts.maxAttempts || !opts.retryOn({ response, attempt })) {\n return response\n }\n\n const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'))\n const delay = retryAfterMs ?? computeDelay(attempt, opts)\n retryOpt.onRetry?.({ attempt, delayMs: delay, reason: `HTTP ${response.status}` })\n await sleep(delay)\n // Drain the body so the connection can be reused.\n response.body?.cancel().catch(() => {})\n } catch (err) {\n lastError = err\n if (err instanceof DOMException && err.name === 'AbortError') throw err\n if (attempt >= opts.maxAttempts || !opts.retryOn({ error: err, attempt })) throw err\n\n const delay = computeDelay(attempt, opts)\n retryOpt.onRetry?.({ attempt, delayMs: delay, reason: (err as Error).message })\n await sleep(delay)\n }\n }\n\n // Unreachable, but the TS narrowing needs it.\n throw lastError ?? new Error('fetchWithRetry: exhausted attempts')\n}\n\nexport function createStreamSource(\n doFetch: (signal: AbortSignal) => Promise<Response>,\n parse: (stream: ReadableStream) => AsyncIterableIterator<StreamChunk>,\n errorLabel: string,\n retry?: RetryOptions,\n): StreamSource {\n let abortController: AbortController | null = new AbortController()\n\n return {\n stream: async function* (): AsyncIterableIterator<StreamChunk> {\n const controller = abortController\n if (!controller) return\n try {\n const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {})\n\n if (!response.ok || !response.body) {\n yield { type: 'error', content: `${errorLabel} error: ${response.status}` }\n return\n }\n\n yield* parse(response.body)\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') return\n yield {\n type: 'error',\n content: err instanceof Error ? err.message : String(err),\n }\n }\n },\n abort: () => {\n abortController?.abort()\n abortController = null\n },\n }\n}\n\n/**\n * Chunk-splitter that turns one large string into N streamable text chunks.\n * Useful when a provider returns the full response in one shot and you\n * want to feed it to a UI that expects streaming.\n *\n * Default splits by whitespace boundaries with a target chunk size of ~32\n * characters.\n */\nexport function chunkText(text: string, targetSize = 32): string[] {\n if (text.length <= targetSize) return [text]\n const out: string[] = []\n let i = 0\n while (i < text.length) {\n let end = Math.min(text.length, i + targetSize)\n // Prefer to cut on whitespace within the next few chars\n if (end < text.length) {\n const nextSpace = text.indexOf(' ', end)\n if (nextSpace !== -1 && nextSpace - end <= 8) end = nextSpace + 1\n }\n out.push(text.slice(i, end))\n i = end\n }\n return out\n}\n\n/**\n * Build a StreamSource from a non-streaming fetch. The adapter is\n * auto-completing: it fetches once, then yields the text as a sequence\n * of chunks so UIs see the same streaming shape they'd see from a\n * native streaming provider.\n *\n * Use this when you're wiring a provider that only has a non-streaming\n * endpoint but you want consumers (useChat, the runtime) to get\n * identical ergonomics.\n */\nexport function simulateStream(\n doFetch: (signal: AbortSignal) => Promise<Response>,\n extractText: (response: Response) => Promise<string>,\n errorLabel: string,\n options: { chunkSize?: number; delayMs?: number; retry?: RetryOptions } = {},\n): StreamSource {\n const { chunkSize = 32, delayMs = 8, retry } = options\n let abortController: AbortController | null = new AbortController()\n\n return {\n stream: async function* (): AsyncIterableIterator<StreamChunk> {\n const controller = abortController\n if (!controller) return\n try {\n const response = await fetchWithRetry(doFetch, controller.signal, retry ?? {})\n\n if (!response.ok) {\n yield { type: 'error', content: `${errorLabel} error: ${response.status}` }\n return\n }\n\n const text = await extractText(response)\n const chunks = chunkText(text, chunkSize)\n for (const chunk of chunks) {\n if (abortController === null) return\n if (delayMs > 0) {\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(resolve, delayMs)\n controller.signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer)\n reject(new DOMException('Aborted', 'AbortError'))\n },\n { once: true },\n )\n })\n }\n yield { type: 'text', content: chunk }\n }\n yield { type: 'done' }\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') return\n yield {\n type: 'error',\n content: err instanceof Error ? err.message : String(err),\n }\n }\n },\n abort: () => {\n abortController?.abort()\n abortController = null\n },\n }\n}\n","import type { AdapterFactory, AdapterRequest, StreamSource } from '@agentskit/core'\nimport { createStreamSource, parseOpenAIStream, toProviderMessages, type RetryOptions } from './utils'\n\nexport interface OpenAIConfig {\n apiKey: string\n model: string\n baseUrl?: string\n retry?: RetryOptions\n /**\n * Ask the provider to include token usage in the final stream chunk via\n * `stream_options: { include_usage: true }`. Off by default because some\n * OpenAI-compatible providers (OpenRouter proxies to a long tail of\n * backends) reject unknown params with a 4xx and break the whole stream.\n * Turn this on for vanilla `api.openai.com`.\n */\n includeUsage?: boolean\n}\n\nexport function openai(config: OpenAIConfig): AdapterFactory {\n const { apiKey, model, baseUrl = 'https://api.openai.com', retry } = config\n // Auto: on for canonical OpenAI, off for every other compatible endpoint\n // where the param is a known source of 4xx surprises.\n // Match the canonical OpenAI host exactly — a substring/prefix check\n // would also accept `https://api.openai.com.evil.test`.\n const isCanonicalOpenAI = (() => {\n try {\n return new URL(baseUrl).host === 'api.openai.com'\n } catch {\n return false\n }\n })()\n const includeUsage = config.includeUsage ?? isCanonicalOpenAI\n\n return {\n capabilities: {\n streaming: true,\n tools: true,\n // o1 / o3 models emit reasoning; older models don't. Accurate per-model\n // detection would need a model registry; 'true' is the safer default here.\n reasoning: model.startsWith('o1') || model.startsWith('o3'),\n multiModal: model.startsWith('gpt-4') || model.startsWith('o'),\n usage: true,\n },\n createSource: (request: AdapterRequest): StreamSource => {\n const body: Record<string, unknown> = {\n model,\n messages: toProviderMessages(request.messages),\n tools: request.context?.tools?.map(tool => ({\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.schema,\n },\n })),\n temperature: request.context?.temperature,\n max_tokens: request.context?.maxTokens,\n stream: true,\n }\n if (includeUsage) body.stream_options = { include_usage: true }\n\n return createStreamSource(\n (signal) => fetch(`${baseUrl}/v1/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n signal,\n }),\n parseOpenAIStream,\n 'OpenAI API',\n retry,\n )\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AdapterRequest, StreamChunk, AdapterFactory } from '@agentskit/core';
|
|
2
|
+
|
|
3
|
+
interface CreateAdapterConfig {
|
|
4
|
+
send: (request: AdapterRequest) => Promise<ReadableStream | Response>;
|
|
5
|
+
parse: (stream: ReadableStream) => AsyncIterableIterator<StreamChunk>;
|
|
6
|
+
abort?: () => void;
|
|
7
|
+
}
|
|
8
|
+
interface GenericAdapterConfig {
|
|
9
|
+
send: (request: AdapterRequest) => Promise<ReadableStream>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare function createAdapter(config: CreateAdapterConfig): AdapterFactory;
|
|
13
|
+
|
|
14
|
+
export { type CreateAdapterConfig as C, type GenericAdapterConfig as G, createAdapter as c };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AdapterRequest, StreamChunk, AdapterFactory } from '@agentskit/core';
|
|
2
|
+
|
|
3
|
+
interface CreateAdapterConfig {
|
|
4
|
+
send: (request: AdapterRequest) => Promise<ReadableStream | Response>;
|
|
5
|
+
parse: (stream: ReadableStream) => AsyncIterableIterator<StreamChunk>;
|
|
6
|
+
abort?: () => void;
|
|
7
|
+
}
|
|
8
|
+
interface GenericAdapterConfig {
|
|
9
|
+
send: (request: AdapterRequest) => Promise<ReadableStream>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
declare function createAdapter(config: CreateAdapterConfig): AdapterFactory;
|
|
13
|
+
|
|
14
|
+
export { type CreateAdapterConfig as C, type GenericAdapterConfig as G, createAdapter as c };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/createAdapter.ts
|
|
4
|
+
function createAdapter(config) {
|
|
5
|
+
return {
|
|
6
|
+
createSource: (request) => ({
|
|
7
|
+
stream: async function* () {
|
|
8
|
+
try {
|
|
9
|
+
const result = await config.send(request);
|
|
10
|
+
const stream = result instanceof Response ? result.body : result;
|
|
11
|
+
yield* config.parse(stream);
|
|
12
|
+
} catch (err) {
|
|
13
|
+
yield {
|
|
14
|
+
type: "error",
|
|
15
|
+
content: err instanceof Error ? err.message : String(err)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
abort: () => {
|
|
20
|
+
config.abort?.();
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
exports.createAdapter = createAdapter;
|
|
27
|
+
//# sourceMappingURL=createAdapter.cjs.map
|
|
28
|
+
//# sourceMappingURL=createAdapter.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/createAdapter.ts"],"names":[],"mappings":";;;AAGO,SAAS,cAAc,MAAA,EAA6C;AACzE,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,CAAC,OAAA,MAA2C;AAAA,MACxD,QAAQ,mBAAuD;AAC7D,QAAA,IAAI;AACF,UAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AACxC,UAAA,MAAM,MAAA,GAAS,MAAA,YAAkB,QAAA,GAC7B,MAAA,CAAO,IAAA,GACP,MAAA;AACJ,UAAA,OAAO,MAAA,CAAO,MAAM,MAAM,CAAA;AAAA,QAC5B,SAAS,GAAA,EAAK;AACZ,UAAA,MAAM;AAAA,YACJ,IAAA,EAAM,OAAA;AAAA,YACN,SAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,WAC1D;AAAA,QACF;AAAA,MACF,CAAA;AAAA,MACA,OAAO,MAAM;AACX,QAAA,MAAA,CAAO,KAAA,IAAQ;AAAA,MACjB;AAAA,KACF;AAAA,GACF;AACF","file":"createAdapter.cjs","sourcesContent":["import type { AdapterFactory, AdapterRequest, StreamChunk, StreamSource } from '@agentskit/core'\nimport type { CreateAdapterConfig } from './types'\n\nexport function createAdapter(config: CreateAdapterConfig): AdapterFactory {\n return {\n createSource: (request: AdapterRequest): StreamSource => ({\n stream: async function* (): AsyncIterableIterator<StreamChunk> {\n try {\n const result = await config.send(request)\n const stream = result instanceof Response\n ? result.body!\n : result\n yield* config.parse(stream)\n } catch (err) {\n yield {\n type: 'error',\n content: err instanceof Error ? err.message : String(err),\n }\n }\n },\n abort: () => {\n config.abort?.()\n },\n }),\n }\n}\n"]}
|