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,7 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ import copy
1
3
  import os
2
- import threading
3
4
  import time
4
- import json
5
+
6
+ from dotenv import load_dotenv
7
+
8
+ from massgen.v1.types import AgentResponse
9
+ from massgen.v1.utils import generate_random_id
10
+
11
+ load_dotenv()
5
12
 
6
13
  try:
7
14
  from google import genai
@@ -15,28 +22,12 @@ except ImportError:
15
22
  class genai:
16
23
  @staticmethod
17
24
  def configure(**kwargs):
18
- raise ImportError(
19
- "Google genai package not installed. Install with: pip install google-genai"
20
- )
25
+ raise ImportError("Google genai package not installed. Install with: pip install google-genai")
21
26
 
22
27
  class types:
23
28
  pass
24
29
 
25
30
 
26
- from dotenv import load_dotenv
27
- import copy
28
-
29
- load_dotenv()
30
-
31
- # Import utility functions and tools
32
- from massgen.v1.utils import (
33
- function_to_json,
34
- execute_function_calls,
35
- generate_random_id,
36
- )
37
- from massgen.v1.types import AgentResponse
38
-
39
-
40
31
  def add_citations_to_response(response):
41
32
  text = response.text
42
33
 
@@ -82,7 +73,6 @@ def parse_completion(completion, add_citations=True):
82
73
  code = []
83
74
  citations = []
84
75
  function_calls = []
85
- reasoning_items = []
86
76
 
87
77
  # Handle response from the official SDK
88
78
  # Always parse candidates.content.parts for complete information
@@ -96,50 +86,31 @@ def parse_completion(completion, add_citations=True):
96
86
  text += part.text
97
87
  # Handle executable code parts
98
88
  elif hasattr(part, "executable_code") and part.executable_code:
99
- if (
100
- hasattr(part.executable_code, "code")
101
- and part.executable_code.code
102
- ):
89
+ if hasattr(part.executable_code, "code") and part.executable_code.code:
103
90
  code.append(part.executable_code.code)
104
- elif hasattr(part.executable_code, "language") and hasattr(
105
- part.executable_code, "code"
106
- ):
91
+ elif hasattr(part.executable_code, "language") and hasattr(part.executable_code, "code"):
107
92
  # Alternative format for executable code
108
93
  code.append(part.executable_code.code)
109
94
  # Handle code execution results
110
- elif (
111
- hasattr(part, "code_execution_result")
112
- and part.code_execution_result
113
- ):
114
- if (
115
- hasattr(part.code_execution_result, "output")
116
- and part.code_execution_result.output
117
- ):
95
+ elif hasattr(part, "code_execution_result") and part.code_execution_result:
96
+ if hasattr(part.code_execution_result, "output") and part.code_execution_result.output:
118
97
  # Add execution result as text output
119
- text += (
120
- f"\n[Code Output]\n{part.code_execution_result.output}\n"
121
- )
98
+ text += f"\n[Code Output]\n{part.code_execution_result.output}\n"
122
99
  # Handle function calls
123
100
  elif hasattr(part, "function_call"):
124
101
  if part.function_call:
125
102
  # Extract function name and arguments
126
103
  func_name = getattr(part.function_call, "name", "unknown")
127
104
  func_args = {}
128
- call_id = getattr(
129
- part.function_call, "id", generate_random_id()
130
- )
131
- if (
132
- hasattr(part.function_call, "args")
133
- and part.function_call.args
134
- ):
105
+ call_id = getattr(part.function_call, "id", generate_random_id())
106
+ if hasattr(part.function_call, "args") and part.function_call.args:
135
107
  # Convert args to dict if it's a struct/object
136
108
  if hasattr(part.function_call.args, "_pb"):
137
109
  # It's a protobuf struct, need to convert to dict
138
- import json
139
110
 
140
111
  try:
141
112
  func_args = dict(part.function_call.args)
142
- except:
113
+ except Exception:
143
114
  func_args = {}
144
115
  else:
145
116
  func_args = part.function_call.args
@@ -150,7 +121,7 @@ def parse_completion(completion, add_citations=True):
150
121
  "call_id": call_id,
151
122
  "name": func_name,
152
123
  "arguments": func_args,
153
- }
124
+ },
154
125
  )
155
126
  # Handle function responses
156
127
  elif hasattr(part, "function_response"):
@@ -175,15 +146,9 @@ def parse_completion(completion, add_citations=True):
175
146
  citations.append(citation)
176
147
 
177
148
  # Handle search entry point (if available)
178
- if (
179
- hasattr(grounding, "search_entry_point")
180
- and grounding.search_entry_point
181
- ):
149
+ if hasattr(grounding, "search_entry_point") and grounding.search_entry_point:
182
150
  entry_point = grounding.search_entry_point
183
- if (
184
- hasattr(entry_point, "rendered_content")
185
- and entry_point.rendered_content
186
- ):
151
+ if hasattr(entry_point, "rendered_content") and entry_point.rendered_content:
187
152
  # Add search summary to citations if available
188
153
  pass
189
154
 
@@ -194,9 +159,7 @@ def parse_completion(completion, add_citations=True):
194
159
  except Exception as e:
195
160
  print(f"[GEMINI] Error adding citations to text: {e}")
196
161
 
197
- return AgentResponse(
198
- text=text, code=code, citations=citations, function_calls=function_calls
199
- )
162
+ return AgentResponse(text=text, code=code, citations=citations, function_calls=function_calls)
200
163
 
201
164
 
202
165
  def process_message(
@@ -255,25 +218,17 @@ def process_message(
255
218
  if role == "system":
256
219
  system_instruction = content
257
220
  elif role == "user":
258
- gemini_messages.append(
259
- types.Content(role="user", parts=[types.Part(text=content)])
260
- )
221
+ gemini_messages.append(types.Content(role="user", parts=[types.Part(text=content)]))
261
222
  elif role == "assistant":
262
- gemini_messages.append(
263
- types.Content(role="model", parts=[types.Part(text=content)])
264
- )
223
+ gemini_messages.append(types.Content(role="model", parts=[types.Part(text=content)]))
265
224
  elif message.get("type", None) == "function_call":
266
225
  function_calls[message["call_id"]] = message
267
226
  elif message.get("type", None) == "function_call_output":
268
227
  func_name = function_calls[message["call_id"]]["name"]
269
228
  func_resp = message["output"]
270
- function_response_part = types.Part.from_function_response(
271
- name=func_name, response={"result": func_resp}
272
- )
229
+ function_response_part = types.Part.from_function_response(name=func_name, response={"result": func_resp})
273
230
  # Append the function response
274
- gemini_messages.append(
275
- types.Content(role="user", parts=[function_response_part])
276
- )
231
+ gemini_messages.append(types.Content(role="user", parts=[function_response_part]))
277
232
 
278
233
  # Set up generation config
279
234
  generation_config = {}
@@ -296,9 +251,7 @@ def process_message(
296
251
  gemini_tools.append(types.Tool(google_search=types.GoogleSearch()))
297
252
  has_native_tools = True
298
253
  elif "code_execution" == tool:
299
- gemini_tools.append(
300
- types.Tool(code_execution=types.ToolCodeExecution())
301
- )
254
+ gemini_tools.append(types.Tool(code_execution=types.ToolCodeExecution()))
302
255
  has_native_tools = True
303
256
  else:
304
257
  # Collect custom function declarations
@@ -312,9 +265,7 @@ def process_message(
312
265
  custom_functions.append(function_declaration)
313
266
 
314
267
  if custom_functions and has_native_tools:
315
- print(
316
- f"[WARNING] Gemini API doesn't support combining native tools with custom functions. Prioritizing built-in tools."
317
- )
268
+ print("[WARNING] Gemini API doesn't support combining native tools with custom functions. Prioritizing built-in tools.")
318
269
  elif custom_functions and not has_native_tools:
319
270
  # add custom functions to the tools
320
271
  gemini_tools.append(types.Tool(function_declarations=custom_functions))
@@ -343,15 +294,11 @@ def process_message(
343
294
  request_params = {
344
295
  "model": model,
345
296
  "contents": gemini_messages,
346
- "config": types.GenerateContentConfig(
347
- safety_settings=safety_settings, **generation_config
348
- ),
297
+ "config": types.GenerateContentConfig(safety_settings=safety_settings, **generation_config),
349
298
  }
350
299
 
351
300
  if system_instruction:
352
- request_params["config"].system_instruction = types.Content(
353
- parts=[types.Part(text=system_instruction)]
354
- )
301
+ request_params["config"].system_instruction = types.Content(parts=[types.Part(text=system_instruction)])
355
302
 
356
303
  if gemini_tools:
357
304
  request_params["config"].tools = gemini_tools
@@ -370,12 +317,9 @@ def process_message(
370
317
 
371
318
  # Code streaming tracking
372
319
  code_lines_shown = 0
373
- current_code_chunk = ""
374
320
  truncation_message_sent = False # Track if truncation message was sent
375
321
 
376
- stream_response = client.models.generate_content_stream(
377
- **request_params
378
- )
322
+ stream_response = client.models.generate_content_stream(**request_params)
379
323
 
380
324
  for chunk in stream_response:
381
325
  # Handle text chunks - be very careful to avoid duplication
@@ -394,15 +338,9 @@ def process_message(
394
338
  # Only process candidates if we haven't already processed text from chunk.text
395
339
  elif hasattr(chunk, "candidates") and chunk.candidates:
396
340
  candidate = chunk.candidates[0]
397
- if hasattr(candidate, "content") and hasattr(
398
- candidate.content, "parts"
399
- ):
341
+ if hasattr(candidate, "content") and hasattr(candidate.content, "parts"):
400
342
  for part in candidate.content.parts:
401
- if (
402
- hasattr(part, "text")
403
- and part.text
404
- and not chunk_text_processed
405
- ):
343
+ if hasattr(part, "text") and part.text and not chunk_text_processed:
406
344
  chunk_text = part.text
407
345
  text += chunk_text
408
346
  try:
@@ -410,12 +348,7 @@ def process_message(
410
348
  chunk_text_processed = True # Mark as processed to avoid further processing
411
349
  except Exception as e:
412
350
  print(f"Stream callback error: {e}")
413
- elif (
414
- hasattr(part, "executable_code")
415
- and part.executable_code
416
- and hasattr(part.executable_code, "code")
417
- and part.executable_code.code
418
- ):
351
+ elif hasattr(part, "executable_code") and part.executable_code and hasattr(part.executable_code, "code") and part.executable_code.code:
419
352
  # Handle code execution streaming
420
353
  code_text = part.executable_code.code
421
354
  code.append(code_text)
@@ -425,9 +358,7 @@ def process_message(
425
358
 
426
359
  if code_lines_shown == 0:
427
360
  try:
428
- stream_callback(
429
- "\n💻 Starting code execution...\n"
430
- )
361
+ stream_callback("\n💻 Starting code execution...\n")
431
362
  except Exception as e:
432
363
  print(f"Stream callback error: {e}")
433
364
 
@@ -438,49 +369,31 @@ def process_message(
438
369
  code_lines_shown += 1
439
370
  except Exception as e:
440
371
  print(f"Stream callback error: {e}")
441
- elif (
442
- code_lines_shown == 3
443
- and not truncation_message_sent
444
- ):
372
+ elif code_lines_shown == 3 and not truncation_message_sent:
445
373
  try:
446
- stream_callback(
447
- "\n[CODE_DISPLAY_ONLY]\n💻 ... (full code in log file)\n"
448
- )
374
+ stream_callback("\n[CODE_DISPLAY_ONLY]\n💻 ... (full code in log file)\n")
449
375
  truncation_message_sent = True # Ensure this message is only sent once
450
376
  code_lines_shown += 1
451
377
  except Exception as e:
452
378
  print(f"Stream callback error: {e}")
453
379
  else:
454
380
  try:
455
- stream_callback(
456
- f"[CODE_LOG_ONLY]{line}\n"
457
- )
381
+ stream_callback(f"[CODE_LOG_ONLY]{line}\n")
458
382
  except Exception as e:
459
383
  print(f"Stream callback error: {e}")
460
384
 
461
- elif (
462
- hasattr(part, "function_call")
463
- and part.function_call
464
- ):
385
+ elif hasattr(part, "function_call") and part.function_call:
465
386
  # Handle function calls - extract the actual function call data
466
- func_name = getattr(
467
- part.function_call, "name", "unknown"
468
- )
387
+ func_name = getattr(part.function_call, "name", "unknown")
469
388
  func_args = {}
470
- if (
471
- hasattr(part.function_call, "args")
472
- and part.function_call.args
473
- ):
389
+ if hasattr(part.function_call, "args") and part.function_call.args:
474
390
  # Convert args to dict if it's a struct/object
475
391
  if hasattr(part.function_call.args, "_pb"):
476
392
  # It's a protobuf struct, need to convert to dict
477
- import json
478
393
 
479
394
  try:
480
- func_args = dict(
481
- part.function_call.args
482
- )
483
- except:
395
+ func_args = dict(part.function_call.args)
396
+ except Exception:
484
397
  func_args = {}
485
398
  else:
486
399
  func_args = part.function_call.args
@@ -491,7 +404,7 @@ def process_message(
491
404
  "call_id": part.function_call.id,
492
405
  "name": func_name,
493
406
  "arguments": func_args,
494
- }
407
+ },
495
408
  )
496
409
 
497
410
  try:
@@ -501,20 +414,12 @@ def process_message(
501
414
 
502
415
  elif hasattr(part, "function_response"):
503
416
  try:
504
- stream_callback(
505
- "\n🔧 Function response received\n"
506
- )
417
+ stream_callback("\n🔧 Function response received\n")
507
418
  except Exception as e:
508
419
  print(f"Stream callback error: {e}")
509
420
 
510
- elif (
511
- hasattr(part, "code_execution_result")
512
- and part.code_execution_result
513
- ):
514
- if (
515
- hasattr(part.code_execution_result, "output")
516
- and part.code_execution_result.output
517
- ):
421
+ elif hasattr(part, "code_execution_result") and part.code_execution_result:
422
+ if hasattr(part.code_execution_result, "output") and part.code_execution_result.output:
518
423
  # Add execution result as text output
519
424
  result_text = f"\n[Code Output]\n{part.code_execution_result.output}\n"
520
425
  text += result_text
@@ -524,15 +429,9 @@ def process_message(
524
429
  print(f"Stream callback error: {e}")
525
430
 
526
431
  # Handle grounding metadata (citations from search) at the candidate level
527
- if (
528
- hasattr(candidate, "grounding_metadata")
529
- and candidate.grounding_metadata
530
- ):
432
+ if hasattr(candidate, "grounding_metadata") and candidate.grounding_metadata:
531
433
  grounding = candidate.grounding_metadata
532
- if (
533
- hasattr(grounding, "grounding_chunks")
534
- and grounding.grounding_chunks
535
- ):
434
+ if hasattr(grounding, "grounding_chunks") and grounding.grounding_chunks:
536
435
  for chunk_item in grounding.grounding_chunks:
537
436
  if hasattr(chunk_item, "web") and chunk_item.web:
538
437
  web_chunk = chunk_item.web
@@ -569,9 +468,7 @@ def process_message(
569
468
 
570
469
  if completion is None:
571
470
  # If we failed all retries, return empty response instead of raising exception
572
- print(
573
- f"Failed to get completion after {max_retries} retries, returning empty response"
574
- )
471
+ print(f"Failed to get completion after {max_retries} retries, returning empty response")
575
472
  return AgentResponse(text="", code=[], citations=[], function_calls=[])
576
473
 
577
474
  # Parse the completion and return text, code, and citations
@@ -1,17 +1,15 @@
1
- import os
2
- import threading
3
- import time
1
+ # -*- coding: utf-8 -*-
4
2
  import json
5
- import inspect
6
- import copy
3
+ import os
7
4
 
8
5
  from dotenv import load_dotenv
9
6
  from xai_sdk import Client
10
- from xai_sdk.chat import assistant, system, user, tool_result, tool as xai_tool_func
7
+ from xai_sdk.chat import assistant, system
8
+ from xai_sdk.chat import tool as xai_tool_func
9
+ from xai_sdk.chat import tool_result, user
11
10
  from xai_sdk.search import SearchParameters
12
11
 
13
12
  # Import utility functions and tools
14
- from massgen.v1.utils import function_to_json, execute_function_calls
15
13
  from massgen.v1.types import AgentResponse
16
14
 
17
15
  load_dotenv()
@@ -23,13 +21,10 @@ def parse_completion(response, add_citations=True):
23
21
  code = []
24
22
  citations = []
25
23
  function_calls = []
26
- reasoning_items = []
27
24
 
28
25
  if hasattr(response, "citations") and response.citations:
29
26
  for citation in response.citations:
30
- citations.append(
31
- {"url": citation, "title": "", "start_index": -1, "end_index": -1}
32
- )
27
+ citations.append({"url": citation, "title": "", "start_index": -1, "end_index": -1})
33
28
 
34
29
  if citations and add_citations:
35
30
  citation_content = []
@@ -48,7 +43,7 @@ def parse_completion(response, add_citations=True):
48
43
  "call_id": tool_call.id,
49
44
  "name": tool_call.function.name,
50
45
  "arguments": tool_call.function.arguments,
51
- }
46
+ },
52
47
  )
53
48
  elif hasattr(tool_call, "name") and hasattr(tool_call, "arguments"):
54
49
  # Direct structure: tool_call.name, tool_call.arguments
@@ -58,12 +53,10 @@ def parse_completion(response, add_citations=True):
58
53
  "call_id": tool_call.id,
59
54
  "name": tool_call.name,
60
55
  "arguments": tool_call.arguments,
61
- }
56
+ },
62
57
  )
63
58
 
64
- return AgentResponse(
65
- text=text, code=code, citations=citations, function_calls=function_calls
66
- )
59
+ return AgentResponse(text=text, code=code, citations=citations, function_calls=function_calls)
67
60
 
68
61
 
69
62
  def process_message(
@@ -234,9 +227,7 @@ def process_message(
234
227
  time.sleep(1.5)
235
228
 
236
229
  if completion is None:
237
- print(
238
- f"Failed to get completion after {max_retries} retries, returning empty response"
239
- )
230
+ print(f"Failed to get completion after {max_retries} retries, returning empty response")
240
231
  return AgentResponse(text="", code=[], citations=[], function_calls=[])
241
232
 
242
233
  if stream and stream_callback is not None:
@@ -256,11 +247,7 @@ def process_message(
256
247
 
257
248
  # Extract delta content from chunk - XAI SDK specific format
258
249
  # Primary method: check for choices structure and extract content directly
259
- if (
260
- hasattr(chunk, "choices")
261
- and chunk.choices
262
- and len(chunk.choices) > 0
263
- ):
250
+ if hasattr(chunk, "choices") and chunk.choices and len(chunk.choices) > 0:
264
251
  choice = chunk.choices[0]
265
252
  # XAI SDK stores content directly in choice.content, not choice.delta.content
266
253
  if hasattr(choice, "content") and choice.content:
@@ -280,11 +267,7 @@ def process_message(
280
267
  if delta_content.strip() == "Thinking...":
281
268
  thinking_count += 1
282
269
  # Show search indicator after first few thinking chunks
283
- if (
284
- thinking_count == 3
285
- and not has_shown_search_indicator
286
- and search_parameters
287
- ):
270
+ if thinking_count == 3 and not has_shown_search_indicator and search_parameters:
288
271
  try:
289
272
  stream_callback("\n🧠 Thinking...\n")
290
273
  except Exception as e:
@@ -316,9 +299,7 @@ def process_message(
316
299
  }
317
300
  if _func_call not in function_calls:
318
301
  function_calls.append(_func_call)
319
- elif hasattr(tool_call, "name") and hasattr(
320
- tool_call, "arguments"
321
- ):
302
+ elif hasattr(tool_call, "name") and hasattr(tool_call, "arguments"):
322
303
  _func_call = {
323
304
  "type": "function_call",
324
305
  "call_id": tool_call.id,
@@ -329,11 +310,7 @@ def process_message(
329
310
  function_calls.append(_func_call)
330
311
  elif hasattr(response, "choices") and response.choices:
331
312
  for choice in response.choices:
332
- if (
333
- hasattr(choice, "message")
334
- and hasattr(choice.message, "tool_calls")
335
- and choice.message.tool_calls
336
- ):
313
+ if hasattr(choice, "message") and hasattr(choice.message, "tool_calls") and choice.message.tool_calls:
337
314
  for tool_call in choice.message.tool_calls:
338
315
  if hasattr(tool_call, "function"):
339
316
  _func_call = {
@@ -344,9 +321,7 @@ def process_message(
344
321
  }
345
322
  if _func_call not in function_calls:
346
323
  function_calls.append(_func_call)
347
- elif hasattr(tool_call, "name") and hasattr(
348
- tool_call, "arguments"
349
- ):
324
+ elif hasattr(tool_call, "name") and hasattr(tool_call, "arguments"):
350
325
  _func_call = {
351
326
  "type": "function_call",
352
327
  "call_id": tool_call.id,
@@ -366,15 +341,13 @@ def process_message(
366
341
  "title": "",
367
342
  "start_index": -1,
368
343
  "end_index": -1,
369
- }
344
+ },
370
345
  )
371
346
 
372
347
  # Notify about found sources if we had search enabled
373
348
  if citations and enable_search and stream_callback is not None:
374
349
  try:
375
- stream_callback(
376
- f"\n\n🔍 Found {len(citations)} web sources\n"
377
- )
350
+ stream_callback(f"\n\n🔍 Found {len(citations)} web sources\n")
378
351
  except Exception as e:
379
352
  print(f"Stream callback error: {e}")
380
353
 
@@ -384,22 +357,16 @@ def process_message(
384
357
  stream_callback(text)
385
358
  if function_calls:
386
359
  for function_call in function_calls:
387
- stream_callback(
388
- f"🔧 Calling function: {function_call['name']}\n"
389
- )
390
- stream_callback(
391
- f"🔧 Arguments: {json.dumps(function_call['arguments'], indent=4)}\n\n"
392
- )
360
+ stream_callback(f"🔧 Calling function: {function_call['name']}\n")
361
+ stream_callback(f"🔧 Arguments: {json.dumps(function_call['arguments'], indent=4)}\n\n")
393
362
 
394
- except Exception as e:
363
+ except Exception:
395
364
  # Fall back to non-streaming
396
365
  completion = make_grok_request(stream=False)
397
366
  result = parse_completion(completion, add_citations=True)
398
367
  return result
399
368
 
400
- result = AgentResponse(
401
- text=text, code=code, citations=citations, function_calls=function_calls
402
- )
369
+ result = AgentResponse(text=text, code=code, citations=citations, function_calls=function_calls)
403
370
  else:
404
371
  result = parse_completion(completion, add_citations=True)
405
372