singularity-grid 0.3.0__tar.gz → 0.4.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.3.0
3
+ Version: 0.4.0
4
4
  Summary: Python SDK for the SGL Network confidential compute grid (end-to-end encrypted + streaming)
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.3.0"
7
+ version = "0.4.0"
8
8
  description = "Python SDK for the SGL Network confidential compute grid (end-to-end encrypted + streaming)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -211,9 +211,25 @@ class GridClient:
211
211
 
212
212
  # -- chat (end-to-end encrypted) ---------------------------------------
213
213
 
214
- def _reserve(self, model: str) -> Dict[str, Any]:
215
- """Reserve a node + learn its X25519 key so we can seal the prompt to it."""
216
- data = self._request("POST", "/v1/reserve", json={"model": model})
214
+ def providers(self, model: str, cluster: Optional[str] = None) -> List[Dict[str, Any]]:
215
+ """List nodes serving ``model`` with their effective price + reputation,
216
+ cheapest first — pick one and pass its ``node_id`` to ``chat_completions(node=...)``."""
217
+ q = f"/v1/providers?model={model}" + (f"&cluster={cluster}" if cluster else "")
218
+ data = self._request("GET", q)
219
+ return data.get("providers", [])
220
+
221
+ def _reserve(self, model: str, cluster: Optional[str] = None, node: Optional[str] = None) -> Dict[str, Any]:
222
+ """Reserve a node + learn its X25519 key so we can seal the prompt to it.
223
+
224
+ When ``cluster`` is given, a node *inside that cluster* (a Tokenised Compute
225
+ Market) is reserved. When ``node`` is given, that specific provider is reserved.
226
+ """
227
+ payload: Dict[str, Any] = {"model": model}
228
+ if cluster is not None:
229
+ payload["cluster"] = cluster
230
+ if node is not None:
231
+ payload["node"] = node
232
+ data = self._request("POST", "/v1/reserve", json=payload)
217
233
  if not data.get("node_x25519_pubkey"):
218
234
  raise SGLAPIError(503, "Reserved node does not support E2E encryption")
219
235
  return data
@@ -225,6 +241,9 @@ class GridClient:
225
241
  *,
226
242
  temperature: float = 0.7,
227
243
  max_tokens: int = 512,
244
+ cluster: Optional[str] = None,
245
+ node: Optional[str] = None,
246
+ pay_in_coin: bool = False,
228
247
  ) -> Dict[str, Any]:
229
248
  """End-to-end encrypted chat completion.
230
249
 
@@ -232,14 +251,24 @@ class GridClient:
232
251
  decrypts inside its TEE — the orchestrator only relays ciphertext. Requires
233
252
  ``api_key`` (credits); x402 pay-per-call isn't signed here (use the wallet
234
253
  flow). Returns an OpenAI-style dict with an extra ``attestation`` field.
254
+
255
+ Parameters
256
+ ----------
257
+ cluster:
258
+ Optional cluster slug — route to a node inside that Tokenised Compute
259
+ Market (only nodes that joined the cluster serve it).
260
+ pay_in_coin:
261
+ When ``True`` and the cluster has a tradeable coin, pay for the request
262
+ in that coin (the believer lane) instead of USDC/credits. Falls back to
263
+ USDC if the coin's oracle price is untrusted.
235
264
  """
236
- reservation = self._reserve(model)
265
+ reservation = self._reserve(model, cluster=cluster, node=node)
237
266
  resp_sk, resp_pub = e2e.new_response_keypair()
238
267
  sealed_ct, eph = e2e.seal_input(
239
268
  reservation["node_x25519_pubkey"], resp_pub,
240
269
  _json.dumps({"messages": messages, "temperature": temperature, "max_tokens": max_tokens}).encode(),
241
270
  )
242
- body = {
271
+ body: Dict[str, Any] = {
243
272
  "reservation_token": reservation["reservation_token"],
244
273
  "max_tokens": max_tokens, # cleartext, only used to quote the x402 price
245
274
  "enc": {
@@ -249,6 +278,8 @@ class GridClient:
249
278
  "algorithm": e2e.ALGO_V2,
250
279
  },
251
280
  }
281
+ if pay_in_coin:
282
+ body["pay_in_coin"] = True
252
283
  try:
253
284
  data = self._request("POST", "/v1/chat/completions", json=body)
254
285
  except SGLAPIError as err: