Skill 172 · Foundry Hosted Agent Copilotkit
Subchapter 172.1
references/architecture.mdMarkdown7 KBView on GitHub
The stack has three layers that must agree: CopilotKit (React hooks + runtime), the AG-UI protocol (SSE event stream), and the Microsoft Agent Framework (MAF) agent, optionally running as an Azure AI Foundry hosted agent. The deployed Foundry hosted agent endpoint speaks OpenAI Responses () or a raw invocations protocol () — . Pointing from directly at a hosted agent’s Responses endpoint does not work.
{project_endpoint}/agents/{name}/endpoint/protocols/openai/responses.../protocols/invocationsHttpAgent@ag-ui/clientThere are three viable wirings. Identify which one the codebase uses before changing anything.
The agent object lives in the same process as the AG-UI HTTP endpoint.
Python:
from agent_framework import Agent
from agent_framework_ag_ui import AgentFrameworkAgent, add_agent_framework_fastapi_endpoint
from fastapi import FastAPI
agent = Agent(name="assistant", instructions="...", client=chat_client, tools=[...])
wrapped = AgentFrameworkAgent(agent=agent, require_confirmation=True) # HITL on
app = FastAPI()
add_agent_framework_fastapi_endpoint(app, wrapped, "/").NET: builder.Services.AddAGUI() + app.MapAGUI("/", agent) from Microsoft.Agents.AI.Hosting.AGUI.AspNetCore, with approval middleware (see hitl.md).
The hosted agent’s own container speaks AG-UI, deployed under Foundry’s invocations protocol (“Custom streaming protocol (AG-UI, etc.) → Invocations” per the Foundry hosted-agents docs). The agent.yaml declares:
protocols:
- protocol: invocations
version: 2.0.0and the container serves AG-UI requests at /invocations (Microsoft’s foundry-samples repository has a bring-your-own invocations AG-UI sample under samples/python/hosted-agents/bring-your-own/invocations/ag-ui/). The CopilotKit runtime’s HttpAgent points at the deployed invocations endpoint.
DefaultAzureCredential), so the CopilotKit runtime usually still needs a thin server-side proxy to attach tokens — browsers cannot call it directly.The hosted agent is deployed with the responses protocol (platform-managed conversation history, agent versioning, per-user isolation), and a separate bridge service translates between AG-UI and the Responses stream. This is the highest-effort wiring; choose it only when you specifically need the Responses platform features.
The bridge must handle, at minimum:
response.output_text.delta → TEXT_MESSAGE_CONTENT, function call items → TOOL_CALL_*, response.completed → RUN_FINISHED, etc.).mcp_approval_request to the UI, and forward the user’s decision back as an mcp_approval_response input item — approved tools then re-execute server-side. The stock AG-UI adapter resolves approvals locally and never forwards them to a remote agent (tracked as microsoft/agent-framework#6652), so a bridge needs explicit code for this path. Verify against the current package version whether this is still required before writing custom routing.previous_response_id chaining (local/direct mode) or a Foundry conversation object (deployed/platform mode). See hitl.md for the critical hazard with previous_response_id chaining across approval turns.STATE_SNAPSHOT/STATE_DELTA events are NOT produced by a Responses stream. Shared-state and predictive-state patterns require the bridge to synthesize them (e.g. from response.function_call_arguments.delta); if the bridge doesn’t implement that, those patterns silently don’t work. Check before promising the feature.Bridge state (response-id or conversation cache) is typically in-memory: run a single replica or externalize the cache before scaling out.
HttpAgent at http://localhost:<port>/.azd ai agent run runs the REAL hosted agent locally (default port 8088) using your az login credentials and the provisioned Foundry project — there is no mock. azd ai agent invoke --local "..." sends a single test payload. A bridge in local mode points at the bare local endpoint instead of the deployed one (commonly switched by a single environment variable holding the direct URL).The AG-UI endpoint, wherever it lives, registers in the CopilotKit runtime as an HttpAgent:
import { HttpAgent } from "@ag-ui/client";
import { CopilotRuntime } from "@copilotkit/runtime";
const runtime = new CopilotRuntime({
agents: { "my_agent": new HttpAgent({ url: process.env.AGUI_BACKEND_URL! }) },
});and the provider selects it by name: <CopilotKit runtimeUrl="/api/copilotkit" agent="my_agent">. Name drift between the agents key, the agent prop, and (for hosted agents) the name in agent.yaml is a recurring failure — keep one constant.
Frontend tools registered with useFrontendTool flow through the runtime into the AG-UI RunAgentInput.tools array and become callable by the agent; this is native in all three architectures.
https://ai.azure.com/.default — the default cognitiveservices.azure.com scope yields 401 “audience is incorrect”.DefaultAzureCredential) is the norm; the async Python credential path needs aiohttp installed.x-ms-user-isolation-key to a deployed agent — deployed agents derive isolation from the Entra identity and reject the header with a 400.