A small Pydantic AI agent that speaks the AG-UI protocol over Microsoft Foundry's Invocations protocol, plus a Next.js + CopilotKit web client that talks to it through a server-side runtime authenticated with Entra ID.
This repo is meant to be read alongside the official Foundry quickstart, not cloned and deployed as-is. The infra (Bicep templates, azure.yaml, agent.manifest.yaml) is what azd ai agent init scaffolds for you — copying it from this repo will only complicate things and pin you to versions that may already be stale.
In an empty folder, follow the Foundry hosted-agent quickstart (azd pivot):
az login # required — DefaultAzureCredential needs it
azd ext install azure.ai.agents
azd ai agent init # interactive; pick the FIRST template in the list
azd up # provision + deploy in one goWhen azd ai agent init asks for the Agent Template, pick the first one. It's the simplest sample and it's what the rest of these instructions assume.
After azd up finishes you have a working hosted agent on Foundry. Verify it before moving on:
azd ai agent invoke "Hello"This is where you bring in the AG-UI implementation from this repo:
- Replace
main.pyin the scaffolded project withsrc/ag-ui-invocations/main.pyfrom this repo. - Replace
requirements.txtwithsrc/ag-ui-invocations/requirements.txt— the default template doesn't includepydantic-ai-slim,ag-ui-protocol, orazure-ai-agentserver-invocations. - Set the model deployment name in
agent.yaml(oragent.manifest.yaml, depending on which the template generates) soAZURE_AI_MODEL_DEPLOYMENT_NAMEmatches the deployment you provisioned.
Test locally, then redeploy:
azd ai agent run # runs main.py on :8088
# in another terminal:
curl -N -X POST http://localhost:8088/invocations \
-H "Content-Type: application/json" -H "Accept: text/event-stream" \
-d @src/ag-ui-invocations/test-payload.json
azd deploy # push the new container to FoundryYou now have an AG-UI agent running on Foundry, reachable at:
https://<account>.services.ai.azure.com/api/projects/<project>/agents/<agent>/endpoint/protocols/invocations?api-version=v1
You can also pretty-print the SSE stream from the deployed agent with the helper script in this repo:
export FOUNDRY_ACCOUNT=<your-account> # e.g. ai-account-xxxxxxxxxxxx
export FOUNDRY_PROJECT=<your-project> # e.g. ai-project-foo-dev
python invoke_remote.py # uses payload.jsonCopy the web/ folder from this repo into your project root. Then:
cd web
npm install
cp .env.local.example .env.localEdit web/.env.local and uncomment / set AGENT_URL to your deployed agent's invocations endpoint (the URL printed by azd deploy, ending in ?api-version=v1):
AGENT_URL=https://<account>.services.ai.azure.com/api/projects/<project>/agents/<agent>/endpoint/protocols/invocations?api-version=v1
Make sure you are still signed in (the runtime route uses DefaultAzureCredential to mint a bearer token for every request):
az login # if your session expired
npm run dev # http://localhost:3000Open http://localhost:3000 and ask "What's the weather in Brussels?". The runtime forwards your request to the Foundry-hosted agent over Entra-authenticated HTTPS; the agent calls the get_weather tool and streams AG-UI events back; CopilotKit intercepts the tool call by name and renders the WeatherCard component.
browser ──► /api/copilotkit ──► Foundry hosted agent ──► Azure OpenAI
(CopilotRuntime, (Pydantic AI +
DefaultAzureCredential AG-UI SSE stream)
→ Bearer token)
- No history is stored anywhere. The browser keeps the message array in React state and replays the full transcript on every turn. The runtime, agent, and Azure OpenAI are all stateless.
- Foundry session affinity is wired via an
agent_session_idquery param generated once per browser tab — same tab keeps the same sandbox until 15 min of idle. Page refresh = new sandbox. - All authentication is Entra ID, no API keys. The web runtime authenticates to the agent; the agent authenticates to Azure OpenAI. Locally
DefaultAzureCredentialpicks upaz login; in Azure it picks up the managed identity assigned to whatever compute hosts each piece.
| Path | Purpose |
|---|---|
src/ag-ui-invocations/main.py |
The agent — Pydantic AI + AG-UI SSE over Foundry Invocations |
src/ag-ui-invocations/requirements.txt |
Pinned dependencies for the agent |
src/ag-ui-invocations/agent.yaml, agent.manifest.yaml |
Reference manifests (the quickstart will generate its own) |
web/ |
Next.js + CopilotKit client |
invoke_remote.py |
Helper to hit the deployed agent and pretty-print the SSE stream |
infra/ |
Reference Bicep used by the original azd up of this repo (you'll get a similar set from azd ai agent init) |
azd downRemoves everything azd up provisioned in your project's resource group.