jarviscore-framework 0.1.1__py3-none-any.whl → 0.2.1__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 (86) hide show
  1. examples/autoagent_distributed_example.py +211 -0
  2. examples/custom_profile_decorator.py +134 -0
  3. examples/custom_profile_wrap.py +168 -0
  4. examples/customagent_distributed_example.py +362 -0
  5. examples/customagent_p2p_example.py +730 -0
  6. jarviscore/__init__.py +49 -36
  7. jarviscore/adapter/__init__.py +15 -9
  8. jarviscore/adapter/decorator.py +23 -19
  9. jarviscore/adapter/wrapper.py +303 -0
  10. jarviscore/cli/scaffold.py +1 -1
  11. jarviscore/cli/smoketest.py +3 -2
  12. jarviscore/core/agent.py +44 -1
  13. jarviscore/core/mesh.py +196 -35
  14. jarviscore/data/examples/autoagent_distributed_example.py +211 -0
  15. jarviscore/data/examples/customagent_distributed_example.py +362 -0
  16. jarviscore/data/examples/customagent_p2p_example.py +730 -0
  17. jarviscore/docs/API_REFERENCE.md +264 -51
  18. jarviscore/docs/AUTOAGENT_GUIDE.md +198 -0
  19. jarviscore/docs/CONFIGURATION.md +35 -21
  20. jarviscore/docs/CUSTOMAGENT_GUIDE.md +1362 -0
  21. jarviscore/docs/GETTING_STARTED.md +107 -14
  22. jarviscore/docs/TROUBLESHOOTING.md +145 -7
  23. jarviscore/docs/USER_GUIDE.md +138 -361
  24. jarviscore/orchestration/engine.py +20 -8
  25. jarviscore/p2p/__init__.py +10 -0
  26. jarviscore/p2p/coordinator.py +129 -0
  27. jarviscore/p2p/messages.py +87 -0
  28. jarviscore/p2p/peer_client.py +576 -0
  29. jarviscore/p2p/peer_tool.py +268 -0
  30. jarviscore_framework-0.2.1.dist-info/METADATA +144 -0
  31. jarviscore_framework-0.2.1.dist-info/RECORD +132 -0
  32. {jarviscore_framework-0.1.1.dist-info → jarviscore_framework-0.2.1.dist-info}/WHEEL +1 -1
  33. {jarviscore_framework-0.1.1.dist-info → jarviscore_framework-0.2.1.dist-info}/top_level.txt +1 -0
  34. test_logs/code_registry/functions/data_generator-558779ed_560ebc37.py +7 -0
  35. test_logs/code_registry/functions/data_generator-5ed3609e_560ebc37.py +7 -0
  36. test_logs/code_registry/functions/data_generator-66da0356_43970bb9.py +25 -0
  37. test_logs/code_registry/functions/data_generator-7a2fac83_583709d9.py +36 -0
  38. test_logs/code_registry/functions/data_generator-888b670f_aa235863.py +9 -0
  39. test_logs/code_registry/functions/data_generator-9ca5f642_aa235863.py +9 -0
  40. test_logs/code_registry/functions/data_generator-bfd90775_560ebc37.py +7 -0
  41. test_logs/code_registry/functions/data_generator-e95d2f7d_aa235863.py +9 -0
  42. test_logs/code_registry/functions/data_generator-f60ca8a2_327eb8c2.py +29 -0
  43. test_logs/code_registry/functions/mathematician-02adf9ee_958658d9.py +19 -0
  44. test_logs/code_registry/functions/mathematician-0706fb57_5df13441.py +23 -0
  45. test_logs/code_registry/functions/mathematician-153c9c4a_ba59c918.py +83 -0
  46. test_logs/code_registry/functions/mathematician-287e61c0_41daa793.py +18 -0
  47. test_logs/code_registry/functions/mathematician-2967af5a_863c2cc6.py +17 -0
  48. test_logs/code_registry/functions/mathematician-303ca6d6_5df13441.py +23 -0
  49. test_logs/code_registry/functions/mathematician-308a4afd_cbf5064d.py +73 -0
  50. test_logs/code_registry/functions/mathematician-353f16e2_0968bcf5.py +18 -0
  51. test_logs/code_registry/functions/mathematician-3c22475a_41daa793.py +17 -0
  52. test_logs/code_registry/functions/mathematician-5bac1029_0968bcf5.py +18 -0
  53. test_logs/code_registry/functions/mathematician-640f76b2_9198780b.py +19 -0
  54. test_logs/code_registry/functions/mathematician-752fa7ea_863c2cc6.py +17 -0
  55. test_logs/code_registry/functions/mathematician-baf9ef39_0968bcf5.py +18 -0
  56. test_logs/code_registry/functions/mathematician-bc8b2a2f_5df13441.py +23 -0
  57. test_logs/code_registry/functions/mathematician-c31e4686_41daa793.py +18 -0
  58. test_logs/code_registry/functions/mathematician-cc84c84c_863c2cc6.py +17 -0
  59. test_logs/code_registry/functions/mathematician-dd7c7144_9198780b.py +19 -0
  60. test_logs/code_registry/functions/mathematician-e671c256_41ea4487.py +74 -0
  61. test_logs/code_registry/functions/report_generator-1a878fcc_18d44bdc.py +47 -0
  62. test_logs/code_registry/functions/report_generator-25c1c331_cea57d0d.py +35 -0
  63. test_logs/code_registry/functions/report_generator-37552117_e711c2b9.py +35 -0
  64. test_logs/code_registry/functions/report_generator-bc662768_e711c2b9.py +35 -0
  65. test_logs/code_registry/functions/report_generator-d6c0e76b_5e7722ec.py +44 -0
  66. test_logs/code_registry/functions/report_generator-f270fb02_680529c3.py +44 -0
  67. test_logs/code_registry/functions/text_processor-11393b14_4370d3ed.py +40 -0
  68. test_logs/code_registry/functions/text_processor-7d02dfc3_d3b569be.py +37 -0
  69. test_logs/code_registry/functions/text_processor-8adb5e32_9168c5fe.py +13 -0
  70. test_logs/code_registry/functions/text_processor-c58ffc19_78b4ceac.py +42 -0
  71. test_logs/code_registry/functions/text_processor-cd5977b1_9168c5fe.py +13 -0
  72. test_logs/code_registry/functions/text_processor-ec1c8773_9168c5fe.py +13 -0
  73. tests/test_01_analyst_standalone.py +124 -0
  74. tests/test_02_assistant_standalone.py +164 -0
  75. tests/test_03_analyst_with_framework.py +945 -0
  76. tests/test_04_assistant_with_framework.py +1002 -0
  77. tests/test_05_integration.py +1301 -0
  78. tests/test_06_real_llm_integration.py +760 -0
  79. tests/test_07_distributed_single_node.py +578 -0
  80. tests/test_08_distributed_multi_node.py +454 -0
  81. tests/test_09_distributed_autoagent.py +509 -0
  82. tests/test_10_distributed_customagent.py +787 -0
  83. tests/test_mesh.py +35 -4
  84. jarviscore_framework-0.1.1.dist-info/METADATA +0 -137
  85. jarviscore_framework-0.1.1.dist-info/RECORD +0 -69
  86. {jarviscore_framework-0.1.1.dist-info → jarviscore_framework-0.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -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 - "autonomous" (single-node) or "distributed" (P2P mesh)
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
- #### `add_agent(profile_class, role, capabilities, **kwargs)`
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
- mesh.add_agent(
59
- AutoAgent,
60
- role="calculator",
61
- capabilities=["math", "calculation"],
62
- system_prompt="You are a math expert"
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
- - `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
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 run_workflow(steps)`
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.run_workflow([
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 LangChainAgent(CustomAgent):
498
+ class MyAgent(CustomAgent):
499
+ role = "my_role"
500
+ capabilities = ["my_capability"]
501
+
301
502
  async def setup(self):
302
- from langchain import LLMChain
303
- self.chain = LLMChain(...)
503
+ await super().setup()
504
+ # Initialize your resources
304
505
 
305
506
  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
- }
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
- **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
518
+ **Class Attributes:**
519
+ - `role` (str): Agent role identifier (required)
520
+ - `capabilities` (list): List of capability strings (required)
319
521
 
320
- **Example:**
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
- ```python
323
- class APIAgent(CustomAgent):
324
- async def setup(self):
325
- self.api_client = MyAPIClient()
527
+ **Key Methods:**
326
528
 
327
- async def execute_task(self, task):
328
- # Manual implementation
329
- response = await self.api_client.call(task['task'])
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
- # Optional cost tracking
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
- return {
339
- "status": "success",
340
- "output": response,
341
- "agent": self.agent_id
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.1.0
1143
+ API Reference for JarvisCore v0.2.1
931
1144
 
932
- Last Updated: 2026-01-12
1145
+ Last Updated: 2026-01-23
@@ -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.
@@ -251,27 +251,28 @@ Generated code is automatically registered:
251
251
 
252
252
  ## P2P Configuration
253
253
 
254
- Configure distributed mesh networking (optional).
254
+ Configure distributed mesh networking for `p2p` and `distributed` modes.
255
255
 
256
- ### Enable P2P
256
+ ### Execution Modes
257
257
 
258
- ```bash
259
- # Enable P2P mesh
260
- P2P_ENABLED=true
261
-
262
- # Node identification
263
- NODE_NAME=jarviscore-node-1
264
- ```
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={...})` | ✅ | ✅ |
265
263
 
266
- ### Network Settings
264
+ ### Network Settings (P2P and Distributed)
267
265
 
268
266
  ```bash
269
267
  # Bind address and port
270
268
  BIND_HOST=0.0.0.0 # Listen on all interfaces
271
- BIND_PORT=7946 # SWIM protocol port
269
+ BIND_PORT=7950 # SWIM protocol port
272
270
 
273
- # Seed nodes (comma-separated)
274
- SEED_NODES=192.168.1.100:7946,192.168.1.101:7946
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
275
276
  ```
276
277
 
277
278
  ### Transport Configuration
@@ -540,14 +541,27 @@ Override environment variables in code:
540
541
  ```python
541
542
  from jarviscore import Mesh
542
543
 
543
- config = {
544
- 'sandbox_mode': 'remote',
545
- 'sandbox_service_url': 'https://...',
544
+ # Autonomous mode (no P2P config needed)
545
+ mesh = Mesh(mode="autonomous", config={
546
546
  'execution_timeout': 600,
547
547
  'log_level': 'DEBUG'
548
- }
549
-
550
- mesh = Mesh(mode="autonomous", config=config)
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
+ })
551
565
  ```
552
566
 
553
567
  **Note:** Programmatic config overrides environment variables.
@@ -752,6 +766,6 @@ LOG_DIRECTORY=/tmp/jarviscore-logs
752
766
 
753
767
  ## Version
754
768
 
755
- Configuration Guide for JarvisCore v0.1.0
769
+ Configuration Guide for JarvisCore v0.2.1
756
770
 
757
- Last Updated: 2026-01-12
771
+ Last Updated: 2026-01-23