Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
55 changes: 23 additions & 32 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ const TEMPLATES: Record<TemplateKey, TemplateInfo> = {
},
[TEMPLATE_ADVANCED_SAMPLE]: {
name: "Advanced Samples",
description:
"Implements sample actions with advanced Kernel configs",
description: "Implements sample actions with advanced Kernel configs",
languages: [LANGUAGE_TYPESCRIPT, LANGUAGE_PYTHON],
},
[TEMPLATE_COMPUTER_USE]: {
Expand All @@ -91,8 +90,7 @@ const INVOKE_SAMPLES: Record<
'kernel invoke ts-basic get-page-title --payload \'{"url": "https://www.google.com"}\'',
[TEMPLATE_STAGEHAND]:
'kernel invoke ts-stagehand stagehand-task --payload \'{"query": "Best wired earbuds"}\'',
[TEMPLATE_ADVANCED_SAMPLE]:
'kernel invoke ts-advanced test-captcha-solver',
[TEMPLATE_ADVANCED_SAMPLE]: "kernel invoke ts-advanced test-captcha-solver",
[TEMPLATE_COMPUTER_USE]:
'kernel invoke ts-cu cu-task --payload \'{"query": "Return the first url of a search result for NYC restaurant reviews Pete Wells"}\'',
[TEMPLATE_CUA]:
Expand All @@ -104,7 +102,7 @@ const INVOKE_SAMPLES: Record<
[TEMPLATE_BROWSER_USE]:
'kernel invoke python-bu bu-task --payload \'{"task": "Compare the price of gpt-4o and DeepSeek-V3"}\'',
[TEMPLATE_ADVANCED_SAMPLE]:
'kernel invoke python-advanced test-captcha-solver',
"kernel invoke python-advanced test-captcha-solver",
[TEMPLATE_COMPUTER_USE]:
'kernel invoke python-cu cu-task --payload \'{"query": "Return the first url of a search result for NYC restaurant reviews Pete Wells"}\'',
[TEMPLATE_CUA]:
Expand All @@ -117,28 +115,18 @@ const REGISTERED_APP_NAMES: Record<
Partial<Record<TemplateKey, string>>
> = {
[LANGUAGE_TYPESCRIPT]: {
[TEMPLATE_SAMPLE_APP]:
'ts-basic',
[TEMPLATE_STAGEHAND]:
'ts-stagehand',
[TEMPLATE_ADVANCED_SAMPLE]:
'ts-advanced',
[TEMPLATE_COMPUTER_USE]:
'ts-cu',
[TEMPLATE_CUA]:
'ts-cua',
[TEMPLATE_SAMPLE_APP]: "ts-basic",
[TEMPLATE_STAGEHAND]: "ts-stagehand",
[TEMPLATE_ADVANCED_SAMPLE]: "ts-advanced",
[TEMPLATE_COMPUTER_USE]: "ts-cu",
[TEMPLATE_CUA]: "ts-cua",
},
[LANGUAGE_PYTHON]: {
[TEMPLATE_SAMPLE_APP]:
'python-basic',
[TEMPLATE_BROWSER_USE]:
'python-bu',
[TEMPLATE_ADVANCED_SAMPLE]:
'python-advanced',
[TEMPLATE_COMPUTER_USE]:
'python-cu',
[TEMPLATE_CUA]:
'python-cua',
[TEMPLATE_SAMPLE_APP]: "python-basic",
[TEMPLATE_BROWSER_USE]: "python-bu",
[TEMPLATE_ADVANCED_SAMPLE]: "python-advanced",
[TEMPLATE_COMPUTER_USE]: "python-cu",
[TEMPLATE_CUA]: "python-cua",
},
};

Expand Down Expand Up @@ -311,14 +299,14 @@ function copyTemplateFiles(
fs.copySync(templatePath, appPath, {
filter: (src, dest) => {
const filename = path.basename(src);
if (filename === '_gitignore') {
if (filename === "_gitignore") {
fs.copyFileSync(src, dest);
// Rename it to .gitignore
fs.renameSync(dest, path.join(path.dirname(dest), '.gitignore'));
fs.renameSync(dest, path.join(path.dirname(dest), ".gitignore"));
return false; // Skip the original copy since we handled it
}
return true; // Copy all other files normally
}
},
});
}

Expand Down Expand Up @@ -363,15 +351,18 @@ function printNextSteps(
): void {
// Determine which sample command to show based on language and template
const deployCommand =
language === LANGUAGE_TYPESCRIPT && (template === TEMPLATE_SAMPLE_APP || template === TEMPLATE_ADVANCED_SAMPLE)
language === LANGUAGE_TYPESCRIPT &&
(template === TEMPLATE_SAMPLE_APP || template === TEMPLATE_ADVANCED_SAMPLE)
? "kernel deploy index.ts"
: language === LANGUAGE_TYPESCRIPT && template === TEMPLATE_STAGEHAND
? "kernel deploy index.ts --env OPENAI_API_KEY=XXX"
: language === LANGUAGE_TYPESCRIPT && template === TEMPLATE_COMPUTER_USE
? "kernel deploy index.ts --env ANTHROPIC_API_KEY=XXX"
: language === LANGUAGE_TYPESCRIPT && template === TEMPLATE_CUA
? "kernel deploy index.ts --env OPENAI_API_KEY=XXX"
: language === LANGUAGE_PYTHON && (template === TEMPLATE_SAMPLE_APP || template === TEMPLATE_ADVANCED_SAMPLE)
: language === LANGUAGE_PYTHON &&
(template === TEMPLATE_SAMPLE_APP ||
template === TEMPLATE_ADVANCED_SAMPLE)
? "kernel deploy main.py"
: language === LANGUAGE_PYTHON && template === TEMPLATE_BROWSER_USE
? "kernel deploy main.py --env OPENAI_API_KEY=XXX"
Expand All @@ -388,11 +379,11 @@ function printNextSteps(
Next steps:
brew install onkernel/tap/kernel
cd ${appName}
export KERNEL_API_KEY=<YOUR_API_KEY>
kernel login
${deployCommand}
${INVOKE_SAMPLES[language][template]}
# Do this in a separate tab
export KERNEL_API_KEY=<YOUR_API_KEY>
kernel login
kernel logs ${REGISTERED_APP_NAMES[language][template]} --follow
`)
);
Expand Down
4 changes: 2 additions & 2 deletions templates/python/advanced-sample/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
None

Invoke this via CLI:
export KERNEL_API_KEY=<your_api_key>
kernel login
kernel deploy main.py # If you haven't already deployed this app
kernel invoke py-advanced test_captcha_solver
kernel logs py-advanced -f # Open in separate tab
Expand All @@ -36,7 +36,7 @@ async def test_captcha_solver(ctx: kernel.KernelContext) -> None:
page = context.pages[0] if context.pages else await context.new_page()

# Access the live view. Retrieve this live_view_url from the Kernel logs in your CLI:
# export KERNEL_API_KEY=<Your API key>
# kernel login
# kernel logs py-advanced --follow
print("Kernel browser live view url: ", kernel_browser.browser_live_view_url)

Expand Down
2 changes: 1 addition & 1 deletion templates/python/cua/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
Returns:
An answer to the task, elapsed time and optionally the messages stack
Invoke this via CLI:
export KERNEL_API_KEY=<your_api_key>
kernel login
kernel deploy main.py -e OPENAI_API_KEY=XXXXX --force
kernel invoke python-cua cua-task -p '{"task":"go to https://news.ycombinator.com and list top 5 articles"}'
kernel logs python-cua -f # Open in separate tab
Expand Down
4 changes: 2 additions & 2 deletions templates/python/sample-app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
Returns:
A dictionary containing the page title
Invoke this via CLI:
export KERNEL_API_KEY=<your_api_key>
kernel login
kernel deploy main.py # If you haven't already deployed this app
kernel invoke python-basic get-page-title -p '{"url": "https://www.google.com"}'
kernel logs python-basic -f # Open in separate tab
Expand Down Expand Up @@ -74,7 +74,7 @@ async def get_page_title(ctx: kernel.KernelContext, input_data: PageTitleInput)
Returns:
A dictionary containing the browser live view url
Invoke this via CLI:
export KERNEL_API_KEY=<your_api_key>
kernel login
kernel deploy main.py # If you haven't already deployed this app
kernel invoke python-basic create-persisted-browser
kernel logs python-basic -f # Open in separate tab
Expand Down
22 changes: 12 additions & 10 deletions templates/typescript/advanced-sample/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@ const app = kernel.app("ts-advanced");
/**
* Example showing Kernel's auto-CAPTCHA solver
* Visit the live view url to see the Kernel browser auto-solve the CAPTCHA on the site
*
*
* Args:
* ctx: Kernel context containing invocation information
* Returns:
* None
*
*
* Invoke this via CLI:
* export KERNEL_API_KEY=<your_api_key>
* kernel login
* kernel deploy index.ts # If you haven't already deployed this app
* kernel invoke ts-advanced test-captcha-solver
* kernel logs ts-advanced -f # Open in separate tab
*/
app.action("test-captcha-solver", async(ctx: KernelContext): Promise<void> => {

app.action("test-captcha-solver", async (ctx: KernelContext): Promise<void> => {
const kernelBrowser = await kernel.browsers.create({
invocation_id: ctx.invocation_id,
stealth: true,
Expand All @@ -32,15 +31,18 @@ app.action("test-captcha-solver", async(ctx: KernelContext): Promise<void> => {
const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url);

// Access the live view. Retrieve this live_view_url from the Kernel logs in your CLI:
// export KERNEL_API_KEY=<Your API key>
// kernel login
// kernel logs ts-advanced --follow
console.log("Kernel browser live view url: ", kernelBrowser.browser_live_view_url);
console.log(
"Kernel browser live view url: ",
kernelBrowser.browser_live_view_url
);

// Navigate to a site with a CAPTCHA
const context = await browser.contexts()[0] || (await browser.newContext());
const page = await context.pages()[0] || (await context.newPage());
const context = (await browser.contexts()[0]) || (await browser.newContext());
const page = (await context.pages()[0]) || (await context.newPage());
await page.waitForTimeout(10000); // Add a delay to give you time to visit the live view url
await page.goto("https://www.google.com/recaptcha/api2/demo");
// Watch Kernel auto-solve the CAPTCHA!
await browser.close();
});
});
2 changes: 1 addition & 1 deletion templates/typescript/cua/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ if (!process.env.OPENAI_API_KEY) {
* Returns:
* An answer to the task, elapsed time and optionally the messages stack
* Invoke this via CLI:
* export KERNEL_API_KEY=<your_api_key>
* kernel login
* kernel deploy index.ts -e OPENAI_API_KEY=XXXXX --force
* kernel invoke ts-cua cua-task -p "{\"task\":\"current market price range for a used dreamcast\"}"
* kernel logs ts-cua -f # Open in separate tab
Expand Down
44 changes: 27 additions & 17 deletions templates/typescript/sample-app/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Kernel, type KernelContext } from '@onkernel/sdk';
import { chromium } from 'playwright';
import { Kernel, type KernelContext } from "@onkernel/sdk";
import { chromium } from "playwright";

const kernel = new Kernel();

const app = kernel.app('ts-basic');
const app = kernel.app("ts-basic");

/**
* Example app that extracts the title of a webpage
Expand All @@ -13,7 +13,7 @@ const app = kernel.app('ts-basic');
* Returns:
* A dictionary containing the page title
* Invoke this via CLI:
* export KERNEL_API_KEY=<your_api_key>
* kernel login
* kernel deploy index.ts # If you haven't already deployed this app
* kernel invoke ts-basic get-page-title -p '{"url": "https://www.google.com"}'
* kernel logs ts-basic -f # Open in separate tab
Expand All @@ -26,13 +26,19 @@ interface PageTitleOutput {
title: string;
}
app.action<PageTitleInput, PageTitleOutput>(
'get-page-title',
async (ctx: KernelContext, payload?: PageTitleInput): Promise<PageTitleOutput> => {
"get-page-title",
async (
ctx: KernelContext,
payload?: PageTitleInput
): Promise<PageTitleOutput> => {
if (!payload?.url) {
throw new Error('URL is required');
throw new Error("URL is required");
}

if (!payload.url.startsWith('http://') && !payload.url.startsWith('https://')) {

if (
!payload.url.startsWith("http://") &&
!payload.url.startsWith("https://")
) {
payload.url = `https://${payload.url}`;
}

Expand All @@ -47,11 +53,15 @@ app.action<PageTitleInput, PageTitleOutput>(
invocation_id: ctx.invocation_id,
});

console.log("Kernel browser live view url: ", kernelBrowser.browser_live_view_url);
console.log(
"Kernel browser live view url: ",
kernelBrowser.browser_live_view_url
);

const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url);
const context = await browser.contexts()[0] || (await browser.newContext());
const page = await context.pages()[0] || (await context.newPage());
const context =
(await browser.contexts()[0]) || (await browser.newContext());
const page = (await context.pages()[0]) || (await context.newPage());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Incorrect await Usage on Array Access

The await keyword was incorrectly applied to synchronous array access operations like browser.contexts()[0] and context.pages()[0] in both advanced-sample and sample-app templates. Since these methods return arrays, not promises, this can lead to runtime errors.

Additional Locations (1)
Fix in Cursor Fix in Web


try {
//////////////////////////////////////
Expand All @@ -63,7 +73,7 @@ app.action<PageTitleInput, PageTitleOutput>(
} finally {
await browser.close();
}
},
}
);

/**
Expand All @@ -75,17 +85,17 @@ app.action<PageTitleInput, PageTitleOutput>(
* Returns:
* A dictionary containing the browser live view url
* Invoke this via CLI:
* export KERNEL_API_KEY=<your_api_key>
* kernel login
* kernel deploy index.ts # If you haven't already deployed this app
* kernel invoke ts-basic create-persisted-browser
* kernel logs ts-basic -f # Open in separate tab
*/
interface CreatePersistedBrowserOutput {
browser_live_view_url: string;
}
app.action("create-persisted-browser",
app.action(
"create-persisted-browser",
async (ctx: KernelContext): Promise<CreatePersistedBrowserOutput> => {

const kernelBrowser = await kernel.browsers.create({
invocation_id: ctx.invocation_id,
persistence: {
Expand All @@ -98,4 +108,4 @@ app.action("create-persisted-browser",
browser_live_view_url: kernelBrowser.browser_live_view_url,
};
}
);
);