Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,9 @@ async def _orchestrate_step(self, cancellation_token: CancellationToken) -> None
for _ in range(self._max_json_retries):
if self._model_client.model_info.get("structured_output", False):
response = await self._model_client.create(
self._get_compatible_context(context), json_output=LedgerEntry
self._get_compatible_context(context),
json_output=LedgerEntry,
cancellation_token=cancellation_token,
)
elif self._model_client.model_info.get("json_output", False):
response = await self._model_client.create(
Expand All @@ -334,7 +336,7 @@ async def _orchestrate_step(self, cancellation_token: CancellationToken) -> None
output_json = extract_json_from_str(ledger_str)
if len(output_json) != 1:
raise ValueError(
f"Progress ledger should contain a single JSON object, but found: {len(progress_ledger)}"
f"Progress ledger should contain a single JSON object, but found: {len(output_json)}"
)
progress_ledger = output_json[0]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

import pytest
import pytest_asyncio
from autogen_core import AgentId, AgentRuntime, CancellationToken, SingleThreadedAgentRuntime
from autogen_core.models import ModelFamily, ModelInfo
from autogen_ext.models.replay import ReplayChatCompletionClient
from utils import FileLogHandler

from autogen_agentchat import EVENT_LOGGER_NAME
from autogen_agentchat.agents import (
BaseChatAgent,
Expand All @@ -18,9 +23,6 @@
MagenticOneGroupChat,
)
from autogen_agentchat.teams._group_chat._magentic_one._magentic_one_orchestrator import MagenticOneOrchestrator
from autogen_core import AgentId, AgentRuntime, CancellationToken, SingleThreadedAgentRuntime
from autogen_ext.models.replay import ReplayChatCompletionClient
from utils import FileLogHandler

logger = logging.getLogger(EVENT_LOGGER_NAME)
logger.setLevel(logging.DEBUG)
Expand Down Expand Up @@ -96,6 +98,46 @@ async def test_magentic_one_group_chat_cancellation(runtime: AgentRuntime | None
await run_task


@pytest.mark.asyncio
async def test_magentic_one_group_chat_structured_output_cancellation_token(runtime: AgentRuntime | None) -> None:
"""Regression test: the progress ledger call in the structured_output branch must receive the cancellation token."""
agent_1 = _EchoAgent("agent_1", description="echo agent 1")

model_client = ReplayChatCompletionClient(
chat_completions=[
"No facts",
"No plan",
json.dumps(
{
"is_request_satisfied": {"answer": True, "reason": "test"},
"is_progress_being_made": {"answer": True, "reason": "test"},
"is_in_loop": {"answer": False, "reason": "test"},
"instruction_or_question": {"answer": "Task completed", "reason": "test"},
"next_speaker": {"answer": "agent_1", "reason": "test"},
}
),
"print('Hello, world!')",
],
model_info=ModelInfo(
vision=False, function_calling=False, json_output=True, family=ModelFamily.UNKNOWN, structured_output=True
),
)

team = MagenticOneGroupChat(participants=[agent_1], model_client=model_client, runtime=runtime)
cancellation_token = CancellationToken()
result = await team.run(
task="Write a program that prints 'Hello, world!'",
cancellation_token=cancellation_token,
)
assert result.stop_reason is not None and result.stop_reason == "test"

# Every model call made by the orchestrator, including the structured_output ledger call, must receive
# the cancellation token so that a cancelled run interrupts in-flight LLM requests.
assert len(model_client.create_calls) == 4
for call in model_client.create_calls:
assert call["cancellation_token"] is cancellation_token


@pytest.mark.asyncio
async def test_magentic_one_group_chat_basic(runtime: AgentRuntime | None) -> None:
agent_1 = _EchoAgent("agent_1", description="echo agent 1")
Expand Down