dooers-agents-client 0.14.0 → 0.15.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/main.cjs CHANGED
@@ -211,6 +211,20 @@ function toThreadEvent(w) {
211
211
  clientEventId: w.client_event_id
212
212
  };
213
213
  }
214
+ function toThreadArtifact(w) {
215
+ return {
216
+ eventId: w.event_id,
217
+ direction: w.direction,
218
+ kind: w.kind,
219
+ filename: w.filename,
220
+ mimeType: w.mime_type,
221
+ url: w.url,
222
+ refId: w.ref_id,
223
+ createdAt: w.created_at,
224
+ userId: w.user_id,
225
+ userName: w.user_name
226
+ };
227
+ }
214
228
  function toRun(w) {
215
229
  return {
216
230
  id: w.id,
@@ -308,12 +322,13 @@ function toWireContentPart(p) {
308
322
  }
309
323
 
310
324
  // src/version.ts
311
- var PACKAGE_VERSION = "0.14.0";
325
+ var PACKAGE_VERSION = "0.15.0";
312
326
 
313
327
  // src/client.ts
314
328
  var MAX_RECONNECT_ATTEMPTS = 5;
315
329
  var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 16e3];
316
330
  var SEND_MESSAGE_TIMEOUT = 3e4;
331
+ var ARTIFACTS_LIST_TIMEOUT = 3e4;
317
332
  var PING_INTERVAL_MS = 3e4;
318
333
  function blobPartFilename(blob, override) {
319
334
  const o = (override ?? "").trim();
@@ -467,6 +482,7 @@ var AgentClient = class {
467
482
  pendingOptimistic = /* @__PURE__ */ new Map();
468
483
  // Pending message promises — keyed by outbound frame id (same as client_event_id for sends).
469
484
  pendingMessages = /* @__PURE__ */ new Map();
485
+ pendingArtifactsRequests = /* @__PURE__ */ new Map();
470
486
  // Track last event ID per thread for gap recovery on reconnect
471
487
  lastEventIds = /* @__PURE__ */ new Map();
472
488
  // Pagination
@@ -604,6 +620,13 @@ var AgentClient = class {
604
620
  }
605
621
  this.pendingMessages.clear();
606
622
  }
623
+ abortPendingArtifacts(reason) {
624
+ for (const [frameId, pending] of this.pendingArtifactsRequests) {
625
+ clearTimeout(pending.timer);
626
+ this.pendingArtifactsRequests.delete(frameId);
627
+ pending.reject(new Error(reason));
628
+ }
629
+ }
607
630
  disconnect() {
608
631
  this.isIntentionallyClosed = true;
609
632
  this.stopHeartbeat();
@@ -612,6 +635,7 @@ var AgentClient = class {
612
635
  this.reconnectTimer = null;
613
636
  }
614
637
  this.abortPendingMessages("Disconnected");
638
+ this.abortPendingArtifacts("Disconnected");
615
639
  if (this.ws) {
616
640
  this.ws.onopen = null;
617
641
  this.ws.onmessage = null;
@@ -670,6 +694,40 @@ var AgentClient = class {
670
694
  limit
671
695
  });
672
696
  }
697
+ requestThreadArtifactsList(threadId, options) {
698
+ if (!this.isConnected()) {
699
+ return Promise.reject(new Error("Not connected"));
700
+ }
701
+ const frameId = crypto.randomUUID();
702
+ return new Promise((resolve, reject) => {
703
+ const timer = setTimeout(() => {
704
+ this.pendingArtifactsRequests.delete(frameId);
705
+ reject(new Error("thread.artifacts.list timed out"));
706
+ }, ARTIFACTS_LIST_TIMEOUT);
707
+ this.pendingArtifactsRequests.set(frameId, {
708
+ threadId,
709
+ resolve: (value) => {
710
+ clearTimeout(timer);
711
+ resolve(value);
712
+ },
713
+ reject: (err) => {
714
+ clearTimeout(timer);
715
+ reject(err);
716
+ },
717
+ timer
718
+ });
719
+ this.sendRaw({
720
+ id: frameId,
721
+ type: "thread.artifacts.list",
722
+ payload: {
723
+ thread_id: threadId,
724
+ cursor: options?.cursor ?? null,
725
+ limit: options?.limit,
726
+ direction: options?.direction ?? "all"
727
+ }
728
+ });
729
+ });
730
+ }
673
731
  // --- Settings ---
674
732
  subscribeSettings(options) {
675
733
  const audience = options?.audience ?? "user";
@@ -915,6 +973,13 @@ var AgentClient = class {
915
973
  pending.reject(new Error(msg));
916
974
  this.callbacks.setSendError(msg);
917
975
  }
976
+ const artifactsPending = this.pendingArtifactsRequests.get(ackId);
977
+ if (artifactsPending) {
978
+ clearTimeout(artifactsPending.timer);
979
+ this.pendingArtifactsRequests.delete(ackId);
980
+ const msg = err.message || "Request rejected";
981
+ artifactsPending.reject(new Error(msg));
982
+ }
918
983
  }
919
984
  this.onError?.({
920
985
  code: err.code,
@@ -999,6 +1064,21 @@ var AgentClient = class {
999
1064
  );
1000
1065
  break;
1001
1066
  }
1067
+ case "thread.artifacts.list.result": {
1068
+ const threadId = frame.payload.thread_id;
1069
+ for (const [frameId, pending] of this.pendingArtifactsRequests) {
1070
+ if (pending.threadId !== threadId) continue;
1071
+ clearTimeout(pending.timer);
1072
+ this.pendingArtifactsRequests.delete(frameId);
1073
+ pending.resolve({
1074
+ artifacts: this.resolveArtifactUrls(frame.payload.artifacts.map(toThreadArtifact)),
1075
+ cursor: frame.payload.cursor,
1076
+ hasMore: frame.payload.has_more
1077
+ });
1078
+ break;
1079
+ }
1080
+ break;
1081
+ }
1002
1082
  case "thread.upsert":
1003
1083
  this.callbacks.onThreadUpsert(toThread(frame.payload.thread));
1004
1084
  break;
@@ -1060,6 +1140,7 @@ var AgentClient = class {
1060
1140
  this.stopHeartbeat();
1061
1141
  if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
1062
1142
  this.abortPendingMessages("Connection lost after maximum retries");
1143
+ this.abortPendingArtifacts("Connection lost after maximum retries");
1063
1144
  this.callbacks.setReconnectFailed();
1064
1145
  this.callbacks.setConnectionStatus("error", "Connection lost after maximum retries");
1065
1146
  return;
@@ -1104,6 +1185,14 @@ var AgentClient = class {
1104
1185
  };
1105
1186
  });
1106
1187
  }
1188
+ resolveArtifactUrls(artifacts) {
1189
+ if (!this.httpBaseUrl) return artifacts;
1190
+ const base = this.httpBaseUrl;
1191
+ return artifacts.map((artifact) => {
1192
+ if (!artifact.url?.startsWith("/")) return artifact;
1193
+ return { ...artifact, url: `${base}${artifact.url}` };
1194
+ });
1195
+ }
1107
1196
  };
1108
1197
  function mergeDisplayContentParts(prev, next) {
1109
1198
  if (!next?.length) return prev;
@@ -2025,6 +2114,60 @@ function useThreadEvents(threadId) {
2025
2114
  );
2026
2115
  return { hasOlderEvents, loadOlderEvents };
2027
2116
  }
2117
+ function useThreadArtifacts(threadId, options) {
2118
+ const { client } = useAgentContext();
2119
+ const direction = options?.direction ?? "all";
2120
+ const enabled = options?.enabled !== false;
2121
+ const limit = options?.limit;
2122
+ const [artifacts, setArtifacts] = react.useState([]);
2123
+ const [cursor, setCursor] = react.useState(null);
2124
+ const [hasMore, setHasMore] = react.useState(false);
2125
+ const [isLoading, setIsLoading] = react.useState(false);
2126
+ const [error, setError] = react.useState(null);
2127
+ const cursorRef = react.useRef(null);
2128
+ const load = react.useCallback(
2129
+ async (append) => {
2130
+ if (!threadId) return;
2131
+ setIsLoading(true);
2132
+ setError(null);
2133
+ try {
2134
+ const result = await client.requestThreadArtifactsList(threadId, {
2135
+ cursor: append ? cursorRef.current : null,
2136
+ limit,
2137
+ direction
2138
+ });
2139
+ cursorRef.current = result.cursor;
2140
+ setCursor(result.cursor);
2141
+ setHasMore(result.hasMore);
2142
+ setArtifacts((prev) => append ? [...prev, ...result.artifacts] : result.artifacts);
2143
+ } catch (err) {
2144
+ setError(err instanceof Error ? err.message : "Failed to load artifacts");
2145
+ } finally {
2146
+ setIsLoading(false);
2147
+ }
2148
+ },
2149
+ [threadId, client, limit, direction]
2150
+ );
2151
+ react.useEffect(() => {
2152
+ if (!threadId || !enabled) {
2153
+ setArtifacts([]);
2154
+ setCursor(null);
2155
+ cursorRef.current = null;
2156
+ setHasMore(false);
2157
+ setError(null);
2158
+ return;
2159
+ }
2160
+ void load(false);
2161
+ }, [threadId, enabled, direction, load]);
2162
+ const loadMore = react.useCallback(() => {
2163
+ if (!hasMore || isLoading) return;
2164
+ void load(true);
2165
+ }, [hasMore, isLoading, load]);
2166
+ const refresh = react.useCallback(() => {
2167
+ void load(false);
2168
+ }, [load]);
2169
+ return { artifacts, cursor, hasMore, isLoading, error, loadMore, refresh };
2170
+ }
2028
2171
  function useThreadsList() {
2029
2172
  const threadOrder = useStore((s) => s.threadOrder);
2030
2173
  const threadMap = useStore((s) => s.threads);
@@ -2087,6 +2230,7 @@ exports.useFormFileUpload = useFormFileUpload;
2087
2230
  exports.useMessage = useMessage;
2088
2231
  exports.useSettings = useSettings;
2089
2232
  exports.useSettingsFileUpload = useSettingsFileUpload;
2233
+ exports.useThreadArtifacts = useThreadArtifacts;
2090
2234
  exports.useThreadDetails = useThreadDetails;
2091
2235
  exports.useThreadEvents = useThreadEvents;
2092
2236
  exports.useThreadsActions = useThreadsActions;