@mohanscodex/spectra-ai 0.4.6 → 0.4.9

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.
Files changed (48) hide show
  1. package/dist/__tests__/e2e.test.js +178 -178
  2. package/dist/__tests__/e2e.test.js.map +1 -1
  3. package/dist/__tests__/event-stream.test.js +83 -40
  4. package/dist/__tests__/event-stream.test.js.map +1 -1
  5. package/dist/__tests__/provider.test.js +46 -31
  6. package/dist/__tests__/provider.test.js.map +1 -1
  7. package/dist/event-stream.d.ts +3 -1
  8. package/dist/event-stream.d.ts.map +1 -1
  9. package/dist/event-stream.js +18 -6
  10. package/dist/event-stream.js.map +1 -1
  11. package/dist/index.d.ts +7 -7
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +4 -4
  14. package/dist/models.d.ts.map +1 -1
  15. package/dist/models.js +493 -473
  16. package/dist/models.js.map +1 -1
  17. package/dist/providers/anthropic.d.ts +2 -2
  18. package/dist/providers/anthropic.d.ts.map +1 -1
  19. package/dist/providers/anthropic.js +155 -102
  20. package/dist/providers/anthropic.js.map +1 -1
  21. package/dist/providers/openai-completions.d.ts +5 -5
  22. package/dist/providers/openai-completions.d.ts.map +1 -1
  23. package/dist/providers/openai-completions.js +90 -85
  24. package/dist/providers/openai-completions.js.map +1 -1
  25. package/dist/providers/openai-responses.d.ts +4 -4
  26. package/dist/providers/openai-responses.d.ts.map +1 -1
  27. package/dist/providers/openai-responses.js +104 -99
  28. package/dist/providers/openai-responses.js.map +1 -1
  29. package/dist/providers/openrouter.d.ts +3 -3
  30. package/dist/providers/openrouter.d.ts.map +1 -1
  31. package/dist/providers/openrouter.js +8 -6
  32. package/dist/providers/openrouter.js.map +1 -1
  33. package/dist/providers/register-builtins.d.ts.map +1 -1
  34. package/dist/providers/register-builtins.js +23 -24
  35. package/dist/providers/register-builtins.js.map +1 -1
  36. package/dist/providers/shared.js +1 -1
  37. package/dist/providers/shared.js.map +1 -1
  38. package/dist/registry.d.ts +3 -3
  39. package/dist/registry.d.ts.map +1 -1
  40. package/dist/registry.js +1 -1
  41. package/dist/registry.js.map +1 -1
  42. package/dist/types.d.ts +20 -20
  43. package/dist/types.d.ts.map +1 -1
  44. package/package.json +31 -31
  45. package/dist/providers/groq.d.ts +0 -16
  46. package/dist/providers/groq.d.ts.map +0 -1
  47. package/dist/providers/groq.js +0 -196
  48. package/dist/providers/groq.js.map +0 -1
@@ -1,6 +1,6 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
2
- import { EventStream, AssistantMessageEventStream } from "../event-stream.js";
3
- import { registerProvider, getProvider, stream, complete } from "../registry.js";
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { EventStream, AssistantMessageEventStream } from '../event-stream.js';
3
+ import { registerProvider, getProvider, stream, complete } from '../registry.js';
4
4
  // Mock provider for testing (following pi-mono's provider pattern)
5
5
  function createMockProvider(name, responseEvents) {
6
6
  return {
@@ -19,70 +19,70 @@ function createMockProvider(name, responseEvents) {
19
19
  };
20
20
  }
21
21
  // Helper to create a complete assistant message
22
- function createAssistantMessage(text, stopReason = "stop") {
22
+ function createAssistantMessage(text, stopReason = 'stop') {
23
23
  return {
24
- role: "assistant",
25
- content: [{ type: "text", text }],
26
- provider: "test",
27
- model: "test-model",
24
+ role: 'assistant',
25
+ content: [{ type: 'text', text }],
26
+ provider: 'test',
27
+ model: 'test-model',
28
28
  usage: { input: 10, output: 20, cacheRead: 0, cacheWrite: 0, totalTokens: 30 },
29
29
  stopReason,
30
30
  timestamp: Date.now(),
31
31
  };
32
32
  }
33
- describe("EventStream (pi-mono pattern)", () => {
34
- it("should implement AsyncIterable interface", async () => {
35
- const stream = new EventStream((e) => e === "end", (e) => e);
33
+ describe('EventStream (pi-mono pattern)', () => {
34
+ it('should implement AsyncIterable interface', async () => {
35
+ const stream = new EventStream((e) => e === 'end', (e) => e);
36
36
  // Verify it's async iterable (pi-mono core pattern)
37
- expect(typeof stream[Symbol.asyncIterator]).toBe("function");
37
+ expect(typeof stream[Symbol.asyncIterator]).toBe('function');
38
38
  });
39
- it("should stream events in order (pi-mono push pattern)", async () => {
40
- const stream = new EventStream((e) => e === "end", (e) => e);
41
- stream.push("first");
42
- stream.push("second");
43
- stream.push("third");
44
- stream.push("end");
39
+ it('should stream events in order (pi-mono push pattern)', async () => {
40
+ const stream = new EventStream((e) => e === 'end', (e) => e);
41
+ stream.push('first');
42
+ stream.push('second');
43
+ stream.push('third');
44
+ stream.push('end');
45
45
  const events = [];
46
46
  for await (const event of stream) {
47
47
  events.push(event);
48
48
  }
49
- expect(events).toEqual(["first", "second", "third", "end"]);
49
+ expect(events).toEqual(['first', 'second', 'third', 'end']);
50
50
  });
51
- it("should resolve result after completion", async () => {
52
- const stream = new EventStream((e) => e === "done", (e) => e === "done" ? 42 : 0);
53
- stream.push("working");
54
- stream.push("done");
51
+ it('should resolve result after completion', async () => {
52
+ const stream = new EventStream((e) => e === 'done', (e) => (e === 'done' ? 42 : 0));
53
+ stream.push('working');
54
+ stream.push('done');
55
55
  stream.end();
56
56
  const result = await stream.result();
57
57
  expect(result).toBe(42);
58
58
  });
59
- it("should handle single consumer pattern (pi-mono design)", async () => {
60
- const stream = new EventStream((e) => e === "end", (e) => e);
61
- stream.push("event1");
62
- stream.push("event2");
63
- stream.push("end");
59
+ it('should handle single consumer pattern (pi-mono design)', async () => {
60
+ const stream = new EventStream((e) => e === 'end', (e) => e);
61
+ stream.push('event1');
62
+ stream.push('event2');
63
+ stream.push('end');
64
64
  const events = [];
65
65
  for await (const e of stream) {
66
66
  events.push(e);
67
67
  }
68
- expect(events).toEqual(["event1", "event2", "end"]);
68
+ expect(events).toEqual(['event1', 'event2', 'end']);
69
69
  // Note: EventStream is single-consumer by design (pi-mono pattern)
70
70
  // Multiple consumers would require a broadcast mechanism
71
71
  });
72
72
  });
73
- describe("AssistantMessageEventStream (pi-mono pattern)", () => {
74
- it("should emit start, delta, and done events", async () => {
73
+ describe('AssistantMessageEventStream (pi-mono pattern)', () => {
74
+ it('should emit start, delta, and done events', async () => {
75
75
  const stream = new AssistantMessageEventStream();
76
- const partial = createAssistantMessage("");
77
- stream.push({ type: "start", partial });
78
- stream.push({ type: "text_start", contentIndex: 0, partial });
79
- stream.push({ type: "text_delta", contentIndex: 0, delta: "Hello", partial });
80
- stream.push({ type: "text_delta", contentIndex: 0, delta: " World", partial });
81
- stream.push({ type: "text_end", contentIndex: 0, content: "Hello World", partial });
76
+ const partial = createAssistantMessage('');
77
+ stream.push({ type: 'start', partial });
78
+ stream.push({ type: 'text_start', contentIndex: 0, partial });
79
+ stream.push({ type: 'text_delta', contentIndex: 0, delta: 'Hello', partial });
80
+ stream.push({ type: 'text_delta', contentIndex: 0, delta: ' World', partial });
81
+ stream.push({ type: 'text_end', contentIndex: 0, content: 'Hello World', partial });
82
82
  stream.push({
83
- type: "done",
84
- reason: "stop",
85
- message: createAssistantMessage("Hello World"),
83
+ type: 'done',
84
+ reason: 'stop',
85
+ message: createAssistantMessage('Hello World'),
86
86
  });
87
87
  stream.end();
88
88
  const events = [];
@@ -90,44 +90,44 @@ describe("AssistantMessageEventStream (pi-mono pattern)", () => {
90
90
  events.push(event);
91
91
  }
92
92
  expect(events).toHaveLength(6);
93
- expect(events[0].type).toBe("start");
94
- expect(events[1].type).toBe("text_start");
95
- expect(events[2].type).toBe("text_delta");
96
- expect(events[5].type).toBe("done");
93
+ expect(events[0].type).toBe('start');
94
+ expect(events[1].type).toBe('text_start');
95
+ expect(events[2].type).toBe('text_delta');
96
+ expect(events[5].type).toBe('done');
97
97
  });
98
- it("should resolve to final AssistantMessage", async () => {
98
+ it('should resolve to final AssistantMessage', async () => {
99
99
  const stream = new AssistantMessageEventStream();
100
- const finalMessage = createAssistantMessage("Final result");
101
- stream.push({ type: "start", partial: createAssistantMessage("") });
102
- stream.push({ type: "done", reason: "stop", message: finalMessage });
100
+ const finalMessage = createAssistantMessage('Final result');
101
+ stream.push({ type: 'start', partial: createAssistantMessage('') });
102
+ stream.push({ type: 'done', reason: 'stop', message: finalMessage });
103
103
  stream.end();
104
104
  const result = await stream.result();
105
- expect(result.content[0]).toEqual({ type: "text", text: "Final result" });
106
- expect(result.stopReason).toBe("stop");
105
+ expect(result.content[0]).toEqual({ type: 'text', text: 'Final result' });
106
+ expect(result.stopReason).toBe('stop');
107
107
  });
108
- it("should handle error events", async () => {
108
+ it('should handle error events', async () => {
109
109
  const stream = new AssistantMessageEventStream();
110
- const errorMessage = createAssistantMessage("");
111
- errorMessage.stopReason = "error";
112
- errorMessage.errorMessage = "Something went wrong";
113
- stream.push({ type: "error", reason: "error", error: errorMessage });
110
+ const errorMessage = createAssistantMessage('');
111
+ errorMessage.stopReason = 'error';
112
+ errorMessage.errorMessage = 'Something went wrong';
113
+ stream.push({ type: 'error', reason: 'error', error: errorMessage });
114
114
  stream.end();
115
115
  const result = await stream.result();
116
- expect(result.stopReason).toBe("error");
117
- expect(result.errorMessage).toBe("Something went wrong");
116
+ expect(result.stopReason).toBe('error');
117
+ expect(result.errorMessage).toBe('Something went wrong');
118
118
  });
119
- it("should handle thinking event streaming", async () => {
119
+ it('should handle thinking event streaming', async () => {
120
120
  const stream = new AssistantMessageEventStream();
121
- const partial = createAssistantMessage("");
122
- stream.push({ type: "start", partial });
123
- stream.push({ type: "thinking_start", contentIndex: 0, partial });
124
- stream.push({ type: "thinking_delta", contentIndex: 0, delta: "Let me", partial });
125
- stream.push({ type: "thinking_delta", contentIndex: 0, delta: " think", partial });
126
- stream.push({ type: "thinking_end", contentIndex: 0, content: "Let me think", partial });
121
+ const partial = createAssistantMessage('');
122
+ stream.push({ type: 'start', partial });
123
+ stream.push({ type: 'thinking_start', contentIndex: 0, partial });
124
+ stream.push({ type: 'thinking_delta', contentIndex: 0, delta: 'Let me', partial });
125
+ stream.push({ type: 'thinking_delta', contentIndex: 0, delta: ' think', partial });
126
+ stream.push({ type: 'thinking_end', contentIndex: 0, content: 'Let me think', partial });
127
127
  stream.push({
128
- type: "done",
129
- reason: "stop",
130
- message: createAssistantMessage("Answer"),
128
+ type: 'done',
129
+ reason: 'stop',
130
+ message: createAssistantMessage('Answer'),
131
131
  });
132
132
  stream.end();
133
133
  const events = [];
@@ -135,55 +135,55 @@ describe("AssistantMessageEventStream (pi-mono pattern)", () => {
135
135
  events.push(event);
136
136
  }
137
137
  expect(events).toHaveLength(6);
138
- const thinkingStart = events.find((e) => e.type === "thinking_start");
138
+ const thinkingStart = events.find((e) => e.type === 'thinking_start');
139
139
  expect(thinkingStart).toBeDefined();
140
- const thinkingEnd = events.find((e) => e.type === "thinking_end");
140
+ const thinkingEnd = events.find((e) => e.type === 'thinking_end');
141
141
  expect(thinkingEnd).toBeDefined();
142
- if (thinkingEnd?.type === "thinking_end") {
143
- expect(thinkingEnd.content).toBe("Let me think");
142
+ if (thinkingEnd?.type === 'thinking_end') {
143
+ expect(thinkingEnd.content).toBe('Let me think');
144
144
  }
145
145
  });
146
- it("should handle tool call streaming (pi-mono tool pattern)", async () => {
146
+ it('should handle tool call streaming (pi-mono tool pattern)', async () => {
147
147
  const stream = new AssistantMessageEventStream();
148
- const partial = createAssistantMessage("");
149
- stream.push({ type: "start", partial });
150
- stream.push({ type: "toolcall_start", contentIndex: 0, partial });
151
- stream.push({ type: "toolcall_delta", contentIndex: 0, delta: '{"lo', partial });
152
- stream.push({ type: "toolcall_delta", contentIndex: 0, delta: 'cation":', partial });
153
- stream.push({ type: "toolcall_delta", contentIndex: 0, delta: '"NYC"}', partial });
148
+ const partial = createAssistantMessage('');
149
+ stream.push({ type: 'start', partial });
150
+ stream.push({ type: 'toolcall_start', contentIndex: 0, partial });
151
+ stream.push({ type: 'toolcall_delta', contentIndex: 0, delta: '{"lo', partial });
152
+ stream.push({ type: 'toolcall_delta', contentIndex: 0, delta: 'cation":', partial });
153
+ stream.push({ type: 'toolcall_delta', contentIndex: 0, delta: '"NYC"}', partial });
154
154
  stream.push({
155
- type: "toolcall_end",
155
+ type: 'toolcall_end',
156
156
  contentIndex: 0,
157
157
  toolCall: {
158
- type: "toolCall",
159
- id: "call_1",
160
- name: "get_weather",
161
- arguments: { location: "NYC" },
158
+ type: 'toolCall',
159
+ id: 'call_1',
160
+ name: 'get_weather',
161
+ arguments: { location: 'NYC' },
162
162
  },
163
163
  partial,
164
164
  });
165
165
  stream.push({
166
- type: "done",
167
- reason: "toolUse",
168
- message: createAssistantMessage("", "toolUse"),
166
+ type: 'done',
167
+ reason: 'toolUse',
168
+ message: createAssistantMessage('', 'toolUse'),
169
169
  });
170
170
  stream.end();
171
171
  const events = [];
172
172
  for await (const event of stream) {
173
173
  events.push(event);
174
174
  }
175
- const toolCallEnd = events.find((e) => e.type === "toolcall_end");
175
+ const toolCallEnd = events.find((e) => e.type === 'toolcall_end');
176
176
  expect(toolCallEnd).toBeDefined();
177
- if (toolCallEnd?.type === "toolcall_end") {
178
- expect(toolCallEnd.toolCall.name).toBe("get_weather");
179
- expect(toolCallEnd.toolCall.arguments).toEqual({ location: "NYC" });
177
+ if (toolCallEnd?.type === 'toolcall_end') {
178
+ expect(toolCallEnd.toolCall.name).toBe('get_weather');
179
+ expect(toolCallEnd.toolCall.arguments).toEqual({ location: 'NYC' });
180
180
  }
181
181
  });
182
182
  });
183
- describe("Provider Registry (pi-mono provider pattern)", () => {
183
+ describe('Provider Registry (pi-mono provider pattern)', () => {
184
184
  beforeEach(() => {
185
185
  // Clear registry
186
- const providers = ["test-provider", "anthropic", "openai"];
186
+ const providers = ['test-provider', 'anthropic', 'openai'];
187
187
  for (const name of providers) {
188
188
  try {
189
189
  // Re-register to ensure clean state
@@ -193,28 +193,28 @@ describe("Provider Registry (pi-mono provider pattern)", () => {
193
193
  }
194
194
  }
195
195
  });
196
- it("should register and retrieve providers", () => {
197
- const provider = createMockProvider("test-provider", []);
196
+ it('should register and retrieve providers', () => {
197
+ const provider = createMockProvider('test-provider', []);
198
198
  registerProvider(provider);
199
- const retrieved = getProvider("test-provider");
199
+ const retrieved = getProvider('test-provider');
200
200
  expect(retrieved).toBeDefined();
201
- expect(retrieved?.name).toBe("test-provider");
201
+ expect(retrieved?.name).toBe('test-provider');
202
202
  });
203
- it("should stream through registered provider", async () => {
204
- const mockMessage = createAssistantMessage("Hello from mock");
205
- const provider = createMockProvider("mock-ai", [
206
- { type: "start", partial: createAssistantMessage("") },
207
- { type: "done", reason: "stop", message: mockMessage },
203
+ it('should stream through registered provider', async () => {
204
+ const mockMessage = createAssistantMessage('Hello from mock');
205
+ const provider = createMockProvider('mock-ai', [
206
+ { type: 'start', partial: createAssistantMessage('') },
207
+ { type: 'done', reason: 'stop', message: mockMessage },
208
208
  ]);
209
209
  registerProvider(provider);
210
210
  const model = {
211
- id: "mock-model",
212
- name: "Mock Model",
213
- provider: "mock-ai",
214
- api: "mock",
211
+ id: 'mock-model',
212
+ name: 'Mock Model',
213
+ provider: 'mock-ai',
214
+ api: 'mock',
215
215
  };
216
216
  const context = {
217
- messages: [{ role: "user", content: "Hi", timestamp: Date.now() }],
217
+ messages: [{ role: 'user', content: 'Hi', timestamp: Date.now() }],
218
218
  };
219
219
  const eventStream = stream(model, context);
220
220
  const events = [];
@@ -222,57 +222,57 @@ describe("Provider Registry (pi-mono provider pattern)", () => {
222
222
  events.push(event);
223
223
  }
224
224
  expect(events.length).toBeGreaterThan(0);
225
- const doneEvent = events.find((e) => e.type === "done");
225
+ const doneEvent = events.find((e) => e.type === 'done');
226
226
  expect(doneEvent).toBeDefined();
227
227
  });
228
- it("should complete through registered provider", async () => {
229
- const mockMessage = createAssistantMessage("Completed");
230
- const provider = createMockProvider("complete-ai", [
231
- { type: "start", partial: createAssistantMessage("") },
232
- { type: "done", reason: "stop", message: mockMessage },
228
+ it('should complete through registered provider', async () => {
229
+ const mockMessage = createAssistantMessage('Completed');
230
+ const provider = createMockProvider('complete-ai', [
231
+ { type: 'start', partial: createAssistantMessage('') },
232
+ { type: 'done', reason: 'stop', message: mockMessage },
233
233
  ]);
234
234
  registerProvider(provider);
235
235
  const model = {
236
- id: "complete-model",
237
- name: "Complete Model",
238
- provider: "complete-ai",
239
- api: "complete",
236
+ id: 'complete-model',
237
+ name: 'Complete Model',
238
+ provider: 'complete-ai',
239
+ api: 'complete',
240
240
  };
241
241
  const context = {
242
- messages: [{ role: "user", content: "Test", timestamp: Date.now() }],
242
+ messages: [{ role: 'user', content: 'Test', timestamp: Date.now() }],
243
243
  };
244
244
  const result = await complete(model, context);
245
- expect(result.content[0]).toEqual({ type: "text", text: "Completed" });
245
+ expect(result.content[0]).toEqual({ type: 'text', text: 'Completed' });
246
246
  });
247
- it("should throw for unregistered provider", () => {
247
+ it('should throw for unregistered provider', () => {
248
248
  const model = {
249
- id: "unknown",
250
- name: "Unknown",
251
- provider: "nonexistent",
252
- api: "unknown",
249
+ id: 'unknown',
250
+ name: 'Unknown',
251
+ provider: 'nonexistent',
252
+ api: 'unknown',
253
253
  };
254
254
  const context = { messages: [] };
255
- expect(() => stream(model, context)).toThrow("No provider registered");
255
+ expect(() => stream(model, context)).toThrow('No provider registered');
256
256
  });
257
257
  });
258
- describe("Provider Error Handling", () => {
259
- it("should emit error event on provider failure", async () => {
258
+ describe('Provider Error Handling', () => {
259
+ it('should emit error event on provider failure', async () => {
260
260
  const errorProvider = {
261
- name: "error-provider",
261
+ name: 'error-provider',
262
262
  stream() {
263
263
  const stream = new AssistantMessageEventStream();
264
264
  setTimeout(() => {
265
265
  const errorMsg = {
266
- role: "assistant",
266
+ role: 'assistant',
267
267
  content: [],
268
- provider: "error-provider",
269
- model: "error-model",
268
+ provider: 'error-provider',
269
+ model: 'error-model',
270
270
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 },
271
- stopReason: "error",
272
- errorMessage: "API Error",
271
+ stopReason: 'error',
272
+ errorMessage: 'API Error',
273
273
  timestamp: Date.now(),
274
274
  };
275
- stream.push({ type: "error", reason: "error", error: errorMsg });
275
+ stream.push({ type: 'error', reason: 'error', error: errorMsg });
276
276
  stream.end();
277
277
  }, 10);
278
278
  return stream;
@@ -280,22 +280,22 @@ describe("Provider Error Handling", () => {
280
280
  };
281
281
  registerProvider(errorProvider);
282
282
  const model = {
283
- id: "error-model",
284
- name: "Error Model",
285
- provider: "error-provider",
286
- api: "error",
283
+ id: 'error-model',
284
+ name: 'Error Model',
285
+ provider: 'error-provider',
286
+ api: 'error',
287
287
  };
288
288
  const context = { messages: [] };
289
289
  const result = await complete(model, context);
290
- expect(result.stopReason).toBe("error");
291
- expect(result.errorMessage).toBe("API Error");
290
+ expect(result.stopReason).toBe('error');
291
+ expect(result.errorMessage).toBe('API Error');
292
292
  });
293
293
  });
294
- describe("Streaming with AbortSignal", () => {
295
- it("should respect abort signal", async () => {
294
+ describe('Streaming with AbortSignal', () => {
295
+ it('should respect abort signal', async () => {
296
296
  const controller = new AbortController();
297
297
  const slowProvider = {
298
- name: "slow-provider",
298
+ name: 'slow-provider',
299
299
  stream(model, context, options) {
300
300
  const stream = new AssistantMessageEventStream();
301
301
  // Simulate slow stream
@@ -303,23 +303,23 @@ describe("Streaming with AbortSignal", () => {
303
303
  if (options?.signal?.aborted) {
304
304
  clearInterval(interval);
305
305
  const abortedMsg = {
306
- role: "assistant",
306
+ role: 'assistant',
307
307
  content: [],
308
- provider: "slow-provider",
309
- model: "slow-model",
308
+ provider: 'slow-provider',
309
+ model: 'slow-model',
310
310
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 },
311
- stopReason: "aborted",
311
+ stopReason: 'aborted',
312
312
  timestamp: Date.now(),
313
313
  };
314
- stream.push({ type: "error", reason: "aborted", error: abortedMsg });
314
+ stream.push({ type: 'error', reason: 'aborted', error: abortedMsg });
315
315
  stream.end();
316
316
  return;
317
317
  }
318
318
  stream.push({
319
- type: "text_delta",
319
+ type: 'text_delta',
320
320
  contentIndex: 0,
321
- delta: "chunk ",
322
- partial: createAssistantMessage(""),
321
+ delta: 'chunk ',
322
+ partial: createAssistantMessage(''),
323
323
  });
324
324
  }, 50);
325
325
  // Auto-abort after 100ms
@@ -329,63 +329,63 @@ describe("Streaming with AbortSignal", () => {
329
329
  };
330
330
  registerProvider(slowProvider);
331
331
  const model = {
332
- id: "slow-model",
333
- name: "Slow Model",
334
- provider: "slow-provider",
335
- api: "slow",
332
+ id: 'slow-model',
333
+ name: 'Slow Model',
334
+ provider: 'slow-provider',
335
+ api: 'slow',
336
336
  };
337
337
  const context = { messages: [] };
338
338
  const eventStream = stream(model, context, { signal: controller.signal });
339
339
  const events = [];
340
340
  for await (const event of eventStream) {
341
341
  events.push(event);
342
- if (event.type === "error" || event.type === "done")
342
+ if (event.type === 'error' || event.type === 'done')
343
343
  break;
344
344
  }
345
345
  // Should have received at least one event before abort
346
346
  expect(events.length).toBeGreaterThan(0);
347
347
  });
348
348
  });
349
- describe("Message Content Types", () => {
350
- it("should handle text content", async () => {
351
- const message = createAssistantMessage("Plain text");
352
- expect(message.content[0]).toEqual({ type: "text", text: "Plain text" });
349
+ describe('Message Content Types', () => {
350
+ it('should handle text content', async () => {
351
+ const message = createAssistantMessage('Plain text');
352
+ expect(message.content[0]).toEqual({ type: 'text', text: 'Plain text' });
353
353
  });
354
- it("should handle thinking content", async () => {
354
+ it('should handle thinking content', async () => {
355
355
  const message = {
356
- role: "assistant",
356
+ role: 'assistant',
357
357
  content: [
358
- { type: "thinking", thinking: "Let me think...", thinkingSignature: "sig1" },
359
- { type: "text", text: "Answer" },
358
+ { type: 'thinking', thinking: 'Let me think...', thinkingSignature: 'sig1' },
359
+ { type: 'text', text: 'Answer' },
360
360
  ],
361
- provider: "test",
362
- model: "test",
361
+ provider: 'test',
362
+ model: 'test',
363
363
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 },
364
- stopReason: "stop",
364
+ stopReason: 'stop',
365
365
  timestamp: Date.now(),
366
366
  };
367
367
  expect(message.content).toHaveLength(2);
368
- expect(message.content[0].type).toBe("thinking");
368
+ expect(message.content[0].type).toBe('thinking');
369
369
  });
370
- it("should handle tool call content", async () => {
370
+ it('should handle tool call content', async () => {
371
371
  const message = {
372
- role: "assistant",
372
+ role: 'assistant',
373
373
  content: [
374
374
  {
375
- type: "toolCall",
376
- id: "call_1",
377
- name: "get_weather",
378
- arguments: { location: "NYC" },
375
+ type: 'toolCall',
376
+ id: 'call_1',
377
+ name: 'get_weather',
378
+ arguments: { location: 'NYC' },
379
379
  },
380
380
  ],
381
- provider: "test",
382
- model: "test",
381
+ provider: 'test',
382
+ model: 'test',
383
383
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0 },
384
- stopReason: "toolUse",
384
+ stopReason: 'toolUse',
385
385
  timestamp: Date.now(),
386
386
  };
387
- expect(message.content[0].type).toBe("toolCall");
388
- expect(message.content[0].name).toBe("get_weather");
387
+ expect(message.content[0].type).toBe('toolCall');
388
+ expect(message.content[0].name).toBe('get_weather');
389
389
  });
390
390
  });
391
391
  //# sourceMappingURL=e2e.test.js.map