Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "slim"]
path = slim
url = https://github.com/agntcy/slim.git
22 changes: 22 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version: '3.8'

services:
slim-control-plane:
build:
context: https://github.com/agntcy/slim.git#main
dockerfile: control-plane/Dockerfile
ports:
- "8080:8080"
restart: unless-stopped

slim-data-plane:
build:
context: https://github.com/agntcy/slim.git#main
dockerfile: data-plane/Dockerfile
ports:
- "50051:50051"
environment:
- CONTROL_PLANE_URL=http://slim-control-plane:8080
restart: unless-stopped
depends_on:
- slim-control-plane
282 changes: 86 additions & 196 deletions examples/nanda_agent.py

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions nanda_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"""

from .core.adapter import NANDA
from .core.agent_bridge import SimpleAgentBridge
from .core.agent_bridge import AgentBridge

__all__ = [
"NANDA",
"SimpleAgentBridge"
"AgentBridge"
]
4 changes: 2 additions & 2 deletions nanda_core/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"""

from .adapter import NANDA
from .agent_bridge import SimpleAgentBridge
from .agent_bridge import AgentBridge

__all__ = [
"NANDA",
"SimpleAgentBridge"
"AgentBridge"
]
131 changes: 105 additions & 26 deletions nanda_core/core/adapter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python3
"""
Simple NANDA Adapter - Clean Agent-to-Agent Communication

Expand All @@ -7,10 +6,13 @@
"""

import os
import asyncio
import requests
from typing import Optional, Callable
from python_a2a import run_server
from .agent_bridge import SimpleAgentBridge
from typing import Optional, Callable, Dict
from .agent_bridge import AgentBridge
from .registry_client import RegistryClient
from ..protocols.router import ProtocolRouter
from ..protocols.a2a.protocol import A2AProtocol


class NANDA:
Expand All @@ -19,30 +21,48 @@ class NANDA:
def __init__(self,
agent_id: str,
agent_logic: Callable[[str, str], str],
agent_name: Optional[str] = None,
domain: Optional[str] = None,
specialization: Optional[str] = None,
description: Optional[str] = None,
capabilities: Optional[list] = None,
port: int = 6000,
registry_url: Optional[str] = None,
public_url: Optional[str] = None,
host: str = "0.0.0.0",
enable_telemetry: bool = True):
enable_telemetry: bool = True,
protocols: Optional[dict] = None):
"""
Create a simple NANDA agent

Args:
agent_id: Unique agent identifier
agent_logic: Function that takes (message: str, conversation_id: str) -> response: str
agent_name: Display name (defaults to agent_id)
domain: Agent's domain of expertise
specialization: Agent's specialization
description: Agent description
capabilities: List of capabilities (default: ["text"])
port: Port to run on
registry_url: Optional registry URL for agent discovery
public_url: Public URL for agent registration (e.g., https://yourdomain.com:6000)
host: Host to bind to
enable_telemetry: Enable telemetry logging (optional)
enable_telemetry: Enable telemetry logging
protocols: Dict of protocol configs (e.g., {"a2a": {"enabled": True}})
"""
self.agent_id = agent_id
self.agent_logic = agent_logic
self.agent_name = agent_name or agent_id
self.domain = domain
self.specialization = specialization
self.description = description or f"AI agent {agent_id}"
self.capabilities = capabilities or ["text"]
self.port = port
self.registry_url = registry_url
self.public_url = public_url
self.public_url = public_url or f"http://localhost:{port}"
self.host = host
self.enable_telemetry = enable_telemetry
self.protocols_config = protocols or {"a2a": {"enabled": True}}

# Initialize telemetry if enabled
self.telemetry = None
Expand All @@ -54,46 +74,105 @@ def __init__(self,
except ImportError:
print(f"⚠️ Telemetry requested but module not available")

# Create the bridge with optional features
self.bridge = SimpleAgentBridge(
# Initialize protocol router
self.router = ProtocolRouter()

# Initialize and register protocols
self._initialize_protocols()

# Initialize registry client
self.registry = RegistryClient(registry_url) if registry_url else RegistryClient(None)

# Create the bridge
self.bridge = AgentBridge(
protocol_router=self.router,
registry_client=self.registry,
agent_id=agent_id,
agent_logic=agent_logic,
registry_url=registry_url,
telemetry=self.telemetry
)

print(f"πŸ€– NANDA Agent '{agent_id}' created")
if registry_url:
print(f"🌐 Registry: {registry_url}")
if public_url:
print(f"πŸ”— Public URL: {public_url}")
print(f"πŸ”— Public URL: {self.public_url}")
print(f"πŸ”Œ Protocols: {self.router.get_all_protocols()}")

def _initialize_protocols(self):
"""Initialize and register protocol adapters based on config"""

# Initialize A2A protocol if enabled
if self.protocols_config.get("a2a", {}).get("enabled", True):
a2a_protocol = A2AProtocol(
agent_id=self.agent_id,
agent_name=self.agent_name,
public_url=self.public_url,
domain=self.domain,
specialization=self.specialization,
description=self.description,
capabilities=self.capabilities
)
self.router.register(a2a_protocol)

slim_config = self.protocols_config.get("slim", {})
if slim_config.get("enabled", False):
from ..protocols.slim.adapter import SLIMProtocol

slim_node_url = slim_config.get("node_url", "grpc://localhost:50051")

slim_protocol = SLIMProtocol(
agent_id=self.agent_id,
slim_node_url=slim_node_url,
agent_name=self.agent_name
)
self.router.register(slim_protocol)
print(f"πŸ”Œ SLIM protocol enabled (node: {slim_node_url})")

def start(self, register: bool = True):
async def start(self, register: bool = True):
"""Start the agent server"""
# Register with registry if provided
if register and self.registry_url and self.public_url:
self._register()
if register and self.registry_url:
await self._register()

print(f"πŸš€ Starting agent '{self.agent_id}' on {self.host}:{self.port}")

# Start the A2A server
run_server(self.bridge, host=self.host, port=self.port)
# Start the bridge (which starts all protocol servers)
await self.bridge.run_server(self.host, self.port)

def _register(self):
"""Register agent with registry"""
async def _register(self):
"""Register agent with NANDA Index"""
try:
data = {
agent_facts = {
"agent_id": self.agent_id,
"agent_url": self.public_url
"name": self.agent_name,
"domain": self.domain,
"specialization": self.specialization,
"description": self.description,
"capabilities": self.capabilities,
"url": self.public_url,
"agent_url": self.public_url, # For backward compatibility
"supported_protocols": self.router.get_all_protocols(),
"endpoints": self._get_endpoints()
}
response = requests.post(f"{self.registry_url}/register", json=data, timeout=10)
if response.status_code == 200:
print(f"βœ… Agent '{self.agent_id}' registered successfully")
else:
print(f"⚠️ Failed to register agent: HTTP {response.status_code}")

await self.registry.register(agent_facts)
print(f"βœ… Agent '{self.agent_id}' registered successfully")

except Exception as e:
print(f"⚠️ Registration error: {e}")

def _get_endpoints(self) -> Dict[str, str]:
"""Get endpoints for all registered protocols"""
endpoints = {}
for protocol_name in self.router.get_all_protocols():
if protocol_name == "a2a":
endpoints["a2a"] = f"{self.public_url}/a2a"
elif protocol_name == "slim":
# SLIM uses agent inbox channel, not HTTP endpoint
endpoints["slim"] = f"slim://{self.agent_id}"

return endpoints

def stop(self):
"""Stop the agent and cleanup telemetry"""
if self.telemetry:
Expand Down
101 changes: 101 additions & 0 deletions nanda_core/core/adapter_copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env python3
"""
Simple NANDA Adapter - Clean Agent-to-Agent Communication

Simple, clean adapter focused on A2A communication without complexity.
8-10 lines to deploy an agent.
"""

import os
import requests
from typing import Optional, Callable
from python_a2a import run_server
from .agent_bridge import SimpleAgentBridge


class NANDA:
"""Simple NANDA class for clean agent deployment"""

def __init__(self,
agent_id: str,
agent_logic: Callable[[str, str], str],
port: int = 6000,
registry_url: Optional[str] = None,
public_url: Optional[str] = None,
host: str = "0.0.0.0",
enable_telemetry: bool = True):
"""
Create a simple NANDA agent

Args:
agent_id: Unique agent identifier
agent_logic: Function that takes (message: str, conversation_id: str) -> response: str
port: Port to run on
registry_url: Optional registry URL for agent discovery
public_url: Public URL for agent registration (e.g., https://yourdomain.com:6000)
host: Host to bind to
enable_telemetry: Enable telemetry logging (optional)
"""
self.agent_id = agent_id
self.agent_logic = agent_logic
self.port = port
self.registry_url = registry_url
self.public_url = public_url
self.host = host
self.enable_telemetry = enable_telemetry

# Initialize telemetry if enabled
self.telemetry = None
if enable_telemetry:
try:
from ..telemetry.telemetry_system import TelemetrySystem
self.telemetry = TelemetrySystem(agent_id)
print(f"πŸ“Š Telemetry enabled for {agent_id}")
except ImportError:
print(f"⚠️ Telemetry requested but module not available")

# Create the bridge with optional features
self.bridge = SimpleAgentBridge(
agent_id=agent_id,
agent_logic=agent_logic,
registry_url=registry_url,
telemetry=self.telemetry
)

print(f"πŸ€– NANDA Agent '{agent_id}' created")
if registry_url:
print(f"🌐 Registry: {registry_url}")
if public_url:
print(f"πŸ”— Public URL: {public_url}")

def start(self, register: bool = True):
"""Start the agent server"""
# Register with registry if provided
if register and self.registry_url and self.public_url:
self._register()

print(f"πŸš€ Starting agent '{self.agent_id}' on {self.host}:{self.port}")

# Start the A2A server
run_server(self.bridge, host=self.host, port=self.port)

def _register(self):
"""Register agent with registry"""
try:
data = {
"agent_id": self.agent_id,
"agent_url": self.public_url
}
response = requests.post(f"{self.registry_url}/register", json=data, timeout=10)
if response.status_code == 200:
print(f"βœ… Agent '{self.agent_id}' registered successfully")
else:
print(f"⚠️ Failed to register agent: HTTP {response.status_code}")
except Exception as e:
print(f"⚠️ Registration error: {e}")

def stop(self):
"""Stop the agent and cleanup telemetry"""
if self.telemetry:
self.telemetry.stop()
print(f"πŸ›‘ Stopping agent '{self.agent_id}'")
Loading