diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bcd0522..e7ca613 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.6.0" + ".": "0.7.0" } diff --git a/.stats.yml b/.stats.yml index c10d829..eeba574 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 26 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browser-use%2Fbrowser-use-9f5ca0cd0a64c620cebceaebf7c6f8c3a917aa6fbc2ea6b9d2a6e3b9d17aaea4.yml -openapi_spec_hash: 3d30ebd2ed6ab3a5b42b6b267a45d34f -config_hash: 9d52be5177b2ede4cb0633c04f4cc4ef +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browser-use%2Fbrowser-use-ce018db4d6891d645cfb220c86d17ac1d431e1ba2f604e8015876b17a5a11149.yml +openapi_spec_hash: e9a00924682ab214ca5d8b6b5c84430e +config_hash: dd3e22b635fa0eb9a7c741a8aaca2a7f diff --git a/CHANGELOG.md b/CHANGELOG.md index a179371..1676bd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.7.0 (2025-08-19) + +Full Changelog: [v0.6.0...v0.7.0](https://github.com/browser-use/browser-use-node/compare/v0.6.0...v0.7.0) + +### Features + +* **api:** manual updates ([d339b83](https://github.com/browser-use/browser-use-node/commit/d339b83355a358c7a55fa501576403cb30e0aa31)) +* **api:** manual updates ([5d09807](https://github.com/browser-use/browser-use-node/commit/5d09807eb2cb8fa30555775d0a5cb21b2c7f3c7f)) + ## 0.6.0 (2025-08-19) Full Changelog: [v0.5.1...v0.6.0](https://github.com/browser-use/browser-use-node/compare/v0.5.1...v0.6.0) diff --git a/README.md b/README.md index 024fd22..25dbb71 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,11 @@ const client = new BrowserUse({ apiKey: process.env['BROWSER_USE_API_KEY'], // This is the default and can be omitted }); -const me = await client.users.me.retrieve(); +const task = await client.tasks.create({ + task: 'Search for the top 10 Hacker News posts and return the title and url.', +}); -console.log(me.additionalCreditsBalanceUsd); +console.log(task.id); ``` ### Request & Response types @@ -43,7 +45,10 @@ const client = new BrowserUse({ apiKey: process.env['BROWSER_USE_API_KEY'], // This is the default and can be omitted }); -const me: BrowserUse.Users.MeRetrieveResponse = await client.users.me.retrieve(); +const params: BrowserUse.TaskCreateParams = { + task: 'Search for the top 10 Hacker News posts and return the title and url.', +}; +const task: BrowserUse.TaskCreateResponse = await client.tasks.create(params); ``` Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors. @@ -56,15 +61,17 @@ a subclass of `APIError` will be thrown: ```ts -const me = await client.users.me.retrieve().catch(async (err) => { - if (err instanceof BrowserUse.APIError) { - console.log(err.status); // 400 - console.log(err.name); // BadRequestError - console.log(err.headers); // {server: 'nginx', ...} - } else { - throw err; - } -}); +const task = await client.tasks + .create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }) + .catch(async (err) => { + if (err instanceof BrowserUse.APIError) { + console.log(err.status); // 400 + console.log(err.name); // BadRequestError + console.log(err.headers); // {server: 'nginx', ...} + } else { + throw err; + } + }); ``` Error codes are as follows: @@ -96,7 +103,7 @@ const client = new BrowserUse({ }); // Or, configure per-request: -await client.users.me.retrieve({ +await client.tasks.create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }, { maxRetries: 5, }); ``` @@ -113,7 +120,7 @@ const client = new BrowserUse({ }); // Override per-request: -await client.users.me.retrieve({ +await client.tasks.create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }, { timeout: 5 * 1000, }); ``` @@ -136,13 +143,17 @@ Unlike `.asResponse()` this method consumes the body, returning once it is parse ```ts const client = new BrowserUse(); -const response = await client.users.me.retrieve().asResponse(); +const response = await client.tasks + .create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }) + .asResponse(); console.log(response.headers.get('X-My-Header')); console.log(response.statusText); // access the underlying Response object -const { data: me, response: raw } = await client.users.me.retrieve().withResponse(); +const { data: task, response: raw } = await client.tasks + .create({ task: 'Search for the top 10 Hacker News posts and return the title and url.' }) + .withResponse(); console.log(raw.headers.get('X-My-Header')); -console.log(me.additionalCreditsBalanceUsd); +console.log(task.id); ``` ### Logging @@ -222,7 +233,7 @@ parameter. This library doesn't validate at runtime that the request matches the send will be sent as-is. ```ts -client.users.me.retrieve({ +client.tasks.create({ // ... // @ts-expect-error baz is not yet public baz: 'undocumented option', diff --git a/examples/run-zod.ts b/examples/run-zod.ts new file mode 100755 index 0000000..a987d09 --- /dev/null +++ b/examples/run-zod.ts @@ -0,0 +1,45 @@ +#!/usr/bin/env -S npm run tsn -T + +import { BrowserUse } from 'browser-use-sdk'; + +import z from 'zod'; +import { env } from './utils'; + +env(); + +// gets API Key from environment variable BROWSER_USE_API_KEY +const browseruse = new BrowserUse(); + +const HackerNewsResponse = z.object({ + title: z.string(), + url: z.string(), + score: z.number(), +}); + +const TaskOutput = z.object({ + posts: z.array(HackerNewsResponse), +}); + +async function main() { + console.log(`Creating Task...`); + + // Create Task + const rsp = await browseruse.tasks.run({ + task: 'Search for the top 10 Hacker News posts and return the title, url, and score', + schema: TaskOutput, + }); + + const posts = rsp.doneOutput?.posts; + + if (posts == null) { + throw new Error('No posts found'); + } + + for (const post of posts) { + console.log(`${post.title} (${post.score}) - ${post.url}`); + } + + console.log(`\nFound ${posts.length} posts`); +} + +main().catch(console.error); diff --git a/examples/run.ts b/examples/run.ts new file mode 100755 index 0000000..0f4fcb4 --- /dev/null +++ b/examples/run.ts @@ -0,0 +1,23 @@ +#!/usr/bin/env -S npm run tsn -T + +import { BrowserUse } from 'browser-use-sdk'; + +import { env } from './utils'; + +env(); + +// gets API Key from environment variable BROWSER_USE_API_KEY +const browseruse = new BrowserUse(); + +async function main() { + console.log(`Creating Task...`); + + // Create Task + const rsp = await browseruse.tasks.run({ + task: "What's the weather line in SF and what's the temperature?", + }); + + console.log(rsp.doneOutput); +} + +main().catch(console.error); diff --git a/examples/stream-zod.ts b/examples/stream-zod.ts index fa283ca..8989bd7 100755 --- a/examples/stream-zod.ts +++ b/examples/stream-zod.ts @@ -26,7 +26,7 @@ async function main() { // Create a task and get the stream const task = await browseruse.tasks.create({ task: 'Extract top 10 Hacker News posts and return the title, url, and score', - structuredOutputJson: TaskOutput, + schema: TaskOutput, }); const stream = browseruse.tasks.stream({ diff --git a/examples/zod.ts b/examples/zod.ts index eb5dbf7..dec48c3 100755 --- a/examples/zod.ts +++ b/examples/zod.ts @@ -28,7 +28,7 @@ async function main() { // Create Task const rsp = await browseruse.tasks.create({ task: 'Extract top 10 Hacker News posts and return the title, url, and score', - structuredOutputJson: TaskOutput, + schema: TaskOutput, }); poll: do { diff --git a/package.json b/package.json index f982322..5fe229b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "browser-use-sdk", - "version": "0.6.0", + "version": "0.7.0", "description": "The official TypeScript library for the Browser Use API", "author": "Browser Use ", "types": "dist/index.d.ts", diff --git a/src/lib/parse.ts b/src/lib/parse.ts index 8c651b8..f235edf 100644 --- a/src/lib/parse.ts +++ b/src/lib/parse.ts @@ -4,7 +4,7 @@ import type { TaskCreateParams, TaskView } from '../resources/tasks'; // RUN export type TaskCreateParamsWithSchema = Omit & { - structuredOutputJson: T; + schema: T; }; export function stringifyStructuredOutput(schema: T): string { diff --git a/src/resources/tasks.ts b/src/resources/tasks.ts index a32eb9e..398e28c 100644 --- a/src/resources/tasks.ts +++ b/src/resources/tasks.ts @@ -70,8 +70,8 @@ export class Tasks extends APIResource { body: TaskCreateParams | TaskCreateParamsWithSchema, options?: RequestOptions, ): APIPromise { - if (body.structuredOutputJson != null && typeof body.structuredOutputJson === 'object') { - const schema = body.structuredOutputJson; + if ('schema' in body && body.schema != null && typeof body.schema === 'object') { + const schema = body.schema; const _body: TaskCreateParams = { ...body, @@ -190,6 +190,47 @@ export class Tasks extends APIResource { } } + /** + * Create and run an agent task. + * + * @returns The output of the task. + */ + run( + body: TaskCreateParamsWithSchema, + options?: RequestOptions, + ): APIPromise>; + run(body: TaskCreateParams, options?: RequestOptions): APIPromise; + run( + body: TaskCreateParams | TaskCreateParamsWithSchema, + options?: RequestOptions, + ): APIPromise { + if ('schema' in body && body.schema != null && typeof body.schema === 'object') { + return this.create(body, options)._thenUnwrap(async (data) => { + const taskId = data.id; + + for await (const msg of this.stream({ taskId, schema: body.schema }, options)) { + if (msg.data.status === 'finished') { + return msg.data; + } + } + + throw new Error('Task did not finish'); + }); + } + + return this.create(body, options)._thenUnwrap(async (data) => { + const taskId = data.id; + + for await (const msg of this.stream(taskId, options)) { + if (msg.data.status === 'finished') { + return msg.data; + } + } + + throw new Error('Task did not finish'); + }); + } + /** * Control the execution of an AI agent task. * diff --git a/src/version.ts b/src/version.ts index 30c2817..d9da9f7 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.6.0'; // x-release-please-version +export const VERSION = '0.7.0'; // x-release-please-version