Files
Dmytro Struk 361c47f30f Python: [Feature Branch] Merge from main to Azure AI branch (#2111)
* Do not build DevUI assets during .NET project build (#2010)

* .NET: Add unit tests for declarative executor SetMultipleVariables (#2016)

* Add unit tests for create conversation executor

* Update indentation and comment typo.

* Added unit tests for declarative executor SetMultipleVariablesExecutor

* Updated comments and syntactic sugar

* Python: DevUI: Use metadata.entity_id instead of model field (#1984)

* DevUI: Use metadata.entity_id for agent/workflow name instead of model field

* OpenAI Responses: add explicit request validation

* Review feedback

* .NET: DevUI - Do not automatically add/map OpenAI services/endpoints (#2014)

* Don't add OpenAIResponses as part of Dev UI

You should be able to add and remove Dev UI without impacting your other production endpoints.

* Remove `AddDevUI()` and do not map OpenAI endpoints from `MapDevUI()`

* Fix comment wording

* Revise documentation

---------

Co-authored-by: Daniel Roth <daroth@microsoft.com>

* Python: DevUI: Add OpenAI Responses API proxy support  + HIL for Workflows (#1737)

* DevUI: Add OpenAI Responses API proxy support with enhanced UI features

This commit adds support for proxying requests to OpenAI's Responses API,
allowing DevUI to route conversations to OpenAI models when configured to enable testing.

Backend changes:
- Add OpenAI proxy executor with conversation routing logic
- Enhance event mapper to support OpenAI Responses API format
- Extend server endpoints to handle OpenAI proxy mode
- Update models with OpenAI-specific response types
- Remove emojis from logging and CLI output for cleaner text

Frontend changes:
- Add settings modal with OpenAI proxy configuration UI
- Enhance agent and workflow views with improved state management
- Add new UI components (separator, switch) for settings
- Update debug panel with better event filtering
- Improve message renderers for OpenAI content types
- Update types and API client for OpenAI integration

* update ui, settings modal and workflow input form, add register cleanup hooks.

* add workflow HIL support, user mode, other fixes

* feat(devui): add human-in-the-loop (HIL) support with dynamic response schemas

Implement  HIL workflow support allowing workflows to pause for user input
with dynamically generated JSON schemas based on response handler type hints.

Key Features:
- Automatic response schema extraction from @response_handler decorators
- Dynamic form generation in UI based on Pydantic/dataclass response types
- Checkpoint-based conversation storage for HIL requests/responses
- Resume workflow execution after user provides HIL response

Backend Changes:
- Add extract_response_type_from_executor() to introspect response handlers
- Enrich RequestInfoEvent with response_schema via _enrich_request_info_event_with_response_schema()
- Map RequestInfoEvent to response.input.requested OpenAI event format
- Store HIL responses in conversation history and restore checkpoints

Frontend Changes:
- Add HILInputModal component with SchemaFormRenderer for dynamic forms
- Support Pydantic BaseModel and dataclass response types
- Render enum fields as dropdowns, strings as text/textarea, numbers, booleans, arrays, objects
- Display original request context alongside response form

Testing:
- Add  tests for checkpoint storage (test_checkpoints.py)
- Add schema generation tests for all input types (test_schema_generation.py)
- Validate end-to-end HIL flow with spam workflow sample

This enables workflows to seamlessly pause execution and request structured user input
with type-safe, validated forms generated automatically from response type annotations.

* improve HIL support, improve workflow execution view

* ui updates

* ui updates

* improve HIL for workflows, add auth and view modes

* update workflow

* security improvements , ui fixes

* fix mypy error

* update loading spinner in ui

---------

Co-authored-by: Mark Wallace <127216156+markwallace-microsoft@users.noreply.github.com>

* .NET: Remove launchSettings.json from .gitignore in dotnet/samples (#2006)

* Remove launchSettings.json from .gitignore in dotnet/samples

* Update dotnet/samples/GettingStarted/DevUI/DevUI_Step01_BasicUsage/Properties/launchSettings.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update dotnet/samples/AGUIClientServer/AGUIServer/Properties/launchSettings.json

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* DevUI: Serialize workflow input as string to maintain conformance with OpenAI Responses format (#2021)

Co-authored-by: Victor Dibia <chuvidi2003@gmail.com>

* Add Microsoft Agent Framework logo to assets (#2007)

* Updated package versions (#2027)

* DevUI: Prevent line breaks within words in the agent view (#2024)

Co-authored-by: Victor Dibia <chuvidi2003@gmail.com>

* .NET [AG-UI]: Adds support for shared state. (#1996)

* Product changes

* Tests

* Dojo project

* Cleanups

* Python: Fix underlying tool choice bug and all for return to previous Handoff subagent (#2037)

* Fix tool_choice override bug and add enable_return_to_previous support

* Add unit test for handoff checkpointing

* Handle tools when we have them

* added missing chatAgent params (#2044)

* .NET: fix ChatCompletions Tools serialization (#2043)

* fix serialization in chat completions on tools

* nit

* .NET: assign AgentCard's URL to mapped-endpoint if not defined explicitly (#2047)

* fix serialization in chat completions on tools

* nit

* write e2e test for agent card resolve + adjust behavior

* nit

* Version 1.0.0-preview.251110.1 (#2048)

* .NET: Remove moved OpenAPI sample and point to SK one. (#1997)

* Remove moved OpenAPI sample and point to SK one.

* Update dotnet/samples/GettingStarted/Agents/README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Bump AWSSDK.Extensions.Bedrock.MEAI from 4.0.4.2 to 4.0.4.6 (#2031)

---
updated-dependencies:
- dependency-name: AWSSDK.Extensions.Bedrock.MEAI
  dependency-version: 4.0.4.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* .NET: Separate all memory and rag samples into their own folders (#2000)

* Separate all memory and rag samples into their own folders

* Fix broken link.

* Python: .Net: Dotnet devui compatibility fixes (#2026)

* DevUI: Add OpenAI Responses API proxy support with enhanced UI features

This commit adds support for proxying requests to OpenAI's Responses API,
allowing DevUI to route conversations to OpenAI models when configured to enable testing.

Backend changes:
- Add OpenAI proxy executor with conversation routing logic
- Enhance event mapper to support OpenAI Responses API format
- Extend server endpoints to handle OpenAI proxy mode
- Update models with OpenAI-specific response types
- Remove emojis from logging and CLI output for cleaner text

Frontend changes:
- Add settings modal with OpenAI proxy configuration UI
- Enhance agent and workflow views with improved state management
- Add new UI components (separator, switch) for settings
- Update debug panel with better event filtering
- Improve message renderers for OpenAI content types
- Update types and API client for OpenAI integration

* update ui, settings modal and workflow input form, add register cleanup hooks.

* add workflow HIL support, user mode, other fixes

* feat(devui): add human-in-the-loop (HIL) support with dynamic response schemas

Implement  HIL workflow support allowing workflows to pause for user input
with dynamically generated JSON schemas based on response handler type hints.

Key Features:
- Automatic response schema extraction from @response_handler decorators
- Dynamic form generation in UI based on Pydantic/dataclass response types
- Checkpoint-based conversation storage for HIL requests/responses
- Resume workflow execution after user provides HIL response

Backend Changes:
- Add extract_response_type_from_executor() to introspect response handlers
- Enrich RequestInfoEvent with response_schema via _enrich_request_info_event_with_response_schema()
- Map RequestInfoEvent to response.input.requested OpenAI event format
- Store HIL responses in conversation history and restore checkpoints

Frontend Changes:
- Add HILInputModal component with SchemaFormRenderer for dynamic forms
- Support Pydantic BaseModel and dataclass response types
- Render enum fields as dropdowns, strings as text/textarea, numbers, booleans, arrays, objects
- Display original request context alongside response form

Testing:
- Add  tests for checkpoint storage (test_checkpoints.py)
- Add schema generation tests for all input types (test_schema_generation.py)
- Validate end-to-end HIL flow with spam workflow sample

This enables workflows to seamlessly pause execution and request structured user input
with type-safe, validated forms generated automatically from response type annotations.

* improve HIL support, improve workflow execution view

* ui updates

* ui updates

* improve HIL for workflows, add auth and view modes

* update workflow

* security improvements , ui fixes

* fix mypy error

* update loading spinner in ui

* DevUI: Serialize workflow input as string to maintain conformance with OpenAI Responses format

* Phase 1: Add /meta endpoint and fix workflow event naming for .NET DevUI compatibility

* additional fixes for .NET DevUI workflow visualization item ID tracking

**Problem:**
.NET DevUI was generating different item IDs for ExecutorInvokedEvent and
ExecutorCompletedEvent, causing only the first executor to highlight in the
workflow graph. Long executor names and error messages also broke UI layout.

**Changes:**
- Add ExecutorActionItemResource to match Python DevUI implementation
- Track item IDs per executor using dictionary in AgentRunResponseUpdateExtensions
- Reuse same item ID across invoked/completed/failed events for proper pairing
- Add truncateText() utility to workflow-utils.ts
- Truncate executor names to 35 chars in execution timeline
- Truncate error messages to 150 chars in workflow graph nodes

** Details:**
- ExecutorActionItemResource registered with JSON source generation context
- Dictionary cleaned up after executor completion/failure to prevent memory leaks
- Frontend item tracking by unique item.id supports multiple executor runs
- All changes follow existing codebase patterns and conventions

Tested with review-workflow showing correct executor highlighting and state
transitions for sequential and concurrent executors.

* format fixes, remove cors tests

* remove unecessary attributes

---------

Co-authored-by: Mark Wallace <127216156+markwallace-microsoft@users.noreply.github.com>
Co-authored-by: Reuben Bond <reuben.bond@gmail.com>

* DevUI: support having both an agent and a workflow with the same id in discovery (#2023)

* Python: Fix Model ID attribute not showing up in `invoke_agent` span (#2061)

* Best effort to surface the model id to invoke agent span

* Fix tests

* Fix tests

* Version 1.0.0-preview.251107.2 (#2065)

* Version 1.0.0-preview.251110.2 (#2067)

* Update README.md to change Grafana links to Azure portal links for dashboard access (#1983)

* .NET - Enable build & test on branch `feature-foundry-agents` (#2068)

* Tests good, mkay

* Update .github/workflows/dotnet-build-and-test.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Enable feature build pipelines

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>

* Python: Add concrete AGUIChatClient (#2072)

* Add concrete AGUIChatClient

* Update logging docstrings and conventions

* PR feedback

* Updates to support client-side tool calls

* .NET: Move catalog samples to the HostedAgents folder (#2090)

* move catalog samples to the HostedAgents folder

* move the catalog samples' projects to the HostedAgents folder

* Bump OpenTelemetry.Instrumentation.Runtime from 1.12.0 to 1.13.0 (#1856)

---
updated-dependencies:
- dependency-name: OpenTelemetry.Instrumentation.Runtime
  dependency-version: 1.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* .NET: Bump Microsoft.SemanticKernel.Agents.Abstractions from 1.66.0 to 1.67.0 (#1962)

* Bump Microsoft.SemanticKernel.Agents.Abstractions from 1.66.0 to 1.67.0

---
updated-dependencies:
- dependency-name: Microsoft.SemanticKernel.Agents.Abstractions
  dependency-version: 1.67.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* .NET: Bump all Microsoft.SemanticKernel packages from 1.66.* to 1.67.* (#1969)

* Initial plan

* Update all Microsoft.SemanticKernel packages to 1.67.*

Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>

* Remove unrelated changes to package-lock.json and yarn.lock

Co-authored-by: markwallace-microsoft <127216156+markwallace-microsoft@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
Co-authored-by: markwallace-microsoft <127216156+markwallace-microsoft@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
Co-authored-by: markwallace-microsoft <127216156+markwallace-microsoft@users.noreply.github.com>

* .NET: fix: WorkflowAsAgent Sample (#1787)

* fix: WorkflowAsAgent Sample

* Also makes ChatForwardingExecutor public

* feat: Expand ChatForwardingExecutor handled types

Make ChatForwardingExecutor match the input types of ChatProtocolExecutor.

* fix: Update for the new AgentRunResponseUpdate merge logic

AIAgent always sends out List<ChatMessage> now.

* Updated (#2076)

* Bump vite in /python/samples/demos/chatkit-integration/frontend (#1918)

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.1.9 to 7.1.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.1.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.12
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump Roslynator.Analyzers from 4.14.0 to 4.14.1 (#1857)

---
updated-dependencies:
- dependency-name: Roslynator.Analyzers
  dependency-version: 4.14.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump MishaKav/pytest-coverage-comment from 1.1.57 to 1.1.59 (#2034)

Bumps [MishaKav/pytest-coverage-comment](https://github.com/mishakav/pytest-coverage-comment) from 1.1.57 to 1.1.59.
- [Release notes](https://github.com/mishakav/pytest-coverage-comment/releases)
- [Changelog](https://github.com/MishaKav/pytest-coverage-comment/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mishakav/pytest-coverage-comment/compare/v1.1.57...v1.1.59)

---
updated-dependencies:
- dependency-name: MishaKav/pytest-coverage-comment
  dependency-version: 1.1.59
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>

* Python: Handle agent user input request in AgentExecutor (#2022)

* Handle agent user input request in AgentExecutor

* fix test

* Address comments

* Fix tests

* Fix tests

* Address comments

* Address comments

* Python: OpenAI Responses Image Generation Stream Support, Sample and Unit Tests (#1853)

* support for image gen streaming

* small fixes

* fixes

* added comment

* Python: Fix MCP Tool Parameter Descriptions Not Propagated to LLMs (#1978)

* mcp tool description fix

* small fix

* .NET: Allow extending agent run options via additional properties (#1872)

* Allow extending agent run options via additional properties

This mirrors the M.E.AI model in ChatOptions.AdditionalProperties which is very useful when building functionality pipelines.

Fixes https://github.com/microsoft/agent-framework/issues/1815

* Expand XML documentation

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Add AdditionalProperties tests to AgentRunOptions

Co-authored-by: kzu <169707+kzu@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: kzu <169707+kzu@users.noreply.github.com>

* Python: Use the last entry in the task history to avoid empty responses (#2101)

* Use the last entry in the task history to avoid empty responses

* History only contains Messages

* Updated package versions (#2104)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Reuben Bond <203839+ReubenBond@users.noreply.github.com>
Co-authored-by: Peter Ibekwe <109177538+peibekwe@users.noreply.github.com>
Co-authored-by: Jeff Handley <jeffhandley@users.noreply.github.com>
Co-authored-by: Daniel Roth <daroth@microsoft.com>
Co-authored-by: Victor Dibia <chuvidi2003@gmail.com>
Co-authored-by: Mark Wallace <127216156+markwallace-microsoft@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Shawn Henry <sphenry@gmail.com>
Co-authored-by: Javier Calvarro Nelson <jacalvar@microsoft.com>
Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
Co-authored-by: Korolev Dmitry <deagle.gross@gmail.com>
Co-authored-by: westey <164392973+westey-m@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Reuben Bond <reuben.bond@gmail.com>
Co-authored-by: Tao Chen <taochen@microsoft.com>
Co-authored-by: wuweng <wuweng@microsoft.com>
Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
Co-authored-by: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Jacob Alber <jaalber@microsoft.com>
Co-authored-by: Giles Odigwe <79032838+giles17@users.noreply.github.com>
Co-authored-by: Daniel Cazzulino <daniel@cazzulino.com>
Co-authored-by: kzu <169707+kzu@users.noreply.github.com>
2025-11-11 23:12:09 -08:00

15 KiB

Getting Started with AG-UI (Python)

The AG-UI (Agent UI) protocol provides a standardized way for client applications to interact with AI agents over HTTP. This tutorial demonstrates how to build both server and client applications using the AG-UI protocol with Python.

Quick Start - Client Examples

If you want to quickly try out the AG-UI client, we provide three ready-to-use examples:

Basic Interactive Client (client.py)

A simple command-line chat client that demonstrates:

  • Streaming responses in real-time
  • Automatic thread management for conversation continuity
  • Direct AGUIChatClient usage (caller manages message history)

Run:

python client.py

Note: This example sends only the current message to the server. The server is responsible for maintaining conversation history using the thread_id.

Advanced Features Client (client_advanced.py)

Demonstrates advanced capabilities:

  • Tool/function calling
  • Both streaming and non-streaming responses
  • Multi-turn conversations
  • Error handling patterns

Run:

python client_advanced.py

Note: This example shows direct AGUIChatClient usage. Tool execution and conversation continuity depend on server-side configuration and capabilities.

ChatAgent Integration (client_with_agent.py)

Best practice example using ChatAgent wrapper with AgentThread

  • AgentThread maintains conversation state
  • Client-side conversation history management via thread.message_store
  • Hybrid tool execution: client-side + server-side tools simultaneously
  • Full conversation history sent on each request
  • Tool calling with conversation context

To demonstrate hybrid tools:

  1. Start server with server-side tool (Terminal 1):

    # Server has get_time_zone tool
    python server.py
    
  2. Run client with client-side tool (Terminal 2):

    # Client has get_weather tool
    python client_with_agent.py
    

All examples require a running AG-UI server (see Step 1 below for setup).

Understanding AG-UI Architecture

Thread Management

The AG-UI protocol supports two approaches to conversation history:

  1. Server-Managed Threads (client.py, client_advanced.py)

    • Client sends only the current message + thread_id
    • Server maintains full conversation history
    • Requires server to support stateful thread storage
    • Lighter network payload
  2. Client-Managed History (client_with_agent.py)

    • Client maintains full conversation history locally
    • Full message history sent with each request
    • Works with any AG-UI server (stateful or stateless)

The ChatAgent wrapper (used in client_with_agent.py) collects messages from local storage and sends the full history to AGUIChatClient, which then forwards everything to the server.

Tool/Function Calling

The AG-UI protocol supports hybrid tool execution - both client-side AND server-side tools can coexist in the same conversation.

The Hybrid Pattern (client_with_agent.py):

Client defines:           Server defines:
- get_weather()          - get_current_time()
- read_sensors()         - get_server_forecast()

User: "What's the weather in SF and what time is it?"
    ↓
ChatAgent sends: full history + tool definitions for get_weather, read_sensors
    ↓
Server LLM decides: "I need get_weather('SF') and get_current_time()"
    ↓
Server executes get_current_time() → "2025-11-11 14:30:00 UTC"
Server sends function call request → get_weather('SF')
    ↓
ChatAgent intercepts get_weather call → executes locally
    ↓
Client sends result → "Sunny, 72°F"
    ↓
Server combines both results → "It's sunny and 72°F in SF, and the current time is 2:30 PM UTC"
    ↓
Client receives final response

How it works:

  1. Client-Side Tools (client_with_agent.py):

    • Tools defined in ChatAgent's tools parameter execute locally
    • Tool metadata (name, description, schema) sent to server for planning
    • When server requests client tool → client intercepts → executes locally → sends result
  2. Server-Side Tools:

    • Defined in server agent's configuration
    • Server executes directly without client involvement
    • Results included in server's response
  3. Hybrid Pattern (Both Together):

    • Server LLM sees ALL tool definitions (client + server)
    • Decides which to use based on task
    • Server tools execute server-side
    • Client tools execute client-side

Direct AGUIChatClient Usage (client_advanced.py): Even without ChatAgent wrapper, client-side tools work:

  • Tools passed in ChatOptions execute locally
  • Server can also have its own tools
  • Hybrid execution works automatically

What is AG-UI?

AG-UI is a protocol that enables:

  • Remote agent hosting: Host AI agents as web services that can be accessed by multiple clients
  • Streaming responses: Real-time streaming of agent responses using Server-Sent Events (SSE)
  • Standardized communication: Consistent message format for agent interactions
  • Thread management: Maintain conversation context across multiple requests
  • Advanced features: Human-in-the-loop, state management, tool rendering

Prerequisites

Before you begin, ensure you have the following:

  • Python 3.10 or later
  • Azure OpenAI service endpoint and deployment configured
  • Azure CLI installed and authenticated (for DefaultAzureCredential)
  • User has the Cognitive Services OpenAI Contributor role for the Azure OpenAI resource

Note: These samples use Azure OpenAI models. For more information, see how to deploy Azure OpenAI models with Azure AI Foundry.

Note: These samples use DefaultAzureCredential for authentication. Make sure you're authenticated with Azure (e.g., via az login, or environment variables). For more information, see the Azure Identity documentation.

Warning

The AG-UI protocol is still under development and subject to change. We will keep these samples updated as the protocol evolves.

Step 1: Creating an AG-UI Server

The AG-UI server hosts your AI agent and exposes it via HTTP endpoints using FastAPI.

Install Required Packages

pip install agent-framework-ag-ui

Or using uv:

uv pip install agent-framework-ag-ui

Server Code

Create a file named server.py:

# Copyright (c) Microsoft. All rights reserved.

"""AG-UI server example."""

import os

from agent_framework import ChatAgent
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.ag_ui import add_agent_framework_fastapi_endpoint
from fastapi import FastAPI

# Read required configuration
endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT")
deployment_name = os.environ.get("AZURE_OPENAI_DEPLOYMENT_NAME")
api_key = os.environ.get("AZURE_OPENAI_API_KEY")

if not endpoint:
    raise ValueError("AZURE_OPENAI_ENDPOINT environment variable is required")
if not deployment_name:
    raise ValueError("AZURE_OPENAI_DEPLOYMENT_NAME environment variable is required")
if not api_key:
    raise ValueError("AZURE_OPENAI_API_KEY environment variable is required")

# Create the AI agent
agent = ChatAgent(
    name="AGUIAssistant",
    instructions="You are a helpful assistant.",
    chat_client=AzureOpenAIChatClient(
        endpoint=endpoint,
        deployment_name=deployment_name,
        api_key=api_key,
    ),
)

# Create FastAPI app
app = FastAPI(title="AG-UI Server")

# Register the AG-UI endpoint
add_agent_framework_fastapi_endpoint(app, agent, "/")

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="127.0.0.1", port=5100)

Key Concepts

  • add_agent_framework_fastapi_endpoint: Registers the AG-UI endpoint with automatic request/response handling and SSE streaming
  • ChatAgent: The agent that will handle incoming requests
  • FastAPI Integration: Uses FastAPI's native async support for streaming responses
  • Instructions: The agent is created with default instructions, which can be overridden by client messages
  • Configuration: AzureOpenAIChatClient can read from environment variables (AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_CHAT_DEPLOYMENT_NAME, AZURE_OPENAI_API_KEY) or accept parameters directly

Alternative (simpler): Use environment variables only:

# No need to read environment variables manually
agent = ChatAgent(
    name="AGUIAssistant",
    instructions="You are a helpful assistant.",
    chat_client=AzureOpenAIChatClient(),  # Reads from environment automatically
)

Configure and Run the Server

Set the required environment variables:

export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_OPENAI_CHAT_DEPLOYMENT_NAME="gpt-4o-mini"
# Optional: Set API key if not using DefaultAzureCredential
# export AZURE_OPENAI_API_KEY="your-api-key"

Run the server:

python server.py

Or using uvicorn directly:

uvicorn server:app --host 127.0.0.1 --port 5100

The server will start listening on http://127.0.0.1:5100.

Step 2: Creating an AG-UI Client

The AG-UI client connects to the remote server and displays streaming responses. The AGUIChatClient is a built-in implementation that integrates with the Agent Framework's standard chat interface.

Install Required Packages

The AGUIChatClient is included in the agent-framework-ag-ui package (already installed if you installed the server packages).

pip install agent-framework-ag-ui

Client Code

Create a file named client.py:

# Copyright (c) Microsoft. All rights reserved.

"""AG-UI client example using AGUIChatClient."""

import asyncio
import os

from agent_framework import TextContent
from agent_framework.ag_ui import AGUIChatClient


async def main():
    """Main client loop demonstrating AGUIChatClient usage."""
    # Get server URL from environment or use default
    server_url = os.environ.get("AGUI_SERVER_URL", "http://127.0.0.1:5100/")
    print(f"Connecting to AG-UI server at: {server_url}\n")

    # Create client with context manager for automatic cleanup
    async with AGUIChatClient(endpoint=server_url) as client:
        thread_id: str | None = None

        try:
            while True:
                # Get user input
                message = input("\nUser (:q or quit to exit): ")
                if not message.strip():
                    print("Request cannot be empty.")
                    continue

                if message.lower() in (":q", "quit"):
                    break

                # Send message and stream the response
                print("\nAssistant: ", end="", flush=True)

                # Use metadata to maintain conversation continuity
                metadata = {"thread_id": thread_id} if thread_id else None

                async for update in client.get_streaming_response(message, metadata=metadata):
                    # Extract thread ID from first update
                    if not thread_id and update.additional_properties:
                        thread_id = update.additional_properties.get("thread_id")
                        if thread_id:
                            print(f"\n[Thread: {thread_id}]")
                            print("Assistant: ", end="", flush=True)

                    # Stream text content as it arrives
                    for content in update.contents:
                        if isinstance(content, TextContent) and content.text:
                            print(content.text, end="", flush=True)

                print()  # New line after response

        except KeyboardInterrupt:
            print("\n\nExiting...")
        except Exception as e:
            print(f"\nAn error occurred: {e}")


if __name__ == "__main__":
    asyncio.run(main())

Key Concepts

  • AGUIChatClient: Built-in client that implements the Agent Framework's BaseChatClient interface
  • Automatic Event Handling: The client automatically converts AG-UI events to Agent Framework types
  • Thread Management: Pass thread_id in metadata to maintain conversation context across requests
  • Streaming Responses: Use get_streaming_response() for real-time streaming or get_response() for non-streaming
  • Context Manager: Use async with for automatic cleanup of HTTP connections
  • Standard Interface: Works with all Agent Framework patterns (ChatAgent, tools, etc.)
  • Hybrid Tool Execution: Supports both client-side and server-side tools executing together in the same conversation

Configure and Run the Client

Optionally set a custom server URL:

export AGUI_SERVER_URL="http://127.0.0.1:5100/"

Run the client (in a separate terminal):

python client.py

Step 3: Testing the Complete System

Expected Output

$ python client.py
Connecting to AG-UI server at: http://127.0.0.1:5100/

User (:q or quit to exit): What is the capital of France?

[Thread: abc123]
Assistant: The capital of France is Paris. It is known for its rich history, culture,
and iconic landmarks such as the Eiffel Tower and the Louvre Museum.

User (:q or quit to exit): Tell me a fun fact about space

Troubleshooting

Connection Refused

Ensure the server is running before starting the client:

# Terminal 1
python server.py

# Terminal 2 (after server starts)
python client.py

Authentication Errors

Make sure you're authenticated with Azure:

az login

Verify you have the correct role assignment on the Azure OpenAI resource.

Streaming Not Working

Check that your client timeout is sufficient:

httpx.AsyncClient(timeout=60.0)  # 60 seconds should be enough

For long-running agents, increase the timeout accordingly.

No Events Received

Ensure you're using the correct Accept header:

headers={"Accept": "text/event-stream"}

And parsing SSE format correctly (lines starting with data: ).

Thread Context Lost

The client automatically manages thread continuity. If context is lost:

  1. Check that threadId is being captured from RUN_STARTED events
  2. Ensure the same client instance is used across messages
  3. Verify the server is receiving the thread_id in subsequent requests

Event Type Mismatches

Remember that event types are UPPERCASE with underscores (RUN_STARTED, not run_started) and field names are camelCase (threadId, not thread_id).

Import Errors

Make sure all packages are installed:

pip install agent-framework-ag-ui agent-framework-core fastapi uvicorn httpx

Or check your virtual environment is activated:

source venv/bin/activate  # Linux/macOS
venv\Scripts\activate     # Windows