Skip to content
Docs

Build an agentic app in FastAPI with OpenAI Agents API and Vercel Sandbox

Learn how to build a repository Q&A app using FastAPI, OpenAI Agents API, and Vercel Sandbox, with isolated code inspection, streamed progress, downloadable evidence, and deployment to Vercel.

Anshuman BhardwajContent Engineer

This FastAPI template answers questions about public GitHub repositories using OpenAI Agents API and Vercel Sandbox. The OpenAI Agents API lets you create agent sessions, submit tasks, and stream progress as the agent works. This template uses the OpenAI Agents API through its Python SDK.

Vercel Sandbox provides Linux microVMs that you can create and manage from your application. A sandbox provides an agent with an isolated environment in which it can read files and run commands.

A user supplies a repository, a Git ref, and a question such as “What framework and package manager does this project use?” The app clones the repository into a sandbox, lets the agent inspect it, and returns an answer with supporting evidence.

In this guide, you'll connect an OpenAI Agents API session to Vercel Sandbox, run the template locally, and deploy the FastAPI app to Vercel.

Deploy the template now, or follow the steps below to build it.

Repository Q&A app with OpenAI Agents API

A FastAPI app that answers questions about GitHub repositories using Vercel Sandbox and OpenAI Agents API, with streamed progress and downloadable evidence.

Deploy Template

Copy link to headingQuick start with an AI coding agent

Agent Prompt

Help me set up and deploy the repository agent from https://github.com/vercel-labs/openai-agents-api-fastapi. Read README.md, AGENTS.md, ARCHITECTURE.md, and .env.example before making changes. Use Python 3.11 or later and a virtual environment. Install the dependencies listed in requirements.txt and requirements-dev.txt. Read the [OpenAI Agents API public beta SDK docs](https://developers.openai.com/api/docs/guides/agents-api/overview) before implementing or making suggestions. Help me configure OPENAI_API_KEY and a separate restricted OPENAI_EXECUTOR_API_KEY using the documented permissions. The application defines its agent inline for each session; no AGENT_ID is needed. Explain how to obtain missing credentials without putting secrets in chat or tracked files. Link a Vercel project with Sandbox access and run vercel env pull .env.local for local authentication. Follow the README to start FastAPI locally. Preserve the bounded repository inspection, separation of application and executor keys, and cleanup of sessions and sandboxes. Run the existing tests and lint checks. Check /api/health, then submit a focused question about a public GitHub repository with a valid ref. Verify the answer, session and sandbox IDs, and RESULT.md, evidence.json, and events.jsonl downloads. Configure both OpenAI keys in Vercel, deploy a preview, and repeat the verification. Report the deployment URL and any remaining setup requirements.

This guide covers the core implementation. The AI assistant prompt above covers all the details your coding agent needs, and you can see the full implementation in the template repository.

Copy link to headingVercel Plugin

Optionally, install the Vercel Plugin for Vercel-specific guidance in your coding agent. It provides product context, skills, and commands for working with Vercel, including Vercel Sandboxes and deployments.

Terminal
npx plugins add vercel/vercel-plugin

Copy link to headingPrerequisites

Before you begin, make sure you have:

  • Python 3.11 or later and Git installed.
  • Node.js and npm to install the Vercel CLI: npm install -g vercel.
  • A Vercel account and a project with Sandbox access.
  • An OpenAI organization and project. You'll create separate application and executor keys during local setup.
  • A public GitHub repository to inspect.

Copy link to headingHow it works

The app is a single FastAPI project that serves the browser interface and handles each inspection through POST /api/inspect:

  1. FastAPI validates the repository URL, Git ref, and question, then creates a self-hosted Agents API session.
  2. The Vercel Sandbox SDK creates a sandbox and clones the selected repository into /vercel/sandbox.
  3. The app installs Codex in the sandbox and starts codex exec-server. The executor connects outbound to the OpenAI Agents API using the session's environment ID.
  4. FastAPI submits the question and streams progress and available answer text to the browser using server-sent events.
  5. The agent writes an answer and structured evidence. FastAPI collects the files, deletes the API session while the executor is connected, stops the sandbox, and returns the result.
Architecture
Browser → FastAPI → Agents API session
│ ↕
└────→ Vercel Sandbox
Codex executor + cloned repository

Each question gets its own session and sandbox. The prompt asks the agent to use at most eight short commands, leave the checkout unchanged, and avoid dependency installation, builds, and network requests during inspection. The sandbox's network policy separately limits outbound connections to the services needed for cloning, installing Codex, and connecting the executor.

The result includes three downloads: RESULT.md for the answer, evidence.json for inspected files, commands, and limitations, and events.jsonl for API events captured by FastAPI. The app keeps these in the response rather than saving them to a database.

Copy link to headingSteps

Copy link to heading1. Set up the project

Clone the template repository and install its dependencies in a virtual environment:

Terminal
git clone https://github.com/vercel-labs/openai-agents-api-fastapi.git
cd openai-agents-api-fastapi
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt -r requirements-dev.txt

On Windows, activate the environment with .venv\Scripts\Activate.ps1 in PowerShell.

The template already includes the complete application. The application is organized into these files:

FilePurpose
sandbox_agent/main.pyServes the page and inspection endpoint
sandbox_agent/runner.pyCreates sessions, streams events, and cleans up resources
sandbox_agent/vercel_sandbox.pyCreates the sandbox and starts the executor
sandbox_agent/prompt.pyDefines the inspection instructions and output files
sandbox_agent/artifacts.pyCollects the answer, evidence, and event log
app.pyExports the application for Vercel

Copy link to heading2. Integrate OpenAI Agents API

In sandbox_agent/runner.py, the session setup follows this pattern inside the asynchronous inspection handler:

sandbox_agent/runner.py
from openai import AsyncOpenAI
from sandbox_agent.config import get_settings
from sandbox_agent.prompt import build_agent_instructions
# Inside the asynchronous inspection handler.
settings = get_settings()
client = AsyncOpenAI(
api_key=settings.openai_api_key,
base_url=settings.agents_api_url,
max_retries=0,
timeout=settings.session_create_timeout_seconds,
)
session = await client.beta.agents.sessions.create(
agent={
"model": settings.agent_model,
"instructions": build_agent_instructions(),
"reasoning": {"effort": settings.agent_reasoning_effort},
"text": {"verbosity": "low"},
},
environment={
"type": "self_hosted",
"workspace_directory": "/vercel/sandbox",
},
)
environment = session.environment
if environment.type != "self_hosted":
raise RuntimeError(
f"Expected self-hosted environment, got {environment.type}"
)
environment_id = environment.id
remote_url = environment.remote_url

The environment ID connects this session to the executor you'll start in the next step. It is separate from both the Agents API session ID and the Vercel Sandbox ID.

settings.agents_api_url defaults to https://api.openai.com/v1, while remote_url comes from the session response and must remain unchanged.

build_agent_instructions() defines the agent's role and tells it to treat repository contents as evidence, never as instructions. build_inspection_prompt() adds the user's question, the command budget, and the required output paths under /tmp/sandbox-agent.

Inside the inspection handler, build the prompt from the validated request:

sandbox_agent/runner.py
from sandbox_agent.prompt import build_inspection_prompt
prompt = build_inspection_prompt(
repo_url=request.repo_url,
ref=request.ref,
question=request.question,
)

Here, request is the validated inspection request containing the repository URL, Git ref, and question. The resulting prompt is what the later input=prompt sends to the agent.

Once the sandbox executor has started, submit the prompt through client.beta.agents.sessions.stream(session.id, input=prompt) as an async context manager. This opens the stream before sending the input:

sandbox_agent/runner.py
from sandbox_agent.sse import encode_sse
text_parts = {}
async with client.beta.agents.sessions.stream(
session.id,
input=prompt,
timeout=settings.stream_no_progress_timeout_seconds,
) as events:
async for event in events:
if event.type == "agent.session.turn.output_text.delta":
key = (event.item_id, event.output_index, event.content_index)
text_parts[key] = text_parts.get(key, "") + event.delta
yield encode_sse("answer_delta", {"delta": event.delta})
elif event.type == "agent.session.turn.output_text.done":
key = (event.item_id, event.output_index, event.content_index)
text_parts[key] = event.text
streamed_answer = "".join(text_parts.values())

output_text.done events replace the matching content part because deltas may be absent. The complete handler also captures events, checks executor health while opening and consuming the stream, handles failures, and collects artifacts. It requires a completed root-agent turn and a final idle session with no run error before reporting success.

By default, the handler stops waiting after 45 seconds without an event or when the inspection reaches its 150-second limit. The final answer is read from RESULT.md when available, with streamed text as a fallback.

Copy link to heading3. Integrate managed compute with the Sandbox SDK

The template uses the Python Sandbox SDK included in the vercel package. In sandbox_agent/vercel_sandbox.py, create a sandbox from the validated repository URL and Git ref:

sandbox_agent/vercel_sandbox.py
from vercel.sandbox import AsyncSandbox, GitSource, NetworkPolicyCustom
sandbox = await AsyncSandbox.create(
source=GitSource(url=repo_url, revision=ref, depth=1),
runtime="node24",
timeout=settings.sandbox_timeout_ms,
network_policy=NetworkPolicyCustom(
allow=list(settings.sandbox_allowed_domains)
),
)

GitSource prepares the checkout in /vercel/sandbox. The Node.js runtime supplies npm so the app can install Codex inside the sandbox:

sandbox_agent/vercel_sandbox.py
install = await sandbox.run_command(
"npm",
["install", "-g", settings.codex_package],
sudo=True,
)
if install.exit_code != 0:
raise RuntimeError("Codex installation failed")

The default package is @openai/codex@alpha. The app also creates /tmp/sandbox-agent for output files and writes the inspection prompt there.

Start the executor as a detached command, passing the environment ID returned by the Agents API:

sandbox_agent/vercel_sandbox.py
executor = await sandbox.run_command_detached(
"codex",
[
"exec-server",
"--remote",
remote_url,
"--environment-id",
environment_id,
],
cwd="/vercel/sandbox",
env={"CODEX_API_KEY": executor_api_key},
)

The executor receives a restricted OpenAI key, while the application key stays in FastAPI. Because the executor connects outbound, this integration does not need an exposed sandbox port.

In sandbox_agent/runner.py, pass the session's environment values and restricted executor key to start_sandbox:

sandbox_agent/vercel_sandbox.py
from sandbox_agent.vercel_sandbox import start_sandbox
handle = await start_sandbox(
executor_api_key=settings.openai_executor_api_key,
environment_id=session.environment.id,
remote_url=session.environment.remote_url,
repo_url=request.repo_url,
ref=request.ref,
prompt=prompt,
settings=settings,
)

After collecting the output, delete the session while the executor is connected, stop the sandbox, and close the OpenAI client. These calls show the cleanup order:

sandbox_agent/vercel_sandbox.py
await client.beta.agents.sessions.delete(session.id)
await sandbox.stop(blocking=True)
await client.close()

The full runner wraps each operation in separate error handling so a failure does not prevent the remaining cleanup attempts. It deletes the session first because stopping the sandbox can move the session into requires_action and block deletion.

Each operation has a separate timeout, and transient session-deletion conflicts are retried within that timeout. Cleanup is shielded from browser-disconnect cancellation, and unfinished work is canceled with an agent.session.input.cancel event before cleanup. Deleting the API session alone does not stop the Vercel Sandbox.

See the Python Sandbox SDK reference when upgrading, since newer SDK versions may use different methods and lifecycle options.

Copy link to headingSet up locally

Copy link to headingConfigure credentials

Copy the environment template:

Terminal
cp .env.example .env

Create two OpenAI API keys under the same organization, project, and user or service account:

VariablePurposeRequired access
OPENAI_API_KEYCreates and manages sessions from FastAPIAn application key with Agents API access; follow the SDK's application-key permissions
OPENAI_EXECUTOR_API_KEYConnects the executor from inside the sandboxA separate restricted key from the OpenAI dashboard > Create Environment key flow

The Agents API quickstart describes application-key permissions. Create the executor key in the Agents dashboard, following the self-hosted environment authentication instructions.

Add both values to .env:

.env
# Application key: keep outside the sandbox.
OPENAI_API_KEY=your_application_key
# Restricted environment key: same organization, project, and owner.
OPENAI_EXECUTOR_API_KEY=your_executor_key

Next, authenticate with Vercel and link the project from the repository root:

Terminal
vercel login
vercel link
vercel env pull .env.local

The last command writes a development VERCEL_OIDC_TOKEN to .env.local. The Sandbox SDK uses it to authenticate local requests; refresh it by running the same command again if it expires. To learn more, see Sandbox authentication.

The app loads .env.local before .env, without overriding existing environment variables. Keep the OpenAI keys in .env and the Vercel token in .env.local; remove duplicate blank entries in .env.local if they mask your keys. Both files are ignored by Git.

Copy link to headingRun the app

With the virtual environment active, start FastAPI:

Terminal
vercel dev

Open localhost:3000, enter a public GitHub repository and a valid ref, and ask a focused question:

What framework and package manager does this repository use? Cite the files that support your answer.

A completed inspection shows the answer, evidence, model, session ID, sandbox ID, duration, and artifact downloads. Review evidence.json for limitations and events.jsonl for the captured API events.

You can check configuration at localhost:3000/api/health. A ready response confirms that the required OpenAI settings are present and distinct; submit an inspection to verify the credentials and service connections. If an inspection times out, try a narrower question.

Copy link to headingDeploy to Vercel

Add both OpenAI keys to the linked Vercel project:

Terminal
vercel env add OPENAI_API_KEY
vercel env add OPENAI_EXECUTOR_API_KEY

Select Preview and Production when prompted so both deployment environments can run inspections. Then create a preview deployment from the repository root:

Terminal
vercel deploy

Vercel automatically detects the project’s framework and deploys the app correctly. To learn more about FastAPI deployments, see FastAPI on Vercel.

The template exports the FastAPI app through app.py:

app.py
from sandbox_agent.main import app

Open the preview URL, check /api/health, and submit a small repository question. Confirm that the answer and downloads appear and that the result includes both session and sandbox IDs. Once you've verified the preview, deploy to production:

Terminal
vercel deploy --prod

Copy link to headingNext steps

Use the working template as a starting point for a more specific repository assistant:

  • Change the inspection task. Adapt sandbox_agent/prompt.py to explain a repository's test setup, trace a request through source files, or identify dependencies relevant to a planned migration.
  • Keep reports between visits. Add storage for the answer, evidence, and event log so users can revisit or compare inspections.
  • Support longer jobs. Move session and sandbox management into a background worker before adding migrations, builds, or multiple turns. The current app ties each run to one browser request and does not resume disconnected runs.
  • Explore the APIs. Read the Agents API SDK guide for session and event handling, and the Vercel Sandbox documentation for execution environments and lifecycle options.

Related documentation

More Vercel Sandbox guides