Skip to main content

Shared FastAPI surface for the H Agent Platform agents API

Project description

hai-agent-api

Shared FastAPI surface for the agents API. This package defines the HTTP routes, request/response models, and authentication dependencies. Your application supplies the backing logic by implementing the service protocols and passing them to create_router.

Install

uv pip install hai-agent-api

You also need an ASGI server to run locally, for example:

uv pip install "uvicorn[standard]"

Quick start

hai-agent-api does not ship a runnable server. Wire the router into your own FastAPI app and provide implementations for all five services.

# app.py
from agent_api import ApiConfig, AuthConfig, Services, create_router
from agent_api.user import ApiUser
from agent_interface.specs.skill import Skill
from agp_types import Page, PageRequest
from fastapi import FastAPI, HTTPException

# ---------------------------------------------------------------------------
# Example service implementations
# ---------------------------------------------------------------------------

class InMemorySkillService:
    """Minimal skill catalog backed by an in-memory dict."""

    def __init__(self) -> None:
        self._skills: dict[str, Skill] = {}

    async def create_skill(self, user: ApiUser, create: Skill) -> Skill:
        if create.name in self._skills:
            raise HTTPException(status_code=409, detail=f"Skill {create.name!r} already exists.")
        self._skills[create.name] = create
        return create

    async def get_page(
        self,
        user: ApiUser,
        page_request: PageRequest,
        *,
        name: str | None = None,
        search: str | None = None,
    ) -> Page[Skill]:
        items = list(self._skills.values())
        if name:
            items = [s for s in items if name.lower() in s.name.lower()]
        if search:
            q = search.lower()
            items = [s for s in items if q in s.name.lower() or q in (s.description or "").lower()]
        return Page[Skill](items=items, page=page_request.page, size=page_request.size, total=len(items))

    async def get_skill(self, user: ApiUser, name: str) -> Skill:
        skill = self._skills.get(name)
        if skill is None:
            raise HTTPException(status_code=404, detail=f"Skill {name!r} not found.")
        return skill

    async def update_skill(self, user: ApiUser, name: str, update: Skill) -> Skill:
        if update.name != name:
            raise HTTPException(status_code=422, detail="update.name must match the path name.")
        if name not in self._skills:
            raise HTTPException(status_code=404, detail=f"Skill {name!r} not found.")
        self._skills[name] = update
        return update

    async def delete_skill(self, user: ApiUser, name: str) -> None:
        if name not in self._skills:
            raise HTTPException(status_code=404, detail=f"Skill {name!r} not found.")
        del self._skills[name]


class StubService:
    """Placeholder for services you have not implemented yet."""

    def __getattr__(self, name: str):
        async def _not_implemented(*_args, **_kwargs):
            raise HTTPException(status_code=501, detail=f"{name} is not implemented.")

        return _not_implemented


# ---------------------------------------------------------------------------
# FastAPI app
# ---------------------------------------------------------------------------

app = FastAPI(title="agents-api", version="0.0.0")

services = Services(
    agents=StubService(),
    environments=StubService(),
    skills=InMemorySkillService(),
    sessions=StubService(),
    memories=StubService(),
)

app.include_router(
    create_router(
        services,
        config=ApiConfig(auth=AuthConfig(mode="local")),
    ),
    prefix="/api",
)

Run the server:

uvicorn app:app --reload --port 8000

Open the interactive docs at http://localhost:8000/docs. Skill endpoints are available under /api/v2/skills; unimplemented services return 501 Not Implemented.

Try a request

curl -s -X POST http://localhost:8000/api/v2/skills \
  -H 'Content-Type: application/json' \
  -d '{"name": "my-skill", "description": "Example", "body": "Do the thing."}' | jq

Service protocols

Implement these protocols (structural typing—no base class required) and pass them in a Services container:

Protocol Router prefix Responsibility
AgentServiceProtocol /v2/agents Agent catalog CRUD and spec resolution
EnvironmentServiceProtocol /v2/environments Environment catalog CRUD
SkillServiceProtocol /v2/skills Skill catalog CRUD
SessionServiceProtocol /v2/sessions Agentic session lifecycle, events, quota
MemoryServiceProtocol /v2/memories Per-org key/value memory (hidden from OpenAPI)

Full method signatures live in agent_api.services.protocols. Raise fastapi.HTTPException for expected client errors (404, 409, 422, etc.). Session creation may raise agent_api.exceptions.IdempotencyKeyConflict; the sessions router maps that to HTTP 422.

Configuration

ApiConfig controls router behaviour:

Field Default Purpose
long_poll_max_wait_for_seconds 60 Upper bound for long-poll on /sessions/{id}/changes
session_share_url_template /share/api/v1/trajectories/{session_id} Template for public share links
auth AuthConfig(mode="platform") How requests are authenticated (see below)

Authentication

Pass AuthConfig via ApiConfig.auth when calling create_router:

Mode Use case Behaviour
platform Agent Platform (default) Requires X-User-Sub and X-User-Org headers injected by the gateway; returns 401 when missing
local Local development / standalone apps Protected routes accept optional identity headers and fall back to default UUIDs when omitted

Local mode defaults:

Field Default
default_user_id 00000000-0000-0000-0000-000000000001
default_org_id 00000000-0000-0000-0000-000000000002
default_email local-dev@example.com

Override headers when you need a specific identity:

curl -s http://localhost:8000/api/v2/skills \
  -H 'X-User-Sub: 11111111-1111-1111-1111-111111111111' \
  -H 'X-User-Org: 22222222-2222-2222-2222-222222222222'

Agent Platform keeps the default platform mode—no change required in production wiring.

API layout

create_router returns a router with this structure:

/v2/sessions/...
/v2/memories/...
/v2/skills/...
/v2/environments/...
/v2/agents/...

Mount it under your chosen prefix (commonly /api, yielding /api/v2/...).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hai_agent_api-0.1.3-py3-none-any.whl (51.7 kB view details)

Uploaded Python 3

File details

Details for the file hai_agent_api-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: hai_agent_api-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 51.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hai_agent_api-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 bc08febbdb31714f37df951403d7302b4f12136a3557e5824c663c54ed246162
MD5 984a7b922ec1840fcd80ff6462d7b398
BLAKE2b-256 43340eb773beb7340c9462770cdddd796d2da63ae4aad2e9fb650ff41958e5ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for hai_agent_api-0.1.3-py3-none-any.whl:

Publisher: publish-agent-api-pypi.yaml on hcompai/agent_platform

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page