mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Simplify Python Poe tasks and unify package selectors (#4722)
* updated automation tasks and commands, with alias for the time being * Restore aggregate test exclusions Preserve the legacy all-tests scope for test --all by excluding lab and devui from the default aggregate sweep, while still allowing explicit package selection. Also ignore hidden/generated test directories such as .mypy_cache during aggregate discovery. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * updated versions in pre-commit --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
d3d0100822
commit
f48c4512d3
@@ -29,7 +29,9 @@ async def main() -> None:
|
||||
client = OpenAIChatClient()
|
||||
|
||||
try:
|
||||
task = asyncio.create_task(client.get_response(messages=[Message(role="user", text="Tell me a fantasy story.")]))
|
||||
task = asyncio.create_task(
|
||||
client.get_response(messages=[Message(role="user", text="Tell me a fantasy story.")])
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
task.cancel()
|
||||
await task
|
||||
|
||||
@@ -94,9 +94,7 @@ class EchoingChatClient(BaseChatClient[OptionsT]):
|
||||
response_text = f"{response_text} {suffix}"
|
||||
stream_delay_seconds = float(options.get("stream_delay_seconds", 0.05))
|
||||
|
||||
response_message = Message(
|
||||
role="assistant", contents=[Content.from_text(response_text)]
|
||||
)
|
||||
response_message = Message(role="assistant", text=response_text)
|
||||
|
||||
response = ChatResponse(
|
||||
messages=[response_message],
|
||||
|
||||
@@ -27,15 +27,9 @@ class KeepLastUserTurnStrategy:
|
||||
group_annotation = message.additional_properties.get(GROUP_ANNOTATION_KEY)
|
||||
group_id = group_annotation.get("id") if isinstance(group_annotation, dict) else None
|
||||
kind = group_annotation.get("kind") if isinstance(group_annotation, dict) else None
|
||||
if (
|
||||
isinstance(group_id, str)
|
||||
and isinstance(kind, str)
|
||||
and group_id not in group_kinds
|
||||
):
|
||||
if isinstance(group_id, str) and isinstance(kind, str) and group_id not in group_kinds:
|
||||
group_kinds[group_id] = kind
|
||||
user_group_ids = [
|
||||
group_id for group_id in group_ids if group_kinds.get(group_id) == "user"
|
||||
]
|
||||
user_group_ids = [group_id for group_id in group_ids if group_kinds.get(group_id) == "user"]
|
||||
if not user_group_ids:
|
||||
return False
|
||||
keep_user_group_id = user_group_ids[-1]
|
||||
|
||||
@@ -33,9 +33,7 @@ Key components:
|
||||
class TiktokenTokenizer(TokenizerProtocol):
|
||||
"""TokenizerProtocol implementation backed by tiktoken's o200k_base (gpt-4.1 and up default) encoding."""
|
||||
|
||||
def __init__(
|
||||
self, *, encoding_name: str = "o200k_base", model_name: str | None = None
|
||||
) -> None:
|
||||
def __init__(self, *, encoding_name: str = "o200k_base", model_name: str | None = None) -> None:
|
||||
if model_name is not None:
|
||||
self._encoding = tiktoken.encoding_for_model(model_name)
|
||||
else:
|
||||
@@ -62,10 +60,7 @@ def _build_messages() -> list[Message]:
|
||||
),
|
||||
Message(
|
||||
role="user",
|
||||
text=(
|
||||
"Now provide a detailed checklist with owners, rollback "
|
||||
"gates, and validation criteria."
|
||||
),
|
||||
text=("Now provide a detailed checklist with owners, rollback gates, and validation criteria."),
|
||||
),
|
||||
Message(
|
||||
role="assistant",
|
||||
|
||||
@@ -37,9 +37,7 @@ def get_weather(
|
||||
"""Get the weather for a given location."""
|
||||
conditions = ["sunny", "cloudy", "rainy", "stormy"]
|
||||
temperature = 53
|
||||
return (
|
||||
f"The weather in {location} is {conditions[0]} with a high of {temperature}°C."
|
||||
)
|
||||
return f"The weather in {location} is {conditions[0]} with a high of {temperature}°C."
|
||||
|
||||
|
||||
@tool(approval_mode="never_require")
|
||||
@@ -68,9 +66,7 @@ class AddExclamation(Executor):
|
||||
"""Add exclamation mark to text."""
|
||||
|
||||
@handler
|
||||
async def add_exclamation(
|
||||
self, text: str, ctx: WorkflowContext[Never, str]
|
||||
) -> None:
|
||||
async def add_exclamation(self, text: str, ctx: WorkflowContext[Never, str]) -> None:
|
||||
"""Add exclamation and yield as workflow output."""
|
||||
result = f"{text}!"
|
||||
await ctx.yield_output(result)
|
||||
|
||||
+1
-3
@@ -19,9 +19,7 @@ from copilot.generated.session_events import PermissionRequest
|
||||
from copilot.types import PermissionRequestResult
|
||||
|
||||
|
||||
def prompt_permission(
|
||||
request: PermissionRequest, context: dict[str, str]
|
||||
) -> PermissionRequestResult:
|
||||
def prompt_permission(request: PermissionRequest, context: dict[str, str]) -> PermissionRequestResult:
|
||||
"""Permission handler that prompts the user for approval."""
|
||||
print(f"\n[Permission Request: {request.kind}]")
|
||||
|
||||
|
||||
@@ -75,7 +75,9 @@ unit_converter_skill = Skill(
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Dynamic Resources — callable function via @skill.resource
|
||||
# ---------------------------------------------------------------------------
|
||||
@unit_converter_skill.resource(name="conversion-policy", description="Current conversion formatting and rounding policy")
|
||||
@unit_converter_skill.resource(
|
||||
name="conversion-policy", description="Current conversion formatting and rounding policy"
|
||||
)
|
||||
def conversion_policy(**kwargs: Any) -> Any:
|
||||
"""Return the current conversion policy.
|
||||
|
||||
@@ -148,8 +150,7 @@ async def main() -> None:
|
||||
print("Converting units")
|
||||
print("-" * 60)
|
||||
response = await agent.run(
|
||||
"How many kilometers is a marathon (26.2 miles)? "
|
||||
"And how many pounds is 75 kilograms?",
|
||||
"How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?",
|
||||
precision=2,
|
||||
)
|
||||
print(f"Agent: {response}\n")
|
||||
|
||||
@@ -70,8 +70,7 @@ async def main() -> None:
|
||||
print("Converting units")
|
||||
print("-" * 60)
|
||||
response = await agent.run(
|
||||
"How many kilometers is a marathon (26.2 miles)? "
|
||||
"And how many pounds is 75 kilograms?"
|
||||
"How many kilometers is a marathon (26.2 miles)? And how many pounds is 75 kilograms?"
|
||||
)
|
||||
print(f"Agent: {response}\n")
|
||||
|
||||
|
||||
@@ -137,8 +137,7 @@ async def main() -> None:
|
||||
print("Converting units")
|
||||
print("-" * 60)
|
||||
response = await agent.run(
|
||||
"How many kilometers is a marathon (26.2 miles)? "
|
||||
"And how many liters is a 5-gallon bucket?"
|
||||
"How many kilometers is a marathon (26.2 miles)? And how many liters is a 5-gallon bucket?"
|
||||
)
|
||||
print(f"Agent: {response}\n")
|
||||
|
||||
|
||||
@@ -135,8 +135,7 @@ async def scenario_max_function_calls():
|
||||
)
|
||||
|
||||
response = await agent.run(
|
||||
"Search for the weather in Paris, London, Tokyo, "
|
||||
"New York, and Sydney, and also search for best travel tips."
|
||||
"Search for the weather in Paris, London, Tokyo, New York, and Sydney, and also search for best travel tips."
|
||||
)
|
||||
print(f" Response: {response.text[:200]}...")
|
||||
print()
|
||||
@@ -236,8 +235,12 @@ async def scenario_per_agent_tool_limits():
|
||||
session_b = agent_b.create_session()
|
||||
await agent_b.run("Look up quantum computing", session=session_b)
|
||||
|
||||
print(f" agent_a_lookup.invocation_count = {agent_a_lookup.invocation_count} (limit {agent_a_lookup.max_invocations})")
|
||||
print(f" agent_b_lookup.invocation_count = {agent_b_lookup.invocation_count} (limit {agent_b_lookup.max_invocations})")
|
||||
print(
|
||||
f" agent_a_lookup.invocation_count = {agent_a_lookup.invocation_count} (limit {agent_a_lookup.max_invocations})"
|
||||
)
|
||||
print(
|
||||
f" agent_b_lookup.invocation_count = {agent_b_lookup.invocation_count} (limit {agent_b_lookup.max_invocations})"
|
||||
)
|
||||
print(" → Agent A hit its limit; Agent B used 1 of 5.")
|
||||
print()
|
||||
|
||||
@@ -254,8 +257,8 @@ async def scenario_combined():
|
||||
client = OpenAIResponsesClient()
|
||||
|
||||
# 1. Configure the client with both iteration and function call limits.
|
||||
client.function_invocation_configuration["max_iterations"] = 5 # max 5 LLM roundtrips
|
||||
client.function_invocation_configuration["max_function_calls"] = 8 # max 8 total tool calls
|
||||
client.function_invocation_configuration["max_iterations"] = 5 # max 5 LLM roundtrips
|
||||
client.function_invocation_configuration["max_function_calls"] = 8 # max 8 total tool calls
|
||||
print(f" max_iterations = {client.function_invocation_configuration['max_iterations']}")
|
||||
print(f" max_function_calls = {client.function_invocation_configuration['max_function_calls']}")
|
||||
|
||||
|
||||
@@ -47,12 +47,8 @@ async def main() -> None:
|
||||
session = agent.create_session()
|
||||
|
||||
# Run the agent with the session; tools receive it via ctx.session.
|
||||
print(
|
||||
f"Agent: {await agent.run('What is the weather in London?', session=session)}"
|
||||
)
|
||||
print(
|
||||
f"Agent: {await agent.run('What is the weather in Amsterdam?', session=session)}"
|
||||
)
|
||||
print(f"Agent: {await agent.run('What is the weather in London?', session=session)}")
|
||||
print(f"Agent: {await agent.run('What is the weather in Amsterdam?', session=session)}")
|
||||
print(f"Agent: {await agent.run('What cities did I ask about?', session=session)}")
|
||||
|
||||
|
||||
|
||||
@@ -72,56 +72,116 @@ def _random_date_within_last_two_months() -> datetime:
|
||||
def _build_invoices() -> list[Invoice]:
|
||||
"""Build 10 mock invoices."""
|
||||
return [
|
||||
Invoice("TICKET-XYZ987", "INV789", "Contoso", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 150, 10.00),
|
||||
Product("Hats", 200, 15.00),
|
||||
Product("Glasses", 300, 5.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ111", "INV111", "XStore", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 2500, 12.00),
|
||||
Product("Hats", 1500, 8.00),
|
||||
Product("Glasses", 200, 20.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ222", "INV222", "Cymbal Direct", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 1200, 14.00),
|
||||
Product("Hats", 800, 7.00),
|
||||
Product("Glasses", 500, 25.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ333", "INV333", "Contoso", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 400, 11.00),
|
||||
Product("Hats", 600, 15.00),
|
||||
Product("Glasses", 700, 5.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ444", "INV444", "XStore", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 800, 10.00),
|
||||
Product("Hats", 500, 18.00),
|
||||
Product("Glasses", 300, 22.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ555", "INV555", "Cymbal Direct", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 1100, 9.00),
|
||||
Product("Hats", 900, 12.00),
|
||||
Product("Glasses", 1200, 15.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ666", "INV666", "Contoso", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 2500, 8.00),
|
||||
Product("Hats", 1200, 10.00),
|
||||
Product("Glasses", 1000, 6.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ777", "INV777", "XStore", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 1900, 13.00),
|
||||
Product("Hats", 1300, 16.00),
|
||||
Product("Glasses", 800, 19.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ888", "INV888", "Cymbal Direct", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 2200, 11.00),
|
||||
Product("Hats", 1700, 8.50),
|
||||
Product("Glasses", 600, 21.00),
|
||||
]),
|
||||
Invoice("TICKET-XYZ999", "INV999", "Contoso", _random_date_within_last_two_months(), [
|
||||
Product("T-Shirts", 1400, 10.50),
|
||||
Product("Hats", 1100, 9.00),
|
||||
Product("Glasses", 950, 12.00),
|
||||
]),
|
||||
Invoice(
|
||||
"TICKET-XYZ987",
|
||||
"INV789",
|
||||
"Contoso",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 150, 10.00),
|
||||
Product("Hats", 200, 15.00),
|
||||
Product("Glasses", 300, 5.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ111",
|
||||
"INV111",
|
||||
"XStore",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 2500, 12.00),
|
||||
Product("Hats", 1500, 8.00),
|
||||
Product("Glasses", 200, 20.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ222",
|
||||
"INV222",
|
||||
"Cymbal Direct",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 1200, 14.00),
|
||||
Product("Hats", 800, 7.00),
|
||||
Product("Glasses", 500, 25.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ333",
|
||||
"INV333",
|
||||
"Contoso",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 400, 11.00),
|
||||
Product("Hats", 600, 15.00),
|
||||
Product("Glasses", 700, 5.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ444",
|
||||
"INV444",
|
||||
"XStore",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 800, 10.00),
|
||||
Product("Hats", 500, 18.00),
|
||||
Product("Glasses", 300, 22.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ555",
|
||||
"INV555",
|
||||
"Cymbal Direct",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 1100, 9.00),
|
||||
Product("Hats", 900, 12.00),
|
||||
Product("Glasses", 1200, 15.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ666",
|
||||
"INV666",
|
||||
"Contoso",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 2500, 8.00),
|
||||
Product("Hats", 1200, 10.00),
|
||||
Product("Glasses", 1000, 6.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ777",
|
||||
"INV777",
|
||||
"XStore",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 1900, 13.00),
|
||||
Product("Hats", 1300, 16.00),
|
||||
Product("Glasses", 800, 19.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ888",
|
||||
"INV888",
|
||||
"Cymbal Direct",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 2200, 11.00),
|
||||
Product("Hats", 1700, 8.50),
|
||||
Product("Glasses", 600, 21.00),
|
||||
],
|
||||
),
|
||||
Invoice(
|
||||
"TICKET-XYZ999",
|
||||
"INV999",
|
||||
"Contoso",
|
||||
_random_date_within_last_two_months(),
|
||||
[
|
||||
Product("T-Shirts", 1400, 10.50),
|
||||
Product("Hats", 1100, 9.00),
|
||||
Product("Glasses", 950, 12.00),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ Users can create a `.env` file in the `python/` directory based on `.env.example
|
||||
|
||||
## Syntax Checking
|
||||
|
||||
Run `uv run poe samples-syntax` to check samples for syntax errors and missing imports from `agent_framework`. This uses a relaxed pyright configuration that validates imports without strict type checking.
|
||||
Run `uv run poe pyright -S` to check samples for syntax errors and missing imports from `agent_framework`. This uses a relaxed pyright configuration that validates imports without strict type checking.
|
||||
|
||||
Some samples depend on external packages (e.g., `azure.ai.agentserver.agentframework`, `microsoft_agents`) that are not installed in the dev environment. These are excluded in `pyrightconfig.samples.json`. When adding or modifying these excluded samples, add them to the exclude list and manually verify they have no import errors from `agent_framework` packages by temporarily removing them from the exclude list and running the check.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user