Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions python/.github/skills/python-development/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def equal(arg1: str, arg2: str) -> bool:

```python
# Core
from agent_framework import ChatAgent, ChatMessage, tool
from agent_framework import ChatAgent, Message, tool

# Components
from agent_framework.observability import enable_instrumentation
Expand All @@ -84,10 +84,10 @@ from agent_framework.azure import AzureOpenAIChatClient
Define `__all__` in each module. Avoid `from module import *` in `__init__.py` files:

```python
__all__ = ["ChatAgent", "ChatMessage", "ChatResponse"]
__all__ = ["ChatAgent", "Message", "ChatResponse"]

from ._agents import ChatAgent
from ._types import ChatMessage, ChatResponse
from ._types import Message, ChatResponse
```

## Performance Guidelines
Expand Down
11 changes: 9 additions & 2 deletions python/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- **agent-framework-core**: Add long-running agents and background responses support with `ContinuationToken` TypedDict, `background` option in `OpenAIResponsesOptions`, and continuation token propagation through response types ([#2478](https://github.com/microsoft/agent-framework/issues/2478))
### Changed

- **agent-framework-core**: [BREAKING] Renamed core types for simpler API:
- `ChatAgent` → `Agent`
- `RawChatAgent` → `RawAgent`
- `ChatMessage` → `Message`
- `ChatClientProtocol` → `SupportsChatGetResponse`

## [1.0.0b260130] - 2026-01-30

Expand Down Expand Up @@ -272,7 +279,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- **agent-framework-core**: [BREAKING] Support Magentic agent tool call approvals and plan stalling HITL behavior (#2569)
- **agent-framework-core**: [BREAKING] Standardize orchestration outputs as list of `ChatMessage`; allow agent as group chat manager (#2291)
- **agent-framework-core**: [BREAKING] Standardize orchestration outputs as list of `Message`; allow agent as group chat manager (#2291)
- **agent-framework-core**: [BREAKING] Respond with `AgentRunResponse` including serialized structured output (#2285)
- **observability**: Use `executor_id` and `edge_group_id` as span names for clearer traces (#2538)
- **agent-framework-devui**: Add multimodal input support for workflows and refactor chat input (#2593)
Expand Down Expand Up @@ -318,7 +325,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **agent-framework-core**: Fix tool execution bleed-over in aiohttp/Bot Framework scenarios ([#2314](https://github.com/microsoft/agent-framework/pull/2314))
- **agent-framework-core**: `@ai_function` now correctly handles `self` parameter ([#2266](https://github.com/microsoft/agent-framework/pull/2266))
- **agent-framework-core**: Resolve string annotations in `FunctionExecutor` ([#2308](https://github.com/microsoft/agent-framework/pull/2308))
- **agent-framework-core**: Langfuse observability captures ChatAgent system instructions ([#2316](https://github.com/microsoft/agent-framework/pull/2316))
- **agent-framework-core**: Langfuse observability captures Agent system instructions ([#2316](https://github.com/microsoft/agent-framework/pull/2316))
- **agent-framework-core**: Incomplete URL substring sanitization fix ([#2274](https://github.com/microsoft/agent-framework/pull/2274))
- **observability**: Handle datetime serialization in tool results ([#2248](https://github.com/microsoft/agent-framework/pull/2248))

Expand Down
18 changes: 9 additions & 9 deletions python/CODING_STANDARD.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ Prefer attributes over inheritance when parameters are mostly the same:

```python
# ✅ Preferred - using attributes
from agent_framework import ChatMessage
from agent_framework import Message

user_msg = ChatMessage("user", ["Hello, world!"])
asst_msg = ChatMessage("assistant", ["Hello, world!"])
user_msg = Message("user", ["Hello, world!"])
asst_msg = Message("assistant", ["Hello, world!"])

# ❌ Not preferred - unnecessary inheritance
from agent_framework import UserMessage, AssistantMessage
Expand Down Expand Up @@ -157,7 +157,7 @@ The package follows a flat import structure:

- **Core**: Import directly from `agent_framework`
```python
from agent_framework import ChatAgent, tool
from agent_framework import Agent, tool
```

- **Components**: Import from `agent_framework.<component>`
Expand Down Expand Up @@ -381,12 +381,12 @@ def create_client(
Use Google-style docstrings for all public APIs:

```python
def create_agent(name: str, chat_client: ChatClientProtocol) -> Agent:
def create_agent(name: str, client: SupportsChatGetResponse) -> Agent:
"""Create a new agent with the specified configuration.

Args:
name: The name of the agent.
chat_client: The chat client to use for communication.
client: The chat client to use for communication.

Returns:
True if the strings are the same, False otherwise.
Expand All @@ -409,10 +409,10 @@ Define `__all__` in each module to explicitly declare the public API. Avoid usin

```python
# ✅ Preferred - explicit __all__ and imports
__all__ = ["ChatAgent", "ChatMessage", "ChatResponse"]
__all__ = ["Agent", "Message", "ChatResponse"]

from ._agents import ChatAgent
from ._types import ChatMessage, ChatResponse
from ._agents import Agent
from ._types import Message, ChatResponse

# ❌ Avoid - star imports
from ._agents import *
Expand Down
2 changes: 1 addition & 1 deletion python/DEV_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ You will then configure the ChatClient class with the keyword argument `env_file
```python
from agent_framework.openai import OpenAIChatClient

chat_client = OpenAIChatClient(env_file_path="openai.env")
client = OpenAIChatClient(env_file_path="openai.env")
```

## Tests
Expand Down
30 changes: 15 additions & 15 deletions python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ You can also override environment variables by explicitly passing configuration
```python
from agent_framework.azure import AzureOpenAIChatClient

chat_client = AzureOpenAIChatClient(
client = AzureOpenAIChatClient(
api_key='',
endpoint='',
deployment_name='',
Expand All @@ -78,12 +78,12 @@ Create agents and invoke them directly:

```python
import asyncio
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient

async def main():
agent = ChatAgent(
chat_client=OpenAIChatClient(),
agent = Agent(
client=OpenAIChatClient(),
instructions="""
1) A robot may not injure a human being...
2) A robot must obey orders given it by human beings...
Expand All @@ -106,15 +106,15 @@ You can use the chat client classes directly for advanced workflows:

```python
import asyncio
from agent_framework import ChatMessage
from agent_framework import Message
from agent_framework.openai import OpenAIChatClient

async def main():
client = OpenAIChatClient()

messages = [
ChatMessage("system", ["You are a helpful assistant."]),
ChatMessage("user", ["Write a haiku about Agent Framework."])
Message("system", ["You are a helpful assistant."]),
Message("user", ["Write a haiku about Agent Framework."])
]

response = await client.get_response(messages)
Expand All @@ -140,7 +140,7 @@ import asyncio
from typing import Annotated
from random import randint
from pydantic import Field
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient


Expand All @@ -162,8 +162,8 @@ def get_menu_specials() -> str:


async def main():
agent = ChatAgent(
chat_client=OpenAIChatClient(),
agent = Agent(
client=OpenAIChatClient(),
instructions="You are a helpful assistant that can provide weather and restaurant information.",
tools=[get_weather, get_menu_specials]
)
Expand All @@ -189,20 +189,20 @@ Coordinate multiple agents to collaborate on complex tasks using orchestration p

```python
import asyncio
from agent_framework import ChatAgent
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient


async def main():
# Create specialized agents
writer = ChatAgent(
chat_client=OpenAIChatClient(),
writer = Agent(
client=OpenAIChatClient(),
name="Writer",
instructions="You are a creative content writer. Generate and refine slogans based on feedback."
)

reviewer = ChatAgent(
chat_client=OpenAIChatClient(),
reviewer = Agent(
client=OpenAIChatClient(),
name="Reviewer",
instructions="You are a critical reviewer. Provide detailed feedback on proposed slogans."
)
Expand Down
38 changes: 19 additions & 19 deletions python/packages/a2a/agent_framework_a2a/_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
FilePart,
FileWithBytes,
FileWithUri,
Message,
Task,
TaskIdParams,
TaskQueryParams,
Expand All @@ -34,9 +33,9 @@
AgentResponseUpdate,
AgentThread,
BaseAgent,
ChatMessage,
Content,
ContinuationToken,
Message,
ResponseStream,
normalize_messages,
prepend_agent_framework_to_user_agent,
Expand Down Expand Up @@ -83,7 +82,7 @@ class A2AAgent(AgentTelemetryLayer, BaseAgent):
"""Agent2Agent (A2A) protocol implementation.

Wraps an A2A Client to connect the Agent Framework with external A2A-compliant agents
via HTTP/JSON-RPC. Converts framework ChatMessages to A2A Messages on send, and converts
via HTTP/JSON-RPC. Converts framework Messages to A2A Messages on send, and converts
A2A responses (Messages/Tasks) back to framework types. Inherits BaseAgent capabilities
while managing the underlying A2A protocol communication.

Expand Down Expand Up @@ -209,7 +208,7 @@ async def __aexit__(
@overload
def run(
self,
messages: str | ChatMessage | Sequence[str | ChatMessage] | None = None,
messages: str | Message | Sequence[str | Message] | None = None,
*,
stream: Literal[False] = ...,
thread: AgentThread | None = None,
Expand All @@ -221,7 +220,7 @@ def run(
@overload
def run(
self,
messages: str | ChatMessage | Sequence[str | ChatMessage] | None = None,
messages: str | Message | Sequence[str | Message] | None = None,
*,
stream: Literal[True],
thread: AgentThread | None = None,
Expand All @@ -232,7 +231,7 @@ def run(

def run(
self,
messages: str | ChatMessage | Sequence[str | ChatMessage] | None = None,
messages: str | Message | Sequence[str | Message] | None = None,
*,
stream: bool = False,
thread: AgentThread | None = None,
Expand Down Expand Up @@ -268,7 +267,7 @@ def run(

response = ResponseStream(
self._map_a2a_stream(a2a_stream, background=background),
finalizer=lambda updates: AgentResponse.from_updates(list(updates)),
finalizer=AgentResponse.from_updates,
)
if stream:
return response
Expand All @@ -291,7 +290,8 @@ async def _map_a2a_stream(
When True, they are yielded with a continuation token.
"""
async for item in a2a_stream:
if isinstance(item, Message):
if isinstance(item, A2AMessage):
# Process A2A Message
contents = self._parse_contents_from_a2a(item.parts)
yield AgentResponseUpdate(
contents=contents,
Expand Down Expand Up @@ -377,10 +377,10 @@ async def poll_task(self, continuation_token: A2AContinuationToken) -> AgentResp
return AgentResponse.from_updates(updates)
return AgentResponse(messages=[], response_id=task.id, raw_representation=task)

def _prepare_message_for_a2a(self, message: ChatMessage) -> A2AMessage:
"""Prepare a ChatMessage for the A2A protocol.
def _prepare_message_for_a2a(self, message: Message) -> A2AMessage:
"""Prepare a Message for the A2A protocol.

Transforms Agent Framework ChatMessage objects into A2A protocol Messages by:
Transforms Agent Framework Message objects into A2A protocol Messages by:
- Converting all message contents to appropriate A2A Part types
- Mapping text content to TextPart objects
- Converting file references (URI/data/hosted_file) to FilePart objects
Expand All @@ -389,7 +389,7 @@ def _prepare_message_for_a2a(self, message: ChatMessage) -> A2AMessage:
"""
parts: list[A2APart] = []
if not message.contents:
raise ValueError("ChatMessage.contents is empty; cannot convert to A2AMessage.")
raise ValueError("Message.contents is empty; cannot convert to A2AMessage.")

# Process ALL contents
for content in message.contents:
Expand Down Expand Up @@ -511,9 +511,9 @@ def _parse_contents_from_a2a(self, parts: Sequence[A2APart]) -> list[Content]:
raise ValueError(f"Unknown Part kind: {inner_part.kind}")
return contents

def _parse_messages_from_task(self, task: Task) -> list[ChatMessage]:
"""Parse A2A Task artifacts into ChatMessages with ASSISTANT role."""
messages: list[ChatMessage] = []
def _parse_messages_from_task(self, task: Task) -> list[Message]:
"""Parse A2A Task artifacts into Messages with ASSISTANT role."""
messages: list[Message] = []

if task.artifacts is not None:
for artifact in task.artifacts:
Expand All @@ -523,7 +523,7 @@ def _parse_messages_from_task(self, task: Task) -> list[ChatMessage]:
history_item = task.history[-1]
contents = self._parse_contents_from_a2a(history_item.parts)
messages.append(
ChatMessage(
Message(
role="assistant" if history_item.role == A2ARole.agent else "user",
contents=contents,
raw_representation=history_item,
Expand All @@ -532,10 +532,10 @@ def _parse_messages_from_task(self, task: Task) -> list[ChatMessage]:

return messages

def _parse_message_from_artifact(self, artifact: Artifact) -> ChatMessage:
"""Parse A2A Artifact into ChatMessage using part contents."""
def _parse_message_from_artifact(self, artifact: Artifact) -> Message:
"""Parse A2A Artifact into Message using part contents."""
contents = self._parse_contents_from_a2a(artifact.parts)
return ChatMessage(
return Message(
role="assistant",
contents=contents,
raw_representation=artifact,
Expand Down
Loading
Loading