jarviscore-framework 0.1.0__py3-none-any.whl → 0.2.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.
- examples/autoagent_distributed_example.py +211 -0
- examples/custom_profile_decorator.py +134 -0
- examples/custom_profile_wrap.py +168 -0
- examples/customagent_distributed_example.py +362 -0
- examples/customagent_p2p_example.py +347 -0
- jarviscore/__init__.py +60 -15
- jarviscore/adapter/__init__.py +40 -0
- jarviscore/adapter/decorator.py +336 -0
- jarviscore/adapter/wrapper.py +303 -0
- jarviscore/cli/check.py +18 -13
- jarviscore/cli/scaffold.py +178 -0
- jarviscore/cli/smoketest.py +3 -2
- jarviscore/context/__init__.py +40 -0
- jarviscore/context/dependency.py +160 -0
- jarviscore/context/jarvis_context.py +207 -0
- jarviscore/context/memory.py +155 -0
- jarviscore/core/agent.py +44 -1
- jarviscore/core/mesh.py +196 -35
- jarviscore/data/.env.example +146 -0
- jarviscore/data/__init__.py +7 -0
- jarviscore/data/examples/autoagent_distributed_example.py +211 -0
- jarviscore/data/examples/calculator_agent_example.py +77 -0
- jarviscore/data/examples/customagent_distributed_example.py +362 -0
- jarviscore/data/examples/customagent_p2p_example.py +347 -0
- jarviscore/data/examples/multi_agent_workflow.py +132 -0
- jarviscore/data/examples/research_agent_example.py +76 -0
- jarviscore/docs/API_REFERENCE.md +264 -51
- jarviscore/docs/AUTOAGENT_GUIDE.md +198 -0
- jarviscore/docs/CONFIGURATION.md +41 -23
- jarviscore/docs/CUSTOMAGENT_GUIDE.md +415 -0
- jarviscore/docs/GETTING_STARTED.md +113 -17
- jarviscore/docs/TROUBLESHOOTING.md +155 -13
- jarviscore/docs/USER_GUIDE.md +144 -363
- jarviscore/execution/llm.py +23 -16
- jarviscore/orchestration/engine.py +20 -8
- jarviscore/p2p/__init__.py +10 -0
- jarviscore/p2p/coordinator.py +129 -0
- jarviscore/p2p/messages.py +87 -0
- jarviscore/p2p/peer_client.py +576 -0
- jarviscore/p2p/peer_tool.py +268 -0
- jarviscore_framework-0.2.0.dist-info/METADATA +143 -0
- jarviscore_framework-0.2.0.dist-info/RECORD +132 -0
- {jarviscore_framework-0.1.0.dist-info → jarviscore_framework-0.2.0.dist-info}/WHEEL +1 -1
- {jarviscore_framework-0.1.0.dist-info → jarviscore_framework-0.2.0.dist-info}/top_level.txt +1 -0
- test_logs/code_registry/functions/data_generator-558779ed_560ebc37.py +7 -0
- test_logs/code_registry/functions/data_generator-5ed3609e_560ebc37.py +7 -0
- test_logs/code_registry/functions/data_generator-66da0356_43970bb9.py +25 -0
- test_logs/code_registry/functions/data_generator-7a2fac83_583709d9.py +36 -0
- test_logs/code_registry/functions/data_generator-888b670f_aa235863.py +9 -0
- test_logs/code_registry/functions/data_generator-9ca5f642_aa235863.py +9 -0
- test_logs/code_registry/functions/data_generator-bfd90775_560ebc37.py +7 -0
- test_logs/code_registry/functions/data_generator-e95d2f7d_aa235863.py +9 -0
- test_logs/code_registry/functions/data_generator-f60ca8a2_327eb8c2.py +29 -0
- test_logs/code_registry/functions/mathematician-02adf9ee_958658d9.py +19 -0
- test_logs/code_registry/functions/mathematician-0706fb57_5df13441.py +23 -0
- test_logs/code_registry/functions/mathematician-153c9c4a_ba59c918.py +83 -0
- test_logs/code_registry/functions/mathematician-287e61c0_41daa793.py +18 -0
- test_logs/code_registry/functions/mathematician-2967af5a_863c2cc6.py +17 -0
- test_logs/code_registry/functions/mathematician-303ca6d6_5df13441.py +23 -0
- test_logs/code_registry/functions/mathematician-308a4afd_cbf5064d.py +73 -0
- test_logs/code_registry/functions/mathematician-353f16e2_0968bcf5.py +18 -0
- test_logs/code_registry/functions/mathematician-3c22475a_41daa793.py +17 -0
- test_logs/code_registry/functions/mathematician-5bac1029_0968bcf5.py +18 -0
- test_logs/code_registry/functions/mathematician-640f76b2_9198780b.py +19 -0
- test_logs/code_registry/functions/mathematician-752fa7ea_863c2cc6.py +17 -0
- test_logs/code_registry/functions/mathematician-baf9ef39_0968bcf5.py +18 -0
- test_logs/code_registry/functions/mathematician-bc8b2a2f_5df13441.py +23 -0
- test_logs/code_registry/functions/mathematician-c31e4686_41daa793.py +18 -0
- test_logs/code_registry/functions/mathematician-cc84c84c_863c2cc6.py +17 -0
- test_logs/code_registry/functions/mathematician-dd7c7144_9198780b.py +19 -0
- test_logs/code_registry/functions/mathematician-e671c256_41ea4487.py +74 -0
- test_logs/code_registry/functions/report_generator-1a878fcc_18d44bdc.py +47 -0
- test_logs/code_registry/functions/report_generator-25c1c331_cea57d0d.py +35 -0
- test_logs/code_registry/functions/report_generator-37552117_e711c2b9.py +35 -0
- test_logs/code_registry/functions/report_generator-bc662768_e711c2b9.py +35 -0
- test_logs/code_registry/functions/report_generator-d6c0e76b_5e7722ec.py +44 -0
- test_logs/code_registry/functions/report_generator-f270fb02_680529c3.py +44 -0
- test_logs/code_registry/functions/text_processor-11393b14_4370d3ed.py +40 -0
- test_logs/code_registry/functions/text_processor-7d02dfc3_d3b569be.py +37 -0
- test_logs/code_registry/functions/text_processor-8adb5e32_9168c5fe.py +13 -0
- test_logs/code_registry/functions/text_processor-c58ffc19_78b4ceac.py +42 -0
- test_logs/code_registry/functions/text_processor-cd5977b1_9168c5fe.py +13 -0
- test_logs/code_registry/functions/text_processor-ec1c8773_9168c5fe.py +13 -0
- tests/test_01_analyst_standalone.py +124 -0
- tests/test_02_assistant_standalone.py +164 -0
- tests/test_03_analyst_with_framework.py +945 -0
- tests/test_04_assistant_with_framework.py +1002 -0
- tests/test_05_integration.py +1301 -0
- tests/test_06_real_llm_integration.py +760 -0
- tests/test_07_distributed_single_node.py +578 -0
- tests/test_08_distributed_multi_node.py +454 -0
- tests/test_09_distributed_autoagent.py +509 -0
- tests/test_10_distributed_customagent.py +787 -0
- tests/test_context.py +467 -0
- tests/test_decorator.py +622 -0
- tests/test_mesh.py +35 -4
- jarviscore_framework-0.1.0.dist-info/METADATA +0 -136
- jarviscore_framework-0.1.0.dist-info/RECORD +0 -55
- {jarviscore_framework-0.1.0.dist-info → jarviscore_framework-0.2.0.dist-info}/licenses/LICENSE +0 -0
jarviscore/docs/API_REFERENCE.md
CHANGED
|
@@ -12,6 +12,7 @@ Complete API documentation for JarvisCore framework components.
|
|
|
12
12
|
- [Profile](#profile)
|
|
13
13
|
2. [Agent Profiles](#agent-profiles)
|
|
14
14
|
- [AutoAgent](#autoagent)
|
|
15
|
+
- [Custom Profile](#custom-profile)
|
|
15
16
|
- [CustomAgent](#customagent)
|
|
16
17
|
3. [Execution Components](#execution-components)
|
|
17
18
|
- [CodeGenerator](#codegenerator)
|
|
@@ -39,35 +40,43 @@ The central orchestrator for managing agents and workflows.
|
|
|
39
40
|
```python
|
|
40
41
|
from jarviscore import Mesh
|
|
41
42
|
|
|
42
|
-
mesh = Mesh(mode="autonomous") # or "distributed"
|
|
43
|
+
mesh = Mesh(mode="autonomous") # or "p2p" or "distributed"
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
**Parameters:**
|
|
46
|
-
- `mode` (str): Execution mode
|
|
47
|
+
- `mode` (str): Execution mode
|
|
48
|
+
- `"autonomous"` - Workflow Engine only (single-node)
|
|
49
|
+
- `"p2p"` - P2P Coordinator only (SWIM protocol, ZMQ messaging)
|
|
50
|
+
- `"distributed"` - Both Workflow Engine AND P2P Coordinator
|
|
47
51
|
- `config` (dict, optional): Configuration dictionary
|
|
48
52
|
|
|
53
|
+
**Modes Comparison:**
|
|
54
|
+
|
|
55
|
+
| Mode | Workflow Engine | P2P Coordinator | Use Case |
|
|
56
|
+
|------|-----------------|-----------------|----------|
|
|
57
|
+
| `autonomous` | ✅ | ❌ | Single machine, simple pipelines |
|
|
58
|
+
| `p2p` | ❌ | ✅ | Agent swarms, real-time coordination |
|
|
59
|
+
| `distributed` | ✅ | ✅ | Multi-node production systems |
|
|
60
|
+
|
|
49
61
|
**Methods:**
|
|
50
62
|
|
|
51
|
-
#### `
|
|
63
|
+
#### `add(agent_class)`
|
|
52
64
|
|
|
53
|
-
Register an agent in the mesh.
|
|
65
|
+
Register an agent class in the mesh.
|
|
54
66
|
|
|
55
67
|
```python
|
|
56
68
|
from jarviscore.profiles import AutoAgent
|
|
57
69
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
70
|
+
class CalculatorAgent(AutoAgent):
|
|
71
|
+
role = "calculator"
|
|
72
|
+
capabilities = ["math", "calculation"]
|
|
73
|
+
system_prompt = "You are a math expert"
|
|
74
|
+
|
|
75
|
+
mesh.add(CalculatorAgent)
|
|
64
76
|
```
|
|
65
77
|
|
|
66
78
|
**Parameters:**
|
|
67
|
-
- `
|
|
68
|
-
- `role` (str): Unique agent role identifier
|
|
69
|
-
- `capabilities` (list): List of capability strings
|
|
70
|
-
- `**kwargs`: Additional agent-specific parameters
|
|
79
|
+
- `agent_class`: Agent class (AutoAgent or CustomAgent subclass)
|
|
71
80
|
|
|
72
81
|
**Returns:** Agent instance
|
|
73
82
|
|
|
@@ -95,12 +104,12 @@ await mesh.stop()
|
|
|
95
104
|
|
|
96
105
|
---
|
|
97
106
|
|
|
98
|
-
#### `async
|
|
107
|
+
#### `async workflow(workflow_id, steps)`
|
|
99
108
|
|
|
100
109
|
Execute a multi-step workflow with dependency management.
|
|
101
110
|
|
|
102
111
|
```python
|
|
103
|
-
results = await mesh.
|
|
112
|
+
results = await mesh.workflow("pipeline-id", [
|
|
104
113
|
{"agent": "scraper", "task": "Scrape data from URL"},
|
|
105
114
|
{"agent": "processor", "task": "Clean the data", "depends_on": [0]},
|
|
106
115
|
{"agent": "storage", "task": "Save to database", "depends_on": [1]}
|
|
@@ -108,6 +117,7 @@ results = await mesh.run_workflow([
|
|
|
108
117
|
```
|
|
109
118
|
|
|
110
119
|
**Parameters:**
|
|
120
|
+
- `workflow_id` (str): Unique workflow identifier
|
|
111
121
|
- `steps` (list): List of step dictionaries with keys:
|
|
112
122
|
- `agent` (str): Role or capability of target agent
|
|
113
123
|
- `task` (str): Task description
|
|
@@ -116,6 +126,20 @@ results = await mesh.run_workflow([
|
|
|
116
126
|
|
|
117
127
|
**Returns:** List of result dictionaries
|
|
118
128
|
|
|
129
|
+
**Note:** Only available in `autonomous` and `distributed` modes.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
#### `async run_forever()`
|
|
134
|
+
|
|
135
|
+
Keep the mesh running until shutdown signal (P2P and distributed modes).
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
await mesh.run_forever() # Blocks until SIGINT/SIGTERM
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Note:** Only available in `p2p` and `distributed` modes.
|
|
142
|
+
|
|
119
143
|
---
|
|
120
144
|
|
|
121
145
|
### Agent
|
|
@@ -288,6 +312,180 @@ results = await mesh.run_workflow([
|
|
|
288
312
|
|
|
289
313
|
---
|
|
290
314
|
|
|
315
|
+
### Custom Profile
|
|
316
|
+
|
|
317
|
+
The Custom Profile enables integration of existing agents without modification.
|
|
318
|
+
|
|
319
|
+
#### Decorator: `@jarvis_agent`
|
|
320
|
+
|
|
321
|
+
Convert any Python class into a JarvisCore agent:
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
from jarviscore import jarvis_agent, JarvisContext
|
|
325
|
+
|
|
326
|
+
@jarvis_agent(role="processor", capabilities=["data_processing"])
|
|
327
|
+
class DataProcessor:
|
|
328
|
+
def run(self, data):
|
|
329
|
+
return {"processed": [x * 2 for x in data]}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Parameters:**
|
|
333
|
+
- `role` (str): Agent role identifier
|
|
334
|
+
- `capabilities` (list): List of capability strings
|
|
335
|
+
- `execute_method` (str, optional): Method name to call (default: auto-detect)
|
|
336
|
+
|
|
337
|
+
**Auto-detected Methods:** `run`, `execute`, `invoke`, `call`, `process`
|
|
338
|
+
|
|
339
|
+
**Context-Aware Methods:**
|
|
340
|
+
|
|
341
|
+
If your method has a parameter named `ctx` or `context`, JarvisContext is automatically injected:
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
@jarvis_agent(role="aggregator", capabilities=["aggregation"])
|
|
345
|
+
class Aggregator:
|
|
346
|
+
def run(self, task, ctx: JarvisContext):
|
|
347
|
+
previous = ctx.previous("step1")
|
|
348
|
+
return {"result": previous}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
#### Function: `wrap()`
|
|
354
|
+
|
|
355
|
+
Wrap an existing instance as a JarvisCore agent:
|
|
356
|
+
|
|
357
|
+
```python
|
|
358
|
+
from jarviscore import wrap
|
|
359
|
+
|
|
360
|
+
wrapped = wrap(
|
|
361
|
+
instance=my_langchain_agent,
|
|
362
|
+
role="assistant",
|
|
363
|
+
capabilities=["chat", "qa"],
|
|
364
|
+
execute_method="invoke"
|
|
365
|
+
)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Parameters:**
|
|
369
|
+
- `instance` (Any): Pre-instantiated object to wrap
|
|
370
|
+
- `role` (str): Agent role identifier
|
|
371
|
+
- `capabilities` (list): List of capability strings
|
|
372
|
+
- `execute_method` (str, optional): Method name to call (default: auto-detect)
|
|
373
|
+
|
|
374
|
+
**Returns:** `CustomAgent` instance ready for `mesh.add()`
|
|
375
|
+
|
|
376
|
+
**Example:**
|
|
377
|
+
|
|
378
|
+
```python
|
|
379
|
+
from jarviscore import Mesh, wrap
|
|
380
|
+
|
|
381
|
+
# Your existing LangChain agent
|
|
382
|
+
my_agent = MyLangChainAgent(model="gpt-4")
|
|
383
|
+
|
|
384
|
+
# Wrap it
|
|
385
|
+
wrapped = wrap(
|
|
386
|
+
my_agent,
|
|
387
|
+
role="assistant",
|
|
388
|
+
capabilities=["chat"],
|
|
389
|
+
execute_method="invoke"
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
mesh = Mesh(mode="autonomous")
|
|
393
|
+
mesh.add(wrapped) # Add directly to mesh
|
|
394
|
+
await mesh.start()
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
#### Class: `JarvisContext`
|
|
400
|
+
|
|
401
|
+
Provides workflow context access for Custom Profile agents:
|
|
402
|
+
|
|
403
|
+
```python
|
|
404
|
+
from jarviscore import JarvisContext
|
|
405
|
+
|
|
406
|
+
def run(self, task, ctx: JarvisContext):
|
|
407
|
+
# Access previous step outputs
|
|
408
|
+
step1_output = ctx.previous("step1")
|
|
409
|
+
|
|
410
|
+
# Get all previous outputs
|
|
411
|
+
all_outputs = ctx.all_previous()
|
|
412
|
+
|
|
413
|
+
# Access shared memory
|
|
414
|
+
ctx.memory["key"] = "value"
|
|
415
|
+
value = ctx.memory.get("key")
|
|
416
|
+
|
|
417
|
+
return {"result": "..."}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Attributes:**
|
|
421
|
+
- `workflow_id` (str): Current workflow identifier
|
|
422
|
+
- `step_id` (str): Current step identifier
|
|
423
|
+
- `task` (str): Task description
|
|
424
|
+
- `params` (dict): Task parameters
|
|
425
|
+
- `memory` (MemoryAccessor): Shared workflow memory
|
|
426
|
+
|
|
427
|
+
**Methods:**
|
|
428
|
+
|
|
429
|
+
#### `previous(step_id: str) -> Optional[Any]`
|
|
430
|
+
|
|
431
|
+
Get output from a specific previous step.
|
|
432
|
+
|
|
433
|
+
```python
|
|
434
|
+
step1_output = ctx.previous("step1")
|
|
435
|
+
if step1_output:
|
|
436
|
+
data = step1_output.get("processed", [])
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Parameters:**
|
|
440
|
+
- `step_id` (str): ID of the step to retrieve
|
|
441
|
+
|
|
442
|
+
**Returns:** Step output or None if not found
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
#### `all_previous() -> Dict[str, Any]`
|
|
447
|
+
|
|
448
|
+
Get outputs from all previous steps.
|
|
449
|
+
|
|
450
|
+
```python
|
|
451
|
+
all_outputs = ctx.all_previous()
|
|
452
|
+
# {"step1": {...}, "step2": {...}}
|
|
453
|
+
|
|
454
|
+
for step_id, output in all_outputs.items():
|
|
455
|
+
print(f"{step_id}: {output}")
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Returns:** Dictionary mapping step IDs to their outputs
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
#### Class: `MemoryAccessor`
|
|
463
|
+
|
|
464
|
+
Dictionary-like interface for shared workflow memory:
|
|
465
|
+
|
|
466
|
+
```python
|
|
467
|
+
# Set value
|
|
468
|
+
ctx.memory["key"] = "value"
|
|
469
|
+
|
|
470
|
+
# Get value
|
|
471
|
+
value = ctx.memory.get("key", "default")
|
|
472
|
+
|
|
473
|
+
# Check existence
|
|
474
|
+
if "key" in ctx.memory:
|
|
475
|
+
...
|
|
476
|
+
|
|
477
|
+
# Get all memory
|
|
478
|
+
all_memory = ctx.memory.all()
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
**Methods:**
|
|
482
|
+
- `get(key, default=None)` - Get value with optional default
|
|
483
|
+
- `set(key, value)` - Set value
|
|
484
|
+
- `all()` - Get entire memory dictionary
|
|
485
|
+
- `__getitem__`, `__setitem__`, `__contains__` - Dict-like access
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
291
489
|
### CustomAgent
|
|
292
490
|
|
|
293
491
|
Flexible agent profile for integrating external frameworks.
|
|
@@ -297,51 +495,66 @@ Flexible agent profile for integrating external frameworks.
|
|
|
297
495
|
```python
|
|
298
496
|
from jarviscore.profiles import CustomAgent
|
|
299
497
|
|
|
300
|
-
class
|
|
498
|
+
class MyAgent(CustomAgent):
|
|
499
|
+
role = "my_role"
|
|
500
|
+
capabilities = ["my_capability"]
|
|
501
|
+
|
|
301
502
|
async def setup(self):
|
|
302
|
-
|
|
303
|
-
|
|
503
|
+
await super().setup()
|
|
504
|
+
# Initialize your resources
|
|
304
505
|
|
|
305
506
|
async def execute_task(self, task):
|
|
306
|
-
|
|
307
|
-
return {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
507
|
+
"""Called by workflow engine (autonomous/distributed modes)."""
|
|
508
|
+
return {"status": "success", "output": result}
|
|
509
|
+
|
|
510
|
+
async def run(self):
|
|
511
|
+
"""Called in P2P mode - continuous run loop."""
|
|
512
|
+
while not self.shutdown_requested:
|
|
513
|
+
msg = await self.peers.receive(timeout=0.5)
|
|
514
|
+
if msg and msg.is_request:
|
|
515
|
+
await self.peers.respond(msg, {"response": "..."})
|
|
312
516
|
```
|
|
313
517
|
|
|
314
|
-
**
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
- Optional cost tracking with `track_cost()`
|
|
318
|
-
- Full access to mesh and workflow context
|
|
518
|
+
**Class Attributes:**
|
|
519
|
+
- `role` (str): Agent role identifier (required)
|
|
520
|
+
- `capabilities` (list): List of capability strings (required)
|
|
319
521
|
|
|
320
|
-
**
|
|
522
|
+
**Instance Attributes:**
|
|
523
|
+
- `agent_id` (str): Unique agent identifier
|
|
524
|
+
- `peers` (PeerTool): P2P communication tool (distributed/p2p modes)
|
|
525
|
+
- `shutdown_requested` (bool): Set to True when shutdown requested
|
|
321
526
|
|
|
322
|
-
|
|
323
|
-
class APIAgent(CustomAgent):
|
|
324
|
-
async def setup(self):
|
|
325
|
-
self.api_client = MyAPIClient()
|
|
527
|
+
**Key Methods:**
|
|
326
528
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
529
|
+
| Method | Purpose | Mode |
|
|
530
|
+
|--------|---------|------|
|
|
531
|
+
| `setup()` | Initialize resources | All |
|
|
532
|
+
| `execute_task(task)` | Handle workflow steps | Autonomous/Distributed |
|
|
533
|
+
| `run()` | Continuous loop | P2P |
|
|
534
|
+
| `teardown()` | Cleanup resources | All |
|
|
330
535
|
|
|
331
|
-
|
|
332
|
-
self.track_cost(
|
|
333
|
-
input_tokens=100,
|
|
334
|
-
output_tokens=50,
|
|
335
|
-
cost_usd=0.01
|
|
336
|
-
)
|
|
536
|
+
**P2P Communication (distributed/p2p modes):**
|
|
337
537
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
538
|
+
```python
|
|
539
|
+
async def run(self):
|
|
540
|
+
while not self.shutdown_requested:
|
|
541
|
+
# Receive messages
|
|
542
|
+
msg = await self.peers.receive(timeout=0.5)
|
|
543
|
+
if msg and msg.is_request:
|
|
544
|
+
# Process and respond
|
|
545
|
+
await self.peers.respond(msg, {"response": result})
|
|
546
|
+
|
|
547
|
+
async def ask_another_agent(self, question):
|
|
548
|
+
# Ask another agent via peer tools
|
|
549
|
+
result = await self.peers.as_tool().execute(
|
|
550
|
+
"ask_peer",
|
|
551
|
+
{"role": "researcher", "question": question}
|
|
552
|
+
)
|
|
553
|
+
return result
|
|
343
554
|
```
|
|
344
555
|
|
|
556
|
+
See [CustomAgent Guide](CUSTOMAGENT_GUIDE.md) for P2P and distributed mode details.
|
|
557
|
+
|
|
345
558
|
---
|
|
346
559
|
|
|
347
560
|
## Execution Components
|
|
@@ -927,6 +1140,6 @@ async def execute_task(self, task: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
927
1140
|
|
|
928
1141
|
## Version
|
|
929
1142
|
|
|
930
|
-
API Reference for JarvisCore v0.
|
|
1143
|
+
API Reference for JarvisCore v0.2.0
|
|
931
1144
|
|
|
932
|
-
Last Updated: 2026-01-
|
|
1145
|
+
Last Updated: 2026-01-22
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# AutoAgent Guide
|
|
2
|
+
|
|
3
|
+
AutoAgent is the **zero-config** profile where the framework handles everything:
|
|
4
|
+
- LLM code generation from natural language
|
|
5
|
+
- Sandboxed code execution
|
|
6
|
+
- Automatic error repair
|
|
7
|
+
- Result storage
|
|
8
|
+
|
|
9
|
+
You write **3 attributes**, framework does the rest.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Quick Reference
|
|
14
|
+
|
|
15
|
+
| Mode | Use Case | Key Difference |
|
|
16
|
+
|------|----------|----------------|
|
|
17
|
+
| **Autonomous** | Single machine | No network, local execution |
|
|
18
|
+
| **Distributed** | Multi-node | P2P network + workflow orchestration |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Autonomous Mode
|
|
23
|
+
|
|
24
|
+
Single-node execution. No networking required.
|
|
25
|
+
|
|
26
|
+
### Example
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import asyncio
|
|
30
|
+
from jarviscore import Mesh
|
|
31
|
+
from jarviscore.profiles import AutoAgent
|
|
32
|
+
|
|
33
|
+
class CalculatorAgent(AutoAgent):
|
|
34
|
+
role = "calculator"
|
|
35
|
+
capabilities = ["math", "calculation"]
|
|
36
|
+
system_prompt = """
|
|
37
|
+
You are a math expert. Generate Python code to solve problems.
|
|
38
|
+
Store the result in a variable named 'result'.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
async def main():
|
|
42
|
+
mesh = Mesh(mode="autonomous") # Default mode
|
|
43
|
+
mesh.add(CalculatorAgent)
|
|
44
|
+
|
|
45
|
+
await mesh.start()
|
|
46
|
+
|
|
47
|
+
results = await mesh.workflow("calc-task", [
|
|
48
|
+
{"agent": "calculator", "task": "Calculate factorial of 10"}
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
print(results[0]["output"]) # {'result': 3628800}
|
|
52
|
+
|
|
53
|
+
await mesh.stop()
|
|
54
|
+
|
|
55
|
+
asyncio.run(main())
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### When to Use
|
|
59
|
+
- Rapid prototyping
|
|
60
|
+
- Single-machine deployments
|
|
61
|
+
- Simple task pipelines
|
|
62
|
+
- No need for agent-to-agent communication
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Distributed Mode
|
|
67
|
+
|
|
68
|
+
Multi-node execution with P2P networking. Same API, just add config.
|
|
69
|
+
|
|
70
|
+
### What Changes
|
|
71
|
+
|
|
72
|
+
| Autonomous | Distributed |
|
|
73
|
+
|------------|-------------|
|
|
74
|
+
| `mode="autonomous"` | `mode="distributed"` |
|
|
75
|
+
| No config needed | Add `bind_port`, `node_name` |
|
|
76
|
+
| Single machine | Can span multiple machines |
|
|
77
|
+
|
|
78
|
+
### Example (Single Node)
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
import asyncio
|
|
82
|
+
from jarviscore import Mesh
|
|
83
|
+
from jarviscore.profiles import AutoAgent
|
|
84
|
+
|
|
85
|
+
class CalculatorAgent(AutoAgent):
|
|
86
|
+
role = "calculator"
|
|
87
|
+
capabilities = ["math", "calculation"]
|
|
88
|
+
system_prompt = """
|
|
89
|
+
You are a math expert. Generate Python code to solve problems.
|
|
90
|
+
Store the result in a variable named 'result'.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
async def main():
|
|
94
|
+
mesh = Mesh(
|
|
95
|
+
mode="distributed", # Enable P2P + workflow
|
|
96
|
+
config={
|
|
97
|
+
'bind_port': 7950, # SWIM protocol port
|
|
98
|
+
'node_name': 'calc-node', # Node identifier
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
mesh.add(CalculatorAgent)
|
|
102
|
+
|
|
103
|
+
await mesh.start()
|
|
104
|
+
|
|
105
|
+
# Same API as autonomous!
|
|
106
|
+
results = await mesh.workflow("calc-task", [
|
|
107
|
+
{"agent": "calculator", "task": "Calculate factorial of 10"}
|
|
108
|
+
])
|
|
109
|
+
|
|
110
|
+
print(results[0]["output"])
|
|
111
|
+
|
|
112
|
+
await mesh.stop()
|
|
113
|
+
|
|
114
|
+
asyncio.run(main())
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Example (Multi-Node)
|
|
118
|
+
|
|
119
|
+
**Node 1 - Seed node with calculator:**
|
|
120
|
+
```python
|
|
121
|
+
# node1.py
|
|
122
|
+
mesh = Mesh(
|
|
123
|
+
mode="distributed",
|
|
124
|
+
config={
|
|
125
|
+
'bind_host': '0.0.0.0',
|
|
126
|
+
'bind_port': 7950,
|
|
127
|
+
'node_name': 'node-1',
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
mesh.add(CalculatorAgent)
|
|
131
|
+
await mesh.start()
|
|
132
|
+
await mesh.serve_forever() # Keep running
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Node 2 - Joins cluster with analyzer:**
|
|
136
|
+
```python
|
|
137
|
+
# node2.py
|
|
138
|
+
mesh = Mesh(
|
|
139
|
+
mode="distributed",
|
|
140
|
+
config={
|
|
141
|
+
'bind_host': '0.0.0.0',
|
|
142
|
+
'bind_port': 7950,
|
|
143
|
+
'node_name': 'node-2',
|
|
144
|
+
'seed_nodes': '192.168.1.10:7950', # Node 1's address
|
|
145
|
+
}
|
|
146
|
+
)
|
|
147
|
+
mesh.add(AnalyzerAgent)
|
|
148
|
+
await mesh.start()
|
|
149
|
+
await mesh.serve_forever()
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Execute workflows across nodes:**
|
|
153
|
+
```python
|
|
154
|
+
# From any node
|
|
155
|
+
results = await mesh.workflow("cross-node", [
|
|
156
|
+
{"agent": "calculator", "task": "..."}, # Runs on Node 1
|
|
157
|
+
{"agent": "analyzer", "task": "...", "depends_on": [0]} # Runs on Node 2
|
|
158
|
+
])
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### When to Use
|
|
162
|
+
- Production multi-node systems
|
|
163
|
+
- Agents on different machines
|
|
164
|
+
- Scalable agent architectures
|
|
165
|
+
- Need cross-node workflow coordination
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Configuration Options
|
|
170
|
+
|
|
171
|
+
| Option | Default | Description |
|
|
172
|
+
|--------|---------|-------------|
|
|
173
|
+
| `bind_host` | `127.0.0.1` | Interface to bind |
|
|
174
|
+
| `bind_port` | `7950` | SWIM protocol port |
|
|
175
|
+
| `node_name` | `jarviscore-node` | Node identifier |
|
|
176
|
+
| `seed_nodes` | `None` | Comma-separated seed addresses |
|
|
177
|
+
| `execution_timeout` | `300` | Max seconds per task |
|
|
178
|
+
| `max_repair_attempts` | `3` | Auto-repair retries |
|
|
179
|
+
| `log_directory` | `./logs` | Result storage path |
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Summary
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
# Autonomous (single node)
|
|
187
|
+
mesh = Mesh(mode="autonomous")
|
|
188
|
+
|
|
189
|
+
# Distributed (multi-node capable)
|
|
190
|
+
mesh = Mesh(mode="distributed", config={'bind_port': 7950})
|
|
191
|
+
|
|
192
|
+
# Everything else stays the same!
|
|
193
|
+
mesh.add(MyAutoAgent)
|
|
194
|
+
await mesh.start()
|
|
195
|
+
results = await mesh.workflow(...)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
See `examples/calculator_agent_example.py` and `examples/autoagent_distributed_example.py` for complete examples.
|
jarviscore/docs/CONFIGURATION.md
CHANGED
|
@@ -52,9 +52,13 @@ That's it! The framework handles the rest.
|
|
|
52
52
|
|
|
53
53
|
### Configuration File
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
Initialize your project and create `.env` file:
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
|
+
# Initialize project (creates .env.example)
|
|
59
|
+
python -m jarviscore.cli.scaffold
|
|
60
|
+
|
|
61
|
+
# Copy and configure
|
|
58
62
|
cp .env.example .env
|
|
59
63
|
# Edit .env with your values
|
|
60
64
|
```
|
|
@@ -247,27 +251,28 @@ Generated code is automatically registered:
|
|
|
247
251
|
|
|
248
252
|
## P2P Configuration
|
|
249
253
|
|
|
250
|
-
Configure distributed mesh networking
|
|
251
|
-
|
|
252
|
-
### Enable P2P
|
|
254
|
+
Configure distributed mesh networking for `p2p` and `distributed` modes.
|
|
253
255
|
|
|
254
|
-
|
|
255
|
-
# Enable P2P mesh
|
|
256
|
-
P2P_ENABLED=true
|
|
256
|
+
### Execution Modes
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
258
|
+
| Mode | Code Config | Workflow Engine | P2P Coordinator |
|
|
259
|
+
|------|-------------|-----------------|-----------------|
|
|
260
|
+
| `autonomous` | `Mesh(mode="autonomous")` | ✅ | ❌ |
|
|
261
|
+
| `p2p` | `Mesh(mode="p2p", config={...})` | ❌ | ✅ |
|
|
262
|
+
| `distributed` | `Mesh(mode="distributed", config={...})` | ✅ | ✅ |
|
|
261
263
|
|
|
262
|
-
### Network Settings
|
|
264
|
+
### Network Settings (P2P and Distributed)
|
|
263
265
|
|
|
264
266
|
```bash
|
|
265
267
|
# Bind address and port
|
|
266
268
|
BIND_HOST=0.0.0.0 # Listen on all interfaces
|
|
267
|
-
BIND_PORT=
|
|
269
|
+
BIND_PORT=7950 # SWIM protocol port
|
|
268
270
|
|
|
269
|
-
#
|
|
270
|
-
|
|
271
|
+
# Node identification
|
|
272
|
+
NODE_NAME=jarviscore-node-1
|
|
273
|
+
|
|
274
|
+
# Seed nodes (comma-separated) for joining existing cluster
|
|
275
|
+
SEED_NODES=192.168.1.100:7950,192.168.1.101:7950
|
|
271
276
|
```
|
|
272
277
|
|
|
273
278
|
### Transport Configuration
|
|
@@ -536,14 +541,27 @@ Override environment variables in code:
|
|
|
536
541
|
```python
|
|
537
542
|
from jarviscore import Mesh
|
|
538
543
|
|
|
539
|
-
config
|
|
540
|
-
|
|
541
|
-
'sandbox_service_url': 'https://...',
|
|
544
|
+
# Autonomous mode (no P2P config needed)
|
|
545
|
+
mesh = Mesh(mode="autonomous", config={
|
|
542
546
|
'execution_timeout': 600,
|
|
543
547
|
'log_level': 'DEBUG'
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
|
|
548
|
+
})
|
|
549
|
+
|
|
550
|
+
# P2P mode (requires network config)
|
|
551
|
+
mesh = Mesh(mode="p2p", config={
|
|
552
|
+
'bind_host': '0.0.0.0',
|
|
553
|
+
'bind_port': 7950,
|
|
554
|
+
'node_name': 'my-node',
|
|
555
|
+
'seed_nodes': '192.168.1.10:7950', # Optional, for joining cluster
|
|
556
|
+
})
|
|
557
|
+
|
|
558
|
+
# Distributed mode (both workflow + P2P)
|
|
559
|
+
mesh = Mesh(mode="distributed", config={
|
|
560
|
+
'bind_host': '0.0.0.0',
|
|
561
|
+
'bind_port': 7950,
|
|
562
|
+
'node_name': 'my-node',
|
|
563
|
+
'execution_timeout': 600,
|
|
564
|
+
})
|
|
547
565
|
```
|
|
548
566
|
|
|
549
567
|
**Note:** Programmatic config overrides environment variables.
|
|
@@ -716,7 +734,7 @@ LOG_DIRECTORY=/tmp/jarviscore-logs
|
|
|
716
734
|
| `AZURE_DEPLOYMENT` | None | Azure deployment name |
|
|
717
735
|
| `AZURE_API_VERSION` | 2024-02-15-preview | Azure API version |
|
|
718
736
|
| `GEMINI_API_KEY` | None | Google Gemini key |
|
|
719
|
-
| `GEMINI_MODEL` | gemini-
|
|
737
|
+
| `GEMINI_MODEL` | gemini-2.0-flash | Gemini model |
|
|
720
738
|
| `LLM_TIMEOUT` | 120.0 | LLM timeout (seconds) |
|
|
721
739
|
| `LLM_TEMPERATURE` | 0.7 | Sampling temperature |
|
|
722
740
|
| `SANDBOX_MODE` | local | Execution mode |
|
|
@@ -748,6 +766,6 @@ LOG_DIRECTORY=/tmp/jarviscore-logs
|
|
|
748
766
|
|
|
749
767
|
## Version
|
|
750
768
|
|
|
751
|
-
Configuration Guide for JarvisCore v0.
|
|
769
|
+
Configuration Guide for JarvisCore v0.2.0
|
|
752
770
|
|
|
753
|
-
Last Updated: 2026-01-
|
|
771
|
+
Last Updated: 2026-01-22
|