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
@@ -0,0 +1,404 @@
1
+ """
2
+ JarvisCore Health Check CLI
3
+
4
+ Validates installation, configuration, and LLM connectivity.
5
+
6
+ Usage:
7
+ python -m jarviscore.cli.check # Basic health check
8
+ python -m jarviscore.cli.check --validate-llm # Test LLM connectivity
9
+ python -m jarviscore.cli.check --verbose # Show detailed info
10
+ """
11
+
12
+ import sys
13
+ import os
14
+ import asyncio
15
+ from pathlib import Path
16
+ from typing import Dict, List, Tuple
17
+ import importlib.util
18
+
19
+
20
+ class HealthChecker:
21
+ """Health check orchestrator for JarvisCore setup."""
22
+
23
+ def __init__(self, validate_llm: bool = False, verbose: bool = False):
24
+ self.validate_llm = validate_llm
25
+ self.verbose = verbose
26
+ self.issues: List[str] = []
27
+ self.warnings: List[str] = []
28
+ self.successes: List[str] = []
29
+
30
+ def print_header(self):
31
+ """Print check header."""
32
+ print("\n" + "="*70)
33
+ print(" JarvisCore Health Check")
34
+ print(" Testing AutoAgent/Prompt-Dev Profile")
35
+ print("="*70 + "\n")
36
+
37
+ def check_python_version(self) -> bool:
38
+ """Check Python version >= 3.10."""
39
+ version = sys.version_info
40
+ status = version >= (3, 10)
41
+
42
+ if status:
43
+ self.successes.append(f"Python {version.major}.{version.minor}.{version.micro}")
44
+ else:
45
+ self.issues.append(
46
+ f"Python {version.major}.{version.minor} found, but 3.10+ required"
47
+ )
48
+
49
+ self._print_status("Python Version", status,
50
+ f"{version.major}.{version.minor}.{version.micro}")
51
+ return status
52
+
53
+ def check_jarviscore_installed(self) -> bool:
54
+ """Check if jarviscore package is installed."""
55
+ try:
56
+ import jarviscore
57
+ version = getattr(jarviscore, '__version__', '0.1.0')
58
+ self.successes.append(f"JarvisCore {version} installed")
59
+ self._print_status("JarvisCore Package", True, f"v{version}")
60
+ return True
61
+ except ImportError as e:
62
+ self.issues.append(f"JarvisCore not installed: {e}")
63
+ self._print_status("JarvisCore Package", False, "Not found")
64
+ return False
65
+
66
+ def check_dependencies(self) -> Dict[str, bool]:
67
+ """Check core dependencies."""
68
+ deps = {
69
+ 'pydantic': 'Core validation',
70
+ 'pydantic_settings': 'Configuration management',
71
+ }
72
+
73
+ results = {}
74
+ print("\n[Dependencies]")
75
+
76
+ for dep, description in deps.items():
77
+ try:
78
+ spec = importlib.util.find_spec(dep)
79
+ installed = spec is not None
80
+ results[dep] = installed
81
+
82
+ if installed:
83
+ self.successes.append(f"{dep}: {description}")
84
+ else:
85
+ self.issues.append(f"{dep} not installed: {description}")
86
+
87
+ self._print_status(f" {dep}", installed, description)
88
+ except Exception as e:
89
+ results[dep] = False
90
+ self.issues.append(f"{dep} check failed: {e}")
91
+ self._print_status(f" {dep}", False, str(e))
92
+
93
+ return results
94
+
95
+ def check_env_file(self) -> Tuple[bool, Path]:
96
+ """Check if .env file exists."""
97
+ env_paths = [
98
+ Path.cwd() / '.env',
99
+ Path.cwd() / 'jarviscore' / '.env',
100
+ ]
101
+
102
+ for env_path in env_paths:
103
+ if env_path.exists():
104
+ self.successes.append(f".env found at {env_path}")
105
+ self._print_status(".env File", True, str(env_path))
106
+ return True, env_path
107
+
108
+ self.warnings.append(".env file not found - using environment variables")
109
+ self._print_status(".env File", False, "Not found (will use environment vars)")
110
+ return False, None
111
+
112
+ def check_llm_config(self) -> Dict[str, bool]:
113
+ """Check which LLM providers are configured."""
114
+ providers = {
115
+ 'Claude': ['CLAUDE_API_KEY', 'ANTHROPIC_API_KEY'],
116
+ 'Azure OpenAI': ['AZURE_API_KEY', 'AZURE_OPENAI_KEY'],
117
+ 'Gemini': ['GEMINI_API_KEY'],
118
+ 'vLLM': ['LLM_ENDPOINT'],
119
+ }
120
+
121
+ configured = {}
122
+ print("\n[LLM Configuration]")
123
+
124
+ for provider, env_vars in providers.items():
125
+ is_configured = any(os.getenv(var) for var in env_vars)
126
+ configured[provider] = is_configured
127
+
128
+ if is_configured:
129
+ key_name = next(var for var in env_vars if os.getenv(var))
130
+ masked = self._mask_api_key(os.getenv(key_name))
131
+ self.successes.append(f"{provider} configured")
132
+ self._print_status(f" {provider}", True, f"{key_name}={masked}")
133
+ else:
134
+ self._print_status(f" {provider}", False, "Not configured")
135
+
136
+ if not any(configured.values()):
137
+ self.issues.append(
138
+ "No LLM provider configured. AutoAgent requires at least one LLM."
139
+ )
140
+
141
+ return configured
142
+
143
+ async def validate_llm_connectivity(self, configured: Dict[str, bool]):
144
+ """Test actual LLM connectivity."""
145
+ print("\n[LLM Connectivity Test]")
146
+
147
+ # Load environment
148
+ from dotenv import load_dotenv
149
+ load_dotenv()
150
+
151
+ # Try each configured provider
152
+ for provider, is_configured in configured.items():
153
+ if not is_configured:
154
+ continue
155
+
156
+ try:
157
+ if provider == "Claude":
158
+ success = await self._test_claude()
159
+ elif provider == "Azure OpenAI":
160
+ success = await self._test_azure()
161
+ elif provider == "Gemini":
162
+ success = await self._test_gemini()
163
+ elif provider == "vLLM":
164
+ success = await self._test_vllm()
165
+ else:
166
+ continue
167
+
168
+ if success:
169
+ self.successes.append(f"{provider} connectivity OK")
170
+ self._print_status(f" {provider} API", True, "Connected")
171
+ else:
172
+ self.issues.append(f"{provider} connection failed")
173
+ self._print_status(f" {provider} API", False, "Connection failed")
174
+
175
+ except Exception as e:
176
+ self.issues.append(f"{provider} test failed: {str(e)}")
177
+ self._print_status(f" {provider} API", False, str(e))
178
+
179
+ async def _test_claude(self) -> bool:
180
+ """Test Claude API connectivity."""
181
+ try:
182
+ from anthropic import AsyncAnthropic
183
+
184
+ api_key = os.getenv('CLAUDE_API_KEY') or os.getenv('ANTHROPIC_API_KEY')
185
+ if not api_key:
186
+ return False
187
+
188
+ client = AsyncAnthropic(api_key=api_key)
189
+
190
+ # Simple test message
191
+ response = await client.messages.create(
192
+ model=os.getenv('CLAUDE_MODEL', 'claude-sonnet-4'),
193
+ max_tokens=10,
194
+ messages=[{"role": "user", "content": "Reply with just 'OK'"}]
195
+ )
196
+
197
+ return response.content[0].text.strip().upper() == 'OK'
198
+
199
+ except Exception:
200
+ return False
201
+
202
+ async def _test_azure(self) -> bool:
203
+ """Test Azure OpenAI connectivity."""
204
+ try:
205
+ from openai import AsyncAzureOpenAI
206
+
207
+ client = AsyncAzureOpenAI(
208
+ api_key=os.getenv('AZURE_API_KEY') or os.getenv('AZURE_OPENAI_KEY'),
209
+ api_version=os.getenv('AZURE_API_VERSION', '2024-02-15-preview'),
210
+ azure_endpoint=os.getenv('AZURE_ENDPOINT')
211
+ )
212
+
213
+ response = await client.chat.completions.create(
214
+ model=os.getenv('AZURE_DEPLOYMENT', 'gpt-4o'),
215
+ messages=[{"role": "user", "content": "Reply with just 'OK'"}],
216
+ max_tokens=10
217
+ )
218
+
219
+ return response.choices[0].message.content.strip().upper() == 'OK'
220
+
221
+ except Exception:
222
+ return False
223
+
224
+ async def _test_gemini(self) -> bool:
225
+ """Test Gemini connectivity."""
226
+ try:
227
+ import google.generativeai as genai
228
+
229
+ genai.configure(api_key=os.getenv('GEMINI_API_KEY'))
230
+ model = genai.GenerativeModel(os.getenv('GEMINI_MODEL', 'gemini-1.5-flash'))
231
+
232
+ response = await model.generate_content_async("Reply with just 'OK'")
233
+ return 'OK' in response.text.upper()
234
+
235
+ except Exception:
236
+ return False
237
+
238
+ async def _test_vllm(self) -> bool:
239
+ """Test vLLM endpoint connectivity."""
240
+ try:
241
+ import httpx
242
+
243
+ endpoint = os.getenv('LLM_ENDPOINT')
244
+ if not endpoint:
245
+ return False
246
+
247
+ async with httpx.AsyncClient(timeout=10.0) as client:
248
+ response = await client.get(f"{endpoint}/health")
249
+ return response.status_code == 200
250
+
251
+ except Exception:
252
+ return False
253
+
254
+ def check_sandbox_config(self):
255
+ """Check sandbox configuration."""
256
+ print("\n[Sandbox Configuration]")
257
+
258
+ mode = os.getenv('SANDBOX_MODE', 'local')
259
+ self._print_status(" Sandbox Mode", True, mode)
260
+
261
+ if mode == 'remote':
262
+ service_url = os.getenv('SANDBOX_SERVICE_URL')
263
+ if service_url:
264
+ self.successes.append(f"Remote sandbox: {service_url}")
265
+ self._print_status(" Remote Service", True, service_url)
266
+ else:
267
+ self.warnings.append("SANDBOX_MODE=remote but no SANDBOX_SERVICE_URL set")
268
+ self._print_status(" Remote Service", False, "URL not set")
269
+
270
+ def print_summary(self):
271
+ """Print summary and recommendations."""
272
+ print("\n" + "="*70)
273
+ print(" Summary")
274
+ print("="*70 + "\n")
275
+
276
+ total_checks = len(self.successes) + len(self.issues) + len(self.warnings)
277
+
278
+ if self.successes:
279
+ print(f"✓ {len(self.successes)} checks passed")
280
+
281
+ if self.warnings:
282
+ print(f"⚠ {len(self.warnings)} warnings")
283
+ for warning in self.warnings:
284
+ print(f" - {warning}")
285
+
286
+ if self.issues:
287
+ print(f"\n✗ {len(self.issues)} issues found:")
288
+ for issue in self.issues:
289
+ print(f" - {issue}")
290
+
291
+ print("\n" + "="*70)
292
+ print(" Next Steps")
293
+ print("="*70)
294
+ print("\n1. Copy .env.example to .env:")
295
+ print(" cp .env.example .env")
296
+ print("\n2. Add your LLM API key to .env (choose one):")
297
+ print(" - CLAUDE_API_KEY=sk-ant-...")
298
+ print(" - AZURE_API_KEY=...")
299
+ print(" - GEMINI_API_KEY=...")
300
+ print(" - LLM_ENDPOINT=http://localhost:8000 (for local vLLM)")
301
+ print("\n3. Run health check again:")
302
+ print(" python -m jarviscore.cli.check --validate-llm")
303
+ print("\n4. Try the smoke test:")
304
+ print(" python -m jarviscore.cli.smoketest")
305
+ print()
306
+
307
+ return False
308
+
309
+ print("\n✓ All checks passed! Ready to use JarvisCore.\n")
310
+ print("Next steps:")
311
+ print(" 1. Run smoke test: python -m jarviscore.cli.smoketest")
312
+ print(" 2. Try examples: python examples/calculator_agent_example.py")
313
+ print(" 3. Read guide: docs/GETTING_STARTED.md")
314
+ print()
315
+
316
+ return True
317
+
318
+ def _print_status(self, label: str, status: bool, detail: str = ""):
319
+ """Print a status line with symbol."""
320
+ symbol = "✓" if status else ("⚠" if detail else "✗")
321
+ label_padded = f"{label}:".ljust(30)
322
+
323
+ if self.verbose or not status:
324
+ print(f"{symbol} {label_padded} {detail}")
325
+ else:
326
+ print(f"{symbol} {label_padded} OK")
327
+
328
+ def _mask_api_key(self, key: str) -> str:
329
+ """Mask API key for display."""
330
+ if not key:
331
+ return "None"
332
+ if len(key) <= 8:
333
+ return "*" * len(key)
334
+ return f"{key[:4]}...{key[-4:]}"
335
+
336
+ async def run(self) -> bool:
337
+ """Run all health checks."""
338
+ self.print_header()
339
+
340
+ # Basic checks
341
+ print("[System Requirements]")
342
+ python_ok = self.check_python_version()
343
+ jarviscore_ok = self.check_jarviscore_installed()
344
+
345
+ if not python_ok or not jarviscore_ok:
346
+ self.print_summary()
347
+ return False
348
+
349
+ # Dependency checks
350
+ deps_ok = self.check_dependencies()
351
+
352
+ # Configuration checks
353
+ print()
354
+ env_exists, env_path = self.check_env_file()
355
+
356
+ # Load .env if it exists
357
+ if env_exists:
358
+ from dotenv import load_dotenv
359
+ load_dotenv(env_path)
360
+
361
+ llm_configured = self.check_llm_config()
362
+
363
+ # LLM connectivity test (optional)
364
+ if self.validate_llm and any(llm_configured.values()):
365
+ await self.validate_llm_connectivity(llm_configured)
366
+
367
+ # Sandbox config
368
+ self.check_sandbox_config()
369
+
370
+ # Summary
371
+ return self.print_summary()
372
+
373
+
374
+ def main():
375
+ """CLI entry point."""
376
+ import argparse
377
+
378
+ parser = argparse.ArgumentParser(
379
+ description='JarvisCore Health Check - Validate your installation'
380
+ )
381
+ parser.add_argument(
382
+ '--validate-llm',
383
+ action='store_true',
384
+ help='Test LLM API connectivity (makes actual API calls)'
385
+ )
386
+ parser.add_argument(
387
+ '--verbose',
388
+ action='store_true',
389
+ help='Show detailed information'
390
+ )
391
+
392
+ args = parser.parse_args()
393
+
394
+ checker = HealthChecker(
395
+ validate_llm=args.validate_llm,
396
+ verbose=args.verbose
397
+ )
398
+
399
+ success = asyncio.run(checker.run())
400
+ sys.exit(0 if success else 1)
401
+
402
+
403
+ if __name__ == '__main__':
404
+ main()