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.
- massgen/__init__.py +142 -8
- massgen/adapters/__init__.py +29 -0
- massgen/adapters/ag2_adapter.py +483 -0
- massgen/adapters/base.py +183 -0
- massgen/adapters/tests/__init__.py +0 -0
- massgen/adapters/tests/test_ag2_adapter.py +439 -0
- massgen/adapters/tests/test_agent_adapter.py +128 -0
- massgen/adapters/utils/__init__.py +2 -0
- massgen/adapters/utils/ag2_utils.py +236 -0
- massgen/adapters/utils/tests/__init__.py +0 -0
- massgen/adapters/utils/tests/test_ag2_utils.py +138 -0
- massgen/agent_config.py +329 -55
- massgen/api_params_handler/__init__.py +10 -0
- massgen/api_params_handler/_api_params_handler_base.py +99 -0
- massgen/api_params_handler/_chat_completions_api_params_handler.py +176 -0
- massgen/api_params_handler/_claude_api_params_handler.py +113 -0
- massgen/api_params_handler/_response_api_params_handler.py +130 -0
- massgen/backend/__init__.py +39 -4
- massgen/backend/azure_openai.py +385 -0
- massgen/backend/base.py +341 -69
- massgen/backend/base_with_mcp.py +1102 -0
- massgen/backend/capabilities.py +386 -0
- massgen/backend/chat_completions.py +577 -130
- massgen/backend/claude.py +1033 -537
- massgen/backend/claude_code.py +1203 -0
- massgen/backend/cli_base.py +209 -0
- massgen/backend/docs/BACKEND_ARCHITECTURE.md +126 -0
- massgen/backend/{CLAUDE_API_RESEARCH.md → docs/CLAUDE_API_RESEARCH.md} +18 -18
- massgen/backend/{GEMINI_API_DOCUMENTATION.md → docs/GEMINI_API_DOCUMENTATION.md} +9 -9
- massgen/backend/docs/Gemini MCP Integration Analysis.md +1050 -0
- massgen/backend/docs/MCP_IMPLEMENTATION_CLAUDE_BACKEND.md +177 -0
- massgen/backend/docs/MCP_INTEGRATION_RESPONSE_BACKEND.md +352 -0
- massgen/backend/docs/OPENAI_GPT5_MODELS.md +211 -0
- massgen/backend/{OPENAI_RESPONSES_API_FORMAT.md → docs/OPENAI_RESPONSE_API_TOOL_CALLS.md} +3 -3
- massgen/backend/docs/OPENAI_response_streaming.md +20654 -0
- massgen/backend/docs/inference_backend.md +257 -0
- massgen/backend/docs/permissions_and_context_files.md +1085 -0
- massgen/backend/external.py +126 -0
- massgen/backend/gemini.py +1850 -241
- massgen/backend/grok.py +40 -156
- massgen/backend/inference.py +156 -0
- massgen/backend/lmstudio.py +171 -0
- massgen/backend/response.py +1095 -322
- massgen/chat_agent.py +131 -113
- massgen/cli.py +1560 -275
- massgen/config_builder.py +2396 -0
- massgen/configs/BACKEND_CONFIGURATION.md +458 -0
- massgen/configs/README.md +559 -216
- massgen/configs/ag2/ag2_case_study.yaml +27 -0
- massgen/configs/ag2/ag2_coder.yaml +34 -0
- massgen/configs/ag2/ag2_coder_case_study.yaml +36 -0
- massgen/configs/ag2/ag2_gemini.yaml +27 -0
- massgen/configs/ag2/ag2_groupchat.yaml +108 -0
- massgen/configs/ag2/ag2_groupchat_gpt.yaml +118 -0
- massgen/configs/ag2/ag2_single_agent.yaml +21 -0
- massgen/configs/basic/multi/fast_timeout_example.yaml +37 -0
- massgen/configs/basic/multi/gemini_4o_claude.yaml +31 -0
- massgen/configs/basic/multi/gemini_gpt5nano_claude.yaml +36 -0
- massgen/configs/{gemini_4o_claude.yaml → basic/multi/geminicode_4o_claude.yaml} +3 -3
- massgen/configs/basic/multi/geminicode_gpt5nano_claude.yaml +36 -0
- massgen/configs/basic/multi/glm_gemini_claude.yaml +25 -0
- massgen/configs/basic/multi/gpt4o_audio_generation.yaml +30 -0
- massgen/configs/basic/multi/gpt4o_image_generation.yaml +31 -0
- massgen/configs/basic/multi/gpt5nano_glm_qwen.yaml +26 -0
- massgen/configs/basic/multi/gpt5nano_image_understanding.yaml +26 -0
- massgen/configs/{three_agents_default.yaml → basic/multi/three_agents_default.yaml} +8 -4
- massgen/configs/basic/multi/three_agents_opensource.yaml +27 -0
- massgen/configs/basic/multi/three_agents_vllm.yaml +20 -0
- massgen/configs/basic/multi/two_agents_gemini.yaml +19 -0
- massgen/configs/{two_agents.yaml → basic/multi/two_agents_gpt5.yaml} +14 -6
- massgen/configs/basic/multi/two_agents_opensource_lmstudio.yaml +31 -0
- massgen/configs/basic/multi/two_qwen_vllm_sglang.yaml +28 -0
- massgen/configs/{single_agent.yaml → basic/single/single_agent.yaml} +1 -1
- massgen/configs/{single_flash2.5.yaml → basic/single/single_flash2.5.yaml} +1 -2
- massgen/configs/basic/single/single_gemini2.5pro.yaml +16 -0
- massgen/configs/basic/single/single_gpt4o_audio_generation.yaml +22 -0
- massgen/configs/basic/single/single_gpt4o_image_generation.yaml +22 -0
- massgen/configs/basic/single/single_gpt4o_video_generation.yaml +24 -0
- massgen/configs/basic/single/single_gpt5nano.yaml +20 -0
- massgen/configs/basic/single/single_gpt5nano_file_search.yaml +18 -0
- massgen/configs/basic/single/single_gpt5nano_image_understanding.yaml +17 -0
- massgen/configs/basic/single/single_gptoss120b.yaml +15 -0
- massgen/configs/basic/single/single_openrouter_audio_understanding.yaml +15 -0
- massgen/configs/basic/single/single_qwen_video_understanding.yaml +15 -0
- massgen/configs/debug/code_execution/command_filtering_blacklist.yaml +29 -0
- massgen/configs/debug/code_execution/command_filtering_whitelist.yaml +28 -0
- massgen/configs/debug/code_execution/docker_verification.yaml +29 -0
- massgen/configs/debug/skip_coordination_test.yaml +27 -0
- massgen/configs/debug/test_sdk_migration.yaml +17 -0
- massgen/configs/docs/DISCORD_MCP_SETUP.md +208 -0
- massgen/configs/docs/TWITTER_MCP_ENESCINAR_SETUP.md +82 -0
- massgen/configs/providers/azure/azure_openai_multi.yaml +21 -0
- massgen/configs/providers/azure/azure_openai_single.yaml +19 -0
- massgen/configs/providers/claude/claude.yaml +14 -0
- massgen/configs/providers/gemini/gemini_gpt5nano.yaml +28 -0
- massgen/configs/providers/local/lmstudio.yaml +11 -0
- massgen/configs/providers/openai/gpt5.yaml +46 -0
- massgen/configs/providers/openai/gpt5_nano.yaml +46 -0
- massgen/configs/providers/others/grok_single_agent.yaml +19 -0
- massgen/configs/providers/others/zai_coding_team.yaml +108 -0
- massgen/configs/providers/others/zai_glm45.yaml +12 -0
- massgen/configs/{creative_team.yaml → teams/creative/creative_team.yaml} +16 -6
- massgen/configs/{travel_planning.yaml → teams/creative/travel_planning.yaml} +16 -6
- massgen/configs/{news_analysis.yaml → teams/research/news_analysis.yaml} +16 -6
- massgen/configs/{research_team.yaml → teams/research/research_team.yaml} +15 -7
- massgen/configs/{technical_analysis.yaml → teams/research/technical_analysis.yaml} +16 -6
- massgen/configs/tools/code-execution/basic_command_execution.yaml +25 -0
- massgen/configs/tools/code-execution/code_execution_use_case_simple.yaml +41 -0
- massgen/configs/tools/code-execution/docker_claude_code.yaml +32 -0
- massgen/configs/tools/code-execution/docker_multi_agent.yaml +32 -0
- massgen/configs/tools/code-execution/docker_simple.yaml +29 -0
- massgen/configs/tools/code-execution/docker_with_resource_limits.yaml +32 -0
- massgen/configs/tools/code-execution/multi_agent_playwright_automation.yaml +57 -0
- massgen/configs/tools/filesystem/cc_gpt5_gemini_filesystem.yaml +34 -0
- massgen/configs/tools/filesystem/claude_code_context_sharing.yaml +68 -0
- massgen/configs/tools/filesystem/claude_code_flash2.5.yaml +43 -0
- massgen/configs/tools/filesystem/claude_code_flash2.5_gptoss.yaml +49 -0
- massgen/configs/tools/filesystem/claude_code_gpt5nano.yaml +31 -0
- massgen/configs/tools/filesystem/claude_code_single.yaml +40 -0
- massgen/configs/tools/filesystem/fs_permissions_test.yaml +87 -0
- massgen/configs/tools/filesystem/gemini_gemini_workspace_cleanup.yaml +54 -0
- massgen/configs/tools/filesystem/gemini_gpt5_filesystem_casestudy.yaml +30 -0
- massgen/configs/tools/filesystem/gemini_gpt5nano_file_context_path.yaml +43 -0
- massgen/configs/tools/filesystem/gemini_gpt5nano_protected_paths.yaml +45 -0
- massgen/configs/tools/filesystem/gpt5mini_cc_fs_context_path.yaml +31 -0
- massgen/configs/tools/filesystem/grok4_gpt5_gemini_filesystem.yaml +32 -0
- massgen/configs/tools/filesystem/multiturn/grok4_gpt5_claude_code_filesystem_multiturn.yaml +58 -0
- massgen/configs/tools/filesystem/multiturn/grok4_gpt5_gemini_filesystem_multiturn.yaml +58 -0
- massgen/configs/tools/filesystem/multiturn/two_claude_code_filesystem_multiturn.yaml +47 -0
- massgen/configs/tools/filesystem/multiturn/two_gemini_flash_filesystem_multiturn.yaml +48 -0
- massgen/configs/tools/mcp/claude_code_discord_mcp_example.yaml +27 -0
- massgen/configs/tools/mcp/claude_code_simple_mcp.yaml +35 -0
- massgen/configs/tools/mcp/claude_code_twitter_mcp_example.yaml +32 -0
- massgen/configs/tools/mcp/claude_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/claude_mcp_test.yaml +27 -0
- massgen/configs/tools/mcp/five_agents_travel_mcp_test.yaml +157 -0
- massgen/configs/tools/mcp/five_agents_weather_mcp_test.yaml +103 -0
- massgen/configs/tools/mcp/gemini_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/gemini_mcp_filesystem_test.yaml +23 -0
- massgen/configs/tools/mcp/gemini_mcp_filesystem_test_sharing.yaml +23 -0
- massgen/configs/tools/mcp/gemini_mcp_filesystem_test_single_agent.yaml +17 -0
- massgen/configs/tools/mcp/gemini_mcp_filesystem_test_with_claude_code.yaml +24 -0
- massgen/configs/tools/mcp/gemini_mcp_test.yaml +27 -0
- massgen/configs/tools/mcp/gemini_notion_mcp.yaml +52 -0
- massgen/configs/tools/mcp/gpt5_nano_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/gpt5_nano_mcp_test.yaml +27 -0
- massgen/configs/tools/mcp/gpt5mini_claude_code_discord_mcp_example.yaml +38 -0
- massgen/configs/tools/mcp/gpt_oss_mcp_example.yaml +25 -0
- massgen/configs/tools/mcp/gpt_oss_mcp_test.yaml +28 -0
- massgen/configs/tools/mcp/grok3_mini_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/grok3_mini_mcp_test.yaml +27 -0
- massgen/configs/tools/mcp/multimcp_gemini.yaml +111 -0
- massgen/configs/tools/mcp/qwen_api_mcp_example.yaml +25 -0
- massgen/configs/tools/mcp/qwen_api_mcp_test.yaml +28 -0
- massgen/configs/tools/mcp/qwen_local_mcp_example.yaml +24 -0
- massgen/configs/tools/mcp/qwen_local_mcp_test.yaml +27 -0
- massgen/configs/tools/planning/five_agents_discord_mcp_planning_mode.yaml +140 -0
- massgen/configs/tools/planning/five_agents_filesystem_mcp_planning_mode.yaml +151 -0
- massgen/configs/tools/planning/five_agents_notion_mcp_planning_mode.yaml +151 -0
- massgen/configs/tools/planning/five_agents_twitter_mcp_planning_mode.yaml +155 -0
- massgen/configs/tools/planning/gpt5_mini_case_study_mcp_planning_mode.yaml +73 -0
- massgen/configs/tools/web-search/claude_streamable_http_test.yaml +43 -0
- massgen/configs/tools/web-search/gemini_streamable_http_test.yaml +43 -0
- massgen/configs/tools/web-search/gpt5_mini_streamable_http_test.yaml +43 -0
- massgen/configs/tools/web-search/gpt_oss_streamable_http_test.yaml +44 -0
- massgen/configs/tools/web-search/grok3_mini_streamable_http_test.yaml +43 -0
- massgen/configs/tools/web-search/qwen_api_streamable_http_test.yaml +44 -0
- massgen/configs/tools/web-search/qwen_local_streamable_http_test.yaml +43 -0
- massgen/coordination_tracker.py +708 -0
- massgen/docker/README.md +462 -0
- massgen/filesystem_manager/__init__.py +21 -0
- massgen/filesystem_manager/_base.py +9 -0
- massgen/filesystem_manager/_code_execution_server.py +545 -0
- massgen/filesystem_manager/_docker_manager.py +477 -0
- massgen/filesystem_manager/_file_operation_tracker.py +248 -0
- massgen/filesystem_manager/_filesystem_manager.py +813 -0
- massgen/filesystem_manager/_path_permission_manager.py +1261 -0
- massgen/filesystem_manager/_workspace_tools_server.py +1815 -0
- massgen/formatter/__init__.py +10 -0
- massgen/formatter/_chat_completions_formatter.py +284 -0
- massgen/formatter/_claude_formatter.py +235 -0
- massgen/formatter/_formatter_base.py +156 -0
- massgen/formatter/_response_formatter.py +263 -0
- massgen/frontend/__init__.py +1 -2
- massgen/frontend/coordination_ui.py +471 -286
- massgen/frontend/displays/base_display.py +56 -11
- massgen/frontend/displays/create_coordination_table.py +1956 -0
- massgen/frontend/displays/rich_terminal_display.py +1259 -619
- massgen/frontend/displays/simple_display.py +9 -4
- massgen/frontend/displays/terminal_display.py +27 -68
- massgen/logger_config.py +681 -0
- massgen/mcp_tools/README.md +232 -0
- massgen/mcp_tools/__init__.py +105 -0
- massgen/mcp_tools/backend_utils.py +1035 -0
- massgen/mcp_tools/circuit_breaker.py +195 -0
- massgen/mcp_tools/client.py +894 -0
- massgen/mcp_tools/config_validator.py +138 -0
- massgen/mcp_tools/docs/circuit_breaker.md +646 -0
- massgen/mcp_tools/docs/client.md +950 -0
- massgen/mcp_tools/docs/config_validator.md +478 -0
- massgen/mcp_tools/docs/exceptions.md +1165 -0
- massgen/mcp_tools/docs/security.md +854 -0
- massgen/mcp_tools/exceptions.py +338 -0
- massgen/mcp_tools/hooks.py +212 -0
- massgen/mcp_tools/security.py +780 -0
- massgen/message_templates.py +342 -64
- massgen/orchestrator.py +1515 -241
- massgen/stream_chunk/__init__.py +35 -0
- massgen/stream_chunk/base.py +92 -0
- massgen/stream_chunk/multimodal.py +237 -0
- massgen/stream_chunk/text.py +162 -0
- massgen/tests/mcp_test_server.py +150 -0
- massgen/tests/multi_turn_conversation_design.md +0 -8
- massgen/tests/test_azure_openai_backend.py +156 -0
- massgen/tests/test_backend_capabilities.py +262 -0
- massgen/tests/test_backend_event_loop_all.py +179 -0
- massgen/tests/test_chat_completions_refactor.py +142 -0
- massgen/tests/test_claude_backend.py +15 -28
- massgen/tests/test_claude_code.py +268 -0
- massgen/tests/test_claude_code_context_sharing.py +233 -0
- massgen/tests/test_claude_code_orchestrator.py +175 -0
- massgen/tests/test_cli_backends.py +180 -0
- massgen/tests/test_code_execution.py +679 -0
- massgen/tests/test_external_agent_backend.py +134 -0
- massgen/tests/test_final_presentation_fallback.py +237 -0
- massgen/tests/test_gemini_planning_mode.py +351 -0
- massgen/tests/test_grok_backend.py +7 -10
- massgen/tests/test_http_mcp_server.py +42 -0
- massgen/tests/test_integration_simple.py +198 -0
- massgen/tests/test_mcp_blocking.py +125 -0
- massgen/tests/test_message_context_building.py +29 -47
- massgen/tests/test_orchestrator_final_presentation.py +48 -0
- massgen/tests/test_path_permission_manager.py +2087 -0
- massgen/tests/test_rich_terminal_display.py +14 -13
- massgen/tests/test_timeout.py +133 -0
- massgen/tests/test_v3_3agents.py +11 -12
- massgen/tests/test_v3_simple.py +8 -13
- massgen/tests/test_v3_three_agents.py +11 -18
- massgen/tests/test_v3_two_agents.py +8 -13
- massgen/token_manager/__init__.py +7 -0
- massgen/token_manager/token_manager.py +400 -0
- massgen/utils.py +52 -16
- massgen/v1/agent.py +45 -91
- massgen/v1/agents.py +18 -53
- massgen/v1/backends/gemini.py +50 -153
- massgen/v1/backends/grok.py +21 -54
- massgen/v1/backends/oai.py +39 -111
- massgen/v1/cli.py +36 -93
- massgen/v1/config.py +8 -12
- massgen/v1/logging.py +43 -127
- massgen/v1/main.py +18 -32
- massgen/v1/orchestrator.py +68 -209
- massgen/v1/streaming_display.py +62 -163
- massgen/v1/tools.py +8 -12
- massgen/v1/types.py +9 -23
- massgen/v1/utils.py +5 -23
- massgen-0.1.0.dist-info/METADATA +1245 -0
- massgen-0.1.0.dist-info/RECORD +273 -0
- massgen-0.1.0.dist-info/entry_points.txt +2 -0
- massgen/frontend/logging/__init__.py +0 -9
- massgen/frontend/logging/realtime_logger.py +0 -197
- massgen-0.0.3.dist-info/METADATA +0 -568
- massgen-0.0.3.dist-info/RECORD +0 -76
- massgen-0.0.3.dist-info/entry_points.txt +0 -2
- /massgen/backend/{Function calling openai responses.md → docs/Function calling openai responses.md} +0 -0
- {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/WHEEL +0 -0
- {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/licenses/LICENSE +0 -0
- {massgen-0.0.3.dist-info → massgen-0.1.0.dist-info}/top_level.txt +0 -0
massgen/v1/backends/gemini.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import copy
|
|
1
3
|
import os
|
|
2
|
-
import threading
|
|
3
4
|
import time
|
|
4
|
-
|
|
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, "
|
|
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
|
-
|
|
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
|
-
|
|
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, "
|
|
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
|
massgen/v1/backends/grok.py
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
import threading
|
|
3
|
-
import time
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
4
2
|
import json
|
|
5
|
-
import
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|