@dudousxd/nestjs-agent-react 0.32.0 → 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-C7eu9WMJ.d.cts → client-B6EE8-AC.d.cts} +36 -1
- package/dist/{client-C7eu9WMJ.d.ts → client-B6EE8-AC.d.ts} +36 -1
- 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 +557 -123
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -10
- package/dist/index.d.ts +28 -10
- package/dist/index.js +551 -120
- 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) {
|
|
@@ -543,6 +601,10 @@ var AgentChatTransport = class {
|
|
|
543
601
|
return queuedChunkStream(response.queued);
|
|
544
602
|
}
|
|
545
603
|
this.captureHeaderMeta(response);
|
|
604
|
+
if (response.proposalDecision !== void 0) {
|
|
605
|
+
this.attemptLive = false;
|
|
606
|
+
return proposalDecisionChunkStream(response.proposalDecision);
|
|
607
|
+
}
|
|
546
608
|
return this.toChunkStream(response, {
|
|
547
609
|
...headers !== void 0 ? { headers } : {},
|
|
548
610
|
...options.abortSignal ? { signal: options.abortSignal } : {}
|
|
@@ -669,7 +731,7 @@ var AgentChatTransport = class {
|
|
|
669
731
|
let reasoningSeq = 0;
|
|
670
732
|
const announced = /* @__PURE__ */ new Set();
|
|
671
733
|
const toolMetadata = /* @__PURE__ */ new Map();
|
|
672
|
-
const
|
|
734
|
+
const record2 = (meta) => {
|
|
673
735
|
streamRunId = meta.runId;
|
|
674
736
|
this.recordMeta(meta);
|
|
675
737
|
};
|
|
@@ -957,7 +1019,7 @@ var AgentChatTransport = class {
|
|
|
957
1019
|
}
|
|
958
1020
|
if (frame.event === "meta") {
|
|
959
1021
|
const meta = parseMeta(frame.data);
|
|
960
|
-
if (meta)
|
|
1022
|
+
if (meta) record2(meta);
|
|
961
1023
|
} else if (frame.data) {
|
|
962
1024
|
const event = parseEvent(frame.data);
|
|
963
1025
|
if (event) emit(event);
|
|
@@ -1025,10 +1087,10 @@ function parseErrorFrame(data) {
|
|
|
1025
1087
|
try {
|
|
1026
1088
|
const parsed = JSON.parse(data);
|
|
1027
1089
|
if (parsed !== null && typeof parsed === "object") {
|
|
1028
|
-
const
|
|
1090
|
+
const record2 = parsed;
|
|
1029
1091
|
return {
|
|
1030
|
-
code: typeof
|
|
1031
|
-
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
|
|
1032
1094
|
};
|
|
1033
1095
|
}
|
|
1034
1096
|
} catch {
|
|
@@ -1068,6 +1130,21 @@ function delay(ms, signal) {
|
|
|
1068
1130
|
signal?.addEventListener("abort", done, { once: true });
|
|
1069
1131
|
});
|
|
1070
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
|
+
}
|
|
1071
1148
|
|
|
1072
1149
|
// src/attachments/files.ts
|
|
1073
1150
|
function fileKind(mediaType) {
|
|
@@ -1206,6 +1283,10 @@ function toGenerativeUIItem(part) {
|
|
|
1206
1283
|
return {
|
|
1207
1284
|
id,
|
|
1208
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 } : {},
|
|
1209
1290
|
props: isRecord(source.props) ? source.props : {},
|
|
1210
1291
|
version: typeof source.version === "number" ? source.version : null,
|
|
1211
1292
|
toolCallId: typeof source.toolCallId === "string" ? source.toolCallId : null
|
|
@@ -1311,20 +1392,29 @@ function useValidatedProps(catalog, name, props) {
|
|
|
1311
1392
|
function useGenerativeUIState(part, options, fallbackTree) {
|
|
1312
1393
|
const item = useMemo(() => toGenerativeUIItem(part), [part]);
|
|
1313
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);
|
|
1314
1397
|
const resolution = useResolvedComponent(
|
|
1315
1398
|
name,
|
|
1316
1399
|
item?.version ?? null,
|
|
1317
|
-
options.registry,
|
|
1400
|
+
incompatible ? {} : options.registry,
|
|
1318
1401
|
item === null ? void 0 : options.resolveComponent,
|
|
1319
1402
|
fallbackTree
|
|
1320
1403
|
);
|
|
1321
1404
|
const empty = useMemo(() => ({}), []);
|
|
1322
1405
|
const validation = useValidatedProps(
|
|
1323
|
-
item === null || name === GENUI_TREE_COMPONENT ? void 0 : options.catalog,
|
|
1406
|
+
item === null || name === GENUI_TREE_COMPONENT || incompatible ? void 0 : options.catalog,
|
|
1324
1407
|
name,
|
|
1325
1408
|
item?.props ?? empty
|
|
1326
1409
|
);
|
|
1327
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
|
+
};
|
|
1328
1418
|
if (resolution.status === "loading") return { status: "loading", item };
|
|
1329
1419
|
if (resolution.status === "unknown") return { status: "problem", reason: "unknown", item };
|
|
1330
1420
|
if (resolution.status === "error") {
|
|
@@ -1342,7 +1432,8 @@ import { jsx } from "react/jsx-runtime";
|
|
|
1342
1432
|
var TreeScopeContext = createContext2(null);
|
|
1343
1433
|
function renderFallback(fallback2, problem) {
|
|
1344
1434
|
if (typeof fallback2 === "function") return fallback2(problem);
|
|
1345
|
-
|
|
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;
|
|
1346
1437
|
}
|
|
1347
1438
|
var ItemBoundary = class extends Component {
|
|
1348
1439
|
state = { error: void 0, failed: false };
|
|
@@ -1374,28 +1465,42 @@ function nodeItem(node, id) {
|
|
|
1374
1465
|
function TreeNode({ node, id }) {
|
|
1375
1466
|
const scope = useContext2(TreeScopeContext);
|
|
1376
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);
|
|
1377
1471
|
const resolution = useResolvedComponent(
|
|
1378
1472
|
node.type,
|
|
1379
|
-
null,
|
|
1380
|
-
scope?.options.registry ?? {},
|
|
1473
|
+
storedVersion ?? null,
|
|
1474
|
+
incompatible ? {} : scope?.options.registry ?? {},
|
|
1381
1475
|
scope?.options.resolveComponent
|
|
1382
1476
|
);
|
|
1383
|
-
const validation = useValidatedProps(
|
|
1477
|
+
const validation = useValidatedProps(
|
|
1478
|
+
incompatible ? void 0 : scope?.options.catalog,
|
|
1479
|
+
node.type,
|
|
1480
|
+
item.props
|
|
1481
|
+
);
|
|
1384
1482
|
if (scope === null) return null;
|
|
1385
1483
|
if (resolution.status === "loading" || validation.status === "pending") return scope.loading;
|
|
1386
1484
|
if (resolution.status === "unknown") {
|
|
1485
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1486
|
+
throw new Error("Unknown tree component");
|
|
1387
1487
|
return renderFallback(scope.fallback, { reason: "unknown", item });
|
|
1388
1488
|
}
|
|
1389
1489
|
if (resolution.status === "error") {
|
|
1490
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0) throw resolution.error;
|
|
1390
1491
|
return renderFallback(scope.fallback, { reason: "error", item, error: resolution.error });
|
|
1391
1492
|
}
|
|
1392
1493
|
if (validation.status === "invalid") {
|
|
1494
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1495
|
+
throw new Error("Invalid tree component");
|
|
1393
1496
|
return renderFallback(scope.fallback, { reason: "invalid", item, issues: validation.issues });
|
|
1394
1497
|
}
|
|
1395
1498
|
const Renderer = resolution.Component;
|
|
1396
1499
|
const children = Array.isArray(node.children) ? node.children : [];
|
|
1397
1500
|
return /* @__PURE__ */ jsx(Renderer, { ...validation.props, children: children.length > 0 ? children.map((child, index) => {
|
|
1398
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);
|
|
1399
1504
|
return /* @__PURE__ */ jsx(
|
|
1400
1505
|
ItemBoundary,
|
|
1401
1506
|
{
|
|
@@ -1417,6 +1522,8 @@ function GenerativeUIScope({
|
|
|
1417
1522
|
catalog,
|
|
1418
1523
|
resolveComponent,
|
|
1419
1524
|
fallback: fallback2,
|
|
1525
|
+
fallbackText,
|
|
1526
|
+
componentVersions,
|
|
1420
1527
|
loading = null,
|
|
1421
1528
|
onError,
|
|
1422
1529
|
children
|
|
@@ -1429,10 +1536,21 @@ function GenerativeUIScope({
|
|
|
1429
1536
|
...resolveComponent !== void 0 ? { resolveComponent } : {}
|
|
1430
1537
|
},
|
|
1431
1538
|
fallback: fallback2,
|
|
1539
|
+
...componentVersions !== void 0 ? { componentVersions } : {},
|
|
1540
|
+
...fallbackText !== void 0 ? { fallbackText } : {},
|
|
1432
1541
|
loading,
|
|
1433
1542
|
onError
|
|
1434
1543
|
}),
|
|
1435
|
-
[
|
|
1544
|
+
[
|
|
1545
|
+
registry,
|
|
1546
|
+
catalog,
|
|
1547
|
+
resolveComponent,
|
|
1548
|
+
fallback2,
|
|
1549
|
+
fallbackText,
|
|
1550
|
+
componentVersions,
|
|
1551
|
+
loading,
|
|
1552
|
+
onError
|
|
1553
|
+
]
|
|
1436
1554
|
);
|
|
1437
1555
|
return /* @__PURE__ */ jsx(TreeScopeContext.Provider, { value: scope, children });
|
|
1438
1556
|
}
|
|
@@ -1492,7 +1610,7 @@ function GenerativeUI({
|
|
|
1492
1610
|
onError: ownOnError
|
|
1493
1611
|
}) {
|
|
1494
1612
|
const provided = useContext2(GenuiContext);
|
|
1495
|
-
const fallback2 = ownFallback
|
|
1613
|
+
const fallback2 = ownFallback !== void 0 ? ownFallback : provided?.fallback;
|
|
1496
1614
|
const loading = ownLoading ?? provided?.loading ?? null;
|
|
1497
1615
|
const onError = ownOnError ?? provided?.onError;
|
|
1498
1616
|
const options = useMergedOptions({
|
|
@@ -1517,6 +1635,8 @@ function GenerativeUI({
|
|
|
1517
1635
|
GenerativeUIScope,
|
|
1518
1636
|
{
|
|
1519
1637
|
...options,
|
|
1638
|
+
...state.item.componentVersions !== void 0 ? { componentVersions: state.item.componentVersions } : {},
|
|
1639
|
+
...state.item.fallbackText !== void 0 ? { fallbackText: state.item.fallbackText } : {},
|
|
1520
1640
|
fallback: fallback2,
|
|
1521
1641
|
loading,
|
|
1522
1642
|
...onError !== void 0 ? { onError } : {},
|
|
@@ -1532,6 +1652,7 @@ var AgentBackendContext = sharedContext(
|
|
|
1532
1652
|
);
|
|
1533
1653
|
function AgentProvider({
|
|
1534
1654
|
backend,
|
|
1655
|
+
uiCapabilities,
|
|
1535
1656
|
baseUrl,
|
|
1536
1657
|
path,
|
|
1537
1658
|
headers,
|
|
@@ -1563,7 +1684,7 @@ function AgentProvider({
|
|
|
1563
1684
|
[backend, baseUrl, path, credentials, fetch, upload]
|
|
1564
1685
|
);
|
|
1565
1686
|
const content = genui !== void 0 ? /* @__PURE__ */ jsx2(GenuiProvider, { ...genui, children }) : children;
|
|
1566
|
-
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 }) });
|
|
1567
1688
|
}
|
|
1568
1689
|
var fallback;
|
|
1569
1690
|
function defaultBackend() {
|
|
@@ -1574,6 +1695,12 @@ function useAgentBackend(own) {
|
|
|
1574
1695
|
const provided = useContext3(AgentBackendContext);
|
|
1575
1696
|
return own ?? provided ?? defaultBackend();
|
|
1576
1697
|
}
|
|
1698
|
+
var AgentUiCapabilitiesContext = sharedContext(
|
|
1699
|
+
"@dudousxd/nestjs-agent-react:ui-capabilities"
|
|
1700
|
+
);
|
|
1701
|
+
function useAgentUiCapabilities() {
|
|
1702
|
+
return useContext3(AgentUiCapabilitiesContext) ?? void 0;
|
|
1703
|
+
}
|
|
1577
1704
|
|
|
1578
1705
|
// src/config/use-agent-config.ts
|
|
1579
1706
|
var shared = /* @__PURE__ */ new WeakMap();
|
|
@@ -1839,7 +1966,7 @@ async function defaultRefusal(response) {
|
|
|
1839
1966
|
}
|
|
1840
1967
|
function defaultForwardedProps(body) {
|
|
1841
1968
|
const out = {};
|
|
1842
|
-
for (const key of ["pageContext", "agent", "model"]) {
|
|
1969
|
+
for (const key of ["pageContext", "agent", "model", "persona", "uiCapabilities"]) {
|
|
1843
1970
|
if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
|
|
1844
1971
|
}
|
|
1845
1972
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
@@ -2888,6 +3015,15 @@ function isActionCall(part) {
|
|
|
2888
3015
|
}
|
|
2889
3016
|
function toolCallState(part) {
|
|
2890
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
|
+
};
|
|
2891
3027
|
const errorText = "errorText" in part ? part.errorText : void 0;
|
|
2892
3028
|
const outputError = output !== null && typeof output === "object" && "error" in output ? String(output.error) : void 0;
|
|
2893
3029
|
const isDenied = part.state === "output-denied";
|
|
@@ -2932,7 +3068,11 @@ function describeToolCall(part, catalog, options = {}) {
|
|
|
2932
3068
|
icon: presentation?.icon ?? null,
|
|
2933
3069
|
tone: presentation?.tone ?? "neutral",
|
|
2934
3070
|
detail: presentation?.detail ?? null,
|
|
2935
|
-
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 : {
|
|
2936
3076
|
title: fillTemplate(confirm.title, input),
|
|
2937
3077
|
verb: confirm.verb,
|
|
2938
3078
|
detail: confirm.detail !== void 0 ? fillTemplate(confirm.detail, input) : null
|
|
@@ -2946,6 +3086,9 @@ function describeToolCall(part, catalog, options = {}) {
|
|
|
2946
3086
|
}
|
|
2947
3087
|
var STATUS_WEIGHT = {
|
|
2948
3088
|
running: 4,
|
|
3089
|
+
queued: 4,
|
|
3090
|
+
executing: 4,
|
|
3091
|
+
succeeded: 0,
|
|
2949
3092
|
"awaiting-approval": 3,
|
|
2950
3093
|
failed: 2,
|
|
2951
3094
|
denied: 1,
|
|
@@ -2965,7 +3108,7 @@ function groupToolActivity(calls, options = {}) {
|
|
|
2965
3108
|
if (corrected.has(call.toolCallId)) continue;
|
|
2966
3109
|
const presentation = options.catalog?.[call.name];
|
|
2967
3110
|
const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;
|
|
2968
|
-
const status =
|
|
3111
|
+
const status = call.description.status;
|
|
2969
3112
|
const phrase = phraseFor(
|
|
2970
3113
|
presentation,
|
|
2971
3114
|
call.part.input,
|
|
@@ -3207,7 +3350,7 @@ function isAncestor(call, candidate, byId) {
|
|
|
3207
3350
|
}
|
|
3208
3351
|
function buildToolCall(part, options, approval, catalog) {
|
|
3209
3352
|
const toolCallId = part.toolCallId;
|
|
3210
|
-
const awaiting = isAwaitingApproval(part);
|
|
3353
|
+
const awaiting = approval?.target?.kind === "proposal" ? approval.status === "pending" : isAwaitingApproval(part);
|
|
3211
3354
|
const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
|
|
3212
3355
|
return {
|
|
3213
3356
|
part,
|
|
@@ -3217,19 +3360,30 @@ function buildToolCall(part, options, approval, catalog) {
|
|
|
3217
3360
|
parentId: toolParentId(part),
|
|
3218
3361
|
children: [],
|
|
3219
3362
|
approval,
|
|
3220
|
-
description:
|
|
3363
|
+
description: proposalDescription(
|
|
3364
|
+
describeToolCall(
|
|
3365
|
+
part,
|
|
3366
|
+
catalog,
|
|
3367
|
+
approval?.confirmation === void 0 ? {} : { confirmation: approval.confirmation }
|
|
3368
|
+
),
|
|
3369
|
+
approval
|
|
3370
|
+
),
|
|
3221
3371
|
isAwaitingApproval: awaiting,
|
|
3222
3372
|
approve: {
|
|
3223
3373
|
available: awaiting && options?.canApprove === true,
|
|
3224
3374
|
isSubmitting: sending === "approve",
|
|
3225
3375
|
// Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,
|
|
3226
3376
|
// and a host's handler must not receive that as its options.
|
|
3227
|
-
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
|
+
)
|
|
3228
3382
|
},
|
|
3229
3383
|
reject: {
|
|
3230
3384
|
available: awaiting && options?.canReject === true,
|
|
3231
3385
|
isSubmitting: sending === "reject",
|
|
3232
|
-
run: () => options?.reject(toolCallId)
|
|
3386
|
+
run: () => approval?.target === void 0 ? options?.reject(toolCallId) : options?.reject(toolCallId, approval.target)
|
|
3233
3387
|
},
|
|
3234
3388
|
error: options?.errorOf(toolCallId) ?? null,
|
|
3235
3389
|
errorCode: options?.errorCodeOf?.(toolCallId) ?? null
|
|
@@ -3379,7 +3533,7 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
3379
3533
|
var UI_PART = "data-ui";
|
|
3380
3534
|
var APPROVAL_PART = "data-approval-requested";
|
|
3381
3535
|
var SETTLED_PART = "data-approval-settled";
|
|
3382
|
-
var SETTLED_STATUSES = ["approved", "rejected", "expired"];
|
|
3536
|
+
var SETTLED_STATUSES = ["approved", "rejected", "expired", "superseded"];
|
|
3383
3537
|
function readApprovals(parts) {
|
|
3384
3538
|
const out = /* @__PURE__ */ new Map();
|
|
3385
3539
|
const entry = (id) => {
|
|
@@ -3400,7 +3554,7 @@ function readApprovals(parts) {
|
|
|
3400
3554
|
return found;
|
|
3401
3555
|
};
|
|
3402
3556
|
for (const part of parts) {
|
|
3403
|
-
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART) {
|
|
3557
|
+
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART && part.type !== "data-action-proposal") {
|
|
3404
3558
|
continue;
|
|
3405
3559
|
}
|
|
3406
3560
|
const data = part.data;
|
|
@@ -3408,12 +3562,35 @@ function readApprovals(parts) {
|
|
|
3408
3562
|
continue;
|
|
3409
3563
|
}
|
|
3410
3564
|
const approval = entry(data.id);
|
|
3411
|
-
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
|
+
}
|
|
3412
3582
|
if (typeof data.approver !== "string") {
|
|
3413
3583
|
continue;
|
|
3414
3584
|
}
|
|
3415
3585
|
approval.approver = data.approver;
|
|
3416
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
|
+
}
|
|
3417
3594
|
approval.reason = typeof data.reason === "string" ? data.reason : null;
|
|
3418
3595
|
continue;
|
|
3419
3596
|
}
|
|
@@ -3437,9 +3614,12 @@ function approvalOf(parts, call) {
|
|
|
3437
3614
|
}
|
|
3438
3615
|
return {
|
|
3439
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 } : {},
|
|
3440
3620
|
expiresAt: parts.expiresAt,
|
|
3441
3621
|
reason: parts.reason,
|
|
3442
|
-
status: parts.status ?? statusFromPart(call),
|
|
3622
|
+
status: parts.status ?? (parts.target?.kind === "proposal" ? "pending" : statusFromPart(call)),
|
|
3443
3623
|
remember: parts.remember,
|
|
3444
3624
|
decidedBy: parts.decidedBy,
|
|
3445
3625
|
decidedVia: parts.decidedVia,
|
|
@@ -3469,6 +3649,10 @@ function readUiComponent(part) {
|
|
|
3469
3649
|
component: data.component,
|
|
3470
3650
|
props: isRecord4(data.props) ? data.props : {},
|
|
3471
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 } : {},
|
|
3472
3656
|
toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
|
|
3473
3657
|
};
|
|
3474
3658
|
}
|
|
@@ -3579,6 +3763,12 @@ function formatCostUsd(cost) {
|
|
|
3579
3763
|
}
|
|
3580
3764
|
return `$${cost.toFixed(2)}`;
|
|
3581
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
|
+
}
|
|
3582
3772
|
|
|
3583
3773
|
// src/transcript/use-stick-to-bottom.ts
|
|
3584
3774
|
import { useCallback as useCallback8, useEffect as useEffect10, useRef as useRef8, useState as useState10 } from "react";
|
|
@@ -3871,23 +4061,31 @@ function useTranscriptItems({
|
|
|
3871
4061
|
[settle]
|
|
3872
4062
|
);
|
|
3873
4063
|
const approve = useCallback9(
|
|
3874
|
-
(toolCallId, options2) => {
|
|
4064
|
+
(toolCallId, options2, target) => {
|
|
3875
4065
|
const onApprove = latest.current.handlers.onApprove;
|
|
3876
4066
|
if (onApprove) {
|
|
3877
4067
|
settle(
|
|
3878
4068
|
toolCallId,
|
|
3879
4069
|
"approve",
|
|
3880
|
-
() => onApprove({
|
|
4070
|
+
() => onApprove({
|
|
4071
|
+
toolCallId,
|
|
4072
|
+
...target === void 0 ? {} : { target },
|
|
4073
|
+
...options2?.remember === true ? { remember: true } : {}
|
|
4074
|
+
})
|
|
3881
4075
|
);
|
|
3882
4076
|
}
|
|
3883
4077
|
},
|
|
3884
4078
|
[settle]
|
|
3885
4079
|
);
|
|
3886
4080
|
const reject = useCallback9(
|
|
3887
|
-
(toolCallId) => {
|
|
4081
|
+
(toolCallId, target) => {
|
|
3888
4082
|
const onReject = latest.current.handlers.onReject;
|
|
3889
4083
|
if (onReject) {
|
|
3890
|
-
settle(
|
|
4084
|
+
settle(
|
|
4085
|
+
toolCallId,
|
|
4086
|
+
"reject",
|
|
4087
|
+
() => onReject({ toolCallId, ...target === void 0 ? {} : { target } })
|
|
4088
|
+
);
|
|
3891
4089
|
}
|
|
3892
4090
|
},
|
|
3893
4091
|
[settle]
|
|
@@ -4085,14 +4283,36 @@ function settleHandlers(options, backend) {
|
|
|
4085
4283
|
),
|
|
4086
4284
|
onApprove: pick(
|
|
4087
4285
|
options.onApprove,
|
|
4088
|
-
backend.approveToolCall ? async (input) => {
|
|
4089
|
-
|
|
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);
|
|
4090
4299
|
} : void 0
|
|
4091
4300
|
),
|
|
4092
4301
|
onReject: pick(
|
|
4093
4302
|
options.onReject,
|
|
4094
|
-
backend.rejectToolCall ? async (input) => {
|
|
4095
|
-
|
|
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);
|
|
4096
4316
|
} : void 0
|
|
4097
4317
|
)
|
|
4098
4318
|
};
|
|
@@ -4997,6 +5217,8 @@ function storedMessageToUiMessage(message) {
|
|
|
4997
5217
|
id: component.id,
|
|
4998
5218
|
component: component.component,
|
|
4999
5219
|
props: component.props,
|
|
5220
|
+
...component.componentVersions !== void 0 ? { componentVersions: component.componentVersions } : {},
|
|
5221
|
+
...component.fallbackText !== void 0 ? { fallbackText: component.fallbackText } : {},
|
|
5000
5222
|
...component.version !== void 0 ? { version: component.version } : {},
|
|
5001
5223
|
...component.toolCallId !== void 0 ? { toolCallId: component.toolCallId } : {}
|
|
5002
5224
|
}
|
|
@@ -5016,6 +5238,8 @@ function storedMessageToUiMessage(message) {
|
|
|
5016
5238
|
data: {
|
|
5017
5239
|
id: approval.toolCallId,
|
|
5018
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 } : {},
|
|
5019
5243
|
...approval.expiresAt !== void 0 ? { expiresAt: approval.expiresAt } : {}
|
|
5020
5244
|
}
|
|
5021
5245
|
});
|
|
@@ -5072,6 +5296,7 @@ function storedMessageToUiMessage(message) {
|
|
|
5072
5296
|
const metadata = {
|
|
5073
5297
|
// The host's own facts first: the library's keys win on a clash.
|
|
5074
5298
|
...message.metadata,
|
|
5299
|
+
...message.actionProposalOutcome === void 0 ? {} : { actionProposalOutcomeId: message.actionProposalOutcome.id },
|
|
5075
5300
|
...message.feedback !== void 0 ? { feedback: message.feedback } : {},
|
|
5076
5301
|
...message.createdAt ? { createdAt: message.createdAt } : {},
|
|
5077
5302
|
...message.agentName !== void 0 ? { agentName: message.agentName } : {},
|
|
@@ -5107,6 +5332,8 @@ function storedThreadToUiMessages(messages) {
|
|
|
5107
5332
|
return turns.map(mergeTurn);
|
|
5108
5333
|
}
|
|
5109
5334
|
function sameRun(previous, next) {
|
|
5335
|
+
if (previous.actionProposalOutcome !== void 0 || next.actionProposalOutcome !== void 0)
|
|
5336
|
+
return false;
|
|
5110
5337
|
return previous.runId === void 0 || next.runId === void 0 || previous.runId === next.runId;
|
|
5111
5338
|
}
|
|
5112
5339
|
function mergeTurn(rows) {
|
|
@@ -5154,7 +5381,162 @@ function sumUsage(rows) {
|
|
|
5154
5381
|
|
|
5155
5382
|
// src/use-agent-chat.ts
|
|
5156
5383
|
import { useChat } from "@ai-sdk/react";
|
|
5157
|
-
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
|
|
5158
5540
|
var EMPTY_QUEUE = { items: [], paused: null };
|
|
5159
5541
|
var localQueueSequence = 0;
|
|
5160
5542
|
function queuedUserMessage(turn) {
|
|
@@ -5209,13 +5591,16 @@ function localChatId() {
|
|
|
5209
5591
|
return `local-chat-${localChatSequence}`;
|
|
5210
5592
|
}
|
|
5211
5593
|
function useAgentChat(options = {}) {
|
|
5212
|
-
const
|
|
5594
|
+
const providerCapabilities = useAgentUiCapabilities();
|
|
5595
|
+
const capabilitiesRef = useRef13(providerCapabilities);
|
|
5596
|
+
capabilitiesRef.current = providerCapabilities;
|
|
5597
|
+
const latest = useRef13(options);
|
|
5213
5598
|
latest.current = options;
|
|
5214
5599
|
const resolved = useAgentBackend(options.backend);
|
|
5215
|
-
const client =
|
|
5216
|
-
const createdThreadId =
|
|
5217
|
-
const chatIdRef =
|
|
5218
|
-
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);
|
|
5219
5604
|
if (options.threadId !== boundThreadRef.current) {
|
|
5220
5605
|
boundThreadRef.current = options.threadId;
|
|
5221
5606
|
const adopting = options.threadId !== void 0 && options.threadId === createdThreadId.current;
|
|
@@ -5225,39 +5610,41 @@ function useAgentChat(options = {}) {
|
|
|
5225
5610
|
}
|
|
5226
5611
|
}
|
|
5227
5612
|
const chatId = chatIdRef.current;
|
|
5228
|
-
const [runId, setRunId] =
|
|
5229
|
-
const runIdRef =
|
|
5613
|
+
const [runId, setRunId] = useState16(options.resumeRunId);
|
|
5614
|
+
const runIdRef = useRef13(runId);
|
|
5230
5615
|
runIdRef.current = runId;
|
|
5231
|
-
const settlingRunIdRef =
|
|
5232
|
-
const autoResumeRunIdRef =
|
|
5233
|
-
const [activeRunId, setActiveRunId] =
|
|
5234
|
-
const [historyFor, setHistoryFor] =
|
|
5235
|
-
const [historyError, setHistoryError] =
|
|
5236
|
-
const [runError, setRunError] =
|
|
5237
|
-
const [threadModel, setThreadModel] =
|
|
5238
|
-
const [threadPersona, setThreadPersona] =
|
|
5239
|
-
const [pickedModel, setPickedModel] =
|
|
5240
|
-
const pickedModelRef =
|
|
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);
|
|
5241
5626
|
pickedModelRef.current = pickedModel;
|
|
5242
|
-
const lockedRef =
|
|
5243
|
-
const pendingPin =
|
|
5244
|
-
const regenerateNext =
|
|
5245
|
-
const currentThreadId =
|
|
5627
|
+
const lockedRef = useRef13(false);
|
|
5628
|
+
const pendingPin = useRef13(void 0);
|
|
5629
|
+
const regenerateNext = useRef13(false);
|
|
5630
|
+
const currentThreadId = useCallback13(
|
|
5246
5631
|
() => latest.current.threadId ?? createdThreadId.current,
|
|
5247
5632
|
[]
|
|
5248
5633
|
);
|
|
5249
|
-
const [queueState, setQueueState] =
|
|
5250
|
-
const queueStateRef =
|
|
5251
|
-
const applyQueue =
|
|
5634
|
+
const [queueState, setQueueState] = useState16(EMPTY_QUEUE);
|
|
5635
|
+
const queueStateRef = useRef13(queueState);
|
|
5636
|
+
const applyQueue = useCallback13((next) => {
|
|
5252
5637
|
queueStateRef.current = next;
|
|
5253
5638
|
setQueueState(next);
|
|
5254
5639
|
}, []);
|
|
5255
|
-
const [pendingSends, setPendingSends] =
|
|
5256
|
-
const [queueError, setQueueError] =
|
|
5257
|
-
const handoff =
|
|
5258
|
-
const queuedSend =
|
|
5259
|
-
const
|
|
5260
|
-
|
|
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(() => {
|
|
5261
5648
|
const current = latest.current;
|
|
5262
5649
|
if (current.persona !== void 0) setThreadPersona(current.persona);
|
|
5263
5650
|
const pageContext = current.getPageContext?.() ?? null;
|
|
@@ -5270,11 +5657,12 @@ function useAgentChat(options = {}) {
|
|
|
5270
5657
|
...current.persona !== void 0 ? { persona: current.persona } : {},
|
|
5271
5658
|
...threadId !== void 0 ? { threadId } : {},
|
|
5272
5659
|
...model !== void 0 ? { model } : {},
|
|
5273
|
-
...pageContext ? { pageContext } : {}
|
|
5660
|
+
...pageContext ? { pageContext } : {},
|
|
5661
|
+
...(current.uiCapabilities ?? capabilitiesRef.current) === void 0 ? {} : { uiCapabilities: current.uiCapabilities ?? capabilitiesRef.current }
|
|
5274
5662
|
};
|
|
5275
5663
|
}, [currentThreadId]);
|
|
5276
|
-
const [connection, setConnection] =
|
|
5277
|
-
const resyncAfterSettle =
|
|
5664
|
+
const [connection, setConnection] = useState16({ status: "live" });
|
|
5665
|
+
const resyncAfterSettle = useRef13(false);
|
|
5278
5666
|
const transport = useMemo11(() => {
|
|
5279
5667
|
function onMeta(meta) {
|
|
5280
5668
|
settlingRunIdRef.current = meta.runId;
|
|
@@ -5327,7 +5715,7 @@ function useAgentChat(options = {}) {
|
|
|
5327
5715
|
}
|
|
5328
5716
|
});
|
|
5329
5717
|
}, []);
|
|
5330
|
-
const backgroundRef =
|
|
5718
|
+
const backgroundRef = useRef13(() => Promise.resolve());
|
|
5331
5719
|
const chat = useChat({
|
|
5332
5720
|
transport,
|
|
5333
5721
|
id: chatId,
|
|
@@ -5335,6 +5723,7 @@ function useAgentChat(options = {}) {
|
|
|
5335
5723
|
...options.initialMessages !== void 0 ? { messages: options.initialMessages } : {},
|
|
5336
5724
|
onData: (part) => {
|
|
5337
5725
|
latest.current.onData?.(part);
|
|
5726
|
+
if (part.type === "data-proposal-decision") void proposalRefreshRef.current();
|
|
5338
5727
|
if (part.type === "data-queue") {
|
|
5339
5728
|
onQueueData(part.data);
|
|
5340
5729
|
}
|
|
@@ -5381,7 +5770,7 @@ function useAgentChat(options = {}) {
|
|
|
5381
5770
|
}
|
|
5382
5771
|
}
|
|
5383
5772
|
});
|
|
5384
|
-
const chatRef =
|
|
5773
|
+
const chatRef = useRef13(chat);
|
|
5385
5774
|
chatRef.current = chat;
|
|
5386
5775
|
function onQueueData(data) {
|
|
5387
5776
|
const frame = data ?? {};
|
|
@@ -5429,8 +5818,8 @@ function useAgentChat(options = {}) {
|
|
|
5429
5818
|
} catch {
|
|
5430
5819
|
}
|
|
5431
5820
|
}
|
|
5432
|
-
const firstChatId =
|
|
5433
|
-
|
|
5821
|
+
const firstChatId = useRef13(chatId);
|
|
5822
|
+
useEffect16(() => {
|
|
5434
5823
|
if (chatId === firstChatId.current) return;
|
|
5435
5824
|
firstChatId.current = chatId;
|
|
5436
5825
|
setRunId(void 0);
|
|
@@ -5449,7 +5838,7 @@ function useAgentChat(options = {}) {
|
|
|
5449
5838
|
handoff.current = void 0;
|
|
5450
5839
|
queuedSend.current = void 0;
|
|
5451
5840
|
}, [chatId]);
|
|
5452
|
-
|
|
5841
|
+
useEffect16(() => {
|
|
5453
5842
|
const threadId = options.threadId;
|
|
5454
5843
|
if (threadId === void 0) return;
|
|
5455
5844
|
if (threadId === createdThreadId.current) return;
|
|
@@ -5496,8 +5885,8 @@ function useAgentChat(options = {}) {
|
|
|
5496
5885
|
};
|
|
5497
5886
|
}, [client, chatId, options.threadId]);
|
|
5498
5887
|
const isLoadingHistory = options.threadId !== void 0 && options.threadId !== createdThreadId.current && options.history !== false && options.initialMessages === void 0 && historyFor !== options.threadId;
|
|
5499
|
-
const turnInFlight =
|
|
5500
|
-
const isTurnInFlight =
|
|
5888
|
+
const turnInFlight = useRef13(false);
|
|
5889
|
+
const isTurnInFlight = useCallback13(
|
|
5501
5890
|
() => turnInFlight.current || transport.isAttemptLive,
|
|
5502
5891
|
[transport]
|
|
5503
5892
|
);
|
|
@@ -5506,20 +5895,20 @@ function useAgentChat(options = {}) {
|
|
|
5506
5895
|
enabled: options.quota !== false && typeof client.getQuota === "function"
|
|
5507
5896
|
});
|
|
5508
5897
|
const blocked = options.blocked !== void 0 ? options.blocked : quota.blocked;
|
|
5509
|
-
const blockedRef =
|
|
5898
|
+
const blockedRef = useRef13(blocked);
|
|
5510
5899
|
blockedRef.current = blocked;
|
|
5511
5900
|
const whileRunning = typeof client.enqueueMessage === "function" ? options.whileRunning ?? "queue" : "block";
|
|
5512
|
-
const whileRunningRef =
|
|
5901
|
+
const whileRunningRef = useRef13(whileRunning);
|
|
5513
5902
|
whileRunningRef.current = whileRunning;
|
|
5514
|
-
const canQueueRef =
|
|
5903
|
+
const canQueueRef = useRef13(false);
|
|
5515
5904
|
canQueueRef.current = typeof client.enqueueMessage === "function";
|
|
5516
|
-
const threadForQueue =
|
|
5905
|
+
const threadForQueue = useCallback13(async () => {
|
|
5517
5906
|
const known = currentThreadId();
|
|
5518
5907
|
if (known !== void 0) return known;
|
|
5519
5908
|
if (!isTurnInFlight()) throw new Error("queue: this chat has no thread yet");
|
|
5520
5909
|
return new Promise((resolve) => threadWaiters.current.push(resolve));
|
|
5521
5910
|
}, [currentThreadId, isTurnInFlight]);
|
|
5522
|
-
const queueCall =
|
|
5911
|
+
const queueCall = useCallback13(async (run) => {
|
|
5523
5912
|
try {
|
|
5524
5913
|
const result = await run();
|
|
5525
5914
|
setQueueError(null);
|
|
@@ -5529,7 +5918,7 @@ function useAgentChat(options = {}) {
|
|
|
5529
5918
|
throw error;
|
|
5530
5919
|
}
|
|
5531
5920
|
}, []);
|
|
5532
|
-
const enqueue =
|
|
5921
|
+
const enqueue = useCallback13(
|
|
5533
5922
|
async (text2, {
|
|
5534
5923
|
attachments = [],
|
|
5535
5924
|
mode = "queue"
|
|
@@ -5577,7 +5966,7 @@ function useAgentChat(options = {}) {
|
|
|
5577
5966
|
},
|
|
5578
5967
|
[client, queueCall, threadForQueue, turnBody, applyQueue, isTurnInFlight]
|
|
5579
5968
|
);
|
|
5580
|
-
const sendMessage =
|
|
5969
|
+
const sendMessage = useCallback13(
|
|
5581
5970
|
async (message, options2) => {
|
|
5582
5971
|
const block = blockedRef.current;
|
|
5583
5972
|
if (block != null) throw new QuotaBlockedError(block);
|
|
@@ -5601,7 +5990,7 @@ function useAgentChat(options = {}) {
|
|
|
5601
5990
|
},
|
|
5602
5991
|
[isTurnInFlight, enqueue]
|
|
5603
5992
|
);
|
|
5604
|
-
const removeQueued =
|
|
5993
|
+
const removeQueued = useCallback13(
|
|
5605
5994
|
async (id) => {
|
|
5606
5995
|
const previous = queueStateRef.current;
|
|
5607
5996
|
applyQueue({ ...previous, items: previous.items.filter((item) => item.id !== id) });
|
|
@@ -5614,7 +6003,7 @@ function useAgentChat(options = {}) {
|
|
|
5614
6003
|
},
|
|
5615
6004
|
[client, queueCall, applyQueue]
|
|
5616
6005
|
);
|
|
5617
|
-
const interruptQueued =
|
|
6006
|
+
const interruptQueued = useCallback13(
|
|
5618
6007
|
async (id) => {
|
|
5619
6008
|
const previous = queueStateRef.current;
|
|
5620
6009
|
const moving = previous.items.find((item) => item.id === id);
|
|
@@ -5649,7 +6038,7 @@ function useAgentChat(options = {}) {
|
|
|
5649
6038
|
},
|
|
5650
6039
|
[client, queueCall, applyQueue, isTurnInFlight]
|
|
5651
6040
|
);
|
|
5652
|
-
const editQueued =
|
|
6041
|
+
const editQueued = useCallback13(
|
|
5653
6042
|
async (id, text2) => {
|
|
5654
6043
|
applyQueue(
|
|
5655
6044
|
await queueCall(
|
|
@@ -5659,7 +6048,7 @@ function useAgentChat(options = {}) {
|
|
|
5659
6048
|
},
|
|
5660
6049
|
[client, queueCall, applyQueue]
|
|
5661
6050
|
);
|
|
5662
|
-
const moveQueued =
|
|
6051
|
+
const moveQueued = useCallback13(
|
|
5663
6052
|
async (id, index) => {
|
|
5664
6053
|
const previous = queueStateRef.current;
|
|
5665
6054
|
const moving = previous.items.find((item) => item.id === id);
|
|
@@ -5681,12 +6070,12 @@ function useAgentChat(options = {}) {
|
|
|
5681
6070
|
},
|
|
5682
6071
|
[client, queueCall, applyQueue]
|
|
5683
6072
|
);
|
|
5684
|
-
const clearQueue =
|
|
6073
|
+
const clearQueue = useCallback13(async () => {
|
|
5685
6074
|
const threadId = currentThreadId();
|
|
5686
6075
|
if (threadId === void 0) return;
|
|
5687
6076
|
applyQueue(await queueCall(() => requireBackendMethod(client, "clearQueue")(threadId)));
|
|
5688
6077
|
}, [client, queueCall, currentThreadId, applyQueue]);
|
|
5689
|
-
const resumeQueue =
|
|
6078
|
+
const resumeQueue = useCallback13(async () => {
|
|
5690
6079
|
const threadId = currentThreadId();
|
|
5691
6080
|
if (threadId === void 0) return;
|
|
5692
6081
|
const before = queueStateRef.current;
|
|
@@ -5704,7 +6093,7 @@ function useAgentChat(options = {}) {
|
|
|
5704
6093
|
else attachTo(turn);
|
|
5705
6094
|
}
|
|
5706
6095
|
}, [client, queueCall, currentThreadId, applyQueue, isTurnInFlight]);
|
|
5707
|
-
const resumeQueueRef =
|
|
6096
|
+
const resumeQueueRef = useRef13(resumeQueue);
|
|
5708
6097
|
resumeQueueRef.current = resumeQueue;
|
|
5709
6098
|
const queuedItems = [
|
|
5710
6099
|
...pendingSends.filter((item) => item.interrupt),
|
|
@@ -5734,7 +6123,7 @@ function useAgentChat(options = {}) {
|
|
|
5734
6123
|
resume: resumeQueue,
|
|
5735
6124
|
error: queueError
|
|
5736
6125
|
};
|
|
5737
|
-
const addToolResult =
|
|
6126
|
+
const addToolResult = useCallback13(
|
|
5738
6127
|
({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
5739
6128
|
tool,
|
|
5740
6129
|
toolCallId,
|
|
@@ -5742,8 +6131,8 @@ function useAgentChat(options = {}) {
|
|
|
5742
6131
|
}),
|
|
5743
6132
|
[]
|
|
5744
6133
|
);
|
|
5745
|
-
const [backgroundRuns, setBackgroundRuns] =
|
|
5746
|
-
const refreshBackground =
|
|
6134
|
+
const [backgroundRuns, setBackgroundRuns] = useState16([]);
|
|
6135
|
+
const refreshBackground = useCallback13(async () => {
|
|
5747
6136
|
const threadId = currentThreadId();
|
|
5748
6137
|
if (threadId === void 0) {
|
|
5749
6138
|
return;
|
|
@@ -5763,13 +6152,13 @@ function useAgentChat(options = {}) {
|
|
|
5763
6152
|
}, [client, currentThreadId]);
|
|
5764
6153
|
backgroundRef.current = refreshBackground;
|
|
5765
6154
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
5766
|
-
|
|
6155
|
+
useEffect16(() => {
|
|
5767
6156
|
if (options.background !== true || options.threadId === void 0) {
|
|
5768
6157
|
return;
|
|
5769
6158
|
}
|
|
5770
6159
|
void refreshBackground();
|
|
5771
6160
|
}, [options.background, options.threadId, chatId, refreshBackground]);
|
|
5772
|
-
|
|
6161
|
+
useEffect16(() => {
|
|
5773
6162
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
5774
6163
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
5775
6164
|
return;
|
|
@@ -5777,7 +6166,15 @@ function useAgentChat(options = {}) {
|
|
|
5777
6166
|
const timer = setInterval(() => void refreshBackground(), every);
|
|
5778
6167
|
return () => clearInterval(timer);
|
|
5779
6168
|
}, [isWorking, refreshBackground]);
|
|
5780
|
-
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 () => {
|
|
5781
6178
|
chatRef.current.stop();
|
|
5782
6179
|
const active = runIdRef.current;
|
|
5783
6180
|
if (active) {
|
|
@@ -5794,8 +6191,23 @@ function useAgentChat(options = {}) {
|
|
|
5794
6191
|
}
|
|
5795
6192
|
}
|
|
5796
6193
|
}, [client, currentThreadId, applyQueue]);
|
|
5797
|
-
const approve =
|
|
5798
|
-
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
|
+
}
|
|
5799
6211
|
await requireBackendMethod(
|
|
5800
6212
|
client,
|
|
5801
6213
|
"approveToolCall"
|
|
@@ -5805,10 +6217,25 @@ function useAgentChat(options = {}) {
|
|
|
5805
6217
|
...via !== void 0 ? { via } : {}
|
|
5806
6218
|
});
|
|
5807
6219
|
},
|
|
5808
|
-
[client]
|
|
6220
|
+
[client, currentThreadId, proposals.refresh]
|
|
5809
6221
|
);
|
|
5810
|
-
const reject =
|
|
5811
|
-
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
|
+
}
|
|
5812
6239
|
await requireBackendMethod(
|
|
5813
6240
|
client,
|
|
5814
6241
|
"rejectToolCall"
|
|
@@ -5818,9 +6245,9 @@ function useAgentChat(options = {}) {
|
|
|
5818
6245
|
...via !== void 0 ? { via } : {}
|
|
5819
6246
|
});
|
|
5820
6247
|
},
|
|
5821
|
-
[client]
|
|
6248
|
+
[client, currentThreadId, proposals.refresh]
|
|
5822
6249
|
);
|
|
5823
|
-
const answer =
|
|
6250
|
+
const answer = useCallback13(
|
|
5824
6251
|
async ({ toolCallId, answers, via }) => {
|
|
5825
6252
|
await requireBackendMethod(
|
|
5826
6253
|
client,
|
|
@@ -5833,7 +6260,7 @@ function useAgentChat(options = {}) {
|
|
|
5833
6260
|
},
|
|
5834
6261
|
[client]
|
|
5835
6262
|
);
|
|
5836
|
-
const skip =
|
|
6263
|
+
const skip = useCallback13(
|
|
5837
6264
|
async ({ toolCallId, via }) => {
|
|
5838
6265
|
await requireBackendMethod(
|
|
5839
6266
|
client,
|
|
@@ -5842,7 +6269,7 @@ function useAgentChat(options = {}) {
|
|
|
5842
6269
|
},
|
|
5843
6270
|
[client]
|
|
5844
6271
|
);
|
|
5845
|
-
const regenerate =
|
|
6272
|
+
const regenerate = useCallback13(
|
|
5846
6273
|
(_input) => {
|
|
5847
6274
|
const block = blockedRef.current;
|
|
5848
6275
|
if (block != null) throw new QuotaBlockedError(block);
|
|
@@ -5855,7 +6282,7 @@ function useAgentChat(options = {}) {
|
|
|
5855
6282
|
},
|
|
5856
6283
|
[isTurnInFlight]
|
|
5857
6284
|
);
|
|
5858
|
-
const storedIdOf =
|
|
6285
|
+
const storedIdOf = useCallback13(
|
|
5859
6286
|
async (messageId, threadId) => {
|
|
5860
6287
|
const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);
|
|
5861
6288
|
const runOf = message?.metadata?.runId;
|
|
@@ -5866,7 +6293,7 @@ function useAgentChat(options = {}) {
|
|
|
5866
6293
|
},
|
|
5867
6294
|
[client]
|
|
5868
6295
|
);
|
|
5869
|
-
const fork =
|
|
6296
|
+
const fork = useCallback13(
|
|
5870
6297
|
async ({
|
|
5871
6298
|
messageId,
|
|
5872
6299
|
threadId
|
|
@@ -5881,7 +6308,7 @@ function useAgentChat(options = {}) {
|
|
|
5881
6308
|
},
|
|
5882
6309
|
[client, currentThreadId, storedIdOf]
|
|
5883
6310
|
);
|
|
5884
|
-
const truncateFrom =
|
|
6311
|
+
const truncateFrom = useCallback13(
|
|
5885
6312
|
async ({ messageId, threadId }) => {
|
|
5886
6313
|
const target = threadId ?? currentThreadId();
|
|
5887
6314
|
if (target === void 0) throw new Error("truncateFrom: this chat has no thread yet");
|
|
@@ -5890,7 +6317,7 @@ function useAgentChat(options = {}) {
|
|
|
5890
6317
|
},
|
|
5891
6318
|
[client, currentThreadId, storedIdOf]
|
|
5892
6319
|
);
|
|
5893
|
-
const promote =
|
|
6320
|
+
const promote = useCallback13(
|
|
5894
6321
|
async ({ threadId } = {}) => {
|
|
5895
6322
|
const target = threadId ?? currentThreadId();
|
|
5896
6323
|
if (target === void 0) throw new Error("promote: this chat has no thread yet");
|
|
@@ -5899,24 +6326,24 @@ function useAgentChat(options = {}) {
|
|
|
5899
6326
|
},
|
|
5900
6327
|
[client, currentThreadId]
|
|
5901
6328
|
);
|
|
5902
|
-
const [modelsWanted, setModelsWanted] =
|
|
5903
|
-
const modelsWantedRef =
|
|
6329
|
+
const [modelsWanted, setModelsWanted] = useState16(false);
|
|
6330
|
+
const modelsWantedRef = useRef13(modelsWanted);
|
|
5904
6331
|
modelsWantedRef.current = modelsWanted;
|
|
5905
6332
|
const catalog = useModels({
|
|
5906
6333
|
backend: client,
|
|
5907
6334
|
...options.agent !== void 0 ? { agent: options.agent } : {},
|
|
5908
6335
|
enabled: modelsWanted && typeof client.listModels === "function"
|
|
5909
6336
|
});
|
|
5910
|
-
const wantModels =
|
|
6337
|
+
const wantModels = useCallback13(() => {
|
|
5911
6338
|
if (modelsWantedRef.current) return;
|
|
5912
6339
|
modelsWantedRef.current = true;
|
|
5913
6340
|
queueMicrotask(() => setModelsWanted(true));
|
|
5914
6341
|
}, []);
|
|
5915
6342
|
lockedRef.current = catalog.locked !== null;
|
|
5916
|
-
const selectModel =
|
|
6343
|
+
const selectModel = useCallback13((id) => {
|
|
5917
6344
|
if (!lockedRef.current) setPickedModel(id);
|
|
5918
6345
|
}, []);
|
|
5919
|
-
const pinToThread =
|
|
6346
|
+
const pinToThread = useCallback13(
|
|
5920
6347
|
async (model) => {
|
|
5921
6348
|
const threadId = currentThreadId();
|
|
5922
6349
|
setThreadModel(model);
|
|
@@ -5956,14 +6383,14 @@ function useAgentChat(options = {}) {
|
|
|
5956
6383
|
};
|
|
5957
6384
|
const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
|
|
5958
6385
|
const isBusy = status === "submitted" || status === "streaming" || status === "reconnecting";
|
|
5959
|
-
const isBusyRef =
|
|
6386
|
+
const isBusyRef = useRef13(isBusy);
|
|
5960
6387
|
isBusyRef.current = isBusy;
|
|
5961
6388
|
const files = useAttachments({ ...options.composer, backend: client });
|
|
5962
|
-
const [text, setText] =
|
|
6389
|
+
const [text, setText] = useState16("");
|
|
5963
6390
|
const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy && whileRunning === "block" ? "busy" : text.trim().length === 0 && files.refs.length === 0 ? "empty" : null;
|
|
5964
|
-
const composerRef =
|
|
6391
|
+
const composerRef = useRef13({ text, files, blockedBy });
|
|
5965
6392
|
composerRef.current = { text, files, blockedBy };
|
|
5966
|
-
const submit =
|
|
6393
|
+
const submit = useCallback13(
|
|
5967
6394
|
async (options2) => {
|
|
5968
6395
|
const current = composerRef.current;
|
|
5969
6396
|
const asked = canQueueRef.current ? options2?.mode : void 0;
|
|
@@ -6045,6 +6472,7 @@ function useAgentChat(options = {}) {
|
|
|
6045
6472
|
addToolResult,
|
|
6046
6473
|
/** Sub-agents this conversation started and did not wait for. */
|
|
6047
6474
|
background,
|
|
6475
|
+
proposals,
|
|
6048
6476
|
runId,
|
|
6049
6477
|
/** The loaded thread's running turn, or `null` once read with none. */
|
|
6050
6478
|
activeRunId,
|
|
@@ -6168,8 +6596,10 @@ export {
|
|
|
6168
6596
|
onThreadsEvent,
|
|
6169
6597
|
persistSpeechLang,
|
|
6170
6598
|
phraseFor,
|
|
6599
|
+
proposalNeedsPolling,
|
|
6171
6600
|
readPath,
|
|
6172
6601
|
readReasoningMs,
|
|
6602
|
+
reconcileProposalMessages,
|
|
6173
6603
|
reframeAgUiStream,
|
|
6174
6604
|
requireBackendMethod,
|
|
6175
6605
|
resolveResultView,
|
|
@@ -6177,6 +6607,7 @@ export {
|
|
|
6177
6607
|
storedThreadToUiMessages,
|
|
6178
6608
|
toolCallState,
|
|
6179
6609
|
toolCatalogFrom,
|
|
6610
|
+
useActionProposals,
|
|
6180
6611
|
useAgentBackend,
|
|
6181
6612
|
useAgentChat,
|
|
6182
6613
|
useAgentConfig,
|