An open API service indexing awesome lists of open source software.

https://github.com/hcompai/hai-agents-python

Python SDK for H Company's Computer-Use Agent API
https://github.com/hcompai/hai-agents-python

Last synced: 19 days ago
JSON representation

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

Awesome Lists containing this project

README

          




Computer-Use Agents


PyPI
Python versions
License: MIT


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


Documentation
 · 
Get an API key
 · 
PyPI
 · 
TypeScript SDK
 · 
H Company

## Installation

```bash
pip install hai-agents
```

Add the optional command-line tools with the `cli` extra:

```bash
pip install "hai-agents[cli]"
```

Python 3.10 or newer is required. Get an API key at [platform.hcompany.ai/settings/api-keys](https://platform.hcompany.ai/settings/api-keys) and export it:

```bash
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. `run_session` polls until the agent finishes and returns the final answer.

```python
from hai_agents import Client

client = Client()

result = client.run_session(
agent="h/web-surfer-pro",
messages="What are the top 3 stories on Hacker News right now?",
)

print(result.status)
print(result.answer)
```

`Client()` reads `HAI_API_KEY` from the environment.

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

## 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. `run_session` creates it and blocks until it settles, which suits one-shot tasks. `start_session` creates it and returns a handle right away, so you can read and steer the agent while it works.

```python
session = client.start_session(
agent="h/web-surfer-pro",
messages="Find the top story on Hacker News",
)

print(session.id)
result = session.wait_for_completion()
print(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:

```python
session.status()
session.changes(from_index=0)
session.get()
```

`status()` is a cheap snapshot with the state, step count, and token usage. `changes(from_index=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:

```python
session.send_message({"type": "user_message", "message": "Only consider the last 24 hours"})
session.pause()
session.resume()
session.force_answer()
session.cancel()
```

`send_message` redirects the agent on its next step and wakes an `idle` session. `pause` halts with state preserved until `resume`. `force_answer` 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 `idle_timeout_s` 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.

```python
session = client.start_session(
agent="h/web-surfer-pro",
idle_timeout_s=600,
messages="Find the top story on Hacker News",
)
first = session.wait_for_completion()

session.send_message({"type": "user_message", "message": "Now summarize its comments"})
second = session.wait_for_completion()
```

## Structured output

Pass a pydantic model as `answer_schema` and the agent's final answer comes back as a validated instance. The model's JSON schema is sent as the agent's answer format; the raw wire value stays at `result.final_changes.answer`.

```python
from pydantic import BaseModel
from hai_agents import Client

class Job(BaseModel):
title: str
company: str

class Jobs(BaseModel):
jobs: list[Job]

client = Client()
result = client.run_session(
agent="h/web-surfer-pro",
messages="Find 3 open ML engineering roles in Paris.",
answer_schema=Jobs,
)

for job in result.answer.jobs:
print(job.title, "@", job.company)
```

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

## Custom tools

Expose your own Python functions to the agent. Pass them to `run_session` and the polling loop runs each one when the agent calls it, then posts the result back so the session continues. Any function with typed parameters and a docstring works; the input schema is derived from the signature.

```python
from hai_agents import Client

def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"Sunny in {city}"

client = Client()

result = client.run_session(
agent="h/web-surfer-pro",
messages="What should I wear in Paris today?",
tools=[get_weather],
)
```

Use the `@tool` decorator to override the name or description:

```python
from hai_agents import tool

@tool(name="lookup_order", description="Look up an order by its id.")
def lookup(order_id: str) -> dict:
return {"id": order_id, "status": "shipped"}
```

A tool that raises is reported to the agent as a tool error rather than crashing the run. With `AsyncClient`, tools may be `async def`.

### Prebuilt: one-time passwords (2FA)

`hai_agents_tools` ships ready-made tools. `otp_tool` 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; `imap_otp_handler` reads the code straight from a mailbox over IMAP (for Gmail, use an app password).

```python
import os

from hai_agents import Client
from hai_agents_tools import imap_otp_handler, otp_tool

handler = imap_otp_handler(
host="imap.gmail.com",
username="agent-inbox@gmail.com",
password=os.environ["GMAIL_APP_PASSWORD"],
)

client = Client()
result = client.run_session(
agent="h/web-surfer-pro",
messages="Log in to example.com and check for new notifications",
tools=[otp_tool(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](https://hub.hcompany.ai/computer-use-agents/browser-profiles) restores saved cookies and storage from an earlier session, and a [vault](https://hub.hcompany.ai/computer-use-agents/vaults) lets the agent sign in to sites with secrets that never enter its context. Bind both through per-run overrides:

```python
result = client.run_session(
agent="h/web-surfer-pro",
messages="Open my dashboard and report any new alerts",
overrides={
"agent.environments[kind=web].browser_profile_id": "",
"agent.environments[kind=web].vault_id": "",
},
)
```

## Async

`AsyncClient` mirrors `Client` for asyncio. Every session method is a coroutine.

```python
import asyncio
from hai_agents import AsyncClient

async def main():
client = AsyncClient()
result = await client.run_session(
agent="h/web-surfer-pro",
messages="What are the top 3 stories on Hacker News right now?",
)
print(result.answer)

asyncio.run(main())
```

## Inspect and share sessions

List past sessions and create a public replay link:

```python
page = client.sessions.list_sessions(size=10)
for summary in page.items:
print(summary.id, summary.status)

link = client.sessions.share_session("")
print(link.share_url)
```

## Regions and configuration

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

```python
from hai_agents import Client, HaiAgentsEnvironment

client = Client(environment=HaiAgentsEnvironment.US)
```

`Client` also accepts a custom `base_url`, and an `api_key` when you do not want to use the environment variable:

```python
client = Client(base_url="https://agp.hcompany.ai", api_key="hk-...")
```

## Errors

```python
from hai_agents import AnswerValidationError, UnprocessableEntityError
from hai_agents.core import ApiError
```

`ApiError` is the base for HTTP failures and carries `.status_code` and `.body`. `UnprocessableEntityError` is the 422 raised when a request fails validation. `AnswerValidationError` is raised when a completed answer does not match `answer_schema`, with the unparsed value on `.raw`.

## Webhooks

Verify the signature on an incoming webhook before trusting it:

```python
from hai_agents import verify_webhook, WebhookVerificationError

event = verify_webhook(request_body, signature, timestamp, secret)
print(event.type, event.data)
```

## Command line

The `cli` extra installs the `hai` command for driving agents from your terminal:

```bash
hai login
hai run "What's the top story on Hacker News?"
hai sessions list
hai sessions watch
hai mcp install
```

`hai login` signs in through the browser and stores a key in `~/.config/hai/.env`. `hai mcp install` adds the hai-agents MCP server to Cursor, VS Code, Claude Code, and other MCP clients. Credentials resolve from `--api-key`, then `HAI_API_KEY`, then a local `.env`, then `~/.config/hai/.env`. Run `hai --help` for the full command set.

## Documentation

Guides, core concepts, and the full API reference live at **[hub.hcompany.ai/computer-use-agents](https://hub.hcompany.ai/computer-use-agents)**.

## License

[MIT](LICENSE)