@truefoundry/assistant-ui-runtime 0.1.0-rc.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/README.md +567 -0
- package/dist/index.d.ts +300 -0
- package/dist/index.js +4440 -0
- package/dist/index.js.map +1 -0
- package/package.json +70 -0
- package/src/agentSessionModule.d.ts +25 -0
- package/src/agentSpec.ts +44 -0
- package/src/askUserQuestion.ts +37 -0
- package/src/attachmentAdapter.test.ts +56 -0
- package/src/attachmentAdapter.ts +58 -0
- package/src/bindDraftAgentSession.test.ts +55 -0
- package/src/bindDraftAgentSession.ts +66 -0
- package/src/buildEditedUserMessageContent.test.ts +61 -0
- package/src/collectPending.test.ts +69 -0
- package/src/collectPending.ts +165 -0
- package/src/constants.ts +2 -0
- package/src/convertTurnMessages.test.ts +1991 -0
- package/src/convertTurnMessages.ts +1251 -0
- package/src/createSubAgent.ts +8 -0
- package/src/draftAgentConfig.test.ts +88 -0
- package/src/draftSessionBridge.ts +28 -0
- package/src/extractTurnUserText.ts +21 -0
- package/src/foldPeerThreads.test.ts +386 -0
- package/src/foldPeerThreads.ts +587 -0
- package/src/hooks.ts +123 -0
- package/src/index.ts +68 -0
- package/src/lastUserMessageText.ts +19 -0
- package/src/loadSessionSnapshot.test.ts +57 -0
- package/src/loadSessionSnapshot.ts +35 -0
- package/src/mcpAuth.ts +44 -0
- package/src/messageCustomMetadata.ts +37 -0
- package/src/modelMessageContent.ts +135 -0
- package/src/modelMessageImageContent.test.ts +109 -0
- package/src/modelMessageImageContent.ts +193 -0
- package/src/requiredActionInputs.test.ts +394 -0
- package/src/requiredActionInputs.ts +65 -0
- package/src/requiredActionsFromActiveUpdate.test.ts +95 -0
- package/src/sessionListStartTimestamp.ts +6 -0
- package/src/sessionSnapshot.ts +107 -0
- package/src/sessions.ts +36 -0
- package/src/streamTurn.test.ts +243 -0
- package/src/streamTurn.ts +119 -0
- package/src/toolApproval.test.ts +137 -0
- package/src/toolApproval.ts +459 -0
- package/src/toolResponse.test.ts +136 -0
- package/src/toolResponse.ts +427 -0
- package/src/truefoundryDraftThreadListAdapter.test.ts +140 -0
- package/src/truefoundryDraftThreadListAdapter.ts +63 -0
- package/src/truefoundryExtras.ts +45 -0
- package/src/truefoundryThreadListAdapter.test.ts +103 -0
- package/src/truefoundryThreadListAdapter.ts +59 -0
- package/src/turnEventHelpers.ts +98 -0
- package/src/turnStreamUpdate.ts +11 -0
- package/src/types.ts +92 -0
- package/src/useDraftAgentSpec.ts +173 -0
- package/src/useTrueFoundryAgentMessages.test.tsx +723 -0
- package/src/useTrueFoundryAgentMessages.ts +757 -0
- package/src/useTrueFoundryAgentRuntime.ts +268 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4440 @@
|
|
|
1
|
+
// src/useTrueFoundryAgentRuntime.ts
|
|
2
|
+
import {
|
|
3
|
+
pickExternalStoreSharedOptions
|
|
4
|
+
} from "@assistant-ui/core";
|
|
5
|
+
import {
|
|
6
|
+
useExternalStoreRuntime,
|
|
7
|
+
useRemoteThreadListRuntime,
|
|
8
|
+
useRuntimeAdapters
|
|
9
|
+
} from "@assistant-ui/core/react";
|
|
10
|
+
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
11
|
+
import { useCallback as useCallback3, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
|
|
12
|
+
|
|
13
|
+
// src/constants.ts
|
|
14
|
+
var ROOT_THREAD_ID = "main";
|
|
15
|
+
|
|
16
|
+
// src/toolApproval.ts
|
|
17
|
+
var TOOL_APPROVAL_THREAD_ID_CUSTOM_KEY = "toolApprovalThreadId";
|
|
18
|
+
function hasPendingToolApproval(approval) {
|
|
19
|
+
return approval != null && approval.approved === void 0 && approval.resolution === void 0;
|
|
20
|
+
}
|
|
21
|
+
function applyApprovalDecisionToToolCall(part, options) {
|
|
22
|
+
const { approved, optionId, reason } = options;
|
|
23
|
+
const targetApproval = part.approval;
|
|
24
|
+
const approval = {
|
|
25
|
+
...targetApproval,
|
|
26
|
+
approved,
|
|
27
|
+
...optionId != null ? { optionId } : {},
|
|
28
|
+
...reason != null ? { reason } : {}
|
|
29
|
+
};
|
|
30
|
+
if (approved) {
|
|
31
|
+
return { ...part, approval };
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
...part,
|
|
35
|
+
approval,
|
|
36
|
+
result: { error: reason || "Tool approval denied" },
|
|
37
|
+
isError: true
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function updateToolApprovalInContent(content, options) {
|
|
41
|
+
let found = false;
|
|
42
|
+
const newContent = content.map((part) => {
|
|
43
|
+
if (part.type !== "tool-call") {
|
|
44
|
+
return part;
|
|
45
|
+
}
|
|
46
|
+
if (part.approval?.id === options.approvalId) {
|
|
47
|
+
found = true;
|
|
48
|
+
return applyApprovalDecisionToToolCall(part, options);
|
|
49
|
+
}
|
|
50
|
+
if (part.messages == null) {
|
|
51
|
+
return part;
|
|
52
|
+
}
|
|
53
|
+
const messages = part.messages.map((message) => {
|
|
54
|
+
if (message.role !== "assistant") {
|
|
55
|
+
return message;
|
|
56
|
+
}
|
|
57
|
+
const nested = updateToolApprovalInContent(message.content, options);
|
|
58
|
+
if (!nested.found) {
|
|
59
|
+
return message;
|
|
60
|
+
}
|
|
61
|
+
found = true;
|
|
62
|
+
return { ...message, content: nested.content };
|
|
63
|
+
});
|
|
64
|
+
return { ...part, messages };
|
|
65
|
+
});
|
|
66
|
+
return { content: newContent, found };
|
|
67
|
+
}
|
|
68
|
+
function applyApprovalDecisionsToMessage(message, options) {
|
|
69
|
+
const { content } = updateToolApprovalInContent(message.content, options);
|
|
70
|
+
return { ...message, content: [...content] };
|
|
71
|
+
}
|
|
72
|
+
function toolApprovalStatus() {
|
|
73
|
+
return { type: "requires-action", reason: "tool-calls" };
|
|
74
|
+
}
|
|
75
|
+
function toolApprovalMessageCustom(threadId) {
|
|
76
|
+
return {
|
|
77
|
+
[TOOL_APPROVAL_THREAD_ID_CUSTOM_KEY]: threadId === ROOT_THREAD_ID ? ROOT_THREAD_ID : threadId
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function getToolApprovalThreadId(message) {
|
|
81
|
+
if (message?.role !== "assistant") {
|
|
82
|
+
return void 0;
|
|
83
|
+
}
|
|
84
|
+
const threadId = message.metadata.custom[TOOL_APPROVAL_THREAD_ID_CUSTOM_KEY];
|
|
85
|
+
return typeof threadId === "string" ? threadId : void 0;
|
|
86
|
+
}
|
|
87
|
+
function findApprovalRequiredInTurn(turn) {
|
|
88
|
+
if (turn.state.status !== "done") {
|
|
89
|
+
return void 0;
|
|
90
|
+
}
|
|
91
|
+
return turn.state.requiredActions?.find(
|
|
92
|
+
(action) => action.type === "tool.approval_required"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
function toolCallPartHasPendingApproval(part) {
|
|
96
|
+
return hasPendingToolApproval(part.approval);
|
|
97
|
+
}
|
|
98
|
+
function nestedMessagesHavePendingApprovals(messages) {
|
|
99
|
+
for (const message of messages) {
|
|
100
|
+
if (messageHasPendingApprovals(message)) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
function messageHasPendingApprovals(message) {
|
|
107
|
+
if (message?.role !== "assistant") {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
for (const part of message.content) {
|
|
111
|
+
if (part.type !== "tool-call") {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (toolCallPartHasPendingApproval(part)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
if (part.messages != null && nestedMessagesHavePendingApprovals(part.messages)) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
function applyApprovalDecisionsToMessages(messages, decisions) {
|
|
124
|
+
return messages.map((message) => {
|
|
125
|
+
if (message.role !== "assistant") {
|
|
126
|
+
return message;
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
...message,
|
|
130
|
+
content: applyApprovalDecisionsToContent(message.content, decisions)
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function applyApprovalDecisionsToContent(content, decisions) {
|
|
135
|
+
return content.map((part) => {
|
|
136
|
+
if (part.type !== "tool-call") {
|
|
137
|
+
return part;
|
|
138
|
+
}
|
|
139
|
+
const decision = part.approval?.id != null ? decisions.get(part.approval.id) : void 0;
|
|
140
|
+
let nextPart = part;
|
|
141
|
+
if (decision != null && part.approval != null && part.approval.approved === void 0) {
|
|
142
|
+
nextPart = applyApprovalDecisionToToolCall(part, {
|
|
143
|
+
approvalId: part.approval.id,
|
|
144
|
+
approved: decision.approved,
|
|
145
|
+
reason: decision.reason
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (nextPart.messages == null) {
|
|
149
|
+
return nextPart;
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
...nextPart,
|
|
153
|
+
messages: applyApprovalDecisionsToMessages(nextPart.messages, decisions)
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function extractToolApprovalsFromTurnInput(input) {
|
|
158
|
+
const events = [];
|
|
159
|
+
for (const item of input ?? []) {
|
|
160
|
+
if (item.type === "user.tool_approval") {
|
|
161
|
+
events.push(item);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return events;
|
|
165
|
+
}
|
|
166
|
+
function collectSubsequentApprovalDecisions(turns, fromIndex) {
|
|
167
|
+
const decisions = /* @__PURE__ */ new Map();
|
|
168
|
+
for (let index = fromIndex + 1; index < turns.length; index++) {
|
|
169
|
+
const input = turns[index]?.input ?? [];
|
|
170
|
+
if (input.some((item) => item.type === "user.message")) {
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
for (const event of extractToolApprovalsFromTurnInput(input)) {
|
|
174
|
+
decisions.set(event.toolCallId, {
|
|
175
|
+
approved: event.approval.status === "allow",
|
|
176
|
+
...event.approval.status === "deny" && event.approval.reason != null ? { reason: event.approval.reason } : {}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return decisions;
|
|
181
|
+
}
|
|
182
|
+
function collectApprovalDecisionsFromTurnInput(input) {
|
|
183
|
+
const decisions = /* @__PURE__ */ new Map();
|
|
184
|
+
for (const event of extractToolApprovalsFromTurnInput(input)) {
|
|
185
|
+
decisions.set(event.toolCallId, {
|
|
186
|
+
approved: event.approval.status === "allow",
|
|
187
|
+
...event.approval.status === "deny" && event.approval.reason != null ? { reason: event.approval.reason } : {}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return decisions;
|
|
191
|
+
}
|
|
192
|
+
function mapApprovalDecision(approved, reason) {
|
|
193
|
+
if (approved) {
|
|
194
|
+
return { status: "allow" };
|
|
195
|
+
}
|
|
196
|
+
return { status: "deny", ...reason != null ? { reason } : {} };
|
|
197
|
+
}
|
|
198
|
+
function isDecidedApprovalAwaitingSdk(part) {
|
|
199
|
+
const { approval, result, isError } = part;
|
|
200
|
+
if (approval?.id == null || approval.approved === void 0) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
if (approval.approved === true) {
|
|
204
|
+
return result === void 0;
|
|
205
|
+
}
|
|
206
|
+
return isError === true;
|
|
207
|
+
}
|
|
208
|
+
function collectApprovalInputsFromMessages(messages, defaultThreadId) {
|
|
209
|
+
const events = [];
|
|
210
|
+
for (const message of messages) {
|
|
211
|
+
events.push(...collectApprovalInputs(message, defaultThreadId));
|
|
212
|
+
}
|
|
213
|
+
return events;
|
|
214
|
+
}
|
|
215
|
+
function collectApprovalInputs(message, threadId) {
|
|
216
|
+
if (message.role !== "assistant" || !threadId) {
|
|
217
|
+
return [];
|
|
218
|
+
}
|
|
219
|
+
if (messageHasPendingApprovals(message)) {
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
const scopedThreadId = getToolApprovalThreadId(message) ?? threadId;
|
|
223
|
+
const events = [];
|
|
224
|
+
for (const part of message.content) {
|
|
225
|
+
if (part.type !== "tool-call") {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (isDecidedApprovalAwaitingSdk(part)) {
|
|
229
|
+
const { approval } = part;
|
|
230
|
+
if (approval == null) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
events.push({
|
|
234
|
+
type: "user.tool_approval",
|
|
235
|
+
threadId: scopedThreadId,
|
|
236
|
+
toolCallId: approval.id,
|
|
237
|
+
approval: mapApprovalDecision(approval.approved, approval.reason)
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
if (part.messages != null) {
|
|
241
|
+
events.push(
|
|
242
|
+
...collectApprovalInputsFromMessages(part.messages, scopedThreadId)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return events;
|
|
247
|
+
}
|
|
248
|
+
function toTrueFoundryApprovalInputs(message, response, defaultThreadId = ROOT_THREAD_ID) {
|
|
249
|
+
const updated = applyApprovalDecisionsToMessage(message, response);
|
|
250
|
+
return collectApprovalInputs(updated, defaultThreadId);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/foldPeerThreads.ts
|
|
254
|
+
import {
|
|
255
|
+
isEventDelta as isEventDelta2
|
|
256
|
+
} from "truefoundry-gateway-sdk/agents";
|
|
257
|
+
|
|
258
|
+
// src/askUserQuestion.ts
|
|
259
|
+
function parseAskUserQuestionArgs(argsText) {
|
|
260
|
+
if (!argsText) {
|
|
261
|
+
return {};
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const parsed = JSON.parse(argsText);
|
|
265
|
+
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
266
|
+
return {};
|
|
267
|
+
}
|
|
268
|
+
const record = parsed;
|
|
269
|
+
const question = typeof record.question === "string" ? record.question : void 0;
|
|
270
|
+
const options = Array.isArray(record.options) ? record.options.filter((item) => typeof item === "string") : void 0;
|
|
271
|
+
return { question, options };
|
|
272
|
+
} catch {
|
|
273
|
+
return {};
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/createSubAgent.ts
|
|
278
|
+
function isCreateSubAgentToolCall(toolCall) {
|
|
279
|
+
return toolCall.toolInfo.type === "truefoundry-system" && toolCall.toolInfo.name === "create_sub_agent";
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// src/modelMessageImageContent.ts
|
|
283
|
+
import { isEventDelta, mergeEventDelta } from "truefoundry-gateway-sdk/agents";
|
|
284
|
+
function parseDataUriMime(data) {
|
|
285
|
+
if (!data.startsWith("data:")) {
|
|
286
|
+
return "image/png";
|
|
287
|
+
}
|
|
288
|
+
const match = /^data:([^;,]+)/.exec(data);
|
|
289
|
+
return match?.[1] ?? "image/png";
|
|
290
|
+
}
|
|
291
|
+
function imageFilenameFromUrl(url, index) {
|
|
292
|
+
const mimeType = parseDataUriMime(url);
|
|
293
|
+
const ext = mimeType.split("/")[1] ?? "png";
|
|
294
|
+
return `image-${index + 1}.${ext}`;
|
|
295
|
+
}
|
|
296
|
+
function isImageUrlContentPart(part) {
|
|
297
|
+
return part != null && typeof part === "object" && part.type === "image_url" && typeof part.image_url?.url === "string";
|
|
298
|
+
}
|
|
299
|
+
function normalizeModelMessageContent(message) {
|
|
300
|
+
const { content } = message;
|
|
301
|
+
if (content == null) {
|
|
302
|
+
return [];
|
|
303
|
+
}
|
|
304
|
+
if (typeof content === "string") {
|
|
305
|
+
return content.length > 0 ? [{ type: "text", text: content }] : [];
|
|
306
|
+
}
|
|
307
|
+
return content;
|
|
308
|
+
}
|
|
309
|
+
function ensureModelMessageContentArray(message) {
|
|
310
|
+
if (Array.isArray(message.content)) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
message.content = normalizeModelMessageContent(message);
|
|
314
|
+
}
|
|
315
|
+
function mergeContentBlockDeltas(message, blocks) {
|
|
316
|
+
ensureModelMessageContentArray(message);
|
|
317
|
+
const content = message.content;
|
|
318
|
+
for (const block of blocks) {
|
|
319
|
+
const index = block.index;
|
|
320
|
+
while (content.length <= index) {
|
|
321
|
+
content.push({ type: "text", text: "" });
|
|
322
|
+
}
|
|
323
|
+
const delta = block.delta;
|
|
324
|
+
if (delta.type === "text") {
|
|
325
|
+
const existing2 = content[index];
|
|
326
|
+
if (existing2?.type === "text") {
|
|
327
|
+
existing2.text += delta.text ?? "";
|
|
328
|
+
} else {
|
|
329
|
+
content[index] = { type: "text", text: delta.text ?? "" };
|
|
330
|
+
}
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (delta.type !== "image_url") {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
const chunk = delta.image_url?.url ?? "";
|
|
337
|
+
const existing = content[index];
|
|
338
|
+
if (isImageUrlContentPart(existing)) {
|
|
339
|
+
existing.image_url.url += chunk;
|
|
340
|
+
} else {
|
|
341
|
+
content[index] = { type: "image_url", image_url: { url: chunk } };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function mergeStreamEventDelta(base, delta) {
|
|
346
|
+
if (!isEventDelta(delta)) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
mergeEventDelta(base, delta);
|
|
350
|
+
if (base.type !== "model.message" || delta.type !== "model.message.delta") {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const extended = delta;
|
|
354
|
+
const blocks = extended.contentBlocks ?? extended.content_blocks;
|
|
355
|
+
if (blocks == null || blocks.length === 0) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
mergeContentBlockDeltas(base, blocks);
|
|
359
|
+
}
|
|
360
|
+
function imageUrlToAttachment(url, attachmentId) {
|
|
361
|
+
const mimeType = parseDataUriMime(url);
|
|
362
|
+
return {
|
|
363
|
+
id: attachmentId,
|
|
364
|
+
type: "image",
|
|
365
|
+
name: imageFilenameFromUrl(url, 0),
|
|
366
|
+
contentType: mimeType,
|
|
367
|
+
status: { type: "complete" },
|
|
368
|
+
content: [{ type: "image", image: url, filename: imageFilenameFromUrl(url, 0) }]
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function imagePartToAssistantImage(url, index) {
|
|
372
|
+
return {
|
|
373
|
+
type: "image",
|
|
374
|
+
image: url,
|
|
375
|
+
filename: imageFilenameFromUrl(url, index)
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function extractImagePartsFromModelMessage(message) {
|
|
379
|
+
const parts = [];
|
|
380
|
+
let imageIndex = 0;
|
|
381
|
+
for (const part of normalizeModelMessageContent(message)) {
|
|
382
|
+
if (!isImageUrlContentPart(part)) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
const url = part.image_url.url.trim();
|
|
386
|
+
if (url.length === 0) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
parts.push(imagePartToAssistantImage(url, imageIndex));
|
|
390
|
+
imageIndex += 1;
|
|
391
|
+
}
|
|
392
|
+
return parts;
|
|
393
|
+
}
|
|
394
|
+
function extractImageUrlFromUserContentItem(part) {
|
|
395
|
+
if (isImageUrlContentPart(part)) {
|
|
396
|
+
const url = part.image_url.url.trim();
|
|
397
|
+
return url.length > 0 ? url : void 0;
|
|
398
|
+
}
|
|
399
|
+
return void 0;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// src/modelMessageContent.ts
|
|
403
|
+
function parseToolArgs(argsText) {
|
|
404
|
+
if (!argsText) {
|
|
405
|
+
return {};
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
const parsed = JSON.parse(argsText);
|
|
409
|
+
if (parsed != null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
410
|
+
return parsed;
|
|
411
|
+
}
|
|
412
|
+
return {};
|
|
413
|
+
} catch {
|
|
414
|
+
return {};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
function toolCallToPart(toolCall, context) {
|
|
418
|
+
const argsText = toolCall.function.arguments ?? "";
|
|
419
|
+
const toolResult = context?.toolResults?.get(toolCall.id);
|
|
420
|
+
const pendingResponse = context?.pendingResponses?.get(toolCall.id);
|
|
421
|
+
const pendingApproval = context?.pendingApprovals?.get(toolCall.id);
|
|
422
|
+
const approvalDecision = context?.approvalDecisions?.get(toolCall.id);
|
|
423
|
+
let interrupt;
|
|
424
|
+
if (pendingResponse != null && toolResult === void 0) {
|
|
425
|
+
interrupt = {
|
|
426
|
+
type: "human",
|
|
427
|
+
payload: {
|
|
428
|
+
...pendingResponse.question != null ? { question: pendingResponse.question } : {},
|
|
429
|
+
...pendingResponse.options != null ? { options: pendingResponse.options } : {}
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
let approval;
|
|
434
|
+
if (approvalDecision != null) {
|
|
435
|
+
approval = {
|
|
436
|
+
id: approvalDecision.id,
|
|
437
|
+
approved: approvalDecision.approved,
|
|
438
|
+
...approvalDecision.reason != null ? { reason: approvalDecision.reason } : {}
|
|
439
|
+
};
|
|
440
|
+
} else if (pendingApproval != null) {
|
|
441
|
+
approval = { id: pendingApproval.id };
|
|
442
|
+
}
|
|
443
|
+
let result;
|
|
444
|
+
let isError = false;
|
|
445
|
+
if (toolResult !== void 0) {
|
|
446
|
+
result = toolResult;
|
|
447
|
+
} else if (approvalDecision?.approved === false) {
|
|
448
|
+
result = { error: approvalDecision.reason || "Tool approval denied" };
|
|
449
|
+
isError = true;
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
type: "tool-call",
|
|
453
|
+
toolCallId: toolCall.id,
|
|
454
|
+
toolName: toolCall.function.name,
|
|
455
|
+
argsText,
|
|
456
|
+
args: parseToolArgs(argsText),
|
|
457
|
+
...result !== void 0 ? { result } : {},
|
|
458
|
+
...isError ? { isError: true } : {},
|
|
459
|
+
...approval != null ? { approval } : {},
|
|
460
|
+
...interrupt != null ? { interrupt } : {}
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function extractText(message) {
|
|
464
|
+
const { content, refusal } = message;
|
|
465
|
+
if (content == null) {
|
|
466
|
+
return refusal ?? "";
|
|
467
|
+
}
|
|
468
|
+
if (typeof content === "string") {
|
|
469
|
+
return content;
|
|
470
|
+
}
|
|
471
|
+
return content.map((part) => {
|
|
472
|
+
if (part.type === "text") {
|
|
473
|
+
return part.text;
|
|
474
|
+
}
|
|
475
|
+
if (part.type === "refusal") {
|
|
476
|
+
return part.refusal;
|
|
477
|
+
}
|
|
478
|
+
return "";
|
|
479
|
+
}).join("");
|
|
480
|
+
}
|
|
481
|
+
function buildAssistantContent(message, context) {
|
|
482
|
+
const parts = [];
|
|
483
|
+
if (message.reasoningContent) {
|
|
484
|
+
parts.push({ type: "reasoning", text: message.reasoningContent });
|
|
485
|
+
}
|
|
486
|
+
const text = extractText(message);
|
|
487
|
+
if (text) {
|
|
488
|
+
parts.push({ type: "text", text });
|
|
489
|
+
}
|
|
490
|
+
parts.push(...extractImagePartsFromModelMessage(message));
|
|
491
|
+
for (const toolCall of message.toolCalls ?? []) {
|
|
492
|
+
parts.push(toolCallToPart(toolCall, context));
|
|
493
|
+
}
|
|
494
|
+
return parts;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// src/foldPeerThreads.ts
|
|
498
|
+
var isDev = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.NODE_ENV !== "production";
|
|
499
|
+
function warnUnexpectedRootThread(threadId, eventType) {
|
|
500
|
+
if (!isDev) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
console.warn(
|
|
504
|
+
`[@truefoundry/assistant-ui-runtime] Expected root thread "${ROOT_THREAD_ID}" but received "${threadId}" on ${eventType}.`
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
function assertRootThreadEvent(threadId, eventType) {
|
|
508
|
+
if (threadId === ROOT_THREAD_ID) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (isDev) {
|
|
512
|
+
throw new Error(
|
|
513
|
+
`[@truefoundry/assistant-ui-runtime] Root-looking event ${eventType} arrived on thread "${threadId}" instead of "${ROOT_THREAD_ID}".`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
warnUnexpectedRootThread(threadId, eventType);
|
|
517
|
+
}
|
|
518
|
+
var PeerThreadFoldState = class {
|
|
519
|
+
threads = /* @__PURE__ */ new Map();
|
|
520
|
+
threadParents = /* @__PURE__ */ new Map();
|
|
521
|
+
getOrCreateBucket(threadId) {
|
|
522
|
+
let bucket = this.threads.get(threadId);
|
|
523
|
+
if (bucket == null) {
|
|
524
|
+
bucket = {
|
|
525
|
+
events: /* @__PURE__ */ new Map(),
|
|
526
|
+
modelMessageIds: [],
|
|
527
|
+
toolResults: /* @__PURE__ */ new Map(),
|
|
528
|
+
pendingApprovals: /* @__PURE__ */ new Map(),
|
|
529
|
+
approvalDecisions: /* @__PURE__ */ new Map(),
|
|
530
|
+
pendingResponses: /* @__PURE__ */ new Map(),
|
|
531
|
+
done: false
|
|
532
|
+
};
|
|
533
|
+
this.threads.set(threadId, bucket);
|
|
534
|
+
}
|
|
535
|
+
return bucket;
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
function isTurnScopedEvent(message) {
|
|
539
|
+
return message.type === "turn.created" || message.type === "turn.done";
|
|
540
|
+
}
|
|
541
|
+
function ingestEventIntoBucket(bucket, message) {
|
|
542
|
+
if (isTurnScopedEvent(message)) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (isEventDelta2(message)) {
|
|
546
|
+
const base = bucket.events.get(message.id);
|
|
547
|
+
if (base != null) {
|
|
548
|
+
mergeStreamEventDelta(base, message);
|
|
549
|
+
}
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
bucket.events.set(message.id, message);
|
|
553
|
+
if (message.type === "model.message") {
|
|
554
|
+
if (!bucket.modelMessageIds.includes(message.id)) {
|
|
555
|
+
bucket.modelMessageIds.push(message.id);
|
|
556
|
+
}
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (message.type === "tool.response") {
|
|
560
|
+
bucket.toolResults.set(message.toolCallId, message.content);
|
|
561
|
+
bucket.pendingResponses.delete(message.toolCallId);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (message.type === "tool.approval_required") {
|
|
565
|
+
for (const ref of message.toolCalls) {
|
|
566
|
+
bucket.pendingApprovals.set(ref.id, { id: ref.id });
|
|
567
|
+
}
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
if (message.type === "tool.response_required") {
|
|
571
|
+
for (const ref of message.toolCalls) {
|
|
572
|
+
const resolved = resolveAskUserQuestionFromBucket(bucket, ref);
|
|
573
|
+
bucket.pendingResponses.set(ref.id, {
|
|
574
|
+
id: ref.id,
|
|
575
|
+
sourceEventId: ref.sourceEventId,
|
|
576
|
+
...resolved?.question != null ? { question: resolved.question } : {},
|
|
577
|
+
...resolved?.options != null ? { options: resolved.options } : {}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (message.type === "thread.done") {
|
|
583
|
+
bucket.done = true;
|
|
584
|
+
if (message.title) {
|
|
585
|
+
bucket.title = message.title;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
function isContentAffectingEvent(message) {
|
|
590
|
+
return message.type === "thread.created" || message.type === "thread.done" || message.type === "model.message" || message.type === "model.message.delta" || message.type === "tool.response" || message.type === "tool.approval_required" || message.type === "tool.response_required";
|
|
591
|
+
}
|
|
592
|
+
function ingestStreamEvent(state, message) {
|
|
593
|
+
if (message.type === "mcp.auth_required" || isTurnScopedEvent(message)) {
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
if (message.threadId == null) {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
if (message.type === "thread.created") {
|
|
600
|
+
state.threadParents.set(message.threadId, {
|
|
601
|
+
parentThreadId: message.parent.threadId,
|
|
602
|
+
toolCallId: message.parent.toolCallId
|
|
603
|
+
});
|
|
604
|
+
const bucket2 = state.getOrCreateBucket(message.threadId);
|
|
605
|
+
bucket2.title = message.title;
|
|
606
|
+
bucket2.agentInfo = message.agentInfo;
|
|
607
|
+
return true;
|
|
608
|
+
}
|
|
609
|
+
if (message.type === "model.message" && message.threadId === ROOT_THREAD_ID) {
|
|
610
|
+
assertRootThreadEvent(message.threadId, message.type);
|
|
611
|
+
}
|
|
612
|
+
const bucket = state.getOrCreateBucket(message.threadId);
|
|
613
|
+
ingestEventIntoBucket(bucket, message);
|
|
614
|
+
return isContentAffectingEvent(message);
|
|
615
|
+
}
|
|
616
|
+
function ingestTurnEvent(state, event) {
|
|
617
|
+
if (event.threadId == null) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (event.type === "thread.created") {
|
|
621
|
+
state.threadParents.set(event.threadId, {
|
|
622
|
+
parentThreadId: event.parent.threadId,
|
|
623
|
+
toolCallId: event.parent.toolCallId
|
|
624
|
+
});
|
|
625
|
+
const bucket = state.getOrCreateBucket(event.threadId);
|
|
626
|
+
bucket.title = event.title;
|
|
627
|
+
bucket.agentInfo = event.agentInfo;
|
|
628
|
+
} else if (event.type === "model.message" && event.threadId === ROOT_THREAD_ID) {
|
|
629
|
+
assertRootThreadEvent(event.threadId, event.type);
|
|
630
|
+
}
|
|
631
|
+
ingestEventIntoBucket(state.getOrCreateBucket(event.threadId), event);
|
|
632
|
+
}
|
|
633
|
+
function resolveAskUserQuestionFromBucket(bucket, ref) {
|
|
634
|
+
const modelMessage = bucket.events.get(ref.sourceEventId);
|
|
635
|
+
if (modelMessage?.type !== "model.message") {
|
|
636
|
+
return void 0;
|
|
637
|
+
}
|
|
638
|
+
const toolCall = modelMessage.toolCalls?.find((call) => call.id === ref.id);
|
|
639
|
+
if (toolCall == null) {
|
|
640
|
+
return void 0;
|
|
641
|
+
}
|
|
642
|
+
return parseAskUserQuestionArgs(toolCall.function.arguments);
|
|
643
|
+
}
|
|
644
|
+
function findToolCallInBucket(bucket, toolCallId) {
|
|
645
|
+
for (const id of bucket.modelMessageIds) {
|
|
646
|
+
const event = bucket.events.get(id);
|
|
647
|
+
if (event?.type !== "model.message") {
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
const match = event.toolCalls?.find((toolCall) => toolCall.id === toolCallId);
|
|
651
|
+
if (match != null) {
|
|
652
|
+
return match;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return void 0;
|
|
656
|
+
}
|
|
657
|
+
function isLinkedCreateSubAgentThread(state, subThreadId) {
|
|
658
|
+
const link = state.threadParents.get(subThreadId);
|
|
659
|
+
if (link == null) {
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
const parentBucket = state.threads.get(link.parentThreadId);
|
|
663
|
+
if (parentBucket == null) {
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
const toolCall = findToolCallInBucket(parentBucket, link.toolCallId);
|
|
667
|
+
return toolCall != null && isCreateSubAgentToolCall(toolCall);
|
|
668
|
+
}
|
|
669
|
+
function childSubThreadIds(state, parentThreadId, toolCallId) {
|
|
670
|
+
const ids = [];
|
|
671
|
+
for (const [subThreadId, link] of state.threadParents) {
|
|
672
|
+
if (link.parentThreadId === parentThreadId && link.toolCallId === toolCallId && isLinkedCreateSubAgentThread(state, subThreadId)) {
|
|
673
|
+
ids.push(subThreadId);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return ids;
|
|
677
|
+
}
|
|
678
|
+
function bucketHasUnresolvedPendingResponses(bucket) {
|
|
679
|
+
for (const id of bucket.pendingResponses.keys()) {
|
|
680
|
+
if (!bucket.toolResults.has(id)) {
|
|
681
|
+
return true;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
function bucketAssistantStatus(bucket) {
|
|
687
|
+
if (bucket.pendingApprovals.size > 0) {
|
|
688
|
+
return toolApprovalStatus();
|
|
689
|
+
}
|
|
690
|
+
if (bucketHasUnresolvedPendingResponses(bucket)) {
|
|
691
|
+
return toolResponseStatus();
|
|
692
|
+
}
|
|
693
|
+
if (!bucket.done && bucket.modelMessageIds.length > 0) {
|
|
694
|
+
return { type: "running" };
|
|
695
|
+
}
|
|
696
|
+
return { type: "complete", reason: "stop" };
|
|
697
|
+
}
|
|
698
|
+
function buildSubAgentCustomMetadata(threadId, bucket) {
|
|
699
|
+
const metadata = {
|
|
700
|
+
threadId,
|
|
701
|
+
...bucket.title != null ? { title: bucket.title } : {},
|
|
702
|
+
...bucket.agentInfo?.name != null ? { name: bucket.agentInfo.name } : {},
|
|
703
|
+
...bucket.agentInfo?.model != null ? { model: bucket.agentInfo.model } : {},
|
|
704
|
+
...bucket.agentInfo?.input != null ? { input: bucket.agentInfo.input } : {}
|
|
705
|
+
};
|
|
706
|
+
return { subAgent: metadata };
|
|
707
|
+
}
|
|
708
|
+
function attachSubAgentMessages(state, parentThreadId, parts) {
|
|
709
|
+
const parentBucket = state.threads.get(parentThreadId);
|
|
710
|
+
return parts.map((part) => {
|
|
711
|
+
if (part.type !== "tool-call" || parentBucket == null) {
|
|
712
|
+
return part;
|
|
713
|
+
}
|
|
714
|
+
const sdkToolCall = findToolCallInBucket(parentBucket, part.toolCallId);
|
|
715
|
+
if (sdkToolCall == null || !isCreateSubAgentToolCall(sdkToolCall)) {
|
|
716
|
+
return part;
|
|
717
|
+
}
|
|
718
|
+
const childIds = childSubThreadIds(state, parentThreadId, part.toolCallId);
|
|
719
|
+
if (childIds.length === 0) {
|
|
720
|
+
return part;
|
|
721
|
+
}
|
|
722
|
+
const messages = [];
|
|
723
|
+
const subAgents = [];
|
|
724
|
+
for (const childId of childIds) {
|
|
725
|
+
const childMessages = buildSubThreadMessages(state, childId);
|
|
726
|
+
if (childMessages.length > 0) {
|
|
727
|
+
messages.push(...childMessages);
|
|
728
|
+
}
|
|
729
|
+
const childBucket = state.threads.get(childId);
|
|
730
|
+
if (childBucket != null) {
|
|
731
|
+
subAgents.push({
|
|
732
|
+
threadId: childId,
|
|
733
|
+
...childBucket.title != null ? { title: childBucket.title } : {},
|
|
734
|
+
...childBucket.agentInfo != null ? { agentInfo: childBucket.agentInfo } : {}
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
if (messages.length === 0) {
|
|
739
|
+
return part;
|
|
740
|
+
}
|
|
741
|
+
const artifact = { subAgents };
|
|
742
|
+
return { ...part, messages, artifact };
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
function buildThreadAssistantParts(state, threadId, modelMessageIds) {
|
|
746
|
+
const bucket = state.threads.get(threadId);
|
|
747
|
+
if (bucket == null) {
|
|
748
|
+
return [];
|
|
749
|
+
}
|
|
750
|
+
const ids = threadId === ROOT_THREAD_ID && modelMessageIds != null ? modelMessageIds : bucket.modelMessageIds;
|
|
751
|
+
const parts = [];
|
|
752
|
+
const toolCallIndexById = /* @__PURE__ */ new Map();
|
|
753
|
+
for (const id of ids) {
|
|
754
|
+
const event = bucket.events.get(id);
|
|
755
|
+
if (event?.type !== "model.message") {
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
for (const part of buildAssistantContent(event, {
|
|
759
|
+
toolResults: bucket.toolResults,
|
|
760
|
+
pendingApprovals: bucket.pendingApprovals,
|
|
761
|
+
approvalDecisions: bucket.approvalDecisions,
|
|
762
|
+
pendingResponses: bucket.pendingResponses
|
|
763
|
+
})) {
|
|
764
|
+
if (part.type === "tool-call") {
|
|
765
|
+
const existingIndex = toolCallIndexById.get(part.toolCallId);
|
|
766
|
+
if (existingIndex != null) {
|
|
767
|
+
parts[existingIndex] = part;
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
toolCallIndexById.set(part.toolCallId, parts.length);
|
|
771
|
+
}
|
|
772
|
+
parts.push(part);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return attachSubAgentMessages(state, threadId, parts);
|
|
776
|
+
}
|
|
777
|
+
function buildSubThreadMessages(state, threadId) {
|
|
778
|
+
const bucket = state.threads.get(threadId);
|
|
779
|
+
if (bucket == null) {
|
|
780
|
+
return [];
|
|
781
|
+
}
|
|
782
|
+
const content = buildThreadAssistantParts(state, threadId);
|
|
783
|
+
if (content.length === 0) {
|
|
784
|
+
return [];
|
|
785
|
+
}
|
|
786
|
+
const custom = {
|
|
787
|
+
...buildSubAgentCustomMetadata(threadId, bucket),
|
|
788
|
+
...bucket.pendingApprovals.size > 0 ? toolApprovalMessageCustom(threadId) : {},
|
|
789
|
+
...bucketHasUnresolvedPendingResponses(bucket) ? toolResponseMessageCustom(threadId) : {}
|
|
790
|
+
};
|
|
791
|
+
return [
|
|
792
|
+
{
|
|
793
|
+
id: `${threadId}-assistant`,
|
|
794
|
+
role: "assistant",
|
|
795
|
+
content,
|
|
796
|
+
status: bucketAssistantStatus(bucket),
|
|
797
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
798
|
+
metadata: {
|
|
799
|
+
unstable_state: null,
|
|
800
|
+
unstable_annotations: [],
|
|
801
|
+
unstable_data: [],
|
|
802
|
+
steps: [],
|
|
803
|
+
custom
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
];
|
|
807
|
+
}
|
|
808
|
+
function buildRootAssistantContent(state) {
|
|
809
|
+
return buildThreadAssistantParts(state, ROOT_THREAD_ID);
|
|
810
|
+
}
|
|
811
|
+
function buildRootAssistantContentForIds(state, modelMessageIds) {
|
|
812
|
+
return buildThreadAssistantParts(state, ROOT_THREAD_ID, modelMessageIds);
|
|
813
|
+
}
|
|
814
|
+
function findFirstPendingApprovalThreadId(state) {
|
|
815
|
+
for (const [threadId, bucket] of state.threads) {
|
|
816
|
+
if (bucket.pendingApprovals.size > 0) {
|
|
817
|
+
return threadId;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return void 0;
|
|
821
|
+
}
|
|
822
|
+
function findFirstPendingResponseThreadId(state) {
|
|
823
|
+
for (const [threadId, bucket] of state.threads) {
|
|
824
|
+
if (bucketHasUnresolvedPendingResponses(bucket)) {
|
|
825
|
+
return threadId;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return void 0;
|
|
829
|
+
}
|
|
830
|
+
function recordToolApprovalInFold(fold, decision) {
|
|
831
|
+
const record = {
|
|
832
|
+
id: decision.toolCallId,
|
|
833
|
+
approved: decision.approved,
|
|
834
|
+
...decision.reason != null ? { reason: decision.reason } : {}
|
|
835
|
+
};
|
|
836
|
+
let applied = false;
|
|
837
|
+
for (const bucket of fold.threads.values()) {
|
|
838
|
+
if (!bucket.pendingApprovals.has(decision.toolCallId)) {
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
bucket.pendingApprovals.delete(decision.toolCallId);
|
|
842
|
+
bucket.approvalDecisions.set(decision.toolCallId, record);
|
|
843
|
+
applied = true;
|
|
844
|
+
}
|
|
845
|
+
if (applied) {
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
const rootBucket = fold.getOrCreateBucket(ROOT_THREAD_ID);
|
|
849
|
+
rootBucket.approvalDecisions.set(decision.toolCallId, record);
|
|
850
|
+
}
|
|
851
|
+
function recordToolResponseInFold(fold, response) {
|
|
852
|
+
let applied = false;
|
|
853
|
+
for (const bucket of fold.threads.values()) {
|
|
854
|
+
if (!bucket.pendingResponses.has(response.toolCallId)) {
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
bucket.toolResults.set(response.toolCallId, response.content);
|
|
858
|
+
bucket.pendingResponses.delete(response.toolCallId);
|
|
859
|
+
applied = true;
|
|
860
|
+
}
|
|
861
|
+
if (applied) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const rootBucket = fold.getOrCreateBucket(ROOT_THREAD_ID);
|
|
865
|
+
rootBucket.toolResults.set(response.toolCallId, response.content);
|
|
866
|
+
rootBucket.pendingResponses.delete(response.toolCallId);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// src/toolResponse.ts
|
|
870
|
+
var TOOL_RESPONSE_THREAD_ID_CUSTOM_KEY = "toolResponseThreadId";
|
|
871
|
+
function hasPendingToolResponse(part) {
|
|
872
|
+
return part.interrupt != null && part.result === void 0;
|
|
873
|
+
}
|
|
874
|
+
function isStagedResponseAwaitingSdk(part) {
|
|
875
|
+
return part.interrupt != null && part.result !== void 0;
|
|
876
|
+
}
|
|
877
|
+
function toolResponseStatus() {
|
|
878
|
+
return { type: "requires-action", reason: "tool-calls" };
|
|
879
|
+
}
|
|
880
|
+
function toolResponseMessageCustom(threadId) {
|
|
881
|
+
return {
|
|
882
|
+
[TOOL_RESPONSE_THREAD_ID_CUSTOM_KEY]: threadId === ROOT_THREAD_ID ? ROOT_THREAD_ID : threadId
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function getToolResponseThreadId(message) {
|
|
886
|
+
if (message?.role !== "assistant") {
|
|
887
|
+
return void 0;
|
|
888
|
+
}
|
|
889
|
+
const threadId = message.metadata.custom[TOOL_RESPONSE_THREAD_ID_CUSTOM_KEY];
|
|
890
|
+
return typeof threadId === "string" ? threadId : void 0;
|
|
891
|
+
}
|
|
892
|
+
function findResponseRequiredInTurn(turn) {
|
|
893
|
+
if (turn.state.status !== "done") {
|
|
894
|
+
return void 0;
|
|
895
|
+
}
|
|
896
|
+
return turn.state.requiredActions?.find(
|
|
897
|
+
(action) => action.type === "tool.response_required"
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
function applyToolResponseToToolCall(part, content) {
|
|
901
|
+
return { ...part, result: content };
|
|
902
|
+
}
|
|
903
|
+
function nestedMessagesHavePendingResponses(messages) {
|
|
904
|
+
for (const message of messages) {
|
|
905
|
+
if (messageHasPendingResponses(message)) {
|
|
906
|
+
return true;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
function messageHasPendingResponses(message) {
|
|
912
|
+
if (message?.role !== "assistant") {
|
|
913
|
+
return false;
|
|
914
|
+
}
|
|
915
|
+
for (const part of message.content) {
|
|
916
|
+
if (part.type !== "tool-call") {
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
if (hasPendingToolResponse(part)) {
|
|
920
|
+
return true;
|
|
921
|
+
}
|
|
922
|
+
if (part.messages != null && nestedMessagesHavePendingResponses(part.messages)) {
|
|
923
|
+
return true;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
function collectResponseInputsFromMessages(messages, defaultThreadId) {
|
|
929
|
+
const events = [];
|
|
930
|
+
for (const message of messages) {
|
|
931
|
+
events.push(...collectResponseInputs(message, defaultThreadId));
|
|
932
|
+
}
|
|
933
|
+
return events;
|
|
934
|
+
}
|
|
935
|
+
function collectResponseInputs(message, threadId) {
|
|
936
|
+
if (message.role !== "assistant" || !threadId) {
|
|
937
|
+
return [];
|
|
938
|
+
}
|
|
939
|
+
if (messageHasPendingResponses(message)) {
|
|
940
|
+
return [];
|
|
941
|
+
}
|
|
942
|
+
const scopedThreadId = getToolResponseThreadId(message) ?? threadId;
|
|
943
|
+
const events = [];
|
|
944
|
+
for (const part of message.content) {
|
|
945
|
+
if (part.type !== "tool-call") {
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
if (isStagedResponseAwaitingSdk(part)) {
|
|
949
|
+
events.push({
|
|
950
|
+
type: "user.tool_response",
|
|
951
|
+
threadId: scopedThreadId,
|
|
952
|
+
toolCallId: part.toolCallId,
|
|
953
|
+
content: String(part.result)
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
if (part.messages != null) {
|
|
957
|
+
events.push(
|
|
958
|
+
...collectResponseInputsFromMessages(part.messages, scopedThreadId)
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
return events;
|
|
963
|
+
}
|
|
964
|
+
function applyStagedResponsesToContentMap(content, staged) {
|
|
965
|
+
return content.map((part) => {
|
|
966
|
+
if (part.type !== "tool-call") {
|
|
967
|
+
return part;
|
|
968
|
+
}
|
|
969
|
+
const contentValue = staged.get(part.toolCallId);
|
|
970
|
+
let nextPart = part;
|
|
971
|
+
if (contentValue != null && hasPendingToolResponse(part)) {
|
|
972
|
+
nextPart = applyToolResponseToToolCall(part, contentValue);
|
|
973
|
+
}
|
|
974
|
+
if (nextPart.messages == null) {
|
|
975
|
+
return nextPart;
|
|
976
|
+
}
|
|
977
|
+
return {
|
|
978
|
+
...nextPart,
|
|
979
|
+
messages: nextPart.messages.map((message) => {
|
|
980
|
+
if (message.role !== "assistant") {
|
|
981
|
+
return message;
|
|
982
|
+
}
|
|
983
|
+
return {
|
|
984
|
+
...message,
|
|
985
|
+
content: applyStagedResponsesToContentMap(message.content, staged)
|
|
986
|
+
};
|
|
987
|
+
})
|
|
988
|
+
};
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
function extractToolResponsesFromTurnInput(input) {
|
|
992
|
+
const events = [];
|
|
993
|
+
for (const item of input ?? []) {
|
|
994
|
+
if (item.type === "user.tool_response") {
|
|
995
|
+
events.push(item);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
return events;
|
|
999
|
+
}
|
|
1000
|
+
function applyUserToolResponsesToFold(fold, inputs) {
|
|
1001
|
+
for (const item of inputs) {
|
|
1002
|
+
if (item.type === "user.tool_response") {
|
|
1003
|
+
recordToolResponseInFold(fold, {
|
|
1004
|
+
toolCallId: item.toolCallId,
|
|
1005
|
+
content: item.content
|
|
1006
|
+
});
|
|
1007
|
+
} else if (item.type === "user.tool_approval") {
|
|
1008
|
+
recordToolApprovalInFold(fold, {
|
|
1009
|
+
toolCallId: item.toolCallId,
|
|
1010
|
+
approved: item.approval.status === "allow",
|
|
1011
|
+
...item.approval.status === "deny" && item.approval.reason != null ? { reason: item.approval.reason } : {}
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
function collectSubsequentToolResponses(turns, fromIndex) {
|
|
1017
|
+
const responses = /* @__PURE__ */ new Map();
|
|
1018
|
+
for (let index = fromIndex + 1; index < turns.length; index++) {
|
|
1019
|
+
const input = turns[index]?.input ?? [];
|
|
1020
|
+
if (input.some((item) => item.type === "user.message")) {
|
|
1021
|
+
break;
|
|
1022
|
+
}
|
|
1023
|
+
for (const event of extractToolResponsesFromTurnInput(input)) {
|
|
1024
|
+
responses.set(event.toolCallId, { content: event.content });
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
return responses;
|
|
1028
|
+
}
|
|
1029
|
+
function collectToolResponsesFromTurnInput(input) {
|
|
1030
|
+
const responses = /* @__PURE__ */ new Map();
|
|
1031
|
+
for (const event of extractToolResponsesFromTurnInput(input)) {
|
|
1032
|
+
responses.set(event.toolCallId, { content: event.content });
|
|
1033
|
+
}
|
|
1034
|
+
return responses;
|
|
1035
|
+
}
|
|
1036
|
+
function applyStagedResponsesToContent(content, responses) {
|
|
1037
|
+
const staged = new Map(
|
|
1038
|
+
[...responses.entries()].map(([toolCallId, value]) => [
|
|
1039
|
+
toolCallId,
|
|
1040
|
+
value.content
|
|
1041
|
+
])
|
|
1042
|
+
);
|
|
1043
|
+
return applyStagedResponsesToContentMap(content, staged);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// src/collectPending.ts
|
|
1047
|
+
function walkToolCallParts(content, visit, threadId) {
|
|
1048
|
+
for (const part of content) {
|
|
1049
|
+
if (part.type !== "tool-call") {
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
visit(part, threadId);
|
|
1053
|
+
if (part.messages == null) {
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
1056
|
+
for (const message of part.messages) {
|
|
1057
|
+
if (message.role !== "assistant") {
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1060
|
+
const nestedThreadId = getToolApprovalThreadId(message) ?? getToolResponseThreadId(message) ?? threadId;
|
|
1061
|
+
walkToolCallParts(message.content, visit, nestedThreadId);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
function collectPendingApprovals(messages) {
|
|
1066
|
+
const pending = [];
|
|
1067
|
+
for (const message of messages) {
|
|
1068
|
+
if (message.role !== "assistant") {
|
|
1069
|
+
continue;
|
|
1070
|
+
}
|
|
1071
|
+
const rootThreadId = getToolApprovalThreadId(message) ?? ROOT_THREAD_ID;
|
|
1072
|
+
walkToolCallParts(message.content, (part, threadId) => {
|
|
1073
|
+
if (!hasPendingToolApproval(part.approval)) {
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
pending.push({
|
|
1077
|
+
approvalId: part.approval.id,
|
|
1078
|
+
threadId,
|
|
1079
|
+
toolName: part.toolName,
|
|
1080
|
+
args: { ...part.args },
|
|
1081
|
+
argsText: part.argsText
|
|
1082
|
+
});
|
|
1083
|
+
}, rootThreadId);
|
|
1084
|
+
}
|
|
1085
|
+
return pending;
|
|
1086
|
+
}
|
|
1087
|
+
function collectPendingToolResponses(messages) {
|
|
1088
|
+
const pending = [];
|
|
1089
|
+
for (const message of messages) {
|
|
1090
|
+
if (message.role !== "assistant") {
|
|
1091
|
+
continue;
|
|
1092
|
+
}
|
|
1093
|
+
const rootThreadId = getToolResponseThreadId(message) ?? ROOT_THREAD_ID;
|
|
1094
|
+
walkToolCallParts(message.content, (part, threadId) => {
|
|
1095
|
+
if (!hasPendingToolResponse(part)) {
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
const payload = part.interrupt?.payload;
|
|
1099
|
+
pending.push({
|
|
1100
|
+
toolCallId: part.toolCallId,
|
|
1101
|
+
threadId,
|
|
1102
|
+
toolName: part.toolName,
|
|
1103
|
+
args: { ...part.args },
|
|
1104
|
+
argsText: part.argsText,
|
|
1105
|
+
...payload?.question != null ? { question: payload.question } : {},
|
|
1106
|
+
...payload?.options != null ? { options: payload.options } : {}
|
|
1107
|
+
});
|
|
1108
|
+
}, rootThreadId);
|
|
1109
|
+
}
|
|
1110
|
+
return pending;
|
|
1111
|
+
}
|
|
1112
|
+
function derivePendingMcpAuth(messages) {
|
|
1113
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1114
|
+
const message = messages[i];
|
|
1115
|
+
if (message?.role !== "assistant") {
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
if (message.status?.type !== "requires-action") {
|
|
1119
|
+
continue;
|
|
1120
|
+
}
|
|
1121
|
+
const custom = message.metadata.custom;
|
|
1122
|
+
if (custom.pendingMcpAuth !== true) {
|
|
1123
|
+
continue;
|
|
1124
|
+
}
|
|
1125
|
+
const servers = custom.mcpServers;
|
|
1126
|
+
if (!Array.isArray(servers)) {
|
|
1127
|
+
return { mcpServers: [] };
|
|
1128
|
+
}
|
|
1129
|
+
return { mcpServers: servers };
|
|
1130
|
+
}
|
|
1131
|
+
return null;
|
|
1132
|
+
}
|
|
1133
|
+
function deriveSandboxId(messages) {
|
|
1134
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1135
|
+
const message = messages[i];
|
|
1136
|
+
if (message?.role !== "assistant") {
|
|
1137
|
+
continue;
|
|
1138
|
+
}
|
|
1139
|
+
const custom = message.metadata.custom;
|
|
1140
|
+
if (typeof custom.sandboxId === "string") {
|
|
1141
|
+
return custom.sandboxId;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
return void 0;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// src/mcpAuth.ts
|
|
1148
|
+
var MCP_AUTH_RESUME_RUN_CUSTOM_KEY = "resumeMcpAuth";
|
|
1149
|
+
function buildMcpAuthTextParts(servers) {
|
|
1150
|
+
const linkLines = servers.map(
|
|
1151
|
+
(server) => `- [Authorize ${server.name}](${server.authUrl})`
|
|
1152
|
+
);
|
|
1153
|
+
const text = [
|
|
1154
|
+
"This agent needs access to external services before it can continue.",
|
|
1155
|
+
"",
|
|
1156
|
+
...linkLines,
|
|
1157
|
+
"",
|
|
1158
|
+
"Open each link to sign in, then press **Continue** below."
|
|
1159
|
+
].join("\n");
|
|
1160
|
+
return [{ type: "text", text }];
|
|
1161
|
+
}
|
|
1162
|
+
function findMcpAuthRequired(requiredActions) {
|
|
1163
|
+
return requiredActions?.find(
|
|
1164
|
+
(action) => action.type === "mcp.auth_required"
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
function mcpAuthAssistantStatus() {
|
|
1168
|
+
return { type: "requires-action", reason: "interrupt" };
|
|
1169
|
+
}
|
|
1170
|
+
function mcpAuthMessageCustom(servers) {
|
|
1171
|
+
return { pendingMcpAuth: true, mcpServers: [...servers] };
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// src/turnEventHelpers.ts
|
|
1175
|
+
function buildToolApprovalUpdate(content, turn) {
|
|
1176
|
+
const pendingApproval = findApprovalRequiredInTurn(turn);
|
|
1177
|
+
if (pendingApproval == null) {
|
|
1178
|
+
return { content };
|
|
1179
|
+
}
|
|
1180
|
+
return {
|
|
1181
|
+
content,
|
|
1182
|
+
status: toolApprovalStatus(),
|
|
1183
|
+
metadata: { custom: toolApprovalMessageCustom(pendingApproval.threadId) }
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
function buildToolResponseUpdate(update, turn) {
|
|
1187
|
+
const pendingResponse = findResponseRequiredInTurn(turn);
|
|
1188
|
+
if (pendingResponse == null) {
|
|
1189
|
+
return update;
|
|
1190
|
+
}
|
|
1191
|
+
return {
|
|
1192
|
+
...update,
|
|
1193
|
+
content: update.content,
|
|
1194
|
+
status: toolResponseStatus(),
|
|
1195
|
+
metadata: {
|
|
1196
|
+
custom: {
|
|
1197
|
+
...update.metadata?.custom,
|
|
1198
|
+
...toolResponseMessageCustom(pendingResponse.threadId)
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
function appendToolResponseToTurnContent(update, turn) {
|
|
1204
|
+
if (update.status?.type === "requires-action") {
|
|
1205
|
+
return update;
|
|
1206
|
+
}
|
|
1207
|
+
return buildToolResponseUpdate(update, turn);
|
|
1208
|
+
}
|
|
1209
|
+
function appendToolApprovalToTurnContent(update, turn) {
|
|
1210
|
+
if (update.status?.type === "requires-action") {
|
|
1211
|
+
return update;
|
|
1212
|
+
}
|
|
1213
|
+
const approvalUpdate = buildToolApprovalUpdate(update.content, turn);
|
|
1214
|
+
return appendToolResponseToTurnContent(approvalUpdate, turn);
|
|
1215
|
+
}
|
|
1216
|
+
function appendMcpAuthToTurnContent(content, turn) {
|
|
1217
|
+
const pendingMcpAuth = findMcpAuthRequired(
|
|
1218
|
+
turn.state.status === "done" ? turn.state.requiredActions : void 0
|
|
1219
|
+
);
|
|
1220
|
+
if (pendingMcpAuth == null) {
|
|
1221
|
+
return appendToolApprovalToTurnContent({ content }, turn);
|
|
1222
|
+
}
|
|
1223
|
+
return appendToolApprovalToTurnContent(
|
|
1224
|
+
{
|
|
1225
|
+
content: [...content, ...buildMcpAuthTextParts(pendingMcpAuth.mcpServers)],
|
|
1226
|
+
status: mcpAuthAssistantStatus(),
|
|
1227
|
+
metadata: { custom: mcpAuthMessageCustom(pendingMcpAuth.mcpServers) }
|
|
1228
|
+
},
|
|
1229
|
+
turn
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// src/extractTurnUserText.ts
|
|
1234
|
+
function extractTurnUserText(input) {
|
|
1235
|
+
const parts = [];
|
|
1236
|
+
for (const item of input ?? []) {
|
|
1237
|
+
if (item.type !== "user.message") {
|
|
1238
|
+
continue;
|
|
1239
|
+
}
|
|
1240
|
+
const { content } = item;
|
|
1241
|
+
if (typeof content === "string") {
|
|
1242
|
+
parts.push(content);
|
|
1243
|
+
continue;
|
|
1244
|
+
}
|
|
1245
|
+
for (const part of content) {
|
|
1246
|
+
if (part.type === "text") {
|
|
1247
|
+
parts.push(part.text);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
return parts.join("\n").trim();
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// src/sessionSnapshot.ts
|
|
1255
|
+
function emptyRequiredActionsOverlay() {
|
|
1256
|
+
return {
|
|
1257
|
+
approvals: /* @__PURE__ */ new Map(),
|
|
1258
|
+
toolResponses: /* @__PURE__ */ new Map()
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
function createEmptySessionSnapshot() {
|
|
1262
|
+
return {
|
|
1263
|
+
fold: new PeerThreadFoldState(),
|
|
1264
|
+
turns: [],
|
|
1265
|
+
requiredActions: emptyRequiredActionsOverlay()
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
function turnToSessionRecord(turn) {
|
|
1269
|
+
const userText = extractTurnUserText(turn.input);
|
|
1270
|
+
return {
|
|
1271
|
+
id: turn.id,
|
|
1272
|
+
...userText ? { userText } : {},
|
|
1273
|
+
createdAt: turn.createdAt,
|
|
1274
|
+
state: turn.state,
|
|
1275
|
+
input: turn.input
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
function replaceSessionSnapshot(snapshot, patch) {
|
|
1279
|
+
return {
|
|
1280
|
+
...snapshot,
|
|
1281
|
+
...patch,
|
|
1282
|
+
...patch.requiredActions != null ? { requiredActions: patch.requiredActions } : {}
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// src/convertTurnMessages.ts
|
|
1287
|
+
var TURN_EVENTS_PAGE_SIZE = 25;
|
|
1288
|
+
function assistantStatusFromTurnState(state) {
|
|
1289
|
+
switch (state.status) {
|
|
1290
|
+
case "done":
|
|
1291
|
+
return { type: "complete", reason: "stop" };
|
|
1292
|
+
case "error":
|
|
1293
|
+
return { type: "incomplete", reason: "error", error: state.message };
|
|
1294
|
+
case "cancelled":
|
|
1295
|
+
return { type: "incomplete", reason: "cancelled" };
|
|
1296
|
+
case "running":
|
|
1297
|
+
return { type: "running" };
|
|
1298
|
+
default:
|
|
1299
|
+
return { type: "complete", reason: "unknown" };
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
function resolveCreatedAt(messageId, fallback, options) {
|
|
1303
|
+
return options?.getCreatedAt?.(messageId, fallback) ?? fallback;
|
|
1304
|
+
}
|
|
1305
|
+
function parseDataUriMime2(data) {
|
|
1306
|
+
if (!data.startsWith("data:")) {
|
|
1307
|
+
return "application/octet-stream";
|
|
1308
|
+
}
|
|
1309
|
+
const match = /^data:([^;,]+)/.exec(data);
|
|
1310
|
+
return match?.[1] ?? "application/octet-stream";
|
|
1311
|
+
}
|
|
1312
|
+
function fileContentToAttachment(file, attachmentId) {
|
|
1313
|
+
const mimeType = parseDataUriMime2(file.data);
|
|
1314
|
+
if (mimeType.startsWith("image/")) {
|
|
1315
|
+
return {
|
|
1316
|
+
id: attachmentId,
|
|
1317
|
+
type: "image",
|
|
1318
|
+
name: file.name,
|
|
1319
|
+
contentType: mimeType,
|
|
1320
|
+
status: { type: "complete" },
|
|
1321
|
+
content: [{ type: "image", image: file.data, filename: file.name }]
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
return {
|
|
1325
|
+
id: attachmentId,
|
|
1326
|
+
type: "file",
|
|
1327
|
+
name: file.name,
|
|
1328
|
+
contentType: mimeType,
|
|
1329
|
+
status: { type: "complete" },
|
|
1330
|
+
content: [
|
|
1331
|
+
{
|
|
1332
|
+
type: "file",
|
|
1333
|
+
mimeType,
|
|
1334
|
+
filename: file.name,
|
|
1335
|
+
data: file.data
|
|
1336
|
+
}
|
|
1337
|
+
]
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
function buildUserMessageFromTurnInput(turnId, input, createdAt, options) {
|
|
1341
|
+
const fallback = createdAt instanceof Date ? createdAt : new Date(createdAt);
|
|
1342
|
+
const id = `${turnId}-user`;
|
|
1343
|
+
const content = [];
|
|
1344
|
+
const attachments = [];
|
|
1345
|
+
for (const item of input ?? []) {
|
|
1346
|
+
if (item.type !== "user.message") {
|
|
1347
|
+
continue;
|
|
1348
|
+
}
|
|
1349
|
+
const messageContent = item.content;
|
|
1350
|
+
if (typeof messageContent === "string") {
|
|
1351
|
+
content.push({ type: "text", text: messageContent });
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
for (const part of messageContent) {
|
|
1355
|
+
if (part.type === "text") {
|
|
1356
|
+
content.push({ type: "text", text: part.text });
|
|
1357
|
+
} else if (part.type === "file") {
|
|
1358
|
+
attachments.push(
|
|
1359
|
+
fileContentToAttachment(
|
|
1360
|
+
part,
|
|
1361
|
+
`${turnId}-file-${attachments.length}`
|
|
1362
|
+
)
|
|
1363
|
+
);
|
|
1364
|
+
} else {
|
|
1365
|
+
const imageUrl = extractImageUrlFromUserContentItem(part);
|
|
1366
|
+
if (imageUrl != null) {
|
|
1367
|
+
attachments.push(
|
|
1368
|
+
imageUrlToAttachment(
|
|
1369
|
+
imageUrl,
|
|
1370
|
+
`${turnId}-file-${attachments.length}`
|
|
1371
|
+
)
|
|
1372
|
+
);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return {
|
|
1378
|
+
id,
|
|
1379
|
+
role: "user",
|
|
1380
|
+
content: content.length > 0 ? content : [{ type: "text", text: "" }],
|
|
1381
|
+
attachments,
|
|
1382
|
+
createdAt: resolveCreatedAt(id, fallback, options),
|
|
1383
|
+
metadata: { custom: {} }
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
function buildAssistantMessage(turnId, content, createdAt, status, custom = {}, options) {
|
|
1387
|
+
const fallback = createdAt instanceof Date ? createdAt : new Date(createdAt);
|
|
1388
|
+
const id = `${turnId}-assistant`;
|
|
1389
|
+
return {
|
|
1390
|
+
id,
|
|
1391
|
+
role: "assistant",
|
|
1392
|
+
content,
|
|
1393
|
+
status,
|
|
1394
|
+
createdAt: resolveCreatedAt(id, fallback, options),
|
|
1395
|
+
metadata: {
|
|
1396
|
+
unstable_state: null,
|
|
1397
|
+
unstable_annotations: [],
|
|
1398
|
+
unstable_data: [],
|
|
1399
|
+
steps: [],
|
|
1400
|
+
custom
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
async function ingestTurnEventsIntoFold(foldState, turn) {
|
|
1405
|
+
for await (const event of await turn.listEvents({
|
|
1406
|
+
order: "asc",
|
|
1407
|
+
limit: TURN_EVENTS_PAGE_SIZE
|
|
1408
|
+
})) {
|
|
1409
|
+
ingestTurnEvent(foldState, event);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
async function fetchTurnEvents(turn) {
|
|
1413
|
+
const events = [];
|
|
1414
|
+
for await (const event of await turn.listEvents({
|
|
1415
|
+
order: "asc",
|
|
1416
|
+
limit: TURN_EVENTS_PAGE_SIZE
|
|
1417
|
+
})) {
|
|
1418
|
+
events.push(event);
|
|
1419
|
+
}
|
|
1420
|
+
return events;
|
|
1421
|
+
}
|
|
1422
|
+
function ingestCollectedEventsIntoFold(foldState, events) {
|
|
1423
|
+
for (const event of events) {
|
|
1424
|
+
ingestTurnEvent(foldState, event);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
async function fetchAllTurnEventsWithConcurrency(turns, concurrency) {
|
|
1428
|
+
const results = new Array(turns.length);
|
|
1429
|
+
const pool = /* @__PURE__ */ new Set();
|
|
1430
|
+
for (let i = 0; i < turns.length; i++) {
|
|
1431
|
+
const idx = i;
|
|
1432
|
+
const turn = turns[idx];
|
|
1433
|
+
const p = fetchTurnEvents(turn).then((events) => {
|
|
1434
|
+
results[idx] = events;
|
|
1435
|
+
pool.delete(p);
|
|
1436
|
+
});
|
|
1437
|
+
pool.add(p);
|
|
1438
|
+
if (pool.size >= concurrency) await Promise.race(pool);
|
|
1439
|
+
}
|
|
1440
|
+
await Promise.all(pool);
|
|
1441
|
+
return results;
|
|
1442
|
+
}
|
|
1443
|
+
function rootModelMessageIdsSinceBaseline(foldState, baseline) {
|
|
1444
|
+
const bucket = foldState.threads.get(ROOT_THREAD_ID);
|
|
1445
|
+
if (bucket == null) {
|
|
1446
|
+
return [];
|
|
1447
|
+
}
|
|
1448
|
+
if (baseline.length === 0) {
|
|
1449
|
+
return [...bucket.modelMessageIds];
|
|
1450
|
+
}
|
|
1451
|
+
const baselineSet = new Set(baseline);
|
|
1452
|
+
return bucket.modelMessageIds.filter((id) => !baselineSet.has(id));
|
|
1453
|
+
}
|
|
1454
|
+
function computeGroupRootBaseline(turns) {
|
|
1455
|
+
let groupStartIndex = turns.length - 1;
|
|
1456
|
+
while (groupStartIndex >= 0 && turns[groupStartIndex]?.userText == null) {
|
|
1457
|
+
groupStartIndex--;
|
|
1458
|
+
}
|
|
1459
|
+
const baseline = [];
|
|
1460
|
+
for (let i = 0; i < groupStartIndex; i++) {
|
|
1461
|
+
baseline.push(...turns[i]?.rootModelMessageIds ?? []);
|
|
1462
|
+
}
|
|
1463
|
+
return baseline;
|
|
1464
|
+
}
|
|
1465
|
+
function buildTurnUpdateFromFold(foldState, turn, rootModelMessageIds) {
|
|
1466
|
+
const content = buildRootAssistantContentForIds(foldState, rootModelMessageIds);
|
|
1467
|
+
let update = { content };
|
|
1468
|
+
update = appendMcpAuthToTurnContent(update.content, turn);
|
|
1469
|
+
update = appendToolApprovalToTurnContent(update, turn);
|
|
1470
|
+
return update;
|
|
1471
|
+
}
|
|
1472
|
+
function contentHasPendingRequiredActions(content) {
|
|
1473
|
+
const message = {
|
|
1474
|
+
id: "pending-check",
|
|
1475
|
+
role: "assistant",
|
|
1476
|
+
content,
|
|
1477
|
+
status: { type: "complete", reason: "stop" },
|
|
1478
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1479
|
+
metadata: {
|
|
1480
|
+
unstable_state: null,
|
|
1481
|
+
unstable_annotations: [],
|
|
1482
|
+
unstable_data: [],
|
|
1483
|
+
steps: [],
|
|
1484
|
+
custom: {}
|
|
1485
|
+
}
|
|
1486
|
+
};
|
|
1487
|
+
return messageHasPendingApprovals(message) || messageHasPendingResponses(message);
|
|
1488
|
+
}
|
|
1489
|
+
function resolveProjectedRequiredActionState(turnUpdate, content, record) {
|
|
1490
|
+
let status = turnUpdate.status ?? assistantStatusFromTurnState(record.state);
|
|
1491
|
+
let custom = { ...turnUpdate.metadata?.custom ?? {} };
|
|
1492
|
+
if (status.type === "requires-action" && status.reason === "tool-calls" && !contentHasPendingRequiredActions(content)) {
|
|
1493
|
+
status = assistantStatusFromTurnState(record.state);
|
|
1494
|
+
const {
|
|
1495
|
+
[TOOL_APPROVAL_THREAD_ID_CUSTOM_KEY]: _approvalThreadId,
|
|
1496
|
+
[TOOL_RESPONSE_THREAD_ID_CUSTOM_KEY]: _responseThreadId,
|
|
1497
|
+
...restCustom
|
|
1498
|
+
} = custom;
|
|
1499
|
+
custom = restCustom;
|
|
1500
|
+
}
|
|
1501
|
+
return { status, custom };
|
|
1502
|
+
}
|
|
1503
|
+
function projectActiveStreamUpdate(snapshot) {
|
|
1504
|
+
const activeStream = snapshot.activeStream;
|
|
1505
|
+
if (activeStream == null) {
|
|
1506
|
+
throw new Error("projectActiveStreamUpdate requires an active stream");
|
|
1507
|
+
}
|
|
1508
|
+
const hasStagedOverlay = snapshot.requiredActions.approvals.size > 0 || snapshot.requiredActions.toolResponses.size > 0;
|
|
1509
|
+
if (hasStagedOverlay) {
|
|
1510
|
+
return activeStream.update;
|
|
1511
|
+
}
|
|
1512
|
+
const baseline = snapshot.groupRootBaseline ?? computeGroupRootBaseline(snapshot.turns);
|
|
1513
|
+
const rootModelMessageIds = rootModelMessageIdsSinceBaseline(
|
|
1514
|
+
snapshot.fold,
|
|
1515
|
+
baseline
|
|
1516
|
+
);
|
|
1517
|
+
const foldContent = buildRootAssistantContentForIds(
|
|
1518
|
+
snapshot.fold,
|
|
1519
|
+
rootModelMessageIds
|
|
1520
|
+
);
|
|
1521
|
+
const content = foldContent.length > 0 ? foldContent : activeStream.update.content;
|
|
1522
|
+
const turnRecord = snapshot.turns.find((turn) => turn.id === activeStream.turnId);
|
|
1523
|
+
const turnLike = turnRecord ?? snapshot.runningTurn;
|
|
1524
|
+
const rebuilt = turnLike != null ? buildTurnUpdateFromFold(snapshot.fold, turnLike, rootModelMessageIds) : { content };
|
|
1525
|
+
return {
|
|
1526
|
+
...activeStream.update,
|
|
1527
|
+
content,
|
|
1528
|
+
metadata: rebuilt.metadata ?? activeStream.update.metadata,
|
|
1529
|
+
status: rebuilt.status ?? activeStream.update.status
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
function applyRequiredActionsOverlayToMessages(messages, overlay) {
|
|
1533
|
+
if (overlay.approvals.size === 0 && overlay.toolResponses.size === 0) {
|
|
1534
|
+
return messages;
|
|
1535
|
+
}
|
|
1536
|
+
return messages.map((message) => {
|
|
1537
|
+
if (message.role !== "assistant") {
|
|
1538
|
+
return message;
|
|
1539
|
+
}
|
|
1540
|
+
let { content } = message;
|
|
1541
|
+
if (overlay.approvals.size > 0) {
|
|
1542
|
+
content = applyApprovalDecisionsToContent(content, overlay.approvals);
|
|
1543
|
+
}
|
|
1544
|
+
if (overlay.toolResponses.size > 0) {
|
|
1545
|
+
content = applyStagedResponsesToContent(content, overlay.toolResponses);
|
|
1546
|
+
}
|
|
1547
|
+
if (content === message.content) {
|
|
1548
|
+
return message;
|
|
1549
|
+
}
|
|
1550
|
+
return { ...message, content: [...content] };
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
function projectHistoryTurns(snapshot, options) {
|
|
1554
|
+
const messages = [];
|
|
1555
|
+
let lastAssistantIndex;
|
|
1556
|
+
let groupRootIds = [];
|
|
1557
|
+
for (let turnIndex = 0; turnIndex < snapshot.turns.length; turnIndex++) {
|
|
1558
|
+
const record = snapshot.turns[turnIndex];
|
|
1559
|
+
const turnRootIds = record.rootModelMessageIds ?? [];
|
|
1560
|
+
if (record.userText) {
|
|
1561
|
+
groupRootIds = [...turnRootIds];
|
|
1562
|
+
} else {
|
|
1563
|
+
groupRootIds = [...groupRootIds, ...turnRootIds];
|
|
1564
|
+
}
|
|
1565
|
+
const turnUpdate = buildTurnUpdateFromFold(snapshot.fold, record, groupRootIds);
|
|
1566
|
+
let content = turnUpdate.content;
|
|
1567
|
+
const subsequentDecisions = collectSubsequentApprovalDecisions(
|
|
1568
|
+
snapshot.turns,
|
|
1569
|
+
turnIndex
|
|
1570
|
+
);
|
|
1571
|
+
if (subsequentDecisions.size > 0) {
|
|
1572
|
+
content = applyApprovalDecisionsToContent(content, subsequentDecisions);
|
|
1573
|
+
}
|
|
1574
|
+
const subsequentResponses = collectSubsequentToolResponses(
|
|
1575
|
+
snapshot.turns,
|
|
1576
|
+
turnIndex
|
|
1577
|
+
);
|
|
1578
|
+
if (subsequentResponses.size > 0) {
|
|
1579
|
+
content = applyStagedResponsesToContent(content, subsequentResponses);
|
|
1580
|
+
}
|
|
1581
|
+
const currentResponses = collectToolResponsesFromTurnInput(record.input);
|
|
1582
|
+
if (currentResponses.size > 0) {
|
|
1583
|
+
content = applyStagedResponsesToContent(content, currentResponses);
|
|
1584
|
+
}
|
|
1585
|
+
const currentDecisions = collectApprovalDecisionsFromTurnInput(record.input);
|
|
1586
|
+
if (currentDecisions.size > 0) {
|
|
1587
|
+
content = applyApprovalDecisionsToContent(content, currentDecisions);
|
|
1588
|
+
}
|
|
1589
|
+
const { status, custom: baseCustom } = resolveProjectedRequiredActionState(
|
|
1590
|
+
turnUpdate,
|
|
1591
|
+
content,
|
|
1592
|
+
record
|
|
1593
|
+
);
|
|
1594
|
+
const custom = record.sandboxId != null ? { ...baseCustom, sandboxId: record.sandboxId } : baseCustom;
|
|
1595
|
+
if (record.userText) {
|
|
1596
|
+
messages.push(
|
|
1597
|
+
buildUserMessageFromTurnInput(
|
|
1598
|
+
record.id,
|
|
1599
|
+
record.input,
|
|
1600
|
+
record.createdAt,
|
|
1601
|
+
options
|
|
1602
|
+
)
|
|
1603
|
+
);
|
|
1604
|
+
if (record.state.status === "running") {
|
|
1605
|
+
if (content.length > 0) {
|
|
1606
|
+
messages.push(
|
|
1607
|
+
buildAssistantMessage(
|
|
1608
|
+
record.id,
|
|
1609
|
+
content,
|
|
1610
|
+
record.createdAt,
|
|
1611
|
+
status,
|
|
1612
|
+
custom,
|
|
1613
|
+
options
|
|
1614
|
+
)
|
|
1615
|
+
);
|
|
1616
|
+
lastAssistantIndex = messages.length - 1;
|
|
1617
|
+
}
|
|
1618
|
+
break;
|
|
1619
|
+
}
|
|
1620
|
+
if (content.length > 0) {
|
|
1621
|
+
messages.push(
|
|
1622
|
+
buildAssistantMessage(
|
|
1623
|
+
record.id,
|
|
1624
|
+
content,
|
|
1625
|
+
record.createdAt,
|
|
1626
|
+
status,
|
|
1627
|
+
custom,
|
|
1628
|
+
options
|
|
1629
|
+
)
|
|
1630
|
+
);
|
|
1631
|
+
lastAssistantIndex = messages.length - 1;
|
|
1632
|
+
}
|
|
1633
|
+
} else if (content.length > 0 && lastAssistantIndex != null) {
|
|
1634
|
+
if (record.state.status === "running") {
|
|
1635
|
+
break;
|
|
1636
|
+
}
|
|
1637
|
+
const existing = messages[lastAssistantIndex];
|
|
1638
|
+
messages[lastAssistantIndex] = {
|
|
1639
|
+
...existing,
|
|
1640
|
+
content,
|
|
1641
|
+
status,
|
|
1642
|
+
metadata: {
|
|
1643
|
+
...existing.metadata,
|
|
1644
|
+
custom
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1647
|
+
} else if (record.state.status === "running") {
|
|
1648
|
+
break;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
return messages;
|
|
1652
|
+
}
|
|
1653
|
+
function projectSessionMessages(snapshot, options) {
|
|
1654
|
+
let messages = projectHistoryTurns(snapshot, options);
|
|
1655
|
+
if (snapshot.pendingUser != null) {
|
|
1656
|
+
messages.push(
|
|
1657
|
+
buildUserMessageFromTurnInput(
|
|
1658
|
+
snapshot.pendingUser.turnId,
|
|
1659
|
+
[{ type: "user.message", content: snapshot.pendingUser.content }],
|
|
1660
|
+
snapshot.pendingUser.createdAt,
|
|
1661
|
+
options
|
|
1662
|
+
)
|
|
1663
|
+
);
|
|
1664
|
+
}
|
|
1665
|
+
if (snapshot.activeStream != null) {
|
|
1666
|
+
const { turnId, update, isContinuation, streamComplete } = snapshot.activeStream;
|
|
1667
|
+
const resolvedUpdate = streamComplete === true ? projectActiveStreamUpdate(snapshot) : update;
|
|
1668
|
+
const last = messages.at(-1);
|
|
1669
|
+
const existingAssistant = isContinuation && last?.role === "assistant" ? last : void 0;
|
|
1670
|
+
let assistantMessage = turnStreamUpdateToAssistantMessage(
|
|
1671
|
+
turnId,
|
|
1672
|
+
resolvedUpdate,
|
|
1673
|
+
existingAssistant,
|
|
1674
|
+
options
|
|
1675
|
+
);
|
|
1676
|
+
if (streamComplete === true && resolvedUpdate.status == null) {
|
|
1677
|
+
assistantMessage = {
|
|
1678
|
+
...assistantMessage,
|
|
1679
|
+
status: { type: "complete", reason: "stop" }
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
if (isContinuation && last?.role === "assistant") {
|
|
1683
|
+
messages = [...messages.slice(0, -1), assistantMessage];
|
|
1684
|
+
} else {
|
|
1685
|
+
messages = [...messages, assistantMessage];
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
return applyRequiredActionsOverlayToMessages(
|
|
1689
|
+
messages,
|
|
1690
|
+
snapshot.requiredActions
|
|
1691
|
+
);
|
|
1692
|
+
}
|
|
1693
|
+
var DEFAULT_LIST_EVENTS_CONCURRENCY = 5;
|
|
1694
|
+
function ingestTurnsIntoSnapshot(snapshot, turns, eventArrays) {
|
|
1695
|
+
let runningTurn;
|
|
1696
|
+
for (let i = 0; i < turns.length; i++) {
|
|
1697
|
+
const turn = turns[i];
|
|
1698
|
+
const rootBucket = snapshot.fold.threads.get(ROOT_THREAD_ID);
|
|
1699
|
+
const beforeCount = rootBucket?.modelMessageIds.length ?? 0;
|
|
1700
|
+
ingestCollectedEventsIntoFold(snapshot.fold, eventArrays[i] ?? []);
|
|
1701
|
+
applyUserToolResponsesToFold(snapshot.fold, turn.input ?? []);
|
|
1702
|
+
const afterBucket = snapshot.fold.threads.get(ROOT_THREAD_ID);
|
|
1703
|
+
const rootModelMessageIds = (afterBucket?.modelMessageIds ?? []).slice(
|
|
1704
|
+
beforeCount
|
|
1705
|
+
);
|
|
1706
|
+
const sandboxEvent = (eventArrays[i] ?? []).find(
|
|
1707
|
+
(event) => event.type === "sandbox.created"
|
|
1708
|
+
);
|
|
1709
|
+
snapshot.turns.push({
|
|
1710
|
+
...turnToSessionRecord(turn),
|
|
1711
|
+
rootModelMessageIds,
|
|
1712
|
+
...sandboxEvent != null ? { sandboxId: sandboxEvent.sandboxId } : {}
|
|
1713
|
+
});
|
|
1714
|
+
if (turn.state.status === "running") {
|
|
1715
|
+
runningTurn = turn;
|
|
1716
|
+
break;
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
return runningTurn;
|
|
1720
|
+
}
|
|
1721
|
+
async function buildSnapshotFromSession(session, concurrency = DEFAULT_LIST_EVENTS_CONCURRENCY) {
|
|
1722
|
+
const turns = [];
|
|
1723
|
+
for await (const turn of await session.listTurns()) {
|
|
1724
|
+
turns.push(turn);
|
|
1725
|
+
}
|
|
1726
|
+
turns.reverse();
|
|
1727
|
+
const eventArrays = await fetchAllTurnEventsWithConcurrency(turns, concurrency);
|
|
1728
|
+
const snapshot = createEmptySessionSnapshot();
|
|
1729
|
+
const runningTurn = ingestTurnsIntoSnapshot(snapshot, turns, eventArrays);
|
|
1730
|
+
return replaceSessionSnapshot(snapshot, {
|
|
1731
|
+
...runningTurn != null ? {
|
|
1732
|
+
runningTurn,
|
|
1733
|
+
unstable_resume: true,
|
|
1734
|
+
groupRootBaseline: computeGroupRootBaseline(snapshot.turns)
|
|
1735
|
+
} : {}
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
async function buildSnapshotBeforeTurnIndex(session, turnIndex, concurrency = DEFAULT_LIST_EVENTS_CONCURRENCY, orderedTurns) {
|
|
1739
|
+
if (turnIndex <= 0) {
|
|
1740
|
+
return createEmptySessionSnapshot();
|
|
1741
|
+
}
|
|
1742
|
+
const turns = orderedTurns ?? await listSessionTurnsOrdered(session);
|
|
1743
|
+
const turnsToInclude = turns.slice(0, turnIndex);
|
|
1744
|
+
if (turnsToInclude.length === 0) {
|
|
1745
|
+
return createEmptySessionSnapshot();
|
|
1746
|
+
}
|
|
1747
|
+
const eventArrays = await fetchAllTurnEventsWithConcurrency(
|
|
1748
|
+
turnsToInclude,
|
|
1749
|
+
concurrency
|
|
1750
|
+
);
|
|
1751
|
+
const snapshot = createEmptySessionSnapshot();
|
|
1752
|
+
ingestTurnsIntoSnapshot(snapshot, turnsToInclude, eventArrays);
|
|
1753
|
+
return snapshot;
|
|
1754
|
+
}
|
|
1755
|
+
async function resolveGatewayBranchPreviousTurnId(session, turnIndex, orderedTurns) {
|
|
1756
|
+
if (turnIndex <= 0) {
|
|
1757
|
+
return null;
|
|
1758
|
+
}
|
|
1759
|
+
const turns = orderedTurns ?? await listSessionTurnsOrdered(session);
|
|
1760
|
+
return turns[turnIndex - 1]?.id ?? null;
|
|
1761
|
+
}
|
|
1762
|
+
async function listSessionTurnsOrdered(session) {
|
|
1763
|
+
const turns = [];
|
|
1764
|
+
for await (const turn of await session.listTurns()) {
|
|
1765
|
+
turns.push(turn);
|
|
1766
|
+
}
|
|
1767
|
+
turns.reverse();
|
|
1768
|
+
return turns;
|
|
1769
|
+
}
|
|
1770
|
+
async function buildTurnAssistantContent(turn, foldState) {
|
|
1771
|
+
const state = foldState ?? new PeerThreadFoldState();
|
|
1772
|
+
const beforeCount = state.threads.get(ROOT_THREAD_ID)?.modelMessageIds.length ?? 0;
|
|
1773
|
+
await ingestTurnEventsIntoFold(state, turn);
|
|
1774
|
+
const afterIds = state.threads.get(ROOT_THREAD_ID)?.modelMessageIds ?? [];
|
|
1775
|
+
const rootModelMessageIds = afterIds.slice(beforeCount);
|
|
1776
|
+
return buildTurnUpdateFromFold(state, turn, rootModelMessageIds).content;
|
|
1777
|
+
}
|
|
1778
|
+
async function convertTurnsToThreadMessages(session) {
|
|
1779
|
+
const snapshot = await buildSnapshotFromSession(session);
|
|
1780
|
+
const messages = projectSessionMessages(snapshot);
|
|
1781
|
+
return {
|
|
1782
|
+
messages,
|
|
1783
|
+
foldState: snapshot.fold,
|
|
1784
|
+
...snapshot.runningTurn != null ? {
|
|
1785
|
+
runningTurn: snapshot.runningTurn,
|
|
1786
|
+
unstable_resume: true
|
|
1787
|
+
} : {}
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
function getTurnMessageContent(message) {
|
|
1791
|
+
const parts = [];
|
|
1792
|
+
for (const part of message.content) {
|
|
1793
|
+
if (part.type === "text") {
|
|
1794
|
+
parts.push(part.text);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
const text = parts.join("\n").trim();
|
|
1798
|
+
if (!text) {
|
|
1799
|
+
throw new Error("User message must contain text content.");
|
|
1800
|
+
}
|
|
1801
|
+
return text;
|
|
1802
|
+
}
|
|
1803
|
+
function toFileDataUri(data, mimeType) {
|
|
1804
|
+
if (data.startsWith("data:")) {
|
|
1805
|
+
return data;
|
|
1806
|
+
}
|
|
1807
|
+
return `data:${mimeType};base64,${data}`;
|
|
1808
|
+
}
|
|
1809
|
+
function toFileContent(name, data, mimeType) {
|
|
1810
|
+
return {
|
|
1811
|
+
type: "file",
|
|
1812
|
+
name,
|
|
1813
|
+
data: toFileDataUri(data, mimeType)
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
function buildUserMessageContent(message) {
|
|
1817
|
+
const contentParts = message.content;
|
|
1818
|
+
const inputParts = [
|
|
1819
|
+
...contentParts,
|
|
1820
|
+
...message.attachments?.flatMap(
|
|
1821
|
+
(attachment) => attachment.content.map((part) => ({
|
|
1822
|
+
...part,
|
|
1823
|
+
filename: attachment.name
|
|
1824
|
+
}))
|
|
1825
|
+
) ?? []
|
|
1826
|
+
];
|
|
1827
|
+
const items = [];
|
|
1828
|
+
for (const part of inputParts) {
|
|
1829
|
+
switch (part.type) {
|
|
1830
|
+
case "text":
|
|
1831
|
+
if (part.text.trim().length > 0) {
|
|
1832
|
+
const textPart = { type: "text", text: part.text };
|
|
1833
|
+
items.push(textPart);
|
|
1834
|
+
}
|
|
1835
|
+
break;
|
|
1836
|
+
case "image":
|
|
1837
|
+
items.push(
|
|
1838
|
+
toFileContent(part.filename ?? "image", part.image, "image/png")
|
|
1839
|
+
);
|
|
1840
|
+
break;
|
|
1841
|
+
case "file":
|
|
1842
|
+
items.push(
|
|
1843
|
+
toFileContent(
|
|
1844
|
+
part.filename ?? "file",
|
|
1845
|
+
part.data,
|
|
1846
|
+
part.mimeType
|
|
1847
|
+
)
|
|
1848
|
+
);
|
|
1849
|
+
break;
|
|
1850
|
+
default:
|
|
1851
|
+
break;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
const hasFile = items.some((item) => item.type === "file");
|
|
1855
|
+
if (!hasFile) {
|
|
1856
|
+
return getTurnMessageContent(message);
|
|
1857
|
+
}
|
|
1858
|
+
return items;
|
|
1859
|
+
}
|
|
1860
|
+
function userMessageContentToText(content) {
|
|
1861
|
+
if (typeof content === "string") {
|
|
1862
|
+
return content;
|
|
1863
|
+
}
|
|
1864
|
+
return content.filter(
|
|
1865
|
+
(item) => item.type === "text"
|
|
1866
|
+
).map((item) => item.text).join("\n").trim();
|
|
1867
|
+
}
|
|
1868
|
+
function parseTurnIdFromMessageId(messageId) {
|
|
1869
|
+
return messageId.replace(/-user$/, "");
|
|
1870
|
+
}
|
|
1871
|
+
function extractEditedText(message) {
|
|
1872
|
+
return getTurnMessageContent(message);
|
|
1873
|
+
}
|
|
1874
|
+
function extractTurnUserMessageContent(input) {
|
|
1875
|
+
for (const item of input ?? []) {
|
|
1876
|
+
if (item.type === "user.message") {
|
|
1877
|
+
return item.content;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
return "";
|
|
1881
|
+
}
|
|
1882
|
+
function buildEditedUserMessageContent(editedText, originalInput) {
|
|
1883
|
+
const fileParts = [];
|
|
1884
|
+
for (const item of originalInput ?? []) {
|
|
1885
|
+
if (item.type !== "user.message") {
|
|
1886
|
+
continue;
|
|
1887
|
+
}
|
|
1888
|
+
const content = item.content;
|
|
1889
|
+
if (typeof content === "string") {
|
|
1890
|
+
continue;
|
|
1891
|
+
}
|
|
1892
|
+
for (const part of content) {
|
|
1893
|
+
if (part.type === "file") {
|
|
1894
|
+
fileParts.push(part);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
if (fileParts.length === 0) {
|
|
1899
|
+
return editedText;
|
|
1900
|
+
}
|
|
1901
|
+
const items = [];
|
|
1902
|
+
if (editedText.trim().length > 0) {
|
|
1903
|
+
items.push({ type: "text", text: editedText });
|
|
1904
|
+
}
|
|
1905
|
+
items.push(...fileParts);
|
|
1906
|
+
return items;
|
|
1907
|
+
}
|
|
1908
|
+
function buildMcpAuthUpdate(pendingMcpAuth, foldState, groupRootBaseline) {
|
|
1909
|
+
const base = groupRootBaseline != null ? buildRootAssistantContentForIds(
|
|
1910
|
+
foldState,
|
|
1911
|
+
rootModelMessageIdsSinceBaseline(foldState, groupRootBaseline)
|
|
1912
|
+
) : buildRootAssistantContent(foldState);
|
|
1913
|
+
return {
|
|
1914
|
+
content: [...base, ...buildMcpAuthTextParts(pendingMcpAuth.mcpServers)],
|
|
1915
|
+
status: mcpAuthAssistantStatus(),
|
|
1916
|
+
metadata: { custom: mcpAuthMessageCustom(pendingMcpAuth.mcpServers) }
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
async function* streamTurnEvents(stream, foldState, groupRootBaseline) {
|
|
1920
|
+
let pendingMcpAuth;
|
|
1921
|
+
let sandboxId;
|
|
1922
|
+
let sandboxIdYielded = false;
|
|
1923
|
+
const withSandbox = (update) => {
|
|
1924
|
+
if (sandboxId == null) {
|
|
1925
|
+
return update;
|
|
1926
|
+
}
|
|
1927
|
+
sandboxIdYielded = true;
|
|
1928
|
+
return {
|
|
1929
|
+
...update,
|
|
1930
|
+
metadata: { ...update.metadata, custom: { ...update.metadata?.custom, sandboxId } }
|
|
1931
|
+
};
|
|
1932
|
+
};
|
|
1933
|
+
const yieldContent = () => {
|
|
1934
|
+
const ids = groupRootBaseline != null ? rootModelMessageIdsSinceBaseline(foldState, groupRootBaseline) : foldState.threads.get(ROOT_THREAD_ID)?.modelMessageIds ?? [];
|
|
1935
|
+
const content = buildRootAssistantContentForIds(foldState, ids);
|
|
1936
|
+
return content.length > 0 ? content : void 0;
|
|
1937
|
+
};
|
|
1938
|
+
for await (const data of stream) {
|
|
1939
|
+
const event = data.event;
|
|
1940
|
+
if (event.type === "sandbox.created") {
|
|
1941
|
+
sandboxId = event.sandboxId;
|
|
1942
|
+
continue;
|
|
1943
|
+
}
|
|
1944
|
+
if (event.type === "mcp.auth_required") {
|
|
1945
|
+
pendingMcpAuth = event;
|
|
1946
|
+
continue;
|
|
1947
|
+
}
|
|
1948
|
+
if (event.type === "turn.done") {
|
|
1949
|
+
if (event.state.status === "error") {
|
|
1950
|
+
throw new Error(event.state.message);
|
|
1951
|
+
}
|
|
1952
|
+
break;
|
|
1953
|
+
}
|
|
1954
|
+
if (!ingestStreamEvent(foldState, event)) {
|
|
1955
|
+
continue;
|
|
1956
|
+
}
|
|
1957
|
+
const content = yieldContent();
|
|
1958
|
+
if (content != null) {
|
|
1959
|
+
yield withSandbox({ content });
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
if (pendingMcpAuth != null) {
|
|
1963
|
+
yield withSandbox(buildMcpAuthUpdate(pendingMcpAuth, foldState, groupRootBaseline));
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
const approvalThreadId = findFirstPendingApprovalThreadId(foldState);
|
|
1967
|
+
const responseThreadId = findFirstPendingResponseThreadId(foldState);
|
|
1968
|
+
if (approvalThreadId != null || responseThreadId != null) {
|
|
1969
|
+
const custom = {};
|
|
1970
|
+
if (approvalThreadId != null) {
|
|
1971
|
+
Object.assign(
|
|
1972
|
+
custom,
|
|
1973
|
+
toolApprovalMessageCustom(
|
|
1974
|
+
approvalThreadId === ROOT_THREAD_ID ? ROOT_THREAD_ID : approvalThreadId
|
|
1975
|
+
)
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
if (responseThreadId != null) {
|
|
1979
|
+
Object.assign(
|
|
1980
|
+
custom,
|
|
1981
|
+
toolResponseMessageCustom(
|
|
1982
|
+
responseThreadId === ROOT_THREAD_ID ? ROOT_THREAD_ID : responseThreadId
|
|
1983
|
+
)
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
const ids = groupRootBaseline != null ? rootModelMessageIdsSinceBaseline(foldState, groupRootBaseline) : foldState.threads.get(ROOT_THREAD_ID)?.modelMessageIds ?? [];
|
|
1987
|
+
yield withSandbox({
|
|
1988
|
+
content: buildRootAssistantContentForIds(foldState, ids),
|
|
1989
|
+
status: approvalThreadId != null ? toolApprovalStatus() : toolResponseStatus(),
|
|
1990
|
+
metadata: { custom }
|
|
1991
|
+
});
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
if (sandboxId != null && !sandboxIdYielded) {
|
|
1995
|
+
const ids = groupRootBaseline != null ? rootModelMessageIdsSinceBaseline(foldState, groupRootBaseline) : foldState.threads.get(ROOT_THREAD_ID)?.modelMessageIds ?? [];
|
|
1996
|
+
yield withSandbox({ content: buildRootAssistantContentForIds(foldState, ids) });
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
function turnStreamUpdateToAssistantMessage(turnId, update, existing, options) {
|
|
2000
|
+
const id = existing?.role === "assistant" ? existing.id : `${turnId}-assistant`;
|
|
2001
|
+
const fallbackCreatedAt = existing?.createdAt ?? /* @__PURE__ */ new Date();
|
|
2002
|
+
return {
|
|
2003
|
+
id,
|
|
2004
|
+
role: "assistant",
|
|
2005
|
+
content: update.content,
|
|
2006
|
+
status: update.status ?? { type: "running" },
|
|
2007
|
+
createdAt: resolveCreatedAt(id, fallbackCreatedAt, options),
|
|
2008
|
+
metadata: {
|
|
2009
|
+
unstable_state: null,
|
|
2010
|
+
unstable_annotations: [],
|
|
2011
|
+
unstable_data: [],
|
|
2012
|
+
steps: [],
|
|
2013
|
+
custom: update.metadata?.custom ?? {}
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
function repositoryItemsFromMessages(messages) {
|
|
2018
|
+
const items = [];
|
|
2019
|
+
let parentId = null;
|
|
2020
|
+
for (const message of messages) {
|
|
2021
|
+
items.push({ parentId, message });
|
|
2022
|
+
parentId = message.id;
|
|
2023
|
+
}
|
|
2024
|
+
return items;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// src/draftSessionBridge.ts
|
|
2028
|
+
function createDraftSessionBridge(gateway) {
|
|
2029
|
+
async function getDraft(draftSessionId) {
|
|
2030
|
+
const response = await gateway.agents.private.draftSessions.get(draftSessionId);
|
|
2031
|
+
return response.data;
|
|
2032
|
+
}
|
|
2033
|
+
return {
|
|
2034
|
+
async getDraftAgentSpec(draftSessionId) {
|
|
2035
|
+
const draft = await getDraft(draftSessionId);
|
|
2036
|
+
return draft.agentSpec;
|
|
2037
|
+
},
|
|
2038
|
+
async syncAgentSpec(draftSessionId, agentSpec) {
|
|
2039
|
+
await gateway.agents.private.draftSessions.update(draftSessionId, { agentSpec });
|
|
2040
|
+
}
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
// src/agentSpec.ts
|
|
2045
|
+
function mergeAgentSpec(base, update) {
|
|
2046
|
+
const { model: modelUpdate, ...rest } = update;
|
|
2047
|
+
const next = {
|
|
2048
|
+
...base,
|
|
2049
|
+
...rest
|
|
2050
|
+
};
|
|
2051
|
+
if (modelUpdate != null) {
|
|
2052
|
+
next.model = {
|
|
2053
|
+
...base.model,
|
|
2054
|
+
...modelUpdate,
|
|
2055
|
+
name: modelUpdate.name ?? base.model.name,
|
|
2056
|
+
params: modelUpdate.params != null ? { ...base.model.params, ...modelUpdate.params } : base.model.params
|
|
2057
|
+
};
|
|
2058
|
+
}
|
|
2059
|
+
return next;
|
|
2060
|
+
}
|
|
2061
|
+
function draftSessionTitle(draft) {
|
|
2062
|
+
return draft.title ?? draft.agentSpec.model.name;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// src/sessionListStartTimestamp.ts
|
|
2066
|
+
function sessionListStartTimestamp() {
|
|
2067
|
+
const start = /* @__PURE__ */ new Date();
|
|
2068
|
+
start.setFullYear(start.getFullYear() - 1);
|
|
2069
|
+
return start.toISOString();
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
// src/truefoundryDraftThreadListAdapter.ts
|
|
2073
|
+
var THREAD_LIST_PAGE_SIZE = 20;
|
|
2074
|
+
function createTrueFoundryDraftThreadListAdapter(options) {
|
|
2075
|
+
const { gateway, defaultAgentSpec, getAgentSpec } = options;
|
|
2076
|
+
return {
|
|
2077
|
+
async list({ after } = {}) {
|
|
2078
|
+
const page = await gateway.agents.private.draftSessions.list({
|
|
2079
|
+
limit: THREAD_LIST_PAGE_SIZE,
|
|
2080
|
+
pageToken: after,
|
|
2081
|
+
startTimestamp: sessionListStartTimestamp()
|
|
2082
|
+
});
|
|
2083
|
+
const threads = page.data.map((draft) => ({
|
|
2084
|
+
status: "regular",
|
|
2085
|
+
remoteId: draft.id,
|
|
2086
|
+
title: draftSessionTitle(draft),
|
|
2087
|
+
lastMessageAt: new Date(draft.updatedAt)
|
|
2088
|
+
}));
|
|
2089
|
+
return {
|
|
2090
|
+
threads,
|
|
2091
|
+
nextCursor: page.response.pagination.nextPageToken ?? void 0
|
|
2092
|
+
};
|
|
2093
|
+
},
|
|
2094
|
+
async initialize(_threadId) {
|
|
2095
|
+
const response = await gateway.agents.private.draftSessions.create({
|
|
2096
|
+
agentSpec: getAgentSpec?.() ?? defaultAgentSpec
|
|
2097
|
+
});
|
|
2098
|
+
const draft = response.data;
|
|
2099
|
+
return { remoteId: draft.id, externalId: void 0 };
|
|
2100
|
+
},
|
|
2101
|
+
async fetch(remoteId) {
|
|
2102
|
+
const response = await gateway.agents.private.draftSessions.get(remoteId);
|
|
2103
|
+
const draft = response.data;
|
|
2104
|
+
return {
|
|
2105
|
+
status: "regular",
|
|
2106
|
+
remoteId: draft.id,
|
|
2107
|
+
title: draftSessionTitle(draft),
|
|
2108
|
+
lastMessageAt: new Date(draft.updatedAt)
|
|
2109
|
+
};
|
|
2110
|
+
},
|
|
2111
|
+
async rename() {
|
|
2112
|
+
},
|
|
2113
|
+
async archive() {
|
|
2114
|
+
},
|
|
2115
|
+
async unarchive() {
|
|
2116
|
+
},
|
|
2117
|
+
async delete() {
|
|
2118
|
+
},
|
|
2119
|
+
async generateTitle() {
|
|
2120
|
+
return new ReadableStream();
|
|
2121
|
+
}
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
// src/truefoundryExtras.ts
|
|
2126
|
+
import { createRuntimeExtras } from "@assistant-ui/core/internal";
|
|
2127
|
+
var trueFoundryExtras = createRuntimeExtras(
|
|
2128
|
+
"useTrueFoundryAgentRuntime"
|
|
2129
|
+
);
|
|
2130
|
+
var EMPTY_DRAFT_EXTRAS = {
|
|
2131
|
+
agentSpec: null,
|
|
2132
|
+
draftSessionId: void 0,
|
|
2133
|
+
isSpecSyncing: false,
|
|
2134
|
+
specError: null,
|
|
2135
|
+
updateAgentSpec: () => {
|
|
2136
|
+
throw new Error("Draft agent extras are only available in draft mode.");
|
|
2137
|
+
}
|
|
2138
|
+
};
|
|
2139
|
+
|
|
2140
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.2.0/node_modules/truefoundry-gateway-sdk/dist/esm/core/fetcher/HttpResponsePromise.mjs
|
|
2141
|
+
var __awaiter = function(thisArg, _arguments, P, generator) {
|
|
2142
|
+
function adopt(value) {
|
|
2143
|
+
return value instanceof P ? value : new P(function(resolve) {
|
|
2144
|
+
resolve(value);
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
return new (P || (P = Promise))(function(resolve, reject) {
|
|
2148
|
+
function fulfilled(value) {
|
|
2149
|
+
try {
|
|
2150
|
+
step(generator.next(value));
|
|
2151
|
+
} catch (e) {
|
|
2152
|
+
reject(e);
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
function rejected(value) {
|
|
2156
|
+
try {
|
|
2157
|
+
step(generator["throw"](value));
|
|
2158
|
+
} catch (e) {
|
|
2159
|
+
reject(e);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
function step(result) {
|
|
2163
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
2164
|
+
}
|
|
2165
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
2166
|
+
});
|
|
2167
|
+
};
|
|
2168
|
+
var HttpResponsePromise = class _HttpResponsePromise extends Promise {
|
|
2169
|
+
constructor(promise) {
|
|
2170
|
+
super((resolve) => {
|
|
2171
|
+
resolve(void 0);
|
|
2172
|
+
});
|
|
2173
|
+
this.innerPromise = promise;
|
|
2174
|
+
}
|
|
2175
|
+
/**
|
|
2176
|
+
* Creates an `HttpResponsePromise` from a function that returns a promise.
|
|
2177
|
+
*
|
|
2178
|
+
* @param fn - A function that returns a promise resolving to a `WithRawResponse` object.
|
|
2179
|
+
* @param args - Arguments to pass to the function.
|
|
2180
|
+
* @returns An `HttpResponsePromise` instance.
|
|
2181
|
+
*/
|
|
2182
|
+
static fromFunction(fn, ...args) {
|
|
2183
|
+
return new _HttpResponsePromise(fn(...args));
|
|
2184
|
+
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Creates a function that returns an `HttpResponsePromise` from a function that returns a promise.
|
|
2187
|
+
*
|
|
2188
|
+
* @param fn - A function that returns a promise resolving to a `WithRawResponse` object.
|
|
2189
|
+
* @returns A function that returns an `HttpResponsePromise` instance.
|
|
2190
|
+
*/
|
|
2191
|
+
static interceptFunction(fn) {
|
|
2192
|
+
return (...args) => {
|
|
2193
|
+
return _HttpResponsePromise.fromPromise(fn(...args));
|
|
2194
|
+
};
|
|
2195
|
+
}
|
|
2196
|
+
/**
|
|
2197
|
+
* Creates an `HttpResponsePromise` from an existing promise.
|
|
2198
|
+
*
|
|
2199
|
+
* @param promise - A promise resolving to a `WithRawResponse` object.
|
|
2200
|
+
* @returns An `HttpResponsePromise` instance.
|
|
2201
|
+
*/
|
|
2202
|
+
static fromPromise(promise) {
|
|
2203
|
+
return new _HttpResponsePromise(promise);
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* Creates an `HttpResponsePromise` from an executor function.
|
|
2207
|
+
*
|
|
2208
|
+
* @param executor - A function that takes resolve and reject callbacks to create a promise.
|
|
2209
|
+
* @returns An `HttpResponsePromise` instance.
|
|
2210
|
+
*/
|
|
2211
|
+
static fromExecutor(executor) {
|
|
2212
|
+
const promise = new Promise(executor);
|
|
2213
|
+
return new _HttpResponsePromise(promise);
|
|
2214
|
+
}
|
|
2215
|
+
/**
|
|
2216
|
+
* Creates an `HttpResponsePromise` from a resolved result.
|
|
2217
|
+
*
|
|
2218
|
+
* @param result - A `WithRawResponse` object to resolve immediately.
|
|
2219
|
+
* @returns An `HttpResponsePromise` instance.
|
|
2220
|
+
*/
|
|
2221
|
+
static fromResult(result) {
|
|
2222
|
+
const promise = Promise.resolve(result);
|
|
2223
|
+
return new _HttpResponsePromise(promise);
|
|
2224
|
+
}
|
|
2225
|
+
unwrap() {
|
|
2226
|
+
if (!this.unwrappedPromise) {
|
|
2227
|
+
this.unwrappedPromise = this.innerPromise.then(({ data }) => data);
|
|
2228
|
+
}
|
|
2229
|
+
return this.unwrappedPromise;
|
|
2230
|
+
}
|
|
2231
|
+
/** @inheritdoc */
|
|
2232
|
+
then(onfulfilled, onrejected) {
|
|
2233
|
+
return this.unwrap().then(onfulfilled, onrejected);
|
|
2234
|
+
}
|
|
2235
|
+
/** @inheritdoc */
|
|
2236
|
+
catch(onrejected) {
|
|
2237
|
+
return this.unwrap().catch(onrejected);
|
|
2238
|
+
}
|
|
2239
|
+
/** @inheritdoc */
|
|
2240
|
+
finally(onfinally) {
|
|
2241
|
+
return this.unwrap().finally(onfinally);
|
|
2242
|
+
}
|
|
2243
|
+
/**
|
|
2244
|
+
* Retrieves the data and raw response.
|
|
2245
|
+
*
|
|
2246
|
+
* @returns A promise resolving to a `WithRawResponse` object.
|
|
2247
|
+
*/
|
|
2248
|
+
withRawResponse() {
|
|
2249
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2250
|
+
return yield this.innerPromise;
|
|
2251
|
+
});
|
|
2252
|
+
}
|
|
2253
|
+
};
|
|
2254
|
+
|
|
2255
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.2.0/node_modules/truefoundry-gateway-sdk/dist/esm/core/pagination/Page.mjs
|
|
2256
|
+
var __awaiter2 = function(thisArg, _arguments, P, generator) {
|
|
2257
|
+
function adopt(value) {
|
|
2258
|
+
return value instanceof P ? value : new P(function(resolve) {
|
|
2259
|
+
resolve(value);
|
|
2260
|
+
});
|
|
2261
|
+
}
|
|
2262
|
+
return new (P || (P = Promise))(function(resolve, reject) {
|
|
2263
|
+
function fulfilled(value) {
|
|
2264
|
+
try {
|
|
2265
|
+
step(generator.next(value));
|
|
2266
|
+
} catch (e) {
|
|
2267
|
+
reject(e);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
function rejected(value) {
|
|
2271
|
+
try {
|
|
2272
|
+
step(generator["throw"](value));
|
|
2273
|
+
} catch (e) {
|
|
2274
|
+
reject(e);
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
function step(result) {
|
|
2278
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
2279
|
+
}
|
|
2280
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
2281
|
+
});
|
|
2282
|
+
};
|
|
2283
|
+
var __await = function(v) {
|
|
2284
|
+
return this instanceof __await ? (this.v = v, this) : new __await(v);
|
|
2285
|
+
};
|
|
2286
|
+
var __asyncGenerator = function(thisArg, _arguments, generator) {
|
|
2287
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
2288
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
2289
|
+
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function() {
|
|
2290
|
+
return this;
|
|
2291
|
+
}, i;
|
|
2292
|
+
function awaitReturn(f) {
|
|
2293
|
+
return function(v) {
|
|
2294
|
+
return Promise.resolve(v).then(f, reject);
|
|
2295
|
+
};
|
|
2296
|
+
}
|
|
2297
|
+
function verb(n, f) {
|
|
2298
|
+
if (g[n]) {
|
|
2299
|
+
i[n] = function(v) {
|
|
2300
|
+
return new Promise(function(a, b) {
|
|
2301
|
+
q.push([n, v, a, b]) > 1 || resume(n, v);
|
|
2302
|
+
});
|
|
2303
|
+
};
|
|
2304
|
+
if (f) i[n] = f(i[n]);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
function resume(n, v) {
|
|
2308
|
+
try {
|
|
2309
|
+
step(g[n](v));
|
|
2310
|
+
} catch (e) {
|
|
2311
|
+
settle(q[0][3], e);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
function step(r) {
|
|
2315
|
+
r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);
|
|
2316
|
+
}
|
|
2317
|
+
function fulfill(value) {
|
|
2318
|
+
resume("next", value);
|
|
2319
|
+
}
|
|
2320
|
+
function reject(value) {
|
|
2321
|
+
resume("throw", value);
|
|
2322
|
+
}
|
|
2323
|
+
function settle(f, v) {
|
|
2324
|
+
if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);
|
|
2325
|
+
}
|
|
2326
|
+
};
|
|
2327
|
+
var __asyncValues = function(o) {
|
|
2328
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
2329
|
+
var m = o[Symbol.asyncIterator], i;
|
|
2330
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
|
|
2331
|
+
return this;
|
|
2332
|
+
}, i);
|
|
2333
|
+
function verb(n) {
|
|
2334
|
+
i[n] = o[n] && function(v) {
|
|
2335
|
+
return new Promise(function(resolve, reject) {
|
|
2336
|
+
v = o[n](v), settle(resolve, reject, v.done, v.value);
|
|
2337
|
+
});
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
function settle(resolve, reject, d, v) {
|
|
2341
|
+
Promise.resolve(v).then(function(v2) {
|
|
2342
|
+
resolve({ value: v2, done: d });
|
|
2343
|
+
}, reject);
|
|
2344
|
+
}
|
|
2345
|
+
};
|
|
2346
|
+
var Page = class {
|
|
2347
|
+
constructor({ response, rawResponse, hasNextPage, getItems, loadPage }) {
|
|
2348
|
+
this.response = response;
|
|
2349
|
+
this.rawResponse = rawResponse;
|
|
2350
|
+
this.data = getItems(response);
|
|
2351
|
+
this._hasNextPage = hasNextPage;
|
|
2352
|
+
this.getItems = getItems;
|
|
2353
|
+
this.loadNextPage = loadPage;
|
|
2354
|
+
}
|
|
2355
|
+
/**
|
|
2356
|
+
* Retrieves the next page
|
|
2357
|
+
* @returns this
|
|
2358
|
+
*/
|
|
2359
|
+
getNextPage() {
|
|
2360
|
+
return __awaiter2(this, void 0, void 0, function* () {
|
|
2361
|
+
const { data, rawResponse } = yield this.loadNextPage(this.response).withRawResponse();
|
|
2362
|
+
this.response = data;
|
|
2363
|
+
this.rawResponse = rawResponse;
|
|
2364
|
+
this.data = this.getItems(this.response);
|
|
2365
|
+
return this;
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
/**
|
|
2369
|
+
* @returns whether there is a next page to load
|
|
2370
|
+
*/
|
|
2371
|
+
hasNextPage() {
|
|
2372
|
+
return this._hasNextPage(this.response);
|
|
2373
|
+
}
|
|
2374
|
+
iterMessages() {
|
|
2375
|
+
return __asyncGenerator(this, arguments, function* iterMessages_1() {
|
|
2376
|
+
for (const item of this.data) {
|
|
2377
|
+
yield yield __await(item);
|
|
2378
|
+
}
|
|
2379
|
+
while (this.hasNextPage()) {
|
|
2380
|
+
yield __await(this.getNextPage());
|
|
2381
|
+
for (const item of this.data) {
|
|
2382
|
+
yield yield __await(item);
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
});
|
|
2386
|
+
}
|
|
2387
|
+
[Symbol.asyncIterator]() {
|
|
2388
|
+
return __asyncGenerator(this, arguments, function* _a() {
|
|
2389
|
+
var _b, e_1, _c, _d;
|
|
2390
|
+
try {
|
|
2391
|
+
for (var _e = true, _f = __asyncValues(this.iterMessages()), _g; _g = yield __await(_f.next()), _b = _g.done, !_b; _e = true) {
|
|
2392
|
+
_d = _g.value;
|
|
2393
|
+
_e = false;
|
|
2394
|
+
const message = _d;
|
|
2395
|
+
yield yield __await(message);
|
|
2396
|
+
}
|
|
2397
|
+
} catch (e_1_1) {
|
|
2398
|
+
e_1 = { error: e_1_1 };
|
|
2399
|
+
} finally {
|
|
2400
|
+
try {
|
|
2401
|
+
if (!_e && !_b && (_c = _f.return)) yield __await(_c.call(_f));
|
|
2402
|
+
} finally {
|
|
2403
|
+
if (e_1) throw e_1.error;
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
};
|
|
2409
|
+
|
|
2410
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.2.0/node_modules/truefoundry-gateway-sdk/dist/esm/agents/TurnStreamData.mjs
|
|
2411
|
+
function parseSequenceNumber(id) {
|
|
2412
|
+
if (!id) {
|
|
2413
|
+
throw new Error("Missing SSE sequence number id.");
|
|
2414
|
+
}
|
|
2415
|
+
const parsed = Number(id);
|
|
2416
|
+
if (!Number.isFinite(parsed)) {
|
|
2417
|
+
throw new Error(`Invalid SSE sequence number id: "${id}".`);
|
|
2418
|
+
}
|
|
2419
|
+
return parsed;
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.2.0/node_modules/truefoundry-gateway-sdk/dist/esm/agents/Turn.mjs
|
|
2423
|
+
var __awaiter3 = function(thisArg, _arguments, P, generator) {
|
|
2424
|
+
function adopt(value) {
|
|
2425
|
+
return value instanceof P ? value : new P(function(resolve) {
|
|
2426
|
+
resolve(value);
|
|
2427
|
+
});
|
|
2428
|
+
}
|
|
2429
|
+
return new (P || (P = Promise))(function(resolve, reject) {
|
|
2430
|
+
function fulfilled(value) {
|
|
2431
|
+
try {
|
|
2432
|
+
step(generator.next(value));
|
|
2433
|
+
} catch (e) {
|
|
2434
|
+
reject(e);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
function rejected(value) {
|
|
2438
|
+
try {
|
|
2439
|
+
step(generator["throw"](value));
|
|
2440
|
+
} catch (e) {
|
|
2441
|
+
reject(e);
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
function step(result) {
|
|
2445
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
2446
|
+
}
|
|
2447
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
2448
|
+
});
|
|
2449
|
+
};
|
|
2450
|
+
var __classPrivateFieldSet = function(receiver, state, value, kind, f) {
|
|
2451
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
2452
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
2453
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
2454
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
2455
|
+
};
|
|
2456
|
+
var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
2457
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
2458
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
2459
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
2460
|
+
};
|
|
2461
|
+
var __await2 = function(v) {
|
|
2462
|
+
return this instanceof __await2 ? (this.v = v, this) : new __await2(v);
|
|
2463
|
+
};
|
|
2464
|
+
var __asyncValues2 = function(o) {
|
|
2465
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
2466
|
+
var m = o[Symbol.asyncIterator], i;
|
|
2467
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
|
|
2468
|
+
return this;
|
|
2469
|
+
}, i);
|
|
2470
|
+
function verb(n) {
|
|
2471
|
+
i[n] = o[n] && function(v) {
|
|
2472
|
+
return new Promise(function(resolve, reject) {
|
|
2473
|
+
v = o[n](v), settle(resolve, reject, v.done, v.value);
|
|
2474
|
+
});
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
function settle(resolve, reject, d, v) {
|
|
2478
|
+
Promise.resolve(v).then(function(v2) {
|
|
2479
|
+
resolve({ value: v2, done: d });
|
|
2480
|
+
}, reject);
|
|
2481
|
+
}
|
|
2482
|
+
};
|
|
2483
|
+
var __asyncGenerator2 = function(thisArg, _arguments, generator) {
|
|
2484
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
2485
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
2486
|
+
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function() {
|
|
2487
|
+
return this;
|
|
2488
|
+
}, i;
|
|
2489
|
+
function awaitReturn(f) {
|
|
2490
|
+
return function(v) {
|
|
2491
|
+
return Promise.resolve(v).then(f, reject);
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2494
|
+
function verb(n, f) {
|
|
2495
|
+
if (g[n]) {
|
|
2496
|
+
i[n] = function(v) {
|
|
2497
|
+
return new Promise(function(a, b) {
|
|
2498
|
+
q.push([n, v, a, b]) > 1 || resume(n, v);
|
|
2499
|
+
});
|
|
2500
|
+
};
|
|
2501
|
+
if (f) i[n] = f(i[n]);
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
function resume(n, v) {
|
|
2505
|
+
try {
|
|
2506
|
+
step(g[n](v));
|
|
2507
|
+
} catch (e) {
|
|
2508
|
+
settle(q[0][3], e);
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
function step(r) {
|
|
2512
|
+
r.value instanceof __await2 ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);
|
|
2513
|
+
}
|
|
2514
|
+
function fulfill(value) {
|
|
2515
|
+
resume("next", value);
|
|
2516
|
+
}
|
|
2517
|
+
function reject(value) {
|
|
2518
|
+
resume("throw", value);
|
|
2519
|
+
}
|
|
2520
|
+
function settle(f, v) {
|
|
2521
|
+
if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);
|
|
2522
|
+
}
|
|
2523
|
+
};
|
|
2524
|
+
var _Turn_instances;
|
|
2525
|
+
var _Turn_client;
|
|
2526
|
+
var _Turn_state;
|
|
2527
|
+
var _Turn_applyEvent;
|
|
2528
|
+
var DEFAULT_POLL_INTERVAL_MS = 3e3;
|
|
2529
|
+
var MIN_POLL_INTERVAL_MS = 3e3;
|
|
2530
|
+
var Turn = class {
|
|
2531
|
+
constructor(turn, session, client) {
|
|
2532
|
+
_Turn_instances.add(this);
|
|
2533
|
+
_Turn_client.set(this, void 0);
|
|
2534
|
+
_Turn_state.set(this, void 0);
|
|
2535
|
+
this.id = turn.id;
|
|
2536
|
+
this.sessionId = turn.sessionId;
|
|
2537
|
+
this.previousTurnId = turn.previousTurnId;
|
|
2538
|
+
this.input = turn.input;
|
|
2539
|
+
this.createdBySubject = turn.createdBySubject;
|
|
2540
|
+
this.createdAt = turn.createdAt;
|
|
2541
|
+
__classPrivateFieldSet(this, _Turn_state, turn.state, "f");
|
|
2542
|
+
this.session = session;
|
|
2543
|
+
__classPrivateFieldSet(this, _Turn_client, client, "f");
|
|
2544
|
+
}
|
|
2545
|
+
/**
|
|
2546
|
+
* @returns {TrueFoundryGatewayApi.TurnState} Updated by `refresh()`, `stream()`, and `waitForCompletion()`.
|
|
2547
|
+
*/
|
|
2548
|
+
get state() {
|
|
2549
|
+
return __classPrivateFieldGet(this, _Turn_state, "f");
|
|
2550
|
+
}
|
|
2551
|
+
// Terminal states are listed explicitly (not `status !== "running"`) so a newly added
|
|
2552
|
+
// non-terminal status keeps polling by default; new terminal states must be added here.
|
|
2553
|
+
isTerminal(state) {
|
|
2554
|
+
switch (state.status) {
|
|
2555
|
+
case "done":
|
|
2556
|
+
case "cancelled":
|
|
2557
|
+
case "error":
|
|
2558
|
+
return true;
|
|
2559
|
+
default:
|
|
2560
|
+
return false;
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
// Refetch from the server, update #state in place, and return self.
|
|
2564
|
+
/**
|
|
2565
|
+
* Refetch from the server, update state in-place and return self.
|
|
2566
|
+
*
|
|
2567
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2568
|
+
* @returns {this} This turn with updated state.
|
|
2569
|
+
*/
|
|
2570
|
+
refresh(requestOptions) {
|
|
2571
|
+
return __awaiter3(this, void 0, void 0, function* () {
|
|
2572
|
+
const response = yield __classPrivateFieldGet(this, _Turn_client, "f").agents.sessions.getTurn(this.sessionId, this.id, requestOptions);
|
|
2573
|
+
__classPrivateFieldSet(this, _Turn_state, response.data.state, "f");
|
|
2574
|
+
return this;
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* Poll getTurn until terminal.
|
|
2579
|
+
*
|
|
2580
|
+
* @param opts.pollIntervalMs - Poll interval ms while waiting. Minimum 3000.
|
|
2581
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2582
|
+
* @returns {TrueFoundryGatewayApi.TurnState} Terminal turn state.
|
|
2583
|
+
*/
|
|
2584
|
+
waitForCompletion(opts, requestOptions) {
|
|
2585
|
+
return __awaiter3(this, void 0, void 0, function* () {
|
|
2586
|
+
var _a;
|
|
2587
|
+
const pollIntervalMs = (_a = opts === null || opts === void 0 ? void 0 : opts.pollIntervalMs) !== null && _a !== void 0 ? _a : DEFAULT_POLL_INTERVAL_MS;
|
|
2588
|
+
if (pollIntervalMs < MIN_POLL_INTERVAL_MS) {
|
|
2589
|
+
throw new Error(`pollIntervalMs must be at least ${MIN_POLL_INTERVAL_MS}ms`);
|
|
2590
|
+
}
|
|
2591
|
+
while (!this.isTerminal(__classPrivateFieldGet(this, _Turn_state, "f"))) {
|
|
2592
|
+
yield new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
2593
|
+
yield this.refresh(requestOptions);
|
|
2594
|
+
}
|
|
2595
|
+
return __classPrivateFieldGet(this, _Turn_state, "f");
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2598
|
+
// Reconnect to the turn's SSE; let the server decide what to stream (no client-side guard).
|
|
2599
|
+
// Updates #state in place from any event that carries a state snapshot.
|
|
2600
|
+
/**
|
|
2601
|
+
* Reconnect to the turn's SSE. Updates state in-place from lifecycle events.
|
|
2602
|
+
*
|
|
2603
|
+
* @param opts.afterSequenceNumber - Sequence number to resume SSE subscription after.
|
|
2604
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2605
|
+
* @yields {TurnStreamData} SSE stream items.
|
|
2606
|
+
*/
|
|
2607
|
+
stream(opts, requestOptions) {
|
|
2608
|
+
return __asyncGenerator2(this, arguments, function* stream_1() {
|
|
2609
|
+
var _a, e_1, _b, _c;
|
|
2610
|
+
const sse = yield __await2(__classPrivateFieldGet(this, _Turn_client, "f").agents.sessions.subscribeToTurn(this.sessionId, this.id, { afterSequenceNumber: opts === null || opts === void 0 ? void 0 : opts.afterSequenceNumber }, requestOptions));
|
|
2611
|
+
try {
|
|
2612
|
+
for (var _d = true, _e = __asyncValues2(sse.withMetadata()), _f; _f = yield __await2(_e.next()), _a = _f.done, !_a; _d = true) {
|
|
2613
|
+
_c = _f.value;
|
|
2614
|
+
_d = false;
|
|
2615
|
+
const { data: event, id } = _c;
|
|
2616
|
+
__classPrivateFieldGet(this, _Turn_instances, "m", _Turn_applyEvent).call(this, event);
|
|
2617
|
+
yield yield __await2({ sequenceNumber: parseSequenceNumber(id), event });
|
|
2618
|
+
}
|
|
2619
|
+
} catch (e_1_1) {
|
|
2620
|
+
e_1 = { error: e_1_1 };
|
|
2621
|
+
} finally {
|
|
2622
|
+
try {
|
|
2623
|
+
if (!_d && !_a && (_b = _e.return)) yield __await2(_b.call(_e));
|
|
2624
|
+
} finally {
|
|
2625
|
+
if (e_1) throw e_1.error;
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
/**
|
|
2631
|
+
* Cancel the running last turn for the session.
|
|
2632
|
+
*
|
|
2633
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2634
|
+
* @returns {void}
|
|
2635
|
+
*/
|
|
2636
|
+
cancel(requestOptions) {
|
|
2637
|
+
return __awaiter3(this, void 0, void 0, function* () {
|
|
2638
|
+
yield __classPrivateFieldGet(this, _Turn_client, "f").agents.sessions.cancel(this.sessionId, {}, requestOptions);
|
|
2639
|
+
});
|
|
2640
|
+
}
|
|
2641
|
+
// Expose the autogen Fern Page as-is (it is already async-iterable); no re-wrapping.
|
|
2642
|
+
/**
|
|
2643
|
+
* Paginated turn events; use `stream()` for live SSE.
|
|
2644
|
+
*
|
|
2645
|
+
* @param opts.pageToken - Token from the previous response nextPageToken.
|
|
2646
|
+
* @param opts.limit - Page size. Default 25.
|
|
2647
|
+
* @param opts.order - Sort by creation time. Default `asc`.
|
|
2648
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2649
|
+
* @returns {Promise<core.Page<TrueFoundryGatewayApi.TurnEvent, TrueFoundryGatewayApi.ListEventsResponse>>} Paginated turn events.
|
|
2650
|
+
*/
|
|
2651
|
+
listEvents(opts, requestOptions) {
|
|
2652
|
+
return __classPrivateFieldGet(this, _Turn_client, "f").agents.sessions.listTurnEvents(this.sessionId, this.id, opts, requestOptions);
|
|
2653
|
+
}
|
|
2654
|
+
};
|
|
2655
|
+
_Turn_client = /* @__PURE__ */ new WeakMap(), _Turn_state = /* @__PURE__ */ new WeakMap(), _Turn_instances = /* @__PURE__ */ new WeakSet(), _Turn_applyEvent = function _Turn_applyEvent2(event) {
|
|
2656
|
+
if (event.type === "turn.created" || event.type === "turn.done")
|
|
2657
|
+
__classPrivateFieldSet(this, _Turn_state, event.state, "f");
|
|
2658
|
+
};
|
|
2659
|
+
|
|
2660
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.2.0/node_modules/truefoundry-gateway-sdk/dist/esm/agents/PreparedTurn.mjs
|
|
2661
|
+
var __awaiter4 = function(thisArg, _arguments, P, generator) {
|
|
2662
|
+
function adopt(value) {
|
|
2663
|
+
return value instanceof P ? value : new P(function(resolve) {
|
|
2664
|
+
resolve(value);
|
|
2665
|
+
});
|
|
2666
|
+
}
|
|
2667
|
+
return new (P || (P = Promise))(function(resolve, reject) {
|
|
2668
|
+
function fulfilled(value) {
|
|
2669
|
+
try {
|
|
2670
|
+
step(generator.next(value));
|
|
2671
|
+
} catch (e) {
|
|
2672
|
+
reject(e);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
function rejected(value) {
|
|
2676
|
+
try {
|
|
2677
|
+
step(generator["throw"](value));
|
|
2678
|
+
} catch (e) {
|
|
2679
|
+
reject(e);
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
function step(result) {
|
|
2683
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
2684
|
+
}
|
|
2685
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
2686
|
+
});
|
|
2687
|
+
};
|
|
2688
|
+
var __classPrivateFieldSet2 = function(receiver, state, value, kind, f) {
|
|
2689
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
2690
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
2691
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
2692
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
2693
|
+
};
|
|
2694
|
+
var __classPrivateFieldGet2 = function(receiver, state, kind, f) {
|
|
2695
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
2696
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
2697
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
2698
|
+
};
|
|
2699
|
+
var __asyncValues3 = function(o) {
|
|
2700
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
2701
|
+
var m = o[Symbol.asyncIterator], i;
|
|
2702
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
|
|
2703
|
+
return this;
|
|
2704
|
+
}, i);
|
|
2705
|
+
function verb(n) {
|
|
2706
|
+
i[n] = o[n] && function(v) {
|
|
2707
|
+
return new Promise(function(resolve, reject) {
|
|
2708
|
+
v = o[n](v), settle(resolve, reject, v.done, v.value);
|
|
2709
|
+
});
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
function settle(resolve, reject, d, v) {
|
|
2713
|
+
Promise.resolve(v).then(function(v2) {
|
|
2714
|
+
resolve({ value: v2, done: d });
|
|
2715
|
+
}, reject);
|
|
2716
|
+
}
|
|
2717
|
+
};
|
|
2718
|
+
var __await3 = function(v) {
|
|
2719
|
+
return this instanceof __await3 ? (this.v = v, this) : new __await3(v);
|
|
2720
|
+
};
|
|
2721
|
+
var __asyncDelegator = function(o) {
|
|
2722
|
+
var i, p;
|
|
2723
|
+
return i = {}, verb("next"), verb("throw", function(e) {
|
|
2724
|
+
throw e;
|
|
2725
|
+
}), verb("return"), i[Symbol.iterator] = function() {
|
|
2726
|
+
return this;
|
|
2727
|
+
}, i;
|
|
2728
|
+
function verb(n, f) {
|
|
2729
|
+
i[n] = o[n] ? function(v) {
|
|
2730
|
+
return (p = !p) ? { value: __await3(o[n](v)), done: false } : f ? f(v) : v;
|
|
2731
|
+
} : f;
|
|
2732
|
+
}
|
|
2733
|
+
};
|
|
2734
|
+
var __asyncGenerator3 = function(thisArg, _arguments, generator) {
|
|
2735
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
2736
|
+
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
2737
|
+
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function() {
|
|
2738
|
+
return this;
|
|
2739
|
+
}, i;
|
|
2740
|
+
function awaitReturn(f) {
|
|
2741
|
+
return function(v) {
|
|
2742
|
+
return Promise.resolve(v).then(f, reject);
|
|
2743
|
+
};
|
|
2744
|
+
}
|
|
2745
|
+
function verb(n, f) {
|
|
2746
|
+
if (g[n]) {
|
|
2747
|
+
i[n] = function(v) {
|
|
2748
|
+
return new Promise(function(a, b) {
|
|
2749
|
+
q.push([n, v, a, b]) > 1 || resume(n, v);
|
|
2750
|
+
});
|
|
2751
|
+
};
|
|
2752
|
+
if (f) i[n] = f(i[n]);
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
function resume(n, v) {
|
|
2756
|
+
try {
|
|
2757
|
+
step(g[n](v));
|
|
2758
|
+
} catch (e) {
|
|
2759
|
+
settle(q[0][3], e);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
function step(r) {
|
|
2763
|
+
r.value instanceof __await3 ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);
|
|
2764
|
+
}
|
|
2765
|
+
function fulfill(value) {
|
|
2766
|
+
resume("next", value);
|
|
2767
|
+
}
|
|
2768
|
+
function reject(value) {
|
|
2769
|
+
resume("throw", value);
|
|
2770
|
+
}
|
|
2771
|
+
function settle(f, v) {
|
|
2772
|
+
if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);
|
|
2773
|
+
}
|
|
2774
|
+
};
|
|
2775
|
+
var _PreparedTurn_client;
|
|
2776
|
+
var _PreparedTurn_input;
|
|
2777
|
+
var _PreparedTurn_previousTurnIdInput;
|
|
2778
|
+
var _PreparedTurn_start;
|
|
2779
|
+
var _PreparedTurn_turn;
|
|
2780
|
+
var PreparedTurn = class {
|
|
2781
|
+
constructor(init, session, client) {
|
|
2782
|
+
_PreparedTurn_client.set(this, void 0);
|
|
2783
|
+
_PreparedTurn_input.set(this, void 0);
|
|
2784
|
+
_PreparedTurn_previousTurnIdInput.set(this, void 0);
|
|
2785
|
+
_PreparedTurn_start.set(this, void 0);
|
|
2786
|
+
_PreparedTurn_turn.set(this, void 0);
|
|
2787
|
+
this.session = session;
|
|
2788
|
+
this.sessionId = session.id;
|
|
2789
|
+
__classPrivateFieldSet2(this, _PreparedTurn_client, client, "f");
|
|
2790
|
+
__classPrivateFieldSet2(this, _PreparedTurn_input, init.input, "f");
|
|
2791
|
+
__classPrivateFieldSet2(this, _PreparedTurn_previousTurnIdInput, init.previousTurnId, "f");
|
|
2792
|
+
}
|
|
2793
|
+
// Remaining data getters delegate to the inner Turn (undefined until started).
|
|
2794
|
+
/**
|
|
2795
|
+
* @returns {string | undefined} Undefined until `execute()` starts the turn.
|
|
2796
|
+
*/
|
|
2797
|
+
get id() {
|
|
2798
|
+
var _a;
|
|
2799
|
+
return (_a = __classPrivateFieldGet2(this, _PreparedTurn_turn, "f")) === null || _a === void 0 ? void 0 : _a.id;
|
|
2800
|
+
}
|
|
2801
|
+
/**
|
|
2802
|
+
* @returns {string | undefined} Undefined until `execute()` starts the turn.
|
|
2803
|
+
*/
|
|
2804
|
+
get previousTurnId() {
|
|
2805
|
+
var _a;
|
|
2806
|
+
return (_a = __classPrivateFieldGet2(this, _PreparedTurn_turn, "f")) === null || _a === void 0 ? void 0 : _a.previousTurnId;
|
|
2807
|
+
}
|
|
2808
|
+
/**
|
|
2809
|
+
* @returns {TrueFoundryGatewayApi.TurnState | undefined} Undefined until `execute()` starts the turn.
|
|
2810
|
+
*/
|
|
2811
|
+
get state() {
|
|
2812
|
+
var _a;
|
|
2813
|
+
return (_a = __classPrivateFieldGet2(this, _PreparedTurn_turn, "f")) === null || _a === void 0 ? void 0 : _a.state;
|
|
2814
|
+
}
|
|
2815
|
+
/**
|
|
2816
|
+
* @returns {TrueFoundryGatewayApi.Subject | undefined} Undefined until `execute()` starts the turn.
|
|
2817
|
+
*/
|
|
2818
|
+
get createdBySubject() {
|
|
2819
|
+
var _a;
|
|
2820
|
+
return (_a = __classPrivateFieldGet2(this, _PreparedTurn_turn, "f")) === null || _a === void 0 ? void 0 : _a.createdBySubject;
|
|
2821
|
+
}
|
|
2822
|
+
/**
|
|
2823
|
+
* @returns {string | undefined} Undefined until `execute()` starts the turn.
|
|
2824
|
+
*/
|
|
2825
|
+
get createdAt() {
|
|
2826
|
+
var _a;
|
|
2827
|
+
return (_a = __classPrivateFieldGet2(this, _PreparedTurn_turn, "f")) === null || _a === void 0 ? void 0 : _a.createdAt;
|
|
2828
|
+
}
|
|
2829
|
+
/**
|
|
2830
|
+
* @returns {TrueFoundryGatewayApi.TurnInputItem[] | undefined} Staged input before execute; inner turn input after.
|
|
2831
|
+
*/
|
|
2832
|
+
get input() {
|
|
2833
|
+
var _a, _b;
|
|
2834
|
+
return (_b = (_a = __classPrivateFieldGet2(this, _PreparedTurn_turn, "f")) === null || _a === void 0 ? void 0 : _a.input) !== null && _b !== void 0 ? _b : __classPrivateFieldGet2(this, _PreparedTurn_input, "f");
|
|
2835
|
+
}
|
|
2836
|
+
execute(opts, requestOptions) {
|
|
2837
|
+
if (__classPrivateFieldGet2(this, _PreparedTurn_start, "f") != null)
|
|
2838
|
+
throw new Error("Turn already started; use stream() / waitForCompletion().");
|
|
2839
|
+
__classPrivateFieldSet2(this, _PreparedTurn_start, this.openCreateTurn(requestOptions), "f");
|
|
2840
|
+
const { stream = true, pollIntervalMs } = opts !== null && opts !== void 0 ? opts : {};
|
|
2841
|
+
return stream === false ? this.startAndWait(pollIntervalMs, requestOptions) : this.runStreaming();
|
|
2842
|
+
}
|
|
2843
|
+
// Post-execution behaviors. Each throws via mustGetTurn() until execute() has started the turn,
|
|
2844
|
+
// then delegates to the inner Turn. stream() here is the re-subscribe path (subscribeToTurn).
|
|
2845
|
+
/**
|
|
2846
|
+
* Resubscribe via subscribeToTurn after `execute()`.
|
|
2847
|
+
*
|
|
2848
|
+
* @param opts.afterSequenceNumber - Sequence number to resume SSE subscription after.
|
|
2849
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2850
|
+
* @yields {TurnStreamData} SSE stream items.
|
|
2851
|
+
*/
|
|
2852
|
+
stream(opts, requestOptions) {
|
|
2853
|
+
return __asyncGenerator3(this, arguments, function* stream_1() {
|
|
2854
|
+
yield __await3(yield* __asyncDelegator(__asyncValues3(this.mustGetTurn().stream(opts, requestOptions))));
|
|
2855
|
+
});
|
|
2856
|
+
}
|
|
2857
|
+
/**
|
|
2858
|
+
* Refetch from the server, update state in-place and return self.
|
|
2859
|
+
*
|
|
2860
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2861
|
+
* @returns {this} This prepared turn with updated state.
|
|
2862
|
+
*/
|
|
2863
|
+
refresh(requestOptions) {
|
|
2864
|
+
return __awaiter4(this, void 0, void 0, function* () {
|
|
2865
|
+
yield this.mustGetTurn().refresh(requestOptions);
|
|
2866
|
+
return this;
|
|
2867
|
+
});
|
|
2868
|
+
}
|
|
2869
|
+
/**
|
|
2870
|
+
* Poll getTurn until terminal.
|
|
2871
|
+
*
|
|
2872
|
+
* @param opts.pollIntervalMs - Poll interval ms while waiting. Minimum 3000.
|
|
2873
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2874
|
+
* @returns {TrueFoundryGatewayApi.TurnState} Terminal turn state.
|
|
2875
|
+
*/
|
|
2876
|
+
waitForCompletion(opts, requestOptions) {
|
|
2877
|
+
return __awaiter4(this, void 0, void 0, function* () {
|
|
2878
|
+
return this.mustGetTurn().waitForCompletion(opts, requestOptions);
|
|
2879
|
+
});
|
|
2880
|
+
}
|
|
2881
|
+
/**
|
|
2882
|
+
* Cancel the running last turn for the session.
|
|
2883
|
+
*
|
|
2884
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2885
|
+
* @returns {void}
|
|
2886
|
+
*/
|
|
2887
|
+
cancel(requestOptions) {
|
|
2888
|
+
return __awaiter4(this, void 0, void 0, function* () {
|
|
2889
|
+
return this.mustGetTurn().cancel(requestOptions);
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
/**
|
|
2893
|
+
* Paginated turn events; use `stream()` for live SSE.
|
|
2894
|
+
*
|
|
2895
|
+
* @param opts.pageToken - Token from the previous response nextPageToken.
|
|
2896
|
+
* @param opts.limit - Page size. Default 25.
|
|
2897
|
+
* @param opts.order - Sort by creation time. Default `asc`.
|
|
2898
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
2899
|
+
* @returns {Promise<core.Page<TrueFoundryGatewayApi.TurnEvent, TrueFoundryGatewayApi.ListEventsResponse>>} Paginated turn events.
|
|
2900
|
+
*/
|
|
2901
|
+
listEvents(opts, requestOptions) {
|
|
2902
|
+
return this.mustGetTurn().listEvents(opts, requestOptions);
|
|
2903
|
+
}
|
|
2904
|
+
// execute(stream:true) path: consume the already-open createTurn SSE (#start), adopting the inner Turn on turn.created.
|
|
2905
|
+
runStreaming() {
|
|
2906
|
+
return __asyncGenerator3(this, arguments, function* runStreaming_1() {
|
|
2907
|
+
yield __await3(yield* __asyncDelegator(__asyncValues3(this.consumeStream(yield __await3(__classPrivateFieldGet2(this, _PreparedTurn_start, "f"))))));
|
|
2908
|
+
});
|
|
2909
|
+
}
|
|
2910
|
+
// execute(stream:false) path: drive the open createTurn SSE until turn.created mints the inner Turn, then poll to terminal.
|
|
2911
|
+
startAndWait(pollIntervalMs, requestOptions) {
|
|
2912
|
+
return __awaiter4(this, void 0, void 0, function* () {
|
|
2913
|
+
const turn = yield this.createTurnIfNotExist();
|
|
2914
|
+
return turn.waitForCompletion({ pollIntervalMs }, requestOptions);
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
// Consume an SSE stream, adopting the inner Turn from the first turn.created and yielding all events.
|
|
2918
|
+
// Isolated so a future reconnect wrapper can re-open the stream (subscribeToTurn) on disconnect.
|
|
2919
|
+
// NOTE: reconnect/resume is out of current scope.
|
|
2920
|
+
consumeStream(sse) {
|
|
2921
|
+
return __asyncGenerator3(this, arguments, function* consumeStream_1() {
|
|
2922
|
+
var _a, e_1, _b, _c;
|
|
2923
|
+
try {
|
|
2924
|
+
for (var _d = true, _e = __asyncValues3(sse.withMetadata()), _f; _f = yield __await3(_e.next()), _a = _f.done, !_a; _d = true) {
|
|
2925
|
+
_c = _f.value;
|
|
2926
|
+
_d = false;
|
|
2927
|
+
const { data: event, id } = _c;
|
|
2928
|
+
if (event.type === "turn.created" && __classPrivateFieldGet2(this, _PreparedTurn_turn, "f") == null)
|
|
2929
|
+
this.adoptTurn(event);
|
|
2930
|
+
else if (__classPrivateFieldGet2(this, _PreparedTurn_turn, "f") != null && event.type === "turn.done")
|
|
2931
|
+
this.replaceTurnState(event.state);
|
|
2932
|
+
yield yield __await3({ sequenceNumber: parseSequenceNumber(id), event });
|
|
2933
|
+
}
|
|
2934
|
+
} catch (e_1_1) {
|
|
2935
|
+
e_1 = { error: e_1_1 };
|
|
2936
|
+
} finally {
|
|
2937
|
+
try {
|
|
2938
|
+
if (!_d && !_a && (_b = _e.return)) yield __await3(_b.call(_e));
|
|
2939
|
+
} finally {
|
|
2940
|
+
if (e_1) throw e_1.error;
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
});
|
|
2944
|
+
}
|
|
2945
|
+
// Returns the inner Turn or throws if execute() has not started it yet.
|
|
2946
|
+
mustGetTurn() {
|
|
2947
|
+
if (__classPrivateFieldGet2(this, _PreparedTurn_turn, "f") == null) {
|
|
2948
|
+
throw new Error("Turn not started yet; call execute() first.");
|
|
2949
|
+
}
|
|
2950
|
+
return __classPrivateFieldGet2(this, _PreparedTurn_turn, "f");
|
|
2951
|
+
}
|
|
2952
|
+
// Drive the in-flight createTurn SSE (#start) only until the first turn.created has built the inner
|
|
2953
|
+
// Turn, then break (which closes the underlying SSE via the generator's return()). Returns the Turn.
|
|
2954
|
+
createTurnIfNotExist() {
|
|
2955
|
+
return __awaiter4(this, void 0, void 0, function* () {
|
|
2956
|
+
var _a, e_2, _b, _c;
|
|
2957
|
+
if (__classPrivateFieldGet2(this, _PreparedTurn_turn, "f") == null) {
|
|
2958
|
+
try {
|
|
2959
|
+
for (var _d = true, _e = __asyncValues3(this.consumeStream(yield __classPrivateFieldGet2(this, _PreparedTurn_start, "f"))), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
|
|
2960
|
+
_c = _f.value;
|
|
2961
|
+
_d = false;
|
|
2962
|
+
const _event = _c;
|
|
2963
|
+
if (__classPrivateFieldGet2(this, _PreparedTurn_turn, "f") != null)
|
|
2964
|
+
break;
|
|
2965
|
+
}
|
|
2966
|
+
} catch (e_2_1) {
|
|
2967
|
+
e_2 = { error: e_2_1 };
|
|
2968
|
+
} finally {
|
|
2969
|
+
try {
|
|
2970
|
+
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
2971
|
+
} finally {
|
|
2972
|
+
if (e_2) throw e_2.error;
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
return this.mustGetTurn();
|
|
2977
|
+
});
|
|
2978
|
+
}
|
|
2979
|
+
// Open the createTurn SSE with the pending input/previousTurnId. Called synchronously by execute()
|
|
2980
|
+
// so the POST is in flight (and #start latched) before execute returns.
|
|
2981
|
+
openCreateTurn(requestOptions) {
|
|
2982
|
+
return __classPrivateFieldGet2(this, _PreparedTurn_client, "f").agents.sessions.createTurn(this.sessionId, { input: __classPrivateFieldGet2(this, _PreparedTurn_input, "f"), previousTurnId: __classPrivateFieldGet2(this, _PreparedTurn_previousTurnIdInput, "f") }, requestOptions);
|
|
2983
|
+
}
|
|
2984
|
+
// Build the inner Turn directly from the turn.created event (no extra getTurn round trip).
|
|
2985
|
+
// The TurnCreatedEvent member of the TurnStreamingEvent union carries everything Turn needs.
|
|
2986
|
+
// input comes from the request we sent (this.#input), not the event.
|
|
2987
|
+
adoptTurn(event) {
|
|
2988
|
+
__classPrivateFieldSet2(this, _PreparedTurn_turn, new Turn({
|
|
2989
|
+
id: event.turnId,
|
|
2990
|
+
sessionId: this.sessionId,
|
|
2991
|
+
previousTurnId: event.previousTurnId,
|
|
2992
|
+
input: __classPrivateFieldGet2(this, _PreparedTurn_input, "f"),
|
|
2993
|
+
state: event.state,
|
|
2994
|
+
createdBySubject: event.createdBy,
|
|
2995
|
+
createdAt: event.createdAt
|
|
2996
|
+
}, this.session, __classPrivateFieldGet2(this, _PreparedTurn_client, "f")), "f");
|
|
2997
|
+
}
|
|
2998
|
+
// Replace the inner Turn with a fresh one carrying the new state. State changes are rare, so
|
|
2999
|
+
// rebuilding via Turn's own constructor (rather than mutating it) keeps Turn the source of truth.
|
|
3000
|
+
replaceTurnState(state) {
|
|
3001
|
+
const turn = this.mustGetTurn();
|
|
3002
|
+
__classPrivateFieldSet2(this, _PreparedTurn_turn, new Turn({
|
|
3003
|
+
id: turn.id,
|
|
3004
|
+
sessionId: turn.sessionId,
|
|
3005
|
+
previousTurnId: turn.previousTurnId,
|
|
3006
|
+
input: turn.input,
|
|
3007
|
+
state,
|
|
3008
|
+
createdBySubject: turn.createdBySubject,
|
|
3009
|
+
createdAt: turn.createdAt
|
|
3010
|
+
}, this.session, __classPrivateFieldGet2(this, _PreparedTurn_client, "f")), "f");
|
|
3011
|
+
}
|
|
3012
|
+
};
|
|
3013
|
+
_PreparedTurn_client = /* @__PURE__ */ new WeakMap(), _PreparedTurn_input = /* @__PURE__ */ new WeakMap(), _PreparedTurn_previousTurnIdInput = /* @__PURE__ */ new WeakMap(), _PreparedTurn_start = /* @__PURE__ */ new WeakMap(), _PreparedTurn_turn = /* @__PURE__ */ new WeakMap();
|
|
3014
|
+
|
|
3015
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.2.0/node_modules/truefoundry-gateway-sdk/dist/esm/agents/AgentSession.mjs
|
|
3016
|
+
var __awaiter5 = function(thisArg, _arguments, P, generator) {
|
|
3017
|
+
function adopt(value) {
|
|
3018
|
+
return value instanceof P ? value : new P(function(resolve) {
|
|
3019
|
+
resolve(value);
|
|
3020
|
+
});
|
|
3021
|
+
}
|
|
3022
|
+
return new (P || (P = Promise))(function(resolve, reject) {
|
|
3023
|
+
function fulfilled(value) {
|
|
3024
|
+
try {
|
|
3025
|
+
step(generator.next(value));
|
|
3026
|
+
} catch (e) {
|
|
3027
|
+
reject(e);
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
function rejected(value) {
|
|
3031
|
+
try {
|
|
3032
|
+
step(generator["throw"](value));
|
|
3033
|
+
} catch (e) {
|
|
3034
|
+
reject(e);
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
function step(result) {
|
|
3038
|
+
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
3039
|
+
}
|
|
3040
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
3041
|
+
});
|
|
3042
|
+
};
|
|
3043
|
+
var __classPrivateFieldSet3 = function(receiver, state, value, kind, f) {
|
|
3044
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3045
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
3046
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
3047
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
3048
|
+
};
|
|
3049
|
+
var __classPrivateFieldGet3 = function(receiver, state, kind, f) {
|
|
3050
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3051
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
3052
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
3053
|
+
};
|
|
3054
|
+
var _AgentSession_client;
|
|
3055
|
+
var AgentSession = class {
|
|
3056
|
+
constructor(session, client) {
|
|
3057
|
+
_AgentSession_client.set(this, void 0);
|
|
3058
|
+
this.id = session.id;
|
|
3059
|
+
this.agentName = session.agentName;
|
|
3060
|
+
this.title = session.title;
|
|
3061
|
+
this.createdBySubject = session.createdBySubject;
|
|
3062
|
+
this.createdAt = session.createdAt;
|
|
3063
|
+
this.updatedAt = session.updatedAt;
|
|
3064
|
+
__classPrivateFieldSet3(this, _AgentSession_client, client, "f");
|
|
3065
|
+
}
|
|
3066
|
+
/**
|
|
3067
|
+
* Stage a turn locally; call `execute()` to start `createTurn`.
|
|
3068
|
+
*
|
|
3069
|
+
* @param opts.input - Turn input items passed to createTurn.
|
|
3070
|
+
* @param opts.previousTurnId - Previous turn to chain from. Default `auto`.
|
|
3071
|
+
* @returns {PreparedTurn} Staged turn.
|
|
3072
|
+
*/
|
|
3073
|
+
prepareTurn(opts) {
|
|
3074
|
+
return new PreparedTurn({ input: opts === null || opts === void 0 ? void 0 : opts.input, previousTurnId: opts === null || opts === void 0 ? void 0 : opts.previousTurnId }, this, __classPrivateFieldGet3(this, _AgentSession_client, "f"));
|
|
3075
|
+
}
|
|
3076
|
+
/**
|
|
3077
|
+
* List turns in this session.
|
|
3078
|
+
*
|
|
3079
|
+
* @param opts.pageToken - Token from the previous response nextPageToken.
|
|
3080
|
+
* @param opts.limit - Page size. Default 10.
|
|
3081
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
3082
|
+
* @returns {core.Page<Turn, TrueFoundryGatewayApi.ListTurnsResponse>} Paginated turns.
|
|
3083
|
+
*/
|
|
3084
|
+
listTurns(opts, requestOptions) {
|
|
3085
|
+
return __awaiter5(this, void 0, void 0, function* () {
|
|
3086
|
+
const client = __classPrivateFieldGet3(this, _AgentSession_client, "f");
|
|
3087
|
+
const sessionId = this.id;
|
|
3088
|
+
const page = yield client.agents.sessions.listTurns(sessionId, opts, requestOptions);
|
|
3089
|
+
return new Page({
|
|
3090
|
+
response: page.response,
|
|
3091
|
+
rawResponse: page.rawResponse,
|
|
3092
|
+
hasNextPage: (response) => !!(response === null || response === void 0 ? void 0 : response.pagination.nextPageToken),
|
|
3093
|
+
getItems: (response) => {
|
|
3094
|
+
var _a;
|
|
3095
|
+
return ((_a = response === null || response === void 0 ? void 0 : response.data) !== null && _a !== void 0 ? _a : []).map((turn) => new Turn(turn, this, client));
|
|
3096
|
+
},
|
|
3097
|
+
loadPage: (response) => HttpResponsePromise.fromPromise(client.agents.sessions.listTurns(sessionId, Object.assign(Object.assign({}, opts), { pageToken: response === null || response === void 0 ? void 0 : response.pagination.nextPageToken }), requestOptions).then((nextPage) => ({ data: nextPage.response, rawResponse: nextPage.rawResponse })))
|
|
3098
|
+
});
|
|
3099
|
+
});
|
|
3100
|
+
}
|
|
3101
|
+
/**
|
|
3102
|
+
* Fetch a turn by ID.
|
|
3103
|
+
*
|
|
3104
|
+
* @param opts.turnId - Unique identifier of the turn to fetch.
|
|
3105
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
3106
|
+
* @returns {Turn} Turn data.
|
|
3107
|
+
*/
|
|
3108
|
+
getTurn(opts, requestOptions) {
|
|
3109
|
+
return __awaiter5(this, void 0, void 0, function* () {
|
|
3110
|
+
const response = yield __classPrivateFieldGet3(this, _AgentSession_client, "f").agents.sessions.getTurn(this.id, opts.turnId, requestOptions);
|
|
3111
|
+
return new Turn(response.data, this, __classPrivateFieldGet3(this, _AgentSession_client, "f"));
|
|
3112
|
+
});
|
|
3113
|
+
}
|
|
3114
|
+
/**
|
|
3115
|
+
* Cancel the running last turn for the session.
|
|
3116
|
+
*
|
|
3117
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
3118
|
+
* @returns {void}
|
|
3119
|
+
*/
|
|
3120
|
+
cancel(requestOptions) {
|
|
3121
|
+
return __awaiter5(this, void 0, void 0, function* () {
|
|
3122
|
+
yield __classPrivateFieldGet3(this, _AgentSession_client, "f").agents.sessions.cancel(this.id, {}, requestOptions);
|
|
3123
|
+
});
|
|
3124
|
+
}
|
|
3125
|
+
};
|
|
3126
|
+
_AgentSession_client = /* @__PURE__ */ new WeakMap();
|
|
3127
|
+
|
|
3128
|
+
// src/bindDraftAgentSession.ts
|
|
3129
|
+
var inflightByDraftId = /* @__PURE__ */ new Map();
|
|
3130
|
+
function getGatewayFromSessionClient(client) {
|
|
3131
|
+
const internal = client;
|
|
3132
|
+
if (internal.client == null) {
|
|
3133
|
+
throw new Error("AgentSessionClient is missing an internal gateway client.");
|
|
3134
|
+
}
|
|
3135
|
+
return internal.client;
|
|
3136
|
+
}
|
|
3137
|
+
function draftToSessionRecord(draft) {
|
|
3138
|
+
return {
|
|
3139
|
+
id: draft.id,
|
|
3140
|
+
agentName: draft.agentName ?? "",
|
|
3141
|
+
title: draft.title,
|
|
3142
|
+
createdBySubject: draft.createdBySubject,
|
|
3143
|
+
createdAt: draft.createdAt,
|
|
3144
|
+
updatedAt: draft.updatedAt
|
|
3145
|
+
};
|
|
3146
|
+
}
|
|
3147
|
+
async function bindDraftAgentSession(client, gateway, draftSessionId) {
|
|
3148
|
+
let inflight = inflightByDraftId.get(draftSessionId);
|
|
3149
|
+
if (inflight == null) {
|
|
3150
|
+
inflight = (async () => {
|
|
3151
|
+
const response = await gateway.agents.private.draftSessions.get(draftSessionId);
|
|
3152
|
+
return new AgentSession(
|
|
3153
|
+
draftToSessionRecord(response.data),
|
|
3154
|
+
getGatewayFromSessionClient(client)
|
|
3155
|
+
);
|
|
3156
|
+
})().finally(() => {
|
|
3157
|
+
if (inflightByDraftId.get(draftSessionId) === inflight) {
|
|
3158
|
+
inflightByDraftId.delete(draftSessionId);
|
|
3159
|
+
}
|
|
3160
|
+
});
|
|
3161
|
+
inflightByDraftId.set(draftSessionId, inflight);
|
|
3162
|
+
}
|
|
3163
|
+
return inflight;
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3166
|
+
// src/sessions.ts
|
|
3167
|
+
var inflightBySessionId = /* @__PURE__ */ new Map();
|
|
3168
|
+
function getSession(client, sessionId, options) {
|
|
3169
|
+
if (options?.draftGateway != null) {
|
|
3170
|
+
return bindDraftAgentSession(client, options.draftGateway, sessionId);
|
|
3171
|
+
}
|
|
3172
|
+
let inflight = inflightBySessionId.get(sessionId);
|
|
3173
|
+
if (inflight == null) {
|
|
3174
|
+
inflight = client.getSession({ sessionId }).finally(() => {
|
|
3175
|
+
if (inflightBySessionId.get(sessionId) === inflight) {
|
|
3176
|
+
inflightBySessionId.delete(sessionId);
|
|
3177
|
+
}
|
|
3178
|
+
});
|
|
3179
|
+
inflightBySessionId.set(sessionId, inflight);
|
|
3180
|
+
}
|
|
3181
|
+
return inflight;
|
|
3182
|
+
}
|
|
3183
|
+
|
|
3184
|
+
// src/truefoundryThreadListAdapter.ts
|
|
3185
|
+
var THREAD_LIST_PAGE_SIZE2 = 20;
|
|
3186
|
+
function createTrueFoundryThreadListAdapter(options) {
|
|
3187
|
+
const { client, agentName } = options;
|
|
3188
|
+
return {
|
|
3189
|
+
async list({ after } = {}) {
|
|
3190
|
+
const page = await client.listSessions({
|
|
3191
|
+
agentName,
|
|
3192
|
+
limit: THREAD_LIST_PAGE_SIZE2,
|
|
3193
|
+
pageToken: after,
|
|
3194
|
+
startTimestamp: sessionListStartTimestamp()
|
|
3195
|
+
});
|
|
3196
|
+
const threads = page.data.map((session) => ({
|
|
3197
|
+
status: "regular",
|
|
3198
|
+
remoteId: session.id,
|
|
3199
|
+
title: session.title,
|
|
3200
|
+
lastMessageAt: new Date(session.updatedAt)
|
|
3201
|
+
}));
|
|
3202
|
+
return {
|
|
3203
|
+
threads,
|
|
3204
|
+
nextCursor: page.response.pagination.nextPageToken ?? void 0
|
|
3205
|
+
};
|
|
3206
|
+
},
|
|
3207
|
+
async initialize(_threadId) {
|
|
3208
|
+
const session = await client.createSession({ agentName });
|
|
3209
|
+
return { remoteId: session.id, externalId: void 0 };
|
|
3210
|
+
},
|
|
3211
|
+
async fetch(remoteId) {
|
|
3212
|
+
const session = await getSession(client, remoteId);
|
|
3213
|
+
return {
|
|
3214
|
+
status: "regular",
|
|
3215
|
+
remoteId: session.id,
|
|
3216
|
+
title: session.title,
|
|
3217
|
+
lastMessageAt: new Date(session.updatedAt)
|
|
3218
|
+
};
|
|
3219
|
+
},
|
|
3220
|
+
async rename() {
|
|
3221
|
+
},
|
|
3222
|
+
async archive() {
|
|
3223
|
+
},
|
|
3224
|
+
async unarchive() {
|
|
3225
|
+
},
|
|
3226
|
+
async delete() {
|
|
3227
|
+
},
|
|
3228
|
+
async generateTitle() {
|
|
3229
|
+
return new ReadableStream();
|
|
3230
|
+
}
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
// src/types.ts
|
|
3235
|
+
function resolveTrueFoundryAgentConfig(options) {
|
|
3236
|
+
if (options.agent != null) {
|
|
3237
|
+
if (options.agent.mode === "named" && options.agentName != null) {
|
|
3238
|
+
return { mode: "named", agentName: options.agentName };
|
|
3239
|
+
}
|
|
3240
|
+
return options.agent;
|
|
3241
|
+
}
|
|
3242
|
+
if (options.agentName != null) {
|
|
3243
|
+
return { mode: "named", agentName: options.agentName };
|
|
3244
|
+
}
|
|
3245
|
+
throw new Error(
|
|
3246
|
+
"useTrueFoundryAgentRuntime requires `agent` or legacy `agentName`."
|
|
3247
|
+
);
|
|
3248
|
+
}
|
|
3249
|
+
function resolveTrueFoundryAgentRuntimeOptions(options) {
|
|
3250
|
+
const agent = resolveTrueFoundryAgentConfig(options);
|
|
3251
|
+
if (agent.mode === "draft" && options.gateway == null) {
|
|
3252
|
+
throw new Error(
|
|
3253
|
+
"Draft agent mode requires a `gateway` TrueFoundryGateway client."
|
|
3254
|
+
);
|
|
3255
|
+
}
|
|
3256
|
+
return {
|
|
3257
|
+
...options,
|
|
3258
|
+
agent,
|
|
3259
|
+
gateway: options.gateway
|
|
3260
|
+
};
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
// src/useDraftAgentSpec.ts
|
|
3264
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3265
|
+
var SPEC_SYNC_DEBOUNCE_MS = 400;
|
|
3266
|
+
function useDraftAgentSpec({
|
|
3267
|
+
draftSessionId,
|
|
3268
|
+
draftBridge,
|
|
3269
|
+
defaultAgentSpec,
|
|
3270
|
+
onAgentSpecChange,
|
|
3271
|
+
onError
|
|
3272
|
+
}) {
|
|
3273
|
+
const enabled = draftBridge != null;
|
|
3274
|
+
const [agentSpec, setAgentSpec] = useState(defaultAgentSpec);
|
|
3275
|
+
const [isSpecSyncing, setIsSpecSyncing] = useState(false);
|
|
3276
|
+
const [specError, setSpecError] = useState(null);
|
|
3277
|
+
const agentSpecRef = useRef(agentSpec);
|
|
3278
|
+
agentSpecRef.current = agentSpec;
|
|
3279
|
+
const syncTimeoutRef = useRef(void 0);
|
|
3280
|
+
const syncGenerationRef = useRef(0);
|
|
3281
|
+
const loadedDraftIdRef = useRef(void 0);
|
|
3282
|
+
const localDirtyRef = useRef(false);
|
|
3283
|
+
useEffect(() => {
|
|
3284
|
+
if (!enabled || draftBridge == null) {
|
|
3285
|
+
return;
|
|
3286
|
+
}
|
|
3287
|
+
if (draftSessionId == null) {
|
|
3288
|
+
loadedDraftIdRef.current = void 0;
|
|
3289
|
+
setAgentSpec(defaultAgentSpec);
|
|
3290
|
+
localDirtyRef.current = false;
|
|
3291
|
+
setSpecError(null);
|
|
3292
|
+
return;
|
|
3293
|
+
}
|
|
3294
|
+
if (loadedDraftIdRef.current === draftSessionId) {
|
|
3295
|
+
return;
|
|
3296
|
+
}
|
|
3297
|
+
let cancelled = false;
|
|
3298
|
+
void (async () => {
|
|
3299
|
+
try {
|
|
3300
|
+
const loaded = await draftBridge.getDraftAgentSpec(draftSessionId);
|
|
3301
|
+
if (cancelled) {
|
|
3302
|
+
return;
|
|
3303
|
+
}
|
|
3304
|
+
loadedDraftIdRef.current = draftSessionId;
|
|
3305
|
+
if (localDirtyRef.current) {
|
|
3306
|
+
scheduleSpecSyncRef.current?.(draftSessionId, agentSpecRef.current);
|
|
3307
|
+
localDirtyRef.current = false;
|
|
3308
|
+
setSpecError(null);
|
|
3309
|
+
return;
|
|
3310
|
+
}
|
|
3311
|
+
setAgentSpec(loaded);
|
|
3312
|
+
setSpecError(null);
|
|
3313
|
+
} catch (error) {
|
|
3314
|
+
if (!cancelled) {
|
|
3315
|
+
onError?.(error);
|
|
3316
|
+
setSpecError(error);
|
|
3317
|
+
}
|
|
3318
|
+
}
|
|
3319
|
+
})();
|
|
3320
|
+
return () => {
|
|
3321
|
+
cancelled = true;
|
|
3322
|
+
};
|
|
3323
|
+
}, [defaultAgentSpec, draftBridge, draftSessionId, enabled, onError]);
|
|
3324
|
+
const flushSpecSync = useCallback(
|
|
3325
|
+
async (draftId, spec, generation) => {
|
|
3326
|
+
if (draftBridge == null) {
|
|
3327
|
+
return;
|
|
3328
|
+
}
|
|
3329
|
+
setIsSpecSyncing(true);
|
|
3330
|
+
try {
|
|
3331
|
+
await draftBridge.syncAgentSpec(draftId, spec);
|
|
3332
|
+
if (generation !== syncGenerationRef.current) {
|
|
3333
|
+
return;
|
|
3334
|
+
}
|
|
3335
|
+
setSpecError(null);
|
|
3336
|
+
onAgentSpecChange?.(spec);
|
|
3337
|
+
} catch (error) {
|
|
3338
|
+
if (generation === syncGenerationRef.current) {
|
|
3339
|
+
setSpecError(error);
|
|
3340
|
+
onError?.(error);
|
|
3341
|
+
}
|
|
3342
|
+
} finally {
|
|
3343
|
+
if (generation === syncGenerationRef.current) {
|
|
3344
|
+
setIsSpecSyncing(false);
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
},
|
|
3348
|
+
[draftBridge, onAgentSpecChange, onError]
|
|
3349
|
+
);
|
|
3350
|
+
const scheduleSpecSync = useCallback(
|
|
3351
|
+
(draftId, spec) => {
|
|
3352
|
+
if (syncTimeoutRef.current != null) {
|
|
3353
|
+
clearTimeout(syncTimeoutRef.current);
|
|
3354
|
+
}
|
|
3355
|
+
const generation = ++syncGenerationRef.current;
|
|
3356
|
+
syncTimeoutRef.current = setTimeout(() => {
|
|
3357
|
+
void flushSpecSync(draftId, spec, generation);
|
|
3358
|
+
}, SPEC_SYNC_DEBOUNCE_MS);
|
|
3359
|
+
},
|
|
3360
|
+
[flushSpecSync]
|
|
3361
|
+
);
|
|
3362
|
+
const scheduleSpecSyncRef = useRef(scheduleSpecSync);
|
|
3363
|
+
scheduleSpecSyncRef.current = scheduleSpecSync;
|
|
3364
|
+
useEffect(
|
|
3365
|
+
() => () => {
|
|
3366
|
+
if (syncTimeoutRef.current != null) {
|
|
3367
|
+
clearTimeout(syncTimeoutRef.current);
|
|
3368
|
+
}
|
|
3369
|
+
},
|
|
3370
|
+
[]
|
|
3371
|
+
);
|
|
3372
|
+
const updateAgentSpec = useCallback(
|
|
3373
|
+
(update) => {
|
|
3374
|
+
if (!enabled || draftBridge == null) {
|
|
3375
|
+
return;
|
|
3376
|
+
}
|
|
3377
|
+
const next = mergeAgentSpec(agentSpecRef.current, update);
|
|
3378
|
+
setAgentSpec(next);
|
|
3379
|
+
localDirtyRef.current = true;
|
|
3380
|
+
if (draftSessionId != null) {
|
|
3381
|
+
scheduleSpecSync(draftSessionId, next);
|
|
3382
|
+
}
|
|
3383
|
+
},
|
|
3384
|
+
[draftBridge, draftSessionId, enabled, scheduleSpecSync]
|
|
3385
|
+
);
|
|
3386
|
+
return useMemo(
|
|
3387
|
+
() => ({
|
|
3388
|
+
agentSpec: enabled ? agentSpec : null,
|
|
3389
|
+
draftSessionId: enabled ? draftSessionId : void 0,
|
|
3390
|
+
isSpecSyncing: enabled ? isSpecSyncing : false,
|
|
3391
|
+
specError: enabled ? specError : null,
|
|
3392
|
+
updateAgentSpec
|
|
3393
|
+
}),
|
|
3394
|
+
[
|
|
3395
|
+
agentSpec,
|
|
3396
|
+
draftSessionId,
|
|
3397
|
+
enabled,
|
|
3398
|
+
isSpecSyncing,
|
|
3399
|
+
specError,
|
|
3400
|
+
updateAgentSpec
|
|
3401
|
+
]
|
|
3402
|
+
);
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
// src/useTrueFoundryAgentMessages.ts
|
|
3406
|
+
import { generateId } from "@assistant-ui/core";
|
|
3407
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
3408
|
+
|
|
3409
|
+
// src/loadSessionSnapshot.ts
|
|
3410
|
+
var inflightBySessionId2 = /* @__PURE__ */ new Map();
|
|
3411
|
+
function loadSessionSnapshot(client, sessionId, concurrency, sessionOptions) {
|
|
3412
|
+
const cacheKey = sessionOptions?.draftGateway != null ? `draft:${sessionId}` : sessionId;
|
|
3413
|
+
let inflight = inflightBySessionId2.get(cacheKey);
|
|
3414
|
+
if (inflight == null) {
|
|
3415
|
+
inflight = getSession(client, sessionId, sessionOptions).then((session) => buildSnapshotFromSession(session, concurrency)).finally(() => {
|
|
3416
|
+
if (inflightBySessionId2.get(cacheKey) === inflight) {
|
|
3417
|
+
inflightBySessionId2.delete(cacheKey);
|
|
3418
|
+
}
|
|
3419
|
+
});
|
|
3420
|
+
inflightBySessionId2.set(cacheKey, inflight);
|
|
3421
|
+
}
|
|
3422
|
+
return inflight;
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
// src/requiredActionInputs.ts
|
|
3426
|
+
function messageHasPendingRequiredActions(message) {
|
|
3427
|
+
return messageHasPendingApprovals(message) || messageHasPendingResponses(message);
|
|
3428
|
+
}
|
|
3429
|
+
function collectRequiredActionInputs(message, defaultThreadId = ROOT_THREAD_ID) {
|
|
3430
|
+
if (messageHasPendingRequiredActions(message)) {
|
|
3431
|
+
return [];
|
|
3432
|
+
}
|
|
3433
|
+
return [
|
|
3434
|
+
...collectApprovalInputs(message, defaultThreadId),
|
|
3435
|
+
...collectResponseInputs(message, defaultThreadId)
|
|
3436
|
+
];
|
|
3437
|
+
}
|
|
3438
|
+
function findPausedAssistantMessage(messages) {
|
|
3439
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
3440
|
+
const candidate = messages[i];
|
|
3441
|
+
if (candidate?.role === "assistant" && candidate.status?.type === "requires-action") {
|
|
3442
|
+
return candidate;
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
return void 0;
|
|
3446
|
+
}
|
|
3447
|
+
|
|
3448
|
+
// src/streamTurn.ts
|
|
3449
|
+
import "truefoundry-gateway-sdk/agents";
|
|
3450
|
+
function buildTurnInput(options) {
|
|
3451
|
+
if (options.inputs != null) {
|
|
3452
|
+
return options.inputs;
|
|
3453
|
+
}
|
|
3454
|
+
if (options.resumeMcpAuth === true) {
|
|
3455
|
+
return [];
|
|
3456
|
+
}
|
|
3457
|
+
return [{ type: "user.message", content: options.userMessage ?? "" }];
|
|
3458
|
+
}
|
|
3459
|
+
function bindAbort(session, abortSignal) {
|
|
3460
|
+
const onAbort = () => {
|
|
3461
|
+
void session.cancel().catch(() => void 0);
|
|
3462
|
+
};
|
|
3463
|
+
if (abortSignal.aborted) {
|
|
3464
|
+
onAbort();
|
|
3465
|
+
return onAbort;
|
|
3466
|
+
}
|
|
3467
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
3468
|
+
return onAbort;
|
|
3469
|
+
}
|
|
3470
|
+
async function* streamTurnContent(session, foldState, options, abortSignal, groupRootBaseline) {
|
|
3471
|
+
const previousTurnId = options.previousTurnId === null ? void 0 : options.previousTurnId ?? "auto";
|
|
3472
|
+
const turn = session.prepareTurn({
|
|
3473
|
+
input: buildTurnInput(options),
|
|
3474
|
+
...previousTurnId != null ? { previousTurnId } : {}
|
|
3475
|
+
});
|
|
3476
|
+
const onAbort = bindAbort(session, abortSignal);
|
|
3477
|
+
if (abortSignal.aborted) {
|
|
3478
|
+
return;
|
|
3479
|
+
}
|
|
3480
|
+
try {
|
|
3481
|
+
yield* streamTurnEvents(
|
|
3482
|
+
turn.execute({ stream: true }, { abortSignal }),
|
|
3483
|
+
foldState,
|
|
3484
|
+
groupRootBaseline
|
|
3485
|
+
);
|
|
3486
|
+
} catch (error) {
|
|
3487
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3488
|
+
return;
|
|
3489
|
+
}
|
|
3490
|
+
throw error;
|
|
3491
|
+
} finally {
|
|
3492
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
async function* resumeTurnStream(turn, foldState, abortSignal, afterSequenceNumber, groupRootBaseline) {
|
|
3496
|
+
const onAbort = () => {
|
|
3497
|
+
void turn.session.cancel().catch(() => void 0);
|
|
3498
|
+
};
|
|
3499
|
+
if (abortSignal.aborted) {
|
|
3500
|
+
onAbort();
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
3504
|
+
try {
|
|
3505
|
+
yield* streamTurnEvents(
|
|
3506
|
+
turn.stream(
|
|
3507
|
+
afterSequenceNumber != null ? { afterSequenceNumber } : {},
|
|
3508
|
+
{ abortSignal }
|
|
3509
|
+
),
|
|
3510
|
+
foldState,
|
|
3511
|
+
groupRootBaseline
|
|
3512
|
+
);
|
|
3513
|
+
} catch (error) {
|
|
3514
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3515
|
+
return;
|
|
3516
|
+
}
|
|
3517
|
+
throw error;
|
|
3518
|
+
} finally {
|
|
3519
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
// src/useTrueFoundryAgentMessages.ts
|
|
3524
|
+
function buildCompletedTurnState(completedAt, requiredActions = []) {
|
|
3525
|
+
return {
|
|
3526
|
+
status: "done",
|
|
3527
|
+
requiredActions,
|
|
3528
|
+
completedAt
|
|
3529
|
+
};
|
|
3530
|
+
}
|
|
3531
|
+
function requiredActionsFromActiveUpdate(update) {
|
|
3532
|
+
const custom = update.metadata?.custom;
|
|
3533
|
+
const requiredActions = [];
|
|
3534
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3535
|
+
if (custom?.pendingMcpAuth === true && Array.isArray(custom.mcpServers)) {
|
|
3536
|
+
const mcpAuthRequired = {
|
|
3537
|
+
type: "mcp.auth_required",
|
|
3538
|
+
id: generateId(),
|
|
3539
|
+
createdAt,
|
|
3540
|
+
mcpServers: custom.mcpServers
|
|
3541
|
+
};
|
|
3542
|
+
requiredActions.push(mcpAuthRequired);
|
|
3543
|
+
}
|
|
3544
|
+
if (update.status?.type === "requires-action") {
|
|
3545
|
+
const approvalThreadId = custom?.[TOOL_APPROVAL_THREAD_ID_CUSTOM_KEY];
|
|
3546
|
+
if (typeof approvalThreadId === "string") {
|
|
3547
|
+
const approvalRequired = {
|
|
3548
|
+
type: "tool.approval_required",
|
|
3549
|
+
id: generateId(),
|
|
3550
|
+
createdAt,
|
|
3551
|
+
threadId: approvalThreadId,
|
|
3552
|
+
toolCalls: []
|
|
3553
|
+
};
|
|
3554
|
+
requiredActions.push(approvalRequired);
|
|
3555
|
+
}
|
|
3556
|
+
const responseThreadId = custom?.[TOOL_RESPONSE_THREAD_ID_CUSTOM_KEY];
|
|
3557
|
+
if (typeof responseThreadId === "string") {
|
|
3558
|
+
const responseRequired = {
|
|
3559
|
+
type: "tool.response_required",
|
|
3560
|
+
id: generateId(),
|
|
3561
|
+
createdAt,
|
|
3562
|
+
threadId: responseThreadId,
|
|
3563
|
+
toolCalls: []
|
|
3564
|
+
};
|
|
3565
|
+
requiredActions.push(responseRequired);
|
|
3566
|
+
}
|
|
3567
|
+
}
|
|
3568
|
+
return requiredActions;
|
|
3569
|
+
}
|
|
3570
|
+
function buildUserTurnInput(content) {
|
|
3571
|
+
return { type: "user.message", content };
|
|
3572
|
+
}
|
|
3573
|
+
function appendTurnInputs(base, continuationInputs) {
|
|
3574
|
+
if (continuationInputs == null || continuationInputs.length === 0) {
|
|
3575
|
+
return base;
|
|
3576
|
+
}
|
|
3577
|
+
return [...base, ...continuationInputs];
|
|
3578
|
+
}
|
|
3579
|
+
function commitActiveStream(snapshot, continuationInputs) {
|
|
3580
|
+
const active = snapshot.activeStream;
|
|
3581
|
+
if (active == null || active.streamComplete !== true) {
|
|
3582
|
+
return snapshot;
|
|
3583
|
+
}
|
|
3584
|
+
const activeSandboxId = active.update.metadata?.custom?.sandboxId;
|
|
3585
|
+
const completedState = buildCompletedTurnState(
|
|
3586
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
3587
|
+
requiredActionsFromActiveUpdate(active.update)
|
|
3588
|
+
);
|
|
3589
|
+
const baseline = snapshot.groupRootBaseline ?? computeGroupRootBaseline(snapshot.turns);
|
|
3590
|
+
const rootModelMessageIds = rootModelMessageIdsSinceBaseline(
|
|
3591
|
+
snapshot.fold,
|
|
3592
|
+
baseline
|
|
3593
|
+
);
|
|
3594
|
+
const lastTurn = snapshot.turns.at(-1);
|
|
3595
|
+
if (lastTurn?.id === active.turnId) {
|
|
3596
|
+
return replaceSessionSnapshot(snapshot, {
|
|
3597
|
+
turns: snapshot.turns.map(
|
|
3598
|
+
(turn) => turn.id === active.turnId ? {
|
|
3599
|
+
...turn,
|
|
3600
|
+
state: completedState,
|
|
3601
|
+
input: appendTurnInputs(turn.input ?? [], continuationInputs),
|
|
3602
|
+
...rootModelMessageIds != null ? { rootModelMessageIds } : {},
|
|
3603
|
+
...activeSandboxId != null ? { sandboxId: activeSandboxId } : {}
|
|
3604
|
+
} : turn
|
|
3605
|
+
),
|
|
3606
|
+
pendingUser: void 0,
|
|
3607
|
+
activeStream: void 0
|
|
3608
|
+
});
|
|
3609
|
+
}
|
|
3610
|
+
const record = {
|
|
3611
|
+
id: active.turnId,
|
|
3612
|
+
createdAt: snapshot.pendingUser?.createdAt.toISOString() ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3613
|
+
state: completedState,
|
|
3614
|
+
input: appendTurnInputs(
|
|
3615
|
+
snapshot.pendingUser ? [buildUserTurnInput(snapshot.pendingUser.content)] : [],
|
|
3616
|
+
continuationInputs
|
|
3617
|
+
),
|
|
3618
|
+
...snapshot.pendingUser != null ? { userText: userMessageContentToText(snapshot.pendingUser.content) } : {},
|
|
3619
|
+
...rootModelMessageIds != null ? { rootModelMessageIds } : {},
|
|
3620
|
+
...activeSandboxId != null ? { sandboxId: activeSandboxId } : {}
|
|
3621
|
+
};
|
|
3622
|
+
return replaceSessionSnapshot(snapshot, {
|
|
3623
|
+
turns: [...snapshot.turns, record],
|
|
3624
|
+
pendingUser: void 0,
|
|
3625
|
+
activeStream: void 0
|
|
3626
|
+
});
|
|
3627
|
+
}
|
|
3628
|
+
async function resolveActiveSessionId(remoteId, resolveConversationSessionId) {
|
|
3629
|
+
if (resolveConversationSessionId != null) {
|
|
3630
|
+
return resolveConversationSessionId(remoteId);
|
|
3631
|
+
}
|
|
3632
|
+
return remoteId;
|
|
3633
|
+
}
|
|
3634
|
+
function findTurnIndex(snapshot, turnId) {
|
|
3635
|
+
const committedIndex = snapshot.turns.findIndex((turn) => turn.id === turnId);
|
|
3636
|
+
if (committedIndex !== -1) {
|
|
3637
|
+
return committedIndex;
|
|
3638
|
+
}
|
|
3639
|
+
if (snapshot.pendingUser?.turnId === turnId) {
|
|
3640
|
+
return snapshot.turns.length;
|
|
3641
|
+
}
|
|
3642
|
+
throw new Error(`Turn ${turnId} not found in session snapshot`);
|
|
3643
|
+
}
|
|
3644
|
+
function resolveTurnInput(snapshot, turnId) {
|
|
3645
|
+
const turnRecord = snapshot.turns.find((turn) => turn.id === turnId);
|
|
3646
|
+
if (turnRecord?.input != null) {
|
|
3647
|
+
return turnRecord.input;
|
|
3648
|
+
}
|
|
3649
|
+
if (snapshot.pendingUser?.turnId === turnId) {
|
|
3650
|
+
return [{ type: "user.message", content: snapshot.pendingUser.content }];
|
|
3651
|
+
}
|
|
3652
|
+
return void 0;
|
|
3653
|
+
}
|
|
3654
|
+
function useTrueFoundryAgentMessages({
|
|
3655
|
+
client,
|
|
3656
|
+
sessionId,
|
|
3657
|
+
listEventsConcurrency,
|
|
3658
|
+
onError,
|
|
3659
|
+
initializeSession,
|
|
3660
|
+
resolveConversationSessionId,
|
|
3661
|
+
draftGateway
|
|
3662
|
+
}) {
|
|
3663
|
+
const sessionOptions = useMemo2(
|
|
3664
|
+
() => draftGateway != null ? { draftGateway } : void 0,
|
|
3665
|
+
[draftGateway]
|
|
3666
|
+
);
|
|
3667
|
+
const [snapshot, setSnapshot] = useState2(createEmptySessionSnapshot);
|
|
3668
|
+
const [isRunning, setIsRunning] = useState2(false);
|
|
3669
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
3670
|
+
const snapshotRef = useRef2(snapshot);
|
|
3671
|
+
snapshotRef.current = snapshot;
|
|
3672
|
+
const createdAtByMessageIdRef = useRef2(/* @__PURE__ */ new Map());
|
|
3673
|
+
const abortControllerRef = useRef2(null);
|
|
3674
|
+
const activeRunRef = useRef2(null);
|
|
3675
|
+
const runningTurnRef = useRef2(void 0);
|
|
3676
|
+
const loadGenerationRef = useRef2(0);
|
|
3677
|
+
const lazilyCreatedSessionIdRef = useRef2(void 0);
|
|
3678
|
+
const projectOptions = useMemo2(
|
|
3679
|
+
() => ({
|
|
3680
|
+
getCreatedAt: (messageId, fallback) => {
|
|
3681
|
+
const cache = createdAtByMessageIdRef.current;
|
|
3682
|
+
const existing = cache.get(messageId);
|
|
3683
|
+
if (existing != null) {
|
|
3684
|
+
return existing;
|
|
3685
|
+
}
|
|
3686
|
+
cache.set(messageId, fallback);
|
|
3687
|
+
return fallback;
|
|
3688
|
+
}
|
|
3689
|
+
}),
|
|
3690
|
+
[]
|
|
3691
|
+
);
|
|
3692
|
+
const messages = useMemo2(
|
|
3693
|
+
() => projectSessionMessages(snapshot, projectOptions),
|
|
3694
|
+
[snapshot, projectOptions]
|
|
3695
|
+
);
|
|
3696
|
+
const applyStreamUpdate = useCallback2(
|
|
3697
|
+
(update, turnId, isContinuation) => {
|
|
3698
|
+
setSnapshot(
|
|
3699
|
+
(prev) => replaceSessionSnapshot(prev, {
|
|
3700
|
+
activeStream: {
|
|
3701
|
+
turnId,
|
|
3702
|
+
update,
|
|
3703
|
+
isContinuation
|
|
3704
|
+
}
|
|
3705
|
+
})
|
|
3706
|
+
);
|
|
3707
|
+
},
|
|
3708
|
+
[]
|
|
3709
|
+
);
|
|
3710
|
+
const runStream = useCallback2(
|
|
3711
|
+
(createStream, turnId, isContinuation) => {
|
|
3712
|
+
abortControllerRef.current?.abort();
|
|
3713
|
+
const abortController = new AbortController();
|
|
3714
|
+
abortControllerRef.current = abortController;
|
|
3715
|
+
setIsRunning(true);
|
|
3716
|
+
const run = (async () => {
|
|
3717
|
+
try {
|
|
3718
|
+
for await (const update of createStream(abortController.signal)) {
|
|
3719
|
+
if (abortController.signal.aborted) {
|
|
3720
|
+
return;
|
|
3721
|
+
}
|
|
3722
|
+
applyStreamUpdate(update, turnId, isContinuation);
|
|
3723
|
+
}
|
|
3724
|
+
} catch (error) {
|
|
3725
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3726
|
+
return;
|
|
3727
|
+
}
|
|
3728
|
+
onError?.(error);
|
|
3729
|
+
throw error;
|
|
3730
|
+
} finally {
|
|
3731
|
+
if (abortControllerRef.current === abortController) {
|
|
3732
|
+
abortControllerRef.current = null;
|
|
3733
|
+
}
|
|
3734
|
+
setIsRunning(false);
|
|
3735
|
+
setSnapshot((prev) => {
|
|
3736
|
+
if (prev.activeStream == null) {
|
|
3737
|
+
return prev;
|
|
3738
|
+
}
|
|
3739
|
+
const marked = replaceSessionSnapshot(prev, {
|
|
3740
|
+
activeStream: {
|
|
3741
|
+
...prev.activeStream,
|
|
3742
|
+
streamComplete: true
|
|
3743
|
+
},
|
|
3744
|
+
requiredActions: {
|
|
3745
|
+
approvals: /* @__PURE__ */ new Map(),
|
|
3746
|
+
toolResponses: /* @__PURE__ */ new Map()
|
|
3747
|
+
}
|
|
3748
|
+
});
|
|
3749
|
+
return commitActiveStream(marked);
|
|
3750
|
+
});
|
|
3751
|
+
}
|
|
3752
|
+
})();
|
|
3753
|
+
activeRunRef.current = run;
|
|
3754
|
+
void run.catch(() => void 0).finally(() => {
|
|
3755
|
+
if (activeRunRef.current === run) {
|
|
3756
|
+
activeRunRef.current = null;
|
|
3757
|
+
}
|
|
3758
|
+
});
|
|
3759
|
+
return run;
|
|
3760
|
+
},
|
|
3761
|
+
[applyStreamUpdate, onError]
|
|
3762
|
+
);
|
|
3763
|
+
const load = useCallback2(async () => {
|
|
3764
|
+
if (sessionId == null) {
|
|
3765
|
+
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3766
|
+
setSnapshot(createEmptySessionSnapshot());
|
|
3767
|
+
return;
|
|
3768
|
+
}
|
|
3769
|
+
if (sessionId === lazilyCreatedSessionIdRef.current) {
|
|
3770
|
+
return;
|
|
3771
|
+
}
|
|
3772
|
+
const generation = ++loadGenerationRef.current;
|
|
3773
|
+
abortControllerRef.current?.abort();
|
|
3774
|
+
setIsLoading(true);
|
|
3775
|
+
try {
|
|
3776
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
3777
|
+
sessionId,
|
|
3778
|
+
resolveConversationSessionId
|
|
3779
|
+
);
|
|
3780
|
+
const loadedSnapshot = await loadSessionSnapshot(
|
|
3781
|
+
client,
|
|
3782
|
+
conversationSessionId,
|
|
3783
|
+
listEventsConcurrency,
|
|
3784
|
+
sessionOptions
|
|
3785
|
+
);
|
|
3786
|
+
if (generation !== loadGenerationRef.current) {
|
|
3787
|
+
return;
|
|
3788
|
+
}
|
|
3789
|
+
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3790
|
+
setSnapshot(loadedSnapshot);
|
|
3791
|
+
runningTurnRef.current = loadedSnapshot.runningTurn;
|
|
3792
|
+
if (loadedSnapshot.runningTurn != null) {
|
|
3793
|
+
const turn = loadedSnapshot.runningTurn;
|
|
3794
|
+
const isContinuation = !extractTurnUserText(turn.input);
|
|
3795
|
+
await runStream(
|
|
3796
|
+
(signal) => resumeTurnStream(
|
|
3797
|
+
turn,
|
|
3798
|
+
snapshotRef.current.fold,
|
|
3799
|
+
signal,
|
|
3800
|
+
void 0,
|
|
3801
|
+
snapshotRef.current.groupRootBaseline
|
|
3802
|
+
),
|
|
3803
|
+
turn.id,
|
|
3804
|
+
isContinuation
|
|
3805
|
+
);
|
|
3806
|
+
}
|
|
3807
|
+
} catch (error) {
|
|
3808
|
+
onError?.(error);
|
|
3809
|
+
throw error;
|
|
3810
|
+
} finally {
|
|
3811
|
+
if (generation === loadGenerationRef.current) {
|
|
3812
|
+
setIsLoading(false);
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
}, [client, listEventsConcurrency, onError, resolveConversationSessionId, runStream, sessionId, sessionOptions]);
|
|
3816
|
+
useEffect2(() => {
|
|
3817
|
+
void load().catch(() => void 0);
|
|
3818
|
+
}, [load]);
|
|
3819
|
+
const sendTurn = useCallback2(
|
|
3820
|
+
async (options) => {
|
|
3821
|
+
let activeSessionId = sessionId;
|
|
3822
|
+
if (activeSessionId == null) {
|
|
3823
|
+
if (initializeSession == null) {
|
|
3824
|
+
throw new Error("Cannot send a turn without an active session.");
|
|
3825
|
+
}
|
|
3826
|
+
const { remoteId } = await initializeSession();
|
|
3827
|
+
activeSessionId = remoteId;
|
|
3828
|
+
lazilyCreatedSessionIdRef.current = remoteId;
|
|
3829
|
+
}
|
|
3830
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
3831
|
+
activeSessionId,
|
|
3832
|
+
resolveConversationSessionId
|
|
3833
|
+
);
|
|
3834
|
+
const session = await getSession(client, conversationSessionId, sessionOptions);
|
|
3835
|
+
const isContinuation = "inputs" in options || "resumeMcpAuth" in options && options.resumeMcpAuth === true;
|
|
3836
|
+
const continuationTurnId = snapshotRef.current.activeStream?.turnId;
|
|
3837
|
+
const turnId = isContinuation && continuationTurnId != null ? continuationTurnId : generateId();
|
|
3838
|
+
if ("inputs" in options) {
|
|
3839
|
+
applyUserToolResponsesToFold(
|
|
3840
|
+
snapshotRef.current.fold,
|
|
3841
|
+
options.inputs
|
|
3842
|
+
);
|
|
3843
|
+
}
|
|
3844
|
+
setSnapshot(
|
|
3845
|
+
(prev) => commitActiveStream(
|
|
3846
|
+
prev,
|
|
3847
|
+
"inputs" in options ? options.inputs : void 0
|
|
3848
|
+
)
|
|
3849
|
+
);
|
|
3850
|
+
let groupRootBaseline;
|
|
3851
|
+
if ("userMessage" in options) {
|
|
3852
|
+
const rootBucket = snapshotRef.current.fold.threads.get(ROOT_THREAD_ID);
|
|
3853
|
+
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
3854
|
+
setSnapshot(
|
|
3855
|
+
(prev) => replaceSessionSnapshot(prev, {
|
|
3856
|
+
pendingUser: {
|
|
3857
|
+
turnId,
|
|
3858
|
+
content: options.userMessage,
|
|
3859
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3860
|
+
},
|
|
3861
|
+
activeStream: void 0,
|
|
3862
|
+
groupRootBaseline
|
|
3863
|
+
})
|
|
3864
|
+
);
|
|
3865
|
+
} else {
|
|
3866
|
+
groupRootBaseline = snapshotRef.current.groupRootBaseline ?? computeGroupRootBaseline(snapshotRef.current.turns);
|
|
3867
|
+
}
|
|
3868
|
+
await runStream(
|
|
3869
|
+
(signal) => {
|
|
3870
|
+
if ("inputs" in options) {
|
|
3871
|
+
return streamTurnContent(
|
|
3872
|
+
session,
|
|
3873
|
+
snapshotRef.current.fold,
|
|
3874
|
+
{ inputs: options.inputs },
|
|
3875
|
+
signal,
|
|
3876
|
+
groupRootBaseline
|
|
3877
|
+
);
|
|
3878
|
+
}
|
|
3879
|
+
if ("resumeMcpAuth" in options) {
|
|
3880
|
+
return streamTurnContent(
|
|
3881
|
+
session,
|
|
3882
|
+
snapshotRef.current.fold,
|
|
3883
|
+
{ resumeMcpAuth: true },
|
|
3884
|
+
signal,
|
|
3885
|
+
groupRootBaseline
|
|
3886
|
+
);
|
|
3887
|
+
}
|
|
3888
|
+
return streamTurnContent(
|
|
3889
|
+
session,
|
|
3890
|
+
snapshotRef.current.fold,
|
|
3891
|
+
{
|
|
3892
|
+
userMessage: options.userMessage,
|
|
3893
|
+
...options.previousTurnId !== void 0 ? { previousTurnId: options.previousTurnId } : {}
|
|
3894
|
+
},
|
|
3895
|
+
signal,
|
|
3896
|
+
groupRootBaseline
|
|
3897
|
+
);
|
|
3898
|
+
},
|
|
3899
|
+
turnId,
|
|
3900
|
+
isContinuation
|
|
3901
|
+
);
|
|
3902
|
+
},
|
|
3903
|
+
[client, initializeSession, resolveConversationSessionId, runStream, sessionId, sessionOptions]
|
|
3904
|
+
);
|
|
3905
|
+
const cancel = useCallback2(async () => {
|
|
3906
|
+
if (sessionId == null) {
|
|
3907
|
+
abortControllerRef.current?.abort();
|
|
3908
|
+
return;
|
|
3909
|
+
}
|
|
3910
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
3911
|
+
sessionId,
|
|
3912
|
+
resolveConversationSessionId
|
|
3913
|
+
);
|
|
3914
|
+
const session = await getSession(client, conversationSessionId, sessionOptions);
|
|
3915
|
+
await session.cancel().catch(() => void 0);
|
|
3916
|
+
await activeRunRef.current?.catch(() => void 0);
|
|
3917
|
+
}, [client, resolveConversationSessionId, sessionId, sessionOptions]);
|
|
3918
|
+
const isRunningRef = useRef2(isRunning);
|
|
3919
|
+
isRunningRef.current = isRunning;
|
|
3920
|
+
const trySendCollectedRequiredActions = useCallback2(
|
|
3921
|
+
(nextSnapshot) => {
|
|
3922
|
+
if (isRunningRef.current) {
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
const projected = projectSessionMessages(nextSnapshot, projectOptions);
|
|
3926
|
+
const paused = findPausedAssistantMessage(projected);
|
|
3927
|
+
if (paused == null || messageHasPendingRequiredActions(paused)) {
|
|
3928
|
+
return;
|
|
3929
|
+
}
|
|
3930
|
+
const inputs = collectRequiredActionInputs(paused);
|
|
3931
|
+
if (inputs.length > 0) {
|
|
3932
|
+
void sendTurn({ inputs }).catch((error) => onError?.(error));
|
|
3933
|
+
}
|
|
3934
|
+
},
|
|
3935
|
+
[onError, projectOptions, sendTurn]
|
|
3936
|
+
);
|
|
3937
|
+
const respondToToolApproval = useCallback2(
|
|
3938
|
+
(response) => {
|
|
3939
|
+
const prev = snapshotRef.current;
|
|
3940
|
+
const approvals = new Map(prev.requiredActions.approvals);
|
|
3941
|
+
approvals.set(response.approvalId, {
|
|
3942
|
+
approved: response.approved,
|
|
3943
|
+
...response.reason != null ? { reason: response.reason } : {}
|
|
3944
|
+
});
|
|
3945
|
+
const nextSnapshot = replaceSessionSnapshot(prev, {
|
|
3946
|
+
requiredActions: {
|
|
3947
|
+
...prev.requiredActions,
|
|
3948
|
+
approvals
|
|
3949
|
+
}
|
|
3950
|
+
});
|
|
3951
|
+
setSnapshot(nextSnapshot);
|
|
3952
|
+
trySendCollectedRequiredActions(nextSnapshot);
|
|
3953
|
+
},
|
|
3954
|
+
[trySendCollectedRequiredActions]
|
|
3955
|
+
);
|
|
3956
|
+
const respondToToolResponse = useCallback2(
|
|
3957
|
+
(response) => {
|
|
3958
|
+
const prev = snapshotRef.current;
|
|
3959
|
+
const toolResponses = new Map(prev.requiredActions.toolResponses);
|
|
3960
|
+
toolResponses.set(response.toolCallId, { content: response.content });
|
|
3961
|
+
const nextSnapshot = replaceSessionSnapshot(prev, {
|
|
3962
|
+
requiredActions: {
|
|
3963
|
+
...prev.requiredActions,
|
|
3964
|
+
toolResponses
|
|
3965
|
+
}
|
|
3966
|
+
});
|
|
3967
|
+
setSnapshot(nextSnapshot);
|
|
3968
|
+
trySendCollectedRequiredActions(nextSnapshot);
|
|
3969
|
+
},
|
|
3970
|
+
[trySendCollectedRequiredActions]
|
|
3971
|
+
);
|
|
3972
|
+
const resumeRun = useCallback2(async () => {
|
|
3973
|
+
const turn = runningTurnRef.current;
|
|
3974
|
+
if (turn == null) {
|
|
3975
|
+
return;
|
|
3976
|
+
}
|
|
3977
|
+
await runStream(
|
|
3978
|
+
(signal) => resumeTurnStream(
|
|
3979
|
+
turn,
|
|
3980
|
+
snapshotRef.current.fold,
|
|
3981
|
+
signal,
|
|
3982
|
+
void 0,
|
|
3983
|
+
snapshotRef.current.groupRootBaseline
|
|
3984
|
+
),
|
|
3985
|
+
turn.id,
|
|
3986
|
+
true
|
|
3987
|
+
);
|
|
3988
|
+
}, [runStream]);
|
|
3989
|
+
const branchFromTurn = useCallback2(
|
|
3990
|
+
async (turnId, userMessage) => {
|
|
3991
|
+
let activeSessionId = sessionId;
|
|
3992
|
+
if (activeSessionId == null) {
|
|
3993
|
+
throw new Error("Cannot branch from a turn without an active session.");
|
|
3994
|
+
}
|
|
3995
|
+
const committed = commitActiveStream(snapshotRef.current);
|
|
3996
|
+
setSnapshot(committed);
|
|
3997
|
+
const turnIndex = findTurnIndex(committed, turnId);
|
|
3998
|
+
await cancel();
|
|
3999
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
4000
|
+
activeSessionId,
|
|
4001
|
+
resolveConversationSessionId
|
|
4002
|
+
);
|
|
4003
|
+
const session = await getSession(client, conversationSessionId, sessionOptions);
|
|
4004
|
+
const previousTurnId = await resolveGatewayBranchPreviousTurnId(
|
|
4005
|
+
session,
|
|
4006
|
+
turnIndex
|
|
4007
|
+
);
|
|
4008
|
+
const rewound = await buildSnapshotBeforeTurnIndex(
|
|
4009
|
+
session,
|
|
4010
|
+
turnIndex,
|
|
4011
|
+
listEventsConcurrency
|
|
4012
|
+
);
|
|
4013
|
+
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
4014
|
+
setSnapshot(rewound);
|
|
4015
|
+
await sendTurn({
|
|
4016
|
+
userMessage,
|
|
4017
|
+
previousTurnId
|
|
4018
|
+
});
|
|
4019
|
+
},
|
|
4020
|
+
[
|
|
4021
|
+
cancel,
|
|
4022
|
+
client,
|
|
4023
|
+
listEventsConcurrency,
|
|
4024
|
+
resolveConversationSessionId,
|
|
4025
|
+
sendTurn,
|
|
4026
|
+
sessionId,
|
|
4027
|
+
sessionOptions
|
|
4028
|
+
]
|
|
4029
|
+
);
|
|
4030
|
+
const resetFromTurn = useCallback2(
|
|
4031
|
+
async (turnId) => {
|
|
4032
|
+
const committed = commitActiveStream(snapshotRef.current);
|
|
4033
|
+
const originalInput = resolveTurnInput(committed, turnId);
|
|
4034
|
+
if (originalInput == null) {
|
|
4035
|
+
throw new Error(`Turn ${turnId} not found in session snapshot`);
|
|
4036
|
+
}
|
|
4037
|
+
const userMessage = extractTurnUserMessageContent(originalInput);
|
|
4038
|
+
await branchFromTurn(turnId, userMessage);
|
|
4039
|
+
},
|
|
4040
|
+
[branchFromTurn]
|
|
4041
|
+
);
|
|
4042
|
+
const editFromTurn = useCallback2(
|
|
4043
|
+
async (turnId, editedText) => {
|
|
4044
|
+
const committed = commitActiveStream(snapshotRef.current);
|
|
4045
|
+
const originalInput = resolveTurnInput(committed, turnId);
|
|
4046
|
+
if (originalInput == null) {
|
|
4047
|
+
throw new Error(`Turn ${turnId} not found in session snapshot`);
|
|
4048
|
+
}
|
|
4049
|
+
const userMessage = buildEditedUserMessageContent(
|
|
4050
|
+
editedText,
|
|
4051
|
+
originalInput
|
|
4052
|
+
);
|
|
4053
|
+
await branchFromTurn(turnId, userMessage);
|
|
4054
|
+
},
|
|
4055
|
+
[branchFromTurn]
|
|
4056
|
+
);
|
|
4057
|
+
return {
|
|
4058
|
+
messages,
|
|
4059
|
+
isRunning,
|
|
4060
|
+
isLoading,
|
|
4061
|
+
load,
|
|
4062
|
+
sendTurn,
|
|
4063
|
+
cancel,
|
|
4064
|
+
respondToToolApproval,
|
|
4065
|
+
respondToToolResponse,
|
|
4066
|
+
resumeRun,
|
|
4067
|
+
branchFromTurn,
|
|
4068
|
+
resetFromTurn,
|
|
4069
|
+
editFromTurn
|
|
4070
|
+
};
|
|
4071
|
+
}
|
|
4072
|
+
|
|
4073
|
+
// src/useTrueFoundryAgentRuntime.ts
|
|
4074
|
+
function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
4075
|
+
const {
|
|
4076
|
+
client,
|
|
4077
|
+
agent,
|
|
4078
|
+
gateway,
|
|
4079
|
+
adapters,
|
|
4080
|
+
onError,
|
|
4081
|
+
listEventsConcurrency,
|
|
4082
|
+
...sharedOptions
|
|
4083
|
+
} = options;
|
|
4084
|
+
const draftBridgeRef = useRef3(
|
|
4085
|
+
agent.mode === "draft" && gateway != null ? createDraftSessionBridge(gateway) : null
|
|
4086
|
+
);
|
|
4087
|
+
const draftSessionId = useAuiState(
|
|
4088
|
+
(state) => agent.mode === "draft" ? state.threadListItem.remoteId ?? void 0 : void 0
|
|
4089
|
+
);
|
|
4090
|
+
const sessionId = useAuiState((state) => state.threadListItem.remoteId ?? void 0);
|
|
4091
|
+
const draftSpec = useDraftAgentSpec({
|
|
4092
|
+
draftSessionId,
|
|
4093
|
+
draftBridge: draftBridgeRef.current,
|
|
4094
|
+
defaultAgentSpec: agent.mode === "draft" ? agent.defaultAgentSpec : { model: { name: "" } },
|
|
4095
|
+
onAgentSpecChange: agent.mode === "draft" ? agent.onAgentSpecChange : void 0,
|
|
4096
|
+
onError
|
|
4097
|
+
});
|
|
4098
|
+
const aui = useAui();
|
|
4099
|
+
const initializeSession = useCallback3(
|
|
4100
|
+
() => aui.threadListItem().initialize(),
|
|
4101
|
+
[aui]
|
|
4102
|
+
);
|
|
4103
|
+
const runtimeAdapters = useRuntimeAdapters();
|
|
4104
|
+
const [toolStatuses, setToolStatuses] = useState3({});
|
|
4105
|
+
const {
|
|
4106
|
+
messages,
|
|
4107
|
+
isRunning,
|
|
4108
|
+
isLoading,
|
|
4109
|
+
sendTurn,
|
|
4110
|
+
cancel,
|
|
4111
|
+
respondToToolApproval,
|
|
4112
|
+
respondToToolResponse,
|
|
4113
|
+
resumeRun,
|
|
4114
|
+
editFromTurn,
|
|
4115
|
+
resetFromTurn
|
|
4116
|
+
} = useTrueFoundryAgentMessages({
|
|
4117
|
+
client,
|
|
4118
|
+
sessionId,
|
|
4119
|
+
listEventsConcurrency,
|
|
4120
|
+
onError,
|
|
4121
|
+
initializeSession,
|
|
4122
|
+
draftGateway: agent.mode === "draft" ? gateway : void 0
|
|
4123
|
+
});
|
|
4124
|
+
if (agent.mode === "draft" && draftSpec.agentSpec != null) {
|
|
4125
|
+
pendingAgentSpecRef.current = draftSpec.agentSpec;
|
|
4126
|
+
}
|
|
4127
|
+
const pendingApprovals = useMemo3(
|
|
4128
|
+
() => collectPendingApprovals(messages),
|
|
4129
|
+
[messages]
|
|
4130
|
+
);
|
|
4131
|
+
const pendingToolResponses = useMemo3(
|
|
4132
|
+
() => collectPendingToolResponses(messages),
|
|
4133
|
+
[messages]
|
|
4134
|
+
);
|
|
4135
|
+
const pendingMcpAuth = useMemo3(() => derivePendingMcpAuth(messages), [messages]);
|
|
4136
|
+
const sandboxId = useMemo3(() => deriveSandboxId(messages), [messages]);
|
|
4137
|
+
const resumeMcpAuth = useMemo3(
|
|
4138
|
+
() => () => sendTurn({ resumeMcpAuth: true }),
|
|
4139
|
+
[sendTurn]
|
|
4140
|
+
);
|
|
4141
|
+
const downloadSandboxFile = useCallback3(
|
|
4142
|
+
async (path) => {
|
|
4143
|
+
if (gateway == null) {
|
|
4144
|
+
const error = new Error(
|
|
4145
|
+
"Downloading a sandbox file requires a `gateway` TrueFoundryGateway client."
|
|
4146
|
+
);
|
|
4147
|
+
onError?.(error);
|
|
4148
|
+
throw error;
|
|
4149
|
+
}
|
|
4150
|
+
if (sandboxId == null) {
|
|
4151
|
+
const error = new Error("No sandbox is available yet for this session.");
|
|
4152
|
+
onError?.(error);
|
|
4153
|
+
throw error;
|
|
4154
|
+
}
|
|
4155
|
+
const response = await gateway.agents.downloadSandboxFile(sandboxId, { path });
|
|
4156
|
+
return await response.blob();
|
|
4157
|
+
},
|
|
4158
|
+
[gateway, sandboxId, onError]
|
|
4159
|
+
);
|
|
4160
|
+
const draftExtras = useMemo3(() => {
|
|
4161
|
+
if (agent.mode !== "draft") {
|
|
4162
|
+
return null;
|
|
4163
|
+
}
|
|
4164
|
+
return {
|
|
4165
|
+
agentSpec: draftSpec.agentSpec,
|
|
4166
|
+
draftSessionId: draftSpec.draftSessionId,
|
|
4167
|
+
isSpecSyncing: draftSpec.isSpecSyncing,
|
|
4168
|
+
specError: draftSpec.specError,
|
|
4169
|
+
updateAgentSpec: draftSpec.updateAgentSpec
|
|
4170
|
+
};
|
|
4171
|
+
}, [agent.mode, draftSpec]);
|
|
4172
|
+
return useExternalStoreRuntime({
|
|
4173
|
+
...pickExternalStoreSharedOptions(sharedOptions),
|
|
4174
|
+
messages,
|
|
4175
|
+
isRunning,
|
|
4176
|
+
isLoading,
|
|
4177
|
+
extras: trueFoundryExtras.provide({
|
|
4178
|
+
pendingApprovals,
|
|
4179
|
+
pendingToolResponses,
|
|
4180
|
+
pendingMcpAuth,
|
|
4181
|
+
sandboxId,
|
|
4182
|
+
respondToToolApproval,
|
|
4183
|
+
respondToToolResponse,
|
|
4184
|
+
resumeMcpAuth,
|
|
4185
|
+
downloadSandboxFile,
|
|
4186
|
+
cancel,
|
|
4187
|
+
resetFromTurn: (turnId) => resetFromTurn(turnId).catch((error) => {
|
|
4188
|
+
onError?.(error);
|
|
4189
|
+
}),
|
|
4190
|
+
draft: draftExtras
|
|
4191
|
+
}),
|
|
4192
|
+
unstable_enableToolInvocations: true,
|
|
4193
|
+
setToolStatuses,
|
|
4194
|
+
adapters: {
|
|
4195
|
+
attachments: adapters?.attachments ?? runtimeAdapters?.attachments,
|
|
4196
|
+
speech: adapters?.speech,
|
|
4197
|
+
dictation: adapters?.dictation,
|
|
4198
|
+
voice: adapters?.voice,
|
|
4199
|
+
feedback: adapters?.feedback
|
|
4200
|
+
},
|
|
4201
|
+
onNew: async (message) => {
|
|
4202
|
+
if (!(message.startRun ?? message.role === "user")) {
|
|
4203
|
+
return;
|
|
4204
|
+
}
|
|
4205
|
+
const resumeMcpAuthFlag = message.runConfig?.custom?.[MCP_AUTH_RESUME_RUN_CUSTOM_KEY] === true;
|
|
4206
|
+
if (resumeMcpAuthFlag) {
|
|
4207
|
+
await sendTurn({ resumeMcpAuth: true });
|
|
4208
|
+
return;
|
|
4209
|
+
}
|
|
4210
|
+
await sendTurn({ userMessage: buildUserMessageContent(message) });
|
|
4211
|
+
},
|
|
4212
|
+
onCancel: async () => {
|
|
4213
|
+
await cancel();
|
|
4214
|
+
},
|
|
4215
|
+
onRespondToToolApproval: async (response) => {
|
|
4216
|
+
respondToToolApproval(response);
|
|
4217
|
+
},
|
|
4218
|
+
onResume: async () => {
|
|
4219
|
+
await resumeRun();
|
|
4220
|
+
},
|
|
4221
|
+
onEdit: async (message) => {
|
|
4222
|
+
const sourceId = message.sourceId;
|
|
4223
|
+
if (sourceId == null) {
|
|
4224
|
+
throw new Error("Could not resolve edited user message.");
|
|
4225
|
+
}
|
|
4226
|
+
const turnId = parseTurnIdFromMessageId(sourceId);
|
|
4227
|
+
const editedText = extractEditedText(message);
|
|
4228
|
+
try {
|
|
4229
|
+
await editFromTurn(turnId, editedText);
|
|
4230
|
+
} catch (error) {
|
|
4231
|
+
onError?.(error);
|
|
4232
|
+
throw error;
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
});
|
|
4236
|
+
}
|
|
4237
|
+
function useTrueFoundryAgentRuntime(options) {
|
|
4238
|
+
const resolved = useMemo3(
|
|
4239
|
+
() => resolveTrueFoundryAgentRuntimeOptions(options),
|
|
4240
|
+
[options]
|
|
4241
|
+
);
|
|
4242
|
+
const { client, agent, gateway } = resolved;
|
|
4243
|
+
const pendingAgentSpecRef = useRef3(
|
|
4244
|
+
agent.mode === "draft" ? agent.defaultAgentSpec : void 0
|
|
4245
|
+
);
|
|
4246
|
+
const threadListAdapter = useMemo3(() => {
|
|
4247
|
+
if (agent.mode === "draft") {
|
|
4248
|
+
if (gateway == null) {
|
|
4249
|
+
throw new Error(
|
|
4250
|
+
"Draft agent mode requires a `gateway` TrueFoundryGateway client."
|
|
4251
|
+
);
|
|
4252
|
+
}
|
|
4253
|
+
return createTrueFoundryDraftThreadListAdapter({
|
|
4254
|
+
gateway,
|
|
4255
|
+
defaultAgentSpec: agent.defaultAgentSpec,
|
|
4256
|
+
getAgentSpec: () => pendingAgentSpecRef.current ?? agent.defaultAgentSpec
|
|
4257
|
+
});
|
|
4258
|
+
}
|
|
4259
|
+
return createTrueFoundryThreadListAdapter({
|
|
4260
|
+
client,
|
|
4261
|
+
agentName: agent.agentName
|
|
4262
|
+
});
|
|
4263
|
+
}, [agent, client, gateway]);
|
|
4264
|
+
return useRemoteThreadListRuntime({
|
|
4265
|
+
allowNesting: true,
|
|
4266
|
+
adapter: threadListAdapter,
|
|
4267
|
+
initialThreadId: resolved.initialSessionId,
|
|
4268
|
+
threadId: resolved.threadId,
|
|
4269
|
+
onThreadIdChange: resolved.onThreadIdChange,
|
|
4270
|
+
runtimeHook: () => useTrueFoundryAgentRuntimeImpl(resolved, pendingAgentSpecRef)
|
|
4271
|
+
});
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4274
|
+
// src/hooks.ts
|
|
4275
|
+
import { useMemo as useMemo4 } from "react";
|
|
4276
|
+
import { useAui as useAui2 } from "@assistant-ui/store";
|
|
4277
|
+
var useTrueFoundryApprovals = () => {
|
|
4278
|
+
const extras = trueFoundryExtras.use((e) => e, void 0);
|
|
4279
|
+
return useMemo4(
|
|
4280
|
+
() => ({
|
|
4281
|
+
pending: extras?.pendingApprovals ?? [],
|
|
4282
|
+
respond: extras?.respondToToolApproval ?? (() => {
|
|
4283
|
+
throw new Error("TrueFoundry runtime is not ready yet");
|
|
4284
|
+
})
|
|
4285
|
+
}),
|
|
4286
|
+
[extras]
|
|
4287
|
+
);
|
|
4288
|
+
};
|
|
4289
|
+
var useTrueFoundryToolResponses = () => {
|
|
4290
|
+
const extras = trueFoundryExtras.use((e) => e, void 0);
|
|
4291
|
+
return useMemo4(
|
|
4292
|
+
() => ({
|
|
4293
|
+
pending: extras?.pendingToolResponses ?? [],
|
|
4294
|
+
respond: extras?.respondToToolResponse ?? ((_response) => {
|
|
4295
|
+
throw new Error("TrueFoundry runtime is not ready yet");
|
|
4296
|
+
})
|
|
4297
|
+
}),
|
|
4298
|
+
[extras]
|
|
4299
|
+
);
|
|
4300
|
+
};
|
|
4301
|
+
var useTrueFoundryMcpAuth = () => {
|
|
4302
|
+
const extras = trueFoundryExtras.use((e) => e, void 0);
|
|
4303
|
+
return useMemo4(
|
|
4304
|
+
() => ({
|
|
4305
|
+
pending: extras?.pendingMcpAuth ?? null,
|
|
4306
|
+
resume: extras?.resumeMcpAuth ?? (async () => {
|
|
4307
|
+
throw new Error("TrueFoundry runtime is not ready yet");
|
|
4308
|
+
})
|
|
4309
|
+
}),
|
|
4310
|
+
[extras]
|
|
4311
|
+
);
|
|
4312
|
+
};
|
|
4313
|
+
var useTrueFoundryRespondToToolApproval = () => {
|
|
4314
|
+
const aui = useAui2();
|
|
4315
|
+
return (response) => trueFoundryExtras.get(aui).respondToToolApproval(response);
|
|
4316
|
+
};
|
|
4317
|
+
var useTrueFoundryRespondToToolResponse = () => {
|
|
4318
|
+
const aui = useAui2();
|
|
4319
|
+
return (response) => trueFoundryExtras.get(aui).respondToToolResponse(response);
|
|
4320
|
+
};
|
|
4321
|
+
var useTrueFoundryResumeMcpAuth = () => {
|
|
4322
|
+
const aui = useAui2();
|
|
4323
|
+
return () => trueFoundryExtras.get(aui).resumeMcpAuth();
|
|
4324
|
+
};
|
|
4325
|
+
var useTrueFoundrySandboxId = () => trueFoundryExtras.use((e) => e.sandboxId, void 0);
|
|
4326
|
+
var useTrueFoundryDownloadSandboxFile = () => {
|
|
4327
|
+
const aui = useAui2();
|
|
4328
|
+
return (path) => trueFoundryExtras.get(aui).downloadSandboxFile(path);
|
|
4329
|
+
};
|
|
4330
|
+
var useTrueFoundryCancel = () => {
|
|
4331
|
+
const aui = useAui2();
|
|
4332
|
+
return () => trueFoundryExtras.get(aui).cancel();
|
|
4333
|
+
};
|
|
4334
|
+
var useTrueFoundryResetFromTurn = () => {
|
|
4335
|
+
const aui = useAui2();
|
|
4336
|
+
return (turnId) => trueFoundryExtras.get(aui).resetFromTurn(turnId);
|
|
4337
|
+
};
|
|
4338
|
+
var useTrueFoundryAgentSpec = () => {
|
|
4339
|
+
const extras = trueFoundryExtras.use((e) => e.draft, null);
|
|
4340
|
+
return useMemo4(
|
|
4341
|
+
() => ({ ...EMPTY_DRAFT_EXTRAS, ...extras }),
|
|
4342
|
+
[extras]
|
|
4343
|
+
);
|
|
4344
|
+
};
|
|
4345
|
+
var useTrueFoundryUpdateAgentSpec = () => {
|
|
4346
|
+
const aui = useAui2();
|
|
4347
|
+
return (update) => trueFoundryExtras.get(aui).draft?.updateAgentSpec(update);
|
|
4348
|
+
};
|
|
4349
|
+
|
|
4350
|
+
// src/attachmentAdapter.ts
|
|
4351
|
+
import {
|
|
4352
|
+
generateId as generateId2
|
|
4353
|
+
} from "@assistant-ui/core";
|
|
4354
|
+
var bytesToBase64 = (bytes) => globalThis.Buffer.from(bytes).toString("base64");
|
|
4355
|
+
var getFileDataURL = async (file) => {
|
|
4356
|
+
if (typeof FileReader === "undefined") {
|
|
4357
|
+
const buffer = await file.arrayBuffer();
|
|
4358
|
+
return `data:${file.type};base64,${bytesToBase64(new Uint8Array(buffer))}`;
|
|
4359
|
+
}
|
|
4360
|
+
return new Promise((resolve, reject) => {
|
|
4361
|
+
const reader = new FileReader();
|
|
4362
|
+
reader.onload = () => resolve(reader.result);
|
|
4363
|
+
reader.onerror = (error) => reject(error);
|
|
4364
|
+
reader.readAsDataURL(file);
|
|
4365
|
+
});
|
|
4366
|
+
};
|
|
4367
|
+
var trueFoundryAttachmentAdapter = {
|
|
4368
|
+
accept: "*",
|
|
4369
|
+
async add({ file }) {
|
|
4370
|
+
return {
|
|
4371
|
+
id: generateId2(),
|
|
4372
|
+
type: "file",
|
|
4373
|
+
name: file.name,
|
|
4374
|
+
file,
|
|
4375
|
+
contentType: file.type,
|
|
4376
|
+
content: [],
|
|
4377
|
+
status: {
|
|
4378
|
+
type: "requires-action",
|
|
4379
|
+
reason: "composer-send"
|
|
4380
|
+
}
|
|
4381
|
+
};
|
|
4382
|
+
},
|
|
4383
|
+
async send(attachment) {
|
|
4384
|
+
return {
|
|
4385
|
+
...attachment,
|
|
4386
|
+
status: { type: "complete" },
|
|
4387
|
+
content: [
|
|
4388
|
+
{
|
|
4389
|
+
type: "file",
|
|
4390
|
+
mimeType: attachment.contentType ?? "",
|
|
4391
|
+
filename: attachment.name,
|
|
4392
|
+
data: await getFileDataURL(attachment.file)
|
|
4393
|
+
}
|
|
4394
|
+
]
|
|
4395
|
+
};
|
|
4396
|
+
},
|
|
4397
|
+
async remove() {
|
|
4398
|
+
}
|
|
4399
|
+
};
|
|
4400
|
+
export {
|
|
4401
|
+
ROOT_THREAD_ID,
|
|
4402
|
+
TOOL_RESPONSE_THREAD_ID_CUSTOM_KEY,
|
|
4403
|
+
buildEditedUserMessageContent,
|
|
4404
|
+
buildTurnAssistantContent,
|
|
4405
|
+
buildUserMessageContent,
|
|
4406
|
+
collectApprovalInputs,
|
|
4407
|
+
collectRequiredActionInputs,
|
|
4408
|
+
collectResponseInputs,
|
|
4409
|
+
convertTurnsToThreadMessages,
|
|
4410
|
+
createDraftSessionBridge,
|
|
4411
|
+
createTrueFoundryDraftThreadListAdapter,
|
|
4412
|
+
createTrueFoundryThreadListAdapter,
|
|
4413
|
+
draftSessionTitle,
|
|
4414
|
+
findPausedAssistantMessage,
|
|
4415
|
+
getSession,
|
|
4416
|
+
getTurnMessageContent,
|
|
4417
|
+
mergeAgentSpec,
|
|
4418
|
+
messageHasPendingApprovals,
|
|
4419
|
+
messageHasPendingRequiredActions,
|
|
4420
|
+
messageHasPendingResponses,
|
|
4421
|
+
parseTurnIdFromMessageId,
|
|
4422
|
+
repositoryItemsFromMessages,
|
|
4423
|
+
toTrueFoundryApprovalInputs,
|
|
4424
|
+
trueFoundryAttachmentAdapter,
|
|
4425
|
+
trueFoundryExtras,
|
|
4426
|
+
useTrueFoundryAgentRuntime,
|
|
4427
|
+
useTrueFoundryAgentSpec,
|
|
4428
|
+
useTrueFoundryApprovals,
|
|
4429
|
+
useTrueFoundryCancel,
|
|
4430
|
+
useTrueFoundryDownloadSandboxFile,
|
|
4431
|
+
useTrueFoundryMcpAuth,
|
|
4432
|
+
useTrueFoundryResetFromTurn,
|
|
4433
|
+
useTrueFoundryRespondToToolApproval,
|
|
4434
|
+
useTrueFoundryRespondToToolResponse,
|
|
4435
|
+
useTrueFoundryResumeMcpAuth,
|
|
4436
|
+
useTrueFoundrySandboxId,
|
|
4437
|
+
useTrueFoundryToolResponses,
|
|
4438
|
+
useTrueFoundryUpdateAgentSpec
|
|
4439
|
+
};
|
|
4440
|
+
//# sourceMappingURL=index.js.map
|