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 +13 -0
- brime-0.1.0/CHANGELOG.md +16 -0
- brime-0.1.0/LICENSE +21 -0
- brime-0.1.0/PKG-INFO +243 -0
- brime-0.1.0/README.md +189 -0
- brime-0.1.0/pyproject.toml +71 -0
- brime-0.1.0/src/brime/__init__.py +58 -0
- brime-0.1.0/src/brime/_http.py +99 -0
- brime-0.1.0/src/brime/_polling.py +72 -0
- brime-0.1.0/src/brime/_sse.py +131 -0
- brime-0.1.0/src/brime/_version.py +1 -0
- brime-0.1.0/src/brime/async_client.py +308 -0
- brime-0.1.0/src/brime/client.py +323 -0
- brime-0.1.0/src/brime/errors.py +128 -0
- brime-0.1.0/src/brime/models/__init__.py +0 -0
- brime-0.1.0/src/brime/models/extract.py +64 -0
- brime-0.1.0/src/brime/models/research.py +83 -0
- brime-0.1.0/src/brime/models/search.py +26 -0
- brime-0.1.0/src/brime/py.typed +0 -0
brime-0.1.0/.gitignore
ADDED
brime-0.1.0/CHANGELOG.md
ADDED
|
@@ -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)
|