|
28 | 28 | ActionType, |
29 | 29 | ActionWait, |
30 | 30 | ) |
| 31 | +from openai.types.responses.response_input_item_param import ( |
| 32 | + ComputerCallOutputAcknowledgedSafetyCheck, |
| 33 | +) |
31 | 34 | from openai.types.responses.response_input_param import ComputerCallOutput, McpApprovalResponse |
32 | 35 | from openai.types.responses.response_output_item import ( |
33 | 36 | ImageGenerationCall, |
|
67 | 70 | from .stream_events import RunItemStreamEvent, StreamEvent |
68 | 71 | from .tool import ( |
69 | 72 | ComputerTool, |
| 73 | + ComputerToolSafetyCheckData, |
70 | 74 | FunctionTool, |
71 | 75 | FunctionToolResult, |
72 | 76 | HostedMCPTool, |
@@ -638,13 +642,37 @@ async def execute_computer_actions( |
638 | 642 | results: list[RunItem] = [] |
639 | 643 | # Need to run these serially, because each action can affect the computer state |
640 | 644 | for action in actions: |
| 645 | + acknowledged: list[ComputerCallOutputAcknowledgedSafetyCheck] | None = None |
| 646 | + if action.tool_call.pending_safety_checks and action.computer_tool.on_safety_check: |
| 647 | + acknowledged = [] |
| 648 | + for check in action.tool_call.pending_safety_checks: |
| 649 | + data = ComputerToolSafetyCheckData( |
| 650 | + ctx_wrapper=context_wrapper, |
| 651 | + agent=agent, |
| 652 | + tool_call=action.tool_call, |
| 653 | + safety_check=check, |
| 654 | + ) |
| 655 | + maybe = action.computer_tool.on_safety_check(data) |
| 656 | + ack = await maybe if inspect.isawaitable(maybe) else maybe |
| 657 | + if ack: |
| 658 | + acknowledged.append( |
| 659 | + ComputerCallOutputAcknowledgedSafetyCheck( |
| 660 | + id=check.id, |
| 661 | + code=check.code, |
| 662 | + message=check.message, |
| 663 | + ) |
| 664 | + ) |
| 665 | + else: |
| 666 | + raise UserError("Computer tool safety check was not acknowledged") |
| 667 | + |
641 | 668 | results.append( |
642 | 669 | await ComputerAction.execute( |
643 | 670 | agent=agent, |
644 | 671 | action=action, |
645 | 672 | hooks=hooks, |
646 | 673 | context_wrapper=context_wrapper, |
647 | 674 | config=config, |
| 675 | + acknowledged_safety_checks=acknowledged, |
648 | 676 | ) |
649 | 677 | ) |
650 | 678 |
|
@@ -998,6 +1026,7 @@ async def execute( |
998 | 1026 | hooks: RunHooks[TContext], |
999 | 1027 | context_wrapper: RunContextWrapper[TContext], |
1000 | 1028 | config: RunConfig, |
| 1029 | + acknowledged_safety_checks: list[ComputerCallOutputAcknowledgedSafetyCheck] | None = None, |
1001 | 1030 | ) -> RunItem: |
1002 | 1031 | output_func = ( |
1003 | 1032 | cls._get_screenshot_async(action.computer_tool.computer, action.tool_call) |
@@ -1036,6 +1065,7 @@ async def execute( |
1036 | 1065 | "image_url": image_url, |
1037 | 1066 | }, |
1038 | 1067 | type="computer_call_output", |
| 1068 | + acknowledged_safety_checks=acknowledged_safety_checks, |
1039 | 1069 | ), |
1040 | 1070 | ) |
1041 | 1071 |
|
|
0 commit comments