beekkon-bridge 1.0.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.
- beekkon_bridge-1.0.0/LICENSE +21 -0
- beekkon_bridge-1.0.0/PKG-INFO +191 -0
- beekkon_bridge-1.0.0/README.md +163 -0
- beekkon_bridge-1.0.0/beekkon/__init__.py +34 -0
- beekkon_bridge-1.0.0/beekkon/agent.py +247 -0
- beekkon_bridge-1.0.0/beekkon/api.py +52 -0
- beekkon_bridge-1.0.0/beekkon/auth.py +223 -0
- beekkon_bridge-1.0.0/beekkon/crypto.py +103 -0
- beekkon_bridge-1.0.0/beekkon/discovery.py +282 -0
- beekkon_bridge-1.0.0/beekkon/memory.py +323 -0
- beekkon_bridge-1.0.0/beekkon/models.py +109 -0
- beekkon_bridge-1.0.0/beekkon/protocol.py +527 -0
- beekkon_bridge-1.0.0/beekkon/router.py +136 -0
- beekkon_bridge-1.0.0/beekkon_bridge.egg-info/PKG-INFO +191 -0
- beekkon_bridge-1.0.0/beekkon_bridge.egg-info/SOURCES.txt +24 -0
- beekkon_bridge-1.0.0/beekkon_bridge.egg-info/dependency_links.txt +1 -0
- beekkon_bridge-1.0.0/beekkon_bridge.egg-info/requires.txt +2 -0
- beekkon_bridge-1.0.0/beekkon_bridge.egg-info/top_level.txt +1 -0
- beekkon_bridge-1.0.0/pyproject.toml +46 -0
- beekkon_bridge-1.0.0/setup.cfg +4 -0
- beekkon_bridge-1.0.0/tests/test_agent.py +47 -0
- beekkon_bridge-1.0.0/tests/test_auth.py +206 -0
- beekkon_bridge-1.0.0/tests/test_crypto.py +93 -0
- beekkon_bridge-1.0.0/tests/test_discovery.py +268 -0
- beekkon_bridge-1.0.0/tests/test_memory.py +217 -0
- beekkon_bridge-1.0.0/tests/test_protocol.py +34 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BeekKon Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: beekkon-bridge
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Secure communication protocol for AI agents - The TCP/IP for the post-AI era
|
|
5
|
+
Author-email: erabytse <contact@fbfconsulting.org>
|
|
6
|
+
Maintainer-email: erabytse <contact@fbfconsulting.org>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/erabytse/BeekKon-Bridge
|
|
9
|
+
Project-URL: Repository, https://github.com/erabytse/BeekKon-Bridge
|
|
10
|
+
Project-URL: Issues, https://github.com/erabytse/BeekKon-Bridge/issues
|
|
11
|
+
Keywords: ai,agents,protocol,p2p,encryption,zero-knowledge
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: System :: Networking
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: PyNaCl>=1.5.0
|
|
26
|
+
Requires-Dist: msgpack>=1.0.5
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
<div align="center">
|
|
30
|
+
<img src="logo.png" alt="BKB">
|
|
31
|
+
|
|
32
|
+
<strong><p><h3>The Protocol for AI Agents - Secure communication protocol for the
|
|
33
|
+
post-AI era.</h3></p></strong>
|
|
34
|
+
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
## 🎯 What is BeekKon-Bridge?
|
|
38
|
+
|
|
39
|
+
BeekKon Bridge is a peer-to-peer communication protocol designed specifically for AI agents. It provides:
|
|
40
|
+
|
|
41
|
+
- 🔐 **Zero-knowledge authentication** (based on CryptoLogin V2)
|
|
42
|
+
- 🔒 **End-to-end encryption** (AES-256-GCM via Curve25519)
|
|
43
|
+
- ✍️ **Message signatures** (Ed25519)
|
|
44
|
+
- 🔍 **Automatic peer discovery** (UDP broadcast)
|
|
45
|
+
- 🤖 **Simple high-level API** (5 lines of code)
|
|
46
|
+
|
|
47
|
+
## 🚀 Quick Start
|
|
48
|
+
|
|
49
|
+
### Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install beekon-bridge
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Create an Agent
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from beekkon import BeekKonAgent
|
|
59
|
+
|
|
60
|
+
# Create agent
|
|
61
|
+
agent = BeekKonAgent(
|
|
62
|
+
name="my_agent",
|
|
63
|
+
secret="my-super-secret-key-1234567890", # min 32 chars
|
|
64
|
+
capabilities=["parse_data", "generate_report"]
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Register handler
|
|
68
|
+
@agent.handler("process_request")
|
|
69
|
+
async def handle_request(data):
|
|
70
|
+
return {"result": "processed", "input": data}
|
|
71
|
+
|
|
72
|
+
# Start agent
|
|
73
|
+
agent.start()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Request Another Agent
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from beekkon import BeekKonAgent
|
|
80
|
+
|
|
81
|
+
agent = BeekKonAgent(
|
|
82
|
+
name="client_agent",
|
|
83
|
+
secret="client-secret-0987654321",
|
|
84
|
+
capabilities=[]
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
agent.start(blocking=False)
|
|
88
|
+
|
|
89
|
+
# Send request
|
|
90
|
+
response = agent.request(
|
|
91
|
+
target="my_agent",
|
|
92
|
+
task="process_request",
|
|
93
|
+
data={"value": 42}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
print(response) # {'success': True, 'data': {'result': 'processed', ...}}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 🎬 Real-World Example: 3-Agent Workflow
|
|
100
|
+
|
|
101
|
+
See the `examples/` folder for a complete workflow with 3 specialized agents:
|
|
102
|
+
|
|
103
|
+
- **CRM Officer** (`agent_crm.py`): Client relationship management
|
|
104
|
+
- **Legal Officer** (`agent_juridique.py`): Contract validation & compliance
|
|
105
|
+
- **Accounting Clerk** (`agent_comptable.py`): Invoice generation & VAT calculation
|
|
106
|
+
|
|
107
|
+
### Run the demo
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Terminal 1: Start Accounting Clerk
|
|
111
|
+
python examples/agent_comptable.py
|
|
112
|
+
|
|
113
|
+
# Terminal 2: Start Legal Officer
|
|
114
|
+
python examples/agent_juridique.py
|
|
115
|
+
|
|
116
|
+
# Terminal 3: Start CRM Officer
|
|
117
|
+
python examples/agent_crm.py
|
|
118
|
+
|
|
119
|
+
# Terminal 4: Trigger workflow
|
|
120
|
+
python examples/run_workflow.py
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### What happens
|
|
124
|
+
|
|
125
|
+
1. Client requests onboarding via CRM
|
|
126
|
+
2. CRM asks Legal to validate the contract
|
|
127
|
+
3. Legal validates and stores contract in shared memory
|
|
128
|
+
4. CRM asks Accounting to generate invoice
|
|
129
|
+
5. Accounting retrieves contract, calculates VAT, issues invoice
|
|
130
|
+
6. CRM validates payment
|
|
131
|
+
7. Workflow completes ✅
|
|
132
|
+
|
|
133
|
+
## 🔐 Security Model
|
|
134
|
+
|
|
135
|
+
- Zero-knowledge: Server never stores master secrets, only derived user_ids
|
|
136
|
+
- E2E encryption: All messages encrypted with AES-256-GCM
|
|
137
|
+
- Forward secrecy: Session keys derived via Curve25519 Diffie-Hellman
|
|
138
|
+
- Message integrity: Ed25519 signatures on all messages
|
|
139
|
+
- Local-first: No cloud, no central server, 100% P2P
|
|
140
|
+
|
|
141
|
+
## 📊 Architecture
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
┌─────────────────────────────────────────────────────┐
|
|
145
|
+
│ BeekKonAgent (API) │
|
|
146
|
+
│ - agent.start() │
|
|
147
|
+
│ - agent.request(target, task, data) │
|
|
148
|
+
│ - @agent.handler("task") │
|
|
149
|
+
└─────────────────────────────────────────────────────┘
|
|
150
|
+
↓
|
|
151
|
+
┌─────────────────────────────────────────────────────┐
|
|
152
|
+
│ BeekKonDiscovery (UDP) │
|
|
153
|
+
│ - Automatic peer discovery │
|
|
154
|
+
│ - Capability-based filtering │
|
|
155
|
+
└─────────────────────────────────────────────────────┘
|
|
156
|
+
↓
|
|
157
|
+
┌─────────────────────────────────────────────────────┐
|
|
158
|
+
│ BeekKonProtocol (TCP) │
|
|
159
|
+
│ - Handshake (zero-knowledge auth) │
|
|
160
|
+
│ - Encrypted communication (AES-256-GCM) │
|
|
161
|
+
│ - Request/Response pattern │
|
|
162
|
+
└─────────────────────────────────────────────────────┘
|
|
163
|
+
↓
|
|
164
|
+
┌─────────────────────────────────────────────────────┐
|
|
165
|
+
│ BeekKonAuth (Crypto) │
|
|
166
|
+
│ - Ed25519 signatures │
|
|
167
|
+
│ - Curve25519 key exchange │
|
|
168
|
+
│ - PBKDF2-HMAC-SHA512 key derivation │
|
|
169
|
+
└─────────────────────────────────────────────────────┘
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## 🧪 Tests
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
pytest tests/ -v
|
|
176
|
+
# 36 tests passed
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## 📄 License
|
|
180
|
+
|
|
181
|
+
MIT License - See LICENSE file for details.
|
|
182
|
+
|
|
183
|
+
## 🤝 Contributing
|
|
184
|
+
|
|
185
|
+
Contributions welcome! Please read CONTRIBUTING.md for guidelines.
|
|
186
|
+
|
|
187
|
+
## 📧 Contact
|
|
188
|
+
|
|
189
|
+
GitHub: https://github.com/erabytse/BeekKon-Bridge
|
|
190
|
+
|
|
191
|
+
Issues: https://github.com/erabytse/BeekKon-Bridge/issues
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="logo.png" alt="BKB">
|
|
3
|
+
|
|
4
|
+
<strong><p><h3>The Protocol for AI Agents - Secure communication protocol for the
|
|
5
|
+
post-AI era.</h3></p></strong>
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
## 🎯 What is BeekKon-Bridge?
|
|
10
|
+
|
|
11
|
+
BeekKon Bridge is a peer-to-peer communication protocol designed specifically for AI agents. It provides:
|
|
12
|
+
|
|
13
|
+
- 🔐 **Zero-knowledge authentication** (based on CryptoLogin V2)
|
|
14
|
+
- 🔒 **End-to-end encryption** (AES-256-GCM via Curve25519)
|
|
15
|
+
- ✍️ **Message signatures** (Ed25519)
|
|
16
|
+
- 🔍 **Automatic peer discovery** (UDP broadcast)
|
|
17
|
+
- 🤖 **Simple high-level API** (5 lines of code)
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
### Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install beekon-bridge
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Create an Agent
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from beekkon import BeekKonAgent
|
|
31
|
+
|
|
32
|
+
# Create agent
|
|
33
|
+
agent = BeekKonAgent(
|
|
34
|
+
name="my_agent",
|
|
35
|
+
secret="my-super-secret-key-1234567890", # min 32 chars
|
|
36
|
+
capabilities=["parse_data", "generate_report"]
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Register handler
|
|
40
|
+
@agent.handler("process_request")
|
|
41
|
+
async def handle_request(data):
|
|
42
|
+
return {"result": "processed", "input": data}
|
|
43
|
+
|
|
44
|
+
# Start agent
|
|
45
|
+
agent.start()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Request Another Agent
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from beekkon import BeekKonAgent
|
|
52
|
+
|
|
53
|
+
agent = BeekKonAgent(
|
|
54
|
+
name="client_agent",
|
|
55
|
+
secret="client-secret-0987654321",
|
|
56
|
+
capabilities=[]
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
agent.start(blocking=False)
|
|
60
|
+
|
|
61
|
+
# Send request
|
|
62
|
+
response = agent.request(
|
|
63
|
+
target="my_agent",
|
|
64
|
+
task="process_request",
|
|
65
|
+
data={"value": 42}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
print(response) # {'success': True, 'data': {'result': 'processed', ...}}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 🎬 Real-World Example: 3-Agent Workflow
|
|
72
|
+
|
|
73
|
+
See the `examples/` folder for a complete workflow with 3 specialized agents:
|
|
74
|
+
|
|
75
|
+
- **CRM Officer** (`agent_crm.py`): Client relationship management
|
|
76
|
+
- **Legal Officer** (`agent_juridique.py`): Contract validation & compliance
|
|
77
|
+
- **Accounting Clerk** (`agent_comptable.py`): Invoice generation & VAT calculation
|
|
78
|
+
|
|
79
|
+
### Run the demo
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Terminal 1: Start Accounting Clerk
|
|
83
|
+
python examples/agent_comptable.py
|
|
84
|
+
|
|
85
|
+
# Terminal 2: Start Legal Officer
|
|
86
|
+
python examples/agent_juridique.py
|
|
87
|
+
|
|
88
|
+
# Terminal 3: Start CRM Officer
|
|
89
|
+
python examples/agent_crm.py
|
|
90
|
+
|
|
91
|
+
# Terminal 4: Trigger workflow
|
|
92
|
+
python examples/run_workflow.py
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### What happens
|
|
96
|
+
|
|
97
|
+
1. Client requests onboarding via CRM
|
|
98
|
+
2. CRM asks Legal to validate the contract
|
|
99
|
+
3. Legal validates and stores contract in shared memory
|
|
100
|
+
4. CRM asks Accounting to generate invoice
|
|
101
|
+
5. Accounting retrieves contract, calculates VAT, issues invoice
|
|
102
|
+
6. CRM validates payment
|
|
103
|
+
7. Workflow completes ✅
|
|
104
|
+
|
|
105
|
+
## 🔐 Security Model
|
|
106
|
+
|
|
107
|
+
- Zero-knowledge: Server never stores master secrets, only derived user_ids
|
|
108
|
+
- E2E encryption: All messages encrypted with AES-256-GCM
|
|
109
|
+
- Forward secrecy: Session keys derived via Curve25519 Diffie-Hellman
|
|
110
|
+
- Message integrity: Ed25519 signatures on all messages
|
|
111
|
+
- Local-first: No cloud, no central server, 100% P2P
|
|
112
|
+
|
|
113
|
+
## 📊 Architecture
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
┌─────────────────────────────────────────────────────┐
|
|
117
|
+
│ BeekKonAgent (API) │
|
|
118
|
+
│ - agent.start() │
|
|
119
|
+
│ - agent.request(target, task, data) │
|
|
120
|
+
│ - @agent.handler("task") │
|
|
121
|
+
└─────────────────────────────────────────────────────┘
|
|
122
|
+
↓
|
|
123
|
+
┌─────────────────────────────────────────────────────┐
|
|
124
|
+
│ BeekKonDiscovery (UDP) │
|
|
125
|
+
│ - Automatic peer discovery │
|
|
126
|
+
│ - Capability-based filtering │
|
|
127
|
+
└─────────────────────────────────────────────────────┘
|
|
128
|
+
↓
|
|
129
|
+
┌─────────────────────────────────────────────────────┐
|
|
130
|
+
│ BeekKonProtocol (TCP) │
|
|
131
|
+
│ - Handshake (zero-knowledge auth) │
|
|
132
|
+
│ - Encrypted communication (AES-256-GCM) │
|
|
133
|
+
│ - Request/Response pattern │
|
|
134
|
+
└─────────────────────────────────────────────────────┘
|
|
135
|
+
↓
|
|
136
|
+
┌─────────────────────────────────────────────────────┐
|
|
137
|
+
│ BeekKonAuth (Crypto) │
|
|
138
|
+
│ - Ed25519 signatures │
|
|
139
|
+
│ - Curve25519 key exchange │
|
|
140
|
+
│ - PBKDF2-HMAC-SHA512 key derivation │
|
|
141
|
+
└─────────────────────────────────────────────────────┘
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 🧪 Tests
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
pytest tests/ -v
|
|
148
|
+
# 36 tests passed
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 📄 License
|
|
152
|
+
|
|
153
|
+
MIT License - See LICENSE file for details.
|
|
154
|
+
|
|
155
|
+
## 🤝 Contributing
|
|
156
|
+
|
|
157
|
+
Contributions welcome! Please read CONTRIBUTING.md for guidelines.
|
|
158
|
+
|
|
159
|
+
## 📧 Contact
|
|
160
|
+
|
|
161
|
+
GitHub: https://github.com/erabytse/BeekKon-Bridge
|
|
162
|
+
|
|
163
|
+
Issues: https://github.com/erabytse/BeekKon-Bridge/issues
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BeekKon Bridge - Secure communication protocol for AI agents
|
|
3
|
+
The TCP/IP for the post-AI era
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__version__ = "1.0.0"
|
|
7
|
+
__author__ = "BeekKon Team"
|
|
8
|
+
|
|
9
|
+
from .auth import BeekKonAuth
|
|
10
|
+
from .discovery import BeekKonDiscovery, PeerInfo
|
|
11
|
+
from .models import BeekKonMessage, MessageType
|
|
12
|
+
from .protocol import BeekKonProtocol, BeekKonServer
|
|
13
|
+
from .agent import BeekKonAgent
|
|
14
|
+
from .crypto import BeekKonCrypto
|
|
15
|
+
from .memory import BeekKonMemory, MemoryEntry
|
|
16
|
+
from .router import BeekKonRouter, Route
|
|
17
|
+
from .api import BeekKonAPI
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"BeekKonAuth",
|
|
21
|
+
"BeekKonDiscovery",
|
|
22
|
+
"PeerInfo",
|
|
23
|
+
"BeekKonMessage",
|
|
24
|
+
"MessageType",
|
|
25
|
+
"BeekKonProtocol",
|
|
26
|
+
"BeekKonServer",
|
|
27
|
+
"BeekKonAgent",
|
|
28
|
+
"BeekKonCrypto",
|
|
29
|
+
"BeekKonMemory",
|
|
30
|
+
"MemoryEntry",
|
|
31
|
+
"BeekKonRouter",
|
|
32
|
+
"Route",
|
|
33
|
+
"BeekKonAPI"
|
|
34
|
+
]
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""
|
|
2
|
+
BeekKon Bridge - High-Level Agent API
|
|
3
|
+
Simple interface for creating AI agents with automatic discovery, authentication, and communication
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import threading
|
|
8
|
+
import time
|
|
9
|
+
from typing import Dict, List, Callable, Any, Optional
|
|
10
|
+
from .auth import BeekKonAuth
|
|
11
|
+
from .discovery import BeekKonDiscovery, PeerInfo
|
|
12
|
+
from .protocol import BeekKonProtocol, BeekKonServer
|
|
13
|
+
from .models import BeekKonMessage
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BeekKonAgent:
|
|
17
|
+
"""
|
|
18
|
+
High-level API for creating AI agents
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
agent = BeekKonAgent(
|
|
22
|
+
name="agent_comptable",
|
|
23
|
+
secret="my-super-secret-12345678901234567890",
|
|
24
|
+
capabilities=["parse_invoice", "calculate_vat"]
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@agent.handler("validate_contract")
|
|
28
|
+
async def handle_validation(data):
|
|
29
|
+
return {"status": "approved"}
|
|
30
|
+
|
|
31
|
+
agent.start() # Starts discovery, auth, and listening
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
name: str,
|
|
37
|
+
secret: str,
|
|
38
|
+
capabilities: List[str],
|
|
39
|
+
port: int = 8765,
|
|
40
|
+
host: str = "0.0.0.0"
|
|
41
|
+
):
|
|
42
|
+
"""
|
|
43
|
+
Initialize a BeekKon agent
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
name: Agent name (public identifier)
|
|
47
|
+
secret: Master secret (min 32 chars, NEVER share)
|
|
48
|
+
capabilities: List of agent capabilities
|
|
49
|
+
port: Port to listen on
|
|
50
|
+
host: Host to bind to
|
|
51
|
+
"""
|
|
52
|
+
self.name = name
|
|
53
|
+
self.secret = secret
|
|
54
|
+
self.capabilities = capabilities
|
|
55
|
+
self.port = port
|
|
56
|
+
self.host = host
|
|
57
|
+
|
|
58
|
+
# Initialize components
|
|
59
|
+
self.auth = BeekKonAuth(name, secret)
|
|
60
|
+
self.discovery = BeekKonDiscovery(
|
|
61
|
+
agent_id=name,
|
|
62
|
+
capabilities=capabilities,
|
|
63
|
+
port=port,
|
|
64
|
+
public_key_sign=self.auth.verify_key.encode().hex(),
|
|
65
|
+
public_key_exchange=self.auth.public_key.encode().hex()
|
|
66
|
+
)
|
|
67
|
+
self.server = BeekKonServer(self.auth, host=host, port=port)
|
|
68
|
+
|
|
69
|
+
# State
|
|
70
|
+
self.handlers: Dict[str, Callable] = {}
|
|
71
|
+
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
|
72
|
+
self._thread: Optional[threading.Thread] = None
|
|
73
|
+
self._running = False
|
|
74
|
+
self.connections: Dict[str, BeekKonProtocol] = {}
|
|
75
|
+
|
|
76
|
+
def authorize_agent(self, agent_name: str, agent_secret: str) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Authorize a remote agent (server-side only)
|
|
79
|
+
Call this before start() for each agent you want to accept
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
agent_name: Remote agent's name
|
|
83
|
+
agent_secret: Remote agent's master secret (used to derive user_id)
|
|
84
|
+
"""
|
|
85
|
+
temp_auth = BeekKonAuth(agent_name, agent_secret)
|
|
86
|
+
self.auth.add_authorized_agent(agent_name, temp_auth.user_id)
|
|
87
|
+
|
|
88
|
+
def handler(self, task_name: str):
|
|
89
|
+
"""
|
|
90
|
+
Decorator to register a handler for a task
|
|
91
|
+
|
|
92
|
+
Example:
|
|
93
|
+
@agent.handler("parse_invoice")
|
|
94
|
+
async def handle_parse(data):
|
|
95
|
+
return {"result": "parsed"}
|
|
96
|
+
"""
|
|
97
|
+
def decorator(func: Callable):
|
|
98
|
+
self.handlers[task_name] = func
|
|
99
|
+
return func
|
|
100
|
+
return decorator
|
|
101
|
+
|
|
102
|
+
async def _handle_connection(self, protocol: BeekKonProtocol):
|
|
103
|
+
"""Handle a new incoming connection"""
|
|
104
|
+
peer_id = protocol.peer_agent_id
|
|
105
|
+
self.connections[peer_id] = protocol
|
|
106
|
+
|
|
107
|
+
# Register request handler
|
|
108
|
+
async def handle_request(msg):
|
|
109
|
+
task = msg.payload.get("task")
|
|
110
|
+
data = msg.payload.get("data", {})
|
|
111
|
+
|
|
112
|
+
handler = self.handlers.get(task)
|
|
113
|
+
if handler:
|
|
114
|
+
try:
|
|
115
|
+
result = await handler(data) if asyncio.iscoroutinefunction(handler) else handler(data)
|
|
116
|
+
await protocol.send_response(
|
|
117
|
+
request_id=msg.id,
|
|
118
|
+
success=True,
|
|
119
|
+
data=result if isinstance(result, dict) else {"result": result}
|
|
120
|
+
)
|
|
121
|
+
except Exception as e:
|
|
122
|
+
await protocol.send_response(
|
|
123
|
+
request_id=msg.id,
|
|
124
|
+
success=False,
|
|
125
|
+
error=str(e)
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
await protocol.send_response(
|
|
129
|
+
request_id=msg.id,
|
|
130
|
+
success=False,
|
|
131
|
+
error=f"Unknown task: {task}"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
protocol.register_handler("request", handle_request)
|
|
135
|
+
|
|
136
|
+
# Start listening
|
|
137
|
+
await protocol.listen()
|
|
138
|
+
|
|
139
|
+
async def _run_async(self):
|
|
140
|
+
"""Async main loop"""
|
|
141
|
+
self._loop = asyncio.get_running_loop()
|
|
142
|
+
|
|
143
|
+
# Register connection handler
|
|
144
|
+
self.server.on_connection(self._handle_connection)
|
|
145
|
+
|
|
146
|
+
# Start server
|
|
147
|
+
await self.server.start()
|
|
148
|
+
|
|
149
|
+
# Start discovery
|
|
150
|
+
self.discovery.start()
|
|
151
|
+
|
|
152
|
+
print(f"🤖 Agent '{self.name}' started")
|
|
153
|
+
print(f" Capabilities: {self.capabilities}")
|
|
154
|
+
print(f" Port: {self.port}")
|
|
155
|
+
|
|
156
|
+
# Keep running
|
|
157
|
+
while self._running:
|
|
158
|
+
await asyncio.sleep(0.1)
|
|
159
|
+
|
|
160
|
+
# Cleanup
|
|
161
|
+
self.discovery.stop()
|
|
162
|
+
await self.server.stop()
|
|
163
|
+
|
|
164
|
+
def start(self, blocking: bool = True):
|
|
165
|
+
"""
|
|
166
|
+
Start the agent
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
blocking: If True, blocks the main thread. If False, runs in background thread.
|
|
170
|
+
"""
|
|
171
|
+
self._running = True
|
|
172
|
+
|
|
173
|
+
if blocking:
|
|
174
|
+
asyncio.run(self._run_async())
|
|
175
|
+
else:
|
|
176
|
+
self._thread = threading.Thread(target=self._run_in_thread, daemon=True)
|
|
177
|
+
self._thread.start()
|
|
178
|
+
time.sleep(0.5) # Wait for startup
|
|
179
|
+
|
|
180
|
+
def _run_in_thread(self):
|
|
181
|
+
"""Run async loop in background thread"""
|
|
182
|
+
asyncio.run(self._run_async())
|
|
183
|
+
|
|
184
|
+
def stop(self):
|
|
185
|
+
"""Stop the agent"""
|
|
186
|
+
self._running = False
|
|
187
|
+
if self._thread:
|
|
188
|
+
self._thread.join(timeout=2.0)
|
|
189
|
+
|
|
190
|
+
def get_peers(self, capability: Optional[str] = None) -> List[PeerInfo]:
|
|
191
|
+
"""Get discovered peers"""
|
|
192
|
+
return self.discovery.get_peers(capability=capability)
|
|
193
|
+
|
|
194
|
+
async def _request_async(self, target: str, task: str, data: Dict[str, Any], timeout: float = 30.0) -> Dict[str, Any]:
|
|
195
|
+
"""Async request to another agent"""
|
|
196
|
+
peer = self.discovery.get_peer(target)
|
|
197
|
+
if not peer:
|
|
198
|
+
raise ValueError(f"Peer '{target}' not found")
|
|
199
|
+
|
|
200
|
+
protocol = BeekKonProtocol(self.auth)
|
|
201
|
+
listen_task = None
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
# Connect to peer
|
|
205
|
+
success = await protocol.connect(peer.ip, peer.port)
|
|
206
|
+
if not success:
|
|
207
|
+
raise ConnectionError(f"Failed to connect to {target}")
|
|
208
|
+
|
|
209
|
+
# CRITICAL: Start listening in background to receive the response
|
|
210
|
+
listen_task = asyncio.create_task(protocol.listen())
|
|
211
|
+
await asyncio.sleep(0.1) # Let listen() start
|
|
212
|
+
|
|
213
|
+
# Send request and wait for response
|
|
214
|
+
response = await protocol.send_request(target, task, data, timeout)
|
|
215
|
+
return response.payload
|
|
216
|
+
|
|
217
|
+
finally:
|
|
218
|
+
# Cleanup
|
|
219
|
+
if listen_task:
|
|
220
|
+
listen_task.cancel()
|
|
221
|
+
try:
|
|
222
|
+
await listen_task
|
|
223
|
+
except asyncio.CancelledError:
|
|
224
|
+
pass
|
|
225
|
+
await protocol.close()
|
|
226
|
+
|
|
227
|
+
def request(self, target: str, task: str, data: Dict[str, Any], timeout: float = 30.0) -> Dict[str, Any]:
|
|
228
|
+
"""
|
|
229
|
+
Send a request to another agent (synchronous)
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
target: Target agent name
|
|
233
|
+
task: Task name
|
|
234
|
+
data: Task data
|
|
235
|
+
timeout: Response timeout
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Response data
|
|
239
|
+
"""
|
|
240
|
+
if not self._loop:
|
|
241
|
+
raise RuntimeError("Agent not started")
|
|
242
|
+
|
|
243
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
244
|
+
self._request_async(target, task, data, timeout),
|
|
245
|
+
self._loop
|
|
246
|
+
)
|
|
247
|
+
return future.result(timeout=timeout + 1)
|