usdf 0.1.2__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.
usdf/types.py ADDED
@@ -0,0 +1,407 @@
1
+ """Shapes of the gateway's responses, from the gateway's own handlers (gateway/src/proxy.ts, public.ts,
2
+ mcp.ts, account.ts, keys.ts, x402.ts). Each dataclass keeps the full response in ``raw`` so a field the
3
+ SDK does not model is still there. Money is carried as strings: ``units`` are whole base units
4
+ (1 unit = $0.000001 = 0.000001 USDF); ``usd`` and ``usdf`` are the same decimal figure."""
5
+
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass, field
9
+ from typing import Any, Dict, List, Optional
10
+
11
+
12
+ @dataclass
13
+ class Amount:
14
+ units: str
15
+ usd: str
16
+ usdf: str
17
+
18
+ @classmethod
19
+ def of(cls, d: Optional[Dict[str, Any]]) -> Optional["Amount"]:
20
+ if not isinstance(d, dict):
21
+ return None
22
+ return cls(str(d.get("units")), str(d.get("usd")), str(d.get("usdf")))
23
+
24
+ @property
25
+ def as_int(self) -> int:
26
+ return int(self.units)
27
+
28
+
29
+ @dataclass
30
+ class Usage:
31
+ prompt_tokens: int
32
+ completion_tokens: int
33
+ cached_tokens: int = 0
34
+ cache_write_tokens: int = 0
35
+
36
+ @classmethod
37
+ def of(cls, d: Optional[Dict[str, Any]]) -> "Usage":
38
+ d = d or {}
39
+ return cls(int(d.get("prompt_tokens") or 0), int(d.get("completion_tokens") or 0), int(d.get("cached_tokens") or 0), int(d.get("cache_write_tokens") or 0))
40
+
41
+
42
+ @dataclass
43
+ class Receipt:
44
+ """The receipt attached to every keyed completion (JSON body, or the stream's last comment line)."""
45
+
46
+ request_id: str
47
+ model: str
48
+ provider: str
49
+ status: str # "ok" | "partial"
50
+ usage: Usage
51
+ price_version: str
52
+ cost: Amount
53
+ balance: Optional[Amount] # None when the ledger had not confirmed the charge when the response went out
54
+ settlement_status: str
55
+ note: Optional[str]
56
+ # What the serving route does with content and what the request asked for; on attested hardware it
57
+ # also carries ``attestation`` (pending, then verified or failed on the lookup) and ``attestation_lookup``.
58
+ data_policy: Optional[Dict[str, Any]] = None
59
+ # A request that failed after its hold was taken: status "failed_refunded", why, and what went back.
60
+ reason: Optional[str] = None
61
+ refunded: Optional[Amount] = None
62
+ batch: bool = False
63
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
64
+
65
+ @property
66
+ def attestation(self) -> Optional[str]:
67
+ return (self.data_policy or {}).get("attestation")
68
+
69
+ @classmethod
70
+ def of(cls, d: Dict[str, Any]) -> "Receipt":
71
+ price = d.get("price") or {}
72
+ return cls(
73
+ request_id=str(d.get("request_id")),
74
+ model=str(d.get("model")),
75
+ provider=str(d.get("provider")),
76
+ status=str(d.get("status")),
77
+ usage=Usage.of(d.get("usage")),
78
+ price_version=str(price.get("version")),
79
+ cost=Amount.of(d.get("cost")) or Amount("0", "0.000000", "0.000000"),
80
+ balance=Amount.of(d.get("balance")),
81
+ settlement_status=str((d.get("settlement") or {}).get("status")),
82
+ note=d.get("note"),
83
+ data_policy=d.get("data_policy"),
84
+ reason=d.get("reason"),
85
+ refunded=Amount.of(d.get("refunded")),
86
+ batch=d.get("batch") is True,
87
+ raw=d,
88
+ )
89
+
90
+
91
+ @dataclass
92
+ class X402Receipt:
93
+ """An x402 receipt: ``paid`` is what the request was charged, its metered cost at the quoted price and
94
+ never more than the payment (``raw["payment"]["amount"]``); the rest of the payment is refunded to the
95
+ payer (``raw["refund"]``). ``usage_cost`` is what the usage came to at that price."""
96
+
97
+ request_id: str
98
+ model: str
99
+ provider: str
100
+ status: str
101
+ usage: Usage
102
+ price_version: str
103
+ paid: Amount
104
+ usage_cost: Amount
105
+ payment_tx: str
106
+ payer: str
107
+ asset: str # "USDF" | "USDG"
108
+ method: str # "permit2" | "eip3009"
109
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
110
+
111
+ @classmethod
112
+ def of(cls, d: Dict[str, Any]) -> "X402Receipt":
113
+ payment = d.get("payment") or {}
114
+ return cls(
115
+ request_id=str(d.get("request_id")),
116
+ model=str(d.get("model")),
117
+ provider=str(d.get("provider")),
118
+ status=str(d.get("status")),
119
+ usage=Usage.of(d.get("usage")),
120
+ price_version=str((d.get("price") or {}).get("version")),
121
+ paid=Amount.of(d.get("paid")) or Amount("0", "0.000000", "0.000000"),
122
+ usage_cost=Amount.of(d.get("usage_cost")) or Amount("0", "0.000000", "0.000000"),
123
+ payment_tx=str(payment.get("tx")),
124
+ payer=str(payment.get("payer")),
125
+ asset=str(payment.get("asset")),
126
+ method=str(payment.get("method")),
127
+ raw=d,
128
+ )
129
+
130
+
131
+ @dataclass
132
+ class ChatCompletion:
133
+ """A completion in the OpenAI shape, with the gateway's receipt. ``raw`` is the whole body."""
134
+
135
+ id: str
136
+ model: str
137
+ content: Optional[str]
138
+ finish_reason: Optional[str]
139
+ tool_calls: Optional[List[Dict[str, Any]]]
140
+ usage: Optional[Dict[str, Any]]
141
+ receipt: Any # Receipt, or X402Receipt for an x402 completion
142
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
143
+
144
+ @classmethod
145
+ def of(cls, d: Dict[str, Any], x402: bool = False) -> "ChatCompletion":
146
+ choices = d.get("choices") or []
147
+ msg = (choices[0].get("message") if choices and isinstance(choices[0], dict) else None) or {}
148
+ receipt = d.get("receipt")
149
+ return cls(
150
+ id=str(d.get("id")),
151
+ model=str(d.get("model")),
152
+ content=msg.get("content"),
153
+ finish_reason=choices[0].get("finish_reason") if choices else None,
154
+ tool_calls=msg.get("tool_calls"),
155
+ usage=d.get("usage"),
156
+ receipt=(X402Receipt.of(receipt) if x402 else Receipt.of(receipt)) if isinstance(receipt, dict) else None,
157
+ raw=d,
158
+ )
159
+
160
+
161
+ @dataclass
162
+ class ReceiptLookup:
163
+ """GET /v1/receipts/{id}: the charge and, once settled, the batch, its transaction and the rows URL."""
164
+
165
+ request_id: str
166
+ model: str
167
+ provider: str
168
+ status: str
169
+ created_at: str
170
+ usage: Usage
171
+ price_version: str
172
+ cost: Amount
173
+ settlement_status: str
174
+ settlement_batch: Optional[str]
175
+ settlement_tx: Optional[str]
176
+ settlement_explorer: Optional[str]
177
+ settlement_rows: Optional[str]
178
+ # The request's leaf in the usage log (status, leaf_index, tree_size, anchored_by, proof).
179
+ log: Optional[Dict[str, Any]] = None
180
+ # Served on attested hardware: pending, verified or failed, the provider's receipt id, where to read it.
181
+ attestation: Optional[str] = None
182
+ attestation_receipt: Optional[str] = None
183
+ attestation_lookup: Optional[str] = None
184
+ reason: Optional[str] = None
185
+ refunded: Optional[Amount] = None
186
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
187
+
188
+ @classmethod
189
+ def of(cls, d: Dict[str, Any]) -> "ReceiptLookup":
190
+ s = d.get("settlement") or {}
191
+ return cls(
192
+ request_id=str(d.get("request_id")),
193
+ model=str(d.get("model")),
194
+ provider=str(d.get("provider")),
195
+ status=str(d.get("status")),
196
+ created_at=str(d.get("created_at")),
197
+ usage=Usage.of(d.get("usage")),
198
+ price_version=str(d.get("price_version")),
199
+ cost=Amount.of(d.get("cost")) or Amount("0", "0.000000", "0.000000"),
200
+ settlement_status=str(s.get("status")),
201
+ settlement_batch=s.get("batch"),
202
+ settlement_tx=s.get("tx_hash"),
203
+ settlement_explorer=s.get("explorer"),
204
+ settlement_rows=s.get("rows"),
205
+ log=d.get("log"),
206
+ attestation=d.get("attestation"),
207
+ attestation_receipt=d.get("attestation_receipt"),
208
+ attestation_lookup=d.get("attestation_lookup"),
209
+ reason=d.get("reason"),
210
+ refunded=Amount.of(d.get("refunded")),
211
+ raw=d,
212
+ )
213
+
214
+
215
+ @dataclass
216
+ class Model:
217
+ id: str
218
+ name: str
219
+ owned_by: str
220
+ context_length: int
221
+ max_output_tokens: int
222
+ endpoints: List[str]
223
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
224
+
225
+ @classmethod
226
+ def of(cls, d: Dict[str, Any]) -> "Model":
227
+ return cls(str(d.get("id")), str(d.get("name")), str(d.get("owned_by")), int(d.get("context_length") or 0), int(d.get("max_output_tokens") or 0), list(d.get("endpoints") or []), d)
228
+
229
+
230
+ @dataclass
231
+ class PricingModel:
232
+ id: str
233
+ name: str
234
+ owned_by: str
235
+ context: int
236
+ max_output: int
237
+ endpoints: List[str]
238
+ pricing: str # "list" | "passthrough": every model at a list price ("markup" only on sheets before 2026-10-10)
239
+ price: Dict[str, Any] # USD per 1M tokens: input, output, cached_input?, long_context?
240
+ available: bool
241
+ routes: List[Dict[str, Any]]
242
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
243
+
244
+ @classmethod
245
+ def of(cls, d: Dict[str, Any]) -> "PricingModel":
246
+ return cls(str(d.get("id")), str(d.get("name")), str(d.get("owned_by")), int(d.get("context") or 0), int(d.get("max_output") or 0), list(d.get("endpoints") or []), str(d.get("pricing")), dict(d.get("price") or {}), bool(d.get("available")), list(d.get("routes") or []), d)
247
+
248
+
249
+ @dataclass
250
+ class Pricing:
251
+ version: str
252
+ unit: str
253
+ markup: str
254
+ sheet_sha256: str
255
+ models: List[PricingModel]
256
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
257
+
258
+ @classmethod
259
+ def of(cls, d: Dict[str, Any]) -> "Pricing":
260
+ return cls(str(d.get("version")), str(d.get("unit")), str(d.get("markup")), str(d.get("sheet_sha256")), [PricingModel.of(m) for m in d.get("models") or []], d)
261
+
262
+ def model(self, model_id: str) -> Optional[PricingModel]:
263
+ base = model_id.split(":")[0]
264
+ return next((m for m in self.models if m.id == base), None)
265
+
266
+
267
+ @dataclass
268
+ class Quote:
269
+ """The hold the gateway places for a request (MCP ``quote``), and the x402 amount for the same request."""
270
+
271
+ model: str
272
+ price_version: str
273
+ max_tokens: int
274
+ prompt_tokens_held: int
275
+ max_cost: Amount
276
+ price: Dict[str, Any]
277
+ note: str
278
+ x402_amount: Optional[Amount]
279
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
280
+
281
+ @classmethod
282
+ def of(cls, d: Dict[str, Any]) -> "Quote":
283
+ x = d.get("x402") or {}
284
+ return cls(str(d.get("model")), str(d.get("price_version")), int(d.get("max_tokens") or 0), int(d.get("prompt_tokens_held") or 0), Amount.of(d.get("max_cost")) or Amount("0", "0.000000", "0.000000"), dict(d.get("price") or {}), str(d.get("note") or ""), Amount.of(x.get("amount")), d)
285
+
286
+
287
+ @dataclass
288
+ class Balance:
289
+ """MCP ``balance``: what the key can spend, the account's balance and holds, the key's budget."""
290
+
291
+ available: Amount
292
+ balance: Optional[Amount]
293
+ held: Optional[Amount]
294
+ key_id: str
295
+ key_budget: Optional[Amount]
296
+ key_spent: Optional[Amount]
297
+ key_budget_left: Optional[Amount]
298
+ rate_limit_rpm: int
299
+ note: Optional[str]
300
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
301
+
302
+ @classmethod
303
+ def of(cls, d: Dict[str, Any]) -> "Balance":
304
+ k = d.get("key") or {}
305
+ return cls(Amount.of(d.get("available")) or Amount("0", "0.000000", "0.000000"), Amount.of(d.get("balance")), Amount.of(d.get("held")), str(k.get("id")), Amount.of(k.get("budget")), Amount.of(k.get("spent")), Amount.of(k.get("budget_left")), int(d.get("rate_limit_rpm") or 0), d.get("note"), d)
306
+
307
+
308
+ @dataclass
309
+ class Account:
310
+ """GET /v1/account: balance, held, linked wallet, pending withdrawals and the deposit address."""
311
+
312
+ id: str
313
+ wallet_address: Optional[str]
314
+ balance_units: int
315
+ held_units: int
316
+ pending_withdrawals: int
317
+ pending_withdrawal_units: int
318
+ deposit_to: str
319
+ deposit_token: str
320
+ chain_id: int
321
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
322
+
323
+ @property
324
+ def available_units(self) -> int:
325
+ return self.balance_units - self.held_units
326
+
327
+ @classmethod
328
+ def of(cls, d: Dict[str, Any]) -> "Account":
329
+ a = d.get("account") or {}
330
+ w = d.get("withdrawals") or {}
331
+ dep = d.get("deposit") or {}
332
+ return cls(str(a.get("id")), a.get("wallet_address"), int(a.get("balance_units") or 0), int(a.get("held_units") or 0), int(w.get("pending_count") or 0), int(w.get("pending_units") or 0), str(dep.get("to")), str(dep.get("token")), int(dep.get("chain_id") or 0), d)
333
+
334
+
335
+ @dataclass
336
+ class Session:
337
+ access_token: str
338
+ refresh_token: Optional[str]
339
+ expires_in: int
340
+ user_id: Optional[str]
341
+ email: Optional[str]
342
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
343
+
344
+ @classmethod
345
+ def of(cls, d: Dict[str, Any]) -> "Session":
346
+ u = d.get("user") or {}
347
+ return cls(str(d.get("access_token")), d.get("refresh_token"), int(d.get("expires_in") or 0), u.get("id"), u.get("email"), d)
348
+
349
+
350
+ @dataclass
351
+ class CreatedKey:
352
+ key_id: str
353
+ api_key: str # shown once; the ledger keeps only its hash
354
+ prefix: str
355
+
356
+
357
+ @dataclass
358
+ class ApiKey:
359
+ id: str
360
+ key_prefix: str
361
+ label: Optional[str]
362
+ budget_units: Optional[int]
363
+ spent_units: int
364
+ rate_limit_rpm: int
365
+ created_at: str
366
+ last_used_at: Optional[str]
367
+ revoked_at: Optional[str]
368
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
369
+
370
+ @classmethod
371
+ def of(cls, d: Dict[str, Any]) -> "ApiKey":
372
+ b = d.get("budget_units")
373
+ return cls(str(d.get("id")), str(d.get("key_prefix")), d.get("label"), None if b is None else int(b), int(d.get("spent_units") or 0), int(d.get("rate_limit_rpm") or 0), str(d.get("created_at")), d.get("last_used_at"), d.get("revoked_at"), d)
374
+
375
+
376
+ @dataclass
377
+ class KeyLimits:
378
+ """GET /v1/keys/{id}/limits: trailing-window spend, caps, pause state, privacy flags, webhook."""
379
+
380
+ key_id: str
381
+ label: Optional[str]
382
+ hour_spent_units: int
383
+ hour_limit_units: Optional[int]
384
+ day_spent_units: int
385
+ day_limit_units: Optional[int]
386
+ month_spent_units: int
387
+ month_limit_units: Optional[int]
388
+ paused: bool
389
+ pause_reason: Optional[str]
390
+ auto_resume: Optional[bool]
391
+ no_logs: bool
392
+ private_tier: bool
393
+ webhook_url: Optional[str]
394
+ updated: List[str]
395
+ raw: Dict[str, Any] = field(repr=False, default_factory=dict)
396
+
397
+ @classmethod
398
+ def of(cls, d: Dict[str, Any]) -> "KeyLimits":
399
+ spend = d.get("spend") or {}
400
+ h = spend.get("hour") or {}
401
+ day = spend.get("day") or {}
402
+ # Pre-migration ledgers (gateway/src/keys.ts): the gateway sends spend.month as null.
403
+ month = spend.get("month") or {}
404
+ p = d.get("paused") or {}
405
+ priv = d.get("privacy") or {}
406
+ lim = lambda v: None if v is None else int(v) # noqa: E731
407
+ return cls(str(d.get("key_id")), d.get("label"), int(h.get("spent_units") or 0), lim(h.get("limit_units")), int(day.get("spent_units") or 0), lim(day.get("limit_units")), int(month.get("spent_units") or 0), lim(month.get("limit_units")), bool(p.get("state")), p.get("reason"), p.get("auto_resume"), bool(priv.get("no_logs")), bool(priv.get("private_tier")), (d.get("webhook") or {}).get("url"), list(d.get("updated") or []), d)