Agent Server API¶
kavalai.server serves a workflow over HTTP. A router built from a
WorkflowEngine exposes the workflow’s own input and output
types as the request and response schemas, so the endpoints are typed by the
graph rather than by hand:
Endpoint |
What it does |
|---|---|
|
Runs the workflow and returns the final output in one response. |
|
Runs the workflow and streams progress as Server-Sent Events; each frame
is a |
|
Returns the workflow graph (used by the backoffice to render it). |
|
Liveness and readiness (readiness also checks the database). |
Both run endpoints accept an optional session_id to continue a conversation,
or an external_id to let the caller key a session by its own identifier.
HTTP basic auth is optional and configured from the environment
(KAVALAI_AGENT_BASIC_AUTH_USER / KAVALAI_AGENT_BASIC_AUTH_PASSWORD).
Streaming a run over SSE¶
POST /stream_agent drives run_stream() and
renders each event as an SSE frame — event: carries the event type and
data: its JSON payload. A : ping comment frame is emitted during silent
stretches (a long tool call, say) so proxies do not drop the connection.
Two consequences of SSE are worth planning for. A response cannot change its
status code once the headers are sent, so a failed run ends the stream after a
workflow_failed event instead of returning an error status — clients must
treat that event as the failure signal. And disconnecting aborts the run:
closing the stream cancels the engine generator, which records the abort on the
run row.
Because the endpoint is a POST with a JSON body, browsers cannot consume it
with EventSource (which supports neither a request body nor auth headers) —
use fetch() with a streaming reader. From Python, use
stream_agent(), which yields each data:
payload as it arrives:
from pydantic import BaseModel
from kavalai.client import AgentClient
class Message(BaseModel):
user_message: str
client = AgentClient("http://localhost:8000")
async for chunk in client.stream_agent(Message(user_message="Hi there")):
print(chunk)
See WorkflowStreamEvent for the event contract
and Workflows for which nodes emit content events.
Server¶
Launch Kaval.AI agent REST server.
SSE_PING_INTERVAL_SECONDS is how long a stream may stay silent before a
keepalive comment is sent. SSE_HEADERS are the response headers every SSE
stream carries: no caching, and no buffering by a reverse proxy.
PUBLIC_FAILURE_MESSAGE is what public_events() sends in place of a
failed run’s error text.
Copyright 2026 OÜ KAVAL AI (registry code 17393877)
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
-
class kavalai.server.AgentRequest(*, session_id: UUID | None =
None, external_id: str | None =None, data: InputT)[source]¶ Bases:
BaseModel,Generic[InputT]The request body of
POST /run_agentandPOST /stream_agent.datais the workflow’s own input type.session_idcontinues a session by its id;external_idcontinues — or starts — the session carrying the caller’s own key. A host that serves a workflow from a route of its own types the body asAgentRequest[MyInput], so its clients speak the same protocol as the SDK’s router.- data : InputT¶
-
model_config : ClassVar[ConfigDict] =
{}¶ Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- kavalai.server.public_events(event: WorkflowStreamEvent) WorkflowStreamEvent | None[source]¶
An event filter for streams served to people other than the operator.
Forwards the run lifecycle and the streamed content, and withholds what only the operator should see:
node_started/node_completedevents, which describe the workflow’s internals;token usage;
the reason attached to a
restart;the error text of a failed run, which can carry a provider’s message. It is replaced by
PUBLIC_FAILURE_MESSAGEand the run id, so a report can be matched to the recorded run; the detail stays in the server log and on the run row.
Which nodes stream content at all is the workflow’s
stream_outputsetting, not this filter’s.
- kavalai.server.validate_auth(credentials: HTTPBasicCredentials | None)[source]¶
Validate HTTP Basic Authentication.
Authentication is disabled if KAVALAI_AGENT_BASIC_AUTH_USER and KAVALAI_AGENT_BASIC_AUTH_PASSWORD are not set in the environment.
- kavalai.server.session_scope(session_or_factory)[source]¶
Provide a database session from either a sessionmaker or an existing session.
This context manager ensures that if a factory is provided, a new session is created and closed properly. If an existing session is provided, it is used as-is.
-
async kavalai.server.handle_agent_run(engine: WorkflowEngine, session_provider: async_sessionmaker | None, input_data: dict, session_id: UUID | None =
None, external_id: str | None =None)[source]¶ Execute the agent workflow with the provided input.
This is a standalone handler that can be used directly or wrapped in a FastAPI route.
- Parameters:¶
- engine: WorkflowEngine¶
The v2 WorkflowEngine to execute.
- session_provider: async_sessionmaker | None¶
An optional SQLAlchemy async_sessionmaker for database sessions (unused, kept for compatibility).
- input_data: dict¶
The input data for the workflow (already extracted from request).
- session_id: UUID | None =
None¶ Optional session ID for continuing a previous session.
- external_id: str | None =
None¶ Optional external identifier for tracking.
- Returns:¶
A tuple of (session_id, output_data).
- kavalai.server.format_sse_event(event: WorkflowStreamEvent) str[source]¶
Render one WorkflowStreamEvent as an SSE frame.
-
async kavalai.server.stream_sse_events(events: AsyncIterable[WorkflowStreamEvent], ping_interval: float =
15.0, *, event_filter: Callable[[WorkflowStreamEvent], WorkflowStreamEvent | None] | None =None) AsyncGenerator[str, None][source]¶ Format a workflow event stream as SSE frames with keepalive pings.
A
: pingcomment frame is emitted whenever no event arrives withinping_intervalseconds (silent stretches such as long tool calls), so proxies don’t drop the connection. AWorkflowExceptionfrom the engine ends the stream quietly — the engine has already emitted theworkflow_failedevent, and an SSE response cannot change its status code after the headers are sent.event_filtersees every event before it is written, and returns the event to send, a modified copy, orNoneto drop it. Seepublic_events().The event stream is consumed by a single pump task (an async generator’s frames must run in one task — the engine binds task-scoped log context), while this generator races the queue against the ping timer. Closing this generator cancels the pump, which aborts the workflow run.
-
kavalai.server.sse_response(events: AsyncIterable[WorkflowStreamEvent], *, event_filter: Callable[[WorkflowStreamEvent], WorkflowStreamEvent | None] | None =
None, headers: dict[str, str] | None =None, ping_interval: float =15.0) StreamingResponse[source]¶ Serve a workflow event stream as a Server-Sent Events response.
What the router’s
/stream_agentreturns, available to a host that serves a workflow from a route of its own — behind its own admission checks — so the frames, the keepalive and the headers stay the SDK’s.headersare added toSSE_HEADERS.
- kavalai.server.create_default_auth_dependency() Callable[source]¶
Create the default HTTP Basic Auth dependency using environment variables.
- Returns:¶
A FastAPI dependency function that validates HTTP Basic Authentication.
-
kavalai.server.create_agent_router(engine: WorkflowEngine, session_provider: async_sessionmaker | None =
None, auth_dependency: Callable | None =None, *, event_filter: Callable[[WorkflowStreamEvent], WorkflowStreamEvent | None] | None =None) APIRouter[source]¶ Create a FastAPI router for a given workflow.
This function creates a reusable router that can be mounted on existing FastAPI applications, allowing for flexible composition and custom routing configurations.
The router serves
POST /run_agent(blocking) andPOST /stream_agent(SSE), both typed by the workflow’s own input and output data types, plusGET /workflow,GET /livenessandGET /health.- Parameters:¶
- engine: WorkflowEngine¶
The
WorkflowEngineinstance to serve.- session_provider: async_sessionmaker | None =
None¶ An optional SQLAlchemy async_sessionmaker to provide database sessions for agent execution.
- auth_dependency: Callable | None =
None¶ An optional FastAPI dependency for authentication. If None, the default HTTP Basic Auth will be used. Pass a custom dependency function to use your own auth, or pass
lambda: Noneto disable authentication.- event_filter: Callable[[WorkflowStreamEvent], WorkflowStreamEvent | None] | None =
None¶ Applied to every event
/stream_agentsends. Passpublic_events()when the stream is served to people other than the operator./run_agentreturns only the output, so it is unaffected.
- Returns:¶
An APIRouter instance with configured endpoints.
Example
# Use with custom auth def my_auth(): # Custom auth logic pass router = create_agent_router(engine, session_provider, auth_dependency=my_auth) app.include_router(router, prefix="/agents/my-workflow") # Or disable auth entirely router = create_agent_router(engine, session_provider, auth_dependency=lambda: None)
-
kavalai.server.create_agent_app(engine: WorkflowEngine, session_provider: async_sessionmaker | None =
None, auth_dependency: Callable | None =None, *, event_filter: Callable[[WorkflowStreamEvent], WorkflowStreamEvent | None] | None =None) FastAPI[source]¶ Create a FastAPI application for a given workflow.
The application dynamically generates input and output models based on the workflow’s schema and provides endpoints to run the agent and retrieve its configuration.
- Parameters:¶
- engine: WorkflowEngine¶
The
WorkflowEngineinstance to serve.- session_provider: async_sessionmaker | None =
None¶ An optional SQLAlchemy async_sessionmaker to provide database sessions for agent execution.
- auth_dependency: Callable | None =
None¶ An optional FastAPI dependency for authentication. If None, the default HTTP Basic Auth will be used.
- event_filter: Callable[[WorkflowStreamEvent], WorkflowStreamEvent | None] | None =
None¶ Applied to the streamed events; see
create_agent_router().
- Returns:¶
A FastAPI application instance.
- kavalai.server.load_provider_modules(module_names: str) list[str][source]¶
Import modules that register custom LLM, embedding or RAG backends.
Each module is expected to call
register_llm_provider(),register_embedding_provider()orregister_rag_service()at import time. After they are loaded, every dotted registration is resolved, so a mistyped path fails here rather than on the first request that happens to reach that node.- Parameters:¶
- Returns:¶
The module names that were imported, in order.
- Raises:¶
ImportError – A named module could not be imported.
RegistryError – A registration names a path that cannot be resolved.
-
kavalai.server.create_app_from_env_conf(workflow_path: str | None =
None, db_uri: str | None =None, db_schema: str | None =None, pool_size: int | None =None, max_overflow: int | None =None, sql_echo: bool | None =None) FastAPI[source]¶ Create Kavalai server application from environment configuration.
Optional parameters can override the environment variables.
The following environment variables are used:
KAVALAI_AGENT_WORKFLOW_PATH: Path to the workflow YAML file.
KAVALAI_AGENT_SETUP_MODULE: Optional module imported before the workflow is loaded, as a dotted name or a
.pypath. Registers the Python tools and named RAG services the workflow refers to.KAVALAI_DB_URI: Database connection string.
KAVALAI_DB_SCHEMA: Database schema name.
KAVALAI_DB_POOL_SIZE: Database connection pool size (optional, default: 0).
KAVALAI_DB_MAX_OVERFLOW: Database connection pool max overflow (optional, default: 0).
KAVALAI_SQL_ECHO: Whether to log SQL queries (optional, default: False).
KAVALAI_PROVIDER_MODULES: Comma-separated modules to import before the workflow loads, so their backend registrations exist (optional).
KAVALAI_DEFAULT_LLM_MODEL: Model used when the workflow and its nodes name none, passed to the engine as
default_llm_model(optional).KAVALAI_LLM_TEMPERATURE, KAVALAI_LLM_TOP_P, KAVALAI_LLM_REASONING_EFFORT, KAVALAI_LLM_SERVICE_TIER, KAVALAI_LLM_TIMEOUT_SECONDS, KAVALAI_LLM_STREAM_TIMEOUT_SECONDS: fleet-wide defaults for every model call, passed to the engine as
default_llm_parameters(optional).KAVALAI_EMBEDDING_NORMALIZER_YAML: Normalizer installed as the default before the workflow loads (optional).
KAVALAI_RAG_MODEL: Embedding model of the
defaultRAG service. Setting it registers that service without a setup module, over the index at KAVALAI_RAG_URI (required alongside it) in KAVALAI_RAG_SCHEMA (optional), with the normalizer above.KAVALAI_AGENT_PUBLIC_EVENTS: Serve streams through
public_events()(optional, default: false).KAVALAI_AGENT_RUN_TIMEOUT_SECONDS: Seconds after which a run is cancelled and recorded as failed, passed to the engine as
run_timeout(optional, default: no limit).
- Parameters:¶
- workflow_path: str | None =
None¶ Path to the workflow YAML file.
- db_uri: str | None =
None¶ Database connection string.
- db_schema: str | None =
None¶ Database schema name.
- pool_size: int | None =
None¶ Database connection pool size.
- max_overflow: int | None =
None¶ Database connection pool max overflow.
- sql_echo: bool | None =
None¶ Whether to log SQL queries.
- workflow_path: str | None =
- Returns:¶
A FastAPI application instance.