singularity-grid 0.1.0__tar.gz → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: singularity-grid
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Python SDK for the SGL Network confidential compute grid
5
5
  Project-URL: Homepage, https://singularitylayer.xyz
6
6
  Project-URL: Repository, https://github.com/SingularityLayer/sgl-network-sdk
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "singularity-grid"
7
- version = "0.1.0"
7
+ version = "0.2.0"
8
8
  description = "Python SDK for the SGL Network confidential compute grid"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -19,11 +19,19 @@ from .models import (
19
19
  ModelsResponse,
20
20
  PricingInfo,
21
21
  PricingResponse,
22
+ ProcessorDeployResult,
23
+ ProcessorInfo,
24
+ ProcessorListResponse,
25
+ ProcessorLogEntry,
26
+ ProcessorLogsResponse,
27
+ ProcessorPayment,
28
+ ProcessorResult,
29
+ ProcessorTeeInfo,
22
30
  TeeCapacity,
23
31
  )
24
32
  from .openai_compat import create_openai_client
25
33
 
26
- __version__ = "0.1.0"
34
+ __version__ = "0.2.0"
27
35
 
28
36
  __all__ = [
29
37
  # Client
@@ -36,7 +44,7 @@ __all__ = [
36
44
  "SGLAuthError",
37
45
  "SGLConnectionError",
38
46
  "SGLNotFoundError",
39
- # Models
47
+ # Models — Grid
40
48
  "AttestationProof",
41
49
  "CapacityResponse",
42
50
  "JobResponse",
@@ -47,4 +55,13 @@ __all__ = [
47
55
  "PricingInfo",
48
56
  "PricingResponse",
49
57
  "TeeCapacity",
58
+ # Models — Processors
59
+ "ProcessorDeployResult",
60
+ "ProcessorInfo",
61
+ "ProcessorListResponse",
62
+ "ProcessorLogEntry",
63
+ "ProcessorLogsResponse",
64
+ "ProcessorPayment",
65
+ "ProcessorResult",
66
+ "ProcessorTeeInfo",
50
67
  ]
@@ -15,6 +15,12 @@ from .models import (
15
15
  ModelsResponse,
16
16
  PricingInfo,
17
17
  PricingResponse,
18
+ ProcessorDeployResult,
19
+ ProcessorInfo,
20
+ ProcessorListResponse,
21
+ ProcessorLogEntry,
22
+ ProcessorLogsResponse,
23
+ ProcessorResult,
18
24
  )
19
25
 
20
26
  DEFAULT_BASE_URL = (
@@ -200,6 +206,151 @@ class GridClient:
200
206
  data = self._request("GET", f"/grid/jobs/{job_id}/attestation")
201
207
  return AttestationProof.model_validate(data)
202
208
 
209
+ # -- processor endpoints -----------------------------------------------
210
+
211
+ def deploy_processor(
212
+ self,
213
+ name: str,
214
+ code: str,
215
+ *,
216
+ wallet_address: str,
217
+ chain: str = "solana",
218
+ runtime: str = "deno",
219
+ memory_mb: int = 128,
220
+ timeout_seconds: int = 30,
221
+ metadata: Optional[Dict[str, Any]] = None,
222
+ ) -> ProcessorDeployResult:
223
+ """Deploy a serverless processor to the TEE grid.
224
+
225
+ Requires $SGL staking for higher tier limits.
226
+
227
+ Parameters
228
+ ----------
229
+ name:
230
+ Processor name (lowercase alphanumeric + hyphens, 2-64 chars).
231
+ code:
232
+ JavaScript/TypeScript source code with a default export function.
233
+ wallet_address:
234
+ Owner wallet address (must have $SGL staked for higher tiers).
235
+ chain:
236
+ Chain the wallet is on (default ``"solana"``).
237
+ runtime:
238
+ Execution runtime (``"deno"`` or ``"wasm"``).
239
+ memory_mb:
240
+ Memory allocation in MB (64, 128, 256, 512, 1024).
241
+ timeout_seconds:
242
+ Max execution time (1-300s, tier-dependent).
243
+ metadata:
244
+ Optional metadata dict attached to the processor.
245
+ """
246
+ body: Dict[str, Any] = {
247
+ "name": name,
248
+ "code": code,
249
+ "runtime": runtime,
250
+ "memory_mb": memory_mb,
251
+ "timeout_seconds": timeout_seconds,
252
+ }
253
+ if metadata:
254
+ body["metadata"] = metadata
255
+
256
+ # Set wallet auth headers
257
+ self._client.headers["X-Auth-Address"] = wallet_address
258
+ self._client.headers["X-Auth-Chain"] = chain
259
+ try:
260
+ data = self._request("POST", "/grid/processors", json=body)
261
+ finally:
262
+ self._client.headers.pop("X-Auth-Address", None)
263
+ self._client.headers.pop("X-Auth-Chain", None)
264
+
265
+ return ProcessorDeployResult.model_validate(data)
266
+
267
+ def invoke_processor(
268
+ self,
269
+ name: str,
270
+ input_data: Dict[str, Any],
271
+ *,
272
+ payment_header: str,
273
+ payment_token: str = "USDC",
274
+ ) -> ProcessorResult:
275
+ """Invoke a deployed processor with x402 payment.
276
+
277
+ Parameters
278
+ ----------
279
+ name:
280
+ Processor name.
281
+ input_data:
282
+ Input object passed to the handler function.
283
+ payment_header:
284
+ x402 payment header (JSON-encoded).
285
+ payment_token:
286
+ Payment token type (``"USDC"`` or ``"SGL"``).
287
+ """
288
+ body: Dict[str, Any] = {
289
+ "input": input_data,
290
+ "payment_token": payment_token,
291
+ }
292
+
293
+ self._client.headers["X-Payment"] = payment_header
294
+ try:
295
+ data = self._request(
296
+ "POST", f"/grid/processors/{name}/invoke", json=body,
297
+ )
298
+ finally:
299
+ self._client.headers.pop("X-Payment", None)
300
+
301
+ return ProcessorResult.model_validate(data)
302
+
303
+ def list_processors(
304
+ self,
305
+ *,
306
+ owner: Optional[str] = None,
307
+ page: int = 0,
308
+ limit: int = 50,
309
+ ) -> ProcessorListResponse:
310
+ """List deployed processors."""
311
+ params: Dict[str, Any] = {"page": page, "limit": limit}
312
+ if owner:
313
+ params["owner"] = owner
314
+ data = self._request("GET", "/grid/processors", params=params)
315
+ return ProcessorListResponse.model_validate(data)
316
+
317
+ def get_processor(self, processor_id: str) -> ProcessorInfo:
318
+ """Get details for a specific processor."""
319
+ data = self._request("GET", f"/grid/processors/{processor_id}")
320
+ return ProcessorInfo.model_validate(data)
321
+
322
+ def delete_processor(
323
+ self,
324
+ processor_id: str,
325
+ *,
326
+ wallet_address: str,
327
+ ) -> Dict[str, Any]:
328
+ """Delete a processor (must be the owner)."""
329
+ self._client.headers["X-Auth-Address"] = wallet_address
330
+ try:
331
+ data = self._request(
332
+ "DELETE", f"/grid/processors/{processor_id}",
333
+ )
334
+ finally:
335
+ self._client.headers.pop("X-Auth-Address", None)
336
+ return data
337
+
338
+ def get_processor_logs(
339
+ self,
340
+ processor_id: str,
341
+ *,
342
+ page: int = 0,
343
+ limit: int = 50,
344
+ ) -> ProcessorLogsResponse:
345
+ """Get invocation logs for a processor."""
346
+ params: Dict[str, Any] = {"page": page, "limit": limit}
347
+ data = self._request(
348
+ "GET",
349
+ f"/grid/processors/{processor_id}/logs",
350
+ params=params,
351
+ )
352
+ return ProcessorLogsResponse.model_validate(data)
353
+
203
354
  # -- lifecycle ----------------------------------------------------------
204
355
 
205
356
  def close(self) -> None:
@@ -108,3 +108,93 @@ class JobResult(BaseModel):
108
108
  created_at: Optional[str] = None
109
109
  completed_at: Optional[str] = None
110
110
  error: Optional[str] = None
111
+
112
+
113
+ # ---------------------------------------------------------------------------
114
+ # Processors
115
+ # ---------------------------------------------------------------------------
116
+
117
+ class ProcessorInfo(BaseModel):
118
+ """Processor descriptor returned by list/get endpoints."""
119
+ id: str
120
+ name: str
121
+ owner_wallet: str = ""
122
+ owner_chain: str = "solana"
123
+ runtime: str = "deno"
124
+ memory_mb: int = 128
125
+ timeout_seconds: int = 30
126
+ invocation_count: int = 0
127
+ last_invoked_at: Optional[str] = None
128
+ status: str = "active"
129
+ deployment_stake_sgl: float = 0.0
130
+ invoke_url: Optional[str] = None
131
+ created_at: Optional[str] = None
132
+ metadata: Dict[str, Any] = Field(default_factory=dict)
133
+
134
+
135
+ class ProcessorDeployResult(BaseModel):
136
+ """Response from deploying a processor."""
137
+ id: str
138
+ name: str
139
+ runtime: str = "deno"
140
+ memory_mb: int = 128
141
+ timeout_seconds: int = 30
142
+ status: str = "active"
143
+ code_hash: str = ""
144
+ invoke_url: str = ""
145
+ tier: str = "free"
146
+ sgl_staked: float = 0.0
147
+ created_at: Optional[str] = None
148
+
149
+
150
+ class ProcessorPayment(BaseModel):
151
+ """Payment details from a processor invocation."""
152
+ amount_usd: str = "0"
153
+ token: str = "USDC"
154
+ discount_pct: float = 0.0
155
+
156
+
157
+ class ProcessorTeeInfo(BaseModel):
158
+ """TEE details from a processor invocation."""
159
+ node_id: str = ""
160
+ tee_type: str = ""
161
+ attestation_verified: bool = False
162
+
163
+
164
+ class ProcessorResult(BaseModel):
165
+ """Response from invoking a processor."""
166
+ job_id: str
167
+ processor: str = ""
168
+ status: str = "pending"
169
+ output: Optional[Any] = None
170
+ duration_ms: Optional[int] = None
171
+ payment: Optional[ProcessorPayment] = None
172
+ tee: Optional[ProcessorTeeInfo] = None
173
+
174
+
175
+ class ProcessorListResponse(BaseModel):
176
+ """Paginated processor listing."""
177
+ processors: List[ProcessorInfo] = Field(default_factory=list)
178
+ total: int = 0
179
+ page: int = 0
180
+ limit: int = 50
181
+
182
+
183
+ class ProcessorLogEntry(BaseModel):
184
+ """Single invocation log entry."""
185
+ id: str = ""
186
+ processor_id: str = ""
187
+ job_id: str = ""
188
+ node_id: Optional[str] = None
189
+ duration_ms: Optional[int] = None
190
+ status: str = ""
191
+ error_message: Optional[str] = None
192
+ created_at: Optional[str] = None
193
+
194
+
195
+ class ProcessorLogsResponse(BaseModel):
196
+ """Paginated processor logs."""
197
+ logs: List[ProcessorLogEntry] = Field(default_factory=list)
198
+ total: int = 0
199
+ page: int = 0
200
+ limit: int = 50