massgen 0.0.3__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 (76) hide show
  1. massgen/__init__.py +94 -0
  2. massgen/agent_config.py +507 -0
  3. massgen/backend/CLAUDE_API_RESEARCH.md +266 -0
  4. massgen/backend/Function calling openai responses.md +1161 -0
  5. massgen/backend/GEMINI_API_DOCUMENTATION.md +410 -0
  6. massgen/backend/OPENAI_RESPONSES_API_FORMAT.md +65 -0
  7. massgen/backend/__init__.py +25 -0
  8. massgen/backend/base.py +180 -0
  9. massgen/backend/chat_completions.py +228 -0
  10. massgen/backend/claude.py +661 -0
  11. massgen/backend/gemini.py +652 -0
  12. massgen/backend/grok.py +187 -0
  13. massgen/backend/response.py +397 -0
  14. massgen/chat_agent.py +440 -0
  15. massgen/cli.py +686 -0
  16. massgen/configs/README.md +293 -0
  17. massgen/configs/creative_team.yaml +53 -0
  18. massgen/configs/gemini_4o_claude.yaml +31 -0
  19. massgen/configs/news_analysis.yaml +51 -0
  20. massgen/configs/research_team.yaml +51 -0
  21. massgen/configs/single_agent.yaml +18 -0
  22. massgen/configs/single_flash2.5.yaml +44 -0
  23. massgen/configs/technical_analysis.yaml +51 -0
  24. massgen/configs/three_agents_default.yaml +31 -0
  25. massgen/configs/travel_planning.yaml +51 -0
  26. massgen/configs/two_agents.yaml +39 -0
  27. massgen/frontend/__init__.py +20 -0
  28. massgen/frontend/coordination_ui.py +945 -0
  29. massgen/frontend/displays/__init__.py +24 -0
  30. massgen/frontend/displays/base_display.py +83 -0
  31. massgen/frontend/displays/rich_terminal_display.py +3497 -0
  32. massgen/frontend/displays/simple_display.py +93 -0
  33. massgen/frontend/displays/terminal_display.py +381 -0
  34. massgen/frontend/logging/__init__.py +9 -0
  35. massgen/frontend/logging/realtime_logger.py +197 -0
  36. massgen/message_templates.py +431 -0
  37. massgen/orchestrator.py +1222 -0
  38. massgen/tests/__init__.py +10 -0
  39. massgen/tests/multi_turn_conversation_design.md +214 -0
  40. massgen/tests/multiturn_llm_input_analysis.md +189 -0
  41. massgen/tests/test_case_studies.md +113 -0
  42. massgen/tests/test_claude_backend.py +310 -0
  43. massgen/tests/test_grok_backend.py +160 -0
  44. massgen/tests/test_message_context_building.py +293 -0
  45. massgen/tests/test_rich_terminal_display.py +378 -0
  46. massgen/tests/test_v3_3agents.py +117 -0
  47. massgen/tests/test_v3_simple.py +216 -0
  48. massgen/tests/test_v3_three_agents.py +272 -0
  49. massgen/tests/test_v3_two_agents.py +176 -0
  50. massgen/utils.py +79 -0
  51. massgen/v1/README.md +330 -0
  52. massgen/v1/__init__.py +91 -0
  53. massgen/v1/agent.py +605 -0
  54. massgen/v1/agents.py +330 -0
  55. massgen/v1/backends/gemini.py +584 -0
  56. massgen/v1/backends/grok.py +410 -0
  57. massgen/v1/backends/oai.py +571 -0
  58. massgen/v1/cli.py +351 -0
  59. massgen/v1/config.py +169 -0
  60. massgen/v1/examples/fast-4o-mini-config.yaml +44 -0
  61. massgen/v1/examples/fast_config.yaml +44 -0
  62. massgen/v1/examples/production.yaml +70 -0
  63. massgen/v1/examples/single_agent.yaml +39 -0
  64. massgen/v1/logging.py +974 -0
  65. massgen/v1/main.py +368 -0
  66. massgen/v1/orchestrator.py +1138 -0
  67. massgen/v1/streaming_display.py +1190 -0
  68. massgen/v1/tools.py +160 -0
  69. massgen/v1/types.py +245 -0
  70. massgen/v1/utils.py +199 -0
  71. massgen-0.0.3.dist-info/METADATA +568 -0
  72. massgen-0.0.3.dist-info/RECORD +76 -0
  73. massgen-0.0.3.dist-info/WHEEL +5 -0
  74. massgen-0.0.3.dist-info/entry_points.txt +2 -0
  75. massgen-0.0.3.dist-info/licenses/LICENSE +204 -0
  76. massgen-0.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,310 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Claude Backend Integration Tests for MassGen
4
+
5
+ Tests the Claude backend implementation with real API calls:
6
+ - Basic text streaming
7
+ - Tool calling functionality
8
+ - Multi-tool support (web search + code execution + user functions)
9
+ - Message format conversion
10
+ - Error handling and token tracking
11
+
12
+ Requires ANTHROPIC_API_KEY environment variable.
13
+ """
14
+
15
+ import os
16
+ import sys
17
+ import asyncio
18
+ import json
19
+ from pathlib import Path
20
+
21
+ # Add project root to path
22
+ project_root = Path(__file__).parent.parent.parent.parent
23
+ sys.path.insert(0, str(project_root))
24
+
25
+ from massgen.backend.claude_backend import ClaudeBackend
26
+ from massgen.backend.base import StreamChunk
27
+
28
+
29
+ async def test_claude_basic_streaming():
30
+ """Test basic Claude streaming functionality."""
31
+ print("๐Ÿงช Testing Claude Basic Streaming...")
32
+
33
+ backend = ClaudeBackend()
34
+
35
+ messages = [
36
+ {"role": "user", "content": "Explain quantum computing in 2-3 sentences."}
37
+ ]
38
+
39
+ content = ""
40
+ async for chunk in backend.stream_with_tools(
41
+ messages, [], model="claude-3-5-haiku-20241022"
42
+ ):
43
+ if chunk.type == "content":
44
+ content += chunk.content
45
+ print(chunk.content, end="", flush=True)
46
+ elif chunk.type == "complete_message":
47
+ print(
48
+ f"\nโœ… Complete message received: {len(chunk.complete_message.get('content', ''))} chars"
49
+ )
50
+ elif chunk.type == "done":
51
+ print("\nโœ… Basic streaming test completed")
52
+ break
53
+ elif chunk.type == "error":
54
+ print(f"\nโŒ Error: {chunk.error}")
55
+ return False
56
+
57
+ return len(content) > 50
58
+
59
+
60
+ async def test_claude_tool_calling():
61
+ """Test Claude with user-defined tool calling."""
62
+ print("\n๐Ÿงช Testing Claude Tool Calling...")
63
+
64
+ backend = ClaudeBackend()
65
+
66
+ # Define a simple tool
67
+ tools = [
68
+ {
69
+ "type": "function",
70
+ "name": "calculate_area",
71
+ "description": "Calculate the area of a rectangle",
72
+ "parameters": {
73
+ "type": "object",
74
+ "properties": {
75
+ "width": {"type": "number", "description": "Width of rectangle"},
76
+ "height": {"type": "number", "description": "Height of rectangle"},
77
+ },
78
+ "required": ["width", "height"],
79
+ },
80
+ }
81
+ ]
82
+
83
+ messages = [
84
+ {
85
+ "role": "user",
86
+ "content": "Calculate the area of a rectangle with width 5 and height 3.",
87
+ }
88
+ ]
89
+
90
+ tool_calls_received = []
91
+ async for chunk in backend.stream_with_tools(
92
+ messages, tools, model="claude-3-5-haiku-20241022"
93
+ ):
94
+ if chunk.type == "content":
95
+ print(chunk.content, end="", flush=True)
96
+ elif chunk.type == "tool_calls":
97
+ tool_calls_received = chunk.tool_calls
98
+ print(f"\n๐Ÿ”ง Tool calls received: {len(tool_calls_received)}")
99
+ for tool_call in tool_calls_received:
100
+ tool_name = backend.extract_tool_name(tool_call)
101
+ tool_args = backend.extract_tool_arguments(tool_call)
102
+ print(f" - {tool_name}: {tool_args}")
103
+ elif chunk.type == "complete_message":
104
+ print(f"\nโœ… Complete message with tool calls received")
105
+ elif chunk.type == "done":
106
+ print("โœ… Tool calling test completed")
107
+ break
108
+ elif chunk.type == "error":
109
+ print(f"\nโŒ Error: {chunk.error}")
110
+ return False
111
+
112
+ return len(tool_calls_received) > 0
113
+
114
+
115
+ async def test_claude_multi_tool_support():
116
+ """Test Claude's multi-tool capabilities (server-side + user-defined)."""
117
+ print("\n๐Ÿงช Testing Claude Multi-Tool Support...")
118
+
119
+ backend = ClaudeBackend()
120
+
121
+ # Define user tool
122
+ user_tools = [
123
+ {
124
+ "type": "function",
125
+ "name": "format_result",
126
+ "description": "Format a result nicely",
127
+ "parameters": {
128
+ "type": "object",
129
+ "properties": {"title": {"type": "string"}, "data": {"type": "string"}},
130
+ "required": ["title", "data"],
131
+ },
132
+ }
133
+ ]
134
+
135
+ messages = [
136
+ {
137
+ "role": "user",
138
+ "content": "Search for recent news about AI and format the result with a nice title.",
139
+ }
140
+ ]
141
+
142
+ # Enable both server-side tools and user tools
143
+ tool_calls_received = []
144
+ search_used = False
145
+
146
+ async for chunk in backend.stream_with_tools(
147
+ messages,
148
+ user_tools,
149
+ model="claude-3-5-haiku-20241022",
150
+ enable_web_search=True, # Server-side tool
151
+ enable_code_execution=False,
152
+ ):
153
+ if chunk.type == "content":
154
+ print(chunk.content, end="", flush=True)
155
+ if "search" in chunk.content.lower():
156
+ search_used = True
157
+ elif chunk.type == "tool_calls":
158
+ tool_calls_received.extend(chunk.tool_calls)
159
+ print(f"\n๐Ÿ”ง Tool calls: {len(chunk.tool_calls)}")
160
+ elif chunk.type == "done":
161
+ print("\nโœ… Multi-tool test completed")
162
+ break
163
+ elif chunk.type == "error":
164
+ print(f"\nโŒ Error: {chunk.error}")
165
+ return False
166
+
167
+ print(f" Search used: {search_used}")
168
+ print(f" Tool calls: {len(tool_calls_received)}")
169
+
170
+ return search_used or len(tool_calls_received) > 0
171
+
172
+
173
+ async def test_claude_message_conversion():
174
+ """Test Claude's message format conversion capabilities."""
175
+ print("\n๐Ÿงช Testing Claude Message Conversion...")
176
+
177
+ backend = ClaudeBackend()
178
+
179
+ # Test with tool result message (Chat Completions format)
180
+ messages = [
181
+ {"role": "user", "content": "What's 5 + 3?"},
182
+ {
183
+ "role": "assistant",
184
+ "content": "Let me calculate that.",
185
+ "tool_calls": [
186
+ {
187
+ "id": "call_123",
188
+ "type": "function",
189
+ "function": {"name": "add", "arguments": {"a": 5, "b": 3}},
190
+ }
191
+ ],
192
+ },
193
+ {"role": "tool", "tool_call_id": "call_123", "content": "8"},
194
+ ]
195
+
196
+ # Convert messages
197
+ converted, system_msg = backend.convert_messages_to_claude_format(messages)
198
+
199
+ print(f" Original messages: {len(messages)}")
200
+ print(f" Converted messages: {len(converted)}")
201
+ print(f" System message: {len(system_msg)} chars")
202
+
203
+ # Check tool result conversion
204
+ tool_result_found = False
205
+ for msg in converted:
206
+ if (
207
+ msg.get("role") == "user"
208
+ and isinstance(msg.get("content"), list)
209
+ and any(item.get("type") == "tool_result" for item in msg["content"])
210
+ ):
211
+ tool_result_found = True
212
+ print(" โœ… Tool result conversion successful")
213
+ break
214
+
215
+ return len(converted) >= 3 and tool_result_found
216
+
217
+
218
+ async def test_claude_error_handling():
219
+ """Test Claude backend error handling."""
220
+ print("\n๐Ÿงช Testing Claude Error Handling...")
221
+
222
+ # Test with invalid API key
223
+ backend = ClaudeBackend(api_key="invalid_key")
224
+
225
+ messages = [{"role": "user", "content": "Test message"}]
226
+
227
+ error_caught = False
228
+ async for chunk in backend.stream_with_tools(messages, []):
229
+ if chunk.type == "error":
230
+ print(f" โœ… Error properly caught: {chunk.error[:50]}...")
231
+ error_caught = True
232
+ break
233
+
234
+ return error_caught
235
+
236
+
237
+ async def test_claude_token_pricing():
238
+ """Test Claude token usage and pricing calculations."""
239
+ print("\n๐Ÿงช Testing Claude Token Pricing...")
240
+
241
+ backend = ClaudeBackend()
242
+
243
+ # Test pricing calculation for different models
244
+ models_to_test = ["claude-4-opus", "claude-4-sonnet", "claude-3.5-haiku"]
245
+
246
+ for model in models_to_test:
247
+ cost = backend.calculate_cost(1000, 500, model)
248
+ print(f" {model}: 1K input + 500 output = ${cost:.4f}")
249
+
250
+ # Test tool pricing
251
+ backend.search_count = 10
252
+ backend.code_session_hours = 0.5
253
+ tool_cost = backend.calculate_cost(0, 0, "claude-4-sonnet")
254
+ print(f" Tool costs: 10 searches + 0.5h code = ${tool_cost:.4f}")
255
+
256
+ return True
257
+
258
+
259
+ async def main():
260
+ """Run all Claude backend tests."""
261
+ print("๐Ÿš€ Starting Claude Backend Integration Tests\n")
262
+
263
+ # Check API key
264
+ if not os.getenv("ANTHROPIC_API_KEY"):
265
+ print("โŒ ANTHROPIC_API_KEY not found. Skipping real API tests.")
266
+ print(" Set ANTHROPIC_API_KEY to run integration tests.")
267
+
268
+ # Run only offline tests
269
+ await test_claude_message_conversion()
270
+ await test_claude_token_pricing()
271
+ return
272
+
273
+ # Run all tests
274
+ tests = [
275
+ ("Basic Streaming", test_claude_basic_streaming),
276
+ ("Tool Calling", test_claude_tool_calling),
277
+ ("Multi-Tool Support", test_claude_multi_tool_support),
278
+ ("Message Conversion", test_claude_message_conversion),
279
+ ("Error Handling", test_claude_error_handling),
280
+ ("Token Pricing", test_claude_token_pricing),
281
+ ]
282
+
283
+ results = []
284
+ for test_name, test_func in tests:
285
+ try:
286
+ result = await test_func()
287
+ results.append((test_name, result))
288
+ except Exception as e:
289
+ print(f"\nโŒ {test_name} failed with exception: {e}")
290
+ results.append((test_name, False))
291
+
292
+ # Summary
293
+ print(f"\n๐Ÿ“Š Test Results Summary:")
294
+ passed = sum(1 for _, result in results if result)
295
+ total = len(results)
296
+
297
+ for test_name, result in results:
298
+ status = "โœ… PASS" if result else "โŒ FAIL"
299
+ print(f" {status} {test_name}")
300
+
301
+ print(f"\n๐ŸŽฏ Overall: {passed}/{total} tests passed")
302
+
303
+ if passed == total:
304
+ print("๐ŸŽ‰ All Claude backend tests completed successfully!")
305
+ else:
306
+ print("โš ๏ธ Some tests failed. Check the output above for details.")
307
+
308
+
309
+ if __name__ == "__main__":
310
+ asyncio.run(main())
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test script for Grok backend integration with current architecture.
4
+ Tests basic functionality, tool integration, and streaming.
5
+ """
6
+
7
+ import asyncio
8
+ import os
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ # Add project root to path
13
+ project_root = Path(__file__).parent.parent.parent.parent
14
+ sys.path.insert(0, str(project_root))
15
+
16
+ from massgen.backend.grok_backend import GrokBackend
17
+ from massgen.chat_agent import SingleAgent
18
+
19
+
20
+ async def test_grok_basic():
21
+ """Test basic Grok backend functionality."""
22
+ print("๐Ÿงช Testing Grok Backend - Basic Functionality")
23
+
24
+ # Check if API key is available
25
+ api_key = os.getenv("XAI_API_KEY")
26
+ if not api_key:
27
+ print("โŒ XAI_API_KEY not found in environment variables")
28
+ print("โš ๏ธ Set XAI_API_KEY to test Grok backend")
29
+ return False
30
+
31
+ try:
32
+ backend = GrokBackend(api_key=api_key)
33
+
34
+ # Test basic info
35
+ print(f"โœ… Provider: {backend.get_provider_name()}")
36
+ print(f"โœ… Supported tools: {backend.get_supported_builtin_tools()}")
37
+
38
+ # Test token estimation
39
+ test_text = "Hello world, this is a test message"
40
+ tokens = backend.estimate_tokens(test_text)
41
+ print(f"โœ… Token estimation: {tokens} tokens for '{test_text}'")
42
+
43
+ # Test cost calculation
44
+ cost = backend.calculate_cost(100, 50, "grok-3-mini")
45
+ print(f"โœ… Cost calculation: ${cost:.6f} for 100 input + 50 output tokens")
46
+
47
+ return True
48
+
49
+ except Exception as e:
50
+ print(f"โŒ Basic test failed: {e}")
51
+ return False
52
+
53
+
54
+ async def test_grok_streaming():
55
+ """Test Grok streaming without tools."""
56
+ print("\n๐Ÿงช Testing Grok Backend - Streaming")
57
+
58
+ api_key = os.getenv("XAI_API_KEY")
59
+ if not api_key:
60
+ print("โŒ XAI_API_KEY not found - skipping streaming test")
61
+ return False
62
+
63
+ try:
64
+ backend = GrokBackend(api_key=api_key)
65
+
66
+ messages = [
67
+ {
68
+ "role": "user",
69
+ "content": "Say hello and explain what you are in one sentence.",
70
+ }
71
+ ]
72
+
73
+ print("๐Ÿ“ค Sending request to Grok...")
74
+ response_content = ""
75
+
76
+ async for chunk in backend.stream_with_tools(
77
+ messages, tools=[], model="grok-3-mini"
78
+ ):
79
+ if chunk.type == "content" and chunk.content:
80
+ response_content += chunk.content
81
+ print(chunk.content, end="", flush=True)
82
+ elif chunk.type == "error":
83
+ print(f"\nโŒ Error: {chunk.error}")
84
+ return False
85
+
86
+ print(
87
+ f"\nโœ… Streaming test completed. Response length: {len(response_content)} chars"
88
+ )
89
+ return True
90
+
91
+ except Exception as e:
92
+ print(f"โŒ Streaming test failed: {e}")
93
+ return False
94
+
95
+
96
+ async def test_grok_with_agent():
97
+ """Test Grok backend through SingleAgent integration."""
98
+ print("\n๐Ÿงช Testing Grok Backend - SingleAgent Integration")
99
+
100
+ api_key = os.getenv("XAI_API_KEY")
101
+ if not api_key:
102
+ print("โŒ XAI_API_KEY not found - skipping agent test")
103
+ return False
104
+
105
+ try:
106
+ # Create Grok backend and agent
107
+ backend = GrokBackend(api_key=api_key)
108
+ agent = SingleAgent(
109
+ backend=backend,
110
+ system_message="You are a helpful AI assistant.",
111
+ agent_id="test_grok_agent",
112
+ )
113
+
114
+ print("๐Ÿ“ค Testing agent response...")
115
+ response_content = ""
116
+
117
+ # Test agent with a simple message
118
+ messages = [{"role": "user", "content": "What is 2+2? Answer briefly."}]
119
+ async for chunk in agent.chat(messages):
120
+ if chunk.type == "content" and chunk.content:
121
+ response_content += chunk.content
122
+ print(chunk.content, end="", flush=True)
123
+ elif chunk.type == "error":
124
+ print(f"\nโŒ Agent error: {chunk.error}")
125
+ return False
126
+
127
+ print(f"\nโœ… Agent test completed. Response: '{response_content.strip()}'")
128
+ return True
129
+
130
+ except Exception as e:
131
+ print(f"โŒ Agent test failed: {e}")
132
+ return False
133
+
134
+
135
+ async def main():
136
+ """Run all Grok backend tests."""
137
+ print("๐Ÿš€ MassGen - Grok Backend Testing")
138
+ print("=" * 50)
139
+
140
+ results = []
141
+
142
+ # Run tests
143
+ results.append(await test_grok_basic())
144
+ results.append(await test_grok_streaming())
145
+ results.append(await test_grok_with_agent())
146
+
147
+ # Summary
148
+ print("\n" + "=" * 50)
149
+ print("๐Ÿ“Š Test Results:")
150
+ print(f"โœ… Passed: {sum(results)}")
151
+ print(f"โŒ Failed: {len(results) - sum(results)}")
152
+
153
+ if all(results):
154
+ print("๐ŸŽ‰ All Grok backend tests passed!")
155
+ else:
156
+ print("โš ๏ธ Some tests failed - check XAI_API_KEY and network connection")
157
+
158
+
159
+ if __name__ == "__main__":
160
+ asyncio.run(main())