Skip to content

Advanced

Bring your own adapter

Implement ModelAdapter for unsupported models:

typescript
import type { ModelAdapter, StepContext, ModelResponse } from "@omxyz/lumen";

class MyAdapter implements ModelAdapter {
  readonly modelId = "my-model";
  readonly provider = "custom";
  readonly nativeComputerUse = false;
  readonly contextWindowTokens = 128_000;

  async step(context: StepContext): Promise<ModelResponse> {
    const res = await myApi.call({ image: context.screenshot.data.toString("base64") });
    return { actions: [{ type: "click", x: 500, y: 300 }], usage: { inputTokens: 1000, outputTokens: 50 }, rawResponse: res };
  }

  async *stream(ctx: StepContext) { for (const a of (await this.step(ctx)).actions) yield a; }
  estimateTokens(ctx: StepContext) { return ctx.wireHistory.length * 200; }
  async summarize(history, state) { return `${history.length} messages`; }
}

Fold action (context compression)

The model can explicitly compress completed sub-tasks:

typescript
systemPrompt: "When you finish a sub-task, call fold with a summary to free context."

Low-level Session API

Bring your own tab and adapter:

typescript
import { Session, CDPTab, CdpConnection, AnthropicAdapter } from "@omxyz/lumen";

const conn = await CdpConnection.connect("ws://localhost:9222/...");
const tab = new CDPTab(conn.mainSession());
const session = new Session({ tab, adapter: new AnthropicAdapter("claude-sonnet-4-6"), maxSteps: 20 });

const result = await session.run({ instruction: "Click the login button." });
conn.close();