HTTP API (OpenAI-compatible)
HTTP API (OpenAI-compatible)
LevPRO AI runtime can expose an OpenAI-compatible HTTP API for host applications. Chat runs through SessionRunner (same path as CLI / stdio). Streaming uses SSE with AgentLoop events (parity with stdio_protocol.md) plus OpenAI chat.completion.chunk frames for text deltas.
Requires the optional extra:
pip install "local-ai-core[http]"
Launch
local-ai serve-http --config config.yaml
CLI overrides (optional):
--host HOST
--port PORT
--bearer-token TOKEN
--mcp-config PATH
Supervisors and ctx.startup() run eagerly at process start (unlike lazy serve-stdio).
Configuration
http:
host: 127.0.0.1 # default
port: 8080 # default
bearer_token: null # when set, require Authorization: Bearer <token>
Port collision: http.port must differ from llama.models.*.port (llama-server). The example config uses Core on 8080 and llama-server on 8081.
When bearer_token is set, /v1/* endpoints require a matching Bearer token. /health stays open for probes.
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/health |
no | Liveness / readiness (llama health, circuit, degradation) |
GET |
/v1/models |
if token set | Lists config agents as OpenAI model objects |
POST |
/v1/chat/completions |
if token set | Agent turn (OpenAI body + Local AI extensions) |
POST /v1/chat/completions
Request (OpenAI + extensions):
| Field | Type | Default | Description |
|---|---|---|---|
model |
string | first agent | Agent name from agents: |
messages |
array | required | OpenAI messages; only the last user message is appended — prior turns come from SessionStore |
stream |
bool | false |
SSE when true |
user |
string | default_user |
Session user_id |
session_id |
string | random 8-char | Session id |
resume |
bool | false |
Resume L2 checkpoint |
approve_execution |
bool | false |
Auto-approve gated tools for this request |
Multimodal: last user content may be a string or an array of {type: text|image_url} parts (same as stdio).
Non-stream response: OpenAI chat.completion object plus:
"local_ai": {
"session_id": "...",
"trace_id": "...",
"warnings": [],
"degradation_tier": "NORMAL"
}
Stream (stream: true): text/event-stream
- Named AgentLoop events (stdio parity), e.g.:
event: run_start
data: {"user_input":"...","trace_id":"..."}
event: llm_chunk
data: {"step":0,"delta":"Hello"}
event: tool_start
data: {"step":1,"tool":"...","args":{...}}
event: final
data: {"step":2,"response":"..."}
- For each
llm_chunk, also an OpenAI chunk (object: chat.completion.chunk,delta.content) so standard OpenAI clients receive text.
- After the run: OpenAI final chunk (
finish_reason: stop),event: result(completion + stdio-shaped fields), thendata: [DONE].
Client disconnect sets the run cancel_event (same idea as stdio cancel).
AgentLoop event names match stdio — see stdio_protocol.md (run_start, memory_start, llm_start, llm_chunk, llm_done, tool_start, tool_done, final, loop_abort, …).
Errors
OpenAI-style body:
{"error": {"message": "...", "type": "invalid_request_error", "param": null, "code": "..."}}
Example
# Non-stream
curl http://127.0.0.1:8080/v1/chat/completions `
-H "Content-Type: application/json" `
-d '{"model":"assistant","messages":[{"role":"user","content":"Hello"}],"session_id":"demo1"}'
# Stream
curl -N http://127.0.0.1:8080/v1/chat/completions `
-H "Content-Type: application/json" `
-d '{"model":"assistant","messages":[{"role":"user","content":"Hello"}],"stream":true}'
With auth:
curl http://127.0.0.1:8080/v1/models -H "Authorization: Bearer YOUR_TOKEN"
Out of scope
- OpenAI embeddings / images / audio endpoints
- OpenAI function-calling protocol (tools stay inside the ReAct loop; they appear as AgentLoop
tool_*SSE events) - TLS termination (bind locally; put a reverse proxy in front if needed)
See also bootstrap.md, api/interfaces.md.