blazing-agents 0.1.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.
Files changed (40) hide show
  1. blazing_agents-0.1.0/.github/workflows/ci.yml +45 -0
  2. blazing_agents-0.1.0/.github/workflows/publish.yml +27 -0
  3. blazing_agents-0.1.0/.gitignore +7 -0
  4. blazing_agents-0.1.0/LICENSE +21 -0
  5. blazing_agents-0.1.0/PKG-INFO +340 -0
  6. blazing_agents-0.1.0/README.md +327 -0
  7. blazing_agents-0.1.0/pyproject.toml +55 -0
  8. blazing_agents-0.1.0/scripts/run_compatibility.py +56 -0
  9. blazing_agents-0.1.0/scripts/run_integration.py +169 -0
  10. blazing_agents-0.1.0/scripts/run_tests.py +188 -0
  11. blazing_agents-0.1.0/scripts/run_typechecks.py +68 -0
  12. blazing_agents-0.1.0/src/blazing_agents/__init__.py +312 -0
  13. blazing_agents-0.1.0/src/blazing_agents/_chat.py +138 -0
  14. blazing_agents-0.1.0/src/blazing_agents/_client.py +782 -0
  15. blazing_agents-0.1.0/src/blazing_agents/_completion.py +165 -0
  16. blazing_agents-0.1.0/src/blazing_agents/_downloads.py +105 -0
  17. blazing_agents-0.1.0/src/blazing_agents/_errors.py +104 -0
  18. blazing_agents-0.1.0/src/blazing_agents/_models.py +883 -0
  19. blazing_agents-0.1.0/src/blazing_agents/_object.py +229 -0
  20. blazing_agents-0.1.0/src/blazing_agents/_resources.py +4616 -0
  21. blazing_agents-0.1.0/src/blazing_agents/_responses.py +16 -0
  22. blazing_agents-0.1.0/src/blazing_agents/_transport.py +784 -0
  23. blazing_agents-0.1.0/src/blazing_agents/_types.py +479 -0
  24. blazing_agents-0.1.0/src/blazing_agents/_version.py +3 -0
  25. blazing_agents-0.1.0/src/blazing_agents/py.typed +1 -0
  26. blazing_agents-0.1.0/tests/test_clients.py +6798 -0
  27. blazing_agents-0.1.0/tests/test_response_observation.py +471 -0
  28. blazing_agents-0.1.0/typing/invalid_agent_configuration.py +7 -0
  29. blazing_agents-0.1.0/typing/invalid_ambiguous.py +15 -0
  30. blazing_agents-0.1.0/typing/invalid_artifacts_user_id.py +3 -0
  31. blazing_agents-0.1.0/typing/invalid_chat_regenerate.py +7 -0
  32. blazing_agents-0.1.0/typing/invalid_chat_regenerate_client.py +17 -0
  33. blazing_agents-0.1.0/typing/invalid_chat_version.py +8 -0
  34. blazing_agents-0.1.0/typing/invalid_request_literal.py +6 -0
  35. blazing_agents-0.1.0/typing/invalid_request_unknown.py +6 -0
  36. blazing_agents-0.1.0/typing/invalid_simultaneous.py +31 -0
  37. blazing_agents-0.1.0/typing/invalid_workspace_none.py +11 -0
  38. blazing_agents-0.1.0/typing/invalid_workspace_none_request.py +7 -0
  39. blazing_agents-0.1.0/typing/valid.py +342 -0
  40. blazing_agents-0.1.0/uv.lock +663 -0
@@ -0,0 +1,45 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ check:
17
+ name: Check
18
+ runs-on: ubuntu-latest
19
+ timeout-minutes: 15
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
23
+ with:
24
+ enable-cache: true
25
+ - run: uv sync --locked
26
+ - run: uv run ruff check .
27
+ - run: uv run ruff format --check .
28
+ - run: uv run python scripts/run_typechecks.py
29
+ - run: uv run python scripts/run_tests.py
30
+
31
+ compatibility:
32
+ name: Python ${{ matrix.python-version }}
33
+ runs-on: ubuntu-latest
34
+ timeout-minutes: 15
35
+ strategy:
36
+ fail-fast: false
37
+ matrix:
38
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
39
+ steps:
40
+ - uses: actions/checkout@v6
41
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
42
+ with:
43
+ enable-cache: true
44
+ python-version: ${{ matrix.python-version }}
45
+ - run: uv run --python ${{ matrix.python-version }} python scripts/run_compatibility.py
@@ -0,0 +1,27 @@
1
+ name: Publish
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ publish:
12
+ if: ${{ !github.event.release.prerelease }}
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 15
15
+ environment: pypi
16
+ permissions:
17
+ id-token: write
18
+ steps:
19
+ - uses: actions/checkout@v6
20
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
21
+ - name: Verify release tag matches package version
22
+ run: >-
23
+ python -c 'import os, tomllib;
24
+ version = tomllib.load(open("pyproject.toml", "rb"))["project"]["version"];
25
+ assert f"v{version}" == os.environ["GITHUB_REF_NAME"]'
26
+ - run: uv build
27
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,7 @@
1
+ .mypy_cache/
2
+ .pytest_cache/
3
+ .ruff_cache/
4
+ .venv/
5
+ .DS_Store
6
+ __pycache__/
7
+ *.py[cod]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Blazing Agents
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,340 @@
1
+ Metadata-Version: 2.5
2
+ Name: blazing_agents
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for Blazing Agents
5
+ Project-URL: Documentation, https://docs.blazingagents.com
6
+ Project-URL: Repository, https://github.com/blazingagents/python-sdk
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Requires-Python: >=3.11
10
+ Requires-Dist: httpx<1,>=0.27
11
+ Requires-Dist: pydantic<3,>=2
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Blazing Agents Python SDK
15
+
16
+ The official backend SDK for the Blazing Agents `/v1` API. It provides native
17
+ synchronous and asynchronous clients, typed Pydantic responses, lazy
18
+ pagination, binary transfers, and one-owner generation streams.
19
+
20
+ ## Installation
21
+
22
+ Blazing Agents supports CPython 3.11 and newer.
23
+
24
+ ```console
25
+ pip install blazing_agents
26
+ ```
27
+
28
+ Create a Tenant API key in the Blazing Agents dashboard. Pass it explicitly or
29
+ set `BLAZING_AGENTS_API_KEY`; an explicit key takes precedence.
30
+
31
+ ```python
32
+ from blazing_agents import BlazingAgents
33
+
34
+ with BlazingAgents(api_key="ba_...") as client:
35
+ tenant = client.tenant.get()
36
+ print(tenant.name)
37
+ ```
38
+
39
+ The production API origin is `https://api.blazingagents.com`. Use `base_url`
40
+ only for an intentional alternative deployment:
41
+
42
+ ```python
43
+ client = BlazingAgents(
44
+ api_key="ba_...",
45
+ base_url="http://127.0.0.1:8787",
46
+ timeout=30.0,
47
+ on_response=lambda response: print(response.request_id, response.status),
48
+ )
49
+ ```
50
+
51
+ Generation methods accept `client_request_id` for caller-owned correlation
52
+ without raw headers. Use `client.with_options(client_request_id=...)` to
53
+ correlate any resource or generation request through a scoped client view.
54
+ `on_response` receives method, path without query,
55
+ status, duration, server request ID, and the optional client request ID once
56
+ for every received response, including errors and streaming handshakes.
57
+ Callback failures are ignored, and failures with no HTTP response do not
58
+ invoke it. Retain the server-owned `request_id` when contacting support; each
59
+ retry receives a different value.
60
+
61
+ Tenant API-key creation, rotation, and revocation are dashboard-only and are
62
+ not exposed by this backend SDK.
63
+
64
+ ## Sync and async clients
65
+
66
+ `BlazingAgents` and `AsyncBlazingAgents` expose the same resources and
67
+ generation behavior. The async client uses HTTPX asynchronously throughout; it
68
+ does not run synchronous calls through an event loop bridge.
69
+
70
+ ```python
71
+ from blazing_agents import AsyncBlazingAgents
72
+
73
+
74
+ async def show_tenant() -> None:
75
+ async with AsyncBlazingAgents(api_key="ba_...") as client:
76
+ tenant = await client.tenant.get()
77
+ print(tenant.name)
78
+ ```
79
+
80
+ Context managers close transports created by the SDK. When injecting an
81
+ `httpx.Client` or `httpx.AsyncClient`, the caller retains ownership and must
82
+ close it.
83
+
84
+ ## Resources
85
+
86
+ Both clients expose these resource groups:
87
+
88
+ | Resource | Operations |
89
+ | --- | --- |
90
+ | `agents` | Create, list, get, update, disable, enable, delete, versions, restore, MCP attachments, avatar upload/removal |
91
+ | `workspaces` | Create, list, iterate, get, update, delete |
92
+ | `agent(agent_id).skills` | Create/upload, list, iterate, get, delete, read/replace/delete files, copy |
93
+ | `providers` | Create, list, get, update, delete, and discover models |
94
+ | `mcp_connections` | Connect, create, list, get, update, delete, test, reconnect |
95
+ | `prompts` | Create, list, get, update, delete |
96
+ | `memories` | Create, list, iterate, get, update, delete |
97
+ | `sessions` | List, iterate, messages, Tool approvals and continuations, delete |
98
+ | `artifacts` | List, iterate, download URL, buffered/streaming download, delete |
99
+ | `tasks` | Create, list, iterate, get, update, delete, submit, runs, messages, cancel |
100
+ | `usage` | Tenant or Agent usage |
101
+ | `tenant` | Get and update Tenant settings |
102
+
103
+ Writes use keyword-only snake-case parameters. SDK-owned names are translated
104
+ to camel case on the wire; keys inside metadata, message parts, variables, and
105
+ JSON Schema remain unchanged. Omitted values are not sent, while explicit
106
+ `None` is sent as JSON null.
107
+
108
+ Returned objects are strict Pydantic v2 models for documented fields and retain
109
+ unknown server fields in `model_extra`. Successful models expose the
110
+ non-serialized `_request_id` correlation attribute.
111
+
112
+ Every Agent has a Workspace. Omitting `workspace_id` when creating an Agent
113
+ creates its default Workspace; passing an existing ID shares that Workspace.
114
+ Updates accept another concrete Workspace ID, and deleting an Agent preserves
115
+ its Workspace for explicit deletion or reuse.
116
+
117
+ An Agent may be created without a Provider configuration. To configure one,
118
+ pass both `provider_id` and `model`. Updates may replace only the model, replace
119
+ both values, or clear the configuration by passing `None` for both values.
120
+
121
+ ## Pagination
122
+
123
+ Cursor resources provide a page-level `list()` and a lazy `iter()`. Iteration
124
+ requests another page only when it is needed.
125
+
126
+ ```python
127
+ with BlazingAgents(api_key="ba_...") as client:
128
+ page = client.sessions.list(agent_id="ag_...", limit=25)
129
+ print(page.data, page.next_cursor)
130
+
131
+ for session in client.sessions.iter(agent_id="ag_...", limit=25):
132
+ print(session.id)
133
+ ```
134
+
135
+ Async resource iterators are consumed with `async for`:
136
+
137
+ ```python
138
+ async with AsyncBlazingAgents(api_key="ba_...") as client:
139
+ sessions = client.sessions.iter(agent_id="ag_...", limit=25)
140
+ async for session in sessions:
141
+ print(session.id)
142
+ ```
143
+
144
+ Task pages support the same lazy pagination with `agent_id`, `cursor`, and
145
+ `limit` filters:
146
+
147
+ ```python
148
+ with BlazingAgents(api_key="ba_...") as client:
149
+ page = client.tasks.list(
150
+ agent_id="ag_...",
151
+ cursor="next-page-token",
152
+ limit=25,
153
+ )
154
+ for task in client.tasks.iter(agent_id="ag_...", limit=25):
155
+ print(task.id)
156
+ ```
157
+
158
+ ## Binary transfer
159
+
160
+ Uploads accept `bytes`, a path-like value, or a readable binary file. The SDK
161
+ closes a file it opens from a path and leaves caller-owned file objects open.
162
+
163
+ ```python
164
+ with BlazingAgents(api_key="ba_...") as client:
165
+ client.agents.upload_avatar("ag_...", file="avatar.png")
166
+ client.agent("ag_...").skills.replace_file(
167
+ skill_id="skill_...",
168
+ path="assets/config.bin",
169
+ content=b"\x00\x01",
170
+ )
171
+ ```
172
+
173
+ Artifact metadata and management are Tenant-level. Create a five-minute
174
+ presigned R2 URL, then fetch the immutable bytes directly:
175
+
176
+ ```python
177
+ with BlazingAgents(api_key="ba_...") as client:
178
+ artifact = client.artifacts.get(
179
+ artifact_id="at_...",
180
+ )
181
+ download = client.artifacts.create_download_url(
182
+ artifact_id=artifact.artifact_id,
183
+ )
184
+ print(download.url, download.expires_at)
185
+ ```
186
+
187
+ Use `await async_client.artifacts.create_download_url(...)` with the async
188
+ client. Keep presigned URLs out of logs and referrers.
189
+
190
+ ## Chat relay
191
+
192
+ `chat()` returns the server's exact SSE bytes. The SDK does not decode or
193
+ re-encode AI SDK `UIMessageChunk` values, so a backend can relay each byte
194
+ chunk unchanged.
195
+
196
+ ```python
197
+ with BlazingAgents(api_key="ba_...") as client:
198
+ with client.chat(
199
+ agent_id="ag_...",
200
+ message={"id": "message-1", "role": "user", "parts": []},
201
+ ) as stream:
202
+ print(stream.status_code, stream.session_id, stream.request_id)
203
+ for chunk in stream:
204
+ relay(chunk)
205
+ ```
206
+
207
+ For a new Session, `session_id` is resolved from the response `Location`
208
+ header. Pass that ID to a later `chat(..., session_id=session_id)` call to
209
+ resume. Status, headers, request ID, and Session ID are available before body
210
+ consumption. `trigger="regenerate-message"` requires an existing `session_id`;
211
+ `message_id` is optional for that regeneration request.
212
+
213
+ ## Completion
214
+
215
+ `completion()` buffers plain text. `completion_stream()` yields decoded text
216
+ deltas, and `get_final_text()` drains any unread remainder before returning the
217
+ complete correlated value.
218
+
219
+ ```python
220
+ with BlazingAgents(api_key="ba_...") as client:
221
+ result = client.completion(agent_id="ag_...", prompt="Summarize this")
222
+ print(str(result), result.request_id)
223
+
224
+ with client.completion_stream(
225
+ agent_id="ag_...",
226
+ prompt="Write a release note",
227
+ ) as stream:
228
+ for delta in stream:
229
+ print(delta, end="")
230
+ final = stream.get_final_text()
231
+ ```
232
+
233
+ ## Structured objects
234
+
235
+ Pass either a Pydantic-compatible `output_type` or a raw `json_schema`, but not
236
+ both. A typed result is inferred from `output_type`.
237
+
238
+ ```python
239
+ from pydantic import BaseModel
240
+
241
+
242
+ class Summary(BaseModel):
243
+ title: str
244
+ risks: list[str]
245
+
246
+
247
+ with BlazingAgents(api_key="ba_...") as client:
248
+ summary = client.object(
249
+ agent_id="ag_...",
250
+ prompt="Summarize the release",
251
+ output_type=Summary,
252
+ )
253
+ ```
254
+
255
+ `object_stream()` yields raw JSON text deltas. It does not construct partial
256
+ models. `get_final_object()` drains the remainder and validates only after
257
+ successful terminal completion:
258
+
259
+ ```python
260
+ with BlazingAgents(api_key="ba_...") as client:
261
+ with client.object_stream(
262
+ agent_id="ag_...",
263
+ prompt="Summarize the release",
264
+ output_type=Summary,
265
+ ) as stream:
266
+ for json_delta in stream:
267
+ print(json_delta, end="")
268
+ summary = stream.get_final_object()
269
+ ```
270
+
271
+ ## Errors, timeouts, and retries
272
+
273
+ ```python
274
+ from blazing_agents import (
275
+ APIConnectionError,
276
+ APIStatusError,
277
+ APITimeoutError,
278
+ StreamError,
279
+ )
280
+
281
+ with BlazingAgents(api_key="ba_...") as client:
282
+ try:
283
+ client.agents.get("ag_...")
284
+ except APIStatusError as error:
285
+ print(error.status_code, error.code, error.request_id, error.retry_after)
286
+ except APITimeoutError:
287
+ ...
288
+ except APIConnectionError:
289
+ ...
290
+ except StreamError:
291
+ ...
292
+ ```
293
+
294
+ `APIStatusError` retains response headers, the server error code, details,
295
+ parameter, request ID, retry information, and the safe response body.
296
+ Cancellation, `KeyboardInterrupt`, and `SystemExit` are not wrapped.
297
+
298
+ Ordinary operations default to 60 seconds. Set `timeout` on a client or an
299
+ individual operation; use `None` to disable it. Streaming responses retain
300
+ connect, write, and pool timeouts but deliberately have no SDK read deadline.
301
+ The SDK performs no automatic retries or implicit idempotency. Task submission
302
+ accepts an explicit `idempotency_key` because that operation defines one.
303
+
304
+ ## Stream and security ownership
305
+
306
+ Every binary, chat, completion, and object stream has one consumer. Exhaustion
307
+ closes it automatically. Early exit requires `close()` or `aclose()`, normally
308
+ through a context manager. Closing an active chat or generation stream
309
+ propagates cancellation; closing an admitted durable Tool continuation only
310
+ detaches.
311
+
312
+ The SDK is silent by default, sends no telemetry or background analytics, and
313
+ starts no background tasks. If the host enables the `blazing_agents` logger at
314
+ debug level, records contain only HTTP method, path without query parameters,
315
+ status, elapsed time, and request ID. Credentials, headers, query values,
316
+ bodies, schemas, file data, and stream content are never logged.
317
+
318
+ ## Verification commands
319
+
320
+ The package checks are self-contained and do not require Supabase:
321
+
322
+ ```console
323
+ uv sync --locked
324
+ uv run ruff check .
325
+ uv run ruff format --check .
326
+ uv run python scripts/run_typechecks.py
327
+ uv run python scripts/run_tests.py
328
+ ```
329
+
330
+ These commands build and test the installed wheel, enforce the 99% line, branch,
331
+ function, and statement thresholds, runs Pyright and mypy, and checks Ruff.
332
+ Interpreter compatibility uses the same installed-wheel behavioral suite for
333
+ each supported Python version:
334
+
335
+ ```console
336
+ uv run --python 3.11 python scripts/run_compatibility.py
337
+ ```
338
+
339
+ Repeat the compatibility command with Python 3.12, 3.13, and 3.14. The
340
+ platform integration suite remains in the private platform repository.