[BREAKING] Python: Remove request_type param from ctx.request_info() (#1824)

* Remove request_type param from ctx.request_info()

* Address comments
This commit is contained in:
Tao Chen
2025-10-31 07:31:15 -07:00
committed by GitHub
Unverified
parent 2101d9d36d
commit 68b6a55757
21 changed files with 72 additions and 48 deletions
@@ -62,7 +62,7 @@ class ApprovalRequiredExecutor(Executor, RequestInfoMixin):
prompt=f"Please approve the operation: {message}",
context="This is a critical operation that requires human approval.",
)
await ctx.request_info(approval_request, UserApprovalRequest, bool)
await ctx.request_info(approval_request, bool)
@response_handler
async def handle_approval_response(
@@ -96,7 +96,7 @@ class CalculationExecutor(Executor, RequestInfoMixin):
try:
operands = [float(x) for x in parts[1:]]
calc_request = CalculationRequest(operation=operation, operands=operands)
await ctx.request_info(calc_request, CalculationRequest, float)
await ctx.request_info(calc_request, float)
except ValueError:
await ctx.send_message("Invalid calculation format")
else:
@@ -126,11 +126,11 @@ class MultiRequestExecutor(Executor, RequestInfoMixin):
approval_request = UserApprovalRequest(
prompt="Approve batch operation", context="Multiple operations will be performed"
)
await ctx.request_info(approval_request, UserApprovalRequest, bool)
await ctx.request_info(approval_request, bool)
# Request calculation
calc_request = CalculationRequest(operation="multiply", operands=[10.0, 5.0])
await ctx.request_info(calc_request, CalculationRequest, float)
await ctx.request_info(calc_request, float)
@response_handler
async def handle_approval_response(
@@ -7,7 +7,7 @@ from datetime import datetime, timezone
import pytest
from agent_framework import InMemoryCheckpointStorage, InProcRunnerContext
from agent_framework._workflows._checkpoint_encoding import encode_checkpoint_value
from agent_framework._workflows._checkpoint_encoding import DATACLASS_MARKER, encode_checkpoint_value
from agent_framework._workflows._checkpoint_summary import get_checkpoint_summary
from agent_framework._workflows._events import RequestInfoEvent
from agent_framework._workflows._shared_state import SharedState
@@ -39,7 +39,6 @@ async def test_rehydrate_request_info_event() -> None:
request_info_event = RequestInfoEvent(
request_id="request-123",
source_executor_id="review_gateway",
request_type=MockRequest,
request_data=MockRequest(),
response_type=bool,
)
@@ -73,7 +72,6 @@ async def test_rehydrate_fails_when_request_type_missing() -> None:
request_info_event = RequestInfoEvent(
request_id="request-123",
source_executor_id="review_gateway",
request_type=MockRequest,
request_data=MockRequest(),
response_type=bool,
)
@@ -97,12 +95,41 @@ async def test_rehydrate_fails_when_request_type_missing() -> None:
await runner_context.apply_checkpoint(checkpoint)
async def test_rehydrate_fails_when_request_type_mismatch() -> None:
"""Rehydration should fail if the request type is mismatched."""
request_info_event = RequestInfoEvent(
request_id="request-123",
source_executor_id="review_gateway",
request_data=MockRequest(),
response_type=bool,
)
runner_context = InProcRunnerContext(InMemoryCheckpointStorage())
await runner_context.add_request_info_event(request_info_event)
checkpoint_id = await runner_context.create_checkpoint(SharedState(), iteration_count=1)
checkpoint = await runner_context.load_checkpoint(checkpoint_id)
assert checkpoint is not None
assert checkpoint.pending_request_info_events
assert "request-123" in checkpoint.pending_request_info_events
assert "request_type" in checkpoint.pending_request_info_events["request-123"]
# Modify the checkpoint to simulate mismatched request type in the serialized data
checkpoint.pending_request_info_events["request-123"]["data"][DATACLASS_MARKER] = (
"nonexistent.module:MissingRequest"
)
# Rehydrate the context
with pytest.raises(TypeError):
await runner_context.apply_checkpoint(checkpoint)
async def test_pending_requests_in_summary() -> None:
"""Test that pending requests are correctly summarized in the checkpoint summary."""
request_info_event = RequestInfoEvent(
request_id="request-123",
source_executor_id="review_gateway",
request_type=MockRequest,
request_data=MockRequest(),
response_type=bool,
)
@@ -134,14 +161,12 @@ async def test_request_info_event_serializes_non_json_payloads() -> None:
req_1 = RequestInfoEvent(
request_id="req-1",
source_executor_id="source",
request_type=TimedApproval,
request_data=TimedApproval(issued_at=datetime(2024, 5, 4, 12, 30, 45)),
response_type=bool,
)
req_2 = RequestInfoEvent(
request_id="req-2",
source_executor_id="source",
request_type=SlottedApproval,
request_data=SlottedApproval(note="slot-based"),
response_type=bool,
)
@@ -76,7 +76,7 @@ class Coordinator(Executor):
else:
# Not in cache, forward to external
self._pending_sub_workflow_requests[domain_request.id] = sub_workflow_request
await ctx.request_info(domain_request, DomainCheckRequest, bool)
await ctx.request_info(domain_request, bool)
@response_handler
async def handle_domain_response(
@@ -138,7 +138,7 @@ class EmailDomainValidator(Executor):
return
# Request domain check from external source
await ctx.request_info(request, DomainCheckRequest, bool)
await ctx.request_info(request, bool)
@response_handler
async def handle_domain_response(
@@ -302,7 +302,7 @@ async def test_workflow_scoped_interception() -> None:
# Unknown source, forward to external
self._pending_sub_workflow_requests[domain_request.id] = sub_workflow_request
await ctx.request_info(domain_request, DomainCheckRequest, bool)
await ctx.request_info(domain_request, bool)
@response_handler
async def handle_domain_response(
@@ -386,7 +386,7 @@ async def test_concurrent_sub_workflow_execution() -> None:
domain_request = sub_workflow_request.source_event.data
self._pending_sub_workflow_requests[domain_request.id] = sub_workflow_request
await ctx.request_info(domain_request, DomainCheckRequest, bool)
await ctx.request_info(domain_request, bool)
@response_handler
async def handle_domain_response(
@@ -179,7 +179,6 @@ def test_serialize_deserialize_roundtrip() -> None:
instance = deserialized(
request_id="request-123",
source_executor_id="executor_1",
request_type=str,
request_data="test",
response_type=str,
)
@@ -89,7 +89,7 @@ class MockExecutorRequestApproval(Executor):
async def mock_handler_a(self, message: NumberMessage, ctx: WorkflowContext) -> None:
"""A mock handler that requests approval."""
await ctx.set_shared_state(self.id, message.data)
await ctx.request_info(MockRequest(prompt="Mock approval request"), MockRequest, ApprovalMessage)
await ctx.request_info(MockRequest(prompt="Mock approval request"), ApprovalMessage)
@response_handler
async def mock_handler_b(
@@ -485,7 +485,6 @@ async def test_workflow_run_stream_from_checkpoint_with_responses(simple_executo
"request_123": RequestInfoEvent(
request_id="request_123",
source_executor_id=simple_executor.id,
request_type=str,
request_data="Mock",
response_type=str,
).to_dict(),
@@ -60,7 +60,7 @@ class RequestingExecutor(Executor):
@handler
async def handle_message(self, _: list[ChatMessage], ctx: WorkflowContext) -> None:
# Send a RequestInfoMessage to trigger the request info process
await ctx.request_info("Mock request data", str, str)
await ctx.request_info("Mock request data", str)
@response_handler
async def handle_request_response(
@@ -78,7 +78,7 @@ class Requester(Executor):
@handler
async def ask(self, _: str, ctx: WorkflowContext) -> None: # pragma: no cover
await ctx.request_info("Mock request data", str, str)
await ctx.request_info("Mock request data", str)
async def test_idle_with_pending_requests_status_streaming():