UAI is a FastAPI service and CLI that exposes a simple, unified API to run different agent frameworks behind a consistent interface. It loads your agent from a kosmos.toml file and executes it either inline (for dev/tests) or via a Procrastinate worker.
- Install:
pip install -e . - Run API:
uai serve --host 0.0.0.0 --port 8000 - Open docs: visit
http://localhost:8000/docs
uai serve: starts the FastAPI server.uai run create --input '<json or string>': creates a run for the configured agent.uai run list: lists all runs with status and counts.uai run status <task_id>: fetches current run status.uai run input <task_id> --text '<reply>': provides human input to a waiting run.uai run logs <task_id> --message '<msg>' [--level INFO]: appends a log entry.uai run cancel <task_id>/uai run stop <task_id>: cancels/stops a run (deletes it from in-memory storage).uai worker install|check|start: installs schema, checks DB, and starts the worker.uai run watch <task_id>: watches status; whenwaiting_input, prompts for input and resumes automatically.uai chat list: lists chat sessions and message counts.- Global: add
--jsonto any command to output machine-readable JSON (disables rich UI). Forrun watch, JSON mode emits events and final status as JSON lines.
src/unified_agent_interface/app.py: FastAPI app factory.src/unified_agent_interface/api/: Routers for/runand/chat.src/unified_agent_interface/models/: Pydantic models and schemas.src/unified_agent_interface/components/: In-memory storage and run agent shim.src/unified_agent_interface/frameworks/: Runtime adapters (crewai,langchain,callable).src/unified_agent_interface/queue.py: Procrastinate integration and job dispatch.examples/: Callable sample and CrewAI examples (with and without human input).
- See
CHANGELOG.mdfor release notes.
-
Location search order:
KOSMOS_TOMLenv var,./kosmos.toml,./examples/kosmos.toml. -
Example config:
[agent] runtime = "callable" # or "crewai", "langchain", or "custom" entrypoint = "examples.simple_entrypoint:run" # Optional: for custom adapters # adapter = "path.to.module:AdapterClassOrInstance"
-
Entrypoint format:
module:attr(e.g.,examples.crewai_user_input.main:crew). UAI resolves imports relative to thekosmos.tomldirectory and also supports package-style modules. -
Custom adapters: set
agent.adapterto amodule:attrthat resolves to either an instance or a zero-arg class. The adapter must explicitly inheritunified_agent_interface.frameworks.base.RuntimeAdapter. Ifruntimeis unknown or set tocustom, UAI will load this adapter. If both a known runtime and an adapter are specified, the adapter takes precedence.
crewai: Imports aCrewand callscrew.kickoff(inputs=...).- Inputs: pass JSON via
--input '{"topic":"..."}'. Dicts are used as-is; string inputs map to{ "input": "..." }. - Human input: When the Crew calls
input(), UAI sets status towaiting_inputand populatesinput_prompt. Provide input withuai run inputand the run resumes.
- Inputs: pass JSON via
langchain: Imports a LangChainRunnable/LLMChainand callsinvoke(inputs)(orrun(...)fallback).- Inputs: dicts are passed as-is. String inputs map to
{ "text": "..." }. - Output: tries
message.content, then common dict keys (text,output_text,output,result), elsestr(result).
- Inputs: dicts are passed as-is. String inputs map to
callable: Imports a Python callable.- If
--inputis a JSON object, UAI triesfn(**obj), falling back tofn(obj); otherwise it callsfn({"input": "...", "params": {}}).
- If
custom: Provideadapter = "module:attr"inkosmos.toml; UAI imports and uses it for both run and chat if implemented.
- Callable:
examples/simple_entrypoint.pywithexamples/kosmos_callable.toml. - CrewAI (basic):
examples/crewai/main.pywithexamples/crewai/kosmos.toml. - CrewAI (human input):
examples/crewai_user_input/main.pywithexamples/crewai_user_input/kosmos.toml. - LangChain (LLMChain):
examples/langchain/app.pywithexamples/langchain/kosmos.toml. - LangChain with instrumentation (logs around LLM calls): set
KOSMOS_TOML=examples/langchain/kosmos_patched.tomlto useapp:run_patchedwhich patchesLLMChain.invokeandChatOpenAI.invokeviainstrumentation.patch_many. - CrewAI with custom logs/input detection (callbacks):
examples/crewai_custom_log_input_detection/app.pywithexamples/crewai_custom_log_input_detection/kosmos.toml.
GET /run/: lists runs (status snapshot).POST /run/(body:{ "input": <any>, "params": <object?> }): creates a run.inputmay be a string or JSON object/array.GET /run/{id}: returns status with fields:status,result_text,logs,artifacts,input_prompt,input_buffer.POST /run/{id}/input(body:{ "input": "..." }): appends toinput_bufferand resumes a waiting run.POST /run/{id}/logs(body:{ level, message }): appends a log.POST /run/{id}/artifacts(body:{ id?, type?, name?, uri?, metadata? }): adds an artifact to the run (server generatesidif missing).POST /run/{id}/complete(internal): worker callback to finalize a run.
GET /chat/: lists chat sessions.
uai run watch <task_id>now streams logs as they arrive and shows the final result on completion.- JSON mode (
--json) prints JSON lines for events:status,prompt,log, then a final object with the full run status. POST /chat/: creates a chat session and returns{ session_id }.POST /chat/{session_id}: sends a user message; responds after generating the assistant reply with{ state, artifacts, messages }.GET /chat/{session_id}/messages: lists messages in the session.DELETE /chat/{session_id}: deletes the session.POST /chat/{session_id}/artifacts(body:{ id?, type?, name?, uri?, metadata? }): adds an artifact to the session (server generatesidif missing).
- Default local DB: If no
PROCRASTINATE_DSN/DATABASE_URLis set, UAI connects tolocalhost:5432withuser=postgres,password=password,dbname=postgres. - Start a local Postgres (optional):
docker run --name pg-procrastinate --detach --rm -p 5432:5432 -e POSTGRES_PASSWORD=password postgres - Worker commands:
uai worker install: installs Procrastinate schema (idempotent).uai worker check: verifies DB connectivity.uai worker start: auto-installs schema, checks DB, then starts the worker.
- Inline mode (no DB):
UAI_PROCRASTINATE_INLINE=1executes runs in-process (used in tests).
KOSMOS_TOML: Path tokosmos.tomlto load agent config.UAI_BASE_URL: Base URL for server (used by worker callbacks). Defaults tohttp://localhost:8000.UAI_PROCRASTINATE_INLINE: Set to1to run jobs inline without Postgres.PROCRASTINATE_DSN/DATABASE_URL: Postgres connection for the worker. If unset, UAI uses local defaults.PROCRASTINATE_HOST/PORT/USER/PASSWORD/DB: Overrides for local default connection.
- Import errors: Ensure
KOSMOS_TOMLpoints to the right example and that the entrypoint’s dependencies (e.g.,crewai,langchain_community) are installed in both server and worker environments. - PoolTimeout on worker start: Check Docker Postgres is running and accessible; use
uai worker check. Add required SSL options to your DSN if using a cloud provider (e.g.,?sslmode=require). - Human input not progressing: Confirm status shows
waiting_inputwith a non-emptyinput_prompt, then senduai run input <task_id> --text '...'.
- Storage is in-memory for now; swap with a persistent backend (Postgres/Redis) for multi-process reliability. The worker currently finalizes runs via a callback to
POST /run/{id}/complete. - LangChain chat requires sessions: stateless
POST /chat/nextis not supported and returns 400. UAI maintains a separate chain instance per session to isolate memory.
- Helper functions for user adapters/agents in
unified_agent_interface.frameworks.utils:post_wait(task_id, prompt): mark run as waiting for input with a prompt.get_status(task_id): get run status JSON.poll_for_next_input(task_id, baseline_index, timeout_seconds=300): poll until new input arrives; returns(value, new_index).request_human_input(task_id, prompt="...", baseline_index=None): convenience wrapper that posts wait and polls; returns(value, new_index).post_log(task_id, level, message): append a log entry to a run.add_run_artifact(task_id, artifact_dict): add an artifact to a run.add_chat_artifact(session_id, artifact_dict): add an artifact to a chat session.
- Instrumentation utilities in
unified_agent_interface.utils:patch_log(target, label=None, capture_return=False): persistently patch a function or method (callable or"module:attr") to auto-log calls usingpost_log.unpatch_log(target): restore a target patched viapatch_log.
patch_function(target, label=None, capture_return=False): temporary/context-managed patch.patch_many(*targets, label=None, capture_return=False): patch multiple targets within one context.
- UAI tracks the current run (
task_id) and chat session (session_id) during execution so helpers can be called without IDs:unified_agent_interface.runtime.task_context(task_id)and.session_context(session_id)are used internally; helpers fall back to these whentask_id/session_idis omitted.- E.g.,
post_log(None, "INFO", "message")andrequest_human_input(None, "prompt")will route to the current run.
These utilities let custom adapters define their own session management and input-waiting behavior.
- Example (LangChain):
from langchain_openai import ChatOpenAIfrom unified_agent_interface.utils import patch_logpatch_log(ChatOpenAI.invoke, capture_return=True)- Calls to
ChatOpenAI.invokewill now be logged to the current run.
- Auto-collect file artifacts created during a run or chat turn.
- Enable via config or env:
- kosmos.toml:
[agent.artifacts] tracking = "auto"(optional:base_dir = "...") - env:
UAI_ARTIFACTS=auto(overrides config) - filters:
UAI_ARTIFACTS_INCLUDE="**/*.md,**/*.png",UAI_ARTIFACTS_EXCLUDE="**/.git/**",UAI_ARTIFACTS_BASEDIR=/path/to/repo
- kosmos.toml:
- How it works:
- UAI registers a Python audit hook and uses contextvars to attribute file creations to the current run/session.
- When enabled, opening files with create/append modes (e.g.,
w,x,a) oros.O_CREATis recorded as artifacts. - Artifacts are posted immediately to
/run/{id}/artifactsor/chat/{session}/artifactsand deduplicated per context.
- Notes:
- Off by default; opt-in via config/env.
- You can still add artifacts explicitly with
add_run_artifact/add_chat_artifact. - For best results, write outputs inside a known base directory and use include/exclude globs.