Skip to content

update 2.0 #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 39 additions & 17 deletions .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,25 @@ This is a project that uses Stagehand, which amplifies Playwright with `act`, `e

Use the following rules to write code for this project.

- To plan an instruction like "click the sign in button", use Stagehand `observe` to get the action to execute.
- To take an action on the page like "click the sign in button", use Stagehand `act` like this:

```typescript
const results = await page.observe("Click the sign in button");
await page.act("Click the sign in button");
```

You can also pass in the following params:
- To plan an instruction before taking an action, use Stagehand `observe` to get the action to execute.

```typescript
await page.observe({
instruction: the instruction to execute,
onlyVisible: false, // DEFAULT: Returns better results and less tokens, but uses Chrome a11y tree so may not always target directly visible elements
returnAction: true, // DEFAULT: return the action to execute
});
const [action] = await page.observe("Click the sign in button");
```

- The result of `observe` is an array of `ObserveResult` objects that can directly be used as params for `act` like this:

```typescript
const results = await page.observe({
instruction: the instruction to execute,
onlyVisible: false, // Returns better results and less tokens, but uses Chrome a11y tree so may not always target directly visible elements
returnAction: true, // return the action to execute
});
await page.act(results[0]);
const [action] = await page.observe("Click the sign in button");
await page.act(action);
```

- When writing code that needs to extract data from the page, use Stagehand `extract`. Explicitly pass the following params by default:

```typescript
Expand All @@ -42,7 +36,6 @@ const { someValue } = await page.extract({
schema: z.object({
someValue: z.string(),
}), // The schema to extract
useTextExtract: true, // Set true for better results on larger extractions (sentences, paragraphs, etc), or set false for small extractions (name, birthday, etc)
});
```

Expand Down Expand Up @@ -83,7 +76,7 @@ if (cachedAction) {
Be sure to cache the results of `observe` and use them as params for `act` to avoid unexpected DOM changes. Using `act` without caching will result in more unpredictable behavior.

Act `action` should be as atomic and specific as possible, i.e. "Click the sign in button" or "Type 'hello' into the search input".
AVOID actions that are more than one step, i.e. "Order me pizza" or "Send an email to Paul asking him to call me".
AVOID actions that are more than one step, i.e. "Order me pizza" or "Type in the search bar and hit enter".

## Extract

Expand All @@ -101,7 +94,6 @@ const data = await page.extract({
schema: z.object({
text: z.string(),
}),
useTextExtract: true, // Set true for larger-scale extractions (multiple paragraphs), or set false for small extractions (name, birthday, etc)
});
```

Expand All @@ -116,3 +108,33 @@ const data = await page.extract({
useTextExtract: true, // Set true for larger-scale extractions (multiple paragraphs), or set false for small extractions (name, birthday, etc)
});
```

## Agent

Use the `agent` method to automonously execute larger tasks like "Get the stock price of NVDA"

```typescript
// Navigate to a website
await stagehand.page.goto("https://www.google.com");

const agent = stagehand.agent({
// You can use either OpenAI or Anthropic
provider: "openai",
// The model to use (claude-3-7-sonnet-20250219 or claude-3-5-sonnet-20240620 for Anthropic)
model: "computer-use-preview",

// Customize the system prompt
instructions: `You are a helpful assistant that can use a web browser.
Do not ask follow up questions, the user will trust your judgement.`,

// Customize the API key
options: {
apiKey: process.env.OPENAI_API_KEY,
},
});

// Execute the agent
await agent.execute(
"Apply for a library card at the San Francisco Public Library"
);
```
34 changes: 11 additions & 23 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,45 +1,33 @@
{
"quickstart": {
"examples/quickstart.ts": "main.ts",
"examples/run.ts": "index.ts"
"examples/quickstart.ts": "index.ts"
},
"blank": {
"examples/blank.ts": "main.ts",
"examples/blank.ts": "index.ts",
"examples/run.ts": "index.ts"
},
"persist-context": {
"examples/persist-context.ts": "index.ts"
},
"sf-ticket-agent": {
"examples/sf-ticket-agent.ts": "index.ts"
},
"deploy-vercel": {
"examples/deploy_vercel.ts": "index.ts",
"examples/api/stagehand.ts": "api/stagehand.ts",
"examples/vercel.json": "vercel.json"
},
"custom-client-ollama": {
"examples/custom_client_ollama.ts": "main.ts",
"examples/ollama_client.ts": "ollama_client.ts",
"examples/run.ts": "index.ts"
"custom-client-openai": {
"examples/quickstart.ts": "index.ts",
"examples/customOpenAI_client.ts": "customOpenAI_client.ts"
},
"custom-client-ollama-blank": {
"examples/blank.ts": "main.ts",
"examples/ollama_client.ts": "ollama_client.ts",
"examples/run.ts": "index.ts"
"custom-client-openai-blank": {
"examples/blank.ts": "index.ts",
"examples/customOpenAI_client.ts": "customOpenAI_client.ts"
},
"custom-client-aisdk": {
"examples/quickstart.ts": "main.ts",
"examples/run.ts": "index.ts",
"examples/quickstart.ts": "index.ts",
"examples/aisdk_client.ts": "aisdk_client.ts"
},
"custom-client-aisdk-blank": {
"examples/blank.ts": "main.ts",
"examples/aisdk_client.ts": "aisdk_client.ts",
"examples/run.ts": "index.ts"
},
"mintlify-ai": {
"examples/mintlify_ai.ts": "main.ts",
"examples/run.ts": "index.ts"
"examples/blank.ts": "index.ts",
"examples/aisdk_client.ts": "aisdk_client.ts"
}
}
27 changes: 21 additions & 6 deletions examples/aisdk_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
/**
* Welcome to the Stagehand Vercel AI SDK client!
*
* This is a client for OpenAI using Vercel AI SDK
* This is a client for Vercel AI SDK
* that allows you to create chat completions with Vercel AI SDK.
*
* To use this client, you need to have Vercel AI SDK installed and the appropriate environment variables set.
*
* ```bash
* npm install @vercel/ai
* npm install ai
* npm install @ai-sdk/openai # or @ai-sdk/anthropic, @ai-sdk/google, etc.
* ```
*/

Expand All @@ -28,12 +29,12 @@ import {
LanguageModel,
TextPart,
} from "ai";
import { ChatCompletion } from "openai/resources/chat/completions";
import {
CreateChatCompletionOptions,
LLMClient,
AvailableModel,
} from "@browserbasehq/stagehand";
import { ChatCompletion } from "openai/resources";

export class AISdkClient extends LLMClient {
public type = "aisdk" as const;
Expand Down Expand Up @@ -107,12 +108,19 @@ export class AISdkClient extends LLMClient {
schema: options.response_model.schema,
});

return response.object;
return {
data: response.object,
usage: {
prompt_tokens: response.usage.promptTokens ?? 0,
completion_tokens: response.usage.completionTokens ?? 0,
total_tokens: response.usage.totalTokens ?? 0,
},
} as T;
}

const tools: Record<string, CoreTool> = {};

for (const rawTool of options.tools || []) {
for (const rawTool of options.tools) {
tools[rawTool.name] = {
description: rawTool.description,
parameters: rawTool.parameters,
Expand All @@ -125,6 +133,13 @@ export class AISdkClient extends LLMClient {
tools,
});

return response as T;
return {
data: response.text,
usage: {
prompt_tokens: response.usage.promptTokens ?? 0,
completion_tokens: response.usage.completionTokens ?? 0,
total_tokens: response.usage.totalTokens ?? 0,
},
} as T;
}
}
80 changes: 64 additions & 16 deletions examples/blank.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { Stagehand, Page, BrowserContext } from "@browserbasehq/stagehand";
import StagehandConfig from "./stagehand.config.js";
import chalk from "chalk";
import boxen from "boxen";

/**
* 🤘 Welcome to Stagehand!
* 🤘 Welcome to Stagehand! Thanks so much for trying us out!
* 🛠️ CONFIGURATION: stagehand.config.ts will help you configure Stagehand
*
* TO RUN THIS PROJECT:
* ```
* npm install
* npm run start
* ```
* 📝 Check out our docs for more fun use cases, like building agents
* https://docs.stagehand.dev/
*
* To edit config, see `stagehand.config.ts`
* 💬 If you have any feedback, reach out to us on Slack!
* https://stagehand.dev/slack
*
* 📚 You might also benefit from the docs for Zod, Browserbase, and Playwright:
* - https://zod.dev/
* - https://docs.browserbase.com/
* - https://playwright.dev/docs/intro
*/
import { Page, BrowserContext, Stagehand } from "@browserbasehq/stagehand";
import { z } from "zod";
import chalk from "chalk";
import dotenv from "dotenv";

dotenv.config();

export async function main({
async function main({
page,
context,
stagehand,
Expand All @@ -26,5 +27,52 @@ export async function main({
context: BrowserContext; // Playwright BrowserContext
stagehand: Stagehand; // Stagehand instance
}) {
// Add your code here
/**
* 📝 Your code here!
*/
}

/**
* This is the main function that runs when you do npm run start
*
* YOU PROBABLY DON'T NEED TO MODIFY ANYTHING BELOW THIS POINT!
*
*/
async function run() {
const stagehand = new Stagehand({
...StagehandConfig,
});
await stagehand.init();

if (StagehandConfig.env === "BROWSERBASE" && stagehand.browserbaseSessionID) {
console.log(
boxen(
`View this session live in your browser: \n${chalk.blue(
`https://browserbase.com/sessions/${stagehand.browserbaseSessionID}`
)}`,
{
title: "Browserbase",
padding: 1,
margin: 3,
}
)
);
}

const page = stagehand.page;
const context = stagehand.context;
await main({
page,
context,
stagehand,
});
await stagehand.close();
stagehand.log({
category: "create-browser-app",
message: `\n🤘 Thanks so much for using Stagehand! Reach out to us on Slack if you have any feedback: ${chalk.blue(
"https://stagehand.dev/slack"
)}\n`,
});
}

run();
Loading