Skip to content

Commit e2efab7

Browse files
committed
cleanup
1 parent 1320841 commit e2efab7

File tree

3 files changed

+56
-136
lines changed

3 files changed

+56
-136
lines changed

examples/stream-zod.ts

Lines changed: 18 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#!/usr/bin/env -S npm run tsn -T
22

33
import { BrowserUse } from 'browser-use-sdk';
4-
import { TaskViewWithSchema } from 'browser-use-sdk/lib/parse';
54
import z from 'zod';
65

76
const HackerNewsResponse = z.object({
@@ -26,65 +25,31 @@ async function main() {
2625
structuredOutputJson: TaskOutput,
2726
});
2827

29-
// Get a reader from the stream
30-
const reader = stream.getReader();
31-
const decoder = new TextDecoder();
32-
33-
try {
34-
// Read the stream chunk by chunk
35-
loop: while (true) {
36-
const { done, value } = await reader.read();
37-
38-
if (done) {
39-
console.log('\nStream completed');
40-
break loop;
41-
}
42-
43-
// Decode the chunk and parse the Server-Sent Events format
44-
const chunk = decoder.decode(value, { stream: true });
45-
const lines = chunk.split('\n');
46-
47-
for (const line of lines) {
48-
if (line.startsWith('event: ')) {
49-
const event = line.slice(7);
50-
process.stdout.write(`\n[${event}] `);
51-
} else if (line.startsWith('data: ')) {
52-
const data = line.slice(6);
53-
if (data.trim() && data !== '{}') {
54-
try {
55-
const parsed = JSON.parse(data) as TaskViewWithSchema<typeof TaskOutput>;
56-
57-
process.stdout.write(`${parsed.status}`);
58-
if (parsed.sessionLiveUrl) {
59-
process.stdout.write(` | Live URL: ${parsed.sessionLiveUrl}`);
60-
}
28+
for await (const msg of stream) {
29+
// Regular
30+
process.stdout.write(`${msg.data.status}`);
31+
if (msg.data.sessionLiveUrl) {
32+
process.stdout.write(` | Live URL: ${msg.data.sessionLiveUrl}`);
33+
}
6134

62-
if (parsed.steps.length > 0) {
63-
const latestStep = parsed.steps[parsed.steps.length - 1];
64-
process.stdout.write(` | ${latestStep!.nextGoal}`);
65-
}
35+
if (msg.data.steps.length > 0) {
36+
const latestStep = msg.data.steps[msg.data.steps.length - 1];
37+
process.stdout.write(` | ${latestStep!.nextGoal}`);
38+
}
6639

67-
if (parsed.status === 'finished') {
68-
process.stdout.write(`\n\nOUTPUT:`);
40+
process.stdout.write('\n');
6941

70-
for (const post of parsed.doneOutput!.posts) {
71-
process.stdout.write(`\n - ${post.title} (${post.score}) ${post.url}`);
72-
}
42+
// Output
43+
if (msg.data.status === 'finished') {
44+
process.stdout.write(`\n\nOUTPUT:`);
7345

74-
break loop;
75-
}
76-
} catch (e) {
77-
process.stdout.write(`Raw data: ${data}`);
78-
}
79-
}
80-
}
46+
for (const post of msg.data.doneOutput!.posts) {
47+
process.stdout.write(`\n - ${post.title} (${post.score}) ${post.url}`);
8148
}
8249
}
83-
} catch (error) {
84-
console.error('Error reading stream:', error);
85-
} finally {
86-
reader.releaseLock();
8750
}
51+
52+
console.log('\nStream completed');
8853
}
8954

9055
main().catch(console.error);

examples/stream.ts

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,18 @@ async function main() {
66
// gets API Key from environment variable BROWSER_USE_API_KEY
77
const browseruse = new BrowserUse();
88

9-
console.log('Creating task and starting stream...\n');
9+
console.log('Creating task and starting stream...');
1010

1111
// Create a task and get the stream
12-
const stream = browseruse.tasks.stream({
12+
const gen = browseruse.tasks.stream({
1313
task: 'What is the weather in San Francisco?',
1414
});
1515

16-
// Get a reader from the stream
17-
const reader = stream.getReader();
18-
const decoder = new TextDecoder();
19-
20-
try {
21-
// Read the stream chunk by chunk
22-
while (true) {
23-
const { done, value } = await reader.read();
24-
25-
if (done) {
26-
console.log('\nStream completed');
27-
break;
28-
}
29-
30-
// Decode the chunk and parse the Server-Sent Events format
31-
const chunk = decoder.decode(value, { stream: true });
32-
const lines = chunk.split('\n');
33-
34-
for (const line of lines) {
35-
console.log(line);
36-
}
37-
}
38-
} catch (error) {
39-
console.error('Error reading stream:', error);
40-
} finally {
41-
reader.releaseLock();
16+
for await (const msg of gen) {
17+
console.log(msg);
4218
}
19+
20+
console.log('\nStream completed');
4321
}
4422

4523
main().catch(console.error);

src/resources/tasks.ts

Lines changed: 32 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -134,65 +134,42 @@ export class Tasks extends APIResource {
134134
stream<T extends ZodType>(
135135
body: TaskCreateParamsWithSchema<T>,
136136
options?: RequestOptions,
137-
): ReadableStream<Uint8Array<ArrayBufferLike>>;
138-
stream(body: TaskCreateParams, options?: RequestOptions): ReadableStream<Uint8Array<ArrayBufferLike>>;
137+
): AsyncGenerator<{ event: 'status'; data: TaskViewWithSchema<T> }>;
139138
stream(
139+
body: TaskCreateParams,
140+
options?: RequestOptions,
141+
): AsyncGenerator<{ event: 'status'; data: TaskView }>;
142+
async *stream(
140143
body: TaskCreateParams | TaskCreateParamsWithSchema<ZodType>,
141144
options?: RequestOptions,
142-
): ReadableStream<Uint8Array<ArrayBufferLike>> {
143-
const self = this;
144-
145-
const enc = new TextEncoder();
146-
147-
const stream = new ReadableStream<Uint8Array>({
148-
async start(controller) {
149-
// open the SSE stream quickly
150-
controller.enqueue(enc.encode(': connected\n\n'));
151-
152-
try {
153-
let req: TaskCreateParams;
154-
155-
if (
156-
'structuredOutputJson' in body &&
157-
body.structuredOutputJson != null &&
158-
typeof body.structuredOutputJson === 'object'
159-
) {
160-
req = {
161-
...body,
162-
structuredOutputJson: stringifyStructuredOutput(body.structuredOutputJson),
163-
};
164-
} else {
165-
req = body as TaskCreateParams;
166-
}
167-
168-
for await (const msg of self.watch(req, { interval: 500 }, options)) {
169-
if (options?.signal?.aborted) {
170-
break;
171-
}
172-
173-
let data: string;
174-
175-
if (body.structuredOutputJson != null && typeof body.structuredOutputJson === 'object') {
176-
const parsed = parseStructuredTaskOutput<ZodType>(msg.data, body.structuredOutputJson);
177-
data = JSON.stringify(parsed);
178-
} else {
179-
data = JSON.stringify(msg.data);
180-
}
181-
182-
const payload = `event: ${msg.event}\ndata: ${data}\n\n`;
183-
controller.enqueue(enc.encode(payload));
184-
}
185-
186-
controller.enqueue(enc.encode('event: end\ndata: {}\n\n'));
187-
} catch (e) {
188-
controller.enqueue(enc.encode(`event: error\ndata: ${JSON.stringify({ message: String(e) })}\n\n`));
189-
} finally {
190-
controller.close();
191-
}
192-
},
193-
});
145+
): AsyncGenerator<unknown> {
146+
let req: TaskCreateParams;
147+
148+
if (
149+
'structuredOutputJson' in body &&
150+
body.structuredOutputJson != null &&
151+
typeof body.structuredOutputJson === 'object'
152+
) {
153+
req = {
154+
...body,
155+
structuredOutputJson: stringifyStructuredOutput(body.structuredOutputJson),
156+
};
157+
} else {
158+
req = body as TaskCreateParams;
159+
}
194160

195-
return stream;
161+
for await (const msg of this.watch(req, { interval: 500 }, options)) {
162+
if (options?.signal?.aborted) {
163+
break;
164+
}
165+
166+
if (body.structuredOutputJson != null && typeof body.structuredOutputJson === 'object') {
167+
const parsed = parseStructuredTaskOutput<ZodType>(msg.data, body.structuredOutputJson);
168+
yield { event: 'status', data: parsed };
169+
} else {
170+
yield { event: 'status', data: msg.data };
171+
}
172+
}
196173
}
197174

198175
/**

0 commit comments

Comments
 (0)