codai-sdk 0.4.0 → 0.6.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/README.md +75 -2
- package/dist/index.d.ts +2591 -1560
- package/dist/index.js +237 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,6 +65,7 @@ surface.
|
|
|
65
65
|
| `receipt` | `get` | `GET /v1/receipt` |
|
|
66
66
|
| `feedback` | `submit` | `POST /v1/feedback` |
|
|
67
67
|
| `phoneModels` | `list` | `GET /v1/phone/models` |
|
|
68
|
+
| `resolve` | `submit`, `get`, `accept`, `attestation`, `health`, `waitFor` | `https://resolve.codai.ro/v1/resolve/*` (own host) |
|
|
68
69
|
|
|
69
70
|
Every method takes an optional last argument `{ ext, signal }` where `ext` is a
|
|
70
71
|
typed bag of `X-Codai-*` extension headers (see below).
|
|
@@ -158,6 +159,73 @@ const receipt = await codai.receipt.get({ sessionId: 'my-project' });
|
|
|
158
159
|
receipt.cost_usd;
|
|
159
160
|
```
|
|
160
161
|
|
|
162
|
+
## Resolve — verified bug fixes
|
|
163
|
+
|
|
164
|
+
`client.resolve` talks to the separate Resolve service (`https://resolve.codai.ro`,
|
|
165
|
+
override with `resolveBaseUrl`) with the same API key. You submit a public GitHub
|
|
166
|
+
repo + issue, triage quotes a tier (or declines), you accept, and only a verified
|
|
167
|
+
fix is billed — with a public attestation. Amounts are USD micros.
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { ResolveInsufficientFundsError } from 'codai-sdk';
|
|
171
|
+
|
|
172
|
+
const q = await codai.resolve.submit({
|
|
173
|
+
repo_url: 'https://github.com/psf/requests',
|
|
174
|
+
issue_url: 'https://github.com/psf/requests/issues/6000', // or issue_text
|
|
175
|
+
test_command: 'python -m pytest -q tests/test_x.py::test_y', // optional
|
|
176
|
+
});
|
|
177
|
+
if (q.status === 'declined') throw new Error(q.decline_reason);
|
|
178
|
+
|
|
179
|
+
if (q.status === 'quoted') {
|
|
180
|
+
try {
|
|
181
|
+
await codai.resolve.accept(q.id); // free-tier jobs are auto-accepted
|
|
182
|
+
} catch (err) {
|
|
183
|
+
if (err instanceof ResolveInsufficientFundsError) console.log('top up:', err.topupUrl);
|
|
184
|
+
throw err;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const job = await codai.resolve.waitFor(q.id, { intervalMs: 5_000, timeoutMs: 30 * 60_000 });
|
|
189
|
+
if (job.status === 'resolved' && job.attestation_url) {
|
|
190
|
+
const proof = await codai.resolve.attestation(job.attestation_url);
|
|
191
|
+
console.log(proof.patch);
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Errors are `ResolveError` (a `CodaiError` with `status` and `detail` = the flat
|
|
196
|
+
`error` string or Zod details); a `402` on `accept` is `ResolveInsufficientFundsError`
|
|
197
|
+
with `balance`, `required`, `currency: 'micro_eur'` and `topupUrl`. `submit` and
|
|
198
|
+
`accept` are never retried. `waitFor` stops at `resolved | failed | declined | error`
|
|
199
|
+
(or `until`), and throws `ResolveError` with `status: 0` on timeout.
|
|
200
|
+
|
|
201
|
+
### Webhooks instead of polling
|
|
202
|
+
|
|
203
|
+
Pass `callback_url` (https, public host) on `submit`; the response carries
|
|
204
|
+
`callback_secret` **once** — store it. Resolve then POSTs `job.quoted`,
|
|
205
|
+
`job.declined`, `job.resolved`, `job.failed` and `job.error` events signed with
|
|
206
|
+
`x-codai-signature: t=<unix>,v1=<hex HMAC-SHA256>`. Verify against the raw body
|
|
207
|
+
with `verifyResolveWebhook` (server-side, uses `node:crypto`; 300 s tolerance by
|
|
208
|
+
default). Up to 3 attempts on `5xx`/`429`/network errors; deduplicate on
|
|
209
|
+
`x-codai-delivery`; delivery never changes job state — `get(id)` stays the truth.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import { verifyResolveWebhook, type ResolveWebhookEvent } from 'codai-sdk';
|
|
213
|
+
|
|
214
|
+
const q = await codai.resolve.submit({
|
|
215
|
+
repo_url: 'https://github.com/psf/requests',
|
|
216
|
+
issue_url: 'https://github.com/psf/requests/issues/6000',
|
|
217
|
+
callback_url: 'https://ci.example.com/hooks/codai-resolve',
|
|
218
|
+
});
|
|
219
|
+
await saveSecret(q.id, q.callback_secret!); // shown once
|
|
220
|
+
|
|
221
|
+
// in your webhook handler (Hono / Next route / express.raw):
|
|
222
|
+
const raw = await req.text();
|
|
223
|
+
if (!verifyResolveWebhook(secret, raw, req.headers.get('x-codai-signature'))) {
|
|
224
|
+
return new Response('bad signature', { status: 401 });
|
|
225
|
+
}
|
|
226
|
+
const evt = JSON.parse(raw) as ResolveWebhookEvent; // evt.event, evt.job.attestation_url
|
|
227
|
+
```
|
|
228
|
+
|
|
161
229
|
## Shared sessions, devices and hosts
|
|
162
230
|
|
|
163
231
|
Shared-sessions and hosts calls need a device UUID (`x-codai-device`). Set it once
|
|
@@ -240,6 +308,7 @@ const models = await codai.models();
|
|
|
240
308
|
const codai = new Codai({
|
|
241
309
|
apiKey: process.env.CODAI_API_KEY!,
|
|
242
310
|
baseUrl: 'https://ai.codai.ro', // default
|
|
311
|
+
resolveBaseUrl: 'https://resolve.codai.ro', // default (client.resolve)
|
|
243
312
|
sessionId: 'my-project', // enables session memory + stickiness
|
|
244
313
|
device: '<uuid>', // shared sessions / hosts (x-codai-device)
|
|
245
314
|
client: 'my-app/1.2.0', // x-codai-client surface tag
|
|
@@ -287,8 +356,12 @@ import type { components, Task, SessionStreamEvent } from 'codai-sdk';
|
|
|
287
356
|
type Receipt = components['schemas']['AccountReceipt'];
|
|
288
357
|
```
|
|
289
358
|
|
|
290
|
-
|
|
291
|
-
|
|
359
|
+
Resolve types are exported as `ResolvePaths`, `ResolveComponents` and
|
|
360
|
+
`ResolveOperations` (plus aliases such as `ResolveJob`, `ResolveQuote`).
|
|
361
|
+
|
|
362
|
+
Regenerate after a spec change with `pnpm gen` (gateway + resolve);
|
|
363
|
+
`operations.test.ts` and `operations.resolve.test.ts` fail when a spec and the
|
|
364
|
+
client drift.
|
|
292
365
|
|
|
293
366
|
## Migrating from the OpenAI SDK
|
|
294
367
|
|