Skip to content
Closed
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
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,30 @@ jobs:
TZAFON_API_KEY: ${{ secrets.TZAFON_API_KEY }}
YUTORI_API_KEY: ${{ secrets.YUTORI_API_KEY }}
run: npm test --workspace @onkernel/cua-agent -- test/e2e.live.test.ts

cli-e2e:
runs-on: ubuntu-latest
timeout-minutes: 45
# Only run on the main repo (not forks) so secrets are available.
# Skip draft PRs; still run on every commit to non-draft PRs and on main pushes.
if: github.event_name == 'push' || (github.event.pull_request.head.repo.full_name == github.repository && !github.event.pull_request.draft)
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- name: Install Zig 0.15.2
run: |
mkdir -p .dev/tools
curl -fsSL https://ziglang.org/download/0.15.2/zig-x86_64-linux-0.15.2.tar.xz -o /tmp/zig-x86_64-linux-0.15.2.tar.xz
tar -xf /tmp/zig-x86_64-linux-0.15.2.tar.xz -C .dev/tools
- run: npm run build:native --workspace @onkernel/ptywright
- run: npm run build --workspace @onkernel/cua-cli
- name: CUA CLI live TUI smoke test
env:
CUA_CLI_E2E_LIVE: "1"
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
KERNEL_API_KEY: ${{ secrets.KERNEL_API_KEY }}
run: npm run test:e2e-live --workspace @onkernel/cua-cli
9 changes: 2 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/agent/test/e2e.live.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ describe("Cua live e2e", () => {
return apiKey ? { apiKey } : undefined;
},
});
if (c.name === "yutori") {
// Yutori can occasionally keep requesting additional tool rounds.
// Terminate after the first completed batch to keep CI deterministic.
harness.on("tool_result", () => ({ terminate: true }));
}

harness.subscribe((event) => {
recordRunEvent(stats, event);
Expand Down
12 changes: 4 additions & 8 deletions packages/cua-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,15 @@
"scripts": {
"build": "tsc -b && chmod +x dist/cli.js",
"clean": "tsc -b --clean",
"test": "node --test dist/tui/testing/*.test.js"
"test": "node --test dist/tui/testing/*.test.js",
"test:e2e-live": "node --test dist/tui/testing/live.e2e.test.js"
},
"dependencies": {
"@mariozechner/pi-agent-core": "0.67.6",
"@mariozechner/pi-ai": "0.67.6",
"@mariozechner/pi-coding-agent": "0.67.6",
"@mariozechner/pi-tui": "0.67.6",
"@onkernel/cua-anthropic": "0.1.0",
"@onkernel/cua-gemini": "0.1.0",
"@onkernel/cua-openai": "0.1.0",
"@onkernel/cua-agent": "0.2.0",
"@onkernel/cua-ai": "0.1.0",
"@onkernel/cua-translator": "0.1.0",
"@onkernel/cua-tzafon": "0.1.0",
"@onkernel/cua-yutori": "0.1.0",
"@onkernel/sdk": "0.49.0",
"smol-toml": "1.5.1"
},
Expand Down
29 changes: 10 additions & 19 deletions packages/cua-cli/src/action/runner.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import type { Agent, AgentEvent } from "@mariozechner/pi-agent-core";
import type { SessionManager } from "@mariozechner/pi-coding-agent";
import type { Agent, AgentEvent } from "@onkernel/cua-agent";
import { type BrowserSession, ComputerTranslator } from "@onkernel/cua-translator";
import { writeFile } from "node:fs/promises";
import { stderr, stdout } from "node:process";
import { promptWithScreenshot } from "../agent-prompt";
import { type CuaAgentHandle, createCuaAgent } from "../agent";
import type { Config } from "../config";
import { persistAgentEvents, seedAgentFromSession } from "../sessions";
import type { CuaSessionState } from "../sessions";
import { type ActionRequest, buildPrompt, DEFAULT_MAX_TURNS } from "./prompts";
import { type ActionEventInfo, type ActionResult, exitCodeFor, formatCompact, parseResult } from "./result";

Expand All @@ -18,11 +17,10 @@ export interface RunOptions {
verbose?: boolean;
maxTurns?: number;
/**
* Optional SessionManager. When supplied, prior turns are seeded into
* the agent transcript and new messages are persisted as they emit.
* Used when chaining action subcommands via `-s <name>`.
* Optional harness-native session state, used when chaining action
* subcommands via `-s <name>`.
*/
sessionManager?: SessionManager;
sessionState?: CuaSessionState;
}

export interface ScreenshotOutput {
Expand Down Expand Up @@ -54,22 +52,16 @@ export async function runAction(
}

const prompt = buildPrompt(req);
const handle = createCuaAgent({
const handle = await createCuaAgent({
cwd: opts.cwd,
browser: opts.browser,
config: opts.config,
session: opts.sessionState,
modelId: opts.modelId,
sessionId: opts.browser.sessionId,
});

let unsubscribePersist: (() => void) | undefined;
let resumed = false;
if (opts.sessionManager) {
seedAgentFromSession(handle.agent, opts.sessionManager);
unsubscribePersist = persistAgentEvents(handle.agent, opts.sessionManager);
resumed = handle.agent.state.messages.some((m) => m.role === "user" || m.role === "assistant");
}
const initialMessageCount = handle.agent.state.messages.length;
const resumed = opts.sessionState?.resumed === true;
const initialMessageCount = opts.sessionState?.priorMessageCount ?? handle.agent.state.messages.length;

const events: ActionEventInfo[] = [];
const maxTurns = req.maxTurns ?? opts.maxTurns ?? DEFAULT_MAX_TURNS;
Expand Down Expand Up @@ -104,7 +96,6 @@ export async function runAction(
runError = err instanceof Error ? err : new Error(String(err));
} finally {
unsubscribe();
unsubscribePersist?.();
}

const elapsed = Date.now() - startedAt;
Expand Down Expand Up @@ -173,7 +164,7 @@ function extractLatestToolError(messages: readonly unknown[]): string | undefine
}

function collectEvent(
event: { type: "tool_execution_start"; toolName: string; args: any },
event: { type: "tool_execution_start"; toolName: string; args: unknown },
events: ActionEventInfo[],
): void {
switch (event.toolName) {
Expand Down
2 changes: 1 addition & 1 deletion packages/cua-cli/src/agent-prompt.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Agent, AgentMessage } from "@mariozechner/pi-agent-core";
import type { Agent, AgentMessage } from "@onkernel/cua-agent";
import type { ImageContent, TextContent } from "@mariozechner/pi-ai";
import type { ComputerTranslator } from "@onkernel/cua-translator";

Expand Down
Loading
Loading