Skip to content

Commit 9952a79

Browse files
test: add e2e regression test for issue #190 (streamObject flush error) (#373)
* test: add regression test for issue #190 (sparse tool call indices) Co-Authored-By: Robert Yeakel <robert.yeakel@openrouter.ai> * test: replace unit test with e2e regression test for issue #190 - Remove sparse array unit test from src/chat/index.test.ts - Add e2e test using streamObject + jsonSchema (matches issue exactly) - Test verifies streamObject works without TypeError in flush function Co-Authored-By: Robert Yeakel <robert.yeakel@openrouter.ai> * test: remove speculative root cause from issue #190 test comments Keep only known facts from the issue report Co-Authored-By: Robert Yeakel <robert.yeakel@openrouter.ai> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent ff33984 commit 9952a79

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

.changeset/cyan-yaks-push.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Regression test for GitHub issue #190
3+
* https://github.com/OpenRouterTeam/ai-sdk-provider/issues/190
4+
*
5+
* Issue: streamObject with ai@4 + @openrouter/ai-sdk-provider@0.7.x threw
6+
* TypeError in flush: "Cannot read properties of undefined (reading 'sent')"
7+
*
8+
* Reported: September 24, 2025
9+
* Affected versions: ai@4.3.18 + @openrouter/ai-sdk-provider@0.7.5
10+
* Working versions: ai@5.x + @openrouter/ai-sdk-provider@1.0.0
11+
*
12+
* This test verifies that streamObject with JSON Schema completes without error.
13+
*/
14+
import type { JSONSchema7 } from 'json-schema';
15+
16+
import { jsonSchema, streamObject } from 'ai';
17+
import { describe, expect, it, vi } from 'vitest';
18+
import { createOpenRouter } from '@/src';
19+
20+
vi.setConfig({
21+
testTimeout: 60_000,
22+
});
23+
24+
describe('Issue #190: streamObject flush TypeError', () => {
25+
const openrouter = createOpenRouter({
26+
apiKey: process.env.OPENROUTER_API_KEY,
27+
baseUrl: `${process.env.OPENROUTER_API_BASE}/api/v1`,
28+
});
29+
30+
// Use a model that supports structured output
31+
const model = openrouter('openai/gpt-4o-mini');
32+
33+
it('should stream structured output without TypeError', async () => {
34+
// This is the exact schema from the issue report
35+
const schema: JSONSchema7 = {
36+
type: 'object',
37+
properties: {
38+
title: { type: 'string', minLength: 3, maxLength: 60 },
39+
priority: { type: 'string', enum: ['low', 'medium', 'high'] },
40+
},
41+
required: ['title', 'priority'],
42+
additionalProperties: false,
43+
};
44+
45+
const result = streamObject({
46+
model,
47+
temperature: 0,
48+
system: 'You are a helpful assistant that outputs strictly valid JSON.',
49+
messages: [
50+
{
51+
role: 'user',
52+
content:
53+
'Generate a concise title (<= 6 words) for a test task and pick priority medium.',
54+
},
55+
],
56+
schema: jsonSchema(schema),
57+
});
58+
59+
const object = (await result.object) as { title: string; priority: string };
60+
61+
// Verify the output matches the schema
62+
expect(object).toBeDefined();
63+
expect(typeof object.title).toBe('string');
64+
expect(object.title.length).toBeGreaterThan(0);
65+
expect(['low', 'medium', 'high']).toContain(object.priority);
66+
});
67+
68+
it('should handle streamObject with nested schema', async () => {
69+
// Test with a more complex nested schema
70+
const schema: JSONSchema7 = {
71+
type: 'object',
72+
properties: {
73+
task: {
74+
type: 'object',
75+
properties: {
76+
name: { type: 'string' },
77+
status: { type: 'string', enum: ['pending', 'done'] },
78+
},
79+
required: ['name', 'status'],
80+
},
81+
tags: {
82+
type: 'array',
83+
items: { type: 'string' },
84+
},
85+
},
86+
required: ['task', 'tags'],
87+
additionalProperties: false,
88+
};
89+
90+
const result = streamObject({
91+
model,
92+
temperature: 0,
93+
messages: [
94+
{
95+
role: 'user',
96+
content:
97+
'Create a task named "Review PR" with status pending and tags ["code", "review"].',
98+
},
99+
],
100+
schema: jsonSchema(schema),
101+
});
102+
103+
const object = (await result.object) as {
104+
task: { name: string; status: string };
105+
tags: string[];
106+
};
107+
108+
expect(object).toBeDefined();
109+
expect(object.task).toBeDefined();
110+
expect(typeof object.task.name).toBe('string');
111+
expect(['pending', 'done']).toContain(object.task.status);
112+
expect(Array.isArray(object.tags)).toBe(true);
113+
});
114+
});

0 commit comments

Comments
 (0)