Skip to content

Commit 10de38b

Browse files
committed
Magnitude Template
Created a magnitude.run template for create-kernel-app and updated the base CLI to include the new template. Confirmed the template files work by running the CLI locally.
1 parent b0d4df2 commit 10de38b

File tree

6 files changed

+212
-2
lines changed

6 files changed

+212
-2
lines changed

index.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ type TemplateKey =
1919
| "stagehand"
2020
| "advanced-sample"
2121
| "computer-use"
22-
| "cua";
22+
| "cua"
23+
| "magnitude";
2324
type LanguageInfo = { name: string; shorthand: string };
2425
type TemplateInfo = {
2526
name: string;
@@ -36,6 +37,7 @@ const TEMPLATE_STAGEHAND = "stagehand";
3637
const TEMPLATE_ADVANCED_SAMPLE = "advanced-sample";
3738
const TEMPLATE_COMPUTER_USE = "computer-use";
3839
const TEMPLATE_CUA = "cua";
40+
const TEMPLATE_MAGNITUDE = "magnitude";
3941
const LANGUAGE_SHORTHAND_TS = "ts";
4042
const LANGUAGE_SHORTHAND_PY = "py";
4143

@@ -79,6 +81,11 @@ const TEMPLATES: Record<TemplateKey, TemplateInfo> = {
7981
description: "Implements a Computer Use Agent (OpenAI CUA) sample",
8082
languages: [LANGUAGE_TYPESCRIPT, LANGUAGE_PYTHON],
8183
},
84+
[TEMPLATE_MAGNITUDE]: {
85+
name: "Magnitude",
86+
description: "Implements the Magnitude.run SDK",
87+
languages: [LANGUAGE_TYPESCRIPT],
88+
},
8289
};
8390

8491
const INVOKE_SAMPLES: Record<
@@ -95,6 +102,8 @@ const INVOKE_SAMPLES: Record<
95102
'kernel invoke ts-cu cu-task --payload \'{"query": "Return the first url of a search result for NYC restaurant reviews Pete Wells"}\'',
96103
[TEMPLATE_CUA]:
97104
'kernel invoke ts-cua cua-task --payload \'{"task": "Go to https://news.ycombinator.com and get the top 5 articles"}\'',
105+
[TEMPLATE_MAGNITUDE]:
106+
'kernel invoke ts-magnitude mag-url-extract --payload \'{"url": "https://en.wikipedia.org/wiki/Special:Random"}\'',
98107
},
99108
[LANGUAGE_PYTHON]: {
100109
[TEMPLATE_SAMPLE_APP]:
@@ -120,6 +129,7 @@ const REGISTERED_APP_NAMES: Record<
120129
[TEMPLATE_ADVANCED_SAMPLE]: "ts-advanced",
121130
[TEMPLATE_COMPUTER_USE]: "ts-cu",
122131
[TEMPLATE_CUA]: "ts-cua",
132+
[TEMPLATE_MAGNITUDE]: "ts-magnitude",
123133
},
124134
[LANGUAGE_PYTHON]: {
125135
[TEMPLATE_SAMPLE_APP]: "python-basic",
@@ -358,6 +368,8 @@ function printNextSteps(
358368
? "kernel deploy index.ts --env OPENAI_API_KEY=XXX"
359369
: language === LANGUAGE_TYPESCRIPT && template === TEMPLATE_COMPUTER_USE
360370
? "kernel deploy index.ts --env ANTHROPIC_API_KEY=XXX"
371+
: language === LANGUAGE_TYPESCRIPT && template === TEMPLATE_MAGNITUDE
372+
? "kernel deploy index.ts --env ANTHROPIC_API_KEY=XXX"
361373
: language === LANGUAGE_TYPESCRIPT && template === TEMPLATE_CUA
362374
? "kernel deploy index.ts --env OPENAI_API_KEY=XXX"
363375
: language === LANGUAGE_PYTHON &&
@@ -403,7 +415,7 @@ program
403415
)
404416
.option(
405417
"-t, --template <template>",
406-
`Template type (${TEMPLATE_SAMPLE_APP}, ${TEMPLATE_BROWSER_USE}, ${TEMPLATE_STAGEHAND}, ${TEMPLATE_ADVANCED_SAMPLE}, ${TEMPLATE_COMPUTER_USE})`
418+
`Template type (${TEMPLATE_SAMPLE_APP}, ${TEMPLATE_BROWSER_USE}, ${TEMPLATE_STAGEHAND}, ${TEMPLATE_ADVANCED_SAMPLE}, ${TEMPLATE_COMPUTER_USE}, ${TEMPLATE_CUA}, ${TEMPLATE_MAGNITUDE})`
407419
)
408420
.action(
409421
async (
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Kernel TypeScript Magnitude.run Template
2+
3+
This template demonstrates integrating Magnitude.run with a Kernel app.
4+
5+
It defines a single action that:
6+
- Navigates to a given URL (via Magnitude `agent.act()`)
7+
- Extracts up to 5 absolute URLs on the page (via Magnitude `agent.extract()`)
8+
9+
## Quickstart
10+
11+
- Deploy:
12+
kernel login # or: export KERNEL_API_KEY=<your_api_key>
13+
kernel deploy index.ts --env ANTHROPIC_API_KEY=XXX
14+
15+
- Invoke:
16+
kernel invoke ts-magnitude mag-url-extract --payload '{"url": "https://fandom.com"}'
17+
18+
## Notes
19+
- Uses Anthropic as the model provider with model: `anthropic/claude-sonnet-4`.
20+
- Requires `ANTHROPIC_API_KEY` in the deployment environment.
21+
- The agent connects to the Kernel-managed browser via CDP for live view & observability.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Dependencies
2+
node_modules/
3+
package-lock.json
4+
5+
# TypeScript
6+
*.tsbuildinfo
7+
dist/
8+
build/
9+
10+
# Environment
11+
.env
12+
.env.local
13+
.env.*.local
14+
15+
# IDE
16+
.vscode/
17+
.idea/
18+
*.swp
19+
*.swo
20+
21+
# OS
22+
.DS_Store
23+
Thumbs.db
24+
25+
# Logs
26+
logs/
27+
*.log
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
32+
# Testing
33+
coverage/
34+
.nyc_output/
35+
36+
# Misc
37+
.cache/
38+
.temp/
39+
.tmp/
40+
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { Kernel, type KernelContext } from "@onkernel/sdk";
2+
import { startBrowserAgent } from "magnitude-core";
3+
import { z } from "zod";
4+
5+
const kernel = new Kernel();
6+
7+
const app = kernel.app("ts-magnitude");
8+
9+
interface UrlInput {
10+
url: string;
11+
}
12+
13+
interface UrlsOutput {
14+
urls: string[];
15+
}
16+
17+
// Use env var + inline model directly in the agent call.
18+
19+
app.action<UrlInput, UrlsOutput>(
20+
"mag-url-extract",
21+
async (ctx: KernelContext, payload?: UrlInput): Promise<UrlsOutput> => {
22+
if (!payload?.url) {
23+
throw new Error("URL is required");
24+
}
25+
26+
let target = payload.url;
27+
if (!target.startsWith("http://") && !target.startsWith("https://")) {
28+
target = `https://${target}`;
29+
}
30+
try {
31+
// Validate URL
32+
new URL(target);
33+
} catch {
34+
throw new Error(`Invalid URL: ${target}`);
35+
}
36+
37+
// Create a Kernel browser so we get a live view and observability
38+
const kernelBrowser = await kernel.browsers.create({
39+
invocation_id: ctx.invocation_id,
40+
stealth: true,
41+
});
42+
43+
console.log(
44+
"Kernel browser live view url:",
45+
kernelBrowser.browser_live_view_url
46+
);
47+
48+
// Start a Magnitude BrowserAgent connected to the Kernel browser via CDP
49+
const agent = await startBrowserAgent({
50+
narrate: true,
51+
url: target,
52+
llm: {
53+
provider: "anthropic",
54+
options: {
55+
model: "claude-sonnet-4-20250514",
56+
apiKey: process.env.ANTHROPIC_API_KEY as string,
57+
},
58+
},
59+
browser: {
60+
cdp: kernelBrowser.cdp_ws_url,
61+
contextOptions: {
62+
viewport: { width: 1024, height: 768 }
63+
}
64+
},
65+
virtualScreenDimensions: { width: 1024, height: 768 }
66+
});
67+
68+
try {
69+
//////////////////////////////////////
70+
// Navigate and extract via Magnitude
71+
//////////////////////////////////////
72+
await agent.act(
73+
`Go to ${target}. Explore the page by scrolling down the page twice. Narrate key steps.`
74+
);
75+
76+
const urls = await agent.extract(
77+
"Extract up to 5 absolute URLs on the current page",
78+
z.array(z.string().url()).describe("List of absolute URLs")
79+
);
80+
81+
return { urls };
82+
} finally {
83+
try {
84+
await agent.stop();
85+
} catch (e) {
86+
console.warn("Warning: failed to stop agent", e);
87+
}
88+
try {
89+
await kernel.invocations.deleteBrowsers(ctx.invocation_id);
90+
console.log(`Browsers for invocation ${ctx.invocation_id} cleaned up successfully`);
91+
} catch (e) {
92+
console.warn(
93+
`Warning: failed to clean up browsers for ${ctx.invocation_id}`,
94+
e
95+
);
96+
}
97+
}
98+
}
99+
);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "ts-magnitude",
3+
"module": "index.ts",
4+
"type": "module",
5+
"private": true,
6+
"peerDependencies": {
7+
"typescript": "^5"
8+
},
9+
"dependencies": {
10+
"@onkernel/sdk": ">=0.11.0",
11+
"magnitude-core": "latest",
12+
"zod": "^3.25.0"
13+
}
14+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"compilerOptions": {
3+
"lib": ["ESNext", "DOM"],
4+
"target": "ESNext",
5+
"module": "ESNext",
6+
"moduleDetection": "force",
7+
"jsx": "react-jsx",
8+
"allowJs": true,
9+
"moduleResolution": "bundler",
10+
"allowImportingTsExtensions": true,
11+
"verbatimModuleSyntax": true,
12+
"noEmit": true,
13+
"strict": true,
14+
"skipLibCheck": true,
15+
"noFallthroughCasesInSwitch": true,
16+
"noUncheckedIndexedAccess": true,
17+
"noUnusedLocals": false,
18+
"noUnusedParameters": false,
19+
"noPropertyAccessFromIndexSignature": false
20+
},
21+
"include": ["./**/*.ts", "./**/*.tsx"],
22+
"exclude": ["node_modules", "dist"]
23+
}
24+

0 commit comments

Comments
 (0)