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
@@ -1,14 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ import json
1
3
  import logging
2
4
  import threading
3
5
  import time
4
- import json
5
6
  from collections import Counter
6
- from datetime import datetime
7
- from typing import Any, Optional, Dict, List
8
7
  from concurrent.futures import ThreadPoolExecutor
8
+ from datetime import datetime
9
+ from typing import Any, Dict, List, Optional
9
10
 
10
- from .types import SystemState, AgentState, TaskInput, VoteRecord
11
11
  from .logging import get_log_manager
12
+ from .types import AgentState, SystemState, TaskInput, VoteRecord
12
13
 
13
14
  # Set up logging
14
15
  logger = logging.getLogger(__name__)
@@ -84,9 +85,7 @@ class MassOrchestrator:
84
85
 
85
86
  def _log_event(self, event_type: str, data: Dict[str, Any]):
86
87
  """Log an orchestrator event."""
87
- self.communication_log.append(
88
- {"timestamp": time.time(), "event_type": event_type, "data": data}
89
- )
88
+ self.communication_log.append({"timestamp": time.time(), "event_type": event_type, "data": data})
90
89
 
91
90
  def update_agent_answer(self, agent_id: int, answer: str):
92
91
  """
@@ -104,9 +103,7 @@ class MassOrchestrator:
104
103
  self.agent_states[agent_id].add_update(answer)
105
104
 
106
105
  preview = answer[:100] + "..." if len(answer) > 100 else answer
107
- print(
108
- f"📝 Agent {agent_id} answer updated ({old_answer_length} → {len(answer)} chars)"
109
- )
106
+ print(f"📝 Agent {agent_id} answer updated ({old_answer_length} → {len(answer)} chars)")
110
107
  print(f" 🔍 {preview}")
111
108
 
112
109
  # Log to the comprehensive logging system
@@ -153,9 +150,7 @@ class MassOrchestrator:
153
150
  """Get current voting status and distribution."""
154
151
  vote_counts = self._get_current_vote_counts()
155
152
  total_agents = len(self.agents)
156
- failed_agents = len(
157
- [s for s in self.agent_states.values() if s.status == "failed"]
158
- )
153
+ failed_agents = len([s for s in self.agent_states.values() if s.status == "failed"])
159
154
  votable_agents = total_agents - failed_agents
160
155
  voted_agents = self._get_current_voted_agents_count()
161
156
 
@@ -165,9 +160,7 @@ class MassOrchestrator:
165
160
  "failed_agents": failed_agents,
166
161
  "votable_agents": votable_agents,
167
162
  "voted_agents": voted_agents,
168
- "votes_needed_for_consensus": max(
169
- 1, int(votable_agents * self.consensus_threshold)
170
- ),
163
+ "votes_needed_for_consensus": max(1, int(votable_agents * self.consensus_threshold)),
171
164
  "leading_agent": vote_counts.most_common(1)[0] if vote_counts else None,
172
165
  }
173
166
 
@@ -181,19 +174,13 @@ class MassOrchestrator:
181
174
  "status": state.status,
182
175
  "update_times": len(state.updated_answers),
183
176
  "chat_round": state.chat_round,
184
- "vote_target": (
185
- state.curr_vote.target_id if state.curr_vote else None
186
- ),
177
+ "vote_target": (state.curr_vote.target_id if state.curr_vote else None),
187
178
  "execution_time": state.execution_time,
188
179
  }
189
180
  for agent_id, state in self.agent_states.items()
190
181
  },
191
182
  "voting_status": self._get_voting_status(),
192
- "runtime": (
193
- (time.time() - self.system_state.start_time)
194
- if self.system_state.start_time
195
- else 0
196
- ),
183
+ "runtime": ((time.time() - self.system_state.start_time) if self.system_state.start_time else 0),
197
184
  }
198
185
 
199
186
  def cast_vote(self, voter_id: int, target_id: int, reason: str = ""):
@@ -208,9 +195,7 @@ class MassOrchestrator:
208
195
  with self._lock:
209
196
  logger.info(f"🗳️ VOTING: Agent {voter_id} casting vote")
210
197
 
211
- print(
212
- f"🗳️ VOTE: Agent {voter_id} → Agent {target_id} ({self.system_state.phase})"
213
- )
198
+ print(f"🗳️ VOTE: Agent {voter_id} → Agent {target_id} ({self.system_state.phase})")
214
199
  if reason:
215
200
  print(f" 📝 Voting reason: {len(reason)} chars")
216
201
 
@@ -225,9 +210,7 @@ class MassOrchestrator:
225
210
  previous_vote = self.agent_states[voter_id].curr_vote
226
211
  # Log vote change type
227
212
  if previous_vote:
228
- logger.info(
229
- f" 🔄 Agent {voter_id} changed vote from Agent {previous_vote.target_id} to Agent {target_id}"
230
- )
213
+ logger.info(f" 🔄 Agent {voter_id} changed vote from Agent {previous_vote.target_id} to Agent {target_id}")
231
214
  else:
232
215
  logger.info(f" ✨ Agent {voter_id} new vote for Agent {target_id}")
233
216
 
@@ -252,20 +235,14 @@ class MassOrchestrator:
252
235
  # Update streaming display
253
236
  if self.streaming_orchestrator:
254
237
  self.streaming_orchestrator.update_agent_status(voter_id, "voted")
255
- self.streaming_orchestrator.update_agent_vote_target(
256
- voter_id, target_id
257
- )
238
+ self.streaming_orchestrator.update_agent_vote_target(voter_id, target_id)
258
239
  # Update agent update count
259
240
  update_count = len(self.agent_states[voter_id].updated_answers)
260
- self.streaming_orchestrator.update_agent_update_count(
261
- voter_id, update_count
262
- )
241
+ self.streaming_orchestrator.update_agent_update_count(voter_id, update_count)
263
242
  # Update vote cast counts for all agents
264
243
  for agent_id, agent_state in self.agent_states.items():
265
244
  vote_cast_count = len(agent_state.cast_votes)
266
- self.streaming_orchestrator.update_agent_votes_cast(
267
- agent_id, vote_cast_count
268
- )
245
+ self.streaming_orchestrator.update_agent_votes_cast(agent_id, vote_cast_count)
269
246
  vote_counts = self._get_current_vote_counts()
270
247
  self.streaming_orchestrator.update_vote_distribution(dict(vote_counts))
271
248
  vote_msg = f"👍 Agent {voter_id} voted for Agent {target_id}"
@@ -291,18 +268,14 @@ class MassOrchestrator:
291
268
  vote_counts = self._get_current_vote_counts()
292
269
  voted_agents_count = self._get_current_voted_agents_count()
293
270
  logger.info(f" 📊 Vote distribution: {dict(vote_counts)}")
294
- logger.info(
295
- f" 📈 Voting progress: {voted_agents_count}/{len(self.agent_states)} agents voted"
296
- )
271
+ logger.info(f" 📈 Voting progress: {voted_agents_count}/{len(self.agent_states)} agents voted")
297
272
 
298
273
  # Calculate consensus requirements
299
274
  total_agents = len(self.agent_states)
300
275
  votes_needed = max(1, int(total_agents * self.consensus_threshold))
301
276
  if vote_counts:
302
277
  leading_agent, leading_votes = vote_counts.most_common(1)[0]
303
- logger.info(
304
- f" 🏆 Leading: Agent {leading_agent} with {leading_votes} votes (need {votes_needed} for consensus)"
305
- )
278
+ logger.info(f" 🏆 Leading: Agent {leading_agent} with {leading_votes} votes (need {votes_needed} for consensus)")
306
279
 
307
280
  # Log event for internal tracking
308
281
  self._log_event(
@@ -332,18 +305,15 @@ class MassOrchestrator:
332
305
  self.streaming_orchestrator.add_system_message(answer_msg)
333
306
  # Update agent update count
334
307
  update_count = len(self.agent_states[agent_id].updated_answers)
335
- self.streaming_orchestrator.update_agent_update_count(
336
- agent_id, update_count
337
- )
308
+ self.streaming_orchestrator.update_agent_update_count(agent_id, update_count)
338
309
 
339
310
  # CRITICAL FIX: Restart voted agents when any agent shares new updates
340
311
  with self._lock:
341
312
  restarted_agents = []
342
- current_time = time.time()
313
+ time.time()
343
314
 
344
315
  for other_agent_id, state in self.agent_states.items():
345
316
  if other_agent_id != agent_id and state.status == "voted":
346
-
347
317
  # Restart the voted agent
348
318
  state.status = "working"
349
319
  # This vote should be cleared as answers have been updated
@@ -351,28 +321,16 @@ class MassOrchestrator:
351
321
  state.execution_start_time = time.time()
352
322
  restarted_agents.append(other_agent_id)
353
323
 
354
- logger.info(
355
- f"🔄 Agent {other_agent_id} restarted due to update from Agent {agent_id}"
356
- )
324
+ logger.info(f"🔄 Agent {other_agent_id} restarted due to update from Agent {agent_id}")
357
325
 
358
326
  # Update streaming display
359
327
  if self.streaming_orchestrator:
360
- self.streaming_orchestrator.update_agent_status(
361
- other_agent_id, "working"
362
- )
363
- self.streaming_orchestrator.update_agent_vote_target(
364
- other_agent_id, None
365
- ) # Clear vote target in display
328
+ self.streaming_orchestrator.update_agent_status(other_agent_id, "working")
329
+ self.streaming_orchestrator.update_agent_vote_target(other_agent_id, None) # Clear vote target in display
366
330
  # Update agent update count for restarted agent
367
- update_count = len(
368
- self.agent_states[other_agent_id].updated_answers
369
- )
370
- self.streaming_orchestrator.update_agent_update_count(
371
- other_agent_id, update_count
372
- )
373
- restart_msg = (
374
- f"🔄 Agent {other_agent_id} restarted due to new update"
375
- )
331
+ update_count = len(self.agent_states[other_agent_id].updated_answers)
332
+ self.streaming_orchestrator.update_agent_update_count(other_agent_id, update_count)
333
+ restart_msg = f"🔄 Agent {other_agent_id} restarted due to new update"
376
334
  self.streaming_orchestrator.add_system_message(restart_msg)
377
335
 
378
336
  # Log agent restart
@@ -391,15 +349,11 @@ class MassOrchestrator:
391
349
  # Update vote distribution in streaming display
392
350
  if self.streaming_orchestrator:
393
351
  vote_counts = self._get_current_vote_counts()
394
- self.streaming_orchestrator.update_vote_distribution(
395
- dict(vote_counts)
396
- )
352
+ self.streaming_orchestrator.update_vote_distribution(dict(vote_counts))
397
353
  # Update vote cast counts for all agents to ensure accuracy
398
354
  for agent_id, agent_state in self.agent_states.items():
399
355
  vote_cast_count = len(agent_state.cast_votes)
400
- self.streaming_orchestrator.update_agent_votes_cast(
401
- agent_id, vote_cast_count
402
- )
356
+ self.streaming_orchestrator.update_agent_votes_cast(agent_id, vote_cast_count)
403
357
 
404
358
  return restarted_agents
405
359
 
@@ -410,9 +364,7 @@ class MassOrchestrator:
410
364
  """
411
365
  with self._lock:
412
366
  total_agents = len(self.agents)
413
- failed_agents_count = len(
414
- [s for s in self.agent_states.values() if s.status == "failed"]
415
- )
367
+ failed_agents_count = len([s for s in self.agent_states.values() if s.status == "failed"])
416
368
  votable_agents_count = total_agents - failed_agents_count
417
369
 
418
370
  # Edge case: no votable agents
@@ -422,18 +374,10 @@ class MassOrchestrator:
422
374
 
423
375
  # Edge case: only one votable agent
424
376
  if votable_agents_count == 1:
425
- working_agents = [
426
- aid
427
- for aid, state in self.agent_states.items()
428
- if state.status == "working"
429
- ]
377
+ working_agents = [aid for aid, state in self.agent_states.items() if state.status == "working"]
430
378
  if not working_agents: # The single agent has voted
431
379
  # Find the single votable agent
432
- votable_agent = [
433
- aid
434
- for aid, state in self.agent_states.items()
435
- if state.status != "failed"
436
- ][0]
380
+ votable_agent = [aid for aid, state in self.agent_states.items() if state.status != "failed"][0]
437
381
  logger.info(f"🎯 Single agent consensus: Agent {votable_agent}")
438
382
  self._reach_consensus(votable_agent)
439
383
  return True
@@ -448,14 +392,10 @@ class MassOrchestrator:
448
392
 
449
393
  # Ensure the winning agent is still votable (not failed)
450
394
  if self.agent_states[winning_agent_id].status == "failed":
451
- logger.warning(
452
- f"⚠️ Winning agent {winning_agent_id} has failed - recalculating"
453
- )
395
+ logger.warning(f"⚠️ Winning agent {winning_agent_id} has failed - recalculating")
454
396
  return False
455
397
 
456
- logger.info(
457
- f"✅ Consensus reached: Agent {winning_agent_id} with {winning_votes}/{votable_agents_count} votes"
458
- )
398
+ logger.info(f"✅ Consensus reached: Agent {winning_agent_id} with {winning_votes}/{votable_agents_count} votes")
459
399
  self._reach_consensus(winning_agent_id)
460
400
  return True
461
401
 
@@ -487,11 +427,7 @@ class MassOrchestrator:
487
427
  # Update streaming display
488
428
  if self.streaming_orchestrator:
489
429
  self.streaming_orchestrator.update_agent_status(agent_id, "failed")
490
- failure_msg = (
491
- f"💥 Agent {agent_id} failed: {reason}"
492
- if reason
493
- else f"💥 Agent {agent_id} failed"
494
- )
430
+ failure_msg = f"💥 Agent {agent_id} failed: {reason}" if reason else f"💥 Agent {agent_id} failed"
495
431
  self.streaming_orchestrator.add_system_message(failure_msg)
496
432
 
497
433
  # Log to the comprehensive logging system
@@ -515,13 +451,9 @@ class MassOrchestrator:
515
451
  )
516
452
 
517
453
  # Show current agent status distribution
518
- status_counts = Counter(
519
- state.status for state in self.agent_states.values()
520
- )
454
+ status_counts = Counter(state.status for state in self.agent_states.values())
521
455
  logger.info(f" 📊 Status distribution: {dict(status_counts)}")
522
- logger.info(
523
- f" 📈 Failed agents: {status_counts.get('failed', 0)}/{len(self.agent_states)} total"
524
- )
456
+ logger.info(f" 📈 Failed agents: {status_counts.get('failed', 0)}/{len(self.agent_states)} total")
525
457
 
526
458
  def _reach_consensus(self, winning_agent_id: int):
527
459
  """Mark consensus as reached and finalize the system."""
@@ -533,9 +465,7 @@ class MassOrchestrator:
533
465
  # Update streaming orchestrator if available
534
466
  if self.streaming_orchestrator:
535
467
  vote_distribution = dict(self._get_current_vote_counts())
536
- self.streaming_orchestrator.update_consensus_status(
537
- winning_agent_id, vote_distribution
538
- )
468
+ self.streaming_orchestrator.update_consensus_status(winning_agent_id, vote_distribution)
539
469
  self.streaming_orchestrator.update_phase(old_phase, "consensus")
540
470
 
541
471
  # Log to the comprehensive logging system
@@ -573,31 +503,17 @@ class MassOrchestrator:
573
503
  """
574
504
  session_log = {
575
505
  "session_metadata": {
576
- "session_id": (
577
- f"mass_session_{int(self.system_state.start_time)}"
578
- if self.system_state.start_time
579
- else None
580
- ),
506
+ "session_id": (f"mass_session_{int(self.system_state.start_time)}" if self.system_state.start_time else None),
581
507
  "start_time": self.system_state.start_time,
582
508
  "end_time": self.system_state.end_time,
583
- "total_duration": (
584
- (self.system_state.end_time - self.system_state.start_time)
585
- if self.system_state.start_time and self.system_state.end_time
586
- else None
587
- ),
509
+ "total_duration": ((self.system_state.end_time - self.system_state.start_time) if self.system_state.start_time and self.system_state.end_time else None),
588
510
  "timestamp": datetime.now().isoformat(),
589
511
  "system_version": "MassGen v1.0",
590
512
  },
591
513
  "task_information": {
592
- "question": (
593
- self.system_state.task.question if self.system_state.task else None
594
- ),
595
- "task_id": (
596
- self.system_state.task.task_id if self.system_state.task else None
597
- ),
598
- "context": (
599
- self.system_state.task.context if self.system_state.task else None
600
- ),
514
+ "question": (self.system_state.task.question if self.system_state.task else None),
515
+ "task_id": (self.system_state.task.task_id if self.system_state.task else None),
516
+ "context": (self.system_state.task.context if self.system_state.task else None),
601
517
  },
602
518
  "system_configuration": {
603
519
  "max_duration": self.max_duration,
@@ -611,9 +527,7 @@ class MassOrchestrator:
611
527
  "updates_count": len(state.updated_answers),
612
528
  "chat_length": len(state.chat_history),
613
529
  "chat_round": state.chat_round,
614
- "vote_target": (
615
- state.curr_vote.target_id if state.curr_vote else None
616
- ),
530
+ "vote_target": (state.curr_vote.target_id if state.curr_vote else None),
617
531
  "execution_time": state.execution_time,
618
532
  "execution_start_time": state.execution_start_time,
619
533
  "execution_end_time": state.execution_end_time,
@@ -651,10 +565,7 @@ class MassOrchestrator:
651
565
  {
652
566
  "timestamp": entry["timestamp"],
653
567
  "event_type": entry["event_type"],
654
- "data_summary": {
655
- k: (len(v) if isinstance(v, (str, list, dict)) else v)
656
- for k, v in entry["data"].items()
657
- },
568
+ "data_summary": {k: (len(v) if isinstance(v, (str, list, dict)) else v) for k, v in entry["data"].items()},
658
569
  }
659
570
  for entry in self.communication_log
660
571
  ],
@@ -711,9 +622,7 @@ class MassOrchestrator:
711
622
  init_msg = f"🚀 Starting MassGen task with {len(self.agents)} agents"
712
623
  self.streaming_orchestrator.add_system_message(init_msg)
713
624
 
714
- self._log_event(
715
- "task_started", {"task_id": task.task_id, "question": task.question}
716
- )
625
+ self._log_event("task_started", {"task_id": task.task_id, "question": task.question})
717
626
  logger.info("✅ Task initialization completed successfully")
718
627
 
719
628
  # Run the workflow
@@ -764,17 +673,13 @@ class MassOrchestrator:
764
673
  self.streaming_orchestrator.update_debate_rounds(debate_rounds)
765
674
 
766
675
  if debate_rounds > self.max_debate_rounds:
767
- logger.warning(
768
- f"⚠️ Maximum debate rounds ({self.max_debate_rounds}) reached"
769
- )
676
+ logger.warning(f"⚠️ Maximum debate rounds ({self.max_debate_rounds}) reached")
770
677
  self._force_consensus_by_timeout()
771
678
  # Representative will present final answer
772
679
  self._present_final_answer(task)
773
680
  break
774
681
 
775
- logger.info(
776
- f"🗣️ No consensus - starting debate round {debate_rounds}"
777
- )
682
+ logger.info(f"🗣️ No consensus - starting debate round {debate_rounds}")
778
683
  # Add debate instruction to the chat history and will be restarted in the next round
779
684
  self._restart_all_agents_for_debate()
780
685
  else:
@@ -795,9 +700,7 @@ class MassOrchestrator:
795
700
  # Start all working agents
796
701
  for agent_id in self.agents.keys():
797
702
  if self.agent_states[agent_id].status not in ["failed"]:
798
- self._start_agent_if_working(
799
- agent_id, task, executor, active_futures
800
- )
703
+ self._start_agent_if_working(agent_id, task, executor, active_futures)
801
704
 
802
705
  # Monitor agents and handle restarts
803
706
  while active_futures and not self._all_agents_voted():
@@ -819,13 +722,8 @@ class MassOrchestrator:
819
722
 
820
723
  # Check for agents that need to restart (status changed back to "working")
821
724
  for agent_id in self.agents.keys():
822
- if (
823
- agent_id not in active_futures
824
- and self.agent_states[agent_id].status == "working"
825
- ):
826
- self._start_agent_if_working(
827
- agent_id, task, executor, active_futures
828
- )
725
+ if agent_id not in active_futures and self.agent_states[agent_id].status == "working":
726
+ self._start_agent_if_working(agent_id, task, executor, active_futures)
829
727
 
830
728
  time.sleep(0.1) # Small delay to prevent busy waiting
831
729
 
@@ -843,11 +741,7 @@ class MassOrchestrator:
843
741
  active_futures: Dict,
844
742
  ):
845
743
  """Start an agent if it's in working status and not already running."""
846
- if (
847
- self.agent_states[agent_id].status == "working"
848
- and agent_id not in active_futures
849
- ):
850
-
744
+ if self.agent_states[agent_id].status == "working" and agent_id not in active_futures:
851
745
  self.agent_states[agent_id].execution_start_time = time.time()
852
746
  future = executor.submit(self._run_single_agent, agent_id, task)
853
747
  active_futures[agent_id] = future
@@ -868,18 +762,12 @@ class MassOrchestrator:
868
762
 
869
763
  # Update streaming display with chat round
870
764
  if self.streaming_orchestrator:
871
- self.streaming_orchestrator.update_agent_chat_round(
872
- agent_id, agent.state.chat_round
873
- )
765
+ self.streaming_orchestrator.update_agent_chat_round(agent_id, agent.state.chat_round)
874
766
  # Update agent update count
875
767
  update_count = len(self.agent_states[agent_id].updated_answers)
876
- self.streaming_orchestrator.update_agent_update_count(
877
- agent_id, update_count
878
- )
768
+ self.streaming_orchestrator.update_agent_update_count(agent_id, update_count)
879
769
 
880
- logger.info(
881
- f"✅ Agent {agent_id} completed work with status: {self.agent_states[agent_id].status}"
882
- )
770
+ logger.info(f"✅ Agent {agent_id} completed work with status: {self.agent_states[agent_id].status}")
883
771
 
884
772
  except Exception as e:
885
773
  logger.error(f"❌ Agent {agent_id} failed: {e}")
@@ -887,14 +775,8 @@ class MassOrchestrator:
887
775
 
888
776
  def _all_agents_voted(self) -> bool:
889
777
  """Check if all votable agents have voted."""
890
- votable_agents = [
891
- aid
892
- for aid, state in self.agent_states.items()
893
- if state.status not in ["failed"]
894
- ]
895
- voted_agents = [
896
- aid for aid, state in self.agent_states.items() if state.status == "voted"
897
- ]
778
+ votable_agents = [aid for aid, state in self.agent_states.items() if state.status not in ["failed"]]
779
+ voted_agents = [aid for aid, state in self.agent_states.items() if state.status == "voted"]
898
780
 
899
781
  return len(voted_agents) == len(votable_agents) and len(votable_agents) > 0
900
782
 
@@ -906,16 +788,11 @@ class MassOrchestrator:
906
788
  logger.info("🔄 Restarting all agents for debate")
907
789
 
908
790
  with self._lock:
909
-
910
791
  # Update streaming display
911
792
  if self.streaming_orchestrator:
912
793
  self.streaming_orchestrator.reset_consensus()
913
- self.streaming_orchestrator.update_phase(
914
- self.system_state.phase, "collaboration"
915
- )
916
- self.streaming_orchestrator.add_system_message(
917
- "🗣️ Starting debate phase - no consensus reached"
918
- )
794
+ self.streaming_orchestrator.update_phase(self.system_state.phase, "collaboration")
795
+ self.streaming_orchestrator.add_system_message("🗣️ Starting debate phase - no consensus reached")
919
796
 
920
797
  # Log debate start
921
798
  if self.log_manager:
@@ -933,16 +810,14 @@ class MassOrchestrator:
933
810
  # Note: We don't clear self.votes as it's a historical record
934
811
  for agent_id, state in self.agent_states.items():
935
812
  if state.status not in ["failed"]:
936
- old_status = state.status
813
+ state.status
937
814
  state.status = "working"
938
815
  # We don't clear vote target when restarting for debate
939
816
  # state.curr_vote = None
940
817
 
941
818
  # Update streaming display for each agent
942
819
  if self.streaming_orchestrator:
943
- self.streaming_orchestrator.update_agent_status(
944
- agent_id, "working"
945
- )
820
+ self.streaming_orchestrator.update_agent_status(agent_id, "working")
946
821
 
947
822
  # Log agent restart
948
823
  if self.log_manager:
@@ -983,7 +858,7 @@ class MassOrchestrator:
983
858
  {
984
859
  "role": "system",
985
860
  "content": """
986
- You are given a task and multiple agents' answers and their votes.
861
+ You are given a task and multiple agents' answers and their votes.
987
862
  Please incorporate these information and provide a final BEST answer to the original message.
988
863
  """,
989
864
  },
@@ -1022,22 +897,12 @@ The final answer must be self-contained, complete, well-sourced, compelling, and
1022
897
  if vote_counts:
1023
898
  # Select agent with most votes
1024
899
  winning_agent_id = vote_counts.most_common(1)[0][0]
1025
- logger.info(
1026
- f" Selected Agent {winning_agent_id} with {vote_counts[winning_agent_id]} votes"
1027
- )
900
+ logger.info(f" Selected Agent {winning_agent_id} with {vote_counts[winning_agent_id]} votes")
1028
901
  else:
1029
902
  # No votes - select first working agent
1030
- working_agents = [
1031
- aid
1032
- for aid, state in self.agent_states.items()
1033
- if state.status == "working"
1034
- ]
1035
- winning_agent_id = (
1036
- working_agents[0] if working_agents else list(self.agents.keys())[0]
1037
- )
1038
- logger.info(
1039
- f" No votes - selected Agent {winning_agent_id} as fallback"
1040
- )
903
+ working_agents = [aid for aid, state in self.agent_states.items() if state.status == "working"]
904
+ winning_agent_id = working_agents[0] if working_agents else list(self.agents.keys())[0]
905
+ logger.info(f" No votes - selected Agent {winning_agent_id} as fallback")
1041
906
 
1042
907
  self._reach_consensus(winning_agent_id)
1043
908
 
@@ -1051,11 +916,7 @@ The final answer must be self-contained, complete, well-sourced, compelling, and
1051
916
  if not self.system_state.end_time:
1052
917
  self.system_state.end_time = time.time()
1053
918
 
1054
- session_duration = (
1055
- self.system_state.end_time - self.system_state.start_time
1056
- if self.system_state.start_time
1057
- else 0
1058
- )
919
+ session_duration = self.system_state.end_time - self.system_state.start_time if self.system_state.start_time else 0
1059
920
 
1060
921
  # Save final agent states to files
1061
922
  if self.log_manager:
@@ -1066,7 +927,7 @@ The final answer must be self-contained, complete, well-sourced, compelling, and
1066
927
  "consensus_reached": self.system_state.consensus_reached,
1067
928
  "representative_agent_id": self.system_state.representative_agent_id,
1068
929
  "session_duration": session_duration,
1069
- }
930
+ },
1070
931
  )
1071
932
 
1072
933
  # Prepare clean, user-facing result
@@ -1077,9 +938,7 @@ The final answer must be self-contained, complete, well-sourced, compelling, and
1077
938
  "session_duration": session_duration,
1078
939
  "summary": {
1079
940
  "total_agents": len(self.agents),
1080
- "failed_agents": len(
1081
- [s for s in self.agent_states.values() if s.status == "failed"]
1082
- ),
941
+ "failed_agents": len([s for s in self.agent_states.values() if s.status == "failed"]),
1083
942
  "total_votes": len(self.votes),
1084
943
  "final_vote_distribution": dict(self._get_current_vote_counts()),
1085
944
  },