Skip to main content

OpenAgent

OpenAgent is an OpenAPI-native API agent for FastAPI. It mounts an assistant on top of an existing FastAPI app, reads the app's OpenAPI schema, and can answer questions, inspect operation contracts, and optionally execute host API calls in-process through ASGI.

The PyPI distribution name is fastapi-openapi-agent. The Python import package is openagent.

Status: alpha. APIs may change before the first stable release.

Features

  • One-line FastAPI integration with install_openapi_agent(app).
  • Framework-neutral OpenAPI runtime for operation search, contract lookup, and tool execution.
  • Built-in agent page at /_agent/ and embeddable widget at /_agent/widget/.
  • Static sidebar loader at /_agent/sidebar.js for adding a floating API assistant to any page.
  • SSE chat endpoint at /_agent/chat/stream with text deltas and tool-call events.
  • JSON fallback endpoint at /_agent/chat.
  • Local deterministic OpenAPI responder for offline development.
  • LiteLLM responder for DeepSeek, OpenAI, Anthropic, Gemini, Azure, and other providers.
  • In-process host API execution through httpx.ASGITransport; no public HTTP round trip is required.
  • Parent-page request bridge for custom auth, tenant headers, request signing, or token refresh.

Installation

Install the FastAPI adapter:

pip install "fastapi-openapi-agent[fastapi]"

Add the LiteLLM integration when using an external model:

pip install "fastapi-openapi-agent[fastapi,llm]"

For local development from source:

pip install -e ".[dev,llm]"
npm install --prefix frontend
npm run build --prefix frontend

The frontend build step generates src/openagent/static/sidebar.js and src/openagent/static/widget/. These files are included in the Python wheel so users installing from PyPI do not need Node.js.

Quick Start

from fastapi import FastAPI
from openagent.fastapi import install_openapi_agent

app = FastAPI(title="My API")

install_openapi_agent(app)

Start your FastAPI app and open:

  • /_agent/ for the standalone agent page.
  • /_agent/widget/ for the widget SPA.
  • /_agent/sidebar.js for the embeddable sidebar loader.
  • /docs for the normal FastAPI Swagger UI.

FastAPI Integration

Customize the route prefix and UI metadata:

install_openapi_agent(
    app,
    path="/api-agent",
    title="Service Agent",
    description="Ask questions about this service API.",
)

Enable live host API calls:

install_openapi_agent(
    app,
    enable_api_calls=True,
    allow_mutating_api_calls=False,
)

By default, live execution only allows GET, HEAD, and OPTIONS. If your product explicitly allows write operations, enable mutating calls:

install_openapi_agent(app, allow_mutating_api_calls=True)

Frontend Embed

Add a floating sidebar to any page served by the same app:

<script src="/_agent/sidebar.js"></script>

Configure cross-path or cross-origin embedding:

<script>
  window.OpenAgent = {
    baseUrl: "https://api.example.com/_agent",
    title: "API Assistant",
    open: false,
    width: 560,
    minWidth: 420,
    maxWidth: 920
  };
</script>
<script src="https://api.example.com/_agent/sidebar.js"></script>

Embed the widget into a container instead of using a floating drawer:

<div id="agent-root"></div>
<script>
  window.OpenAgent = {
    baseUrl: "/_agent",
    container: "#agent-root"
  };
</script>
<script src="/_agent/sidebar.js"></script>

The sidebar supports resizing, persists the chosen width, and can be toggled with Ctrl/Cmd + E.

Custom Request Bridge

If the host product already has a frontend request layer, provide window.OpenAgent.request. The widget runs inside an iframe, so sidebar.js bridges iframe requests to the parent page and lets your code execute the actual request.

<script>
  window.OpenAgent = {
    baseUrl: "https://api.example.com/_agent",
    async request(input) {
      const token = await getAccessToken();

      return fetch(input.url, {
        method: input.method,
        headers: {
          ...input.headers,
          Authorization: `Bearer ${token}`,
          "X-Tenant-ID": getTenantId()
        },
        body: input.body,
        credentials: "include"
      });
    }
  };
</script>
<script src="https://api.example.com/_agent/sidebar.js"></script>

request(input) must return a standard fetch Response. The bridge covers /_agent/chat/stream and /_agent/chat. Stream responses are forwarded to the iframe chunk by chunk. For safety, the bridge only allows requests under the configured baseUrl.

Authentication

There are two separate auth concerns.

Protect the agent routes with your normal FastAPI authentication layer, for example by mounting the agent behind authenticated middleware, a protected router, or reverse-proxy auth.

Forward the current user identity when the agent calls host APIs. The FastAPI adapter forwards selected headers into in-process API calls:

install_openapi_agent(
    app,
    forward_headers=("authorization", "cookie"),
    allow_mutating_api_calls=False,
)

If your frontend is cross-origin, the request bridge is usually the safest place to attach JWTs, cookies, tenant IDs, or gateway signatures.

Multi-Provider LLM Integration

OpenAgent uses LiteLLM as its provider-neutral model layer. LiteLLM exposes one OpenAI-style Python API for DeepSeek, OpenAI, Anthropic, Gemini, Azure, Bedrock, OpenRouter, Ollama, and other providers. The default OpenAgent responder remains deterministic and makes no external request until a model is configured.

Set OPENAGENT_MODEL to a LiteLLM model name and provide that provider's normal credentials. OpenAgent then enables the model responder automatically:

# DeepSeek
export OPENAGENT_MODEL="deepseek/deepseek-chat"
export DEEPSEEK_API_KEY="your-api-key"

# OpenAI
export OPENAGENT_MODEL="openai/gpt-4o-mini"
export OPENAI_API_KEY="your-api-key"

# Anthropic
export OPENAGENT_MODEL="anthropic/claude-sonnet-4-5"
export ANTHROPIC_API_KEY="your-api-key"

# Gemini
export OPENAGENT_MODEL="gemini/gemini-2.5-flash"
export GEMINI_API_KEY="your-api-key"

Only configure one model for a running application. The examples are alternatives, not a single combined configuration.

The same options can be passed directly to the FastAPI adapter:

from openagent.fastapi import install_openapi_agent

install_openapi_agent(
    app,
    llm_model="openai/gpt-4o-mini",
    llm_api_key="your-api-key",  # Prefer a secret environment variable in production.
)

For a LiteLLM Proxy or another OpenAI-compatible gateway, set a custom base URL:

export OPENAGENT_MODEL="openai/my-model"
export OPENAGENT_API_KEY="gateway-key"
export OPENAGENT_BASE_URL="http://localhost:4000/v1"

Provider-specific LiteLLM options can be supplied through llm_model_kwargs:

install_openapi_agent(
    app,
    llm_model="azure/my-deployment",
    llm_model_kwargs={"api_version": "2024-10-21"},
)

Or create a responder explicitly:

from openagent import create_llm_responder
from openagent.fastapi import install_openapi_agent

responder = create_llm_responder(model="openrouter/openai/gpt-4o-mini")
install_openapi_agent(app, responder=responder)

The explicit responder can search operations and load contracts locally. Because it has no host application invoker, live operation_request calls remain disabled. Use automatic LiteLLM integration or a custom OpenAPIAgent backend when live host API execution is required. Select a model that supports tool calling.

A bare model name without a provider prefix is treated as a DeepSeek model, so deepseek-chat is normalized to deepseek/deepseek-chat. New code should use create_llm_responder and stream_llm_agent.

For large APIs, the initial metadata catalog is compacted to max_context_chars. If every operation cannot fit, the context sets catalogComplete to false and the model uses operation_search before loading the selected contract. Operations without an operationId are addressed by method and path.

The model initially receives a compact catalog of every operation's metadata, including method, path, operationId, summary, description, tags, parameter names, and response status codes. Request and response schemas are not included in that initial context. The selected operation's full contract and referenced schemas are loaded on demand with operation_get.

When tool calling is enabled, the required API execution chain is:

operation_get -> operation_request -> final answer

operation_search remains available as an optional catalog filter. The runtime rejects operation_request unless the same operation was first loaded with operation_get during that agent run.

Custom Responder

You can replace the built-in responder with your own LLM, internal agent platform, or policy layer:

from openagent import AgentRequest, AgentResponse
from openagent.fastapi import install_openapi_agent

async def my_responder(request: AgentRequest, openapi: dict) -> AgentResponse:
    return AgentResponse(
        answer="LLM response",
        operations=[],
        sources=[],
    )

install_openapi_agent(app, responder=my_responder)

Custom Agent SDK

Use the core SDK when a custom implementation needs operation discovery, detailed contracts, runtime tools, and the standard JSON/SSE routes. OperationCatalog keeps schema-free metadata separate from contracts loaded on demand.

from openagent import (
    AgentBackend,
    AgentContext,
    AgentResponse,
    OpenAPIAgent,
)
from openagent.fastapi import install_openapi_agent


class MyAgentBackend(AgentBackend):
    async def respond(self, context: AgentContext) -> AgentResponse:
        matches = context.catalog.search_operations(
            context.request.message,
            limit=1,
        )
        if not matches or not matches[0].operation_id:
            return AgentResponse(answer="No matching operation was found.")

        operation = matches[0]
        contract = await context.run_tool(
            "operation_get",
            {"operationId": operation.operation_id},
        )
        return AgentResponse(
            answer=f"Selected {operation.method} {operation.path}: {contract['preview']}",
            sources=[f"{operation.method} {operation.path}"],
        )


agent = OpenAPIAgent(MyAgentBackend())
install_openapi_agent(app, agent=agent)

Implementing respond is sufficient: AgentBackend converts it to the standard SSE event sequence automatically. Override stream to emit incremental typed events such as TextDeltaEvent, ToolInputAvailableEvent, and ToolOutputAvailableEvent.

The catalog can also be used independently of FastAPI:

from openagent import OperationCatalog

catalog = OperationCatalog.from_openapi(openapi_document)
metadata = catalog.list_operations()
matches = catalog.search_operations("create user")
contract = catalog.require_operation("create_user_users_post")

OperationMetadata contains no request or response schemas. OperationContract contains the selected operation, merged path-level parameters, risk metadata, and all referenced component schemas.

Local Demo

With devyard:

devyard run install
devyard run build
devyard up
devyard status

Without devyard:

pip install -e ".[dev]"
npm install --prefix frontend
npm run build --prefix frontend
python -m uvicorn examples.demo:app --reload

Then open http://127.0.0.1:8000/_agent/.

Development

npm run check --prefix frontend
npm run build --prefix frontend
pytest

Full local validation:

npm run check --prefix frontend && npm run build --prefix frontend && pytest

Packaging

Build and inspect the Python distributions:

pip install -e ".[dev]"
npm run build --prefix frontend
python -m build
python -m twine check dist/*

Inspect the wheel contents before publishing:

python -m zipfile -l dist/fastapi_openapi_agent-*.whl

The wheel should include:

  • openagent/static/sidebar.js
  • openagent/static/widget/index.html
  • openagent/static/widget/assets/...
  • openagent/py.typed

PyPI Release

This repository includes .github/workflows/publish.yml for token-free PyPI Trusted Publishing. A published GitHub release automatically runs the frontend checks, Python tests, package build, twine validation, and PyPI upload. The release tag must match the version in pyproject.toml; both 0.1.0 and v0.1.0 tag formats are accepted.

Before the first release, configure a trusted publisher on PyPI with:

  • PyPI project name: fastapi-openapi-agent
  • GitHub owner: yangsengui
  • GitHub repository: fastapi-openapi-agent
  • Workflow filename: publish.yml
  • Environment name: pypi

Create a pypi environment under the GitHub repository's Settings > Environments page. Environment reviewers are optional, but recommended when manual approval is required before production publication. No PYPI_API_TOKEN secret is needed.

Recommended release flow:

  1. Update version in pyproject.toml.
  2. Update CHANGELOG.md.
  3. Run the packaging checks above.
  4. Commit and push the release changes.
  5. Create and publish a GitHub release using a matching tag such as v0.1.0.
  6. Verify the Publish Python Package workflow and the release on PyPI.

The workflow can also be started manually from Actions > Publish Python Package > Run workflow. By default, a manual run only tests and builds the distributions without publishing them. Enable the publish input to upload the version declared by the selected branch; PyPI rejects a version that has already been uploaded.

Manual upload is also possible:

python -m twine upload dist/*

License

MIT. See LICENSE.

Metadata

Release files for fastapi-openapi-agent 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastapi-openapi-agent 0.1.0
File Size Uploaded Provenance Actions
fastapi_openapi_agent-0.1.0.tar.gz 139.6 kB Without provenance Details for fastapi_openapi_agent-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fastapi-openapi-agent 0.1.0
File Interpreter ABI Platform Actions
fastapi_openapi_agent-0.1.0-py3-none-any.whl Python 3 none any Details for fastapi_openapi_agent-0.1.0-py3-none-any.whl

Total release size: 246.3 kB

Release files / fastapi_openapi_agent-0.1.0.tar.gz

Download URL fastapi_openapi_agent-0.1.0.tar.gz
Size 139.6 kB
Tags Source
SHA-256 checksum
How to use checksums
baedc11d3560cc49e4aca08672c0e4e280dc820fb5f5d5ec191574d4a09a0b09
BLAKE2b-256 checksum
How to use checksums
b178bba7fb0f76cbf9daa809282242c7fe2387109a3868be8741f700d10a3902
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release files / fastapi_openapi_agent-0.1.0-py3-none-any.whl

Download URL fastapi_openapi_agent-0.1.0-py3-none-any.whl
Size 106.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
80cb68ae8973bd8f1577a1448355205ad41f937ce818bbacdd032cbfc5eb5349
BLAKE2b-256 checksum
How to use checksums
c097e88d3cdaff13755da5af1f899e76a683149a3b0b933881e00c233133396a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Security for fastapi-openapi-agent 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page