@truefoundry/assistant-ui-runtime 0.1.0-rc.1 → 0.1.2
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 +45 -77
- package/dist/index.d.ts +14 -2
- package/dist/index.js +697 -147
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/agentSessionModule.d.ts +14 -2
- package/src/convertTurnMessages.test.ts +502 -1
- package/src/convertTurnMessages.ts +471 -28
- package/src/createSubAgent.ts +13 -5
- package/src/draftAgentConfig.test.ts +1 -1
- package/src/foldPeerThreads.test.ts +56 -0
- package/src/foldPeerThreads.ts +7 -1
- package/src/hooks.ts +24 -0
- package/src/index.ts +7 -5
- package/src/loadSessionSnapshot.test.ts +21 -6
- package/src/loadSessionSnapshot.ts +9 -5
- package/src/{bindDraftAgentSession.test.ts → private/bindDraftAgentSession.test.ts} +3 -2
- package/src/{draftSessionBridge.ts → private/draftSessionBridge.ts} +8 -2
- package/src/{truefoundryDraftThreadListAdapter.ts → private/truefoundryDraftThreadListAdapter.ts} +1 -1
- package/src/private/useDraftAgentSpec.test.tsx +153 -0
- package/src/{useDraftAgentSpec.ts → private/useDraftAgentSpec.ts} +80 -3
- package/src/sessionSnapshot.ts +48 -2
- package/src/sessions.ts +1 -1
- package/src/streamTurn.test.ts +34 -0
- package/src/streamTurn.ts +9 -1
- package/src/truefoundryExtras.ts +5 -1
- package/src/types.ts +1 -1
- package/src/useTrueFoundryAgentMessages.test.tsx +275 -1
- package/src/useTrueFoundryAgentMessages.ts +263 -70
- package/src/useTrueFoundryAgentRuntime.ts +51 -13
- /package/src/{agentSpec.ts → private/agentSpec.ts} +0 -0
- /package/src/{bindDraftAgentSession.ts → private/bindDraftAgentSession.ts} +0 -0
- /package/src/{truefoundryDraftThreadListAdapter.test.ts → private/truefoundryDraftThreadListAdapter.test.ts} +0 -0
package/dist/index.js
CHANGED
|
@@ -276,7 +276,10 @@ function parseAskUserQuestionArgs(argsText) {
|
|
|
276
276
|
|
|
277
277
|
// src/createSubAgent.ts
|
|
278
278
|
function isCreateSubAgentToolCall(toolCall) {
|
|
279
|
-
|
|
279
|
+
if (toolCall.toolInfo?.type === "truefoundry-system" && toolCall.toolInfo?.name === "create_sub_agent") {
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
return toolCall.function?.name === "create_sub_agent";
|
|
280
283
|
}
|
|
281
284
|
|
|
282
285
|
// src/modelMessageImageContent.ts
|
|
@@ -735,10 +738,13 @@ function attachSubAgentMessages(state, parentThreadId, parts) {
|
|
|
735
738
|
});
|
|
736
739
|
}
|
|
737
740
|
}
|
|
738
|
-
if (messages.length === 0) {
|
|
741
|
+
if (messages.length === 0 && subAgents.length === 0) {
|
|
739
742
|
return part;
|
|
740
743
|
}
|
|
741
744
|
const artifact = { subAgents };
|
|
745
|
+
if (messages.length === 0) {
|
|
746
|
+
return { ...part, artifact };
|
|
747
|
+
}
|
|
742
748
|
return { ...part, messages, artifact };
|
|
743
749
|
});
|
|
744
750
|
}
|
|
@@ -1144,6 +1150,27 @@ function deriveSandboxId(messages) {
|
|
|
1144
1150
|
return void 0;
|
|
1145
1151
|
}
|
|
1146
1152
|
|
|
1153
|
+
// src/extractTurnUserText.ts
|
|
1154
|
+
function extractTurnUserText(input) {
|
|
1155
|
+
const parts = [];
|
|
1156
|
+
for (const item of input ?? []) {
|
|
1157
|
+
if (item.type !== "user.message") {
|
|
1158
|
+
continue;
|
|
1159
|
+
}
|
|
1160
|
+
const { content } = item;
|
|
1161
|
+
if (typeof content === "string") {
|
|
1162
|
+
parts.push(content);
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
for (const part of content) {
|
|
1166
|
+
if (part.type === "text") {
|
|
1167
|
+
parts.push(part.text);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return parts.join("\n").trim();
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1147
1174
|
// src/mcpAuth.ts
|
|
1148
1175
|
var MCP_AUTH_RESUME_RUN_CUSTOM_KEY = "resumeMcpAuth";
|
|
1149
1176
|
function buildMcpAuthTextParts(servers) {
|
|
@@ -1230,27 +1257,6 @@ function appendMcpAuthToTurnContent(content, turn) {
|
|
|
1230
1257
|
);
|
|
1231
1258
|
}
|
|
1232
1259
|
|
|
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
1260
|
// src/sessionSnapshot.ts
|
|
1255
1261
|
function emptyRequiredActionsOverlay() {
|
|
1256
1262
|
return {
|
|
@@ -1275,6 +1281,18 @@ function turnToSessionRecord(turn) {
|
|
|
1275
1281
|
input: turn.input
|
|
1276
1282
|
};
|
|
1277
1283
|
}
|
|
1284
|
+
function sessionEventsToSessionRecord(turnId, createdEvent, doneEvent, rootModelMessageIds, sandboxId) {
|
|
1285
|
+
const userText = extractTurnUserText(createdEvent.input);
|
|
1286
|
+
return {
|
|
1287
|
+
id: turnId,
|
|
1288
|
+
...userText ? { userText } : {},
|
|
1289
|
+
createdAt: createdEvent.createdAt,
|
|
1290
|
+
state: doneEvent.state,
|
|
1291
|
+
input: createdEvent.input,
|
|
1292
|
+
rootModelMessageIds,
|
|
1293
|
+
...sandboxId != null ? { sandboxId } : {}
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1278
1296
|
function replaceSessionSnapshot(snapshot, patch) {
|
|
1279
1297
|
return {
|
|
1280
1298
|
...snapshot,
|
|
@@ -1285,6 +1303,281 @@ function replaceSessionSnapshot(snapshot, patch) {
|
|
|
1285
1303
|
|
|
1286
1304
|
// src/convertTurnMessages.ts
|
|
1287
1305
|
var TURN_EVENTS_PAGE_SIZE = 25;
|
|
1306
|
+
var SESSION_EVENTS_PAGE_SIZE = 100;
|
|
1307
|
+
var MAX_HISTORY_BOUNDARY_PAGES = 10;
|
|
1308
|
+
function trimIncompleteLeadingEvents(itemsAsc) {
|
|
1309
|
+
const start = itemsAsc.findIndex((item) => item.event.type === "turn.created");
|
|
1310
|
+
if (start === -1) {
|
|
1311
|
+
return [];
|
|
1312
|
+
}
|
|
1313
|
+
return itemsAsc.slice(start);
|
|
1314
|
+
}
|
|
1315
|
+
function oldestCompleteTurnGroupState(itemsAsc) {
|
|
1316
|
+
const trimmed = trimIncompleteLeadingEvents(itemsAsc);
|
|
1317
|
+
if (trimmed.length === 0) {
|
|
1318
|
+
return "incomplete";
|
|
1319
|
+
}
|
|
1320
|
+
const created = trimmed[0];
|
|
1321
|
+
if (created?.event.type !== "turn.created") {
|
|
1322
|
+
return "incomplete";
|
|
1323
|
+
}
|
|
1324
|
+
const hasDone = trimmed.some(
|
|
1325
|
+
(item) => item.turnId === created.turnId && item.event.type === "turn.done"
|
|
1326
|
+
);
|
|
1327
|
+
if (!hasDone) {
|
|
1328
|
+
return "incomplete";
|
|
1329
|
+
}
|
|
1330
|
+
return extractTurnUserText(created.event.input) != null ? "user-group" : "continuation";
|
|
1331
|
+
}
|
|
1332
|
+
async function fetchSessionEventsPage(session, options) {
|
|
1333
|
+
const page = await session.listEvents({
|
|
1334
|
+
limit: SESSION_EVENTS_PAGE_SIZE,
|
|
1335
|
+
...options?.lastTurnId != null ? { lastTurnId: options.lastTurnId } : {},
|
|
1336
|
+
...options?.pageToken != null ? { pageToken: options.pageToken } : {}
|
|
1337
|
+
});
|
|
1338
|
+
const response = page.response;
|
|
1339
|
+
const olderPageToken = response.pagination?.nextPageToken;
|
|
1340
|
+
const hasOlder = typeof page.hasNextPage === "function" ? page.hasNextPage() : olderPageToken != null && olderPageToken !== "";
|
|
1341
|
+
return {
|
|
1342
|
+
itemsNewestFirst: page.data,
|
|
1343
|
+
...olderPageToken != null && olderPageToken !== "" ? { olderPageToken } : {},
|
|
1344
|
+
hasOlder
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1347
|
+
async function fetchSessionEventsWindow(session, options) {
|
|
1348
|
+
let itemsNewestFirst = [];
|
|
1349
|
+
let pageToken = options?.pageToken;
|
|
1350
|
+
let olderPageToken;
|
|
1351
|
+
let hasOlder = false;
|
|
1352
|
+
for (let pageCount = 0; pageCount < MAX_HISTORY_BOUNDARY_PAGES; pageCount++) {
|
|
1353
|
+
const page = await fetchSessionEventsPage(session, {
|
|
1354
|
+
...options,
|
|
1355
|
+
...pageToken != null ? { pageToken } : {}
|
|
1356
|
+
});
|
|
1357
|
+
itemsNewestFirst = [...itemsNewestFirst, ...page.itemsNewestFirst];
|
|
1358
|
+
olderPageToken = page.olderPageToken;
|
|
1359
|
+
hasOlder = page.hasOlder;
|
|
1360
|
+
const itemsAsc2 = trimIncompleteLeadingEvents([...itemsNewestFirst].reverse());
|
|
1361
|
+
const groupState = oldestCompleteTurnGroupState(itemsAsc2);
|
|
1362
|
+
if (groupState === "user-group" || !hasOlder) {
|
|
1363
|
+
return {
|
|
1364
|
+
itemsAsc: itemsAsc2,
|
|
1365
|
+
...olderPageToken != null ? { olderPageToken } : {},
|
|
1366
|
+
hasOlder
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
if (olderPageToken == null) {
|
|
1370
|
+
return { itemsAsc: itemsAsc2, hasOlder: false };
|
|
1371
|
+
}
|
|
1372
|
+
pageToken = olderPageToken;
|
|
1373
|
+
}
|
|
1374
|
+
const itemsAsc = trimIncompleteLeadingEvents([...itemsNewestFirst].reverse());
|
|
1375
|
+
return {
|
|
1376
|
+
itemsAsc,
|
|
1377
|
+
...olderPageToken != null ? { olderPageToken } : {},
|
|
1378
|
+
hasOlder
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
async function fetchAllSessionEvents(session, options) {
|
|
1382
|
+
const items = [];
|
|
1383
|
+
for await (const item of await session.listEvents({
|
|
1384
|
+
limit: SESSION_EVENTS_PAGE_SIZE,
|
|
1385
|
+
...options?.lastTurnId != null ? { lastTurnId: options.lastTurnId } : {}
|
|
1386
|
+
})) {
|
|
1387
|
+
items.push(item);
|
|
1388
|
+
}
|
|
1389
|
+
items.reverse();
|
|
1390
|
+
return items;
|
|
1391
|
+
}
|
|
1392
|
+
function cloneThreadBucket(bucket) {
|
|
1393
|
+
return {
|
|
1394
|
+
events: new Map(bucket.events),
|
|
1395
|
+
modelMessageIds: [...bucket.modelMessageIds],
|
|
1396
|
+
toolResults: new Map(bucket.toolResults),
|
|
1397
|
+
pendingApprovals: new Map(bucket.pendingApprovals),
|
|
1398
|
+
approvalDecisions: new Map(bucket.approvalDecisions),
|
|
1399
|
+
pendingResponses: new Map(bucket.pendingResponses),
|
|
1400
|
+
done: bucket.done,
|
|
1401
|
+
...bucket.title != null ? { title: bucket.title } : {},
|
|
1402
|
+
...bucket.agentInfo != null ? { agentInfo: bucket.agentInfo } : {}
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
function prependFoldState(older, newer) {
|
|
1406
|
+
const result = new PeerThreadFoldState();
|
|
1407
|
+
const threadIds = /* @__PURE__ */ new Set([...older.threads.keys(), ...newer.threads.keys()]);
|
|
1408
|
+
for (const threadId of threadIds) {
|
|
1409
|
+
const olderBucket = older.threads.get(threadId);
|
|
1410
|
+
const newerBucket = newer.threads.get(threadId);
|
|
1411
|
+
if (olderBucket == null && newerBucket != null) {
|
|
1412
|
+
result.threads.set(threadId, cloneThreadBucket(newerBucket));
|
|
1413
|
+
continue;
|
|
1414
|
+
}
|
|
1415
|
+
if (newerBucket == null && olderBucket != null) {
|
|
1416
|
+
result.threads.set(threadId, cloneThreadBucket(olderBucket));
|
|
1417
|
+
continue;
|
|
1418
|
+
}
|
|
1419
|
+
if (olderBucket == null || newerBucket == null) {
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
result.threads.set(threadId, {
|
|
1423
|
+
events: new Map([...olderBucket.events, ...newerBucket.events]),
|
|
1424
|
+
modelMessageIds: [
|
|
1425
|
+
...olderBucket.modelMessageIds,
|
|
1426
|
+
...newerBucket.modelMessageIds
|
|
1427
|
+
],
|
|
1428
|
+
toolResults: new Map([
|
|
1429
|
+
...olderBucket.toolResults,
|
|
1430
|
+
...newerBucket.toolResults
|
|
1431
|
+
]),
|
|
1432
|
+
pendingApprovals: new Map([
|
|
1433
|
+
...olderBucket.pendingApprovals,
|
|
1434
|
+
...newerBucket.pendingApprovals
|
|
1435
|
+
]),
|
|
1436
|
+
approvalDecisions: new Map([
|
|
1437
|
+
...olderBucket.approvalDecisions,
|
|
1438
|
+
...newerBucket.approvalDecisions
|
|
1439
|
+
]),
|
|
1440
|
+
pendingResponses: new Map([
|
|
1441
|
+
...olderBucket.pendingResponses,
|
|
1442
|
+
...newerBucket.pendingResponses
|
|
1443
|
+
]),
|
|
1444
|
+
done: newerBucket.done || olderBucket.done,
|
|
1445
|
+
...newerBucket.title != null || olderBucket.title != null ? { title: newerBucket.title ?? olderBucket.title } : {},
|
|
1446
|
+
...newerBucket.agentInfo != null || olderBucket.agentInfo != null ? { agentInfo: newerBucket.agentInfo ?? olderBucket.agentInfo } : {}
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
for (const [threadId, link] of older.threadParents) {
|
|
1450
|
+
result.threadParents.set(threadId, link);
|
|
1451
|
+
}
|
|
1452
|
+
for (const [threadId, link] of newer.threadParents) {
|
|
1453
|
+
result.threadParents.set(threadId, link);
|
|
1454
|
+
}
|
|
1455
|
+
return result;
|
|
1456
|
+
}
|
|
1457
|
+
function ingestSessionEventsIntoSnapshot(snapshot, items, onTurnComplete) {
|
|
1458
|
+
let currentTurnId = null;
|
|
1459
|
+
let currentCreatedEvent = null;
|
|
1460
|
+
let currentContentEvents = [];
|
|
1461
|
+
let beforeCount = 0;
|
|
1462
|
+
for (const item of items) {
|
|
1463
|
+
const { turnId, event } = item;
|
|
1464
|
+
if (event.type === "turn.created") {
|
|
1465
|
+
currentTurnId = turnId;
|
|
1466
|
+
currentCreatedEvent = event;
|
|
1467
|
+
currentContentEvents = [];
|
|
1468
|
+
beforeCount = snapshot.fold.threads.get(ROOT_THREAD_ID)?.modelMessageIds.length ?? 0;
|
|
1469
|
+
} else if (event.type === "turn.done") {
|
|
1470
|
+
if (currentTurnId == null || currentCreatedEvent == null) {
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
const afterBucket = snapshot.fold.threads.get(ROOT_THREAD_ID);
|
|
1474
|
+
const rootModelMessageIds = (afterBucket?.modelMessageIds ?? []).slice(
|
|
1475
|
+
beforeCount
|
|
1476
|
+
);
|
|
1477
|
+
const sandboxEvent = currentContentEvents.find(
|
|
1478
|
+
(ev) => ev.type === "sandbox.created"
|
|
1479
|
+
);
|
|
1480
|
+
applyUserToolResponsesToFold(
|
|
1481
|
+
snapshot.fold,
|
|
1482
|
+
currentCreatedEvent.input ?? []
|
|
1483
|
+
);
|
|
1484
|
+
snapshot.turns.push(
|
|
1485
|
+
sessionEventsToSessionRecord(
|
|
1486
|
+
currentTurnId,
|
|
1487
|
+
currentCreatedEvent,
|
|
1488
|
+
event,
|
|
1489
|
+
rootModelMessageIds,
|
|
1490
|
+
sandboxEvent?.sandboxId
|
|
1491
|
+
)
|
|
1492
|
+
);
|
|
1493
|
+
onTurnComplete?.(replaceSessionSnapshot(snapshot, {}));
|
|
1494
|
+
currentTurnId = null;
|
|
1495
|
+
currentCreatedEvent = null;
|
|
1496
|
+
currentContentEvents = [];
|
|
1497
|
+
} else {
|
|
1498
|
+
if (currentTurnId != null) {
|
|
1499
|
+
ingestTurnEvent(snapshot.fold, event);
|
|
1500
|
+
currentContentEvents.push(event);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
function attachRunningTurn(snapshot, runningTurn) {
|
|
1506
|
+
if (runningTurn == null) {
|
|
1507
|
+
return snapshot;
|
|
1508
|
+
}
|
|
1509
|
+
const pendingUserText = extractTurnUserText(runningTurn.input);
|
|
1510
|
+
return replaceSessionSnapshot(snapshot, {
|
|
1511
|
+
runningTurn,
|
|
1512
|
+
unstable_resume: true,
|
|
1513
|
+
groupRootBaseline: computeGroupRootBaseline(snapshot.turns),
|
|
1514
|
+
...pendingUserText ? {
|
|
1515
|
+
pendingUser: {
|
|
1516
|
+
turnId: runningTurn.id,
|
|
1517
|
+
content: extractTurnUserMessageContent(runningTurn.input),
|
|
1518
|
+
createdAt: new Date(runningTurn.createdAt)
|
|
1519
|
+
}
|
|
1520
|
+
} : {}
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
async function buildSnapshotFromSessionEvents(session, onProgress) {
|
|
1524
|
+
const turnsPage = await session.listTurns({ limit: 1 });
|
|
1525
|
+
const newestTurn = turnsPage.data[0];
|
|
1526
|
+
const runningTurn = newestTurn?.state?.status === "running" ? newestTurn : void 0;
|
|
1527
|
+
const window = await fetchSessionEventsWindow(session);
|
|
1528
|
+
const historyPagination = {
|
|
1529
|
+
hasOlder: window.hasOlder,
|
|
1530
|
+
...window.olderPageToken != null ? { olderPageToken: window.olderPageToken } : {}
|
|
1531
|
+
};
|
|
1532
|
+
const snapshot = createEmptySessionSnapshot();
|
|
1533
|
+
ingestSessionEventsIntoSnapshot(snapshot, window.itemsAsc, onProgress);
|
|
1534
|
+
const withHistory = replaceSessionSnapshot(snapshot, {
|
|
1535
|
+
historyEvents: window.itemsAsc,
|
|
1536
|
+
historyPagination
|
|
1537
|
+
});
|
|
1538
|
+
return attachRunningTurn(withHistory, runningTurn);
|
|
1539
|
+
}
|
|
1540
|
+
async function prependOlderSessionHistory(session, snapshot) {
|
|
1541
|
+
const pagination = snapshot.historyPagination;
|
|
1542
|
+
if (pagination?.hasOlder !== true || pagination.olderPageToken == null) {
|
|
1543
|
+
return snapshot;
|
|
1544
|
+
}
|
|
1545
|
+
const window = await fetchSessionEventsWindow(session, {
|
|
1546
|
+
pageToken: pagination.olderPageToken
|
|
1547
|
+
});
|
|
1548
|
+
if (window.itemsAsc.length === 0) {
|
|
1549
|
+
return replaceSessionSnapshot(snapshot, {
|
|
1550
|
+
historyPagination: { hasOlder: false }
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
const olderSnap = createEmptySessionSnapshot();
|
|
1554
|
+
ingestSessionEventsIntoSnapshot(olderSnap, window.itemsAsc);
|
|
1555
|
+
const existingIds = new Set(snapshot.turns.map((turn) => turn.id));
|
|
1556
|
+
const olderTurns = olderSnap.turns.filter((turn) => !existingIds.has(turn.id));
|
|
1557
|
+
const mergedFold = prependFoldState(olderSnap.fold, snapshot.fold);
|
|
1558
|
+
const historyEvents = [
|
|
1559
|
+
...window.itemsAsc,
|
|
1560
|
+
...snapshot.historyEvents ?? []
|
|
1561
|
+
];
|
|
1562
|
+
const olderRootIds = olderTurns.flatMap(
|
|
1563
|
+
(turn) => turn.rootModelMessageIds ?? []
|
|
1564
|
+
);
|
|
1565
|
+
return replaceSessionSnapshot(snapshot, {
|
|
1566
|
+
fold: mergedFold,
|
|
1567
|
+
turns: [...olderTurns, ...snapshot.turns],
|
|
1568
|
+
historyEvents,
|
|
1569
|
+
historyPagination: {
|
|
1570
|
+
hasOlder: window.hasOlder,
|
|
1571
|
+
...window.olderPageToken != null ? { olderPageToken: window.olderPageToken } : {}
|
|
1572
|
+
},
|
|
1573
|
+
...snapshot.groupRootBaseline != null ? {
|
|
1574
|
+
groupRootBaseline: [
|
|
1575
|
+
...olderRootIds,
|
|
1576
|
+
...snapshot.groupRootBaseline
|
|
1577
|
+
]
|
|
1578
|
+
} : {}
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1288
1581
|
function assistantStatusFromTurnState(state) {
|
|
1289
1582
|
switch (state.status) {
|
|
1290
1583
|
case "done":
|
|
@@ -1719,37 +2012,41 @@ function ingestTurnsIntoSnapshot(snapshot, turns, eventArrays) {
|
|
|
1719
2012
|
return runningTurn;
|
|
1720
2013
|
}
|
|
1721
2014
|
async function buildSnapshotFromSession(session, concurrency = DEFAULT_LIST_EVENTS_CONCURRENCY) {
|
|
1722
|
-
const
|
|
1723
|
-
|
|
1724
|
-
|
|
2015
|
+
const snapshot = await buildSnapshotFromSessionEvents(session);
|
|
2016
|
+
if (snapshot.runningTurn == null) {
|
|
2017
|
+
return snapshot;
|
|
1725
2018
|
}
|
|
1726
|
-
|
|
1727
|
-
const eventArrays = await fetchAllTurnEventsWithConcurrency(
|
|
1728
|
-
|
|
1729
|
-
const runningTurn = ingestTurnsIntoSnapshot(snapshot, turns, eventArrays);
|
|
2019
|
+
const turn = snapshot.runningTurn;
|
|
2020
|
+
const eventArrays = await fetchAllTurnEventsWithConcurrency([turn], concurrency);
|
|
2021
|
+
ingestTurnsIntoSnapshot(snapshot, [turn], eventArrays);
|
|
1730
2022
|
return replaceSessionSnapshot(snapshot, {
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
} : {}
|
|
2023
|
+
runningTurn: turn,
|
|
2024
|
+
unstable_resume: true,
|
|
2025
|
+
groupRootBaseline: computeGroupRootBaseline(snapshot.turns),
|
|
2026
|
+
pendingUser: void 0
|
|
1736
2027
|
});
|
|
1737
2028
|
}
|
|
1738
|
-
async function
|
|
2029
|
+
async function buildSnapshotBeforeTurn(session, beforeTurnId, concurrency = DEFAULT_LIST_EVENTS_CONCURRENCY) {
|
|
2030
|
+
const turns = await listSessionTurnsOrdered(session);
|
|
2031
|
+
const beforeIndex = turns.findIndex((turn) => turn.id === beforeTurnId);
|
|
2032
|
+
if (beforeIndex === -1) {
|
|
2033
|
+
throw new Error(`Turn ${beforeTurnId} not found in session`);
|
|
2034
|
+
}
|
|
2035
|
+
return buildSnapshotBeforeTurnIndex(session, beforeIndex, concurrency, turns);
|
|
2036
|
+
}
|
|
2037
|
+
async function buildSnapshotBeforeTurnIndex(session, turnIndex, _concurrency = DEFAULT_LIST_EVENTS_CONCURRENCY, orderedTurns) {
|
|
1739
2038
|
if (turnIndex <= 0) {
|
|
1740
2039
|
return createEmptySessionSnapshot();
|
|
1741
2040
|
}
|
|
1742
2041
|
const turns = orderedTurns ?? await listSessionTurnsOrdered(session);
|
|
1743
2042
|
const turnsToInclude = turns.slice(0, turnIndex);
|
|
1744
|
-
|
|
2043
|
+
const lastTurnId = turnsToInclude.at(-1)?.id;
|
|
2044
|
+
if (lastTurnId == null) {
|
|
1745
2045
|
return createEmptySessionSnapshot();
|
|
1746
2046
|
}
|
|
1747
|
-
const
|
|
1748
|
-
turnsToInclude,
|
|
1749
|
-
concurrency
|
|
1750
|
-
);
|
|
2047
|
+
const items = await fetchAllSessionEvents(session, { lastTurnId });
|
|
1751
2048
|
const snapshot = createEmptySessionSnapshot();
|
|
1752
|
-
|
|
2049
|
+
ingestSessionEventsIntoSnapshot(snapshot, items);
|
|
1753
2050
|
return snapshot;
|
|
1754
2051
|
}
|
|
1755
2052
|
async function resolveGatewayBranchPreviousTurnId(session, turnIndex, orderedTurns) {
|
|
@@ -1759,6 +2056,11 @@ async function resolveGatewayBranchPreviousTurnId(session, turnIndex, orderedTur
|
|
|
1759
2056
|
const turns = orderedTurns ?? await listSessionTurnsOrdered(session);
|
|
1760
2057
|
return turns[turnIndex - 1]?.id ?? null;
|
|
1761
2058
|
}
|
|
2059
|
+
async function resolveGatewayBranchPreviousTurnIdForTurn(session, turnId) {
|
|
2060
|
+
const turns = await listSessionTurnsOrdered(session);
|
|
2061
|
+
const turnIndex = turns.findIndex((turn) => turn.id === turnId);
|
|
2062
|
+
return resolveGatewayBranchPreviousTurnId(session, turnIndex, turns);
|
|
2063
|
+
}
|
|
1762
2064
|
async function listSessionTurnsOrdered(session) {
|
|
1763
2065
|
const turns = [];
|
|
1764
2066
|
for await (const turn of await session.listTurns()) {
|
|
@@ -2024,7 +2326,8 @@ function repositoryItemsFromMessages(messages) {
|
|
|
2024
2326
|
return items;
|
|
2025
2327
|
}
|
|
2026
2328
|
|
|
2027
|
-
// src/draftSessionBridge.ts
|
|
2329
|
+
// src/private/draftSessionBridge.ts
|
|
2330
|
+
var DRAFT_SESSION_LAST_UPDATED_AT_HEADER = "x-tfy-session-last-updated-at";
|
|
2028
2331
|
function createDraftSessionBridge(gateway) {
|
|
2029
2332
|
async function getDraft(draftSessionId) {
|
|
2030
2333
|
const response = await gateway.agents.private.draftSessions.get(draftSessionId);
|
|
@@ -2036,12 +2339,16 @@ function createDraftSessionBridge(gateway) {
|
|
|
2036
2339
|
return draft.agentSpec;
|
|
2037
2340
|
},
|
|
2038
2341
|
async syncAgentSpec(draftSessionId, agentSpec) {
|
|
2039
|
-
await gateway.agents.private.draftSessions.update(
|
|
2342
|
+
const response = await gateway.agents.private.draftSessions.update(
|
|
2343
|
+
draftSessionId,
|
|
2344
|
+
{ agentSpec }
|
|
2345
|
+
);
|
|
2346
|
+
return response.data.updatedAt;
|
|
2040
2347
|
}
|
|
2041
2348
|
};
|
|
2042
2349
|
}
|
|
2043
2350
|
|
|
2044
|
-
// src/agentSpec.ts
|
|
2351
|
+
// src/private/agentSpec.ts
|
|
2045
2352
|
function mergeAgentSpec(base, update) {
|
|
2046
2353
|
const { model: modelUpdate, ...rest } = update;
|
|
2047
2354
|
const next = {
|
|
@@ -2069,7 +2376,7 @@ function sessionListStartTimestamp() {
|
|
|
2069
2376
|
return start.toISOString();
|
|
2070
2377
|
}
|
|
2071
2378
|
|
|
2072
|
-
// src/truefoundryDraftThreadListAdapter.ts
|
|
2379
|
+
// src/private/truefoundryDraftThreadListAdapter.ts
|
|
2073
2380
|
var THREAD_LIST_PAGE_SIZE = 20;
|
|
2074
2381
|
function createTrueFoundryDraftThreadListAdapter(options) {
|
|
2075
2382
|
const { gateway, defaultAgentSpec, getAgentSpec } = options;
|
|
@@ -2137,7 +2444,7 @@ var EMPTY_DRAFT_EXTRAS = {
|
|
|
2137
2444
|
}
|
|
2138
2445
|
};
|
|
2139
2446
|
|
|
2140
|
-
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.
|
|
2447
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.3.1/node_modules/truefoundry-gateway-sdk/dist/esm/core/fetcher/HttpResponsePromise.mjs
|
|
2141
2448
|
var __awaiter = function(thisArg, _arguments, P, generator) {
|
|
2142
2449
|
function adopt(value) {
|
|
2143
2450
|
return value instanceof P ? value : new P(function(resolve) {
|
|
@@ -2252,7 +2559,7 @@ var HttpResponsePromise = class _HttpResponsePromise extends Promise {
|
|
|
2252
2559
|
}
|
|
2253
2560
|
};
|
|
2254
2561
|
|
|
2255
|
-
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.
|
|
2562
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.3.1/node_modules/truefoundry-gateway-sdk/dist/esm/core/pagination/Page.mjs
|
|
2256
2563
|
var __awaiter2 = function(thisArg, _arguments, P, generator) {
|
|
2257
2564
|
function adopt(value) {
|
|
2258
2565
|
return value instanceof P ? value : new P(function(resolve) {
|
|
@@ -2407,7 +2714,7 @@ var Page = class {
|
|
|
2407
2714
|
}
|
|
2408
2715
|
};
|
|
2409
2716
|
|
|
2410
|
-
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.
|
|
2717
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.3.1/node_modules/truefoundry-gateway-sdk/dist/esm/agents/TurnStreamData.mjs
|
|
2411
2718
|
function parseSequenceNumber(id) {
|
|
2412
2719
|
if (!id) {
|
|
2413
2720
|
throw new Error("Missing SSE sequence number id.");
|
|
@@ -2419,7 +2726,7 @@ function parseSequenceNumber(id) {
|
|
|
2419
2726
|
return parsed;
|
|
2420
2727
|
}
|
|
2421
2728
|
|
|
2422
|
-
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.
|
|
2729
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.3.1/node_modules/truefoundry-gateway-sdk/dist/esm/agents/Turn.mjs
|
|
2423
2730
|
var __awaiter3 = function(thisArg, _arguments, P, generator) {
|
|
2424
2731
|
function adopt(value) {
|
|
2425
2732
|
return value instanceof P ? value : new P(function(resolve) {
|
|
@@ -2657,7 +2964,7 @@ _Turn_client = /* @__PURE__ */ new WeakMap(), _Turn_state = /* @__PURE__ */ new
|
|
|
2657
2964
|
__classPrivateFieldSet(this, _Turn_state, event.state, "f");
|
|
2658
2965
|
};
|
|
2659
2966
|
|
|
2660
|
-
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.
|
|
2967
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.3.1/node_modules/truefoundry-gateway-sdk/dist/esm/agents/PreparedTurn.mjs
|
|
2661
2968
|
var __awaiter4 = function(thisArg, _arguments, P, generator) {
|
|
2662
2969
|
function adopt(value) {
|
|
2663
2970
|
return value instanceof P ? value : new P(function(resolve) {
|
|
@@ -3012,7 +3319,7 @@ var PreparedTurn = class {
|
|
|
3012
3319
|
};
|
|
3013
3320
|
_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
3321
|
|
|
3015
|
-
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.
|
|
3322
|
+
// ../../node_modules/.pnpm/truefoundry-gateway-sdk@0.3.1/node_modules/truefoundry-gateway-sdk/dist/esm/agents/AgentSession.mjs
|
|
3016
3323
|
var __awaiter5 = function(thisArg, _arguments, P, generator) {
|
|
3017
3324
|
function adopt(value) {
|
|
3018
3325
|
return value instanceof P ? value : new P(function(resolve) {
|
|
@@ -3122,10 +3429,22 @@ var AgentSession = class {
|
|
|
3122
3429
|
yield __classPrivateFieldGet3(this, _AgentSession_client, "f").agents.sessions.cancel(this.id, {}, requestOptions);
|
|
3123
3430
|
});
|
|
3124
3431
|
}
|
|
3432
|
+
/**
|
|
3433
|
+
* Paginated session events across turns (newest first); subscribe to a running turn for live events.
|
|
3434
|
+
*
|
|
3435
|
+
* @param opts.pageToken - Token from the previous response nextPageToken.
|
|
3436
|
+
* @param opts.lastTurnId - Newest turn in the listing window (initial load only). Omit to use the session last turn.
|
|
3437
|
+
* @param opts.limit - Page size. Default 100.
|
|
3438
|
+
* @param requestOptions - Overrides client timeout, retries, abortSignal, headers, queryParams.
|
|
3439
|
+
* @returns {Promise<core.Page<TrueFoundryGatewayApi.SessionEventItem, TrueFoundryGatewayApi.ListSessionEventsResponse>>} Paginated session events.
|
|
3440
|
+
*/
|
|
3441
|
+
listEvents(opts, requestOptions) {
|
|
3442
|
+
return __classPrivateFieldGet3(this, _AgentSession_client, "f").agents.sessions.listEvents(this.id, opts, requestOptions);
|
|
3443
|
+
}
|
|
3125
3444
|
};
|
|
3126
3445
|
_AgentSession_client = /* @__PURE__ */ new WeakMap();
|
|
3127
3446
|
|
|
3128
|
-
// src/bindDraftAgentSession.ts
|
|
3447
|
+
// src/private/bindDraftAgentSession.ts
|
|
3129
3448
|
var inflightByDraftId = /* @__PURE__ */ new Map();
|
|
3130
3449
|
function getGatewayFromSessionClient(client) {
|
|
3131
3450
|
const internal = client;
|
|
@@ -3260,7 +3579,7 @@ function resolveTrueFoundryAgentRuntimeOptions(options) {
|
|
|
3260
3579
|
};
|
|
3261
3580
|
}
|
|
3262
3581
|
|
|
3263
|
-
// src/useDraftAgentSpec.ts
|
|
3582
|
+
// src/private/useDraftAgentSpec.ts
|
|
3264
3583
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3265
3584
|
var SPEC_SYNC_DEBOUNCE_MS = 400;
|
|
3266
3585
|
function useDraftAgentSpec({
|
|
@@ -3280,6 +3599,29 @@ function useDraftAgentSpec({
|
|
|
3280
3599
|
const syncGenerationRef = useRef(0);
|
|
3281
3600
|
const loadedDraftIdRef = useRef(void 0);
|
|
3282
3601
|
const localDirtyRef = useRef(false);
|
|
3602
|
+
const lastUpdatedAtRef = useRef(void 0);
|
|
3603
|
+
const pendingFlushRef = useRef(void 0);
|
|
3604
|
+
const inFlightFlushRef = useRef(void 0);
|
|
3605
|
+
const activeDraftIdRef = useRef(draftSessionId);
|
|
3606
|
+
useEffect(() => {
|
|
3607
|
+
const previousDraftId = activeDraftIdRef.current;
|
|
3608
|
+
if (previousDraftId === draftSessionId) {
|
|
3609
|
+
return;
|
|
3610
|
+
}
|
|
3611
|
+
activeDraftIdRef.current = draftSessionId;
|
|
3612
|
+
syncGenerationRef.current++;
|
|
3613
|
+
if (syncTimeoutRef.current != null) {
|
|
3614
|
+
clearTimeout(syncTimeoutRef.current);
|
|
3615
|
+
syncTimeoutRef.current = void 0;
|
|
3616
|
+
}
|
|
3617
|
+
pendingFlushRef.current = void 0;
|
|
3618
|
+
inFlightFlushRef.current = void 0;
|
|
3619
|
+
lastUpdatedAtRef.current = void 0;
|
|
3620
|
+
setIsSpecSyncing(false);
|
|
3621
|
+
if (previousDraftId != null) {
|
|
3622
|
+
localDirtyRef.current = false;
|
|
3623
|
+
}
|
|
3624
|
+
}, [draftSessionId]);
|
|
3283
3625
|
useEffect(() => {
|
|
3284
3626
|
if (!enabled || draftBridge == null) {
|
|
3285
3627
|
return;
|
|
@@ -3328,10 +3670,11 @@ function useDraftAgentSpec({
|
|
|
3328
3670
|
}
|
|
3329
3671
|
setIsSpecSyncing(true);
|
|
3330
3672
|
try {
|
|
3331
|
-
await draftBridge.syncAgentSpec(draftId, spec);
|
|
3673
|
+
const updatedAt = await draftBridge.syncAgentSpec(draftId, spec);
|
|
3332
3674
|
if (generation !== syncGenerationRef.current) {
|
|
3333
3675
|
return;
|
|
3334
3676
|
}
|
|
3677
|
+
lastUpdatedAtRef.current = updatedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
3335
3678
|
setSpecError(null);
|
|
3336
3679
|
onAgentSpecChange?.(spec);
|
|
3337
3680
|
} catch (error) {
|
|
@@ -3353,14 +3696,47 @@ function useDraftAgentSpec({
|
|
|
3353
3696
|
clearTimeout(syncTimeoutRef.current);
|
|
3354
3697
|
}
|
|
3355
3698
|
const generation = ++syncGenerationRef.current;
|
|
3699
|
+
const flush = () => {
|
|
3700
|
+
pendingFlushRef.current = void 0;
|
|
3701
|
+
syncTimeoutRef.current = void 0;
|
|
3702
|
+
const promise = flushSpecSync(draftId, spec, generation).finally(() => {
|
|
3703
|
+
if (inFlightFlushRef.current === promise) {
|
|
3704
|
+
inFlightFlushRef.current = void 0;
|
|
3705
|
+
}
|
|
3706
|
+
});
|
|
3707
|
+
inFlightFlushRef.current = promise;
|
|
3708
|
+
return promise;
|
|
3709
|
+
};
|
|
3710
|
+
pendingFlushRef.current = flush;
|
|
3356
3711
|
syncTimeoutRef.current = setTimeout(() => {
|
|
3357
|
-
void
|
|
3712
|
+
void flush();
|
|
3358
3713
|
}, SPEC_SYNC_DEBOUNCE_MS);
|
|
3359
3714
|
},
|
|
3360
3715
|
[flushSpecSync]
|
|
3361
3716
|
);
|
|
3362
3717
|
const scheduleSpecSyncRef = useRef(scheduleSpecSync);
|
|
3363
3718
|
scheduleSpecSyncRef.current = scheduleSpecSync;
|
|
3719
|
+
const flushPendingSpecSyncNow = useCallback(async () => {
|
|
3720
|
+
if (syncTimeoutRef.current != null) {
|
|
3721
|
+
clearTimeout(syncTimeoutRef.current);
|
|
3722
|
+
syncTimeoutRef.current = void 0;
|
|
3723
|
+
}
|
|
3724
|
+
const pending = pendingFlushRef.current;
|
|
3725
|
+
if (pending != null) {
|
|
3726
|
+
pendingFlushRef.current = void 0;
|
|
3727
|
+
await pending();
|
|
3728
|
+
return;
|
|
3729
|
+
}
|
|
3730
|
+
if (inFlightFlushRef.current != null) {
|
|
3731
|
+
await inFlightFlushRef.current;
|
|
3732
|
+
}
|
|
3733
|
+
}, []);
|
|
3734
|
+
const takeTurnHeaderTimestamp = useCallback(async () => {
|
|
3735
|
+
await flushPendingSpecSyncNow();
|
|
3736
|
+
const updatedAt = lastUpdatedAtRef.current;
|
|
3737
|
+
lastUpdatedAtRef.current = void 0;
|
|
3738
|
+
return updatedAt;
|
|
3739
|
+
}, [flushPendingSpecSyncNow]);
|
|
3364
3740
|
useEffect(
|
|
3365
3741
|
() => () => {
|
|
3366
3742
|
if (syncTimeoutRef.current != null) {
|
|
@@ -3389,7 +3765,8 @@ function useDraftAgentSpec({
|
|
|
3389
3765
|
draftSessionId: enabled ? draftSessionId : void 0,
|
|
3390
3766
|
isSpecSyncing: enabled ? isSpecSyncing : false,
|
|
3391
3767
|
specError: enabled ? specError : null,
|
|
3392
|
-
updateAgentSpec
|
|
3768
|
+
updateAgentSpec,
|
|
3769
|
+
takeTurnHeaderTimestamp
|
|
3393
3770
|
}),
|
|
3394
3771
|
[
|
|
3395
3772
|
agentSpec,
|
|
@@ -3397,6 +3774,7 @@ function useDraftAgentSpec({
|
|
|
3397
3774
|
enabled,
|
|
3398
3775
|
isSpecSyncing,
|
|
3399
3776
|
specError,
|
|
3777
|
+
takeTurnHeaderTimestamp,
|
|
3400
3778
|
updateAgentSpec
|
|
3401
3779
|
]
|
|
3402
3780
|
);
|
|
@@ -3408,11 +3786,13 @@ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMem
|
|
|
3408
3786
|
|
|
3409
3787
|
// src/loadSessionSnapshot.ts
|
|
3410
3788
|
var inflightBySessionId2 = /* @__PURE__ */ new Map();
|
|
3411
|
-
function loadSessionSnapshot(client, sessionId,
|
|
3789
|
+
function loadSessionSnapshot(client, sessionId, sessionOptions, onProgress) {
|
|
3412
3790
|
const cacheKey = sessionOptions?.draftGateway != null ? `draft:${sessionId}` : sessionId;
|
|
3413
3791
|
let inflight = inflightBySessionId2.get(cacheKey);
|
|
3414
3792
|
if (inflight == null) {
|
|
3415
|
-
inflight = getSession(client, sessionId, sessionOptions).then(
|
|
3793
|
+
inflight = getSession(client, sessionId, sessionOptions).then(
|
|
3794
|
+
(session) => buildSnapshotFromSessionEvents(session, onProgress)
|
|
3795
|
+
).finally(() => {
|
|
3416
3796
|
if (inflightBySessionId2.get(cacheKey) === inflight) {
|
|
3417
3797
|
inflightBySessionId2.delete(cacheKey);
|
|
3418
3798
|
}
|
|
@@ -3479,7 +3859,13 @@ async function* streamTurnContent(session, foldState, options, abortSignal, grou
|
|
|
3479
3859
|
}
|
|
3480
3860
|
try {
|
|
3481
3861
|
yield* streamTurnEvents(
|
|
3482
|
-
turn.execute(
|
|
3862
|
+
turn.execute(
|
|
3863
|
+
{ stream: true },
|
|
3864
|
+
{
|
|
3865
|
+
abortSignal,
|
|
3866
|
+
...options.headers != null ? { headers: options.headers } : {}
|
|
3867
|
+
}
|
|
3868
|
+
),
|
|
3483
3869
|
foldState,
|
|
3484
3870
|
groupRootBaseline
|
|
3485
3871
|
);
|
|
@@ -3631,16 +4017,6 @@ async function resolveActiveSessionId(remoteId, resolveConversationSessionId) {
|
|
|
3631
4017
|
}
|
|
3632
4018
|
return remoteId;
|
|
3633
4019
|
}
|
|
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
4020
|
function resolveTurnInput(snapshot, turnId) {
|
|
3645
4021
|
const turnRecord = snapshot.turns.find((turn) => turn.id === turnId);
|
|
3646
4022
|
if (turnRecord?.input != null) {
|
|
@@ -3654,11 +4030,13 @@ function resolveTurnInput(snapshot, turnId) {
|
|
|
3654
4030
|
function useTrueFoundryAgentMessages({
|
|
3655
4031
|
client,
|
|
3656
4032
|
sessionId,
|
|
4033
|
+
isMain,
|
|
3657
4034
|
listEventsConcurrency,
|
|
3658
4035
|
onError,
|
|
3659
4036
|
initializeSession,
|
|
3660
4037
|
resolveConversationSessionId,
|
|
3661
|
-
draftGateway
|
|
4038
|
+
draftGateway,
|
|
4039
|
+
getTurnHeaders
|
|
3662
4040
|
}) {
|
|
3663
4041
|
const sessionOptions = useMemo2(
|
|
3664
4042
|
() => draftGateway != null ? { draftGateway } : void 0,
|
|
@@ -3667,13 +4045,25 @@ function useTrueFoundryAgentMessages({
|
|
|
3667
4045
|
const [snapshot, setSnapshot] = useState2(createEmptySessionSnapshot);
|
|
3668
4046
|
const [isRunning, setIsRunning] = useState2(false);
|
|
3669
4047
|
const [isLoading, setIsLoading] = useState2(false);
|
|
4048
|
+
const [isLoadingOlderHistory, setIsLoadingOlderHistory] = useState2(false);
|
|
4049
|
+
const [loadRetryTrigger, setLoadRetryTrigger] = useState2(0);
|
|
3670
4050
|
const snapshotRef = useRef2(snapshot);
|
|
3671
4051
|
snapshotRef.current = snapshot;
|
|
4052
|
+
const loadOlderInflightRef = useRef2(null);
|
|
4053
|
+
const onErrorRef = useRef2(onError);
|
|
4054
|
+
onErrorRef.current = onError;
|
|
4055
|
+
const resolveConversationSessionIdRef = useRef2(resolveConversationSessionId);
|
|
4056
|
+
resolveConversationSessionIdRef.current = resolveConversationSessionId;
|
|
4057
|
+
const initializeSessionRef = useRef2(initializeSession);
|
|
4058
|
+
initializeSessionRef.current = initializeSession;
|
|
4059
|
+
const getTurnHeadersRef = useRef2(getTurnHeaders);
|
|
4060
|
+
getTurnHeadersRef.current = getTurnHeaders;
|
|
3672
4061
|
const createdAtByMessageIdRef = useRef2(/* @__PURE__ */ new Map());
|
|
3673
4062
|
const abortControllerRef = useRef2(null);
|
|
3674
4063
|
const activeRunRef = useRef2(null);
|
|
3675
4064
|
const runningTurnRef = useRef2(void 0);
|
|
3676
4065
|
const loadGenerationRef = useRef2(0);
|
|
4066
|
+
const streamGenerationRef = useRef2(0);
|
|
3677
4067
|
const lazilyCreatedSessionIdRef = useRef2(void 0);
|
|
3678
4068
|
const projectOptions = useMemo2(
|
|
3679
4069
|
() => ({
|
|
@@ -3693,41 +4083,62 @@ function useTrueFoundryAgentMessages({
|
|
|
3693
4083
|
() => projectSessionMessages(snapshot, projectOptions),
|
|
3694
4084
|
[snapshot, projectOptions]
|
|
3695
4085
|
);
|
|
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
4086
|
const runStream = useCallback2(
|
|
3711
4087
|
(createStream, turnId, isContinuation) => {
|
|
4088
|
+
const streamGeneration = ++streamGenerationRef.current;
|
|
3712
4089
|
abortControllerRef.current?.abort();
|
|
3713
4090
|
const abortController = new AbortController();
|
|
3714
4091
|
abortControllerRef.current = abortController;
|
|
3715
4092
|
setIsRunning(true);
|
|
3716
4093
|
const run = (async () => {
|
|
4094
|
+
let pendingStreamUpdate = null;
|
|
4095
|
+
let streamUpdateRaf = null;
|
|
4096
|
+
const flushPendingStreamUpdate = () => {
|
|
4097
|
+
streamUpdateRaf = null;
|
|
4098
|
+
const pending = pendingStreamUpdate;
|
|
4099
|
+
pendingStreamUpdate = null;
|
|
4100
|
+
if (pending == null || streamGeneration !== streamGenerationRef.current) {
|
|
4101
|
+
return;
|
|
4102
|
+
}
|
|
4103
|
+
const { update, turnId: pendingTurnId, isContinuation: pendingIsContinuation } = pending;
|
|
4104
|
+
setSnapshot(
|
|
4105
|
+
(prev) => replaceSessionSnapshot(prev, {
|
|
4106
|
+
activeStream: {
|
|
4107
|
+
turnId: pendingTurnId,
|
|
4108
|
+
update,
|
|
4109
|
+
isContinuation: pendingIsContinuation
|
|
4110
|
+
}
|
|
4111
|
+
})
|
|
4112
|
+
);
|
|
4113
|
+
};
|
|
4114
|
+
const applyStreamUpdate = (update) => {
|
|
4115
|
+
pendingStreamUpdate = { update, turnId, isContinuation };
|
|
4116
|
+
if (streamUpdateRaf == null) {
|
|
4117
|
+
streamUpdateRaf = requestAnimationFrame(flushPendingStreamUpdate);
|
|
4118
|
+
}
|
|
4119
|
+
};
|
|
3717
4120
|
try {
|
|
3718
4121
|
for await (const update of createStream(abortController.signal)) {
|
|
3719
4122
|
if (abortController.signal.aborted) {
|
|
3720
4123
|
return;
|
|
3721
4124
|
}
|
|
3722
|
-
applyStreamUpdate(update
|
|
4125
|
+
applyStreamUpdate(update);
|
|
3723
4126
|
}
|
|
3724
4127
|
} catch (error) {
|
|
3725
4128
|
if (error instanceof Error && error.name === "AbortError") {
|
|
3726
4129
|
return;
|
|
3727
4130
|
}
|
|
3728
|
-
|
|
4131
|
+
onErrorRef.current?.(error);
|
|
3729
4132
|
throw error;
|
|
3730
4133
|
} finally {
|
|
4134
|
+
if (streamUpdateRaf != null) {
|
|
4135
|
+
cancelAnimationFrame(streamUpdateRaf);
|
|
4136
|
+
streamUpdateRaf = null;
|
|
4137
|
+
}
|
|
4138
|
+
if (streamGeneration !== streamGenerationRef.current) {
|
|
4139
|
+
return;
|
|
4140
|
+
}
|
|
4141
|
+
flushPendingStreamUpdate();
|
|
3731
4142
|
if (abortControllerRef.current === abortController) {
|
|
3732
4143
|
abortControllerRef.current = null;
|
|
3733
4144
|
}
|
|
@@ -3758,7 +4169,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3758
4169
|
});
|
|
3759
4170
|
return run;
|
|
3760
4171
|
},
|
|
3761
|
-
[
|
|
4172
|
+
[onError]
|
|
3762
4173
|
);
|
|
3763
4174
|
const load = useCallback2(async () => {
|
|
3764
4175
|
if (sessionId == null) {
|
|
@@ -3766,22 +4177,35 @@ function useTrueFoundryAgentMessages({
|
|
|
3766
4177
|
setSnapshot(createEmptySessionSnapshot());
|
|
3767
4178
|
return;
|
|
3768
4179
|
}
|
|
4180
|
+
if (isMain === false) return;
|
|
4181
|
+
if (lazilyCreatedSessionIdRef.current != null && sessionId !== lazilyCreatedSessionIdRef.current) {
|
|
4182
|
+
lazilyCreatedSessionIdRef.current = void 0;
|
|
4183
|
+
}
|
|
3769
4184
|
if (sessionId === lazilyCreatedSessionIdRef.current) {
|
|
3770
4185
|
return;
|
|
3771
4186
|
}
|
|
3772
4187
|
const generation = ++loadGenerationRef.current;
|
|
4188
|
+
++streamGenerationRef.current;
|
|
3773
4189
|
abortControllerRef.current?.abort();
|
|
4190
|
+
loadOlderInflightRef.current = null;
|
|
4191
|
+
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
4192
|
+
setSnapshot(createEmptySessionSnapshot());
|
|
3774
4193
|
setIsLoading(true);
|
|
4194
|
+
setIsLoadingOlderHistory(false);
|
|
3775
4195
|
try {
|
|
3776
4196
|
const conversationSessionId = await resolveActiveSessionId(
|
|
3777
4197
|
sessionId,
|
|
3778
|
-
|
|
4198
|
+
resolveConversationSessionIdRef.current
|
|
3779
4199
|
);
|
|
3780
4200
|
const loadedSnapshot = await loadSessionSnapshot(
|
|
3781
4201
|
client,
|
|
3782
4202
|
conversationSessionId,
|
|
3783
|
-
|
|
3784
|
-
|
|
4203
|
+
sessionOptions,
|
|
4204
|
+
(snap) => {
|
|
4205
|
+
if (generation === loadGenerationRef.current) {
|
|
4206
|
+
setSnapshot(snap);
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
3785
4209
|
);
|
|
3786
4210
|
if (generation !== loadGenerationRef.current) {
|
|
3787
4211
|
return;
|
|
@@ -3789,30 +4213,33 @@ function useTrueFoundryAgentMessages({
|
|
|
3789
4213
|
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3790
4214
|
setSnapshot(loadedSnapshot);
|
|
3791
4215
|
runningTurnRef.current = loadedSnapshot.runningTurn;
|
|
4216
|
+
setIsLoading(false);
|
|
3792
4217
|
if (loadedSnapshot.runningTurn != null) {
|
|
3793
4218
|
const turn = loadedSnapshot.runningTurn;
|
|
3794
4219
|
const isContinuation = !extractTurnUserText(turn.input);
|
|
3795
|
-
|
|
4220
|
+
void runStream(
|
|
3796
4221
|
(signal) => resumeTurnStream(
|
|
3797
4222
|
turn,
|
|
3798
|
-
|
|
4223
|
+
loadedSnapshot.fold,
|
|
3799
4224
|
signal,
|
|
3800
4225
|
void 0,
|
|
3801
|
-
|
|
4226
|
+
loadedSnapshot.groupRootBaseline
|
|
3802
4227
|
),
|
|
3803
4228
|
turn.id,
|
|
3804
4229
|
isContinuation
|
|
3805
|
-
);
|
|
4230
|
+
).catch(() => void 0);
|
|
3806
4231
|
}
|
|
3807
4232
|
} catch (error) {
|
|
3808
|
-
|
|
4233
|
+
if (generation === loadGenerationRef.current) {
|
|
4234
|
+
onErrorRef.current?.(error);
|
|
4235
|
+
}
|
|
3809
4236
|
throw error;
|
|
3810
4237
|
} finally {
|
|
3811
4238
|
if (generation === loadGenerationRef.current) {
|
|
3812
4239
|
setIsLoading(false);
|
|
3813
4240
|
}
|
|
3814
4241
|
}
|
|
3815
|
-
}, [client,
|
|
4242
|
+
}, [client, runStream, sessionId, sessionOptions, loadRetryTrigger, isMain]);
|
|
3816
4243
|
useEffect2(() => {
|
|
3817
4244
|
void load().catch(() => void 0);
|
|
3818
4245
|
}, [load]);
|
|
@@ -3820,18 +4247,20 @@ function useTrueFoundryAgentMessages({
|
|
|
3820
4247
|
async (options) => {
|
|
3821
4248
|
let activeSessionId = sessionId;
|
|
3822
4249
|
if (activeSessionId == null) {
|
|
3823
|
-
if (
|
|
4250
|
+
if (initializeSessionRef.current == null) {
|
|
3824
4251
|
throw new Error("Cannot send a turn without an active session.");
|
|
3825
4252
|
}
|
|
3826
|
-
const { remoteId } = await
|
|
4253
|
+
const { remoteId } = await initializeSessionRef.current();
|
|
3827
4254
|
activeSessionId = remoteId;
|
|
3828
4255
|
lazilyCreatedSessionIdRef.current = remoteId;
|
|
3829
4256
|
}
|
|
3830
4257
|
const conversationSessionId = await resolveActiveSessionId(
|
|
3831
4258
|
activeSessionId,
|
|
3832
|
-
|
|
4259
|
+
resolveConversationSessionIdRef.current
|
|
3833
4260
|
);
|
|
3834
4261
|
const session = await getSession(client, conversationSessionId, sessionOptions);
|
|
4262
|
+
const turnHeaders = await getTurnHeadersRef.current?.();
|
|
4263
|
+
const streamHeaders = turnHeaders != null ? { headers: turnHeaders } : {};
|
|
3835
4264
|
const isContinuation = "inputs" in options || "resumeMcpAuth" in options && options.resumeMcpAuth === true;
|
|
3836
4265
|
const continuationTurnId = snapshotRef.current.activeStream?.turnId;
|
|
3837
4266
|
const turnId = isContinuation && continuationTurnId != null ? continuationTurnId : generateId();
|
|
@@ -3841,29 +4270,48 @@ function useTrueFoundryAgentMessages({
|
|
|
3841
4270
|
options.inputs
|
|
3842
4271
|
);
|
|
3843
4272
|
}
|
|
3844
|
-
|
|
3845
|
-
(prev) => commitActiveStream(
|
|
3846
|
-
prev,
|
|
3847
|
-
"inputs" in options ? options.inputs : void 0
|
|
3848
|
-
)
|
|
3849
|
-
);
|
|
4273
|
+
const branchBase = "userMessage" in options ? options.branchFromSnapshot : void 0;
|
|
3850
4274
|
let groupRootBaseline;
|
|
3851
|
-
if ("userMessage" in options) {
|
|
3852
|
-
const rootBucket =
|
|
4275
|
+
if (branchBase != null && "userMessage" in options) {
|
|
4276
|
+
const rootBucket = branchBase.fold.threads.get(ROOT_THREAD_ID);
|
|
3853
4277
|
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
4278
|
+
const nextSnapshot = replaceSessionSnapshot(branchBase, {
|
|
4279
|
+
pendingUser: {
|
|
4280
|
+
turnId,
|
|
4281
|
+
content: options.userMessage,
|
|
4282
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
4283
|
+
},
|
|
4284
|
+
activeStream: void 0,
|
|
4285
|
+
groupRootBaseline
|
|
4286
|
+
});
|
|
4287
|
+
snapshotRef.current = nextSnapshot;
|
|
4288
|
+
setSnapshot(nextSnapshot);
|
|
4289
|
+
} else {
|
|
3854
4290
|
setSnapshot(
|
|
3855
|
-
(prev) =>
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
3860
|
-
},
|
|
3861
|
-
activeStream: void 0,
|
|
3862
|
-
groupRootBaseline
|
|
3863
|
-
})
|
|
4291
|
+
(prev) => commitActiveStream(
|
|
4292
|
+
prev,
|
|
4293
|
+
"inputs" in options ? options.inputs : void 0
|
|
4294
|
+
)
|
|
3864
4295
|
);
|
|
3865
|
-
|
|
3866
|
-
|
|
4296
|
+
if ("userMessage" in options) {
|
|
4297
|
+
const rootBucket = snapshotRef.current.fold.threads.get(ROOT_THREAD_ID);
|
|
4298
|
+
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
4299
|
+
setSnapshot((prev) => {
|
|
4300
|
+
const next = replaceSessionSnapshot(prev, {
|
|
4301
|
+
pendingUser: {
|
|
4302
|
+
turnId,
|
|
4303
|
+
content: options.userMessage,
|
|
4304
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
4305
|
+
},
|
|
4306
|
+
activeStream: void 0,
|
|
4307
|
+
groupRootBaseline
|
|
4308
|
+
});
|
|
4309
|
+
snapshotRef.current = next;
|
|
4310
|
+
return next;
|
|
4311
|
+
});
|
|
4312
|
+
} else {
|
|
4313
|
+
groupRootBaseline = snapshotRef.current.groupRootBaseline ?? computeGroupRootBaseline(snapshotRef.current.turns);
|
|
4314
|
+
}
|
|
3867
4315
|
}
|
|
3868
4316
|
await runStream(
|
|
3869
4317
|
(signal) => {
|
|
@@ -3871,7 +4319,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3871
4319
|
return streamTurnContent(
|
|
3872
4320
|
session,
|
|
3873
4321
|
snapshotRef.current.fold,
|
|
3874
|
-
{ inputs: options.inputs },
|
|
4322
|
+
{ inputs: options.inputs, ...streamHeaders },
|
|
3875
4323
|
signal,
|
|
3876
4324
|
groupRootBaseline
|
|
3877
4325
|
);
|
|
@@ -3880,7 +4328,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3880
4328
|
return streamTurnContent(
|
|
3881
4329
|
session,
|
|
3882
4330
|
snapshotRef.current.fold,
|
|
3883
|
-
{ resumeMcpAuth: true },
|
|
4331
|
+
{ resumeMcpAuth: true, ...streamHeaders },
|
|
3884
4332
|
signal,
|
|
3885
4333
|
groupRootBaseline
|
|
3886
4334
|
);
|
|
@@ -3890,7 +4338,8 @@ function useTrueFoundryAgentMessages({
|
|
|
3890
4338
|
snapshotRef.current.fold,
|
|
3891
4339
|
{
|
|
3892
4340
|
userMessage: options.userMessage,
|
|
3893
|
-
...options.previousTurnId !== void 0 ? { previousTurnId: options.previousTurnId } : {}
|
|
4341
|
+
...options.previousTurnId !== void 0 ? { previousTurnId: options.previousTurnId } : {},
|
|
4342
|
+
...streamHeaders
|
|
3894
4343
|
},
|
|
3895
4344
|
signal,
|
|
3896
4345
|
groupRootBaseline
|
|
@@ -3900,7 +4349,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3900
4349
|
isContinuation
|
|
3901
4350
|
);
|
|
3902
4351
|
},
|
|
3903
|
-
[client,
|
|
4352
|
+
[client, runStream, sessionId, sessionOptions]
|
|
3904
4353
|
);
|
|
3905
4354
|
const cancel = useCallback2(async () => {
|
|
3906
4355
|
if (sessionId == null) {
|
|
@@ -3909,12 +4358,12 @@ function useTrueFoundryAgentMessages({
|
|
|
3909
4358
|
}
|
|
3910
4359
|
const conversationSessionId = await resolveActiveSessionId(
|
|
3911
4360
|
sessionId,
|
|
3912
|
-
|
|
4361
|
+
resolveConversationSessionIdRef.current
|
|
3913
4362
|
);
|
|
3914
4363
|
const session = await getSession(client, conversationSessionId, sessionOptions);
|
|
3915
4364
|
await session.cancel().catch(() => void 0);
|
|
3916
4365
|
await activeRunRef.current?.catch(() => void 0);
|
|
3917
|
-
}, [client,
|
|
4366
|
+
}, [client, sessionId, sessionOptions]);
|
|
3918
4367
|
const isRunningRef = useRef2(isRunning);
|
|
3919
4368
|
isRunningRef.current = isRunning;
|
|
3920
4369
|
const trySendCollectedRequiredActions = useCallback2(
|
|
@@ -3929,10 +4378,10 @@ function useTrueFoundryAgentMessages({
|
|
|
3929
4378
|
}
|
|
3930
4379
|
const inputs = collectRequiredActionInputs(paused);
|
|
3931
4380
|
if (inputs.length > 0) {
|
|
3932
|
-
void sendTurn({ inputs }).catch((error) =>
|
|
4381
|
+
void sendTurn({ inputs }).catch((error) => onErrorRef.current?.(error));
|
|
3933
4382
|
}
|
|
3934
4383
|
},
|
|
3935
|
-
[
|
|
4384
|
+
[projectOptions, sendTurn]
|
|
3936
4385
|
);
|
|
3937
4386
|
const respondToToolApproval = useCallback2(
|
|
3938
4387
|
(response) => {
|
|
@@ -3994,34 +4443,34 @@ function useTrueFoundryAgentMessages({
|
|
|
3994
4443
|
}
|
|
3995
4444
|
const committed = commitActiveStream(snapshotRef.current);
|
|
3996
4445
|
setSnapshot(committed);
|
|
3997
|
-
const turnIndex = findTurnIndex(committed, turnId);
|
|
3998
4446
|
await cancel();
|
|
3999
4447
|
const conversationSessionId = await resolveActiveSessionId(
|
|
4000
4448
|
activeSessionId,
|
|
4001
|
-
|
|
4449
|
+
resolveConversationSessionIdRef.current
|
|
4002
4450
|
);
|
|
4003
4451
|
const session = await getSession(client, conversationSessionId, sessionOptions);
|
|
4004
|
-
const previousTurnId = await
|
|
4452
|
+
const previousTurnId = await resolveGatewayBranchPreviousTurnIdForTurn(
|
|
4005
4453
|
session,
|
|
4006
|
-
|
|
4454
|
+
turnId
|
|
4007
4455
|
);
|
|
4008
|
-
const rewound = await
|
|
4456
|
+
const rewound = await buildSnapshotBeforeTurn(
|
|
4009
4457
|
session,
|
|
4010
|
-
|
|
4458
|
+
turnId,
|
|
4011
4459
|
listEventsConcurrency
|
|
4012
4460
|
);
|
|
4013
4461
|
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
4462
|
+
snapshotRef.current = rewound;
|
|
4014
4463
|
setSnapshot(rewound);
|
|
4015
4464
|
await sendTurn({
|
|
4016
4465
|
userMessage,
|
|
4017
|
-
previousTurnId
|
|
4466
|
+
previousTurnId,
|
|
4467
|
+
branchFromSnapshot: rewound
|
|
4018
4468
|
});
|
|
4019
4469
|
},
|
|
4020
4470
|
[
|
|
4021
4471
|
cancel,
|
|
4022
4472
|
client,
|
|
4023
4473
|
listEventsConcurrency,
|
|
4024
|
-
resolveConversationSessionId,
|
|
4025
4474
|
sendTurn,
|
|
4026
4475
|
sessionId,
|
|
4027
4476
|
sessionOptions
|
|
@@ -4054,11 +4503,68 @@ function useTrueFoundryAgentMessages({
|
|
|
4054
4503
|
},
|
|
4055
4504
|
[branchFromTurn]
|
|
4056
4505
|
);
|
|
4506
|
+
const retryLoad = useCallback2(() => {
|
|
4507
|
+
setLoadRetryTrigger((n) => n + 1);
|
|
4508
|
+
}, []);
|
|
4509
|
+
const hasOlderHistory = snapshot.historyPagination?.hasOlder === true;
|
|
4510
|
+
const loadOlderHistory = useCallback2(async () => {
|
|
4511
|
+
if (sessionId == null || isMain === false) {
|
|
4512
|
+
return;
|
|
4513
|
+
}
|
|
4514
|
+
if (loadOlderInflightRef.current != null) {
|
|
4515
|
+
return loadOlderInflightRef.current;
|
|
4516
|
+
}
|
|
4517
|
+
const current = snapshotRef.current;
|
|
4518
|
+
if (current.historyPagination?.hasOlder !== true) {
|
|
4519
|
+
return;
|
|
4520
|
+
}
|
|
4521
|
+
if (current.historyPagination.olderPageToken == null) {
|
|
4522
|
+
return;
|
|
4523
|
+
}
|
|
4524
|
+
const generation = loadGenerationRef.current;
|
|
4525
|
+
setIsLoadingOlderHistory(true);
|
|
4526
|
+
const run = (async () => {
|
|
4527
|
+
try {
|
|
4528
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
4529
|
+
sessionId,
|
|
4530
|
+
resolveConversationSessionIdRef.current
|
|
4531
|
+
);
|
|
4532
|
+
const session = await getSession(
|
|
4533
|
+
client,
|
|
4534
|
+
conversationSessionId,
|
|
4535
|
+
sessionOptions
|
|
4536
|
+
);
|
|
4537
|
+
const next = await prependOlderSessionHistory(
|
|
4538
|
+
session,
|
|
4539
|
+
snapshotRef.current
|
|
4540
|
+
);
|
|
4541
|
+
if (generation !== loadGenerationRef.current) {
|
|
4542
|
+
return;
|
|
4543
|
+
}
|
|
4544
|
+
setSnapshot(next);
|
|
4545
|
+
} catch (error) {
|
|
4546
|
+
if (generation === loadGenerationRef.current) {
|
|
4547
|
+
onErrorRef.current?.(error);
|
|
4548
|
+
}
|
|
4549
|
+
throw error;
|
|
4550
|
+
} finally {
|
|
4551
|
+
if (generation === loadGenerationRef.current) {
|
|
4552
|
+
setIsLoadingOlderHistory(false);
|
|
4553
|
+
}
|
|
4554
|
+
loadOlderInflightRef.current = null;
|
|
4555
|
+
}
|
|
4556
|
+
})();
|
|
4557
|
+
loadOlderInflightRef.current = run;
|
|
4558
|
+
return run;
|
|
4559
|
+
}, [client, isMain, sessionId, sessionOptions]);
|
|
4057
4560
|
return {
|
|
4058
4561
|
messages,
|
|
4059
4562
|
isRunning,
|
|
4060
4563
|
isLoading,
|
|
4061
|
-
|
|
4564
|
+
isLoadingOlderHistory,
|
|
4565
|
+
hasOlderHistory,
|
|
4566
|
+
loadOlderHistory,
|
|
4567
|
+
retryLoad,
|
|
4062
4568
|
sendTurn,
|
|
4063
4569
|
cancel,
|
|
4064
4570
|
respondToToolApproval,
|
|
@@ -4088,6 +4594,9 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
4088
4594
|
(state) => agent.mode === "draft" ? state.threadListItem.remoteId ?? void 0 : void 0
|
|
4089
4595
|
);
|
|
4090
4596
|
const sessionId = useAuiState((state) => state.threadListItem.remoteId ?? void 0);
|
|
4597
|
+
const isMain = useAuiState(
|
|
4598
|
+
(state) => state.threads.mainThreadId === state.threadListItem.id
|
|
4599
|
+
);
|
|
4091
4600
|
const draftSpec = useDraftAgentSpec({
|
|
4092
4601
|
draftSessionId,
|
|
4093
4602
|
draftBridge: draftBridgeRef.current,
|
|
@@ -4095,6 +4604,18 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
4095
4604
|
onAgentSpecChange: agent.mode === "draft" ? agent.onAgentSpecChange : void 0,
|
|
4096
4605
|
onError
|
|
4097
4606
|
});
|
|
4607
|
+
const takeTurnHeaderTimestampRef = useRef3(draftSpec.takeTurnHeaderTimestamp);
|
|
4608
|
+
takeTurnHeaderTimestampRef.current = draftSpec.takeTurnHeaderTimestamp;
|
|
4609
|
+
const getTurnHeaders = useCallback3(async () => {
|
|
4610
|
+
if (agent.mode !== "draft") {
|
|
4611
|
+
return void 0;
|
|
4612
|
+
}
|
|
4613
|
+
const updatedAt = await takeTurnHeaderTimestampRef.current();
|
|
4614
|
+
if (updatedAt == null) {
|
|
4615
|
+
return void 0;
|
|
4616
|
+
}
|
|
4617
|
+
return { [DRAFT_SESSION_LAST_UPDATED_AT_HEADER]: updatedAt };
|
|
4618
|
+
}, [agent.mode]);
|
|
4098
4619
|
const aui = useAui();
|
|
4099
4620
|
const initializeSession = useCallback3(
|
|
4100
4621
|
() => aui.threadListItem().initialize(),
|
|
@@ -4106,20 +4627,26 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
4106
4627
|
messages,
|
|
4107
4628
|
isRunning,
|
|
4108
4629
|
isLoading,
|
|
4630
|
+
isLoadingOlderHistory,
|
|
4631
|
+
hasOlderHistory,
|
|
4632
|
+
loadOlderHistory,
|
|
4109
4633
|
sendTurn,
|
|
4110
4634
|
cancel,
|
|
4111
4635
|
respondToToolApproval,
|
|
4112
4636
|
respondToToolResponse,
|
|
4113
4637
|
resumeRun,
|
|
4114
4638
|
editFromTurn,
|
|
4115
|
-
resetFromTurn
|
|
4639
|
+
resetFromTurn,
|
|
4640
|
+
retryLoad
|
|
4116
4641
|
} = useTrueFoundryAgentMessages({
|
|
4117
4642
|
client,
|
|
4118
4643
|
sessionId,
|
|
4644
|
+
isMain,
|
|
4119
4645
|
listEventsConcurrency,
|
|
4120
4646
|
onError,
|
|
4121
4647
|
initializeSession,
|
|
4122
|
-
draftGateway: agent.mode === "draft" ? gateway : void 0
|
|
4648
|
+
draftGateway: agent.mode === "draft" ? gateway : void 0,
|
|
4649
|
+
getTurnHeaders: agent.mode === "draft" ? getTurnHeaders : void 0
|
|
4123
4650
|
});
|
|
4124
4651
|
if (agent.mode === "draft" && draftSpec.agentSpec != null) {
|
|
4125
4652
|
pendingAgentSpecRef.current = draftSpec.agentSpec;
|
|
@@ -4187,6 +4714,10 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
4187
4714
|
resetFromTurn: (turnId) => resetFromTurn(turnId).catch((error) => {
|
|
4188
4715
|
onError?.(error);
|
|
4189
4716
|
}),
|
|
4717
|
+
reload: retryLoad,
|
|
4718
|
+
hasOlderHistory,
|
|
4719
|
+
isLoadingOlderHistory,
|
|
4720
|
+
loadOlderHistory,
|
|
4190
4721
|
draft: draftExtras
|
|
4191
4722
|
}),
|
|
4192
4723
|
unstable_enableToolInvocations: true,
|
|
@@ -4235,32 +4766,32 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
4235
4766
|
});
|
|
4236
4767
|
}
|
|
4237
4768
|
function useTrueFoundryAgentRuntime(options) {
|
|
4238
|
-
const resolved =
|
|
4239
|
-
() => resolveTrueFoundryAgentRuntimeOptions(options),
|
|
4240
|
-
[options]
|
|
4241
|
-
);
|
|
4769
|
+
const resolved = resolveTrueFoundryAgentRuntimeOptions(options);
|
|
4242
4770
|
const { client, agent, gateway } = resolved;
|
|
4243
4771
|
const pendingAgentSpecRef = useRef3(
|
|
4244
4772
|
agent.mode === "draft" ? agent.defaultAgentSpec : void 0
|
|
4245
4773
|
);
|
|
4774
|
+
const agentMode = agent.mode;
|
|
4775
|
+
const namedAgentName = agent.mode === "named" ? agent.agentName : void 0;
|
|
4246
4776
|
const threadListAdapter = useMemo3(() => {
|
|
4247
|
-
if (
|
|
4777
|
+
if (agentMode === "draft") {
|
|
4248
4778
|
if (gateway == null) {
|
|
4249
4779
|
throw new Error(
|
|
4250
4780
|
"Draft agent mode requires a `gateway` TrueFoundryGateway client."
|
|
4251
4781
|
);
|
|
4252
4782
|
}
|
|
4783
|
+
const draftAgent = agent;
|
|
4253
4784
|
return createTrueFoundryDraftThreadListAdapter({
|
|
4254
4785
|
gateway,
|
|
4255
|
-
defaultAgentSpec:
|
|
4256
|
-
getAgentSpec: () => pendingAgentSpecRef.current ??
|
|
4786
|
+
defaultAgentSpec: draftAgent.defaultAgentSpec,
|
|
4787
|
+
getAgentSpec: () => pendingAgentSpecRef.current ?? draftAgent.defaultAgentSpec
|
|
4257
4788
|
});
|
|
4258
4789
|
}
|
|
4259
4790
|
return createTrueFoundryThreadListAdapter({
|
|
4260
4791
|
client,
|
|
4261
|
-
agentName:
|
|
4792
|
+
agentName: namedAgentName
|
|
4262
4793
|
});
|
|
4263
|
-
}, [
|
|
4794
|
+
}, [agentMode, namedAgentName, client, gateway]);
|
|
4264
4795
|
return useRemoteThreadListRuntime({
|
|
4265
4796
|
allowNesting: true,
|
|
4266
4797
|
adapter: threadListAdapter,
|
|
@@ -4331,6 +4862,23 @@ var useTrueFoundryCancel = () => {
|
|
|
4331
4862
|
const aui = useAui2();
|
|
4332
4863
|
return () => trueFoundryExtras.get(aui).cancel();
|
|
4333
4864
|
};
|
|
4865
|
+
var useTrueFoundryReload = () => {
|
|
4866
|
+
const aui = useAui2();
|
|
4867
|
+
return () => trueFoundryExtras.get(aui).reload();
|
|
4868
|
+
};
|
|
4869
|
+
var useTrueFoundryHistoryPagination = () => {
|
|
4870
|
+
const extras = trueFoundryExtras.use((e) => e, void 0);
|
|
4871
|
+
return useMemo4(
|
|
4872
|
+
() => ({
|
|
4873
|
+
hasOlderHistory: extras?.hasOlderHistory ?? false,
|
|
4874
|
+
isLoadingOlderHistory: extras?.isLoadingOlderHistory ?? false,
|
|
4875
|
+
loadOlderHistory: extras?.loadOlderHistory ?? (async () => {
|
|
4876
|
+
throw new Error("TrueFoundry runtime is not ready yet");
|
|
4877
|
+
})
|
|
4878
|
+
}),
|
|
4879
|
+
[extras]
|
|
4880
|
+
);
|
|
4881
|
+
};
|
|
4334
4882
|
var useTrueFoundryResetFromTurn = () => {
|
|
4335
4883
|
const aui = useAui2();
|
|
4336
4884
|
return (turnId) => trueFoundryExtras.get(aui).resetFromTurn(turnId);
|
|
@@ -4428,7 +4976,9 @@ export {
|
|
|
4428
4976
|
useTrueFoundryApprovals,
|
|
4429
4977
|
useTrueFoundryCancel,
|
|
4430
4978
|
useTrueFoundryDownloadSandboxFile,
|
|
4979
|
+
useTrueFoundryHistoryPagination,
|
|
4431
4980
|
useTrueFoundryMcpAuth,
|
|
4981
|
+
useTrueFoundryReload,
|
|
4432
4982
|
useTrueFoundryResetFromTurn,
|
|
4433
4983
|
useTrueFoundryRespondToToolApproval,
|
|
4434
4984
|
useTrueFoundryRespondToToolResponse,
|