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,932 @@
1
+ # JarvisCore API Reference
2
+
3
+ Complete API documentation for JarvisCore framework components.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Core Components](#core-components)
10
+ - [Mesh](#mesh)
11
+ - [Agent](#agent)
12
+ - [Profile](#profile)
13
+ 2. [Agent Profiles](#agent-profiles)
14
+ - [AutoAgent](#autoagent)
15
+ - [CustomAgent](#customagent)
16
+ 3. [Execution Components](#execution-components)
17
+ - [CodeGenerator](#codegenerator)
18
+ - [SandboxExecutor](#sandboxexecutor)
19
+ - [AutoRepair](#autorepair)
20
+ 4. [Storage Components](#storage-components)
21
+ - [ResultHandler](#resulthandler)
22
+ - [CodeRegistry](#coderegistry)
23
+ 5. [Orchestration](#orchestration)
24
+ - [WorkflowEngine](#workflowengine)
25
+ 6. [Utilities](#utilities)
26
+ - [InternetSearch](#internetsearch)
27
+ - [UnifiedLLMClient](#unifiedllmclient)
28
+
29
+ ---
30
+
31
+ ## Core Components
32
+
33
+ ### Mesh
34
+
35
+ The central orchestrator for managing agents and workflows.
36
+
37
+ #### Class: `Mesh`
38
+
39
+ ```python
40
+ from jarviscore import Mesh
41
+
42
+ mesh = Mesh(mode="autonomous") # or "distributed"
43
+ ```
44
+
45
+ **Parameters:**
46
+ - `mode` (str): Execution mode - "autonomous" (single-node) or "distributed" (P2P mesh)
47
+ - `config` (dict, optional): Configuration dictionary
48
+
49
+ **Methods:**
50
+
51
+ #### `add_agent(profile_class, role, capabilities, **kwargs)`
52
+
53
+ Register an agent in the mesh.
54
+
55
+ ```python
56
+ from jarviscore.profiles import AutoAgent
57
+
58
+ mesh.add_agent(
59
+ AutoAgent,
60
+ role="calculator",
61
+ capabilities=["math", "calculation"],
62
+ system_prompt="You are a math expert"
63
+ )
64
+ ```
65
+
66
+ **Parameters:**
67
+ - `profile_class`: Agent profile class (AutoAgent or CustomAgent)
68
+ - `role` (str): Unique agent role identifier
69
+ - `capabilities` (list): List of capability strings
70
+ - `**kwargs`: Additional agent-specific parameters
71
+
72
+ **Returns:** Agent instance
73
+
74
+ ---
75
+
76
+ #### `async start()`
77
+
78
+ Start the mesh and initialize all agents.
79
+
80
+ ```python
81
+ await mesh.start()
82
+ ```
83
+
84
+ **Raises:** `RuntimeError` if no agents registered or already started
85
+
86
+ ---
87
+
88
+ #### `async stop()`
89
+
90
+ Stop the mesh and cleanup all agents.
91
+
92
+ ```python
93
+ await mesh.stop()
94
+ ```
95
+
96
+ ---
97
+
98
+ #### `async run_workflow(steps)`
99
+
100
+ Execute a multi-step workflow with dependency management.
101
+
102
+ ```python
103
+ results = await mesh.run_workflow([
104
+ {"agent": "scraper", "task": "Scrape data from URL"},
105
+ {"agent": "processor", "task": "Clean the data", "depends_on": [0]},
106
+ {"agent": "storage", "task": "Save to database", "depends_on": [1]}
107
+ ])
108
+ ```
109
+
110
+ **Parameters:**
111
+ - `steps` (list): List of step dictionaries with keys:
112
+ - `agent` (str): Role or capability of target agent
113
+ - `task` (str): Task description
114
+ - `depends_on` (list, optional): List of step indices/IDs this step depends on
115
+ - `id` (str, optional): Custom step identifier
116
+
117
+ **Returns:** List of result dictionaries
118
+
119
+ ---
120
+
121
+ ### Agent
122
+
123
+ Base class for all agents. Inherit from this to create custom agents.
124
+
125
+ #### Class: `Agent`
126
+
127
+ ```python
128
+ from jarviscore.core import Agent
129
+
130
+ class MyAgent(Agent):
131
+ async def execute_task(self, task):
132
+ # Your implementation
133
+ return {"status": "success", "output": result}
134
+ ```
135
+
136
+ **Attributes:**
137
+ - `agent_id` (str): Unique agent identifier
138
+ - `role` (str): Agent role
139
+ - `capabilities` (list): List of capabilities
140
+ - `mesh`: Reference to parent mesh (set automatically)
141
+
142
+ **Methods:**
143
+
144
+ #### `can_handle(task)`
145
+
146
+ Check if agent can handle a task.
147
+
148
+ ```python
149
+ if agent.can_handle({"agent": "calculator"}):
150
+ result = await agent.execute_task(task)
151
+ ```
152
+
153
+ **Parameters:**
154
+ - `task` (dict): Task dictionary with `agent` or `capability` key
155
+
156
+ **Returns:** bool
157
+
158
+ ---
159
+
160
+ #### `async execute_task(task)`
161
+
162
+ Execute a task (must be implemented by subclasses).
163
+
164
+ ```python
165
+ async def execute_task(self, task):
166
+ task_desc = task.get('task', '')
167
+ # Process task
168
+ return {
169
+ "status": "success",
170
+ "output": result,
171
+ "agent": self.agent_id
172
+ }
173
+ ```
174
+
175
+ **Parameters:**
176
+ - `task` (dict): Task dictionary with `task` key
177
+
178
+ **Returns:** Result dictionary with `status`, `output`, `agent` keys
179
+
180
+ ---
181
+
182
+ ### Profile
183
+
184
+ Base class for agent profiles (AutoAgent, CustomAgent).
185
+
186
+ #### Class: `Profile(Agent)`
187
+
188
+ ```python
189
+ from jarviscore.core import Profile
190
+
191
+ class MyProfile(Profile):
192
+ async def setup(self):
193
+ # Initialize components
194
+ pass
195
+ ```
196
+
197
+ **Methods:**
198
+
199
+ #### `async setup()`
200
+
201
+ Initialize agent components (called during mesh.start()).
202
+
203
+ ```python
204
+ async def setup(self):
205
+ self.llm_client = create_llm_client()
206
+ self.my_tool = MyTool()
207
+ ```
208
+
209
+ ---
210
+
211
+ #### `async teardown()`
212
+
213
+ Cleanup agent resources (called during mesh.stop()).
214
+
215
+ ```python
216
+ async def teardown(self):
217
+ await self.llm_client.close()
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Agent Profiles
223
+
224
+ ### AutoAgent
225
+
226
+ Zero-config autonomous agent with LLM-powered code generation.
227
+
228
+ #### Class: `AutoAgent(Profile)`
229
+
230
+ ```python
231
+ from jarviscore.profiles import AutoAgent
232
+
233
+ agent = AutoAgent(
234
+ role="researcher",
235
+ capabilities=["research", "web_search"],
236
+ system_prompt="You are a research expert",
237
+ enable_search=True
238
+ )
239
+ ```
240
+
241
+ **Parameters:**
242
+ - `role` (str): Agent role identifier
243
+ - `capabilities` (list): List of capability strings
244
+ - `system_prompt` (str): LLM system prompt defining agent expertise
245
+ - `enable_search` (bool, optional): Enable internet search (default: False)
246
+ - `max_repair_attempts` (int, optional): Max code repair attempts (default: 3)
247
+
248
+ **Features:**
249
+ - Automatic LLM-based code generation
250
+ - Autonomous code repair (up to 3 attempts)
251
+ - Internet search integration (DuckDuckGo)
252
+ - Result storage with file-based persistence
253
+ - Code registry for function reuse
254
+ - Local and remote sandbox execution
255
+
256
+ **Example:**
257
+
258
+ ```python
259
+ from jarviscore import Mesh
260
+ from jarviscore.profiles import AutoAgent
261
+
262
+ mesh = Mesh(mode="autonomous")
263
+
264
+ # Add research agent with internet access
265
+ mesh.add_agent(
266
+ AutoAgent,
267
+ role="researcher",
268
+ capabilities=["research", "web_search"],
269
+ system_prompt="You are an expert researcher",
270
+ enable_search=True
271
+ )
272
+
273
+ await mesh.start()
274
+
275
+ # Execute task
276
+ results = await mesh.run_workflow([
277
+ {"agent": "researcher", "task": "Search for Python async tutorials"}
278
+ ])
279
+ ```
280
+
281
+ **AutoAgent Components:**
282
+ - `codegen`: CodeGenerator instance
283
+ - `sandbox`: SandboxExecutor instance
284
+ - `repair`: AutoRepair instance
285
+ - `result_handler`: ResultHandler instance
286
+ - `code_registry`: CodeRegistry instance
287
+ - `search`: InternetSearch instance (if enabled)
288
+
289
+ ---
290
+
291
+ ### CustomAgent
292
+
293
+ Flexible agent profile for integrating external frameworks.
294
+
295
+ #### Class: `CustomAgent(Profile)`
296
+
297
+ ```python
298
+ from jarviscore.profiles import CustomAgent
299
+
300
+ class LangChainAgent(CustomAgent):
301
+ async def setup(self):
302
+ from langchain import LLMChain
303
+ self.chain = LLMChain(...)
304
+
305
+ async def execute_task(self, task):
306
+ result = await self.chain.arun(task['task'])
307
+ return {
308
+ "status": "success",
309
+ "output": result,
310
+ "agent": self.agent_id
311
+ }
312
+ ```
313
+
314
+ **Features:**
315
+ - Integrate LangChain, LlamaIndex, Haystack, CrewAI, etc.
316
+ - Manual control over execution logic
317
+ - Optional cost tracking with `track_cost()`
318
+ - Full access to mesh and workflow context
319
+
320
+ **Example:**
321
+
322
+ ```python
323
+ class APIAgent(CustomAgent):
324
+ async def setup(self):
325
+ self.api_client = MyAPIClient()
326
+
327
+ async def execute_task(self, task):
328
+ # Manual implementation
329
+ response = await self.api_client.call(task['task'])
330
+
331
+ # Optional cost tracking
332
+ self.track_cost(
333
+ input_tokens=100,
334
+ output_tokens=50,
335
+ cost_usd=0.01
336
+ )
337
+
338
+ return {
339
+ "status": "success",
340
+ "output": response,
341
+ "agent": self.agent_id
342
+ }
343
+ ```
344
+
345
+ ---
346
+
347
+ ## Execution Components
348
+
349
+ ### CodeGenerator
350
+
351
+ LLM-based Python code generation from natural language.
352
+
353
+ #### Class: `CodeGenerator`
354
+
355
+ ```python
356
+ from jarviscore.execution import create_code_generator
357
+
358
+ codegen = create_code_generator(llm_client, search_client)
359
+ ```
360
+
361
+ **Parameters:**
362
+ - `llm_client`: UnifiedLLMClient instance
363
+ - `search_client` (optional): InternetSearch instance
364
+
365
+ **Methods:**
366
+
367
+ #### `async generate(task, system_prompt, context=None, enable_search=True)`
368
+
369
+ Generate Python code for a task.
370
+
371
+ ```python
372
+ code = await codegen.generate(
373
+ task={"task": "Calculate factorial of 10"},
374
+ system_prompt="You are a math expert",
375
+ enable_search=False
376
+ )
377
+ ```
378
+
379
+ **Parameters:**
380
+ - `task` (dict): Task dictionary with `task` key
381
+ - `system_prompt` (str): Agent's system prompt
382
+ - `context` (dict, optional): Context from previous steps
383
+ - `enable_search` (bool): Auto-inject search tools if available
384
+
385
+ **Returns:** Python code string
386
+
387
+ **Features:**
388
+ - Automatic syntax validation
389
+ - Code cleaning (removes markdown, comments)
390
+ - Search tool auto-injection for research tasks
391
+ - Context-aware code generation
392
+
393
+ ---
394
+
395
+ ### SandboxExecutor
396
+
397
+ Safe code execution with resource limits and remote execution support.
398
+
399
+ #### Class: `SandboxExecutor`
400
+
401
+ ```python
402
+ from jarviscore.execution import create_sandbox_executor
403
+
404
+ executor = create_sandbox_executor(
405
+ timeout=300,
406
+ search_client=None,
407
+ config={
408
+ 'sandbox_mode': 'remote',
409
+ 'sandbox_service_url': 'https://...'
410
+ }
411
+ )
412
+ ```
413
+
414
+ **Parameters:**
415
+ - `timeout` (int): Max execution time in seconds (default: 300)
416
+ - `search_client` (optional): InternetSearch for web access
417
+ - `config` (dict, optional): Configuration with:
418
+ - `sandbox_mode`: "local" or "remote"
419
+ - `sandbox_service_url`: URL for remote sandbox
420
+
421
+ **Methods:**
422
+
423
+ #### `async execute(code, timeout=None, context=None)`
424
+
425
+ Execute Python code in isolated sandbox.
426
+
427
+ ```python
428
+ result = await executor.execute(
429
+ code="result = 2 + 2",
430
+ timeout=10,
431
+ context={"previous_result": 42}
432
+ )
433
+ ```
434
+
435
+ **Parameters:**
436
+ - `code` (str): Python code to execute
437
+ - `timeout` (int, optional): Override default timeout
438
+ - `context` (dict, optional): Variables to inject into namespace
439
+
440
+ **Returns:**
441
+ ```python
442
+ {
443
+ "status": "success" | "failure",
444
+ "output": Any, # Value of 'result' variable
445
+ "error": str, # Error message if failed
446
+ "error_type": str, # Exception type
447
+ "execution_time": float, # Seconds
448
+ "mode": "local" | "remote"
449
+ }
450
+ ```
451
+
452
+ **Execution Modes:**
453
+
454
+ **Local Mode** (default):
455
+ - In-process execution with isolated namespace
456
+ - Fast, no network latency
457
+ - Perfect for development
458
+
459
+ **Remote Mode** (production):
460
+ - Azure Container Apps sandbox
461
+ - Full isolation, better security
462
+ - Automatic fallback to local on failure
463
+
464
+ **Example:**
465
+ ```python
466
+ # Async code execution
467
+ code = """
468
+ async def main():
469
+ results = await search.search("Python tutorials")
470
+ return results
471
+ """
472
+
473
+ result = await executor.execute(code, timeout=30)
474
+ print(result['output']) # Search results
475
+ ```
476
+
477
+ ---
478
+
479
+ ### AutoRepair
480
+
481
+ Autonomous code repair with LLM-guided error fixing.
482
+
483
+ #### Class: `AutoRepair`
484
+
485
+ ```python
486
+ from jarviscore.execution import create_auto_repair
487
+
488
+ repair = create_auto_repair(llm_client, max_attempts=3)
489
+ ```
490
+
491
+ **Parameters:**
492
+ - `llm_client`: UnifiedLLMClient instance
493
+ - `max_attempts` (int): Maximum repair attempts (default: 3)
494
+
495
+ **Methods:**
496
+
497
+ #### `async repair(code, error_msg, error_type, task, system_prompt)`
498
+
499
+ Attempt to fix broken code.
500
+
501
+ ```python
502
+ fixed_code = await repair.repair(
503
+ code=broken_code,
504
+ error_msg="NameError: name 'x' is not defined",
505
+ error_type="NameError",
506
+ task="Calculate sum of numbers",
507
+ system_prompt="You are a Python expert"
508
+ )
509
+ ```
510
+
511
+ **Parameters:**
512
+ - `code` (str): Broken code
513
+ - `error_msg` (str): Error message from execution
514
+ - `error_type` (str): Exception type
515
+ - `task` (str): Original task description
516
+ - `system_prompt` (str): Agent's system prompt
517
+
518
+ **Returns:** Fixed code string or raises exception
519
+
520
+ ---
521
+
522
+ ## Storage Components
523
+
524
+ ### ResultHandler
525
+
526
+ File-based storage for execution results with in-memory caching.
527
+
528
+ #### Class: `ResultHandler`
529
+
530
+ ```python
531
+ from jarviscore.execution import create_result_handler
532
+
533
+ handler = create_result_handler(log_directory="./logs")
534
+ ```
535
+
536
+ **Parameters:**
537
+ - `log_directory` (str): Base directory for result storage (default: "./logs")
538
+ - `cache_size` (int): Max results in memory cache (default: 1000)
539
+
540
+ **Methods:**
541
+
542
+ #### `process_result(...)`
543
+
544
+ Store execution result.
545
+
546
+ ```python
547
+ stored = handler.process_result(
548
+ agent_id="calculator-abc123",
549
+ task="Calculate factorial",
550
+ code="result = math.factorial(10)",
551
+ output=3628800,
552
+ status="success",
553
+ execution_time=0.001,
554
+ repairs=0
555
+ )
556
+ ```
557
+
558
+ **Parameters:**
559
+ - `agent_id` (str): Agent identifier
560
+ - `task` (str): Task description
561
+ - `code` (str): Executed code
562
+ - `output` (Any): Execution output
563
+ - `status` (str): "success" or "failure"
564
+ - `error` (str, optional): Error message
565
+ - `execution_time` (float, optional): Execution time in seconds
566
+ - `tokens` (dict, optional): Token usage `{input, output, total}`
567
+ - `cost_usd` (float, optional): Cost in USD
568
+ - `repairs` (int, optional): Number of repair attempts
569
+ - `metadata` (dict, optional): Additional metadata
570
+
571
+ **Returns:**
572
+ ```python
573
+ {
574
+ "result_id": "calculator-abc123_2026-01-12T12-00-00_123456",
575
+ "agent_id": "calculator-abc123",
576
+ "task": "Calculate factorial",
577
+ "output": 3628800,
578
+ "status": "success",
579
+ "timestamp": "2026-01-12T12:00:00.123456",
580
+ # ... more fields
581
+ }
582
+ ```
583
+
584
+ **Storage:**
585
+ - File: `./logs/{agent_id}/{result_id}.json`
586
+ - Cache: In-memory LRU cache (1000 results)
587
+
588
+ ---
589
+
590
+ #### `get_result(result_id)`
591
+
592
+ Retrieve a specific result (checks cache first, then file).
593
+
594
+ ```python
595
+ result = handler.get_result("calculator-abc123_2026-01-12T12-00-00_123456")
596
+ ```
597
+
598
+ ---
599
+
600
+ #### `get_agent_results(agent_id, limit=10)`
601
+
602
+ Get recent results for an agent.
603
+
604
+ ```python
605
+ recent = handler.get_agent_results("calculator-abc123", limit=5)
606
+ ```
607
+
608
+ ---
609
+
610
+ ### CodeRegistry
611
+
612
+ Searchable storage for generated code functions.
613
+
614
+ #### Class: `CodeRegistry`
615
+
616
+ ```python
617
+ from jarviscore.execution import create_code_registry
618
+
619
+ registry = create_code_registry(registry_directory="./logs/code_registry")
620
+ ```
621
+
622
+ **Parameters:**
623
+ - `registry_directory` (str): Directory for registry storage
624
+
625
+ **Methods:**
626
+
627
+ #### `register(code, agent_id, task, capabilities, output, result_id=None)`
628
+
629
+ Register generated code in the registry.
630
+
631
+ ```python
632
+ function_id = registry.register(
633
+ code="result = math.factorial(10)",
634
+ agent_id="calculator-abc123",
635
+ task="Calculate factorial of 10",
636
+ capabilities=["math", "calculation"],
637
+ output=3628800,
638
+ result_id="calculator-abc123_2026-01-12T12-00-00_123456"
639
+ )
640
+ ```
641
+
642
+ **Parameters:**
643
+ - `code` (str): Python code
644
+ - `agent_id` (str): Agent identifier
645
+ - `task` (str): Task description
646
+ - `capabilities` (list): Agent capabilities
647
+ - `output` (Any): Sample output
648
+ - `result_id` (str, optional): Associated result ID
649
+
650
+ **Returns:** function_id string
651
+
652
+ **Storage:**
653
+ - Index: `./logs/code_registry/index.json`
654
+ - Code: `./logs/code_registry/functions/{function_id}.py`
655
+
656
+ ---
657
+
658
+ #### `search(query, capabilities=None, limit=5)`
659
+
660
+ Search for registered functions.
661
+
662
+ ```python
663
+ matches = registry.search(
664
+ query="factorial calculation",
665
+ capabilities=["math"],
666
+ limit=3
667
+ )
668
+ ```
669
+
670
+ **Parameters:**
671
+ - `query` (str): Search keywords
672
+ - `capabilities` (list, optional): Filter by capabilities
673
+ - `limit` (int): Max results (default: 5)
674
+
675
+ **Returns:** List of matching function metadata
676
+
677
+ ---
678
+
679
+ #### `get(function_id)`
680
+
681
+ Get function details including code.
682
+
683
+ ```python
684
+ func = registry.get("calculator-abc123_3a5b2f76")
685
+ print(func['code']) # Print the code
686
+ ```
687
+
688
+ ---
689
+
690
+ ## Orchestration
691
+
692
+ ### WorkflowEngine
693
+
694
+ Multi-step workflow execution with dependency management.
695
+
696
+ #### Class: `WorkflowEngine`
697
+
698
+ ```python
699
+ from jarviscore.orchestration import WorkflowEngine
700
+
701
+ engine = WorkflowEngine(mesh, p2p_coordinator=None)
702
+ ```
703
+
704
+ **Parameters:**
705
+ - `mesh`: Mesh instance
706
+ - `p2p_coordinator` (optional): P2P coordinator for distributed execution
707
+ - `config` (dict, optional): Configuration
708
+
709
+ **Methods:**
710
+
711
+ #### `async execute(workflow_id, steps)`
712
+
713
+ Execute workflow with dependency resolution.
714
+
715
+ ```python
716
+ results = await engine.execute(
717
+ workflow_id="pipeline-1",
718
+ steps=[
719
+ {"id": "fetch", "agent": "scraper", "task": "Fetch data"},
720
+ {"id": "process", "agent": "processor", "task": "Process data", "depends_on": ["fetch"]},
721
+ {"id": "save", "agent": "storage", "task": "Save results", "depends_on": ["process"]}
722
+ ]
723
+ )
724
+ ```
725
+
726
+ **Parameters:**
727
+ - `workflow_id` (str): Unique workflow identifier
728
+ - `steps` (list): List of step dictionaries
729
+
730
+ **Step Format:**
731
+ ```python
732
+ {
733
+ "id": "step_id", # Optional, auto-generated if missing
734
+ "agent": "role_or_capability",
735
+ "task": "Task description",
736
+ "depends_on": ["step1", "step2"] # Optional dependencies
737
+ }
738
+ ```
739
+
740
+ **Dependency Injection:**
741
+
742
+ Dependent steps automatically receive context:
743
+ ```python
744
+ task['context'] = {
745
+ 'previous_step_results': {
746
+ 'step1': <output from step1>,
747
+ 'step2': <output from step2>
748
+ },
749
+ 'workflow_id': 'pipeline-1',
750
+ 'step_id': 'current_step'
751
+ }
752
+ ```
753
+
754
+ ---
755
+
756
+ ## Utilities
757
+
758
+ ### InternetSearch
759
+
760
+ Web search integration using DuckDuckGo.
761
+
762
+ #### Class: `InternetSearch`
763
+
764
+ ```python
765
+ from jarviscore.tools import create_internet_search
766
+
767
+ search = create_internet_search()
768
+ ```
769
+
770
+ **Methods:**
771
+
772
+ #### `async search(query, max_results=5)`
773
+
774
+ Search the web.
775
+
776
+ ```python
777
+ results = await search.search("Python asyncio tutorial", max_results=3)
778
+ ```
779
+
780
+ **Returns:**
781
+ ```python
782
+ [
783
+ {
784
+ "title": "Page title",
785
+ "snippet": "Description...",
786
+ "url": "https://..."
787
+ },
788
+ ...
789
+ ]
790
+ ```
791
+
792
+ ---
793
+
794
+ #### `async extract_content(url, max_length=10000)`
795
+
796
+ Extract text content from URL.
797
+
798
+ ```python
799
+ content = await search.extract_content("https://example.com")
800
+ ```
801
+
802
+ **Returns:**
803
+ ```python
804
+ {
805
+ "title": "Page title",
806
+ "content": "Extracted text...",
807
+ "success": true
808
+ }
809
+ ```
810
+
811
+ ---
812
+
813
+ #### `async search_and_extract(query, num_results=3)`
814
+
815
+ Combined search and content extraction.
816
+
817
+ ```python
818
+ results = await search.search_and_extract("Python tutorials", num_results=2)
819
+ ```
820
+
821
+ ---
822
+
823
+ ### UnifiedLLMClient
824
+
825
+ Multi-provider LLM client with automatic fallback.
826
+
827
+ #### Class: `UnifiedLLMClient`
828
+
829
+ ```python
830
+ from jarviscore.execution import create_llm_client
831
+
832
+ llm = create_llm_client(config)
833
+ ```
834
+
835
+ **Supported Providers:**
836
+ 1. Claude (Anthropic)
837
+ 2. vLLM (self-hosted)
838
+ 3. Azure OpenAI
839
+ 4. Google Gemini
840
+
841
+ **Methods:**
842
+
843
+ #### `async generate(prompt, system_msg=None, temperature=0.7, max_tokens=4000)`
844
+
845
+ Generate text from prompt.
846
+
847
+ ```python
848
+ response = await llm.generate(
849
+ prompt="Write Python code to calculate factorial",
850
+ system_msg="You are a Python expert",
851
+ temperature=0.3,
852
+ max_tokens=2000
853
+ )
854
+ ```
855
+
856
+ **Returns:**
857
+ ```python
858
+ {
859
+ "content": "Generated text",
860
+ "provider": "claude",
861
+ "model": "claude-sonnet-4",
862
+ "tokens": {"input": 100, "output": 50, "total": 150},
863
+ "cost_usd": 0.05
864
+ }
865
+ ```
866
+
867
+ **Automatic Fallback:**
868
+ - Tries providers in order: Claude → vLLM → Azure → Gemini
869
+ - Switches on API errors or rate limits
870
+ - Logs provider switches
871
+
872
+ ---
873
+
874
+ ## Configuration
875
+
876
+ See [Configuration Guide](CONFIGURATION.md) for environment variable reference.
877
+
878
+ ---
879
+
880
+ ## Error Handling
881
+
882
+ All async methods may raise:
883
+ - `RuntimeError`: Component not initialized or configuration error
884
+ - `ValueError`: Invalid parameters or data
885
+ - `TimeoutError`: Operation exceeded timeout
886
+ - `ExecutionTimeout`: Code execution timeout (sandbox)
887
+
888
+ **Example:**
889
+ ```python
890
+ try:
891
+ result = await agent.execute_task(task)
892
+ except TimeoutError:
893
+ print("Task timed out")
894
+ except RuntimeError as e:
895
+ print(f"Runtime error: {e}")
896
+ ```
897
+
898
+ ---
899
+
900
+ ## Type Hints
901
+
902
+ JarvisCore uses Python type hints for better IDE support:
903
+
904
+ ```python
905
+ from typing import Dict, List, Any, Optional
906
+
907
+ async def execute_task(self, task: Dict[str, Any]) -> Dict[str, Any]:
908
+ ...
909
+ ```
910
+
911
+ ---
912
+
913
+ ## Best Practices
914
+
915
+ 1. **Always use async/await**: JarvisCore is fully async
916
+ 2. **Call mesh.start() before execution**: Initializes all agents
917
+ 3. **Call mesh.stop() on shutdown**: Cleanup resources
918
+ 4. **Use context managers where possible**: Automatic cleanup
919
+ 5. **Handle errors gracefully**: Operations may fail
920
+ 6. **Set reasonable timeouts**: Prevent hanging operations
921
+ 7. **Monitor costs**: Track LLM token usage and costs
922
+ 8. **Use AutoAgent for quick prototypes**: Zero-config
923
+ 9. **Use CustomAgent for production**: Full control
924
+ 10. **Enable remote sandbox in production**: Better isolation
925
+
926
+ ---
927
+
928
+ ## Version
929
+
930
+ API Reference for JarvisCore v0.1.0
931
+
932
+ Last Updated: 2026-01-12