@hoodcompute/sdk 0.1.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HoodCompute
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,332 @@
1
+ # @hoodcompute/sdk
2
+
3
+ The official TypeScript SDK for [HoodCompute](https://hoodcompute.com), the decentralized AI inference network on Robinhood Chain.
4
+
5
+ Private, censorship-free inference from a distributed pool of GPU providers. Every job is settled on-chain, so every completion comes with a receipt you can verify yourself on Blockscout.
6
+
7
+ - **OpenAI-compatible** chat completions. If you know the OpenAI SDK, you know this one.
8
+ - **Streaming** token delivery over Server-Sent Events, as an async iterable.
9
+ - **On-chain receipts** attached to every completion. Job ID and settlement transaction, no extra call.
10
+ - **Typed end to end.** Full TypeScript types for requests, responses, jobs, models, and webhooks.
11
+ - **React hooks** in a separate entry point, so the core stays framework-agnostic.
12
+ - **Zero runtime dependencies.** Built on the platform `fetch`.
13
+
14
+ > **Beta.** HoodCompute is an early, real, working network. The SDK follows semantic versioning. Expect additive changes as the network grows.
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @hoodcompute/sdk
22
+ ```
23
+
24
+ Requires Node 18 or newer (for the built-in `fetch`), or any modern browser or edge runtime.
25
+
26
+ ---
27
+
28
+ ## Quickstart
29
+
30
+ Get an API key from the Settings tab at [hoodcompute.com/app/settings](https://hoodcompute.com/app/settings). Keys are formatted `hoodc_live_...` and are linked to your wallet's credit balance.
31
+
32
+ ```typescript
33
+ import { HoodComputeClient } from "@hoodcompute/sdk"
34
+
35
+ const client = new HoodComputeClient({
36
+ apiKey: process.env.HOODCOMPUTE_API_KEY,
37
+ })
38
+
39
+ const completion = await client.chat.completions.create({
40
+ model: "qwen3-8b",
41
+ messages: [{ role: "user", content: "What is an ERC-4337 smart account?" }],
42
+ })
43
+
44
+ console.log(completion.choices[0].message.content)
45
+ console.log("Job:", completion.jobId)
46
+ console.log("Settled:", completion.settlementTx)
47
+ ```
48
+
49
+ If you omit `apiKey`, the client reads `HOODCOMPUTE_API_KEY` from the environment.
50
+
51
+ ---
52
+
53
+ ## Streaming
54
+
55
+ Pass `stream: true` to receive an async iterable of chunks. Once the stream closes, the settlement receipt is available on the stream object.
56
+
57
+ ```typescript
58
+ import { HoodComputeClient, explorerTxUrl } from "@hoodcompute/sdk"
59
+
60
+ const client = new HoodComputeClient()
61
+
62
+ const stream = await client.chat.completions.create({
63
+ model: "llama-3.3-70b",
64
+ messages: [{ role: "user", content: "Explain how optimistic rollups work." }],
65
+ stream: true,
66
+ })
67
+
68
+ for await (const chunk of stream) {
69
+ process.stdout.write(chunk.choices[0]?.delta?.content ?? "")
70
+ }
71
+
72
+ console.log("\nSettled:", explorerTxUrl(stream.receipt.settlementTx!))
73
+ console.log("Credits remaining:", stream.receipt.creditsRemaining)
74
+ ```
75
+
76
+ Need the whole response as a string? Use `await stream.text()`.
77
+
78
+ ---
79
+
80
+ ## On-chain receipts
81
+
82
+ Every completed job has a receipt whose transaction hashes resolve on the Robinhood Chain [Blockscout explorer](https://robinhoodchain.blockscout.com). The receipt never contains prompt or completion content, only settlement metadata.
83
+
84
+ ```typescript
85
+ // Fetch the full receipt for any settled job
86
+ const receipt = await client.jobs.getReceipt("job_8fx2kp3m9qrstvwxyz")
87
+
88
+ console.log(receipt.workerAddress) // 0x9d24ab7e...
89
+ console.log(receipt.creditsCharged) // 8
90
+ console.log(receipt.settlementTx) // 0x3a91d5c0...
91
+
92
+ import { explorerTxUrl } from "@hoodcompute/sdk"
93
+ console.log(explorerTxUrl(receipt.settlementTx))
94
+ ```
95
+
96
+ You do not need to trust the API's report of what happened. The Robinhood Chain transaction is the authoritative record.
97
+
98
+ ---
99
+
100
+ ## Models
101
+
102
+ The model list reflects the live worker pool. A model appears only while at least one worker is hosting it.
103
+
104
+ ```typescript
105
+ const { data: models } = await client.models.list()
106
+
107
+ for (const model of models) {
108
+ console.log(
109
+ `${model.id} ${model.hoodcompute.tier} ` +
110
+ `${model.hoodcompute.activeWorkers} workers ` +
111
+ `~${model.hoodcompute.medianLatencyMs}ms`,
112
+ )
113
+ }
114
+
115
+ // Inspect one model before submitting a job
116
+ const qwen = await client.models.retrieve("qwen3-8b")
117
+ ```
118
+
119
+ | Model ID | Parameters | Context | Tier | Credits/request |
120
+ |---|---|---|---|---|
121
+ | `llama-3.3-70b` | 70B | 128K | Max | 40 |
122
+ | `deepseek-r1` | 70B | 128K | Max | 40 |
123
+ | `qwen3-14b` | 14B | 32K | Pro | 18 |
124
+ | `qwen3-8b` | 8B | 32K | Standard | 8 |
125
+ | `mistral-7b` | 7B | 32K | Standard | 8 |
126
+ | `llama-3.2-3b` | 3B | 128K | Lite | 2 |
127
+
128
+ Call `client.models.list()` for the current catalog. One credit is $0.01.
129
+
130
+ ---
131
+
132
+ ## Jobs
133
+
134
+ ```typescript
135
+ // Retrieve a job, including its on-chain settlement detail
136
+ const job = await client.jobs.get("job_8fx2kp3m9qrstvwxyz")
137
+ console.log(job.status) // "settled"
138
+ console.log(job.onChain?.settlementTx)
139
+
140
+ // List recent jobs
141
+ const jobs = await client.jobs.list({ limit: 20, status: "settled" })
142
+ for (const j of jobs.data) {
143
+ console.log(`${j.id} ${j.model} ${j.creditsCharged} credits`)
144
+ }
145
+ ```
146
+
147
+ ### Disputes
148
+
149
+ If a worker's on-chain proof does not match the output you received, open a dispute within 60 seconds of the final token. Hash the full response text you received (SHA-256, UTF-8, no trailing newline) and submit it.
150
+
151
+ ```typescript
152
+ const result = await client.jobs.dispute(
153
+ "job_8fx2kp3m9qrstvwxyz",
154
+ "sha256:a1b2c3d4...",
155
+ )
156
+ console.log(result.disputeOpened, result.disputeTx)
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Account and credits
162
+
163
+ ```typescript
164
+ const account = await client.account.get()
165
+ console.log(account.wallet) // 0x7f3ce8b1...
166
+ console.log(account.creditsRemaining) // 1420
167
+ console.log(account.usdgValue) // 14.20
168
+ ```
169
+
170
+ ---
171
+
172
+ ## React hooks
173
+
174
+ Import from the `@hoodcompute/sdk/react` entry point. `react` is an optional peer dependency, so it is pulled in only when you use this subpath.
175
+
176
+ ```tsx
177
+ import { useHoodComputeChat } from "@hoodcompute/sdk/react"
178
+
179
+ function Chat() {
180
+ const { send, messages, status, balance, lastReceipt } = useHoodComputeChat({
181
+ model: "qwen3-8b",
182
+ apiKey: process.env.NEXT_PUBLIC_HOODCOMPUTE_API_KEY,
183
+ })
184
+
185
+ return (
186
+ <div>
187
+ <p>Credits: {balance?.creditsRemaining ?? "..."}</p>
188
+ {messages.map((m, i) => (
189
+ <p key={i}>
190
+ <strong>{m.role}:</strong> {m.content}
191
+ </p>
192
+ ))}
193
+ <button disabled={status === "streaming"} onClick={() => send("Hello")}>
194
+ Send
195
+ </button>
196
+ {lastReceipt?.settlementTx && (
197
+ <a href={`https://robinhoodchain.blockscout.com/tx/${lastReceipt.settlementTx}`}>
198
+ View settlement
199
+ </a>
200
+ )}
201
+ </div>
202
+ )
203
+ }
204
+ ```
205
+
206
+ Calling the API directly from the browser exposes your key. In production, proxy requests through your own server. During beta, if you must call from the browser, use a `NEXT_PUBLIC_`-scoped key you can revoke at any time.
207
+
208
+ ---
209
+
210
+ ## Webhooks
211
+
212
+ Verify the `HoodCompute-Signature` header against the raw request body before parsing it.
213
+
214
+ ```typescript
215
+ import { constructWebhookEvent } from "@hoodcompute/sdk"
216
+
217
+ app.post("/hoodcompute-events", express.raw({ type: "application/json" }), (req, res) => {
218
+ try {
219
+ const event = constructWebhookEvent(
220
+ req.body.toString(),
221
+ req.header("HoodCompute-Signature"),
222
+ process.env.HOODCOMPUTE_WEBHOOK_SECRET!,
223
+ )
224
+
225
+ if (event.event === "job.completed") {
226
+ console.log("Settled:", event.data.settlement_tx)
227
+ }
228
+
229
+ res.json({ received: true })
230
+ } catch {
231
+ res.status(400).json({ error: "Invalid signature" })
232
+ }
233
+ })
234
+ ```
235
+
236
+ `verifyWebhookSignature(rawBody, signature, secret)` is also exported if you want to verify without parsing.
237
+
238
+ ---
239
+
240
+ ## Configuration
241
+
242
+ ```typescript
243
+ const client = new HoodComputeClient({
244
+ apiKey: "hoodc_live_...", // or HOODCOMPUTE_API_KEY
245
+ baseURL: "https://api.hoodcompute.com/v1", // default
246
+ timeout: 120_000, // per-request timeout, ms
247
+ maxRetries: 2, // retries on 5xx, 429, network errors
248
+ defaultHeaders: { "x-app-version": "1.0.0" },
249
+ })
250
+ ```
251
+
252
+ Every request method accepts an `AbortSignal` for cancellation:
253
+
254
+ ```typescript
255
+ const controller = new AbortController()
256
+ const promise = client.chat.completions.create(
257
+ { model: "qwen3-8b", messages },
258
+ { signal: controller.signal },
259
+ )
260
+ controller.abort()
261
+ ```
262
+
263
+ ---
264
+
265
+ ## Error handling
266
+
267
+ Failed requests throw a typed `HoodComputeError` subclass. Retryable conditions (5xx, 429, network failures, and `no_workers_available`) are retried automatically up to `maxRetries`.
268
+
269
+ ```typescript
270
+ import {
271
+ HoodComputeError,
272
+ InsufficientCreditsError,
273
+ NoWorkersAvailableError,
274
+ } from "@hoodcompute/sdk"
275
+
276
+ try {
277
+ await client.chat.completions.create({ model, messages })
278
+ } catch (err) {
279
+ if (err instanceof InsufficientCreditsError) {
280
+ console.error("Add credits to continue.")
281
+ } else if (err instanceof NoWorkersAvailableError) {
282
+ console.error(`No workers online. Retry in ${err.retryAfter}s.`)
283
+ } else if (err instanceof HoodComputeError) {
284
+ console.error(err.code, err.message)
285
+ }
286
+ }
287
+ ```
288
+
289
+ | Class | Status | When |
290
+ |---|---|---|
291
+ | `AuthenticationError` | 401, 403 | Missing, invalid, revoked, or suspended key |
292
+ | `InsufficientCreditsError` | 402 | Credit balance too low for the tier |
293
+ | `InvalidRequestError` | 400, 422 | Malformed request or invalid field |
294
+ | `NotFoundError` | 404 | Job, model, or resource does not exist |
295
+ | `RateLimitError` | 429 | Request rate to the API too high |
296
+ | `NoWorkersAvailableError` | 503 | No worker hosting the model right now |
297
+ | `JobTimeoutError` | 504 | No worker completed within the window, credits refunded |
298
+ | `ServerError` | 5xx | Internal error, usually safe to retry |
299
+ | `ConnectionError` | none | Network failure, timeout, or aborted request |
300
+
301
+ ---
302
+
303
+ ## Migrating from the OpenAI SDK
304
+
305
+ Requests and responses share the OpenAI shape, so most code changes only the client and the model ID.
306
+
307
+ ```diff
308
+ - import OpenAI from "openai"
309
+ - const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
310
+ + import { HoodComputeClient } from "@hoodcompute/sdk"
311
+ + const client = new HoodComputeClient({ apiKey: process.env.HOODCOMPUTE_API_KEY })
312
+
313
+ const completion = await client.chat.completions.create({
314
+ - model: "gpt-4o",
315
+ + model: "llama-3.3-70b",
316
+ messages: [{ role: "user", content: "Hello" }],
317
+ })
318
+ ```
319
+
320
+ The HoodCompute responses add `jobId`, `settlementTx`, and `creditsRemaining` on top of the standard fields.
321
+
322
+ ---
323
+
324
+ ## Documentation
325
+
326
+ - API reference: [docs.hoodcompute.com](https://docs.hoodcompute.com)
327
+ - Concept and architecture: [hoodcompute.com](https://hoodcompute.com)
328
+ - Explorer: [robinhoodchain.blockscout.com](https://robinhoodchain.blockscout.com)
329
+
330
+ ## License
331
+
332
+ MIT