pygeai-orchestration 0.1.0b2__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.
Files changed (61) hide show
  1. pygeai_orchestration/__init__.py +99 -0
  2. pygeai_orchestration/cli/__init__.py +7 -0
  3. pygeai_orchestration/cli/__main__.py +11 -0
  4. pygeai_orchestration/cli/commands/__init__.py +13 -0
  5. pygeai_orchestration/cli/commands/base.py +192 -0
  6. pygeai_orchestration/cli/error_handler.py +123 -0
  7. pygeai_orchestration/cli/formatters.py +419 -0
  8. pygeai_orchestration/cli/geai_orch.py +270 -0
  9. pygeai_orchestration/cli/interactive.py +265 -0
  10. pygeai_orchestration/cli/texts/help.py +169 -0
  11. pygeai_orchestration/core/__init__.py +130 -0
  12. pygeai_orchestration/core/base/__init__.py +23 -0
  13. pygeai_orchestration/core/base/agent.py +121 -0
  14. pygeai_orchestration/core/base/geai_agent.py +144 -0
  15. pygeai_orchestration/core/base/geai_orchestrator.py +77 -0
  16. pygeai_orchestration/core/base/orchestrator.py +142 -0
  17. pygeai_orchestration/core/base/pattern.py +161 -0
  18. pygeai_orchestration/core/base/tool.py +149 -0
  19. pygeai_orchestration/core/common/__init__.py +18 -0
  20. pygeai_orchestration/core/common/context.py +140 -0
  21. pygeai_orchestration/core/common/memory.py +176 -0
  22. pygeai_orchestration/core/common/message.py +50 -0
  23. pygeai_orchestration/core/common/state.py +181 -0
  24. pygeai_orchestration/core/composition.py +190 -0
  25. pygeai_orchestration/core/config.py +356 -0
  26. pygeai_orchestration/core/exceptions.py +400 -0
  27. pygeai_orchestration/core/handlers.py +380 -0
  28. pygeai_orchestration/core/utils/__init__.py +37 -0
  29. pygeai_orchestration/core/utils/cache.py +138 -0
  30. pygeai_orchestration/core/utils/config.py +94 -0
  31. pygeai_orchestration/core/utils/logging.py +57 -0
  32. pygeai_orchestration/core/utils/metrics.py +184 -0
  33. pygeai_orchestration/core/utils/validators.py +140 -0
  34. pygeai_orchestration/dev/__init__.py +15 -0
  35. pygeai_orchestration/dev/debug.py +288 -0
  36. pygeai_orchestration/dev/templates.py +321 -0
  37. pygeai_orchestration/dev/testing.py +301 -0
  38. pygeai_orchestration/patterns/__init__.py +15 -0
  39. pygeai_orchestration/patterns/multi_agent.py +237 -0
  40. pygeai_orchestration/patterns/planning.py +219 -0
  41. pygeai_orchestration/patterns/react.py +221 -0
  42. pygeai_orchestration/patterns/reflection.py +134 -0
  43. pygeai_orchestration/patterns/tool_use.py +170 -0
  44. pygeai_orchestration/tests/__init__.py +1 -0
  45. pygeai_orchestration/tests/test_base_classes.py +187 -0
  46. pygeai_orchestration/tests/test_cache.py +184 -0
  47. pygeai_orchestration/tests/test_cli_formatters.py +232 -0
  48. pygeai_orchestration/tests/test_common.py +214 -0
  49. pygeai_orchestration/tests/test_composition.py +265 -0
  50. pygeai_orchestration/tests/test_config.py +301 -0
  51. pygeai_orchestration/tests/test_dev_utils.py +337 -0
  52. pygeai_orchestration/tests/test_exceptions.py +327 -0
  53. pygeai_orchestration/tests/test_handlers.py +307 -0
  54. pygeai_orchestration/tests/test_metrics.py +171 -0
  55. pygeai_orchestration/tests/test_patterns.py +165 -0
  56. pygeai_orchestration-0.1.0b2.dist-info/METADATA +290 -0
  57. pygeai_orchestration-0.1.0b2.dist-info/RECORD +61 -0
  58. pygeai_orchestration-0.1.0b2.dist-info/WHEEL +5 -0
  59. pygeai_orchestration-0.1.0b2.dist-info/entry_points.txt +2 -0
  60. pygeai_orchestration-0.1.0b2.dist-info/licenses/LICENSE +8 -0
  61. pygeai_orchestration-0.1.0b2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,321 @@
1
+ """Pattern templates and code generators."""
2
+
3
+ from enum import Enum
4
+ from pathlib import Path
5
+ from typing import Dict, Optional
6
+
7
+
8
+ class PatternTemplate(str, Enum):
9
+ """Available pattern templates."""
10
+
11
+ REFLECTION = "reflection"
12
+ REACT = "react"
13
+ PLANNING = "planning"
14
+ MULTI_AGENT = "multi_agent"
15
+ CUSTOM = "custom"
16
+
17
+
18
+ class TemplateGenerator:
19
+ """Generate pattern boilerplate code."""
20
+
21
+ @staticmethod
22
+ def generate_reflection_pattern(
23
+ name: str,
24
+ description: str = "Custom reflection pattern"
25
+ ) -> str:
26
+ """Generate reflection pattern template.
27
+
28
+ Args:
29
+ name: Pattern class name
30
+ description: Pattern description
31
+
32
+ Returns:
33
+ Generated code
34
+ """
35
+ return f'''"""
36
+ {description}
37
+ """
38
+
39
+ from pygeai_orchestration.patterns.reflection import ReflectionPattern
40
+ from pygeai_orchestration.core.base import PatternConfig, PatternResult
41
+
42
+
43
+ class {name}(ReflectionPattern):
44
+ """{description}."""
45
+
46
+ async def reflect(self, task: str, result: str, context=None) -> str:
47
+ """Reflect on task and result.
48
+
49
+ Args:
50
+ task: Original task
51
+ result: Initial result
52
+ context: Optional context
53
+
54
+ Returns:
55
+ Reflection feedback
56
+ """
57
+ reflection_prompt = f"""
58
+ Task: {{task}}
59
+ Result: {{result}}
60
+
61
+ Please analyze this result and provide feedback for improvement.
62
+ """
63
+
64
+ reflection = await self.agent.generate(reflection_prompt)
65
+ return reflection
66
+
67
+ async def improve(self, task: str, result: str, reflection: str, context=None) -> str:
68
+ """Improve result based on reflection.
69
+
70
+ Args:
71
+ task: Original task
72
+ result: Initial result
73
+ reflection: Reflection feedback
74
+ context: Optional context
75
+
76
+ Returns:
77
+ Improved result
78
+ """
79
+ improvement_prompt = f"""
80
+ Task: {{task}}
81
+ Previous Result: {{result}}
82
+ Reflection: {{reflection}}
83
+
84
+ Please provide an improved result based on the reflection.
85
+ """
86
+
87
+ improved = await self.agent.generate(improvement_prompt)
88
+ return improved
89
+ '''
90
+
91
+ @staticmethod
92
+ def generate_react_pattern(
93
+ name: str,
94
+ description: str = "Custom ReAct pattern"
95
+ ) -> str:
96
+ """Generate ReAct pattern template.
97
+
98
+ Args:
99
+ name: Pattern class name
100
+ description: Pattern description
101
+
102
+ Returns:
103
+ Generated code
104
+ """
105
+ return f'''"""
106
+ {description}
107
+ """
108
+
109
+ from pygeai_orchestration.patterns.react import ReActPattern
110
+ from pygeai_orchestration.core.base import PatternConfig, PatternResult
111
+
112
+
113
+ class {name}(ReActPattern):
114
+ """{description}."""
115
+
116
+ async def think(self, task: str, context=None) -> str:
117
+ """Reason about the task.
118
+
119
+ Args:
120
+ task: Task to think about
121
+ context: Optional context
122
+
123
+ Returns:
124
+ Reasoning result
125
+ """
126
+ thought_prompt = f"""
127
+ Task: {{task}}
128
+
129
+ Think step by step about how to solve this task.
130
+ """
131
+
132
+ thought = await self.agent.generate(thought_prompt)
133
+ return thought
134
+
135
+ async def act(self, task: str, thought: str, context=None) -> str:
136
+ """Take action based on reasoning.
137
+
138
+ Args:
139
+ task: Original task
140
+ thought: Reasoning result
141
+ context: Optional context
142
+
143
+ Returns:
144
+ Action result
145
+ """
146
+ action_prompt = f"""
147
+ Task: {{task}}
148
+ Thought: {{thought}}
149
+
150
+ Based on this reasoning, take the appropriate action.
151
+ """
152
+
153
+ action = await self.agent.generate(action_prompt)
154
+ return action
155
+ '''
156
+
157
+ @staticmethod
158
+ def generate_custom_pattern(
159
+ name: str,
160
+ description: str = "Custom orchestration pattern"
161
+ ) -> str:
162
+ """Generate custom pattern template.
163
+
164
+ Args:
165
+ name: Pattern class name
166
+ description: Pattern description
167
+
168
+ Returns:
169
+ Generated code
170
+ """
171
+ return f'''"""
172
+ {description}
173
+ """
174
+
175
+ from pygeai_orchestration.core.base import OrchestrationPattern, PatternConfig, PatternResult
176
+
177
+
178
+ class {name}(OrchestrationPattern):
179
+ """{description}."""
180
+
181
+ async def _execute_impl(self, task: str, context=None) -> PatternResult:
182
+ """Execute pattern implementation.
183
+
184
+ Args:
185
+ task: Task to execute
186
+ context: Optional execution context
187
+
188
+ Returns:
189
+ Pattern execution result
190
+ """
191
+ # TODO: Implement your pattern logic here
192
+
193
+ result = await self.agent.generate(task)
194
+
195
+ return PatternResult(
196
+ success=True,
197
+ result=result,
198
+ metadata={{"pattern": "{name}"}}
199
+ )
200
+ '''
201
+
202
+ @staticmethod
203
+ def generate_test_file(
204
+ pattern_name: str,
205
+ template: PatternTemplate
206
+ ) -> str:
207
+ """Generate test file for pattern.
208
+
209
+ Args:
210
+ pattern_name: Pattern class name
211
+ template: Pattern template type
212
+
213
+ Returns:
214
+ Generated test code
215
+ """
216
+ return f'''"""
217
+ Tests for {pattern_name}.
218
+ """
219
+
220
+ import unittest
221
+ from pygeai_orchestration.dev.testing import MockAgent, PatternTestCase
222
+
223
+
224
+ class Test{pattern_name}(PatternTestCase):
225
+ """Test cases for {pattern_name}."""
226
+
227
+ def setUp(self):
228
+ """Set up test fixtures."""
229
+ self.agent = MockAgent()
230
+ # TODO: Initialize your pattern
231
+ # self.pattern = {pattern_name}(self.agent)
232
+
233
+ async def test_basic_execution(self):
234
+ """Test basic pattern execution."""
235
+ # TODO: Implement test
236
+ pass
237
+
238
+ async def test_error_handling(self):
239
+ """Test error handling."""
240
+ # TODO: Implement test
241
+ pass
242
+
243
+ async def test_result_format(self):
244
+ """Test result format."""
245
+ # TODO: Implement test
246
+ pass
247
+
248
+
249
+ if __name__ == "__main__":
250
+ unittest.main()
251
+ '''
252
+
253
+ @staticmethod
254
+ def save_template(
255
+ code: str,
256
+ output_path: Path,
257
+ overwrite: bool = False
258
+ ) -> None:
259
+ """Save generated template to file.
260
+
261
+ Args:
262
+ code: Generated code
263
+ output_path: Output file path
264
+ overwrite: Whether to overwrite existing file
265
+
266
+ Raises:
267
+ FileExistsError: If file exists and overwrite is False
268
+ """
269
+ if output_path.exists() and not overwrite:
270
+ raise FileExistsError(f"File already exists: {output_path}")
271
+
272
+ output_path.parent.mkdir(parents=True, exist_ok=True)
273
+
274
+ with open(output_path, "w") as f:
275
+ f.write(code)
276
+
277
+ @classmethod
278
+ def create_pattern(
279
+ cls,
280
+ template: PatternTemplate,
281
+ name: str,
282
+ description: str,
283
+ output_dir: Optional[Path] = None,
284
+ include_tests: bool = True
285
+ ) -> Dict[str, str]:
286
+ """Create complete pattern with optional tests.
287
+
288
+ Args:
289
+ template: Pattern template type
290
+ name: Pattern class name
291
+ description: Pattern description
292
+ output_dir: Output directory (optional)
293
+ include_tests: Generate test file
294
+
295
+ Returns:
296
+ Dictionary of filename -> code
297
+ """
298
+ files = {}
299
+
300
+ if template == PatternTemplate.REFLECTION:
301
+ code = cls.generate_reflection_pattern(name, description)
302
+ elif template == PatternTemplate.REACT:
303
+ code = cls.generate_react_pattern(name, description)
304
+ else:
305
+ code = cls.generate_custom_pattern(name, description)
306
+
307
+ pattern_filename = f"{name.lower()}.py"
308
+ files[pattern_filename] = code
309
+
310
+ if include_tests:
311
+ test_code = cls.generate_test_file(name, template)
312
+ test_filename = f"test_{name.lower()}.py"
313
+ files[test_filename] = test_code
314
+
315
+ if output_dir:
316
+ output_path = Path(output_dir)
317
+ for filename, content in files.items():
318
+ file_path = output_path / filename
319
+ cls.save_template(content, file_path)
320
+
321
+ return files
@@ -0,0 +1,301 @@
1
+ """Testing utilities and helpers."""
2
+
3
+ import unittest
4
+ from typing import Any, Dict, List, Optional
5
+ from unittest.mock import AsyncMock, MagicMock
6
+
7
+ from pygeai_orchestration.core.base import BasePattern, PatternConfig, PatternResult, PatternType
8
+
9
+
10
+ class MockAgent:
11
+ """Mock agent for testing."""
12
+
13
+ def __init__(self, responses: Optional[List[str]] = None):
14
+ """Initialize mock agent.
15
+
16
+ Args:
17
+ responses: Pre-defined responses
18
+ """
19
+ self.responses = responses or ["Mock response"]
20
+ self.call_count = 0
21
+ self.calls: List[Dict[str, Any]] = []
22
+
23
+ async def generate(self, prompt: str, **kwargs) -> str:
24
+ """Generate mock response.
25
+
26
+ Args:
27
+ prompt: Input prompt
28
+ **kwargs: Additional arguments
29
+
30
+ Returns:
31
+ Mock response
32
+ """
33
+ self.calls.append({
34
+ "prompt": prompt,
35
+ "kwargs": kwargs,
36
+ "call_number": self.call_count
37
+ })
38
+
39
+ response_index = min(self.call_count, len(self.responses) - 1)
40
+ response = self.responses[response_index]
41
+ self.call_count += 1
42
+
43
+ return response
44
+
45
+ async def chat(self, messages: List[Dict[str, str]], **kwargs) -> str:
46
+ """Mock chat method.
47
+
48
+ Args:
49
+ messages: Chat messages
50
+ **kwargs: Additional arguments
51
+
52
+ Returns:
53
+ Mock response
54
+ """
55
+ last_message = messages[-1]["content"] if messages else ""
56
+ return await self.generate(last_message, **kwargs)
57
+
58
+ def reset(self) -> None:
59
+ """Reset mock agent state."""
60
+ self.call_count = 0
61
+ self.calls.clear()
62
+
63
+
64
+ class MockPattern(BasePattern):
65
+ """Mock pattern for testing."""
66
+
67
+ def __init__(
68
+ self,
69
+ name: str = "MockPattern",
70
+ result: str = "Mock result",
71
+ success: bool = True,
72
+ iterations: int = 1
73
+ ):
74
+ """Initialize mock pattern.
75
+
76
+ Args:
77
+ name: Pattern name
78
+ result: Result to return
79
+ success: Success status
80
+ iterations: Number of iterations
81
+ """
82
+ config = PatternConfig(
83
+ name=name,
84
+ pattern_type=PatternType.REFLECTION
85
+ )
86
+ super().__init__(config)
87
+
88
+ self.agent = MockAgent([result])
89
+ self.mock_result = result
90
+ self.mock_success = success
91
+ self.mock_iterations = iterations
92
+ self.execution_count = 0
93
+
94
+ async def execute(self, task: str, **kwargs) -> PatternResult:
95
+ """Execute mock pattern.
96
+
97
+ Args:
98
+ task: Task to execute
99
+ **kwargs: Additional arguments
100
+
101
+ Returns:
102
+ Mock result
103
+ """
104
+ self.execution_count += 1
105
+
106
+ return PatternResult(
107
+ success=self.mock_success,
108
+ result=self.mock_result,
109
+ iterations=self.mock_iterations,
110
+ metadata={"execution_count": self.execution_count}
111
+ )
112
+
113
+ async def step(self, task: str, context=None) -> PatternResult:
114
+ """Execute one step.
115
+
116
+ Args:
117
+ task: Task to execute
118
+ context: Optional context
119
+
120
+ Returns:
121
+ Mock result
122
+ """
123
+ return await self.execute(task)
124
+
125
+
126
+ class PatternTestCase(unittest.IsolatedAsyncioTestCase):
127
+ """Base test case for pattern testing."""
128
+
129
+ def create_mock_agent(self, responses: Optional[List[str]] = None) -> MockAgent:
130
+ """Create mock agent for testing.
131
+
132
+ Args:
133
+ responses: Pre-defined responses
134
+
135
+ Returns:
136
+ Mock agent instance
137
+ """
138
+ return MockAgent(responses)
139
+
140
+ def assert_pattern_result(
141
+ self,
142
+ result: PatternResult,
143
+ success: Optional[bool] = None,
144
+ has_result: bool = True,
145
+ min_iterations: int = 1
146
+ ) -> None:
147
+ """Assert pattern result properties.
148
+
149
+ Args:
150
+ result: Pattern result to check
151
+ success: Expected success status
152
+ has_result: Whether result should have output
153
+ min_iterations: Minimum iterations
154
+ """
155
+ self.assertIsInstance(result, PatternResult)
156
+
157
+ if success is not None:
158
+ self.assertEqual(result.success, success)
159
+
160
+ if has_result:
161
+ self.assertIsNotNone(result.result)
162
+ self.assertNotEqual(result.result, "")
163
+
164
+ self.assertGreaterEqual(result.iterations, min_iterations)
165
+
166
+ def assert_agent_called(
167
+ self,
168
+ agent: MockAgent,
169
+ min_calls: int = 1,
170
+ contains: Optional[str] = None
171
+ ) -> None:
172
+ """Assert agent was called correctly.
173
+
174
+ Args:
175
+ agent: Mock agent
176
+ min_calls: Minimum number of calls
177
+ contains: Text that should be in prompts
178
+ """
179
+ self.assertGreaterEqual(agent.call_count, min_calls)
180
+
181
+ if contains:
182
+ prompts = [call["prompt"] for call in agent.calls]
183
+ self.assertTrue(
184
+ any(contains in prompt for prompt in prompts),
185
+ f"No prompt contains '{contains}'"
186
+ )
187
+
188
+
189
+ def create_test_pattern(
190
+ pattern_class: type,
191
+ agent_responses: Optional[List[str]] = None,
192
+ config_overrides: Optional[Dict[str, Any]] = None
193
+ ) -> BasePattern:
194
+ """Create pattern instance for testing.
195
+
196
+ Args:
197
+ pattern_class: Pattern class to instantiate
198
+ agent_responses: Mock agent responses
199
+ config_overrides: Configuration overrides
200
+
201
+ Returns:
202
+ Pattern instance
203
+ """
204
+ config_dict = {
205
+ "name": pattern_class.__name__,
206
+ "pattern_type": PatternType.REFLECTION
207
+ }
208
+
209
+ if config_overrides:
210
+ config_dict.update(config_overrides)
211
+
212
+ config = PatternConfig(**config_dict)
213
+ pattern = pattern_class(config)
214
+
215
+ if agent_responses:
216
+ pattern.agent = MockAgent(agent_responses)
217
+
218
+ return pattern
219
+
220
+
221
+ class AsyncMockHelper:
222
+ """Helper for creating async mocks."""
223
+
224
+ @staticmethod
225
+ def create_async_mock(return_value: Any = None) -> AsyncMock:
226
+ """Create async mock with return value.
227
+
228
+ Args:
229
+ return_value: Value to return
230
+
231
+ Returns:
232
+ Async mock
233
+ """
234
+ mock = AsyncMock()
235
+ mock.return_value = return_value
236
+ return mock
237
+
238
+ @staticmethod
239
+ def create_agent_mock(responses: List[str]) -> MagicMock:
240
+ """Create mock agent with multiple responses.
241
+
242
+ Args:
243
+ responses: List of responses
244
+
245
+ Returns:
246
+ Mock agent
247
+ """
248
+ agent = MagicMock()
249
+ agent.generate = AsyncMock(side_effect=responses)
250
+ return agent
251
+
252
+
253
+ class TestDataBuilder:
254
+ """Builder for test data."""
255
+
256
+ @staticmethod
257
+ def build_pattern_result(
258
+ success: bool = True,
259
+ result: str = "Test result",
260
+ iterations: int = 1,
261
+ **metadata
262
+ ) -> PatternResult:
263
+ """Build pattern result for testing.
264
+
265
+ Args:
266
+ success: Success status
267
+ result: Result string
268
+ iterations: Number of iterations
269
+ **metadata: Additional metadata
270
+
271
+ Returns:
272
+ Pattern result
273
+ """
274
+ return PatternResult(
275
+ success=success,
276
+ result=result,
277
+ iterations=iterations,
278
+ metadata=metadata
279
+ )
280
+
281
+ @staticmethod
282
+ def build_pattern_config(
283
+ name: str = "TestPattern",
284
+ pattern_type: PatternType = PatternType.REFLECTION,
285
+ **kwargs
286
+ ) -> PatternConfig:
287
+ """Build pattern config for testing.
288
+
289
+ Args:
290
+ name: Pattern name
291
+ pattern_type: Pattern type
292
+ **kwargs: Additional config
293
+
294
+ Returns:
295
+ Pattern config
296
+ """
297
+ return PatternConfig(
298
+ name=name,
299
+ pattern_type=pattern_type,
300
+ **kwargs
301
+ )
@@ -0,0 +1,15 @@
1
+ from .reflection import ReflectionPattern
2
+ from .tool_use import ToolUsePattern
3
+ from .react import ReActPattern
4
+ from .planning import PlanningPattern, PlanStep
5
+ from .multi_agent import MultiAgentPattern, AgentRole
6
+
7
+ __all__ = [
8
+ "ReflectionPattern",
9
+ "ToolUsePattern",
10
+ "ReActPattern",
11
+ "PlanningPattern",
12
+ "PlanStep",
13
+ "MultiAgentPattern",
14
+ "AgentRole",
15
+ ]