mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
361c47f30f
* 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>
462 lines
15 KiB
Markdown
462 lines
15 KiB
Markdown
# 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:**
|
|
```bash
|
|
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:**
|
|
```bash
|
|
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):
|
|
```bash
|
|
# Server has get_time_zone tool
|
|
python server.py
|
|
```
|
|
|
|
2. **Run client with client-side tool** (Terminal 2):
|
|
```bash
|
|
# 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](https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/deploy-models-openai).
|
|
|
|
**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](https://learn.microsoft.com/python/api/azure-identity/azure.identity.defaultazurecredential).
|
|
|
|
> **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
|
|
|
|
```bash
|
|
pip install agent-framework-ag-ui
|
|
```
|
|
|
|
Or using uv:
|
|
|
|
```bash
|
|
uv pip install agent-framework-ag-ui
|
|
```
|
|
|
|
### Server Code
|
|
|
|
Create a file named `server.py`:
|
|
|
|
```python
|
|
# 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:
|
|
|
|
```python
|
|
# 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
python server.py
|
|
```
|
|
|
|
Or using uvicorn directly:
|
|
|
|
```bash
|
|
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).
|
|
|
|
```bash
|
|
pip install agent-framework-ag-ui
|
|
```
|
|
|
|
### Client Code
|
|
|
|
Create a file named `client.py`:
|
|
|
|
```python
|
|
# 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:
|
|
|
|
```bash
|
|
export AGUI_SERVER_URL="http://127.0.0.1:5100/"
|
|
```
|
|
|
|
Run the client (in a separate terminal):
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
# Terminal 1
|
|
python server.py
|
|
|
|
# Terminal 2 (after server starts)
|
|
python client.py
|
|
```
|
|
|
|
### Authentication Errors
|
|
|
|
Make sure you're authenticated with Azure:
|
|
|
|
```bash
|
|
az login
|
|
```
|
|
|
|
Verify you have the correct role assignment on the Azure OpenAI resource.
|
|
|
|
### Streaming Not Working
|
|
|
|
Check that your client timeout is sufficient:
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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:
|
|
|
|
```bash
|
|
pip install agent-framework-ag-ui agent-framework-core fastapi uvicorn httpx
|
|
```
|
|
|
|
Or check your virtual environment is activated:
|
|
|
|
```bash
|
|
source venv/bin/activate # Linux/macOS
|
|
venv\Scripts\activate # Windows
|
|
```
|