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,176 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Chat Completions API parameters handler.
4
+ Handles parameter building for OpenAI Chat Completions API format.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Dict, List, Set
10
+
11
+ from ._api_params_handler_base import APIParamsHandlerBase
12
+
13
+
14
+ class ChatCompletionsAPIParamsHandler(APIParamsHandlerBase):
15
+ """Handler for Chat Completions API parameters."""
16
+
17
+ def get_excluded_params(self) -> Set[str]:
18
+ """Get parameters to exclude from Chat Completions API calls."""
19
+ return self.get_base_excluded_params().union(
20
+ {
21
+ "base_url", # Used for client initialization, not API calls
22
+ "enable_web_search",
23
+ "enable_code_interpreter",
24
+ "allowed_tools",
25
+ "exclude_tools",
26
+ },
27
+ )
28
+
29
+ def get_provider_tools(self, all_params: Dict[str, Any]) -> List[Dict[str, Any]]:
30
+ """Get provider tools for Chat Completions format."""
31
+ provider_tools = []
32
+
33
+ if all_params.get("enable_web_search", False):
34
+ provider_tools.append(
35
+ {
36
+ "type": "function",
37
+ "function": {
38
+ "name": "web_search",
39
+ "description": "Search the web for current or factual information",
40
+ "parameters": {
41
+ "type": "object",
42
+ "properties": {
43
+ "query": {
44
+ "type": "string",
45
+ "description": "The search query to send to the web",
46
+ },
47
+ },
48
+ "required": ["query"],
49
+ },
50
+ },
51
+ },
52
+ )
53
+
54
+ if all_params.get("enable_code_interpreter", False):
55
+ provider_tools.append(
56
+ {
57
+ "type": "code_interpreter",
58
+ "container": {"type": "auto"},
59
+ },
60
+ )
61
+
62
+ return provider_tools
63
+
64
+ def build_base_api_params(self, messages: List[Dict[str, Any]], all_params: Dict[str, Any]) -> Dict[str, Any]:
65
+ """Build base API parameters for Chat Completions requests."""
66
+ # Sanitize: remove trailing assistant tool_calls without corresponding tool results
67
+ sanitized_messages = self._sanitize_messages_for_api(messages)
68
+ # Convert messages to ensure tool call arguments are properly serialized
69
+ converted_messages = self.formatter.format_messages(sanitized_messages)
70
+
71
+ api_params = {
72
+ "messages": converted_messages,
73
+ "stream": True,
74
+ }
75
+
76
+ # Direct passthrough of all parameters except those handled separately
77
+ for key, value in all_params.items():
78
+ if key not in self.get_excluded_params() and value is not None:
79
+ api_params[key] = value
80
+
81
+ return api_params
82
+
83
+ async def build_api_params(
84
+ self,
85
+ messages: List[Dict[str, Any]],
86
+ tools: List[Dict[str, Any]],
87
+ all_params: Dict[str, Any],
88
+ ) -> Dict[str, Any]:
89
+ """Build Chat Completions API parameters."""
90
+ # Sanitize messages if needed
91
+ if hasattr(self.backend, "_sanitize_messages_for_api"):
92
+ messages = self._sanitize_messages_for_api(messages)
93
+
94
+ # Convert messages to Chat Completions format
95
+ converted_messages = self.formatter.format_messages(messages)
96
+
97
+ # Build base parameters
98
+ api_params = {
99
+ "messages": converted_messages,
100
+ "stream": True,
101
+ }
102
+
103
+ # Add filtered parameters
104
+ excluded = self.get_excluded_params()
105
+ for key, value in all_params.items():
106
+ if key not in excluded and value is not None:
107
+ api_params[key] = value
108
+
109
+ # Combine all tools
110
+ combined_tools = []
111
+
112
+ # Server-side tools (provider tools) go first
113
+ provider_tools = self.get_provider_tools(all_params)
114
+ if provider_tools:
115
+ combined_tools.extend(provider_tools)
116
+
117
+ # User-defined tools
118
+ if tools:
119
+ converted_tools = self.formatter.format_tools(tools)
120
+ combined_tools.extend(converted_tools)
121
+
122
+ # MCP tools
123
+ mcp_tools = self.get_mcp_tools()
124
+ if mcp_tools:
125
+ combined_tools.extend(mcp_tools)
126
+
127
+ if combined_tools:
128
+ api_params["tools"] = combined_tools
129
+
130
+ return api_params
131
+
132
+ def _sanitize_messages_for_api(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
133
+ """
134
+ Ensure assistant tool_calls are valid per OpenAI Chat Completions rules:
135
+ - For any assistant message with tool_calls, each tool_call.id must have a following
136
+ tool message with matching tool_call_id in the subsequent history.
137
+ - Remove any tool_calls lacking matching tool results; drop the whole assistant message
138
+ if no valid tool_calls remain and it has no useful content.
139
+ This prevents 400 wrong_api_format errors.
140
+ """
141
+ try:
142
+ sanitized: List[Dict[str, Any]] = []
143
+ len(messages)
144
+ for i, msg in enumerate(messages):
145
+ if msg.get("role") == "assistant" and "tool_calls" in msg:
146
+ tool_calls = msg.get("tool_calls") or []
147
+ valid_tool_calls = []
148
+ for tc in tool_calls:
149
+ tc_id = tc.get("id")
150
+ if not tc_id:
151
+ continue
152
+ # Does a later tool message reference this id?
153
+ has_match = any((m.get("role") == "tool" and m.get("tool_call_id") == tc_id) for m in messages[i + 1 :])
154
+ if has_match:
155
+ # Normalize arguments to string
156
+ fn = dict(tc.get("function", {}))
157
+ fn["arguments"] = self.formatter._serialize_tool_arguments(fn.get("arguments"))
158
+ valid_tc = dict(tc)
159
+ valid_tc["function"] = fn
160
+ valid_tool_calls.append(valid_tc)
161
+ if valid_tool_calls:
162
+ new_msg = dict(msg)
163
+ new_msg["tool_calls"] = valid_tool_calls
164
+ sanitized.append(new_msg)
165
+ else:
166
+ # Keep as plain assistant if it has content; otherwise drop
167
+ if msg.get("content"):
168
+ new_msg = {k: v for k, v in msg.items() if k != "tool_calls"}
169
+ sanitized.append(new_msg)
170
+ else:
171
+ continue
172
+ else:
173
+ sanitized.append(msg)
174
+ return sanitized
175
+ except Exception:
176
+ return messages
@@ -0,0 +1,113 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Claude API parameters handler.
4
+ Handles parameter building for Anthropic Claude Messages API format.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Dict, List, Set
10
+
11
+ from ._api_params_handler_base import APIParamsHandlerBase
12
+
13
+
14
+ class ClaudeAPIParamsHandler(APIParamsHandlerBase):
15
+ """Handler for Claude API parameters."""
16
+
17
+ def get_excluded_params(self) -> Set[str]:
18
+ """Get parameters to exclude from Claude API calls."""
19
+ return self.get_base_excluded_params().union(
20
+ {
21
+ "enable_web_search",
22
+ "enable_code_execution",
23
+ "allowed_tools",
24
+ "exclude_tools",
25
+ "_has_files_api_files",
26
+ },
27
+ )
28
+
29
+ def get_provider_tools(self, all_params: Dict[str, Any]) -> List[Dict[str, Any]]:
30
+ """Get provider tools for Claude format (server-side tools)."""
31
+ provider_tools = []
32
+
33
+ if all_params.get("enable_web_search", False):
34
+ provider_tools.append(
35
+ {
36
+ "type": "web_search_20250305",
37
+ "name": "web_search",
38
+ },
39
+ )
40
+
41
+ if all_params.get("enable_code_execution", False):
42
+ provider_tools.append(
43
+ {
44
+ "type": "code_execution_20250522",
45
+ "name": "code_execution",
46
+ },
47
+ )
48
+
49
+ return provider_tools
50
+
51
+ async def build_api_params(
52
+ self,
53
+ messages: List[Dict[str, Any]],
54
+ tools: List[Dict[str, Any]],
55
+ all_params: Dict[str, Any],
56
+ ) -> Dict[str, Any]:
57
+ """Build Claude API parameters."""
58
+ # Convert messages to Claude format and extract system message
59
+ converted_messages, system_message = self.formatter.format_messages_and_system(messages)
60
+
61
+ # Build base parameters
62
+ api_params: Dict[str, Any] = {
63
+ "messages": converted_messages,
64
+ "stream": True,
65
+ }
66
+
67
+ # Add filtered parameters
68
+ excluded = self.get_excluded_params()
69
+ for key, value in all_params.items():
70
+ if key not in excluded and value is not None:
71
+ api_params[key] = value
72
+
73
+ # Claude API requires max_tokens - add default if not provided
74
+ if "max_tokens" not in api_params:
75
+ api_params["max_tokens"] = 4096
76
+
77
+ # Handle multiple betas (code execution and files API)
78
+ betas_list = []
79
+ if all_params.get("enable_code_execution"):
80
+ betas_list.append("code-execution-2025-05-22")
81
+ if all_params.get("_has_files_api_files"):
82
+ betas_list.append("files-api-2025-04-14")
83
+ if betas_list:
84
+ api_params["betas"] = betas_list
85
+
86
+ # Remove internal flag so it doesn't leak
87
+ all_params.pop("_has_files_api_files", None)
88
+
89
+ # Add system message if present
90
+ if system_message:
91
+ api_params["system"] = system_message
92
+
93
+ combined_tools = []
94
+
95
+ # Server-side tools (provider tools) go first
96
+ provider_tools = self.get_provider_tools(all_params)
97
+ if provider_tools:
98
+ combined_tools.extend(provider_tools)
99
+
100
+ # User-defined tools
101
+ if tools:
102
+ converted_tools = self.formatter.format_tools(tools)
103
+ combined_tools.extend(converted_tools)
104
+
105
+ # MCP tools
106
+ mcp_tools = self.get_mcp_tools()
107
+ if mcp_tools:
108
+ combined_tools.extend(mcp_tools)
109
+
110
+ if combined_tools:
111
+ api_params["tools"] = combined_tools
112
+
113
+ return api_params
@@ -0,0 +1,130 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Response API parameters handler.
4
+ Handles parameter building for OpenAI Response API format.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Dict, List, Set
10
+
11
+ from ._api_params_handler_base import APIParamsHandlerBase
12
+
13
+
14
+ class ResponseAPIParamsHandler(APIParamsHandlerBase):
15
+ """Handler for Response API parameters."""
16
+
17
+ def get_excluded_params(self) -> Set[str]:
18
+ """Get parameters to exclude from Response API calls."""
19
+ return self.get_base_excluded_params().union(
20
+ {
21
+ "enable_web_search",
22
+ "enable_code_interpreter",
23
+ "allowed_tools",
24
+ "exclude_tools",
25
+ "_has_file_search_files", # Internal flag for file search tracking
26
+ },
27
+ )
28
+
29
+ def get_provider_tools(self, all_params: Dict[str, Any]) -> List[Dict[str, Any]]:
30
+ """Get provider tools for Response API format."""
31
+ provider_tools = []
32
+
33
+ if all_params.get("enable_web_search", False):
34
+ provider_tools.append({"type": "web_search"})
35
+
36
+ if all_params.get("enable_code_interpreter", False):
37
+ provider_tools.append(
38
+ {
39
+ "type": "code_interpreter",
40
+ "container": {"type": "auto"},
41
+ },
42
+ )
43
+
44
+ return provider_tools
45
+
46
+ def _convert_mcp_tools_to_openai_format(self) -> List[Dict[str, Any]]:
47
+ """Convert MCP tools to OpenAI function format for Response API."""
48
+ if not hasattr(self.backend, "_mcp_functions") or not self.backend._mcp_functions:
49
+ return []
50
+
51
+ converted_tools = []
52
+ for function in self.backend._mcp_functions.values():
53
+ converted_tools.append(function.to_openai_format())
54
+
55
+ return converted_tools
56
+
57
+ async def build_api_params(
58
+ self,
59
+ messages: List[Dict[str, Any]],
60
+ tools: List[Dict[str, Any]],
61
+ all_params: Dict[str, Any],
62
+ ) -> Dict[str, Any]:
63
+ """Build Response API parameters."""
64
+ # Convert messages to Response API format
65
+ converted_messages = self.formatter.format_messages(messages)
66
+
67
+ # Response API uses 'input' instead of 'messages'
68
+ api_params = {
69
+ "input": converted_messages,
70
+ "stream": True,
71
+ }
72
+
73
+ # Add filtered parameters with parameter mapping
74
+ excluded = self.get_excluded_params()
75
+ for key, value in all_params.items():
76
+ if key not in excluded and value is not None:
77
+ # Handle Response API parameter name differences
78
+ if key == "max_tokens":
79
+ api_params["max_output_tokens"] = value
80
+ else:
81
+ api_params[key] = value
82
+
83
+ # Combine all tools
84
+ combined_tools = api_params.setdefault("tools", [])
85
+
86
+ # Add provider tools first
87
+ provider_tools = self.get_provider_tools(all_params)
88
+ if provider_tools:
89
+ combined_tools.extend(provider_tools)
90
+
91
+ # Add framework tools
92
+ if tools:
93
+ converted_tools = self.formatter.format_tools(tools)
94
+ combined_tools.extend(converted_tools)
95
+
96
+ # Add MCP tools (use OpenAI format)
97
+ mcp_tools = self._convert_mcp_tools_to_openai_format()
98
+ if mcp_tools:
99
+ combined_tools.extend(mcp_tools)
100
+
101
+ if combined_tools:
102
+ api_params["tools"] = combined_tools
103
+ # File Search integration
104
+ vector_store_ids = all_params.get("_file_search_vector_store_ids")
105
+ if vector_store_ids:
106
+ # Ensure vector_store_ids is a list
107
+ if not isinstance(vector_store_ids, list):
108
+ vector_store_ids = [vector_store_ids]
109
+
110
+ # Check if file_search tool already exists
111
+ file_search_tool_index = None
112
+ for i, tool in enumerate(combined_tools):
113
+ if tool.get("type") == "file_search":
114
+ file_search_tool_index = i
115
+ break
116
+
117
+ # Add or update file_search tool with embedded vector_store_ids
118
+ if file_search_tool_index is not None:
119
+ # Update existing file_search tool
120
+ combined_tools[file_search_tool_index]["vector_store_ids"] = vector_store_ids
121
+ else:
122
+ # Add new file_search tool with vector_store_ids
123
+ combined_tools.append(
124
+ {
125
+ "type": "file_search",
126
+ "vector_store_ids": vector_store_ids,
127
+ },
128
+ )
129
+
130
+ return api_params
@@ -1,25 +1,60 @@
1
+ # -*- coding: utf-8 -*-
1
2
  """
2
3
  MassGen Backend System - Multi-Provider LLM Integration
3
4
 
4
5
  Supports multiple LLM providers with standardized StreamChunk interface:
5
- - Response API (standard format with tool support)
6
- - Grok/xAI (Chat Completions API compatible)
6
+ - ChatCompletions (OpenAI-compatible for Cerebras AI, etc.)
7
+ - Response API (OpenAI Response API with reasoning support)
8
+ - Grok (xAI API with live search capabilities)
7
9
  - Claude (Messages API with multi-tool support)
8
10
  - Gemini (structured output for coordination)
11
+ - Claude Code (claude-code-sdk streaming integration)
12
+
13
+ TODO:
14
+
15
+ - Gemini CLI (command-line interface integration)
16
+ - Clean up StreamChunk design (too many optional fields for reasoning/provider features)
17
+ - Check if we indeed need to pass agent_id & session_id to backends
9
18
  """
10
19
 
11
20
  from .base import LLMBackend, StreamChunk, TokenUsage
12
- from .response import ResponseBackend
13
- from .grok import GrokBackend
21
+ from .chat_completions import ChatCompletionsBackend
14
22
  from .claude import ClaudeBackend
23
+
24
+ # from .claude_code_cli import ClaudeCodeCLIBackend # File removed
25
+ from .claude_code import ClaudeCodeBackend
26
+ from .cli_base import CLIBackend
15
27
  from .gemini import GeminiBackend
28
+ from .grok import GrokBackend
29
+ from .lmstudio import LMStudioBackend
30
+ from .response import ResponseBackend
31
+
32
+ # from .gemini_cli import GeminiCLIBackend
33
+
34
+ # Azure OpenAI backend (optional)
35
+ try:
36
+ from .azure_openai import AzureOpenAIBackend
37
+
38
+ AZURE_OPENAI_AVAILABLE = True
39
+ except ImportError:
40
+ AZURE_OPENAI_AVAILABLE = False
41
+ AzureOpenAIBackend = None
16
42
 
17
43
  __all__ = [
18
44
  "LLMBackend",
19
45
  "StreamChunk",
20
46
  "TokenUsage",
47
+ "ChatCompletionsBackend",
21
48
  "ResponseBackend",
22
49
  "GrokBackend",
50
+ "LMStudioBackend",
23
51
  "ClaudeBackend",
24
52
  "GeminiBackend",
53
+ "CLIBackend",
54
+ "ClaudeCodeBackend",
55
+ # "GeminiCLIBackend",
25
56
  ]
57
+
58
+ # Add Azure OpenAI if available
59
+ if AZURE_OPENAI_AVAILABLE:
60
+ __all__.append("AzureOpenAIBackend")