@smoothcodes/agent-client 0.2.3 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @smoothcodes/agent-client
2
2
 
3
+ ## 0.3.0
4
+
5
+ - `watch(chatId).send()` durável: se o socket não confirmar em 2 s (`stream.sendFallbackMs`), a mensagem vai pelo REST `POST /v3/chats/{id}/messages` com o MESMO messageId (`clientMessageId` e `Idempotency-Key`); o servidor deduplica, nunca 2x. Gravada pelo REST, aparece em `local.sending` como `pending`. Antes, com o socket fechado a mensagem ficava só na memória do navegador e se perdia.
6
+ - `close()` não deixa espera pendurada: o `send` não confirmado vai pelo REST na hora e resolve gravado; se nem isso der, rejeita com `SendNotConfirmedError` (`reason`, `messageId`, `content`, `mode`) pro app reenviar. Os outros comandos (stop/respond/reset/fila/troca) rejeitam com `CommandAbortedError` (`ref`). Mensagem continua `stream closed` (compatível).
7
+ - `send(content, { timeoutMs })`: rejeita com `SendNotConfirmedError` `reason: 'timeout'` se nada confirmou no prazo (reenviar com o mesmo `messageId` é seguro). O `timeoutMs` só para de esperar: NÃO cancela o envio pelo socket, então a mensagem ainda pode chegar à fila depois, e a ordem dela em relação aos `send` seguintes não é garantida.
8
+ - Os envios pelo REST saem em ordem por chat, um por vez (B nunca passa na frente de A). Com o servidor fora, a nova tentativa espera cada vez mais (5 s, dobrando, até 60 s).
9
+ - Exporta `SendNotConfirmedError` e `CommandAbortedError`.
10
+
3
11
  ## 0.2.3
4
12
 
5
13
  - `files.upload` agora envia o arquivo: o tipo virou `file: Uploadable` (obrigatório; `Blob`, `File`, `Buffer`/`Uint8Array`, `ReadableStream`, `{ data, filename, contentType }` ou, no Node, `{ path }`) e a parte `file` vai no multipart. Até a 0.2.2 o campo era `file?: unknown` e só array/Set era anexado, então `files.upload({ file: blob })` saía sem o arquivo.
@@ -11351,6 +11351,62 @@ var serverEnv = {
11351
11351
  }
11352
11352
  };
11353
11353
 
11354
+ // ../core-live/src/ids.ts
11355
+ function newMessageId(nowMs = Date.now()) {
11356
+ return "msg_" + uuidv7(nowMs);
11357
+ }
11358
+ function uuidv7(nowMs = Date.now()) {
11359
+ const bytes = new Uint8Array(16);
11360
+ globalThis.crypto.getRandomValues(bytes);
11361
+ let ts = BigInt(Math.floor(nowMs));
11362
+ for (let i = 5; i >= 0; i--) {
11363
+ bytes[i] = Number(ts & 0xffn);
11364
+ ts >>= 8n;
11365
+ }
11366
+ bytes[6] = bytes[6] & 15 | 112;
11367
+ bytes[8] = bytes[8] & 63 | 128;
11368
+ const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
11369
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
11370
+ }
11371
+
11372
+ // ../../../contract/events/ts/src/gen/known.ts
11373
+ var KNOWN_ERROR_CODES = ["unauthorized", "forbidden", "not_found", "invalid_request", "provider_not_connected", "provider_auth_expired", "provider_error", "usage_limit_reached", "plan_limit", "rate_limited", "box_unavailable", "conflict", "machine_offline", "request_expired", "no_run", "queue_full", "internal"];
11374
+
11375
+ // ../core-live/src/rest.ts
11376
+ function idempotencyHeaders() {
11377
+ return { "Idempotency-Key": () => "idk_" + uuidv7() };
11378
+ }
11379
+ var SEND_ATTEMPTS = 6;
11380
+ function transient(e, errors) {
11381
+ if (e instanceof errors.timeout) return true;
11382
+ if (!(e instanceof errors.api)) return false;
11383
+ const { statusCode, body } = e;
11384
+ const retryable = body?.error?.retryable;
11385
+ if (retryable === false) return false;
11386
+ if (statusCode === 409) return retryable === true;
11387
+ return statusCode === void 0 || statusCode === 408 || statusCode === 429 || statusCode >= 500;
11388
+ }
11389
+ function apiErrorBody(e) {
11390
+ const err = e?.body?.error;
11391
+ if (!err || typeof err !== "object" || typeof err.code !== "string") return void 0;
11392
+ return { ...err, code: KNOWN_ERROR_CODES.includes(err.code) ? err.code : "internal", message: String(err.message ?? ""), retryable: err.retryable === true };
11393
+ }
11394
+ function sendBody(req) {
11395
+ const clientMessageId = req.clientMessageId ?? newMessageId();
11396
+ return { ...req, clientMessageId, "Idempotency-Key": req["Idempotency-Key"] ?? clientMessageId };
11397
+ }
11398
+ async function untilStored(call2, o) {
11399
+ const attempts = o.attempts ?? SEND_ATTEMPTS;
11400
+ for (let n = 0; ; n++) {
11401
+ try {
11402
+ return await call2();
11403
+ } catch (e) {
11404
+ if (n + 1 >= attempts || !o.isTransient(e) || o.abortSignal?.aborted) throw e;
11405
+ await new Promise((res) => o.clock.setTimeout(res, 1e3 * 2 ** n * (0.75 + 0.5 * Math.random())));
11406
+ }
11407
+ }
11408
+ }
11409
+
11354
11410
  // ../core-live/src/wasm/live.js
11355
11411
  var live_exports = {};
11356
11412
  __export(live_exports, {
@@ -13586,30 +13642,9 @@ var Edge = class {
13586
13642
  }
13587
13643
  };
13588
13644
 
13589
- // ../core-live/src/ids.ts
13590
- function newMessageId(nowMs = Date.now()) {
13591
- return "msg_" + uuidv7(nowMs);
13592
- }
13593
- function uuidv7(nowMs = Date.now()) {
13594
- const bytes = new Uint8Array(16);
13595
- globalThis.crypto.getRandomValues(bytes);
13596
- let ts = BigInt(Math.floor(nowMs));
13597
- for (let i = 5; i >= 0; i--) {
13598
- bytes[i] = Number(ts & 0xffn);
13599
- ts >>= 8n;
13600
- }
13601
- bytes[6] = bytes[6] & 15 | 112;
13602
- bytes[8] = bytes[8] & 63 | 128;
13603
- const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
13604
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13605
- }
13606
-
13607
13645
  // ../core-live/src/wasm/empty.ts
13608
13646
  var EMPTY_STATE_JSON = '{"seq":0,"chat":{"state":"idle"},"items":{},"order":[],"history":[],"tasks":{},"pending":{},"limits":{},"usage":{"chat":{}},"runs":[],"switches":[]}';
13609
13647
 
13610
- // ../../../contract/events/ts/src/gen/known.ts
13611
- var KNOWN_ERROR_CODES = ["unauthorized", "forbidden", "not_found", "invalid_request", "provider_not_connected", "provider_auth_expired", "provider_error", "usage_limit_reached", "plan_limit", "rate_limited", "box_unavailable", "conflict", "machine_offline", "request_expired", "no_run", "queue_full", "internal"];
13612
-
13613
13648
  // ../core-live/src/backoff.ts
13614
13649
  var DEFAULT_BACKOFF = {
13615
13650
  baseMs: 250,
@@ -13739,6 +13774,35 @@ function toContentParts(content, attachments = []) {
13739
13774
  }
13740
13775
 
13741
13776
  // ../core-live/src/watch.ts
13777
+ var SendNotConfirmedError = class extends Error {
13778
+ constructor(reason, messageId, content, mode, cause) {
13779
+ super(reason === "closed" ? "stream closed" : reason === "timeout" ? "send: sem confirma\xE7\xE3o no prazo" : "send: n\xE3o confirmado");
13780
+ this.reason = reason;
13781
+ this.messageId = messageId;
13782
+ this.content = content;
13783
+ this.mode = mode;
13784
+ this.cause = cause;
13785
+ }
13786
+ name = "SendNotConfirmedError";
13787
+ };
13788
+ var CommandAbortedError = class extends Error {
13789
+ constructor(ref) {
13790
+ super("stream closed");
13791
+ this.ref = ref;
13792
+ }
13793
+ name = "CommandAbortedError";
13794
+ };
13795
+ var SEND_FALLBACK_MS = 2e3;
13796
+ var REST_RETRY_MS = 5e3;
13797
+ var REST_RETRY_MAX_MS = 6e4;
13798
+ function safeCause(e) {
13799
+ const x = e ?? {};
13800
+ const out = new Error(typeof x.message === "string" ? x.message : String(e));
13801
+ if (typeof x.name === "string") out.name = x.name;
13802
+ if (typeof x.status === "number") out.status = x.status;
13803
+ if (typeof x.code === "string") out.code = x.code;
13804
+ return out;
13805
+ }
13742
13806
  var EMPTY_INBOX = { version: -1, pending: [], queue: [], notDelivered: [], responses: [] };
13743
13807
  var EMPTY_QUEUE = { version: -1, owner: "cold", turn: "idle", items: [], notDelivered: [] };
13744
13808
  var LiveChat = class {
@@ -13770,6 +13834,17 @@ var LiveChat = class {
13770
13834
  eventTaps = /* @__PURE__ */ new Set();
13771
13835
  waiting = /* @__PURE__ */ new Map();
13772
13836
  historyWaiting = /* @__PURE__ */ new Map();
13837
+ /** os `send` esperando, NA ORDEM em que foram mandados (o Map guarda a ordem de inserção) */
13838
+ sends = /* @__PURE__ */ new Map();
13839
+ /** a corrente do REST: um pedido por vez, em ordem (B nunca passa na frente de A) */
13840
+ restBusy = false;
13841
+ restRetry = null;
13842
+ /** falhas de vez seguidas da corrente (a espera cresce; zera quando uma grava) */
13843
+ restFails = 0;
13844
+ /** gravados pelo REST e ainda em `local.sending` do núcleo (que não viu o ack): a tela mostra `pending` */
13845
+ restStored = /* @__PURE__ */ new Map();
13846
+ /** o `local.sending` como o núcleo mandou (antes da sobreposição do REST) */
13847
+ coreLocal = [];
13773
13848
  /** itens que vieram de páginas do histórico (não estão na timeline viva) */
13774
13849
  pageItems = /* @__PURE__ */ new Map();
13775
13850
  historyIds = [];
@@ -13803,13 +13878,130 @@ var LiveChat = class {
13803
13878
  return this.o.chatId;
13804
13879
  }
13805
13880
  // ------------------------------------------------------------------ comandos
13806
- /** Manda uma mensagem. Aparece na hora em `local.sending`; sai quando a inbox do log a mostra. */
13881
+ /**
13882
+ * Manda uma mensagem. Aparece na hora em `local.sending`; sai quando a inbox do log a mostra. Resolve quando
13883
+ * gravada: pelo socket ou, se ele não confirmar em `sendFallbackMs`, pelo REST com o mesmo messageId (o servidor
13884
+ * deduplica). `timeoutMs`: rejeita com `SendNotConfirmedError` ('timeout') se nada confirmou no prazo.
13885
+ *
13886
+ * O `timeoutMs` só desiste de ESPERAR: não cancela o envio pelo socket (o núcleo segue reenviando aquele frame
13887
+ * até o ack ou o `close()`), então a mensagem ainda pode chegar à fila depois do timeout — e, chegando, a ordem
13888
+ * relativa dela com os `send` seguintes não é garantida (o caminho do REST também não espera mais por ela).
13889
+ * Reenviar com o mesmo `messageId` é seguro (o servidor deduplica).
13890
+ */
13807
13891
  async send(content, opts = {}) {
13808
13892
  const messageId = opts.messageId ?? newMessageId(this.d.clock.now());
13809
- const parts = JSON.stringify(toContentParts(content, opts.attachments));
13810
- const r = await this.wait(`send:${messageId}`, (c, e) => c.send(...e, messageId, parts, opts.mode ?? "auto"));
13893
+ const parts = toContentParts(content, opts.attachments);
13894
+ const mode = opts.mode ?? "auto";
13895
+ if (this.closed) throw new SendNotConfirmedError("closed", messageId, parts, mode);
13896
+ const r = await new Promise((resolve, reject) => {
13897
+ const prev = this.sends.get(messageId);
13898
+ if (prev && !prev.done) {
13899
+ prev.done = true;
13900
+ for (const t of prev.timers) this.d.clock.clearTimeout(t);
13901
+ }
13902
+ const ps = {
13903
+ messageId,
13904
+ content: parts,
13905
+ mode,
13906
+ timers: [],
13907
+ rest: false,
13908
+ done: false,
13909
+ resolve: prev ? (x) => (prev.resolve(x), resolve(x)) : resolve,
13910
+ reject: prev ? (e) => (prev.reject(e), reject(e)) : reject
13911
+ };
13912
+ this.sends.set(messageId, ps);
13913
+ const fallback = this.o.sendFallbackMs ?? SEND_FALLBACK_MS;
13914
+ if (this.d.postMessage && Number.isFinite(fallback)) ps.timers.push(this.d.clock.setTimeout(() => this.viaRest(ps), Math.max(0, fallback)));
13915
+ if (opts.timeoutMs !== void 0 && Number.isFinite(opts.timeoutMs))
13916
+ ps.timers.push(this.d.clock.setTimeout(() => this.settleSend(ps, new SendNotConfirmedError("timeout", messageId, parts, mode)), Math.max(0, opts.timeoutMs)));
13917
+ this.waiting.set(`send:${messageId}`, {
13918
+ resolve: (x) => this.settleSend(ps, x),
13919
+ // o núcleo desistiu (fechou): vale o REST, se houver
13920
+ reject: (e) => this.coreGaveUp(ps, e)
13921
+ });
13922
+ this.edge.run((c, e) => c.send(...e, messageId, JSON.stringify(parts), mode));
13923
+ });
13811
13924
  return { ...r, messageId };
13812
13925
  }
13926
+ /** Pede o caminho durável pra este send (e, pela ordem, pra todos os anteriores ainda esperando). */
13927
+ viaRest(ps) {
13928
+ if (ps.done || !this.d.postMessage) return;
13929
+ ps.rest = true;
13930
+ this.pumpRest();
13931
+ }
13932
+ /**
13933
+ * A corrente do REST, por chat: grava UM por vez, na ordem dos `send`. A cabeça é o send mais antigo ainda
13934
+ * esperando; se algum depois dela pediu o REST, ela vai antes (a fila no servidor fica na ordem em que o usuário
13935
+ * mandou). A cabeça confirmada (por qualquer caminho) libera a próxima. Falhou de vez: com o chat aberto a corrente
13936
+ * para e tenta de novo com espera crescente, 5 s até 60 s (o socket também segue tentando); fechado, a cabeça e TODAS as de trás
13937
+ * rejeitam — nenhuma pula a que não foi gravada.
13938
+ */
13939
+ pumpRest() {
13940
+ if (this.restBusy || !this.d.postMessage) return;
13941
+ const order = [...this.sends.values()].filter((x) => !x.done);
13942
+ const head = order[0];
13943
+ if (!head || !order.some((x) => x.rest)) return;
13944
+ if (this.restRetry !== null) {
13945
+ this.d.clock.clearTimeout(this.restRetry);
13946
+ this.restRetry = null;
13947
+ }
13948
+ this.restBusy = true;
13949
+ this.d.postMessage(this.o.chatId, { clientMessageId: head.messageId, content: head.content, mode: head.mode }).then(
13950
+ (r) => {
13951
+ this.restBusy = false;
13952
+ this.restFails = 0;
13953
+ if (r.status === "accepted" || r.status === "duplicate") this.markStored(head.messageId, r.version ?? r.inboxVersion);
13954
+ this.settleSend(head, r);
13955
+ this.pumpRest();
13956
+ },
13957
+ (e) => {
13958
+ this.restBusy = false;
13959
+ if (head.done) return this.pumpRest();
13960
+ if (this.closed) {
13961
+ const cause = safeCause(e);
13962
+ this.restBusy = true;
13963
+ for (const x of [...this.sends.values()].filter((y) => !y.done)) this.settleSend(x, new SendNotConfirmedError("failed", x.messageId, x.content, x.mode, cause));
13964
+ this.restBusy = false;
13965
+ return;
13966
+ }
13967
+ const wait = Math.min(REST_RETRY_MAX_MS, REST_RETRY_MS * 2 ** this.restFails++);
13968
+ this.restRetry = this.d.clock.setTimeout(() => {
13969
+ this.restRetry = null;
13970
+ this.pumpRest();
13971
+ }, wait);
13972
+ }
13973
+ );
13974
+ }
13975
+ coreGaveUp(ps, e) {
13976
+ if (ps.done) return;
13977
+ if (this.d.postMessage) this.viaRest(ps);
13978
+ else this.settleSend(ps, new SendNotConfirmedError("closed", ps.messageId, ps.content, ps.mode, e));
13979
+ }
13980
+ settleSend(ps, r) {
13981
+ if (ps.done) return;
13982
+ ps.done = true;
13983
+ for (const t of ps.timers) this.d.clock.clearTimeout(t);
13984
+ if (this.sends.get(ps.messageId) === ps) this.sends.delete(ps.messageId);
13985
+ if (r instanceof Error) ps.reject(r);
13986
+ else ps.resolve(r);
13987
+ if (!this.restBusy) this.pumpRest();
13988
+ }
13989
+ /** Gravado pelo REST: no `local.sending` passa de `sending` a `pending` (o núcleo não viu o ack). */
13990
+ markStored(messageId, version) {
13991
+ if (this.closed || !this.coreLocal.some((l) => l.messageId === messageId)) return;
13992
+ this.restStored.set(messageId, version);
13993
+ this.state = { ...this.state, local: { sending: this.overlayLocal() } };
13994
+ for (const l of this.listeners) l(this.state);
13995
+ }
13996
+ overlayLocal() {
13997
+ for (const id of [...this.restStored.keys()]) if (!this.coreLocal.some((l) => l.messageId === id)) this.restStored.delete(id);
13998
+ if (!this.restStored.size) return this.coreLocal;
13999
+ return this.coreLocal.map((l) => {
14000
+ if (l.status !== "sending" || !this.restStored.has(l.messageId)) return l;
14001
+ const v = this.restStored.get(l.messageId);
14002
+ return { ...l, status: "pending", ...v !== void 0 ? { ackVersion: v } : {} };
14003
+ });
14004
+ }
13813
14005
  stop() {
13814
14006
  const stopId = uuidv7(this.d.clock.now());
13815
14007
  return this.command({ t: "stop", ref: `stop:${stopId}`, chatId: this.o.chatId, stopId });
@@ -13878,6 +14070,11 @@ var LiveChat = class {
13878
14070
  tokenRenewed(token) {
13879
14071
  this.edge.run((c, e) => c.token_renewed(...e, token));
13880
14072
  }
14073
+ /**
14074
+ * Fecha. Nenhuma espera fica pendurada: o `send` não confirmado vai pelo REST (mesmo messageId) e resolve quando
14075
+ * gravado; sem REST, rejeita com `SendNotConfirmedError` ('closed', com a mensagem). Os demais comandos
14076
+ * rejeitam com `CommandAbortedError`.
14077
+ */
13881
14078
  close() {
13882
14079
  if (this.closed) return;
13883
14080
  this.edge.run((c, e) => c.close(...e));
@@ -13886,6 +14083,11 @@ var LiveChat = class {
13886
14083
  this.edge.stop();
13887
14084
  this.listeners.clear();
13888
14085
  this.eventTaps.clear();
14086
+ const left = [...this.waiting];
14087
+ this.waiting.clear();
14088
+ for (const [ref, w] of left) w.reject(new CommandAbortedError(ref));
14089
+ for (const ps of [...this.sends.values()]) this.coreGaveUp(ps, new Error("stream closed"));
14090
+ this.pumpRest();
13889
14091
  }
13890
14092
  // ------------------------------------------------------------------ histórico (§4.9)
13891
14093
  history = {
@@ -13950,7 +14152,7 @@ var LiveChat = class {
13950
14152
  case "reject": {
13951
14153
  const w = this.waiting.get(f.ref);
13952
14154
  this.waiting.delete(f.ref);
13953
- return w?.reject(new Error(String(f.v)));
14155
+ return w?.reject(String(f.v) === "stream closed" ? new CommandAbortedError(f.ref) : new Error(String(f.v)));
13954
14156
  }
13955
14157
  }
13956
14158
  }
@@ -13983,7 +14185,7 @@ var LiveChat = class {
13983
14185
  inbox: p.inbox ?? prev.inbox,
13984
14186
  needsProvider: p.needsProvider !== void 0 ? p.needsProvider : prev.needsProvider,
13985
14187
  box: p.box !== void 0 ? p.box : prev.box,
13986
- local: p.local ? { sending: p.local } : prev.local,
14188
+ local: p.local ? { sending: (this.coreLocal = p.local, this.overlayLocal()) } : prev.local,
13987
14189
  history,
13988
14190
  sync: p.sync ?? prev.sync
13989
14191
  };
@@ -14206,6 +14408,10 @@ var ChatListLive = class {
14206
14408
  };
14207
14409
 
14208
14410
  // ../core-live/src/client.ts
14411
+ function restTransient(e) {
14412
+ const st = e?.status;
14413
+ return st === void 0 || st === 408 || st === 429 || st >= 500;
14414
+ }
14209
14415
  var LiveClient = class {
14210
14416
  constructor(o) {
14211
14417
  this.o = o;
@@ -14374,9 +14580,32 @@ var LiveClient = class {
14374
14580
  if (res.status === 403 || res.status === 404) return "forbidden";
14375
14581
  return "ok";
14376
14582
  },
14377
- history: async (id, q) => fromControlPage(id, await this.json(`/chats/${encodeURIComponent(id)}/history?${historyQs(q)}`))
14583
+ history: async (id, q) => fromControlPage(id, await this.json(`/chats/${encodeURIComponent(id)}/history?${historyQs(q)}`)),
14584
+ postMessage: (id, m) => this.postMessage(id, m)
14378
14585
  };
14379
14586
  }
14587
+ /**
14588
+ * O caminho durável do `send` (REST `SendMessage`): a mesma fila fria do ChatLog, deduplicada pelo
14589
+ * `clientMessageId` (= o messageId do socket) e pela Idempotency-Key (a mesma). Falha passageira: repete com
14590
+ * espera (`untilStored`) e, esgotado, rejeita; recusa do servidor = `rejected` com o código do §6.
14591
+ */
14592
+ async postMessage(id, m) {
14593
+ const call2 = () => this.json(`/chats/${encodeURIComponent(id)}/messages`, {
14594
+ method: "POST",
14595
+ body: JSON.stringify(m),
14596
+ headers: { "Content-Type": "application/json", "Idempotency-Key": m.clientMessageId }
14597
+ });
14598
+ try {
14599
+ const r = await untilStored(call2, { clock: this.clock, isTransient: (e) => restTransient(e) });
14600
+ const v = r.inboxVersion ?? 0;
14601
+ return r.status === "duplicate" ? { status: "duplicate", messageId: m.clientMessageId, inboxVersion: v } : { status: "accepted", messageId: m.clientMessageId, inboxVersion: v };
14602
+ } catch (e) {
14603
+ if (restTransient(e)) throw e;
14604
+ const err = e;
14605
+ const code = KNOWN_ERROR_CODES.includes(err.code ?? "") ? err.code : "internal";
14606
+ return { status: "rejected", code, message: err.message ?? code };
14607
+ }
14608
+ }
14380
14609
  async json(path, init) {
14381
14610
  const res = await this.fetch(`${this.api}${path}`, { ...init, headers: { Accept: "application/json", ...init?.headers ?? {} } });
14382
14611
  if (!res.ok) {
@@ -14438,41 +14667,6 @@ function browserEnv() {
14438
14667
  };
14439
14668
  }
14440
14669
 
14441
- // ../core-live/src/rest.ts
14442
- function idempotencyHeaders() {
14443
- return { "Idempotency-Key": () => "idk_" + uuidv7() };
14444
- }
14445
- var SEND_ATTEMPTS = 6;
14446
- function transient(e, errors) {
14447
- if (e instanceof errors.timeout) return true;
14448
- if (!(e instanceof errors.api)) return false;
14449
- const { statusCode, body } = e;
14450
- const retryable = body?.error?.retryable;
14451
- if (retryable === false) return false;
14452
- if (statusCode === 409) return retryable === true;
14453
- return statusCode === void 0 || statusCode === 408 || statusCode === 429 || statusCode >= 500;
14454
- }
14455
- function apiErrorBody(e) {
14456
- const err = e?.body?.error;
14457
- if (!err || typeof err !== "object" || typeof err.code !== "string") return void 0;
14458
- return { ...err, code: KNOWN_ERROR_CODES.includes(err.code) ? err.code : "internal", message: String(err.message ?? ""), retryable: err.retryable === true };
14459
- }
14460
- function sendBody(req) {
14461
- const clientMessageId = req.clientMessageId ?? newMessageId();
14462
- return { ...req, clientMessageId, "Idempotency-Key": req["Idempotency-Key"] ?? clientMessageId };
14463
- }
14464
- async function untilStored(call2, o) {
14465
- const attempts = o.attempts ?? SEND_ATTEMPTS;
14466
- for (let n = 0; ; n++) {
14467
- try {
14468
- return await call2();
14469
- } catch (e) {
14470
- if (n + 1 >= attempts || !o.isTransient(e) || o.abortSignal?.aborted) throw e;
14471
- await new Promise((res) => o.clock.setTimeout(res, 1e3 * 2 ** n * (0.75 + 0.5 * Math.random())));
14472
- }
14473
- }
14474
- }
14475
-
14476
14670
  // ../core-live/src/providers.ts
14477
14671
  var TERMINAL = /* @__PURE__ */ new Set(["connected", "expired", "failed", "cancelled"]);
14478
14672
  var PROVIDER_POLL_MS = 2e3;
@@ -14845,9 +15039,11 @@ export {
14845
15039
  SmoothAgentApiError,
14846
15040
  SmoothAgentApiTimeoutError,
14847
15041
  apiErrorBody,
15042
+ SendNotConfirmedError,
15043
+ CommandAbortedError,
14848
15044
  sortProviders,
14849
15045
  ProviderSet,
14850
15046
  DEFAULT_BASE_URL,
14851
15047
  SmoothAgent
14852
15048
  };
14853
- //# sourceMappingURL=chunk-ERJ5SQDU.js.map
15049
+ //# sourceMappingURL=chunk-4HQLFTS2.js.map