olbrain-python-sdk 0.3.2__tar.gz → 0.5.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.
- {olbrain_python_sdk-0.3.2/olbrain_python_sdk.egg-info → olbrain_python_sdk-0.5.0}/PKG-INFO +35 -29
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/README.md +34 -28
- olbrain_python_sdk-0.5.0/olbrain/AGENTS.md +264 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain/__init__.py +12 -4
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain/client.py +42 -200
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain/exceptions.py +22 -0
- olbrain_python_sdk-0.5.0/olbrain/olbrain.py +241 -0
- olbrain_python_sdk-0.5.0/olbrain/research.py +200 -0
- olbrain_python_sdk-0.5.0/olbrain/streaming.py +95 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0/olbrain_python_sdk.egg-info}/PKG-INFO +35 -29
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain_python_sdk.egg-info/SOURCES.txt +3 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/setup.py +1 -1
- olbrain_python_sdk-0.5.0/tests/test_client.py +98 -0
- olbrain_python_sdk-0.5.0/tests/test_olbrain.py +215 -0
- olbrain_python_sdk-0.3.2/olbrain/AGENTS.md +0 -167
- olbrain_python_sdk-0.3.2/olbrain/streaming.py +0 -143
- olbrain_python_sdk-0.3.2/tests/test_client.py +0 -131
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/.gitignore +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/LICENSE +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/MANIFEST.in +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/examples/advanced_features.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/examples/basic_usage.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/examples/error_handling.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/examples/session_management.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/examples/streaming_responses.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain/session.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain/utils.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain_python_sdk.egg-info/dependency_links.txt +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain_python_sdk.egg-info/not-zip-safe +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain_python_sdk.egg-info/requires.txt +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/olbrain_python_sdk.egg-info/top_level.txt +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/pyproject.toml +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/requirements.txt +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/setup.cfg +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/tests/__init__.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/tests/test_exceptions.py +0 -0
- {olbrain_python_sdk-0.3.2 → olbrain_python_sdk-0.5.0}/tests/test_session.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: olbrain-python-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Official Python SDK for Olbrain AI agents
|
|
5
5
|
Home-page: https://github.com/Olbrain/olbrain-sdk
|
|
6
6
|
Author: Olbrain Team
|
|
@@ -86,7 +86,7 @@ pytest tests/
|
|
|
86
86
|
|
|
87
87
|
Get your credentials from the Olbrain dashboard:
|
|
88
88
|
- **Agent ID**: Your unique agent identifier
|
|
89
|
-
- **API Key**:
|
|
89
|
+
- **API Key**: an access key (`ak_…`) from Noesis → Settings → Organization → Access keys, or from the finish page Alchemist links to when it hands an agent over (that key works only for that agent)
|
|
90
90
|
|
|
91
91
|
### Basic Example
|
|
92
92
|
|
|
@@ -96,7 +96,7 @@ from olbrain import AgentClient
|
|
|
96
96
|
# Initialize client
|
|
97
97
|
client = AgentClient(
|
|
98
98
|
agent_id="your-agent-id",
|
|
99
|
-
api_key="
|
|
99
|
+
api_key="ak_your_api_key"
|
|
100
100
|
)
|
|
101
101
|
|
|
102
102
|
# Create a session and send a message
|
|
@@ -115,7 +115,7 @@ client.close()
|
|
|
115
115
|
from olbrain import AgentClient
|
|
116
116
|
|
|
117
117
|
# Automatically closes client when done
|
|
118
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
118
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
119
119
|
session_id = client.create_session(title="My Chat")
|
|
120
120
|
response = client.send_and_wait(session_id, "What is machine learning?")
|
|
121
121
|
print(response.text)
|
|
@@ -129,6 +129,21 @@ with AgentClient(agent_id="your-agent-id", api_key="sk_live_your_key") as client
|
|
|
129
129
|
- **Token Tracking** - Monitor usage and costs per request
|
|
130
130
|
- **Model Override** - Switch models per-message
|
|
131
131
|
- **Error Handling** - Comprehensive exception hierarchy
|
|
132
|
+
- **Workflow Agents** - Run workflow agents, read and control their runs, resolve approvals (`Olbrain`)
|
|
133
|
+
- **Research Agents** - Sessions, streamed turns, plans, reports and review (`Olbrain.research`, sign-ins only)
|
|
134
|
+
|
|
135
|
+
### Workflow agents
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
import os
|
|
139
|
+
from olbrain import Olbrain
|
|
140
|
+
|
|
141
|
+
olbrain = Olbrain(api_key=os.environ["OLBRAIN_API_KEY"]) # keep the key on your server
|
|
142
|
+
run = olbrain.workflows.run("your-agent-id", payload={"url": "https://example.com"})
|
|
143
|
+
print(olbrain.runs.get("your-agent-id", run["run_id"]))
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
See [`olbrain/AGENTS.md`](olbrain/AGENTS.md) for runs, approvals and research agents.
|
|
132
147
|
|
|
133
148
|
## Usage
|
|
134
149
|
|
|
@@ -139,7 +154,7 @@ Send a message and wait for the complete response:
|
|
|
139
154
|
```python
|
|
140
155
|
from olbrain import AgentClient
|
|
141
156
|
|
|
142
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
157
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
143
158
|
# Create a new chat session
|
|
144
159
|
session_id = client.create_session(title="My Chat")
|
|
145
160
|
|
|
@@ -154,12 +169,12 @@ with AgentClient(agent_id="your-agent-id", api_key="sk_live_your_key") as client
|
|
|
154
169
|
|
|
155
170
|
### 2. Real-Time Streaming (Callback Pattern)
|
|
156
171
|
|
|
157
|
-
Receive messages
|
|
172
|
+
Receive new messages as they arrive (the client polls the session every 2 seconds):
|
|
158
173
|
|
|
159
174
|
```python
|
|
160
175
|
from olbrain import AgentClient
|
|
161
176
|
|
|
162
|
-
client = AgentClient(agent_id="your-agent-id", api_key="
|
|
177
|
+
client = AgentClient(agent_id="your-agent-id", api_key="ak_your_key")
|
|
163
178
|
|
|
164
179
|
# Define message handler
|
|
165
180
|
def on_message(msg):
|
|
@@ -191,7 +206,7 @@ Create, retrieve, and manage chat sessions:
|
|
|
191
206
|
```python
|
|
192
207
|
from olbrain import AgentClient
|
|
193
208
|
|
|
194
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
209
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
195
210
|
# Create session with metadata
|
|
196
211
|
session = client.create_session(
|
|
197
212
|
title="Support Chat",
|
|
@@ -210,15 +225,9 @@ with AgentClient(agent_id="your-agent-id", api_key="sk_live_your_key") as client
|
|
|
210
225
|
for msg in messages.get('messages', []):
|
|
211
226
|
print(f"{msg['role']}: {msg['content']}")
|
|
212
227
|
|
|
213
|
-
# Update session
|
|
214
|
-
updated = client.update_session(session, title="Updated Chat Title")
|
|
215
|
-
|
|
216
228
|
# Get session statistics
|
|
217
229
|
stats = client.get_session_stats(session)
|
|
218
230
|
print(f"Stats: {stats}")
|
|
219
|
-
|
|
220
|
-
# Archive/delete session
|
|
221
|
-
client.delete_session(session)
|
|
222
231
|
```
|
|
223
232
|
|
|
224
233
|
### 4. Model Override
|
|
@@ -228,7 +237,7 @@ Send messages using a specific model:
|
|
|
228
237
|
```python
|
|
229
238
|
from olbrain import AgentClient
|
|
230
239
|
|
|
231
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
240
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
232
241
|
session_id = client.create_session()
|
|
233
242
|
|
|
234
243
|
# Use specific model for this request
|
|
@@ -248,7 +257,7 @@ Maintain conversation context:
|
|
|
248
257
|
```python
|
|
249
258
|
from olbrain import AgentClient
|
|
250
259
|
|
|
251
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
260
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
252
261
|
session_id = client.create_session(title="Q&A Session")
|
|
253
262
|
|
|
254
263
|
# First message
|
|
@@ -279,7 +288,7 @@ from olbrain.exceptions import (
|
|
|
279
288
|
)
|
|
280
289
|
|
|
281
290
|
try:
|
|
282
|
-
client = AgentClient(agent_id="your-agent-id", api_key="
|
|
291
|
+
client = AgentClient(agent_id="your-agent-id", api_key="ak_your_key")
|
|
283
292
|
session_id = client.create_session()
|
|
284
293
|
response = client.send_and_wait(session_id, "Hello")
|
|
285
294
|
|
|
@@ -307,24 +316,21 @@ finally:
|
|
|
307
316
|
|
|
308
317
|
### API Key
|
|
309
318
|
|
|
310
|
-
The SDK validates API keys.
|
|
311
|
-
|
|
312
|
-
- `org_live_` - Organization keys
|
|
313
|
-
- `sk_` - Test keys
|
|
314
|
-
- `org_` - Test organization keys
|
|
319
|
+
The SDK validates API keys. Access keys (`ak_`) are the only kind issued today; the older
|
|
320
|
+
`sk_live_`, `org_live_`, `sk_` and `org_` prefixes still pass validation.
|
|
315
321
|
|
|
316
322
|
```python
|
|
317
323
|
# Valid API key
|
|
318
324
|
client = AgentClient(
|
|
319
325
|
agent_id="your-agent-id",
|
|
320
|
-
api_key="
|
|
326
|
+
api_key="ak_your_api_key_here"
|
|
321
327
|
)
|
|
322
328
|
```
|
|
323
329
|
|
|
324
330
|
### Environment Variables
|
|
325
331
|
|
|
326
332
|
```bash
|
|
327
|
-
export OLBRAIN_API_KEY="
|
|
333
|
+
export OLBRAIN_API_KEY="ak_your_api_key"
|
|
328
334
|
export OLBRAIN_AGENT_ID="your-agent-id"
|
|
329
335
|
```
|
|
330
336
|
|
|
@@ -350,10 +356,10 @@ client = AgentClient(agent_id="...", api_key="...")
|
|
|
350
356
|
### Common Issues
|
|
351
357
|
|
|
352
358
|
**"Invalid API key" error**
|
|
353
|
-
- Ensure your API key starts with `sk_live_`, `org_live_`, `sk_`,
|
|
359
|
+
- Ensure your API key starts with `ak_` (or one of the older `sk_live_`, `org_live_`, `sk_`, `org_` prefixes)
|
|
354
360
|
- Check that you copied the key correctly (no extra spaces)
|
|
355
361
|
|
|
356
|
-
**"
|
|
362
|
+
**"Message poll failed" in the logs**
|
|
357
363
|
- Check that your agent ID is correct
|
|
358
364
|
- Verify you have a stable internet connection
|
|
359
365
|
- Try restarting the client
|
|
@@ -399,8 +405,8 @@ The test will:
|
|
|
399
405
|
|--------|-----------|---------|-------------|
|
|
400
406
|
| `create_session()` | `title`, `user_id`, `metadata`, `on_message`, `mode`, `description` | `str` (session_id) | Create a new chat session |
|
|
401
407
|
| `get_session(session_id)` | `session_id` | `SessionInfo` | Get session details |
|
|
402
|
-
| `update_session(session_id, ...)` | `session_id`, `title`, `metadata`, `status` | `
|
|
403
|
-
| `delete_session(session_id)` | `session_id` | `
|
|
408
|
+
| `update_session(session_id, ...)` | `session_id`, `title`, `metadata`, `status` | - | Not supported: raises `OlbrainError` (the Olbrain API has no endpoint for it) |
|
|
409
|
+
| `delete_session(session_id)` | `session_id` | - | Not supported: raises `OlbrainError` (the Olbrain API has no endpoint for it) |
|
|
404
410
|
| `get_messages(session_id, ...)` | `session_id`, `limit`, `offset` | `Dict` | Get message history |
|
|
405
411
|
| `get_session_stats(session_id)` | `session_id` | `Dict` | Get session statistics |
|
|
406
412
|
|
|
@@ -410,7 +416,7 @@ The test will:
|
|
|
410
416
|
|--------|-----------|---------|-------------|
|
|
411
417
|
| `send(session_id, message, ...)` | `session_id`, `message`, `user_id`, `metadata`, `model` | `Dict` | Send message (async with callback) |
|
|
412
418
|
| `send_and_wait(session_id, message, ...)` | `session_id`, `message`, `user_id`, `metadata`, `model`, `timeout` | `ChatResponse` | Send and wait for response |
|
|
413
|
-
| `listen(session_id, on_message)` | `session_id`, `on_message` | - |
|
|
419
|
+
| `listen(session_id, on_message)` | `session_id`, `on_message` | - | Poll the session every 2 s and call `on_message` for each new message |
|
|
414
420
|
| `run()` | - | - | Block and process streaming messages |
|
|
415
421
|
| `close()` | - | - | Close client and cleanup resources |
|
|
416
422
|
|
|
@@ -38,7 +38,7 @@ pytest tests/
|
|
|
38
38
|
|
|
39
39
|
Get your credentials from the Olbrain dashboard:
|
|
40
40
|
- **Agent ID**: Your unique agent identifier
|
|
41
|
-
- **API Key**:
|
|
41
|
+
- **API Key**: an access key (`ak_…`) from Noesis → Settings → Organization → Access keys, or from the finish page Alchemist links to when it hands an agent over (that key works only for that agent)
|
|
42
42
|
|
|
43
43
|
### Basic Example
|
|
44
44
|
|
|
@@ -48,7 +48,7 @@ from olbrain import AgentClient
|
|
|
48
48
|
# Initialize client
|
|
49
49
|
client = AgentClient(
|
|
50
50
|
agent_id="your-agent-id",
|
|
51
|
-
api_key="
|
|
51
|
+
api_key="ak_your_api_key"
|
|
52
52
|
)
|
|
53
53
|
|
|
54
54
|
# Create a session and send a message
|
|
@@ -67,7 +67,7 @@ client.close()
|
|
|
67
67
|
from olbrain import AgentClient
|
|
68
68
|
|
|
69
69
|
# Automatically closes client when done
|
|
70
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
70
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
71
71
|
session_id = client.create_session(title="My Chat")
|
|
72
72
|
response = client.send_and_wait(session_id, "What is machine learning?")
|
|
73
73
|
print(response.text)
|
|
@@ -81,6 +81,21 @@ with AgentClient(agent_id="your-agent-id", api_key="sk_live_your_key") as client
|
|
|
81
81
|
- **Token Tracking** - Monitor usage and costs per request
|
|
82
82
|
- **Model Override** - Switch models per-message
|
|
83
83
|
- **Error Handling** - Comprehensive exception hierarchy
|
|
84
|
+
- **Workflow Agents** - Run workflow agents, read and control their runs, resolve approvals (`Olbrain`)
|
|
85
|
+
- **Research Agents** - Sessions, streamed turns, plans, reports and review (`Olbrain.research`, sign-ins only)
|
|
86
|
+
|
|
87
|
+
### Workflow agents
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import os
|
|
91
|
+
from olbrain import Olbrain
|
|
92
|
+
|
|
93
|
+
olbrain = Olbrain(api_key=os.environ["OLBRAIN_API_KEY"]) # keep the key on your server
|
|
94
|
+
run = olbrain.workflows.run("your-agent-id", payload={"url": "https://example.com"})
|
|
95
|
+
print(olbrain.runs.get("your-agent-id", run["run_id"]))
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
See [`olbrain/AGENTS.md`](olbrain/AGENTS.md) for runs, approvals and research agents.
|
|
84
99
|
|
|
85
100
|
## Usage
|
|
86
101
|
|
|
@@ -91,7 +106,7 @@ Send a message and wait for the complete response:
|
|
|
91
106
|
```python
|
|
92
107
|
from olbrain import AgentClient
|
|
93
108
|
|
|
94
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
109
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
95
110
|
# Create a new chat session
|
|
96
111
|
session_id = client.create_session(title="My Chat")
|
|
97
112
|
|
|
@@ -106,12 +121,12 @@ with AgentClient(agent_id="your-agent-id", api_key="sk_live_your_key") as client
|
|
|
106
121
|
|
|
107
122
|
### 2. Real-Time Streaming (Callback Pattern)
|
|
108
123
|
|
|
109
|
-
Receive messages
|
|
124
|
+
Receive new messages as they arrive (the client polls the session every 2 seconds):
|
|
110
125
|
|
|
111
126
|
```python
|
|
112
127
|
from olbrain import AgentClient
|
|
113
128
|
|
|
114
|
-
client = AgentClient(agent_id="your-agent-id", api_key="
|
|
129
|
+
client = AgentClient(agent_id="your-agent-id", api_key="ak_your_key")
|
|
115
130
|
|
|
116
131
|
# Define message handler
|
|
117
132
|
def on_message(msg):
|
|
@@ -143,7 +158,7 @@ Create, retrieve, and manage chat sessions:
|
|
|
143
158
|
```python
|
|
144
159
|
from olbrain import AgentClient
|
|
145
160
|
|
|
146
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
161
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
147
162
|
# Create session with metadata
|
|
148
163
|
session = client.create_session(
|
|
149
164
|
title="Support Chat",
|
|
@@ -162,15 +177,9 @@ with AgentClient(agent_id="your-agent-id", api_key="sk_live_your_key") as client
|
|
|
162
177
|
for msg in messages.get('messages', []):
|
|
163
178
|
print(f"{msg['role']}: {msg['content']}")
|
|
164
179
|
|
|
165
|
-
# Update session
|
|
166
|
-
updated = client.update_session(session, title="Updated Chat Title")
|
|
167
|
-
|
|
168
180
|
# Get session statistics
|
|
169
181
|
stats = client.get_session_stats(session)
|
|
170
182
|
print(f"Stats: {stats}")
|
|
171
|
-
|
|
172
|
-
# Archive/delete session
|
|
173
|
-
client.delete_session(session)
|
|
174
183
|
```
|
|
175
184
|
|
|
176
185
|
### 4. Model Override
|
|
@@ -180,7 +189,7 @@ Send messages using a specific model:
|
|
|
180
189
|
```python
|
|
181
190
|
from olbrain import AgentClient
|
|
182
191
|
|
|
183
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
192
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
184
193
|
session_id = client.create_session()
|
|
185
194
|
|
|
186
195
|
# Use specific model for this request
|
|
@@ -200,7 +209,7 @@ Maintain conversation context:
|
|
|
200
209
|
```python
|
|
201
210
|
from olbrain import AgentClient
|
|
202
211
|
|
|
203
|
-
with AgentClient(agent_id="your-agent-id", api_key="
|
|
212
|
+
with AgentClient(agent_id="your-agent-id", api_key="ak_your_key") as client:
|
|
204
213
|
session_id = client.create_session(title="Q&A Session")
|
|
205
214
|
|
|
206
215
|
# First message
|
|
@@ -231,7 +240,7 @@ from olbrain.exceptions import (
|
|
|
231
240
|
)
|
|
232
241
|
|
|
233
242
|
try:
|
|
234
|
-
client = AgentClient(agent_id="your-agent-id", api_key="
|
|
243
|
+
client = AgentClient(agent_id="your-agent-id", api_key="ak_your_key")
|
|
235
244
|
session_id = client.create_session()
|
|
236
245
|
response = client.send_and_wait(session_id, "Hello")
|
|
237
246
|
|
|
@@ -259,24 +268,21 @@ finally:
|
|
|
259
268
|
|
|
260
269
|
### API Key
|
|
261
270
|
|
|
262
|
-
The SDK validates API keys.
|
|
263
|
-
|
|
264
|
-
- `org_live_` - Organization keys
|
|
265
|
-
- `sk_` - Test keys
|
|
266
|
-
- `org_` - Test organization keys
|
|
271
|
+
The SDK validates API keys. Access keys (`ak_`) are the only kind issued today; the older
|
|
272
|
+
`sk_live_`, `org_live_`, `sk_` and `org_` prefixes still pass validation.
|
|
267
273
|
|
|
268
274
|
```python
|
|
269
275
|
# Valid API key
|
|
270
276
|
client = AgentClient(
|
|
271
277
|
agent_id="your-agent-id",
|
|
272
|
-
api_key="
|
|
278
|
+
api_key="ak_your_api_key_here"
|
|
273
279
|
)
|
|
274
280
|
```
|
|
275
281
|
|
|
276
282
|
### Environment Variables
|
|
277
283
|
|
|
278
284
|
```bash
|
|
279
|
-
export OLBRAIN_API_KEY="
|
|
285
|
+
export OLBRAIN_API_KEY="ak_your_api_key"
|
|
280
286
|
export OLBRAIN_AGENT_ID="your-agent-id"
|
|
281
287
|
```
|
|
282
288
|
|
|
@@ -302,10 +308,10 @@ client = AgentClient(agent_id="...", api_key="...")
|
|
|
302
308
|
### Common Issues
|
|
303
309
|
|
|
304
310
|
**"Invalid API key" error**
|
|
305
|
-
- Ensure your API key starts with `sk_live_`, `org_live_`, `sk_`,
|
|
311
|
+
- Ensure your API key starts with `ak_` (or one of the older `sk_live_`, `org_live_`, `sk_`, `org_` prefixes)
|
|
306
312
|
- Check that you copied the key correctly (no extra spaces)
|
|
307
313
|
|
|
308
|
-
**"
|
|
314
|
+
**"Message poll failed" in the logs**
|
|
309
315
|
- Check that your agent ID is correct
|
|
310
316
|
- Verify you have a stable internet connection
|
|
311
317
|
- Try restarting the client
|
|
@@ -351,8 +357,8 @@ The test will:
|
|
|
351
357
|
|--------|-----------|---------|-------------|
|
|
352
358
|
| `create_session()` | `title`, `user_id`, `metadata`, `on_message`, `mode`, `description` | `str` (session_id) | Create a new chat session |
|
|
353
359
|
| `get_session(session_id)` | `session_id` | `SessionInfo` | Get session details |
|
|
354
|
-
| `update_session(session_id, ...)` | `session_id`, `title`, `metadata`, `status` | `
|
|
355
|
-
| `delete_session(session_id)` | `session_id` | `
|
|
360
|
+
| `update_session(session_id, ...)` | `session_id`, `title`, `metadata`, `status` | - | Not supported: raises `OlbrainError` (the Olbrain API has no endpoint for it) |
|
|
361
|
+
| `delete_session(session_id)` | `session_id` | - | Not supported: raises `OlbrainError` (the Olbrain API has no endpoint for it) |
|
|
356
362
|
| `get_messages(session_id, ...)` | `session_id`, `limit`, `offset` | `Dict` | Get message history |
|
|
357
363
|
| `get_session_stats(session_id)` | `session_id` | `Dict` | Get session statistics |
|
|
358
364
|
|
|
@@ -362,7 +368,7 @@ The test will:
|
|
|
362
368
|
|--------|-----------|---------|-------------|
|
|
363
369
|
| `send(session_id, message, ...)` | `session_id`, `message`, `user_id`, `metadata`, `model` | `Dict` | Send message (async with callback) |
|
|
364
370
|
| `send_and_wait(session_id, message, ...)` | `session_id`, `message`, `user_id`, `metadata`, `model`, `timeout` | `ChatResponse` | Send and wait for response |
|
|
365
|
-
| `listen(session_id, on_message)` | `session_id`, `on_message` | - |
|
|
371
|
+
| `listen(session_id, on_message)` | `session_id`, `on_message` | - | Poll the session every 2 s and call `on_message` for each new message |
|
|
366
372
|
| `run()` | - | - | Block and process streaming messages |
|
|
367
373
|
| `close()` | - | - | Close client and cleanup resources |
|
|
368
374
|
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# olbrain-python-sdk — reference for coding assistants
|
|
2
|
+
|
|
3
|
+
This file ships inside the installed package (`site-packages/olbrain/AGENTS.md`).
|
|
4
|
+
It is the complete, offline reference for the public API. Everything here is
|
|
5
|
+
taken from the source. If it disagrees with the web docs, this file is right.
|
|
6
|
+
|
|
7
|
+
Find it from Python with:
|
|
8
|
+
`python -c "import olbrain, os; print(os.path.join(os.path.dirname(olbrain.__file__), 'AGENTS.md'))"`
|
|
9
|
+
|
|
10
|
+
## Pick the right client
|
|
11
|
+
|
|
12
|
+
| You want to… | Use | Auth |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| Chat with a conversational agent (send a message, get a reply) | `AgentClient` | `api_key="ak_…"` (the only kind issued today; `sk_live_`, `org_live_`, `sk_` and `org_` still pass validation) |
|
|
15
|
+
| Trigger workflow agents, read/control runs, resolve approvals | `Olbrain` | `api_key="ak_…"` **or** `get_id_token` (Olbrain sign-in) |
|
|
16
|
+
| Drive a research agent (sessions, streamed turns, plans, reports) | `Olbrain.research` | `get_id_token` only. An `ak_` key gets `NotFoundError` (`agent_not_found`) |
|
|
17
|
+
|
|
18
|
+
These are two separate HTTP clients with different error rules. Both default
|
|
19
|
+
to `https://webhook.olbrain.com`. The JavaScript SDK (`@olbrain/js-sdk`) has
|
|
20
|
+
the same two clients plus a browser `ChatWidget`.
|
|
21
|
+
|
|
22
|
+
Keep the `ak_` key on your server (an environment variable such as
|
|
23
|
+
`OLBRAIN_API_KEY`). Never send it to a browser.
|
|
24
|
+
|
|
25
|
+
## Install and import
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install olbrain-python-sdk # import name: olbrain. Requires Python 3.7+ and requests.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from olbrain import AgentClient, Olbrain, OlbrainError
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Both clients are synchronous and use `requests`.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 1. `AgentClient` — conversational agents
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import os
|
|
43
|
+
from olbrain import AgentClient
|
|
44
|
+
|
|
45
|
+
with AgentClient(agent_id="your-agent-id", api_key=os.environ["OLBRAIN_API_KEY"]) as client:
|
|
46
|
+
session_id = client.create_session(title="Support chat", user_id="u_42")
|
|
47
|
+
reply = client.send_and_wait(session_id, "Hello!")
|
|
48
|
+
if reply.success:
|
|
49
|
+
print(reply.text)
|
|
50
|
+
else:
|
|
51
|
+
print("agent error:", reply.error)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `AgentClient(agent_id, api_key, agent_url=None)`
|
|
55
|
+
|
|
56
|
+
- `agent_id`: required. An empty value raises `ValueError`.
|
|
57
|
+
- `api_key`: must start with `ak_`, `sk_live_`, `org_live_`, `sk_` or `org_`,
|
|
58
|
+
or the constructor raises `ValueError`.
|
|
59
|
+
- `agent_url`: optional. Defaults to `https://webhook.olbrain.com`.
|
|
60
|
+
|
|
61
|
+
Chat calls are `POST {agent_url}/api/agents/webhook/{agent_id}` with
|
|
62
|
+
`Authorization: Bearer <api_key>`. Session reads are
|
|
63
|
+
`GET {agent_url}/api/agents/{agent_id}/sessions/{session_id}[/messages]`. The
|
|
64
|
+
client is a context manager, and `__exit__` calls `close()`.
|
|
65
|
+
|
|
66
|
+
### Methods
|
|
67
|
+
|
|
68
|
+
| Method | Returns | Notes |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| `create_session(on_message=None, title=None, user_id=None, metadata=None, mode="production", description=None)` | `str` session id | Sends `title` (default `"New Session"`) to the agent **as the first message**. `mode` must be `"development"`, `"testing"` or `"production"`, otherwise `ValueError`, but it is not sent: the API always serves the published agent. `description` is stored as `metadata["session_description"]`. If you pass `on_message`, it also calls `listen()`. Timeout 30 s. |
|
|
71
|
+
| `send_and_wait(session_id, message, user_id=None, metadata=None, model=None, timeout=120)` | `ChatResponse` | Waits for the reply. `timeout` is in **seconds**. `model` overrides the agent's model. Empty or whitespace-only messages raise `ValueError`. |
|
|
72
|
+
| `send(session_id, message, user_id=None, metadata=None, model=None, mode="production")` | `dict` (raw JSON) | Same request, but returns the raw response dict (`response`, `token_usage`, `success`, …). It still blocks, with a 120 s timeout. |
|
|
73
|
+
| `listen(session_id, on_message)` | `None` | Starts a background daemon thread that polls the session's messages every 2 s and calls `on_message` once per **new** message (messages already there are skipped). Calling it again for the same session does nothing. |
|
|
74
|
+
| `run()` | `None` | Blocks until Ctrl+C, then calls `close()`. Use it to keep a script alive for `listen` callbacks. |
|
|
75
|
+
| `close()` | `None` | Stops all listeners. |
|
|
76
|
+
| `get_session(session_id)` | `SessionInfo` | `SessionNotFoundError` if it doesn't exist (or belongs to another agent). |
|
|
77
|
+
| `get_session_stats(session_id)` | `dict` | `message_count`, `token_usage`, `cost`, `created_at`, `last_message_at`. |
|
|
78
|
+
| `get_messages(session_id, limit=20, offset=0)` | `dict` | `{"messages": [...], "limit", "offset"}`, oldest first; `limit` at most 200. |
|
|
79
|
+
| `update_session(...)`, `delete_session(...)` | — | Always raise `OlbrainError`: the API has no endpoint for them. |
|
|
80
|
+
|
|
81
|
+
`on_message` gets each message as a raw dict (`role`, `content`, …). It runs
|
|
82
|
+
on the listener thread, so keep it fast and don't raise from it.
|
|
83
|
+
|
|
84
|
+
### Data classes (`olbrain.session`, re-exported from `olbrain`)
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
@dataclass
|
|
88
|
+
class ChatResponse:
|
|
89
|
+
text: str
|
|
90
|
+
session_id: str
|
|
91
|
+
success: bool = True
|
|
92
|
+
token_usage: Optional[TokenUsage] = None # None if the server sent none
|
|
93
|
+
model_used: Optional[str] = None
|
|
94
|
+
response_time_ms: Optional[int] = None
|
|
95
|
+
metadata: Optional[dict] = None
|
|
96
|
+
error: Optional[str] = None
|
|
97
|
+
# ChatResponse.from_dict(data, session_id=""), .to_dict()
|
|
98
|
+
|
|
99
|
+
@dataclass
|
|
100
|
+
class TokenUsage:
|
|
101
|
+
prompt_tokens: int = 0
|
|
102
|
+
completion_tokens: int = 0
|
|
103
|
+
total_tokens: int = 0
|
|
104
|
+
cost: float = 0.0
|
|
105
|
+
|
|
106
|
+
@dataclass
|
|
107
|
+
class SessionInfo:
|
|
108
|
+
session_id: str
|
|
109
|
+
title: str = ""
|
|
110
|
+
status: str = "active" # "active" | "archived"
|
|
111
|
+
created_at: str = ""
|
|
112
|
+
updated_at: str = ""
|
|
113
|
+
message_count: int = 0
|
|
114
|
+
user_id: Optional[str] = None
|
|
115
|
+
channel: str = "api"
|
|
116
|
+
metadata: dict = {}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`token_usage` can be `None`, so guard before reading it:
|
|
120
|
+
`reply.token_usage.total_tokens if reply.token_usage else 0`. Always check
|
|
121
|
+
`reply.success` too. A 200 response can carry `success=False` and an `error`.
|
|
122
|
+
|
|
123
|
+
Avoid the exported `Message` and `Session` classes. Nothing in the client
|
|
124
|
+
returns them.
|
|
125
|
+
|
|
126
|
+
### Errors (`AgentClient`)
|
|
127
|
+
|
|
128
|
+
| Condition | Raised |
|
|
129
|
+
|---|---|
|
|
130
|
+
| Bad constructor args, empty message, bad `mode`/`status` | `ValueError` (**not** `ValidationError`) |
|
|
131
|
+
| HTTP 401 | `AuthenticationError` |
|
|
132
|
+
| HTTP 404 whose detail mentions "session" | `SessionNotFoundError` (a subclass of `SessionError`) |
|
|
133
|
+
| Other HTTP 404 | `OlbrainError` ("Endpoint not found (404) …") |
|
|
134
|
+
| HTTP 429 | `RateLimitError` (`.retry_after` from `detail.retry_after`, may be `None`) |
|
|
135
|
+
| Any other non-200 (403, 5xx…) | `OlbrainError("Failed to <operation>: <status> - <detail>")` |
|
|
136
|
+
| Connection error or timeout | `NetworkError` |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 2. `Olbrain` — workflow agents, runs, approvals
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
olbrain = Olbrain(api_key=os.environ["OLBRAIN_API_KEY"]) # server / script
|
|
144
|
+
# olbrain = Olbrain(get_id_token=lambda: current_user_id_token()) # signed-in Olbrain user (Firebase ID token)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`Olbrain(api_key=None, get_id_token=None, base_url=None, timeout=30)`:
|
|
148
|
+
`api_key` must start `ak_`; `get_id_token` is a callable returning the
|
|
149
|
+
token and is called before **every** request; `base_url` defaults to
|
|
150
|
+
`https://webhook.olbrain.com`; `timeout` is in seconds. Give **exactly one** of
|
|
151
|
+
`api_key` or `get_id_token`, or the constructor raises `ValidationError`.
|
|
152
|
+
|
|
153
|
+
Every method takes the agent id first and returns the API's JSON (snake_case
|
|
154
|
+
dicts and lists).
|
|
155
|
+
|
|
156
|
+
| Method | HTTP | Returns |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `workflows.run(agent_id, payload=None, variables=None)` | `POST /api/workflows/{agent_id}/trigger` | `{"run_id", "status"}` |
|
|
159
|
+
| `runs.list(agent_id, status=None, limit=None)` | `GET /api/agents/{agent_id}/runs` | list of runs |
|
|
160
|
+
| `runs.get(agent_id, run_id)` | `GET …/runs/{run_id}` | run |
|
|
161
|
+
| `runs.cancel / pause / retry / resume(agent_id, run_id)` | `POST …/runs/{run_id}/{verb}` | dict |
|
|
162
|
+
| `approvals.list(agent_id, run_id)` | `GET …/runs/{run_id}/approvals` | list of approvals |
|
|
163
|
+
| `approvals.resolve(agent_id, run_id, exception_id, resolution, modified_data=None)` | `POST …/approvals/resolve` | `{"exception_id", "resolution", "all_resolved", "resumed"}` |
|
|
164
|
+
|
|
165
|
+
A run has `run_id`, `status`, and optionally `progress_percent`, `started_at`,
|
|
166
|
+
`completed_at`, `duration_seconds`, `error` and `summary`
|
|
167
|
+
(`total_processed`, `successful`, `failed`, `exceptions`, `skipped`). An
|
|
168
|
+
approval has `exception_id`, `step_id`, `item_id`, `data`, `error`,
|
|
169
|
+
`requires_human_review` and `blocking`. `resolution` is `"approved"`,
|
|
170
|
+
`"rejected"` or `"modified"`; send `modified_data` only with `"modified"`.
|
|
171
|
+
|
|
172
|
+
There is no SDK helper for waiting on a run, so poll `runs.get` yourself:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
import os, time
|
|
176
|
+
from olbrain import Olbrain
|
|
177
|
+
|
|
178
|
+
olbrain = Olbrain(api_key=os.environ["OLBRAIN_API_KEY"])
|
|
179
|
+
run_id = olbrain.workflows.run(agent_id, payload={"url": url})["run_id"]
|
|
180
|
+
DONE = {"completed", "failed", "canceled", "cancelled"}
|
|
181
|
+
run = olbrain.runs.get(agent_id, run_id)
|
|
182
|
+
while run["status"] not in DONE:
|
|
183
|
+
for a in olbrain.approvals.list(agent_id, run_id):
|
|
184
|
+
olbrain.approvals.resolve(agent_id, run_id, a["exception_id"], "approved")
|
|
185
|
+
time.sleep(3)
|
|
186
|
+
run = olbrain.runs.get(agent_id, run_id)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The terminal status strings in that loop are an assumption. Check the values
|
|
190
|
+
your agent actually returns.
|
|
191
|
+
|
|
192
|
+
### Errors (`Olbrain`, including `research`)
|
|
193
|
+
|
|
194
|
+
The error code and message come from the response body: `{error:{code,message}}`
|
|
195
|
+
or FastAPI's `{detail}`.
|
|
196
|
+
|
|
197
|
+
| Condition | Raised |
|
|
198
|
+
|---|---|
|
|
199
|
+
| code is `insufficient_funds`, `credit_limit_exceeded`, `subscription_suspended`, `subscription_inactive` or `billing_unavailable` (any status) | `BillingError` (`.status`, `.code`) |
|
|
200
|
+
| 401 | `AuthenticationError` |
|
|
201
|
+
| 404 | `NotFoundError` (`.status = 404`, `.code`, e.g. `agent_not_found`) |
|
|
202
|
+
| 429 | `RateLimitError` (`.retry_after` seconds from the `Retry-After` header, or `None`) |
|
|
203
|
+
| any other non-2xx (403, 409, 422, 5xx…) | `ApiError` (`.status`, `.code`, `.message`, `.detail` = raw `detail`) |
|
|
204
|
+
| connection failure, timeout, or a dropped stream | `NetworkError` |
|
|
205
|
+
|
|
206
|
+
`BillingError` and `NotFoundError` subclass `ApiError`, and every error class
|
|
207
|
+
subclasses `OlbrainError`, so put the narrower `except` clauses first.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 3. `Olbrain.research` — research agents (sign-ins only)
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
olbrain = Olbrain(get_id_token=lambda: user_id_token)
|
|
215
|
+
r = olbrain.research
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
All paths sit under `/api/agents/{agent_id}/research`. The agent must be a
|
|
219
|
+
research agent that is bound to a screen in the user's org. Payloads are
|
|
220
|
+
returned untyped (dicts and lists) because their shape belongs to the
|
|
221
|
+
research-runtime service.
|
|
222
|
+
|
|
223
|
+
| Method | |
|
|
224
|
+
|---|---|
|
|
225
|
+
| `sessions.create(agent_id)` | session (has `session_id`) |
|
|
226
|
+
| `sessions.list(agent_id, include_archived=False)`, `sessions.get / delete(agent_id, session_id)` | |
|
|
227
|
+
| `sessions.patch(agent_id, session_id, patch)` | partial session fields, passed through |
|
|
228
|
+
| `sessions.models(agent_id, session_id)` | available models |
|
|
229
|
+
| `sessions.set_model / set_review_model(agent_id, session_id, model)` | `None` resets to the default |
|
|
230
|
+
| `sessions.stream_message(agent_id, session_id, content, attachments=None, effort=None, escalates_run_id=None, command=None, target_run_id=None)` | generator of frames |
|
|
231
|
+
| `plans.approve(agent_id, session_id, message_id, body=None)`, `plans.approve_by_id(agent_id, session_id, plan_id, body=None)` | |
|
|
232
|
+
| `attachments.add(agent_id, session_id, files)` | multipart upload of `(filename, file or bytes[, content_type])` tuples; returns refs to pass as `attachments` |
|
|
233
|
+
| `attachments.upload_url(agent_id, session_id, storage_path)` | `{"url"}` |
|
|
234
|
+
| `runs.cancel / retry(agent_id, run_id)`, `runs.active_job(agent_id, run_id)` (or `None`), `runs.resolve_claims(agent_id, run_id, resolutions)` | |
|
|
235
|
+
| `reports.get(agent_id, run_id, version=None)`, `reports.artifact_url(agent_id, run_id, profile_id, fmt)`, `reports.evidence(agent_id, run_id)` | |
|
|
236
|
+
| `reports.share.get / revoke(agent_id, run_id)`, `reports.share.set(agent_id, run_id, visibility)` | |
|
|
237
|
+
| `review.get(agent_id, run_id)`; `review.run(agent_id, run_id)`, `review.apply(agent_id, run_id, finding_ids)` | the last two block, up to 600 s |
|
|
238
|
+
| `review.stream(agent_id, run_id)`, `review.stream_apply(agent_id, run_id, finding_ids)` | generators of frames |
|
|
239
|
+
| `templates.versions(agent_id)` | |
|
|
240
|
+
| `messages.older(agent_id, session_id, before_ts)` | one page of older messages, oldest first |
|
|
241
|
+
|
|
242
|
+
Stream frames come straight from research-runtime, unchanged: `{"type": "text_delta", "text"}`,
|
|
243
|
+
`{"type": "tool_use_start", …}`, `{"type": "complete", …}` and `{"type": "error", …}`.
|
|
244
|
+
The request is sent when you start iterating, and it can wait up to 600 s for
|
|
245
|
+
its first frame while the agent searches. To cancel, stop iterating (`break`,
|
|
246
|
+
or `.close()` the generator); the connection is closed.
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
for ev in r.sessions.stream_message(agent_id, sid, "Size the Indian EV charger market"):
|
|
250
|
+
if ev.get("type") == "text_delta":
|
|
251
|
+
print(ev["text"], end="", flush=True)
|
|
252
|
+
elif ev.get("type") == "error":
|
|
253
|
+
raise RuntimeError(ev.get("message", "research error"))
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
The JavaScript SDK's `live.*` polling subscriptions are not in Python. Poll
|
|
257
|
+
`sessions.get` / `reports.get` yourself.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Logging
|
|
262
|
+
|
|
263
|
+
`AgentClient` logs through `logging.getLogger("olbrain")`. Turn on
|
|
264
|
+
`logging.basicConfig(level=logging.DEBUG)` to see requests and listener events.
|