Skip to main content
Deploy single or multi-agent systems as HTTP REST API servers.

Quick Start

1

Install Dependencies

2

Set API Key

3

Initialize Agents

4

Start Server (localhost)

Expected Output:
5

Start Server (public bind)

A non-localhost host requires an API key:
6

Verify

Security

praisonai serve agents drives YAML-defined tools (including execute_command), so binding it to a non-localhost interface without authentication is refused.
Binding to any host other than 127.0.0.1 / localhost requires an API key. The server exits immediately (SystemExit) if neither --api-key nor PRAISONAI_SERVE_API_KEY is set.
Clients then send the key in the Authorization: Bearer … header (mirrors jobs/server.py).

Python - Single Agent

Expected Output:

Cleaning up .launch() endpoints

Call Agent.close() when you’re done serving an agent — the launched HTTP endpoint is torn down, its route is removed from the FastAPI app, and the cached OpenAPI schema is invalidated so /docs and /openapi.json no longer advertise it. Only the agent’s own POST route on that path is dropped; other verbs bound to the same path (e.g. the built-in GET /health) are preserved.
Prior to PR #3810, Agent.close() cleaned an unrelated registry — the launched endpoint stayed live and the request handler kept the agent object graph alive.

Python - Multi-Agent

Expected Output:
Multiple Agent / Agents instances may call .launch(port=N) concurrently from different threads — registration is atomic. If two launch calls use the same path on the same port, the second gets an auto-suffixed path (/path_abc123) and a warning is logged. Server readiness is signalled deterministically (no fixed sleep); .launch() returns only after the port is accepting connections. The wait defaults to 5 seconds and is configurable via the PRAISONAI_SERVER_READY_TIMEOUT environment variable. If the server doesn’t become ready in time, .launch() still returns and a warning is logged — check server logs for startup errors.

agents.yaml

CLI Commands

launch() Parameters

Endpoints

/agents and /agents/{agent_name} share one pipeline. The named-agent route previously used a hand-rolled agent that dropped every safety/reliability field; both routes now apply identical YAML lowering.

Example Request/Response

Request:
Response:

Remote Access

Use host="0.0.0.0" to allow remote connections. For praisonai serve agents, a non-localhost bind requires an API key (see Security):
praisonai serve agents --host 0.0.0.0 without --api-key / PRAISONAI_SERVE_API_KEY exits immediately with SystemExit. Set a key before binding remotely.
Connect from remote (include the Bearer key when serving agents):

How It Works

The agents server builds one shared generator per app at startup, then builds a lightweight per-request generator for each call that borrows the cached generator’s warm pieces.
  • Generator cached per app. A FastAPI lifespan builds a single AgentsGenerator at startup and close()s it at shutdown — no per-request YAML re-parse, framework re-resolution, or fresh 32-worker tool-timeout pool on every call.
  • Truly concurrent. Each request builds a lightweight per-request AgentsGenerator that carries its own cli_config and borrows the cached generator’s warm, immutable pieces (adapter, config_list, tool_resolver, tool-timeout thread pool). Concurrent requests never share mutable state and are not serialised — throughput now scales with the event loop.
  • Cached pool ownership. The cached generator still owns and shuts down the tool-timeout thread pool at app shutdown; per-request generators treat it as borrowed and delegate leak accounting / recycling back to the owner (_get_tool_timeout_executor, _note_leaked_worker, _timeout_owner_key).
  • Graceful fallback. If the cached generator can’t be built, the server falls back to the per-request praisonai.arun path.
  • Route convergence. Both /agents and /agents/{agent_name} run through the same YAML lowering (ToolResolver, tool_timeout, approval, guardrails, retry policy). POST /agents/{agent_name} returns 404 for an unknown name.
What changed in PR #3812. The per-app asyncio.Lock that used to serialise every request on the shared cli_config is gone. Each request now runs on its own per-request AgentsGenerator that borrows the cached generator’s warm pieces, so concurrent requests are no longer serialised. Behaviour is otherwise unchanged — same routes, same YAML pipeline.

Environment Variables

Troubleshooting