@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.cjs
CHANGED
|
@@ -78,8 +78,10 @@ __export(src_exports, {
|
|
|
78
78
|
onThreadsEvent: () => onThreadsEvent,
|
|
79
79
|
persistSpeechLang: () => persistSpeechLang,
|
|
80
80
|
phraseFor: () => phraseFor,
|
|
81
|
+
proposalNeedsPolling: () => proposalNeedsPolling,
|
|
81
82
|
readPath: () => readPath,
|
|
82
83
|
readReasoningMs: () => readReasoningMs,
|
|
84
|
+
reconcileProposalMessages: () => reconcileProposalMessages,
|
|
83
85
|
reframeAgUiStream: () => reframeAgUiStream,
|
|
84
86
|
requireBackendMethod: () => requireBackendMethod,
|
|
85
87
|
resolveResultView: () => resolveResultView,
|
|
@@ -87,6 +89,7 @@ __export(src_exports, {
|
|
|
87
89
|
storedThreadToUiMessages: () => storedThreadToUiMessages,
|
|
88
90
|
toolCallState: () => toolCallState,
|
|
89
91
|
toolCatalogFrom: () => toolCatalogFrom,
|
|
92
|
+
useActionProposals: () => useActionProposals,
|
|
90
93
|
useAgentBackend: () => useAgentBackend,
|
|
91
94
|
useAgentChat: () => useAgentChat,
|
|
92
95
|
useAgentConfig: () => useAgentConfig,
|
|
@@ -121,9 +124,9 @@ function readErrorAnswer(text) {
|
|
|
121
124
|
}
|
|
122
125
|
if (body === null || typeof body !== "object")
|
|
123
126
|
return { body, message: void 0, code: void 0 };
|
|
124
|
-
const
|
|
125
|
-
const message = typeof
|
|
126
|
-
const code = typeof
|
|
127
|
+
const record2 = body;
|
|
128
|
+
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;
|
|
129
|
+
const code = typeof record2.code === "string" && record2.code !== "" ? record2.code : void 0;
|
|
127
130
|
return { body, message, code };
|
|
128
131
|
}
|
|
129
132
|
async function readErrorResponse(response) {
|
|
@@ -200,6 +203,12 @@ var AgentClient = class {
|
|
|
200
203
|
if (response.status === 202) {
|
|
201
204
|
return { body: emptyStream(), queued: await response.json() };
|
|
202
205
|
}
|
|
206
|
+
if (response.ok && response.headers.get("content-type")?.includes("application/json")) {
|
|
207
|
+
const decision = await response.json();
|
|
208
|
+
if (decision.proposalDecision !== void 0 && typeof decision.threadId === "string")
|
|
209
|
+
return { body: emptyStream(), threadId: decision.threadId, proposalDecision: decision };
|
|
210
|
+
throw new Error("Unexpected JSON chat response");
|
|
211
|
+
}
|
|
203
212
|
if (!response.ok || !response.body) {
|
|
204
213
|
throw await this.failure(response, "POST", `${this.agentPath()}/chat`);
|
|
205
214
|
}
|
|
@@ -432,6 +441,54 @@ var AgentClient = class {
|
|
|
432
441
|
* `remember` approves later calls of the same tool in the same thread; `via` names the surface
|
|
433
442
|
* the decision came through (the server records `'web'` when omitted).
|
|
434
443
|
*/
|
|
444
|
+
async listActionProposals({ threadId }) {
|
|
445
|
+
const proposals = /* @__PURE__ */ new Map();
|
|
446
|
+
let after;
|
|
447
|
+
for (; ; ) {
|
|
448
|
+
const route = `/threads/${encodeURIComponent(threadId)}/action-proposals${after === void 0 ? "" : `?after=${encodeURIComponent(JSON.stringify(after))}`}`;
|
|
449
|
+
const response = await this.requestResponse("GET", route);
|
|
450
|
+
const page = await this.handleResponse(
|
|
451
|
+
response,
|
|
452
|
+
"GET",
|
|
453
|
+
`${this.agentPath()}${route}`
|
|
454
|
+
);
|
|
455
|
+
if (!Array.isArray(page)) throw new TypeError("Invalid action proposal page");
|
|
456
|
+
for (const proposal of page) proposals.set(proposal.id, proposal);
|
|
457
|
+
const header = response.headers.get("X-Action-Proposals-Next");
|
|
458
|
+
if (header === null) return [...proposals.values()];
|
|
459
|
+
let next;
|
|
460
|
+
try {
|
|
461
|
+
next = JSON.parse(decodeURIComponent(header));
|
|
462
|
+
} catch {
|
|
463
|
+
throw new TypeError("Invalid action proposal cursor");
|
|
464
|
+
}
|
|
465
|
+
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))
|
|
466
|
+
throw new TypeError("Invalid or non-advancing action proposal cursor");
|
|
467
|
+
after = { createdAt: next.createdAt, id: next.id };
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
approveActionProposal({
|
|
471
|
+
threadId,
|
|
472
|
+
proposalId,
|
|
473
|
+
remember
|
|
474
|
+
}) {
|
|
475
|
+
return this.request(
|
|
476
|
+
"POST",
|
|
477
|
+
`/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/approve`,
|
|
478
|
+
remember === void 0 ? {} : { remember }
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
rejectActionProposal({
|
|
482
|
+
threadId,
|
|
483
|
+
proposalId,
|
|
484
|
+
reason
|
|
485
|
+
}) {
|
|
486
|
+
return this.request(
|
|
487
|
+
"POST",
|
|
488
|
+
`/threads/${encodeURIComponent(threadId)}/action-proposals/${encodeURIComponent(proposalId)}/reject`,
|
|
489
|
+
reason === void 0 ? {} : { reason }
|
|
490
|
+
);
|
|
491
|
+
}
|
|
435
492
|
approveToolCall(input) {
|
|
436
493
|
return this.request("POST", "/tool-call/approve", input);
|
|
437
494
|
}
|
|
@@ -488,6 +545,10 @@ var AgentClient = class {
|
|
|
488
545
|
return this.options.credentials !== void 0 ? { credentials: this.options.credentials } : {};
|
|
489
546
|
}
|
|
490
547
|
async request(method, route, body) {
|
|
548
|
+
const response = await this.requestResponse(method, route, body);
|
|
549
|
+
return this.handleResponse(response, method, `${this.agentPath()}${route}`);
|
|
550
|
+
}
|
|
551
|
+
async requestResponse(method, route, body) {
|
|
491
552
|
const path = `${this.agentPath()}${route}`;
|
|
492
553
|
const response = await this.fetchImpl()(`${this.baseUrl()}${path}`, {
|
|
493
554
|
method,
|
|
@@ -499,7 +560,7 @@ var AgentClient = class {
|
|
|
499
560
|
...body !== void 0 ? { body: JSON.stringify(body) } : {},
|
|
500
561
|
...this.credentials()
|
|
501
562
|
});
|
|
502
|
-
return
|
|
563
|
+
return response;
|
|
503
564
|
}
|
|
504
565
|
/** The error for a refused `response`, already reported to `onHttpError`. */
|
|
505
566
|
async failure(response, method, path) {
|
|
@@ -655,6 +716,10 @@ var AgentChatTransport = class {
|
|
|
655
716
|
return queuedChunkStream(response.queued);
|
|
656
717
|
}
|
|
657
718
|
this.captureHeaderMeta(response);
|
|
719
|
+
if (response.proposalDecision !== void 0) {
|
|
720
|
+
this.attemptLive = false;
|
|
721
|
+
return proposalDecisionChunkStream(response.proposalDecision);
|
|
722
|
+
}
|
|
658
723
|
return this.toChunkStream(response, {
|
|
659
724
|
...headers !== void 0 ? { headers } : {},
|
|
660
725
|
...options.abortSignal ? { signal: options.abortSignal } : {}
|
|
@@ -781,7 +846,7 @@ var AgentChatTransport = class {
|
|
|
781
846
|
let reasoningSeq = 0;
|
|
782
847
|
const announced = /* @__PURE__ */ new Set();
|
|
783
848
|
const toolMetadata = /* @__PURE__ */ new Map();
|
|
784
|
-
const
|
|
849
|
+
const record2 = (meta) => {
|
|
785
850
|
streamRunId = meta.runId;
|
|
786
851
|
this.recordMeta(meta);
|
|
787
852
|
};
|
|
@@ -1069,7 +1134,7 @@ var AgentChatTransport = class {
|
|
|
1069
1134
|
}
|
|
1070
1135
|
if (frame.event === "meta") {
|
|
1071
1136
|
const meta = parseMeta(frame.data);
|
|
1072
|
-
if (meta)
|
|
1137
|
+
if (meta) record2(meta);
|
|
1073
1138
|
} else if (frame.data) {
|
|
1074
1139
|
const event = parseEvent(frame.data);
|
|
1075
1140
|
if (event) emit(event);
|
|
@@ -1137,10 +1202,10 @@ function parseErrorFrame(data) {
|
|
|
1137
1202
|
try {
|
|
1138
1203
|
const parsed = JSON.parse(data);
|
|
1139
1204
|
if (parsed !== null && typeof parsed === "object") {
|
|
1140
|
-
const
|
|
1205
|
+
const record2 = parsed;
|
|
1141
1206
|
return {
|
|
1142
|
-
code: typeof
|
|
1143
|
-
message: typeof
|
|
1207
|
+
code: typeof record2.code === "string" && record2.code !== "" ? record2.code : void 0,
|
|
1208
|
+
message: typeof record2.message === "string" && record2.message !== "" ? record2.message : fallback2.message
|
|
1144
1209
|
};
|
|
1145
1210
|
}
|
|
1146
1211
|
} catch {
|
|
@@ -1180,6 +1245,21 @@ function delay(ms, signal) {
|
|
|
1180
1245
|
signal?.addEventListener("abort", done, { once: true });
|
|
1181
1246
|
});
|
|
1182
1247
|
}
|
|
1248
|
+
function proposalDecisionChunkStream(decision) {
|
|
1249
|
+
return new ReadableStream({
|
|
1250
|
+
start(controller) {
|
|
1251
|
+
controller.enqueue({ type: "start", messageId: `decision:${crypto.randomUUID()}` });
|
|
1252
|
+
controller.enqueue({ type: "data-proposal-decision", data: decision, transient: true });
|
|
1253
|
+
if (decision.text !== void 0 && decision.text.length > 0) {
|
|
1254
|
+
controller.enqueue({ type: "text-start", id: "decision" });
|
|
1255
|
+
controller.enqueue({ type: "text-delta", id: "decision", delta: decision.text });
|
|
1256
|
+
controller.enqueue({ type: "text-end", id: "decision" });
|
|
1257
|
+
}
|
|
1258
|
+
controller.enqueue({ type: "finish", finishReason: "stop" });
|
|
1259
|
+
controller.close();
|
|
1260
|
+
}
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1183
1263
|
|
|
1184
1264
|
// src/attachments/files.ts
|
|
1185
1265
|
function fileKind(mediaType) {
|
|
@@ -1312,6 +1392,10 @@ function toGenerativeUIItem(part) {
|
|
|
1312
1392
|
return {
|
|
1313
1393
|
id,
|
|
1314
1394
|
component: source.component,
|
|
1395
|
+
...isRecord(source.componentVersions) && Object.values(source.componentVersions).every(
|
|
1396
|
+
(version) => typeof version === "number" && Number.isSafeInteger(version) && version > 0
|
|
1397
|
+
) ? { componentVersions: { ...source.componentVersions } } : {},
|
|
1398
|
+
...typeof source.fallbackText === "string" ? { fallbackText: source.fallbackText } : {},
|
|
1315
1399
|
props: isRecord(source.props) ? source.props : {},
|
|
1316
1400
|
version: typeof source.version === "number" ? source.version : null,
|
|
1317
1401
|
toolCallId: typeof source.toolCallId === "string" ? source.toolCallId : null
|
|
@@ -1417,20 +1501,29 @@ function useValidatedProps(catalog, name, props) {
|
|
|
1417
1501
|
function useGenerativeUIState(part, options, fallbackTree) {
|
|
1418
1502
|
const item = (0, import_react3.useMemo)(() => toGenerativeUIItem(part), [part]);
|
|
1419
1503
|
const name = item?.component ?? "";
|
|
1504
|
+
const definition = options.catalog?.get?.(name);
|
|
1505
|
+
const incompatible = item?.fallbackText !== void 0 && item.version !== null && definition !== void 0 && item.version !== (definition.version ?? 1);
|
|
1420
1506
|
const resolution = useResolvedComponent(
|
|
1421
1507
|
name,
|
|
1422
1508
|
item?.version ?? null,
|
|
1423
|
-
options.registry,
|
|
1509
|
+
incompatible ? {} : options.registry,
|
|
1424
1510
|
item === null ? void 0 : options.resolveComponent,
|
|
1425
1511
|
fallbackTree
|
|
1426
1512
|
);
|
|
1427
1513
|
const empty = (0, import_react3.useMemo)(() => ({}), []);
|
|
1428
1514
|
const validation = useValidatedProps(
|
|
1429
|
-
item === null || name === GENUI_TREE_COMPONENT ? void 0 : options.catalog,
|
|
1515
|
+
item === null || name === GENUI_TREE_COMPONENT || incompatible ? void 0 : options.catalog,
|
|
1430
1516
|
name,
|
|
1431
1517
|
item?.props ?? empty
|
|
1432
1518
|
);
|
|
1433
1519
|
if (item === null) return null;
|
|
1520
|
+
if (name === GENUI_TREE_COMPONENT && item.fallbackText !== void 0 && (!isRecord(item.props.root) || typeof item.props.root.type !== "string"))
|
|
1521
|
+
return {
|
|
1522
|
+
status: "problem",
|
|
1523
|
+
reason: "invalid",
|
|
1524
|
+
item,
|
|
1525
|
+
issues: [{ path: ["root"], message: "Invalid UI tree root" }]
|
|
1526
|
+
};
|
|
1434
1527
|
if (resolution.status === "loading") return { status: "loading", item };
|
|
1435
1528
|
if (resolution.status === "unknown") return { status: "problem", reason: "unknown", item };
|
|
1436
1529
|
if (resolution.status === "error") {
|
|
@@ -1448,7 +1541,8 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
1448
1541
|
var TreeScopeContext = (0, import_react4.createContext)(null);
|
|
1449
1542
|
function renderFallback(fallback2, problem) {
|
|
1450
1543
|
if (typeof fallback2 === "function") return fallback2(problem);
|
|
1451
|
-
|
|
1544
|
+
if (fallback2 !== void 0) return fallback2;
|
|
1545
|
+
return problem.item.fallbackText !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { whiteSpace: "pre-wrap" }, children: problem.item.fallbackText }) : null;
|
|
1452
1546
|
}
|
|
1453
1547
|
var ItemBoundary = class extends import_react4.Component {
|
|
1454
1548
|
state = { error: void 0, failed: false };
|
|
@@ -1480,28 +1574,42 @@ function nodeItem(node, id) {
|
|
|
1480
1574
|
function TreeNode({ node, id }) {
|
|
1481
1575
|
const scope = (0, import_react4.useContext)(TreeScopeContext);
|
|
1482
1576
|
const item = (0, import_react4.useMemo)(() => nodeItem(node, id), [node, id]);
|
|
1577
|
+
const storedVersion = scope?.componentVersions?.[node.type];
|
|
1578
|
+
const definition = scope?.options.catalog?.get?.(node.type);
|
|
1579
|
+
const incompatible = storedVersion !== void 0 && definition !== void 0 && storedVersion !== (definition.version ?? 1);
|
|
1483
1580
|
const resolution = useResolvedComponent(
|
|
1484
1581
|
node.type,
|
|
1485
|
-
null,
|
|
1486
|
-
scope?.options.registry ?? {},
|
|
1582
|
+
storedVersion ?? null,
|
|
1583
|
+
incompatible ? {} : scope?.options.registry ?? {},
|
|
1487
1584
|
scope?.options.resolveComponent
|
|
1488
1585
|
);
|
|
1489
|
-
const validation = useValidatedProps(
|
|
1586
|
+
const validation = useValidatedProps(
|
|
1587
|
+
incompatible ? void 0 : scope?.options.catalog,
|
|
1588
|
+
node.type,
|
|
1589
|
+
item.props
|
|
1590
|
+
);
|
|
1490
1591
|
if (scope === null) return null;
|
|
1491
1592
|
if (resolution.status === "loading" || validation.status === "pending") return scope.loading;
|
|
1492
1593
|
if (resolution.status === "unknown") {
|
|
1594
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1595
|
+
throw new Error("Unknown tree component");
|
|
1493
1596
|
return renderFallback(scope.fallback, { reason: "unknown", item });
|
|
1494
1597
|
}
|
|
1495
1598
|
if (resolution.status === "error") {
|
|
1599
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0) throw resolution.error;
|
|
1496
1600
|
return renderFallback(scope.fallback, { reason: "error", item, error: resolution.error });
|
|
1497
1601
|
}
|
|
1498
1602
|
if (validation.status === "invalid") {
|
|
1603
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1604
|
+
throw new Error("Invalid tree component");
|
|
1499
1605
|
return renderFallback(scope.fallback, { reason: "invalid", item, issues: validation.issues });
|
|
1500
1606
|
}
|
|
1501
1607
|
const Renderer = resolution.Component;
|
|
1502
1608
|
const children = Array.isArray(node.children) ? node.children : [];
|
|
1503
1609
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Renderer, { ...validation.props, children: children.length > 0 ? children.map((child, index) => {
|
|
1504
1610
|
const childId = `${id}.${index}`;
|
|
1611
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeNode, { node: child, id: childId }, childId);
|
|
1505
1613
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1506
1614
|
ItemBoundary,
|
|
1507
1615
|
{
|
|
@@ -1523,6 +1631,8 @@ function GenerativeUIScope({
|
|
|
1523
1631
|
catalog,
|
|
1524
1632
|
resolveComponent,
|
|
1525
1633
|
fallback: fallback2,
|
|
1634
|
+
fallbackText,
|
|
1635
|
+
componentVersions,
|
|
1526
1636
|
loading = null,
|
|
1527
1637
|
onError,
|
|
1528
1638
|
children
|
|
@@ -1535,10 +1645,21 @@ function GenerativeUIScope({
|
|
|
1535
1645
|
...resolveComponent !== void 0 ? { resolveComponent } : {}
|
|
1536
1646
|
},
|
|
1537
1647
|
fallback: fallback2,
|
|
1648
|
+
...componentVersions !== void 0 ? { componentVersions } : {},
|
|
1649
|
+
...fallbackText !== void 0 ? { fallbackText } : {},
|
|
1538
1650
|
loading,
|
|
1539
1651
|
onError
|
|
1540
1652
|
}),
|
|
1541
|
-
[
|
|
1653
|
+
[
|
|
1654
|
+
registry,
|
|
1655
|
+
catalog,
|
|
1656
|
+
resolveComponent,
|
|
1657
|
+
fallback2,
|
|
1658
|
+
fallbackText,
|
|
1659
|
+
componentVersions,
|
|
1660
|
+
loading,
|
|
1661
|
+
onError
|
|
1662
|
+
]
|
|
1542
1663
|
);
|
|
1543
1664
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeScopeContext.Provider, { value: scope, children });
|
|
1544
1665
|
}
|
|
@@ -1598,7 +1719,7 @@ function GenerativeUI({
|
|
|
1598
1719
|
onError: ownOnError
|
|
1599
1720
|
}) {
|
|
1600
1721
|
const provided = (0, import_react4.useContext)(GenuiContext);
|
|
1601
|
-
const fallback2 = ownFallback
|
|
1722
|
+
const fallback2 = ownFallback !== void 0 ? ownFallback : provided?.fallback;
|
|
1602
1723
|
const loading = ownLoading ?? provided?.loading ?? null;
|
|
1603
1724
|
const onError = ownOnError ?? provided?.onError;
|
|
1604
1725
|
const options = useMergedOptions({
|
|
@@ -1623,6 +1744,8 @@ function GenerativeUI({
|
|
|
1623
1744
|
GenerativeUIScope,
|
|
1624
1745
|
{
|
|
1625
1746
|
...options,
|
|
1747
|
+
...state.item.componentVersions !== void 0 ? { componentVersions: state.item.componentVersions } : {},
|
|
1748
|
+
...state.item.fallbackText !== void 0 ? { fallbackText: state.item.fallbackText } : {},
|
|
1626
1749
|
fallback: fallback2,
|
|
1627
1750
|
loading,
|
|
1628
1751
|
...onError !== void 0 ? { onError } : {},
|
|
@@ -1638,6 +1761,7 @@ var AgentBackendContext = sharedContext(
|
|
|
1638
1761
|
);
|
|
1639
1762
|
function AgentProvider({
|
|
1640
1763
|
backend,
|
|
1764
|
+
uiCapabilities,
|
|
1641
1765
|
baseUrl,
|
|
1642
1766
|
path,
|
|
1643
1767
|
headers,
|
|
@@ -1669,7 +1793,7 @@ function AgentProvider({
|
|
|
1669
1793
|
[backend, baseUrl, path, credentials, fetch, upload]
|
|
1670
1794
|
);
|
|
1671
1795
|
const content = genui !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GenuiProvider, { ...genui, children }) : children;
|
|
1672
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AgentBackendContext.Provider, { value, children: content });
|
|
1796
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AgentUiCapabilitiesContext.Provider, { value: uiCapabilities ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AgentBackendContext.Provider, { value, children: content }) });
|
|
1673
1797
|
}
|
|
1674
1798
|
var fallback;
|
|
1675
1799
|
function defaultBackend() {
|
|
@@ -1680,6 +1804,12 @@ function useAgentBackend(own) {
|
|
|
1680
1804
|
const provided = (0, import_react5.useContext)(AgentBackendContext);
|
|
1681
1805
|
return own ?? provided ?? defaultBackend();
|
|
1682
1806
|
}
|
|
1807
|
+
var AgentUiCapabilitiesContext = sharedContext(
|
|
1808
|
+
"@dudousxd/nestjs-agent-react:ui-capabilities"
|
|
1809
|
+
);
|
|
1810
|
+
function useAgentUiCapabilities() {
|
|
1811
|
+
return (0, import_react5.useContext)(AgentUiCapabilitiesContext) ?? void 0;
|
|
1812
|
+
}
|
|
1683
1813
|
|
|
1684
1814
|
// src/config/use-agent-config.ts
|
|
1685
1815
|
var shared = /* @__PURE__ */ new WeakMap();
|
|
@@ -1945,7 +2075,7 @@ async function defaultRefusal(response) {
|
|
|
1945
2075
|
}
|
|
1946
2076
|
function defaultForwardedProps(body) {
|
|
1947
2077
|
const out = {};
|
|
1948
|
-
for (const key of ["pageContext", "agent", "model"]) {
|
|
2078
|
+
for (const key of ["pageContext", "agent", "model", "persona", "uiCapabilities"]) {
|
|
1949
2079
|
if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
|
|
1950
2080
|
}
|
|
1951
2081
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
@@ -2979,6 +3109,15 @@ function isActionCall(part) {
|
|
|
2979
3109
|
}
|
|
2980
3110
|
function toolCallState(part) {
|
|
2981
3111
|
const output = "output" in part ? part.output : void 0;
|
|
3112
|
+
if (output !== null && typeof output === "object" && "proposalId" in output && "executed" in output && output.executed === false)
|
|
3113
|
+
return {
|
|
3114
|
+
status: "awaiting-approval",
|
|
3115
|
+
isSettled: false,
|
|
3116
|
+
isFailed: false,
|
|
3117
|
+
isDenied: false,
|
|
3118
|
+
output,
|
|
3119
|
+
error: null
|
|
3120
|
+
};
|
|
2982
3121
|
const errorText = "errorText" in part ? part.errorText : void 0;
|
|
2983
3122
|
const outputError = output !== null && typeof output === "object" && "error" in output ? String(output.error) : void 0;
|
|
2984
3123
|
const isDenied = part.state === "output-denied";
|
|
@@ -3023,7 +3162,11 @@ function describeToolCall(part, catalog, options = {}) {
|
|
|
3023
3162
|
icon: presentation?.icon ?? null,
|
|
3024
3163
|
tone: presentation?.tone ?? "neutral",
|
|
3025
3164
|
detail: presentation?.detail ?? null,
|
|
3026
|
-
confirm:
|
|
3165
|
+
confirm: options.confirmation !== void 0 ? {
|
|
3166
|
+
title: options.confirmation.title,
|
|
3167
|
+
verb: options.confirmation.verb,
|
|
3168
|
+
detail: options.confirmation.detail ?? null
|
|
3169
|
+
} : confirm === void 0 ? null : {
|
|
3027
3170
|
title: fillTemplate(confirm.title, input),
|
|
3028
3171
|
verb: confirm.verb,
|
|
3029
3172
|
detail: confirm.detail !== void 0 ? fillTemplate(confirm.detail, input) : null
|
|
@@ -3037,6 +3180,9 @@ function describeToolCall(part, catalog, options = {}) {
|
|
|
3037
3180
|
}
|
|
3038
3181
|
var STATUS_WEIGHT = {
|
|
3039
3182
|
running: 4,
|
|
3183
|
+
queued: 4,
|
|
3184
|
+
executing: 4,
|
|
3185
|
+
succeeded: 0,
|
|
3040
3186
|
"awaiting-approval": 3,
|
|
3041
3187
|
failed: 2,
|
|
3042
3188
|
denied: 1,
|
|
@@ -3056,7 +3202,7 @@ function groupToolActivity(calls, options = {}) {
|
|
|
3056
3202
|
if (corrected.has(call.toolCallId)) continue;
|
|
3057
3203
|
const presentation = options.catalog?.[call.name];
|
|
3058
3204
|
const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;
|
|
3059
|
-
const status =
|
|
3205
|
+
const status = call.description.status;
|
|
3060
3206
|
const phrase = phraseFor(
|
|
3061
3207
|
presentation,
|
|
3062
3208
|
call.part.input,
|
|
@@ -3298,7 +3444,7 @@ function isAncestor(call, candidate, byId) {
|
|
|
3298
3444
|
}
|
|
3299
3445
|
function buildToolCall(part, options, approval, catalog) {
|
|
3300
3446
|
const toolCallId = part.toolCallId;
|
|
3301
|
-
const awaiting = isAwaitingApproval(part);
|
|
3447
|
+
const awaiting = approval?.target?.kind === "proposal" ? approval.status === "pending" : isAwaitingApproval(part);
|
|
3302
3448
|
const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
|
|
3303
3449
|
return {
|
|
3304
3450
|
part,
|
|
@@ -3308,19 +3454,30 @@ function buildToolCall(part, options, approval, catalog) {
|
|
|
3308
3454
|
parentId: toolParentId(part),
|
|
3309
3455
|
children: [],
|
|
3310
3456
|
approval,
|
|
3311
|
-
description:
|
|
3457
|
+
description: proposalDescription(
|
|
3458
|
+
describeToolCall(
|
|
3459
|
+
part,
|
|
3460
|
+
catalog,
|
|
3461
|
+
approval?.confirmation === void 0 ? {} : { confirmation: approval.confirmation }
|
|
3462
|
+
),
|
|
3463
|
+
approval
|
|
3464
|
+
),
|
|
3312
3465
|
isAwaitingApproval: awaiting,
|
|
3313
3466
|
approve: {
|
|
3314
3467
|
available: awaiting && options?.canApprove === true,
|
|
3315
3468
|
isSubmitting: sending === "approve",
|
|
3316
3469
|
// Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,
|
|
3317
3470
|
// and a host's handler must not receive that as its options.
|
|
3318
|
-
run: (approveOptions) => approveOptions?.remember === true ? options?.approve(toolCallId, { remember: true }) : options?.approve(toolCallId)
|
|
3471
|
+
run: (approveOptions) => approval?.target === void 0 ? approveOptions?.remember === true ? options?.approve(toolCallId, { remember: true }) : options?.approve(toolCallId) : options?.approve(
|
|
3472
|
+
toolCallId,
|
|
3473
|
+
approveOptions?.remember === true ? { remember: true } : void 0,
|
|
3474
|
+
approval.target
|
|
3475
|
+
)
|
|
3319
3476
|
},
|
|
3320
3477
|
reject: {
|
|
3321
3478
|
available: awaiting && options?.canReject === true,
|
|
3322
3479
|
isSubmitting: sending === "reject",
|
|
3323
|
-
run: () => options?.reject(toolCallId)
|
|
3480
|
+
run: () => approval?.target === void 0 ? options?.reject(toolCallId) : options?.reject(toolCallId, approval.target)
|
|
3324
3481
|
},
|
|
3325
3482
|
error: options?.errorOf(toolCallId) ?? null,
|
|
3326
3483
|
errorCode: options?.errorCodeOf?.(toolCallId) ?? null
|
|
@@ -3470,7 +3627,7 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
3470
3627
|
var UI_PART = "data-ui";
|
|
3471
3628
|
var APPROVAL_PART = "data-approval-requested";
|
|
3472
3629
|
var SETTLED_PART = "data-approval-settled";
|
|
3473
|
-
var SETTLED_STATUSES = ["approved", "rejected", "expired"];
|
|
3630
|
+
var SETTLED_STATUSES = ["approved", "rejected", "expired", "superseded"];
|
|
3474
3631
|
function readApprovals(parts) {
|
|
3475
3632
|
const out = /* @__PURE__ */ new Map();
|
|
3476
3633
|
const entry = (id) => {
|
|
@@ -3491,7 +3648,7 @@ function readApprovals(parts) {
|
|
|
3491
3648
|
return found;
|
|
3492
3649
|
};
|
|
3493
3650
|
for (const part of parts) {
|
|
3494
|
-
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART) {
|
|
3651
|
+
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART && part.type !== "data-action-proposal") {
|
|
3495
3652
|
continue;
|
|
3496
3653
|
}
|
|
3497
3654
|
const data = part.data;
|
|
@@ -3499,12 +3656,35 @@ function readApprovals(parts) {
|
|
|
3499
3656
|
continue;
|
|
3500
3657
|
}
|
|
3501
3658
|
const approval = entry(data.id);
|
|
3502
|
-
if (part.type === APPROVAL_PART) {
|
|
3659
|
+
if (part.type === APPROVAL_PART || part.type === "data-action-proposal") {
|
|
3660
|
+
if (isRecord4(data.target) && data.target.kind === "proposal" && typeof data.target.proposalId === "string") {
|
|
3661
|
+
approval.target = {
|
|
3662
|
+
kind: "proposal",
|
|
3663
|
+
proposalId: data.target.proposalId,
|
|
3664
|
+
...typeof data.target.threadId === "string" ? { threadId: data.target.threadId } : {}
|
|
3665
|
+
};
|
|
3666
|
+
}
|
|
3667
|
+
if (part.type === "data-action-proposal") {
|
|
3668
|
+
if (typeof data.status === "string" && ["pending", "approved", "rejected", "expired", "superseded"].includes(data.status))
|
|
3669
|
+
approval.status = data.status === "pending" ? null : data.status;
|
|
3670
|
+
if (data.executionStatus === null || data.executionStatus === "queued" || data.executionStatus === "executing" || data.executionStatus === "succeeded" || data.executionStatus === "failed")
|
|
3671
|
+
approval.executionStatus = data.executionStatus;
|
|
3672
|
+
approval.remember = data.remember === true;
|
|
3673
|
+
approval.decidedBy = typeof data.decidedBy === "string" ? data.decidedBy : null;
|
|
3674
|
+
approval.decidedVia = typeof data.decidedVia === "string" ? data.decidedVia : null;
|
|
3675
|
+
}
|
|
3503
3676
|
if (typeof data.approver !== "string") {
|
|
3504
3677
|
continue;
|
|
3505
3678
|
}
|
|
3506
3679
|
approval.approver = data.approver;
|
|
3507
3680
|
approval.expiresAt = typeof data.expiresAt === "string" ? data.expiresAt : null;
|
|
3681
|
+
if (isRecord4(data.confirmation) && typeof data.confirmation.title === "string" && typeof data.confirmation.verb === "string" && (data.confirmation.detail === void 0 || typeof data.confirmation.detail === "string")) {
|
|
3682
|
+
approval.confirmation = {
|
|
3683
|
+
title: data.confirmation.title,
|
|
3684
|
+
verb: data.confirmation.verb,
|
|
3685
|
+
...typeof data.confirmation.detail === "string" ? { detail: data.confirmation.detail } : {}
|
|
3686
|
+
};
|
|
3687
|
+
}
|
|
3508
3688
|
approval.reason = typeof data.reason === "string" ? data.reason : null;
|
|
3509
3689
|
continue;
|
|
3510
3690
|
}
|
|
@@ -3528,9 +3708,12 @@ function approvalOf(parts, call) {
|
|
|
3528
3708
|
}
|
|
3529
3709
|
return {
|
|
3530
3710
|
approver: parts.approver,
|
|
3711
|
+
...parts.target === void 0 ? {} : { target: parts.target },
|
|
3712
|
+
...parts.executionStatus === void 0 ? {} : { executionStatus: parts.executionStatus },
|
|
3713
|
+
...parts.confirmation !== void 0 ? { confirmation: parts.confirmation } : {},
|
|
3531
3714
|
expiresAt: parts.expiresAt,
|
|
3532
3715
|
reason: parts.reason,
|
|
3533
|
-
status: parts.status ?? statusFromPart(call),
|
|
3716
|
+
status: parts.status ?? (parts.target?.kind === "proposal" ? "pending" : statusFromPart(call)),
|
|
3534
3717
|
remember: parts.remember,
|
|
3535
3718
|
decidedBy: parts.decidedBy,
|
|
3536
3719
|
decidedVia: parts.decidedVia,
|
|
@@ -3560,6 +3743,10 @@ function readUiComponent(part) {
|
|
|
3560
3743
|
component: data.component,
|
|
3561
3744
|
props: isRecord4(data.props) ? data.props : {},
|
|
3562
3745
|
version: typeof data.version === "number" ? data.version : null,
|
|
3746
|
+
...isRecord4(data.componentVersions) && Object.values(data.componentVersions).every(
|
|
3747
|
+
(version) => typeof version === "number" && Number.isSafeInteger(version) && version > 0
|
|
3748
|
+
) ? { componentVersions: { ...data.componentVersions } } : {},
|
|
3749
|
+
...typeof data.fallbackText === "string" ? { fallbackText: data.fallbackText } : {},
|
|
3563
3750
|
toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
|
|
3564
3751
|
};
|
|
3565
3752
|
}
|
|
@@ -3670,6 +3857,12 @@ function formatCostUsd(cost) {
|
|
|
3670
3857
|
}
|
|
3671
3858
|
return `$${cost.toFixed(2)}`;
|
|
3672
3859
|
}
|
|
3860
|
+
function proposalDescription(description, approval) {
|
|
3861
|
+
if (approval?.target?.kind !== "proposal") return description;
|
|
3862
|
+
const status = approval.status === "pending" ? "awaiting-approval" : approval.status === "approved" ? approval.executionStatus ?? "queued" : "denied";
|
|
3863
|
+
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";
|
|
3864
|
+
return { ...description, status, phrase, result: null };
|
|
3865
|
+
}
|
|
3673
3866
|
|
|
3674
3867
|
// src/transcript/use-stick-to-bottom.ts
|
|
3675
3868
|
var import_react16 = require("react");
|
|
@@ -3962,23 +4155,31 @@ function useTranscriptItems({
|
|
|
3962
4155
|
[settle]
|
|
3963
4156
|
);
|
|
3964
4157
|
const approve = (0, import_react17.useCallback)(
|
|
3965
|
-
(toolCallId, options2) => {
|
|
4158
|
+
(toolCallId, options2, target) => {
|
|
3966
4159
|
const onApprove = latest.current.handlers.onApprove;
|
|
3967
4160
|
if (onApprove) {
|
|
3968
4161
|
settle(
|
|
3969
4162
|
toolCallId,
|
|
3970
4163
|
"approve",
|
|
3971
|
-
() => onApprove({
|
|
4164
|
+
() => onApprove({
|
|
4165
|
+
toolCallId,
|
|
4166
|
+
...target === void 0 ? {} : { target },
|
|
4167
|
+
...options2?.remember === true ? { remember: true } : {}
|
|
4168
|
+
})
|
|
3972
4169
|
);
|
|
3973
4170
|
}
|
|
3974
4171
|
},
|
|
3975
4172
|
[settle]
|
|
3976
4173
|
);
|
|
3977
4174
|
const reject = (0, import_react17.useCallback)(
|
|
3978
|
-
(toolCallId) => {
|
|
4175
|
+
(toolCallId, target) => {
|
|
3979
4176
|
const onReject = latest.current.handlers.onReject;
|
|
3980
4177
|
if (onReject) {
|
|
3981
|
-
settle(
|
|
4178
|
+
settle(
|
|
4179
|
+
toolCallId,
|
|
4180
|
+
"reject",
|
|
4181
|
+
() => onReject({ toolCallId, ...target === void 0 ? {} : { target } })
|
|
4182
|
+
);
|
|
3982
4183
|
}
|
|
3983
4184
|
},
|
|
3984
4185
|
[settle]
|
|
@@ -4176,14 +4377,36 @@ function settleHandlers(options, backend) {
|
|
|
4176
4377
|
),
|
|
4177
4378
|
onApprove: pick(
|
|
4178
4379
|
options.onApprove,
|
|
4179
|
-
backend.approveToolCall ? async (input) => {
|
|
4180
|
-
|
|
4380
|
+
backend.approveToolCall || backend.approveActionProposal ? async (input) => {
|
|
4381
|
+
if (input.target?.kind === "proposal") {
|
|
4382
|
+
if (input.target.threadId === void 0)
|
|
4383
|
+
throw new Error("A proposal decision requires its thread scope");
|
|
4384
|
+
await requireBackendMethod(
|
|
4385
|
+
backend,
|
|
4386
|
+
"approveActionProposal"
|
|
4387
|
+
)({
|
|
4388
|
+
threadId: input.target.threadId,
|
|
4389
|
+
proposalId: input.target.proposalId,
|
|
4390
|
+
...input.remember === void 0 ? {} : { remember: input.remember }
|
|
4391
|
+
});
|
|
4392
|
+
} else await requireBackendMethod(backend, "approveToolCall")(input);
|
|
4181
4393
|
} : void 0
|
|
4182
4394
|
),
|
|
4183
4395
|
onReject: pick(
|
|
4184
4396
|
options.onReject,
|
|
4185
|
-
backend.rejectToolCall ? async (input) => {
|
|
4186
|
-
|
|
4397
|
+
backend.rejectToolCall || backend.rejectActionProposal ? async (input) => {
|
|
4398
|
+
if (input.target?.kind === "proposal") {
|
|
4399
|
+
if (input.target.threadId === void 0)
|
|
4400
|
+
throw new Error("A proposal decision requires its thread scope");
|
|
4401
|
+
await requireBackendMethod(
|
|
4402
|
+
backend,
|
|
4403
|
+
"rejectActionProposal"
|
|
4404
|
+
)({
|
|
4405
|
+
threadId: input.target.threadId,
|
|
4406
|
+
proposalId: input.target.proposalId,
|
|
4407
|
+
...input.reason === void 0 ? {} : { reason: input.reason }
|
|
4408
|
+
});
|
|
4409
|
+
} else await requireBackendMethod(backend, "rejectToolCall")(input);
|
|
4187
4410
|
} : void 0
|
|
4188
4411
|
)
|
|
4189
4412
|
};
|
|
@@ -5088,6 +5311,8 @@ function storedMessageToUiMessage(message) {
|
|
|
5088
5311
|
id: component.id,
|
|
5089
5312
|
component: component.component,
|
|
5090
5313
|
props: component.props,
|
|
5314
|
+
...component.componentVersions !== void 0 ? { componentVersions: component.componentVersions } : {},
|
|
5315
|
+
...component.fallbackText !== void 0 ? { fallbackText: component.fallbackText } : {},
|
|
5091
5316
|
...component.version !== void 0 ? { version: component.version } : {},
|
|
5092
5317
|
...component.toolCallId !== void 0 ? { toolCallId: component.toolCallId } : {}
|
|
5093
5318
|
}
|
|
@@ -5107,6 +5332,8 @@ function storedMessageToUiMessage(message) {
|
|
|
5107
5332
|
data: {
|
|
5108
5333
|
id: approval.toolCallId,
|
|
5109
5334
|
approver: approval.approver,
|
|
5335
|
+
...approval.target !== void 0 ? { target: approval.target } : approval.proposalId !== void 0 ? { target: { kind: "proposal", proposalId: approval.proposalId } } : {},
|
|
5336
|
+
...approval.confirmation !== void 0 ? { confirmation: approval.confirmation } : {},
|
|
5110
5337
|
...approval.expiresAt !== void 0 ? { expiresAt: approval.expiresAt } : {}
|
|
5111
5338
|
}
|
|
5112
5339
|
});
|
|
@@ -5163,6 +5390,7 @@ function storedMessageToUiMessage(message) {
|
|
|
5163
5390
|
const metadata = {
|
|
5164
5391
|
// The host's own facts first: the library's keys win on a clash.
|
|
5165
5392
|
...message.metadata,
|
|
5393
|
+
...message.actionProposalOutcome === void 0 ? {} : { actionProposalOutcomeId: message.actionProposalOutcome.id },
|
|
5166
5394
|
...message.feedback !== void 0 ? { feedback: message.feedback } : {},
|
|
5167
5395
|
...message.createdAt ? { createdAt: message.createdAt } : {},
|
|
5168
5396
|
...message.agentName !== void 0 ? { agentName: message.agentName } : {},
|
|
@@ -5198,6 +5426,8 @@ function storedThreadToUiMessages(messages) {
|
|
|
5198
5426
|
return turns.map(mergeTurn);
|
|
5199
5427
|
}
|
|
5200
5428
|
function sameRun(previous, next) {
|
|
5429
|
+
if (previous.actionProposalOutcome !== void 0 || next.actionProposalOutcome !== void 0)
|
|
5430
|
+
return false;
|
|
5201
5431
|
return previous.runId === void 0 || next.runId === void 0 || previous.runId === next.runId;
|
|
5202
5432
|
}
|
|
5203
5433
|
function mergeTurn(rows) {
|
|
@@ -5244,8 +5474,163 @@ function sumUsage(rows) {
|
|
|
5244
5474
|
}
|
|
5245
5475
|
|
|
5246
5476
|
// src/use-agent-chat.ts
|
|
5247
|
-
var
|
|
5248
|
-
var
|
|
5477
|
+
var import_react23 = require("@ai-sdk/react");
|
|
5478
|
+
var import_react24 = require("react");
|
|
5479
|
+
|
|
5480
|
+
// src/approvals/use-action-proposals.ts
|
|
5481
|
+
var import_react22 = require("react");
|
|
5482
|
+
|
|
5483
|
+
// src/approvals/proposals.ts
|
|
5484
|
+
function proposalNeedsPolling(proposal) {
|
|
5485
|
+
return proposal.decision === "pending" || proposal.execution?.status === "queued" || proposal.execution?.status === "executing" || proposal.outcomeDelivery?.status === "pending";
|
|
5486
|
+
}
|
|
5487
|
+
function reconcileProposalMessages(current, proposals, facts) {
|
|
5488
|
+
const messages = current.map((message) => {
|
|
5489
|
+
const relevant = proposals.filter(
|
|
5490
|
+
(proposal) => message.parts.some((part) => {
|
|
5491
|
+
if ("data" in part && record(part.data) && record(part.data.target) && part.data.target.kind === "proposal")
|
|
5492
|
+
return part.data.target.proposalId === proposal.id;
|
|
5493
|
+
if ("toolCallId" in part && part.toolCallId === proposal.originToolCallId) {
|
|
5494
|
+
if ("output" in part && record(part.output) && typeof part.output.proposalId === "string")
|
|
5495
|
+
return part.output.proposalId === proposal.id;
|
|
5496
|
+
return record(message.metadata) && message.metadata.runId === proposal.originRunId;
|
|
5497
|
+
}
|
|
5498
|
+
return false;
|
|
5499
|
+
})
|
|
5500
|
+
);
|
|
5501
|
+
if (relevant.length === 0) return message;
|
|
5502
|
+
const ids = new Set(relevant.map((proposal) => proposal.originToolCallId));
|
|
5503
|
+
const parts = message.parts.filter(
|
|
5504
|
+
(part) => !(part.type === "data-action-proposal" && "id" in part && typeof part.id === "string" && ids.has(part.id))
|
|
5505
|
+
);
|
|
5506
|
+
for (const proposal of relevant)
|
|
5507
|
+
parts.push({
|
|
5508
|
+
type: "data-action-proposal",
|
|
5509
|
+
id: proposal.originToolCallId,
|
|
5510
|
+
data: {
|
|
5511
|
+
id: proposal.originToolCallId,
|
|
5512
|
+
target: { kind: "proposal", proposalId: proposal.id, threadId: proposal.threadId },
|
|
5513
|
+
approver: proposal.approver,
|
|
5514
|
+
confirmation: proposal.confirmation,
|
|
5515
|
+
expiresAt: proposal.expiresAt === null ? null : Math.abs(proposal.expiresAt) <= 864e13 ? new Date(proposal.expiresAt).toISOString() : null,
|
|
5516
|
+
status: proposal.decision,
|
|
5517
|
+
executionStatus: proposal.execution?.status ?? null,
|
|
5518
|
+
remember: proposal.decisionAudit?.remember === true,
|
|
5519
|
+
decidedBy: proposal.decisionAudit?.actorRef ?? null,
|
|
5520
|
+
decidedVia: proposal.decisionAudit?.via ?? null,
|
|
5521
|
+
reason: proposal.decisionAudit?.reason ?? null
|
|
5522
|
+
}
|
|
5523
|
+
});
|
|
5524
|
+
return { ...message, parts };
|
|
5525
|
+
});
|
|
5526
|
+
const knownMessages = new Set(messages.map((message) => message.id));
|
|
5527
|
+
const knownOutcomes = new Set(
|
|
5528
|
+
messages.map((message) => outcomeId(message.metadata)).filter(Boolean)
|
|
5529
|
+
);
|
|
5530
|
+
for (const fact of facts) {
|
|
5531
|
+
const id = fact.actionProposalOutcome?.id;
|
|
5532
|
+
if (id === void 0 || knownMessages.has(fact.id) || knownOutcomes.has(id)) continue;
|
|
5533
|
+
const message = storedMessageToUiMessage(fact);
|
|
5534
|
+
messages.push({
|
|
5535
|
+
...message,
|
|
5536
|
+
metadata: {
|
|
5537
|
+
...record(message.metadata) ? message.metadata : {},
|
|
5538
|
+
actionProposalOutcomeId: id
|
|
5539
|
+
}
|
|
5540
|
+
});
|
|
5541
|
+
knownMessages.add(fact.id);
|
|
5542
|
+
knownOutcomes.add(id);
|
|
5543
|
+
}
|
|
5544
|
+
return messages;
|
|
5545
|
+
}
|
|
5546
|
+
function record(value) {
|
|
5547
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5548
|
+
}
|
|
5549
|
+
function outcomeId(value) {
|
|
5550
|
+
return record(value) && typeof value.actionProposalOutcomeId === "string" ? value.actionProposalOutcomeId : void 0;
|
|
5551
|
+
}
|
|
5552
|
+
|
|
5553
|
+
// src/approvals/use-action-proposals.ts
|
|
5554
|
+
function useActionProposals(backend, threadId, setMessages, refreshKey, pollMs = 1e3) {
|
|
5555
|
+
const [items, setItems] = (0, import_react22.useState)([]);
|
|
5556
|
+
const [error, setError] = (0, import_react22.useState)(null);
|
|
5557
|
+
const latest = (0, import_react22.useRef)({ threadId, setMessages });
|
|
5558
|
+
latest.current = { threadId, setMessages };
|
|
5559
|
+
const mounted = (0, import_react22.useRef)(true);
|
|
5560
|
+
const requests = (0, import_react22.useRef)(/* @__PURE__ */ new Map());
|
|
5561
|
+
(0, import_react22.useEffect)(() => {
|
|
5562
|
+
mounted.current = true;
|
|
5563
|
+
return () => {
|
|
5564
|
+
mounted.current = false;
|
|
5565
|
+
};
|
|
5566
|
+
}, []);
|
|
5567
|
+
const refresh = (0, import_react22.useCallback)(async () => {
|
|
5568
|
+
if (threadId === void 0 || backend.listActionProposals === void 0) return;
|
|
5569
|
+
const pending = requests.current.get(threadId);
|
|
5570
|
+
if (pending) return pending;
|
|
5571
|
+
const request = (async () => {
|
|
5572
|
+
try {
|
|
5573
|
+
const proposals = await backend.listActionProposals?.({ threadId });
|
|
5574
|
+
if (!mounted.current || latest.current.threadId !== threadId || !Array.isArray(proposals))
|
|
5575
|
+
return;
|
|
5576
|
+
const admitted = proposals.some(
|
|
5577
|
+
(proposal) => proposal.outcomeDelivery?.status === "admitted"
|
|
5578
|
+
);
|
|
5579
|
+
const facts = admitted ? (await backend.getThread(threadId)).messages.filter(
|
|
5580
|
+
(message) => message.actionProposalOutcome !== void 0
|
|
5581
|
+
) : [];
|
|
5582
|
+
if (!mounted.current || latest.current.threadId !== threadId) return;
|
|
5583
|
+
setItems(proposals);
|
|
5584
|
+
setError(null);
|
|
5585
|
+
latest.current.setMessages(
|
|
5586
|
+
(current) => reconcileProposalMessages(current, proposals, facts)
|
|
5587
|
+
);
|
|
5588
|
+
} catch (cause) {
|
|
5589
|
+
if (mounted.current && latest.current.threadId === threadId)
|
|
5590
|
+
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
5591
|
+
}
|
|
5592
|
+
})();
|
|
5593
|
+
requests.current.set(threadId, request);
|
|
5594
|
+
try {
|
|
5595
|
+
await request;
|
|
5596
|
+
} finally {
|
|
5597
|
+
requests.current.delete(threadId);
|
|
5598
|
+
}
|
|
5599
|
+
}, [backend, threadId]);
|
|
5600
|
+
(0, import_react22.useEffect)(() => {
|
|
5601
|
+
setItems([]);
|
|
5602
|
+
setError(null);
|
|
5603
|
+
}, [threadId]);
|
|
5604
|
+
(0, import_react22.useEffect)(() => {
|
|
5605
|
+
void refresh();
|
|
5606
|
+
}, [refresh, refreshKey]);
|
|
5607
|
+
(0, import_react22.useEffect)(() => {
|
|
5608
|
+
if (!items.some(proposalNeedsPolling) || pollMs <= 0) return;
|
|
5609
|
+
const timer = setInterval(() => {
|
|
5610
|
+
void refresh();
|
|
5611
|
+
}, pollMs);
|
|
5612
|
+
return () => clearInterval(timer);
|
|
5613
|
+
}, [items, pollMs, refresh]);
|
|
5614
|
+
(0, import_react22.useEffect)(() => {
|
|
5615
|
+
const refetch = () => {
|
|
5616
|
+
void refresh();
|
|
5617
|
+
};
|
|
5618
|
+
const visible = () => {
|
|
5619
|
+
if (document.visibilityState === "visible") refetch();
|
|
5620
|
+
};
|
|
5621
|
+
window.addEventListener("focus", refetch);
|
|
5622
|
+
window.addEventListener("online", refetch);
|
|
5623
|
+
document.addEventListener("visibilitychange", visible);
|
|
5624
|
+
return () => {
|
|
5625
|
+
window.removeEventListener("focus", refetch);
|
|
5626
|
+
window.removeEventListener("online", refetch);
|
|
5627
|
+
document.removeEventListener("visibilitychange", visible);
|
|
5628
|
+
};
|
|
5629
|
+
}, [refresh]);
|
|
5630
|
+
return { items, error, refresh };
|
|
5631
|
+
}
|
|
5632
|
+
|
|
5633
|
+
// src/use-agent-chat.ts
|
|
5249
5634
|
var EMPTY_QUEUE = { items: [], paused: null };
|
|
5250
5635
|
var localQueueSequence = 0;
|
|
5251
5636
|
function queuedUserMessage(turn) {
|
|
@@ -5300,13 +5685,16 @@ function localChatId() {
|
|
|
5300
5685
|
return `local-chat-${localChatSequence}`;
|
|
5301
5686
|
}
|
|
5302
5687
|
function useAgentChat(options = {}) {
|
|
5303
|
-
const
|
|
5688
|
+
const providerCapabilities = useAgentUiCapabilities();
|
|
5689
|
+
const capabilitiesRef = (0, import_react24.useRef)(providerCapabilities);
|
|
5690
|
+
capabilitiesRef.current = providerCapabilities;
|
|
5691
|
+
const latest = (0, import_react24.useRef)(options);
|
|
5304
5692
|
latest.current = options;
|
|
5305
5693
|
const resolved = useAgentBackend(options.backend);
|
|
5306
|
-
const client = (0,
|
|
5307
|
-
const createdThreadId = (0,
|
|
5308
|
-
const chatIdRef = (0,
|
|
5309
|
-
const boundThreadRef = (0,
|
|
5694
|
+
const client = (0, import_react24.useRef)(resolved).current;
|
|
5695
|
+
const createdThreadId = (0, import_react24.useRef)(void 0);
|
|
5696
|
+
const chatIdRef = (0, import_react24.useRef)(options.threadId ?? localChatId());
|
|
5697
|
+
const boundThreadRef = (0, import_react24.useRef)(options.threadId);
|
|
5310
5698
|
if (options.threadId !== boundThreadRef.current) {
|
|
5311
5699
|
boundThreadRef.current = options.threadId;
|
|
5312
5700
|
const adopting = options.threadId !== void 0 && options.threadId === createdThreadId.current;
|
|
@@ -5316,39 +5704,41 @@ function useAgentChat(options = {}) {
|
|
|
5316
5704
|
}
|
|
5317
5705
|
}
|
|
5318
5706
|
const chatId = chatIdRef.current;
|
|
5319
|
-
const [runId, setRunId] = (0,
|
|
5320
|
-
const runIdRef = (0,
|
|
5707
|
+
const [runId, setRunId] = (0, import_react24.useState)(options.resumeRunId);
|
|
5708
|
+
const runIdRef = (0, import_react24.useRef)(runId);
|
|
5321
5709
|
runIdRef.current = runId;
|
|
5322
|
-
const settlingRunIdRef = (0,
|
|
5323
|
-
const autoResumeRunIdRef = (0,
|
|
5324
|
-
const [activeRunId, setActiveRunId] = (0,
|
|
5325
|
-
const [historyFor, setHistoryFor] = (0,
|
|
5326
|
-
const [historyError, setHistoryError] = (0,
|
|
5327
|
-
const [runError, setRunError] = (0,
|
|
5328
|
-
const [threadModel, setThreadModel] = (0,
|
|
5329
|
-
const [threadPersona, setThreadPersona] = (0,
|
|
5330
|
-
const [pickedModel, setPickedModel] = (0,
|
|
5331
|
-
const pickedModelRef = (0,
|
|
5710
|
+
const settlingRunIdRef = (0, import_react24.useRef)(void 0);
|
|
5711
|
+
const autoResumeRunIdRef = (0, import_react24.useRef)(void 0);
|
|
5712
|
+
const [activeRunId, setActiveRunId] = (0, import_react24.useState)(null);
|
|
5713
|
+
const [historyFor, setHistoryFor] = (0, import_react24.useState)(void 0);
|
|
5714
|
+
const [historyError, setHistoryError] = (0, import_react24.useState)(null);
|
|
5715
|
+
const [runError, setRunError] = (0, import_react24.useState)(null);
|
|
5716
|
+
const [threadModel, setThreadModel] = (0, import_react24.useState)(null);
|
|
5717
|
+
const [threadPersona, setThreadPersona] = (0, import_react24.useState)(null);
|
|
5718
|
+
const [pickedModel, setPickedModel] = (0, import_react24.useState)(void 0);
|
|
5719
|
+
const pickedModelRef = (0, import_react24.useRef)(pickedModel);
|
|
5332
5720
|
pickedModelRef.current = pickedModel;
|
|
5333
|
-
const lockedRef = (0,
|
|
5334
|
-
const pendingPin = (0,
|
|
5335
|
-
const regenerateNext = (0,
|
|
5336
|
-
const currentThreadId = (0,
|
|
5721
|
+
const lockedRef = (0, import_react24.useRef)(false);
|
|
5722
|
+
const pendingPin = (0, import_react24.useRef)(void 0);
|
|
5723
|
+
const regenerateNext = (0, import_react24.useRef)(false);
|
|
5724
|
+
const currentThreadId = (0, import_react24.useCallback)(
|
|
5337
5725
|
() => latest.current.threadId ?? createdThreadId.current,
|
|
5338
5726
|
[]
|
|
5339
5727
|
);
|
|
5340
|
-
const [queueState, setQueueState] = (0,
|
|
5341
|
-
const queueStateRef = (0,
|
|
5342
|
-
const applyQueue = (0,
|
|
5728
|
+
const [queueState, setQueueState] = (0, import_react24.useState)(EMPTY_QUEUE);
|
|
5729
|
+
const queueStateRef = (0, import_react24.useRef)(queueState);
|
|
5730
|
+
const applyQueue = (0, import_react24.useCallback)((next) => {
|
|
5343
5731
|
queueStateRef.current = next;
|
|
5344
5732
|
setQueueState(next);
|
|
5345
5733
|
}, []);
|
|
5346
|
-
const [pendingSends, setPendingSends] = (0,
|
|
5347
|
-
const [queueError, setQueueError] = (0,
|
|
5348
|
-
const handoff = (0,
|
|
5349
|
-
const queuedSend = (0,
|
|
5350
|
-
const
|
|
5351
|
-
|
|
5734
|
+
const [pendingSends, setPendingSends] = (0, import_react24.useState)([]);
|
|
5735
|
+
const [queueError, setQueueError] = (0, import_react24.useState)(null);
|
|
5736
|
+
const handoff = (0, import_react24.useRef)(void 0);
|
|
5737
|
+
const queuedSend = (0, import_react24.useRef)(void 0);
|
|
5738
|
+
const proposalRefreshRef = (0, import_react24.useRef)(async () => {
|
|
5739
|
+
});
|
|
5740
|
+
const threadWaiters = (0, import_react24.useRef)([]);
|
|
5741
|
+
const turnBody = (0, import_react24.useCallback)(() => {
|
|
5352
5742
|
const current = latest.current;
|
|
5353
5743
|
if (current.persona !== void 0) setThreadPersona(current.persona);
|
|
5354
5744
|
const pageContext = current.getPageContext?.() ?? null;
|
|
@@ -5361,12 +5751,13 @@ function useAgentChat(options = {}) {
|
|
|
5361
5751
|
...current.persona !== void 0 ? { persona: current.persona } : {},
|
|
5362
5752
|
...threadId !== void 0 ? { threadId } : {},
|
|
5363
5753
|
...model !== void 0 ? { model } : {},
|
|
5364
|
-
...pageContext ? { pageContext } : {}
|
|
5754
|
+
...pageContext ? { pageContext } : {},
|
|
5755
|
+
...(current.uiCapabilities ?? capabilitiesRef.current) === void 0 ? {} : { uiCapabilities: current.uiCapabilities ?? capabilitiesRef.current }
|
|
5365
5756
|
};
|
|
5366
5757
|
}, [currentThreadId]);
|
|
5367
|
-
const [connection, setConnection] = (0,
|
|
5368
|
-
const resyncAfterSettle = (0,
|
|
5369
|
-
const transport = (0,
|
|
5758
|
+
const [connection, setConnection] = (0, import_react24.useState)({ status: "live" });
|
|
5759
|
+
const resyncAfterSettle = (0, import_react24.useRef)(false);
|
|
5760
|
+
const transport = (0, import_react24.useMemo)(() => {
|
|
5370
5761
|
function onMeta(meta) {
|
|
5371
5762
|
settlingRunIdRef.current = meta.runId;
|
|
5372
5763
|
setRunId(meta.runId);
|
|
@@ -5418,14 +5809,15 @@ function useAgentChat(options = {}) {
|
|
|
5418
5809
|
}
|
|
5419
5810
|
});
|
|
5420
5811
|
}, []);
|
|
5421
|
-
const backgroundRef = (0,
|
|
5422
|
-
const chat = (0,
|
|
5812
|
+
const backgroundRef = (0, import_react24.useRef)(() => Promise.resolve());
|
|
5813
|
+
const chat = (0, import_react23.useChat)({
|
|
5423
5814
|
transport,
|
|
5424
5815
|
id: chatId,
|
|
5425
5816
|
resume: options.resumeRunId !== void 0,
|
|
5426
5817
|
...options.initialMessages !== void 0 ? { messages: options.initialMessages } : {},
|
|
5427
5818
|
onData: (part) => {
|
|
5428
5819
|
latest.current.onData?.(part);
|
|
5820
|
+
if (part.type === "data-proposal-decision") void proposalRefreshRef.current();
|
|
5429
5821
|
if (part.type === "data-queue") {
|
|
5430
5822
|
onQueueData(part.data);
|
|
5431
5823
|
}
|
|
@@ -5472,7 +5864,7 @@ function useAgentChat(options = {}) {
|
|
|
5472
5864
|
}
|
|
5473
5865
|
}
|
|
5474
5866
|
});
|
|
5475
|
-
const chatRef = (0,
|
|
5867
|
+
const chatRef = (0, import_react24.useRef)(chat);
|
|
5476
5868
|
chatRef.current = chat;
|
|
5477
5869
|
function onQueueData(data) {
|
|
5478
5870
|
const frame = data ?? {};
|
|
@@ -5520,8 +5912,8 @@ function useAgentChat(options = {}) {
|
|
|
5520
5912
|
} catch {
|
|
5521
5913
|
}
|
|
5522
5914
|
}
|
|
5523
|
-
const firstChatId = (0,
|
|
5524
|
-
(0,
|
|
5915
|
+
const firstChatId = (0, import_react24.useRef)(chatId);
|
|
5916
|
+
(0, import_react24.useEffect)(() => {
|
|
5525
5917
|
if (chatId === firstChatId.current) return;
|
|
5526
5918
|
firstChatId.current = chatId;
|
|
5527
5919
|
setRunId(void 0);
|
|
@@ -5540,7 +5932,7 @@ function useAgentChat(options = {}) {
|
|
|
5540
5932
|
handoff.current = void 0;
|
|
5541
5933
|
queuedSend.current = void 0;
|
|
5542
5934
|
}, [chatId]);
|
|
5543
|
-
(0,
|
|
5935
|
+
(0, import_react24.useEffect)(() => {
|
|
5544
5936
|
const threadId = options.threadId;
|
|
5545
5937
|
if (threadId === void 0) return;
|
|
5546
5938
|
if (threadId === createdThreadId.current) return;
|
|
@@ -5587,8 +5979,8 @@ function useAgentChat(options = {}) {
|
|
|
5587
5979
|
};
|
|
5588
5980
|
}, [client, chatId, options.threadId]);
|
|
5589
5981
|
const isLoadingHistory = options.threadId !== void 0 && options.threadId !== createdThreadId.current && options.history !== false && options.initialMessages === void 0 && historyFor !== options.threadId;
|
|
5590
|
-
const turnInFlight = (0,
|
|
5591
|
-
const isTurnInFlight = (0,
|
|
5982
|
+
const turnInFlight = (0, import_react24.useRef)(false);
|
|
5983
|
+
const isTurnInFlight = (0, import_react24.useCallback)(
|
|
5592
5984
|
() => turnInFlight.current || transport.isAttemptLive,
|
|
5593
5985
|
[transport]
|
|
5594
5986
|
);
|
|
@@ -5597,20 +5989,20 @@ function useAgentChat(options = {}) {
|
|
|
5597
5989
|
enabled: options.quota !== false && typeof client.getQuota === "function"
|
|
5598
5990
|
});
|
|
5599
5991
|
const blocked = options.blocked !== void 0 ? options.blocked : quota.blocked;
|
|
5600
|
-
const blockedRef = (0,
|
|
5992
|
+
const blockedRef = (0, import_react24.useRef)(blocked);
|
|
5601
5993
|
blockedRef.current = blocked;
|
|
5602
5994
|
const whileRunning = typeof client.enqueueMessage === "function" ? options.whileRunning ?? "queue" : "block";
|
|
5603
|
-
const whileRunningRef = (0,
|
|
5995
|
+
const whileRunningRef = (0, import_react24.useRef)(whileRunning);
|
|
5604
5996
|
whileRunningRef.current = whileRunning;
|
|
5605
|
-
const canQueueRef = (0,
|
|
5997
|
+
const canQueueRef = (0, import_react24.useRef)(false);
|
|
5606
5998
|
canQueueRef.current = typeof client.enqueueMessage === "function";
|
|
5607
|
-
const threadForQueue = (0,
|
|
5999
|
+
const threadForQueue = (0, import_react24.useCallback)(async () => {
|
|
5608
6000
|
const known = currentThreadId();
|
|
5609
6001
|
if (known !== void 0) return known;
|
|
5610
6002
|
if (!isTurnInFlight()) throw new Error("queue: this chat has no thread yet");
|
|
5611
6003
|
return new Promise((resolve) => threadWaiters.current.push(resolve));
|
|
5612
6004
|
}, [currentThreadId, isTurnInFlight]);
|
|
5613
|
-
const queueCall = (0,
|
|
6005
|
+
const queueCall = (0, import_react24.useCallback)(async (run) => {
|
|
5614
6006
|
try {
|
|
5615
6007
|
const result = await run();
|
|
5616
6008
|
setQueueError(null);
|
|
@@ -5620,7 +6012,7 @@ function useAgentChat(options = {}) {
|
|
|
5620
6012
|
throw error;
|
|
5621
6013
|
}
|
|
5622
6014
|
}, []);
|
|
5623
|
-
const enqueue = (0,
|
|
6015
|
+
const enqueue = (0, import_react24.useCallback)(
|
|
5624
6016
|
async (text2, {
|
|
5625
6017
|
attachments = [],
|
|
5626
6018
|
mode = "queue"
|
|
@@ -5668,7 +6060,7 @@ function useAgentChat(options = {}) {
|
|
|
5668
6060
|
},
|
|
5669
6061
|
[client, queueCall, threadForQueue, turnBody, applyQueue, isTurnInFlight]
|
|
5670
6062
|
);
|
|
5671
|
-
const sendMessage = (0,
|
|
6063
|
+
const sendMessage = (0, import_react24.useCallback)(
|
|
5672
6064
|
async (message, options2) => {
|
|
5673
6065
|
const block = blockedRef.current;
|
|
5674
6066
|
if (block != null) throw new QuotaBlockedError(block);
|
|
@@ -5692,7 +6084,7 @@ function useAgentChat(options = {}) {
|
|
|
5692
6084
|
},
|
|
5693
6085
|
[isTurnInFlight, enqueue]
|
|
5694
6086
|
);
|
|
5695
|
-
const removeQueued = (0,
|
|
6087
|
+
const removeQueued = (0, import_react24.useCallback)(
|
|
5696
6088
|
async (id) => {
|
|
5697
6089
|
const previous = queueStateRef.current;
|
|
5698
6090
|
applyQueue({ ...previous, items: previous.items.filter((item) => item.id !== id) });
|
|
@@ -5705,7 +6097,7 @@ function useAgentChat(options = {}) {
|
|
|
5705
6097
|
},
|
|
5706
6098
|
[client, queueCall, applyQueue]
|
|
5707
6099
|
);
|
|
5708
|
-
const interruptQueued = (0,
|
|
6100
|
+
const interruptQueued = (0, import_react24.useCallback)(
|
|
5709
6101
|
async (id) => {
|
|
5710
6102
|
const previous = queueStateRef.current;
|
|
5711
6103
|
const moving = previous.items.find((item) => item.id === id);
|
|
@@ -5740,7 +6132,7 @@ function useAgentChat(options = {}) {
|
|
|
5740
6132
|
},
|
|
5741
6133
|
[client, queueCall, applyQueue, isTurnInFlight]
|
|
5742
6134
|
);
|
|
5743
|
-
const editQueued = (0,
|
|
6135
|
+
const editQueued = (0, import_react24.useCallback)(
|
|
5744
6136
|
async (id, text2) => {
|
|
5745
6137
|
applyQueue(
|
|
5746
6138
|
await queueCall(
|
|
@@ -5750,7 +6142,7 @@ function useAgentChat(options = {}) {
|
|
|
5750
6142
|
},
|
|
5751
6143
|
[client, queueCall, applyQueue]
|
|
5752
6144
|
);
|
|
5753
|
-
const moveQueued = (0,
|
|
6145
|
+
const moveQueued = (0, import_react24.useCallback)(
|
|
5754
6146
|
async (id, index) => {
|
|
5755
6147
|
const previous = queueStateRef.current;
|
|
5756
6148
|
const moving = previous.items.find((item) => item.id === id);
|
|
@@ -5772,12 +6164,12 @@ function useAgentChat(options = {}) {
|
|
|
5772
6164
|
},
|
|
5773
6165
|
[client, queueCall, applyQueue]
|
|
5774
6166
|
);
|
|
5775
|
-
const clearQueue = (0,
|
|
6167
|
+
const clearQueue = (0, import_react24.useCallback)(async () => {
|
|
5776
6168
|
const threadId = currentThreadId();
|
|
5777
6169
|
if (threadId === void 0) return;
|
|
5778
6170
|
applyQueue(await queueCall(() => requireBackendMethod(client, "clearQueue")(threadId)));
|
|
5779
6171
|
}, [client, queueCall, currentThreadId, applyQueue]);
|
|
5780
|
-
const resumeQueue = (0,
|
|
6172
|
+
const resumeQueue = (0, import_react24.useCallback)(async () => {
|
|
5781
6173
|
const threadId = currentThreadId();
|
|
5782
6174
|
if (threadId === void 0) return;
|
|
5783
6175
|
const before = queueStateRef.current;
|
|
@@ -5795,7 +6187,7 @@ function useAgentChat(options = {}) {
|
|
|
5795
6187
|
else attachTo(turn);
|
|
5796
6188
|
}
|
|
5797
6189
|
}, [client, queueCall, currentThreadId, applyQueue, isTurnInFlight]);
|
|
5798
|
-
const resumeQueueRef = (0,
|
|
6190
|
+
const resumeQueueRef = (0, import_react24.useRef)(resumeQueue);
|
|
5799
6191
|
resumeQueueRef.current = resumeQueue;
|
|
5800
6192
|
const queuedItems = [
|
|
5801
6193
|
...pendingSends.filter((item) => item.interrupt),
|
|
@@ -5825,7 +6217,7 @@ function useAgentChat(options = {}) {
|
|
|
5825
6217
|
resume: resumeQueue,
|
|
5826
6218
|
error: queueError
|
|
5827
6219
|
};
|
|
5828
|
-
const addToolResult = (0,
|
|
6220
|
+
const addToolResult = (0, import_react24.useCallback)(
|
|
5829
6221
|
({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
5830
6222
|
tool,
|
|
5831
6223
|
toolCallId,
|
|
@@ -5833,8 +6225,8 @@ function useAgentChat(options = {}) {
|
|
|
5833
6225
|
}),
|
|
5834
6226
|
[]
|
|
5835
6227
|
);
|
|
5836
|
-
const [backgroundRuns, setBackgroundRuns] = (0,
|
|
5837
|
-
const refreshBackground = (0,
|
|
6228
|
+
const [backgroundRuns, setBackgroundRuns] = (0, import_react24.useState)([]);
|
|
6229
|
+
const refreshBackground = (0, import_react24.useCallback)(async () => {
|
|
5838
6230
|
const threadId = currentThreadId();
|
|
5839
6231
|
if (threadId === void 0) {
|
|
5840
6232
|
return;
|
|
@@ -5854,13 +6246,13 @@ function useAgentChat(options = {}) {
|
|
|
5854
6246
|
}, [client, currentThreadId]);
|
|
5855
6247
|
backgroundRef.current = refreshBackground;
|
|
5856
6248
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
5857
|
-
(0,
|
|
6249
|
+
(0, import_react24.useEffect)(() => {
|
|
5858
6250
|
if (options.background !== true || options.threadId === void 0) {
|
|
5859
6251
|
return;
|
|
5860
6252
|
}
|
|
5861
6253
|
void refreshBackground();
|
|
5862
6254
|
}, [options.background, options.threadId, chatId, refreshBackground]);
|
|
5863
|
-
(0,
|
|
6255
|
+
(0, import_react24.useEffect)(() => {
|
|
5864
6256
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
5865
6257
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
5866
6258
|
return;
|
|
@@ -5868,7 +6260,15 @@ function useAgentChat(options = {}) {
|
|
|
5868
6260
|
const timer = setInterval(() => void refreshBackground(), every);
|
|
5869
6261
|
return () => clearInterval(timer);
|
|
5870
6262
|
}, [isWorking, refreshBackground]);
|
|
5871
|
-
const
|
|
6263
|
+
const proposals = useActionProposals(
|
|
6264
|
+
client,
|
|
6265
|
+
options.proposals === false || options.proposals !== true && options.history === false && options.resume === false ? void 0 : currentThreadId(),
|
|
6266
|
+
(update) => chatRef.current.setMessages(update),
|
|
6267
|
+
`${chat.status}:${connection.status}`,
|
|
6268
|
+
options.proposalPollMs
|
|
6269
|
+
);
|
|
6270
|
+
proposalRefreshRef.current = proposals.refresh;
|
|
6271
|
+
const cancel = (0, import_react24.useCallback)(async () => {
|
|
5872
6272
|
chatRef.current.stop();
|
|
5873
6273
|
const active = runIdRef.current;
|
|
5874
6274
|
if (active) {
|
|
@@ -5885,8 +6285,23 @@ function useAgentChat(options = {}) {
|
|
|
5885
6285
|
}
|
|
5886
6286
|
}
|
|
5887
6287
|
}, [client, currentThreadId, applyQueue]);
|
|
5888
|
-
const approve = (0,
|
|
5889
|
-
async ({ toolCallId, remember, via }) => {
|
|
6288
|
+
const approve = (0, import_react24.useCallback)(
|
|
6289
|
+
async ({ toolCallId, target, remember, via }) => {
|
|
6290
|
+
if (target?.kind === "proposal") {
|
|
6291
|
+
const threadId = target.threadId ?? currentThreadId();
|
|
6292
|
+
if (threadId === void 0)
|
|
6293
|
+
throw new Error("A proposal decision requires its thread scope");
|
|
6294
|
+
await requireBackendMethod(
|
|
6295
|
+
client,
|
|
6296
|
+
"approveActionProposal"
|
|
6297
|
+
)({
|
|
6298
|
+
threadId,
|
|
6299
|
+
proposalId: target.proposalId,
|
|
6300
|
+
...remember === true ? { remember: true } : {}
|
|
6301
|
+
});
|
|
6302
|
+
await proposals.refresh();
|
|
6303
|
+
return;
|
|
6304
|
+
}
|
|
5890
6305
|
await requireBackendMethod(
|
|
5891
6306
|
client,
|
|
5892
6307
|
"approveToolCall"
|
|
@@ -5896,10 +6311,25 @@ function useAgentChat(options = {}) {
|
|
|
5896
6311
|
...via !== void 0 ? { via } : {}
|
|
5897
6312
|
});
|
|
5898
6313
|
},
|
|
5899
|
-
[client]
|
|
6314
|
+
[client, currentThreadId, proposals.refresh]
|
|
5900
6315
|
);
|
|
5901
|
-
const reject = (0,
|
|
5902
|
-
async ({ toolCallId, reason, via }) => {
|
|
6316
|
+
const reject = (0, import_react24.useCallback)(
|
|
6317
|
+
async ({ toolCallId, target, reason, via }) => {
|
|
6318
|
+
if (target?.kind === "proposal") {
|
|
6319
|
+
const threadId = target.threadId ?? currentThreadId();
|
|
6320
|
+
if (threadId === void 0)
|
|
6321
|
+
throw new Error("A proposal decision requires its thread scope");
|
|
6322
|
+
await requireBackendMethod(
|
|
6323
|
+
client,
|
|
6324
|
+
"rejectActionProposal"
|
|
6325
|
+
)({
|
|
6326
|
+
threadId,
|
|
6327
|
+
proposalId: target.proposalId,
|
|
6328
|
+
...reason === void 0 ? {} : { reason }
|
|
6329
|
+
});
|
|
6330
|
+
await proposals.refresh();
|
|
6331
|
+
return;
|
|
6332
|
+
}
|
|
5903
6333
|
await requireBackendMethod(
|
|
5904
6334
|
client,
|
|
5905
6335
|
"rejectToolCall"
|
|
@@ -5909,9 +6339,9 @@ function useAgentChat(options = {}) {
|
|
|
5909
6339
|
...via !== void 0 ? { via } : {}
|
|
5910
6340
|
});
|
|
5911
6341
|
},
|
|
5912
|
-
[client]
|
|
6342
|
+
[client, currentThreadId, proposals.refresh]
|
|
5913
6343
|
);
|
|
5914
|
-
const answer = (0,
|
|
6344
|
+
const answer = (0, import_react24.useCallback)(
|
|
5915
6345
|
async ({ toolCallId, answers, via }) => {
|
|
5916
6346
|
await requireBackendMethod(
|
|
5917
6347
|
client,
|
|
@@ -5924,7 +6354,7 @@ function useAgentChat(options = {}) {
|
|
|
5924
6354
|
},
|
|
5925
6355
|
[client]
|
|
5926
6356
|
);
|
|
5927
|
-
const skip = (0,
|
|
6357
|
+
const skip = (0, import_react24.useCallback)(
|
|
5928
6358
|
async ({ toolCallId, via }) => {
|
|
5929
6359
|
await requireBackendMethod(
|
|
5930
6360
|
client,
|
|
@@ -5933,7 +6363,7 @@ function useAgentChat(options = {}) {
|
|
|
5933
6363
|
},
|
|
5934
6364
|
[client]
|
|
5935
6365
|
);
|
|
5936
|
-
const regenerate = (0,
|
|
6366
|
+
const regenerate = (0, import_react24.useCallback)(
|
|
5937
6367
|
(_input) => {
|
|
5938
6368
|
const block = blockedRef.current;
|
|
5939
6369
|
if (block != null) throw new QuotaBlockedError(block);
|
|
@@ -5946,7 +6376,7 @@ function useAgentChat(options = {}) {
|
|
|
5946
6376
|
},
|
|
5947
6377
|
[isTurnInFlight]
|
|
5948
6378
|
);
|
|
5949
|
-
const storedIdOf = (0,
|
|
6379
|
+
const storedIdOf = (0, import_react24.useCallback)(
|
|
5950
6380
|
async (messageId, threadId) => {
|
|
5951
6381
|
const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);
|
|
5952
6382
|
const runOf = message?.metadata?.runId;
|
|
@@ -5957,7 +6387,7 @@ function useAgentChat(options = {}) {
|
|
|
5957
6387
|
},
|
|
5958
6388
|
[client]
|
|
5959
6389
|
);
|
|
5960
|
-
const fork = (0,
|
|
6390
|
+
const fork = (0, import_react24.useCallback)(
|
|
5961
6391
|
async ({
|
|
5962
6392
|
messageId,
|
|
5963
6393
|
threadId
|
|
@@ -5972,7 +6402,7 @@ function useAgentChat(options = {}) {
|
|
|
5972
6402
|
},
|
|
5973
6403
|
[client, currentThreadId, storedIdOf]
|
|
5974
6404
|
);
|
|
5975
|
-
const truncateFrom = (0,
|
|
6405
|
+
const truncateFrom = (0, import_react24.useCallback)(
|
|
5976
6406
|
async ({ messageId, threadId }) => {
|
|
5977
6407
|
const target = threadId ?? currentThreadId();
|
|
5978
6408
|
if (target === void 0) throw new Error("truncateFrom: this chat has no thread yet");
|
|
@@ -5981,7 +6411,7 @@ function useAgentChat(options = {}) {
|
|
|
5981
6411
|
},
|
|
5982
6412
|
[client, currentThreadId, storedIdOf]
|
|
5983
6413
|
);
|
|
5984
|
-
const promote = (0,
|
|
6414
|
+
const promote = (0, import_react24.useCallback)(
|
|
5985
6415
|
async ({ threadId } = {}) => {
|
|
5986
6416
|
const target = threadId ?? currentThreadId();
|
|
5987
6417
|
if (target === void 0) throw new Error("promote: this chat has no thread yet");
|
|
@@ -5990,24 +6420,24 @@ function useAgentChat(options = {}) {
|
|
|
5990
6420
|
},
|
|
5991
6421
|
[client, currentThreadId]
|
|
5992
6422
|
);
|
|
5993
|
-
const [modelsWanted, setModelsWanted] = (0,
|
|
5994
|
-
const modelsWantedRef = (0,
|
|
6423
|
+
const [modelsWanted, setModelsWanted] = (0, import_react24.useState)(false);
|
|
6424
|
+
const modelsWantedRef = (0, import_react24.useRef)(modelsWanted);
|
|
5995
6425
|
modelsWantedRef.current = modelsWanted;
|
|
5996
6426
|
const catalog = useModels({
|
|
5997
6427
|
backend: client,
|
|
5998
6428
|
...options.agent !== void 0 ? { agent: options.agent } : {},
|
|
5999
6429
|
enabled: modelsWanted && typeof client.listModels === "function"
|
|
6000
6430
|
});
|
|
6001
|
-
const wantModels = (0,
|
|
6431
|
+
const wantModels = (0, import_react24.useCallback)(() => {
|
|
6002
6432
|
if (modelsWantedRef.current) return;
|
|
6003
6433
|
modelsWantedRef.current = true;
|
|
6004
6434
|
queueMicrotask(() => setModelsWanted(true));
|
|
6005
6435
|
}, []);
|
|
6006
6436
|
lockedRef.current = catalog.locked !== null;
|
|
6007
|
-
const selectModel = (0,
|
|
6437
|
+
const selectModel = (0, import_react24.useCallback)((id) => {
|
|
6008
6438
|
if (!lockedRef.current) setPickedModel(id);
|
|
6009
6439
|
}, []);
|
|
6010
|
-
const pinToThread = (0,
|
|
6440
|
+
const pinToThread = (0, import_react24.useCallback)(
|
|
6011
6441
|
async (model) => {
|
|
6012
6442
|
const threadId = currentThreadId();
|
|
6013
6443
|
setThreadModel(model);
|
|
@@ -6047,14 +6477,14 @@ function useAgentChat(options = {}) {
|
|
|
6047
6477
|
};
|
|
6048
6478
|
const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
|
|
6049
6479
|
const isBusy = status === "submitted" || status === "streaming" || status === "reconnecting";
|
|
6050
|
-
const isBusyRef = (0,
|
|
6480
|
+
const isBusyRef = (0, import_react24.useRef)(isBusy);
|
|
6051
6481
|
isBusyRef.current = isBusy;
|
|
6052
6482
|
const files = useAttachments({ ...options.composer, backend: client });
|
|
6053
|
-
const [text, setText] = (0,
|
|
6483
|
+
const [text, setText] = (0, import_react24.useState)("");
|
|
6054
6484
|
const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy && whileRunning === "block" ? "busy" : text.trim().length === 0 && files.refs.length === 0 ? "empty" : null;
|
|
6055
|
-
const composerRef = (0,
|
|
6485
|
+
const composerRef = (0, import_react24.useRef)({ text, files, blockedBy });
|
|
6056
6486
|
composerRef.current = { text, files, blockedBy };
|
|
6057
|
-
const submit = (0,
|
|
6487
|
+
const submit = (0, import_react24.useCallback)(
|
|
6058
6488
|
async (options2) => {
|
|
6059
6489
|
const current = composerRef.current;
|
|
6060
6490
|
const asked = canQueueRef.current ? options2?.mode : void 0;
|
|
@@ -6136,6 +6566,7 @@ function useAgentChat(options = {}) {
|
|
|
6136
6566
|
addToolResult,
|
|
6137
6567
|
/** Sub-agents this conversation started and did not wait for. */
|
|
6138
6568
|
background,
|
|
6569
|
+
proposals,
|
|
6139
6570
|
runId,
|
|
6140
6571
|
/** The loaded thread's running turn, or `null` once read with none. */
|
|
6141
6572
|
activeRunId,
|
|
@@ -6260,8 +6691,10 @@ function isRunNotActiveError(error) {
|
|
|
6260
6691
|
onThreadsEvent,
|
|
6261
6692
|
persistSpeechLang,
|
|
6262
6693
|
phraseFor,
|
|
6694
|
+
proposalNeedsPolling,
|
|
6263
6695
|
readPath,
|
|
6264
6696
|
readReasoningMs,
|
|
6697
|
+
reconcileProposalMessages,
|
|
6265
6698
|
reframeAgUiStream,
|
|
6266
6699
|
requireBackendMethod,
|
|
6267
6700
|
resolveResultView,
|
|
@@ -6269,6 +6702,7 @@ function isRunNotActiveError(error) {
|
|
|
6269
6702
|
storedThreadToUiMessages,
|
|
6270
6703
|
toolCallState,
|
|
6271
6704
|
toolCatalogFrom,
|
|
6705
|
+
useActionProposals,
|
|
6272
6706
|
useAgentBackend,
|
|
6273
6707
|
useAgentChat,
|
|
6274
6708
|
useAgentConfig,
|