@finalai/agents 0.8.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.

Potentially problematic release.


This version of @finalai/agents might be problematic. Click here for more details.

Files changed (153) hide show
  1. package/README.md +30 -0
  2. package/dist/modules/agent-client/acp-frames.d.mts +19 -0
  3. package/dist/modules/agent-client/acp-frames.mjs +49 -0
  4. package/dist/modules/agent-client/acp-frames.mjs.map +7 -0
  5. package/dist/modules/agent-client/acp.d.mts +43 -0
  6. package/dist/modules/agent-client/acp.mjs +76 -0
  7. package/dist/modules/agent-client/acp.mjs.map +7 -0
  8. package/dist/modules/agent-client/async-queue.d.mts +10 -0
  9. package/dist/modules/agent-client/async-queue.mjs +66 -0
  10. package/dist/modules/agent-client/async-queue.mjs.map +7 -0
  11. package/dist/modules/agent-client/build.d.mts +107 -0
  12. package/dist/modules/agent-client/build.mjs +222 -0
  13. package/dist/modules/agent-client/build.mjs.map +7 -0
  14. package/dist/modules/agent-client/client.d.mts +111 -0
  15. package/dist/modules/agent-client/client.mjs +198 -0
  16. package/dist/modules/agent-client/client.mjs.map +7 -0
  17. package/dist/modules/agent-client/collection-events.d.mts +35 -0
  18. package/dist/modules/agent-client/collection-events.mjs +142 -0
  19. package/dist/modules/agent-client/collection-events.mjs.map +7 -0
  20. package/dist/modules/agent-client/config-options.d.mts +24 -0
  21. package/dist/modules/agent-client/config-options.mjs +49 -0
  22. package/dist/modules/agent-client/config-options.mjs.map +7 -0
  23. package/dist/modules/agent-client/context.d.mts +31 -0
  24. package/dist/modules/agent-client/context.mjs +11 -0
  25. package/dist/modules/agent-client/context.mjs.map +7 -0
  26. package/dist/modules/agent-client/conversations.d.mts +385 -0
  27. package/dist/modules/agent-client/conversations.mjs +1156 -0
  28. package/dist/modules/agent-client/conversations.mjs.map +7 -0
  29. package/dist/modules/agent-client/errors.d.mts +85 -0
  30. package/dist/modules/agent-client/errors.mjs +94 -0
  31. package/dist/modules/agent-client/errors.mjs.map +7 -0
  32. package/dist/modules/agent-client/event-stream.d.mts +14 -0
  33. package/dist/modules/agent-client/event-stream.mjs +89 -0
  34. package/dist/modules/agent-client/event-stream.mjs.map +7 -0
  35. package/dist/modules/agent-client/frame-stream.d.mts +51 -0
  36. package/dist/modules/agent-client/frame-stream.mjs +333 -0
  37. package/dist/modules/agent-client/frame-stream.mjs.map +7 -0
  38. package/dist/modules/agent-client/http.d.mts +68 -0
  39. package/dist/modules/agent-client/http.mjs +168 -0
  40. package/dist/modules/agent-client/http.mjs.map +7 -0
  41. package/dist/modules/agent-client/index.d.mts +17 -0
  42. package/dist/modules/agent-client/index.mjs +86 -0
  43. package/dist/modules/agent-client/index.mjs.map +7 -0
  44. package/dist/modules/agent-client/live-stream.d.mts +18 -0
  45. package/dist/modules/agent-client/live-stream.mjs +94 -0
  46. package/dist/modules/agent-client/live-stream.mjs.map +7 -0
  47. package/dist/modules/agent-client/realtime.d.mts +72 -0
  48. package/dist/modules/agent-client/realtime.mjs +186 -0
  49. package/dist/modules/agent-client/realtime.mjs.map +7 -0
  50. package/dist/modules/agent-client/sandbox-uri.d.mts +19 -0
  51. package/dist/modules/agent-client/sandbox-uri.mjs +43 -0
  52. package/dist/modules/agent-client/sandbox-uri.mjs.map +7 -0
  53. package/dist/modules/agent-client/sessions.d.mts +124 -0
  54. package/dist/modules/agent-client/sessions.mjs +350 -0
  55. package/dist/modules/agent-client/sessions.mjs.map +7 -0
  56. package/dist/modules/agent-client/test-fakes.d.mts +40 -0
  57. package/dist/modules/agent-client/test-fakes.mjs +94 -0
  58. package/dist/modules/agent-client/test-fakes.mjs.map +7 -0
  59. package/dist/modules/authoring/approval.d.mts +1 -0
  60. package/dist/modules/authoring/approval.mjs +2 -0
  61. package/dist/modules/authoring/approval.mjs.map +7 -0
  62. package/dist/modules/authoring/channels.d.mts +1 -0
  63. package/dist/modules/authoring/channels.mjs +2 -0
  64. package/dist/modules/authoring/channels.mjs.map +7 -0
  65. package/dist/modules/authoring/final-channel.d.mts +1 -0
  66. package/dist/modules/authoring/final-channel.mjs +2 -0
  67. package/dist/modules/authoring/final-channel.mjs.map +7 -0
  68. package/dist/modules/authoring/hooks.d.mts +1 -0
  69. package/dist/modules/authoring/hooks.mjs +2 -0
  70. package/dist/modules/authoring/hooks.mjs.map +7 -0
  71. package/dist/modules/authoring/index.d.mts +1 -0
  72. package/dist/modules/authoring/index.mjs +2 -0
  73. package/dist/modules/authoring/index.mjs.map +7 -0
  74. package/dist/modules/authoring/instructions.d.mts +1 -0
  75. package/dist/modules/authoring/instructions.mjs +2 -0
  76. package/dist/modules/authoring/instructions.mjs.map +7 -0
  77. package/dist/modules/authoring/providers.d.mts +2 -0
  78. package/dist/modules/authoring/providers.mjs +1 -0
  79. package/dist/modules/authoring/providers.mjs.map +7 -0
  80. package/dist/modules/authoring/tools.d.mts +1 -0
  81. package/dist/modules/authoring/tools.mjs +2 -0
  82. package/dist/modules/authoring/tools.mjs.map +7 -0
  83. package/dist/modules/cli/build.d.mts +22 -0
  84. package/dist/modules/cli/build.mjs +77 -0
  85. package/dist/modules/cli/build.mjs.map +7 -0
  86. package/dist/modules/cli/channel-socket.d.mts +9 -0
  87. package/dist/modules/cli/channel-socket.mjs +114 -0
  88. package/dist/modules/cli/channel-socket.mjs.map +7 -0
  89. package/dist/modules/cli/cli.d.mts +16 -0
  90. package/dist/modules/cli/cli.mjs +151 -0
  91. package/dist/modules/cli/cli.mjs.map +7 -0
  92. package/dist/modules/cli/conformance.d.mts +36 -0
  93. package/dist/modules/cli/conformance.mjs +220 -0
  94. package/dist/modules/cli/conformance.mjs.map +7 -0
  95. package/dist/modules/cli/dev.d.mts +24 -0
  96. package/dist/modules/cli/dev.mjs +263 -0
  97. package/dist/modules/cli/dev.mjs.map +7 -0
  98. package/dist/modules/cli/files.d.mts +18 -0
  99. package/dist/modules/cli/files.mjs +66 -0
  100. package/dist/modules/cli/files.mjs.map +7 -0
  101. package/dist/modules/cli/harness-descriptions.d.mts +20 -0
  102. package/dist/modules/cli/harness-descriptions.mjs +70 -0
  103. package/dist/modules/cli/harness-descriptions.mjs.map +7 -0
  104. package/dist/modules/cli/main.d.mts +2 -0
  105. package/dist/modules/cli/main.mjs +20 -0
  106. package/dist/modules/cli/main.mjs.map +7 -0
  107. package/dist/modules/cli/output.d.mts +14 -0
  108. package/dist/modules/cli/output.mjs +94 -0
  109. package/dist/modules/cli/output.mjs.map +7 -0
  110. package/dist/modules/cli/publish.d.mts +14 -0
  111. package/dist/modules/cli/publish.mjs +89 -0
  112. package/dist/modules/cli/publish.mjs.map +7 -0
  113. package/dist/modules/compile.d.mts +3 -0
  114. package/dist/modules/compile.mjs +62 -0
  115. package/dist/modules/compile.mjs.map +7 -0
  116. package/dist/modules/harnesses.d.mts +1 -0
  117. package/dist/modules/harnesses.mjs +2 -0
  118. package/dist/modules/harnesses.mjs.map +7 -0
  119. package/dist/modules/index.browser.d.mts +4 -0
  120. package/dist/modules/index.browser.mjs +8 -0
  121. package/dist/modules/index.browser.mjs.map +7 -0
  122. package/dist/modules/index.d.mts +3 -0
  123. package/dist/modules/index.mjs +6 -0
  124. package/dist/modules/index.mjs.map +7 -0
  125. package/dist/modules/models.d.mts +1 -0
  126. package/dist/modules/models.mjs +2 -0
  127. package/dist/modules/models.mjs.map +7 -0
  128. package/dist/modules/public.d.mts +6 -0
  129. package/dist/modules/public.mjs +68 -0
  130. package/dist/modules/public.mjs.map +7 -0
  131. package/dist/modules/sandboxes.d.mts +1 -0
  132. package/dist/modules/sandboxes.mjs +2 -0
  133. package/dist/modules/sandboxes.mjs.map +7 -0
  134. package/examples/custom-harness/README.md +16 -0
  135. package/examples/custom-harness/agent.ts +154 -0
  136. package/examples/custom-sandbox/README.md +12 -0
  137. package/examples/custom-sandbox/agent.ts +14 -0
  138. package/examples/custom-sandbox/sandbox.ts +22 -0
  139. package/examples/release-scout/README.md +11 -0
  140. package/examples/release-scout/agent/agent.ts +22 -0
  141. package/examples/release-scout/agent/channels/github-signature.ts +27 -0
  142. package/examples/release-scout/agent/channels/github.ts +38 -0
  143. package/examples/release-scout/agent/connections/linear.ts +9 -0
  144. package/examples/release-scout/agent/hooks/audit.ts +24 -0
  145. package/examples/release-scout/agent/instructions/org-context.ts +26 -0
  146. package/examples/release-scout/agent/instructions.md +2 -0
  147. package/examples/release-scout/agent/sandbox.ts +20 -0
  148. package/examples/release-scout/agent/schedules/daily-digest.md +7 -0
  149. package/examples/release-scout/agent/skills/triage/SKILL.md +8 -0
  150. package/examples/release-scout/agent/skills/triage/checklist.md +3 -0
  151. package/examples/release-scout/agent/tools/lookup_release_notes.ts +24 -0
  152. package/examples/release-scout/client.ts +123 -0
  153. package/package.json +126 -0
@@ -0,0 +1,1156 @@
1
+ import {
2
+ ProcessInspectionOperation,
3
+ processInspectionRequestSchema,
4
+ processInspectionResultSchema
5
+ } from "@finalai/agent-protocol";
6
+ import {
7
+ agentRealtimeFrameSchema,
8
+ AgentRealtimeFrameType,
9
+ AgentRealtimeKind,
10
+ agentRealtimeTopics,
11
+ AgentSessionState,
12
+ attachmentDownloadSchema,
13
+ attachmentUploadSchema,
14
+ cancelConversationRequestSchema,
15
+ conversationLinkListSchema,
16
+ conversationLinkSchema,
17
+ conversationListSchema,
18
+ conversationMessageSchema,
19
+ conversationMessagesPageSchema,
20
+ conversationSandboxListSchema,
21
+ conversationSandboxSchema,
22
+ conversationScheduleListSchema,
23
+ conversationScheduleSchema,
24
+ conversationSchema,
25
+ createAttachmentUploadRequestSchema,
26
+ createConversationLinkRequestSchema,
27
+ createConversationRequestSchema,
28
+ createConversationScheduleRequestSchema,
29
+ createDirectConversationRequestSchema,
30
+ decisionsPageSchema,
31
+ markReadRequestSchema,
32
+ messageDeliveriesSchema,
33
+ MessageStreamingState,
34
+ MessageThreadFilter,
35
+ okResponseSchema,
36
+ parseAgentRealtimeEvent,
37
+ participantInputSchema,
38
+ ParticipantKind,
39
+ participantListSchema,
40
+ participantSchema,
41
+ PendingEventState,
42
+ pendingRequestListSchema,
43
+ postConversationEventRequestSchema,
44
+ pushDeliveryOpenResponseSchema,
45
+ reactionRequestSchema,
46
+ reactionsResponseSchema,
47
+ readStateSchema,
48
+ removeParticipantRequestSchema,
49
+ respondPendingRequestSchema,
50
+ respondPendingResponseSchema,
51
+ sandboxDirectorySchema,
52
+ sandboxEditorAuthorizationSchema,
53
+ sandboxEditorSessionSchema,
54
+ sandboxFileSchema,
55
+ sandboxPathSchema,
56
+ sandboxPreviewOptionsSchema,
57
+ sandboxPreviewSchema,
58
+ sandboxSearchSchema,
59
+ searchMessagesPageSchema,
60
+ sendMessageRequestSchema,
61
+ sendMessageResponseSchema,
62
+ sessionSchema,
63
+ typingRequestSchema,
64
+ updateConversationRequestSchema,
65
+ updateConversationScheduleRequestSchema,
66
+ updateParticipantRequestSchema
67
+ } from "@finalai/agent-protocol/agent-platform";
68
+ import { createAsyncQueue, failOnAbort } from "./async-queue.mjs";
69
+ import {
70
+ streamCollectionEvents
71
+ } from "./collection-events.mjs";
72
+ import {
73
+ ClientCollection,
74
+ encodePath
75
+ } from "./context.mjs";
76
+ import {
77
+ clientError,
78
+ ClientErrorCode,
79
+ isRetryableClientError,
80
+ isTerminalRealtimeError,
81
+ realtimeSubscriptionError
82
+ } from "./errors.mjs";
83
+ import { errorFromResponse, HttpMethod } from "./http.mjs";
84
+ import { outcomeOf } from "./sessions.mjs";
85
+ const TURN_OPEN_SESSION_STATES = /* @__PURE__ */ new Set([
86
+ AgentSessionState.Running,
87
+ AgentSessionState.RequiresAction
88
+ ]);
89
+ const conversationPath = (conversationId, suffix = "") => `/v1/conversations/${encodePath(conversationId)}${suffix}`;
90
+ const messagePath = (conversationId, messageId, suffix = "") => conversationPath(conversationId, `/messages/${encodePath(messageId)}${suffix}`);
91
+ const MAX_REMEMBERED = 4096;
92
+ const SESSION_PENDING_LIMIT = 200;
93
+ const remember = (map, key, value) => {
94
+ map.delete(key);
95
+ map.set(key, value);
96
+ if (map.size > MAX_REMEMBERED) {
97
+ const oldest = map.keys().next();
98
+ if (oldest.done !== true) map.delete(oldest.value);
99
+ }
100
+ };
101
+ const isTransientEvent = (event) => event.kind === AgentRealtimeKind.AcpPending || event.kind === AgentRealtimeKind.TurnStarted || event.kind === AgentRealtimeKind.TurnEnded;
102
+ const REPLAY_PAGE = 100;
103
+ const RECOVERY_SKEW_MS = 3e4;
104
+ const stampOf = (message) => Math.max(
105
+ ...[message.updatedAt, message.deletedAt, message.createdAt].map(
106
+ (value) => value == null ? 0 : Date.parse(value) || 0
107
+ )
108
+ );
109
+ const isoMs = (value) => {
110
+ if (value == null) return null;
111
+ const ms = Date.parse(value);
112
+ return Number.isNaN(ms) ? null : ms;
113
+ };
114
+ const messageVersionOf = (message) => ({
115
+ revision: message.revision,
116
+ updatedAt: isoMs(message.updatedAt),
117
+ stamp: stampOf(message),
118
+ deleted: message.deletedAt != null,
119
+ final: message.streaming?.state === MessageStreamingState.Final,
120
+ fingerprint: JSON.stringify([
121
+ message.deletedAt,
122
+ message.streaming?.state ?? null,
123
+ message.body,
124
+ message.reactions
125
+ ])
126
+ });
127
+ const isNewerMessageVersion = (incoming, current) => {
128
+ if (current == null) return true;
129
+ if (current.deleted && !incoming.deleted) return false;
130
+ if (incoming.revision != null && current.revision != null) {
131
+ return incoming.revision > current.revision;
132
+ }
133
+ if (incoming.updatedAt != null && current.updatedAt != null) {
134
+ if (incoming.updatedAt !== current.updatedAt) return incoming.updatedAt > current.updatedAt;
135
+ return incoming.final && !current.final;
136
+ }
137
+ if (incoming.stamp !== current.stamp) return incoming.stamp > current.stamp;
138
+ if (current.final && !incoming.final) return false;
139
+ return incoming.fingerprint !== current.fingerprint;
140
+ };
141
+ const streamConversationEvents = (args) => {
142
+ const topic = agentRealtimeTopics.conversation(args.conversationId);
143
+ const follow = args.options?.follow ?? true;
144
+ const controller = new AbortController();
145
+ const signal = AbortSignal.any([
146
+ controller.signal,
147
+ args.context.closeSignal,
148
+ ...args.options?.signal == null ? [] : [args.options.signal]
149
+ ]);
150
+ const versions = /* @__PURE__ */ new Map();
151
+ let newestStamp = null;
152
+ const subscribedAt = Date.now();
153
+ let recoveryFloor = null;
154
+ let subscribedOnce = false;
155
+ let recovering = 0;
156
+ let recovery = Promise.resolve();
157
+ const held = [];
158
+ const recoverTransientState = args.options?.recoverTransient ?? true;
159
+ let transientClock = 0;
160
+ const pendingSeen = /* @__PURE__ */ new Map();
161
+ const runningTurns = /* @__PURE__ */ new Map();
162
+ const endedTurns = /* @__PURE__ */ new Map();
163
+ let degraded = false;
164
+ let pollTimer = null;
165
+ const clearPoll = () => {
166
+ if (pollTimer != null) clearTimeout(pollTimer);
167
+ pollTimer = null;
168
+ };
169
+ let unsubscribe = null;
170
+ let detachAbort = () => {
171
+ };
172
+ let detachClose = () => {
173
+ };
174
+ const queue = createAsyncQueue(() => {
175
+ controller.abort();
176
+ held.length = 0;
177
+ clearPoll();
178
+ unsubscribe?.();
179
+ detachAbort();
180
+ detachClose();
181
+ });
182
+ const resumeFrom = args.options?.resumeFrom ?? [];
183
+ const anchor = resumeFrom.length === 0 && args.options?.afterSeq == null ? args.listMessages({ limit: 1, thread: MessageThreadFilter.All, signal }) : null;
184
+ anchor?.catch(() => {
185
+ });
186
+ for (const message of resumeFrom) {
187
+ versions.set(message.id, messageVersionOf(message));
188
+ newestStamp = Math.max(newestStamp ?? 0, stampOf(message));
189
+ }
190
+ const emitMessage = (message, meta, live) => {
191
+ const version = messageVersionOf(message);
192
+ const previous = versions.get(message.id);
193
+ if (!isNewerMessageVersion(version, previous)) return;
194
+ versions.set(message.id, version);
195
+ newestStamp = Math.max(newestStamp ?? 0, stampOf(message));
196
+ if (live != null) {
197
+ queue.push({ ...live, ...meta });
198
+ return;
199
+ }
200
+ queue.push(
201
+ previous == null ? { kind: AgentRealtimeKind.MessageCreated, message, ...meta } : { kind: AgentRealtimeKind.MessageUpdated, message, ...meta }
202
+ );
203
+ };
204
+ const notePending = (pending, state) => {
205
+ const seen = pendingSeen.get(pending.id);
206
+ if (state === PendingEventState.Resolved) {
207
+ if (seen?.state === PendingEventState.Resolved) return false;
208
+ transientClock += 1;
209
+ remember(pendingSeen, pending.id, { state, pending, noted: transientClock });
210
+ return true;
211
+ }
212
+ if (state === PendingEventState.Created) {
213
+ if (seen != null) return false;
214
+ transientClock += 1;
215
+ remember(pendingSeen, pending.id, { state, pending, noted: transientClock });
216
+ return true;
217
+ }
218
+ return true;
219
+ };
220
+ const noteTransient = (event) => {
221
+ if (event.kind === AgentRealtimeKind.AcpPending) return notePending(event.pending, event.state);
222
+ if (event.kind === AgentRealtimeKind.TurnStarted) {
223
+ if (!endedTurns.has(event.turnId)) {
224
+ transientClock += 1;
225
+ remember(runningTurns, event.turnId, { turn: event, noted: transientClock });
226
+ }
227
+ return true;
228
+ }
229
+ if (event.kind === AgentRealtimeKind.TurnEnded) {
230
+ if (endedTurns.has(event.turnId)) return false;
231
+ remember(endedTurns, event.turnId, true);
232
+ runningTurns.delete(event.turnId);
233
+ }
234
+ return true;
235
+ };
236
+ const emitLive = (event, meta) => {
237
+ if (event.kind === AgentRealtimeKind.MessageCreated || event.kind === AgentRealtimeKind.MessageUpdated) {
238
+ emitMessage(event.message, meta, event);
239
+ return;
240
+ }
241
+ if (event.kind === AgentRealtimeKind.MessageDeleted) {
242
+ const current = versions.get(event.messageId);
243
+ if (current?.deleted === true) return;
244
+ const deletedAt = isoMs(event.deletedAt) ?? current?.stamp ?? 0;
245
+ versions.set(event.messageId, {
246
+ revision: current?.revision ?? null,
247
+ updatedAt: Math.max(current?.updatedAt ?? 0, deletedAt),
248
+ stamp: Math.max(current?.stamp ?? 0, deletedAt),
249
+ deleted: true,
250
+ final: current?.final ?? false,
251
+ fingerprint: current?.fingerprint ?? ""
252
+ });
253
+ }
254
+ if (!noteTransient(event)) return;
255
+ queue.push({ ...event, ...meta });
256
+ };
257
+ const replayed = (message) => ({
258
+ topic,
259
+ cursor: null,
260
+ createdAt: message.updatedAt ?? message.createdAt,
261
+ replayed: true
262
+ });
263
+ const emitPage = (messages) => {
264
+ for (const message of [...messages].sort((left, right) => left.seq - right.seq)) {
265
+ emitMessage(message, replayed(message), null);
266
+ }
267
+ };
268
+ const recoverChanges = async () => {
269
+ const since = Math.max(
270
+ 0,
271
+ Math.min(newestStamp ?? subscribedAt, recoveryFloor ?? Infinity) - RECOVERY_SKEW_MS
272
+ );
273
+ let position = {
274
+ updatedAfter: new Date(since).toISOString()
275
+ };
276
+ let nextFloor = null;
277
+ for (; ; ) {
278
+ const page = await args.listMessages({
279
+ ...position,
280
+ thread: MessageThreadFilter.All,
281
+ limit: REPLAY_PAGE,
282
+ signal
283
+ });
284
+ if (nextFloor == null && page.recoverySince != null) {
285
+ const stamp = Date.parse(page.recoverySince);
286
+ if (Number.isFinite(stamp)) nextFloor = stamp;
287
+ }
288
+ emitPage(page.messages);
289
+ const next = page.nextUpdatedCursor;
290
+ if (next == null || !page.hasMoreAfter || page.messages.length === 0) {
291
+ recoveryFloor = nextFloor ?? recoveryFloor;
292
+ return;
293
+ }
294
+ position = { updatedCursor: next };
295
+ }
296
+ };
297
+ const recoverFromAnchor = async (anchor2) => {
298
+ const page = await anchor2;
299
+ if (page.recoverySince != null) {
300
+ const stamp = Date.parse(page.recoverySince);
301
+ if (Number.isFinite(stamp)) recoveryFloor = stamp;
302
+ }
303
+ const newest = page.messages.reduce(
304
+ (best, message) => best == null || message.seq > best.seq ? message : best,
305
+ null
306
+ );
307
+ if (newest != null && !versions.has(newest.id)) {
308
+ versions.set(newest.id, messageVersionOf(newest));
309
+ newestStamp = Math.max(newestStamp ?? 0, stampOf(newest));
310
+ }
311
+ await recoverChanges();
312
+ };
313
+ const recoverAfterSeq = async (afterSeq) => {
314
+ let cursor = afterSeq;
315
+ for (; ; ) {
316
+ const page = await args.listMessages({
317
+ after: cursor,
318
+ thread: MessageThreadFilter.All,
319
+ limit: REPLAY_PAGE,
320
+ signal
321
+ });
322
+ emitPage(page.messages);
323
+ const next = Math.max(cursor, ...page.messages.map((message) => message.seq));
324
+ if (!page.hasMoreAfter || next === cursor) return;
325
+ cursor = next;
326
+ }
327
+ };
328
+ const recoveredMeta = () => ({
329
+ topic,
330
+ cursor: null,
331
+ createdAt: null,
332
+ replayed: true
333
+ });
334
+ const optional = async (read) => {
335
+ try {
336
+ return await read();
337
+ } catch (cause) {
338
+ if (isRetryableClientError(cause)) throw cause;
339
+ return null;
340
+ }
341
+ };
342
+ const emitRecovered = (event) => {
343
+ held.push({ event, meta: recoveredMeta(), noted: true });
344
+ };
345
+ const recoverTransient = async () => {
346
+ if (!recoverTransientState) return;
347
+ const asOf = transientClock;
348
+ const participants = await optional(() => args.listParticipants({ signal }));
349
+ const current = participants == null ? null : new Set(
350
+ participants.flatMap(
351
+ (participant) => participant.kind === ParticipantKind.Agent && participant.sessionId != null && participant.leftAt == null ? [participant.sessionId] : []
352
+ )
353
+ );
354
+ const remembered = /* @__PURE__ */ new Set([
355
+ ...[...pendingSeen.values()].flatMap(
356
+ (seen) => seen.state === PendingEventState.Created ? [seen.pending.sessionId] : []
357
+ ),
358
+ ...[...runningTurns.values()].map((entry) => entry.turn.sessionId)
359
+ ]);
360
+ const checked = await Promise.all(
361
+ [.../* @__PURE__ */ new Set([...current ?? [], ...remembered])].map(async (sessionId) => {
362
+ const [session, open] = await Promise.all([
363
+ optional(() => args.getSession(sessionId, { signal })),
364
+ optional(() => args.sessionPending(sessionId, { signal }))
365
+ ]);
366
+ const departed = current != null && !current.has(sessionId);
367
+ return {
368
+ sessionId,
369
+ running: session == null ? departed ? false : null : TURN_OPEN_SESSION_STATES.has(session.state),
370
+ open: open ?? (departed ? [] : null)
371
+ };
372
+ })
373
+ );
374
+ for (const { sessionId, running, open } of checked) {
375
+ if (open != null) {
376
+ const complete = open.length < SESSION_PENDING_LIMIT;
377
+ const openIds = new Set(open.map((pending) => pending.id));
378
+ for (const pending of open) {
379
+ if (notePending(pending, PendingEventState.Created))
380
+ emitRecovered({
381
+ kind: AgentRealtimeKind.AcpPending,
382
+ pending,
383
+ state: PendingEventState.Created
384
+ });
385
+ }
386
+ for (const seen of [...pendingSeen.values()]) {
387
+ if (!complete || seen.state !== PendingEventState.Created || seen.noted > asOf || seen.pending.sessionId !== sessionId || openIds.has(seen.pending.id))
388
+ continue;
389
+ notePending(seen.pending, PendingEventState.Resolved);
390
+ emitRecovered({
391
+ kind: AgentRealtimeKind.AcpPending,
392
+ pending: seen.pending,
393
+ state: PendingEventState.Resolved
394
+ });
395
+ }
396
+ }
397
+ if (running !== false) continue;
398
+ for (const { turn, noted } of [...runningTurns.values()]) {
399
+ if (turn.sessionId !== sessionId || noted > asOf) continue;
400
+ runningTurns.delete(turn.turnId);
401
+ remember(endedTurns, turn.turnId, true);
402
+ emitRecovered({
403
+ kind: AgentRealtimeKind.TurnEnded,
404
+ conversationId: turn.conversationId,
405
+ participantId: turn.participantId,
406
+ sessionId: turn.sessionId,
407
+ turnId: turn.turnId,
408
+ stopReason: null
409
+ });
410
+ }
411
+ }
412
+ };
413
+ const scheduleRecovery = (run) => {
414
+ recovering += 1;
415
+ recovery = recovery.then(async () => {
416
+ let delay = 250;
417
+ while (!queue.closed()) {
418
+ try {
419
+ await run();
420
+ return;
421
+ } catch (cause) {
422
+ if (!follow || !isRetryableClientError(cause)) throw cause;
423
+ await new Promise((resolve) => {
424
+ const done = () => {
425
+ clearTimeout(timer);
426
+ signal.removeEventListener("abort", done);
427
+ resolve();
428
+ };
429
+ const timer = setTimeout(done, delay);
430
+ if (signal.aborted) done();
431
+ else signal.addEventListener("abort", done, { once: true });
432
+ });
433
+ delay = Math.min(delay * 2, 3e4);
434
+ }
435
+ }
436
+ }).then(() => {
437
+ recovering -= 1;
438
+ if (recovering > 0) return;
439
+ for (const entry of held.splice(0)) {
440
+ if (entry.noted) queue.push({ ...entry.event, ...entry.meta });
441
+ else emitLive(entry.event, entry.meta);
442
+ }
443
+ }).catch((cause) => queue.fail(cause));
444
+ };
445
+ let newestRecoveryPending = false;
446
+ let newestRecoveryRequested = false;
447
+ const recoverFromNewest = () => {
448
+ newestRecoveryRequested = true;
449
+ if (newestRecoveryPending) return;
450
+ newestRecoveryPending = true;
451
+ scheduleRecovery(async () => {
452
+ do {
453
+ newestRecoveryRequested = false;
454
+ await recoverChanges();
455
+ await recoverTransient();
456
+ } while (newestRecoveryRequested && !queue.closed());
457
+ newestRecoveryPending = false;
458
+ });
459
+ };
460
+ let initialRecoveryStarted = false;
461
+ const startInitialRecovery = () => {
462
+ if (initialRecoveryStarted) return;
463
+ initialRecoveryStarted = true;
464
+ const afterSeq = args.options?.afterSeq;
465
+ if (afterSeq != null) scheduleRecovery(() => recoverAfterSeq(afterSeq));
466
+ if (resumeFrom.length > 0) recoverFromNewest();
467
+ if (anchor != null)
468
+ scheduleRecovery(async () => {
469
+ try {
470
+ await recoverFromAnchor(anchor);
471
+ } catch (cause) {
472
+ if (!isRetryableClientError(cause)) throw cause;
473
+ await recoverChanges();
474
+ }
475
+ });
476
+ if (resumeFrom.length === 0) scheduleRecovery(recoverTransient);
477
+ };
478
+ const poll = () => {
479
+ pollTimer = null;
480
+ if (!degraded || queue.closed()) return;
481
+ if (initialRecoveryStarted) recoverFromNewest();
482
+ else startInitialRecovery();
483
+ void recovery.then(() => {
484
+ if (!degraded || queue.closed() || pollTimer != null) return;
485
+ pollTimer = setTimeout(poll, args.context.timing.conversationPollIntervalMs);
486
+ });
487
+ };
488
+ const onFrame = (raw) => {
489
+ const frame = agentRealtimeFrameSchema.safeParse(raw);
490
+ if (!frame.success || queue.closed()) return;
491
+ switch (frame.data.type) {
492
+ case AgentRealtimeFrameType.Event: {
493
+ const envelope = frame.data;
494
+ const entry = {
495
+ event: parseAgentRealtimeEvent(envelope),
496
+ meta: {
497
+ topic: envelope.topic,
498
+ cursor: envelope.cursor,
499
+ createdAt: envelope.createdAt,
500
+ replayed: false
501
+ }
502
+ };
503
+ if (recovering > 0) {
504
+ if (held.length >= 1024) {
505
+ queue.fail(
506
+ clientError({
507
+ code: ClientErrorCode.Network,
508
+ status: 0,
509
+ message: "Conversation recovery buffer is full; reconnect from the last message."
510
+ })
511
+ );
512
+ return;
513
+ }
514
+ if (isTransientEvent(entry.event)) {
515
+ if (noteTransient(entry.event)) held.push({ ...entry, noted: true });
516
+ } else held.push({ ...entry, noted: false });
517
+ } else emitLive(entry.event, entry.meta);
518
+ return;
519
+ }
520
+ case AgentRealtimeFrameType.Subscribed: {
521
+ degraded = false;
522
+ clearPoll();
523
+ if (!subscribedOnce) {
524
+ subscribedOnce = true;
525
+ if (initialRecoveryStarted) recoverFromNewest();
526
+ else startInitialRecovery();
527
+ } else {
528
+ recoverFromNewest();
529
+ args.options?.onResubscribed?.();
530
+ }
531
+ if (!follow) void recovery.then(() => queue.end());
532
+ return;
533
+ }
534
+ case AgentRealtimeFrameType.ResyncRequired:
535
+ recoverFromNewest();
536
+ args.options?.onResubscribed?.();
537
+ return;
538
+ case AgentRealtimeFrameType.Error:
539
+ if (isTerminalRealtimeError(frame.data)) {
540
+ queue.fail(
541
+ realtimeSubscriptionError({
542
+ topic: frame.data.topic ?? topic,
543
+ code: frame.data.code ?? "unknown",
544
+ message: frame.data.message ?? "Realtime subscription was refused"
545
+ })
546
+ );
547
+ return;
548
+ }
549
+ if (!follow) {
550
+ if (subscribedOnce) return;
551
+ subscribedOnce = true;
552
+ startInitialRecovery();
553
+ void recovery.then(() => queue.end());
554
+ return;
555
+ }
556
+ if (!degraded) {
557
+ degraded = true;
558
+ poll();
559
+ }
560
+ return;
561
+ default:
562
+ return;
563
+ }
564
+ };
565
+ detachAbort = failOnAbort(queue, signal);
566
+ detachClose = failOnAbort(queue, args.context.closeSignal);
567
+ if (!queue.closed()) {
568
+ const subscribeOptions = args.options?.afterCursor == null ? void 0 : { afterCursor: args.options.afterCursor };
569
+ const stop = args.context.realtime().subscribe(topic, onFrame, subscribeOptions);
570
+ if (queue.closed()) stop();
571
+ else unsubscribe = stop;
572
+ }
573
+ return queue.iterator;
574
+ };
575
+ const createConversationHandle = (context, conversationId) => {
576
+ const { http } = context;
577
+ const sandboxFileContentRequest = async (args) => {
578
+ if (args.path.length === 0 || args.path.length > 4096 || args.path.includes("\0")) {
579
+ throw clientError({
580
+ message: "Invalid sandbox file path",
581
+ status: 0,
582
+ code: ClientErrorCode.InvalidRequest
583
+ });
584
+ }
585
+ const target = http.url(
586
+ conversationPath(conversationId, `/sandboxes/${encodePath(args.bindingId)}/file/content`)
587
+ );
588
+ target.searchParams.set("path", args.path);
589
+ if (args.snapshotId != null) target.searchParams.set("snapshotId", args.snapshotId);
590
+ if (args.download != null) target.searchParams.set("download", String(args.download));
591
+ const headers = await http.headers();
592
+ if (args.range != null) headers.range = args.range;
593
+ return {
594
+ url: target.toString(),
595
+ headers,
596
+ credentials: http.usesCookies ? "include" : "omit"
597
+ };
598
+ };
599
+ const listMessages = (options = {}) => http.request({
600
+ method: HttpMethod.Get,
601
+ path: conversationPath(conversationId, "/messages"),
602
+ query: {
603
+ before: options.before,
604
+ after: options.after,
605
+ limit: options.limit,
606
+ thread: options.thread,
607
+ updatedAfter: options.updatedAfter,
608
+ updatedCursor: options.updatedCursor
609
+ },
610
+ response: conversationMessagesPageSchema,
611
+ signal: options.signal
612
+ });
613
+ const listParticipants = async (options) => (await http.request({
614
+ method: HttpMethod.Get,
615
+ path: conversationPath(conversationId, "/participants"),
616
+ response: participantListSchema,
617
+ signal: options.signal
618
+ })).participants;
619
+ const getSession = (sessionId, options) => http.request({
620
+ method: HttpMethod.Get,
621
+ path: `/v1/sessions/${encodePath(sessionId)}`,
622
+ response: sessionSchema,
623
+ signal: options.signal
624
+ });
625
+ const sessionPending = async (sessionId, options) => (await http.request({
626
+ method: HttpMethod.Get,
627
+ path: `/v1/sessions/${encodePath(sessionId)}/pending`,
628
+ response: pendingRequestListSchema,
629
+ signal: options.signal
630
+ })).pending;
631
+ const reaction = async (args) => (await http.request({
632
+ method: args.method,
633
+ path: messagePath(conversationId, args.messageId, "/reactions"),
634
+ body: { schema: reactionRequestSchema, value: { emoji: args.emoji } },
635
+ response: reactionsResponseSchema,
636
+ signal: args.signal
637
+ })).reactions;
638
+ return {
639
+ id: conversationId,
640
+ info: (options) => http.request({
641
+ method: HttpMethod.Get,
642
+ path: conversationPath(conversationId),
643
+ response: conversationSchema,
644
+ signal: options?.signal
645
+ }),
646
+ send: async (content, options) => {
647
+ const sent = await http.request({
648
+ method: HttpMethod.Post,
649
+ path: conversationPath(conversationId, "/messages"),
650
+ body: {
651
+ schema: sendMessageRequestSchema,
652
+ value: {
653
+ content,
654
+ clientMessageId: options?.clientMessageId ?? context.newKey(),
655
+ replyTo: options?.replyTo,
656
+ threadRootId: options?.threadRootId,
657
+ quotes: options?.quotes,
658
+ mentions: options?.mentions,
659
+ attachmentIds: options?.attachmentIds,
660
+ clientSubmittedAtMs: options?.clientSubmittedAtMs ?? context.now()
661
+ }
662
+ },
663
+ response: sendMessageResponseSchema,
664
+ signal: options?.signal
665
+ });
666
+ return {
667
+ message: sent.message,
668
+ messageId: sent.message.id,
669
+ seq: sent.message.seq,
670
+ deliveries: sent.deliveries
671
+ };
672
+ },
673
+ events: (options) => streamConversationEvents({
674
+ context,
675
+ conversationId,
676
+ options,
677
+ listMessages,
678
+ listParticipants,
679
+ getSession,
680
+ sessionPending
681
+ }),
682
+ messages: (options) => listMessages(options),
683
+ deliveries: async (args, options) => (await http.request({
684
+ method: HttpMethod.Get,
685
+ path: `${messagePath(conversationId, args.messageId)}/deliveries`,
686
+ response: messageDeliveriesSchema,
687
+ signal: options?.signal
688
+ })).deliveries,
689
+ message: (args, options) => http.request({
690
+ method: HttpMethod.Get,
691
+ path: messagePath(conversationId, args.messageId),
692
+ response: conversationMessageSchema,
693
+ signal: options?.signal
694
+ }),
695
+ react: (args, options) => reaction({ method: HttpMethod.Post, ...args, signal: options?.signal }),
696
+ unreact: (args, options) => reaction({ method: HttpMethod.Delete, ...args, signal: options?.signal }),
697
+ markThreadRead: async ({ rootId, throughSeq }, options) => {
698
+ await http.request({
699
+ method: HttpMethod.Post,
700
+ path: conversationPath(conversationId, `/threads/${encodePath(rootId)}/read`),
701
+ body: { schema: markReadRequestSchema, value: { throughSeq } },
702
+ response: okResponseSchema,
703
+ signal: options?.signal
704
+ });
705
+ },
706
+ postEvent: async (event, options) => {
707
+ const sent = await http.request({
708
+ method: HttpMethod.Post,
709
+ path: conversationPath(conversationId, "/events"),
710
+ body: { schema: postConversationEventRequestSchema, value: event },
711
+ response: sendMessageResponseSchema,
712
+ signal: options?.signal
713
+ });
714
+ return {
715
+ message: sent.message,
716
+ messageId: sent.message.id,
717
+ seq: sent.message.seq,
718
+ deliveries: sent.deliveries
719
+ };
720
+ },
721
+ typing: async (args, options) => {
722
+ await http.request({
723
+ method: HttpMethod.Post,
724
+ path: conversationPath(conversationId, "/typing"),
725
+ body: { schema: typingRequestSchema, value: args },
726
+ response: okResponseSchema,
727
+ signal: options?.signal
728
+ });
729
+ },
730
+ recordPushOpen: (args, options) => http.request({
731
+ method: HttpMethod.Post,
732
+ path: conversationPath(
733
+ conversationId,
734
+ `/push-deliveries/${encodeURIComponent(args.deliveryId)}/open`
735
+ ),
736
+ response: pushDeliveryOpenResponseSchema,
737
+ signal: options?.signal
738
+ }),
739
+ markRead: (args, options) => http.request({
740
+ method: HttpMethod.Post,
741
+ path: conversationPath(conversationId, "/read"),
742
+ body: { schema: markReadRequestSchema, value: args },
743
+ response: readStateSchema,
744
+ signal: options?.signal
745
+ }),
746
+ respond: (args, options) => http.request({
747
+ method: HttpMethod.Post,
748
+ path: conversationPath(conversationId, "/respond"),
749
+ body: {
750
+ schema: respondPendingRequestSchema,
751
+ value: { pendingId: args.pendingId, outcome: outcomeOf(args) }
752
+ },
753
+ response: respondPendingResponseSchema,
754
+ signal: options?.signal,
755
+ context: { pendingId: args.pendingId }
756
+ }),
757
+ cancel: async (options) => {
758
+ await http.request({
759
+ method: HttpMethod.Post,
760
+ path: conversationPath(conversationId, "/cancel"),
761
+ body: {
762
+ schema: cancelConversationRequestSchema,
763
+ value: { reason: options?.reason, throughMessageSeq: options?.throughMessageSeq }
764
+ },
765
+ response: okResponseSchema,
766
+ signal: options?.signal
767
+ });
768
+ },
769
+ participants: (options) => listParticipants({ signal: options?.signal }),
770
+ turns: async (options) => {
771
+ const participants = await listParticipants({ signal: options?.signal });
772
+ return Promise.all(
773
+ participants.flatMap((participant) => {
774
+ const sessionId = participant.sessionId;
775
+ if (participant.kind !== ParticipantKind.Agent || sessionId == null) return [];
776
+ return [
777
+ getSession(sessionId, { signal: options?.signal }).then(
778
+ (session) => ({
779
+ participantId: participant.id,
780
+ sessionId,
781
+ state: session.state,
782
+ running: TURN_OPEN_SESSION_STATES.has(session.state)
783
+ })
784
+ )
785
+ ];
786
+ })
787
+ );
788
+ },
789
+ addParticipant: (participant, options) => http.request({
790
+ method: HttpMethod.Post,
791
+ path: conversationPath(conversationId, "/participants"),
792
+ body: { schema: participantInputSchema, value: participant },
793
+ response: participantSchema,
794
+ signal: options?.signal
795
+ }),
796
+ updateParticipant: ({ participantId, ...patch }, options) => http.request({
797
+ method: HttpMethod.Patch,
798
+ path: conversationPath(conversationId, `/participants/${encodePath(participantId)}`),
799
+ body: { schema: updateParticipantRequestSchema, value: patch },
800
+ response: participantSchema,
801
+ signal: options?.signal
802
+ }),
803
+ removeParticipant: async (args, options) => {
804
+ await http.request({
805
+ method: HttpMethod.Delete,
806
+ path: conversationPath(conversationId, "/participants"),
807
+ body: { schema: removeParticipantRequestSchema, value: args },
808
+ response: okResponseSchema,
809
+ signal: options?.signal
810
+ });
811
+ },
812
+ update: (patch, options) => http.request({
813
+ method: HttpMethod.Patch,
814
+ path: conversationPath(conversationId),
815
+ body: { schema: updateConversationRequestSchema, value: patch },
816
+ response: conversationSchema,
817
+ signal: options?.signal
818
+ }),
819
+ delete: async (args, options) => {
820
+ await http.request({
821
+ method: HttpMethod.Delete,
822
+ path: messagePath(conversationId, args.messageId),
823
+ response: okResponseSchema,
824
+ signal: options?.signal
825
+ });
826
+ },
827
+ links: async (options) => (await http.request({
828
+ method: HttpMethod.Get,
829
+ path: conversationPath(conversationId, "/links"),
830
+ response: conversationLinkListSchema,
831
+ signal: options?.signal
832
+ })).links,
833
+ parentLinks: async (options) => (await http.request({
834
+ method: HttpMethod.Get,
835
+ path: conversationPath(conversationId, "/parent-links"),
836
+ response: conversationLinkListSchema,
837
+ signal: options?.signal
838
+ })).links,
839
+ link: (args, options) => http.request({
840
+ method: HttpMethod.Post,
841
+ path: conversationPath(conversationId, "/links"),
842
+ body: { schema: createConversationLinkRequestSchema, value: args },
843
+ response: conversationLinkSchema,
844
+ signal: options?.signal
845
+ }),
846
+ unlink: async (args, options) => {
847
+ await http.request({
848
+ method: HttpMethod.Delete,
849
+ path: conversationPath(conversationId, `/links/${encodePath(args.linkId)}`),
850
+ response: okResponseSchema,
851
+ signal: options?.signal
852
+ });
853
+ },
854
+ attachmentUrl: (args, options) => http.request({
855
+ method: HttpMethod.Get,
856
+ path: conversationPath(conversationId, `/attachments/${encodePath(args.attachmentId)}`),
857
+ response: attachmentDownloadSchema,
858
+ signal: options?.signal
859
+ }),
860
+ sandboxes: async (options) => (await http.request({
861
+ method: HttpMethod.Get,
862
+ path: conversationPath(conversationId, "/sandboxes"),
863
+ response: conversationSandboxListSchema,
864
+ signal: options?.signal
865
+ })).sandboxes,
866
+ sandboxFiles: (args, options) => http.request({
867
+ method: HttpMethod.Get,
868
+ path: conversationPath(conversationId, `/sandboxes/${encodePath(args.bindingId)}/files`),
869
+ query: { path: args.path, snapshotId: args.snapshotId },
870
+ response: sandboxDirectorySchema,
871
+ signal: options?.signal
872
+ }),
873
+ sandboxPath: (args, options) => http.request({
874
+ method: HttpMethod.Get,
875
+ path: conversationPath(conversationId, `/sandboxes/${encodePath(args.bindingId)}/path`),
876
+ query: { path: args.path, snapshotId: args.snapshotId },
877
+ response: sandboxPathSchema,
878
+ signal: options?.signal
879
+ }),
880
+ searchSandboxFiles: (args, options) => http.request({
881
+ method: HttpMethod.Get,
882
+ path: conversationPath(
883
+ conversationId,
884
+ `/sandboxes/${encodePath(args.bindingId)}/files/search`
885
+ ),
886
+ query: { path: args.path, query: args.query, limit: args.limit },
887
+ response: sandboxSearchSchema,
888
+ signal: options?.signal
889
+ }),
890
+ sandboxFile: (args, options) => http.request({
891
+ method: HttpMethod.Get,
892
+ path: conversationPath(conversationId, `/sandboxes/${encodePath(args.bindingId)}/file`),
893
+ query: {
894
+ path: args.path,
895
+ offset: args.offset,
896
+ length: args.length,
897
+ snapshotId: args.snapshotId
898
+ },
899
+ response: sandboxFileSchema,
900
+ signal: options?.signal
901
+ }),
902
+ sandboxFileContentRequest,
903
+ openSandboxEditor: (args, options) => http.request({
904
+ method: HttpMethod.Post,
905
+ path: conversationPath(conversationId, `/sandboxes/${encodePath(args.bindingId)}/editor`),
906
+ response: sandboxEditorSessionSchema,
907
+ signal: options?.signal
908
+ }),
909
+ refreshSandboxEditor: (args, options) => http.request({
910
+ method: HttpMethod.Post,
911
+ path: conversationPath(
912
+ conversationId,
913
+ `/sandboxes/${encodePath(args.bindingId)}/editor/${encodePath(args.editorId)}/refresh`
914
+ ),
915
+ body: {
916
+ schema: sandboxEditorAuthorizationSchema,
917
+ value: { authorizationId: args.authorizationId }
918
+ },
919
+ response: sandboxEditorSessionSchema,
920
+ signal: options?.signal
921
+ }),
922
+ closeSandboxEditor: async (args, options) => {
923
+ await http.request({
924
+ method: HttpMethod.Delete,
925
+ path: conversationPath(
926
+ conversationId,
927
+ `/sandboxes/${encodePath(args.bindingId)}/editor/${encodePath(args.editorId)}`
928
+ ),
929
+ body: {
930
+ schema: sandboxEditorAuthorizationSchema,
931
+ value: { authorizationId: args.authorizationId }
932
+ },
933
+ response: okResponseSchema,
934
+ signal: options?.signal,
935
+ keepalive: options?.keepalive
936
+ });
937
+ },
938
+ sandboxFileContent: async (args, options) => {
939
+ const request = await sandboxFileContentRequest(args);
940
+ let response;
941
+ try {
942
+ response = await http.fetch(request.url, {
943
+ method: HttpMethod.Get,
944
+ headers: request.headers,
945
+ credentials: request.credentials,
946
+ signal: options?.signal
947
+ });
948
+ } catch (cause) {
949
+ if (options?.signal?.aborted === true) throw cause;
950
+ throw clientError({
951
+ message: "Sandbox file request failed",
952
+ status: 0,
953
+ code: ClientErrorCode.Network,
954
+ cause
955
+ });
956
+ }
957
+ if (!response.ok) {
958
+ let text;
959
+ try {
960
+ text = await response.text();
961
+ } catch (cause) {
962
+ if (options?.signal?.aborted === true) throw cause;
963
+ throw clientError({
964
+ message: "Sandbox file response failed",
965
+ status: 0,
966
+ code: ClientErrorCode.Network,
967
+ cause
968
+ });
969
+ }
970
+ throw errorFromResponse({ status: response.status, text, context: void 0 });
971
+ }
972
+ return response;
973
+ },
974
+ inspectSandboxProcesses: (args, options) => {
975
+ const request = processInspectionRequestSchema.parse(args.request);
976
+ const { operation } = request;
977
+ const suffix = operation === ProcessInspectionOperation.Available ? "/available" : "processId" in request ? "/" + encodePath(request.processId) : "";
978
+ const query = {};
979
+ if ("bootId" in request) query.bootId = request.bootId;
980
+ if ("cursor" in request) query.cursor = request.cursor;
981
+ if ("limit" in request) query.limit = request.limit;
982
+ return http.request({
983
+ method: operation === ProcessInspectionOperation.Stop ? HttpMethod.Delete : HttpMethod.Get,
984
+ path: conversationPath(
985
+ conversationId,
986
+ `/sandboxes/${encodePath(args.bindingId)}/processes${suffix}`
987
+ ),
988
+ query,
989
+ response: processInspectionResultSchema,
990
+ signal: options?.signal
991
+ });
992
+ },
993
+ sandboxPreview: (args, options) => {
994
+ const request = {
995
+ method: args.viewOnly === false ? HttpMethod.Post : HttpMethod.Get,
996
+ path: conversationPath(conversationId, `/sandboxes/${encodePath(args.bindingId)}/preview`),
997
+ response: sandboxPreviewSchema,
998
+ signal: options?.signal
999
+ };
1000
+ if (args.viewOnly === false)
1001
+ request.body = { schema: sandboxPreviewOptionsSchema, value: { viewOnly: false } };
1002
+ return http.request(request);
1003
+ },
1004
+ wakeSandbox: (args, options) => http.request({
1005
+ method: HttpMethod.Post,
1006
+ path: conversationPath(conversationId, `/sandboxes/${encodePath(args.bindingId)}/wake`),
1007
+ response: conversationSandboxSchema,
1008
+ signal: options?.signal
1009
+ }),
1010
+ schedules: async (options) => (await http.request({
1011
+ method: HttpMethod.Get,
1012
+ path: conversationPath(conversationId, "/schedules"),
1013
+ response: conversationScheduleListSchema,
1014
+ signal: options?.signal
1015
+ })).schedules,
1016
+ createSchedule: (args, options) => http.request({
1017
+ method: HttpMethod.Post,
1018
+ path: conversationPath(conversationId, "/schedules"),
1019
+ body: { schema: createConversationScheduleRequestSchema, value: args },
1020
+ response: conversationScheduleSchema,
1021
+ signal: options?.signal
1022
+ }),
1023
+ updateSchedule: ({ scheduleId, ...patch }, options) => http.request({
1024
+ method: HttpMethod.Patch,
1025
+ path: conversationPath(conversationId, `/schedules/${encodePath(scheduleId)}`),
1026
+ body: { schema: updateConversationScheduleRequestSchema, value: patch },
1027
+ response: conversationScheduleSchema,
1028
+ signal: options?.signal
1029
+ }),
1030
+ deleteSchedule: async (args, options) => {
1031
+ await http.request({
1032
+ method: HttpMethod.Delete,
1033
+ path: conversationPath(conversationId, `/schedules/${encodePath(args.scheduleId)}`),
1034
+ response: okResponseSchema,
1035
+ signal: options?.signal
1036
+ });
1037
+ },
1038
+ uploadAttachment: async (args) => {
1039
+ const sizeBytes = "byteLength" in args.data ? args.data.byteLength : args.data.size;
1040
+ const upload = await http.request({
1041
+ method: HttpMethod.Post,
1042
+ path: conversationPath(conversationId, "/attachments"),
1043
+ body: {
1044
+ schema: createAttachmentUploadRequestSchema,
1045
+ value: { name: args.name, contentType: args.contentType, sizeBytes }
1046
+ },
1047
+ response: attachmentUploadSchema,
1048
+ signal: args.signal
1049
+ });
1050
+ const response = await context.storageFetch(upload.uploadUrl, {
1051
+ method: upload.method,
1052
+ headers: { "content-type": args.contentType, ...upload.headers },
1053
+ body: args.data,
1054
+ signal: args.signal,
1055
+ credentials: "omit"
1056
+ });
1057
+ if (!response.ok) {
1058
+ throw clientError({
1059
+ message: `Attachment upload failed with status ${response.status}`,
1060
+ status: response.status,
1061
+ code: ClientErrorCode.UploadFailed,
1062
+ body: await response.text()
1063
+ });
1064
+ }
1065
+ return upload;
1066
+ }
1067
+ };
1068
+ };
1069
+ const createConversationsApi = (context) => {
1070
+ const opened = (conversation) => ({
1071
+ ...createConversationHandle(context, conversation.id),
1072
+ conversation
1073
+ });
1074
+ return {
1075
+ list: (options) => context.http.request({
1076
+ method: HttpMethod.Get,
1077
+ path: "/v1/conversations",
1078
+ query: {
1079
+ cursor: options?.cursor,
1080
+ limit: options?.limit,
1081
+ includeArchived: options?.includeArchived
1082
+ },
1083
+ response: conversationListSchema,
1084
+ signal: options?.signal
1085
+ }),
1086
+ direct: async (args) => opened(
1087
+ await context.http.request({
1088
+ method: HttpMethod.Post,
1089
+ path: "/v1/conversations/direct",
1090
+ body: { schema: createDirectConversationRequestSchema, value: { agent: args.agent } },
1091
+ response: conversationSchema,
1092
+ signal: args.signal
1093
+ })
1094
+ ),
1095
+ home: async (options) => opened(
1096
+ await context.http.request({
1097
+ method: HttpMethod.Get,
1098
+ path: "/v1/conversations/home",
1099
+ response: conversationSchema,
1100
+ signal: options?.signal
1101
+ })
1102
+ ),
1103
+ create: async (args) => opened(
1104
+ await context.http.request({
1105
+ method: HttpMethod.Post,
1106
+ path: "/v1/conversations",
1107
+ body: {
1108
+ schema: createConversationRequestSchema,
1109
+ value: {
1110
+ kind: args.kind,
1111
+ title: args.title,
1112
+ participants: args.participants,
1113
+ turnPolicy: args.turnPolicy
1114
+ }
1115
+ },
1116
+ response: conversationSchema,
1117
+ signal: args.signal
1118
+ })
1119
+ ),
1120
+ get: (conversationId) => createConversationHandle(context, conversationId),
1121
+ search: (args) => context.http.request({
1122
+ method: HttpMethod.Get,
1123
+ path: "/v1/conversations/search",
1124
+ query: {
1125
+ q: args.q,
1126
+ conversationId: args.conversationId,
1127
+ cursor: args.cursor,
1128
+ limit: args.limit
1129
+ },
1130
+ response: searchMessagesPageSchema,
1131
+ signal: args.signal
1132
+ }),
1133
+ listEvents: (options) => streamCollectionEvents({
1134
+ context,
1135
+ topicFor: agentRealtimeTopics.userConversations,
1136
+ collection: ClientCollection.Conversations,
1137
+ options
1138
+ }),
1139
+ decisions: (options) => context.http.request({
1140
+ method: HttpMethod.Get,
1141
+ path: "/v1/decisions",
1142
+ query: { cursor: options?.cursor, limit: options?.limit },
1143
+ response: decisionsPageSchema,
1144
+ signal: options?.signal
1145
+ })
1146
+ };
1147
+ };
1148
+ export {
1149
+ RECOVERY_SKEW_MS,
1150
+ TURN_OPEN_SESSION_STATES,
1151
+ createConversationHandle,
1152
+ createConversationsApi,
1153
+ isNewerMessageVersion,
1154
+ messageVersionOf
1155
+ };
1156
+ //# sourceMappingURL=conversations.mjs.map