93 lines
3.1 KiB
Python
93 lines
3.1 KiB
Python
# Copy/paste command (does not modify uv.lock):
|
|
# uv run -m examples.agent_patterns.hosted_multi_agent_beta --mode stream
|
|
|
|
import argparse
|
|
import asyncio
|
|
from collections.abc import Mapping
|
|
from typing import Any
|
|
|
|
from agents import Agent, Runner, function_tool
|
|
from agents.extensions.experimental.hosted_multi_agent import (
|
|
OpenAIHostedMultiAgentModel,
|
|
get_hosted_agent_metadata,
|
|
)
|
|
from agents.tool_context import ToolContext
|
|
|
|
PROPOSALS = {
|
|
"alpha": {"estimated_weeks": 6, "risk": "medium"},
|
|
"beta": {"estimated_weeks": 8, "risk": "low"},
|
|
}
|
|
|
|
|
|
@function_tool
|
|
def get_proposal(ctx: ToolContext[Any], proposal: str) -> dict[str, object]:
|
|
"""Return deterministic details for one proposal."""
|
|
metadata = get_hosted_agent_metadata(ctx)
|
|
caller = metadata.agent_name if metadata else "unknown"
|
|
print(f"local tool caller={caller} call_id={ctx.tool_call_id} proposal={proposal}")
|
|
if proposal not in PROPOSALS:
|
|
raise ValueError(f"Unknown proposal: {proposal}")
|
|
return PROPOSALS[proposal]
|
|
|
|
|
|
def build_agent() -> Agent[Any]:
|
|
return Agent(
|
|
name="Hosted proposal coordinator",
|
|
instructions=(
|
|
"Create two subagents. Ask one to inspect proposal alpha and the other to inspect "
|
|
"proposal beta. Each subagent must call get_proposal for its assigned proposal. "
|
|
"Wait for both results, then return one concise comparison from the root agent."
|
|
),
|
|
model=OpenAIHostedMultiAgentModel(
|
|
model="gpt-5.6-sol",
|
|
config={"max_concurrent_subagents": 3},
|
|
),
|
|
tools=[get_proposal],
|
|
)
|
|
|
|
|
|
def log_hosted_event(event: object) -> None:
|
|
if getattr(event, "type", None) != "response.output_item.done":
|
|
return
|
|
item = getattr(event, "item", None)
|
|
item_type = item.get("type") if isinstance(item, Mapping) else getattr(item, "type", None)
|
|
metadata = get_hosted_agent_metadata(item)
|
|
is_hosted_item = item_type in {
|
|
"agent_message",
|
|
"multi_agent_call",
|
|
"multi_agent_call_output",
|
|
}
|
|
is_subagent_message = (
|
|
item_type == "message" and metadata is not None and metadata.agent_name != "/root"
|
|
)
|
|
if is_hosted_item or is_subagent_message:
|
|
caller = metadata.agent_name if metadata else "unknown"
|
|
print(f"hosted item type={item_type} agent={caller}")
|
|
|
|
|
|
async def run_nonstreamed() -> None:
|
|
result = await Runner.run(build_agent(), "Compare proposal alpha and proposal beta.")
|
|
print(f"\nFinal response:\n{result.final_output}")
|
|
|
|
|
|
async def run_streamed() -> None:
|
|
result = Runner.run_streamed(build_agent(), "Compare proposal alpha and proposal beta.")
|
|
async for event in result.stream_events():
|
|
if event.type == "raw_response_event":
|
|
log_hosted_event(event.data)
|
|
print(f"\nFinal response:\n{result.final_output}")
|
|
|
|
|
|
async def main() -> None:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--mode", choices=("nonstream", "stream"), default="nonstream")
|
|
args = parser.parse_args()
|
|
if args.mode == "stream":
|
|
await run_streamed()
|
|
else:
|
|
await run_nonstreamed()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|