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