akribes 0.21.17__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.
- akribes-0.21.17/LICENSE +21 -0
- akribes-0.21.17/PKG-INFO +236 -0
- akribes-0.21.17/README.md +195 -0
- akribes-0.21.17/akribes.egg-info/PKG-INFO +236 -0
- akribes-0.21.17/akribes.egg-info/SOURCES.txt +67 -0
- akribes-0.21.17/akribes.egg-info/dependency_links.txt +1 -0
- akribes-0.21.17/akribes.egg-info/requires.txt +15 -0
- akribes-0.21.17/akribes.egg-info/top_level.txt +1 -0
- akribes-0.21.17/akribes_sdk/__init__.py +365 -0
- akribes-0.21.17/akribes_sdk/_handles.py +279 -0
- akribes-0.21.17/akribes_sdk/_otel.py +54 -0
- akribes-0.21.17/akribes_sdk/_pagination.py +70 -0
- akribes-0.21.17/akribes_sdk/_parsers.py +690 -0
- akribes-0.21.17/akribes_sdk/_retry.py +138 -0
- akribes-0.21.17/akribes_sdk/_timing.py +23 -0
- akribes-0.21.17/akribes_sdk/_token_safety.py +32 -0
- akribes-0.21.17/akribes_sdk/_transport.py +333 -0
- akribes-0.21.17/akribes_sdk/client.py +540 -0
- akribes-0.21.17/akribes_sdk/errors.py +438 -0
- akribes-0.21.17/akribes_sdk/ingest_handle.py +109 -0
- akribes-0.21.17/akribes_sdk/models.py +1392 -0
- akribes-0.21.17/akribes_sdk/py.typed +0 -0
- akribes-0.21.17/akribes_sdk/resources/__init__.py +34 -0
- akribes-0.21.17/akribes_sdk/resources/_base.py +95 -0
- akribes-0.21.17/akribes_sdk/resources/_sentinel.py +23 -0
- akribes-0.21.17/akribes_sdk/resources/channels.py +46 -0
- akribes-0.21.17/akribes_sdk/resources/clients.py +78 -0
- akribes-0.21.17/akribes_sdk/resources/documents.py +423 -0
- akribes-0.21.17/akribes_sdk/resources/drafts.py +32 -0
- akribes-0.21.17/akribes_sdk/resources/evals.py +226 -0
- akribes-0.21.17/akribes_sdk/resources/events.py +782 -0
- akribes-0.21.17/akribes_sdk/resources/executions.py +560 -0
- akribes-0.21.17/akribes_sdk/resources/mcp.py +57 -0
- akribes-0.21.17/akribes_sdk/resources/me.py +26 -0
- akribes-0.21.17/akribes_sdk/resources/projects.py +164 -0
- akribes-0.21.17/akribes_sdk/resources/scripts.py +88 -0
- akribes-0.21.17/akribes_sdk/resources/tokens.py +86 -0
- akribes-0.21.17/akribes_sdk/resources/versions.py +88 -0
- akribes-0.21.17/akribes_sdk/run_stream.py +492 -0
- akribes-0.21.17/akribes_sdk/script_type.py +51 -0
- akribes-0.21.17/akribes_sdk/types.py +78 -0
- akribes-0.21.17/akribes_sdk/workflow_events.py +1079 -0
- akribes-0.21.17/pyproject.toml +63 -0
- akribes-0.21.17/setup.cfg +4 -0
- akribes-0.21.17/tests/test_backoff.py +42 -0
- akribes-0.21.17/tests/test_client.py +1688 -0
- akribes-0.21.17/tests/test_documents.py +519 -0
- akribes-0.21.17/tests/test_dx_improvements.py +726 -0
- akribes-0.21.17/tests/test_errors.py +110 -0
- akribes-0.21.17/tests/test_evals.py +69 -0
- akribes-0.21.17/tests/test_events.py +340 -0
- akribes-0.21.17/tests/test_execution_ergonomics.py +333 -0
- akribes-0.21.17/tests/test_ingest_handle.py +226 -0
- akribes-0.21.17/tests/test_mcp.py +174 -0
- akribes-0.21.17/tests/test_models_dataclass.py +713 -0
- akribes-0.21.17/tests/test_otel.py +164 -0
- akribes-0.21.17/tests/test_pagination.py +260 -0
- akribes-0.21.17/tests/test_retry_policy.py +336 -0
- akribes-0.21.17/tests/test_run_stream.py +312 -0
- akribes-0.21.17/tests/test_runtime_events.py +545 -0
- akribes-0.21.17/tests/test_sandbox.py +137 -0
- akribes-0.21.17/tests/test_script_type.py +289 -0
- akribes-0.21.17/tests/test_smoke_integration.py +136 -0
- akribes-0.21.17/tests/test_suspend_trigger.py +363 -0
- akribes-0.21.17/tests/test_token_safety.py +27 -0
- akribes-0.21.17/tests/test_validation_failure.py +130 -0
- akribes-0.21.17/tests/test_workflow_events.py +379 -0
- akribes-0.21.17/tests/test_workflow_events_dataclass.py +383 -0
- akribes-0.21.17/tests/test_ws_transport.py +354 -0
akribes-0.21.17/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Podesta
|
|
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.
|
akribes-0.21.17/PKG-INFO
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: akribes
|
|
3
|
+
Version: 0.21.17
|
|
4
|
+
Summary: Pythonic async client for the Akribes workflow server
|
|
5
|
+
Author-email: Podesta <info@podesta.ai>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://akribes.ai
|
|
8
|
+
Project-URL: Repository, https://github.com/PodestaAI/akribes-sdks
|
|
9
|
+
Project-URL: Documentation, https://akribes.ai
|
|
10
|
+
Project-URL: Issues, https://github.com/PodestaAI/akribes-sdks/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/PodestaAI/akribes-sdks/blob/main/packages/akribes-sdk-python/CHANGELOG.md
|
|
12
|
+
Keywords: akribes,llm,ai-workflows,agent,dsl,sdk
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: httpx>=0.27.0
|
|
28
|
+
Requires-Dist: httpx-sse>=0.4.0
|
|
29
|
+
Requires-Dist: pydantic>=2.6
|
|
30
|
+
Requires-Dist: typing-extensions>=4.10
|
|
31
|
+
Requires-Dist: websockets>=12.0
|
|
32
|
+
Provides-Extra: otel
|
|
33
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == "otel"
|
|
34
|
+
Provides-Extra: test
|
|
35
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "test"
|
|
37
|
+
Requires-Dist: respx>=0.21.0; extra == "test"
|
|
38
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == "test"
|
|
39
|
+
Requires-Dist: opentelemetry-sdk>=1.20; extra == "test"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# akribes
|
|
43
|
+
|
|
44
|
+
Pythonic async client for the [Akribes](https://akribes.ai) workflow server.
|
|
45
|
+
|
|
46
|
+
Requires Python 3.10+.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install akribes
|
|
52
|
+
# or with optional OpenTelemetry support:
|
|
53
|
+
pip install 'akribes[otel]'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asyncio
|
|
60
|
+
from akribes_sdk import AkribesClient
|
|
61
|
+
|
|
62
|
+
async def main():
|
|
63
|
+
async with AkribesClient("https://akribes.example.com", token="akribes_tk_...") as client:
|
|
64
|
+
proj = client.project(2)
|
|
65
|
+
output = await proj.script("summarize").run_and_await(brief="explain quantum")
|
|
66
|
+
print(output.execution_id, output.result)
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Construction
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import os
|
|
75
|
+
from datetime import timedelta
|
|
76
|
+
from akribes_sdk import AkribesClient, RetryPolicy
|
|
77
|
+
|
|
78
|
+
client = AkribesClient(
|
|
79
|
+
"https://akribes.example.com",
|
|
80
|
+
token=os.environ["AKRIBES_TOKEN"],
|
|
81
|
+
timeout=timedelta(seconds=30),
|
|
82
|
+
retry=RetryPolicy(max_attempts=4), # retries transients + 429 by default
|
|
83
|
+
otel=True, # opt-in OTel auto-instrumentation
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Project handles
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
proj = client.project(2) # sync, lazy
|
|
91
|
+
proj = await client.get_project("podesta-staging") # async, resolves name → id
|
|
92
|
+
sandbox = await client.sandbox() # per-user sandbox project
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Typed inputs (codegen)
|
|
96
|
+
|
|
97
|
+
Generate typed `ScriptType[I, O]` stubs from a live server:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
akribes types pull --project podesta --lang python --out src/akribes_types/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Then:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from akribes_types.podesta import summarize # ScriptType[I, O] with typed input/output
|
|
107
|
+
|
|
108
|
+
out = await proj.run(summarize, brief="hi", tone="formal")
|
|
109
|
+
# IDE knows brief: str, tone: Literal["formal","casual"]
|
|
110
|
+
print(out.execution_id, out.result)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Streaming
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
run = await proj.executions.run_stream("summarize", brief="hi")
|
|
117
|
+
async for evt in run:
|
|
118
|
+
match evt.kind:
|
|
119
|
+
case "agent_chunk": print(evt.chunk, end="")
|
|
120
|
+
case "task_end": print(f"\n[task {evt.task!r} done]")
|
|
121
|
+
case "error": print(f"\n[error {evt.message}]")
|
|
122
|
+
output = await run.output()
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Document ingest
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from pathlib import Path
|
|
129
|
+
|
|
130
|
+
# One-liner
|
|
131
|
+
result = await proj.documents.ingest_and_wait(Path("invoice.pdf"))
|
|
132
|
+
|
|
133
|
+
# With progress
|
|
134
|
+
handle = proj.documents.ingest(Path("invoice.pdf"))
|
|
135
|
+
async for evt in handle:
|
|
136
|
+
print(evt)
|
|
137
|
+
result = await handle.result()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Subscribe (long-lived events)
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
async with proj.events.subscribe(interests=[{"script_name": "summarize"}]) as sub:
|
|
144
|
+
async for evt in sub:
|
|
145
|
+
print(evt)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Heartbeat runs for the lifetime of the subscription only — not automatically on client construction.
|
|
149
|
+
|
|
150
|
+
## Pagination
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
async for script in proj.scripts.list():
|
|
154
|
+
print(script.name)
|
|
155
|
+
|
|
156
|
+
# Or materialise
|
|
157
|
+
scripts = await proj.scripts.list().to_list()
|
|
158
|
+
first = await proj.scripts.list().first()
|
|
159
|
+
top10 = await proj.scripts.list().take(10)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Error handling
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from akribes_sdk import (
|
|
166
|
+
AkribesError, AuthError, NotFoundError, TransientError,
|
|
167
|
+
RateLimitError, ScriptError, AkribesTimeoutError,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
output = await proj.run_and_await("summarize", brief="hi")
|
|
172
|
+
except AuthError: # 401/403
|
|
173
|
+
...
|
|
174
|
+
except NotFoundError: # 404
|
|
175
|
+
...
|
|
176
|
+
except TransientError: # 502/503 (retried by default)
|
|
177
|
+
...
|
|
178
|
+
except RateLimitError: # 429 (retried by default, respects Retry-After)
|
|
179
|
+
...
|
|
180
|
+
except ScriptError as e: # workflow failed; e.error_kind, e.execution_id
|
|
181
|
+
...
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Tokens
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from datetime import timedelta
|
|
188
|
+
minted = await client.tokens.mint(
|
|
189
|
+
scopes={"projects": "*", "role": "admin"},
|
|
190
|
+
expires_in=timedelta(hours=8),
|
|
191
|
+
label="web-session",
|
|
192
|
+
user_email="alice@acme.com",
|
|
193
|
+
)
|
|
194
|
+
print(minted.token) # ship to the browser
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Authentication
|
|
198
|
+
|
|
199
|
+
`AkribesClient` accepts either a **service token** (long-lived, set via
|
|
200
|
+
`AKRIBES_SERVICE_TOKEN_<NAME>=<scope>:<secret>` on the server) or a **scoped
|
|
201
|
+
token** (`akribes_tk_...` — legacy `aura_tk_...` still accepted — minted
|
|
202
|
+
via `client.tokens.mint(...)`).
|
|
203
|
+
|
|
204
|
+
### Prefer `Authorization: Bearer` over `?token=…` (#789)
|
|
205
|
+
|
|
206
|
+
`AkribesClient` always sends the token in the `Authorization` header
|
|
207
|
+
for HTTP requests and WebSocket upgrades. The `?token=…` query-string
|
|
208
|
+
form exists only because browser `EventSource` / `WebSocket`
|
|
209
|
+
constructors cannot set arbitrary headers — treat it as a browser-only
|
|
210
|
+
escape hatch.
|
|
211
|
+
|
|
212
|
+
For CLIs, scripts, and backend services, avoid `?token=…` because:
|
|
213
|
+
|
|
214
|
+
- Reverse proxies, ingress controllers, and CDNs log the full URL
|
|
215
|
+
(including the token) in access logs by default.
|
|
216
|
+
- CI runners (Forgejo Actions, GitHub Actions) echo `curl` commands
|
|
217
|
+
into job logs.
|
|
218
|
+
- Browsers leak `?token=` in the `Referer` header on cross-origin
|
|
219
|
+
sub-resource requests.
|
|
220
|
+
|
|
221
|
+
The server stamps `X-Token-Source: query-param` on responses to any
|
|
222
|
+
request that used the query fallback so operators can chart adoption.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
See `examples/` for runnable end-to-end demos.
|
|
227
|
+
|
|
228
|
+
Upgrading from v0.20.x? See [MIGRATION-0.21.md](./MIGRATION-0.21.md).
|
|
229
|
+
|
|
230
|
+
- Source mirror: <https://github.com/PodestaAI/akribes-sdks>
|
|
231
|
+
- Language guide: <https://akribes.ai/docs>
|
|
232
|
+
- Issues: <https://github.com/PodestaAI/akribes-sdks/issues>
|
|
233
|
+
|
|
234
|
+
## License
|
|
235
|
+
|
|
236
|
+
MIT
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# akribes
|
|
2
|
+
|
|
3
|
+
Pythonic async client for the [Akribes](https://akribes.ai) workflow server.
|
|
4
|
+
|
|
5
|
+
Requires Python 3.10+.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install akribes
|
|
11
|
+
# or with optional OpenTelemetry support:
|
|
12
|
+
pip install 'akribes[otel]'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import asyncio
|
|
19
|
+
from akribes_sdk import AkribesClient
|
|
20
|
+
|
|
21
|
+
async def main():
|
|
22
|
+
async with AkribesClient("https://akribes.example.com", token="akribes_tk_...") as client:
|
|
23
|
+
proj = client.project(2)
|
|
24
|
+
output = await proj.script("summarize").run_and_await(brief="explain quantum")
|
|
25
|
+
print(output.execution_id, output.result)
|
|
26
|
+
|
|
27
|
+
asyncio.run(main())
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Construction
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import os
|
|
34
|
+
from datetime import timedelta
|
|
35
|
+
from akribes_sdk import AkribesClient, RetryPolicy
|
|
36
|
+
|
|
37
|
+
client = AkribesClient(
|
|
38
|
+
"https://akribes.example.com",
|
|
39
|
+
token=os.environ["AKRIBES_TOKEN"],
|
|
40
|
+
timeout=timedelta(seconds=30),
|
|
41
|
+
retry=RetryPolicy(max_attempts=4), # retries transients + 429 by default
|
|
42
|
+
otel=True, # opt-in OTel auto-instrumentation
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Project handles
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
proj = client.project(2) # sync, lazy
|
|
50
|
+
proj = await client.get_project("podesta-staging") # async, resolves name → id
|
|
51
|
+
sandbox = await client.sandbox() # per-user sandbox project
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Typed inputs (codegen)
|
|
55
|
+
|
|
56
|
+
Generate typed `ScriptType[I, O]` stubs from a live server:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
akribes types pull --project podesta --lang python --out src/akribes_types/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from akribes_types.podesta import summarize # ScriptType[I, O] with typed input/output
|
|
66
|
+
|
|
67
|
+
out = await proj.run(summarize, brief="hi", tone="formal")
|
|
68
|
+
# IDE knows brief: str, tone: Literal["formal","casual"]
|
|
69
|
+
print(out.execution_id, out.result)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Streaming
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
run = await proj.executions.run_stream("summarize", brief="hi")
|
|
76
|
+
async for evt in run:
|
|
77
|
+
match evt.kind:
|
|
78
|
+
case "agent_chunk": print(evt.chunk, end="")
|
|
79
|
+
case "task_end": print(f"\n[task {evt.task!r} done]")
|
|
80
|
+
case "error": print(f"\n[error {evt.message}]")
|
|
81
|
+
output = await run.output()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Document ingest
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from pathlib import Path
|
|
88
|
+
|
|
89
|
+
# One-liner
|
|
90
|
+
result = await proj.documents.ingest_and_wait(Path("invoice.pdf"))
|
|
91
|
+
|
|
92
|
+
# With progress
|
|
93
|
+
handle = proj.documents.ingest(Path("invoice.pdf"))
|
|
94
|
+
async for evt in handle:
|
|
95
|
+
print(evt)
|
|
96
|
+
result = await handle.result()
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Subscribe (long-lived events)
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
async with proj.events.subscribe(interests=[{"script_name": "summarize"}]) as sub:
|
|
103
|
+
async for evt in sub:
|
|
104
|
+
print(evt)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Heartbeat runs for the lifetime of the subscription only — not automatically on client construction.
|
|
108
|
+
|
|
109
|
+
## Pagination
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
async for script in proj.scripts.list():
|
|
113
|
+
print(script.name)
|
|
114
|
+
|
|
115
|
+
# Or materialise
|
|
116
|
+
scripts = await proj.scripts.list().to_list()
|
|
117
|
+
first = await proj.scripts.list().first()
|
|
118
|
+
top10 = await proj.scripts.list().take(10)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Error handling
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from akribes_sdk import (
|
|
125
|
+
AkribesError, AuthError, NotFoundError, TransientError,
|
|
126
|
+
RateLimitError, ScriptError, AkribesTimeoutError,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
output = await proj.run_and_await("summarize", brief="hi")
|
|
131
|
+
except AuthError: # 401/403
|
|
132
|
+
...
|
|
133
|
+
except NotFoundError: # 404
|
|
134
|
+
...
|
|
135
|
+
except TransientError: # 502/503 (retried by default)
|
|
136
|
+
...
|
|
137
|
+
except RateLimitError: # 429 (retried by default, respects Retry-After)
|
|
138
|
+
...
|
|
139
|
+
except ScriptError as e: # workflow failed; e.error_kind, e.execution_id
|
|
140
|
+
...
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Tokens
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from datetime import timedelta
|
|
147
|
+
minted = await client.tokens.mint(
|
|
148
|
+
scopes={"projects": "*", "role": "admin"},
|
|
149
|
+
expires_in=timedelta(hours=8),
|
|
150
|
+
label="web-session",
|
|
151
|
+
user_email="alice@acme.com",
|
|
152
|
+
)
|
|
153
|
+
print(minted.token) # ship to the browser
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Authentication
|
|
157
|
+
|
|
158
|
+
`AkribesClient` accepts either a **service token** (long-lived, set via
|
|
159
|
+
`AKRIBES_SERVICE_TOKEN_<NAME>=<scope>:<secret>` on the server) or a **scoped
|
|
160
|
+
token** (`akribes_tk_...` — legacy `aura_tk_...` still accepted — minted
|
|
161
|
+
via `client.tokens.mint(...)`).
|
|
162
|
+
|
|
163
|
+
### Prefer `Authorization: Bearer` over `?token=…` (#789)
|
|
164
|
+
|
|
165
|
+
`AkribesClient` always sends the token in the `Authorization` header
|
|
166
|
+
for HTTP requests and WebSocket upgrades. The `?token=…` query-string
|
|
167
|
+
form exists only because browser `EventSource` / `WebSocket`
|
|
168
|
+
constructors cannot set arbitrary headers — treat it as a browser-only
|
|
169
|
+
escape hatch.
|
|
170
|
+
|
|
171
|
+
For CLIs, scripts, and backend services, avoid `?token=…` because:
|
|
172
|
+
|
|
173
|
+
- Reverse proxies, ingress controllers, and CDNs log the full URL
|
|
174
|
+
(including the token) in access logs by default.
|
|
175
|
+
- CI runners (Forgejo Actions, GitHub Actions) echo `curl` commands
|
|
176
|
+
into job logs.
|
|
177
|
+
- Browsers leak `?token=` in the `Referer` header on cross-origin
|
|
178
|
+
sub-resource requests.
|
|
179
|
+
|
|
180
|
+
The server stamps `X-Token-Source: query-param` on responses to any
|
|
181
|
+
request that used the query fallback so operators can chart adoption.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
See `examples/` for runnable end-to-end demos.
|
|
186
|
+
|
|
187
|
+
Upgrading from v0.20.x? See [MIGRATION-0.21.md](./MIGRATION-0.21.md).
|
|
188
|
+
|
|
189
|
+
- Source mirror: <https://github.com/PodestaAI/akribes-sdks>
|
|
190
|
+
- Language guide: <https://akribes.ai/docs>
|
|
191
|
+
- Issues: <https://github.com/PodestaAI/akribes-sdks/issues>
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
MIT
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: akribes
|
|
3
|
+
Version: 0.21.17
|
|
4
|
+
Summary: Pythonic async client for the Akribes workflow server
|
|
5
|
+
Author-email: Podesta <info@podesta.ai>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://akribes.ai
|
|
8
|
+
Project-URL: Repository, https://github.com/PodestaAI/akribes-sdks
|
|
9
|
+
Project-URL: Documentation, https://akribes.ai
|
|
10
|
+
Project-URL: Issues, https://github.com/PodestaAI/akribes-sdks/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/PodestaAI/akribes-sdks/blob/main/packages/akribes-sdk-python/CHANGELOG.md
|
|
12
|
+
Keywords: akribes,llm,ai-workflows,agent,dsl,sdk
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: httpx>=0.27.0
|
|
28
|
+
Requires-Dist: httpx-sse>=0.4.0
|
|
29
|
+
Requires-Dist: pydantic>=2.6
|
|
30
|
+
Requires-Dist: typing-extensions>=4.10
|
|
31
|
+
Requires-Dist: websockets>=12.0
|
|
32
|
+
Provides-Extra: otel
|
|
33
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == "otel"
|
|
34
|
+
Provides-Extra: test
|
|
35
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "test"
|
|
37
|
+
Requires-Dist: respx>=0.21.0; extra == "test"
|
|
38
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == "test"
|
|
39
|
+
Requires-Dist: opentelemetry-sdk>=1.20; extra == "test"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# akribes
|
|
43
|
+
|
|
44
|
+
Pythonic async client for the [Akribes](https://akribes.ai) workflow server.
|
|
45
|
+
|
|
46
|
+
Requires Python 3.10+.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install akribes
|
|
52
|
+
# or with optional OpenTelemetry support:
|
|
53
|
+
pip install 'akribes[otel]'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asyncio
|
|
60
|
+
from akribes_sdk import AkribesClient
|
|
61
|
+
|
|
62
|
+
async def main():
|
|
63
|
+
async with AkribesClient("https://akribes.example.com", token="akribes_tk_...") as client:
|
|
64
|
+
proj = client.project(2)
|
|
65
|
+
output = await proj.script("summarize").run_and_await(brief="explain quantum")
|
|
66
|
+
print(output.execution_id, output.result)
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Construction
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import os
|
|
75
|
+
from datetime import timedelta
|
|
76
|
+
from akribes_sdk import AkribesClient, RetryPolicy
|
|
77
|
+
|
|
78
|
+
client = AkribesClient(
|
|
79
|
+
"https://akribes.example.com",
|
|
80
|
+
token=os.environ["AKRIBES_TOKEN"],
|
|
81
|
+
timeout=timedelta(seconds=30),
|
|
82
|
+
retry=RetryPolicy(max_attempts=4), # retries transients + 429 by default
|
|
83
|
+
otel=True, # opt-in OTel auto-instrumentation
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Project handles
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
proj = client.project(2) # sync, lazy
|
|
91
|
+
proj = await client.get_project("podesta-staging") # async, resolves name → id
|
|
92
|
+
sandbox = await client.sandbox() # per-user sandbox project
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Typed inputs (codegen)
|
|
96
|
+
|
|
97
|
+
Generate typed `ScriptType[I, O]` stubs from a live server:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
akribes types pull --project podesta --lang python --out src/akribes_types/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Then:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from akribes_types.podesta import summarize # ScriptType[I, O] with typed input/output
|
|
107
|
+
|
|
108
|
+
out = await proj.run(summarize, brief="hi", tone="formal")
|
|
109
|
+
# IDE knows brief: str, tone: Literal["formal","casual"]
|
|
110
|
+
print(out.execution_id, out.result)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Streaming
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
run = await proj.executions.run_stream("summarize", brief="hi")
|
|
117
|
+
async for evt in run:
|
|
118
|
+
match evt.kind:
|
|
119
|
+
case "agent_chunk": print(evt.chunk, end="")
|
|
120
|
+
case "task_end": print(f"\n[task {evt.task!r} done]")
|
|
121
|
+
case "error": print(f"\n[error {evt.message}]")
|
|
122
|
+
output = await run.output()
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Document ingest
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from pathlib import Path
|
|
129
|
+
|
|
130
|
+
# One-liner
|
|
131
|
+
result = await proj.documents.ingest_and_wait(Path("invoice.pdf"))
|
|
132
|
+
|
|
133
|
+
# With progress
|
|
134
|
+
handle = proj.documents.ingest(Path("invoice.pdf"))
|
|
135
|
+
async for evt in handle:
|
|
136
|
+
print(evt)
|
|
137
|
+
result = await handle.result()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Subscribe (long-lived events)
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
async with proj.events.subscribe(interests=[{"script_name": "summarize"}]) as sub:
|
|
144
|
+
async for evt in sub:
|
|
145
|
+
print(evt)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Heartbeat runs for the lifetime of the subscription only — not automatically on client construction.
|
|
149
|
+
|
|
150
|
+
## Pagination
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
async for script in proj.scripts.list():
|
|
154
|
+
print(script.name)
|
|
155
|
+
|
|
156
|
+
# Or materialise
|
|
157
|
+
scripts = await proj.scripts.list().to_list()
|
|
158
|
+
first = await proj.scripts.list().first()
|
|
159
|
+
top10 = await proj.scripts.list().take(10)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Error handling
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from akribes_sdk import (
|
|
166
|
+
AkribesError, AuthError, NotFoundError, TransientError,
|
|
167
|
+
RateLimitError, ScriptError, AkribesTimeoutError,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
output = await proj.run_and_await("summarize", brief="hi")
|
|
172
|
+
except AuthError: # 401/403
|
|
173
|
+
...
|
|
174
|
+
except NotFoundError: # 404
|
|
175
|
+
...
|
|
176
|
+
except TransientError: # 502/503 (retried by default)
|
|
177
|
+
...
|
|
178
|
+
except RateLimitError: # 429 (retried by default, respects Retry-After)
|
|
179
|
+
...
|
|
180
|
+
except ScriptError as e: # workflow failed; e.error_kind, e.execution_id
|
|
181
|
+
...
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Tokens
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from datetime import timedelta
|
|
188
|
+
minted = await client.tokens.mint(
|
|
189
|
+
scopes={"projects": "*", "role": "admin"},
|
|
190
|
+
expires_in=timedelta(hours=8),
|
|
191
|
+
label="web-session",
|
|
192
|
+
user_email="alice@acme.com",
|
|
193
|
+
)
|
|
194
|
+
print(minted.token) # ship to the browser
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Authentication
|
|
198
|
+
|
|
199
|
+
`AkribesClient` accepts either a **service token** (long-lived, set via
|
|
200
|
+
`AKRIBES_SERVICE_TOKEN_<NAME>=<scope>:<secret>` on the server) or a **scoped
|
|
201
|
+
token** (`akribes_tk_...` — legacy `aura_tk_...` still accepted — minted
|
|
202
|
+
via `client.tokens.mint(...)`).
|
|
203
|
+
|
|
204
|
+
### Prefer `Authorization: Bearer` over `?token=…` (#789)
|
|
205
|
+
|
|
206
|
+
`AkribesClient` always sends the token in the `Authorization` header
|
|
207
|
+
for HTTP requests and WebSocket upgrades. The `?token=…` query-string
|
|
208
|
+
form exists only because browser `EventSource` / `WebSocket`
|
|
209
|
+
constructors cannot set arbitrary headers — treat it as a browser-only
|
|
210
|
+
escape hatch.
|
|
211
|
+
|
|
212
|
+
For CLIs, scripts, and backend services, avoid `?token=…` because:
|
|
213
|
+
|
|
214
|
+
- Reverse proxies, ingress controllers, and CDNs log the full URL
|
|
215
|
+
(including the token) in access logs by default.
|
|
216
|
+
- CI runners (Forgejo Actions, GitHub Actions) echo `curl` commands
|
|
217
|
+
into job logs.
|
|
218
|
+
- Browsers leak `?token=` in the `Referer` header on cross-origin
|
|
219
|
+
sub-resource requests.
|
|
220
|
+
|
|
221
|
+
The server stamps `X-Token-Source: query-param` on responses to any
|
|
222
|
+
request that used the query fallback so operators can chart adoption.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
See `examples/` for runnable end-to-end demos.
|
|
227
|
+
|
|
228
|
+
Upgrading from v0.20.x? See [MIGRATION-0.21.md](./MIGRATION-0.21.md).
|
|
229
|
+
|
|
230
|
+
- Source mirror: <https://github.com/PodestaAI/akribes-sdks>
|
|
231
|
+
- Language guide: <https://akribes.ai/docs>
|
|
232
|
+
- Issues: <https://github.com/PodestaAI/akribes-sdks/issues>
|
|
233
|
+
|
|
234
|
+
## License
|
|
235
|
+
|
|
236
|
+
MIT
|