diff --git a/pkg/templates/python/anthropic-computer-use/main.py b/pkg/templates/python/anthropic-computer-use/main.py index 51b571db..9f3e58ba 100644 --- a/pkg/templates/python/anthropic-computer-use/main.py +++ b/pkg/templates/python/anthropic-computer-use/main.py @@ -48,6 +48,7 @@ async def cua_task( record_replay = payload.get("record_replay", False) async with KernelBrowserSession( + invocation_id=ctx.invocation_id, stealth=True, record_replay=record_replay, ) as session: diff --git a/pkg/templates/python/anthropic-computer-use/pyproject.toml b/pkg/templates/python/anthropic-computer-use/pyproject.toml index f5b75dee..4356b1a2 100644 --- a/pkg/templates/python/anthropic-computer-use/pyproject.toml +++ b/pkg/templates/python/anthropic-computer-use/pyproject.toml @@ -8,6 +8,6 @@ dependencies = [ "python-dateutil>=2.9.0", "pydantic>=2.12.5", "typing-extensions>=4.15.0", - "kernel>=0.24.0", + "kernel>=0.35.0", "python-dotenv>=1.2.1", ] diff --git a/pkg/templates/python/anthropic-computer-use/session.py b/pkg/templates/python/anthropic-computer-use/session.py index 4718dbd7..eb4c16b0 100644 --- a/pkg/templates/python/anthropic-computer-use/session.py +++ b/pkg/templates/python/anthropic-computer-use/session.py @@ -39,6 +39,9 @@ class KernelBrowserSession: record_replay: bool = False replay_grace_period: float = 5.0 # Seconds to wait before stopping replay + # Invocation ID to link browser session to the action invocation + invocation_id: Optional[str] = None + # Set after browser creation session_id: Optional[str] = field(default=None, init=False) live_view_url: Optional[str] = field(default=None, init=False) @@ -52,6 +55,7 @@ async def __aenter__(self) -> "KernelBrowserSession": # Create browser with specified settings browser = self._kernel.browsers.create( + invocation_id=self.invocation_id, stealth=self.stealth, timeout_seconds=self.timeout_seconds, viewport={ diff --git a/pkg/templates/python/gemini-computer-use/main.py b/pkg/templates/python/gemini-computer-use/main.py index 0c7d4616..870ff776 100644 --- a/pkg/templates/python/gemini-computer-use/main.py +++ b/pkg/templates/python/gemini-computer-use/main.py @@ -52,6 +52,7 @@ async def cua_task( record_replay = payload.get("record_replay", False) async with KernelBrowserSession( + invocation_id=ctx.invocation_id, stealth=True, record_replay=record_replay, ) as session: diff --git a/pkg/templates/python/gemini-computer-use/pyproject.toml b/pkg/templates/python/gemini-computer-use/pyproject.toml index c689f305..b8d1a979 100644 --- a/pkg/templates/python/gemini-computer-use/pyproject.toml +++ b/pkg/templates/python/gemini-computer-use/pyproject.toml @@ -6,7 +6,7 @@ readme = "README.md" requires-python = ">=3.11" dependencies = [ "google-genai>=1.0.0", - "kernel>=0.5.0", + "kernel>=0.35.0", ] [tool.uv] diff --git a/pkg/templates/python/gemini-computer-use/session.py b/pkg/templates/python/gemini-computer-use/session.py index 82e856db..16c998ba 100644 --- a/pkg/templates/python/gemini-computer-use/session.py +++ b/pkg/templates/python/gemini-computer-use/session.py @@ -23,6 +23,9 @@ class KernelBrowserSession: record_replay: bool = False replay_grace_period: float = 5.0 # Seconds to wait before stopping replay + # Invocation ID to link browser session to the action invocation + invocation_id: Optional[str] = None + # Set after browser creation session_id: Optional[str] = field(default=None, init=False) live_view_url: Optional[str] = field(default=None, init=False) @@ -35,6 +38,7 @@ async def __aenter__(self) -> "KernelBrowserSession": # Create browser with specified settings browser = self._kernel.browsers.create( + invocation_id=self.invocation_id, stealth=self.stealth, timeout_seconds=self.timeout_seconds, viewport={ diff --git a/pkg/templates/python/openagi-computer-use/kernel_session.py b/pkg/templates/python/openagi-computer-use/kernel_session.py index 61758e70..1e8984f7 100644 --- a/pkg/templates/python/openagi-computer-use/kernel_session.py +++ b/pkg/templates/python/openagi-computer-use/kernel_session.py @@ -35,6 +35,9 @@ class KernelBrowserSession: replay_framerate: int = 30 replay_grace_period: float = 5.0 # Seconds to wait before stopping replay + # Invocation ID to link browser session to the action invocation + invocation_id: str | None = None + # Set after browser creation session_id: str | None = None live_view_url: str | None = None @@ -48,6 +51,7 @@ async def __aenter__(self) -> "KernelBrowserSession": # Create browser with specified settings browser = self._kernel.browsers.create( + invocation_id=self.invocation_id, stealth=self.stealth, timeout_seconds=self.timeout_seconds, ) diff --git a/pkg/templates/python/openagi-computer-use/main.py b/pkg/templates/python/openagi-computer-use/main.py index 83b172c6..1ac427d1 100644 --- a/pkg/templates/python/openagi-computer-use/main.py +++ b/pkg/templates/python/openagi-computer-use/main.py @@ -103,7 +103,10 @@ async def oagi_default_task( model = payload.get("model", "lux-actor-1") record_replay = payload.get("record_replay", False) - async with KernelBrowserSession(record_replay=record_replay) as session: + async with KernelBrowserSession( + record_replay=record_replay, + invocation_id=ctx.invocation_id, + ) as session: print("Kernel browser live view url:", session.live_view_url) provider = KernelScreenshotProvider(session) @@ -155,7 +158,10 @@ async def oagi_tasker_task( todos = payload["todos"] record_replay = payload.get("record_replay", False) - async with KernelBrowserSession(record_replay=record_replay) as session: + async with KernelBrowserSession( + record_replay=record_replay, + invocation_id=ctx.invocation_id, + ) as session: print("Kernel browser live view url:", session.live_view_url) provider = KernelScreenshotProvider(session) diff --git a/pkg/templates/python/openagi-computer-use/pyproject.toml b/pkg/templates/python/openagi-computer-use/pyproject.toml index a4ea55d9..8c2345c9 100644 --- a/pkg/templates/python/openagi-computer-use/pyproject.toml +++ b/pkg/templates/python/openagi-computer-use/pyproject.toml @@ -5,7 +5,7 @@ description = "Kernel sample app for OpenAGI Lux computer-use models" readme = "README.md" requires-python = ">=3.11" dependencies = [ - "kernel>=0.22.0", + "kernel>=0.35.0", "oagi>=0.1.0", "python-dotenv>=1.0.0", "Pillow>=10.0.0", diff --git a/pkg/templates/python/yutori-computer-use/main.py b/pkg/templates/python/yutori-computer-use/main.py index 8952af59..4679df8c 100644 --- a/pkg/templates/python/yutori-computer-use/main.py +++ b/pkg/templates/python/yutori-computer-use/main.py @@ -50,6 +50,7 @@ async def cua_task( kiosk_mode = payload.get("kiosk", False) async with KernelBrowserSession( + invocation_id=ctx.invocation_id, stealth=True, record_replay=record_replay, kiosk_mode=kiosk_mode, diff --git a/pkg/templates/python/yutori-computer-use/pyproject.toml b/pkg/templates/python/yutori-computer-use/pyproject.toml index 25471749..aafe423d 100644 --- a/pkg/templates/python/yutori-computer-use/pyproject.toml +++ b/pkg/templates/python/yutori-computer-use/pyproject.toml @@ -5,7 +5,7 @@ description = "Kernel reference app for Yutori n1 Computer Use" requires-python = ">=3.9" dependencies = [ "openai>=1.58.0", - "kernel>=0.24.0", + "kernel>=0.35.0", "python-dotenv>=1.2.1", "Pillow>=10.0.0", ] diff --git a/pkg/templates/python/yutori-computer-use/session.py b/pkg/templates/python/yutori-computer-use/session.py index 74c27deb..9bf020f2 100644 --- a/pkg/templates/python/yutori-computer-use/session.py +++ b/pkg/templates/python/yutori-computer-use/session.py @@ -42,6 +42,9 @@ class KernelBrowserSession: # Kiosk mode (hides address bar and tabs in live view) kiosk_mode: bool = False + # Invocation ID to link browser session to the action invocation + invocation_id: Optional[str] = None + # Set after browser creation session_id: Optional[str] = field(default=None, init=False) live_view_url: Optional[str] = field(default=None, init=False) @@ -54,6 +57,7 @@ async def __aenter__(self) -> "KernelBrowserSession": self._kernel = Kernel() browser = self._kernel.browsers.create( + invocation_id=self.invocation_id, stealth=self.stealth, timeout_seconds=self.timeout_seconds, viewport={ diff --git a/pkg/templates/typescript/anthropic-computer-use/index.ts b/pkg/templates/typescript/anthropic-computer-use/index.ts index b126626f..ec16d400 100644 --- a/pkg/templates/typescript/anthropic-computer-use/index.ts +++ b/pkg/templates/typescript/anthropic-computer-use/index.ts @@ -33,6 +33,7 @@ app.action( // Create browser session with optional replay recording const session = new KernelBrowserSession(kernel, { + invocationId: ctx.invocation_id, stealth: true, recordReplay: payload.record_replay ?? false, }); diff --git a/pkg/templates/typescript/anthropic-computer-use/package.json b/pkg/templates/typescript/anthropic-computer-use/package.json index 8012da1d..ad09a3d5 100644 --- a/pkg/templates/typescript/anthropic-computer-use/package.json +++ b/pkg/templates/typescript/anthropic-computer-use/package.json @@ -5,7 +5,7 @@ "private": true, "dependencies": { "@anthropic-ai/sdk": "^0.71.2", - "@onkernel/sdk": "^0.24.0", + "@onkernel/sdk": "^0.35.0", "luxon": "^3.7.2" }, "devDependencies": { diff --git a/pkg/templates/typescript/anthropic-computer-use/session.ts b/pkg/templates/typescript/anthropic-computer-use/session.ts index fed3dd47..6c2c77d9 100644 --- a/pkg/templates/typescript/anthropic-computer-use/session.ts +++ b/pkg/templates/typescript/anthropic-computer-use/session.ts @@ -8,6 +8,8 @@ import type { Kernel } from '@onkernel/sdk'; export interface SessionOptions { + /** Invocation ID to link browser session to the action invocation */ + invocationId?: string; /** Enable stealth mode to avoid bot detection */ stealth?: boolean; /** Browser session timeout in seconds */ @@ -31,7 +33,9 @@ export interface SessionInfo { viewportHeight: number; } -const DEFAULT_OPTIONS: Required = { +type SessionOptionsWithDefaults = Required> & Pick; + +const DEFAULT_OPTIONS: Required> = { stealth: true, timeoutSeconds: 300, recordReplay: false, @@ -56,8 +60,8 @@ const DEFAULT_OPTIONS: Required = { */ export class KernelBrowserSession { private kernel: Kernel; - private options: Required; - + private options: SessionOptionsWithDefaults; + // Session state private _sessionId: string | null = null; private _liveViewUrl: string | null = null; @@ -109,6 +113,7 @@ export class KernelBrowserSession { async start(): Promise { // Create browser with specified settings const browser = await this.kernel.browsers.create({ + invocation_id: this.options.invocationId, stealth: this.options.stealth, timeout_seconds: this.options.timeoutSeconds, viewport: { diff --git a/pkg/templates/typescript/gemini-computer-use/index.ts b/pkg/templates/typescript/gemini-computer-use/index.ts index 1b27b423..91f47e4a 100644 --- a/pkg/templates/typescript/gemini-computer-use/index.ts +++ b/pkg/templates/typescript/gemini-computer-use/index.ts @@ -39,6 +39,7 @@ app.action( // Create browser session with optional replay recording const session = new KernelBrowserSession(kernel, { + invocationId: ctx.invocation_id, stealth: true, recordReplay: payload.record_replay ?? false, }); diff --git a/pkg/templates/typescript/gemini-computer-use/package.json b/pkg/templates/typescript/gemini-computer-use/package.json index 8ef6ebf7..eee99372 100644 --- a/pkg/templates/typescript/gemini-computer-use/package.json +++ b/pkg/templates/typescript/gemini-computer-use/package.json @@ -5,7 +5,7 @@ "private": true, "dependencies": { "@google/genai": "^1.0.0", - "@onkernel/sdk": "^0.23.0" + "@onkernel/sdk": "^0.35.0" }, "devDependencies": { "@types/node": "^22.15.17", diff --git a/pkg/templates/typescript/gemini-computer-use/session.ts b/pkg/templates/typescript/gemini-computer-use/session.ts index fd684427..627b4420 100644 --- a/pkg/templates/typescript/gemini-computer-use/session.ts +++ b/pkg/templates/typescript/gemini-computer-use/session.ts @@ -9,6 +9,8 @@ import type { Kernel } from '@onkernel/sdk'; import { DEFAULT_SCREEN_SIZE } from './tools/types/gemini'; export interface SessionOptions { + /** Invocation ID to link browser session to the action invocation */ + invocationId?: string; stealth?: boolean; timeoutSeconds?: number; recordReplay?: boolean; @@ -22,7 +24,9 @@ export interface SessionInfo { replayViewUrl?: string; } -const DEFAULT_OPTIONS: Required = { +type SessionOptionsWithDefaults = Required> & Pick; + +const DEFAULT_OPTIONS: Required> = { stealth: true, timeoutSeconds: 300, recordReplay: false, @@ -31,7 +35,7 @@ const DEFAULT_OPTIONS: Required = { export class KernelBrowserSession { private kernel: Kernel; - private options: Required; + private options: SessionOptionsWithDefaults; // Session state private _sessionId: string | null = null; @@ -71,6 +75,7 @@ export class KernelBrowserSession { async start(): Promise { // Create browser with specified settings const browser = await this.kernel.browsers.create({ + invocation_id: this.options.invocationId, stealth: this.options.stealth, timeout_seconds: this.options.timeoutSeconds, viewport: { diff --git a/pkg/templates/typescript/yutori-computer-use/index.ts b/pkg/templates/typescript/yutori-computer-use/index.ts index b3786f45..364e7237 100644 --- a/pkg/templates/typescript/yutori-computer-use/index.ts +++ b/pkg/templates/typescript/yutori-computer-use/index.ts @@ -35,6 +35,7 @@ app.action( // Create browser session with optional replay recording and kiosk mode const kioskMode = payload.kiosk ?? false; const session = new KernelBrowserSession(kernel, { + invocationId: ctx.invocation_id, stealth: true, recordReplay: payload.record_replay ?? false, kioskMode, diff --git a/pkg/templates/typescript/yutori-computer-use/package.json b/pkg/templates/typescript/yutori-computer-use/package.json index e3683db3..f1fc38c1 100644 --- a/pkg/templates/typescript/yutori-computer-use/package.json +++ b/pkg/templates/typescript/yutori-computer-use/package.json @@ -4,7 +4,7 @@ "type": "module", "private": true, "dependencies": { - "@onkernel/sdk": "^0.24.0", + "@onkernel/sdk": "^0.35.0", "openai": "^4.77.0", "sharp": "^0.33.0" }, diff --git a/pkg/templates/typescript/yutori-computer-use/session.ts b/pkg/templates/typescript/yutori-computer-use/session.ts index 4a0699bd..b0edcc3d 100644 --- a/pkg/templates/typescript/yutori-computer-use/session.ts +++ b/pkg/templates/typescript/yutori-computer-use/session.ts @@ -8,6 +8,8 @@ import type { Kernel } from '@onkernel/sdk'; export interface SessionOptions { + /** Invocation ID to link browser session to the action invocation */ + invocationId?: string; /** Enable stealth mode to avoid bot detection */ stealth?: boolean; /** Browser session timeout in seconds */ @@ -34,7 +36,9 @@ export interface SessionInfo { viewportHeight: number; } -const DEFAULT_OPTIONS: Required = { +type SessionOptionsWithDefaults = Required> & Pick; + +const DEFAULT_OPTIONS: Required> = { stealth: true, timeoutSeconds: 300, recordReplay: false, @@ -60,7 +64,7 @@ const DEFAULT_OPTIONS: Required = { */ export class KernelBrowserSession { private kernel: Kernel; - private options: Required; + private options: SessionOptionsWithDefaults; // Session state private _sessionId: string | null = null; @@ -119,6 +123,7 @@ export class KernelBrowserSession { async start(): Promise { const browser = await this.kernel.browsers.create({ + invocation_id: this.options.invocationId, stealth: this.options.stealth, timeout_seconds: this.options.timeoutSeconds, viewport: { @@ -128,9 +133,9 @@ export class KernelBrowserSession { kiosk_mode: this.options.kioskMode, }); - this._sessionId = browser.session_id; - this._liveViewUrl = browser.browser_live_view_url; - this._cdpWsUrl = browser.cdp_ws_url; + this._sessionId = browser.session_id ?? null; + this._liveViewUrl = browser.browser_live_view_url ?? null; + this._cdpWsUrl = browser.cdp_ws_url ?? null; console.log(`Kernel browser created: ${this._sessionId}`); console.log(`Live view URL: ${this._liveViewUrl}`); @@ -183,7 +188,7 @@ export class KernelBrowserSession { const replays = await this.kernel.browsers.replays.list(this._sessionId); for (const replay of replays) { if (replay.replay_id === this._replayId) { - this._replayViewUrl = replay.replay_view_url; + this._replayViewUrl = replay.replay_view_url ?? null; replayReady = true; break; }