Skip to content

Commit b7ac6de

Browse files
authored
Update Stagehand Sample App to be compatible with Stagehand v3 (#62)
* Update Stagehand Sample App to Stagehand v3 Updated Stagehand example app to v3 Stagehand compatible version of script. * Remove -v3 in readme Remove "-v3" from the end of the app name as it's not used. * Update next steps for stagehand template Updated the next steps invocation example for Stagehand so that it's accurate now. * Update input/output schemas and payloads Add more descriptive and accurate input and output schemas and payloads for the stagehand sample app.
1 parent 2595fef commit b7ac6de

File tree

5 files changed

+4531
-1664
lines changed

5 files changed

+4531
-1664
lines changed

index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const TEMPLATES: Record<TemplateKey, TemplateInfo> = {
6565
},
6666
[TEMPLATE_STAGEHAND]: {
6767
name: "Stagehand",
68-
description: "Implements the Stagehand SDK",
68+
description: "Implements the Stagehand v3 SDK",
6969
languages: [LANGUAGE_TYPESCRIPT],
7070
},
7171
[TEMPLATE_ADVANCED_SAMPLE]: {
@@ -103,7 +103,7 @@ const INVOKE_SAMPLES: Record<
103103
[TEMPLATE_SAMPLE_APP]:
104104
'kernel invoke ts-basic get-page-title --payload \'{"url": "https://www.google.com"}\'',
105105
[TEMPLATE_STAGEHAND]:
106-
'kernel invoke ts-stagehand stagehand-task --payload \'{"query": "Best wired earbuds"}\'',
106+
'kernel invoke ts-stagehand teamsize-task --payload \'{"company": "Kernel"}\'',
107107
[TEMPLATE_ADVANCED_SAMPLE]: "kernel invoke ts-advanced test-captcha-solver",
108108
[TEMPLATE_COMPUTER_USE]:
109109
'kernel invoke ts-cu cu-task --payload \'{"query": "Return the first url of a search result for NYC restaurant reviews Pete Wells"}\'',
Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,50 @@
1-
# Kernel Typscript Sample App - Stagehand
1+
# Kernel TypeScript Sample App - Stagehand
22

3-
This is a simple Kernel application that implements the Stagehand SDK.
3+
A Stagehand-powered browser automation app that extracts team size information from Y Combinator company pages.
44

5-
See the [docs](https://onkernel.com/docs/quickstart) for information.
5+
## What it does
6+
7+
The `teamsize-task` searches for a startup on Y Combinator's company directory and extracts the team size (number of employees).
8+
9+
## Input
10+
11+
```json
12+
{
13+
"company": "kernel" // Startup name to search (optional, defaults to "kernel")
14+
}
15+
```
16+
17+
## Output
18+
19+
```json
20+
{
21+
"teamSize": "11" // Team size as shown on YC company page
22+
}
23+
```
24+
25+
## Setup
26+
27+
Create a `.env` file:
28+
29+
```
30+
OPENAI_API_KEY=your-openai-api-key
31+
```
32+
33+
## Deploy
34+
35+
```bash
36+
kernel login
37+
kernel deploy index.ts --env-file .env
38+
```
39+
40+
## Invoke
41+
42+
Default query (searches for "kernel"):
43+
```bash
44+
kernel invoke ts-stagehand teamsize-task
45+
```
46+
47+
Custom query:
48+
```bash
49+
kernel invoke ts-stagehand teamsize-task --payload '{"company": "Mixpanel"}'
50+
```

templates/typescript/stagehand/index.ts

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,72 +6,77 @@ const kernel = new Kernel();
66

77
const app = kernel.app('ts-stagehand');
88

9-
interface SearchQueryInput {
10-
query: string;
9+
interface CompanyInput {
10+
company: string;
1111
}
1212

13-
interface SearchQueryOutput {
14-
url: string;
13+
interface TeamSizeOutput {
14+
teamSize: string;
1515
}
1616

1717
// LLM API Keys are set in the environment during `kernel deploy <filename> -e OPENAI_API_KEY=XXX`
18-
// See https://onkernel.com/docs/launch/deploy#environment-variables
18+
// See https://www.onkernel.com/docs/apps/deploy#environment-variables
19+
1920
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
2021

2122
if (!OPENAI_API_KEY) {
2223
throw new Error('OPENAI_API_KEY is not set');
2324
}
2425

25-
app.action<SearchQueryInput, SearchQueryOutput>(
26-
'stagehand-task',
27-
async (ctx: KernelContext, payload?: SearchQueryInput): Promise<SearchQueryOutput> => {
28-
// A function that returns the first search result of a given search query from Google
29-
26+
app.action<CompanyInput, TeamSizeOutput>(
27+
'teamsize-task',
28+
async (ctx: KernelContext, payload?: CompanyInput): Promise<TeamSizeOutput> => {
29+
// A function that returns the team size of a Y Combinator startup
30+
3031
// Args:
3132
// ctx: Kernel context containing invocation information
32-
// payload: A search query string
33-
33+
// payload: A startup name to search for on YCombinator's website
34+
3435
// Returns:
35-
// output: The URL of the first search result
36+
// output: The team size (number of employees) of the startup
3637

37-
if (!payload?.query) {
38-
throw new Error('Query is required');
39-
}
38+
const company = payload?.company || 'kernel';
4039

4140
const kernelBrowser = await kernel.browsers.create({
4241
invocation_id: ctx.invocation_id,
4342
stealth: true,
4443
});
45-
44+
4645
console.log("Kernel browser live view url: ", kernelBrowser.browser_live_view_url);
4746

4847
const stagehand = new Stagehand({
4948
env: "LOCAL",
50-
verbose: 1,
51-
domSettleTimeoutMs: 30_000,
52-
modelName: "openai/gpt-4o",
53-
modelClientOptions: {
54-
apiKey: OPENAI_API_KEY,
55-
},
5649
localBrowserLaunchOptions: {
5750
cdpUrl: kernelBrowser.cdp_ws_url,
58-
}
51+
},
52+
model: "openai/gpt-4.1",
53+
apiKey: OPENAI_API_KEY,
54+
verbose: 1,
55+
domSettleTimeout: 30_000
5956
});
6057
await stagehand.init();
6158

6259
/////////////////////////////////////
6360
// Your Stagehand implementation here
6461
/////////////////////////////////////
65-
const page = stagehand.page;
66-
await page.act(`Type in ${payload.query} into the search bar`);
67-
await page.act("Click the search button");
68-
const output = await page.extract({
69-
instruction: "Extract the url of the first search result",
70-
schema: z.object({ url: z.string() })
71-
});
62+
const page = stagehand.context.pages()[0];
63+
await page.goto("https://www.ycombinator.com/companies");
7264

65+
await stagehand.act(`Type in ${company} into the search box`);
66+
await stagehand.act("Click on the first search result");
67+
68+
// Schema definition
69+
const teamSizeSchema = z.object({
70+
teamSize: z.string(),
71+
});
72+
// Extract team size from the YC startup page
73+
const output = await stagehand.extract(
74+
"Extract the team size (number of employees) shown on this Y Combinator company page.",
75+
teamSizeSchema
76+
);
7377
await stagehand.close();
74-
78+
await kernel.browsers.deleteByID(kernelBrowser.session_id);
79+
7580
return output;
7681
},
7782
);

0 commit comments

Comments
 (0)