GitHub Action
commited on
Commit
·
18163dc
1
Parent(s):
6d02891
Sync from GitHub with Git LFS
Browse files- agents/config.yml +43 -67
- agents/examples/config.yml +2 -1
- agents/peer_sync.py +116 -0
- agents/start_repl.py +1 -1
- agents/tools/storage.py +43 -0
agents/config.yml
CHANGED
@@ -1,70 +1,46 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
agent_id: "" # Оставьте пустым для генерации DiD автоматически
|
5 |
-
agent_name: "CognitiveCore" # Имя агента
|
6 |
-
agent_role: "core" # 'core' или 'shell'
|
7 |
-
|
8 |
-
# === Прокси ===
|
9 |
-
proxy_mode: false # false — прокси не используется, иначе true
|
10 |
-
proxy_type: "socks5" # 'http', 'socks4', 'socks5' и т.д. (если proxy_mode: true)
|
11 |
-
proxy_address: "127.0.0.1:9050"
|
12 |
-
|
13 |
-
# === Функции ядра ===
|
14 |
-
enable_llm: true # доступ к LLM
|
15 |
-
|
16 |
-
serve_api: true # REST API
|
17 |
api_port: 8080
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
27 |
llm_backends:
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
# - "::" # (небезопасно) доступ с любых IPv6-адресов
|
56 |
-
ui_hosts: # Какие IP прослушиваются, ["0.0.0.0"; "::"] - доступен везде
|
57 |
-
- "127.0.0.1"
|
58 |
-
- "::1"
|
59 |
ui_port: 8765
|
60 |
-
|
61 |
-
# === Данные пользователя ===
|
62 |
-
default_user:
|
63 |
-
username: "user"
|
64 |
-
badges: "📌"
|
65 |
-
email: "[email protected]"
|
66 |
-
password: "password" # пусто при инициализации, будет установлен при регистрации
|
67 |
-
|
68 |
-
# === Отладка и логгирование ===
|
69 |
-
debug: true
|
70 |
-
log_level: "INFO" # DEBUG, INFO, WARNING, ERROR
|
|
|
1 |
+
agent_id: did:hmp:4b2e20ef-a6c1-4605-897f-665140035494
|
2 |
+
agent_name: CognitiveCore
|
3 |
+
agent_role: core
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
api_port: 8080
|
5 |
+
bootstrap_responder: true
|
6 |
+
debug: true
|
7 |
+
default_llm: local-model
|
8 |
+
default_user:
|
9 |
+
badges: 📌
|
10 |
+
email: [email protected]
|
11 |
+
password: password
|
12 |
+
username: user
|
13 |
+
dht_enabled: true
|
14 |
+
dht_update: true
|
15 |
+
enable_llm: true
|
16 |
+
identity_agent: 4b2e20ef-a6c1-4605-897f-665140035494
|
17 |
llm_backends:
|
18 |
+
- format: gguf
|
19 |
+
name: local-model
|
20 |
+
path: /models/gguf/mistral.gguf
|
21 |
+
prompt_template: mistral
|
22 |
+
type: local
|
23 |
+
- api_key: lm-studio-any-key
|
24 |
+
base_url: http://127.0.0.1:1234/v1
|
25 |
+
model: mistral
|
26 |
+
name: lmstudio-local
|
27 |
+
provider: openai-compatible
|
28 |
+
type: api
|
29 |
+
- api_key: sk-...
|
30 |
+
model: gpt-4o
|
31 |
+
name: openai-gpt4o
|
32 |
+
provider: openai
|
33 |
+
type: api
|
34 |
+
log_level: INFO
|
35 |
+
notebook_ui: true
|
36 |
+
proxy_address: 127.0.0.1:9050
|
37 |
+
proxy_mode: false
|
38 |
+
proxy_type: socks5
|
39 |
+
serve_api: true
|
40 |
+
tcp_port: 5000
|
41 |
+
udp_port: 4000
|
42 |
+
ui_hosts:
|
43 |
+
- 127.0.0.1
|
44 |
+
- ::1
|
|
|
|
|
|
|
|
|
45 |
ui_port: 8765
|
46 |
+
update_interval: 60
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
agents/examples/config.yml
CHANGED
@@ -20,7 +20,8 @@ api_port: 8080
|
|
20 |
dht_enabled: true # Включение участия в DHT-сети (включено принудительно!)
|
21 |
dht_update: true # Регулярные обновления и публикация данных в DHT (включено принудительно!)
|
22 |
bootstrap_responder: true # Агент отвечает на bootstrap-запросы (включено принудительно!)
|
23 |
-
|
|
|
24 |
update_interval: 60 # секунд (для DHT-обновлений)
|
25 |
|
26 |
# === LLM-бэкенды ===
|
|
|
20 |
dht_enabled: true # Включение участия в DHT-сети (включено принудительно!)
|
21 |
dht_update: true # Регулярные обновления и публикация данных в DHT (включено принудительно!)
|
22 |
bootstrap_responder: true # Агент отвечает на bootstrap-запросы (включено принудительно!)
|
23 |
+
udp_port: 4000
|
24 |
+
tcp_port: 5000
|
25 |
update_interval: 60 # секунд (для DHT-обновлений)
|
26 |
|
27 |
# === LLM-бэкенды ===
|
agents/peer_sync.py
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# agents/peer_sync.py
|
2 |
+
|
3 |
+
"""
|
4 |
+
peer_sync.py — фоновый процесс синхронизации пиров в сети HMP
|
5 |
+
"""
|
6 |
+
|
7 |
+
import socket
|
8 |
+
import threading
|
9 |
+
import time
|
10 |
+
import json
|
11 |
+
from tools.storage import Storage
|
12 |
+
|
13 |
+
storage = Storage()
|
14 |
+
|
15 |
+
# ======================
|
16 |
+
# UDP Discovery
|
17 |
+
# ======================
|
18 |
+
|
19 |
+
def udp_discovery_listener(udp_port: int):
|
20 |
+
"""Слушаем UDP-пакеты"""
|
21 |
+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
22 |
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
23 |
+
sock.bind(("", udp_port))
|
24 |
+
|
25 |
+
while True:
|
26 |
+
data, addr = sock.recvfrom(1024)
|
27 |
+
try:
|
28 |
+
msg = json.loads(data.decode("utf-8"))
|
29 |
+
peer_id = msg.get("id")
|
30 |
+
name = msg.get("name", "unknown")
|
31 |
+
addresses = msg.get("addresses", [f"{addr[0]}:{msg.get('tcp_port', udp_port)}"])
|
32 |
+
storage.add_or_update_peer(peer_id, name, addresses, source="discovery", status="online")
|
33 |
+
except Exception as e:
|
34 |
+
print("[PeerSync] Ошибка при обработке UDP пакета:", e)
|
35 |
+
|
36 |
+
|
37 |
+
def udp_discovery_sender(agent_id: str, agent_name: str, udp_port: int, tcp_port: int):
|
38 |
+
"""Рассылаем UDP multicast/broadcast пакеты"""
|
39 |
+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
40 |
+
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
|
41 |
+
|
42 |
+
msg = {
|
43 |
+
"id": agent_id,
|
44 |
+
"name": agent_name,
|
45 |
+
"tcp_port": tcp_port,
|
46 |
+
"addresses": [f"127.0.0.1:{tcp_port}"]
|
47 |
+
}
|
48 |
+
|
49 |
+
last_broadcast = 0
|
50 |
+
DISCOVERY_INTERVAL = 60
|
51 |
+
BROADCAST_INTERVAL = 600
|
52 |
+
|
53 |
+
while True:
|
54 |
+
now = time.time()
|
55 |
+
# Multicast раз в минуту
|
56 |
+
if int(now) % DISCOVERY_INTERVAL == 0:
|
57 |
+
sock.sendto(json.dumps(msg).encode("utf-8"), ("239.255.0.1", udp_port))
|
58 |
+
# Broadcast раз в 10 минут
|
59 |
+
if now - last_broadcast > BROADCAST_INTERVAL:
|
60 |
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
61 |
+
sock.sendto(json.dumps(msg).encode("utf-8"), ("255.255.255.255", udp_port))
|
62 |
+
last_broadcast = now
|
63 |
+
time.sleep(1)
|
64 |
+
|
65 |
+
|
66 |
+
# ======================
|
67 |
+
# Peer Exchange (TCP)
|
68 |
+
# ======================
|
69 |
+
|
70 |
+
def peer_exchange():
|
71 |
+
"""Периодический обмен списками пиров"""
|
72 |
+
PEER_EXCHANGE_INTERVAL = 120
|
73 |
+
while True:
|
74 |
+
peers = storage.get_online_peers(limit=50)
|
75 |
+
for peer in peers:
|
76 |
+
peer_id, addresses = peer["id"], peer["addresses"]
|
77 |
+
try:
|
78 |
+
addr = json.loads(addresses)[0]
|
79 |
+
host, port = addr.split(":")
|
80 |
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
81 |
+
s.settimeout(2)
|
82 |
+
s.connect((host, int(port)))
|
83 |
+
# пока только "каркас"
|
84 |
+
s.sendall(b"PEER_EXCHANGE_REQUEST")
|
85 |
+
s.close()
|
86 |
+
except Exception as e:
|
87 |
+
print(f"[PeerSync] Не удалось подключиться к {peer_id} ({addresses}): {e}")
|
88 |
+
time.sleep(PEER_EXCHANGE_INTERVAL)
|
89 |
+
|
90 |
+
|
91 |
+
# ======================
|
92 |
+
# Основной запуск
|
93 |
+
# ======================
|
94 |
+
|
95 |
+
def start_sync():
|
96 |
+
print("[PeerSync] Запуск фоновой синхронизации")
|
97 |
+
|
98 |
+
# 1. Конфиг
|
99 |
+
udp_port = int(storage.get_config_value("udp_port", 4000))
|
100 |
+
tcp_port = int(storage.get_config_value("tcp_port", 5000))
|
101 |
+
agent_id = storage.get_config_value("agent_id", "unknown-agent")
|
102 |
+
agent_name = storage.get_config_value("agent_name", "HMP-Agent")
|
103 |
+
|
104 |
+
# 2. Bootstrap загрузка
|
105 |
+
storage.load_bootstrap()
|
106 |
+
|
107 |
+
# 3. UDP discovery
|
108 |
+
threading.Thread(target=udp_discovery_listener, args=(udp_port,), daemon=True).start()
|
109 |
+
threading.Thread(target=udp_discovery_sender, args=(agent_id, agent_name, udp_port, tcp_port), daemon=True).start()
|
110 |
+
|
111 |
+
# 4. Peer exchange (TCP)
|
112 |
+
threading.Thread(target=peer_exchange, daemon=True).start()
|
113 |
+
|
114 |
+
# вечный цикл (чтобы поток не завершался)
|
115 |
+
while True:
|
116 |
+
time.sleep(60)
|
agents/start_repl.py
CHANGED
@@ -16,7 +16,7 @@ storage = Storage()
|
|
16 |
ENABLE_REPL = False # 🧠 repl.py
|
17 |
ENABLE_UI = True # 📓 web_ui.py (FastAPI)
|
18 |
ENABLE_MESH = False # 🌐 agent_mesh_listener.py
|
19 |
-
ENABLE_SYNC =
|
20 |
ENABLE_TRANSPORT = False # 📡 transporter.py
|
21 |
ENABLE_CONTROL = False # 🧭 agent_controller.py
|
22 |
ENABLE_CONTAINER = False # 🧱 container_agent.py
|
|
|
16 |
ENABLE_REPL = False # 🧠 repl.py
|
17 |
ENABLE_UI = True # 📓 web_ui.py (FastAPI)
|
18 |
ENABLE_MESH = False # 🌐 agent_mesh_listener.py
|
19 |
+
ENABLE_SYNC = True # 🔄 peer_sync.py
|
20 |
ENABLE_TRANSPORT = False # 📡 transporter.py
|
21 |
ENABLE_CONTROL = False # 🧭 agent_controller.py
|
22 |
ENABLE_CONTAINER = False # 🧱 container_agent.py
|
agents/tools/storage.py
CHANGED
@@ -870,6 +870,49 @@ class Storage:
|
|
870 |
}
|
871 |
return None
|
872 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
873 |
# Утилиты
|
874 |
|
875 |
def close(self):
|
|
|
870 |
}
|
871 |
return None
|
872 |
|
873 |
+
# Работа с пирам (agent_peers)
|
874 |
+
def add_or_update_peer(self, peer_id, name, addresses, source="discovery", status="unknown"):
|
875 |
+
c = self.conn.cursor()
|
876 |
+
c.execute("""
|
877 |
+
INSERT INTO agent_peers (id, name, addresses, source, status, last_seen)
|
878 |
+
VALUES (?, ?, ?, ?, ?, ?)
|
879 |
+
ON CONFLICT(id) DO UPDATE SET
|
880 |
+
addresses=excluded.addresses,
|
881 |
+
source=excluded.source,
|
882 |
+
status=excluded.status,
|
883 |
+
last_seen=excluded.last_seen
|
884 |
+
""", (
|
885 |
+
peer_id,
|
886 |
+
name,
|
887 |
+
json.dumps(addresses),
|
888 |
+
source,
|
889 |
+
status,
|
890 |
+
datetime.now(UTC).isoformat()
|
891 |
+
))
|
892 |
+
self.conn.commit()
|
893 |
+
|
894 |
+
def get_online_peers(self, limit=50):
|
895 |
+
c = self.conn.cursor()
|
896 |
+
c.execute("SELECT id, addresses FROM agent_peers WHERE status='online' LIMIT ?", (limit,))
|
897 |
+
return c.fetchall()
|
898 |
+
|
899 |
+
def load_bootstrap(self, bootstrap_file="bootstrap.txt"):
|
900 |
+
if not os.path.exists(bootstrap_file):
|
901 |
+
return
|
902 |
+
with open(bootstrap_file, "r", encoding="utf-8") as f:
|
903 |
+
for line in f:
|
904 |
+
line = line.strip()
|
905 |
+
if not line or line.startswith("#"):
|
906 |
+
continue
|
907 |
+
# Пример: http://node1.mesh.local:8000
|
908 |
+
try:
|
909 |
+
peer_url = line
|
910 |
+
peer_id = str(uuid.uuid4()) # временно генерим ID, потом можно подтянуть DID
|
911 |
+
name = peer_url.split("://")[1].split(":")[0]
|
912 |
+
self.add_or_update_peer(peer_id, name, [peer_url], source="bootstrap")
|
913 |
+
except Exception as e:
|
914 |
+
print(f"[Storage] Ошибка парсинга bootstrap: {line} -> {e}")
|
915 |
+
|
916 |
# Утилиты
|
917 |
|
918 |
def close(self):
|