commb-agent 0.3.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.
- commb_agent-0.3.0/.gitignore +10 -0
- commb_agent-0.3.0/PKG-INFO +238 -0
- commb_agent-0.3.0/README.md +220 -0
- commb_agent-0.3.0/commb_agent/__init__.py +23 -0
- commb_agent-0.3.0/commb_agent/client.py +677 -0
- commb_agent-0.3.0/commb_agent/py.typed +1 -0
- commb_agent-0.3.0/pyproject.toml +35 -0
- commb_agent-0.3.0/tests/__init__.py +1 -0
- commb_agent-0.3.0/tests/test_client.py +454 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: commb-agent
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Official Python telemetry & remote-config client for CommB (Commercial Bots)
|
|
5
|
+
Project-URL: Homepage, https://commb.app
|
|
6
|
+
Project-URL: Repository, https://github.com/sannex-01/commb-agent
|
|
7
|
+
Project-URL: Issues, https://github.com/sannex-01/commb-agent/issues
|
|
8
|
+
Author-email: Sannex Tech LTD <info@sannex.ng>
|
|
9
|
+
License: MIT
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Requires-Dist: httpx>=0.24.0
|
|
12
|
+
Requires-Dist: pydantic>=2.0
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest-mock>=3.0; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# commb-agent
|
|
20
|
+
|
|
21
|
+
Official Python SDK for the **CommB platform** — connects standalone CommB bot engines to the CommB collector dashboard via telemetry tracking and remote config sync.
|
|
22
|
+
|
|
23
|
+
[](https://pypi.org/project/commb-agent)
|
|
24
|
+
[](LICENSE)
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install commb-agent
|
|
30
|
+
# or
|
|
31
|
+
uv add commb-agent
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## How it works
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
CommB collector Dashboard (Supabase)
|
|
38
|
+
▲▼ commb-agent SDK
|
|
39
|
+
CommB Engine (standalone FastAPI bot)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- **CommB** calls `get_config()` to pull system prompt, knowledge docs, and catalog from CommB collector.
|
|
43
|
+
- **CommB** calls `track()` after every message/order to push telemetry back.
|
|
44
|
+
- **CommB** calls `sync_conversation()` to log 48h active session chat history to CommB collector CRM.
|
|
45
|
+
- FastAPI streaming endpoints use `stream_chat()` for SSE responses to the Telegram Mini App.
|
|
46
|
+
|
|
47
|
+
## Quick Start (Sync — for scripts & workers)
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from commb_agent import CommBClient
|
|
51
|
+
|
|
52
|
+
client = CommBClient(
|
|
53
|
+
api_key="snx_bot_xxxx",
|
|
54
|
+
host="https://commb.app",
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Quick Start (Async — for FastAPI)
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from commb_agent import AsyncCommBClient
|
|
62
|
+
|
|
63
|
+
client = AsyncCommBClient(
|
|
64
|
+
api_key="snx_bot_xxxx",
|
|
65
|
+
host="https://commb.app",
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## API Reference
|
|
70
|
+
|
|
71
|
+
### `get_config()` / `await client.get_config()` — Pull config from CommB collector
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
# Sync
|
|
75
|
+
config_resp = client.get_config()
|
|
76
|
+
|
|
77
|
+
# Async
|
|
78
|
+
config_resp = await client.get_config()
|
|
79
|
+
|
|
80
|
+
print(config_resp.config.system_prompt)
|
|
81
|
+
print(config_resp.config.model_name) # "gemini-2.5-flash"
|
|
82
|
+
print(len(config_resp.knowledge_docs)) # RAG docs
|
|
83
|
+
print(len(config_resp.catalog_items)) # Product catalog
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `track()` / `await client.track()` — Push telemetry
|
|
87
|
+
|
|
88
|
+
Non-blocking. Batches and flushes in the background. Never raises.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# Sync (thread-safe, fire-and-forget)
|
|
92
|
+
client.track(
|
|
93
|
+
channel="telegram",
|
|
94
|
+
customer_id="tg_123456",
|
|
95
|
+
event="order_created",
|
|
96
|
+
amount=45000.0,
|
|
97
|
+
metadata={"order_id": "ORD-001"},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Async
|
|
101
|
+
await client.track(
|
|
102
|
+
channel="whatsapp",
|
|
103
|
+
customer_id="+2348012345678",
|
|
104
|
+
event="message_received",
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `sync_conversation()` / `await client.sync_conversation()` — 48h Chat Transcript Sync
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
# Sync
|
|
112
|
+
client.sync_conversation(
|
|
113
|
+
channel="whatsapp",
|
|
114
|
+
customer_id="+2348012345678",
|
|
115
|
+
messages=[
|
|
116
|
+
{"role": "user", "content": "How much is the blue dress?"},
|
|
117
|
+
{"role": "assistant", "content": "The blue dress is ₦15,000."}
|
|
118
|
+
]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Async
|
|
122
|
+
await client.sync_conversation(
|
|
123
|
+
channel="telegram",
|
|
124
|
+
customer_id="tg_123456",
|
|
125
|
+
messages=[
|
|
126
|
+
{"role": "user", "content": "Is shipping free?"},
|
|
127
|
+
{"role": "assistant", "content": "Yes, on orders above ₦50,000."}
|
|
128
|
+
]
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
### `stream_chat()` — Stream AI responses (SSE)
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# Sync
|
|
137
|
+
for chunk in client.stream_chat("What dresses do you have?", user_id="user_123"):
|
|
138
|
+
print(chunk, end="", flush=True)
|
|
139
|
+
|
|
140
|
+
# Async (FastAPI SSE endpoint)
|
|
141
|
+
async for chunk in client.stream_chat("What dresses do you have?", user_id="user_123"):
|
|
142
|
+
yield f"data: {chunk}\n\n"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `ping()` / `await client.ping()` — Health check
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
is_up = client.ping() # sync
|
|
149
|
+
is_up = await client.ping() # async
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### `get_bot()` / `await client.get_bot()` — Bot identity
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
bot = client.get_bot()
|
|
156
|
+
print(bot.name) # "Elena Luxe Bot"
|
|
157
|
+
print(bot.reseller) # "Sannex Digital Agency"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## FastAPI CommB Engine Integration
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# commb_engine/main.py
|
|
164
|
+
import os
|
|
165
|
+
from contextlib import asynccontextmanager
|
|
166
|
+
from fastapi import FastAPI
|
|
167
|
+
from fastapi.responses import StreamingResponse
|
|
168
|
+
from commb_agent import AsyncCommBClient, ChatMessage
|
|
169
|
+
|
|
170
|
+
commb = AsyncCommBClient(
|
|
171
|
+
api_key=os.environ["BOT_API_KEY"],
|
|
172
|
+
host=os.environ.get("COMMB_COLLECTOR_URL", "https://commb.app"),
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
@asynccontextmanager
|
|
176
|
+
async def lifespan(app: FastAPI):
|
|
177
|
+
# Pull config from CommB collector on startup
|
|
178
|
+
config = await commb.get_config()
|
|
179
|
+
app.state.system_prompt = config.config.system_prompt
|
|
180
|
+
app.state.knowledge_docs = config.knowledge_docs
|
|
181
|
+
app.state.catalog_items = config.catalog_items
|
|
182
|
+
yield
|
|
183
|
+
await commb.close()
|
|
184
|
+
|
|
185
|
+
app = FastAPI(lifespan=lifespan)
|
|
186
|
+
|
|
187
|
+
@app.post("/v1/chat")
|
|
188
|
+
async def chat(message: str, user_id: str):
|
|
189
|
+
async def event_stream():
|
|
190
|
+
async for chunk in commb.stream_chat(message, user_id):
|
|
191
|
+
yield f"data: {chunk}\n\n"
|
|
192
|
+
yield "data: [DONE]\n\n"
|
|
193
|
+
|
|
194
|
+
# Track the conversation event
|
|
195
|
+
await commb.track(
|
|
196
|
+
channel="telegram",
|
|
197
|
+
customer_id=user_id,
|
|
198
|
+
event="message_received",
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
return StreamingResponse(event_stream(), media_type="text/event-stream")
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Context Manager (Sync)
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
with CommBClient(api_key="snx_bot_xxxx") as client:
|
|
208
|
+
config = client.get_config()
|
|
209
|
+
# ... use client
|
|
210
|
+
# auto-flushes and closes on exit
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Context Manager (Async)
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
async with AsyncCommBClient(api_key="snx_bot_xxxx") as client:
|
|
217
|
+
config = await client.get_config()
|
|
218
|
+
# ... use client
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Environment Variables
|
|
222
|
+
|
|
223
|
+
```env
|
|
224
|
+
BOT_API_KEY=snx_bot_xxxx # From CommB collector Bot Settings
|
|
225
|
+
COMMB_COLLECTOR_URL=https://commb.app # CommB collector host
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Response Models (Pydantic v2)
|
|
229
|
+
|
|
230
|
+
All responses are typed Pydantic models:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
from commb_agent import CommBConfigResponse, BotConfig, KnowledgeDoc, CatalogItem, BotInfo
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
MIT — Sannex Tech LTD
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# commb-agent
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the **CommB platform** — connects standalone CommB bot engines to the CommB collector dashboard via telemetry tracking and remote config sync.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/commb-agent)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install commb-agent
|
|
12
|
+
# or
|
|
13
|
+
uv add commb-agent
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## How it works
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
CommB collector Dashboard (Supabase)
|
|
20
|
+
▲▼ commb-agent SDK
|
|
21
|
+
CommB Engine (standalone FastAPI bot)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- **CommB** calls `get_config()` to pull system prompt, knowledge docs, and catalog from CommB collector.
|
|
25
|
+
- **CommB** calls `track()` after every message/order to push telemetry back.
|
|
26
|
+
- **CommB** calls `sync_conversation()` to log 48h active session chat history to CommB collector CRM.
|
|
27
|
+
- FastAPI streaming endpoints use `stream_chat()` for SSE responses to the Telegram Mini App.
|
|
28
|
+
|
|
29
|
+
## Quick Start (Sync — for scripts & workers)
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from commb_agent import CommBClient
|
|
33
|
+
|
|
34
|
+
client = CommBClient(
|
|
35
|
+
api_key="snx_bot_xxxx",
|
|
36
|
+
host="https://commb.app",
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start (Async — for FastAPI)
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from commb_agent import AsyncCommBClient
|
|
44
|
+
|
|
45
|
+
client = AsyncCommBClient(
|
|
46
|
+
api_key="snx_bot_xxxx",
|
|
47
|
+
host="https://commb.app",
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## API Reference
|
|
52
|
+
|
|
53
|
+
### `get_config()` / `await client.get_config()` — Pull config from CommB collector
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
# Sync
|
|
57
|
+
config_resp = client.get_config()
|
|
58
|
+
|
|
59
|
+
# Async
|
|
60
|
+
config_resp = await client.get_config()
|
|
61
|
+
|
|
62
|
+
print(config_resp.config.system_prompt)
|
|
63
|
+
print(config_resp.config.model_name) # "gemini-2.5-flash"
|
|
64
|
+
print(len(config_resp.knowledge_docs)) # RAG docs
|
|
65
|
+
print(len(config_resp.catalog_items)) # Product catalog
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `track()` / `await client.track()` — Push telemetry
|
|
69
|
+
|
|
70
|
+
Non-blocking. Batches and flushes in the background. Never raises.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
# Sync (thread-safe, fire-and-forget)
|
|
74
|
+
client.track(
|
|
75
|
+
channel="telegram",
|
|
76
|
+
customer_id="tg_123456",
|
|
77
|
+
event="order_created",
|
|
78
|
+
amount=45000.0,
|
|
79
|
+
metadata={"order_id": "ORD-001"},
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Async
|
|
83
|
+
await client.track(
|
|
84
|
+
channel="whatsapp",
|
|
85
|
+
customer_id="+2348012345678",
|
|
86
|
+
event="message_received",
|
|
87
|
+
)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `sync_conversation()` / `await client.sync_conversation()` — 48h Chat Transcript Sync
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
# Sync
|
|
94
|
+
client.sync_conversation(
|
|
95
|
+
channel="whatsapp",
|
|
96
|
+
customer_id="+2348012345678",
|
|
97
|
+
messages=[
|
|
98
|
+
{"role": "user", "content": "How much is the blue dress?"},
|
|
99
|
+
{"role": "assistant", "content": "The blue dress is ₦15,000."}
|
|
100
|
+
]
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Async
|
|
104
|
+
await client.sync_conversation(
|
|
105
|
+
channel="telegram",
|
|
106
|
+
customer_id="tg_123456",
|
|
107
|
+
messages=[
|
|
108
|
+
{"role": "user", "content": "Is shipping free?"},
|
|
109
|
+
{"role": "assistant", "content": "Yes, on orders above ₦50,000."}
|
|
110
|
+
]
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
### `stream_chat()` — Stream AI responses (SSE)
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
# Sync
|
|
119
|
+
for chunk in client.stream_chat("What dresses do you have?", user_id="user_123"):
|
|
120
|
+
print(chunk, end="", flush=True)
|
|
121
|
+
|
|
122
|
+
# Async (FastAPI SSE endpoint)
|
|
123
|
+
async for chunk in client.stream_chat("What dresses do you have?", user_id="user_123"):
|
|
124
|
+
yield f"data: {chunk}\n\n"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `ping()` / `await client.ping()` — Health check
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
is_up = client.ping() # sync
|
|
131
|
+
is_up = await client.ping() # async
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### `get_bot()` / `await client.get_bot()` — Bot identity
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
bot = client.get_bot()
|
|
138
|
+
print(bot.name) # "Elena Luxe Bot"
|
|
139
|
+
print(bot.reseller) # "Sannex Digital Agency"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## FastAPI CommB Engine Integration
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
# commb_engine/main.py
|
|
146
|
+
import os
|
|
147
|
+
from contextlib import asynccontextmanager
|
|
148
|
+
from fastapi import FastAPI
|
|
149
|
+
from fastapi.responses import StreamingResponse
|
|
150
|
+
from commb_agent import AsyncCommBClient, ChatMessage
|
|
151
|
+
|
|
152
|
+
commb = AsyncCommBClient(
|
|
153
|
+
api_key=os.environ["BOT_API_KEY"],
|
|
154
|
+
host=os.environ.get("COMMB_COLLECTOR_URL", "https://commb.app"),
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
@asynccontextmanager
|
|
158
|
+
async def lifespan(app: FastAPI):
|
|
159
|
+
# Pull config from CommB collector on startup
|
|
160
|
+
config = await commb.get_config()
|
|
161
|
+
app.state.system_prompt = config.config.system_prompt
|
|
162
|
+
app.state.knowledge_docs = config.knowledge_docs
|
|
163
|
+
app.state.catalog_items = config.catalog_items
|
|
164
|
+
yield
|
|
165
|
+
await commb.close()
|
|
166
|
+
|
|
167
|
+
app = FastAPI(lifespan=lifespan)
|
|
168
|
+
|
|
169
|
+
@app.post("/v1/chat")
|
|
170
|
+
async def chat(message: str, user_id: str):
|
|
171
|
+
async def event_stream():
|
|
172
|
+
async for chunk in commb.stream_chat(message, user_id):
|
|
173
|
+
yield f"data: {chunk}\n\n"
|
|
174
|
+
yield "data: [DONE]\n\n"
|
|
175
|
+
|
|
176
|
+
# Track the conversation event
|
|
177
|
+
await commb.track(
|
|
178
|
+
channel="telegram",
|
|
179
|
+
customer_id=user_id,
|
|
180
|
+
event="message_received",
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return StreamingResponse(event_stream(), media_type="text/event-stream")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Context Manager (Sync)
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
with CommBClient(api_key="snx_bot_xxxx") as client:
|
|
190
|
+
config = client.get_config()
|
|
191
|
+
# ... use client
|
|
192
|
+
# auto-flushes and closes on exit
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Context Manager (Async)
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
async with AsyncCommBClient(api_key="snx_bot_xxxx") as client:
|
|
199
|
+
config = await client.get_config()
|
|
200
|
+
# ... use client
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Environment Variables
|
|
204
|
+
|
|
205
|
+
```env
|
|
206
|
+
BOT_API_KEY=snx_bot_xxxx # From CommB collector Bot Settings
|
|
207
|
+
COMMB_COLLECTOR_URL=https://commb.app # CommB collector host
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Response Models (Pydantic v2)
|
|
211
|
+
|
|
212
|
+
All responses are typed Pydantic models:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from commb_agent import CommBConfigResponse, BotConfig, KnowledgeDoc, CatalogItem, BotInfo
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
MIT — Sannex Tech LTD
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from .client import (
|
|
2
|
+
CommBClient,
|
|
3
|
+
AsyncCommBClient,
|
|
4
|
+
CommBConfigResponse,
|
|
5
|
+
BotConfig,
|
|
6
|
+
BotInfo,
|
|
7
|
+
KnowledgeDoc,
|
|
8
|
+
CatalogItem,
|
|
9
|
+
ChatMessage,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__version__ = "0.3.0"
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"CommBClient",
|
|
16
|
+
"AsyncCommBClient",
|
|
17
|
+
"CommBConfigResponse",
|
|
18
|
+
"BotConfig",
|
|
19
|
+
"BotInfo",
|
|
20
|
+
"KnowledgeDoc",
|
|
21
|
+
"CatalogItem",
|
|
22
|
+
"ChatMessage",
|
|
23
|
+
]
|