measyai 2.0.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.
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ htmlcov/
measyai-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MeasyAI
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.
measyai-2.0.0/PKG-INFO ADDED
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.4
2
+ Name: measyai
3
+ Version: 2.0.0
4
+ Summary: Typed Python client for the MeasyAI API — OpenAI-compatible chat completions, streaming, batches and webhook verification.
5
+ Project-URL: Homepage, https://measyai.com
6
+ Project-URL: Documentation, https://docs.measyai.com
7
+ Project-URL: Source, https://github.com/measyai/Python-SDK
8
+ Project-URL: Issues, https://github.com/measyai/Python-SDK/issues
9
+ Project-URL: Changelog, https://github.com/measyai/Python-SDK/releases
10
+ Author-email: MeasyAI <support@measyai.com>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: ai,api-client,chat,llm,measyai,openai,streaming
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: Implementation :: CPython
24
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.9
28
+ Requires-Dist: httpx<1,>=0.27
29
+ Provides-Extra: dev
30
+ Requires-Dist: mypy>=1.11; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
32
+ Requires-Dist: pytest>=8.0; extra == 'dev'
33
+ Requires-Dist: ruff>=0.6; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # MeasyAI Python SDK
37
+
38
+ Python client for the [MeasyAI API](https://docs.measyai.com).
39
+
40
+ ```bash
41
+ pip install measyai
42
+ ```
43
+
44
+ Requires Python 3.9+. One dependency: [httpx](https://www.python-httpx.org/).
45
+
46
+ ## Chat
47
+
48
+ ```python
49
+ from measyai import MeasyAI
50
+
51
+ client = MeasyAI() # reads MEASYAI_API_KEY
52
+
53
+ completion = client.chat.create(
54
+ model="measyai/meridian",
55
+ messages=[{"role": "user", "content": "Explain HTTP/3 briefly."}],
56
+ )
57
+ print(completion.text)
58
+ ```
59
+
60
+ `completion.text` is the first choice's content. The full shape is there
61
+ when you need it — `completion.choices[0].finish_reason`,
62
+ `completion.usage.total_tokens`.
63
+
64
+ ## Streaming
65
+
66
+ `stream()` opens the connection before it returns, so a rejected request
67
+ raises there rather than on the first frame. Iterating yields chunks;
68
+ `text()` yields just the deltas.
69
+
70
+ ```python
71
+ with client.chat.stream(
72
+ messages=[{"role": "user", "content": "Why is Postgres MVCC useful?"}],
73
+ ) as stream:
74
+ for delta in stream.text():
75
+ print(delta, end="", flush=True)
76
+ ```
77
+
78
+ Use it as a context manager. Iterating to the end releases the connection
79
+ on its own, but breaking out early only does so once the iterator is
80
+ collected — `with` makes that immediate.
81
+
82
+ For finish reasons or the closing usage block, iterate the chunks:
83
+
84
+ ```python
85
+ with client.chat.stream(messages=messages) as stream:
86
+ for chunk in stream:
87
+ if chunk.usage:
88
+ print(f"\n{chunk.usage.total_tokens} tokens")
89
+ ```
90
+
91
+ ## Async
92
+
93
+ `AsyncMeasyAI` has the same surface with `await` on the calls and
94
+ `async for` on the streams.
95
+
96
+ ```python
97
+ import asyncio
98
+ from measyai import AsyncMeasyAI
99
+
100
+ async def main() -> None:
101
+ async with AsyncMeasyAI() as client:
102
+ stream = await client.chat.stream(
103
+ messages=[{"role": "user", "content": "Explain QUIC."}],
104
+ )
105
+ async with stream:
106
+ async for delta in stream.text():
107
+ print(delta, end="", flush=True)
108
+
109
+ asyncio.run(main())
110
+ ```
111
+
112
+ ## Unmodelled parameters
113
+
114
+ Anything this package does not model is passed as a keyword argument and
115
+ forwarded to the provider unchanged:
116
+
117
+ ```python
118
+ client.chat.create(
119
+ messages=messages,
120
+ temperature=0.2,
121
+ tools=my_tools,
122
+ response_format={"type": "json_object"},
123
+ )
124
+ ```
125
+
126
+ `model`, `messages` and `stream` are owned by the method signature and are
127
+ refused rather than silently dropped — otherwise `stream=True` would hand
128
+ `create()` an SSE body it then tries to decode as JSON.
129
+
130
+ Response fields this package does not model are kept too: every object
131
+ carries the payload it was built from in `.raw`.
132
+
133
+ ## Batches
134
+
135
+ ```python
136
+ from measyai import BatchRequest
137
+
138
+ batch = client.batches.create([
139
+ BatchRequest(custom_id="row-1", body={"messages": messages}),
140
+ ])
141
+
142
+ done = client.batches.wait(batch.id, interval=5)
143
+ print(f"{done.completed} completed, {done.failed} failed")
144
+
145
+ for item in done.items:
146
+ if item.response:
147
+ print(item.custom_id, item.response.text)
148
+ ```
149
+
150
+ `wait()` polls until the batch is terminal. It waits indefinitely by
151
+ default — a large batch legitimately runs for hours — so pass `timeout=`
152
+ if you want it to give up.
153
+
154
+ ## Webhooks
155
+
156
+ Verify against the **raw** body. Re-encoding a payload you already decoded
157
+ will not reproduce the same bytes, and the check will fail on a delivery
158
+ that was perfectly valid.
159
+
160
+ ```python
161
+ import measyai
162
+
163
+ @app.post("/webhooks/measyai")
164
+ async def receive(request: Request):
165
+ raw = await request.body()
166
+
167
+ if not measyai.verify_webhook(
168
+ secret,
169
+ request.headers[measyai.HEADER_SIGNATURE],
170
+ request.headers[measyai.HEADER_TIMESTAMP],
171
+ raw,
172
+ ):
173
+ raise HTTPException(400)
174
+ ...
175
+ ```
176
+
177
+ The timestamp is signed inside the message and checked against a
178
+ tolerance, so a captured delivery cannot be replayed. The comparison is
179
+ constant-time.
180
+
181
+ ## Errors
182
+
183
+ Everything raised inherits from `MeasyAIError`. Below it the tree forks on
184
+ why the call failed: `APIError` when the API rejected the request,
185
+ `APIConnectionError` when there was never a response.
186
+
187
+ ```python
188
+ from measyai import APIError, MeasyAIError
189
+
190
+ try:
191
+ completion = client.chat.create(messages=messages)
192
+ except APIError as err:
193
+ if err.retryable: # 429 or 5xx — worth backing off
194
+ ...
195
+ print(err.code, err.request_id)
196
+ except MeasyAIError:
197
+ ... # connection, timeout, malformed body
198
+ ```
199
+
200
+ `APIError` also subclasses by status — `AuthenticationError`,
201
+ `RateLimitError`, `NotFoundError` and the rest — so you can catch just the
202
+ case you handle. Branch on `err.code`, which is stable; `err.message` is
203
+ written for humans and may be reworded.
204
+
205
+ Nothing is retried for you. `retryable` tells you when a retry could
206
+ succeed; the backoff policy is yours.
207
+
208
+ ## Configuration
209
+
210
+ ```python
211
+ client = MeasyAI(
212
+ api_key="msy_...", # or MEASYAI_API_KEY
213
+ base_url="http://localhost:8080", # or MEASYAI_BASE_URL
214
+ user_agent="acme-crm/3.1", # appended, for server logs
215
+ timeout=httpx.Timeout(connect=10.0, read=60.0),
216
+ )
217
+ ```
218
+
219
+ The default timeouts bound *stalls*, not total duration — a streamed
220
+ generation legitimately runs for minutes, and an overall deadline would
221
+ cut it off mid-answer.
222
+
223
+ Pass `http_client=` to supply your own `httpx.Client` for a proxy, a
224
+ custom transport or a test double. You keep ownership of it: closing the
225
+ MeasyAI client leaves yours open.
226
+
227
+ Reuse one client for the life of the process. It is safe to share between
228
+ threads, and a client per call throws away the connection pool.
229
+
230
+ ## Using an OpenAI client instead
231
+
232
+ The `/v1` surface is OpenAI-compatible, so the official OpenAI SDK works
233
+ by changing its base URL:
234
+
235
+ ```python
236
+ from openai import OpenAI
237
+
238
+ client = OpenAI(api_key="msy_...", base_url="https://api.measyai.com/v1")
239
+ ```
240
+
241
+ Use this package when you also want batches and webhook verification
242
+ typed.
243
+
244
+ ## Links
245
+
246
+ - [Documentation](https://docs.measyai.com)
247
+ - [Status](https://status.measyai.com)
248
+ - [Go SDK](https://github.com/measyai/Go-SDK)
249
+ - [TypeScript SDK](https://github.com/measyai/NPM-SDK)
250
+
251
+ MIT licensed.
@@ -0,0 +1,216 @@
1
+ # MeasyAI Python SDK
2
+
3
+ Python client for the [MeasyAI API](https://docs.measyai.com).
4
+
5
+ ```bash
6
+ pip install measyai
7
+ ```
8
+
9
+ Requires Python 3.9+. One dependency: [httpx](https://www.python-httpx.org/).
10
+
11
+ ## Chat
12
+
13
+ ```python
14
+ from measyai import MeasyAI
15
+
16
+ client = MeasyAI() # reads MEASYAI_API_KEY
17
+
18
+ completion = client.chat.create(
19
+ model="measyai/meridian",
20
+ messages=[{"role": "user", "content": "Explain HTTP/3 briefly."}],
21
+ )
22
+ print(completion.text)
23
+ ```
24
+
25
+ `completion.text` is the first choice's content. The full shape is there
26
+ when you need it — `completion.choices[0].finish_reason`,
27
+ `completion.usage.total_tokens`.
28
+
29
+ ## Streaming
30
+
31
+ `stream()` opens the connection before it returns, so a rejected request
32
+ raises there rather than on the first frame. Iterating yields chunks;
33
+ `text()` yields just the deltas.
34
+
35
+ ```python
36
+ with client.chat.stream(
37
+ messages=[{"role": "user", "content": "Why is Postgres MVCC useful?"}],
38
+ ) as stream:
39
+ for delta in stream.text():
40
+ print(delta, end="", flush=True)
41
+ ```
42
+
43
+ Use it as a context manager. Iterating to the end releases the connection
44
+ on its own, but breaking out early only does so once the iterator is
45
+ collected — `with` makes that immediate.
46
+
47
+ For finish reasons or the closing usage block, iterate the chunks:
48
+
49
+ ```python
50
+ with client.chat.stream(messages=messages) as stream:
51
+ for chunk in stream:
52
+ if chunk.usage:
53
+ print(f"\n{chunk.usage.total_tokens} tokens")
54
+ ```
55
+
56
+ ## Async
57
+
58
+ `AsyncMeasyAI` has the same surface with `await` on the calls and
59
+ `async for` on the streams.
60
+
61
+ ```python
62
+ import asyncio
63
+ from measyai import AsyncMeasyAI
64
+
65
+ async def main() -> None:
66
+ async with AsyncMeasyAI() as client:
67
+ stream = await client.chat.stream(
68
+ messages=[{"role": "user", "content": "Explain QUIC."}],
69
+ )
70
+ async with stream:
71
+ async for delta in stream.text():
72
+ print(delta, end="", flush=True)
73
+
74
+ asyncio.run(main())
75
+ ```
76
+
77
+ ## Unmodelled parameters
78
+
79
+ Anything this package does not model is passed as a keyword argument and
80
+ forwarded to the provider unchanged:
81
+
82
+ ```python
83
+ client.chat.create(
84
+ messages=messages,
85
+ temperature=0.2,
86
+ tools=my_tools,
87
+ response_format={"type": "json_object"},
88
+ )
89
+ ```
90
+
91
+ `model`, `messages` and `stream` are owned by the method signature and are
92
+ refused rather than silently dropped — otherwise `stream=True` would hand
93
+ `create()` an SSE body it then tries to decode as JSON.
94
+
95
+ Response fields this package does not model are kept too: every object
96
+ carries the payload it was built from in `.raw`.
97
+
98
+ ## Batches
99
+
100
+ ```python
101
+ from measyai import BatchRequest
102
+
103
+ batch = client.batches.create([
104
+ BatchRequest(custom_id="row-1", body={"messages": messages}),
105
+ ])
106
+
107
+ done = client.batches.wait(batch.id, interval=5)
108
+ print(f"{done.completed} completed, {done.failed} failed")
109
+
110
+ for item in done.items:
111
+ if item.response:
112
+ print(item.custom_id, item.response.text)
113
+ ```
114
+
115
+ `wait()` polls until the batch is terminal. It waits indefinitely by
116
+ default — a large batch legitimately runs for hours — so pass `timeout=`
117
+ if you want it to give up.
118
+
119
+ ## Webhooks
120
+
121
+ Verify against the **raw** body. Re-encoding a payload you already decoded
122
+ will not reproduce the same bytes, and the check will fail on a delivery
123
+ that was perfectly valid.
124
+
125
+ ```python
126
+ import measyai
127
+
128
+ @app.post("/webhooks/measyai")
129
+ async def receive(request: Request):
130
+ raw = await request.body()
131
+
132
+ if not measyai.verify_webhook(
133
+ secret,
134
+ request.headers[measyai.HEADER_SIGNATURE],
135
+ request.headers[measyai.HEADER_TIMESTAMP],
136
+ raw,
137
+ ):
138
+ raise HTTPException(400)
139
+ ...
140
+ ```
141
+
142
+ The timestamp is signed inside the message and checked against a
143
+ tolerance, so a captured delivery cannot be replayed. The comparison is
144
+ constant-time.
145
+
146
+ ## Errors
147
+
148
+ Everything raised inherits from `MeasyAIError`. Below it the tree forks on
149
+ why the call failed: `APIError` when the API rejected the request,
150
+ `APIConnectionError` when there was never a response.
151
+
152
+ ```python
153
+ from measyai import APIError, MeasyAIError
154
+
155
+ try:
156
+ completion = client.chat.create(messages=messages)
157
+ except APIError as err:
158
+ if err.retryable: # 429 or 5xx — worth backing off
159
+ ...
160
+ print(err.code, err.request_id)
161
+ except MeasyAIError:
162
+ ... # connection, timeout, malformed body
163
+ ```
164
+
165
+ `APIError` also subclasses by status — `AuthenticationError`,
166
+ `RateLimitError`, `NotFoundError` and the rest — so you can catch just the
167
+ case you handle. Branch on `err.code`, which is stable; `err.message` is
168
+ written for humans and may be reworded.
169
+
170
+ Nothing is retried for you. `retryable` tells you when a retry could
171
+ succeed; the backoff policy is yours.
172
+
173
+ ## Configuration
174
+
175
+ ```python
176
+ client = MeasyAI(
177
+ api_key="msy_...", # or MEASYAI_API_KEY
178
+ base_url="http://localhost:8080", # or MEASYAI_BASE_URL
179
+ user_agent="acme-crm/3.1", # appended, for server logs
180
+ timeout=httpx.Timeout(connect=10.0, read=60.0),
181
+ )
182
+ ```
183
+
184
+ The default timeouts bound *stalls*, not total duration — a streamed
185
+ generation legitimately runs for minutes, and an overall deadline would
186
+ cut it off mid-answer.
187
+
188
+ Pass `http_client=` to supply your own `httpx.Client` for a proxy, a
189
+ custom transport or a test double. You keep ownership of it: closing the
190
+ MeasyAI client leaves yours open.
191
+
192
+ Reuse one client for the life of the process. It is safe to share between
193
+ threads, and a client per call throws away the connection pool.
194
+
195
+ ## Using an OpenAI client instead
196
+
197
+ The `/v1` surface is OpenAI-compatible, so the official OpenAI SDK works
198
+ by changing its base URL:
199
+
200
+ ```python
201
+ from openai import OpenAI
202
+
203
+ client = OpenAI(api_key="msy_...", base_url="https://api.measyai.com/v1")
204
+ ```
205
+
206
+ Use this package when you also want batches and webhook verification
207
+ typed.
208
+
209
+ ## Links
210
+
211
+ - [Documentation](https://docs.measyai.com)
212
+ - [Status](https://status.measyai.com)
213
+ - [Go SDK](https://github.com/measyai/Go-SDK)
214
+ - [TypeScript SDK](https://github.com/measyai/NPM-SDK)
215
+
216
+ MIT licensed.
@@ -0,0 +1,104 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.27"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "measyai"
7
+ description = "Typed Python client for the MeasyAI API — OpenAI-compatible chat completions, streaming, batches and webhook verification."
8
+ readme = "README.md"
9
+ license = "MIT"
10
+ license-files = ["LICENSE"]
11
+ requires-python = ">=3.9"
12
+ dynamic = ["version"]
13
+ authors = [{ name = "MeasyAI", email = "support@measyai.com" }]
14
+ keywords = ["measyai", "ai", "llm", "chat", "streaming", "openai", "api-client"]
15
+ classifiers = [
16
+ "Development Status :: 5 - Production/Stable",
17
+ "Intended Audience :: Developers",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: Implementation :: CPython",
26
+ "Programming Language :: Python :: Implementation :: PyPy",
27
+ "Topic :: Software Development :: Libraries :: Python Modules",
28
+ "Typing :: Typed",
29
+ ]
30
+ dependencies = ["httpx>=0.27,<1"]
31
+
32
+ [project.urls]
33
+ Homepage = "https://measyai.com"
34
+ Documentation = "https://docs.measyai.com"
35
+ Source = "https://github.com/measyai/Python-SDK"
36
+ Issues = "https://github.com/measyai/Python-SDK/issues"
37
+ Changelog = "https://github.com/measyai/Python-SDK/releases"
38
+
39
+ [project.optional-dependencies]
40
+ dev = [
41
+ "pytest>=8.0",
42
+ "pytest-asyncio>=0.24",
43
+ "mypy>=1.11",
44
+ "ruff>=0.6",
45
+ ]
46
+
47
+ [tool.hatch.version]
48
+ path = "src/measyai/_version.py"
49
+
50
+ [tool.hatch.build.targets.sdist]
51
+ # The wheel is the package; the sdist adds what you need to rebuild and
52
+ # verify it, and nothing else.
53
+ include = ["src/measyai", "tests", "README.md", "LICENSE", "pyproject.toml"]
54
+
55
+ [tool.hatch.build.targets.wheel]
56
+ packages = ["src/measyai"]
57
+
58
+ [tool.pytest.ini_options]
59
+ testpaths = ["tests"]
60
+ asyncio_mode = "auto"
61
+ asyncio_default_fixture_loop_scope = "function"
62
+ filterwarnings = ["error"]
63
+
64
+ [tool.ruff]
65
+ line-length = 88
66
+ target-version = "py39"
67
+ src = ["src", "tests"]
68
+
69
+ [tool.ruff.format]
70
+ # Ruff would reformat the Python inside the README's fences, which is
71
+ # written for reading rather than for a formatter.
72
+ exclude = ["*.md"]
73
+
74
+ [tool.ruff.lint]
75
+ select = ["E", "F", "W", "I", "UP", "B", "C4", "SIM", "RUF"]
76
+ ignore = [
77
+ # The package supports 3.9, so `typing.Optional`/`Dict`/`Type` and
78
+ # `typing.Union` stay. PEP 604 and PEP 585 spellings are only safe in
79
+ # annotation positions here (`from __future__ import annotations`),
80
+ # and using one spelling in annotations and another in the runtime
81
+ # positions next to them reads as an inconsistency rather than as the
82
+ # version boundary it actually is.
83
+ "UP006",
84
+ "UP007",
85
+ "UP035",
86
+ "UP045",
87
+ # `datetime.timezone.utc` over `datetime.UTC`: the latter is 3.11+.
88
+ "UP017",
89
+ ]
90
+
91
+ [tool.ruff.lint.isort]
92
+ # `tests` is a package here so `tests.conftest` imports the same way
93
+ # under pytest as it does under the linter.
94
+ known-first-party = ["measyai", "tests"]
95
+
96
+ [tool.ruff.lint.per-file-ignores]
97
+ "tests/*" = ["B011"]
98
+
99
+ [tool.mypy]
100
+ # No `python_version` pin: current mypy refuses 3.9, and the pytest matrix
101
+ # is what actually proves the package still runs there.
102
+ strict = true
103
+ warn_unreachable = true
104
+ files = ["src/measyai"]
@@ -0,0 +1,102 @@
1
+ """Python client for the MeasyAI API.
2
+
3
+ The `/v1` surface is OpenAI-compatible, so the official OpenAI SDK works
4
+ by pointing its `base_url` at `https://api.measyai.com/v1`. Use this
5
+ package when you also want the endpoints OpenAI has no equivalent for —
6
+ batches and webhook verification — typed.
7
+
8
+ ```python
9
+ from measyai import MeasyAI
10
+
11
+ client = MeasyAI() # reads MEASYAI_API_KEY
12
+
13
+ with client.chat.stream(
14
+ model="measyai/meridian",
15
+ messages=[{"role": "user", "content": "Explain HTTP/3 briefly."}],
16
+ ) as stream:
17
+ for delta in stream.text():
18
+ print(delta, end="", flush=True)
19
+ ```
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from ._client import DEFAULT_BASE_URL, DEFAULT_TIMEOUT, AsyncMeasyAI, MeasyAI
25
+ from ._version import __version__
26
+ from .errors import (
27
+ APIConnectionError,
28
+ APIError,
29
+ APITimeoutError,
30
+ AuthenticationError,
31
+ BadRequestError,
32
+ ConflictError,
33
+ InternalServerError,
34
+ MeasyAIError,
35
+ NotFoundError,
36
+ PermissionDeniedError,
37
+ RateLimitError,
38
+ )
39
+ from .resources import AsyncChatStream, ChatStream
40
+ from .types import (
41
+ Batch,
42
+ BatchItem,
43
+ BatchRequest,
44
+ BatchWithItems,
45
+ ChatCompletion,
46
+ ChatCompletionChunk,
47
+ Choice,
48
+ ChunkChoice,
49
+ ChunkDelta,
50
+ Message,
51
+ Model,
52
+ Usage,
53
+ )
54
+ from .webhooks import (
55
+ DEFAULT_TOLERANCE,
56
+ HEADER_DELIVERY,
57
+ HEADER_EVENT,
58
+ HEADER_SIGNATURE,
59
+ HEADER_TIMESTAMP,
60
+ sign_webhook,
61
+ verify_webhook,
62
+ )
63
+
64
+ __all__ = [
65
+ "DEFAULT_BASE_URL",
66
+ "DEFAULT_TIMEOUT",
67
+ "DEFAULT_TOLERANCE",
68
+ "HEADER_DELIVERY",
69
+ "HEADER_EVENT",
70
+ "HEADER_SIGNATURE",
71
+ "HEADER_TIMESTAMP",
72
+ "APIConnectionError",
73
+ "APIError",
74
+ "APITimeoutError",
75
+ "AsyncChatStream",
76
+ "AsyncMeasyAI",
77
+ "AuthenticationError",
78
+ "BadRequestError",
79
+ "Batch",
80
+ "BatchItem",
81
+ "BatchRequest",
82
+ "BatchWithItems",
83
+ "ChatCompletion",
84
+ "ChatCompletionChunk",
85
+ "ChatStream",
86
+ "Choice",
87
+ "ChunkChoice",
88
+ "ChunkDelta",
89
+ "ConflictError",
90
+ "InternalServerError",
91
+ "MeasyAI",
92
+ "MeasyAIError",
93
+ "Message",
94
+ "Model",
95
+ "NotFoundError",
96
+ "PermissionDeniedError",
97
+ "RateLimitError",
98
+ "Usage",
99
+ "__version__",
100
+ "sign_webhook",
101
+ "verify_webhook",
102
+ ]