Compare commits

..
19 changed files with 139 additions and 118 deletions
@@ -8,11 +8,12 @@ from typing import Annotated
from agent_framework import Message, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework.observability import enable_instrumentation
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from opentelemetry._logs import set_logger_provider
from opentelemetry.metrics import set_meter_provider
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogExporter
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogRecordExporter
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import ConsoleMetricExporter, PeriodicExportingMetricReader
from opentelemetry.sdk.resources import Resource
@@ -37,7 +38,7 @@ def setup_logging():
# Create and set a global logger provider for the application.
logger_provider = LoggerProvider(resource=resource)
# Log processors are initialized with an exporter which is responsible
logger_provider.add_log_record_processor(BatchLogRecordProcessor(ConsoleLogExporter()))
logger_provider.add_log_record_processor(BatchLogRecordProcessor(ConsoleLogRecordExporter()))
# Sets the global default logger provider
set_logger_provider(logger_provider)
# Create a logging handler to write logging records, in OTLP format, to the exporter.
@@ -115,11 +116,15 @@ async def run_chat_client() -> None:
2 spans with gen_ai.operation.name=execute_tool
"""
client = FoundryChatClient()
client = FoundryChatClient(credential=AzureCliCredential())
message = "What's the weather in Amsterdam and in Paris?"
print(f"User: {message}")
print("Assistant: ", end="")
async for chunk in client.get_response([Message(role="user", text=message)], tools=get_weather, stream=True):
async for chunk in client.get_response(
[Message(role="user", text=message)],
stream=True,
options={"tools": [get_weather]},
):
if chunk.text:
print(chunk.text, end="")
print("")
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, Annotated
from agent_framework import Message, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework.observability import get_tracer
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from opentelemetry.trace import SpanKind
from opentelemetry.trace.span import format_trace_id
@@ -90,12 +91,19 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
print(f"User: {message}")
if stream:
print("Assistant: ", end="")
async for chunk in client.get_response([Message(role="user", text=message)], tools=get_weather, stream=True):
async for chunk in client.get_response(
[Message(role="user", text=message)],
stream=True,
options={"tools": [get_weather]},
):
if chunk.text:
print(chunk.text, end="")
print("")
else:
response = await client.get_response([Message(role="user", text=message)], tools=get_weather)
response = await client.get_response(
[Message(role="user", text=message)],
options={"tools": [get_weather]},
)
print(f"Assistant: {response}")
@@ -103,7 +111,7 @@ async def main() -> None:
with get_tracer().start_as_current_span("Zero Code", kind=SpanKind.CLIENT) as current_span:
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
client = FoundryChatClient()
client = FoundryChatClient(credential=AzureCliCredential())
await run_chat_client(client, stream=True)
await run_chat_client(client, stream=False)
@@ -7,6 +7,7 @@ from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework.observability import configure_otel_providers, get_tracer
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from opentelemetry.trace import SpanKind
from opentelemetry.trace.span import format_trace_id
@@ -18,6 +19,12 @@ load_dotenv()
"""
This sample shows how you can observe an agent in Agent Framework by using the
same observability setup function.
Pre-requisites:
- A Foundry project
- An observability backend to receive traces and metrics (for example, a local or remote
OpenTelemetry Collector, another OTLP-compatible backend, or console exporters enabled
via environment variables).
"""
@@ -47,7 +54,7 @@ async def main():
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
agent = Agent(
client=FoundryChatClient(),
client=FoundryChatClient(credential=AzureCliCredential()),
tools=get_weather,
name="WeatherAgent",
instructions="You are a weather assistant.",
@@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Annotated, Literal
from agent_framework import Message, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework.observability import configure_otel_providers, get_tracer
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from opentelemetry import trace
from opentelemetry.trace.span import format_trace_id
@@ -24,8 +25,9 @@ This sample shows how you can configure observability of an application via the
When you run this sample with an OTLP endpoint or an Application Insights connection string,
you should see traces, logs, and metrics in the configured backend.
If no OTLP endpoint or Application Insights connection string is configured, the sample will
output traces, logs, and metrics to the console.
Pre-requisites:
- A Foundry project
- A local OpenTelemetry Collector instance to receive the traces and metrics.
"""
# Load environment variables from .env file
@@ -78,13 +80,18 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
if stream:
print("Assistant: ", end="")
async for chunk in client.get_response(
[Message(role="user", text=message)], tools=get_weather, stream=True
[Message(role="user", text=message)],
stream=True,
options={"tools": [get_weather]},
):
if chunk.text:
print(chunk.text, end="")
print("")
else:
response = await client.get_response([Message(role="user", text=message)], tools=get_weather)
response = await client.get_response(
[Message(role="user", text=message)],
options={"tools": [get_weather]},
)
print(f"Assistant: {response}")
@@ -101,7 +108,7 @@ async def run_tool() -> None:
with get_tracer().start_as_current_span("Scenario: AI Function", kind=trace.SpanKind.CLIENT):
print("Running scenario: AI Function")
weather = await get_weather.invoke(location="Amsterdam")
print(f"Weather in Amsterdam:\n{weather}")
print(f"Weather in Amsterdam:\n{weather[-1]}")
async def main(scenario: Literal["client", "client_stream", "tool", "all"] = "all"):
@@ -114,7 +121,7 @@ async def main(scenario: Literal["client", "client_stream", "tool", "all"] = "al
with get_tracer().start_as_current_span("Sample Scenarios", kind=trace.SpanKind.CLIENT) as current_span:
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
client = FoundryChatClient()
client = FoundryChatClient(credential=AzureCliCredential())
# Scenarios where telemetry is collected in the SDK, from the most basic to the most complex.
if scenario == "tool" or scenario == "all":
@@ -10,6 +10,7 @@ from typing import TYPE_CHECKING, Annotated, Literal
from agent_framework import Message, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework.observability import configure_otel_providers, get_tracer
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
from opentelemetry import trace
from opentelemetry.trace.span import format_trace_id
@@ -27,6 +28,10 @@ and allows you to add multiple exporters programmatically.
For standard OTLP setup, it's recommended to use environment variables (see configure_otel_providers_with_env_var.py).
Use this approach when you need custom exporter configuration beyond what environment variables provide.
Pre-requisites:
- A Foundry project
- A local OpenTelemetry Collector instance to receive the traces and metrics.
"""
# Load environment variables from .env file
@@ -79,13 +84,18 @@ async def run_chat_client(client: "SupportsChatGetResponse", stream: bool = Fals
if stream:
print("Assistant: ", end="")
async for chunk in client.get_response(
[Message(role="user", text=message)], stream=True, tools=get_weather
[Message(role="user", text=message)],
stream=True,
options={"tools": [get_weather]},
):
if chunk.text:
print(chunk.text, end="")
print("")
else:
response = await client.get_response([Message(role="user", text=message)], tools=get_weather)
response = await client.get_response(
[Message(role="user", text=message)],
options={"tools": [get_weather]},
)
print(f"Assistant: {response}")
@@ -102,7 +112,7 @@ async def run_tool() -> None:
with get_tracer().start_as_current_span("Scenario: AI Function", kind=trace.SpanKind.CLIENT):
print("Running scenario: AI Function")
weather = await get_weather.invoke(location="Amsterdam")
print(f"Weather in Amsterdam:\n{weather}")
print(f"Weather in Amsterdam:\n{weather[-1]}")
async def main(scenario: Literal["client", "client_stream", "tool", "all"] = "all"):
@@ -153,7 +163,7 @@ async def main(scenario: Literal["client", "client_stream", "tool", "all"] = "al
with get_tracer().start_as_current_span("Sample Scenarios", kind=trace.SpanKind.CLIENT) as current_span:
print(f"Trace ID: {format_trace_id(current_span.get_span_context().trace_id)}")
client = FoundryChatClient()
client = FoundryChatClient(credential=AzureCliCredential())
# Scenarios where telemetry is collected in the SDK, from the most basic to the most complex.
if scenario == "tool" or scenario == "all":
+4 -4
View File
@@ -6,9 +6,9 @@ This gallery helps AutoGen developers move to the Microsoft Agent Framework (AF)
### Single-Agent Parity
- [01_basic_agent.py](single_agent/01_basic_agent.py) — Minimal AutoGen `AssistantAgent` and AF `Agent` comparison.
- [02_agent_with_tool.py](single_agent/02_agent_with_tool.py) — Function tool integration in both SDKs.
- [03_agent_thread_and_stream.py](single_agent/03_agent_thread_and_stream.py) — Session management and streaming responses.
- [01_basic_assistant_agent.py](single_agent/01_basic_assistant_agent.py) — Minimal AutoGen `AssistantAgent` and AF `Agent` comparison.
- [02_assistant_agent_with_tool.py](single_agent/02_assistant_agent_with_tool.py) — Function tool integration in both SDKs.
- [03_assistant_agent_thread_and_stream.py](single_agent/03_assistant_agent_thread_and_stream.py) — Session management and streaming responses.
- [04_agent_as_tool.py](single_agent/04_agent_as_tool.py) — Using agents as tools (hierarchical agent pattern) and streaming with tools.
### Multi-Agent Orchestration
@@ -35,7 +35,7 @@ Each script is fully async and the `main()` routine runs both implementations ba
From the repository root:
```bash
python samples/autogen-migration/single_agent/01_basic_agent.py
python samples/autogen-migration/single_agent/01_basic_assistant_agent.py
```
Every script accepts no CLI arguments and will first call the AutoGen implementation, followed by the AF version. Adjust the prompt or credentials inside the file as necessary before running.
@@ -65,7 +65,7 @@ async def run_agent_framework() -> None:
from agent_framework.openai import OpenAIChatClient
from agent_framework.orchestrations import SequentialBuilder
client = OpenAIChatClient(model="gpt-4.1-mini")
client = OpenAIChatClient(model_id="gpt-4.1-mini")
# Create specialized agents
researcher = Agent(
@@ -112,7 +112,7 @@ async def run_agent_framework_with_cycle() -> None:
)
from agent_framework.openai import OpenAIChatClient
client = OpenAIChatClient(model="gpt-4.1-mini")
client = OpenAIChatClient(model_id="gpt-4.1-mini")
# Create specialized agents
researcher = Agent(
@@ -76,7 +76,7 @@ async def run_agent_framework() -> None:
from agent_framework.openai import OpenAIChatClient
from agent_framework.orchestrations import MagenticBuilder
client = OpenAIChatClient(model="gpt-4.1-mini")
client = OpenAIChatClient(model_id="gpt-4.1-mini")
# Create specialized agents
researcher = Agent(
@@ -23,7 +23,7 @@ load_dotenv()
async def run_semantic_kernel() -> None:
from semantic_kernel.agents import ChatCompletionAgent
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.functions import kernel_function
@@ -39,7 +39,11 @@ async def run_semantic_kernel() -> None:
instructions="Answer menu questions accurately.",
plugins=[SpecialsPlugin()],
)
response = await agent.get_response("What soup can I order today?")
thread = ChatHistoryAgentThread()
response = await agent.get_response(
messages="What soup can I order today?",
thread=thread,
)
print("[SK]", response.message.content)
@@ -58,7 +62,12 @@ async def run_agent_framework() -> None:
instructions="Answer menu questions accurately.",
tools=[specials],
)
reply = await chat_agent.run("What soup can I order today?")
session = chat_agent.create_session()
reply = await chat_agent.run(
"What soup can I order today?",
session=session,
tool_choice="auto",
)
print("[AF]", reply.text)
@@ -22,13 +22,10 @@ async def run_semantic_kernel() -> None:
from semantic_kernel.agents import OpenAIResponsesAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
openai_settings = OpenAISettings()
assert openai_settings.responses_model_id is not None, "Responses model ID must be set in OpenAISettings"
client = OpenAIResponsesAgent.create_client()
# SK response agents wrap OpenAI's hosted Responses API.
agent = OpenAIResponsesAgent(
ai_model_id=openai_settings.responses_model_id,
ai_model=OpenAISettings().responses_model_id,
client=client,
instructions="Answer in one concise sentence.",
name="Expert",
@@ -28,13 +28,10 @@ async def run_semantic_kernel() -> None:
def add(self, a: float, b: float) -> float:
return a + b
openai_settings = OpenAISettings()
assert openai_settings.responses_model_id is not None, "Responses model ID must be set in OpenAISettings"
client = OpenAIResponsesAgent.create_client()
# Plugins advertise callable tools to the Responses agent.
agent = OpenAIResponsesAgent(
ai_model_id=openai_settings.responses_model_id,
ai_model=OpenAISettings().responses_model_id,
client=client,
instructions="Use the add tool when math is required.",
name="MathExpert",
@@ -29,17 +29,14 @@ async def run_semantic_kernel() -> None:
from semantic_kernel.agents import OpenAIResponsesAgent
from semantic_kernel.connectors.ai.open_ai import OpenAISettings
openai_settings = OpenAISettings()
assert openai_settings.responses_model_id is not None, "Responses model ID must be set in OpenAISettings"
client = OpenAIResponsesAgent.create_client()
# response_format requests schema-constrained output from the model.
agent = OpenAIResponsesAgent(
ai_model_id=openai_settings.responses_model_id,
ai_model=OpenAISettings().responses_model_id,
client=client,
instructions="Return launch briefs as structured JSON.",
name="ProductMarketer",
text=OpenAIResponsesAgent.configure_response_format(ReleaseBrief), # type: ignore
text=OpenAIResponsesAgent.configure_response_format(ReleaseBrief),
)
response = await agent.get_response(
"Draft a launch brief for the Contoso Note app.",
@@ -55,7 +55,7 @@ def build_semantic_kernel_agents() -> list[ChatCompletionAgent]:
async def run_semantic_kernel_example(prompt: str) -> Sequence[ChatMessageContent]:
concurrent_orchestration = ConcurrentOrchestration(members=build_semantic_kernel_agents()) # type: ignore
concurrent_orchestration = ConcurrentOrchestration(members=build_semantic_kernel_agents())
runtime = InProcessRuntime()
runtime.start()
@@ -91,14 +91,12 @@ def _print_semantic_kernel_outputs(outputs: Sequence[ChatMessageContent]) -> Non
async def run_agent_framework_example(prompt: str) -> Sequence[list[Message]]:
client = OpenAIChatCompletionClient(credential=AzureCliCredential())
physics = Agent(
client=client,
physics = Agent(client=client,
instructions=("You are an expert in physics. Answer questions from a physics perspective."),
name="physics",
)
chemistry = Agent(
client=client,
chemistry = Agent(client=client,
instructions=("You are an expert in chemistry. Answer questions from a chemistry perspective."),
name="chemistry",
)
@@ -16,8 +16,8 @@ import sys
from collections.abc import Sequence
from typing import Any, cast
from agent_framework import Agent, AgentResponseUpdate, Message
from agent_framework.openai import OpenAIChatCompletionClient
from agent_framework import Agent, Message
from agent_framework.foundry import FoundryChatClient
from agent_framework.orchestrations import GroupChatBuilder
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
@@ -82,6 +82,9 @@ def build_semantic_kernel_agents() -> list[ChatCompletionAgent]:
class ChatCompletionGroupChatManager(GroupChatManager):
"""Group chat manager that delegates orchestration decisions to an Azure OpenAI deployment."""
service: ChatCompletionClientBase
topic: str
termination_prompt: str = (
"You are coordinating a conversation about '{{$topic}}'. "
"Decide if the discussion has produced a solid answer. "
@@ -101,11 +104,8 @@ class ChatCompletionGroupChatManager(GroupChatManager):
)
def __init__(self, *, topic: str, service: ChatCompletionClientBase, max_rounds: int | None = None) -> None:
super().__init__(max_rounds=max_rounds)
super().__init__(topic=topic, service=service, max_rounds=max_rounds)
self._round_robin_index = 0
self._topic = topic
self._service = service
async def _render_prompt(self, template: str, **kwargs: Any) -> str:
prompt_template = KernelPromptTemplate(prompt_template_config=PromptTemplateConfig(template=template))
@@ -117,7 +117,7 @@ class ChatCompletionGroupChatManager(GroupChatManager):
@override
async def should_terminate(self, chat_history: ChatHistory) -> BooleanResult:
rendered_prompt = await self._render_prompt(self.termination_prompt, topic=self._topic)
rendered_prompt = await self._render_prompt(self.termination_prompt, topic=self.topic)
chat_history.messages.insert(
0,
ChatMessageContent(role=AuthorRole.SYSTEM, content=rendered_prompt),
@@ -126,11 +126,11 @@ class ChatCompletionGroupChatManager(GroupChatManager):
ChatMessageContent(role=AuthorRole.USER, content="Decide if the discussion is complete."),
)
response = await self._service.get_chat_message_content(
response = await self.service.get_chat_message_content(
chat_history,
settings=PromptExecutionSettings(response_format=BooleanResult),
)
return BooleanResult.model_validate_json(response.content) # type: ignore
return BooleanResult.model_validate_json(response.content)
@override
async def select_next_agent(
@@ -140,7 +140,7 @@ class ChatCompletionGroupChatManager(GroupChatManager):
) -> StringResult:
rendered_prompt = await self._render_prompt(
self.selection_prompt,
topic=self._topic,
topic=self.topic,
participants=", ".join(participant_descriptions.keys()),
)
chat_history.messages.insert(
@@ -151,18 +151,18 @@ class ChatCompletionGroupChatManager(GroupChatManager):
ChatMessageContent(role=AuthorRole.USER, content="Pick the next participant to speak."),
)
response = await self._service.get_chat_message_content(
response = await self.service.get_chat_message_content(
chat_history,
settings=PromptExecutionSettings(response_format=StringResult),
)
result = StringResult.model_validate_json(response.content) # type: ignore
result = StringResult.model_validate_json(response.content)
if result.result not in participant_descriptions:
raise RuntimeError(f"Unknown participant selected: {result.result}")
return result
@override
async def filter_results(self, chat_history: ChatHistory) -> MessageResult:
rendered_prompt = await self._render_prompt(self.summary_prompt, topic=self._topic)
rendered_prompt = await self._render_prompt(self.summary_prompt, topic=self.topic)
chat_history.messages.insert(
0,
ChatMessageContent(role=AuthorRole.SYSTEM, content=rendered_prompt),
@@ -171,11 +171,11 @@ class ChatCompletionGroupChatManager(GroupChatManager):
ChatMessageContent(role=AuthorRole.USER, content="Summarize the plan."),
)
response = await self._service.get_chat_message_content(
response = await self.service.get_chat_message_content(
chat_history,
settings=PromptExecutionSettings(response_format=StringResult),
)
string_result = StringResult.model_validate_json(response.content) # type: ignore
string_result = StringResult.model_validate_json(response.content)
return MessageResult(
result=ChatMessageContent(role=AuthorRole.ASSISTANT, content=string_result.result),
reason=string_result.reason,
@@ -197,7 +197,7 @@ async def sk_agent_response_callback(message: ChatMessageContent | Sequence[Chat
async def run_semantic_kernel_example(task: str) -> str:
credential = AzureCliCredential()
orchestration = GroupChatOrchestration(
members=build_semantic_kernel_agents(), # type: ignore
members=build_semantic_kernel_agents(),
manager=ChatCompletionGroupChatManager(
topic=DISCUSSION_TOPIC,
service=AzureChatCompletion(credential=credential),
@@ -225,7 +225,7 @@ async def run_semantic_kernel_example(task: str) -> str:
async def run_agent_framework_example(task: str) -> str:
client = OpenAIChatCompletionClient(credential=AzureCliCredential())
credential = AzureCliCredential()
researcher = Agent(
name="Researcher",
@@ -234,42 +234,32 @@ async def run_agent_framework_example(task: str) -> str:
"Gather concise facts or considerations that help plan a community hackathon. "
"Keep your responses factual and scannable."
),
client=client,
client=FoundryChatClient(credential=credential),
)
planner = Agent(
name="Planner",
description="Turns the collected notes into a concrete action plan.",
instructions=("Propose a structured action plan that accounts for logistics, roles, and timeline."),
client=client,
client=FoundryChatClient(credential=credential),
)
workflow = GroupChatBuilder(
participants=[researcher, planner],
orchestrator_agent=Agent(client=client),
max_rounds=8,
intermediate_outputs=True,
orchestrator_agent=Agent(client=FoundryChatClient(credential=credential)),
).build()
output_messages: list[Message] = []
last_message_id: str | None = None
final_response = ""
async for event in workflow.run(task, stream=True):
if event.type == "output":
if isinstance(event.data, AgentResponseUpdate):
if event.data.message_id != last_message_id:
last_message_id = event.data.message_id
print(f"{event.data.author_name}: {event.data.text}", end="")
else:
print(event.data.text, end="")
data = event.data
if isinstance(data, list) and len(data) > 0:
# Get the final message from the conversation
final_message = data[-1]
final_response = final_message.text or "" if isinstance(final_message, Message) else str(data)
else:
output_messages.extend(cast(list[Message], event.data))
for message in output_messages:
print(f"[{message.author_name}] {message.text}")
if output_messages:
return output_messages[-1].text
return ""
final_response = str(data)
return final_response
async def main() -> None:
@@ -11,14 +11,15 @@
"""Side-by-side handoff orchestrations for Semantic Kernel and Agent Framework."""
import asyncio
from collections.abc import AsyncIterable, Callable, Iterator, Sequence
import sys
from collections.abc import AsyncIterable, Iterator, Sequence
from agent_framework import (
Agent,
Message,
WorkflowEvent,
)
from agent_framework.openai import OpenAIChatCompletionClient
from agent_framework.foundry import FoundryChatClient
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder
from azure.identity import AzureCliCredential
from dotenv import load_dotenv
@@ -35,6 +36,11 @@ from semantic_kernel.contents import (
)
from semantic_kernel.functions import kernel_function
if sys.version_info >= (3, 12):
pass # pragma: no cover
else:
pass # pragma: no cover
# Load environment variables from .env file
load_dotenv()
@@ -143,7 +149,7 @@ def _sk_streaming_callback(message: StreamingChatMessageContent, is_final: bool)
_sk_new_message = True
def _make_sk_human_responder(script: Iterator[str]) -> Callable[[], ChatMessageContent]:
def _make_sk_human_responder(script: Iterator[str]) -> callable:
def _responder() -> ChatMessageContent:
try:
user_text = next(script)
@@ -184,7 +190,7 @@ async def run_semantic_kernel_example(initial_task: str, scripted_responses: Seq
######################################################################
def _create_af_agents(client: OpenAIChatCompletionClient):
def _create_af_agents(client: FoundryChatClient):
triage = Agent(
client=client,
name="triage_agent",
@@ -239,7 +245,7 @@ def _extract_final_conversation(events: list[WorkflowEvent]) -> list[Message]:
async def run_agent_framework_example(initial_task: str, scripted_responses: Sequence[str]) -> str:
client = OpenAIChatCompletionClient(credential=AzureCliCredential())
client = FoundryChatClient(credential=AzureCliCredential())
triage, refund, status, returns = _create_af_agents(client)
workflow = (
@@ -275,7 +281,7 @@ async def run_agent_framework_example(initial_task: str, scripted_responses: Seq
return ""
# Render final transcript succinctly.
lines: list[str] = []
lines = []
for message in conversation:
text = message.text or ""
if not text.strip():
@@ -13,9 +13,8 @@
import asyncio
from collections.abc import Sequence
from typing import cast
from agent_framework import Agent, AgentResponseUpdate, Message
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from agent_framework.orchestrations import MagenticBuilder
from dotenv import load_dotenv
@@ -47,21 +46,21 @@ PROMPT = (
######################################################################
async def build_semantic_kernel_agents() -> list[ChatCompletionAgent | OpenAIAssistantAgent]:
async def build_semantic_kernel_agents() -> list:
research_agent = ChatCompletionAgent(
name="ResearchAgent",
description="A helpful assistant with access to web search. Ask it to perform web searches.",
instructions=(
"You are a Researcher. You find information without additional computation or quantitative analysis."
),
service=OpenAIChatCompletion(ai_model_id="gpt-4o-mini-search-preview"),
service=OpenAIChatCompletion(ai_model_id="gpt-4o-search-preview"),
)
client = OpenAIAssistantAgent.create_client()
code_interpreter_tool, code_interpreter_tool_resources = OpenAIAssistantAgent.configure_code_interpreter_tool()
openai_settings = OpenAISettings()
model_id = openai_settings.chat_model_id if openai_settings.chat_model_id else "gpt-5"
definition = await client.beta.assistants.create( # pyright: ignore[reportDeprecated]
definition = await client.beta.assistants.create(
model=model_id,
name="CoderAgent",
description="A helpful assistant that writes and executes code to process and analyze data.",
@@ -95,7 +94,7 @@ def sk_agent_response_callback(
async def run_semantic_kernel_example(prompt: str) -> Sequence[ChatMessageContent]:
agents = await build_semantic_kernel_agents()
magentic_orchestration = MagenticOrchestration(
members=agents, # type: ignore
members=agents,
manager=StandardMagenticManager(chat_completion_service=OpenAIChatCompletion()),
agent_response_callback=sk_agent_response_callback,
)
@@ -138,7 +137,7 @@ async def run_agent_framework_example(prompt: str) -> str | None:
instructions=(
"You are a Researcher. You find information without additional computation or quantitative analysis."
),
client=OpenAIChatClient(model="gpt-4o-mini-search-preview"),
client=OpenAIChatClient(model="gpt-4o-search-preview"),
)
# Create code interpreter tool using static method
@@ -161,31 +160,22 @@ async def run_agent_framework_example(prompt: str) -> str | None:
client=OpenAIChatClient(),
)
workflow = MagenticBuilder(
participants=[researcher, coder],
manager_agent=manager_agent, # type: ignore
intermediate_outputs=True,
).build()
workflow = MagenticBuilder(participants=[researcher, coder], manager_agent=manager_agent).build()
output_messages: list[Message] = []
last_message_id: str | None = None
final_text: str | None = None
async for event in workflow.run(prompt, stream=True):
if event.type == "output":
if isinstance(event.data, AgentResponseUpdate):
if event.data.message_id != last_message_id:
last_message_id = event.data.message_id
print(f"{event.data.author_name}: {event.data.text}", end="")
else:
print(event.data.text, end="")
else:
output_messages.extend(cast(list[Message], event.data))
for message in output_messages:
print(f"[{message.author_name}] {message.text}")
data = event.data
if isinstance(data, str):
final_text = data
elif isinstance(data, list):
# Extract text from the last assistant message
for msg in reversed(data):
if hasattr(msg, "text") and msg.text:
final_text = msg.text
break
if output_messages:
return output_messages[-1].text
return None
return final_text
def _print_agent_framework_output(result: str | None) -> None: