# How ego-lite's Code-Based Function Call Interface Improves Agent Interaction

> Discover how ego-lite's code-based function call interface simplifies agent interaction. Experience deterministic browser automation without CDP complexity.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: deep-dive
- Published: 2026-07-31

---

**TLDR:** ego-lite replaces raw Chrome DevTools Protocol (CDP) messages with a high-level JavaScript API that injects helpers like `page`, `locator`, and `taskSpaces` directly into the agent's execution context, enabling deterministic, retry-aware browser automation without protocol complexity.

ego-lite is an open-source browser automation framework from citrolabs that abstracts low-level browser protocols into developer-friendly JavaScript helpers. Instead of forcing agents to construct and manage raw CDP JSON messages, the **ego-lite code-based function call interface** exposes a structured API that handles session management, element resolution, and error recovery automatically. This approach transforms imperative protocol commands into declarative function calls that run inside a heredoc execution context.

## Central Helper Façade (helperContext)

The foundation of the interface is `helperContext()`, defined in **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)** (lines 22-36), which aggregates all public helpers into a single object. This façade groups functionality into six primary domains:

- **page** – A Playwright-style API for navigation, evaluation, screenshots, and input simulation
- **locator** – Chainable, auto-waiting element selectors that handle stability checks internally
- **browser** – Tab management operations including listing, switching, opening, and closing contexts
- **taskSpaces** – Isolated browsing contexts with ownership semantics for concurrent workflows
- **site** – Learned site-skill discovery and execution for domain-specific automation
- **fetch** – Unified HTTP client for both server-side and browser-side requests

Each helper is implemented as a pure function that internally coordinates CDP calls, session caching, and error handling. Agents never interact directly with protocol internals; they invoke high-level methods like `await page.goto(url)` while the runtime manages the underlying complexity.

## Automatic Injection into Global Scope

When the ego-lite runtime initializes, `installEgoSdk()` in **[`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts)** (lines 51-73) automatically injects these helpers into the agent's global scope (typically `globalThis`). The installation process follows a specific readiness pattern:

1. **Synchronous helpers** (enumerated in `SYNC_HELPERS` and `SYNC_FACTORY_HELPERS`) such as `help` and `page.locator` are available immediately
2. **Asynchronous helpers** are wrapped via `wrapReady()` (lines 164-168) to defer execution until the runtime signals readiness

The injection mechanism ensures that within any heredoc script, agents can reference `page`, `locator`, `taskSpaces`, and other utilities without import statements or boilerplate setup. This design choice eliminates configuration overhead and guarantees that the full API surface is available consistently across execution contexts.

## Synchronous vs Asynchronous Helper Design

The interface carefully distinguishes between synchronous and asynchronous operations to prevent event-loop blocking while maintaining ergonomics. As implemented in **[`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts)** (lines 24-30), the `wrapReady` function checks helper categories:

- **Synchronous**: Returns the original value immediately for utilities like help text or factory methods
- **Asynchronous**: Returns a Promise-based wrapper that first awaits the runtime's "ready" state before executing the underlying CDP command

This separation allows agents to write natural async/await patterns (`await locator.click()`) while the runtime handles the complexity of session initialization and protocol handshake in the background.

## High-Level Abstractions Hiding CDP Intricacies

The code-based interface translates low-level browser operations into composable, typed functions that reduce protocol errors and script verbosity.

### Locator Abstraction

The `createLocator()` function in **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)** (lines 520-610) transforms selector strings into intelligent query engines. It supports "nth" indexing, filtering, and role-based queries while automatically implementing retry logic and element stability checks. Agents write `await page.getByRole('button', { name: /submit/i }).click()` instead of managing DOM node IDs or CDP node resolution chains.

### Task-Space Management

The `taskSpaces` façade encapsulates complex CDP session lifecycle management. Methods like `useOrCreate()` and `complete()` (defined in **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)** lines 86-118) handle context creation, ownership claiming, and hand-off protocols. Agents can isolate multi-step workflows without manually manipulating browser targets or debugging session leaks.

### Site-Skill Integration

Learned site-specific capabilities are exposed through the `site` helper, which loads skill definitions from **[`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts)**. Functions like `site.runTool()` and `site.runBrowserTool()` provide first-class access to domain-specific automation patterns while the underlying module loader and sandbox execution remain hidden from the agent.

## Consistent Output Handling

`installEgoSdk()` configures a buffered logging system via `createBufferedLog()` in **[`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts)** (lines 67-73) that intercepts `console.log` output. Rather than streaming logs immediately, the system accumulates entries and flushes them once the agent script completes. This ensures that agent-generated output is captured reliably and can be combined with runtime status messages without interleaving or corruption.

## Practical Code Example

The following script can be run as an ego-lite heredoc (no imports needed):

```javascript
// Navigate and wait for full load
await page.goto('https://example.com', { waitUntil: 'load' });

// Chain locators with automatic waiting
await page.getByRole('button', { name: /login/i }).click();

// Build complex interactions through method chaining
const loginForm = page.locator('form#login');
await loginForm.getByLabel('Email').fill('agent@example.com');
await loginForm.getByLabel('Password').fill('s3cr3t');
await loginForm.locator('button[type=submit]').click();

// Execute learned site-specific tools
await site.runTool('example.com', 'extractProfile');

// Isolate workflow in dedicated task space
await taskSpaces.useOrCreate('profile-scrape');
await page.goto('https://example.com/profile');
const name = await page.locator('h1').innerText();
await taskSpaces.complete('profile-scrape', { keep: true });

console.log('Finished, name =', name);

```

## Summary

- **helperContext()** in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) aggregates six helper categories into a unified façade
- **installEgoSdk()** automatically injects helpers into `globalThis`, eliminating setup boilerplate
- **wrapReady()** manages the distinction between synchronous utilities and asynchronous CDP operations
- **Locator abstraction** via `createLocator()` handles element resolution, retries, and stability checks internally
- **Task spaces** provide isolated browsing contexts through simple function calls rather than manual session management
- **Buffered logging** ensures reliable output capture without streaming complexity

## Frequently Asked Questions

### What files implement the core function call interface?

The primary implementation resides in **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)**, which exports the `helperContext()` façade and all public helpers. **[`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts)** handles the injection mechanism through `installEgoSdk()`. Low-level driver implementations in **`src/driver/*.ts`** (including [`pointer.ts`](https://github.com/citrolabs/ego-lite/blob/main/pointer.ts), [`keyboard.ts`](https://github.com/citrolabs/ego-lite/blob/main/keyboard.ts), and [`nav.ts`](https://github.com/citrolabs/ego-lite/blob/main/nav.ts)) provide the underlying CDP coordination that the high-level API consumes.

### How does ego-lite handle element selection compared to raw CDP?

Instead of requiring agents to construct CDP node resolution chains or manage element IDs, ego-lite exposes the **locator** helper with methods like `getByRole()`, `getByLabel()`, and `locator()`. These methods, implemented in `createLocator()` within [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts), automatically handle selector parsing, element stability waiting, and retry logic, reducing the likelihood of flaky scripts due to timing issues.

### Can agents use these helpers synchronously or only with await?

The interface supports both patterns. **Synchronous helpers** such as `help` and locator factories are enumerated in `SYNC_HELPERS` and available immediately. All other helpers return Promises and must be awaited. The `wrapReady()` function in [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) enforces this distinction, ensuring that async helpers wait for runtime initialization before executing underlying CDP commands.

### What happens to console output from agent scripts?

`installEgoSdk()` redirects `console.log` to a buffered sink created by `createBufferedLog()` in [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts). Output accumulates during script execution and flushes only upon completion, preventing interleaving with runtime status messages and ensuring that structured logging remains intact for downstream processing.