pi-freerouter 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.
@@ -0,0 +1,74 @@
1
+ import { strict as assert } from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import { FreeRouter } from "./router.js";
4
+ describe("FreeRouter", () => {
5
+ it("returns the first model when none exhausted", () => {
6
+ const r = new FreeRouter(["a:free", "b:free", "c:free"]);
7
+ assert.equal(r.nextModel(), "a:free");
8
+ });
9
+ it("skips exhausted models", () => {
10
+ const r = new FreeRouter(["a:free", "b:free", "c:free"]);
11
+ r.markExhausted("a:free");
12
+ assert.equal(r.nextModel(), "b:free");
13
+ });
14
+ it("returns null when all models exhausted", () => {
15
+ const r = new FreeRouter(["a:free", "b:free"]);
16
+ r.markExhausted("a:free");
17
+ r.markExhausted("b:free");
18
+ assert.equal(r.nextModel(), null);
19
+ });
20
+ it("always returns first available in insertion order", () => {
21
+ const r = new FreeRouter(["a:free", "b:free", "c:free"]);
22
+ r.markExhausted("a:free");
23
+ r.markExhausted("b:free");
24
+ assert.equal(r.nextModel(), "c:free");
25
+ assert.equal(r.nextModel(), "c:free"); // stable
26
+ });
27
+ it("handles empty model list", () => {
28
+ const r = new FreeRouter([]);
29
+ assert.equal(r.nextModel(), null);
30
+ });
31
+ it("ignores markExhausted with unknown ID", () => {
32
+ const r = new FreeRouter(["a:free", "b:free"]);
33
+ r.markExhausted("unknown:free"); // not in models list
34
+ assert.equal(r.nextModel(), "a:free"); // unchanged
35
+ });
36
+ it("markExhausted is idempotent", () => {
37
+ const r = new FreeRouter(["a:free", "b:free"]);
38
+ r.markExhausted("a:free");
39
+ r.markExhausted("a:free"); // second call, same ID
40
+ assert.equal(r.nextModel(), "b:free"); // still correct
41
+ });
42
+ it("nextModels returns up to count non-exhausted models in order", () => {
43
+ const r = new FreeRouter(["a:free", "b:free", "c:free", "d:free"]);
44
+ r.markExhausted("b:free");
45
+ assert.deepEqual(r.nextModels(2), ["a:free", "c:free"]);
46
+ });
47
+ it("nextModels returns fewer than count when not enough available", () => {
48
+ const r = new FreeRouter(["a:free", "b:free"]);
49
+ r.markExhausted("b:free");
50
+ assert.deepEqual(r.nextModels(3), ["a:free"]);
51
+ });
52
+ it("exhausted model returns after TTL expires", async () => {
53
+ const r = new FreeRouter(["a:free", "b:free"], 20); // 20ms TTL for test speed
54
+ r.markExhausted("a:free");
55
+ assert.equal(r.nextModel(), "b:free"); // a is excluded
56
+ await new Promise((res) => setTimeout(res, 30)); // wait past TTL
57
+ assert.equal(r.nextModel(), "a:free"); // a is back at front of list
58
+ });
59
+ it("markSlow skips model with short TTL", async () => {
60
+ const r = new FreeRouter(["a:free", "b:free"]);
61
+ r.markSlow("a:free");
62
+ assert.equal(r.nextModel(), "b:free"); // a temporarily skipped
63
+ // Note: full 15s slow TTL not tested to keep tests fast; TTL logic is shared with markExhausted
64
+ });
65
+ it("markSlow does not downgrade an exhausted model to slow TTL", () => {
66
+ const r = new FreeRouter(["a:free", "b:free"], 90_000);
67
+ r.markExhausted("a:free");
68
+ r.markSlow("a:free"); // should keep the longer 90s TTL
69
+ // Both markExhausted and markSlow skip the model; the key invariant is that
70
+ // markSlow won't replace a long-TTL entry with a short one.
71
+ assert.equal(r.nextModel(), "b:free"); // a still excluded
72
+ });
73
+ });
74
+ //# sourceMappingURL=router.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.test.js","sourceRoot":"","sources":["../src/router.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { AssistantMessageEventStream, Context } from "./types.js";
2
+ export declare class ModelExhaustedError extends Error {
3
+ readonly modelId: string;
4
+ readonly status: number;
5
+ constructor(modelId: string, status: number);
6
+ }
7
+ /** Thrown when the API key has insufficient credits (HTTP 402). Not retriable. */
8
+ export declare class ModelFatalError extends Error {
9
+ constructor(message: string);
10
+ }
11
+ export declare function streamFreeModel(modelId: string, context: Context, apiKey: string, outStream: AssistantMessageEventStream, signal?: AbortSignal, maxTokens?: number): Promise<void>;
package/dist/stream.js ADDED
@@ -0,0 +1,292 @@
1
+ export class ModelExhaustedError extends Error {
2
+ modelId;
3
+ status;
4
+ constructor(modelId, status) {
5
+ super(`Model ${modelId} quota exceeded (HTTP ${status})`);
6
+ this.modelId = modelId;
7
+ this.status = status;
8
+ this.name = "ModelExhaustedError";
9
+ }
10
+ }
11
+ /** Thrown when the API key has insufficient credits (HTTP 402). Not retriable. */
12
+ export class ModelFatalError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = "ModelFatalError";
16
+ }
17
+ }
18
+ // Fix 6: Helper — normalize OpenRouter finish_reason to Pi StopReason
19
+ function normalizeStopReason(finishReason) {
20
+ if (finishReason === "tool_calls")
21
+ return "toolUse";
22
+ if (finishReason === "length")
23
+ return "length";
24
+ return "stop";
25
+ }
26
+ // Fix 7: Helper — deep-clone output for partial snapshots (content items are shallow-cloned)
27
+ function snapshot(output) {
28
+ return { ...output, content: output.content.map((c) => ({ ...c })) };
29
+ }
30
+ // Fix 6: Helper — get current text for text_end content field
31
+ function getCurrentText(output, textIndex) {
32
+ const block = output.content[textIndex];
33
+ return block?.type === "text" ? block.text : "";
34
+ }
35
+ // Fix 6: Helper — emit text_end event
36
+ function emitTextEnd(outStream, output, contentIndex) {
37
+ outStream.push({
38
+ type: "text_end",
39
+ contentIndex,
40
+ content: getCurrentText(output, contentIndex),
41
+ partial: snapshot(output),
42
+ });
43
+ }
44
+ /**
45
+ * Convert Pi's internal message format to OpenRouter's chat-completion format.
46
+ *
47
+ * Pi uses role:"toolResult" and embeds tool calls inside content[]; OpenRouter
48
+ * expects role:"tool" and tool_calls as a top-level array on assistant messages.
49
+ */
50
+ function normalizeMessages(messages) {
51
+ const out = [];
52
+ for (const msg of messages) {
53
+ if (msg.role === "user") {
54
+ if (typeof msg.content === "string") {
55
+ out.push({ role: "user", content: msg.content });
56
+ }
57
+ else {
58
+ const parts = msg.content.map((c) => {
59
+ if (c.type === "text")
60
+ return { type: "text", text: c.text };
61
+ // image → data URL
62
+ return { type: "image_url", image_url: { url: `data:${c.mimeType};base64,${c.data}` } };
63
+ });
64
+ out.push({ role: "user", content: parts });
65
+ }
66
+ }
67
+ else if (msg.role === "assistant") {
68
+ const textParts = msg.content
69
+ .filter((c) => c.type === "text")
70
+ .map((c) => c.text)
71
+ .join("");
72
+ const toolCalls = msg.content
73
+ .filter((c) => c.type === "toolCall")
74
+ .map((tc) => ({
75
+ id: tc.id,
76
+ type: "function",
77
+ function: { name: tc.name, arguments: JSON.stringify(tc.arguments) },
78
+ }));
79
+ if (toolCalls.length > 0) {
80
+ out.push({ role: "assistant", content: textParts || null, tool_calls: toolCalls });
81
+ }
82
+ else {
83
+ out.push({ role: "assistant", content: textParts });
84
+ }
85
+ }
86
+ else if (msg.role === "toolResult") {
87
+ const tr = msg;
88
+ const text = tr.content
89
+ .filter((c) => c.type === "text")
90
+ .map((c) => c.text)
91
+ .join("\n");
92
+ out.push({ role: "tool", tool_call_id: tr.toolCallId, content: text });
93
+ }
94
+ // unknown roles: silently drop (forward compatibility)
95
+ }
96
+ return out;
97
+ }
98
+ export async function streamFreeModel(modelId, context, apiKey, outStream, signal, maxTokens) {
99
+ const messages = [
100
+ ...(context.systemPrompt ? [{ role: "system", content: context.systemPrompt }] : []),
101
+ ...normalizeMessages(context.messages),
102
+ ];
103
+ const body = { model: modelId, stream: true, messages };
104
+ if (maxTokens !== undefined)
105
+ body.max_tokens = maxTokens;
106
+ // Forward tool definitions if Pi provided them — free models that support
107
+ // function calling will use them; those that don't will return 400 and be
108
+ // temporarily skipped by the router.
109
+ if (context.tools && context.tools.length > 0) {
110
+ body.tools = context.tools.map((t) => ({
111
+ type: "function",
112
+ function: { name: t.name, description: t.description, parameters: t.parameters },
113
+ }));
114
+ }
115
+ const response = await fetch("https://openrouter.ai/api/v1/chat/completions", {
116
+ method: "POST",
117
+ headers: {
118
+ Authorization: `Bearer ${apiKey}`,
119
+ "Content-Type": "application/json",
120
+ "X-Title": "pi-freerouter",
121
+ },
122
+ body: JSON.stringify(body),
123
+ signal,
124
+ });
125
+ if (response.status === 402) {
126
+ throw new ModelFatalError("OpenRouter API key has insufficient credits. Add credits at openrouter.ai/credits.");
127
+ }
128
+ if (response.status === 429 || response.status >= 500) {
129
+ throw new ModelExhaustedError(modelId, response.status);
130
+ }
131
+ // 400/422: model rejected the request (unsupported features, content policy, etc.)
132
+ // Treat like exhaustion so the router skips this model for the current batch.
133
+ if (response.status === 400 || response.status === 422) {
134
+ throw new ModelExhaustedError(modelId, response.status);
135
+ }
136
+ if (!response.ok) {
137
+ throw new Error(`OpenRouter error: ${response.status} ${response.statusText}`);
138
+ }
139
+ // Fix 4: Guard response.body null
140
+ if (!response.body) {
141
+ throw new Error(`OpenRouter returned empty body for model ${modelId}`);
142
+ }
143
+ const now = Date.now();
144
+ const output = {
145
+ role: "assistant",
146
+ content: [],
147
+ api: "openrouter",
148
+ provider: "openrouter",
149
+ model: modelId,
150
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
151
+ stopReason: "stop",
152
+ timestamp: now,
153
+ };
154
+ outStream.push({ type: "start", partial: snapshot(output) });
155
+ let textStarted = false;
156
+ // Text content is always at index 0.
157
+ const TEXT_INDEX = 0;
158
+ const pendingToolCalls = new Map();
159
+ function flushToolCalls() {
160
+ for (const [, p] of pendingToolCalls) {
161
+ let args = {};
162
+ try {
163
+ args = JSON.parse(p.argsBuffer);
164
+ }
165
+ catch {
166
+ args = { _raw: p.argsBuffer };
167
+ }
168
+ const block = output.content[p.contentIndex];
169
+ if (block?.type === "toolCall")
170
+ block.arguments = args;
171
+ outStream.push({
172
+ type: "toolcall_end",
173
+ contentIndex: p.contentIndex,
174
+ toolCall: { type: "toolCall", id: p.id, name: p.name, arguments: args },
175
+ partial: snapshot(output),
176
+ });
177
+ }
178
+ pendingToolCalls.clear();
179
+ }
180
+ const reader = response.body.getReader();
181
+ const decoder = new TextDecoder();
182
+ let buffer = "";
183
+ try {
184
+ while (true) {
185
+ const { done, value } = await reader.read();
186
+ if (done)
187
+ break;
188
+ buffer += decoder.decode(value, { stream: true });
189
+ const lines = buffer.split("\n");
190
+ buffer = lines.pop();
191
+ for (const line of lines) {
192
+ if (!line.startsWith("data: "))
193
+ continue;
194
+ const data = line.slice(6).trim();
195
+ if (data === "[DONE]") {
196
+ if (textStarted)
197
+ emitTextEnd(outStream, output, TEXT_INDEX);
198
+ flushToolCalls();
199
+ outStream.push({ type: "done", reason: output.stopReason, message: snapshot(output) });
200
+ outStream.end();
201
+ return;
202
+ }
203
+ let chunk;
204
+ try {
205
+ chunk = JSON.parse(data);
206
+ }
207
+ catch {
208
+ continue;
209
+ }
210
+ // OpenRouter sometimes streams errors inline as {"error":{"code":N,"message":"..."}}
211
+ // instead of returning a non-200 HTTP status.
212
+ if (chunk.error) {
213
+ const code = chunk.error.code ?? chunk.error.status ?? 0;
214
+ if (code === 402)
215
+ throw new ModelFatalError(chunk.error.message ?? "insufficient credits");
216
+ if (code === 429 || code >= 500)
217
+ throw new ModelExhaustedError(modelId, code);
218
+ // Other inline errors (e.g. content policy): treat as exhausted so we skip this model.
219
+ throw new ModelExhaustedError(modelId, code || 400);
220
+ }
221
+ const choice = chunk.choices?.[0];
222
+ const delta = choice?.delta;
223
+ const finishReason = choice?.finish_reason;
224
+ const usage = chunk.usage;
225
+ if (usage) {
226
+ output.usage.input = usage.prompt_tokens ?? 0;
227
+ output.usage.output = usage.completion_tokens ?? 0;
228
+ output.usage.totalTokens = usage.total_tokens ?? 0;
229
+ }
230
+ if (finishReason) {
231
+ output.stopReason = normalizeStopReason(finishReason);
232
+ }
233
+ // ── Text content ──────────────────────────────────────────────────────
234
+ if (delta?.content) {
235
+ if (!textStarted) {
236
+ output.content.push({ type: "text", text: "" });
237
+ outStream.push({ type: "text_start", contentIndex: TEXT_INDEX, partial: snapshot(output) });
238
+ textStarted = true;
239
+ }
240
+ const textBlock = output.content[TEXT_INDEX];
241
+ if (textBlock?.type === "text")
242
+ textBlock.text += delta.content;
243
+ outStream.push({ type: "text_delta", contentIndex: TEXT_INDEX, delta: delta.content, partial: snapshot(output) });
244
+ }
245
+ // ── Tool calls ────────────────────────────────────────────────────────
246
+ if (delta?.tool_calls) {
247
+ for (const tc of delta.tool_calls) {
248
+ const tcIdx = tc.index ?? 0;
249
+ if (tc.id) {
250
+ // First chunk for this tool call — open it.
251
+ const contentIndex = output.content.length;
252
+ const name = tc.function?.name ?? "";
253
+ output.content.push({ type: "toolCall", id: tc.id, name, arguments: {} });
254
+ pendingToolCalls.set(tcIdx, { contentIndex, id: tc.id, name, argsBuffer: tc.function?.arguments ?? "" });
255
+ outStream.push({ type: "toolcall_start", contentIndex, partial: snapshot(output) });
256
+ }
257
+ else if (tc.function?.arguments) {
258
+ // Continuation chunk — stream argument JSON fragment.
259
+ const p = pendingToolCalls.get(tcIdx);
260
+ if (p) {
261
+ p.argsBuffer += tc.function.arguments;
262
+ outStream.push({ type: "toolcall_delta", contentIndex: p.contentIndex, delta: tc.function.arguments, partial: snapshot(output) });
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ // Flush TextDecoder
270
+ const remaining = decoder.decode();
271
+ if (remaining)
272
+ buffer += remaining;
273
+ // Fallback: stream ended without [DONE]
274
+ if (textStarted)
275
+ emitTextEnd(outStream, output, TEXT_INDEX);
276
+ flushToolCalls();
277
+ outStream.push({ type: "done", reason: output.stopReason, message: snapshot(output) });
278
+ outStream.end();
279
+ }
280
+ catch (err) {
281
+ // Close any in-progress text/tool-call blocks so consumers don't see
282
+ // dangling text_start or toolcall_start events without their closers.
283
+ if (textStarted)
284
+ emitTextEnd(outStream, output, TEXT_INDEX);
285
+ flushToolCalls();
286
+ const isAbort = err instanceof Error && err.name === "AbortError";
287
+ outStream.push({ type: "error", reason: isAbort ? "aborted" : "error", error: output });
288
+ outStream.end();
289
+ throw err;
290
+ }
291
+ }
292
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,129 @@
1
+ import { strict as assert } from "node:assert";
2
+ import { describe, it, beforeEach, afterEach } from "node:test";
3
+ import { ModelExhaustedError, ModelFatalError } from "./stream.js";
4
+ function makeStream() {
5
+ const events = [];
6
+ let ended = false;
7
+ return {
8
+ push: (e) => events.push(e),
9
+ end: () => { ended = true; },
10
+ get events() { return events; },
11
+ get ended() { return ended; },
12
+ };
13
+ }
14
+ function makeSseBody(lines) {
15
+ const encoder = new TextEncoder();
16
+ const text = lines.map((l) => `data: ${l}\n\n`).join("");
17
+ return new ReadableStream({
18
+ start(controller) {
19
+ controller.enqueue(encoder.encode(text));
20
+ controller.close();
21
+ },
22
+ });
23
+ }
24
+ describe("streamFreeModel", () => {
25
+ let originalFetch;
26
+ beforeEach(() => { originalFetch = globalThis.fetch; });
27
+ afterEach(() => { globalThis.fetch = originalFetch; });
28
+ it("throws ModelExhaustedError on 429", async () => {
29
+ globalThis.fetch = async () => ({ ok: false, status: 429, statusText: "Too Many Requests", body: null });
30
+ const { streamFreeModel } = await import("./stream.js");
31
+ const stream = makeStream();
32
+ await assert.rejects(() => streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream), ModelExhaustedError);
33
+ });
34
+ it("throws ModelFatalError on 402", async () => {
35
+ globalThis.fetch = async () => ({ ok: false, status: 402, statusText: "Payment Required", body: null });
36
+ const { streamFreeModel } = await import("./stream.js");
37
+ const stream = makeStream();
38
+ await assert.rejects(() => streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream), ModelFatalError);
39
+ });
40
+ it("throws ModelExhaustedError on 503", async () => {
41
+ globalThis.fetch = async () => ({ ok: false, status: 503, statusText: "Service Unavailable", body: null });
42
+ const { streamFreeModel } = await import("./stream.js");
43
+ const stream = makeStream();
44
+ await assert.rejects(() => streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream), ModelExhaustedError);
45
+ });
46
+ it("throws ModelExhaustedError on 400 (model rejects request)", async () => {
47
+ globalThis.fetch = async () => ({ ok: false, status: 400, statusText: "Bad Request", body: null });
48
+ const { streamFreeModel } = await import("./stream.js");
49
+ const stream = makeStream();
50
+ await assert.rejects(() => streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream), ModelExhaustedError);
51
+ });
52
+ it("throws ModelExhaustedError on 422 (unprocessable)", async () => {
53
+ globalThis.fetch = async () => ({ ok: false, status: 422, statusText: "Unprocessable Entity", body: null });
54
+ const { streamFreeModel } = await import("./stream.js");
55
+ const stream = makeStream();
56
+ await assert.rejects(() => streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream), ModelExhaustedError);
57
+ });
58
+ it("throws ModelExhaustedError on inline SSE 429 error", async () => {
59
+ const sseLines = [
60
+ JSON.stringify({ error: { code: 429, message: "rate limit exceeded" } }),
61
+ ];
62
+ globalThis.fetch = async () => ({ ok: true, status: 200, body: makeSseBody(sseLines) });
63
+ const { streamFreeModel } = await import("./stream.js");
64
+ const stream = makeStream();
65
+ await assert.rejects(() => streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream), ModelExhaustedError);
66
+ });
67
+ it("throws ModelFatalError on inline SSE 402 error", async () => {
68
+ const sseLines = [
69
+ JSON.stringify({ error: { code: 402, message: "insufficient credits" } }),
70
+ ];
71
+ globalThis.fetch = async () => ({ ok: true, status: 200, body: makeSseBody(sseLines) });
72
+ const { streamFreeModel } = await import("./stream.js");
73
+ const stream = makeStream();
74
+ await assert.rejects(() => streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream), ModelFatalError);
75
+ });
76
+ it("emits toolcall events for tool call responses", async () => {
77
+ const sseLines = [
78
+ JSON.stringify({ choices: [{ delta: { role: "assistant", content: null, tool_calls: [{ index: 0, id: "call_abc", type: "function", function: { name: "bash", arguments: "" } }] }, finish_reason: null }] }),
79
+ JSON.stringify({ choices: [{ delta: { tool_calls: [{ index: 0, function: { arguments: '{"command' } }] }, finish_reason: null }] }),
80
+ JSON.stringify({ choices: [{ delta: { tool_calls: [{ index: 0, function: { arguments: '":"ls"}' } }] }, finish_reason: null }] }),
81
+ JSON.stringify({ choices: [{ delta: {}, finish_reason: "tool_calls" }], usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 } }),
82
+ "[DONE]",
83
+ ];
84
+ globalThis.fetch = async () => ({ ok: true, status: 200, body: makeSseBody(sseLines) });
85
+ const { streamFreeModel } = await import("./stream.js");
86
+ const stream = makeStream();
87
+ await streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream);
88
+ const types = stream.events.map((e) => e.type);
89
+ assert.ok(types.includes("start"), "missing start event");
90
+ assert.ok(types.includes("toolcall_start"), "missing toolcall_start");
91
+ assert.ok(types.includes("toolcall_delta"), "missing toolcall_delta");
92
+ assert.ok(types.includes("toolcall_end"), "missing toolcall_end");
93
+ assert.ok(types.includes("done"), "missing done event");
94
+ assert.ok(stream.ended, "stream.end() was not called");
95
+ const tcEnd = stream.events.find((e) => e.type === "toolcall_end");
96
+ assert.equal(tcEnd.toolCall.id, "call_abc");
97
+ assert.equal(tcEnd.toolCall.name, "bash");
98
+ assert.deepEqual(tcEnd.toolCall.arguments, { command: "ls" });
99
+ const done = stream.events.find((e) => e.type === "done");
100
+ assert.equal(done.reason, "toolUse");
101
+ });
102
+ it("pushes text events and done on success", async () => {
103
+ const sseLines = [
104
+ JSON.stringify({ choices: [{ delta: { role: "assistant", content: "" }, finish_reason: null }] }),
105
+ JSON.stringify({ choices: [{ delta: { content: "Hello" }, finish_reason: null }] }),
106
+ JSON.stringify({ choices: [{ delta: { content: " world" }, finish_reason: null }] }),
107
+ JSON.stringify({ choices: [{ delta: {}, finish_reason: "stop" }], usage: { prompt_tokens: 5, completion_tokens: 2, total_tokens: 7 } }),
108
+ "[DONE]",
109
+ ];
110
+ globalThis.fetch = async () => ({ ok: true, status: 200, body: makeSseBody(sseLines) });
111
+ const { streamFreeModel } = await import("./stream.js");
112
+ const stream = makeStream();
113
+ await streamFreeModel("model:free", { messages: [] }, "sk-or-test", stream);
114
+ const types = stream.events.map((e) => e.type);
115
+ assert.ok(types.includes("start"), "missing start event");
116
+ assert.ok(types.includes("text_start"), "missing text_start");
117
+ assert.ok(types.includes("text_delta"), "missing text_delta");
118
+ assert.ok(types.includes("done"), "missing done event");
119
+ assert.ok(stream.ended, "stream.end() was not called");
120
+ const deltas = stream.events
121
+ .filter((e) => e.type === "text_delta")
122
+ .map((e) => e.delta);
123
+ assert.deepEqual(deltas, ["Hello", " world"]);
124
+ const done = stream.events.find((e) => e.type === "done");
125
+ assert.equal(done.message.usage.input, 5);
126
+ assert.equal(done.message.usage.output, 2);
127
+ });
128
+ });
129
+ //# sourceMappingURL=stream.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.test.js","sourceRoot":"","sources":["../src/stream.test.ts"],"names":[],"mappings":"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"}