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,142 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Test script to verify ChatCompletionsBackend refactoring.
5
+ Tests integration with different OpenAI-compatible providers.
6
+ """
7
+
8
+ import asyncio
9
+ import os
10
+
11
+ from massgen.backend import ChatCompletionsBackend
12
+
13
+
14
+ async def test_openai_backend():
15
+ """Test ChatCompletionsBackend with OpenAI."""
16
+ print("🔧 Testing ChatCompletionsBackend with OpenAI...")
17
+
18
+ # Create backend with OpenAI defaults
19
+ backend = ChatCompletionsBackend()
20
+ print(f"Provider: {backend.get_provider_name()}")
21
+ print(f"Base URL: {backend.base_url}")
22
+ print(f"API Key configured: {'Yes' if backend.api_key else 'No'}")
23
+
24
+ # Test token estimation
25
+ test_text = "Hello world, how are you doing today?"
26
+ tokens = backend.estimate_tokens(test_text)
27
+ print(f"Estimated tokens for '{test_text}': {tokens}")
28
+
29
+ # Test cost calculation
30
+ cost = backend.calculate_cost(1000, 500, "gpt-4o-mini")
31
+ print(f"Cost for 1000 input + 500 output tokens (gpt-4o-mini): ${cost:.4f}")
32
+
33
+
34
+ async def test_together_ai_backend():
35
+ """Test ChatCompletionsBackend configured for Together AI."""
36
+ print("\n🔧 Testing ChatCompletionsBackend with Together AI...")
37
+
38
+ # Create backend configured for Together AI
39
+ backend = ChatCompletionsBackend(
40
+ base_url="https://api.together.xyz/v1",
41
+ provider_name="Together AI",
42
+ api_key=os.getenv("TOGETHER_API_KEY"),
43
+ )
44
+ print(f"Provider: {backend.get_provider_name()}")
45
+ print(f"Base URL: {backend.base_url}")
46
+ print(f"API Key configured: {'Yes' if backend.api_key else 'No'}")
47
+
48
+ # Test cost calculation with Together AI model
49
+ cost = backend.calculate_cost(1000, 500, "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo")
50
+ print(f"Cost for 1000 input + 500 output tokens (fallback pricing): ${cost:.4f}")
51
+
52
+
53
+ async def test_cerebras_backend():
54
+ """Test ChatCompletionsBackend configured for Cerebras AI."""
55
+ print("\n🔧 Testing ChatCompletionsBackend with Cerebras AI...")
56
+
57
+ # Create backend configured for Cerebras AI
58
+ backend = ChatCompletionsBackend(
59
+ base_url="https://api.cerebras.ai/v1",
60
+ provider_name="Cerebras AI",
61
+ api_key=os.getenv("CEREBRAS_API_KEY"),
62
+ )
63
+ print(f"Provider: {backend.get_provider_name()}")
64
+ print(f"Base URL: {backend.base_url}")
65
+ print(f"API Key configured: {'Yes' if backend.api_key else 'No'}")
66
+
67
+
68
+ async def test_tool_conversion():
69
+ """Test tool format conversion."""
70
+ print("\n🔧 Testing tool format conversion...")
71
+
72
+ backend = ChatCompletionsBackend()
73
+
74
+ # Test Response API format conversion
75
+ response_tools = [
76
+ {
77
+ "type": "function",
78
+ "name": "get_weather",
79
+ "description": "Get weather information",
80
+ "parameters": {
81
+ "type": "object",
82
+ "properties": {"location": {"type": "string"}},
83
+ "required": ["location"],
84
+ },
85
+ },
86
+ ]
87
+
88
+ converted = backend.convert_tools_to_chat_completions_format(response_tools)
89
+ print("Response API tools converted to Chat Completions format:")
90
+ print(f" Original: {response_tools[0]}")
91
+ print(f" Converted: {converted[0]}")
92
+
93
+ # Test Chat Completions format (should remain unchanged)
94
+ chat_tools = [
95
+ {
96
+ "type": "function",
97
+ "function": {
98
+ "name": "search_web",
99
+ "description": "Search the web",
100
+ "parameters": {
101
+ "type": "object",
102
+ "properties": {"query": {"type": "string"}},
103
+ "required": ["query"],
104
+ },
105
+ },
106
+ },
107
+ ]
108
+
109
+ converted_chat = backend.convert_tools_to_chat_completions_format(chat_tools)
110
+ print("\nChat Completions tools (should remain unchanged):")
111
+ print(f" Original: {chat_tools[0]}")
112
+ print(f" After conversion: {converted_chat[0]}")
113
+
114
+
115
+ async def main():
116
+ """Run all tests."""
117
+ print("🚀 Testing ChatCompletionsBackend refactoring...")
118
+ print("=" * 60)
119
+
120
+ try:
121
+ await test_openai_backend()
122
+ await test_together_ai_backend()
123
+ await test_cerebras_backend()
124
+ await test_tool_conversion()
125
+
126
+ print("\n" + "=" * 60)
127
+ print("✅ All tests completed successfully!")
128
+ print("\n📋 ChatCompletionsBackend is now ready for use with:")
129
+ print(" • OpenAI (default)")
130
+ print(" • Together AI")
131
+ print(" • Cerebras AI")
132
+ print(" • Any OpenAI-compatible provider")
133
+
134
+ except Exception as e:
135
+ print(f"\n❌ Test failed: {e}")
136
+ return 1
137
+
138
+ return 0
139
+
140
+
141
+ if __name__ == "__main__":
142
+ exit(asyncio.run(main()))
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
2
3
  """
3
4
  Claude Backend Integration Tests for MassGen
4
5
 
@@ -12,18 +13,16 @@ Tests the Claude backend implementation with real API calls:
12
13
  Requires ANTHROPIC_API_KEY environment variable.
13
14
  """
14
15
 
16
+ import asyncio
15
17
  import os
16
18
  import sys
17
- import asyncio
18
- import json
19
19
  from pathlib import Path
20
20
 
21
21
  # Add project root to path
22
22
  project_root = Path(__file__).parent.parent.parent.parent
23
23
  sys.path.insert(0, str(project_root))
24
24
 
25
- from massgen.backend.claude_backend import ClaudeBackend
26
- from massgen.backend.base import StreamChunk
25
+ from massgen.backend.claude import ClaudeBackend # noqa: E402
27
26
 
28
27
 
29
28
  async def test_claude_basic_streaming():
@@ -32,21 +31,15 @@ async def test_claude_basic_streaming():
32
31
 
33
32
  backend = ClaudeBackend()
34
33
 
35
- messages = [
36
- {"role": "user", "content": "Explain quantum computing in 2-3 sentences."}
37
- ]
34
+ messages = [{"role": "user", "content": "Explain quantum computing in 2-3 sentences."}]
38
35
 
39
36
  content = ""
40
- async for chunk in backend.stream_with_tools(
41
- messages, [], model="claude-3-5-haiku-20241022"
42
- ):
37
+ async for chunk in backend.stream_with_tools(messages, [], model="claude-3-5-haiku-20241022"):
43
38
  if chunk.type == "content":
44
39
  content += chunk.content
45
40
  print(chunk.content, end="", flush=True)
46
41
  elif chunk.type == "complete_message":
47
- print(
48
- f"\n✅ Complete message received: {len(chunk.complete_message.get('content', ''))} chars"
49
- )
42
+ print(f"\n✅ Complete message received: {len(chunk.complete_message.get('content', ''))} chars")
50
43
  elif chunk.type == "done":
51
44
  print("\n✅ Basic streaming test completed")
52
45
  break
@@ -77,20 +70,18 @@ async def test_claude_tool_calling():
77
70
  },
78
71
  "required": ["width", "height"],
79
72
  },
80
- }
73
+ },
81
74
  ]
82
75
 
83
76
  messages = [
84
77
  {
85
78
  "role": "user",
86
79
  "content": "Calculate the area of a rectangle with width 5 and height 3.",
87
- }
80
+ },
88
81
  ]
89
82
 
90
83
  tool_calls_received = []
91
- async for chunk in backend.stream_with_tools(
92
- messages, tools, model="claude-3-5-haiku-20241022"
93
- ):
84
+ async for chunk in backend.stream_with_tools(messages, tools, model="claude-3-5-haiku-20241022"):
94
85
  if chunk.type == "content":
95
86
  print(chunk.content, end="", flush=True)
96
87
  elif chunk.type == "tool_calls":
@@ -101,7 +92,7 @@ async def test_claude_tool_calling():
101
92
  tool_args = backend.extract_tool_arguments(tool_call)
102
93
  print(f" - {tool_name}: {tool_args}")
103
94
  elif chunk.type == "complete_message":
104
- print(f"\n✅ Complete message with tool calls received")
95
+ print("\n✅ Complete message with tool calls received")
105
96
  elif chunk.type == "done":
106
97
  print("✅ Tool calling test completed")
107
98
  break
@@ -129,14 +120,14 @@ async def test_claude_multi_tool_support():
129
120
  "properties": {"title": {"type": "string"}, "data": {"type": "string"}},
130
121
  "required": ["title", "data"],
131
122
  },
132
- }
123
+ },
133
124
  ]
134
125
 
135
126
  messages = [
136
127
  {
137
128
  "role": "user",
138
129
  "content": "Search for recent news about AI and format the result with a nice title.",
139
- }
130
+ },
140
131
  ]
141
132
 
142
133
  # Enable both server-side tools and user tools
@@ -187,7 +178,7 @@ async def test_claude_message_conversion():
187
178
  "id": "call_123",
188
179
  "type": "function",
189
180
  "function": {"name": "add", "arguments": {"a": 5, "b": 3}},
190
- }
181
+ },
191
182
  ],
192
183
  },
193
184
  {"role": "tool", "tool_call_id": "call_123", "content": "8"},
@@ -203,11 +194,7 @@ async def test_claude_message_conversion():
203
194
  # Check tool result conversion
204
195
  tool_result_found = False
205
196
  for msg in converted:
206
- if (
207
- msg.get("role") == "user"
208
- and isinstance(msg.get("content"), list)
209
- and any(item.get("type") == "tool_result" for item in msg["content"])
210
- ):
197
+ if msg.get("role") == "user" and isinstance(msg.get("content"), list) and any(item.get("type") == "tool_result" for item in msg["content"]):
211
198
  tool_result_found = True
212
199
  print(" ✅ Tool result conversion successful")
213
200
  break
@@ -290,7 +277,7 @@ async def main():
290
277
  results.append((test_name, False))
291
278
 
292
279
  # Summary
293
- print(f"\n📊 Test Results Summary:")
280
+ print("\n📊 Test Results Summary:")
294
281
  passed = sum(1 for _, result in results if result)
295
282
  total = len(results)
296
283
 
@@ -0,0 +1,268 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Real test of ClaudeCodeBackend with actual Claude Code API calls.
5
+ This test outputs the actual stream chunks to verify functionality.
6
+ """
7
+
8
+ import asyncio
9
+ import os
10
+
11
+ from massgen.backend.claude_code import ClaudeCodeBackend
12
+
13
+
14
+ async def test_real_stream_with_tools():
15
+ """Test real streaming with Claude Code API and output stream chunks."""
16
+
17
+ # Check if API key is available
18
+ if not os.getenv("ANTHROPIC_API_KEY"):
19
+ print("❌ ANTHROPIC_API_KEY not found in environment")
20
+ print("Set your API key: export ANTHROPIC_API_KEY=your-key-here")
21
+ return
22
+
23
+ print("🚀 Testing ClaudeCodeBackend with real Claude Code API")
24
+ print("=" * 60)
25
+
26
+ # Initialize backend
27
+ backend = ClaudeCodeBackend()
28
+ print(f"✅ Backend initialized: {backend.get_provider_name()}")
29
+ print(f"📊 Supported tools: {len(backend.get_supported_builtin_tools())} tools")
30
+
31
+ # Test single turn conversation
32
+ print("\n🔄 Testing single turn conversation...")
33
+ messages = [
34
+ {
35
+ "role": "user",
36
+ "content": "Hello! Can you tell me what 2+2 equals and show your calculation?",
37
+ },
38
+ ]
39
+
40
+ try:
41
+ print("\n📨 Sending messages:", messages)
42
+ print("\n📡 Stream chunks received:")
43
+ print("-" * 40)
44
+
45
+ chunk_count = 0
46
+ total_content = ""
47
+
48
+ async for chunk in backend.stream_with_tools(messages, []):
49
+ chunk_count += 1
50
+ print(f"[{chunk_count:2d}] Type: {chunk.type:<20} Source: {chunk.source or 'None':<20}")
51
+
52
+ if chunk.type == "content":
53
+ print(f" Content: {repr(chunk.content)}")
54
+ total_content += chunk.content or ""
55
+ elif chunk.type == "complete_message":
56
+ print(f" Complete message: {chunk.complete_message}")
57
+ elif chunk.type == "complete_response":
58
+ print(f" Response metadata: {chunk.response}")
59
+ elif chunk.type == "agent_status":
60
+ print(f" Status: {chunk.status} - {chunk.content}")
61
+ elif chunk.type == "builtin_tool_results":
62
+ print(f" Tool results: {chunk.builtin_tool_results}")
63
+ elif chunk.type == "tool_calls":
64
+ print(f" Tool calls: {chunk.tool_calls}")
65
+ elif chunk.type == "error":
66
+ print(f" Error: {chunk.error}")
67
+ elif chunk.type == "done":
68
+ print(" ✅ Stream completed")
69
+ break
70
+
71
+ print()
72
+
73
+ print("-" * 40)
74
+ print(f"📊 Total chunks: {chunk_count}")
75
+ print(f"📝 Total content length: {len(total_content)} chars")
76
+ print(f"💰 Token usage: {backend.get_token_usage()}")
77
+ print(f"🔗 Session ID: {backend.get_current_session_id()}")
78
+
79
+ if total_content:
80
+ print(f"\n📄 Complete response:\n{total_content}")
81
+
82
+ except Exception as e:
83
+ print(f"❌ Error during streaming: {e}")
84
+ import traceback
85
+
86
+ traceback.print_exc()
87
+ return
88
+
89
+ # Test multi-turn conversation
90
+ print("\n" + "=" * 60)
91
+ print("🔄 Testing multi-turn conversation...")
92
+
93
+ # Add assistant response to conversation
94
+ messages.append({"role": "assistant", "content": total_content})
95
+
96
+ # Add follow-up question
97
+ messages.append(
98
+ {
99
+ "role": "user",
100
+ "content": "Great! Now can you show me how to calculate the result times 5?",
101
+ },
102
+ )
103
+
104
+ try:
105
+ print("\n📨 Sending multi-turn messages:")
106
+ for i, msg in enumerate(messages):
107
+ print(f" [{i+1}] {msg['role']}: {msg['content'][:100]}{'...' if len(msg['content']) > 100 else ''}")
108
+
109
+ print("\n📡 Stream chunks received:")
110
+ print("-" * 40)
111
+
112
+ chunk_count = 0
113
+ turn2_content = ""
114
+
115
+ async for chunk in backend.stream_with_tools(messages, []):
116
+ chunk_count += 1
117
+ print(f"[{chunk_count:2d}] Type: {chunk.type:<20} Source: {chunk.source or 'None':<20}")
118
+
119
+ if chunk.type == "content":
120
+ print(f" Content: {repr(chunk.content)}")
121
+ turn2_content += chunk.content or ""
122
+ elif chunk.type == "complete_response":
123
+ print(f" Response metadata: {chunk.response}")
124
+ elif chunk.type == "done":
125
+ print(" ✅ Stream completed")
126
+ break
127
+
128
+ print()
129
+
130
+ print("-" * 40)
131
+ print(f"📊 Turn 2 chunks: {chunk_count}")
132
+ print(f"📝 Turn 2 content length: {len(turn2_content)} chars")
133
+ print(f"💰 Cumulative token usage: {backend.get_token_usage()}")
134
+ print(f"🔗 Session ID: {backend.get_current_session_id()}")
135
+
136
+ if turn2_content:
137
+ print(f"\n📄 Turn 2 response:\n{turn2_content}")
138
+
139
+ except Exception as e:
140
+ print(f"❌ Error during multi-turn: {e}")
141
+ import traceback
142
+
143
+ traceback.print_exc()
144
+ return
145
+
146
+ print("\n✅ Multi-turn conversation test completed successfully!")
147
+
148
+
149
+ async def test_with_workflow_tools():
150
+ """Test with MassGen workflow tools."""
151
+
152
+ print("\n" + "=" * 60)
153
+ print("🛠️ Testing with workflow tools...")
154
+
155
+ backend = ClaudeCodeBackend()
156
+
157
+ # Define workflow tools
158
+ workflow_tools = [
159
+ {
160
+ "type": "function",
161
+ "function": {
162
+ "name": "new_answer",
163
+ "description": "Provide an improved answer to the ORIGINAL MESSAGE",
164
+ "parameters": {
165
+ "type": "object",
166
+ "properties": {
167
+ "content": {
168
+ "type": "string",
169
+ "description": "Your improved answer",
170
+ },
171
+ },
172
+ "required": ["content"],
173
+ },
174
+ },
175
+ },
176
+ {
177
+ "type": "function",
178
+ "function": {
179
+ "name": "vote",
180
+ "description": "Vote for the best agent to present final answer",
181
+ "parameters": {
182
+ "type": "object",
183
+ "properties": {
184
+ "agent_id": {
185
+ "type": "string",
186
+ "description": "Agent ID to vote for",
187
+ },
188
+ "reason": {
189
+ "type": "string",
190
+ "description": "Reason for voting",
191
+ },
192
+ },
193
+ "required": ["agent_id", "reason"],
194
+ },
195
+ },
196
+ },
197
+ ]
198
+
199
+ messages = [
200
+ {
201
+ "role": "user",
202
+ "content": "You are participating in a multi-agent workflow. Please provide an answer about the benefits of Python programming, then use the new_answer tool to submit your response.",
203
+ },
204
+ ]
205
+
206
+ try:
207
+ print(f"\n📨 Sending workflow tool message with {len(workflow_tools)} tools")
208
+ print(f"🛠️ Tools: {[t['function']['name'] for t in workflow_tools]}")
209
+
210
+ print("\n📡 Stream chunks received:")
211
+ print("-" * 40)
212
+
213
+ chunk_count = 0
214
+ workflow_content = ""
215
+ detected_tool_calls = []
216
+
217
+ async for chunk in backend.stream_with_tools(messages, workflow_tools):
218
+ chunk_count += 1
219
+ print(f"[{chunk_count:2d}] Type: {chunk.type:<20} Source: {chunk.source or 'None':<20}")
220
+
221
+ if chunk.type == "content":
222
+ print(f" Content: {repr(chunk.content)}")
223
+ workflow_content += chunk.content or ""
224
+ elif chunk.type == "tool_calls":
225
+ print(f" 🛠️ Tool calls detected: {chunk.tool_calls}")
226
+ detected_tool_calls.extend(chunk.tool_calls or [])
227
+ elif chunk.type == "complete_response":
228
+ print(f" Response metadata: {chunk.response}")
229
+ elif chunk.type == "done":
230
+ print(" ✅ Stream completed")
231
+ break
232
+
233
+ print()
234
+
235
+ print("-" * 40)
236
+ print(f"📊 Workflow chunks: {chunk_count}")
237
+ print(f"📝 Workflow content length: {len(workflow_content)} chars")
238
+ print(f"🛠️ Detected tool calls: {len(detected_tool_calls)}")
239
+ for i, tool_call in enumerate(detected_tool_calls):
240
+ print(f" [{i+1}] {tool_call.get('function', {}).get('name', 'unknown')}: {tool_call}")
241
+ print(f"💰 Token usage: {backend.get_token_usage()}")
242
+
243
+ if workflow_content:
244
+ print(f"\n📄 Workflow response:\n{workflow_content}")
245
+
246
+ except Exception as e:
247
+ print(f"❌ Error during workflow test: {e}")
248
+ import traceback
249
+
250
+ traceback.print_exc()
251
+ return
252
+
253
+ print("\n✅ Workflow tools test completed!")
254
+
255
+
256
+ async def main():
257
+ """Run all real tests."""
258
+ print("🧪 ClaudeCodeBackend Real API Tests")
259
+ print("=" * 60)
260
+
261
+ await test_real_stream_with_tools()
262
+ await test_with_workflow_tools()
263
+
264
+ print("\n🎉 All tests completed!")
265
+
266
+
267
+ if __name__ == "__main__":
268
+ asyncio.run(main())