jarviscore-framework 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.
Files changed (55) hide show
  1. examples/calculator_agent_example.py +77 -0
  2. examples/multi_agent_workflow.py +132 -0
  3. examples/research_agent_example.py +76 -0
  4. jarviscore/__init__.py +54 -0
  5. jarviscore/cli/__init__.py +7 -0
  6. jarviscore/cli/__main__.py +33 -0
  7. jarviscore/cli/check.py +404 -0
  8. jarviscore/cli/smoketest.py +371 -0
  9. jarviscore/config/__init__.py +7 -0
  10. jarviscore/config/settings.py +128 -0
  11. jarviscore/core/__init__.py +7 -0
  12. jarviscore/core/agent.py +163 -0
  13. jarviscore/core/mesh.py +463 -0
  14. jarviscore/core/profile.py +64 -0
  15. jarviscore/docs/API_REFERENCE.md +932 -0
  16. jarviscore/docs/CONFIGURATION.md +753 -0
  17. jarviscore/docs/GETTING_STARTED.md +600 -0
  18. jarviscore/docs/TROUBLESHOOTING.md +424 -0
  19. jarviscore/docs/USER_GUIDE.md +983 -0
  20. jarviscore/execution/__init__.py +94 -0
  21. jarviscore/execution/code_registry.py +298 -0
  22. jarviscore/execution/generator.py +268 -0
  23. jarviscore/execution/llm.py +430 -0
  24. jarviscore/execution/repair.py +283 -0
  25. jarviscore/execution/result_handler.py +332 -0
  26. jarviscore/execution/sandbox.py +555 -0
  27. jarviscore/execution/search.py +281 -0
  28. jarviscore/orchestration/__init__.py +18 -0
  29. jarviscore/orchestration/claimer.py +101 -0
  30. jarviscore/orchestration/dependency.py +143 -0
  31. jarviscore/orchestration/engine.py +292 -0
  32. jarviscore/orchestration/status.py +96 -0
  33. jarviscore/p2p/__init__.py +23 -0
  34. jarviscore/p2p/broadcaster.py +353 -0
  35. jarviscore/p2p/coordinator.py +364 -0
  36. jarviscore/p2p/keepalive.py +361 -0
  37. jarviscore/p2p/swim_manager.py +290 -0
  38. jarviscore/profiles/__init__.py +6 -0
  39. jarviscore/profiles/autoagent.py +264 -0
  40. jarviscore/profiles/customagent.py +137 -0
  41. jarviscore_framework-0.1.0.dist-info/METADATA +136 -0
  42. jarviscore_framework-0.1.0.dist-info/RECORD +55 -0
  43. jarviscore_framework-0.1.0.dist-info/WHEEL +5 -0
  44. jarviscore_framework-0.1.0.dist-info/licenses/LICENSE +21 -0
  45. jarviscore_framework-0.1.0.dist-info/top_level.txt +3 -0
  46. tests/conftest.py +44 -0
  47. tests/test_agent.py +165 -0
  48. tests/test_autoagent.py +140 -0
  49. tests/test_autoagent_day4.py +186 -0
  50. tests/test_customagent.py +248 -0
  51. tests/test_integration.py +293 -0
  52. tests/test_llm_fallback.py +185 -0
  53. tests/test_mesh.py +356 -0
  54. tests/test_p2p_integration.py +375 -0
  55. tests/test_remote_sandbox.py +116 -0
tests/test_agent.py ADDED
@@ -0,0 +1,165 @@
1
+ """
2
+ Tests for Agent base class.
3
+ """
4
+ import pytest
5
+ from jarviscore.core.agent import Agent
6
+
7
+
8
+ # Test agent implementations
9
+ class ValidAgent(Agent):
10
+ """Valid agent for testing."""
11
+ role = "test_agent"
12
+ capabilities = ["testing", "validation"]
13
+
14
+ async def execute_task(self, task):
15
+ return {"status": "success", "output": "test result"}
16
+
17
+
18
+ class NoRoleAgent(Agent):
19
+ """Agent without role (should fail validation)."""
20
+ capabilities = ["testing"]
21
+
22
+ async def execute_task(self, task):
23
+ return {"status": "success"}
24
+
25
+
26
+ class NoCapabilitiesAgent(Agent):
27
+ """Agent without capabilities (should fail validation)."""
28
+ role = "no_caps"
29
+
30
+ async def execute_task(self, task):
31
+ return {"status": "success"}
32
+
33
+
34
+ class TestAgentInitialization:
35
+ """Test agent initialization and validation."""
36
+
37
+ def test_valid_agent_creation(self):
38
+ """Test creating a valid agent."""
39
+ agent = ValidAgent()
40
+
41
+ assert agent.role == "test_agent"
42
+ assert agent.capabilities == ["testing", "validation"]
43
+ assert agent.agent_id.startswith("test_agent-")
44
+ assert len(agent.agent_id.split("-")[1]) == 8 # 8-char UUID
45
+
46
+ def test_agent_with_custom_id(self):
47
+ """Test creating agent with custom ID."""
48
+ agent = ValidAgent(agent_id="custom-agent-123")
49
+
50
+ assert agent.agent_id == "custom-agent-123"
51
+ assert agent.role == "test_agent"
52
+
53
+ def test_agent_without_role_fails(self):
54
+ """Test that agent without role raises ValueError."""
55
+ with pytest.raises(ValueError) as exc_info:
56
+ NoRoleAgent()
57
+
58
+ assert "must define 'role' class attribute" in str(exc_info.value)
59
+
60
+ def test_agent_without_capabilities_fails(self):
61
+ """Test that agent without capabilities raises ValueError."""
62
+ with pytest.raises(ValueError) as exc_info:
63
+ NoCapabilitiesAgent()
64
+
65
+ assert "must define 'capabilities' class attribute" in str(exc_info.value)
66
+
67
+ def test_agent_mesh_initially_none(self):
68
+ """Test that agent._mesh is initially None."""
69
+ agent = ValidAgent()
70
+ assert agent._mesh is None
71
+
72
+
73
+ class TestAgentTaskHandling:
74
+ """Test agent task handling capabilities."""
75
+
76
+ def test_can_handle_by_role(self):
77
+ """Test agent can handle task by role."""
78
+ agent = ValidAgent()
79
+
80
+ task = {"role": "test_agent", "task": "Do something"}
81
+ assert agent.can_handle(task) is True
82
+
83
+ def test_can_handle_by_capability(self):
84
+ """Test agent can handle task by capability."""
85
+ agent = ValidAgent()
86
+
87
+ task1 = {"capability": "testing", "task": "Run tests"}
88
+ assert agent.can_handle(task1) is True
89
+
90
+ task2 = {"capability": "validation", "task": "Validate data"}
91
+ assert agent.can_handle(task2) is True
92
+
93
+ def test_cannot_handle_wrong_role(self):
94
+ """Test agent rejects task with wrong role."""
95
+ agent = ValidAgent()
96
+
97
+ task = {"role": "different_agent", "task": "Do something"}
98
+ assert agent.can_handle(task) is False
99
+
100
+ def test_cannot_handle_wrong_capability(self):
101
+ """Test agent rejects task with wrong capability."""
102
+ agent = ValidAgent()
103
+
104
+ task = {"capability": "unknown_capability", "task": "Do something"}
105
+ assert agent.can_handle(task) is False
106
+
107
+ def test_can_handle_no_role_or_capability(self):
108
+ """Test agent behavior when task has no role or capability."""
109
+ agent = ValidAgent()
110
+
111
+ task = {"task": "Do something"}
112
+ assert agent.can_handle(task) is False
113
+
114
+
115
+ class TestAgentExecution:
116
+ """Test agent task execution."""
117
+
118
+ @pytest.mark.asyncio
119
+ async def test_execute_task_implementation(self):
120
+ """Test that execute_task can be called and returns result."""
121
+ agent = ValidAgent()
122
+
123
+ task = {"task": "Test task"}
124
+ result = await agent.execute_task(task)
125
+
126
+ assert result["status"] == "success"
127
+ assert result["output"] == "test result"
128
+
129
+
130
+ class TestAgentLifecycle:
131
+ """Test agent setup and teardown lifecycle."""
132
+
133
+ @pytest.mark.asyncio
134
+ async def test_setup_hook(self):
135
+ """Test agent setup hook."""
136
+ agent = ValidAgent()
137
+ await agent.setup() # Should not raise
138
+
139
+ @pytest.mark.asyncio
140
+ async def test_teardown_hook(self):
141
+ """Test agent teardown hook."""
142
+ agent = ValidAgent()
143
+ await agent.teardown() # Should not raise
144
+
145
+
146
+ class TestAgentRepresentation:
147
+ """Test agent string representations."""
148
+
149
+ def test_repr(self):
150
+ """Test agent __repr__."""
151
+ agent = ValidAgent(agent_id="test-123")
152
+ repr_str = repr(agent)
153
+
154
+ assert "ValidAgent" in repr_str
155
+ assert "test-123" in repr_str
156
+ assert "test_agent" in repr_str
157
+ assert "testing" in repr_str
158
+
159
+ def test_str(self):
160
+ """Test agent __str__."""
161
+ agent = ValidAgent(agent_id="test-123")
162
+ str_repr = str(agent)
163
+
164
+ assert "test_agent" in str_repr
165
+ assert "test-123" in str_repr
@@ -0,0 +1,140 @@
1
+ """
2
+ Tests for AutoAgent profile.
3
+ """
4
+ import pytest
5
+ from jarviscore.profiles.autoagent import AutoAgent
6
+
7
+
8
+ class ValidAutoAgent(AutoAgent):
9
+ """Valid AutoAgent for testing."""
10
+ role = "test_auto"
11
+ capabilities = ["testing"]
12
+ system_prompt = "You are a test agent that performs testing tasks."
13
+
14
+
15
+ class NoPromptAutoAgent(AutoAgent):
16
+ """AutoAgent without system_prompt (should fail)."""
17
+ role = "no_prompt"
18
+ capabilities = ["testing"]
19
+
20
+
21
+ class TestAutoAgentInitialization:
22
+ """Test AutoAgent initialization."""
23
+
24
+ def test_valid_autoagent_creation(self):
25
+ """Test creating a valid AutoAgent."""
26
+ agent = ValidAutoAgent()
27
+
28
+ assert agent.role == "test_auto"
29
+ assert agent.capabilities == ["testing"]
30
+ assert agent.system_prompt == "You are a test agent that performs testing tasks."
31
+
32
+ def test_autoagent_without_system_prompt_fails(self):
33
+ """Test that AutoAgent without system_prompt raises ValueError."""
34
+ with pytest.raises(ValueError) as exc_info:
35
+ NoPromptAutoAgent()
36
+
37
+ assert "must define 'system_prompt'" in str(exc_info.value)
38
+
39
+ def test_autoagent_execution_components_initially_none(self):
40
+ """Test that execution components are initially None."""
41
+ agent = ValidAutoAgent()
42
+
43
+ assert agent.llm is None
44
+ assert agent.codegen is None
45
+ assert agent.sandbox is None
46
+ assert agent.repair is None
47
+
48
+
49
+ class TestAutoAgentSetup:
50
+ """Test AutoAgent setup."""
51
+
52
+ @pytest.mark.asyncio
53
+ async def test_autoagent_setup(self):
54
+ """Test AutoAgent setup hook."""
55
+ agent = ValidAutoAgent()
56
+ await agent.setup()
57
+
58
+ # Day 1: Just verify it runs without error
59
+ # Day 4: Will test actual LLM initialization
60
+
61
+
62
+ class TestAutoAgentExecution:
63
+ """Test AutoAgent task execution."""
64
+
65
+ @pytest.mark.asyncio
66
+ async def test_execute_task_without_setup_fails(self):
67
+ """Test AutoAgent execute_task fails gracefully without setup."""
68
+ agent = ValidAutoAgent()
69
+
70
+ task = {"task": "Test task description"}
71
+ result = await agent.execute_task(task)
72
+
73
+ # Day 4: Should fail gracefully when components not initialized
74
+ assert result["status"] == "failure"
75
+ assert "Fatal error" in result.get("error", "")
76
+
77
+ @pytest.mark.asyncio
78
+ async def test_execute_task_with_mock_components(self):
79
+ """Test AutoAgent with mocked execution components."""
80
+ from unittest.mock import Mock, AsyncMock
81
+
82
+ agent = ValidAutoAgent()
83
+
84
+ # Mock the execution components
85
+ agent.codegen = Mock()
86
+ agent.codegen.generate = AsyncMock(return_value="result = 42")
87
+
88
+ agent.sandbox = Mock()
89
+ agent.sandbox.execute = AsyncMock(return_value={
90
+ "status": "success",
91
+ "output": 42
92
+ })
93
+
94
+ agent.repair = Mock() # Not called if execution succeeds
95
+
96
+ # Mock result handler (Phase 1)
97
+ agent.result_handler = Mock()
98
+ agent.result_handler.process_result = Mock(return_value={
99
+ 'result_id': 'test-result-id',
100
+ 'status': 'success'
101
+ })
102
+
103
+ # Mock code registry (Phase 3)
104
+ agent.code_registry = Mock()
105
+ agent.code_registry.register = Mock(return_value='test-function-id')
106
+
107
+ task = {"task": "Calculate 21 * 2"}
108
+ result = await agent.execute_task(task)
109
+
110
+ # Should succeed with mocked components
111
+ assert result["status"] == "success"
112
+ assert result["output"] == 42
113
+ assert result["code"] == "result = 42"
114
+
115
+
116
+ class TestAutoAgentInheritance:
117
+ """Test AutoAgent inheritance from Profile and Agent."""
118
+
119
+ def test_autoagent_inherits_agent_methods(self):
120
+ """Test that AutoAgent inherits Agent methods."""
121
+ agent = ValidAutoAgent()
122
+
123
+ # Should have Agent methods
124
+ assert hasattr(agent, "can_handle")
125
+ assert hasattr(agent, "execute_task")
126
+ assert hasattr(agent, "setup")
127
+ assert hasattr(agent, "teardown")
128
+
129
+ def test_autoagent_can_handle_tasks(self):
130
+ """Test that AutoAgent can check task compatibility."""
131
+ agent = ValidAutoAgent()
132
+
133
+ task1 = {"role": "test_auto", "task": "Do something"}
134
+ assert agent.can_handle(task1) is True
135
+
136
+ task2 = {"capability": "testing", "task": "Run tests"}
137
+ assert agent.can_handle(task2) is True
138
+
139
+ task3 = {"role": "different", "task": "Won't handle"}
140
+ assert agent.can_handle(task3) is False
@@ -0,0 +1,186 @@
1
+ """
2
+ Tests for Day 4: AutoAgent with Code Generation
3
+
4
+ Tests the complete execution pipeline:
5
+ - LLM client initialization
6
+ - Code generation
7
+ - Sandbox execution
8
+ - Autonomous repair
9
+ """
10
+ import pytest
11
+ import asyncio
12
+ from jarviscore.profiles import AutoAgent
13
+ from jarviscore.execution import (
14
+ create_llm_client,
15
+ create_search_client,
16
+ create_code_generator,
17
+ create_sandbox_executor,
18
+ create_autonomous_repair
19
+ )
20
+
21
+
22
+ class SimpleAgent(AutoAgent):
23
+ """Test agent for unit tests."""
24
+ role = "test_agent"
25
+ capabilities = ["testing"]
26
+ system_prompt = "You are a test agent."
27
+
28
+
29
+ def test_autoagent_initialization():
30
+ """Test AutoAgent can be instantiated."""
31
+ agent = SimpleAgent()
32
+ assert agent.role == "test_agent"
33
+ assert agent.capabilities == ["testing"]
34
+ assert agent.system_prompt == "You are a test agent."
35
+
36
+
37
+ @pytest.mark.asyncio
38
+ async def test_execution_components_creation():
39
+ """Test all execution components can be created."""
40
+ # LLM client (no config, just instantiation test)
41
+ llm = create_llm_client({})
42
+ assert llm is not None
43
+
44
+ # Search client
45
+ search = create_search_client()
46
+ assert search is not None
47
+
48
+ # Code generator
49
+ codegen = create_code_generator(llm, search)
50
+ assert codegen is not None
51
+
52
+ # Sandbox executor
53
+ sandbox = create_sandbox_executor(timeout=60, search_client=search)
54
+ assert sandbox is not None
55
+
56
+ # Autonomous repair
57
+ repair = create_autonomous_repair(codegen)
58
+ assert repair is not None
59
+
60
+
61
+ @pytest.mark.asyncio
62
+ async def test_sandbox_simple_execution():
63
+ """Test sandbox can execute simple code."""
64
+ from jarviscore.execution import SandboxExecutor
65
+
66
+ sandbox = SandboxExecutor(timeout=10)
67
+
68
+ code = """
69
+ # Simple calculation
70
+ result = 2 + 2
71
+ """
72
+
73
+ result = await sandbox.execute(code)
74
+
75
+ assert result['status'] == 'success'
76
+ assert result['output'] == 4
77
+
78
+
79
+ @pytest.mark.asyncio
80
+ async def test_sandbox_async_execution():
81
+ """Test sandbox can execute async code."""
82
+ from jarviscore.execution import SandboxExecutor
83
+
84
+ sandbox = SandboxExecutor(timeout=10)
85
+
86
+ code = """
87
+ import asyncio
88
+
89
+ async def main():
90
+ await asyncio.sleep(0.01)
91
+ return 42
92
+
93
+ # The result will be extracted by sandbox's _execute_async
94
+ """
95
+
96
+ result = await sandbox.execute(code)
97
+
98
+ assert result['status'] == 'success'
99
+ assert result['output'] == 42
100
+
101
+
102
+ @pytest.mark.asyncio
103
+ async def test_sandbox_error_handling():
104
+ """Test sandbox properly handles errors."""
105
+ from jarviscore.execution import SandboxExecutor
106
+
107
+ sandbox = SandboxExecutor(timeout=10)
108
+
109
+ code = """
110
+ # This will raise an error
111
+ result = 1 / 0
112
+ """
113
+
114
+ result = await sandbox.execute(code)
115
+
116
+ assert result['status'] == 'failure'
117
+ assert 'ZeroDivisionError' in result.get('error_type', '')
118
+
119
+
120
+ @pytest.mark.asyncio
121
+ async def test_code_generator_validation():
122
+ """Test code generator validates syntax."""
123
+ from jarviscore.execution import CodeGenerator, UnifiedLLMClient
124
+
125
+ llm = UnifiedLLMClient({})
126
+ codegen = CodeGenerator(llm, None)
127
+
128
+ # Test syntax validation
129
+ valid_code = "result = 42"
130
+ codegen._validate_code(valid_code) # Should not raise
131
+
132
+ invalid_code = "result = if 42"
133
+ with pytest.raises(ValueError):
134
+ codegen._validate_code(invalid_code)
135
+
136
+
137
+ @pytest.mark.asyncio
138
+ async def test_code_generator_cleaning():
139
+ """Test code generator cleans markdown blocks."""
140
+ from jarviscore.execution import CodeGenerator, UnifiedLLMClient
141
+
142
+ llm = UnifiedLLMClient({})
143
+ codegen = CodeGenerator(llm, None)
144
+
145
+ # Test cleaning markdown blocks
146
+ markdown_code = """
147
+ ```python
148
+ result = 42
149
+ ```
150
+ """
151
+
152
+ cleaned = codegen._clean_code(markdown_code)
153
+ assert cleaned == "result = 42"
154
+
155
+
156
+ def test_autoagent_requires_system_prompt():
157
+ """Test AutoAgent requires system_prompt."""
158
+ with pytest.raises(ValueError) as exc_info:
159
+ class BadAgent(AutoAgent):
160
+ role = "bad"
161
+ capabilities = ["test"]
162
+ # Missing system_prompt
163
+
164
+ BadAgent()
165
+
166
+ assert "system_prompt" in str(exc_info.value)
167
+
168
+
169
+ @pytest.mark.asyncio
170
+ async def test_search_client_initialization():
171
+ """Test search client can be created and initialized."""
172
+ from jarviscore.execution import InternetSearch
173
+
174
+ search = InternetSearch()
175
+ await search.initialize()
176
+
177
+ assert search.session is not None
178
+ assert not search.session.closed
179
+
180
+ await search.close()
181
+ assert search.session is None
182
+
183
+
184
+ if __name__ == "__main__":
185
+ # Run tests with pytest
186
+ pytest.main([__file__, "-v"])