Skip to content

Commit 4201564

Browse files
committed
fixes
1 parent 07e6e13 commit 4201564

File tree

4 files changed

+64
-58
lines changed

4 files changed

+64
-58
lines changed

examples/demo.ts

Lines changed: 1 addition & 2 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 { TaskView } from 'browser-use-sdk/resources';
54
import { spinner } from './utils';
65

76
// gets API Key from environment variable BROWSER_USE_API_KEY
@@ -18,7 +17,7 @@ async function main() {
1817

1918
poll: do {
2019
// Wait for Task to Finish
21-
const status = (await browseruse.tasks.retrieve(rsp.id, { statusOnly: false })) as TaskView;
20+
const status = await browseruse.tasks.retrieve(rsp.id);
2221

2322
switch (status.status) {
2423
case 'started':

examples/structured-output.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ async function main() {
2323
const stop = spinner(() => log);
2424

2525
// Create Task
26-
const rsp = await browseruse.tasks.createWithStructuredOutput({
26+
const rsp = await browseruse.tasks.create({
2727
task: 'Extract top 10 Hacker News posts and return the title, url, and score',
2828
structuredOutputJson: TaskOutput,
2929
});
3030

3131
poll: do {
3232
// Wait for Task to Finish
33-
const status = await browseruse.tasks.retrieveWithStructuredOutput(rsp.id, {
34-
structuredOutputJson: TaskOutput,
33+
const status = await browseruse.tasks.retrieve({
34+
taskId: rsp.id,
35+
schema: TaskOutput,
3536
});
3637

3738
switch (status.status) {
@@ -52,12 +53,16 @@ async function main() {
5253
}
5354

5455
case 'finished':
56+
if (status.doneOutput == null) {
57+
throw new Error('No output');
58+
}
59+
5560
stop();
5661

5762
// Print Structured Output
5863
console.log('TOP POSTS:');
5964

60-
for (const post of status.doneOutput!.posts) {
65+
for (const post of status.doneOutput.posts) {
6166
console.log(` - ${post.title} (${post.score}) ${post.url}`);
6267
}
6368

src/lib/parse.ts

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,34 @@
11
import z, { type ZodType } from 'zod';
2-
import type { TaskCreateParams, TaskRetrieveParams, TaskView } from '../resources/tasks';
2+
import type { TaskCreateParams, TaskView } from '../resources/tasks';
33

44
// RUN
55

6-
export type RunTaskCreateParamsWithStructuredOutput<T extends ZodType> = Omit<
7-
TaskCreateParams,
8-
'structuredOutputJson'
9-
> & {
6+
export type TaskCreateParamsWithSchema<T extends ZodType> = Omit<TaskCreateParams, 'structuredOutputJson'> & {
107
structuredOutputJson: T;
118
};
129

13-
export function stringifyStructuredOutput<T extends ZodType>(
14-
req: RunTaskCreateParamsWithStructuredOutput<T>,
15-
): TaskCreateParams {
16-
return {
17-
...req,
18-
structuredOutputJson: JSON.stringify(z.toJSONSchema(req.structuredOutputJson)),
19-
};
10+
export function stringifyStructuredOutput<T extends ZodType>(schema: T): string {
11+
return JSON.stringify(z.toJSONSchema(schema));
2012
}
2113

2214
// RETRIEVE
2315

24-
export type GetTaskStatusParamsWithStructuredOutput<T extends ZodType> = Omit<
25-
TaskRetrieveParams,
26-
'statusOnly'
27-
> & {
28-
statusOnly?: false;
29-
structuredOutputJson: T;
30-
};
31-
32-
export type TaskViewWithStructuredOutput<T extends ZodType> = Omit<TaskView, 'doneOutput'> & {
16+
export type TaskViewWithSchema<T extends ZodType> = Omit<TaskView, 'doneOutput'> & {
3317
doneOutput: z.output<T> | null;
3418
};
3519

3620
export function parseStructuredTaskOutput<T extends ZodType>(
3721
res: TaskView,
38-
body: GetTaskStatusParamsWithStructuredOutput<T>,
39-
): TaskViewWithStructuredOutput<T> {
22+
schema: T,
23+
): TaskViewWithSchema<T> {
24+
if (res.doneOutput == null) {
25+
return { ...res, doneOutput: null };
26+
}
27+
4028
try {
4129
const parsed = JSON.parse(res.doneOutput);
4230

43-
const response = body.structuredOutputJson.safeParse(parsed);
31+
const response = schema.safeParse(parsed);
4432
if (!response.success) {
4533
throw new Error(`Invalid structured output: ${response.error.message}`);
4634
}

src/resources/tasks.ts

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ import { path } from '../internal/utils/path';
1010
import {
1111
parseStructuredTaskOutput,
1212
stringifyStructuredOutput,
13-
type TaskViewWithStructuredOutput,
14-
type GetTaskStatusParamsWithStructuredOutput,
15-
type RunTaskCreateParamsWithStructuredOutput,
13+
type TaskViewWithSchema,
14+
type TaskCreateParamsWithSchema,
1615
} from '../lib/parse';
1716

1817
export class Tasks extends APIResource {
@@ -62,17 +61,33 @@ export class Tasks extends APIResource {
6261
* - 404: If referenced agent/browser profiles don't exist
6362
* - 400: If session is stopped or already has a running task
6463
*/
65-
create(body: TaskCreateParams, options?: RequestOptions): APIPromise<TaskView> {
66-
return this._client.post('/tasks', { body, ...options });
67-
}
68-
69-
createWithStructuredOutput<T extends ZodType>(
70-
body: RunTaskCreateParamsWithStructuredOutput<T>,
64+
create<T extends ZodType>(
65+
body: TaskCreateParamsWithSchema<T>,
7166
options?: RequestOptions,
72-
): APIPromise<TaskViewWithStructuredOutput<T>> {
73-
return this.create(stringifyStructuredOutput(body), options)._thenUnwrap((rsp) =>
74-
parseStructuredTaskOutput(rsp as TaskView, body),
75-
);
67+
): APIPromise<TaskViewWithSchema<T>>;
68+
create(body: TaskCreateParams, options?: RequestOptions): APIPromise<TaskView>;
69+
create(
70+
body: TaskCreateParams | TaskCreateParamsWithSchema<ZodType>,
71+
options?: RequestOptions,
72+
): APIPromise<unknown> {
73+
if (body.structuredOutputJson == null || typeof body.structuredOutputJson === 'string') {
74+
return this._client.post('/tasks', { body, ...options });
75+
}
76+
77+
if (typeof body.structuredOutputJson === 'object') {
78+
const schema = body.structuredOutputJson;
79+
80+
const _body: TaskCreateParams = {
81+
...body,
82+
structuredOutputJson: stringifyStructuredOutput(schema),
83+
};
84+
85+
return this._client
86+
.post('/tasks', { body: _body, ...options })
87+
._thenUnwrap((rsp) => parseStructuredTaskOutput(rsp as TaskView, schema));
88+
}
89+
90+
return this._client.post('/tasks', { body, ...options });
7691
}
7792

7893
/**
@@ -101,22 +116,21 @@ export class Tasks extends APIResource {
101116
*
102117
* - 404: If the user agent task doesn't exist
103118
*/
104-
retrieve(taskID: string, options?: RequestOptions): APIPromise<TaskView> {
105-
return this._client.get(path`/tasks/${taskID}`, options);
106-
}
107-
108-
retrieveWithStructuredOutput<T extends ZodType>(
109-
taskID: string,
110-
query: GetTaskStatusParamsWithStructuredOutput<T>,
119+
retrieve<T extends ZodType>(
120+
req: { taskId: string; schema: T },
111121
options?: RequestOptions,
112-
): APIPromise<TaskViewWithStructuredOutput<T>> {
113-
// NOTE: We manually remove structuredOutputJson from the query object because
114-
// it's not a valid Browser Use Cloud parameter.
115-
const { structuredOutputJson, ...rest } = query;
116-
117-
return this.retrieve(taskID, rest, options)._thenUnwrap((rsp) =>
118-
parseStructuredTaskOutput(rsp as TaskView, query),
119-
);
122+
): APIPromise<TaskViewWithSchema<T>>;
123+
retrieve(taskID: string, options?: RequestOptions): APIPromise<TaskView>;
124+
retrieve(req: string | { taskId: string; schema: ZodType }, options?: RequestOptions): APIPromise<unknown> {
125+
if (typeof req === 'string') {
126+
return this._client.get(path`/tasks/${req}`, options);
127+
}
128+
129+
const { taskId, schema } = req;
130+
131+
return this._client
132+
.get(path`/tasks/${taskId}`, options)
133+
._thenUnwrap((rsp) => parseStructuredTaskOutput(rsp as TaskView, schema));
120134
}
121135

122136
/**

0 commit comments

Comments
 (0)