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