meshapi 0.1.0__py3-none-any.whl
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.
- meshapi/__init__.py +251 -0
- meshapi/_errors.py +94 -0
- meshapi/_http.py +444 -0
- meshapi/_types.py +573 -0
- meshapi/resources/__init__.py +1 -0
- meshapi/resources/batches.py +60 -0
- meshapi/resources/chat.py +63 -0
- meshapi/resources/compare.py +43 -0
- meshapi/resources/embeddings.py +24 -0
- meshapi/resources/files.py +44 -0
- meshapi/resources/models.py +48 -0
- meshapi/resources/responses.py +43 -0
- meshapi/resources/templates.py +60 -0
- meshapi-0.1.0.dist-info/METADATA +519 -0
- meshapi-0.1.0.dist-info/RECORD +16 -0
- meshapi-0.1.0.dist-info/WHEEL +4 -0
meshapi/__init__.py
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"""MeshAPI Python SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ._errors import MeshAPIError
|
|
8
|
+
from ._http import AsyncHttpClient, MeshAPIConfig, SyncHttpClient
|
|
9
|
+
from ._types import (
|
|
10
|
+
ApiErrorBody,
|
|
11
|
+
ApiErrorEnvelope,
|
|
12
|
+
ChatCompletionChunk,
|
|
13
|
+
ChatCompletionChunkChoice,
|
|
14
|
+
ChatCompletionChunkDelta,
|
|
15
|
+
ChatCompletionChoice,
|
|
16
|
+
ChatCompletionMessage,
|
|
17
|
+
ChatCompletionParams,
|
|
18
|
+
ChatCompletionResponse,
|
|
19
|
+
ChatMessage,
|
|
20
|
+
ChatRole,
|
|
21
|
+
CompareParams,
|
|
22
|
+
CompareResponse,
|
|
23
|
+
CompareStreamEvent,
|
|
24
|
+
ContentPart,
|
|
25
|
+
ContentPartAudio,
|
|
26
|
+
ContentPartImage,
|
|
27
|
+
ContentPartText,
|
|
28
|
+
CreateBatchParams,
|
|
29
|
+
CreateTemplateParams,
|
|
30
|
+
EmbeddingItem,
|
|
31
|
+
EmbeddingsParams,
|
|
32
|
+
EmbeddingsResponse,
|
|
33
|
+
EmbeddingsUsage,
|
|
34
|
+
FileObject,
|
|
35
|
+
ImageDetail,
|
|
36
|
+
ImageOptions,
|
|
37
|
+
InputAudio,
|
|
38
|
+
ListModelsParams,
|
|
39
|
+
ModelOverride,
|
|
40
|
+
ModelInfo,
|
|
41
|
+
ModelPricing,
|
|
42
|
+
BatchListResponse,
|
|
43
|
+
BatchObject,
|
|
44
|
+
BatchRequestItem,
|
|
45
|
+
ProviderPreferences,
|
|
46
|
+
ResponsesFunctionTool,
|
|
47
|
+
ResponsesParams,
|
|
48
|
+
ResponsesResponse,
|
|
49
|
+
ResponsesStreamEvent,
|
|
50
|
+
ResponsesUsage,
|
|
51
|
+
TemplateSummary,
|
|
52
|
+
TokenUsage,
|
|
53
|
+
Tool,
|
|
54
|
+
ToolCall,
|
|
55
|
+
ToolCallFunction,
|
|
56
|
+
ToolChoice,
|
|
57
|
+
ToolChoiceFunction,
|
|
58
|
+
ToolChoiceObject,
|
|
59
|
+
ToolFunction,
|
|
60
|
+
UploadBatchFileParams,
|
|
61
|
+
AudioOutputOptions,
|
|
62
|
+
BuiltinTool,
|
|
63
|
+
UpdateTemplateParams,
|
|
64
|
+
UsageInfo,
|
|
65
|
+
)
|
|
66
|
+
from .resources.batches import AsyncBatchesResource, BatchesResource
|
|
67
|
+
from .resources.chat import AsyncChatResource, ChatResource
|
|
68
|
+
from .resources.compare import AsyncCompareResource, CompareResource
|
|
69
|
+
from .resources.embeddings import AsyncEmbeddingsResource, EmbeddingsResource
|
|
70
|
+
from .resources.files import AsyncFilesResource, FilesResource
|
|
71
|
+
from .resources.models import AsyncModelsResource, ModelsResource
|
|
72
|
+
from .resources.responses import AsyncResponsesResource, ResponsesResource
|
|
73
|
+
from .resources.templates import AsyncTemplatesResource, TemplatesResource
|
|
74
|
+
|
|
75
|
+
__version__ = "0.1.0"
|
|
76
|
+
__all__ = [
|
|
77
|
+
"__version__",
|
|
78
|
+
"MeshAPI",
|
|
79
|
+
"AsyncMeshAPI",
|
|
80
|
+
"MeshAPIConfig",
|
|
81
|
+
"MeshAPIError",
|
|
82
|
+
# types
|
|
83
|
+
"ChatRole",
|
|
84
|
+
"ChatMessage",
|
|
85
|
+
"ContentPart",
|
|
86
|
+
"ContentPartAudio",
|
|
87
|
+
"ContentPartText",
|
|
88
|
+
"ContentPartImage",
|
|
89
|
+
"ImageDetail",
|
|
90
|
+
"InputAudio",
|
|
91
|
+
"ImageOptions",
|
|
92
|
+
"AudioOutputOptions",
|
|
93
|
+
"ToolFunction",
|
|
94
|
+
"Tool",
|
|
95
|
+
"ToolCall",
|
|
96
|
+
"ToolCallFunction",
|
|
97
|
+
"ToolChoice",
|
|
98
|
+
"ToolChoiceFunction",
|
|
99
|
+
"ToolChoiceObject",
|
|
100
|
+
"ChatCompletionParams",
|
|
101
|
+
"ChatCompletionResponse",
|
|
102
|
+
"ChatCompletionChoice",
|
|
103
|
+
"ChatCompletionMessage",
|
|
104
|
+
"ChatCompletionChunk",
|
|
105
|
+
"ChatCompletionChunkChoice",
|
|
106
|
+
"ChatCompletionChunkDelta",
|
|
107
|
+
"UsageInfo",
|
|
108
|
+
"ModelPricing",
|
|
109
|
+
"ModelInfo",
|
|
110
|
+
"ListModelsParams",
|
|
111
|
+
"EmbeddingsParams",
|
|
112
|
+
"EmbeddingItem",
|
|
113
|
+
"EmbeddingsUsage",
|
|
114
|
+
"EmbeddingsResponse",
|
|
115
|
+
"ResponsesFunctionTool",
|
|
116
|
+
"BuiltinTool",
|
|
117
|
+
"ResponsesParams",
|
|
118
|
+
"ResponsesUsage",
|
|
119
|
+
"ResponsesResponse",
|
|
120
|
+
"ResponsesStreamEvent",
|
|
121
|
+
"ModelOverride",
|
|
122
|
+
"CompareParams",
|
|
123
|
+
"TokenUsage",
|
|
124
|
+
"CompareResponse",
|
|
125
|
+
"CompareStreamEvent",
|
|
126
|
+
"BatchRequestItem",
|
|
127
|
+
"UploadBatchFileParams",
|
|
128
|
+
"FileObject",
|
|
129
|
+
"CreateBatchParams",
|
|
130
|
+
"BatchObject",
|
|
131
|
+
"BatchListResponse",
|
|
132
|
+
"ProviderPreferences",
|
|
133
|
+
"CreateTemplateParams",
|
|
134
|
+
"UpdateTemplateParams",
|
|
135
|
+
"TemplateSummary",
|
|
136
|
+
"ApiErrorBody",
|
|
137
|
+
"ApiErrorEnvelope",
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class MeshAPI:
|
|
142
|
+
"""Synchronous MeshAPI client.
|
|
143
|
+
|
|
144
|
+
One instance = one auth realm. Use separate instances for different tokens
|
|
145
|
+
(e.g., ``rsk_`` key for inference, JWT for template management).
|
|
146
|
+
|
|
147
|
+
Example::
|
|
148
|
+
|
|
149
|
+
from meshapi import MeshAPI, ChatCompletionParams, ChatMessage
|
|
150
|
+
|
|
151
|
+
client = MeshAPI(base_url="http://localhost:8000", token="rsk_...")
|
|
152
|
+
resp = client.chat.completions.create(
|
|
153
|
+
ChatCompletionParams(
|
|
154
|
+
model="openai/gpt-4o-mini",
|
|
155
|
+
messages=[ChatMessage(role="user", content="Hello!")],
|
|
156
|
+
)
|
|
157
|
+
)
|
|
158
|
+
print(resp.choices[0].message.content)
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
def __init__(
|
|
162
|
+
self,
|
|
163
|
+
*,
|
|
164
|
+
base_url: str,
|
|
165
|
+
token: str,
|
|
166
|
+
timeout: float = 60.0,
|
|
167
|
+
max_retries: int = 3,
|
|
168
|
+
httpx_client: Any = None,
|
|
169
|
+
) -> None:
|
|
170
|
+
config = MeshAPIConfig(
|
|
171
|
+
base_url=base_url,
|
|
172
|
+
token=token,
|
|
173
|
+
timeout=timeout,
|
|
174
|
+
max_retries=max_retries,
|
|
175
|
+
httpx_client=httpx_client,
|
|
176
|
+
)
|
|
177
|
+
http = SyncHttpClient(config)
|
|
178
|
+
self.chat = ChatResource(http)
|
|
179
|
+
self.responses = ResponsesResource(http)
|
|
180
|
+
self.embeddings = EmbeddingsResource(http)
|
|
181
|
+
self.compare = CompareResource(http)
|
|
182
|
+
self.files = FilesResource(http)
|
|
183
|
+
self.batches = BatchesResource(http)
|
|
184
|
+
self.models = ModelsResource(http)
|
|
185
|
+
self.templates = TemplatesResource(http)
|
|
186
|
+
self._http = http
|
|
187
|
+
|
|
188
|
+
def close(self) -> None:
|
|
189
|
+
self._http.close()
|
|
190
|
+
|
|
191
|
+
def __enter__(self) -> "MeshAPI":
|
|
192
|
+
return self
|
|
193
|
+
|
|
194
|
+
def __exit__(self, *args: Any) -> None:
|
|
195
|
+
self.close()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class AsyncMeshAPI:
|
|
199
|
+
"""Asynchronous MeshAPI client.
|
|
200
|
+
|
|
201
|
+
Example::
|
|
202
|
+
|
|
203
|
+
import asyncio
|
|
204
|
+
from meshapi import AsyncMeshAPI, ChatCompletionParams, ChatMessage
|
|
205
|
+
|
|
206
|
+
async def main():
|
|
207
|
+
async with AsyncMeshAPI(base_url="http://localhost:8000", token="rsk_...") as client:
|
|
208
|
+
resp = await client.chat.completions.create(
|
|
209
|
+
ChatCompletionParams(
|
|
210
|
+
model="openai/gpt-4o-mini",
|
|
211
|
+
messages=[ChatMessage(role="user", content="Hello!")],
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
print(resp.choices[0].message.content)
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
def __init__(
|
|
218
|
+
self,
|
|
219
|
+
*,
|
|
220
|
+
base_url: str,
|
|
221
|
+
token: str,
|
|
222
|
+
timeout: float = 60.0,
|
|
223
|
+
max_retries: int = 3,
|
|
224
|
+
async_httpx_client: Any = None,
|
|
225
|
+
) -> None:
|
|
226
|
+
config = MeshAPIConfig(
|
|
227
|
+
base_url=base_url,
|
|
228
|
+
token=token,
|
|
229
|
+
timeout=timeout,
|
|
230
|
+
max_retries=max_retries,
|
|
231
|
+
async_httpx_client=async_httpx_client,
|
|
232
|
+
)
|
|
233
|
+
http = AsyncHttpClient(config)
|
|
234
|
+
self.chat = AsyncChatResource(http)
|
|
235
|
+
self.responses = AsyncResponsesResource(http)
|
|
236
|
+
self.embeddings = AsyncEmbeddingsResource(http)
|
|
237
|
+
self.compare = AsyncCompareResource(http)
|
|
238
|
+
self.files = AsyncFilesResource(http)
|
|
239
|
+
self.batches = AsyncBatchesResource(http)
|
|
240
|
+
self.models = AsyncModelsResource(http)
|
|
241
|
+
self.templates = AsyncTemplatesResource(http)
|
|
242
|
+
self._http = http
|
|
243
|
+
|
|
244
|
+
async def aclose(self) -> None:
|
|
245
|
+
await self._http.aclose()
|
|
246
|
+
|
|
247
|
+
async def __aenter__(self) -> "AsyncMeshAPI":
|
|
248
|
+
return self
|
|
249
|
+
|
|
250
|
+
async def __aexit__(self, *args: Any) -> None:
|
|
251
|
+
await self.aclose()
|
meshapi/_errors.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""MeshAPI API error type."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
import httpx
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MeshAPIError(Exception):
|
|
12
|
+
"""Raised when MeshAPI returns a non-2xx response or a mid-stream error."""
|
|
13
|
+
|
|
14
|
+
status: int
|
|
15
|
+
error_code: str
|
|
16
|
+
request_id: str
|
|
17
|
+
details: List[Any]
|
|
18
|
+
provider_error: Optional[Dict[str, Any]]
|
|
19
|
+
retry_after_seconds: Optional[int]
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
message: str,
|
|
24
|
+
*,
|
|
25
|
+
status: int,
|
|
26
|
+
error_code: str,
|
|
27
|
+
request_id: str,
|
|
28
|
+
details: Optional[List[Any]] = None,
|
|
29
|
+
provider_error: Optional[Dict[str, Any]] = None,
|
|
30
|
+
retry_after_seconds: Optional[int] = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__(message)
|
|
33
|
+
self.status = status
|
|
34
|
+
self.error_code = error_code
|
|
35
|
+
self.request_id = request_id
|
|
36
|
+
self.details = details or []
|
|
37
|
+
self.provider_error = provider_error
|
|
38
|
+
self.retry_after_seconds = retry_after_seconds
|
|
39
|
+
|
|
40
|
+
def __repr__(self) -> str:
|
|
41
|
+
return (
|
|
42
|
+
f"MeshAPIError(status={self.status!r}, "
|
|
43
|
+
f"error_code={self.error_code!r}, "
|
|
44
|
+
f"request_id={self.request_id!r}, "
|
|
45
|
+
f"message={str(self)!r})"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def from_response(cls, response: "httpx.Response") -> "MeshAPIError":
|
|
50
|
+
"""Parse a MeshAPIError from an httpx Response."""
|
|
51
|
+
status = response.status_code
|
|
52
|
+
content_type = response.headers.get("content-type", "")
|
|
53
|
+
request_id = response.headers.get("x-request-id", "")
|
|
54
|
+
|
|
55
|
+
if "application/json" not in content_type:
|
|
56
|
+
raw = response.text[:500]
|
|
57
|
+
return cls(
|
|
58
|
+
raw or f"HTTP {status}",
|
|
59
|
+
status=status,
|
|
60
|
+
error_code="parse_error",
|
|
61
|
+
request_id=request_id,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
body = response.json()
|
|
66
|
+
error = body.get("error", {})
|
|
67
|
+
request_id = body.get("request_id", request_id)
|
|
68
|
+
return cls(
|
|
69
|
+
error.get("message", f"HTTP {status}"),
|
|
70
|
+
status=status,
|
|
71
|
+
error_code=error.get("code", "unknown_error"),
|
|
72
|
+
request_id=request_id,
|
|
73
|
+
details=error.get("details") or [],
|
|
74
|
+
provider_error=error.get("provider_error"),
|
|
75
|
+
retry_after_seconds=error.get("retry_after_seconds"),
|
|
76
|
+
)
|
|
77
|
+
except Exception:
|
|
78
|
+
raw = response.text[:500]
|
|
79
|
+
return cls(
|
|
80
|
+
raw or f"HTTP {status}",
|
|
81
|
+
status=status,
|
|
82
|
+
error_code="parse_error",
|
|
83
|
+
request_id=request_id,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def stream_interrupted(cls, cause: str) -> "MeshAPIError":
|
|
88
|
+
"""Create an error representing a mid-stream connection failure."""
|
|
89
|
+
return cls(
|
|
90
|
+
f"Stream interrupted: {cause}",
|
|
91
|
+
status=0,
|
|
92
|
+
error_code="stream_interrupted",
|
|
93
|
+
request_id="",
|
|
94
|
+
)
|