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 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
+ )