Skip to content

Commit 68cf25e

Browse files
authored
fix(world-vercel): include runId in streams.get() request URL (vercel#1676)
* fix(world-vercel): include runId in streams.get() request URL streams.get() was ignoring the runId parameter and hardcoding undefined, causing requests to hit /api/v2/stream/:streamId instead of the correct /api/v2/runs/:runId/stream/:streamId. Also removes the fallback path in getStreamUrl() that allowed omitting runId. * test(world-vercel): add regression test for streams.get() runId in URL
1 parent ea97bd6 commit 68cf25e

3 files changed

Lines changed: 52 additions & 13 deletions

File tree

.changeset/fix-stream-get-runid.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@workflow/world-vercel': patch
3+
---
4+
5+
Fix `streams.get()` to include `runId` in the request URL instead of always omitting it.

packages/world-vercel/src/streamer.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,47 @@ vi.mock('./utils.js', () => ({
180180
}),
181181
}));
182182

183+
describe('streams.get', () => {
184+
async function getStreamer() {
185+
const { createStreamer } = await import('./streamer.js');
186+
return createStreamer();
187+
}
188+
189+
afterEach(() => {
190+
vi.restoreAllMocks();
191+
});
192+
193+
it('includes runId in the fetch URL', async () => {
194+
const fetchSpy = vi
195+
.spyOn(globalThis, 'fetch')
196+
.mockImplementation(
197+
async () => new Response(new ReadableStream(), { status: 200 })
198+
);
199+
200+
const streamer = await getStreamer();
201+
await streamer.streams.get('run-123', 'my-stream');
202+
203+
expect(fetchSpy).toHaveBeenCalledTimes(1);
204+
const url = new URL(fetchSpy.mock.calls[0][0] as string);
205+
expect(url.pathname).toBe('/v2/runs/run-123/stream/my-stream');
206+
});
207+
208+
it('passes startIndex as a query parameter', async () => {
209+
const fetchSpy = vi
210+
.spyOn(globalThis, 'fetch')
211+
.mockImplementation(
212+
async () => new Response(new ReadableStream(), { status: 200 })
213+
);
214+
215+
const streamer = await getStreamer();
216+
await streamer.streams.get('run-123', 'my-stream', 5);
217+
218+
const url = new URL(fetchSpy.mock.calls[0][0] as string);
219+
expect(url.pathname).toBe('/v2/runs/run-123/stream/my-stream');
220+
expect(url.searchParams.get('startIndex')).toBe('5');
221+
});
222+
});
223+
183224
describe('writeMulti pagination', () => {
184225
/**
185226
* Decode length-prefixed multi-chunk body to count chunks per request.

packages/world-vercel/src/streamer.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,10 @@ export const MAX_CHUNKS_PER_REQUEST = 1000;
2323
// (partial writes, long-lived reads), and duplex streams are incompatible
2424
// with undici's experimental H2 support.
2525

26-
function getStreamUrl(
27-
name: string,
28-
runId: string | undefined,
29-
httpConfig: HttpConfig
30-
) {
31-
if (runId) {
32-
return new URL(
33-
`${httpConfig.baseUrl}/v2/runs/${encodeURIComponent(runId)}/stream/${encodeURIComponent(name)}`
34-
);
35-
}
36-
return new URL(`${httpConfig.baseUrl}/v2/stream/${encodeURIComponent(name)}`);
26+
function getStreamUrl(name: string, runId: string, httpConfig: HttpConfig) {
27+
return new URL(
28+
`${httpConfig.baseUrl}/v2/runs/${encodeURIComponent(runId)}/stream/${encodeURIComponent(name)}`
29+
);
3730
}
3831

3932
/**
@@ -188,9 +181,9 @@ export function createStreamer(config?: APIConfig): Streamer {
188181
}
189182
},
190183

191-
async get(_runId: string, name: string, startIndex?: number) {
184+
async get(runId: string, name: string, startIndex?: number) {
192185
const httpConfig = await getHttpConfig(config);
193-
const url = getStreamUrl(name, undefined, httpConfig);
186+
const url = getStreamUrl(name, runId, httpConfig);
194187
if (typeof startIndex === 'number') {
195188
url.searchParams.set('startIndex', String(startIndex));
196189
}

0 commit comments

Comments
 (0)