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, install_exception_handlers
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(),
webhooks=StubService(),
)
app.include_router(
create_router(
services,
config=ApiConfig(auth=AuthConfig(mode="local")),
),
prefix="/api",
)
install_exception_handlers(app)
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.). Domain exceptions such as agent_api.exceptions.IdempotencyKeyConflict are mapped to the standard error body when you call install_exception_handlers(app) on your FastAPI app (Agent Platform does this in hplatform.app).
Error responses
All API errors use a single JSON shape:
{
"message": "Human-readable summary",
"detail": ["..."]
}
messageis a short summary string.detailis always an array. For validation failures it contains the usual Pydantic error objects; for application errors it contains objects withtypeandmessage.
Pydantic request validation, HTTPException, and registered domain exceptions are all normalized to this format by install_exception_handlers.
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hai_agent_api-0.1.24-py3-none-any.whl.
File metadata
- Download URL: hai_agent_api-0.1.24-py3-none-any.whl
- Upload date:
- Size: 65.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
403183c40fcca91e1be181552300bd7f1f7508d46d5a40f7d88ddf35b576240e
|
|
| MD5 |
a6ce92b4cf0203a5b63f3fed328640d3
|
|
| BLAKE2b-256 |
eff49423a95ced344093f00c57513dc01e7f5e3c4d5f801e1b22e7109d85ffd0
|
Provenance
The following attestation bundles were made for hai_agent_api-0.1.24-py3-none-any.whl:
Publisher:
publish-agent-api-pypi.yaml on hcompai/agent_platform
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hai_agent_api-0.1.24-py3-none-any.whl -
Subject digest:
403183c40fcca91e1be181552300bd7f1f7508d46d5a40f7d88ddf35b576240e - Sigstore transparency entry: 1870385404
- Sigstore integration time:
-
Permalink:
hcompai/agent_platform@e4aa35d8e1c8c5deddddb19a40445bee3342b519 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/hcompai
-
Access:
internal
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
self-hosted -
Publication workflow:
publish-agent-api-pypi.yaml@e4aa35d8e1c8c5deddddb19a40445bee3342b519 -
Trigger Event:
push
-
Statement type: