@dudousxd/nestjs-agent-react 0.31.5 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{client-BuobfZtx.d.cts → client-B6EE8-AC.d.cts} +39 -2
- package/dist/{client-BuobfZtx.d.ts → client-B6EE8-AC.d.ts} +39 -2
- package/dist/{generative-ui-VTZ1EADD.d.cts → generative-ui-DOe2RsoO.d.cts} +35 -9
- package/dist/{generative-ui-VTZ1EADD.d.ts → generative-ui-DOe2RsoO.d.ts} +35 -9
- package/dist/genui-json-render.cjs +51 -8
- package/dist/genui-json-render.cjs.map +1 -1
- package/dist/genui-json-render.d.cts +1 -1
- package/dist/genui-json-render.d.ts +1 -1
- package/dist/genui-json-render.js +51 -8
- package/dist/genui-json-render.js.map +1 -1
- package/dist/genui.cjs +51 -8
- package/dist/genui.cjs.map +1 -1
- package/dist/genui.d.cts +2 -2
- package/dist/genui.d.ts +2 -2
- package/dist/genui.js +51 -8
- package/dist/genui.js.map +1 -1
- package/dist/index.cjs +581 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -12
- package/dist/index.d.ts +56 -12
- package/dist/index.js +625 -171
- package/dist/index.js.map +1 -1
- package/dist/media.cjs.map +1 -1
- package/dist/media.d.cts +1 -1
- package/dist/media.d.ts +1 -1
- package/dist/media.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9,9 +9,9 @@ function readErrorAnswer(text) {
|
|
|
9
9
|
}
|
|
10
10
|
if (body === null || typeof body !== "object")
|
|
11
11
|
return { body, message: void 0, code: void 0 };
|
|
12
|
-
const
|
|
13
|
-
const message = typeof
|
|
14
|
-
const code = typeof
|
|
12
|
+
const record2 = body;
|
|
13
|
+
const message = typeof record2.message === "string" && record2.message !== "" ? record2.message : Array.isArray(record2.message) && record2.message.length > 0 && record2.message.every((each) => typeof each === "string") ? record2.message.join("; ") : void 0;
|
|
14
|
+
const code = typeof record2.code === "string" && record2.code !== "" ? record2.code : void 0;
|
|
15
15
|
return { body, message, code };
|
|
16
16
|
}
|
|
17
17
|
async function readErrorResponse(response) {
|
|
@@ -88,6 +88,12 @@ var AgentClient = class {
|
|
|
88
88
|
if (response.status === 202) {
|
|
89
89
|
return { body: emptyStream(), queued: await response.json() };
|
|
90
90
|
}
|
|
91
|
+
if (response.ok && response.headers.get("content-type")?.includes("application/json")) {
|
|
92
|
+
const decision = await response.json();
|
|
93
|
+
if (decision.proposalDecision !== void 0 && typeof decision.threadId === "string")
|
|
94
|
+
return { body: emptyStream(), threadId: decision.threadId, proposalDecision: decision };
|
|
95
|
+
throw new Error("Unexpected JSON chat response");
|
|
96
|
+
}
|
|
91
97
|
if (!response.ok || !response.body) {
|
|
92
98
|
throw await this.failure(response, "POST", `${this.agentPath()}/chat`);
|
|
93
99
|
}
|
|
@@ -320,6 +326,54 @@ var AgentClient = class {
|
|
|
320
326
|
* `remember` approves later calls of the same tool in the same thread; `via` names the surface
|
|
321
327
|
* the decision came through (the server records `'web'` when omitted).
|
|
322
328
|
*/
|
|
329
|
+
async listActionProposals({ threadId }) {
|
|
330
|
+
const proposals = /* @__PURE__ */ new Map();
|
|
331
|
+
let after;
|
|
332
|
+
for (; ; ) {
|
|
333
|
+
const route = `/threads/${encodeURIComponent(threadId)}/action-proposals${after === void 0 ? "" : `?after=${encodeURIComponent(JSON.stringify(after))}`}`;
|
|
334
|
+
const response = await this.requestResponse("GET", route);
|
|
335
|
+
const page = await this.handleResponse(
|
|
336
|
+
response,
|
|
337
|
+
"GET",
|
|
338
|
+
`${this.agentPath()}${route}`
|
|
339
|
+
);
|
|
340
|
+
if (!Array.isArray(page)) throw new TypeError("Invalid action proposal page");
|
|
341
|
+
for (const proposal of page) proposals.set(proposal.id, proposal);
|
|
342
|
+
const header = response.headers.get("X-Action-Proposals-Next");
|
|
343
|
+
if (header === null) return [...proposals.values()];
|
|
344
|
+
let next;
|
|
345
|
+
try {
|
|
346
|
+
next = JSON.parse(decodeURIComponent(header));
|
|
347
|
+
} catch {
|
|
348
|
+
throw new TypeError("Invalid action proposal cursor");
|
|
349
|
+
}
|
|
350
|
+
if (typeof next !== "object" || next === null || !("createdAt" in next) || typeof next.createdAt !== "number" || !Number.isSafeInteger(next.createdAt) || !("id" in next) || typeof next.id !== "string" || next.id.length === 0 || next.id.length > 255 || after !== void 0 && (next.createdAt < after.createdAt || next.createdAt === after.createdAt && next.id <= after.id))
|
|
351
|
+
throw new TypeError("Invalid or non-advancing action proposal cursor");
|
|
352
|
+
after = { createdAt: next.createdAt, id: next.id };
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
approveActionProposal({
|
|
356
|
+
threadId,
|
|
357
|
+
proposalId,
|
|
358
|
+
remember
|
|
359
|
+
}) {
|
|
360
|
+
return this.request(
|
|
361
|
+
"POST",
|
|
362
|
+
`/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/approve`,
|
|
363
|
+
remember === void 0 ? {} : { remember }
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
rejectActionProposal({
|
|
367
|
+
threadId,
|
|
368
|
+
proposalId,
|
|
369
|
+
reason
|
|
370
|
+
}) {
|
|
371
|
+
return this.request(
|
|
372
|
+
"POST",
|
|
373
|
+
`/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/reject`,
|
|
374
|
+
reason === void 0 ? {} : { reason }
|
|
375
|
+
);
|
|
376
|
+
}
|
|
323
377
|
approveToolCall(input) {
|
|
324
378
|
return this.request("POST", "/tool-call/approve", input);
|
|
325
379
|
}
|
|
@@ -376,6 +430,10 @@ var AgentClient = class {
|
|
|
376
430
|
return this.options.credentials !== void 0 ? { credentials: this.options.credentials } : {};
|
|
377
431
|
}
|
|
378
432
|
async request(method, route, body) {
|
|
433
|
+
const response = await this.requestResponse(method, route, body);
|
|
434
|
+
return this.handleResponse(response, method, `${this.agentPath()}${route}`);
|
|
435
|
+
}
|
|
436
|
+
async requestResponse(method, route, body) {
|
|
379
437
|
const path = `${this.agentPath()}${route}`;
|
|
380
438
|
const response = await this.fetchImpl()(`${this.baseUrl()}${path}`, {
|
|
381
439
|
method,
|
|
@@ -387,7 +445,7 @@ var AgentClient = class {
|
|
|
387
445
|
...body !== void 0 ? { body: JSON.stringify(body) } : {},
|
|
388
446
|
...this.credentials()
|
|
389
447
|
});
|
|
390
|
-
return
|
|
448
|
+
return response;
|
|
391
449
|
}
|
|
392
450
|
/** The error for a refused `response`, already reported to `onHttpError`. */
|
|
393
451
|
async failure(response, method, path) {
|
|
@@ -527,6 +585,7 @@ var AgentChatTransport = class {
|
|
|
527
585
|
const message = lastMessage ? extractText(lastMessage) : "";
|
|
528
586
|
const body = {
|
|
529
587
|
...this.options.agent !== void 0 ? { agent: this.options.agent } : {},
|
|
588
|
+
...this.options.persona !== void 0 ? { persona: this.options.persona } : {},
|
|
530
589
|
...this.options.getBody?.() ?? {},
|
|
531
590
|
...options.body ?? {},
|
|
532
591
|
message
|
|
@@ -542,6 +601,10 @@ var AgentChatTransport = class {
|
|
|
542
601
|
return queuedChunkStream(response.queued);
|
|
543
602
|
}
|
|
544
603
|
this.captureHeaderMeta(response);
|
|
604
|
+
if (response.proposalDecision !== void 0) {
|
|
605
|
+
this.attemptLive = false;
|
|
606
|
+
return proposalDecisionChunkStream(response.proposalDecision);
|
|
607
|
+
}
|
|
545
608
|
return this.toChunkStream(response, {
|
|
546
609
|
...headers !== void 0 ? { headers } : {},
|
|
547
610
|
...options.abortSignal ? { signal: options.abortSignal } : {}
|
|
@@ -668,7 +731,7 @@ var AgentChatTransport = class {
|
|
|
668
731
|
let reasoningSeq = 0;
|
|
669
732
|
const announced = /* @__PURE__ */ new Set();
|
|
670
733
|
const toolMetadata = /* @__PURE__ */ new Map();
|
|
671
|
-
const
|
|
734
|
+
const record2 = (meta) => {
|
|
672
735
|
streamRunId = meta.runId;
|
|
673
736
|
this.recordMeta(meta);
|
|
674
737
|
};
|
|
@@ -956,7 +1019,7 @@ var AgentChatTransport = class {
|
|
|
956
1019
|
}
|
|
957
1020
|
if (frame.event === "meta") {
|
|
958
1021
|
const meta = parseMeta(frame.data);
|
|
959
|
-
if (meta)
|
|
1022
|
+
if (meta) record2(meta);
|
|
960
1023
|
} else if (frame.data) {
|
|
961
1024
|
const event = parseEvent(frame.data);
|
|
962
1025
|
if (event) emit(event);
|
|
@@ -1024,10 +1087,10 @@ function parseErrorFrame(data) {
|
|
|
1024
1087
|
try {
|
|
1025
1088
|
const parsed = JSON.parse(data);
|
|
1026
1089
|
if (parsed !== null && typeof parsed === "object") {
|
|
1027
|
-
const
|
|
1090
|
+
const record2 = parsed;
|
|
1028
1091
|
return {
|
|
1029
|
-
code: typeof
|
|
1030
|
-
message: typeof
|
|
1092
|
+
code: typeof record2.code === "string" && record2.code !== "" ? record2.code : void 0,
|
|
1093
|
+
message: typeof record2.message === "string" && record2.message !== "" ? record2.message : fallback2.message
|
|
1031
1094
|
};
|
|
1032
1095
|
}
|
|
1033
1096
|
} catch {
|
|
@@ -1067,6 +1130,21 @@ function delay(ms, signal) {
|
|
|
1067
1130
|
signal?.addEventListener("abort", done, { once: true });
|
|
1068
1131
|
});
|
|
1069
1132
|
}
|
|
1133
|
+
function proposalDecisionChunkStream(decision) {
|
|
1134
|
+
return new ReadableStream({
|
|
1135
|
+
start(controller) {
|
|
1136
|
+
controller.enqueue({ type: "start", messageId: `decision:${crypto.randomUUID()}` });
|
|
1137
|
+
controller.enqueue({ type: "data-proposal-decision", data: decision, transient: true });
|
|
1138
|
+
if (decision.text !== void 0 && decision.text.length > 0) {
|
|
1139
|
+
controller.enqueue({ type: "text-start", id: "decision" });
|
|
1140
|
+
controller.enqueue({ type: "text-delta", id: "decision", delta: decision.text });
|
|
1141
|
+
controller.enqueue({ type: "text-end", id: "decision" });
|
|
1142
|
+
}
|
|
1143
|
+
controller.enqueue({ type: "finish", finishReason: "stop" });
|
|
1144
|
+
controller.close();
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1070
1148
|
|
|
1071
1149
|
// src/attachments/files.ts
|
|
1072
1150
|
function fileKind(mediaType) {
|
|
@@ -1205,6 +1283,10 @@ function toGenerativeUIItem(part) {
|
|
|
1205
1283
|
return {
|
|
1206
1284
|
id,
|
|
1207
1285
|
component: source.component,
|
|
1286
|
+
...isRecord(source.componentVersions) && Object.values(source.componentVersions).every(
|
|
1287
|
+
(version) => typeof version === "number" && Number.isSafeInteger(version) && version > 0
|
|
1288
|
+
) ? { componentVersions: { ...source.componentVersions } } : {},
|
|
1289
|
+
...typeof source.fallbackText === "string" ? { fallbackText: source.fallbackText } : {},
|
|
1208
1290
|
props: isRecord(source.props) ? source.props : {},
|
|
1209
1291
|
version: typeof source.version === "number" ? source.version : null,
|
|
1210
1292
|
toolCallId: typeof source.toolCallId === "string" ? source.toolCallId : null
|
|
@@ -1310,20 +1392,29 @@ function useValidatedProps(catalog, name, props) {
|
|
|
1310
1392
|
function useGenerativeUIState(part, options, fallbackTree) {
|
|
1311
1393
|
const item = useMemo(() => toGenerativeUIItem(part), [part]);
|
|
1312
1394
|
const name = item?.component ?? "";
|
|
1395
|
+
const definition = options.catalog?.get?.(name);
|
|
1396
|
+
const incompatible = item?.fallbackText !== void 0 && item.version !== null && definition !== void 0 && item.version !== (definition.version ?? 1);
|
|
1313
1397
|
const resolution = useResolvedComponent(
|
|
1314
1398
|
name,
|
|
1315
1399
|
item?.version ?? null,
|
|
1316
|
-
options.registry,
|
|
1400
|
+
incompatible ? {} : options.registry,
|
|
1317
1401
|
item === null ? void 0 : options.resolveComponent,
|
|
1318
1402
|
fallbackTree
|
|
1319
1403
|
);
|
|
1320
1404
|
const empty = useMemo(() => ({}), []);
|
|
1321
1405
|
const validation = useValidatedProps(
|
|
1322
|
-
item === null || name === GENUI_TREE_COMPONENT ? void 0 : options.catalog,
|
|
1406
|
+
item === null || name === GENUI_TREE_COMPONENT || incompatible ? void 0 : options.catalog,
|
|
1323
1407
|
name,
|
|
1324
1408
|
item?.props ?? empty
|
|
1325
1409
|
);
|
|
1326
1410
|
if (item === null) return null;
|
|
1411
|
+
if (name === GENUI_TREE_COMPONENT && item.fallbackText !== void 0 && (!isRecord(item.props.root) || typeof item.props.root.type !== "string"))
|
|
1412
|
+
return {
|
|
1413
|
+
status: "problem",
|
|
1414
|
+
reason: "invalid",
|
|
1415
|
+
item,
|
|
1416
|
+
issues: [{ path: ["root"], message: "Invalid UI tree root" }]
|
|
1417
|
+
};
|
|
1327
1418
|
if (resolution.status === "loading") return { status: "loading", item };
|
|
1328
1419
|
if (resolution.status === "unknown") return { status: "problem", reason: "unknown", item };
|
|
1329
1420
|
if (resolution.status === "error") {
|
|
@@ -1341,7 +1432,8 @@ import { jsx } from "react/jsx-runtime";
|
|
|
1341
1432
|
var TreeScopeContext = createContext2(null);
|
|
1342
1433
|
function renderFallback(fallback2, problem) {
|
|
1343
1434
|
if (typeof fallback2 === "function") return fallback2(problem);
|
|
1344
|
-
|
|
1435
|
+
if (fallback2 !== void 0) return fallback2;
|
|
1436
|
+
return problem.item.fallbackText !== void 0 ? /* @__PURE__ */ jsx("span", { style: { whiteSpace: "pre-wrap" }, children: problem.item.fallbackText }) : null;
|
|
1345
1437
|
}
|
|
1346
1438
|
var ItemBoundary = class extends Component {
|
|
1347
1439
|
state = { error: void 0, failed: false };
|
|
@@ -1373,28 +1465,42 @@ function nodeItem(node, id) {
|
|
|
1373
1465
|
function TreeNode({ node, id }) {
|
|
1374
1466
|
const scope = useContext2(TreeScopeContext);
|
|
1375
1467
|
const item = useMemo2(() => nodeItem(node, id), [node, id]);
|
|
1468
|
+
const storedVersion = scope?.componentVersions?.[node.type];
|
|
1469
|
+
const definition = scope?.options.catalog?.get?.(node.type);
|
|
1470
|
+
const incompatible = storedVersion !== void 0 && definition !== void 0 && storedVersion !== (definition.version ?? 1);
|
|
1376
1471
|
const resolution = useResolvedComponent(
|
|
1377
1472
|
node.type,
|
|
1378
|
-
null,
|
|
1379
|
-
scope?.options.registry ?? {},
|
|
1473
|
+
storedVersion ?? null,
|
|
1474
|
+
incompatible ? {} : scope?.options.registry ?? {},
|
|
1380
1475
|
scope?.options.resolveComponent
|
|
1381
1476
|
);
|
|
1382
|
-
const validation = useValidatedProps(
|
|
1477
|
+
const validation = useValidatedProps(
|
|
1478
|
+
incompatible ? void 0 : scope?.options.catalog,
|
|
1479
|
+
node.type,
|
|
1480
|
+
item.props
|
|
1481
|
+
);
|
|
1383
1482
|
if (scope === null) return null;
|
|
1384
1483
|
if (resolution.status === "loading" || validation.status === "pending") return scope.loading;
|
|
1385
1484
|
if (resolution.status === "unknown") {
|
|
1485
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1486
|
+
throw new Error("Unknown tree component");
|
|
1386
1487
|
return renderFallback(scope.fallback, { reason: "unknown", item });
|
|
1387
1488
|
}
|
|
1388
1489
|
if (resolution.status === "error") {
|
|
1490
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0) throw resolution.error;
|
|
1389
1491
|
return renderFallback(scope.fallback, { reason: "error", item, error: resolution.error });
|
|
1390
1492
|
}
|
|
1391
1493
|
if (validation.status === "invalid") {
|
|
1494
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1495
|
+
throw new Error("Invalid tree component");
|
|
1392
1496
|
return renderFallback(scope.fallback, { reason: "invalid", item, issues: validation.issues });
|
|
1393
1497
|
}
|
|
1394
1498
|
const Renderer = resolution.Component;
|
|
1395
1499
|
const children = Array.isArray(node.children) ? node.children : [];
|
|
1396
1500
|
return /* @__PURE__ */ jsx(Renderer, { ...validation.props, children: children.length > 0 ? children.map((child, index) => {
|
|
1397
1501
|
const childId = `${id}.${index}`;
|
|
1502
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1503
|
+
return /* @__PURE__ */ jsx(TreeNode, { node: child, id: childId }, childId);
|
|
1398
1504
|
return /* @__PURE__ */ jsx(
|
|
1399
1505
|
ItemBoundary,
|
|
1400
1506
|
{
|
|
@@ -1416,6 +1522,8 @@ function GenerativeUIScope({
|
|
|
1416
1522
|
catalog,
|
|
1417
1523
|
resolveComponent,
|
|
1418
1524
|
fallback: fallback2,
|
|
1525
|
+
fallbackText,
|
|
1526
|
+
componentVersions,
|
|
1419
1527
|
loading = null,
|
|
1420
1528
|
onError,
|
|
1421
1529
|
children
|
|
@@ -1428,10 +1536,21 @@ function GenerativeUIScope({
|
|
|
1428
1536
|
...resolveComponent !== void 0 ? { resolveComponent } : {}
|
|
1429
1537
|
},
|
|
1430
1538
|
fallback: fallback2,
|
|
1539
|
+
...componentVersions !== void 0 ? { componentVersions } : {},
|
|
1540
|
+
...fallbackText !== void 0 ? { fallbackText } : {},
|
|
1431
1541
|
loading,
|
|
1432
1542
|
onError
|
|
1433
1543
|
}),
|
|
1434
|
-
[
|
|
1544
|
+
[
|
|
1545
|
+
registry,
|
|
1546
|
+
catalog,
|
|
1547
|
+
resolveComponent,
|
|
1548
|
+
fallback2,
|
|
1549
|
+
fallbackText,
|
|
1550
|
+
componentVersions,
|
|
1551
|
+
loading,
|
|
1552
|
+
onError
|
|
1553
|
+
]
|
|
1435
1554
|
);
|
|
1436
1555
|
return /* @__PURE__ */ jsx(TreeScopeContext.Provider, { value: scope, children });
|
|
1437
1556
|
}
|
|
@@ -1491,7 +1610,7 @@ function GenerativeUI({
|
|
|
1491
1610
|
onError: ownOnError
|
|
1492
1611
|
}) {
|
|
1493
1612
|
const provided = useContext2(GenuiContext);
|
|
1494
|
-
const fallback2 = ownFallback
|
|
1613
|
+
const fallback2 = ownFallback !== void 0 ? ownFallback : provided?.fallback;
|
|
1495
1614
|
const loading = ownLoading ?? provided?.loading ?? null;
|
|
1496
1615
|
const onError = ownOnError ?? provided?.onError;
|
|
1497
1616
|
const options = useMergedOptions({
|
|
@@ -1516,6 +1635,8 @@ function GenerativeUI({
|
|
|
1516
1635
|
GenerativeUIScope,
|
|
1517
1636
|
{
|
|
1518
1637
|
...options,
|
|
1638
|
+
...state.item.componentVersions !== void 0 ? { componentVersions: state.item.componentVersions } : {},
|
|
1639
|
+
...state.item.fallbackText !== void 0 ? { fallbackText: state.item.fallbackText } : {},
|
|
1519
1640
|
fallback: fallback2,
|
|
1520
1641
|
loading,
|
|
1521
1642
|
...onError !== void 0 ? { onError } : {},
|
|
@@ -1531,6 +1652,7 @@ var AgentBackendContext = sharedContext(
|
|
|
1531
1652
|
);
|
|
1532
1653
|
function AgentProvider({
|
|
1533
1654
|
backend,
|
|
1655
|
+
uiCapabilities,
|
|
1534
1656
|
baseUrl,
|
|
1535
1657
|
path,
|
|
1536
1658
|
headers,
|
|
@@ -1562,7 +1684,7 @@ function AgentProvider({
|
|
|
1562
1684
|
[backend, baseUrl, path, credentials, fetch, upload]
|
|
1563
1685
|
);
|
|
1564
1686
|
const content = genui !== void 0 ? /* @__PURE__ */ jsx2(GenuiProvider, { ...genui, children }) : children;
|
|
1565
|
-
return /* @__PURE__ */ jsx2(AgentBackendContext.Provider, { value, children: content });
|
|
1687
|
+
return /* @__PURE__ */ jsx2(AgentUiCapabilitiesContext.Provider, { value: uiCapabilities ?? null, children: /* @__PURE__ */ jsx2(AgentBackendContext.Provider, { value, children: content }) });
|
|
1566
1688
|
}
|
|
1567
1689
|
var fallback;
|
|
1568
1690
|
function defaultBackend() {
|
|
@@ -1573,6 +1695,12 @@ function useAgentBackend(own) {
|
|
|
1573
1695
|
const provided = useContext3(AgentBackendContext);
|
|
1574
1696
|
return own ?? provided ?? defaultBackend();
|
|
1575
1697
|
}
|
|
1698
|
+
var AgentUiCapabilitiesContext = sharedContext(
|
|
1699
|
+
"@dudousxd/nestjs-agent-react:ui-capabilities"
|
|
1700
|
+
);
|
|
1701
|
+
function useAgentUiCapabilities() {
|
|
1702
|
+
return useContext3(AgentUiCapabilitiesContext) ?? void 0;
|
|
1703
|
+
}
|
|
1576
1704
|
|
|
1577
1705
|
// src/config/use-agent-config.ts
|
|
1578
1706
|
var shared = /* @__PURE__ */ new WeakMap();
|
|
@@ -1838,7 +1966,7 @@ async function defaultRefusal(response) {
|
|
|
1838
1966
|
}
|
|
1839
1967
|
function defaultForwardedProps(body) {
|
|
1840
1968
|
const out = {};
|
|
1841
|
-
for (const key of ["pageContext", "agent", "model"]) {
|
|
1969
|
+
for (const key of ["pageContext", "agent", "model", "persona", "uiCapabilities"]) {
|
|
1842
1970
|
if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
|
|
1843
1971
|
}
|
|
1844
1972
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
@@ -2155,7 +2283,7 @@ function applyPatch(target, patch) {
|
|
|
2155
2283
|
}
|
|
2156
2284
|
|
|
2157
2285
|
// src/catalog/use-agents.ts
|
|
2158
|
-
import { useMemo as useMemo5 } from "react";
|
|
2286
|
+
import { useCallback as useCallback4, useMemo as useMemo5 } from "react";
|
|
2159
2287
|
|
|
2160
2288
|
// src/catalog/use-resource.ts
|
|
2161
2289
|
import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
|
|
@@ -2197,16 +2325,24 @@ function useAgents(options = {}) {
|
|
|
2197
2325
|
"",
|
|
2198
2326
|
enabled
|
|
2199
2327
|
);
|
|
2328
|
+
const find = useCallback4(
|
|
2329
|
+
(name) => (data ?? []).find(
|
|
2330
|
+
(agent) => name === void 0 ? agent.isDefault === true : agent.name === name
|
|
2331
|
+
),
|
|
2332
|
+
[data]
|
|
2333
|
+
);
|
|
2200
2334
|
return useMemo5(() => {
|
|
2201
2335
|
const agents = data ?? [];
|
|
2202
2336
|
return {
|
|
2203
2337
|
agents,
|
|
2204
2338
|
defaultAgent: agents.find((agent) => agent.isDefault === true)?.name ?? null,
|
|
2339
|
+
personasOf: (agent) => find(agent)?.personas ?? [],
|
|
2340
|
+
defaultPersonaOf: (agent) => find(agent)?.defaultPersona ?? null,
|
|
2205
2341
|
isLoading,
|
|
2206
2342
|
error,
|
|
2207
2343
|
refresh
|
|
2208
2344
|
};
|
|
2209
|
-
}, [data, isLoading, error, refresh]);
|
|
2345
|
+
}, [data, find, isLoading, error, refresh]);
|
|
2210
2346
|
}
|
|
2211
2347
|
|
|
2212
2348
|
// src/catalog/use-models.ts
|
|
@@ -2304,7 +2440,7 @@ function useQuota(options = {}) {
|
|
|
2304
2440
|
}
|
|
2305
2441
|
|
|
2306
2442
|
// src/feedback/use-message-feedback.ts
|
|
2307
|
-
import { useCallback as
|
|
2443
|
+
import { useCallback as useCallback5, useRef as useRef5, useState as useState6 } from "react";
|
|
2308
2444
|
function useMessageFeedback(options = {}) {
|
|
2309
2445
|
const backend = useAgentBackend(options.backend);
|
|
2310
2446
|
const latest = useRef5({ ...options, backend });
|
|
@@ -2315,7 +2451,7 @@ function useMessageFeedback(options = {}) {
|
|
|
2315
2451
|
const localRef = useRef5(local);
|
|
2316
2452
|
localRef.current = local;
|
|
2317
2453
|
const resolved = useRef5(/* @__PURE__ */ new Map());
|
|
2318
|
-
const feedbackOf =
|
|
2454
|
+
const feedbackOf = useCallback5(
|
|
2319
2455
|
(message) => {
|
|
2320
2456
|
const mine = local.get(message.id);
|
|
2321
2457
|
if (mine !== void 0) return mine.feedback;
|
|
@@ -2323,8 +2459,8 @@ function useMessageFeedback(options = {}) {
|
|
|
2323
2459
|
},
|
|
2324
2460
|
[local]
|
|
2325
2461
|
);
|
|
2326
|
-
const isPending =
|
|
2327
|
-
const storedIdFor =
|
|
2462
|
+
const isPending = useCallback5((message) => pending.has(message.id), [pending]);
|
|
2463
|
+
const storedIdFor = useCallback5(async (message) => {
|
|
2328
2464
|
const runId = metadataOf(message).runId;
|
|
2329
2465
|
if (runId === void 0) return message.id;
|
|
2330
2466
|
const known = resolved.current.get(message.id);
|
|
@@ -2342,7 +2478,7 @@ function useMessageFeedback(options = {}) {
|
|
|
2342
2478
|
resolved.current.set(message.id, row.id);
|
|
2343
2479
|
return row.id;
|
|
2344
2480
|
}, []);
|
|
2345
|
-
const rate =
|
|
2481
|
+
const rate = useCallback5(
|
|
2346
2482
|
async (message, value, comment) => {
|
|
2347
2483
|
const setFeedback = requireBackendMethod(latest.current.backend, "setMessageFeedback");
|
|
2348
2484
|
const had = localRef.current.get(message.id);
|
|
@@ -2381,7 +2517,7 @@ function useMessageFeedback(options = {}) {
|
|
|
2381
2517
|
},
|
|
2382
2518
|
[storedIdFor]
|
|
2383
2519
|
);
|
|
2384
|
-
const toggle =
|
|
2520
|
+
const toggle = useCallback5(
|
|
2385
2521
|
(message, value) => {
|
|
2386
2522
|
const mine = localRef.current.get(message.id);
|
|
2387
2523
|
const current = mine !== void 0 ? mine.feedback : metadataOf(message).feedback ?? null;
|
|
@@ -2397,7 +2533,7 @@ function metadataOf(message) {
|
|
|
2397
2533
|
}
|
|
2398
2534
|
|
|
2399
2535
|
// src/threads/use-threads.ts
|
|
2400
|
-
import { useCallback as
|
|
2536
|
+
import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef6, useState as useState7 } from "react";
|
|
2401
2537
|
function useThreads(options = {}) {
|
|
2402
2538
|
const { enabled = true } = options;
|
|
2403
2539
|
const backend = useAgentBackend(options.backend);
|
|
@@ -2407,7 +2543,7 @@ function useThreads(options = {}) {
|
|
|
2407
2543
|
const threadsRef = useRef6(threads);
|
|
2408
2544
|
threadsRef.current = threads;
|
|
2409
2545
|
const generation = useRef6(0);
|
|
2410
|
-
const refresh =
|
|
2546
|
+
const refresh = useCallback6(async () => {
|
|
2411
2547
|
const mine = ++generation.current;
|
|
2412
2548
|
setIsLoading(true);
|
|
2413
2549
|
try {
|
|
@@ -2439,7 +2575,7 @@ function useThreads(options = {}) {
|
|
|
2439
2575
|
}
|
|
2440
2576
|
});
|
|
2441
2577
|
}, [backend, enabled, refresh]);
|
|
2442
|
-
const rename =
|
|
2578
|
+
const rename = useCallback6(
|
|
2443
2579
|
async (id, title) => {
|
|
2444
2580
|
const before = threadsRef.current;
|
|
2445
2581
|
setThreads(
|
|
@@ -2455,7 +2591,7 @@ function useThreads(options = {}) {
|
|
|
2455
2591
|
},
|
|
2456
2592
|
[backend]
|
|
2457
2593
|
);
|
|
2458
|
-
const remove =
|
|
2594
|
+
const remove = useCallback6(
|
|
2459
2595
|
async (id) => {
|
|
2460
2596
|
const before = threadsRef.current;
|
|
2461
2597
|
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
@@ -2514,7 +2650,7 @@ function backgroundRunsFromThread(messages) {
|
|
|
2514
2650
|
import { useEffect as useEffect9, useState as useState9 } from "react";
|
|
2515
2651
|
|
|
2516
2652
|
// src/components/use-speech-recognition.ts
|
|
2517
|
-
import { useCallback as
|
|
2653
|
+
import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo8, useRef as useRef7, useState as useState8 } from "react";
|
|
2518
2654
|
function getRecognitionCtor() {
|
|
2519
2655
|
if (typeof window === "undefined") return null;
|
|
2520
2656
|
const scope = window;
|
|
@@ -2569,7 +2705,7 @@ function useSpeechRecognition({
|
|
|
2569
2705
|
recognitionRef.current = null;
|
|
2570
2706
|
};
|
|
2571
2707
|
}, [ctor, lang]);
|
|
2572
|
-
const start =
|
|
2708
|
+
const start = useCallback7(() => {
|
|
2573
2709
|
const recognition = recognitionRef.current;
|
|
2574
2710
|
if (!recognition) return;
|
|
2575
2711
|
try {
|
|
@@ -2579,7 +2715,7 @@ function useSpeechRecognition({
|
|
|
2579
2715
|
console.warn("SpeechRecognition start failed", error);
|
|
2580
2716
|
}
|
|
2581
2717
|
}, []);
|
|
2582
|
-
const stop =
|
|
2718
|
+
const stop = useCallback7(() => {
|
|
2583
2719
|
const recognition = recognitionRef.current;
|
|
2584
2720
|
if (!recognition) return;
|
|
2585
2721
|
try {
|
|
@@ -2699,7 +2835,7 @@ function ChatInput({
|
|
|
2699
2835
|
import React2 from "react";
|
|
2700
2836
|
|
|
2701
2837
|
// src/transcript/use-chat-transcript.ts
|
|
2702
|
-
import { useCallback as
|
|
2838
|
+
import { useCallback as useCallback9, useEffect as useEffect11, useRef as useRef9, useState as useState11 } from "react";
|
|
2703
2839
|
|
|
2704
2840
|
// src/transcript/model.ts
|
|
2705
2841
|
import {
|
|
@@ -2879,6 +3015,15 @@ function isActionCall(part) {
|
|
|
2879
3015
|
}
|
|
2880
3016
|
function toolCallState(part) {
|
|
2881
3017
|
const output = "output" in part ? part.output : void 0;
|
|
3018
|
+
if (output !== null && typeof output === "object" && "proposalId" in output && "executed" in output && output.executed === false)
|
|
3019
|
+
return {
|
|
3020
|
+
status: "awaiting-approval",
|
|
3021
|
+
isSettled: false,
|
|
3022
|
+
isFailed: false,
|
|
3023
|
+
isDenied: false,
|
|
3024
|
+
output,
|
|
3025
|
+
error: null
|
|
3026
|
+
};
|
|
2882
3027
|
const errorText = "errorText" in part ? part.errorText : void 0;
|
|
2883
3028
|
const outputError = output !== null && typeof output === "object" && "error" in output ? String(output.error) : void 0;
|
|
2884
3029
|
const isDenied = part.state === "output-denied";
|
|
@@ -2923,7 +3068,11 @@ function describeToolCall(part, catalog, options = {}) {
|
|
|
2923
3068
|
icon: presentation?.icon ?? null,
|
|
2924
3069
|
tone: presentation?.tone ?? "neutral",
|
|
2925
3070
|
detail: presentation?.detail ?? null,
|
|
2926
|
-
confirm:
|
|
3071
|
+
confirm: options.confirmation !== void 0 ? {
|
|
3072
|
+
title: options.confirmation.title,
|
|
3073
|
+
verb: options.confirmation.verb,
|
|
3074
|
+
detail: options.confirmation.detail ?? null
|
|
3075
|
+
} : confirm === void 0 ? null : {
|
|
2927
3076
|
title: fillTemplate(confirm.title, input),
|
|
2928
3077
|
verb: confirm.verb,
|
|
2929
3078
|
detail: confirm.detail !== void 0 ? fillTemplate(confirm.detail, input) : null
|
|
@@ -2937,6 +3086,9 @@ function describeToolCall(part, catalog, options = {}) {
|
|
|
2937
3086
|
}
|
|
2938
3087
|
var STATUS_WEIGHT = {
|
|
2939
3088
|
running: 4,
|
|
3089
|
+
queued: 4,
|
|
3090
|
+
executing: 4,
|
|
3091
|
+
succeeded: 0,
|
|
2940
3092
|
"awaiting-approval": 3,
|
|
2941
3093
|
failed: 2,
|
|
2942
3094
|
denied: 1,
|
|
@@ -2956,7 +3108,7 @@ function groupToolActivity(calls, options = {}) {
|
|
|
2956
3108
|
if (corrected.has(call.toolCallId)) continue;
|
|
2957
3109
|
const presentation = options.catalog?.[call.name];
|
|
2958
3110
|
const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;
|
|
2959
|
-
const status =
|
|
3111
|
+
const status = call.description.status;
|
|
2960
3112
|
const phrase = phraseFor(
|
|
2961
3113
|
presentation,
|
|
2962
3114
|
call.part.input,
|
|
@@ -3198,7 +3350,7 @@ function isAncestor(call, candidate, byId) {
|
|
|
3198
3350
|
}
|
|
3199
3351
|
function buildToolCall(part, options, approval, catalog) {
|
|
3200
3352
|
const toolCallId = part.toolCallId;
|
|
3201
|
-
const awaiting = isAwaitingApproval(part);
|
|
3353
|
+
const awaiting = approval?.target?.kind === "proposal" ? approval.status === "pending" : isAwaitingApproval(part);
|
|
3202
3354
|
const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
|
|
3203
3355
|
return {
|
|
3204
3356
|
part,
|
|
@@ -3208,19 +3360,30 @@ function buildToolCall(part, options, approval, catalog) {
|
|
|
3208
3360
|
parentId: toolParentId(part),
|
|
3209
3361
|
children: [],
|
|
3210
3362
|
approval,
|
|
3211
|
-
description:
|
|
3363
|
+
description: proposalDescription(
|
|
3364
|
+
describeToolCall(
|
|
3365
|
+
part,
|
|
3366
|
+
catalog,
|
|
3367
|
+
approval?.confirmation === void 0 ? {} : { confirmation: approval.confirmation }
|
|
3368
|
+
),
|
|
3369
|
+
approval
|
|
3370
|
+
),
|
|
3212
3371
|
isAwaitingApproval: awaiting,
|
|
3213
3372
|
approve: {
|
|
3214
3373
|
available: awaiting && options?.canApprove === true,
|
|
3215
3374
|
isSubmitting: sending === "approve",
|
|
3216
3375
|
// Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,
|
|
3217
3376
|
// and a host's handler must not receive that as its options.
|
|
3218
|
-
run: (approveOptions) => approveOptions?.remember === true ? options?.approve(toolCallId, { remember: true }) : options?.approve(toolCallId)
|
|
3377
|
+
run: (approveOptions) => approval?.target === void 0 ? approveOptions?.remember === true ? options?.approve(toolCallId, { remember: true }) : options?.approve(toolCallId) : options?.approve(
|
|
3378
|
+
toolCallId,
|
|
3379
|
+
approveOptions?.remember === true ? { remember: true } : void 0,
|
|
3380
|
+
approval.target
|
|
3381
|
+
)
|
|
3219
3382
|
},
|
|
3220
3383
|
reject: {
|
|
3221
3384
|
available: awaiting && options?.canReject === true,
|
|
3222
3385
|
isSubmitting: sending === "reject",
|
|
3223
|
-
run: () => options?.reject(toolCallId)
|
|
3386
|
+
run: () => approval?.target === void 0 ? options?.reject(toolCallId) : options?.reject(toolCallId, approval.target)
|
|
3224
3387
|
},
|
|
3225
3388
|
error: options?.errorOf(toolCallId) ?? null,
|
|
3226
3389
|
errorCode: options?.errorCodeOf?.(toolCallId) ?? null
|
|
@@ -3370,7 +3533,7 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
3370
3533
|
var UI_PART = "data-ui";
|
|
3371
3534
|
var APPROVAL_PART = "data-approval-requested";
|
|
3372
3535
|
var SETTLED_PART = "data-approval-settled";
|
|
3373
|
-
var SETTLED_STATUSES = ["approved", "rejected", "expired"];
|
|
3536
|
+
var SETTLED_STATUSES = ["approved", "rejected", "expired", "superseded"];
|
|
3374
3537
|
function readApprovals(parts) {
|
|
3375
3538
|
const out = /* @__PURE__ */ new Map();
|
|
3376
3539
|
const entry = (id) => {
|
|
@@ -3391,7 +3554,7 @@ function readApprovals(parts) {
|
|
|
3391
3554
|
return found;
|
|
3392
3555
|
};
|
|
3393
3556
|
for (const part of parts) {
|
|
3394
|
-
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART) {
|
|
3557
|
+
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART && part.type !== "data-action-proposal") {
|
|
3395
3558
|
continue;
|
|
3396
3559
|
}
|
|
3397
3560
|
const data = part.data;
|
|
@@ -3399,12 +3562,35 @@ function readApprovals(parts) {
|
|
|
3399
3562
|
continue;
|
|
3400
3563
|
}
|
|
3401
3564
|
const approval = entry(data.id);
|
|
3402
|
-
if (part.type === APPROVAL_PART) {
|
|
3565
|
+
if (part.type === APPROVAL_PART || part.type === "data-action-proposal") {
|
|
3566
|
+
if (isRecord4(data.target) && data.target.kind === "proposal" && typeof data.target.proposalId === "string") {
|
|
3567
|
+
approval.target = {
|
|
3568
|
+
kind: "proposal",
|
|
3569
|
+
proposalId: data.target.proposalId,
|
|
3570
|
+
...typeof data.target.threadId === "string" ? { threadId: data.target.threadId } : {}
|
|
3571
|
+
};
|
|
3572
|
+
}
|
|
3573
|
+
if (part.type === "data-action-proposal") {
|
|
3574
|
+
if (typeof data.status === "string" && ["pending", "approved", "rejected", "expired", "superseded"].includes(data.status))
|
|
3575
|
+
approval.status = data.status === "pending" ? null : data.status;
|
|
3576
|
+
if (data.executionStatus === null || data.executionStatus === "queued" || data.executionStatus === "executing" || data.executionStatus === "succeeded" || data.executionStatus === "failed")
|
|
3577
|
+
approval.executionStatus = data.executionStatus;
|
|
3578
|
+
approval.remember = data.remember === true;
|
|
3579
|
+
approval.decidedBy = typeof data.decidedBy === "string" ? data.decidedBy : null;
|
|
3580
|
+
approval.decidedVia = typeof data.decidedVia === "string" ? data.decidedVia : null;
|
|
3581
|
+
}
|
|
3403
3582
|
if (typeof data.approver !== "string") {
|
|
3404
3583
|
continue;
|
|
3405
3584
|
}
|
|
3406
3585
|
approval.approver = data.approver;
|
|
3407
3586
|
approval.expiresAt = typeof data.expiresAt === "string" ? data.expiresAt : null;
|
|
3587
|
+
if (isRecord4(data.confirmation) && typeof data.confirmation.title === "string" && typeof data.confirmation.verb === "string" && (data.confirmation.detail === void 0 || typeof data.confirmation.detail === "string")) {
|
|
3588
|
+
approval.confirmation = {
|
|
3589
|
+
title: data.confirmation.title,
|
|
3590
|
+
verb: data.confirmation.verb,
|
|
3591
|
+
...typeof data.confirmation.detail === "string" ? { detail: data.confirmation.detail } : {}
|
|
3592
|
+
};
|
|
3593
|
+
}
|
|
3408
3594
|
approval.reason = typeof data.reason === "string" ? data.reason : null;
|
|
3409
3595
|
continue;
|
|
3410
3596
|
}
|
|
@@ -3428,9 +3614,12 @@ function approvalOf(parts, call) {
|
|
|
3428
3614
|
}
|
|
3429
3615
|
return {
|
|
3430
3616
|
approver: parts.approver,
|
|
3617
|
+
...parts.target === void 0 ? {} : { target: parts.target },
|
|
3618
|
+
...parts.executionStatus === void 0 ? {} : { executionStatus: parts.executionStatus },
|
|
3619
|
+
...parts.confirmation !== void 0 ? { confirmation: parts.confirmation } : {},
|
|
3431
3620
|
expiresAt: parts.expiresAt,
|
|
3432
3621
|
reason: parts.reason,
|
|
3433
|
-
status: parts.status ?? statusFromPart(call),
|
|
3622
|
+
status: parts.status ?? (parts.target?.kind === "proposal" ? "pending" : statusFromPart(call)),
|
|
3434
3623
|
remember: parts.remember,
|
|
3435
3624
|
decidedBy: parts.decidedBy,
|
|
3436
3625
|
decidedVia: parts.decidedVia,
|
|
@@ -3460,6 +3649,10 @@ function readUiComponent(part) {
|
|
|
3460
3649
|
component: data.component,
|
|
3461
3650
|
props: isRecord4(data.props) ? data.props : {},
|
|
3462
3651
|
version: typeof data.version === "number" ? data.version : null,
|
|
3652
|
+
...isRecord4(data.componentVersions) && Object.values(data.componentVersions).every(
|
|
3653
|
+
(version) => typeof version === "number" && Number.isSafeInteger(version) && version > 0
|
|
3654
|
+
) ? { componentVersions: { ...data.componentVersions } } : {},
|
|
3655
|
+
...typeof data.fallbackText === "string" ? { fallbackText: data.fallbackText } : {},
|
|
3463
3656
|
toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
|
|
3464
3657
|
};
|
|
3465
3658
|
}
|
|
@@ -3570,16 +3763,22 @@ function formatCostUsd(cost) {
|
|
|
3570
3763
|
}
|
|
3571
3764
|
return `$${cost.toFixed(2)}`;
|
|
3572
3765
|
}
|
|
3766
|
+
function proposalDescription(description, approval) {
|
|
3767
|
+
if (approval?.target?.kind !== "proposal") return description;
|
|
3768
|
+
const status = approval.status === "pending" ? "awaiting-approval" : approval.status === "approved" ? approval.executionStatus ?? "queued" : "denied";
|
|
3769
|
+
const phrase = status === "awaiting-approval" ? "Awaiting approval" : status === "queued" ? "Queued" : status === "executing" ? "Executing" : status === "succeeded" ? "Succeeded" : status === "failed" ? "Failed" : approval.status === "expired" ? "Expired" : approval.status === "superseded" ? "Replaced" : "Rejected";
|
|
3770
|
+
return { ...description, status, phrase, result: null };
|
|
3771
|
+
}
|
|
3573
3772
|
|
|
3574
3773
|
// src/transcript/use-stick-to-bottom.ts
|
|
3575
|
-
import { useCallback as
|
|
3774
|
+
import { useCallback as useCallback8, useEffect as useEffect10, useRef as useRef8, useState as useState10 } from "react";
|
|
3576
3775
|
function useStickToBottom({
|
|
3577
3776
|
contentKey,
|
|
3578
3777
|
threshold = 32
|
|
3579
3778
|
}) {
|
|
3580
3779
|
const containerRef = useRef8(null);
|
|
3581
3780
|
const [isAtBottom, setIsAtBottom] = useState10(true);
|
|
3582
|
-
const measure =
|
|
3781
|
+
const measure = useCallback8(() => {
|
|
3583
3782
|
const element = containerRef.current;
|
|
3584
3783
|
if (!element) {
|
|
3585
3784
|
return;
|
|
@@ -3587,7 +3786,7 @@ function useStickToBottom({
|
|
|
3587
3786
|
const distance = element.scrollHeight - element.scrollTop - element.clientHeight;
|
|
3588
3787
|
setIsAtBottom(distance <= threshold);
|
|
3589
3788
|
}, [threshold]);
|
|
3590
|
-
const scrollToBottom =
|
|
3789
|
+
const scrollToBottom = useCallback8(() => {
|
|
3591
3790
|
const element = containerRef.current;
|
|
3592
3791
|
if (!element) {
|
|
3593
3792
|
return;
|
|
@@ -3595,7 +3794,7 @@ function useStickToBottom({
|
|
|
3595
3794
|
element.scrollTop = element.scrollHeight;
|
|
3596
3795
|
setIsAtBottom(true);
|
|
3597
3796
|
}, []);
|
|
3598
|
-
const setContainer =
|
|
3797
|
+
const setContainer = useCallback8(
|
|
3599
3798
|
(element) => {
|
|
3600
3799
|
containerRef.current = element;
|
|
3601
3800
|
if (element) {
|
|
@@ -3609,7 +3808,7 @@ function useStickToBottom({
|
|
|
3609
3808
|
scrollToBottom();
|
|
3610
3809
|
}
|
|
3611
3810
|
}, [contentKey, isAtBottom, scrollToBottom]);
|
|
3612
|
-
const getContainerProps =
|
|
3811
|
+
const getContainerProps = useCallback8(
|
|
3613
3812
|
() => ({ ref: setContainer, onScroll: measure }),
|
|
3614
3813
|
[setContainer, measure]
|
|
3615
3814
|
);
|
|
@@ -3656,7 +3855,7 @@ function useChatTranscript(options) {
|
|
|
3656
3855
|
streamingMessageId,
|
|
3657
3856
|
options
|
|
3658
3857
|
});
|
|
3659
|
-
const stop =
|
|
3858
|
+
const stop = useCallback9(() => {
|
|
3660
3859
|
const current = latest.current;
|
|
3661
3860
|
if (current.status !== "submitted" && current.status !== "streaming" && current.status !== "reconnecting") {
|
|
3662
3861
|
return;
|
|
@@ -3664,13 +3863,13 @@ function useChatTranscript(options) {
|
|
|
3664
3863
|
setStopRequested(true);
|
|
3665
3864
|
void current.onStop?.();
|
|
3666
3865
|
}, []);
|
|
3667
|
-
const loadEarlier =
|
|
3866
|
+
const loadEarlier = useCallback9(
|
|
3668
3867
|
() => setVisibleCount(
|
|
3669
3868
|
(count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)
|
|
3670
3869
|
),
|
|
3671
3870
|
[]
|
|
3672
3871
|
);
|
|
3673
|
-
const showAll =
|
|
3872
|
+
const showAll = useCallback9(() => setVisibleCount(latest.current.messages.length), []);
|
|
3674
3873
|
const scroll = useStickToBottom({
|
|
3675
3874
|
contentKey: contentSignature(messages),
|
|
3676
3875
|
...stickToBottomThreshold !== void 0 ? { threshold: stickToBottomThreshold } : {}
|
|
@@ -3708,7 +3907,7 @@ function useQueuedItems(queue, readOnly) {
|
|
|
3708
3907
|
const latestQueue = useRef9(queue);
|
|
3709
3908
|
latestQueue.current = queue;
|
|
3710
3909
|
const removers = useRef9(/* @__PURE__ */ new Map());
|
|
3711
|
-
const removerFor =
|
|
3910
|
+
const removerFor = useCallback9((id) => {
|
|
3712
3911
|
let remover = removers.current.get(id);
|
|
3713
3912
|
if (remover === void 0) {
|
|
3714
3913
|
remover = () => {
|
|
@@ -3784,14 +3983,14 @@ function useTranscriptItems({
|
|
|
3784
3983
|
);
|
|
3785
3984
|
const callbackCache = useRef9(/* @__PURE__ */ new Map());
|
|
3786
3985
|
const reasoningToggleCache = useRef9(/* @__PURE__ */ new Map());
|
|
3787
|
-
const toggleReasoning =
|
|
3986
|
+
const toggleReasoning = useCallback9((key, open) => {
|
|
3788
3987
|
setOpenReasoning((current) => {
|
|
3789
3988
|
const next = new Map(current);
|
|
3790
3989
|
next.set(key, open ?? !(current.get(key) ?? false));
|
|
3791
3990
|
return next;
|
|
3792
3991
|
});
|
|
3793
3992
|
}, []);
|
|
3794
|
-
const stableToggle =
|
|
3993
|
+
const stableToggle = useCallback9(
|
|
3795
3994
|
(key) => {
|
|
3796
3995
|
let cached = reasoningToggleCache.current.get(key);
|
|
3797
3996
|
if (!cached) {
|
|
@@ -3802,10 +4001,10 @@ function useTranscriptItems({
|
|
|
3802
4001
|
},
|
|
3803
4002
|
[toggleReasoning]
|
|
3804
4003
|
);
|
|
3805
|
-
const pick =
|
|
4004
|
+
const pick = useCallback9((toolCallId, questionId, values) => {
|
|
3806
4005
|
setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));
|
|
3807
4006
|
}, []);
|
|
3808
|
-
const settle =
|
|
4007
|
+
const settle = useCallback9(
|
|
3809
4008
|
(toolCallId, action, send) => {
|
|
3810
4009
|
setSettleErrors((current) => {
|
|
3811
4010
|
if (!current.has(toolCallId)) {
|
|
@@ -3837,7 +4036,7 @@ function useTranscriptItems({
|
|
|
3837
4036
|
},
|
|
3838
4037
|
[]
|
|
3839
4038
|
);
|
|
3840
|
-
const answer =
|
|
4039
|
+
const answer = useCallback9(
|
|
3841
4040
|
(toolCallId) => {
|
|
3842
4041
|
const current = latest.current;
|
|
3843
4042
|
const onAnswer = current.handlers.onAnswer;
|
|
@@ -3852,7 +4051,7 @@ function useTranscriptItems({
|
|
|
3852
4051
|
},
|
|
3853
4052
|
[settle]
|
|
3854
4053
|
);
|
|
3855
|
-
const skip =
|
|
4054
|
+
const skip = useCallback9(
|
|
3856
4055
|
(toolCallId) => {
|
|
3857
4056
|
const onSkip = latest.current.handlers.onSkip;
|
|
3858
4057
|
if (onSkip) {
|
|
@@ -3861,29 +4060,37 @@ function useTranscriptItems({
|
|
|
3861
4060
|
},
|
|
3862
4061
|
[settle]
|
|
3863
4062
|
);
|
|
3864
|
-
const approve =
|
|
3865
|
-
(toolCallId, options2) => {
|
|
4063
|
+
const approve = useCallback9(
|
|
4064
|
+
(toolCallId, options2, target) => {
|
|
3866
4065
|
const onApprove = latest.current.handlers.onApprove;
|
|
3867
4066
|
if (onApprove) {
|
|
3868
4067
|
settle(
|
|
3869
4068
|
toolCallId,
|
|
3870
4069
|
"approve",
|
|
3871
|
-
() => onApprove({
|
|
4070
|
+
() => onApprove({
|
|
4071
|
+
toolCallId,
|
|
4072
|
+
...target === void 0 ? {} : { target },
|
|
4073
|
+
...options2?.remember === true ? { remember: true } : {}
|
|
4074
|
+
})
|
|
3872
4075
|
);
|
|
3873
4076
|
}
|
|
3874
4077
|
},
|
|
3875
4078
|
[settle]
|
|
3876
4079
|
);
|
|
3877
|
-
const reject =
|
|
3878
|
-
(toolCallId) => {
|
|
4080
|
+
const reject = useCallback9(
|
|
4081
|
+
(toolCallId, target) => {
|
|
3879
4082
|
const onReject = latest.current.handlers.onReject;
|
|
3880
4083
|
if (onReject) {
|
|
3881
|
-
settle(
|
|
4084
|
+
settle(
|
|
4085
|
+
toolCallId,
|
|
4086
|
+
"reject",
|
|
4087
|
+
() => onReject({ toolCallId, ...target === void 0 ? {} : { target } })
|
|
4088
|
+
);
|
|
3882
4089
|
}
|
|
3883
4090
|
},
|
|
3884
4091
|
[settle]
|
|
3885
4092
|
);
|
|
3886
|
-
const callbacksFor =
|
|
4093
|
+
const callbacksFor = useCallback9((id) => {
|
|
3887
4094
|
const cached = callbackCache.current.get(id);
|
|
3888
4095
|
if (cached) {
|
|
3889
4096
|
return cached;
|
|
@@ -4076,14 +4283,36 @@ function settleHandlers(options, backend) {
|
|
|
4076
4283
|
),
|
|
4077
4284
|
onApprove: pick(
|
|
4078
4285
|
options.onApprove,
|
|
4079
|
-
backend.approveToolCall ? async (input) => {
|
|
4080
|
-
|
|
4286
|
+
backend.approveToolCall || backend.approveActionProposal ? async (input) => {
|
|
4287
|
+
if (input.target?.kind === "proposal") {
|
|
4288
|
+
if (input.target.threadId === void 0)
|
|
4289
|
+
throw new Error("A proposal decision requires its thread scope");
|
|
4290
|
+
await requireBackendMethod(
|
|
4291
|
+
backend,
|
|
4292
|
+
"approveActionProposal"
|
|
4293
|
+
)({
|
|
4294
|
+
threadId: input.target.threadId,
|
|
4295
|
+
proposalId: input.target.proposalId,
|
|
4296
|
+
...input.remember === void 0 ? {} : { remember: input.remember }
|
|
4297
|
+
});
|
|
4298
|
+
} else await requireBackendMethod(backend, "approveToolCall")(input);
|
|
4081
4299
|
} : void 0
|
|
4082
4300
|
),
|
|
4083
4301
|
onReject: pick(
|
|
4084
4302
|
options.onReject,
|
|
4085
|
-
backend.rejectToolCall ? async (input) => {
|
|
4086
|
-
|
|
4303
|
+
backend.rejectToolCall || backend.rejectActionProposal ? async (input) => {
|
|
4304
|
+
if (input.target?.kind === "proposal") {
|
|
4305
|
+
if (input.target.threadId === void 0)
|
|
4306
|
+
throw new Error("A proposal decision requires its thread scope");
|
|
4307
|
+
await requireBackendMethod(
|
|
4308
|
+
backend,
|
|
4309
|
+
"rejectActionProposal"
|
|
4310
|
+
)({
|
|
4311
|
+
threadId: input.target.threadId,
|
|
4312
|
+
proposalId: input.target.proposalId,
|
|
4313
|
+
...input.reason === void 0 ? {} : { reason: input.reason }
|
|
4314
|
+
});
|
|
4315
|
+
} else await requireBackendMethod(backend, "rejectToolCall")(input);
|
|
4087
4316
|
} : void 0
|
|
4088
4317
|
)
|
|
4089
4318
|
};
|
|
@@ -4608,7 +4837,7 @@ function toItem(entry) {
|
|
|
4608
4837
|
}
|
|
4609
4838
|
|
|
4610
4839
|
// src/composer/use-composer-autocomplete.ts
|
|
4611
|
-
import { useCallback as
|
|
4840
|
+
import { useCallback as useCallback10, useEffect as useEffect12, useId, useLayoutEffect, useMemo as useMemo9, useRef as useRef10, useState as useState12 } from "react";
|
|
4612
4841
|
function useComposerAutocomplete(options) {
|
|
4613
4842
|
const { value, sources, acceptOnTab = true } = options;
|
|
4614
4843
|
const latest = useRef10(options);
|
|
@@ -4683,22 +4912,22 @@ function useComposerAutocomplete(options) {
|
|
|
4683
4912
|
const activeItem = isOpen ? items[activeIndex] ?? null : null;
|
|
4684
4913
|
const reactId = useId();
|
|
4685
4914
|
const listboxId = options.id ?? `agent-autocomplete-${reactId}`;
|
|
4686
|
-
const optionId =
|
|
4687
|
-
const highlight =
|
|
4915
|
+
const optionId = useCallback10((index) => `${listboxId}-option-${index}`, [listboxId]);
|
|
4916
|
+
const highlight = useCallback10((index) => {
|
|
4688
4917
|
const total = itemsRef.current.length;
|
|
4689
4918
|
if (total === 0) return;
|
|
4690
4919
|
setActiveIndex((index % total + total) % total);
|
|
4691
4920
|
}, []);
|
|
4692
|
-
const moveHighlight =
|
|
4921
|
+
const moveHighlight = useCallback10(
|
|
4693
4922
|
(delta) => highlight(activeIndexRef.current + delta),
|
|
4694
4923
|
[highlight]
|
|
4695
4924
|
);
|
|
4696
|
-
const dismiss =
|
|
4925
|
+
const dismiss = useCallback10(() => {
|
|
4697
4926
|
const current = matchRef.current;
|
|
4698
4927
|
if (current) setDismissedIndex(current.index);
|
|
4699
4928
|
}, []);
|
|
4700
4929
|
const pendingCaret = useRef10(null);
|
|
4701
|
-
const accept =
|
|
4930
|
+
const accept = useCallback10((item) => {
|
|
4702
4931
|
const current = matchRef.current;
|
|
4703
4932
|
if (!current) return;
|
|
4704
4933
|
const chosen = item ?? itemsRef.current[activeIndexRef.current];
|
|
@@ -4715,10 +4944,10 @@ function useComposerAutocomplete(options) {
|
|
|
4715
4944
|
pendingCaret.current = null;
|
|
4716
4945
|
inputRef.current?.setSelectionRange(position, position);
|
|
4717
4946
|
});
|
|
4718
|
-
const readCaret =
|
|
4947
|
+
const readCaret = useCallback10((element) => {
|
|
4719
4948
|
setCaret(element.selectionStart ?? element.value.length);
|
|
4720
4949
|
}, []);
|
|
4721
|
-
const onKeyDown =
|
|
4950
|
+
const onKeyDown = useCallback10(
|
|
4722
4951
|
(event) => {
|
|
4723
4952
|
if (!isOpen) return;
|
|
4724
4953
|
const hasItems = itemsRef.current.length > 0;
|
|
@@ -4753,7 +4982,7 @@ function useComposerAutocomplete(options) {
|
|
|
4753
4982
|
},
|
|
4754
4983
|
[isOpen, acceptOnTab, accept, dismiss, moveHighlight]
|
|
4755
4984
|
);
|
|
4756
|
-
const onChange =
|
|
4985
|
+
const onChange = useCallback10(
|
|
4757
4986
|
(event) => {
|
|
4758
4987
|
readCaret(event.target);
|
|
4759
4988
|
const next = findActiveTrigger(
|
|
@@ -4767,18 +4996,18 @@ function useComposerAutocomplete(options) {
|
|
|
4767
4996
|
},
|
|
4768
4997
|
[readCaret]
|
|
4769
4998
|
);
|
|
4770
|
-
const onSelect =
|
|
4999
|
+
const onSelect = useCallback10(
|
|
4771
5000
|
(event) => readCaret(event.currentTarget),
|
|
4772
5001
|
[readCaret]
|
|
4773
5002
|
);
|
|
4774
|
-
const onClick =
|
|
5003
|
+
const onClick = useCallback10(
|
|
4775
5004
|
(event) => readCaret(event.currentTarget),
|
|
4776
5005
|
[readCaret]
|
|
4777
5006
|
);
|
|
4778
|
-
const setInput =
|
|
5007
|
+
const setInput = useCallback10((element) => {
|
|
4779
5008
|
inputRef.current = element;
|
|
4780
5009
|
}, []);
|
|
4781
|
-
const getInputProps =
|
|
5010
|
+
const getInputProps = useCallback10(
|
|
4782
5011
|
() => ({
|
|
4783
5012
|
ref: setInput,
|
|
4784
5013
|
onChange,
|
|
@@ -4805,7 +5034,7 @@ function useComposerAutocomplete(options) {
|
|
|
4805
5034
|
optionId
|
|
4806
5035
|
]
|
|
4807
5036
|
);
|
|
4808
|
-
const getListboxProps =
|
|
5037
|
+
const getListboxProps = useCallback10(
|
|
4809
5038
|
() => ({
|
|
4810
5039
|
id: listboxId,
|
|
4811
5040
|
role: "listbox",
|
|
@@ -4813,7 +5042,7 @@ function useComposerAutocomplete(options) {
|
|
|
4813
5042
|
}),
|
|
4814
5043
|
[listboxId, match]
|
|
4815
5044
|
);
|
|
4816
|
-
const getOptionProps =
|
|
5045
|
+
const getOptionProps = useCallback10(
|
|
4817
5046
|
(index) => ({
|
|
4818
5047
|
id: optionId(index),
|
|
4819
5048
|
role: "option",
|
|
@@ -4846,7 +5075,7 @@ function isPromise(value) {
|
|
|
4846
5075
|
|
|
4847
5076
|
// src/presentation/use-tool-catalog.ts
|
|
4848
5077
|
import { ALL_AGENTS } from "@dudousxd/nestjs-agent-core";
|
|
4849
|
-
import { useCallback as
|
|
5078
|
+
import { useCallback as useCallback11, useEffect as useEffect13, useMemo as useMemo10, useState as useState13 } from "react";
|
|
4850
5079
|
var shared2 = /* @__PURE__ */ new WeakMap();
|
|
4851
5080
|
function load2(client, agent) {
|
|
4852
5081
|
let byAgent = shared2.get(client);
|
|
@@ -4898,7 +5127,7 @@ function useToolCatalog(options = {}) {
|
|
|
4898
5127
|
cancelled = true;
|
|
4899
5128
|
};
|
|
4900
5129
|
}, [client, agent, enabled, generation]);
|
|
4901
|
-
const refresh =
|
|
5130
|
+
const refresh = useCallback11(() => {
|
|
4902
5131
|
shared2.get(client)?.delete(agent ?? "");
|
|
4903
5132
|
setGeneration((current) => current + 1);
|
|
4904
5133
|
}, [client, agent]);
|
|
@@ -4988,6 +5217,8 @@ function storedMessageToUiMessage(message) {
|
|
|
4988
5217
|
id: component.id,
|
|
4989
5218
|
component: component.component,
|
|
4990
5219
|
props: component.props,
|
|
5220
|
+
...component.componentVersions !== void 0 ? { componentVersions: component.componentVersions } : {},
|
|
5221
|
+
...component.fallbackText !== void 0 ? { fallbackText: component.fallbackText } : {},
|
|
4991
5222
|
...component.version !== void 0 ? { version: component.version } : {},
|
|
4992
5223
|
...component.toolCallId !== void 0 ? { toolCallId: component.toolCallId } : {}
|
|
4993
5224
|
}
|
|
@@ -5007,6 +5238,8 @@ function storedMessageToUiMessage(message) {
|
|
|
5007
5238
|
data: {
|
|
5008
5239
|
id: approval.toolCallId,
|
|
5009
5240
|
approver: approval.approver,
|
|
5241
|
+
...approval.target !== void 0 ? { target: approval.target } : approval.proposalId !== void 0 ? { target: { kind: "proposal", proposalId: approval.proposalId } } : {},
|
|
5242
|
+
...approval.confirmation !== void 0 ? { confirmation: approval.confirmation } : {},
|
|
5010
5243
|
...approval.expiresAt !== void 0 ? { expiresAt: approval.expiresAt } : {}
|
|
5011
5244
|
}
|
|
5012
5245
|
});
|
|
@@ -5063,8 +5296,11 @@ function storedMessageToUiMessage(message) {
|
|
|
5063
5296
|
const metadata = {
|
|
5064
5297
|
// The host's own facts first: the library's keys win on a clash.
|
|
5065
5298
|
...message.metadata,
|
|
5299
|
+
...message.actionProposalOutcome === void 0 ? {} : { actionProposalOutcomeId: message.actionProposalOutcome.id },
|
|
5066
5300
|
...message.feedback !== void 0 ? { feedback: message.feedback } : {},
|
|
5067
5301
|
...message.createdAt ? { createdAt: message.createdAt } : {},
|
|
5302
|
+
...message.agentName !== void 0 ? { agentName: message.agentName } : {},
|
|
5303
|
+
...message.persona !== void 0 ? { persona: message.persona } : {},
|
|
5068
5304
|
...message.usage !== void 0 ? {
|
|
5069
5305
|
usage: {
|
|
5070
5306
|
inputTokens: message.usage.inputTokens,
|
|
@@ -5096,6 +5332,8 @@ function storedThreadToUiMessages(messages) {
|
|
|
5096
5332
|
return turns.map(mergeTurn);
|
|
5097
5333
|
}
|
|
5098
5334
|
function sameRun(previous, next) {
|
|
5335
|
+
if (previous.actionProposalOutcome !== void 0 || next.actionProposalOutcome !== void 0)
|
|
5336
|
+
return false;
|
|
5099
5337
|
return previous.runId === void 0 || next.runId === void 0 || previous.runId === next.runId;
|
|
5100
5338
|
}
|
|
5101
5339
|
function mergeTurn(rows) {
|
|
@@ -5115,7 +5353,9 @@ function mergeTurn(rows) {
|
|
|
5115
5353
|
...Object.assign({}, ...rows.map((row) => row.metadata ?? {})),
|
|
5116
5354
|
...usage !== void 0 ? { usage } : {},
|
|
5117
5355
|
...feedback !== void 0 ? { feedback } : {},
|
|
5118
|
-
...createdAt ? { createdAt } : {}
|
|
5356
|
+
...createdAt ? { createdAt } : {},
|
|
5357
|
+
...lastRow.agentName !== void 0 ? { agentName: lastRow.agentName } : {},
|
|
5358
|
+
...lastRow.persona !== void 0 ? { persona: lastRow.persona } : {}
|
|
5119
5359
|
};
|
|
5120
5360
|
return {
|
|
5121
5361
|
id: lastRow.id,
|
|
@@ -5141,7 +5381,162 @@ function sumUsage(rows) {
|
|
|
5141
5381
|
|
|
5142
5382
|
// src/use-agent-chat.ts
|
|
5143
5383
|
import { useChat } from "@ai-sdk/react";
|
|
5144
|
-
import { useCallback as
|
|
5384
|
+
import { useCallback as useCallback13, useEffect as useEffect16, useMemo as useMemo11, useRef as useRef13, useState as useState16 } from "react";
|
|
5385
|
+
|
|
5386
|
+
// src/approvals/use-action-proposals.ts
|
|
5387
|
+
import { useCallback as useCallback12, useEffect as useEffect15, useRef as useRef12, useState as useState15 } from "react";
|
|
5388
|
+
|
|
5389
|
+
// src/approvals/proposals.ts
|
|
5390
|
+
function proposalNeedsPolling(proposal) {
|
|
5391
|
+
return proposal.decision === "pending" || proposal.execution?.status === "queued" || proposal.execution?.status === "executing" || proposal.outcomeDelivery?.status === "pending";
|
|
5392
|
+
}
|
|
5393
|
+
function reconcileProposalMessages(current, proposals, facts) {
|
|
5394
|
+
const messages = current.map((message) => {
|
|
5395
|
+
const relevant = proposals.filter(
|
|
5396
|
+
(proposal) => message.parts.some((part) => {
|
|
5397
|
+
if ("data" in part && record(part.data) && record(part.data.target) && part.data.target.kind === "proposal")
|
|
5398
|
+
return part.data.target.proposalId === proposal.id;
|
|
5399
|
+
if ("toolCallId" in part && part.toolCallId === proposal.originToolCallId) {
|
|
5400
|
+
if ("output" in part && record(part.output) && typeof part.output.proposalId === "string")
|
|
5401
|
+
return part.output.proposalId === proposal.id;
|
|
5402
|
+
return record(message.metadata) && message.metadata.runId === proposal.originRunId;
|
|
5403
|
+
}
|
|
5404
|
+
return false;
|
|
5405
|
+
})
|
|
5406
|
+
);
|
|
5407
|
+
if (relevant.length === 0) return message;
|
|
5408
|
+
const ids = new Set(relevant.map((proposal) => proposal.originToolCallId));
|
|
5409
|
+
const parts = message.parts.filter(
|
|
5410
|
+
(part) => !(part.type === "data-action-proposal" && "id" in part && typeof part.id === "string" && ids.has(part.id))
|
|
5411
|
+
);
|
|
5412
|
+
for (const proposal of relevant)
|
|
5413
|
+
parts.push({
|
|
5414
|
+
type: "data-action-proposal",
|
|
5415
|
+
id: proposal.originToolCallId,
|
|
5416
|
+
data: {
|
|
5417
|
+
id: proposal.originToolCallId,
|
|
5418
|
+
target: { kind: "proposal", proposalId: proposal.id, threadId: proposal.threadId },
|
|
5419
|
+
approver: proposal.approver,
|
|
5420
|
+
confirmation: proposal.confirmation,
|
|
5421
|
+
expiresAt: proposal.expiresAt === null ? null : Math.abs(proposal.expiresAt) <= 864e13 ? new Date(proposal.expiresAt).toISOString() : null,
|
|
5422
|
+
status: proposal.decision,
|
|
5423
|
+
executionStatus: proposal.execution?.status ?? null,
|
|
5424
|
+
remember: proposal.decisionAudit?.remember === true,
|
|
5425
|
+
decidedBy: proposal.decisionAudit?.actorRef ?? null,
|
|
5426
|
+
decidedVia: proposal.decisionAudit?.via ?? null,
|
|
5427
|
+
reason: proposal.decisionAudit?.reason ?? null
|
|
5428
|
+
}
|
|
5429
|
+
});
|
|
5430
|
+
return { ...message, parts };
|
|
5431
|
+
});
|
|
5432
|
+
const knownMessages = new Set(messages.map((message) => message.id));
|
|
5433
|
+
const knownOutcomes = new Set(
|
|
5434
|
+
messages.map((message) => outcomeId(message.metadata)).filter(Boolean)
|
|
5435
|
+
);
|
|
5436
|
+
for (const fact of facts) {
|
|
5437
|
+
const id = fact.actionProposalOutcome?.id;
|
|
5438
|
+
if (id === void 0 || knownMessages.has(fact.id) || knownOutcomes.has(id)) continue;
|
|
5439
|
+
const message = storedMessageToUiMessage(fact);
|
|
5440
|
+
messages.push({
|
|
5441
|
+
...message,
|
|
5442
|
+
metadata: {
|
|
5443
|
+
...record(message.metadata) ? message.metadata : {},
|
|
5444
|
+
actionProposalOutcomeId: id
|
|
5445
|
+
}
|
|
5446
|
+
});
|
|
5447
|
+
knownMessages.add(fact.id);
|
|
5448
|
+
knownOutcomes.add(id);
|
|
5449
|
+
}
|
|
5450
|
+
return messages;
|
|
5451
|
+
}
|
|
5452
|
+
function record(value) {
|
|
5453
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5454
|
+
}
|
|
5455
|
+
function outcomeId(value) {
|
|
5456
|
+
return record(value) && typeof value.actionProposalOutcomeId === "string" ? value.actionProposalOutcomeId : void 0;
|
|
5457
|
+
}
|
|
5458
|
+
|
|
5459
|
+
// src/approvals/use-action-proposals.ts
|
|
5460
|
+
function useActionProposals(backend, threadId, setMessages, refreshKey, pollMs = 1e3) {
|
|
5461
|
+
const [items, setItems] = useState15([]);
|
|
5462
|
+
const [error, setError] = useState15(null);
|
|
5463
|
+
const latest = useRef12({ threadId, setMessages });
|
|
5464
|
+
latest.current = { threadId, setMessages };
|
|
5465
|
+
const mounted = useRef12(true);
|
|
5466
|
+
const requests = useRef12(/* @__PURE__ */ new Map());
|
|
5467
|
+
useEffect15(() => {
|
|
5468
|
+
mounted.current = true;
|
|
5469
|
+
return () => {
|
|
5470
|
+
mounted.current = false;
|
|
5471
|
+
};
|
|
5472
|
+
}, []);
|
|
5473
|
+
const refresh = useCallback12(async () => {
|
|
5474
|
+
if (threadId === void 0 || backend.listActionProposals === void 0) return;
|
|
5475
|
+
const pending = requests.current.get(threadId);
|
|
5476
|
+
if (pending) return pending;
|
|
5477
|
+
const request = (async () => {
|
|
5478
|
+
try {
|
|
5479
|
+
const proposals = await backend.listActionProposals?.({ threadId });
|
|
5480
|
+
if (!mounted.current || latest.current.threadId !== threadId || !Array.isArray(proposals))
|
|
5481
|
+
return;
|
|
5482
|
+
const admitted = proposals.some(
|
|
5483
|
+
(proposal) => proposal.outcomeDelivery?.status === "admitted"
|
|
5484
|
+
);
|
|
5485
|
+
const facts = admitted ? (await backend.getThread(threadId)).messages.filter(
|
|
5486
|
+
(message) => message.actionProposalOutcome !== void 0
|
|
5487
|
+
) : [];
|
|
5488
|
+
if (!mounted.current || latest.current.threadId !== threadId) return;
|
|
5489
|
+
setItems(proposals);
|
|
5490
|
+
setError(null);
|
|
5491
|
+
latest.current.setMessages(
|
|
5492
|
+
(current) => reconcileProposalMessages(current, proposals, facts)
|
|
5493
|
+
);
|
|
5494
|
+
} catch (cause) {
|
|
5495
|
+
if (mounted.current && latest.current.threadId === threadId)
|
|
5496
|
+
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
5497
|
+
}
|
|
5498
|
+
})();
|
|
5499
|
+
requests.current.set(threadId, request);
|
|
5500
|
+
try {
|
|
5501
|
+
await request;
|
|
5502
|
+
} finally {
|
|
5503
|
+
requests.current.delete(threadId);
|
|
5504
|
+
}
|
|
5505
|
+
}, [backend, threadId]);
|
|
5506
|
+
useEffect15(() => {
|
|
5507
|
+
setItems([]);
|
|
5508
|
+
setError(null);
|
|
5509
|
+
}, [threadId]);
|
|
5510
|
+
useEffect15(() => {
|
|
5511
|
+
void refresh();
|
|
5512
|
+
}, [refresh, refreshKey]);
|
|
5513
|
+
useEffect15(() => {
|
|
5514
|
+
if (!items.some(proposalNeedsPolling) || pollMs <= 0) return;
|
|
5515
|
+
const timer = setInterval(() => {
|
|
5516
|
+
void refresh();
|
|
5517
|
+
}, pollMs);
|
|
5518
|
+
return () => clearInterval(timer);
|
|
5519
|
+
}, [items, pollMs, refresh]);
|
|
5520
|
+
useEffect15(() => {
|
|
5521
|
+
const refetch = () => {
|
|
5522
|
+
void refresh();
|
|
5523
|
+
};
|
|
5524
|
+
const visible = () => {
|
|
5525
|
+
if (document.visibilityState === "visible") refetch();
|
|
5526
|
+
};
|
|
5527
|
+
window.addEventListener("focus", refetch);
|
|
5528
|
+
window.addEventListener("online", refetch);
|
|
5529
|
+
document.addEventListener("visibilitychange", visible);
|
|
5530
|
+
return () => {
|
|
5531
|
+
window.removeEventListener("focus", refetch);
|
|
5532
|
+
window.removeEventListener("online", refetch);
|
|
5533
|
+
document.removeEventListener("visibilitychange", visible);
|
|
5534
|
+
};
|
|
5535
|
+
}, [refresh]);
|
|
5536
|
+
return { items, error, refresh };
|
|
5537
|
+
}
|
|
5538
|
+
|
|
5539
|
+
// src/use-agent-chat.ts
|
|
5145
5540
|
var EMPTY_QUEUE = { items: [], paused: null };
|
|
5146
5541
|
var localQueueSequence = 0;
|
|
5147
5542
|
function queuedUserMessage(turn) {
|
|
@@ -5196,13 +5591,16 @@ function localChatId() {
|
|
|
5196
5591
|
return `local-chat-${localChatSequence}`;
|
|
5197
5592
|
}
|
|
5198
5593
|
function useAgentChat(options = {}) {
|
|
5199
|
-
const
|
|
5594
|
+
const providerCapabilities = useAgentUiCapabilities();
|
|
5595
|
+
const capabilitiesRef = useRef13(providerCapabilities);
|
|
5596
|
+
capabilitiesRef.current = providerCapabilities;
|
|
5597
|
+
const latest = useRef13(options);
|
|
5200
5598
|
latest.current = options;
|
|
5201
5599
|
const resolved = useAgentBackend(options.backend);
|
|
5202
|
-
const client =
|
|
5203
|
-
const createdThreadId =
|
|
5204
|
-
const chatIdRef =
|
|
5205
|
-
const boundThreadRef =
|
|
5600
|
+
const client = useRef13(resolved).current;
|
|
5601
|
+
const createdThreadId = useRef13(void 0);
|
|
5602
|
+
const chatIdRef = useRef13(options.threadId ?? localChatId());
|
|
5603
|
+
const boundThreadRef = useRef13(options.threadId);
|
|
5206
5604
|
if (options.threadId !== boundThreadRef.current) {
|
|
5207
5605
|
boundThreadRef.current = options.threadId;
|
|
5208
5606
|
const adopting = options.threadId !== void 0 && options.threadId === createdThreadId.current;
|
|
@@ -5212,39 +5610,43 @@ function useAgentChat(options = {}) {
|
|
|
5212
5610
|
}
|
|
5213
5611
|
}
|
|
5214
5612
|
const chatId = chatIdRef.current;
|
|
5215
|
-
const [runId, setRunId] =
|
|
5216
|
-
const runIdRef =
|
|
5613
|
+
const [runId, setRunId] = useState16(options.resumeRunId);
|
|
5614
|
+
const runIdRef = useRef13(runId);
|
|
5217
5615
|
runIdRef.current = runId;
|
|
5218
|
-
const settlingRunIdRef =
|
|
5219
|
-
const autoResumeRunIdRef =
|
|
5220
|
-
const [activeRunId, setActiveRunId] =
|
|
5221
|
-
const [historyFor, setHistoryFor] =
|
|
5222
|
-
const [historyError, setHistoryError] =
|
|
5223
|
-
const [runError, setRunError] =
|
|
5224
|
-
const [threadModel, setThreadModel] =
|
|
5225
|
-
const [
|
|
5226
|
-
const
|
|
5616
|
+
const settlingRunIdRef = useRef13(void 0);
|
|
5617
|
+
const autoResumeRunIdRef = useRef13(void 0);
|
|
5618
|
+
const [activeRunId, setActiveRunId] = useState16(null);
|
|
5619
|
+
const [historyFor, setHistoryFor] = useState16(void 0);
|
|
5620
|
+
const [historyError, setHistoryError] = useState16(null);
|
|
5621
|
+
const [runError, setRunError] = useState16(null);
|
|
5622
|
+
const [threadModel, setThreadModel] = useState16(null);
|
|
5623
|
+
const [threadPersona, setThreadPersona] = useState16(null);
|
|
5624
|
+
const [pickedModel, setPickedModel] = useState16(void 0);
|
|
5625
|
+
const pickedModelRef = useRef13(pickedModel);
|
|
5227
5626
|
pickedModelRef.current = pickedModel;
|
|
5228
|
-
const lockedRef =
|
|
5229
|
-
const pendingPin =
|
|
5230
|
-
const regenerateNext =
|
|
5231
|
-
const currentThreadId =
|
|
5627
|
+
const lockedRef = useRef13(false);
|
|
5628
|
+
const pendingPin = useRef13(void 0);
|
|
5629
|
+
const regenerateNext = useRef13(false);
|
|
5630
|
+
const currentThreadId = useCallback13(
|
|
5232
5631
|
() => latest.current.threadId ?? createdThreadId.current,
|
|
5233
5632
|
[]
|
|
5234
5633
|
);
|
|
5235
|
-
const [queueState, setQueueState] =
|
|
5236
|
-
const queueStateRef =
|
|
5237
|
-
const applyQueue =
|
|
5634
|
+
const [queueState, setQueueState] = useState16(EMPTY_QUEUE);
|
|
5635
|
+
const queueStateRef = useRef13(queueState);
|
|
5636
|
+
const applyQueue = useCallback13((next) => {
|
|
5238
5637
|
queueStateRef.current = next;
|
|
5239
5638
|
setQueueState(next);
|
|
5240
5639
|
}, []);
|
|
5241
|
-
const [pendingSends, setPendingSends] =
|
|
5242
|
-
const [queueError, setQueueError] =
|
|
5243
|
-
const handoff =
|
|
5244
|
-
const queuedSend =
|
|
5245
|
-
const
|
|
5246
|
-
|
|
5640
|
+
const [pendingSends, setPendingSends] = useState16([]);
|
|
5641
|
+
const [queueError, setQueueError] = useState16(null);
|
|
5642
|
+
const handoff = useRef13(void 0);
|
|
5643
|
+
const queuedSend = useRef13(void 0);
|
|
5644
|
+
const proposalRefreshRef = useRef13(async () => {
|
|
5645
|
+
});
|
|
5646
|
+
const threadWaiters = useRef13([]);
|
|
5647
|
+
const turnBody = useCallback13(() => {
|
|
5247
5648
|
const current = latest.current;
|
|
5649
|
+
if (current.persona !== void 0) setThreadPersona(current.persona);
|
|
5248
5650
|
const pageContext = current.getPageContext?.() ?? null;
|
|
5249
5651
|
const threadId = currentThreadId();
|
|
5250
5652
|
const model = current.model ?? (lockedRef.current ? void 0 : pickedModelRef.current);
|
|
@@ -5252,13 +5654,15 @@ function useAgentChat(options = {}) {
|
|
|
5252
5654
|
// Read per send: a host that switches agents before the first message (a picker on a new
|
|
5253
5655
|
// chat) sends the one picked now, not the one this chat mounted with.
|
|
5254
5656
|
...current.agent !== void 0 ? { agent: current.agent } : {},
|
|
5657
|
+
...current.persona !== void 0 ? { persona: current.persona } : {},
|
|
5255
5658
|
...threadId !== void 0 ? { threadId } : {},
|
|
5256
5659
|
...model !== void 0 ? { model } : {},
|
|
5257
|
-
...pageContext ? { pageContext } : {}
|
|
5660
|
+
...pageContext ? { pageContext } : {},
|
|
5661
|
+
...(current.uiCapabilities ?? capabilitiesRef.current) === void 0 ? {} : { uiCapabilities: current.uiCapabilities ?? capabilitiesRef.current }
|
|
5258
5662
|
};
|
|
5259
5663
|
}, [currentThreadId]);
|
|
5260
|
-
const [connection, setConnection] =
|
|
5261
|
-
const resyncAfterSettle =
|
|
5664
|
+
const [connection, setConnection] = useState16({ status: "live" });
|
|
5665
|
+
const resyncAfterSettle = useRef13(false);
|
|
5262
5666
|
const transport = useMemo11(() => {
|
|
5263
5667
|
function onMeta(meta) {
|
|
5264
5668
|
settlingRunIdRef.current = meta.runId;
|
|
@@ -5311,7 +5715,7 @@ function useAgentChat(options = {}) {
|
|
|
5311
5715
|
}
|
|
5312
5716
|
});
|
|
5313
5717
|
}, []);
|
|
5314
|
-
const backgroundRef =
|
|
5718
|
+
const backgroundRef = useRef13(() => Promise.resolve());
|
|
5315
5719
|
const chat = useChat({
|
|
5316
5720
|
transport,
|
|
5317
5721
|
id: chatId,
|
|
@@ -5319,6 +5723,7 @@ function useAgentChat(options = {}) {
|
|
|
5319
5723
|
...options.initialMessages !== void 0 ? { messages: options.initialMessages } : {},
|
|
5320
5724
|
onData: (part) => {
|
|
5321
5725
|
latest.current.onData?.(part);
|
|
5726
|
+
if (part.type === "data-proposal-decision") void proposalRefreshRef.current();
|
|
5322
5727
|
if (part.type === "data-queue") {
|
|
5323
5728
|
onQueueData(part.data);
|
|
5324
5729
|
}
|
|
@@ -5365,7 +5770,7 @@ function useAgentChat(options = {}) {
|
|
|
5365
5770
|
}
|
|
5366
5771
|
}
|
|
5367
5772
|
});
|
|
5368
|
-
const chatRef =
|
|
5773
|
+
const chatRef = useRef13(chat);
|
|
5369
5774
|
chatRef.current = chat;
|
|
5370
5775
|
function onQueueData(data) {
|
|
5371
5776
|
const frame = data ?? {};
|
|
@@ -5413,13 +5818,14 @@ function useAgentChat(options = {}) {
|
|
|
5413
5818
|
} catch {
|
|
5414
5819
|
}
|
|
5415
5820
|
}
|
|
5416
|
-
const firstChatId =
|
|
5417
|
-
|
|
5821
|
+
const firstChatId = useRef13(chatId);
|
|
5822
|
+
useEffect16(() => {
|
|
5418
5823
|
if (chatId === firstChatId.current) return;
|
|
5419
5824
|
firstChatId.current = chatId;
|
|
5420
5825
|
setRunId(void 0);
|
|
5421
5826
|
setActiveRunId(null);
|
|
5422
5827
|
setThreadModel(null);
|
|
5828
|
+
setThreadPersona(null);
|
|
5423
5829
|
setPickedModel(void 0);
|
|
5424
5830
|
setBackgroundRuns([]);
|
|
5425
5831
|
setHistoryError(null);
|
|
@@ -5432,7 +5838,7 @@ function useAgentChat(options = {}) {
|
|
|
5432
5838
|
handoff.current = void 0;
|
|
5433
5839
|
queuedSend.current = void 0;
|
|
5434
5840
|
}, [chatId]);
|
|
5435
|
-
|
|
5841
|
+
useEffect16(() => {
|
|
5436
5842
|
const threadId = options.threadId;
|
|
5437
5843
|
if (threadId === void 0) return;
|
|
5438
5844
|
if (threadId === createdThreadId.current) return;
|
|
@@ -5448,6 +5854,7 @@ function useAgentChat(options = {}) {
|
|
|
5448
5854
|
const stored = Array.isArray(thread.messages) ? thread.messages : [];
|
|
5449
5855
|
setActiveRunId(active);
|
|
5450
5856
|
setThreadModel(thread.model ?? null);
|
|
5857
|
+
setThreadPersona(thread.persona ?? null);
|
|
5451
5858
|
setHistoryError(null);
|
|
5452
5859
|
const queue2 = thread.queue ?? EMPTY_QUEUE;
|
|
5453
5860
|
applyQueue(queue2);
|
|
@@ -5478,8 +5885,8 @@ function useAgentChat(options = {}) {
|
|
|
5478
5885
|
};
|
|
5479
5886
|
}, [client, chatId, options.threadId]);
|
|
5480
5887
|
const isLoadingHistory = options.threadId !== void 0 && options.threadId !== createdThreadId.current && options.history !== false && options.initialMessages === void 0 && historyFor !== options.threadId;
|
|
5481
|
-
const turnInFlight =
|
|
5482
|
-
const isTurnInFlight =
|
|
5888
|
+
const turnInFlight = useRef13(false);
|
|
5889
|
+
const isTurnInFlight = useCallback13(
|
|
5483
5890
|
() => turnInFlight.current || transport.isAttemptLive,
|
|
5484
5891
|
[transport]
|
|
5485
5892
|
);
|
|
@@ -5488,20 +5895,20 @@ function useAgentChat(options = {}) {
|
|
|
5488
5895
|
enabled: options.quota !== false && typeof client.getQuota === "function"
|
|
5489
5896
|
});
|
|
5490
5897
|
const blocked = options.blocked !== void 0 ? options.blocked : quota.blocked;
|
|
5491
|
-
const blockedRef =
|
|
5898
|
+
const blockedRef = useRef13(blocked);
|
|
5492
5899
|
blockedRef.current = blocked;
|
|
5493
5900
|
const whileRunning = typeof client.enqueueMessage === "function" ? options.whileRunning ?? "queue" : "block";
|
|
5494
|
-
const whileRunningRef =
|
|
5901
|
+
const whileRunningRef = useRef13(whileRunning);
|
|
5495
5902
|
whileRunningRef.current = whileRunning;
|
|
5496
|
-
const canQueueRef =
|
|
5903
|
+
const canQueueRef = useRef13(false);
|
|
5497
5904
|
canQueueRef.current = typeof client.enqueueMessage === "function";
|
|
5498
|
-
const threadForQueue =
|
|
5905
|
+
const threadForQueue = useCallback13(async () => {
|
|
5499
5906
|
const known = currentThreadId();
|
|
5500
5907
|
if (known !== void 0) return known;
|
|
5501
5908
|
if (!isTurnInFlight()) throw new Error("queue: this chat has no thread yet");
|
|
5502
5909
|
return new Promise((resolve) => threadWaiters.current.push(resolve));
|
|
5503
5910
|
}, [currentThreadId, isTurnInFlight]);
|
|
5504
|
-
const queueCall =
|
|
5911
|
+
const queueCall = useCallback13(async (run) => {
|
|
5505
5912
|
try {
|
|
5506
5913
|
const result = await run();
|
|
5507
5914
|
setQueueError(null);
|
|
@@ -5511,7 +5918,7 @@ function useAgentChat(options = {}) {
|
|
|
5511
5918
|
throw error;
|
|
5512
5919
|
}
|
|
5513
5920
|
}, []);
|
|
5514
|
-
const enqueue =
|
|
5921
|
+
const enqueue = useCallback13(
|
|
5515
5922
|
async (text2, {
|
|
5516
5923
|
attachments = [],
|
|
5517
5924
|
mode = "queue"
|
|
@@ -5559,7 +5966,7 @@ function useAgentChat(options = {}) {
|
|
|
5559
5966
|
},
|
|
5560
5967
|
[client, queueCall, threadForQueue, turnBody, applyQueue, isTurnInFlight]
|
|
5561
5968
|
);
|
|
5562
|
-
const sendMessage =
|
|
5969
|
+
const sendMessage = useCallback13(
|
|
5563
5970
|
async (message, options2) => {
|
|
5564
5971
|
const block = blockedRef.current;
|
|
5565
5972
|
if (block != null) throw new QuotaBlockedError(block);
|
|
@@ -5583,7 +5990,7 @@ function useAgentChat(options = {}) {
|
|
|
5583
5990
|
},
|
|
5584
5991
|
[isTurnInFlight, enqueue]
|
|
5585
5992
|
);
|
|
5586
|
-
const removeQueued =
|
|
5993
|
+
const removeQueued = useCallback13(
|
|
5587
5994
|
async (id) => {
|
|
5588
5995
|
const previous = queueStateRef.current;
|
|
5589
5996
|
applyQueue({ ...previous, items: previous.items.filter((item) => item.id !== id) });
|
|
@@ -5596,7 +6003,7 @@ function useAgentChat(options = {}) {
|
|
|
5596
6003
|
},
|
|
5597
6004
|
[client, queueCall, applyQueue]
|
|
5598
6005
|
);
|
|
5599
|
-
const interruptQueued =
|
|
6006
|
+
const interruptQueued = useCallback13(
|
|
5600
6007
|
async (id) => {
|
|
5601
6008
|
const previous = queueStateRef.current;
|
|
5602
6009
|
const moving = previous.items.find((item) => item.id === id);
|
|
@@ -5631,7 +6038,7 @@ function useAgentChat(options = {}) {
|
|
|
5631
6038
|
},
|
|
5632
6039
|
[client, queueCall, applyQueue, isTurnInFlight]
|
|
5633
6040
|
);
|
|
5634
|
-
const editQueued =
|
|
6041
|
+
const editQueued = useCallback13(
|
|
5635
6042
|
async (id, text2) => {
|
|
5636
6043
|
applyQueue(
|
|
5637
6044
|
await queueCall(
|
|
@@ -5641,7 +6048,7 @@ function useAgentChat(options = {}) {
|
|
|
5641
6048
|
},
|
|
5642
6049
|
[client, queueCall, applyQueue]
|
|
5643
6050
|
);
|
|
5644
|
-
const moveQueued =
|
|
6051
|
+
const moveQueued = useCallback13(
|
|
5645
6052
|
async (id, index) => {
|
|
5646
6053
|
const previous = queueStateRef.current;
|
|
5647
6054
|
const moving = previous.items.find((item) => item.id === id);
|
|
@@ -5663,12 +6070,12 @@ function useAgentChat(options = {}) {
|
|
|
5663
6070
|
},
|
|
5664
6071
|
[client, queueCall, applyQueue]
|
|
5665
6072
|
);
|
|
5666
|
-
const clearQueue =
|
|
6073
|
+
const clearQueue = useCallback13(async () => {
|
|
5667
6074
|
const threadId = currentThreadId();
|
|
5668
6075
|
if (threadId === void 0) return;
|
|
5669
6076
|
applyQueue(await queueCall(() => requireBackendMethod(client, "clearQueue")(threadId)));
|
|
5670
6077
|
}, [client, queueCall, currentThreadId, applyQueue]);
|
|
5671
|
-
const resumeQueue =
|
|
6078
|
+
const resumeQueue = useCallback13(async () => {
|
|
5672
6079
|
const threadId = currentThreadId();
|
|
5673
6080
|
if (threadId === void 0) return;
|
|
5674
6081
|
const before = queueStateRef.current;
|
|
@@ -5686,7 +6093,7 @@ function useAgentChat(options = {}) {
|
|
|
5686
6093
|
else attachTo(turn);
|
|
5687
6094
|
}
|
|
5688
6095
|
}, [client, queueCall, currentThreadId, applyQueue, isTurnInFlight]);
|
|
5689
|
-
const resumeQueueRef =
|
|
6096
|
+
const resumeQueueRef = useRef13(resumeQueue);
|
|
5690
6097
|
resumeQueueRef.current = resumeQueue;
|
|
5691
6098
|
const queuedItems = [
|
|
5692
6099
|
...pendingSends.filter((item) => item.interrupt),
|
|
@@ -5716,7 +6123,7 @@ function useAgentChat(options = {}) {
|
|
|
5716
6123
|
resume: resumeQueue,
|
|
5717
6124
|
error: queueError
|
|
5718
6125
|
};
|
|
5719
|
-
const addToolResult =
|
|
6126
|
+
const addToolResult = useCallback13(
|
|
5720
6127
|
({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
5721
6128
|
tool,
|
|
5722
6129
|
toolCallId,
|
|
@@ -5724,8 +6131,8 @@ function useAgentChat(options = {}) {
|
|
|
5724
6131
|
}),
|
|
5725
6132
|
[]
|
|
5726
6133
|
);
|
|
5727
|
-
const [backgroundRuns, setBackgroundRuns] =
|
|
5728
|
-
const refreshBackground =
|
|
6134
|
+
const [backgroundRuns, setBackgroundRuns] = useState16([]);
|
|
6135
|
+
const refreshBackground = useCallback13(async () => {
|
|
5729
6136
|
const threadId = currentThreadId();
|
|
5730
6137
|
if (threadId === void 0) {
|
|
5731
6138
|
return;
|
|
@@ -5745,13 +6152,13 @@ function useAgentChat(options = {}) {
|
|
|
5745
6152
|
}, [client, currentThreadId]);
|
|
5746
6153
|
backgroundRef.current = refreshBackground;
|
|
5747
6154
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
5748
|
-
|
|
6155
|
+
useEffect16(() => {
|
|
5749
6156
|
if (options.background !== true || options.threadId === void 0) {
|
|
5750
6157
|
return;
|
|
5751
6158
|
}
|
|
5752
6159
|
void refreshBackground();
|
|
5753
6160
|
}, [options.background, options.threadId, chatId, refreshBackground]);
|
|
5754
|
-
|
|
6161
|
+
useEffect16(() => {
|
|
5755
6162
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
5756
6163
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
5757
6164
|
return;
|
|
@@ -5759,7 +6166,15 @@ function useAgentChat(options = {}) {
|
|
|
5759
6166
|
const timer = setInterval(() => void refreshBackground(), every);
|
|
5760
6167
|
return () => clearInterval(timer);
|
|
5761
6168
|
}, [isWorking, refreshBackground]);
|
|
5762
|
-
const
|
|
6169
|
+
const proposals = useActionProposals(
|
|
6170
|
+
client,
|
|
6171
|
+
options.proposals === false || options.proposals !== true && options.history === false && options.resume === false ? void 0 : currentThreadId(),
|
|
6172
|
+
(update) => chatRef.current.setMessages(update),
|
|
6173
|
+
`${chat.status}:${connection.status}`,
|
|
6174
|
+
options.proposalPollMs
|
|
6175
|
+
);
|
|
6176
|
+
proposalRefreshRef.current = proposals.refresh;
|
|
6177
|
+
const cancel = useCallback13(async () => {
|
|
5763
6178
|
chatRef.current.stop();
|
|
5764
6179
|
const active = runIdRef.current;
|
|
5765
6180
|
if (active) {
|
|
@@ -5776,8 +6191,23 @@ function useAgentChat(options = {}) {
|
|
|
5776
6191
|
}
|
|
5777
6192
|
}
|
|
5778
6193
|
}, [client, currentThreadId, applyQueue]);
|
|
5779
|
-
const approve =
|
|
5780
|
-
async ({ toolCallId, remember, via }) => {
|
|
6194
|
+
const approve = useCallback13(
|
|
6195
|
+
async ({ toolCallId, target, remember, via }) => {
|
|
6196
|
+
if (target?.kind === "proposal") {
|
|
6197
|
+
const threadId = target.threadId ?? currentThreadId();
|
|
6198
|
+
if (threadId === void 0)
|
|
6199
|
+
throw new Error("A proposal decision requires its thread scope");
|
|
6200
|
+
await requireBackendMethod(
|
|
6201
|
+
client,
|
|
6202
|
+
"approveActionProposal"
|
|
6203
|
+
)({
|
|
6204
|
+
threadId,
|
|
6205
|
+
proposalId: target.proposalId,
|
|
6206
|
+
...remember === true ? { remember: true } : {}
|
|
6207
|
+
});
|
|
6208
|
+
await proposals.refresh();
|
|
6209
|
+
return;
|
|
6210
|
+
}
|
|
5781
6211
|
await requireBackendMethod(
|
|
5782
6212
|
client,
|
|
5783
6213
|
"approveToolCall"
|
|
@@ -5787,10 +6217,25 @@ function useAgentChat(options = {}) {
|
|
|
5787
6217
|
...via !== void 0 ? { via } : {}
|
|
5788
6218
|
});
|
|
5789
6219
|
},
|
|
5790
|
-
[client]
|
|
6220
|
+
[client, currentThreadId, proposals.refresh]
|
|
5791
6221
|
);
|
|
5792
|
-
const reject =
|
|
5793
|
-
async ({ toolCallId, reason, via }) => {
|
|
6222
|
+
const reject = useCallback13(
|
|
6223
|
+
async ({ toolCallId, target, reason, via }) => {
|
|
6224
|
+
if (target?.kind === "proposal") {
|
|
6225
|
+
const threadId = target.threadId ?? currentThreadId();
|
|
6226
|
+
if (threadId === void 0)
|
|
6227
|
+
throw new Error("A proposal decision requires its thread scope");
|
|
6228
|
+
await requireBackendMethod(
|
|
6229
|
+
client,
|
|
6230
|
+
"rejectActionProposal"
|
|
6231
|
+
)({
|
|
6232
|
+
threadId,
|
|
6233
|
+
proposalId: target.proposalId,
|
|
6234
|
+
...reason === void 0 ? {} : { reason }
|
|
6235
|
+
});
|
|
6236
|
+
await proposals.refresh();
|
|
6237
|
+
return;
|
|
6238
|
+
}
|
|
5794
6239
|
await requireBackendMethod(
|
|
5795
6240
|
client,
|
|
5796
6241
|
"rejectToolCall"
|
|
@@ -5800,9 +6245,9 @@ function useAgentChat(options = {}) {
|
|
|
5800
6245
|
...via !== void 0 ? { via } : {}
|
|
5801
6246
|
});
|
|
5802
6247
|
},
|
|
5803
|
-
[client]
|
|
6248
|
+
[client, currentThreadId, proposals.refresh]
|
|
5804
6249
|
);
|
|
5805
|
-
const answer =
|
|
6250
|
+
const answer = useCallback13(
|
|
5806
6251
|
async ({ toolCallId, answers, via }) => {
|
|
5807
6252
|
await requireBackendMethod(
|
|
5808
6253
|
client,
|
|
@@ -5815,7 +6260,7 @@ function useAgentChat(options = {}) {
|
|
|
5815
6260
|
},
|
|
5816
6261
|
[client]
|
|
5817
6262
|
);
|
|
5818
|
-
const skip =
|
|
6263
|
+
const skip = useCallback13(
|
|
5819
6264
|
async ({ toolCallId, via }) => {
|
|
5820
6265
|
await requireBackendMethod(
|
|
5821
6266
|
client,
|
|
@@ -5824,7 +6269,7 @@ function useAgentChat(options = {}) {
|
|
|
5824
6269
|
},
|
|
5825
6270
|
[client]
|
|
5826
6271
|
);
|
|
5827
|
-
const regenerate =
|
|
6272
|
+
const regenerate = useCallback13(
|
|
5828
6273
|
(_input) => {
|
|
5829
6274
|
const block = blockedRef.current;
|
|
5830
6275
|
if (block != null) throw new QuotaBlockedError(block);
|
|
@@ -5837,7 +6282,7 @@ function useAgentChat(options = {}) {
|
|
|
5837
6282
|
},
|
|
5838
6283
|
[isTurnInFlight]
|
|
5839
6284
|
);
|
|
5840
|
-
const storedIdOf =
|
|
6285
|
+
const storedIdOf = useCallback13(
|
|
5841
6286
|
async (messageId, threadId) => {
|
|
5842
6287
|
const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);
|
|
5843
6288
|
const runOf = message?.metadata?.runId;
|
|
@@ -5848,7 +6293,7 @@ function useAgentChat(options = {}) {
|
|
|
5848
6293
|
},
|
|
5849
6294
|
[client]
|
|
5850
6295
|
);
|
|
5851
|
-
const fork =
|
|
6296
|
+
const fork = useCallback13(
|
|
5852
6297
|
async ({
|
|
5853
6298
|
messageId,
|
|
5854
6299
|
threadId
|
|
@@ -5863,7 +6308,7 @@ function useAgentChat(options = {}) {
|
|
|
5863
6308
|
},
|
|
5864
6309
|
[client, currentThreadId, storedIdOf]
|
|
5865
6310
|
);
|
|
5866
|
-
const truncateFrom =
|
|
6311
|
+
const truncateFrom = useCallback13(
|
|
5867
6312
|
async ({ messageId, threadId }) => {
|
|
5868
6313
|
const target = threadId ?? currentThreadId();
|
|
5869
6314
|
if (target === void 0) throw new Error("truncateFrom: this chat has no thread yet");
|
|
@@ -5872,7 +6317,7 @@ function useAgentChat(options = {}) {
|
|
|
5872
6317
|
},
|
|
5873
6318
|
[client, currentThreadId, storedIdOf]
|
|
5874
6319
|
);
|
|
5875
|
-
const promote =
|
|
6320
|
+
const promote = useCallback13(
|
|
5876
6321
|
async ({ threadId } = {}) => {
|
|
5877
6322
|
const target = threadId ?? currentThreadId();
|
|
5878
6323
|
if (target === void 0) throw new Error("promote: this chat has no thread yet");
|
|
@@ -5881,24 +6326,24 @@ function useAgentChat(options = {}) {
|
|
|
5881
6326
|
},
|
|
5882
6327
|
[client, currentThreadId]
|
|
5883
6328
|
);
|
|
5884
|
-
const [modelsWanted, setModelsWanted] =
|
|
5885
|
-
const modelsWantedRef =
|
|
6329
|
+
const [modelsWanted, setModelsWanted] = useState16(false);
|
|
6330
|
+
const modelsWantedRef = useRef13(modelsWanted);
|
|
5886
6331
|
modelsWantedRef.current = modelsWanted;
|
|
5887
6332
|
const catalog = useModels({
|
|
5888
6333
|
backend: client,
|
|
5889
6334
|
...options.agent !== void 0 ? { agent: options.agent } : {},
|
|
5890
6335
|
enabled: modelsWanted && typeof client.listModels === "function"
|
|
5891
6336
|
});
|
|
5892
|
-
const wantModels =
|
|
6337
|
+
const wantModels = useCallback13(() => {
|
|
5893
6338
|
if (modelsWantedRef.current) return;
|
|
5894
6339
|
modelsWantedRef.current = true;
|
|
5895
6340
|
queueMicrotask(() => setModelsWanted(true));
|
|
5896
6341
|
}, []);
|
|
5897
6342
|
lockedRef.current = catalog.locked !== null;
|
|
5898
|
-
const selectModel =
|
|
6343
|
+
const selectModel = useCallback13((id) => {
|
|
5899
6344
|
if (!lockedRef.current) setPickedModel(id);
|
|
5900
6345
|
}, []);
|
|
5901
|
-
const pinToThread =
|
|
6346
|
+
const pinToThread = useCallback13(
|
|
5902
6347
|
async (model) => {
|
|
5903
6348
|
const threadId = currentThreadId();
|
|
5904
6349
|
setThreadModel(model);
|
|
@@ -5938,14 +6383,14 @@ function useAgentChat(options = {}) {
|
|
|
5938
6383
|
};
|
|
5939
6384
|
const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
|
|
5940
6385
|
const isBusy = status === "submitted" || status === "streaming" || status === "reconnecting";
|
|
5941
|
-
const isBusyRef =
|
|
6386
|
+
const isBusyRef = useRef13(isBusy);
|
|
5942
6387
|
isBusyRef.current = isBusy;
|
|
5943
6388
|
const files = useAttachments({ ...options.composer, backend: client });
|
|
5944
|
-
const [text, setText] =
|
|
6389
|
+
const [text, setText] = useState16("");
|
|
5945
6390
|
const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy && whileRunning === "block" ? "busy" : text.trim().length === 0 && files.refs.length === 0 ? "empty" : null;
|
|
5946
|
-
const composerRef =
|
|
6391
|
+
const composerRef = useRef13({ text, files, blockedBy });
|
|
5947
6392
|
composerRef.current = { text, files, blockedBy };
|
|
5948
|
-
const submit =
|
|
6393
|
+
const submit = useCallback13(
|
|
5949
6394
|
async (options2) => {
|
|
5950
6395
|
const current = composerRef.current;
|
|
5951
6396
|
const asked = canQueueRef.current ? options2?.mode : void 0;
|
|
@@ -6027,6 +6472,7 @@ function useAgentChat(options = {}) {
|
|
|
6027
6472
|
addToolResult,
|
|
6028
6473
|
/** Sub-agents this conversation started and did not wait for. */
|
|
6029
6474
|
background,
|
|
6475
|
+
proposals,
|
|
6030
6476
|
runId,
|
|
6031
6477
|
/** The loaded thread's running turn, or `null` once read with none. */
|
|
6032
6478
|
activeRunId,
|
|
@@ -6059,6 +6505,11 @@ function useAgentChat(options = {}) {
|
|
|
6059
6505
|
queue,
|
|
6060
6506
|
/** The model picker: `list`, `selected`, `select(id)`, `pinToThread(id)`. */
|
|
6061
6507
|
models,
|
|
6508
|
+
/**
|
|
6509
|
+
* The persona pinned on this thread (`ThreadSummary.persona`), or `null` when none is — what a
|
|
6510
|
+
* persona picker on a reopened thread starts from (`?? agent.defaultPersona`).
|
|
6511
|
+
*/
|
|
6512
|
+
threadPersona,
|
|
6062
6513
|
/** The caller's budget (`GET <base>/quota`); `quota.blocked` gates sends. */
|
|
6063
6514
|
quota,
|
|
6064
6515
|
/** The window blocking sends right now (the `blocked` option, else the quota report's). */
|
|
@@ -6145,8 +6596,10 @@ export {
|
|
|
6145
6596
|
onThreadsEvent,
|
|
6146
6597
|
persistSpeechLang,
|
|
6147
6598
|
phraseFor,
|
|
6599
|
+
proposalNeedsPolling,
|
|
6148
6600
|
readPath,
|
|
6149
6601
|
readReasoningMs,
|
|
6602
|
+
reconcileProposalMessages,
|
|
6150
6603
|
reframeAgUiStream,
|
|
6151
6604
|
requireBackendMethod,
|
|
6152
6605
|
resolveResultView,
|
|
@@ -6154,6 +6607,7 @@ export {
|
|
|
6154
6607
|
storedThreadToUiMessages,
|
|
6155
6608
|
toolCallState,
|
|
6156
6609
|
toolCatalogFrom,
|
|
6610
|
+
useActionProposals,
|
|
6157
6611
|
useAgentBackend,
|
|
6158
6612
|
useAgentChat,
|
|
6159
6613
|
useAgentConfig,
|