agentscope-runtime 0.1.4__py3-none-any.whl → 0.1.5b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. agentscope_runtime/engine/agents/agentscope_agent/agent.py +3 -0
  2. agentscope_runtime/engine/deployers/__init__.py +13 -0
  3. agentscope_runtime/engine/deployers/adapter/responses/__init__.py +0 -0
  4. agentscope_runtime/engine/deployers/adapter/responses/response_api_adapter_utils.py +2886 -0
  5. agentscope_runtime/engine/deployers/adapter/responses/response_api_agent_adapter.py +51 -0
  6. agentscope_runtime/engine/deployers/adapter/responses/response_api_protocol_adapter.py +314 -0
  7. agentscope_runtime/engine/deployers/cli_fc_deploy.py +143 -0
  8. agentscope_runtime/engine/deployers/kubernetes_deployer.py +265 -0
  9. agentscope_runtime/engine/deployers/local_deployer.py +356 -501
  10. agentscope_runtime/engine/deployers/modelstudio_deployer.py +626 -0
  11. agentscope_runtime/engine/deployers/utils/__init__.py +0 -0
  12. agentscope_runtime/engine/deployers/utils/deployment_modes.py +14 -0
  13. agentscope_runtime/engine/deployers/utils/docker_image_utils/__init__.py +8 -0
  14. agentscope_runtime/engine/deployers/utils/docker_image_utils/docker_image_builder.py +429 -0
  15. agentscope_runtime/engine/deployers/utils/docker_image_utils/dockerfile_generator.py +240 -0
  16. agentscope_runtime/engine/deployers/utils/docker_image_utils/runner_image_factory.py +297 -0
  17. agentscope_runtime/engine/deployers/utils/package_project_utils.py +932 -0
  18. agentscope_runtime/engine/deployers/utils/service_utils/__init__.py +9 -0
  19. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_factory.py +504 -0
  20. agentscope_runtime/engine/deployers/utils/service_utils/fastapi_templates.py +157 -0
  21. agentscope_runtime/engine/deployers/utils/service_utils/process_manager.py +268 -0
  22. agentscope_runtime/engine/deployers/utils/service_utils/service_config.py +75 -0
  23. agentscope_runtime/engine/deployers/utils/service_utils/service_factory.py +220 -0
  24. agentscope_runtime/engine/deployers/utils/wheel_packager.py +389 -0
  25. agentscope_runtime/engine/helpers/agent_api_builder.py +651 -0
  26. agentscope_runtime/engine/runner.py +36 -10
  27. agentscope_runtime/engine/schemas/agent_schemas.py +70 -2
  28. agentscope_runtime/engine/schemas/embedding.py +37 -0
  29. agentscope_runtime/engine/schemas/modelstudio_llm.py +310 -0
  30. agentscope_runtime/engine/schemas/oai_llm.py +538 -0
  31. agentscope_runtime/engine/schemas/realtime.py +254 -0
  32. agentscope_runtime/engine/services/mem0_memory_service.py +124 -0
  33. agentscope_runtime/engine/services/memory_service.py +2 -1
  34. agentscope_runtime/engine/services/redis_session_history_service.py +4 -3
  35. agentscope_runtime/engine/services/session_history_service.py +4 -3
  36. agentscope_runtime/sandbox/manager/container_clients/kubernetes_client.py +555 -10
  37. agentscope_runtime/version.py +1 -1
  38. {agentscope_runtime-0.1.4.dist-info → agentscope_runtime-0.1.5b1.dist-info}/METADATA +21 -4
  39. {agentscope_runtime-0.1.4.dist-info → agentscope_runtime-0.1.5b1.dist-info}/RECORD +43 -16
  40. {agentscope_runtime-0.1.4.dist-info → agentscope_runtime-0.1.5b1.dist-info}/entry_points.txt +1 -0
  41. {agentscope_runtime-0.1.4.dist-info → agentscope_runtime-0.1.5b1.dist-info}/WHEEL +0 -0
  42. {agentscope_runtime-0.1.4.dist-info → agentscope_runtime-0.1.5b1.dist-info}/licenses/LICENSE +0 -0
  43. {agentscope_runtime-0.1.4.dist-info → agentscope_runtime-0.1.5b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,2886 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint: disable=too-many-branches,too-many-return-statements,line-too-long
3
+
4
+ """
5
+ Responses Adapter
6
+
7
+ Bidirectional protocol converter: Responses API ↔ Agent API
8
+
9
+ Conversion functions:
10
+ 1. Responses API request → Agent API request
11
+ 2. Agent API event → Responses API event
12
+ 3. Support for streaming and non-streaming conversion
13
+ """
14
+
15
+ import time
16
+ import uuid
17
+ from typing import Any, Dict, List, Optional, Union
18
+
19
+ # OpenAI Responses API Types
20
+ from openai.types.responses import (
21
+ Response,
22
+ ResponseCompletedEvent,
23
+ ResponseContentPartAddedEvent,
24
+ ResponseContentPartDoneEvent,
25
+ ResponseCreatedEvent,
26
+ ResponseErrorEvent,
27
+ ResponseFailedEvent,
28
+ ResponseFunctionCallArgumentsDeltaEvent,
29
+ ResponseFunctionCallArgumentsDoneEvent,
30
+ ResponseInProgressEvent,
31
+ ResponseOutputItemAddedEvent,
32
+ ResponseOutputItemDoneEvent,
33
+ ResponseReasoningTextDeltaEvent,
34
+ ResponseReasoningTextDoneEvent,
35
+ ResponseRefusalDeltaEvent,
36
+ ResponseRefusalDoneEvent,
37
+ ResponseStatus,
38
+ ResponseStreamEvent,
39
+ ResponseTextDeltaEvent,
40
+ ResponseTextDoneEvent,
41
+ )
42
+ from openai.types.responses.response_function_tool_call import (
43
+ ResponseFunctionToolCall,
44
+ )
45
+ from openai.types.responses.response_mcp_call_completed_event import (
46
+ ResponseMcpCallCompletedEvent,
47
+ )
48
+ from openai.types.responses.response_mcp_call_in_progress_event import (
49
+ ResponseMcpCallInProgressEvent,
50
+ )
51
+ from openai.types.responses.response_mcp_list_tools_completed_event import (
52
+ ResponseMcpListToolsCompletedEvent,
53
+ )
54
+ from openai.types.responses.response_mcp_list_tools_in_progress_event import (
55
+ ResponseMcpListToolsInProgressEvent,
56
+ )
57
+ from openai.types.responses.response_output_item import (
58
+ McpCall,
59
+ McpListTools,
60
+ McpListToolsTool,
61
+ ResponseOutputItem,
62
+ )
63
+ from openai.types.responses.response_output_message import (
64
+ ResponseOutputMessage,
65
+ )
66
+ from openai.types.responses.response_output_refusal import (
67
+ ResponseOutputRefusal,
68
+ )
69
+ from openai.types.responses.response_output_text import ResponseOutputText
70
+ from openai.types.responses.response_reasoning_item import (
71
+ ResponseReasoningItem,
72
+ )
73
+
74
+ from agentscope_runtime.engine.schemas.agent_schemas import (
75
+ AgentRequest,
76
+ BaseResponse,
77
+ Content,
78
+ ContentType,
79
+ DataContent,
80
+ Event,
81
+ Message,
82
+ MessageType,
83
+ RefusalContent,
84
+ Role,
85
+ RunStatus,
86
+ TextContent,
87
+ ToolCall,
88
+ ToolCallOutput,
89
+ FunctionTool,
90
+ Tool,
91
+ ImageContent,
92
+ AudioContent,
93
+ FileContent,
94
+ )
95
+
96
+
97
+ # Agent API Types
98
+
99
+
100
+ class ResponsesAdapter:
101
+ """
102
+ Bidirectional protocol converter: Responses API ↔ Agent API
103
+
104
+ Main functions:
105
+ 1. Convert Responses API request → Agent API request
106
+ 2. Convert Agent API event → Responses API event
107
+ 3. Convert Responses API event stream → Agent API event stream
108
+ 4. Handle various message types (text, tool calls, reasoning, etc.)
109
+ """
110
+
111
+ def __init__(self):
112
+ self.sequence_counter = 0
113
+ # Temporary storage structure: key is message id, value is dict
114
+ # containing message_type and content_index_list
115
+ self._message_content_index_map: Dict = {}
116
+ # Additional adaptation work for adapting Agent API RAG plugin calls
117
+ # to Responses API FileSearch calls
118
+ self._file_search_call_map: Optional[Dict] = None
119
+ self._output_index: int = 0
120
+ self._output: List[ResponseOutputItem] = []
121
+
122
+ def convert_agent_response_to_responses(
123
+ self,
124
+ agent_response: BaseResponse,
125
+ ):
126
+ # First convert Response
127
+ response = self._convert_agent_response_responses_api(
128
+ agent_response=agent_response,
129
+ )
130
+
131
+ # Convert Message
132
+ messages = self._convert_agent_message_to_responses(
133
+ agent_message_list=agent_response.output,
134
+ )
135
+ response.output = messages
136
+
137
+ # Convert Content
138
+ return response
139
+
140
+ def convert_status_to_responses(self, agent_status: str) -> ResponseStatus:
141
+ if agent_status in (RunStatus.Created, RunStatus.Queued):
142
+ return "queued"
143
+ elif agent_status == RunStatus.InProgress:
144
+ return "in_progress"
145
+ elif agent_status == RunStatus.Completed:
146
+ return "completed"
147
+ elif agent_status == RunStatus.Failed:
148
+ return "failed"
149
+ elif agent_status == RunStatus.Cancelled:
150
+ return "cancelled"
151
+ elif agent_status == RunStatus.Incomplete:
152
+ return "incomplete"
153
+ else:
154
+ return "in_progress"
155
+
156
+ def _convert_agent_message_to_responses(
157
+ self,
158
+ agent_message_list: List[Message],
159
+ ):
160
+ messages = []
161
+ if agent_message_list:
162
+ for message in agent_message_list:
163
+ if message.type == MessageType.MESSAGE:
164
+ output_message = (
165
+ self._convert_message_type_to_output_message(
166
+ message,
167
+ )
168
+ )
169
+ messages.append(output_message)
170
+ if message.type == MessageType.FUNCTION_CALL:
171
+ function_call_message = (
172
+ self._convert_function_call_to_output_message(
173
+ message,
174
+ )
175
+ )
176
+ messages.append(function_call_message)
177
+ if message.type == MessageType.MCP_LIST_TOOLS:
178
+ mcp_list_tools_message = (
179
+ self._convert_mcp_list_tools_to_output_message(
180
+ message,
181
+ )
182
+ )
183
+ messages.append(mcp_list_tools_message)
184
+ if message.type == MessageType.MCP_TOOL_CALL:
185
+ tool_call_message = (
186
+ self._convert_mcp_tool_call_to_output_message(
187
+ message,
188
+ )
189
+ )
190
+ messages.append(tool_call_message)
191
+ if message.type == MessageType.REASONING:
192
+ reasoning_message = (
193
+ self._convert_reasoning_to_output_message(
194
+ message,
195
+ )
196
+ )
197
+ messages.append(reasoning_message)
198
+ return messages
199
+
200
+ def _convert_agent_response_responses_api(
201
+ self,
202
+ agent_response: BaseResponse,
203
+ ):
204
+ status = agent_response.status
205
+ response_status = self.convert_status_to_responses(status)
206
+
207
+ # Extract real data from agent_event
208
+ response_id = (
209
+ getattr(
210
+ agent_response,
211
+ "id",
212
+ f"resp_{uuid.uuid4().hex[:8]}",
213
+ )
214
+ or f"resp_{uuid.uuid4().hex[:8]}"
215
+ )
216
+ created_at = (
217
+ getattr(
218
+ agent_response,
219
+ "created_at",
220
+ time.time(),
221
+ )
222
+ or time.time()
223
+ )
224
+ # Modified: ensure model value returns default empty string when None
225
+ model = getattr(agent_response, "model", "") or ""
226
+ parallel_tool_calls = (
227
+ getattr(
228
+ agent_response,
229
+ "parallel_tool_calls",
230
+ False,
231
+ )
232
+ or False
233
+ )
234
+ tool_choice = getattr(agent_response, "tool_choice", "auto") or "auto"
235
+ tools = getattr(agent_response, "tools", []) or []
236
+ error = getattr(agent_response, "error", None)
237
+
238
+ # Convert Agent API error to Responses API error
239
+ responses_error = None
240
+ if error:
241
+ responses_error = self._convert_agent_error_to_responses_error(
242
+ error,
243
+ )
244
+
245
+ # Create real Response object using data from agent_event
246
+ response = Response(
247
+ id=response_id,
248
+ status=response_status,
249
+ created_at=created_at,
250
+ model=model,
251
+ object="response",
252
+ output=[],
253
+ parallel_tool_calls=parallel_tool_calls,
254
+ tool_choice=tool_choice,
255
+ tools=tools,
256
+ error=responses_error, # Set converted error
257
+ )
258
+
259
+ return response
260
+
261
+ # ===== Request conversion: Responses API → Agent API =====
262
+
263
+ def convert_responses_request_to_agent_request(
264
+ self,
265
+ responses_request: Dict[str, Any],
266
+ ) -> AgentRequest:
267
+ """
268
+ Convert Responses API request to Agent API request
269
+
270
+ Implement automatic assignment of fields with the same name,
271
+ then explicitly handle different field names
272
+
273
+ Args:
274
+ responses_request: OpenAI ResponseCreateParams
275
+
276
+ Returns:
277
+ AgentRequest: Agent API request format
278
+ """
279
+ # 1. Extract input messages
280
+ input_messages = self._extract_input_messages(responses_request)
281
+
282
+ # 2. Automatic assignment of fields with the same name
283
+ common_fields = self._extract_common_fields(
284
+ responses_request=responses_request,
285
+ request_type="agent",
286
+ )
287
+
288
+ # 3. Explicit mapping of different field names
289
+ special_mappings = self._extract_special_mappings(responses_request)
290
+
291
+ # 4. Merge all fields to create AgentRequest
292
+ agent_request_data = {
293
+ "input": input_messages,
294
+ **common_fields,
295
+ **special_mappings,
296
+ }
297
+
298
+ return AgentRequest(**agent_request_data)
299
+
300
+ def _extract_input_messages(
301
+ self,
302
+ responses_request: Dict[str, Any],
303
+ ) -> List[Message]:
304
+ """Extract and convert input messages"""
305
+ input_messages = []
306
+
307
+ # Extract input from responses_request
308
+ if "input" in responses_request and responses_request["input"]:
309
+ input_data = responses_request["input"]
310
+
311
+ # Handle Text input (string) type
312
+ if isinstance(input_data, str):
313
+ message = self._convert_text_input_to_agent_message(input_data)
314
+ input_messages.append(message)
315
+
316
+ # Handle Input item list (array) type
317
+ elif isinstance(input_data, list):
318
+ for input_item in input_data:
319
+ # Filter out developer role (not supported yet)
320
+ if "developer" == input_item.get("role", "user"):
321
+ continue
322
+
323
+ # Handle dictionary format input
324
+ if isinstance(input_item, dict):
325
+ item_type = input_item.get("type")
326
+
327
+ # If there's no type field but has role and content,
328
+ # consider it as message type
329
+ if (
330
+ not item_type
331
+ and "role" in input_item
332
+ and "content" in input_item
333
+ ):
334
+ item_type = "message"
335
+ else:
336
+ item_type = getattr(input_item, "type", None)
337
+
338
+ if item_type == "message":
339
+ # Convert to Agent API Message
340
+ message = self._convert_responses_input_message_to_agent_message( # noqa: E501
341
+ input_item,
342
+ )
343
+ input_messages.append(message)
344
+ elif item_type == "reasoning":
345
+ # Convert to Agent API Message (type=REASONING)
346
+ message = self._convert_reasoning_to_message(
347
+ input_item,
348
+ )
349
+ input_messages.append(message)
350
+ elif item_type == "custom_tool_call":
351
+ # Convert to Agent API Message (type=PLUGIN_CALL)
352
+ message = self._convert_custom_tool_call_to_message(
353
+ input_item,
354
+ )
355
+ input_messages.append(message)
356
+ elif item_type == "custom_tool_call_output":
357
+ # Convert to Agent API Message
358
+ # (type=PLUGIN_CALL_OUTPUT)
359
+ message = (
360
+ self._convert_custom_tool_call_output_to_message(
361
+ input_item,
362
+ )
363
+ )
364
+ input_messages.append(message)
365
+ elif item_type == "function_call":
366
+ # Convert to Agent API Message (type=FUNCTION_CALL)
367
+ message = self._convert_function_call_to_message(
368
+ input_item,
369
+ )
370
+ input_messages.append(message)
371
+ elif item_type == "function_call_output":
372
+ # Convert to Agent API Message
373
+ # (type=FUNCTION_CALL_OUTPUT)
374
+ message = (
375
+ self._convert_function_call_output_to_message(
376
+ input_item,
377
+ )
378
+ )
379
+ input_messages.append(message)
380
+
381
+ return input_messages
382
+
383
+ def _convert_text_input_to_agent_message(self, text_input: str) -> Message:
384
+ """Convert Text input (string) to Agent API Message"""
385
+
386
+ # Create text content
387
+ text_content = TextContent(type="text", text=text_input, delta=False)
388
+
389
+ # Create message
390
+ message = Message(
391
+ role=Role.USER,
392
+ type="message",
393
+ content=[text_content],
394
+ )
395
+
396
+ return message
397
+
398
+ def _extract_common_fields(
399
+ self,
400
+ responses_request: Dict[str, Any],
401
+ request_type: Optional[str] = "agent",
402
+ ) -> Dict[str, Any]:
403
+ """
404
+ Intelligently extract fields with the same name, automatically detect
405
+ and map fields with the same name and type
406
+
407
+ Automatically discover fields with the same name and type in
408
+ ResponseCreateParams and AgentRequest through reflection mechanism
409
+ """
410
+ common_fields = {}
411
+
412
+ # Get AgentRequest field information
413
+ request_fields = None
414
+ if request_type == "workflow":
415
+ request_fields = self._get_workflow_request_field_info()
416
+ else:
417
+ request_fields = self._get_agent_request_field_info()
418
+
419
+ # Iterate through all keys in ResponseCreateParams
420
+ for attr_name in responses_request.keys():
421
+ # Skip private attributes and methods
422
+ if attr_name.startswith("_"):
423
+ continue
424
+
425
+ # Get value
426
+ try:
427
+ value = responses_request[attr_name]
428
+ except KeyError:
429
+ continue
430
+
431
+ # Skip None values
432
+ if value is None:
433
+ continue
434
+
435
+ # Check if AgentRequest has field with same name
436
+ if attr_name not in request_fields:
437
+ continue
438
+
439
+ # Skip fields that need special handling
440
+ if attr_name == "input":
441
+ # input field needs special conversion, not handled here
442
+ continue
443
+ if attr_name == "tools":
444
+ # tools field needs special conversion, convert Responses API
445
+ # format to Agent API format
446
+ converted_tools = self._convert_responses_tools_to_agent_tools(
447
+ value,
448
+ )
449
+ if converted_tools is not None:
450
+ common_fields[attr_name] = converted_tools
451
+ continue
452
+
453
+ # Check if types are compatible
454
+ agent_field_type = request_fields[attr_name]
455
+ if self._is_type_compatible(value, agent_field_type):
456
+ common_fields[attr_name] = value
457
+
458
+ return common_fields
459
+
460
+ def _convert_responses_tools_to_agent_tools(
461
+ self,
462
+ responses_tools: List[
463
+ Dict[
464
+ str,
465
+ Any,
466
+ ]
467
+ ],
468
+ ) -> Optional[List[Any]]:
469
+ """
470
+ Convert Responses API tools format to Agent API tools format
471
+
472
+ Responses API format:
473
+ [{
474
+ "name": "get_weather",
475
+ "description": "Get the current weather in a given location",
476
+ "strict": true,
477
+ "type": "function",
478
+ "parameters": {
479
+ "type": "object",
480
+ "properties": {...},
481
+ "required": [...]
482
+ }
483
+ }]
484
+
485
+ Agent API format:
486
+ [{
487
+ "type": "function",
488
+ "function": {
489
+ "name": "get_weather",
490
+ "description": "Get the current weather in a given location",
491
+ "parameters": {
492
+ "type": "object",
493
+ "properties": {...},
494
+ "required": [...]
495
+ }
496
+ }
497
+ }]
498
+ """
499
+ if not responses_tools or not isinstance(responses_tools, list):
500
+ return None
501
+
502
+ converted_tools = []
503
+ for tool_data in responses_tools:
504
+ if not isinstance(tool_data, dict):
505
+ continue
506
+
507
+ # Extract basic information
508
+ name = tool_data.get("name", "")
509
+ description = tool_data.get("description", "")
510
+ tool_type = tool_data.get("type", "function")
511
+ parameters = tool_data.get("parameters", {})
512
+
513
+ # Skip invalid tools
514
+ if not name:
515
+ continue
516
+
517
+ # Create FunctionTool
518
+ function_tool = FunctionTool(
519
+ name=name,
520
+ description=description,
521
+ parameters=parameters,
522
+ )
523
+
524
+ # Create Agent API Tool
525
+ agent_tool = Tool(type=tool_type, function=function_tool)
526
+
527
+ converted_tools.append(agent_tool)
528
+
529
+ return converted_tools if converted_tools else None
530
+
531
+ def _get_agent_request_field_info(self) -> Dict[str, type]:
532
+ """Get AgentRequest field type information"""
533
+ # Cache field information to avoid repeated calculations
534
+ if not hasattr(self, "_agent_request_fields_cache"):
535
+ from typing import get_type_hints
536
+
537
+ # Get AgentRequest type annotations
538
+ type_hints = get_type_hints(AgentRequest)
539
+ self._agent_request_fields_cache = type_hints
540
+
541
+ return self._agent_request_fields_cache
542
+
543
+ def _is_type_compatible(self, value: Any, target_type: type) -> bool:
544
+ """Check if value type is compatible with target type"""
545
+ if target_type is None:
546
+ return True
547
+
548
+ # Handle Union types (e.g. Optional[str] = Union[str, None])
549
+ if (
550
+ hasattr(
551
+ target_type,
552
+ "__origin__",
553
+ )
554
+ and target_type.__origin__ is Union
555
+ ):
556
+ # Check if compatible with any type in Union
557
+ for union_type in target_type.__args__:
558
+ if union_type is type(None): # Skip None type
559
+ continue
560
+ if self._is_type_compatible(value, union_type):
561
+ return True
562
+ return False
563
+
564
+ # Handle List types
565
+ if (
566
+ hasattr(
567
+ target_type,
568
+ "__origin__",
569
+ )
570
+ and target_type.__origin__ is list
571
+ ):
572
+ if isinstance(value, list):
573
+ return True
574
+ return False
575
+
576
+ # Handle basic types
577
+ try:
578
+ # Direct type check
579
+ if isinstance(value, target_type):
580
+ return True
581
+
582
+ # Special type conversion check - more strict check
583
+ if target_type == str and isinstance(value, (str, int, float)):
584
+ return True
585
+ if target_type == int and isinstance(value, int):
586
+ return True # Only allow integers
587
+ if target_type == float and isinstance(value, (float, int)):
588
+ return True # Allow integer to float conversion
589
+ if target_type == bool and isinstance(value, bool):
590
+ return True # Only allow boolean values
591
+
592
+ except Exception:
593
+ pass
594
+
595
+ return False
596
+
597
+ def _extract_special_mappings(
598
+ self,
599
+ responses_request: Dict[str, Any],
600
+ ) -> Dict[str, Any]:
601
+ """
602
+ Extract different field names, explicit mapping
603
+
604
+ Different field name mappings:
605
+ - max_output_tokens -> max_tokens
606
+ - conversation -> session_id
607
+ - previous_response_id -> previous_response_id
608
+ """
609
+ special_mappings = {}
610
+
611
+ # conversation -> session_id
612
+ if "conversation" in responses_request:
613
+ conversation = responses_request["conversation"]
614
+ if conversation is not None:
615
+ # If conversation is an object, extract ID
616
+ if hasattr(conversation, "id"):
617
+ special_mappings["session_id"] = conversation.id
618
+ elif isinstance(conversation, dict) and "id" in conversation:
619
+ special_mappings["session_id"] = conversation["id"]
620
+ else:
621
+ # If conversation is itself an ID string
622
+ special_mappings["session_id"] = str(conversation)
623
+
624
+ return special_mappings
625
+
626
+ def _convert_responses_input_message_to_agent_message(
627
+ self,
628
+ input_message,
629
+ ) -> Message:
630
+ """Convert Responses API Input message to Agent API Message"""
631
+
632
+ # Extract message attributes
633
+ if isinstance(input_message, dict):
634
+ content = input_message.get("content", [])
635
+ role = input_message.get("role", "user")
636
+ msg_type = input_message.get("type", "message")
637
+ else:
638
+ content = getattr(input_message, "content", [])
639
+ role = getattr(input_message, "role", "user")
640
+ msg_type = getattr(input_message, "type", "message")
641
+
642
+ # Convert content items
643
+ content_list = []
644
+
645
+ # If content is string, directly convert to TextContent
646
+ if isinstance(content, str):
647
+ text_content = TextContent(
648
+ type=ContentType.TEXT,
649
+ text=content,
650
+ delta=False,
651
+ )
652
+ content_list.append(text_content)
653
+ # If content is list, iterate and convert each item
654
+ elif isinstance(content, list):
655
+ for content_item in content:
656
+ agent_content = self._convert_content_item_to_agent_content(
657
+ content_item,
658
+ )
659
+ if agent_content:
660
+ content_list.append(agent_content)
661
+
662
+ # Create Agent API Message
663
+ message = Message(role=role, type=msg_type, content=content_list)
664
+
665
+ return message
666
+
667
+ def _convert_reasoning_to_message(self, input_reasoning) -> Message:
668
+ """Convert Responses API Input reasoning to Agent API Message"""
669
+ # Extract reasoning attributes
670
+ if isinstance(input_reasoning, dict):
671
+ content = input_reasoning.get("content", [])
672
+ else:
673
+ content = getattr(input_reasoning, "content", [])
674
+
675
+ # Convert content items to text content
676
+ content_list = []
677
+
678
+ # Process content
679
+ for content_item in content:
680
+ if isinstance(content_item, dict):
681
+ content_text = content_item.get("text", "")
682
+ else:
683
+ content_text = getattr(content_item, "text", "")
684
+
685
+ if content_text:
686
+ text_content = TextContent(
687
+ type=ContentType.TEXT,
688
+ text=content_text,
689
+ )
690
+ content_list.append(text_content)
691
+
692
+ # Create Agent API Message (type=REASONING)
693
+ message = Message(
694
+ role="assistant",
695
+ # reasoning is usually assistant's reasoning process
696
+ type=MessageType.REASONING,
697
+ content=content_list,
698
+ )
699
+
700
+ return message
701
+
702
+ def _convert_content_item_to_agent_content(self, content_item):
703
+ """Convert content item to Agent API Content"""
704
+
705
+ # Handle dictionary or object format content items
706
+ if isinstance(content_item, dict):
707
+ content_type = content_item.get("type")
708
+ content_text = content_item.get("text")
709
+ content_refusal = content_item.get("refusal")
710
+ image_url = content_item.get("image_url")
711
+ # Audio data is in input_audio object
712
+ input_audio = content_item.get("input_audio", {})
713
+ audio_data = (
714
+ input_audio.get("data")
715
+ if isinstance(
716
+ input_audio,
717
+ dict,
718
+ )
719
+ else None
720
+ )
721
+ audio_format = (
722
+ input_audio.get("format")
723
+ if isinstance(
724
+ input_audio,
725
+ dict,
726
+ )
727
+ else None
728
+ )
729
+ # File data is directly at root level
730
+ file_data = content_item.get("file_data")
731
+ file_id = content_item.get("file_id")
732
+ file_url = content_item.get("file_url")
733
+ filename = content_item.get("filename")
734
+ else:
735
+ content_type = getattr(content_item, "type", None)
736
+ content_text = getattr(content_item, "text", None)
737
+ content_refusal = getattr(content_item, "refusal", None)
738
+ image_url = getattr(content_item, "image_url", None)
739
+ # Audio data is in input_audio object
740
+ input_audio = getattr(content_item, "input_audio", None)
741
+ audio_data = (
742
+ getattr(
743
+ input_audio,
744
+ "data",
745
+ None,
746
+ )
747
+ if input_audio
748
+ else None
749
+ )
750
+ audio_format = (
751
+ getattr(
752
+ input_audio,
753
+ "format",
754
+ None,
755
+ )
756
+ if input_audio
757
+ else None
758
+ )
759
+ # File data is directly at root level
760
+ file_data = getattr(content_item, "file_data", None)
761
+ file_id = getattr(content_item, "file_id", None)
762
+ file_url = getattr(content_item, "file_url", None)
763
+ filename = getattr(content_item, "filename", None)
764
+
765
+ # Convert different types of input content
766
+ if content_type == "input_text" and content_text:
767
+ return TextContent(type=ContentType.TEXT, text=content_text)
768
+ elif content_type == "output_text" and content_text:
769
+ return TextContent(type=ContentType.TEXT, text=content_text)
770
+ elif content_type == "refusal" and content_refusal:
771
+ return RefusalContent(
772
+ type=ContentType.REFUSAL,
773
+ refusal=content_refusal,
774
+ )
775
+ elif content_type == "input_image" and image_url:
776
+ return ImageContent(type=ContentType.IMAGE, image_url=image_url)
777
+ elif content_type == "input_audio" and audio_data:
778
+ return AudioContent(
779
+ type=ContentType.AUDIO,
780
+ data=audio_data,
781
+ format=audio_format,
782
+ )
783
+ elif content_type == "input_file" and (
784
+ file_url or file_id or file_data
785
+ ):
786
+ return FileContent(
787
+ type=ContentType.FILE,
788
+ file_url=file_url,
789
+ file_id=file_id,
790
+ filename=filename,
791
+ )
792
+
793
+ return None
794
+
795
+ # ===== Response conversion: Agent API → Responses API =====
796
+
797
+ def convert_agent_event_to_responses_event(
798
+ self,
799
+ agent_event: Event,
800
+ ) -> Optional[List[ResponseStreamEvent]]:
801
+ """
802
+ Convert Agent API event to Responses API stream event
803
+
804
+ Args:
805
+ agent_event: Agent API Event
806
+
807
+ Returns:
808
+ ResponseStreamEvent or None
809
+ """
810
+ # 1. If it's a response message type, convert to response stream
811
+ # message in responses api
812
+ if isinstance(agent_event, BaseResponse):
813
+ return self._convert_response_to_responses_event(agent_event)
814
+
815
+ # 2. If it's a message message type, convert to corresponding
816
+ # message type
817
+ elif isinstance(agent_event, Message):
818
+ return self._convert_message_to_responses_event(agent_event)
819
+
820
+ # 3. If it's a content message, perform corresponding
821
+ # content conversion
822
+ elif isinstance(agent_event, Content):
823
+ return self._convert_content_to_responses_event(agent_event)
824
+
825
+ # Other types return None for now
826
+ return None
827
+
828
+ def _convert_response_to_responses_event(
829
+ self,
830
+ response_event: BaseResponse,
831
+ ) -> Optional[List[ResponseStreamEvent]]:
832
+ """
833
+ Convert response message type to Responses API stream event
834
+
835
+ Args:
836
+ response_event: Agent API BaseResponse
837
+
838
+ Returns:
839
+ ResponseStreamEvent or None
840
+ """
841
+ status = response_event.status
842
+ responses = []
843
+
844
+ response = self._convert_agent_response_responses_api(response_event)
845
+ response.output = self._output
846
+
847
+ # Create corresponding events based on status
848
+ if status == "created":
849
+ created = ResponseCreatedEvent(
850
+ type="response.created",
851
+ response=response,
852
+ sequence_number=0,
853
+ ) # Will be set uniformly in responses_service
854
+ responses.append(created)
855
+ elif status == "in_progress":
856
+ in_progress = ResponseInProgressEvent(
857
+ type="response.in_progress",
858
+ response=response,
859
+ sequence_number=0,
860
+ ) # Will be set uniformly in responses_service
861
+ responses.append(in_progress)
862
+ elif status == "completed":
863
+ completed = ResponseCompletedEvent(
864
+ type="response.completed",
865
+ response=response,
866
+ sequence_number=0,
867
+ ) # Will be set uniformly in responses_service
868
+ responses.append(completed)
869
+ elif status == "failed":
870
+ failed = ResponseFailedEvent(
871
+ type="response.failed",
872
+ response=response,
873
+ sequence_number=0,
874
+ ) # Will be set uniformly in responses_service
875
+ responses.append(failed)
876
+
877
+ return responses
878
+
879
+ def _convert_message_to_responses_event(
880
+ self,
881
+ message_event: Message,
882
+ ) -> Optional[List[ResponseStreamEvent]]:
883
+ """
884
+ Convert message message type to Responses API stream event
885
+
886
+ Args:
887
+ message_event: Agent API Message
888
+
889
+ Returns:
890
+ ResponseStreamEvent or None
891
+ """
892
+ message_id = message_event.id
893
+
894
+ # Check if message id already exists in temporary storage structure
895
+ if message_id not in self._message_content_index_map:
896
+ # If not, record it in the structure
897
+ self._message_content_index_map[message_id] = {
898
+ "message_type": message_event.type,
899
+ "content_index_list": [],
900
+ }
901
+
902
+ # If message_id doesn't exist, handle new message
903
+ return self._handle_new_message(message_event)
904
+ else:
905
+ # If message_id already exists, handle differently based on
906
+ # message status
907
+ return self._handle_existing_message(message_event)
908
+
909
+ def _get_add_output_index(self, message_id: str):
910
+ output_index = self._output_index
911
+ if (
912
+ self._message_content_index_map
913
+ and self._message_content_index_map[message_id]
914
+ ):
915
+ self._message_content_index_map[message_id][
916
+ "output_index"
917
+ ] = output_index
918
+ self._output_index += 1
919
+ return output_index
920
+
921
+ def _get_output_index(self, message_id: str):
922
+ if (
923
+ self._message_content_index_map
924
+ and self._message_content_index_map[message_id]
925
+ ):
926
+ return self._message_content_index_map[message_id]["output_index"]
927
+ return self._output_index
928
+
929
+ def _handle_new_message(
930
+ self,
931
+ message_event: Message,
932
+ ) -> Optional[List[ResponseStreamEvent]]:
933
+ messages = []
934
+
935
+ # Handle different message types
936
+ if message_event.type == MessageType.FUNCTION_CALL:
937
+ self._get_add_output_index(message_event.id)
938
+
939
+ elif message_event.type == MessageType.REASONING:
940
+ # reasoning directly returns ResponseReasoningItem
941
+ reasoning_item = self._convert_reasoning_to_output_message(
942
+ message_event,
943
+ )
944
+ item_added_event = ResponseOutputItemAddedEvent(
945
+ type="response.output_item.added",
946
+ item=reasoning_item,
947
+ output_index=self._output_index,
948
+ sequence_number=0,
949
+ ) # Will be set uniformly in responses_service
950
+
951
+ # sequence_number will be set uniformly in responses_service
952
+ self._get_add_output_index(message_event.id)
953
+ messages.append(item_added_event)
954
+
955
+ elif message_event.type == MessageType.MCP_LIST_TOOLS:
956
+ # Convert MCP tool list to ResponseOutputMessage
957
+ output_message = self._convert_mcp_list_tools_to_output_message(
958
+ message_event,
959
+ )
960
+ output_item_added_event = ResponseOutputItemAddedEvent(
961
+ type="response.output_item.added",
962
+ item=output_message,
963
+ output_index=self._output_index,
964
+ sequence_number=0,
965
+ ) # Will be set uniformly in responses_service
966
+
967
+ # sequence_number will be set uniformly in responses_service
968
+ self._get_add_output_index(message_event.id)
969
+ messages.append(output_item_added_event)
970
+
971
+ elif message_event.type == MessageType.MCP_TOOL_CALL:
972
+ # Convert MCP tool call to ResponseFunctionToolCall
973
+ function_tool_call = self._convert_mcp_tool_call_to_output_message(
974
+ message_event,
975
+ )
976
+ output_item_added_event = ResponseOutputItemAddedEvent(
977
+ type="response.output_item.added",
978
+ item=function_tool_call,
979
+ output_index=self._output_index,
980
+ sequence_number=0,
981
+ ) # Will be set uniformly in responses_service
982
+
983
+ # sequence_number will be set uniformly in responses_service
984
+ self._get_add_output_index(message_event.id)
985
+ messages.append(output_item_added_event)
986
+
987
+ elif message_event.type == MessageType.MESSAGE:
988
+ # Convert other types to ResponseOutputMessage
989
+ add_output_message = self._convert_message_type_to_output_message(
990
+ message_event,
991
+ )
992
+ add_output_message.content = []
993
+ add_output_message.status = RunStatus.InProgress
994
+ output_item_added_event = ResponseOutputItemAddedEvent(
995
+ type="response.output_item.added",
996
+ item=add_output_message,
997
+ output_index=self._output_index,
998
+ sequence_number=0,
999
+ ) # Will be set uniformly in responses_service
1000
+
1001
+ # sequence_number will be set uniformly in responses_service
1002
+ self._get_add_output_index(message_event.id)
1003
+ messages.append(output_item_added_event)
1004
+
1005
+ if message_event.status == "completed":
1006
+ output_message = self._convert_message_type_to_output_message(
1007
+ message_event,
1008
+ )
1009
+
1010
+ if not output_message:
1011
+ return messages
1012
+
1013
+ # Generate response.output_item.done
1014
+ # corresponding responses api object
1015
+ # sequence_number will be set uniformly in responses_service
1016
+ event = ResponseOutputItemDoneEvent(
1017
+ type="response.output_item.done",
1018
+ item=output_message,
1019
+ output_index=self._output_index,
1020
+ sequence_number=0,
1021
+ ) # Will be set uniformly in responses_service
1022
+ self._output.append(output_message)
1023
+ messages.append(event)
1024
+
1025
+ return messages
1026
+
1027
+ def _handle_existing_message(
1028
+ self,
1029
+ message_event: Message,
1030
+ ) -> Optional[List[ResponseStreamEvent]]:
1031
+ """
1032
+ # Handle existing message, generate corresponding events
1033
+ # based on message type and status
1034
+
1035
+ Args:
1036
+ message_event: Agent API Message
1037
+
1038
+ Returns:
1039
+ ResponseStreamEvent or None
1040
+ """
1041
+ # Dispatch to corresponding handler functions based on message type
1042
+ if message_event.type == MessageType.MESSAGE:
1043
+ return self._handle_message_status_change(message_event)
1044
+ elif message_event.type == MessageType.FUNCTION_CALL:
1045
+ return self._handle_function_call_status_change(message_event)
1046
+ elif message_event.type == MessageType.MCP_LIST_TOOLS:
1047
+ return self._handle_mcp_list_tools_status_change(message_event)
1048
+ elif message_event.type == MessageType.MCP_TOOL_CALL:
1049
+ return self._handle_mcp_tool_call_status_change(message_event)
1050
+ elif message_event.type == MessageType.REASONING:
1051
+ return self._handle_reasoning_status_change(message_event)
1052
+ elif message_event.type == MessageType.ERROR:
1053
+ return self._handle_error_status_change(message_event)
1054
+
1055
+ return None
1056
+
1057
+ def _handle_message_status_change(
1058
+ self,
1059
+ message_event: Message,
1060
+ ) -> Optional[List[ResponseStreamEvent]]:
1061
+ """
1062
+ Handle MESSAGE type message status changes
1063
+
1064
+ Args:
1065
+ message_event: Agent API Message
1066
+
1067
+ Returns:
1068
+ ResponseStreamEvent list or None
1069
+ """
1070
+ status = getattr(message_event, "status", "completed")
1071
+
1072
+ messages = []
1073
+
1074
+ if status == "completed":
1075
+ output_message = self._convert_message_type_to_output_message(
1076
+ message_event,
1077
+ )
1078
+
1079
+ if not output_message:
1080
+ return messages
1081
+
1082
+ output_index = self._get_output_index(message_id=message_event.id)
1083
+
1084
+ # Generate response.output_item.done
1085
+ # corresponding responses api object
1086
+ # sequence_number will be set uniformly in responses_service
1087
+ event = ResponseOutputItemDoneEvent(
1088
+ type="response.output_item.done",
1089
+ item=output_message,
1090
+ output_index=output_index,
1091
+ sequence_number=0,
1092
+ ) # Will be set uniformly in responses_service
1093
+ self._output.append(output_message)
1094
+ messages.append(event)
1095
+
1096
+ return messages
1097
+
1098
+ def _handle_function_call_status_change(
1099
+ self,
1100
+ message_event: Message,
1101
+ ) -> Optional[List[ResponseStreamEvent]]:
1102
+ """
1103
+ Handle FUNCTION_CALL type message status changes
1104
+
1105
+ Args:
1106
+ message_event: Agent API Message
1107
+
1108
+ Returns:
1109
+ ResponseStreamEvent list or None
1110
+ """
1111
+ status = getattr(message_event, "status", "completed")
1112
+
1113
+ if status == "completed":
1114
+ messages = []
1115
+ output_message = None
1116
+
1117
+ output_message = self._convert_function_call_to_output_message(
1118
+ message_event,
1119
+ )
1120
+
1121
+ if not output_message:
1122
+ return messages
1123
+
1124
+ output_index = self._get_output_index(message_id=message_event.id)
1125
+
1126
+ # Generate response.output_item.done
1127
+ # corresponding responses api object
1128
+ # sequence_number will be set uniformly in responses_service
1129
+ event = ResponseOutputItemDoneEvent(
1130
+ type="response.output_item.done",
1131
+ item=output_message,
1132
+ output_index=output_index,
1133
+ sequence_number=0,
1134
+ ) # Will be set uniformly in responses_service
1135
+ messages.append(event)
1136
+ self._output.append(output_message)
1137
+ return messages
1138
+
1139
+ return None
1140
+
1141
+ def _handle_mcp_list_tools_status_change(
1142
+ self,
1143
+ message_event: Message,
1144
+ ) -> Optional[List[ResponseStreamEvent]]:
1145
+ """
1146
+ Handle MCP_LIST_TOOLS type message status changes
1147
+
1148
+ Args:
1149
+ message_event: Agent API Message
1150
+
1151
+ Returns:
1152
+ ResponseStreamEvent list or None
1153
+ """
1154
+ status = getattr(message_event, "status", "completed")
1155
+ events = []
1156
+
1157
+ # Get output_index
1158
+ output_index = self._get_output_index(message_event.id)
1159
+
1160
+ if status == "in_progress":
1161
+ event = self._create_mcp_list_tools_in_progress_event(
1162
+ message_event,
1163
+ output_index,
1164
+ )
1165
+ if event:
1166
+ events.append(event)
1167
+ elif status == "completed":
1168
+ completed_events = self._create_mcp_list_tools_completed_event(
1169
+ message_event,
1170
+ output_index,
1171
+ )
1172
+ if completed_events:
1173
+ events.extend(completed_events)
1174
+ elif status == "failed":
1175
+ error_message = "MCP list tools operation failed"
1176
+ error_event = self._create_error_event(
1177
+ error_message=error_message,
1178
+ )
1179
+ if error_event:
1180
+ events.append(error_event)
1181
+
1182
+ return events if events else None
1183
+
1184
+ def _handle_mcp_tool_call_status_change(
1185
+ self,
1186
+ message_event: Message,
1187
+ ) -> Optional[List[ResponseStreamEvent]]:
1188
+ """
1189
+ Handle MCP_TOOL_CALL type message status changes
1190
+
1191
+ Args:
1192
+ message_event: Agent API Message
1193
+
1194
+ Returns:
1195
+ ResponseStreamEvent list or None
1196
+ """
1197
+ status = getattr(message_event, "status", "completed")
1198
+ events = []
1199
+
1200
+ # Get output_index
1201
+ output_index = self._get_output_index(message_event.id)
1202
+
1203
+ if status == "in_progress":
1204
+ event = self._create_mcp_tool_call_in_progress_event(
1205
+ message_event,
1206
+ output_index,
1207
+ )
1208
+ if event:
1209
+ events.append(event)
1210
+ elif status == "completed":
1211
+ completed_events = self._create_mcp_tool_call_completed_event(
1212
+ message_event,
1213
+ output_index,
1214
+ )
1215
+ if completed_events:
1216
+ events.extend(completed_events)
1217
+ elif status == "failed":
1218
+ error_message = "MCP tool call operation failed"
1219
+ error_event = self._create_error_event(
1220
+ error_message=error_message,
1221
+ )
1222
+ if error_event:
1223
+ events.append(error_event)
1224
+
1225
+ return events if events else None
1226
+
1227
+ def _handle_reasoning_status_change(
1228
+ self,
1229
+ message_event: Message,
1230
+ ) -> Optional[List[ResponseStreamEvent]]:
1231
+ """
1232
+ Handle REASONING type message status changes
1233
+
1234
+ Args:
1235
+ message_event: Agent API Message
1236
+
1237
+ Returns:
1238
+ ResponseStreamEvent list or None
1239
+ """
1240
+ status = getattr(message_event, "status", "completed")
1241
+
1242
+ if status == "completed":
1243
+ messages = []
1244
+
1245
+ output_message = self._convert_reasoning_to_output_message(
1246
+ message_event,
1247
+ )
1248
+
1249
+ if not output_message:
1250
+ return messages
1251
+
1252
+ # Generate response.output_item.done
1253
+ # corresponding responses api object
1254
+ # sequence_number will be set uniformly in responses_service
1255
+ event = ResponseOutputItemDoneEvent(
1256
+ type="response.output_item.done",
1257
+ item=output_message,
1258
+ output_index=self._output_index,
1259
+ sequence_number=0,
1260
+ ) # Will be set uniformly in responses_service
1261
+ messages.append(event)
1262
+ self._output.append(output_message)
1263
+ return messages
1264
+
1265
+ return None
1266
+
1267
+ def _handle_error_status_change(
1268
+ self,
1269
+ message_event: Message,
1270
+ ) -> Optional[List[ResponseStreamEvent]]:
1271
+ """
1272
+ Handle ERROR type message status changes
1273
+
1274
+ Args:
1275
+ message_event: Agent API Message
1276
+
1277
+ Returns:
1278
+ ResponseStreamEvent list or None
1279
+ """
1280
+ status = getattr(message_event, "status", "completed")
1281
+
1282
+ if status == "completed":
1283
+ messages = []
1284
+
1285
+ output_message = self._convert_error_to_output_message(
1286
+ message_event,
1287
+ )
1288
+
1289
+ if not output_message:
1290
+ return messages
1291
+
1292
+ # Generate response.output_item.done
1293
+ # corresponding responses api object
1294
+ # sequence_number will be set uniformly in responses_service
1295
+ event = ResponseOutputItemDoneEvent(
1296
+ type="response.output_item.done",
1297
+ item=output_message,
1298
+ output_index=self._output_index,
1299
+ sequence_number=0,
1300
+ ) # Will be set uniformly in responses_service
1301
+ messages.append(event)
1302
+ return messages
1303
+
1304
+ return None
1305
+
1306
+ def _convert_message_type_to_output_message(
1307
+ self,
1308
+ message: Message,
1309
+ ) -> ResponseOutputMessage:
1310
+ """
1311
+ Convert normal message type to ResponseOutputMessage
1312
+
1313
+ Args:
1314
+ message: Agent API Message (type='message')
1315
+
1316
+ Returns:
1317
+ ResponseOutputMessage: Responses API output message
1318
+ """
1319
+ # Convert content
1320
+ output_content = []
1321
+ if message.content:
1322
+ for content_item in message.content:
1323
+ if content_item.type == ContentType.TEXT:
1324
+ output_text = ResponseOutputText(
1325
+ type="output_text",
1326
+ text=content_item.text,
1327
+ annotations=[],
1328
+ )
1329
+ output_content.append(output_text)
1330
+ elif content_item.type == ContentType.REFUSAL:
1331
+ # Handle REFUSAL type
1332
+ refusal_text = getattr(content_item, "refusal", "")
1333
+ output_refusal = ResponseOutputRefusal(
1334
+ type="refusal",
1335
+ refusal=refusal_text,
1336
+ )
1337
+ output_content.append(output_refusal)
1338
+
1339
+ return self._create_base_output_message(message, output_content)
1340
+
1341
+ def _convert_function_call_to_output_message(
1342
+ self,
1343
+ message: Message,
1344
+ ) -> ResponseFunctionToolCall:
1345
+ """
1346
+ Convert function_call type to ResponseFunctionToolCall
1347
+
1348
+ Args:
1349
+ message: Agent API Message (type='function_call')
1350
+
1351
+ Returns:
1352
+ ResponseFunctionToolCall: Responses API function tool call
1353
+ """
1354
+ # Convert function call data
1355
+ function_call_data = {}
1356
+ if message.content:
1357
+ for content_item in message.content:
1358
+ if content_item.type == ContentType.DATA:
1359
+ function_call_data = content_item.data
1360
+ break
1361
+
1362
+ if not isinstance(function_call_data, dict):
1363
+ function_call_data = {}
1364
+
1365
+ # Create ResponseFunctionToolCall
1366
+ return ResponseFunctionToolCall(
1367
+ id=message.id,
1368
+ type="function_call",
1369
+ name=function_call_data.get("name", ""),
1370
+ arguments=function_call_data.get("arguments", ""),
1371
+ call_id=function_call_data.get("call_id", ""),
1372
+ status=message.status,
1373
+ )
1374
+
1375
+ def _convert_reasoning_to_output_message(
1376
+ self,
1377
+ message: Message,
1378
+ ) -> ResponseReasoningItem:
1379
+ """
1380
+ Convert reasoning type to ResponseReasoningItem
1381
+
1382
+ Args:
1383
+ message: Agent API Message (type='reasoning')
1384
+
1385
+ Returns:
1386
+ ResponseReasoningItem: Responses API reasoning item
1387
+ """
1388
+ # Extract reasoning text content from message content
1389
+ reasoning_text = ""
1390
+ if message.content:
1391
+ for content_item in message.content:
1392
+ if content_item.type == ContentType.TEXT:
1393
+ reasoning_text = content_item.text
1394
+ break
1395
+
1396
+ # Create ResponseReasoningItem
1397
+ return ResponseReasoningItem(
1398
+ type="reasoning",
1399
+ id=message.id,
1400
+ summary=[], # Empty summary
1401
+ content=(
1402
+ [Content(type="reasoning_text", text=reasoning_text)]
1403
+ if reasoning_text
1404
+ else None
1405
+ ),
1406
+ encrypted_content=None,
1407
+ status=None,
1408
+ )
1409
+
1410
+ def _convert_error_to_output_message(
1411
+ self,
1412
+ message: Message,
1413
+ ) -> ResponseOutputMessage:
1414
+ """
1415
+ Convert error type to ResponseOutputMessage
1416
+
1417
+ Args:
1418
+ message: Agent API Message (type='error')
1419
+
1420
+ Returns:
1421
+ ResponseOutputMessage: Responses API output message
1422
+ """
1423
+ # Convert error data to text content
1424
+ output_content = []
1425
+ if message.content:
1426
+ for content_item in message.content:
1427
+ if content_item.type == ContentType.TEXT:
1428
+ # Convert error text content to ResponseOutputText
1429
+ error_text = content_item.text
1430
+ if error_text:
1431
+ output_text_obj = ResponseOutputText(
1432
+ type="output_text",
1433
+ text=error_text,
1434
+ annotations=[],
1435
+ )
1436
+ output_content.append(output_text_obj)
1437
+ elif content_item.type == ContentType.DATA:
1438
+ # Handle error data content
1439
+ error_data = content_item.data
1440
+ if isinstance(error_data, dict):
1441
+ error_message = error_data.get(
1442
+ "message",
1443
+ str(error_data),
1444
+ )
1445
+ if error_message:
1446
+ output_text_obj = ResponseOutputText(
1447
+ type="output_text",
1448
+ text=error_message,
1449
+ annotations=[],
1450
+ )
1451
+ output_content.append(output_text_obj)
1452
+
1453
+ return self._create_base_output_message(message, output_content)
1454
+
1455
+ def _create_base_output_message(
1456
+ self,
1457
+ message: Message,
1458
+ content: List,
1459
+ ) -> ResponseOutputMessage:
1460
+ """
1461
+ Create base ResponseOutputMessage object
1462
+
1463
+ Args:
1464
+ message: Agent API Message
1465
+ content: Converted content list
1466
+
1467
+ Returns:
1468
+ ResponseOutputMessage: Responses API output message
1469
+ """
1470
+ # Determine status
1471
+ status = "completed" # Default status
1472
+ if hasattr(message, "status") and message.status:
1473
+ # Map Agent API status to Responses API status
1474
+ if message.status in ["in_progress", "completed", "incomplete"]:
1475
+ status = message.status
1476
+ else:
1477
+ status = "completed" # Other statuses default to completed
1478
+
1479
+ return ResponseOutputMessage(
1480
+ id=message.id,
1481
+ type="message",
1482
+ role="assistant",
1483
+ content=content,
1484
+ status=status,
1485
+ )
1486
+
1487
+ def _convert_content_to_responses_event(
1488
+ self,
1489
+ content_event,
1490
+ ) -> Optional[ResponseStreamEvent]:
1491
+ """
1492
+ Convert content message type to Responses API stream event
1493
+
1494
+ Args:
1495
+ content_event: Agent API Content
1496
+
1497
+ Returns:
1498
+ ResponseStreamEvent or None
1499
+ """
1500
+ message_id = getattr(content_event, "msg_id", None)
1501
+ if not message_id:
1502
+ return None
1503
+
1504
+ # Query corresponding message id from temporary storage structure
1505
+ # If message id doesn't exist, indicates abnormal situation,
1506
+ # should not process this content
1507
+ if message_id not in self._message_content_index_map:
1508
+ # Abnormal situation: message corresponding to
1509
+ # content event doesn't exist
1510
+ # This usually indicates message processing order issue,
1511
+ # directly return None
1512
+ return None
1513
+
1514
+ # Get message information
1515
+ message_info = self._message_content_index_map[message_id]
1516
+ message_type = message_info["message_type"]
1517
+
1518
+ # plugin calls need special adaptation, streaming not supported
1519
+ if message_type in [
1520
+ MessageType.PLUGIN_CALL,
1521
+ MessageType.PLUGIN_CALL_OUTPUT,
1522
+ ]:
1523
+ return None
1524
+
1525
+ content_indexes = message_info["content_index_list"]
1526
+ output_index = message_info["output_index"]
1527
+
1528
+ # Check if corresponding index already exists
1529
+ # (need to determine index based on content)
1530
+ content_index = content_event.index
1531
+
1532
+ new_content = content_index not in content_indexes
1533
+
1534
+ # If not, insert
1535
+ if new_content:
1536
+ content_indexes.append(content_index)
1537
+
1538
+ # Perform different content adaptation based on message type
1539
+ message_type = message_info["message_type"]
1540
+ if message_type == MessageType.MESSAGE:
1541
+ events = self._convert_message_content_to_responses_event(
1542
+ content_event,
1543
+ new_content,
1544
+ output_index,
1545
+ )
1546
+ return events if events else None
1547
+ elif message_type == MessageType.FUNCTION_CALL:
1548
+ events = self._convert_function_call_content_to_responses_event(
1549
+ content_event,
1550
+ new_content,
1551
+ output_index,
1552
+ )
1553
+ return events if events else None
1554
+ elif message_type == MessageType.REASONING:
1555
+ events = self._convert_reasoning_content_to_responses_event(
1556
+ content_event=content_event,
1557
+ output_index=output_index,
1558
+ )
1559
+ return events if events else None
1560
+ elif message_type == MessageType.ERROR:
1561
+ events = self._convert_error_content_to_responses_event(
1562
+ content_event=content_event,
1563
+ new_content=new_content,
1564
+ )
1565
+ return events if events else None
1566
+
1567
+ return None
1568
+
1569
+ def convert_response_to_agent_events(
1570
+ self,
1571
+ response: Response,
1572
+ ) -> List[Event]:
1573
+ """
1574
+ Convert OpenAI Response object to Agent API Event list
1575
+
1576
+ Args:
1577
+ response: OpenAI Response object
1578
+
1579
+ Returns:
1580
+ Agent API Event list
1581
+ """
1582
+ events = []
1583
+
1584
+ # Reset sequence counter
1585
+ self.sequence_counter = 0
1586
+
1587
+ # Create response created event
1588
+ response_created = BaseResponse(
1589
+ sequence_number=0, # Will be set uniformly in responses_service
1590
+ object="response",
1591
+ status="created",
1592
+ error=None,
1593
+ )
1594
+ events.append(response_created)
1595
+
1596
+ # Process output items
1597
+ for output_item in response.output:
1598
+ if output_item.type == "message":
1599
+ # Convert to Agent API Message and Content events
1600
+ message_events = self._convert_output_message_to_events(
1601
+ output_item,
1602
+ )
1603
+ events.extend(message_events)
1604
+
1605
+ # Create response completed event
1606
+ response_completed = BaseResponse(
1607
+ sequence_number=0, # Will be set uniformly in responses_service
1608
+ object="response",
1609
+ status="completed",
1610
+ error=None,
1611
+ )
1612
+ events.append(response_completed)
1613
+
1614
+ return events
1615
+
1616
+ def _convert_output_message_to_events(self, output_message) -> List[Event]:
1617
+ """Convert OutputMessage to Agent API events"""
1618
+ events = []
1619
+
1620
+ # Create message in progress event
1621
+ message_id = f"msg_{uuid.uuid4().hex[:8]}"
1622
+ message_event = Message(
1623
+ sequence_number=0, # Will be set uniformly in responses_service
1624
+ object="message",
1625
+ status="in_progress",
1626
+ error=None,
1627
+ id=message_id,
1628
+ type=MessageType.MESSAGE,
1629
+ role=Role.ASSISTANT,
1630
+ )
1631
+ events.append(message_event)
1632
+
1633
+ # Process content items
1634
+ for content_item in output_message.content:
1635
+ if content_item.type == "output_text":
1636
+ # Create text content events
1637
+ text_content = TextContent(
1638
+ sequence_number=0,
1639
+ # Will be set uniformly in responses_service
1640
+ object="content",
1641
+ status="completed",
1642
+ error=None,
1643
+ type=ContentType.TEXT,
1644
+ msg_id=message_id,
1645
+ delta=False,
1646
+ text=content_item.text,
1647
+ )
1648
+ events.append(text_content)
1649
+
1650
+ # Create message completed event
1651
+ message_completed = Message(
1652
+ sequence_number=0, # Will be set uniformly in responses_service
1653
+ object="message",
1654
+ status="completed",
1655
+ error=None,
1656
+ id=message_id,
1657
+ type=MessageType.MESSAGE,
1658
+ role=Role.ASSISTANT,
1659
+ )
1660
+ events.append(message_completed)
1661
+
1662
+ return events
1663
+
1664
+ def _convert_custom_tool_call_to_message(self, tool_call_item) -> Message:
1665
+ """Convert Custom tool call to Agent API Message"""
1666
+
1667
+ # Extract tool call attributes
1668
+ if isinstance(tool_call_item, dict):
1669
+ call_id = tool_call_item.get("call_id", "")
1670
+ name = tool_call_item.get("name", "")
1671
+ input_data = tool_call_item.get("input", "")
1672
+ tool_id = tool_call_item.get("id", "")
1673
+ else:
1674
+ call_id = getattr(tool_call_item, "call_id", "")
1675
+ name = getattr(tool_call_item, "name", "")
1676
+ input_data = getattr(tool_call_item, "input", "")
1677
+ tool_id = getattr(tool_call_item, "id", "")
1678
+
1679
+ # Create DataContent containing tool call data
1680
+ tool_call_data = {
1681
+ "call_id": call_id,
1682
+ "name": name,
1683
+ "input": input_data,
1684
+ "id": tool_id,
1685
+ }
1686
+
1687
+ data_content = DataContent(
1688
+ type=ContentType.DATA,
1689
+ data=tool_call_data,
1690
+ delta=False,
1691
+ )
1692
+
1693
+ # Create Message
1694
+ message = Message(type=MessageType.PLUGIN_CALL, content=[data_content])
1695
+
1696
+ return message
1697
+
1698
+ def _convert_custom_tool_call_output_to_message(
1699
+ self,
1700
+ tool_output_item,
1701
+ ) -> Message:
1702
+ """Convert Custom tool call output to Agent API Message"""
1703
+
1704
+ # Extract tool call output attributes
1705
+ if isinstance(tool_output_item, dict):
1706
+ call_id = tool_output_item.get("call_id", "")
1707
+ output = tool_output_item.get("output", "")
1708
+ output_id = tool_output_item.get("id", "")
1709
+ else:
1710
+ call_id = getattr(tool_output_item, "call_id", "")
1711
+ output = getattr(tool_output_item, "output", "")
1712
+ output_id = getattr(tool_output_item, "id", "")
1713
+
1714
+ # Create DataContent containing tool call output data
1715
+ tool_output_data = {
1716
+ "call_id": call_id,
1717
+ "output": output,
1718
+ "id": output_id,
1719
+ }
1720
+
1721
+ data_content = DataContent(
1722
+ type=ContentType.DATA,
1723
+ data=tool_output_data,
1724
+ delta=False,
1725
+ )
1726
+
1727
+ # Create Message
1728
+ message = Message(
1729
+ type=MessageType.PLUGIN_CALL_OUTPUT,
1730
+ content=[data_content],
1731
+ )
1732
+
1733
+ return message
1734
+
1735
+ def _convert_function_call_to_message(self, function_call_item) -> Message:
1736
+ """Convert Function tool call to Agent API Message"""
1737
+
1738
+ # Extract function call attributes
1739
+ if isinstance(function_call_item, dict):
1740
+ name = function_call_item.get("name", "")
1741
+ arguments = function_call_item.get("arguments", "")
1742
+ call_id = function_call_item.get("call_id", "")
1743
+ else:
1744
+ name = getattr(function_call_item, "name", "")
1745
+ arguments = getattr(function_call_item, "arguments", "")
1746
+ call_id = getattr(function_call_item, "call_id", "")
1747
+
1748
+ # Create DataContent containing function call data
1749
+ function_call_data = ToolCall.model_validate(
1750
+ {
1751
+ "name": name,
1752
+ "arguments": arguments,
1753
+ "call_id": call_id,
1754
+ },
1755
+ ).model_dump()
1756
+
1757
+ data_content = DataContent(
1758
+ type=ContentType.DATA,
1759
+ data=function_call_data,
1760
+ )
1761
+
1762
+ # Create Message
1763
+ message = Message(
1764
+ type=MessageType.FUNCTION_CALL,
1765
+ content=[data_content],
1766
+ )
1767
+
1768
+ return message
1769
+
1770
+ def _convert_function_call_output_to_message(
1771
+ self,
1772
+ function_output_item,
1773
+ ) -> Message:
1774
+ """Convert Function tool call output to Agent API Message"""
1775
+
1776
+ # Extract function call output attributes
1777
+ if isinstance(function_output_item, dict):
1778
+ call_id = function_output_item.get("call_id", "")
1779
+ output = function_output_item.get("output", "")
1780
+ else:
1781
+ call_id = getattr(function_output_item, "call_id", "")
1782
+ output = getattr(function_output_item, "output", "")
1783
+
1784
+ # Create DataContent containing function call output data
1785
+ function_output_data = ToolCallOutput.model_validate(
1786
+ {
1787
+ "call_id": call_id,
1788
+ "output": output,
1789
+ },
1790
+ ).model_dump()
1791
+
1792
+ data_content = DataContent(
1793
+ type=ContentType.DATA,
1794
+ data=function_output_data,
1795
+ )
1796
+
1797
+ # Create Message
1798
+ message = Message(
1799
+ type=MessageType.FUNCTION_CALL_OUTPUT,
1800
+ content=[data_content],
1801
+ )
1802
+
1803
+ return message
1804
+
1805
+ # ===== Content adaptation methods =====
1806
+
1807
+ def _convert_message_content_to_responses_event(
1808
+ self,
1809
+ content_event,
1810
+ new_content: bool,
1811
+ output_index: int = 0,
1812
+ ) -> Optional[ResponseStreamEvent]:
1813
+ """
1814
+ Convert MESSAGE type content to Responses API events
1815
+
1816
+ Args:
1817
+ content_event: Agent API Content event
1818
+ new_content: whether it is new content
1819
+
1820
+ Returns:
1821
+ ResponseStreamEvent or None
1822
+ """
1823
+ events = []
1824
+
1825
+ # Determine event type based on content type
1826
+ content_type = getattr(content_event, "type", None)
1827
+ content_status = getattr(content_event, "status", None)
1828
+
1829
+ if content_type == ContentType.TEXT:
1830
+ # If content is new, generate a response.content_part.added event
1831
+ if new_content:
1832
+ content_add_event = self._create_content_part_added_event(
1833
+ content_event,
1834
+ output_index,
1835
+ )
1836
+ events.append(content_add_event)
1837
+
1838
+ # If content is completed, generate a
1839
+ # response.content_part.done event
1840
+ if content_status == "completed":
1841
+ output_text_done_event = self._create_output_text_done_event(
1842
+ content_event,
1843
+ output_index,
1844
+ )
1845
+ events.append(output_text_done_event)
1846
+ content_done_event = self._create_content_part_done_event(
1847
+ content_event,
1848
+ output_index,
1849
+ )
1850
+ events.append(content_done_event)
1851
+
1852
+ if content_status == "in_progress":
1853
+ content_in_progress_event = self._create_text_delta_event(
1854
+ content_event,
1855
+ output_index,
1856
+ )
1857
+ events.append(content_in_progress_event)
1858
+
1859
+ if content_type == ContentType.REFUSAL:
1860
+ if new_content:
1861
+ content_add_event = self._create_content_part_added_event(
1862
+ content_event,
1863
+ output_index,
1864
+ )
1865
+ events.append(content_add_event)
1866
+
1867
+ if content_status == "completed":
1868
+ output_text_done_event = self._create_refusal_text_done_event(
1869
+ content_event,
1870
+ output_index,
1871
+ )
1872
+ events.append(output_text_done_event)
1873
+ content_done_event = self._create_content_part_done_event(
1874
+ content_event,
1875
+ output_index,
1876
+ )
1877
+ events.append(content_done_event)
1878
+
1879
+ if content_status == "in_progress":
1880
+ content_in_progress_event = (
1881
+ self._create_refusal_text_delta_event(
1882
+ content_event,
1883
+ output_index,
1884
+ )
1885
+ )
1886
+ events.append(content_in_progress_event)
1887
+
1888
+ return events
1889
+
1890
+ def _convert_function_call_content_to_responses_event(
1891
+ self,
1892
+ content_event,
1893
+ new_content: bool,
1894
+ output_index: int = 0,
1895
+ ) -> Optional[ResponseStreamEvent]:
1896
+ """
1897
+ Convert FUNCTION_CALL type content to Responses API events
1898
+
1899
+ Args:
1900
+ content_event: Agent API Content event
1901
+ new_content: whether it is new content
1902
+
1903
+ Returns:
1904
+ ResponseStreamEvent or None
1905
+ """
1906
+ events = []
1907
+
1908
+ # Get content type and status
1909
+ content_type = getattr(content_event, "type", None)
1910
+ content_status = getattr(content_event, "status", None)
1911
+
1912
+ if content_type == ContentType.DATA:
1913
+ if new_content:
1914
+ add_event = (
1915
+ self._create_function_call_arguments_add_output_item_event(
1916
+ content_event=content_event,
1917
+ output_index=output_index,
1918
+ )
1919
+ )
1920
+ events.append(add_event)
1921
+
1922
+ # Extract function call information from data
1923
+ function = getattr(content_event, "data", {})
1924
+ if isinstance(function, dict):
1925
+ arguments = function.get("arguments", "")
1926
+
1927
+ # Generate function_call_arguments.delta event
1928
+ if content_status == "in_progress":
1929
+ delta_event = (
1930
+ self._create_function_call_arguments_delta_event(
1931
+ content_event,
1932
+ arguments,
1933
+ output_index,
1934
+ )
1935
+ )
1936
+ events.append(delta_event)
1937
+
1938
+ if content_status == "completed":
1939
+ done_event = (
1940
+ self._create_function_call_arguments_done_event(
1941
+ content_event,
1942
+ arguments,
1943
+ output_index,
1944
+ )
1945
+ )
1946
+ events.append(done_event)
1947
+
1948
+ return events if events else None
1949
+
1950
+ def _convert_reasoning_content_to_responses_event(
1951
+ self,
1952
+ content_event,
1953
+ output_index: int = 0,
1954
+ ) -> Optional[ResponseStreamEvent]:
1955
+ """
1956
+ Convert REASONING type content to Responses API events
1957
+
1958
+ Args:
1959
+ content_event: Agent API Content event
1960
+ new_content: whether it is new content
1961
+ output_index: output index
1962
+
1963
+ Returns:
1964
+ ResponseStreamEvent or None
1965
+ """
1966
+ events = []
1967
+
1968
+ # Get content type and status
1969
+ content_type = getattr(content_event, "type", None)
1970
+ content_status = getattr(content_event, "status", None)
1971
+
1972
+ if content_type == ContentType.TEXT:
1973
+ # Extract reasoning content from text
1974
+ reasoning_text = getattr(content_event, "text", "")
1975
+
1976
+ # Generate reasoning_text.delta event
1977
+ if content_status == "in_progress":
1978
+ delta_event = self._create_reasoning_text_delta_event(
1979
+ content_event,
1980
+ reasoning_text,
1981
+ output_index,
1982
+ )
1983
+ events.append(delta_event)
1984
+
1985
+ if content_status == "completed":
1986
+ # First generate delta event, then generate done event
1987
+ delta_event = self._create_reasoning_text_delta_event(
1988
+ content_event,
1989
+ reasoning_text,
1990
+ output_index,
1991
+ )
1992
+ events.append(delta_event)
1993
+ done_event = self._create_reasoning_text_done_event(
1994
+ content_event,
1995
+ reasoning_text,
1996
+ output_index,
1997
+ )
1998
+ events.append(done_event)
1999
+
2000
+ return events if events else None
2001
+
2002
+ def _convert_error_content_to_responses_event(
2003
+ self,
2004
+ content_event,
2005
+ new_content: bool,
2006
+ ) -> Optional[ResponseStreamEvent]:
2007
+ """
2008
+ Convert ERROR type content to Responses API events
2009
+
2010
+ Args:
2011
+ content_event: Agent API Content event
2012
+ new_content: whether it is new content
2013
+
2014
+ Returns:
2015
+ ResponseStreamEvent or None
2016
+ """
2017
+ events = []
2018
+
2019
+ # Get content type and status
2020
+ content_type = getattr(content_event, "type", None)
2021
+ content_status = getattr(content_event, "status", None)
2022
+
2023
+ if content_type == ContentType.TEXT:
2024
+ # Extract error message from text
2025
+ error_text = getattr(content_event, "text", "")
2026
+
2027
+ if new_content and content_status == "completed":
2028
+ # Generate error event
2029
+ error_event = self._create_error_event(
2030
+ error_message=error_text,
2031
+ )
2032
+ events.append(error_event)
2033
+ elif content_type == ContentType.DATA:
2034
+ # Extract error information from data
2035
+ data = getattr(content_event, "data", {})
2036
+ if isinstance(data, dict):
2037
+ error_message = data.get("message", str(data))
2038
+
2039
+ if new_content and content_status == "completed":
2040
+ # Generate error event
2041
+ error_event = self._create_error_event(
2042
+ error_message=error_message,
2043
+ )
2044
+ events.append(error_event)
2045
+
2046
+ return events if events else None
2047
+
2048
+ def _create_content_part_added_event(
2049
+ self,
2050
+ content_event: Content,
2051
+ output_index: int = 0,
2052
+ ) -> ResponseStreamEvent:
2053
+ """
2054
+ Create response.content_part.added event
2055
+
2056
+ Args:
2057
+ content_event: Agent API Content event
2058
+
2059
+ Returns:
2060
+ ResponseStreamEvent: Responses API event
2061
+ """
2062
+ # Create corresponding part based on content type
2063
+ content_type = getattr(content_event, "type", None)
2064
+
2065
+ if content_type == ContentType.TEXT:
2066
+ part = ResponseOutputText(
2067
+ type="output_text",
2068
+ text="",
2069
+ annotations=[],
2070
+ )
2071
+ elif content_type == ContentType.REFUSAL:
2072
+ part = ResponseOutputRefusal(type="refusal", refusal="")
2073
+ else:
2074
+ # Default to text type
2075
+ part = ResponseOutputText(
2076
+ type="output_text",
2077
+ text=getattr(content_event, "text", ""),
2078
+ annotations=[],
2079
+ )
2080
+
2081
+ # Generate response.content_part.added structure
2082
+ # sequence_number will be set uniformly in responses_service
2083
+ return ResponseContentPartAddedEvent(
2084
+ type="response.content_part.added",
2085
+ content_index=content_event.index,
2086
+ item_id=content_event.msg_id,
2087
+ output_index=output_index,
2088
+ part=part,
2089
+ sequence_number=0,
2090
+ ) # Will be set uniformly in responses_service
2091
+
2092
+ def _create_content_part_done_event(
2093
+ self,
2094
+ content_event: Content,
2095
+ output_index: int = 0,
2096
+ ) -> ResponseStreamEvent:
2097
+ """
2098
+ Create response.content_part.done event
2099
+
2100
+ Args:
2101
+ content_event: Agent API Content event
2102
+
2103
+ Returns:
2104
+ ResponseStreamEvent: Responses API event
2105
+ """
2106
+ # Create corresponding part based on content type
2107
+ content_type = getattr(content_event, "type", None)
2108
+
2109
+ if content_type == ContentType.TEXT:
2110
+ part = ResponseOutputText(
2111
+ type="output_text",
2112
+ text=getattr(content_event, "text", ""),
2113
+ annotations=[],
2114
+ )
2115
+ elif content_type == ContentType.REFUSAL:
2116
+ part = ResponseOutputRefusal(
2117
+ type="refusal",
2118
+ refusal=getattr(
2119
+ content_event,
2120
+ "refusal",
2121
+ "",
2122
+ ),
2123
+ )
2124
+ else:
2125
+ # Default to text type
2126
+ part = ResponseOutputText(
2127
+ type="output_text",
2128
+ text=getattr(content_event, "text", ""),
2129
+ annotations=[],
2130
+ )
2131
+
2132
+ # Generate response.content_part.done structure
2133
+ # sequence_number will be set uniformly in responses_service
2134
+ return ResponseContentPartDoneEvent(
2135
+ type="response.content_part.done",
2136
+ content_index=content_event.index,
2137
+ item_id=content_event.msg_id,
2138
+ output_index=output_index,
2139
+ part=part,
2140
+ sequence_number=0,
2141
+ ) # Will be set uniformly in responses_service
2142
+
2143
+ def _create_output_text_done_event(
2144
+ self,
2145
+ content_event: Content,
2146
+ output_index: int = 0,
2147
+ ) -> ResponseStreamEvent:
2148
+ """
2149
+ Create response.output_text.done event
2150
+
2151
+ Args:
2152
+ content_event: Agent API Content event
2153
+
2154
+ Returns:
2155
+ ResponseStreamEvent: Responses API event
2156
+ """
2157
+ # Generate response.output_text.done structure
2158
+ # sequence_number will be set uniformly in responses_service
2159
+ return ResponseTextDoneEvent(
2160
+ type="response.output_text.done",
2161
+ content_index=content_event.index,
2162
+ item_id=content_event.msg_id,
2163
+ output_index=output_index,
2164
+ text=getattr(content_event, "text", ""),
2165
+ logprobs=[],
2166
+ # Temporarily use empty list, can add logprobs support later
2167
+ sequence_number=0,
2168
+ ) # Will be set uniformly in responses_service
2169
+
2170
+ def _create_text_delta_event(
2171
+ self,
2172
+ content_event: Content,
2173
+ output_index: int = 0,
2174
+ ) -> ResponseStreamEvent:
2175
+ """
2176
+ Create response.output_text.delta event
2177
+
2178
+ Args:
2179
+ content_event: Agent API Content event
2180
+
2181
+ Returns:
2182
+ ResponseStreamEvent: Responses API event
2183
+ """
2184
+ # Generate response.output_text.delta structure
2185
+ # sequence_number will be set uniformly in responses_service
2186
+ return ResponseTextDeltaEvent(
2187
+ type="response.output_text.delta",
2188
+ content_index=content_event.index,
2189
+ item_id=content_event.msg_id,
2190
+ output_index=output_index,
2191
+ delta=getattr(content_event, "text", ""),
2192
+ logprobs=[],
2193
+ # Temporarily use empty list, can add logprobs support later
2194
+ sequence_number=0,
2195
+ ) # Will be set uniformly in responses_service
2196
+
2197
+ def _create_refusal_text_done_event(
2198
+ self,
2199
+ content_event: Content,
2200
+ output_index: int = 0,
2201
+ ) -> ResponseStreamEvent:
2202
+ """
2203
+ Create response.refusal.done event
2204
+
2205
+ Args:
2206
+ content_event: Agent API Content event
2207
+
2208
+ Returns:
2209
+ ResponseStreamEvent: Responses API event
2210
+ """
2211
+ # Generate response.refusal.done structure
2212
+ # sequence_number will be set uniformly in responses_service
2213
+ return ResponseRefusalDoneEvent(
2214
+ type="response.refusal.done",
2215
+ content_index=content_event.index,
2216
+ item_id=content_event.msg_id,
2217
+ output_index=output_index,
2218
+ refusal=getattr(content_event, "refusal", ""),
2219
+ sequence_number=0,
2220
+ ) # Will be set uniformly in responses_service
2221
+
2222
+ def _create_refusal_text_delta_event(
2223
+ self,
2224
+ content_event: Content,
2225
+ output_index: int = 0,
2226
+ ) -> ResponseStreamEvent:
2227
+ """
2228
+ Create response.refusal.delta event
2229
+
2230
+ Args:
2231
+ content_event: Agent API Content event
2232
+
2233
+ Returns:
2234
+ ResponseStreamEvent: Responses API event
2235
+ """
2236
+ # Generate response.refusal.delta structure
2237
+ # sequence_number will be set uniformly in responses_service
2238
+ return ResponseRefusalDeltaEvent(
2239
+ type="response.refusal.delta",
2240
+ content_index=content_event.index,
2241
+ item_id=content_event.msg_id,
2242
+ output_index=output_index,
2243
+ delta=getattr(content_event, "refusal", ""),
2244
+ sequence_number=0,
2245
+ ) # Will be set uniformly in responses_service
2246
+
2247
+ def _next_sequence(self) -> int:
2248
+ """Get next sequence number"""
2249
+ current = self.sequence_counter
2250
+ # sequence_number will be set uniformly in responses_service
2251
+ return current
2252
+
2253
+ # ===== New event creation methods =====
2254
+
2255
+ def _create_function_call_arguments_add_output_item_event(
2256
+ self,
2257
+ content_event,
2258
+ output_index: int = 0,
2259
+ ) -> ResponseStreamEvent:
2260
+ """
2261
+ Create function call corresponding response.output_item.added event
2262
+
2263
+ Args:
2264
+ content_event: Agent API Content event
2265
+ arguments: function call parameters
2266
+ output_index: output index
2267
+
2268
+ Returns:
2269
+ ResponseStreamEvent: Responses API event
2270
+ """
2271
+
2272
+ # Convert function call data
2273
+ function_call_data = {}
2274
+ if content_event:
2275
+ if content_event.type == ContentType.DATA:
2276
+ function_call_data = content_event.data
2277
+
2278
+ if not isinstance(function_call_data, dict):
2279
+ function_call_data = {}
2280
+
2281
+ # Create ResponseFunctionToolCall
2282
+ function_tool_call = ResponseFunctionToolCall(
2283
+ type="function_call",
2284
+ name=function_call_data.get("name", ""),
2285
+ arguments="",
2286
+ call_id=function_call_data.get("call_id", ""),
2287
+ status=content_event.status,
2288
+ )
2289
+
2290
+ return ResponseOutputItemAddedEvent(
2291
+ type="response.output_item.added",
2292
+ item=function_tool_call,
2293
+ output_index=output_index,
2294
+ sequence_number=0,
2295
+ ) # Will be set uniformly in responses_service
2296
+
2297
+ def _create_function_call_arguments_delta_event(
2298
+ self,
2299
+ content_event,
2300
+ arguments: str,
2301
+ output_index: int = 0,
2302
+ ) -> ResponseStreamEvent:
2303
+ """
2304
+ Create response.function_call_arguments.delta event
2305
+
2306
+ Args:
2307
+ content_event: Agent API Content event
2308
+ arguments: function call parameters
2309
+ output_index: output index
2310
+
2311
+ Returns:
2312
+ ResponseStreamEvent: Responses API event
2313
+ """
2314
+ # sequence_number will be set uniformly in responses_service
2315
+ return ResponseFunctionCallArgumentsDeltaEvent(
2316
+ type="response.function_call_arguments.delta",
2317
+ delta=arguments,
2318
+ item_id=content_event.msg_id,
2319
+ output_index=output_index,
2320
+ sequence_number=0,
2321
+ ) # Will be set uniformly in responses_service
2322
+
2323
+ def _create_function_call_arguments_done_event(
2324
+ self,
2325
+ content_event,
2326
+ arguments: str,
2327
+ output_index: int = 0,
2328
+ ) -> ResponseStreamEvent:
2329
+ """
2330
+ Create response.function_call_arguments.done event
2331
+
2332
+ Args:
2333
+ content_event: Agent API Content event
2334
+ arguments: function call parameters
2335
+ output_index: output index
2336
+
2337
+ Returns:
2338
+ ResponseStreamEvent: Responses API event
2339
+ """
2340
+ # sequence_number will be set uniformly in responses_service
2341
+ return ResponseFunctionCallArgumentsDoneEvent(
2342
+ type="response.function_call_arguments.done",
2343
+ arguments=arguments,
2344
+ item_id=content_event.msg_id,
2345
+ output_index=output_index,
2346
+ sequence_number=0,
2347
+ ) # Will be set uniformly in responses_service
2348
+
2349
+ def _create_reasoning_text_delta_event(
2350
+ self,
2351
+ content_event,
2352
+ text: str,
2353
+ output_index: int = 0,
2354
+ ) -> ResponseStreamEvent:
2355
+ """
2356
+ Create response.reasoning_text.delta event
2357
+
2358
+ Args:
2359
+ content_event: Agent API Content event
2360
+ text: reasoning text content
2361
+ output_index: output index
2362
+
2363
+ Returns:
2364
+ ResponseStreamEvent: Responses API event
2365
+ """
2366
+ # sequence_number will be set uniformly in responses_service
2367
+ return ResponseReasoningTextDeltaEvent(
2368
+ type="response.reasoning_text.delta",
2369
+ content_index=content_event.index,
2370
+ delta=text,
2371
+ item_id=content_event.msg_id,
2372
+ output_index=output_index,
2373
+ sequence_number=0,
2374
+ ) # Will be set uniformly in responses_service
2375
+
2376
+ def _create_reasoning_text_done_event(
2377
+ self,
2378
+ content_event,
2379
+ text: str,
2380
+ output_index: int = 0,
2381
+ ) -> ResponseStreamEvent:
2382
+ """
2383
+ Create response.reasoning_text.done event
2384
+
2385
+ Args:
2386
+ content_event: Agent API Content event
2387
+ text: reasoning text content
2388
+ output_index: output index
2389
+
2390
+ Returns:
2391
+ ResponseStreamEvent: Responses API event
2392
+ """
2393
+ # sequence_number will be set uniformly in responses_service
2394
+ return ResponseReasoningTextDoneEvent(
2395
+ type="response.reasoning_text.done",
2396
+ content_index=content_event.index,
2397
+ text=text,
2398
+ item_id=content_event.msg_id,
2399
+ output_index=output_index,
2400
+ sequence_number=0,
2401
+ ) # Will be set uniformly in responses_service
2402
+
2403
+ def _convert_agent_error_to_responses_error(
2404
+ self,
2405
+ agent_error,
2406
+ ) -> Optional[Any]:
2407
+ """
2408
+ Convert Agent API Error to Responses API ResponseError
2409
+
2410
+ Args:
2411
+ agent_error: Agent API Error object
2412
+
2413
+ Returns:
2414
+ ResponseError: Responses API ResponseError or None
2415
+ """
2416
+ if not agent_error:
2417
+ return None
2418
+
2419
+ try:
2420
+ # Extract error information from Agent API Error object
2421
+ error_code = getattr(agent_error, "code", "server_error")
2422
+ error_message = getattr(
2423
+ agent_error,
2424
+ "message",
2425
+ "Unknown error occurred",
2426
+ )
2427
+
2428
+ # Map Agent API error code to Responses API error code
2429
+ # If Agent API code is not in Responses API allowed range,
2430
+ # use server_error as default
2431
+ valid_codes = [
2432
+ "server_error",
2433
+ "rate_limit_exceeded",
2434
+ "invalid_prompt",
2435
+ "vector_store_timeout",
2436
+ "invalid_image",
2437
+ "invalid_image_format",
2438
+ "invalid_base64_image",
2439
+ "invalid_image_url",
2440
+ "image_too_large",
2441
+ "image_too_small",
2442
+ "image_parse_error",
2443
+ "image_content_policy_violation",
2444
+ "invalid_image_mode",
2445
+ "image_file_too_large",
2446
+ "unsupported_image_media_type",
2447
+ "empty_image_file",
2448
+ "failed_to_download_image",
2449
+ "image_file_not_found",
2450
+ ]
2451
+
2452
+ # If Agent API code is in valid range, use directly;
2453
+ # otherwise use server_error
2454
+ mapped_code = (
2455
+ error_code if error_code in valid_codes else "server_error"
2456
+ )
2457
+
2458
+ # Create Responses API ResponseError
2459
+ from openai.types.responses import ResponseError
2460
+
2461
+ return ResponseError(code=mapped_code, message=error_message)
2462
+ except Exception as e:
2463
+ # If conversion fails, log error and return None
2464
+ print(f"Error converting agent error to responses error: {e}")
2465
+ return None
2466
+
2467
+ def _create_error_event(
2468
+ self,
2469
+ error_message: str,
2470
+ ) -> ResponseStreamEvent:
2471
+ """
2472
+ Create error event
2473
+
2474
+ Args:
2475
+ content_event: Agent API Content event
2476
+ error_message: error message
2477
+ output_index: output index
2478
+
2479
+ Returns:
2480
+ ResponseStreamEvent: Responses API event
2481
+ """
2482
+ # sequence_number will be set uniformly in responses_service
2483
+ return ResponseErrorEvent(
2484
+ type="error",
2485
+ message=error_message,
2486
+ sequence_number=0,
2487
+ ) # Will be set uniformly in responses_service
2488
+
2489
+ def _create_function_call_item_added_event(
2490
+ self,
2491
+ content_event,
2492
+ output_index: int = 0,
2493
+ ) -> ResponseStreamEvent:
2494
+ """
2495
+ Create function_call type response.output_item.added event
2496
+
2497
+ Args:
2498
+ content_event: Agent API Content event
2499
+ output_index: output index
2500
+
2501
+ Returns:
2502
+ ResponseStreamEvent: Responses API event
2503
+ """
2504
+ # Extract function call information from data
2505
+ data = getattr(content_event, "data", {})
2506
+ name = data.get("name", "")
2507
+ arguments = data.get("arguments", "")
2508
+ call_id = data.get("call_id", "")
2509
+
2510
+ # Create ResponseFunctionToolCall as item
2511
+ item = ResponseFunctionToolCall(
2512
+ type="function_call",
2513
+ name=name,
2514
+ arguments=arguments,
2515
+ call_id=call_id,
2516
+ id=data.get("id"),
2517
+ status=data.get("status"),
2518
+ )
2519
+
2520
+ # Generate response.output_item.added structure
2521
+ # sequence_number will be set uniformly in responses_service
2522
+ return ResponseOutputItemAddedEvent(
2523
+ type="response.output_item.added",
2524
+ item=item,
2525
+ output_index=output_index,
2526
+ sequence_number=0,
2527
+ ) # Will be set uniformly in responses_service
2528
+
2529
+ def _create_reasoning_item_added_event(
2530
+ self,
2531
+ content_event,
2532
+ output_index: int = 0,
2533
+ ) -> ResponseStreamEvent:
2534
+ """
2535
+ Create reasoning type response.output_item.added event
2536
+
2537
+ Args:
2538
+ content_event: Agent API Content event
2539
+ output_index: output index
2540
+
2541
+ Returns:
2542
+ ResponseStreamEvent: Responses API event
2543
+ """
2544
+ # Extract reasoning content from text
2545
+ reasoning_text = getattr(content_event, "text", "")
2546
+
2547
+ # Create ResponseReasoningItem as item
2548
+ item = ResponseReasoningItem(
2549
+ type="reasoning",
2550
+ id=content_event.msg_id,
2551
+ summary=[], # Empty summary
2552
+ content=(
2553
+ [Content(type="reasoning_text", text=reasoning_text)]
2554
+ if reasoning_text
2555
+ else None
2556
+ ),
2557
+ encrypted_content=None,
2558
+ status=None,
2559
+ )
2560
+
2561
+ # Generate response.output_item.added structure
2562
+ # sequence_number will be set uniformly in responses_service
2563
+ return ResponseOutputItemAddedEvent(
2564
+ type="response.output_item.added",
2565
+ item=item,
2566
+ output_index=output_index,
2567
+ sequence_number=0,
2568
+ ) # Will be set uniformly in responses_service
2569
+
2570
+ def _convert_mcp_list_tools_to_output_message(
2571
+ self,
2572
+ message: Message,
2573
+ ) -> McpListTools:
2574
+ """
2575
+ Convert MCP tool list message to McpListTools
2576
+
2577
+ Args:
2578
+ message: Agent API Message (type='mcp_list_tools')
2579
+
2580
+ Returns:
2581
+ McpListTools: Responses API MCP tool list
2582
+ """
2583
+ # Convert MCP tool list data
2584
+ mcp_data = {}
2585
+ if message.content:
2586
+ for content_item in message.content:
2587
+ if content_item.type == ContentType.DATA:
2588
+ mcp_data = content_item.data
2589
+ break
2590
+
2591
+ if not isinstance(mcp_data, dict):
2592
+ mcp_data = {}
2593
+
2594
+ # Extract tool list information
2595
+ tools_info = mcp_data.get("tools", [])
2596
+ tools = []
2597
+ for tool_info in tools_info:
2598
+ if isinstance(tool_info, dict):
2599
+ tool = McpListToolsTool(
2600
+ name=tool_info.get("name", "unknown"),
2601
+ input_schema=tool_info.get("input_schema", {}),
2602
+ description=tool_info.get("description", ""),
2603
+ annotations=tool_info.get("annotations"),
2604
+ )
2605
+ tools.append(tool)
2606
+
2607
+ # Create McpListTools
2608
+ return McpListTools(
2609
+ id=message.id,
2610
+ server_label=mcp_data.get("server_label", "MCP Server"),
2611
+ tools=tools,
2612
+ type="mcp_list_tools",
2613
+ )
2614
+
2615
+ def _convert_mcp_tool_call_to_output_message(
2616
+ self,
2617
+ message: Message,
2618
+ ) -> McpCall:
2619
+ """
2620
+ Convert MCP tool call message to McpCall
2621
+
2622
+ Args:
2623
+ message: Agent API Message (type='mcp_call')
2624
+
2625
+ Returns:
2626
+ McpCall: Responses API MCP tool call
2627
+ """
2628
+ # Convert MCP tool call data
2629
+ mcp_call_data = {}
2630
+ if message.content:
2631
+ for content_item in message.content:
2632
+ if content_item.type == ContentType.DATA:
2633
+ mcp_call_data = content_item.data
2634
+ break
2635
+
2636
+ if not isinstance(mcp_call_data, dict):
2637
+ mcp_call_data = {}
2638
+
2639
+ # Extract MCP tool call information
2640
+ tool_name = mcp_call_data.get("name", "mcp_tool")
2641
+ tool_arguments = mcp_call_data.get("arguments", "{}")
2642
+ server_label = mcp_call_data.get("server_label", "MCP Server")
2643
+
2644
+ # Create McpCall
2645
+ return McpCall(
2646
+ id=message.id,
2647
+ name=tool_name,
2648
+ arguments=tool_arguments,
2649
+ server_label=server_label,
2650
+ type="mcp_call",
2651
+ error=mcp_call_data.get("error"),
2652
+ output=mcp_call_data.get("output"),
2653
+ )
2654
+
2655
+ def _create_mcp_list_tools_item_added_event(
2656
+ self,
2657
+ content_event,
2658
+ output_index: int = 0,
2659
+ ) -> ResponseStreamEvent:
2660
+ """
2661
+ Create MCP tool list item added event
2662
+
2663
+ Args:
2664
+ content_event: Agent API Content event
2665
+ output_index: output index
2666
+
2667
+ Returns:
2668
+ ResponseStreamEvent: Responses API event
2669
+ """
2670
+ # Extract MCP tool list information from data
2671
+ data = getattr(content_event, "data", {})
2672
+ if not isinstance(data, dict):
2673
+ data = {}
2674
+
2675
+ # Extract tool list information
2676
+ tools_info = data.get("tools", [])
2677
+ tools = []
2678
+ for tool_info in tools_info:
2679
+ if isinstance(tool_info, dict):
2680
+ tool = McpListToolsTool(
2681
+ name=tool_info.get("name", "unknown"),
2682
+ input_schema=tool_info.get("input_schema", {}),
2683
+ description=tool_info.get("description", ""),
2684
+ annotations=tool_info.get("annotations"),
2685
+ )
2686
+ tools.append(tool)
2687
+
2688
+ # Create McpListTools as item
2689
+ item = McpListTools(
2690
+ id=content_event.msg_id,
2691
+ server_label=data.get("server_label", "MCP Server"),
2692
+ tools=tools,
2693
+ type="mcp_list_tools",
2694
+ )
2695
+
2696
+ # Generate response.output_item.added structure
2697
+ # sequence_number will be set uniformly in responses_service
2698
+ return ResponseOutputItemAddedEvent(
2699
+ type="response.output_item.added",
2700
+ item=item,
2701
+ output_index=output_index,
2702
+ sequence_number=0,
2703
+ ) # Will be set uniformly in responses_service
2704
+
2705
+ def _create_mcp_tool_call_item_added_event(
2706
+ self,
2707
+ content_event,
2708
+ output_index: int = 0,
2709
+ ) -> ResponseStreamEvent:
2710
+ """
2711
+ Create MCP tool call item added event
2712
+
2713
+ Args:
2714
+ content_event: Agent API Content event
2715
+ output_index: output index
2716
+
2717
+ Returns:
2718
+ ResponseStreamEvent: Responses API event
2719
+ """
2720
+ # Extract MCP tool call information from data
2721
+ data = getattr(content_event, "data", {})
2722
+ if not isinstance(data, dict):
2723
+ data = {}
2724
+
2725
+ # Extract MCP tool call information
2726
+ tool_name = data.get("name", "mcp_tool")
2727
+ tool_arguments = data.get("arguments", "{}")
2728
+ server_label = data.get("server_label", "MCP Server")
2729
+
2730
+ # Create McpCall as item
2731
+ item = McpCall(
2732
+ id=content_event.msg_id,
2733
+ name=tool_name,
2734
+ arguments=tool_arguments,
2735
+ server_label=server_label,
2736
+ type="mcp_call",
2737
+ error=data.get("error"),
2738
+ output=data.get("output"),
2739
+ )
2740
+
2741
+ # Generate response.output_item.added structure
2742
+ # sequence_number will be set uniformly in responses_service
2743
+ return ResponseOutputItemAddedEvent(
2744
+ type="response.output_item.added",
2745
+ item=item,
2746
+ output_index=output_index,
2747
+ sequence_number=0,
2748
+ ) # Will be set uniformly in responses_service
2749
+
2750
+ def _create_mcp_list_tools_in_progress_event(
2751
+ self,
2752
+ message_event: Message,
2753
+ output_index: int = 0,
2754
+ ) -> ResponseStreamEvent:
2755
+ """
2756
+ Create MCP tool list in_progress event
2757
+
2758
+ Args:
2759
+ message_event: Agent API Message event
2760
+ output_index: output index
2761
+
2762
+ Returns:
2763
+ ResponseStreamEvent: Responses API event
2764
+ """
2765
+ # Generate response.mcp_list_tools.in_progress event
2766
+ # sequence_number will be set uniformly in responses_service
2767
+ return ResponseMcpListToolsInProgressEvent(
2768
+ type="response.mcp_list_tools.in_progress",
2769
+ item_id=message_event.id,
2770
+ output_index=output_index,
2771
+ sequence_number=0,
2772
+ ) # Will be set uniformly in responses_service
2773
+
2774
+ def _create_mcp_list_tools_completed_event(
2775
+ self,
2776
+ message_event: Message,
2777
+ output_index: int = 0,
2778
+ ) -> List[ResponseStreamEvent]:
2779
+ """
2780
+ Create MCP tool list completed event
2781
+
2782
+ Args:
2783
+ message_event: Agent API Message event
2784
+ output_index: output index
2785
+
2786
+ Returns:
2787
+ List[ResponseStreamEvent]: Responses API event list
2788
+ """
2789
+ events = []
2790
+
2791
+ # 1. Generate response.mcp_list_tools.completed event
2792
+ mcp_completed_event = ResponseMcpListToolsCompletedEvent(
2793
+ type="response.mcp_list_tools.completed",
2794
+ item_id=message_event.id,
2795
+ output_index=output_index,
2796
+ sequence_number=0,
2797
+ ) # Will be set uniformly in responses_service
2798
+ events.append(mcp_completed_event)
2799
+
2800
+ # 2. Generate response.output_item.done event
2801
+ output_message = self._convert_mcp_list_tools_to_output_message(
2802
+ message_event,
2803
+ )
2804
+ if output_message:
2805
+ output_item_done_event = ResponseOutputItemDoneEvent(
2806
+ type="response.output_item.done",
2807
+ item=output_message,
2808
+ output_index=output_index,
2809
+ sequence_number=0,
2810
+ ) # Will be set uniformly in responses_service
2811
+ events.append(output_item_done_event)
2812
+ # Add to _output list
2813
+ self._output.append(output_message)
2814
+
2815
+ return events
2816
+
2817
+ def _create_mcp_tool_call_in_progress_event(
2818
+ self,
2819
+ message_event: Message,
2820
+ output_index: int = 0,
2821
+ ) -> ResponseStreamEvent:
2822
+ """
2823
+ Create MCP tool call in_progress event
2824
+
2825
+ Args:
2826
+ message_event: Agent API Message event
2827
+ output_index: output index
2828
+
2829
+ Returns:
2830
+ ResponseStreamEvent: Responses API event
2831
+ """
2832
+ # Generate response.mcp_call.in_progress event
2833
+ # sequence_number will be set uniformly in responses_service
2834
+ return ResponseMcpCallInProgressEvent(
2835
+ type="response.mcp_call.in_progress",
2836
+ item_id=message_event.id,
2837
+ output_index=output_index,
2838
+ sequence_number=0,
2839
+ ) # Will be set uniformly in responses_service
2840
+
2841
+ def _create_mcp_tool_call_completed_event(
2842
+ self,
2843
+ message_event: Message,
2844
+ output_index: int = 0,
2845
+ ) -> List[ResponseStreamEvent]:
2846
+ """
2847
+ Create MCP tool call completed event
2848
+
2849
+ Args:
2850
+ message_event: Agent API Message event
2851
+ output_index: output index
2852
+
2853
+ Returns:
2854
+ List[ResponseStreamEvent]: Responses API event list
2855
+ """
2856
+ events = []
2857
+
2858
+ # 1. Generate response.mcp_call.completed event
2859
+ mcp_completed_event = ResponseMcpCallCompletedEvent(
2860
+ type="response.mcp_call.completed",
2861
+ item_id=message_event.id,
2862
+ output_index=output_index,
2863
+ sequence_number=0,
2864
+ ) # Will be set uniformly in responses_service
2865
+ events.append(mcp_completed_event)
2866
+
2867
+ # 2. Generate response.output_item.done event
2868
+ output_message = self._convert_mcp_tool_call_to_output_message(
2869
+ message_event,
2870
+ )
2871
+ if output_message:
2872
+ output_item_done_event = ResponseOutputItemDoneEvent(
2873
+ type="response.output_item.done",
2874
+ item=output_message,
2875
+ output_index=output_index,
2876
+ sequence_number=0,
2877
+ ) # Will be set uniformly in responses_service
2878
+ events.append(output_item_done_event)
2879
+ # Add to _output list
2880
+ self._output.append(output_message)
2881
+
2882
+ return events
2883
+
2884
+
2885
+ # Export main adapter class
2886
+ __all__ = ["ResponsesAdapter"]