codai-sdk 0.4.0 → 0.5.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/dist/index.js CHANGED
@@ -1219,6 +1219,173 @@ var Projects = class {
1219
1219
  }
1220
1220
  };
1221
1221
 
1222
+ // src/resources/resolve.ts
1223
+ var RESOLVE_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
1224
+ "resolved",
1225
+ "failed",
1226
+ "declined",
1227
+ "error"
1228
+ ]);
1229
+ var ResolveError = class extends CodaiError {
1230
+ /** The `error` field of the body: a message, or Zod `flatten()` details on a 400. */
1231
+ detail;
1232
+ constructor(message, status, body, meta = {}) {
1233
+ super(message, status, body, meta);
1234
+ this.name = "ResolveError";
1235
+ this.detail = extractDetail(body);
1236
+ }
1237
+ };
1238
+ var ResolveInsufficientFundsError = class extends ResolveError {
1239
+ /** Wallet balance, in `currency` units (EUR micros). */
1240
+ balance;
1241
+ /** Amount the hold needs, in `currency` units (EUR micros). */
1242
+ required;
1243
+ currency;
1244
+ /** pay.codai.ro checkout link for the shortfall — open it, then retry `accept()`. */
1245
+ topupUrl;
1246
+ constructor(message, body, meta = {}) {
1247
+ super(message, 402, body, meta);
1248
+ this.name = "ResolveInsufficientFundsError";
1249
+ this.balance = body.balance;
1250
+ this.required = body.required;
1251
+ this.currency = body.currency;
1252
+ this.topupUrl = body.topup_url;
1253
+ }
1254
+ };
1255
+ var Resolve = class {
1256
+ constructor(http) {
1257
+ this.http = http;
1258
+ }
1259
+ http;
1260
+ /**
1261
+ * `POST /v1/resolve/jobs` — submit a public GitHub repo + issue for triage.
1262
+ * Returns a quote (`status: 'quoted'`), a free-tier auto-accept
1263
+ * (`status: 'accepted'`) or a decline (`status: 'declined'`). Never retried:
1264
+ * a retry could create a second job.
1265
+ */
1266
+ submit(body, opts = {}) {
1267
+ if (!body.issue_url && !body.issue_text)
1268
+ throw new TypeError("resolve.submit: one of issue_url or issue_text is required");
1269
+ return this.call("/v1/resolve/jobs", {
1270
+ method: "POST",
1271
+ body,
1272
+ noRetry: true,
1273
+ signal: opts.signal
1274
+ });
1275
+ }
1276
+ /** `GET /v1/resolve/jobs/{id}` — status, quote, reasons, cost and attestation pointer. */
1277
+ get(id, opts = {}) {
1278
+ return this.call(`/v1/resolve/jobs/${encodeURIComponent(id)}`, {
1279
+ signal: opts.signal
1280
+ });
1281
+ }
1282
+ /**
1283
+ * `POST /v1/resolve/jobs/{id}/accept` — accept a paid quote and start the job.
1284
+ * Throws `ResolveInsufficientFundsError` (402, carries `topupUrl`) when the
1285
+ * wallet is short, `ResolveError` 409 when the job is not `quoted`.
1286
+ */
1287
+ accept(id, opts = {}) {
1288
+ return this.call(`/v1/resolve/jobs/${encodeURIComponent(id)}/accept`, {
1289
+ method: "POST",
1290
+ rawBody: "",
1291
+ // no body — sent with content-length: 0
1292
+ noRetry: true,
1293
+ signal: opts.signal
1294
+ });
1295
+ }
1296
+ /**
1297
+ * `GET /v1/resolve/attestations/{id}` — public execution proof (no auth needed
1298
+ * server-side). Accepts the attestation id or the job's `attestation_url`.
1299
+ */
1300
+ attestation(idOrUrl, opts = {}) {
1301
+ const id = idOrUrl.replace(/^.*\/v1\/resolve\/attestations\//, "");
1302
+ return this.call(`/v1/resolve/attestations/${encodeURIComponent(id)}`, {
1303
+ signal: opts.signal
1304
+ });
1305
+ }
1306
+ /** `GET /health` — liveness of the Resolve service. */
1307
+ health(opts = {}) {
1308
+ return this.call("/health", { signal: opts.signal });
1309
+ }
1310
+ /**
1311
+ * Poll `get(id)` until the job reaches a terminal status (`resolved`,
1312
+ * `failed`, `declined`, `error`) or one of `opts.until`. A `quoted` job
1313
+ * does not move until you `accept()` it.
1314
+ */
1315
+ async waitFor(id, opts = {}) {
1316
+ const intervalMs = opts.intervalMs ?? 5e3;
1317
+ const timeoutMs = opts.timeoutMs ?? 18e5;
1318
+ const until = new Set(opts.until ?? RESOLVE_TERMINAL_STATUSES);
1319
+ const deadline = Date.now() + timeoutMs;
1320
+ for (; ; ) {
1321
+ const job = await this.get(id, { signal: opts.signal });
1322
+ opts.onPoll?.(job);
1323
+ if (until.has(job.status)) return job;
1324
+ const left = deadline - Date.now();
1325
+ if (left <= 0)
1326
+ throw new ResolveError(
1327
+ `codai-resolve job ${id} still ${job.status} after ${timeoutMs} ms`,
1328
+ 0,
1329
+ job
1330
+ );
1331
+ await abortableSleep(Math.min(intervalMs, left), opts.signal);
1332
+ }
1333
+ }
1334
+ async call(path, init) {
1335
+ try {
1336
+ return await this.http.json(path, init);
1337
+ } catch (err) {
1338
+ throw toResolveError(path, err);
1339
+ }
1340
+ }
1341
+ };
1342
+ function extractDetail(body) {
1343
+ if (body && typeof body === "object" && "error" in body) {
1344
+ const e = body.error;
1345
+ if (typeof e === "string") return e;
1346
+ if (e && typeof e === "object") return e;
1347
+ }
1348
+ return null;
1349
+ }
1350
+ function isInsufficientFunds(body) {
1351
+ return !!body && typeof body === "object" && body.error === "insufficient_funds" && typeof body.topup_url === "string";
1352
+ }
1353
+ function toResolveError(path, err) {
1354
+ if (!(err instanceof CodaiError) || err instanceof ResolveError) return err;
1355
+ if (err.status === 0) return err;
1356
+ const meta = { requestId: err.requestId, retryAfter: err.retryAfter };
1357
+ if (err.status === 402 && isInsufficientFunds(err.body)) {
1358
+ const b = err.body;
1359
+ return new ResolveInsufficientFundsError(
1360
+ `codai-resolve ${path} \u2192 402: insufficient funds (balance ${b.balance}, required ${b.required} ${b.currency}); top up at ${b.topup_url}`,
1361
+ b,
1362
+ meta
1363
+ );
1364
+ }
1365
+ const detail = extractDetail(err.body);
1366
+ const text = detail === null ? "" : `: ${typeof detail === "string" ? detail : JSON.stringify(detail)}`;
1367
+ return new ResolveError(
1368
+ `codai-resolve ${path} \u2192 ${err.status}${text}`,
1369
+ err.status,
1370
+ err.body,
1371
+ meta
1372
+ );
1373
+ }
1374
+ function abortableSleep(ms, signal) {
1375
+ return new Promise((resolve, reject) => {
1376
+ if (signal?.aborted) return reject(signal.reason);
1377
+ const onAbort = () => {
1378
+ clearTimeout(t);
1379
+ reject(signal?.reason);
1380
+ };
1381
+ const t = setTimeout(() => {
1382
+ signal?.removeEventListener("abort", onAbort);
1383
+ resolve();
1384
+ }, ms);
1385
+ signal?.addEventListener("abort", onAbort, { once: true });
1386
+ });
1387
+ }
1388
+
1222
1389
  // src/resources/responses.ts
1223
1390
  var Responses = class {
1224
1391
  constructor(http) {
@@ -1663,6 +1830,14 @@ var Notifications = class {
1663
1830
  markRead(ids, opts = {}) {
1664
1831
  return this.http.json("/v1/notifications/read", { method: "POST", body: ids ? { ids } : {}, ext: opts.ext, signal: opts.signal });
1665
1832
  }
1833
+ /** `DELETE /v1/notifications/:id` — `{ deleted: 0 }` when the id is missing or not yours. */
1834
+ delete(id, opts = {}) {
1835
+ return this.http.json(`/v1/notifications/${encodeURIComponent(String(id))}`, { method: "DELETE", ext: opts.ext, signal: opts.signal });
1836
+ }
1837
+ /** `POST /v1/notifications/delete` — 1..200 ids; ids of other users are skipped. */
1838
+ deleteMany(ids, opts = {}) {
1839
+ return this.http.json("/v1/notifications/delete", { method: "POST", body: { ids }, ext: opts.ext, signal: opts.signal });
1840
+ }
1666
1841
  };
1667
1842
 
1668
1843
  // src/resources/tokens.ts
@@ -1756,6 +1931,8 @@ var OPERATION_METHODS = {
1756
1931
  receiveTriggerHook: "triggers.fireHook",
1757
1932
  listNotifications: "notifications.list",
1758
1933
  markNotificationsRead: "notifications.markRead",
1934
+ deleteNotification: "notifications.delete",
1935
+ deleteNotifications: "notifications.deleteMany",
1759
1936
  // Sessions
1760
1937
  createSession: "sessions.create",
1761
1938
  listSessions: "sessions.list",
@@ -1837,6 +2014,13 @@ var STREAMING_OPERATIONS = /* @__PURE__ */ new Set([
1837
2014
  "streamSession",
1838
2015
  "streamHost"
1839
2016
  ]);
2017
+ var RESOLVE_OPERATION_METHODS = {
2018
+ resolveHealth: "resolve.health",
2019
+ createResolveJob: "resolve.submit",
2020
+ getResolveJob: "resolve.get",
2021
+ acceptResolveJob: "resolve.accept",
2022
+ getResolveAttestation: "resolve.attestation"
2023
+ };
1840
2024
 
1841
2025
  // src/index.ts
1842
2026
  var Codai = class {
@@ -1869,6 +2053,8 @@ var Codai = class {
1869
2053
  receipt;
1870
2054
  feedback;
1871
2055
  phoneModels;
2056
+ /** codai Resolve — execution-verified bug fixes (separate host, `resolveBaseUrl`). */
2057
+ resolve;
1872
2058
  constructor(opts) {
1873
2059
  if (!opts.apiKey) throw new Error("Codai: apiKey is required");
1874
2060
  this.http = new HttpClient({
@@ -1907,6 +2093,16 @@ var Codai = class {
1907
2093
  this.account = new Account(http);
1908
2094
  this.receipt = new Receipts(http);
1909
2095
  this.phoneModels = new PhoneModels(http);
2096
+ this.resolve = new Resolve(
2097
+ new HttpClient({
2098
+ apiKey: opts.apiKey,
2099
+ baseUrl: opts.resolveBaseUrl ?? "https://resolve.codai.ro",
2100
+ timeoutMs: opts.timeoutMs ?? 12e4,
2101
+ maxRetries: opts.maxRetries ?? 2,
2102
+ fetch: opts.fetch,
2103
+ defaults: opts.client ? { client: opts.client } : {}
2104
+ })
2105
+ );
1910
2106
  this.chat = callable(
1911
2107
  new Chat(http),
1912
2108
  (o) => this.chat.completions.create(this.legacyBody(o), {
@@ -1991,6 +2187,6 @@ function allKeys(obj) {
1991
2187
  }
1992
2188
  var index_default = Codai;
1993
2189
 
1994
- export { Account, AgentRuns, Agents, Audio, Chat, ChatCompletions, Codai, CodaiError, Devices, Embeddings, EnvironmentMembers, EnvironmentPorts, EnvironmentSecrets, EnvironmentTasks, Environments, Feedback, Health, Hosts, HttpClient, Messages, Models, Notifications, OPERATION_METHODS, OrgMembers, Orgs, PhoneModels, Projects, Receipts, Responses, STREAMING_OPERATIONS, SessionControls, SessionEvents, SessionLease, SessionShares, Sessions, Tasks, Tokens, Tools, Triggers, index_default as default, extensionHeaders, frameJson, mergeToolCall, readSse };
2190
+ export { Account, AgentRuns, Agents, Audio, Chat, ChatCompletions, Codai, CodaiError, Devices, Embeddings, EnvironmentMembers, EnvironmentPorts, EnvironmentSecrets, EnvironmentTasks, Environments, Feedback, Health, Hosts, HttpClient, Messages, Models, Notifications, OPERATION_METHODS, OrgMembers, Orgs, PhoneModels, Projects, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, Receipts, Resolve, ResolveError, ResolveInsufficientFundsError, Responses, STREAMING_OPERATIONS, SessionControls, SessionEvents, SessionLease, SessionShares, Sessions, Tasks, Tokens, Tools, Triggers, index_default as default, extensionHeaders, frameJson, mergeToolCall, readSse };
1995
2191
  //# sourceMappingURL=index.js.map
1996
2192
  //# sourceMappingURL=index.js.map