> ## Documentation Index
> Fetch the complete documentation index at: https://hub.hcompany.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> H Platform has four products: the Agents API (managed computer-use agents, base URL https://agp.eu.hcompany.ai/api/v2 or https://agp.hcompany.ai/api/v2 for the US), the Models API (OpenAI-compatible Holo vision-language models at https://api.hcompany.ai/v1), HoloDesktop CLI (Holo on the user's own desktop), and HoloTab (a free no-code Chrome extension that runs Holo in the user's browser, with recordable routines and schedules).
> Authenticate with a bearer API key from the HAI_API_KEY environment variable. SDKs: `pip install hai-agents` (Python, `from hai_agents import Client`) and `npm install hai-agents` (TypeScript, `import { HaiAgentsClient } from "hai-agents"`). CLI: `hai`.
> Agents do work in a browser or on a desktop; describe the task as an imperative instruction. To run a task quickly, prefer the pre-built agent `h/web-surfer-flash`. Read results from the session's `latest_answer` after it reaches a terminal status.
> Sessions are the unit of work; wait for a terminal status (completed, failed, timed_out, interrupted) before reading the answer. Use webhooks or the `changes` long-poll endpoint to follow progress.

# Give an agent custom tools

> Extend the agent's toolbox with functions from your own code: the agent calls them, the SDK executes them, the run continues with the result.

export const CustomToolLoop = () => {
  const stroke = {
    fill: "none",
    stroke: "currentColor",
    strokeWidth: 1.75,
    strokeLinecap: "round",
    strokeLinejoin: "round"
  };
  const S = c => ({
    className: c,
    ...stroke
  });
  const icons = {
    agent: c => <svg viewBox="0 0 24 24" {...S(c)}><path d="M12 8V4H8" /><rect width="16" height="12" x="4" y="8" rx="2" /><path d="M2 14h2M20 14h2M15 13v2M9 13v2" /></svg>,
    code: c => <svg viewBox="0 0 24 24" {...S(c)}><path d="m16 18 6-6-6-6" /><path d="m8 6-6 6 6 6" /></svg>
  };
  const Card = ({icon, title, sub, children}) => <div className="flex shrink-0 flex-col self-center rounded-xl border border-zinc-200 bg-white p-5 dark:border-zinc-800 dark:bg-zinc-950">
      <div className="flex items-center gap-2.5">
        <span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200">{icon("h-5 w-5")}</span>
        <div>
          <div className="whitespace-nowrap text-base font-semibold leading-6 text-zinc-900 dark:text-zinc-100">{title}</div>
          <div className="whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400">{sub}</div>
        </div>
      </div>
      {children}
    </div>;
  const Arrow = ({top, bottom, dir = "right"}) => <div className="flex flex-col items-stretch justify-center gap-1 px-4 text-center text-xs leading-4 text-zinc-500 dark:text-zinc-400">
      {top && <span className="whitespace-nowrap">{top}</span>}
      <div className={`${dir === "left" ? "flex flex-row-reverse items-center text-zinc-400 dark:text-zinc-600" : "flex items-center text-zinc-400 dark:text-zinc-600"}`}>
        <span className="h-px flex-1 bg-current" />
        <svg className="-ml-px h-3 w-2 shrink-0" viewBox="0 0 8 12" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={dir === "left" ? {
    transform: "scaleX(-1)",
    marginLeft: 0,
    marginRight: -1
  } : undefined}>
          <path d="M1 1.5 6 6l-5 4.5" />
        </svg>
      </div>
      {bottom && <span className="whitespace-nowrap">{bottom}</span>}
    </div>;
  const Chip = ({children}) => <span className="whitespace-nowrap rounded-md bg-zinc-100 px-2 py-0.5 font-mono text-xs text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300">{children}</span>;
  return <div className="not-prose my-8 overflow-x-auto">
      <div className="flex min-w-[620px] items-stretch justify-center">
        <Card icon={icons.agent} title="Agent" sub="in a session">
          <div className="mt-4 flex flex-col items-start gap-2 text-sm text-zinc-600 dark:text-zinc-400">
            <div>Needs a tool</div>
            <Chip>awaiting_tool_results</Chip>
            <div>Resumes once every call has a result</div>
          </div>
        </Card>

        <div className="flex min-w-[200px] flex-1 flex-col justify-center gap-6">
          <Arrow top="pending_tool_calls" />
          <Arrow bottom="POST /tool_results" dir="left" />
        </div>

        <Card icon={icons.code} title="Your code" sub="the SDK loop">
          <div className="mt-4 flex flex-col items-start gap-2 text-sm text-zinc-600 dark:text-zinc-400">
            <div>Match <span className="font-mono text-[13px]">tool_name</span></div>
            <div className="flex gap-1.5">
              <Chip>get_order_status()</Chip>
              <Chip>issue_refund()</Chip>
            </div>
            <div>Run it locally, echo <span className="font-mono text-[13px]">tool_req</span></div>
          </div>
        </Card>
      </div>
    </div>;
};

<CustomToolLoop />

The [environment](/agents-api/environments/overview) supplies the agent's core tools. Custom tools are functions from your own code: the agent calls one mid-run, your process executes it, and the run continues with the result.

| | Environment tools | Custom tools |
| - | - | - |
| Examples | Navigate, click, type, scroll | Query your database, call an internal API, look up a customer |
| Defined by | The environment | You, as a function |
| Runs | In the environment | In your process, via the SDK |
| Agent sees | The screen | The return value |

## With the SDKs

Pass your functions via `tools`. Python derives the schema from the signature and docstring. TypeScript declares it with `tool()`. The SDK runs the whole loop.

<CodeGroup>
  ```python Python theme={"system"}
  from hai_agents import Client

  def get_order_status(order_id: str) -> str:
      """Look up the status of an order in our system."""
      return db.orders.get(order_id).status

  client = Client()
  result = client.run_session(
      agent="h/web-surfer-flash",
      messages="Check order 4242 and email the customer if it shipped.",
      tools=[get_order_status],
  )
  print(result.answer)
  ```

  ```typescript TypeScript theme={"system"}
  import { HaiAgentsClient, tool } from "hai-agents";

  const getOrderStatus = tool({
    name: "get_order_status",
    description: "Look up the status of an order in our system.",
    inputSchema: {
      type: "object",
      properties: { order_id: { type: "string" } },
      required: ["order_id"],
    },
    fn: async ({ order_id }) => db.orders.get(order_id).status,
  });

  const client = new HaiAgentsClient();
  const result = await client.runSession({
    agent: "h/web-surfer-flash",
    messages: "Check order 4242 and email the customer if it shipped.",
    tools: [getOrderStatus],
  });
  console.log(result.answer);
  ```
</CodeGroup>

* Functions may be sync or async. Exceptions reach the agent as tool errors and don't crash the run.
* Tools run in the process that polls the session: only while your program waits on `run_session` / `runSession`, or on a handle's `wait_for_completion` / `waitForCompletion` with the same `tools`.
* Execution is at-least-once: if posting a result fails and the wait retries, the tool may run again. Make side-effecting tools idempotent.

## Over the raw API

<Steps titleSize="h3">
  <Step id="declare-tools" title="Declare the tools at session create">
    Declare the tools when [creating the session](/agents-api/sessions/create), inline on the agent or via the `agent.tools` override for a registered agent:

    ```json Session create body theme={"system"}
    {
      "agent": {
        "name": "support-agent",
        "environments": [{ "kind": "web" }],
        "tools": [
          {
            "name": "get_order_status",
            "description": "Look up the status of an order in our system.",
            "input_schema": {
              "type": "object",
              "properties": { "order_id": { "type": "string" } },
              "required": ["order_id"]
            }
          }
        ]
      },
      "messages": "Check order 4242 and email the customer if it shipped."
    }
    ```
  </Step>

  <Step id="detect-call" title="Detect the pending call">
    Long-poll [`changes`](/agents-api/sessions/changes) for an `ActiveStateChangeEvent` whose `data.state` is `"awaiting_tool_results"`. Its `data.pending_tool_calls` lists each pending call as a `{ tool_name, args, id }` object:

    ```json Pending tool call event theme={"system"}
    {
      "type": "ActiveStateChangeEvent",
      "data": {
        "state": "awaiting_tool_results",
        "pending_tool_calls": [
          { "tool_name": "get_order_status", "args": { "order_id": "4242" }, "id": "call_1" }
        ]
      },
      "timestamp": "2026-06-01T15:14:05Z"
    }
    ```
  </Step>

  <Step id="post-result" title="Post the result">
    Execute the call and [post the result](/agents-api/sessions/tool-results), echoing the pending call back as `tool_req`:

    ```bash theme={"system"}
    curl -X POST "https://agp.eu.hcompany.ai/api/v2/sessions/$SESSION_ID/tool_results" \
      -H "Authorization: Bearer $HAI_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"kind": "tool_result", "tool_req": {"tool_name": "get_order_status", "args": {"order_id": "4242"}, "id": "call_1"}, "result": "shipped"}'
    ```

    Send several at once with `{"type": "batch", "results": [...]}`. Report a failure as an `error_event` instead of a `tool_result`. It carries `error`, `origin` (both required), and the echoed `tool_req`:

    ```json Tool error report theme={"system"}
    { "kind": "error_event", "error": "Order not found", "origin": "custom_tools", "tool_req": { "tool_name": "get_order_status", "args": { "order_id": "4242" }, "id": "call_1" } }
    ```

    The agent resumes once every pending call has a result. Calls still unresolved when the run ends (for example on `max_time_s`) fail with a model-visible error. Posting to a finished session returns `409`.
  </Step>
</Steps>

Related: [Two-factor authentication](/agents-api/two-factor-auth) (a built-in tool for one-time codes), [Watch and steer sessions](/agents-api/observe-and-steer)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.