Files
Eduard van Valkenburg 5e056b672e Python: [BREAKING] Python: Provider-leading client design & OpenAI package extraction (#4818)
* Python: Provider-leading client design & OpenAI package extraction

Major refactoring of the Python Agent Framework client architecture:

- Extract OpenAI clients into new `agent-framework-openai` package
- Core package no longer depends on openai, azure-identity, azure-ai-projects
- Rename clients for discoverability: OpenAIResponsesClient → OpenAIChatClient,
  OpenAIChatClient → OpenAIChatCompletionClient
- Unify `model_id`/`deployment_name`/`model_deployment_name` → `model` param
- New FoundryChatClient for Azure AI Foundry Responses API
- New FoundryAgent/FoundryAgentClient for connecting to pre-configured Foundry agents
- Remove OpenAIBase/OpenAIConfigMixin from non-deprecated client MRO
- Deprecate AzureOpenAI* clients, AzureAIClient, OpenAIAssistantsClient
- Reorganize samples: azure_openai+azure_ai+azure_ai_agent → azure/
- ADR-0020: Provider-Leading Client Design

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

* fix: missing Agent imports in samples, .model_id → .model in foundry_local sample

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

* fix: CI failures — mypy errors, coverage targets, sample imports

- azure-ai mypy: add type ignores for TypedDict total=, model arg, forward ref
- Coverage: replace core.azure/openai targets with openai package target
- project_provider: add type annotation for opts dict

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

* fix: populate openai .pyi stub, fix broken README links, coverage targets

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

* fixes

* updated observabilitty

* reset azure init.pyi

* fix errors

* updated adr number

* fix foundry local

* fixed not renamed docstrings and comments, and added deprecated markers to old classes

* fix tests and pyprojects

* fix test vars

* updated function tests

* update durable

* updated test setup for functions

* Fix Foundry auth in workflow samples

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

* Stabilize Python integration workflows

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

* Update hosting samples for Foundry

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

* Trigger full CI rerun

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

* Trigger CI rerun again

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

* trigger rerun

* trigger rerun

* fix for litellm

* undo durabletask changes

* Move Foundry APIs into foundry namespace

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

* Fix Foundry pyproject formatting

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

* Split provider samples by Foundry surface

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

* Restore hosting sample requirements

Also fix the Foundry Local sample link after the provider sample move.

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

* updated tests

* udpated foundry integration tests

* removed dist from azurefunctions tests

* Use separate Foundry clients for concurrent agents

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

* fix client setup in azfunc and durable

* disabled two tests

* updated setup for some function and durable tests

* improved azure openai setup with new clients

* ignore deprecated

* fixes

* skip 11

* remove openai assistants int tests

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-25 09:56:29 +00:00

173 lines
5.5 KiB
Python

# Copyright (c) Microsoft. All rights reserved.
"""Agent definitions and AgentCard factories for the A2A server sample.
Provides factory functions to create Agent Framework agents and A2A
AgentCards for the invoice, policy, and logistics agent types.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from a2a.types import AgentCapabilities, AgentCard, AgentSkill
from invoice_data import query_by_invoice_id, query_by_transaction_id, query_invoices
if TYPE_CHECKING:
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
# ---------------------------------------------------------------------------
# Agent instructions
# ---------------------------------------------------------------------------
INVOICE_INSTRUCTIONS = "You specialize in handling queries related to invoices."
POLICY_INSTRUCTIONS = """\
You specialize in handling queries related to policies and customer communications.
Always reply with exactly this text:
Policy: Short Shipment Dispute Handling Policy V2.1
Summary: "For short shipments reported by customers, first verify internal shipment records
(SAP) and physical logistics scan data (BigQuery). If discrepancy is confirmed and logistics data
shows fewer items packed than invoiced, issue a credit for the missing items. Document the
resolution in SAP CRM and notify the customer via email within 2 business days, referencing the
original invoice and the credit memo number. Use the 'Formal Credit Notification' email
template."
"""
LOGISTICS_INSTRUCTIONS = """\
You specialize in handling queries related to logistics.
Always reply with exactly:
Shipment number: SHPMT-SAP-001
Item: TSHIRT-RED-L
Quantity: 900
"""
# ---------------------------------------------------------------------------
# Agent factories
# ---------------------------------------------------------------------------
def create_invoice_agent(client: FoundryChatClient) -> Agent:
"""Create an invoice agent backed by the given client with query tools."""
return Agent(
client=client,
name="InvoiceAgent",
instructions=INVOICE_INSTRUCTIONS,
tools=[query_invoices, query_by_transaction_id, query_by_invoice_id],
)
def create_policy_agent(client: FoundryChatClient) -> Agent:
"""Create a policy agent backed by the given client."""
return Agent(
client=client,
name="PolicyAgent",
instructions=POLICY_INSTRUCTIONS,
)
def create_logistics_agent(client: FoundryChatClient) -> Agent:
"""Create a logistics agent backed by the given client."""
return Agent(
client=client,
name="LogisticsAgent",
instructions=LOGISTICS_INSTRUCTIONS,
)
# ---------------------------------------------------------------------------
# AgentCard factories
# ---------------------------------------------------------------------------
_CAPABILITIES = AgentCapabilities(streaming=True, push_notifications=False)
def get_invoice_agent_card(url: str) -> AgentCard:
"""Return an A2A AgentCard for the invoice agent."""
return AgentCard(
name="InvoiceAgent",
description="Handles requests relating to invoices.",
url=url,
version="1.0.0",
default_input_modes=["text"],
default_output_modes=["text"],
capabilities=_CAPABILITIES,
skills=[
AgentSkill(
id="id_invoice_agent",
name="InvoiceQuery",
description="Handles requests relating to invoices.",
tags=["invoice", "agent-framework"],
examples=["List the latest invoices for Contoso."],
),
],
)
def get_policy_agent_card(url: str) -> AgentCard:
"""Return an A2A AgentCard for the policy agent."""
return AgentCard(
name="PolicyAgent",
description="Handles requests relating to policies and customer communications.",
url=url,
version="1.0.0",
default_input_modes=["text"],
default_output_modes=["text"],
capabilities=_CAPABILITIES,
skills=[
AgentSkill(
id="id_policy_agent",
name="PolicyAgent",
description="Handles requests relating to policies and customer communications.",
tags=["policy", "agent-framework"],
examples=["What is the policy for short shipments?"],
),
],
)
def get_logistics_agent_card(url: str) -> AgentCard:
"""Return an A2A AgentCard for the logistics agent."""
return AgentCard(
name="LogisticsAgent",
description="Handles requests relating to logistics.",
url=url,
version="1.0.0",
default_input_modes=["text"],
default_output_modes=["text"],
capabilities=_CAPABILITIES,
skills=[
AgentSkill(
id="id_logistics_agent",
name="LogisticsQuery",
description="Handles requests relating to logistics.",
tags=["logistics", "agent-framework"],
examples=["What is the status for SHPMT-SAP-001"],
),
],
)
# ---------------------------------------------------------------------------
# Lookup helpers
# ---------------------------------------------------------------------------
AGENT_FACTORIES = {
"invoice": create_invoice_agent,
"policy": create_policy_agent,
"logistics": create_logistics_agent,
}
AGENT_CARD_FACTORIES = {
"invoice": get_invoice_agent_card,
"policy": get_policy_agent_card,
"logistics": get_logistics_agent_card,
}