jarviscore-framework 0.2.0__py3-none-any.whl → 0.3.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/cloud_deployment_example.py +162 -0
- examples/customagent_p2p_example.py +566 -183
- examples/fastapi_integration_example.py +570 -0
- examples/listeneragent_cognitive_discovery_example.py +343 -0
- jarviscore/__init__.py +22 -5
- jarviscore/cli/smoketest.py +8 -4
- jarviscore/core/agent.py +227 -0
- jarviscore/data/examples/cloud_deployment_example.py +162 -0
- jarviscore/data/examples/customagent_p2p_example.py +566 -183
- jarviscore/data/examples/fastapi_integration_example.py +570 -0
- jarviscore/data/examples/listeneragent_cognitive_discovery_example.py +343 -0
- jarviscore/docs/API_REFERENCE.md +296 -3
- jarviscore/docs/CHANGELOG.md +97 -0
- jarviscore/docs/CONFIGURATION.md +2 -2
- jarviscore/docs/CUSTOMAGENT_GUIDE.md +2021 -255
- jarviscore/docs/GETTING_STARTED.md +112 -8
- jarviscore/docs/TROUBLESHOOTING.md +3 -3
- jarviscore/docs/USER_GUIDE.md +152 -6
- jarviscore/integrations/__init__.py +16 -0
- jarviscore/integrations/fastapi.py +247 -0
- jarviscore/p2p/broadcaster.py +10 -3
- jarviscore/p2p/coordinator.py +310 -14
- jarviscore/p2p/keepalive.py +45 -23
- jarviscore/p2p/peer_client.py +282 -10
- jarviscore/p2p/swim_manager.py +9 -4
- jarviscore/profiles/__init__.py +10 -2
- jarviscore/profiles/listeneragent.py +292 -0
- {jarviscore_framework-0.2.0.dist-info → jarviscore_framework-0.3.0.dist-info}/METADATA +42 -8
- {jarviscore_framework-0.2.0.dist-info → jarviscore_framework-0.3.0.dist-info}/RECORD +36 -22
- {jarviscore_framework-0.2.0.dist-info → jarviscore_framework-0.3.0.dist-info}/WHEEL +1 -1
- tests/test_13_dx_improvements.py +554 -0
- tests/test_14_cloud_deployment.py +403 -0
- tests/test_15_llm_cognitive_discovery.py +684 -0
- tests/test_16_unified_dx_flow.py +947 -0
- {jarviscore_framework-0.2.0.dist-info → jarviscore_framework-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {jarviscore_framework-0.2.0.dist-info → jarviscore_framework-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cloud Deployment Example (v0.3.0)
|
|
3
|
+
|
|
4
|
+
Demonstrates agent self-registration with join_mesh() and leave_mesh().
|
|
5
|
+
Agents join an existing mesh independently - no central orchestrator needed.
|
|
6
|
+
|
|
7
|
+
This is the pattern for:
|
|
8
|
+
- Docker containers where each container runs one agent
|
|
9
|
+
- Kubernetes pods with auto-scaling
|
|
10
|
+
- Cloud Functions / Lambda
|
|
11
|
+
- Any distributed deployment where agents start independently
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
# Terminal 1: Start a mesh (or use an existing one)
|
|
15
|
+
python examples/customagent_p2p_example.py
|
|
16
|
+
|
|
17
|
+
# Terminal 2: Run standalone agent that joins the mesh
|
|
18
|
+
JARVISCORE_SEED_NODES=127.0.0.1:7946 python examples/cloud_deployment_example.py
|
|
19
|
+
|
|
20
|
+
Environment Variables:
|
|
21
|
+
JARVISCORE_SEED_NODES: Comma-separated seed nodes (e.g., "host1:7946,host2:7946")
|
|
22
|
+
JARVISCORE_MESH_ENDPOINT: Single mesh endpoint (alternative to seed_nodes)
|
|
23
|
+
"""
|
|
24
|
+
import asyncio
|
|
25
|
+
import os
|
|
26
|
+
import signal
|
|
27
|
+
import sys
|
|
28
|
+
|
|
29
|
+
sys.path.insert(0, '.')
|
|
30
|
+
|
|
31
|
+
from jarviscore.profiles import ListenerAgent
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class StandaloneProcessor(ListenerAgent):
|
|
35
|
+
"""
|
|
36
|
+
Example standalone agent that joins mesh independently.
|
|
37
|
+
|
|
38
|
+
This agent:
|
|
39
|
+
- Self-registers with the mesh on startup
|
|
40
|
+
- Listens for peer requests
|
|
41
|
+
- Shows its view of the mesh (cognitive context)
|
|
42
|
+
- Gracefully leaves mesh on shutdown
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
role = "standalone_processor"
|
|
46
|
+
capabilities = ["standalone", "processing", "example"]
|
|
47
|
+
description = "Processes requests from other mesh agents (standalone deployment)"
|
|
48
|
+
|
|
49
|
+
async def on_peer_request(self, msg):
|
|
50
|
+
"""Handle incoming requests from other agents."""
|
|
51
|
+
print(f"\n[{self.role}] Received request from {msg.sender}:")
|
|
52
|
+
print(f" Data: {msg.data}")
|
|
53
|
+
|
|
54
|
+
# Process the request
|
|
55
|
+
task = msg.data.get("task", "")
|
|
56
|
+
result = {
|
|
57
|
+
"status": "success",
|
|
58
|
+
"output": f"Processed: {task}",
|
|
59
|
+
"agent_id": self.agent_id,
|
|
60
|
+
"processed_by": self.role
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
print(f"[{self.role}] Sending response: {result}")
|
|
64
|
+
return result
|
|
65
|
+
|
|
66
|
+
async def on_peer_notify(self, msg):
|
|
67
|
+
"""Handle incoming notifications from other agents."""
|
|
68
|
+
print(f"\n[{self.role}] Received notification from {msg.sender}:")
|
|
69
|
+
print(f" Event: {msg.data.get('event', 'unknown')}")
|
|
70
|
+
print(f" Data: {msg.data}")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
async def main():
|
|
74
|
+
print("=" * 60)
|
|
75
|
+
print("Standalone Agent Example - Cloud Deployment Pattern")
|
|
76
|
+
print("=" * 60)
|
|
77
|
+
|
|
78
|
+
# Check for mesh connection info
|
|
79
|
+
endpoint = os.environ.get("JARVISCORE_MESH_ENDPOINT")
|
|
80
|
+
seed_nodes = os.environ.get("JARVISCORE_SEED_NODES")
|
|
81
|
+
|
|
82
|
+
if not endpoint and not seed_nodes:
|
|
83
|
+
print("\nNo mesh endpoint configured!")
|
|
84
|
+
print("\nSet one of:")
|
|
85
|
+
print(" - JARVISCORE_MESH_ENDPOINT (single endpoint)")
|
|
86
|
+
print(" - JARVISCORE_SEED_NODES (comma-separated list)")
|
|
87
|
+
print("\nExample:")
|
|
88
|
+
print(" JARVISCORE_SEED_NODES=127.0.0.1:7946 python cloud_deployment_example.py")
|
|
89
|
+
print("\nTo start a mesh first, run:")
|
|
90
|
+
print(" python examples/customagent_p2p_example.py")
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
print(f"\nConnecting to mesh via: {endpoint or seed_nodes}")
|
|
94
|
+
|
|
95
|
+
# Create agent
|
|
96
|
+
agent = StandaloneProcessor()
|
|
97
|
+
|
|
98
|
+
# Join the mesh
|
|
99
|
+
print(f"\nJoining mesh...")
|
|
100
|
+
try:
|
|
101
|
+
await agent.join_mesh()
|
|
102
|
+
except Exception as e:
|
|
103
|
+
print(f"Failed to join mesh: {e}")
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
print(f"\nSuccessfully joined mesh!")
|
|
107
|
+
print(f" Agent ID: {agent.agent_id}")
|
|
108
|
+
print(f" Role: {agent.role}")
|
|
109
|
+
print(f" Capabilities: {agent.capabilities}")
|
|
110
|
+
|
|
111
|
+
# Show discovered peers
|
|
112
|
+
print(f"\n--- Discovered Peers ---")
|
|
113
|
+
peers = agent.peers.list_peers()
|
|
114
|
+
if peers:
|
|
115
|
+
for p in peers:
|
|
116
|
+
location = f" ({p.get('location', 'unknown')})" if 'location' in p else ""
|
|
117
|
+
print(f" - {p['role']}: {p['capabilities']}{location}")
|
|
118
|
+
else:
|
|
119
|
+
print(" No other peers discovered yet")
|
|
120
|
+
|
|
121
|
+
# Show cognitive context (what an LLM would see)
|
|
122
|
+
print(f"\n--- Cognitive Context for LLM ---")
|
|
123
|
+
print(agent.peers.get_cognitive_context())
|
|
124
|
+
|
|
125
|
+
# Setup graceful shutdown
|
|
126
|
+
shutdown_event = asyncio.Event()
|
|
127
|
+
|
|
128
|
+
def signal_handler():
|
|
129
|
+
print("\n\nShutdown requested (Ctrl+C)...")
|
|
130
|
+
agent.request_shutdown()
|
|
131
|
+
shutdown_event.set()
|
|
132
|
+
|
|
133
|
+
# Register signal handlers
|
|
134
|
+
loop = asyncio.get_event_loop()
|
|
135
|
+
for sig in (signal.SIGINT, signal.SIGTERM):
|
|
136
|
+
try:
|
|
137
|
+
loop.add_signal_handler(sig, signal_handler)
|
|
138
|
+
except NotImplementedError:
|
|
139
|
+
# Windows doesn't support add_signal_handler
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
print(f"\n--- Agent Running ---")
|
|
143
|
+
print("Listening for peer requests...")
|
|
144
|
+
print("Press Ctrl+C to stop.\n")
|
|
145
|
+
|
|
146
|
+
# Run agent (ListenerAgent's run() handles the message loop)
|
|
147
|
+
try:
|
|
148
|
+
await agent.run()
|
|
149
|
+
except asyncio.CancelledError:
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
# Leave mesh gracefully
|
|
153
|
+
print("\nLeaving mesh...")
|
|
154
|
+
await agent.leave_mesh()
|
|
155
|
+
print("Goodbye!")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
if __name__ == "__main__":
|
|
159
|
+
try:
|
|
160
|
+
asyncio.run(main())
|
|
161
|
+
except KeyboardInterrupt:
|
|
162
|
+
print("\nInterrupted.")
|