Skip to content

Repository files navigation

Computer-Use Agents

npm Node version License: MIT

TypeScript SDK for H Company's Computer-Use Agents.

Documentation  ·  Get an API key  ·  npm  ·  Python SDK  ·  H Company

Installation

npm install hai-agents

Node.js 18 or newer is required. Get an API key at platform.hcompany.ai/settings/api-keys and export it:

export HAI_API_KEY=hk-...

Quickstart

Launch the built-in h/web-surfer-pro agent, which ships with its own browser, and describe the task in plain language. runSession polls until the agent finishes and returns the final answer.

import { HaiAgentsClient } from "hai-agents";

const client = new HaiAgentsClient();

const result = await client.runSession({
  agent: "h/web-surfer-pro",
  messages: "What are the top 3 stories on Hacker News right now?",
});

console.log(result.status);
console.log(result.answer);

new HaiAgentsClient() reads HAI_API_KEY from the environment.

result is a SessionRunResult: id, status, answer, the accumulated events, and finalChanges.

How a session works

A session is one run of an agent against a task. It moves through a small set of states: pending, running, and then a settled state such as completed, idle, failed, timed_out, or interrupted.

You drive a session two ways. runSession creates it and resolves once it settles, which suits one-shot tasks. startSession creates it and returns a handle right away, so you can read and steer the agent while it works.

const session = await client.startSession({
  agent: "h/web-surfer-pro",
  messages: "Find the top story on Hacker News",
});

console.log(session.id);
const result = await session.waitForCompletion();
console.log(result.status, result.answer);

Watch and steer a running session

A handle bound to the session id exposes the full lifecycle. Read the agent's progress at three levels of detail:

await session.status();
await session.changes({ fromIndex: 0 });
await session.get();

status() is a cheap snapshot with the state, step count, and token usage. changes({ fromIndex: 0 }) long-polls for new events and the final answer. get() returns the full Session resource.

While the session is not in a terminal state, you can intervene:

await session.sendMessage({ type: "user_message", message: "Only consider the last 24 hours" });
await session.pause();
await session.resume();
await session.forceAnswer();
await session.cancel();

sendMessage redirects the agent on its next step and wakes an idle session. pause halts with state preserved until resume. forceAnswer makes the agent stop exploring and answer from what it has. cancel ends the session as interrupted.

Multi-turn sessions

By default a session ends as soon as the agent answers. Set idleTimeoutS to keep it open: after each answer the session goes idle and waits that long for your next message, carrying its full context and browser state across turns.

const session = await client.startSession({
  agent: "h/web-surfer-pro",
  idleTimeoutS: 600,
  messages: "Find the top story on Hacker News",
});
const first = await session.waitForCompletion();

await session.sendMessage({ type: "user_message", message: "Now summarize its comments" });
const second = await session.waitForCompletion();

Structured output

Pass a Zod v4 schema as answerSchema and the agent's final answer resolves as a parsed, typed value. The schema is sent as the agent's answer format; the raw wire value stays at result.finalChanges.answer. Zod is an optional peer dependency, only needed when you use this.

import { HaiAgentsClient } from "hai-agents";
import { z } from "zod";

const Jobs = z.object({
  jobs: z.array(z.object({ title: z.string(), company: z.string() })),
});

const client = new HaiAgentsClient();
const result = await client.runSession({
  agent: "h/web-surfer-pro",
  messages: "Find 3 open ML engineering roles in Paris.",
  answerSchema: Jobs,
});

for (const job of result.answer?.jobs ?? []) {
  console.log(job.title, "@", job.company);
}

A completed answer that does not match the schema throws AnswerValidationError, with the raw payload on .raw. Sessions that end without completing resolve with their raw answer untouched.

Custom tools

Give the agent tools that run in your own process. Declare each tool with a JSON schema and a function; the SDK registers them on the session, runs them when the agent calls them, and posts the results back so the agent can continue.

import { HaiAgentsClient, tool } from "hai-agents";

const getWeather = tool({
  name: "get_weather",
  description: "Get the current weather for a city.",
  inputSchema: {
    type: "object",
    properties: { city: { type: "string" } },
    required: ["city"],
  },
  fn: async ({ city }) => `Sunny in ${city}, 24C`,
});

const client = new HaiAgentsClient();

const result = await client.runSession({
  agent: "h/web-surfer-pro",
  messages: "What should I wear in Paris today?",
  tools: [getWeather],
});

console.log(result.answer);

Tool functions may be sync or async. A tool that throws is reported to the agent as a tool error rather than crashing the run.

Prebuilt: one-time passwords (2FA)

The SDK ships ready-made tools. otpTool lets the agent ask for a one-time password, verification code, or confirmation link when a login or signup step needs one. Without a handler it prompts on stdin; imapOtpHandler reads the code straight from a mailbox over IMAP (requires the optional dependencies imapflow and mailparser; for Gmail, use an app password).

import { HaiAgentsClient, imapOtpHandler, otpTool } from "hai-agents";

const handler = imapOtpHandler({
  host: "imap.gmail.com",
  username: "agent-inbox@gmail.com",
  password: process.env.GMAIL_APP_PASSWORD!,
});

const client = new HaiAgentsClient();
const result = await client.runSession({
  agent: "h/web-surfer-pro",
  messages: "Log in to example.com and check for new notifications",
  tools: [otpTool({ handler })],
});

Like every custom tool, the handler runs entirely in your process: the IMAP credentials never leave your machine, and the agent only receives the single extracted code or link -- never mailbox contents.

Browser profiles and vaults

Start a session on a browser that already knows the user. A browser profile restores saved cookies and storage from an earlier session, and a vault lets the agent sign in to sites with secrets that never enter its context. Bind both through per-run overrides:

const result = await client.runSession({
  agent: "h/web-surfer-pro",
  messages: "Open my dashboard and report any new alerts",
  overrides: {
    "agent.environments[kind=web].browser_profile_id": "<profile-id>",
    "agent.environments[kind=web].vault_id": "<vault-id>",
  },
});

Inspect and share sessions

List past sessions and create a public replay link:

const page = await client.sessions.listSessions({ size: 10 });
for (const summary of page.items) {
  console.log(summary.id, summary.status);
}

const link = await client.sessions.shareSession({ id: "<session-id>" });
console.log(link.shareUrl);

Regions and configuration

The client targets the EU region by default; pass environment to use the US region instead:

import { HaiAgentsClient, HaiAgentsEnvironment } from "hai-agents";

const client = new HaiAgentsClient({ environment: HaiAgentsEnvironment.Us });

The client also accepts a custom baseUrl, and an apiKey when you do not want to use the environment variable:

const client = new HaiAgentsClient({ baseUrl: "https://agp.hcompany.ai", apiKey: "hk-..." });

Errors

import { HaiAgentsError, HaiAgentsTimeoutError, AnswerValidationError } from "hai-agents";

HaiAgentsError is the base for HTTP failures and carries .statusCode and .body. HaiAgentsTimeoutError is thrown when a request exceeds its time budget. HaiAgents.UnprocessableEntityError is the 422 raised when a request fails validation. AnswerValidationError is thrown when a completed answer does not match answerSchema, with the unparsed value on .raw.

Webhooks

Verify the signature on an incoming webhook before trusting it:

import { verifyWebhook, WebhookVerificationError } from "hai-agents";

const event = verifyWebhook(rawBody, signature, timestamp, secret);
console.log(event.type, event.data);

Documentation

Guides, core concepts, and the full API reference live at hub.hcompany.ai/computer-use-agents.

License

MIT

About

TypeScript SDK for H Company's Computer-Use Agent API

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages