elo-node 0.4.0__tar.gz

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.
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.4
2
+ Name: elo-node
3
+ Version: 0.4.0
4
+ Summary: Elo — malha P2P de mensagens para agentes de IA. Zero infraestrutura.
5
+ Author: Elo Contributors
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/xalq/elo
8
+ Project-URL: Repository, https://github.com/xalq/elo
9
+ Keywords: p2p,agents,ai,distributed,messaging,mesh
10
+ Classifier: Development Status :: 2 - Pre-Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Requires-Python: >=3.11
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: cryptography>=42.0
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8.0; extra == "dev"
21
+ Requires-Dist: pytest-asyncio>=0.25; extra == "dev"
22
+
23
+ # Elo Node — Malha P2P para Agentes de IA
24
+
25
+ **Zero infraestrutura. Um processo. Uma porta TCP. Uma chave ed25519.**
26
+
27
+ Elo é uma malha de mensagens P2P descentralizada para comunicação entre agentes de IA. Sem servidor central, sem Kafka, sem Redis, sem NATS. Apenas TCP direto entre nós.
28
+
29
+ ```bash
30
+ pip install elo-node
31
+ ```
32
+
33
+ ```python
34
+ import asyncio
35
+ from elo import Node
36
+
37
+ async def main():
38
+ node = Node("meu-agente", port=7878)
39
+ await node.connect()
40
+ await node.register(agents=["analyst"], tools=["web-search"])
41
+
42
+ @node.on_task
43
+ async def handle(task):
44
+ return {"result": f"processed by {node.node_id}"}
45
+
46
+ await node.run()
47
+
48
+ asyncio.run(main())
49
+ ```
50
+
51
+ ## Recursos
52
+
53
+ - **P2P descentralizado** — descoberta via tracker público ou DHT Kademlia
54
+ - **Assinatura ed25519** — identidade criptográfica, mensagens autenticadas
55
+ - **Capabilities** — publish/subscribe de capacidades entre nós
56
+ - **Zero infra** — sem Kafka, Redis, NATS, ou servidor central
57
+ - **CLI nativo** — `python -m elo serve`, `status`, `init`, `id`
58
+
59
+ ## CLI
60
+
61
+ ```bash
62
+ python -m elo status # Node ID, hash, chaves
63
+ python -m elo id # Apenas o node_id
64
+ python -m elo pubkey # Chave pública (hex + b64)
65
+ python -m elo init # Gerar identidade persistente
66
+ python -m elo serve # Iniciar nó interativo
67
+ ```
68
+
69
+ ## Arquitetura
70
+
71
+ ```
72
+ ┌──────────────────┐ TCP/JSON ┌──────────────────┐
73
+ │ Node A │◄──────────────►│ Node B │
74
+ │ ed25519 key │ │ ed25519 key │
75
+ │ Capabilities │ │ Capabilities │
76
+ │ Interests │ │ Interests │
77
+ └──────────────────┘ └──────────────────┘
78
+ │ │
79
+ │ Tracker (opcional) │
80
+ └───────────── DHT ────────────────┘
81
+ ```
82
+
83
+ Cada nó:
84
+ 1. Gera identidade ed25519 na primeira execução
85
+ 2. Escuta em uma porta TCP
86
+ 3. Anuncia capacidades (ex: "analyst", "web-search")
87
+ 4. Descobre outros nós via tracker compartilhado ou peers manuais
88
+ 5. Troca mensagens assinadas (tasks, results, events)
89
+
90
+ ## Compatibilidade
91
+
92
+ - Python 3.11+
93
+ - Linux, macOS, Windows
94
+
95
+ ## Desenvolvimento
96
+
97
+ ```bash
98
+ git clone https://github.com/xalq/elo
99
+ cd elo/py
100
+ pip install -e ".[dev]"
101
+ pytest
102
+ ```
103
+
104
+ ## Projetos Relacionados
105
+
106
+ - [Hermes Agent](https://hermes-agent.nousresearch.com) — runtime de agentes autônomos
107
+ - [Honcho](https://github.com/argmax-inc/honcho) — memória persistente para agentes
@@ -0,0 +1,85 @@
1
+ # Elo Node — Malha P2P para Agentes de IA
2
+
3
+ **Zero infraestrutura. Um processo. Uma porta TCP. Uma chave ed25519.**
4
+
5
+ Elo é uma malha de mensagens P2P descentralizada para comunicação entre agentes de IA. Sem servidor central, sem Kafka, sem Redis, sem NATS. Apenas TCP direto entre nós.
6
+
7
+ ```bash
8
+ pip install elo-node
9
+ ```
10
+
11
+ ```python
12
+ import asyncio
13
+ from elo import Node
14
+
15
+ async def main():
16
+ node = Node("meu-agente", port=7878)
17
+ await node.connect()
18
+ await node.register(agents=["analyst"], tools=["web-search"])
19
+
20
+ @node.on_task
21
+ async def handle(task):
22
+ return {"result": f"processed by {node.node_id}"}
23
+
24
+ await node.run()
25
+
26
+ asyncio.run(main())
27
+ ```
28
+
29
+ ## Recursos
30
+
31
+ - **P2P descentralizado** — descoberta via tracker público ou DHT Kademlia
32
+ - **Assinatura ed25519** — identidade criptográfica, mensagens autenticadas
33
+ - **Capabilities** — publish/subscribe de capacidades entre nós
34
+ - **Zero infra** — sem Kafka, Redis, NATS, ou servidor central
35
+ - **CLI nativo** — `python -m elo serve`, `status`, `init`, `id`
36
+
37
+ ## CLI
38
+
39
+ ```bash
40
+ python -m elo status # Node ID, hash, chaves
41
+ python -m elo id # Apenas o node_id
42
+ python -m elo pubkey # Chave pública (hex + b64)
43
+ python -m elo init # Gerar identidade persistente
44
+ python -m elo serve # Iniciar nó interativo
45
+ ```
46
+
47
+ ## Arquitetura
48
+
49
+ ```
50
+ ┌──────────────────┐ TCP/JSON ┌──────────────────┐
51
+ │ Node A │◄──────────────►│ Node B │
52
+ │ ed25519 key │ │ ed25519 key │
53
+ │ Capabilities │ │ Capabilities │
54
+ │ Interests │ │ Interests │
55
+ └──────────────────┘ └──────────────────┘
56
+ │ │
57
+ │ Tracker (opcional) │
58
+ └───────────── DHT ────────────────┘
59
+ ```
60
+
61
+ Cada nó:
62
+ 1. Gera identidade ed25519 na primeira execução
63
+ 2. Escuta em uma porta TCP
64
+ 3. Anuncia capacidades (ex: "analyst", "web-search")
65
+ 4. Descobre outros nós via tracker compartilhado ou peers manuais
66
+ 5. Troca mensagens assinadas (tasks, results, events)
67
+
68
+ ## Compatibilidade
69
+
70
+ - Python 3.11+
71
+ - Linux, macOS, Windows
72
+
73
+ ## Desenvolvimento
74
+
75
+ ```bash
76
+ git clone https://github.com/xalq/elo
77
+ cd elo/py
78
+ pip install -e ".[dev]"
79
+ pytest
80
+ ```
81
+
82
+ ## Projetos Relacionados
83
+
84
+ - [Hermes Agent](https://hermes-agent.nousresearch.com) — runtime de agentes autônomos
85
+ - [Honcho](https://github.com/argmax-inc/honcho) — memória persistente para agentes
@@ -0,0 +1,29 @@
1
+ """
2
+ Elo — malha P2P de mensagens para agentes de IA.
3
+
4
+ Um processo. Uma porta TCP. Uma chave ed25519.
5
+ Zero infraestrutura externa.
6
+
7
+ Uso:
8
+ from elo import Node
9
+
10
+ node = Node("meu-agente", port=7878)
11
+ await node.connect()
12
+ await node.register(agents=["analyst"], tools=["web-search"])
13
+
14
+ @node.on_task
15
+ async def handle(task):
16
+ return {"result": "ok"}
17
+
18
+ await node.run()
19
+ """
20
+
21
+ from elo.node import Node
22
+ from elo.security import EphemeralIdentity, generate_and_save_identity, load_identity
23
+ from elo.types import Task, Result, Event, NodeInfo, Capabilities
24
+
25
+ __all__ = [
26
+ "Node", "Task", "Result", "Event", "NodeInfo", "Capabilities",
27
+ "EphemeralIdentity", "generate_and_save_identity", "load_identity",
28
+ ]
29
+ __version__ = "0.4.0"
@@ -0,0 +1,153 @@
1
+ """Elo CLI — gerenciamento de identidade e status do nó.
2
+
3
+ Uso:
4
+ python -m elo status # Status completo (id, chaves)
5
+ python -m elo id # Apenas o node_id
6
+ python -m elo pubkey # Chave pública completa
7
+ python -m elo init # Gera e salva identidade persistente
8
+ python -m elo serve # Inicia um nó interativo
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import asyncio
15
+ import hashlib
16
+ import json
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ from elo.security import (
21
+ EphemeralIdentity,
22
+ generate_and_save_identity,
23
+ load_identity,
24
+ pubkey_to_id,
25
+ DEFAULT_KEY_DIR,
26
+ )
27
+
28
+
29
+ def _short_id(node_id: str, n: int = 12) -> str:
30
+ h = hashlib.sha256(node_id.encode()).hexdigest()[:16]
31
+ return f"{node_id[:n]}... (sha256:{h})"
32
+
33
+
34
+ def cmd_status() -> None:
35
+ """Exibe o status completo do nó (identidade, chaves)."""
36
+ identity = EphemeralIdentity()
37
+ node_id = identity.node_id
38
+ pubkey_bytes = identity.public_key.public_bytes_raw()
39
+
40
+ print("=" * 52)
41
+ print(" ELO NODE STATUS")
42
+ print("=" * 52)
43
+ print(f" Node ID: {node_id}")
44
+ print(f" Hash: {_short_id(node_id)}")
45
+ print("-" * 52)
46
+ print(f" Algorithm: ed25519")
47
+ print("-" * 52)
48
+ print(f" Public key (hex):")
49
+ print(f" {pubkey_bytes.hex()}")
50
+ print(f" Public key (b64):")
51
+ print(f" {node_id}")
52
+ print("-" * 52)
53
+
54
+ seed_path = DEFAULT_KEY_DIR / "identity.seed"
55
+ if seed_path.exists():
56
+ try:
57
+ priv, x25519 = load_identity()
58
+ pub = priv.public_key()
59
+ saved_id = pubkey_to_id(pub)
60
+ print(f" Persisted: {DEFAULT_KEY_DIR}")
61
+ print(f" Saved ID: {saved_id}")
62
+ except Exception:
63
+ print(f" Persisted: ERROR loading from {DEFAULT_KEY_DIR}")
64
+ else:
65
+ print(f" Persisted: no (ephemeral)")
66
+ print(f" Use 'python -m elo init' to save")
67
+ print(f" Default dir: {DEFAULT_KEY_DIR}")
68
+
69
+ print("=" * 52)
70
+
71
+
72
+ def cmd_id() -> None:
73
+ identity = EphemeralIdentity()
74
+ print(identity.node_id)
75
+
76
+
77
+ def cmd_pubkey() -> None:
78
+ identity = EphemeralIdentity()
79
+ node_id = identity.node_id
80
+ pubkey = identity.public_key.public_bytes_raw()
81
+ print(f"node_id (b64): {node_id}")
82
+ print(f"public (hex): {pubkey.hex()}")
83
+ print(f"algorithm: ed25519")
84
+
85
+
86
+ def cmd_init() -> None:
87
+ key_dir = DEFAULT_KEY_DIR
88
+ pub, priv = generate_and_save_identity(key_dir)
89
+ node_id = pubkey_to_id(pub)
90
+ print(f"Identity generated and saved to: {key_dir}")
91
+ print(f" identity.seed -- ed25519 private key")
92
+ print()
93
+ print(f"Node ID: {node_id}")
94
+ print(f"Hash: {_short_id(node_id)}")
95
+ print()
96
+ print("!! Keep identity.seed safe -- it is your node's identity.")
97
+ print(" Without it, peers will not recognize this node after restart.")
98
+
99
+
100
+ def cmd_serve() -> None:
101
+ from elo import Node
102
+
103
+ async def _serve():
104
+ node = Node("elo-cli", port=7878)
105
+ await node.connect()
106
+ await node.register(agents=["echo-cli"])
107
+
108
+ @node.on_task
109
+ async def handle(task):
110
+ print(f"[task] {task.capability}: {task.payload}")
111
+ return {"echo": task.payload, "from": node.node_id}
112
+
113
+ print(f"[elo] serving on port {node.port} | id={_short_id(node.node_id)}")
114
+ print(f"[elo] Press Ctrl+C to stop")
115
+ await node.run()
116
+
117
+ try:
118
+ asyncio.run(_serve())
119
+ except KeyboardInterrupt:
120
+ print("\n[elo] stopped")
121
+
122
+
123
+ def main() -> None:
124
+ parser = argparse.ArgumentParser(
125
+ prog="elo",
126
+ description="Elo CLI — malha P2P para agentes de IA",
127
+ )
128
+ sub = parser.add_subparsers(dest="command", help="Comandos")
129
+
130
+ sub.add_parser("status", help="Status completo do nó (identidade + chaves)")
131
+ sub.add_parser("id", help="Apenas o node_id")
132
+ sub.add_parser("pubkey", help="Chave pública em formatos úteis")
133
+ sub.add_parser("init", help="Gerar e salvar identidade persistente")
134
+ sub.add_parser("serve", help="Iniciar um nó interativo (porta 7878)")
135
+
136
+ args = parser.parse_args()
137
+
138
+ commands = {
139
+ "status": cmd_status,
140
+ "id": cmd_id,
141
+ "pubkey": cmd_pubkey,
142
+ "init": cmd_init,
143
+ "serve": cmd_serve,
144
+ }
145
+
146
+ if args.command in commands:
147
+ commands[args.command]()
148
+ else:
149
+ parser.print_help()
150
+
151
+
152
+ if __name__ == "__main__":
153
+ main()