brime 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.
brime-0.1.0/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ venv/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ htmlcov/
13
+ *.egg
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-05-06
4
+
5
+ Initial release. Beta.
6
+
7
+ ### Added
8
+ - `Brime` synchronous client and `AsyncBrime` asynchronous client
9
+ - `search`, `extract`, `research`, `research_status`, `research_stream` methods
10
+ - Native `/v1/*` endpoint coverage (Brime-native surface — Tavily/Exa/Parallel users should use those vendors' official SDKs against the matching `/tavily/*`, `/exa/*`, `/parallel/*` paths)
11
+ - `research(depth="deep", wait=True)` blocking polling helper with exponential backoff
12
+ - Pydantic v2 response models with full type hints (`py.typed`)
13
+ - Error hierarchy: `BrimeError` → `AuthenticationError`, `RateLimitError`, `InsufficientCreditsError`, `InvalidRequestError`, `NotFoundError`, `UpstreamError`, `InternalError`
14
+ - Auto-generated `Idempotency-Key` for `extract` and deep `research` calls
15
+ - SSE parser with fragmented-chunk and `[DONE]` terminator handling
16
+ - `BRIME_API_KEY` and `BRIME_BASE_URL` env-var fallbacks
brime-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Brime
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.
brime-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,243 @@
1
+ Metadata-Version: 2.4
2
+ Name: brime
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Brime API (search · extract · research)
5
+ Project-URL: Homepage, https://brime.dev
6
+ Project-URL: Documentation, https://docs.brime.dev
7
+ Project-URL: Repository, https://github.com/brime-dev/brime-python
8
+ Project-URL: Issues, https://github.com/brime-dev/brime-python/issues
9
+ Author-email: Brime <support@brime.dev>
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 Brime
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: agents,brime,extract,llm,rag,research,search
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.9
38
+ Classifier: Programming Language :: Python :: 3.10
39
+ Classifier: Programming Language :: Python :: 3.11
40
+ Classifier: Programming Language :: Python :: 3.12
41
+ Classifier: Programming Language :: Python :: 3.13
42
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
43
+ Classifier: Typing :: Typed
44
+ Requires-Python: >=3.9
45
+ Requires-Dist: httpx<1.0,>=0.27
46
+ Requires-Dist: pydantic<3.0,>=2.6
47
+ Provides-Extra: dev
48
+ Requires-Dist: mypy>=1.10; extra == 'dev'
49
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
50
+ Requires-Dist: pytest>=8.0; extra == 'dev'
51
+ Requires-Dist: respx>=0.21; extra == 'dev'
52
+ Requires-Dist: ruff>=0.6; extra == 'dev'
53
+ Description-Content-Type: text/markdown
54
+
55
+ # brime
56
+
57
+ **The live-web toolkit for AI apps.** One API key. One SDK. Search, scrape, and research the open web — clean output, sane defaults, no plumbing.
58
+
59
+ ```bash
60
+ pip install brime
61
+ ```
62
+
63
+ Python 3.9+. Sync and async clients. Fully typed (`py.typed`). Single dependency tree: `httpx` + `pydantic`.
64
+
65
+ ## Why brime?
66
+
67
+ - **One key, three primitives.** `search`, `extract`, `research` — the shape every AI app needs from the web.
68
+ - **Tuned defaults.** No depth selectors, no round counters, no knobs to babysit. The gateway is tuned for you; you pass a query, you get a clean answer.
69
+ - **Drop-in compatible.** Already on Tavily, Exa, or Parallel? Point their SDK at our adapter URL and your code keeps working. Migrate when you're ready.
70
+ - **Honest pricing.** Flat per-call credits. 0.5 for search, 1 per URL for extract, 5 for research. No surprises.
71
+
72
+ ## 30 seconds
73
+
74
+ ```python
75
+ from brime import Brime
76
+
77
+ brime = Brime() # reads BRIME_API_KEY
78
+
79
+ # Live answer + ranked sources, sub-second.
80
+ result = brime.search(query="what changed in the latest TypeScript release")
81
+ print(result.answer)
82
+ ```
83
+
84
+ That's the whole shape. Same pattern for `extract` and `research`.
85
+
86
+ ## What you can build
87
+
88
+ ### Search the open web
89
+
90
+ ```python
91
+ result = brime.search(
92
+ query="tesla earnings",
93
+ topic="finance", # optional: news / general / finance recency hint
94
+ time_range="week", # optional: day / week / month / year
95
+ domains=["sec.gov"], # optional allow-list
96
+ )
97
+ ```
98
+
99
+ ### Turn any URL into clean markdown
100
+
101
+ ```python
102
+ result = brime.extract(urls=[
103
+ "https://example.com",
104
+ "https://en.wikipedia.org/wiki/BM25",
105
+ ])
106
+
107
+ for r in result.results:
108
+ print(r.url, len(r.markdown))
109
+ for f in result.failed:
110
+ print("skipped", f.url, f.error.message)
111
+ ```
112
+
113
+ Handles HTML, PDF, DOCX, and JavaScript-heavy SPAs. The smart-clean pipeline strips chrome, nav, cookie banners, and template noise — what's left is the article.
114
+
115
+ ### Multi-step research with citations
116
+
117
+ ```python
118
+ result = brime.research(
119
+ query="compare frontier coding models with concrete benchmark numbers",
120
+ )
121
+
122
+ print(result.answer)
123
+ print(f"{len(result.sources)} sources cited")
124
+ ```
125
+
126
+ One call, ~30–90 seconds, real synthesis from real sources.
127
+
128
+ Live progress? Stream it:
129
+
130
+ ```python
131
+ for evt in brime.research_stream(query="..."):
132
+ print(evt.event, evt.data)
133
+ if evt.event in ("complete", "error", "timeout"):
134
+ break
135
+ ```
136
+
137
+ ## Authentication
138
+
139
+ ```bash
140
+ export BRIME_API_KEY="sk-brime-..."
141
+ ```
142
+
143
+ ```python
144
+ Brime() # uses BRIME_API_KEY
145
+ Brime(api_key="sk-brime-...") # explicit
146
+ Brime(base_url="https://...") # staging override (or BRIME_BASE_URL env)
147
+ ```
148
+
149
+ Get a key at [brime.dev](https://brime.dev) — the free tier comes with 1,000 credits/month and no card.
150
+
151
+ ## Async
152
+
153
+ Every method is mirrored on `AsyncBrime`:
154
+
155
+ ```python
156
+ import asyncio
157
+ from brime import AsyncBrime
158
+
159
+ async def main():
160
+ async with AsyncBrime() as brime:
161
+ result = await brime.search(query="python async io")
162
+ print(result.answer)
163
+
164
+ asyncio.run(main())
165
+ ```
166
+
167
+ Async streaming works the same way:
168
+
169
+ ```python
170
+ async with AsyncBrime() as brime:
171
+ async for evt in brime.research_stream(query="..."):
172
+ if evt.event == "complete":
173
+ print(evt.data)
174
+ break
175
+ ```
176
+
177
+ ## Error handling
178
+
179
+ Typed exceptions, predictable surface area:
180
+
181
+ ```python
182
+ from brime import (
183
+ BrimeError,
184
+ AuthenticationError,
185
+ RateLimitError,
186
+ InsufficientCreditsError,
187
+ )
188
+
189
+ try:
190
+ brime.search(query="...")
191
+ except AuthenticationError:
192
+ ... # bad key
193
+ except RateLimitError:
194
+ ... # back off
195
+ except InsufficientCreditsError:
196
+ ... # top up
197
+ except BrimeError as e:
198
+ print(e.code, e.message)
199
+ ```
200
+
201
+ ## Idempotency, baked in
202
+
203
+ `extract` calls require an `Idempotency-Key` — the SDK auto-generates one per call so accidental retries never double-charge. Pin it yourself for cross-process dedup:
204
+
205
+ ```python
206
+ brime.extract(
207
+ urls=["https://x"],
208
+ idempotency_key="user-42-prefetch-2026-05",
209
+ )
210
+ ```
211
+
212
+ ## Configuration
213
+
214
+ | Constructor arg | Env var | Default |
215
+ |-----------------|------------------|--------------------------|
216
+ | `api_key` | `BRIME_API_KEY` | — (required) |
217
+ | `base_url` | `BRIME_BASE_URL` | `https://api.brime.dev` |
218
+ | `timeout` | — | `30.0` seconds |
219
+
220
+ Per-call override: `brime.search(query="...", timeout=60)`.
221
+
222
+ ## Already using Tavily, Exa, or Parallel?
223
+
224
+ You don't have to rip them out. Brime exposes wire-compatible adapters:
225
+
226
+ ```python
227
+ TavilyClient(api_key, api_base_url="https://api.brime.dev/tavily")
228
+ Exa(api_key=..., base_url="https://api.brime.dev/exa")
229
+ Parallel(api_key, base_url="https://api.brime.dev/parallel")
230
+ ```
231
+
232
+ Same response shapes, same code. Switch to the native `brime` SDK when you want the extras (research synthesis, SSE streaming, smart-clean extract).
233
+
234
+ ## Links
235
+
236
+ - Docs — [docs.brime.dev](https://docs.brime.dev)
237
+ - API reference — [docs.brime.dev/api-reference](https://docs.brime.dev/api-reference)
238
+ - Status — [brime.dev](https://brime.dev)
239
+ - Issues — [github.com/brime-dev/brime-python/issues](https://github.com/brime-dev/brime-python/issues)
240
+
241
+ ## License
242
+
243
+ MIT © Brime
brime-0.1.0/README.md ADDED
@@ -0,0 +1,189 @@
1
+ # brime
2
+
3
+ **The live-web toolkit for AI apps.** One API key. One SDK. Search, scrape, and research the open web — clean output, sane defaults, no plumbing.
4
+
5
+ ```bash
6
+ pip install brime
7
+ ```
8
+
9
+ Python 3.9+. Sync and async clients. Fully typed (`py.typed`). Single dependency tree: `httpx` + `pydantic`.
10
+
11
+ ## Why brime?
12
+
13
+ - **One key, three primitives.** `search`, `extract`, `research` — the shape every AI app needs from the web.
14
+ - **Tuned defaults.** No depth selectors, no round counters, no knobs to babysit. The gateway is tuned for you; you pass a query, you get a clean answer.
15
+ - **Drop-in compatible.** Already on Tavily, Exa, or Parallel? Point their SDK at our adapter URL and your code keeps working. Migrate when you're ready.
16
+ - **Honest pricing.** Flat per-call credits. 0.5 for search, 1 per URL for extract, 5 for research. No surprises.
17
+
18
+ ## 30 seconds
19
+
20
+ ```python
21
+ from brime import Brime
22
+
23
+ brime = Brime() # reads BRIME_API_KEY
24
+
25
+ # Live answer + ranked sources, sub-second.
26
+ result = brime.search(query="what changed in the latest TypeScript release")
27
+ print(result.answer)
28
+ ```
29
+
30
+ That's the whole shape. Same pattern for `extract` and `research`.
31
+
32
+ ## What you can build
33
+
34
+ ### Search the open web
35
+
36
+ ```python
37
+ result = brime.search(
38
+ query="tesla earnings",
39
+ topic="finance", # optional: news / general / finance recency hint
40
+ time_range="week", # optional: day / week / month / year
41
+ domains=["sec.gov"], # optional allow-list
42
+ )
43
+ ```
44
+
45
+ ### Turn any URL into clean markdown
46
+
47
+ ```python
48
+ result = brime.extract(urls=[
49
+ "https://example.com",
50
+ "https://en.wikipedia.org/wiki/BM25",
51
+ ])
52
+
53
+ for r in result.results:
54
+ print(r.url, len(r.markdown))
55
+ for f in result.failed:
56
+ print("skipped", f.url, f.error.message)
57
+ ```
58
+
59
+ Handles HTML, PDF, DOCX, and JavaScript-heavy SPAs. The smart-clean pipeline strips chrome, nav, cookie banners, and template noise — what's left is the article.
60
+
61
+ ### Multi-step research with citations
62
+
63
+ ```python
64
+ result = brime.research(
65
+ query="compare frontier coding models with concrete benchmark numbers",
66
+ )
67
+
68
+ print(result.answer)
69
+ print(f"{len(result.sources)} sources cited")
70
+ ```
71
+
72
+ One call, ~30–90 seconds, real synthesis from real sources.
73
+
74
+ Live progress? Stream it:
75
+
76
+ ```python
77
+ for evt in brime.research_stream(query="..."):
78
+ print(evt.event, evt.data)
79
+ if evt.event in ("complete", "error", "timeout"):
80
+ break
81
+ ```
82
+
83
+ ## Authentication
84
+
85
+ ```bash
86
+ export BRIME_API_KEY="sk-brime-..."
87
+ ```
88
+
89
+ ```python
90
+ Brime() # uses BRIME_API_KEY
91
+ Brime(api_key="sk-brime-...") # explicit
92
+ Brime(base_url="https://...") # staging override (or BRIME_BASE_URL env)
93
+ ```
94
+
95
+ Get a key at [brime.dev](https://brime.dev) — the free tier comes with 1,000 credits/month and no card.
96
+
97
+ ## Async
98
+
99
+ Every method is mirrored on `AsyncBrime`:
100
+
101
+ ```python
102
+ import asyncio
103
+ from brime import AsyncBrime
104
+
105
+ async def main():
106
+ async with AsyncBrime() as brime:
107
+ result = await brime.search(query="python async io")
108
+ print(result.answer)
109
+
110
+ asyncio.run(main())
111
+ ```
112
+
113
+ Async streaming works the same way:
114
+
115
+ ```python
116
+ async with AsyncBrime() as brime:
117
+ async for evt in brime.research_stream(query="..."):
118
+ if evt.event == "complete":
119
+ print(evt.data)
120
+ break
121
+ ```
122
+
123
+ ## Error handling
124
+
125
+ Typed exceptions, predictable surface area:
126
+
127
+ ```python
128
+ from brime import (
129
+ BrimeError,
130
+ AuthenticationError,
131
+ RateLimitError,
132
+ InsufficientCreditsError,
133
+ )
134
+
135
+ try:
136
+ brime.search(query="...")
137
+ except AuthenticationError:
138
+ ... # bad key
139
+ except RateLimitError:
140
+ ... # back off
141
+ except InsufficientCreditsError:
142
+ ... # top up
143
+ except BrimeError as e:
144
+ print(e.code, e.message)
145
+ ```
146
+
147
+ ## Idempotency, baked in
148
+
149
+ `extract` calls require an `Idempotency-Key` — the SDK auto-generates one per call so accidental retries never double-charge. Pin it yourself for cross-process dedup:
150
+
151
+ ```python
152
+ brime.extract(
153
+ urls=["https://x"],
154
+ idempotency_key="user-42-prefetch-2026-05",
155
+ )
156
+ ```
157
+
158
+ ## Configuration
159
+
160
+ | Constructor arg | Env var | Default |
161
+ |-----------------|------------------|--------------------------|
162
+ | `api_key` | `BRIME_API_KEY` | — (required) |
163
+ | `base_url` | `BRIME_BASE_URL` | `https://api.brime.dev` |
164
+ | `timeout` | — | `30.0` seconds |
165
+
166
+ Per-call override: `brime.search(query="...", timeout=60)`.
167
+
168
+ ## Already using Tavily, Exa, or Parallel?
169
+
170
+ You don't have to rip them out. Brime exposes wire-compatible adapters:
171
+
172
+ ```python
173
+ TavilyClient(api_key, api_base_url="https://api.brime.dev/tavily")
174
+ Exa(api_key=..., base_url="https://api.brime.dev/exa")
175
+ Parallel(api_key, base_url="https://api.brime.dev/parallel")
176
+ ```
177
+
178
+ Same response shapes, same code. Switch to the native `brime` SDK when you want the extras (research synthesis, SSE streaming, smart-clean extract).
179
+
180
+ ## Links
181
+
182
+ - Docs — [docs.brime.dev](https://docs.brime.dev)
183
+ - API reference — [docs.brime.dev/api-reference](https://docs.brime.dev/api-reference)
184
+ - Status — [brime.dev](https://brime.dev)
185
+ - Issues — [github.com/brime-dev/brime-python/issues](https://github.com/brime-dev/brime-python/issues)
186
+
187
+ ## License
188
+
189
+ MIT © Brime
@@ -0,0 +1,71 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "brime"
7
+ version = "0.1.0"
8
+ description = "Official Python SDK for the Brime API (search · extract · research)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "Brime", email = "support@brime.dev" }]
13
+ keywords = ["brime", "search", "extract", "research", "rag", "llm", "agents"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ "Typing :: Typed",
26
+ ]
27
+ dependencies = [
28
+ "httpx>=0.27,<1.0",
29
+ "pydantic>=2.6,<3.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "pytest>=8.0",
35
+ "pytest-asyncio>=0.23",
36
+ "respx>=0.21",
37
+ "mypy>=1.10",
38
+ "ruff>=0.6",
39
+ ]
40
+
41
+ [project.urls]
42
+ Homepage = "https://brime.dev"
43
+ Documentation = "https://docs.brime.dev"
44
+ Repository = "https://github.com/brime-dev/brime-python"
45
+ Issues = "https://github.com/brime-dev/brime-python/issues"
46
+
47
+ [tool.hatch.build.targets.wheel]
48
+ packages = ["src/brime"]
49
+
50
+ [tool.hatch.build.targets.sdist]
51
+ include = ["src/brime", "README.md", "LICENSE", "CHANGELOG.md"]
52
+
53
+ [tool.pytest.ini_options]
54
+ asyncio_mode = "auto"
55
+ markers = [
56
+ "live: marks tests requiring BRIME_API_KEY env var (deselect with -m 'not live')",
57
+ ]
58
+ testpaths = ["tests"]
59
+
60
+ [tool.mypy]
61
+ strict = true
62
+ python_version = "3.9"
63
+ files = ["src/brime"]
64
+
65
+ [tool.ruff]
66
+ line-length = 100
67
+ target-version = "py39"
68
+
69
+ [tool.ruff.lint]
70
+ select = ["E", "F", "I", "B", "UP", "N", "RUF"]
71
+ ignore = ["E501"]
@@ -0,0 +1,58 @@
1
+ """Brime — Official Python SDK."""
2
+
3
+ from brime._version import __version__
4
+ from brime.client import Brime
5
+ from brime.errors import (
6
+ AuthenticationError,
7
+ BrimeError,
8
+ InsufficientCreditsError,
9
+ InternalError,
10
+ InvalidRequestError,
11
+ NotFoundError,
12
+ RateLimitError,
13
+ UpstreamError,
14
+ )
15
+ from brime.models.extract import (
16
+ ExtractFailedItem,
17
+ ExtractMetadata,
18
+ ExtractResponse,
19
+ ExtractResultItem,
20
+ )
21
+ from brime.models.research import (
22
+ ResearchBasicResponse,
23
+ ResearchDeepInitResponse,
24
+ ResearchSseEvent,
25
+ ResearchStatusResponse,
26
+ )
27
+ from brime.models.search import SearchResponse, SearchResultItem
28
+
29
+ __all__ = [
30
+ "__version__",
31
+ "Brime",
32
+ "BrimeError",
33
+ "AuthenticationError",
34
+ "RateLimitError",
35
+ "InsufficientCreditsError",
36
+ "InvalidRequestError",
37
+ "NotFoundError",
38
+ "UpstreamError",
39
+ "InternalError",
40
+ "SearchResponse",
41
+ "SearchResultItem",
42
+ "ExtractResponse",
43
+ "ExtractResultItem",
44
+ "ExtractFailedItem",
45
+ "ExtractMetadata",
46
+ "ResearchBasicResponse",
47
+ "ResearchDeepInitResponse",
48
+ "ResearchStatusResponse",
49
+ "ResearchSseEvent",
50
+ ]
51
+
52
+
53
+ def __getattr__(name: str) -> object: # pragma: no cover
54
+ """Lazy AsyncBrime import (added in S6)."""
55
+ if name == "AsyncBrime":
56
+ from brime.async_client import AsyncBrime
57
+ return AsyncBrime
58
+ raise AttributeError(name)