@astralform/js 4.8.0 → 4.9.1

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.cjs CHANGED
@@ -784,7 +784,8 @@ var AstralformClient = class {
784
784
  name: a.name,
785
785
  teamId: a.team_id,
786
786
  createdAt: a.created_at,
787
- updatedAt: a.updated_at
787
+ updatedAt: a.updated_at,
788
+ avatarUrl: a.avatar_url ?? null
788
789
  }));
789
790
  }
790
791
  // --- Jobs API ---
@@ -1066,6 +1067,19 @@ function translateAgentIdentity(raw) {
1066
1067
  description: raw.description ?? null
1067
1068
  };
1068
1069
  }
1070
+ function translateTodoItem(raw) {
1071
+ return {
1072
+ id: raw.id ?? 0,
1073
+ subject: raw.subject ?? "",
1074
+ status: raw.status ?? "pending",
1075
+ description: raw.description ?? null,
1076
+ activeForm: raw.active_form ?? null,
1077
+ owner: raw.owner ?? null,
1078
+ blockedBy: raw.blocked_by ?? null,
1079
+ blocks: raw.blocks ?? null,
1080
+ priority: raw.priority ?? null
1081
+ };
1082
+ }
1069
1083
  function translateCustomEvent(name, data) {
1070
1084
  switch (name) {
1071
1085
  case "user_message":
@@ -1082,7 +1096,9 @@ function translateCustomEvent(name, data) {
1082
1096
  case "todo_update":
1083
1097
  return {
1084
1098
  type: "todo_update",
1085
- todos: data.todos ?? []
1099
+ todos: (data.todos ?? []).map(
1100
+ (t) => translateTodoItem(t)
1101
+ )
1086
1102
  };
1087
1103
  case "plan_update":
1088
1104
  return {
@@ -1275,7 +1291,8 @@ function translateWireEvent(wire) {
1275
1291
  usage: {
1276
1292
  inputTokens: wire.usage.input_tokens ?? 0,
1277
1293
  outputTokens: wire.usage.output_tokens ?? 0,
1278
- cachedTokens: wire.usage.cached_tokens ?? 0
1294
+ cachedTokens: wire.usage.cached_tokens ?? 0,
1295
+ cacheCreationTokens: wire.usage.cache_creation_tokens ?? 0
1279
1296
  },
1280
1297
  ttfbMs: wire.ttfb_ms,
1281
1298
  totalMs: wire.total_ms,
@@ -1321,6 +1338,7 @@ function translateWireEvent(wire) {
1321
1338
 
1322
1339
  // src/session.ts
1323
1340
  var SSE_MAX_RECONNECTS = 6;
1341
+ var SSE_STALL_TIMEOUT_MS = 45e3;
1324
1342
  var TOOL_RESULT_MAX_RETRIES = 3;
1325
1343
  var CONVERSATION_PAGE_SIZE = 50;
1326
1344
  function sseReconnectDelayMs(attempt) {
@@ -1483,6 +1501,7 @@ var ChatSession = class {
1483
1501
  agent_name: options?.agentName,
1484
1502
  plan_mode: options?.planMode,
1485
1503
  image_mode: options?.imageMode,
1504
+ video_mode: options?.videoMode,
1486
1505
  goal: options?.goal,
1487
1506
  // Per-request model choice (client-side model selection).
1488
1507
  provider: options?.provider,
@@ -1571,14 +1590,23 @@ var ChatSession = class {
1571
1590
  async consumeEventStream(jobId, conversationId, messageId, executeClientTools) {
1572
1591
  const signal = this.abortController?.signal;
1573
1592
  for (let attempt = 0; ; attempt++) {
1574
- const stream = this.client.streamJobEvents(jobId, this.lastSeq, signal);
1593
+ if (signal?.aborted) return;
1594
+ const attemptController = new AbortController();
1595
+ const linkAbort = () => attemptController.abort();
1596
+ signal?.addEventListener("abort", linkAbort);
1575
1597
  let sawTerminal;
1576
1598
  try {
1599
+ const stream = this.client.streamJobEvents(
1600
+ jobId,
1601
+ this.lastSeq,
1602
+ attemptController.signal
1603
+ );
1577
1604
  sawTerminal = await this.pumpStream(
1578
1605
  stream,
1579
1606
  conversationId,
1580
1607
  messageId,
1581
- executeClientTools
1608
+ executeClientTools,
1609
+ () => attemptController.abort()
1582
1610
  );
1583
1611
  } catch (err) {
1584
1612
  if (signal?.aborted) return;
@@ -1588,6 +1616,8 @@ var ChatSession = class {
1588
1616
  if (attempt >= SSE_MAX_RECONNECTS) throw err;
1589
1617
  await this.sleepUnlessAborted(sseReconnectDelayMs(attempt + 1), signal);
1590
1618
  continue;
1619
+ } finally {
1620
+ signal?.removeEventListener("abort", linkAbort);
1591
1621
  }
1592
1622
  if (sawTerminal || signal?.aborted) return;
1593
1623
  if (attempt >= SSE_MAX_RECONNECTS) {
@@ -1600,35 +1630,66 @@ var ChatSession = class {
1600
1630
  * Consume a single SSE stream to exhaustion. Returns whether a terminal
1601
1631
  * event (``message_stop`` / ``error``) was seen, so the caller can decide
1602
1632
  * whether an ended stream means "turn done" vs "dropped, reconnect".
1633
+ *
1634
+ * ``onStall`` aborts the per-attempt connection: if no event arrives within
1635
+ * SSE_STALL_TIMEOUT_MS (backend keepalives land every 15s), the stream is a
1636
+ * zombie — ``reader.read()`` will never settle — so we kill the fetch and
1637
+ * throw a ConnectionError, feeding the caller's reconnect-from-lastSeq loop.
1603
1638
  */
1604
- async pumpStream(stream, conversationId, messageId, executeClientTools) {
1639
+ async pumpStream(stream, conversationId, messageId, executeClientTools, onStall) {
1605
1640
  let sawTerminal = false;
1606
- for await (const raw of stream) {
1607
- let parsed;
1608
- try {
1609
- const data = JSON.parse(raw.data);
1610
- if (typeof data !== "object" || data === null || typeof data.type !== "string") {
1611
- if (typeof data?.seq === "number") {
1641
+ const iterator = stream[Symbol.asyncIterator]();
1642
+ try {
1643
+ while (true) {
1644
+ const next = iterator.next();
1645
+ let stallTimer;
1646
+ const stall = new Promise((_, reject) => {
1647
+ stallTimer = setTimeout(() => {
1648
+ reject(
1649
+ new ConnectionError(
1650
+ `Stream stalled: no events for ${SSE_STALL_TIMEOUT_MS}ms`
1651
+ )
1652
+ );
1653
+ onStall?.();
1654
+ }, SSE_STALL_TIMEOUT_MS);
1655
+ });
1656
+ let result;
1657
+ try {
1658
+ result = await Promise.race([next, stall]);
1659
+ } finally {
1660
+ clearTimeout(stallTimer);
1661
+ }
1662
+ if (result.done) break;
1663
+ const raw = result.value;
1664
+ let parsed;
1665
+ try {
1666
+ const data = JSON.parse(raw.data);
1667
+ if (typeof data !== "object" || data === null || typeof data.type !== "string") {
1668
+ if (typeof data?.seq === "number") {
1669
+ this.lastSeq = data.seq;
1670
+ }
1671
+ continue;
1672
+ }
1673
+ parsed = data;
1674
+ if (typeof data.seq === "number") {
1612
1675
  this.lastSeq = data.seq;
1613
1676
  }
1677
+ } catch {
1614
1678
  continue;
1615
1679
  }
1616
- parsed = data;
1617
- if (typeof data.seq === "number") {
1618
- this.lastSeq = data.seq;
1680
+ if (parsed.type === "message_stop" || parsed.type === "error") {
1681
+ sawTerminal = true;
1619
1682
  }
1620
- } catch {
1621
- continue;
1622
- }
1623
- if (parsed.type === "message_stop" || parsed.type === "error") {
1624
- sawTerminal = true;
1683
+ await this.dispatchWireEvent(
1684
+ parsed,
1685
+ conversationId,
1686
+ messageId,
1687
+ executeClientTools
1688
+ );
1625
1689
  }
1626
- await this.dispatchWireEvent(
1627
- parsed,
1628
- conversationId,
1629
- messageId,
1630
- executeClientTools
1631
- );
1690
+ } finally {
1691
+ void iterator.return?.(void 0).catch(() => {
1692
+ });
1632
1693
  }
1633
1694
  return sawTerminal;
1634
1695
  }
@@ -2190,6 +2251,7 @@ var StreamManager = class {
2190
2251
  uploadIds: options?.uploadIds,
2191
2252
  planMode: options?.planMode,
2192
2253
  imageMode: options?.imageMode,
2254
+ videoMode: options?.videoMode,
2193
2255
  goal: options?.goal,
2194
2256
  provider: options?.provider,
2195
2257
  model: options?.model,