Skip to content
Merged
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 @@ -28,7 +28,7 @@ async def handle_approvals_without_thread(query: str, agent: "AgentProtocol") ->
new_inputs.append(ChatMessage(role="assistant", contents=[user_input_needed]))
user_approval = input("Approve function call? (y/n): ")
new_inputs.append(
ChatMessage(role="user", contents=[user_input_needed.create_response(user_approval.lower() == "y")])
ChatMessage(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
)

result = await agent.run(new_inputs, store=False)
Expand All @@ -50,7 +50,7 @@ async def handle_approvals_with_thread(query: str, agent: "AgentProtocol", threa
new_input.append(
ChatMessage(
role="user",
contents=[user_input_needed.create_response(user_approval.lower() == "y")],
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_input, thread=thread)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async def handle_approvals_with_thread(query: str, agent: "AgentProtocol", threa
new_input.append(
ChatMessage(
role="user",
contents=[user_input_needed.create_response(user_approval.lower() == "y")],
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_input, thread=thread, store=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async def handle_approvals_with_thread(query: str, agent: "AgentProtocol", threa
new_input.append(
ChatMessage(
role="user",
contents=[user_input_needed.create_response(user_approval.lower() == "y")],
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_input, thread=thread, store=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ async def handle_approvals_without_thread(query: str, agent: "AgentProtocol"):
new_inputs.append(ChatMessage(role="assistant", contents=[user_input_needed]))
user_approval = input("Approve function call? (y/n): ")
new_inputs.append(
ChatMessage(role="user", contents=[user_input_needed.create_response(user_approval.lower() == "y")])
ChatMessage(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
)

result = await agent.run(new_inputs)
Expand All @@ -56,7 +56,7 @@ async def handle_approvals_with_thread(query: str, agent: "AgentProtocol", threa
new_input.append(
ChatMessage(
role="user",
contents=[user_input_needed.create_response(user_approval.lower() == "y")],
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_input, thread=thread, store=True)
Expand All @@ -82,7 +82,7 @@ async def handle_approvals_with_thread_streaming(query: str, agent: "AgentProtoc
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
role="user", contents=[user_input_needed.create_response(user_approval.lower() == "y")]
role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")]
)
)
new_input_added = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async def handle_approvals_without_thread(query: str, agent: "AgentProtocol"):
new_inputs.append(ChatMessage(role="assistant", contents=[user_input_needed]))
user_approval = input("Approve function call? (y/n): ")
new_inputs.append(
ChatMessage(role="user", contents=[user_input_needed.create_response(user_approval.lower() == "y")])
ChatMessage(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
)

result = await agent.run(new_inputs)
Expand All @@ -55,7 +55,7 @@ async def handle_approvals_with_thread(query: str, agent: "AgentProtocol", threa
new_input.append(
ChatMessage(
role="user",
contents=[user_input_needed.create_response(user_approval.lower() == "y")],
contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")],
)
)
result = await agent.run(new_input, thread=thread, store=True)
Expand All @@ -81,7 +81,7 @@ async def handle_approvals_with_thread_streaming(query: str, agent: "AgentProtoc
user_approval = input("Approve function call? (y/n): ")
new_input.append(
ChatMessage(
role="user", contents=[user_input_needed.create_response(user_approval.lower() == "y")]
role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")]
)
)
new_input_added = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async def handle_approvals(query: str, agent: "AgentProtocol") -> AgentResponse:

# Add the user's approval response
new_inputs.append(
ChatMessage(role="user", contents=[user_input_needed.create_response(user_approval.lower() == "y")])
ChatMessage(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
)

# Run again with all the context
Expand Down Expand Up @@ -116,7 +116,7 @@ async def handle_approvals_streaming(query: str, agent: "AgentProtocol") -> None

# Add the user's approval response
new_inputs.append(
ChatMessage(role="user", contents=[user_input_needed.create_response(user_approval.lower() == "y")])
ChatMessage(role="user", contents=[user_input_needed.to_function_approval_response(user_approval.lower() == "y")])
)

# Update input with all the context for next iteration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async def approval_example() -> None:
print(f" Decision: {'Approved' if approved else 'Rejected'}")

# Step 2: Send approval response
approval_response = request.create_response(approved=approved)
approval_response = request.to_function_approval_response(approved=approved)
result = await agent.run(ChatMessage(role="user", contents=[approval_response]), thread=thread)

print(f"Agent: {result}\n")
Expand Down Expand Up @@ -87,7 +87,7 @@ async def rejection_example() -> None:
print(" Decision: Rejected")

# Send rejection response
rejection_response = request.create_response(approved=False)
rejection_response = request.to_function_approval_response(approved=False)
result = await agent.run(ChatMessage(role="user", contents=[rejection_response]), thread=thread)

print(f"Agent: {result}\n")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
from agent_framework import (
ChatAgent,
ChatMessage,
Content,
FileCheckpointStorage,
FunctionApprovalRequestContent,
HandoffBuilder,
HandoffUserInputRequest,
RequestInfoEvent,
Expand All @@ -26,7 +26,7 @@
Sample: Handoff Workflow with Tool Approvals + Checkpoint Resume

Demonstrates the two-step pattern for resuming a handoff workflow from a checkpoint
while handling both HandoffUserInputRequest prompts and FunctionApprovalRequestContent
while handling both HandoffUserInputRequest prompts and function approval request Content
for tool calls (e.g., submit_refund).

Scenario:
Expand Down Expand Up @@ -137,7 +137,7 @@ def _print_handoff_request(request: HandoffUserInputRequest, request_id: str) ->
print(f"{'=' * 60}\n")


def _print_function_approval_request(request: FunctionApprovalRequestContent, request_id: str) -> None:
def _print_function_approval_request(request: Content, request_id: str) -> None:
"""Log pending tool approval details for debugging."""
args = request.function_call.parse_arguments() or {}
print(f"\n{'=' * 60}")
Expand All @@ -161,10 +161,10 @@ def _build_responses_for_requests(
if user_response is None:
raise ValueError("User response is required for HandoffUserInputRequest")
responses[request.request_id] = user_response
elif isinstance(request.data, FunctionApprovalRequestContent):
elif isinstance(request.data, Content) and request.data.type == "function_approval_request":
if approve_tools is None:
raise ValueError("Approval decision is required for FunctionApprovalRequestContent")
responses[request.request_id] = request.data.create_response(approved=approve_tools)
raise ValueError("Approval decision is required for function approval request")
responses[request.request_id] = request.data.to_function_approval_response(approved=approve_tools)
else:
raise ValueError(f"Unsupported request type: {type(request.data)}")
return responses
Expand Down Expand Up @@ -201,7 +201,7 @@ async def run_until_user_input_needed(
pending_requests.append(event)
if isinstance(event.data, HandoffUserInputRequest):
_print_handoff_request(event.data, event.request_id)
elif isinstance(event.data, FunctionApprovalRequestContent):
elif isinstance(event.data, Content) and event.data.type == "function_approval_request":
_print_function_approval_request(event.data, event.request_id)

elif isinstance(event, WorkflowOutputEvent):
Expand Down Expand Up @@ -258,7 +258,7 @@ async def resume_with_responses(
restored_requests.append(event)
if isinstance(event.data, HandoffUserInputRequest):
_print_handoff_request(event.data, event.request_id)
elif isinstance(event.data, FunctionApprovalRequestContent):
elif isinstance(event.data, Content) and event.data.type == "function_approval_request":
_print_function_approval_request(event.data, event.request_id)

if not restored_requests:
Expand Down Expand Up @@ -291,7 +291,7 @@ async def resume_with_responses(
new_pending_requests.append(event)
if isinstance(event.data, HandoffUserInputRequest):
_print_handoff_request(event.data, event.request_id)
elif isinstance(event.data, FunctionApprovalRequestContent):
elif isinstance(event.data, Content) and event.data.type == "function_approval_request":
_print_function_approval_request(event.data, event.request_id)

return new_pending_requests, latest_checkpoint.checkpoint_id
Expand Down Expand Up @@ -362,7 +362,7 @@ async def main() -> None:
workflow_step, _, _, _ = create_workflow(checkpoint_storage=storage)

needs_user_input = any(isinstance(req.data, HandoffUserInputRequest) for req in pending_requests)
needs_tool_approval = any(isinstance(req.data, FunctionApprovalRequestContent) for req in pending_requests)
needs_tool_approval = any(isinstance(req.data, Content) and req.data.type == "function_approval_request" for req in pending_requests)

user_response = None
if needs_user_input:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
AgentExecutorResponse,
ChatAgent,
ChatMessage,
Content,
Executor,
FunctionApprovalRequestContent,
FunctionApprovalResponseContent,
WorkflowBuilder,
WorkflowContext,
tool,
Expand Down Expand Up @@ -251,7 +250,7 @@ async def main() -> None:
body="Please provide your team's status update on the project since last week.",
)

responses: dict[str, FunctionApprovalResponseContent] = {}
responses: dict[str, Content] = {}
output: list[ChatMessage] | None = None
while True:
if responses:
Expand All @@ -262,8 +261,8 @@ async def main() -> None:

request_info_events = events.get_request_info_events()
for request_info_event in request_info_events:
# We should only expect FunctionApprovalRequestContent in this sample
if not isinstance(request_info_event.data, FunctionApprovalRequestContent):
# We should only expect function_approval_request Content in this sample
if not isinstance(request_info_event.data, Content) or request_info_event.data.type != "function_approval_request":
raise ValueError(f"Unexpected request info content type: {type(request_info_event.data)}")

# Pretty print the function call details
Expand All @@ -274,10 +273,10 @@ async def main() -> None:
)

# For demo purposes, we automatically approve the request
# The expected response type of the request is `FunctionApprovalResponseContent`,
# which can be created via `create_response` method on the request content
# The expected response type of the request is `function_approval_response Content`,
# which can be created via `to_function_approval_response` method on the request content
print("Performing automatic approval for demo purposes...")
responses[request_info_event.request_id] = request_info_event.data.create_response(approved=True)
responses[request_info_event.request_id] = request_info_event.data.to_function_approval_response(approved=True)

# Once we get an output event, we can conclude the workflow
# Outputs can only be produced by the conclude_workflow_executor in this sample
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from agent_framework import (
ChatMessage,
ConcurrentBuilder,
FunctionApprovalRequestContent,
FunctionApprovalResponseContent,
Content,
RequestInfoEvent,
WorkflowOutputEvent,
tool,
Expand Down Expand Up @@ -139,20 +138,20 @@ async def main() -> None:
):
if isinstance(event, RequestInfoEvent):
request_info_events.append(event)
if isinstance(event.data, FunctionApprovalRequestContent):
if isinstance(event.data, Content) and event.data.type == "function_approval_request":
print(f"\nApproval requested for tool: {event.data.function_call.name}")
print(f" Arguments: {event.data.function_call.arguments}")
elif isinstance(event, WorkflowOutputEvent):
_print_output(event)

# 6. Handle approval requests (if any)
if request_info_events:
responses: dict[str, FunctionApprovalResponseContent] = {}
responses: dict[str, Content] = {}
for request_event in request_info_events:
if isinstance(request_event.data, FunctionApprovalRequestContent):
if isinstance(request_event.data, Content) and request_event.data.type == "function_approval_request":
print(f"\nSimulating human approval for: {request_event.data.function_call.name}")
# Create approval response
responses[request_event.request_id] = request_event.data.create_response(approved=True)
responses[request_event.request_id] = request_event.data.to_function_approval_response(approved=True)

if responses:
# Phase 2: Send all approvals and continue workflow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from agent_framework import (
AgentRunUpdateEvent,
FunctionApprovalRequestContent,
Content,
GroupChatBuilder,
GroupChatRequestSentEvent,
GroupChatState,
Expand Down Expand Up @@ -144,7 +144,7 @@ async def main() -> None:
):
if isinstance(event, RequestInfoEvent):
request_info_events.append(event)
if isinstance(event.data, FunctionApprovalRequestContent):
if isinstance(event.data, Content) and event.data.type == "function_approval_request":
print("\n[APPROVAL REQUIRED] From agent:", event.source_executor_id)
print(f" Tool: {event.data.function_call.name}")
print(f" Arguments: {event.data.function_call.arguments}")
Expand All @@ -164,15 +164,15 @@ async def main() -> None:
# 6. Handle approval requests
if request_info_events:
for request_event in request_info_events:
if isinstance(request_event.data, FunctionApprovalRequestContent):
if isinstance(request_event.data, Content) and request_event.data.type == "function_approval_request":
print("\n" + "=" * 60)
print("Human review required for production deployment!")
print("In a real scenario, you would review the deployment details here.")
print("Simulating approval for demo purposes...")
print("=" * 60)

# Create approval response
approval_response = request_event.data.create_response(approved=True)
approval_response = request_event.data.to_function_approval_response(approved=True)

# Phase 2: Send approval and continue workflow
# Keep track of the response to format output nicely in streaming mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from agent_framework import (
ChatMessage,
FunctionApprovalRequestContent,
Content,
RequestInfoEvent,
SequentialBuilder,
WorkflowOutputEvent,
Expand All @@ -23,7 +23,7 @@
This sample works as follows:
1. A SequentialBuilder workflow is created with a single agent that has tools requiring approval.
2. The agent receives a user task and determines it needs to call a sensitive tool.
3. The tool call triggers a FunctionApprovalRequestContent, pausing the workflow.
3. The tool call triggers a function_approval_request Content, pausing the workflow.
4. The sample simulates human approval by responding to the RequestInfoEvent.
5. Once approved, the tool executes and the agent completes its response.
6. The workflow outputs the final conversation with all messages.
Expand All @@ -34,7 +34,7 @@

Demonstrate:
- Using @tool(approval_mode="always_require") for sensitive operations.
- Handling RequestInfoEvent with FunctionApprovalRequestContent in sequential workflows.
- Handling RequestInfoEvent with function_approval_request Content in sequential workflows.
- Resuming workflow execution after approval via send_responses_streaming.

Prerequisites:
Expand Down Expand Up @@ -92,19 +92,19 @@ async def main() -> None:
):
if isinstance(event, RequestInfoEvent):
request_info_events.append(event)
if isinstance(event.data, FunctionApprovalRequestContent):
if isinstance(event.data, Content) and event.data.type == "function_approval_request":
print(f"\nApproval requested for tool: {event.data.function_call.name}")
print(f" Arguments: {event.data.function_call.arguments}")

# 5. Handle approval requests
if request_info_events:
for request_event in request_info_events:
if isinstance(request_event.data, FunctionApprovalRequestContent):
if isinstance(request_event.data, Content) and request_event.data.type == "function_approval_request":
# In a real application, you would prompt the user here
print("\nSimulating human approval (auto-approving for demo)...")

# Create approval response
approval_response = request_event.data.create_response(approved=True)
approval_response = request_event.data.to_function_approval_response(approved=True)

# Phase 2: Send approval and continue workflow
output: list[ChatMessage] | None = None
Expand Down
Loading