massgen 0.0.3__py3-none-any.whl → 0.1.0__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.

Potentially problematic release.


This version of massgen might be problematic. Click here for more details.

Files changed (268) hide show
  1. massgen/__init__.py +142 -8
  2. massgen/adapters/__init__.py +29 -0
  3. massgen/adapters/ag2_adapter.py +483 -0
  4. massgen/adapters/base.py +183 -0
  5. massgen/adapters/tests/__init__.py +0 -0
  6. massgen/adapters/tests/test_ag2_adapter.py +439 -0
  7. massgen/adapters/tests/test_agent_adapter.py +128 -0
  8. massgen/adapters/utils/__init__.py +2 -0
  9. massgen/adapters/utils/ag2_utils.py +236 -0
  10. massgen/adapters/utils/tests/__init__.py +0 -0
  11. massgen/adapters/utils/tests/test_ag2_utils.py +138 -0
  12. massgen/agent_config.py +329 -55
  13. massgen/api_params_handler/__init__.py +10 -0
  14. massgen/api_params_handler/_api_params_handler_base.py +99 -0
  15. massgen/api_params_handler/_chat_completions_api_params_handler.py +176 -0
  16. massgen/api_params_handler/_claude_api_params_handler.py +113 -0
  17. massgen/api_params_handler/_response_api_params_handler.py +130 -0
  18. massgen/backend/__init__.py +39 -4
  19. massgen/backend/azure_openai.py +385 -0
  20. massgen/backend/base.py +341 -69
  21. massgen/backend/base_with_mcp.py +1102 -0
  22. massgen/backend/capabilities.py +386 -0
  23. massgen/backend/chat_completions.py +577 -130
  24. massgen/backend/claude.py +1033 -537
  25. massgen/backend/claude_code.py +1203 -0
  26. massgen/backend/cli_base.py +209 -0
  27. massgen/backend/docs/BACKEND_ARCHITECTURE.md +126 -0
  28. massgen/backend/{CLAUDE_API_RESEARCH.md → docs/CLAUDE_API_RESEARCH.md} +18 -18
  29. massgen/backend/{GEMINI_API_DOCUMENTATION.md → docs/GEMINI_API_DOCUMENTATION.md} +9 -9
  30. massgen/backend/docs/Gemini MCP Integration Analysis.md +1050 -0
  31. massgen/backend/docs/MCP_IMPLEMENTATION_CLAUDE_BACKEND.md +177 -0
  32. massgen/backend/docs/MCP_INTEGRATION_RESPONSE_BACKEND.md +352 -0
  33. massgen/backend/docs/OPENAI_GPT5_MODELS.md +211 -0
  34. massgen/backend/{OPENAI_RESPONSES_API_FORMAT.md → docs/OPENAI_RESPONSE_API_TOOL_CALLS.md} +3 -3
  35. massgen/backend/docs/OPENAI_response_streaming.md +20654 -0
  36. massgen/backend/docs/inference_backend.md +257 -0
  37. massgen/backend/docs/permissions_and_context_files.md +1085 -0
  38. massgen/backend/external.py +126 -0
  39. massgen/backend/gemini.py +1850 -241
  40. massgen/backend/grok.py +40 -156
  41. massgen/backend/inference.py +156 -0
  42. massgen/backend/lmstudio.py +171 -0
  43. massgen/backend/response.py +1095 -322
  44. massgen/chat_agent.py +131 -113
  45. massgen/cli.py +1560 -275
  46. massgen/config_builder.py +2396 -0
  47. massgen/configs/BACKEND_CONFIGURATION.md +458 -0
  48. massgen/configs/README.md +559 -216
  49. massgen/configs/ag2/ag2_case_study.yaml +27 -0
  50. massgen/configs/ag2/ag2_coder.yaml +34 -0
  51. massgen/configs/ag2/ag2_coder_case_study.yaml +36 -0
  52. massgen/configs/ag2/ag2_gemini.yaml +27 -0
  53. massgen/configs/ag2/ag2_groupchat.yaml +108 -0
  54. massgen/configs/ag2/ag2_groupchat_gpt.yaml +118 -0
  55. massgen/configs/ag2/ag2_single_agent.yaml +21 -0
  56. massgen/configs/basic/multi/fast_timeout_example.yaml +37 -0
  57. massgen/configs/basic/multi/gemini_4o_claude.yaml +31 -0
  58. massgen/configs/basic/multi/gemini_gpt5nano_claude.yaml +36 -0
  59. massgen/configs/{gemini_4o_claude.yaml → basic/multi/geminicode_4o_claude.yaml} +3 -3
  60. massgen/configs/basic/multi/geminicode_gpt5nano_claude.yaml +36 -0
  61. massgen/configs/basic/multi/glm_gemini_claude.yaml +25 -0
  62. massgen/configs/basic/multi/gpt4o_audio_generation.yaml +30 -0
  63. massgen/configs/basic/multi/gpt4o_image_generation.yaml +31 -0
  64. massgen/configs/basic/multi/gpt5nano_glm_qwen.yaml +26 -0
  65. massgen/configs/basic/multi/gpt5nano_image_understanding.yaml +26 -0
  66. massgen/configs/{three_agents_default.yaml → basic/multi/three_agents_default.yaml} +8 -4
  67. massgen/configs/basic/multi/three_agents_opensource.yaml +27 -0
  68. massgen/configs/basic/multi/three_agents_vllm.yaml +20 -0
  69. massgen/configs/basic/multi/two_agents_gemini.yaml +19 -0
  70. massgen/configs/{two_agents.yaml → basic/multi/two_agents_gpt5.yaml} +14 -6
  71. massgen/configs/basic/multi/two_agents_opensource_lmstudio.yaml +31 -0
  72. massgen/configs/basic/multi/two_qwen_vllm_sglang.yaml +28 -0
  73. massgen/configs/{single_agent.yaml → basic/single/single_agent.yaml} +1 -1
  74. massgen/configs/{single_flash2.5.yaml → basic/single/single_flash2.5.yaml} +1 -2
  75. massgen/configs/basic/single/single_gemini2.5pro.yaml +16 -0
  76. massgen/configs/basic/single/single_gpt4o_audio_generation.yaml +22 -0
  77. massgen/configs/basic/single/single_gpt4o_image_generation.yaml +22 -0
  78. massgen/configs/basic/single/single_gpt4o_video_generation.yaml +24 -0
  79. massgen/configs/basic/single/single_gpt5nano.yaml +20 -0
  80. massgen/configs/basic/single/single_gpt5nano_file_search.yaml +18 -0
  81. massgen/configs/basic/single/single_gpt5nano_image_understanding.yaml +17 -0
  82. massgen/configs/basic/single/single_gptoss120b.yaml +15 -0
  83. massgen/configs/basic/single/single_openrouter_audio_understanding.yaml +15 -0
  84. massgen/configs/basic/single/single_qwen_video_understanding.yaml +15 -0
  85. massgen/configs/debug/code_execution/command_filtering_blacklist.yaml +29 -0
  86. massgen/configs/debug/code_execution/command_filtering_whitelist.yaml +28 -0
  87. massgen/configs/debug/code_execution/docker_verification.yaml +29 -0
  88. massgen/configs/debug/skip_coordination_test.yaml +27 -0
  89. massgen/configs/debug/test_sdk_migration.yaml +17 -0
  90. massgen/configs/docs/DISCORD_MCP_SETUP.md +208 -0
  91. massgen/configs/docs/TWITTER_MCP_ENESCINAR_SETUP.md +82 -0
  92. massgen/configs/providers/azure/azure_openai_multi.yaml +21 -0
  93. massgen/configs/providers/azure/azure_openai_single.yaml +19 -0
  94. massgen/configs/providers/claude/claude.yaml +14 -0
  95. massgen/configs/providers/gemini/gemini_gpt5nano.yaml +28 -0
  96. massgen/configs/providers/local/lmstudio.yaml +11 -0
  97. massgen/configs/providers/openai/gpt5.yaml +46 -0
  98. massgen/configs/providers/openai/gpt5_nano.yaml +46 -0
  99. massgen/configs/providers/others/grok_single_agent.yaml +19 -0
  100. massgen/configs/providers/others/zai_coding_team.yaml +108 -0
  101. massgen/configs/providers/others/zai_glm45.yaml +12 -0
  102. massgen/configs/{creative_team.yaml → teams/creative/creative_team.yaml} +16 -6
  103. massgen/configs/{travel_planning.yaml → teams/creative/travel_planning.yaml} +16 -6
  104. massgen/configs/{news_analysis.yaml → teams/research/news_analysis.yaml} +16 -6
  105. massgen/configs/{research_team.yaml → teams/research/research_team.yaml} +15 -7
  106. massgen/configs/{technical_analysis.yaml → teams/research/technical_analysis.yaml} +16 -6
  107. massgen/configs/tools/code-execution/basic_command_execution.yaml +25 -0
  108. massgen/configs/tools/code-execution/code_execution_use_case_simple.yaml +41 -0
  109. massgen/configs/tools/code-execution/docker_claude_code.yaml +32 -0
  110. massgen/configs/tools/code-execution/docker_multi_agent.yaml +32 -0
  111. massgen/configs/tools/code-execution/docker_simple.yaml +29 -0
  112. massgen/configs/tools/code-execution/docker_with_resource_limits.yaml +32 -0
  113. massgen/configs/tools/code-execution/multi_agent_playwright_automation.yaml +57 -0
  114. massgen/configs/tools/filesystem/cc_gpt5_gemini_filesystem.yaml +34 -0
  115. massgen/configs/tools/filesystem/claude_code_context_sharing.yaml +68 -0
  116. massgen/configs/tools/filesystem/claude_code_flash2.5.yaml +43 -0
  117. massgen/configs/tools/filesystem/claude_code_flash2.5_gptoss.yaml +49 -0
  118. massgen/configs/tools/filesystem/claude_code_gpt5nano.yaml +31 -0
  119. massgen/configs/tools/filesystem/claude_code_single.yaml +40 -0
  120. massgen/configs/tools/filesystem/fs_permissions_test.yaml +87 -0
  121. massgen/configs/tools/filesystem/gemini_gemini_workspace_cleanup.yaml +54 -0
  122. massgen/configs/tools/filesystem/gemini_gpt5_filesystem_casestudy.yaml +30 -0
  123. massgen/configs/tools/filesystem/gemini_gpt5nano_file_context_path.yaml +43 -0
  124. massgen/configs/tools/filesystem/gemini_gpt5nano_protected_paths.yaml +45 -0
  125. massgen/configs/tools/filesystem/gpt5mini_cc_fs_context_path.yaml +31 -0
  126. massgen/configs/tools/filesystem/grok4_gpt5_gemini_filesystem.yaml +32 -0
  127. massgen/configs/tools/filesystem/multiturn/grok4_gpt5_claude_code_filesystem_multiturn.yaml +58 -0
  128. massgen/configs/tools/filesystem/multiturn/grok4_gpt5_gemini_filesystem_multiturn.yaml +58 -0
  129. massgen/configs/tools/filesystem/multiturn/two_claude_code_filesystem_multiturn.yaml +47 -0
  130. massgen/configs/tools/filesystem/multiturn/two_gemini_flash_filesystem_multiturn.yaml +48 -0
  131. massgen/configs/tools/mcp/claude_code_discord_mcp_example.yaml +27 -0
  132. massgen/configs/tools/mcp/claude_code_simple_mcp.yaml +35 -0
  133. massgen/configs/tools/mcp/claude_code_twitter_mcp_example.yaml +32 -0
  134. massgen/configs/tools/mcp/claude_mcp_example.yaml +24 -0
  135. massgen/configs/tools/mcp/claude_mcp_test.yaml +27 -0
  136. massgen/configs/tools/mcp/five_agents_travel_mcp_test.yaml +157 -0
  137. massgen/configs/tools/mcp/five_agents_weather_mcp_test.yaml +103 -0
  138. massgen/configs/tools/mcp/gemini_mcp_example.yaml +24 -0
  139. massgen/configs/tools/mcp/gemini_mcp_filesystem_test.yaml +23 -0
  140. massgen/configs/tools/mcp/gemini_mcp_filesystem_test_sharing.yaml +23 -0
  141. massgen/configs/tools/mcp/gemini_mcp_filesystem_test_single_agent.yaml +17 -0
  142. massgen/configs/tools/mcp/gemini_mcp_filesystem_test_with_claude_code.yaml +24 -0
  143. massgen/configs/tools/mcp/gemini_mcp_test.yaml +27 -0
  144. massgen/configs/tools/mcp/gemini_notion_mcp.yaml +52 -0
  145. massgen/configs/tools/mcp/gpt5_nano_mcp_example.yaml +24 -0
  146. massgen/configs/tools/mcp/gpt5_nano_mcp_test.yaml +27 -0
  147. massgen/configs/tools/mcp/gpt5mini_claude_code_discord_mcp_example.yaml +38 -0
  148. massgen/configs/tools/mcp/gpt_oss_mcp_example.yaml +25 -0
  149. massgen/configs/tools/mcp/gpt_oss_mcp_test.yaml +28 -0
  150. massgen/configs/tools/mcp/grok3_mini_mcp_example.yaml +24 -0
  151. massgen/configs/tools/mcp/grok3_mini_mcp_test.yaml +27 -0
  152. massgen/configs/tools/mcp/multimcp_gemini.yaml +111 -0
  153. massgen/configs/tools/mcp/qwen_api_mcp_example.yaml +25 -0
  154. massgen/configs/tools/mcp/qwen_api_mcp_test.yaml +28 -0
  155. massgen/configs/tools/mcp/qwen_local_mcp_example.yaml +24 -0
  156. massgen/configs/tools/mcp/qwen_local_mcp_test.yaml +27 -0
  157. massgen/configs/tools/planning/five_agents_discord_mcp_planning_mode.yaml +140 -0
  158. massgen/configs/tools/planning/five_agents_filesystem_mcp_planning_mode.yaml +151 -0
  159. massgen/configs/tools/planning/five_agents_notion_mcp_planning_mode.yaml +151 -0
  160. massgen/configs/tools/planning/five_agents_twitter_mcp_planning_mode.yaml +155 -0
  161. massgen/configs/tools/planning/gpt5_mini_case_study_mcp_planning_mode.yaml +73 -0
  162. massgen/configs/tools/web-search/claude_streamable_http_test.yaml +43 -0
  163. massgen/configs/tools/web-search/gemini_streamable_http_test.yaml +43 -0
  164. massgen/configs/tools/web-search/gpt5_mini_streamable_http_test.yaml +43 -0
  165. massgen/configs/tools/web-search/gpt_oss_streamable_http_test.yaml +44 -0
  166. massgen/configs/tools/web-search/grok3_mini_streamable_http_test.yaml +43 -0
  167. massgen/configs/tools/web-search/qwen_api_streamable_http_test.yaml +44 -0
  168. massgen/configs/tools/web-search/qwen_local_streamable_http_test.yaml +43 -0
  169. massgen/coordination_tracker.py +708 -0
  170. massgen/docker/README.md +462 -0
  171. massgen/filesystem_manager/__init__.py +21 -0
  172. massgen/filesystem_manager/_base.py +9 -0
  173. massgen/filesystem_manager/_code_execution_server.py +545 -0
  174. massgen/filesystem_manager/_docker_manager.py +477 -0
  175. massgen/filesystem_manager/_file_operation_tracker.py +248 -0
  176. massgen/filesystem_manager/_filesystem_manager.py +813 -0
  177. massgen/filesystem_manager/_path_permission_manager.py +1261 -0
  178. massgen/filesystem_manager/_workspace_tools_server.py +1815 -0
  179. massgen/formatter/__init__.py +10 -0
  180. massgen/formatter/_chat_completions_formatter.py +284 -0
  181. massgen/formatter/_claude_formatter.py +235 -0
  182. massgen/formatter/_formatter_base.py +156 -0
  183. massgen/formatter/_response_formatter.py +263 -0
  184. massgen/frontend/__init__.py +1 -2
  185. massgen/frontend/coordination_ui.py +471 -286
  186. massgen/frontend/displays/base_display.py +56 -11
  187. massgen/frontend/displays/create_coordination_table.py +1956 -0
  188. massgen/frontend/displays/rich_terminal_display.py +1259 -619
  189. massgen/frontend/displays/simple_display.py +9 -4
  190. massgen/frontend/displays/terminal_display.py +27 -68
  191. massgen/logger_config.py +681 -0
  192. massgen/mcp_tools/README.md +232 -0
  193. massgen/mcp_tools/__init__.py +105 -0
  194. massgen/mcp_tools/backend_utils.py +1035 -0
  195. massgen/mcp_tools/circuit_breaker.py +195 -0
  196. massgen/mcp_tools/client.py +894 -0
  197. massgen/mcp_tools/config_validator.py +138 -0
  198. massgen/mcp_tools/docs/circuit_breaker.md +646 -0
  199. massgen/mcp_tools/docs/client.md +950 -0
  200. massgen/mcp_tools/docs/config_validator.md +478 -0
  201. massgen/mcp_tools/docs/exceptions.md +1165 -0
  202. massgen/mcp_tools/docs/security.md +854 -0
  203. massgen/mcp_tools/exceptions.py +338 -0
  204. massgen/mcp_tools/hooks.py +212 -0
  205. massgen/mcp_tools/security.py +780 -0
  206. massgen/message_templates.py +342 -64
  207. massgen/orchestrator.py +1515 -241
  208. massgen/stream_chunk/__init__.py +35 -0
  209. massgen/stream_chunk/base.py +92 -0
  210. massgen/stream_chunk/multimodal.py +237 -0
  211. massgen/stream_chunk/text.py +162 -0
  212. massgen/tests/mcp_test_server.py +150 -0
  213. massgen/tests/multi_turn_conversation_design.md +0 -8
  214. massgen/tests/test_azure_openai_backend.py +156 -0
  215. massgen/tests/test_backend_capabilities.py +262 -0
  216. massgen/tests/test_backend_event_loop_all.py +179 -0
  217. massgen/tests/test_chat_completions_refactor.py +142 -0
  218. massgen/tests/test_claude_backend.py +15 -28
  219. massgen/tests/test_claude_code.py +268 -0
  220. massgen/tests/test_claude_code_context_sharing.py +233 -0
  221. massgen/tests/test_claude_code_orchestrator.py +175 -0
  222. massgen/tests/test_cli_backends.py +180 -0
  223. massgen/tests/test_code_execution.py +679 -0
  224. massgen/tests/test_external_agent_backend.py +134 -0
  225. massgen/tests/test_final_presentation_fallback.py +237 -0
  226. massgen/tests/test_gemini_planning_mode.py +351 -0
  227. massgen/tests/test_grok_backend.py +7 -10
  228. massgen/tests/test_http_mcp_server.py +42 -0
  229. massgen/tests/test_integration_simple.py +198 -0
  230. massgen/tests/test_mcp_blocking.py +125 -0
  231. massgen/tests/test_message_context_building.py +29 -47
  232. massgen/tests/test_orchestrator_final_presentation.py +48 -0
  233. massgen/tests/test_path_permission_manager.py +2087 -0
  234. massgen/tests/test_rich_terminal_display.py +14 -13
  235. massgen/tests/test_timeout.py +133 -0
  236. massgen/tests/test_v3_3agents.py +11 -12
  237. massgen/tests/test_v3_simple.py +8 -13
  238. massgen/tests/test_v3_three_agents.py +11 -18
  239. massgen/tests/test_v3_two_agents.py +8 -13
  240. massgen/token_manager/__init__.py +7 -0
  241. massgen/token_manager/token_manager.py +400 -0
  242. massgen/utils.py +52 -16
  243. massgen/v1/agent.py +45 -91
  244. massgen/v1/agents.py +18 -53
  245. massgen/v1/backends/gemini.py +50 -153
  246. massgen/v1/backends/grok.py +21 -54
  247. massgen/v1/backends/oai.py +39 -111
  248. massgen/v1/cli.py +36 -93
  249. massgen/v1/config.py +8 -12
  250. massgen/v1/logging.py +43 -127
  251. massgen/v1/main.py +18 -32
  252. massgen/v1/orchestrator.py +68 -209
  253. massgen/v1/streaming_display.py +62 -163
  254. massgen/v1/tools.py +8 -12
  255. massgen/v1/types.py +9 -23
  256. massgen/v1/utils.py +5 -23
  257. massgen-0.1.0.dist-info/METADATA +1245 -0
  258. massgen-0.1.0.dist-info/RECORD +273 -0
  259. massgen-0.1.0.dist-info/entry_points.txt +2 -0
  260. massgen/frontend/logging/__init__.py +0 -9
  261. massgen/frontend/logging/realtime_logger.py +0 -197
  262. massgen-0.0.3.dist-info/METADATA +0 -568
  263. massgen-0.0.3.dist-info/RECORD +0 -76
  264. massgen-0.0.3.dist-info/entry_points.txt +0 -2
  265. /massgen/backend/{Function calling openai responses.md → docs/Function calling openai responses.md} +0 -0
  266. {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/WHEEL +0 -0
  267. {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/licenses/LICENSE +0 -0
  268. {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,263 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Response API formatter implementation.
4
+ Handles formatting for OpenAI Response API format with multimodal support.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Dict, List
10
+
11
+ from ._formatter_base import FormatterBase
12
+
13
+
14
+ class ResponseFormatter(FormatterBase):
15
+ """Formatter for Response API format with multimodal support."""
16
+
17
+ def format_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
18
+ """
19
+ Convert messages from Chat Completions format to Response API format.
20
+
21
+ Chat Completions tool message: {"role": "tool", "tool_call_id": "...", "content": "..."}
22
+ Response API tool message: {"type": "function_call_output", "call_id": "...", "output": "..."}
23
+
24
+ Also handles multimodal content conversion:
25
+ - {"type": "text", "text": "..."} → {"type": "input_text", "text": "..."}
26
+ - {"type": "image", "url": "..."} → {"type": "input_image", "image_url": "..."}
27
+ - {"type": "image", "base64": "..."} → {"type": "input_image", "image_url": "data:image/...;base64,..."}
28
+
29
+ Note: Assistant messages with tool_calls should not be in input - they're generated by the backend.
30
+ """
31
+ cleaned_messages = []
32
+ for message in messages:
33
+ if "status" in message and "role" not in message:
34
+ # Create a copy without 'status'
35
+ cleaned_message = {k: v for k, v in message.items() if k != "status"}
36
+ cleaned_messages.append(cleaned_message)
37
+ else:
38
+ cleaned_messages.append(message)
39
+
40
+ converted_messages = []
41
+
42
+ for message in cleaned_messages:
43
+ if message.get("role") == "tool":
44
+ # Convert Chat Completions tool message to Response API format
45
+ converted_message = {
46
+ "type": "function_call_output",
47
+ "call_id": message.get("tool_call_id"),
48
+ "output": message.get("content", ""),
49
+ }
50
+ converted_messages.append(converted_message)
51
+ elif message.get("type") == "function_call_output":
52
+ # Already in Response API format
53
+ converted_messages.append(message)
54
+ elif message.get("role") == "assistant" and "tool_calls" in message:
55
+ # Assistant message with tool_calls - remove tool_calls when sending as input
56
+ cleaned_message = {k: v for k, v in message.items() if k != "tool_calls"}
57
+ converted_messages.append(cleaned_message)
58
+ else:
59
+ # For other message types, check for multimodal content
60
+ converted_message = self._convert_multimodal_content(message.copy())
61
+ converted_messages.append(converted_message)
62
+
63
+ return converted_messages
64
+
65
+ def _convert_multimodal_content(self, message: Dict[str, Any]) -> Dict[str, Any]:
66
+ """
67
+ Convert multimodal content to Response API format.
68
+
69
+ Handles conversion of content arrays with text and image items:
70
+ - text items: {"type": "text", "text": "..."} → {"type": "input_text", "text": "..."}
71
+ - image URL: {"type": "image", "url": "..."} → {"type": "input_image", "image_url": "..."}
72
+ - image base64: {"type": "image", "base64": "...", "mime_type": "..."} →
73
+ {"type": "input_image", "image_url": "data:image/...;base64,..."}
74
+ - file: {"type": "file", "file_id": "..."} → {"type": "input_file", "file_id": "..."}
75
+
76
+ Args:
77
+ message: Message dictionary that may contain multimodal content
78
+
79
+ Returns:
80
+ Message with content converted to Response API format
81
+ """
82
+ content = message.get("content")
83
+
84
+ # If content is not a list, no conversion needed
85
+ if not isinstance(content, list):
86
+ return message
87
+
88
+ converted_content = []
89
+ for item in content:
90
+ if not isinstance(item, dict):
91
+ # If item is a string, treat as text
92
+ converted_content.append({"type": "input_text", "text": str(item)})
93
+ continue
94
+
95
+ item_type = item.get("type")
96
+
97
+ if item_type == "text":
98
+ # Convert text item to input_text
99
+ converted_content.append(
100
+ {
101
+ "type": "input_text",
102
+ "text": item.get("text", ""),
103
+ },
104
+ )
105
+
106
+ elif item_type == "image":
107
+ # Convert image item to input_image
108
+ converted_item = self._convert_image_content(item)
109
+ if converted_item:
110
+ converted_content.append(converted_item)
111
+
112
+ elif item_type == "file":
113
+ # Convert file item to input_file
114
+ converted_content.append(
115
+ {
116
+ "type": "input_file",
117
+ "file_id": item.get("file_id", ""),
118
+ },
119
+ )
120
+
121
+ elif item_type == "file_pending_upload":
122
+ converted_content.append(item)
123
+
124
+ elif item_type in ["input_text", "input_image", "input_file"]:
125
+ # Already in Response API format
126
+ converted_content.append(item)
127
+
128
+ else:
129
+ # Unknown type, pass through
130
+ converted_content.append(item)
131
+
132
+ message["content"] = converted_content
133
+ return message
134
+
135
+ def _convert_image_content(self, image_item: Dict[str, Any]) -> Dict[str, Any]:
136
+ """
137
+ Convert image content item to Response API format.
138
+
139
+ Supports:
140
+ - URL format: {"type": "image", "url": "https://..."}
141
+ - Base64 format: {"type": "image", "base64": "...", "mime_type": "image/jpeg"}
142
+ - Image URL format: {"type": "image", "image_url": "..."} (already correct)
143
+
144
+ Args:
145
+ image_item: Image content item dictionary
146
+
147
+ Returns:
148
+ Converted image item in Response API format, or None if invalid
149
+ """
150
+ # Check if already in correct format
151
+ if "image_url" in image_item:
152
+ return {
153
+ "type": "input_image",
154
+ "image_url": image_item["image_url"],
155
+ }
156
+
157
+ # Handle URL format
158
+ if "url" in image_item:
159
+ return {
160
+ "type": "input_image",
161
+ "image_url": image_item["url"],
162
+ }
163
+
164
+ # Handle base64 format
165
+ if "base64" in image_item:
166
+ mime_type = image_item.get("mime_type", "image/jpeg")
167
+ base64_data = image_item["base64"]
168
+
169
+ # Validate base64 data
170
+ if not self._validate_base64_image(base64_data):
171
+ return None
172
+
173
+ # Create data URL
174
+ data_url = f"data:{mime_type};base64,{base64_data}"
175
+ return {
176
+ "type": "input_image",
177
+ "image_url": data_url,
178
+ }
179
+
180
+ # No valid image data found
181
+ return None
182
+
183
+ def _validate_base64_image(self, base64_data: str) -> bool:
184
+ """
185
+ Validate base64 image data.
186
+
187
+ Checks:
188
+ - Data is not empty
189
+ - Data is valid base64 (basic check)
190
+ - Data size is within limits (20MB)
191
+
192
+ Args:
193
+ base64_data: Base64 encoded image string
194
+
195
+ Returns:
196
+ True if valid, False otherwise
197
+ """
198
+ if not base64_data:
199
+ return False
200
+
201
+ # Check size (base64 is ~33% larger than binary)
202
+ # 20MB binary = ~27MB base64
203
+ max_base64_size = 27 * 1024 * 1024
204
+ if len(base64_data) > max_base64_size:
205
+ return False
206
+
207
+ # Basic base64 validation (contains only valid characters)
208
+ import re
209
+
210
+ if not re.match(r"^[A-Za-z0-9+/]*={0,2}$", base64_data):
211
+ return False
212
+
213
+ return True
214
+
215
+ def format_tools(self, tools: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
216
+ """
217
+ Convert tools from Chat Completions format to Response API format if needed.
218
+
219
+ Chat Completions format: {"type": "function", "function": {"name": ..., "description": ..., "parameters": ...}}
220
+ Response API format: {"type": "function", "name": ..., "description": ..., "parameters": ...}
221
+ """
222
+ if not tools:
223
+ return tools
224
+
225
+ converted_tools = []
226
+ for tool in tools:
227
+ if tool.get("type") == "function" and "function" in tool:
228
+ # Chat Completions format - convert to Response API format
229
+ func = tool["function"]
230
+ converted_tools.append(
231
+ {
232
+ "type": "function",
233
+ "name": func["name"],
234
+ "description": func["description"],
235
+ "parameters": func.get("parameters", {}),
236
+ },
237
+ )
238
+ else:
239
+ # Already in Response API format or non-function tool
240
+ converted_tools.append(tool)
241
+
242
+ return converted_tools
243
+
244
+ def format_mcp_tools(self, mcp_functions: Dict[str, Any]) -> List[Dict[str, Any]]:
245
+ """Convert MCP tools to Response API format (OpenAI function declarations)."""
246
+ if not mcp_functions:
247
+ return []
248
+
249
+ converted_tools = []
250
+ for mcp_function in mcp_functions.values():
251
+ if hasattr(mcp_function, "to_openai_format"):
252
+ tool = mcp_function.to_openai_format()
253
+ else:
254
+ # Fallback format - Response API expects flat structure
255
+ tool = {
256
+ "type": "function",
257
+ "name": getattr(mcp_function, "name", "unknown"),
258
+ "description": getattr(mcp_function, "description", ""),
259
+ "parameters": getattr(mcp_function, "input_schema", {}),
260
+ }
261
+ converted_tools.append(tool)
262
+
263
+ return converted_tools
@@ -15,6 +15,5 @@ TODO - Missing Frontend Features from v0.0.1:
15
15
 
16
16
  from .coordination_ui import CoordinationUI
17
17
  from .displays import TerminalDisplay, SimpleDisplay
18
- from .logging import RealtimeLogger
19
18
 
20
- __all__ = ["CoordinationUI", "TerminalDisplay", "SimpleDisplay", "RealtimeLogger"]
19
+ __all__ = ["CoordinationUI", "TerminalDisplay", "SimpleDisplay"]