@dudousxd/nestjs-agent-react 0.31.5 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{client-BuobfZtx.d.cts → client-B6EE8-AC.d.cts} +39 -2
- package/dist/{client-BuobfZtx.d.ts → client-B6EE8-AC.d.ts} +39 -2
- package/dist/{generative-ui-VTZ1EADD.d.cts → generative-ui-DOe2RsoO.d.cts} +35 -9
- package/dist/{generative-ui-VTZ1EADD.d.ts → generative-ui-DOe2RsoO.d.ts} +35 -9
- package/dist/genui-json-render.cjs +51 -8
- package/dist/genui-json-render.cjs.map +1 -1
- package/dist/genui-json-render.d.cts +1 -1
- package/dist/genui-json-render.d.ts +1 -1
- package/dist/genui-json-render.js +51 -8
- package/dist/genui-json-render.js.map +1 -1
- package/dist/genui.cjs +51 -8
- package/dist/genui.cjs.map +1 -1
- package/dist/genui.d.cts +2 -2
- package/dist/genui.d.ts +2 -2
- package/dist/genui.js +51 -8
- package/dist/genui.js.map +1 -1
- package/dist/index.cjs +581 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -12
- package/dist/index.d.ts +56 -12
- package/dist/index.js +625 -171
- package/dist/index.js.map +1 -1
- package/dist/media.cjs.map +1 -1
- package/dist/media.d.cts +1 -1
- package/dist/media.d.ts +1 -1
- package/dist/media.js.map +1 -1
- package/package.json +2 -2
package/dist/index.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) {
|
|
@@ -639,6 +700,7 @@ var AgentChatTransport = class {
|
|
|
639
700
|
const message = lastMessage ? extractText(lastMessage) : "";
|
|
640
701
|
const body = {
|
|
641
702
|
...this.options.agent !== void 0 ? { agent: this.options.agent } : {},
|
|
703
|
+
...this.options.persona !== void 0 ? { persona: this.options.persona } : {},
|
|
642
704
|
...this.options.getBody?.() ?? {},
|
|
643
705
|
...options.body ?? {},
|
|
644
706
|
message
|
|
@@ -654,6 +716,10 @@ var AgentChatTransport = class {
|
|
|
654
716
|
return queuedChunkStream(response.queued);
|
|
655
717
|
}
|
|
656
718
|
this.captureHeaderMeta(response);
|
|
719
|
+
if (response.proposalDecision !== void 0) {
|
|
720
|
+
this.attemptLive = false;
|
|
721
|
+
return proposalDecisionChunkStream(response.proposalDecision);
|
|
722
|
+
}
|
|
657
723
|
return this.toChunkStream(response, {
|
|
658
724
|
...headers !== void 0 ? { headers } : {},
|
|
659
725
|
...options.abortSignal ? { signal: options.abortSignal } : {}
|
|
@@ -780,7 +846,7 @@ var AgentChatTransport = class {
|
|
|
780
846
|
let reasoningSeq = 0;
|
|
781
847
|
const announced = /* @__PURE__ */ new Set();
|
|
782
848
|
const toolMetadata = /* @__PURE__ */ new Map();
|
|
783
|
-
const
|
|
849
|
+
const record2 = (meta) => {
|
|
784
850
|
streamRunId = meta.runId;
|
|
785
851
|
this.recordMeta(meta);
|
|
786
852
|
};
|
|
@@ -1068,7 +1134,7 @@ var AgentChatTransport = class {
|
|
|
1068
1134
|
}
|
|
1069
1135
|
if (frame.event === "meta") {
|
|
1070
1136
|
const meta = parseMeta(frame.data);
|
|
1071
|
-
if (meta)
|
|
1137
|
+
if (meta) record2(meta);
|
|
1072
1138
|
} else if (frame.data) {
|
|
1073
1139
|
const event = parseEvent(frame.data);
|
|
1074
1140
|
if (event) emit(event);
|
|
@@ -1136,10 +1202,10 @@ function parseErrorFrame(data) {
|
|
|
1136
1202
|
try {
|
|
1137
1203
|
const parsed = JSON.parse(data);
|
|
1138
1204
|
if (parsed !== null && typeof parsed === "object") {
|
|
1139
|
-
const
|
|
1205
|
+
const record2 = parsed;
|
|
1140
1206
|
return {
|
|
1141
|
-
code: typeof
|
|
1142
|
-
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
|
|
1143
1209
|
};
|
|
1144
1210
|
}
|
|
1145
1211
|
} catch {
|
|
@@ -1179,6 +1245,21 @@ function delay(ms, signal) {
|
|
|
1179
1245
|
signal?.addEventListener("abort", done, { once: true });
|
|
1180
1246
|
});
|
|
1181
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
|
+
}
|
|
1182
1263
|
|
|
1183
1264
|
// src/attachments/files.ts
|
|
1184
1265
|
function fileKind(mediaType) {
|
|
@@ -1311,6 +1392,10 @@ function toGenerativeUIItem(part) {
|
|
|
1311
1392
|
return {
|
|
1312
1393
|
id,
|
|
1313
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 } : {},
|
|
1314
1399
|
props: isRecord(source.props) ? source.props : {},
|
|
1315
1400
|
version: typeof source.version === "number" ? source.version : null,
|
|
1316
1401
|
toolCallId: typeof source.toolCallId === "string" ? source.toolCallId : null
|
|
@@ -1416,20 +1501,29 @@ function useValidatedProps(catalog, name, props) {
|
|
|
1416
1501
|
function useGenerativeUIState(part, options, fallbackTree) {
|
|
1417
1502
|
const item = (0, import_react3.useMemo)(() => toGenerativeUIItem(part), [part]);
|
|
1418
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);
|
|
1419
1506
|
const resolution = useResolvedComponent(
|
|
1420
1507
|
name,
|
|
1421
1508
|
item?.version ?? null,
|
|
1422
|
-
options.registry,
|
|
1509
|
+
incompatible ? {} : options.registry,
|
|
1423
1510
|
item === null ? void 0 : options.resolveComponent,
|
|
1424
1511
|
fallbackTree
|
|
1425
1512
|
);
|
|
1426
1513
|
const empty = (0, import_react3.useMemo)(() => ({}), []);
|
|
1427
1514
|
const validation = useValidatedProps(
|
|
1428
|
-
item === null || name === GENUI_TREE_COMPONENT ? void 0 : options.catalog,
|
|
1515
|
+
item === null || name === GENUI_TREE_COMPONENT || incompatible ? void 0 : options.catalog,
|
|
1429
1516
|
name,
|
|
1430
1517
|
item?.props ?? empty
|
|
1431
1518
|
);
|
|
1432
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
|
+
};
|
|
1433
1527
|
if (resolution.status === "loading") return { status: "loading", item };
|
|
1434
1528
|
if (resolution.status === "unknown") return { status: "problem", reason: "unknown", item };
|
|
1435
1529
|
if (resolution.status === "error") {
|
|
@@ -1447,7 +1541,8 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
1447
1541
|
var TreeScopeContext = (0, import_react4.createContext)(null);
|
|
1448
1542
|
function renderFallback(fallback2, problem) {
|
|
1449
1543
|
if (typeof fallback2 === "function") return fallback2(problem);
|
|
1450
|
-
|
|
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;
|
|
1451
1546
|
}
|
|
1452
1547
|
var ItemBoundary = class extends import_react4.Component {
|
|
1453
1548
|
state = { error: void 0, failed: false };
|
|
@@ -1479,28 +1574,42 @@ function nodeItem(node, id) {
|
|
|
1479
1574
|
function TreeNode({ node, id }) {
|
|
1480
1575
|
const scope = (0, import_react4.useContext)(TreeScopeContext);
|
|
1481
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);
|
|
1482
1580
|
const resolution = useResolvedComponent(
|
|
1483
1581
|
node.type,
|
|
1484
|
-
null,
|
|
1485
|
-
scope?.options.registry ?? {},
|
|
1582
|
+
storedVersion ?? null,
|
|
1583
|
+
incompatible ? {} : scope?.options.registry ?? {},
|
|
1486
1584
|
scope?.options.resolveComponent
|
|
1487
1585
|
);
|
|
1488
|
-
const validation = useValidatedProps(
|
|
1586
|
+
const validation = useValidatedProps(
|
|
1587
|
+
incompatible ? void 0 : scope?.options.catalog,
|
|
1588
|
+
node.type,
|
|
1589
|
+
item.props
|
|
1590
|
+
);
|
|
1489
1591
|
if (scope === null) return null;
|
|
1490
1592
|
if (resolution.status === "loading" || validation.status === "pending") return scope.loading;
|
|
1491
1593
|
if (resolution.status === "unknown") {
|
|
1594
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1595
|
+
throw new Error("Unknown tree component");
|
|
1492
1596
|
return renderFallback(scope.fallback, { reason: "unknown", item });
|
|
1493
1597
|
}
|
|
1494
1598
|
if (resolution.status === "error") {
|
|
1599
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0) throw resolution.error;
|
|
1495
1600
|
return renderFallback(scope.fallback, { reason: "error", item, error: resolution.error });
|
|
1496
1601
|
}
|
|
1497
1602
|
if (validation.status === "invalid") {
|
|
1603
|
+
if (scope.fallback === void 0 && scope.fallbackText !== void 0)
|
|
1604
|
+
throw new Error("Invalid tree component");
|
|
1498
1605
|
return renderFallback(scope.fallback, { reason: "invalid", item, issues: validation.issues });
|
|
1499
1606
|
}
|
|
1500
1607
|
const Renderer = resolution.Component;
|
|
1501
1608
|
const children = Array.isArray(node.children) ? node.children : [];
|
|
1502
1609
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Renderer, { ...validation.props, children: children.length > 0 ? children.map((child, index) => {
|
|
1503
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);
|
|
1504
1613
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1505
1614
|
ItemBoundary,
|
|
1506
1615
|
{
|
|
@@ -1522,6 +1631,8 @@ function GenerativeUIScope({
|
|
|
1522
1631
|
catalog,
|
|
1523
1632
|
resolveComponent,
|
|
1524
1633
|
fallback: fallback2,
|
|
1634
|
+
fallbackText,
|
|
1635
|
+
componentVersions,
|
|
1525
1636
|
loading = null,
|
|
1526
1637
|
onError,
|
|
1527
1638
|
children
|
|
@@ -1534,10 +1645,21 @@ function GenerativeUIScope({
|
|
|
1534
1645
|
...resolveComponent !== void 0 ? { resolveComponent } : {}
|
|
1535
1646
|
},
|
|
1536
1647
|
fallback: fallback2,
|
|
1648
|
+
...componentVersions !== void 0 ? { componentVersions } : {},
|
|
1649
|
+
...fallbackText !== void 0 ? { fallbackText } : {},
|
|
1537
1650
|
loading,
|
|
1538
1651
|
onError
|
|
1539
1652
|
}),
|
|
1540
|
-
[
|
|
1653
|
+
[
|
|
1654
|
+
registry,
|
|
1655
|
+
catalog,
|
|
1656
|
+
resolveComponent,
|
|
1657
|
+
fallback2,
|
|
1658
|
+
fallbackText,
|
|
1659
|
+
componentVersions,
|
|
1660
|
+
loading,
|
|
1661
|
+
onError
|
|
1662
|
+
]
|
|
1541
1663
|
);
|
|
1542
1664
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TreeScopeContext.Provider, { value: scope, children });
|
|
1543
1665
|
}
|
|
@@ -1597,7 +1719,7 @@ function GenerativeUI({
|
|
|
1597
1719
|
onError: ownOnError
|
|
1598
1720
|
}) {
|
|
1599
1721
|
const provided = (0, import_react4.useContext)(GenuiContext);
|
|
1600
|
-
const fallback2 = ownFallback
|
|
1722
|
+
const fallback2 = ownFallback !== void 0 ? ownFallback : provided?.fallback;
|
|
1601
1723
|
const loading = ownLoading ?? provided?.loading ?? null;
|
|
1602
1724
|
const onError = ownOnError ?? provided?.onError;
|
|
1603
1725
|
const options = useMergedOptions({
|
|
@@ -1622,6 +1744,8 @@ function GenerativeUI({
|
|
|
1622
1744
|
GenerativeUIScope,
|
|
1623
1745
|
{
|
|
1624
1746
|
...options,
|
|
1747
|
+
...state.item.componentVersions !== void 0 ? { componentVersions: state.item.componentVersions } : {},
|
|
1748
|
+
...state.item.fallbackText !== void 0 ? { fallbackText: state.item.fallbackText } : {},
|
|
1625
1749
|
fallback: fallback2,
|
|
1626
1750
|
loading,
|
|
1627
1751
|
...onError !== void 0 ? { onError } : {},
|
|
@@ -1637,6 +1761,7 @@ var AgentBackendContext = sharedContext(
|
|
|
1637
1761
|
);
|
|
1638
1762
|
function AgentProvider({
|
|
1639
1763
|
backend,
|
|
1764
|
+
uiCapabilities,
|
|
1640
1765
|
baseUrl,
|
|
1641
1766
|
path,
|
|
1642
1767
|
headers,
|
|
@@ -1668,7 +1793,7 @@ function AgentProvider({
|
|
|
1668
1793
|
[backend, baseUrl, path, credentials, fetch, upload]
|
|
1669
1794
|
);
|
|
1670
1795
|
const content = genui !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GenuiProvider, { ...genui, children }) : children;
|
|
1671
|
-
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 }) });
|
|
1672
1797
|
}
|
|
1673
1798
|
var fallback;
|
|
1674
1799
|
function defaultBackend() {
|
|
@@ -1679,6 +1804,12 @@ function useAgentBackend(own) {
|
|
|
1679
1804
|
const provided = (0, import_react5.useContext)(AgentBackendContext);
|
|
1680
1805
|
return own ?? provided ?? defaultBackend();
|
|
1681
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
|
+
}
|
|
1682
1813
|
|
|
1683
1814
|
// src/config/use-agent-config.ts
|
|
1684
1815
|
var shared = /* @__PURE__ */ new WeakMap();
|
|
@@ -1944,7 +2075,7 @@ async function defaultRefusal(response) {
|
|
|
1944
2075
|
}
|
|
1945
2076
|
function defaultForwardedProps(body) {
|
|
1946
2077
|
const out = {};
|
|
1947
|
-
for (const key of ["pageContext", "agent", "model"]) {
|
|
2078
|
+
for (const key of ["pageContext", "agent", "model", "persona", "uiCapabilities"]) {
|
|
1948
2079
|
if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
|
|
1949
2080
|
}
|
|
1950
2081
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
@@ -2303,16 +2434,24 @@ function useAgents(options = {}) {
|
|
|
2303
2434
|
"",
|
|
2304
2435
|
enabled
|
|
2305
2436
|
);
|
|
2437
|
+
const find = (0, import_react9.useCallback)(
|
|
2438
|
+
(name) => (data ?? []).find(
|
|
2439
|
+
(agent) => name === void 0 ? agent.isDefault === true : agent.name === name
|
|
2440
|
+
),
|
|
2441
|
+
[data]
|
|
2442
|
+
);
|
|
2306
2443
|
return (0, import_react9.useMemo)(() => {
|
|
2307
2444
|
const agents = data ?? [];
|
|
2308
2445
|
return {
|
|
2309
2446
|
agents,
|
|
2310
2447
|
defaultAgent: agents.find((agent) => agent.isDefault === true)?.name ?? null,
|
|
2448
|
+
personasOf: (agent) => find(agent)?.personas ?? [],
|
|
2449
|
+
defaultPersonaOf: (agent) => find(agent)?.defaultPersona ?? null,
|
|
2311
2450
|
isLoading,
|
|
2312
2451
|
error,
|
|
2313
2452
|
refresh
|
|
2314
2453
|
};
|
|
2315
|
-
}, [data, isLoading, error, refresh]);
|
|
2454
|
+
}, [data, find, isLoading, error, refresh]);
|
|
2316
2455
|
}
|
|
2317
2456
|
|
|
2318
2457
|
// src/catalog/use-models.ts
|
|
@@ -2970,6 +3109,15 @@ function isActionCall(part) {
|
|
|
2970
3109
|
}
|
|
2971
3110
|
function toolCallState(part) {
|
|
2972
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
|
+
};
|
|
2973
3121
|
const errorText = "errorText" in part ? part.errorText : void 0;
|
|
2974
3122
|
const outputError = output !== null && typeof output === "object" && "error" in output ? String(output.error) : void 0;
|
|
2975
3123
|
const isDenied = part.state === "output-denied";
|
|
@@ -3014,7 +3162,11 @@ function describeToolCall(part, catalog, options = {}) {
|
|
|
3014
3162
|
icon: presentation?.icon ?? null,
|
|
3015
3163
|
tone: presentation?.tone ?? "neutral",
|
|
3016
3164
|
detail: presentation?.detail ?? null,
|
|
3017
|
-
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 : {
|
|
3018
3170
|
title: fillTemplate(confirm.title, input),
|
|
3019
3171
|
verb: confirm.verb,
|
|
3020
3172
|
detail: confirm.detail !== void 0 ? fillTemplate(confirm.detail, input) : null
|
|
@@ -3028,6 +3180,9 @@ function describeToolCall(part, catalog, options = {}) {
|
|
|
3028
3180
|
}
|
|
3029
3181
|
var STATUS_WEIGHT = {
|
|
3030
3182
|
running: 4,
|
|
3183
|
+
queued: 4,
|
|
3184
|
+
executing: 4,
|
|
3185
|
+
succeeded: 0,
|
|
3031
3186
|
"awaiting-approval": 3,
|
|
3032
3187
|
failed: 2,
|
|
3033
3188
|
denied: 1,
|
|
@@ -3047,7 +3202,7 @@ function groupToolActivity(calls, options = {}) {
|
|
|
3047
3202
|
if (corrected.has(call.toolCallId)) continue;
|
|
3048
3203
|
const presentation = options.catalog?.[call.name];
|
|
3049
3204
|
const key = options.keyOf?.(call, presentation) ?? presentation?.label ?? call.name;
|
|
3050
|
-
const status =
|
|
3205
|
+
const status = call.description.status;
|
|
3051
3206
|
const phrase = phraseFor(
|
|
3052
3207
|
presentation,
|
|
3053
3208
|
call.part.input,
|
|
@@ -3289,7 +3444,7 @@ function isAncestor(call, candidate, byId) {
|
|
|
3289
3444
|
}
|
|
3290
3445
|
function buildToolCall(part, options, approval, catalog) {
|
|
3291
3446
|
const toolCallId = part.toolCallId;
|
|
3292
|
-
const awaiting = isAwaitingApproval(part);
|
|
3447
|
+
const awaiting = approval?.target?.kind === "proposal" ? approval.status === "pending" : isAwaitingApproval(part);
|
|
3293
3448
|
const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
|
|
3294
3449
|
return {
|
|
3295
3450
|
part,
|
|
@@ -3299,19 +3454,30 @@ function buildToolCall(part, options, approval, catalog) {
|
|
|
3299
3454
|
parentId: toolParentId(part),
|
|
3300
3455
|
children: [],
|
|
3301
3456
|
approval,
|
|
3302
|
-
description:
|
|
3457
|
+
description: proposalDescription(
|
|
3458
|
+
describeToolCall(
|
|
3459
|
+
part,
|
|
3460
|
+
catalog,
|
|
3461
|
+
approval?.confirmation === void 0 ? {} : { confirmation: approval.confirmation }
|
|
3462
|
+
),
|
|
3463
|
+
approval
|
|
3464
|
+
),
|
|
3303
3465
|
isAwaitingApproval: awaiting,
|
|
3304
3466
|
approve: {
|
|
3305
3467
|
available: awaiting && options?.canApprove === true,
|
|
3306
3468
|
isSubmitting: sending === "approve",
|
|
3307
3469
|
// Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,
|
|
3308
3470
|
// and a host's handler must not receive that as its options.
|
|
3309
|
-
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
|
+
)
|
|
3310
3476
|
},
|
|
3311
3477
|
reject: {
|
|
3312
3478
|
available: awaiting && options?.canReject === true,
|
|
3313
3479
|
isSubmitting: sending === "reject",
|
|
3314
|
-
run: () => options?.reject(toolCallId)
|
|
3480
|
+
run: () => approval?.target === void 0 ? options?.reject(toolCallId) : options?.reject(toolCallId, approval.target)
|
|
3315
3481
|
},
|
|
3316
3482
|
error: options?.errorOf(toolCallId) ?? null,
|
|
3317
3483
|
errorCode: options?.errorCodeOf?.(toolCallId) ?? null
|
|
@@ -3461,7 +3627,7 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
3461
3627
|
var UI_PART = "data-ui";
|
|
3462
3628
|
var APPROVAL_PART = "data-approval-requested";
|
|
3463
3629
|
var SETTLED_PART = "data-approval-settled";
|
|
3464
|
-
var SETTLED_STATUSES = ["approved", "rejected", "expired"];
|
|
3630
|
+
var SETTLED_STATUSES = ["approved", "rejected", "expired", "superseded"];
|
|
3465
3631
|
function readApprovals(parts) {
|
|
3466
3632
|
const out = /* @__PURE__ */ new Map();
|
|
3467
3633
|
const entry = (id) => {
|
|
@@ -3482,7 +3648,7 @@ function readApprovals(parts) {
|
|
|
3482
3648
|
return found;
|
|
3483
3649
|
};
|
|
3484
3650
|
for (const part of parts) {
|
|
3485
|
-
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART) {
|
|
3651
|
+
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART && part.type !== "data-action-proposal") {
|
|
3486
3652
|
continue;
|
|
3487
3653
|
}
|
|
3488
3654
|
const data = part.data;
|
|
@@ -3490,12 +3656,35 @@ function readApprovals(parts) {
|
|
|
3490
3656
|
continue;
|
|
3491
3657
|
}
|
|
3492
3658
|
const approval = entry(data.id);
|
|
3493
|
-
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
|
+
}
|
|
3494
3676
|
if (typeof data.approver !== "string") {
|
|
3495
3677
|
continue;
|
|
3496
3678
|
}
|
|
3497
3679
|
approval.approver = data.approver;
|
|
3498
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
|
+
}
|
|
3499
3688
|
approval.reason = typeof data.reason === "string" ? data.reason : null;
|
|
3500
3689
|
continue;
|
|
3501
3690
|
}
|
|
@@ -3519,9 +3708,12 @@ function approvalOf(parts, call) {
|
|
|
3519
3708
|
}
|
|
3520
3709
|
return {
|
|
3521
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 } : {},
|
|
3522
3714
|
expiresAt: parts.expiresAt,
|
|
3523
3715
|
reason: parts.reason,
|
|
3524
|
-
status: parts.status ?? statusFromPart(call),
|
|
3716
|
+
status: parts.status ?? (parts.target?.kind === "proposal" ? "pending" : statusFromPart(call)),
|
|
3525
3717
|
remember: parts.remember,
|
|
3526
3718
|
decidedBy: parts.decidedBy,
|
|
3527
3719
|
decidedVia: parts.decidedVia,
|
|
@@ -3551,6 +3743,10 @@ function readUiComponent(part) {
|
|
|
3551
3743
|
component: data.component,
|
|
3552
3744
|
props: isRecord4(data.props) ? data.props : {},
|
|
3553
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 } : {},
|
|
3554
3750
|
toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
|
|
3555
3751
|
};
|
|
3556
3752
|
}
|
|
@@ -3661,6 +3857,12 @@ function formatCostUsd(cost) {
|
|
|
3661
3857
|
}
|
|
3662
3858
|
return `$${cost.toFixed(2)}`;
|
|
3663
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
|
+
}
|
|
3664
3866
|
|
|
3665
3867
|
// src/transcript/use-stick-to-bottom.ts
|
|
3666
3868
|
var import_react16 = require("react");
|
|
@@ -3953,23 +4155,31 @@ function useTranscriptItems({
|
|
|
3953
4155
|
[settle]
|
|
3954
4156
|
);
|
|
3955
4157
|
const approve = (0, import_react17.useCallback)(
|
|
3956
|
-
(toolCallId, options2) => {
|
|
4158
|
+
(toolCallId, options2, target) => {
|
|
3957
4159
|
const onApprove = latest.current.handlers.onApprove;
|
|
3958
4160
|
if (onApprove) {
|
|
3959
4161
|
settle(
|
|
3960
4162
|
toolCallId,
|
|
3961
4163
|
"approve",
|
|
3962
|
-
() => onApprove({
|
|
4164
|
+
() => onApprove({
|
|
4165
|
+
toolCallId,
|
|
4166
|
+
...target === void 0 ? {} : { target },
|
|
4167
|
+
...options2?.remember === true ? { remember: true } : {}
|
|
4168
|
+
})
|
|
3963
4169
|
);
|
|
3964
4170
|
}
|
|
3965
4171
|
},
|
|
3966
4172
|
[settle]
|
|
3967
4173
|
);
|
|
3968
4174
|
const reject = (0, import_react17.useCallback)(
|
|
3969
|
-
(toolCallId) => {
|
|
4175
|
+
(toolCallId, target) => {
|
|
3970
4176
|
const onReject = latest.current.handlers.onReject;
|
|
3971
4177
|
if (onReject) {
|
|
3972
|
-
settle(
|
|
4178
|
+
settle(
|
|
4179
|
+
toolCallId,
|
|
4180
|
+
"reject",
|
|
4181
|
+
() => onReject({ toolCallId, ...target === void 0 ? {} : { target } })
|
|
4182
|
+
);
|
|
3973
4183
|
}
|
|
3974
4184
|
},
|
|
3975
4185
|
[settle]
|
|
@@ -4167,14 +4377,36 @@ function settleHandlers(options, backend) {
|
|
|
4167
4377
|
),
|
|
4168
4378
|
onApprove: pick(
|
|
4169
4379
|
options.onApprove,
|
|
4170
|
-
backend.approveToolCall ? async (input) => {
|
|
4171
|
-
|
|
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);
|
|
4172
4393
|
} : void 0
|
|
4173
4394
|
),
|
|
4174
4395
|
onReject: pick(
|
|
4175
4396
|
options.onReject,
|
|
4176
|
-
backend.rejectToolCall ? async (input) => {
|
|
4177
|
-
|
|
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);
|
|
4178
4410
|
} : void 0
|
|
4179
4411
|
)
|
|
4180
4412
|
};
|
|
@@ -5079,6 +5311,8 @@ function storedMessageToUiMessage(message) {
|
|
|
5079
5311
|
id: component.id,
|
|
5080
5312
|
component: component.component,
|
|
5081
5313
|
props: component.props,
|
|
5314
|
+
...component.componentVersions !== void 0 ? { componentVersions: component.componentVersions } : {},
|
|
5315
|
+
...component.fallbackText !== void 0 ? { fallbackText: component.fallbackText } : {},
|
|
5082
5316
|
...component.version !== void 0 ? { version: component.version } : {},
|
|
5083
5317
|
...component.toolCallId !== void 0 ? { toolCallId: component.toolCallId } : {}
|
|
5084
5318
|
}
|
|
@@ -5098,6 +5332,8 @@ function storedMessageToUiMessage(message) {
|
|
|
5098
5332
|
data: {
|
|
5099
5333
|
id: approval.toolCallId,
|
|
5100
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 } : {},
|
|
5101
5337
|
...approval.expiresAt !== void 0 ? { expiresAt: approval.expiresAt } : {}
|
|
5102
5338
|
}
|
|
5103
5339
|
});
|
|
@@ -5154,8 +5390,11 @@ function storedMessageToUiMessage(message) {
|
|
|
5154
5390
|
const metadata = {
|
|
5155
5391
|
// The host's own facts first: the library's keys win on a clash.
|
|
5156
5392
|
...message.metadata,
|
|
5393
|
+
...message.actionProposalOutcome === void 0 ? {} : { actionProposalOutcomeId: message.actionProposalOutcome.id },
|
|
5157
5394
|
...message.feedback !== void 0 ? { feedback: message.feedback } : {},
|
|
5158
5395
|
...message.createdAt ? { createdAt: message.createdAt } : {},
|
|
5396
|
+
...message.agentName !== void 0 ? { agentName: message.agentName } : {},
|
|
5397
|
+
...message.persona !== void 0 ? { persona: message.persona } : {},
|
|
5159
5398
|
...message.usage !== void 0 ? {
|
|
5160
5399
|
usage: {
|
|
5161
5400
|
inputTokens: message.usage.inputTokens,
|
|
@@ -5187,6 +5426,8 @@ function storedThreadToUiMessages(messages) {
|
|
|
5187
5426
|
return turns.map(mergeTurn);
|
|
5188
5427
|
}
|
|
5189
5428
|
function sameRun(previous, next) {
|
|
5429
|
+
if (previous.actionProposalOutcome !== void 0 || next.actionProposalOutcome !== void 0)
|
|
5430
|
+
return false;
|
|
5190
5431
|
return previous.runId === void 0 || next.runId === void 0 || previous.runId === next.runId;
|
|
5191
5432
|
}
|
|
5192
5433
|
function mergeTurn(rows) {
|
|
@@ -5206,7 +5447,9 @@ function mergeTurn(rows) {
|
|
|
5206
5447
|
...Object.assign({}, ...rows.map((row) => row.metadata ?? {})),
|
|
5207
5448
|
...usage !== void 0 ? { usage } : {},
|
|
5208
5449
|
...feedback !== void 0 ? { feedback } : {},
|
|
5209
|
-
...createdAt ? { createdAt } : {}
|
|
5450
|
+
...createdAt ? { createdAt } : {},
|
|
5451
|
+
...lastRow.agentName !== void 0 ? { agentName: lastRow.agentName } : {},
|
|
5452
|
+
...lastRow.persona !== void 0 ? { persona: lastRow.persona } : {}
|
|
5210
5453
|
};
|
|
5211
5454
|
return {
|
|
5212
5455
|
id: lastRow.id,
|
|
@@ -5231,8 +5474,163 @@ function sumUsage(rows) {
|
|
|
5231
5474
|
}
|
|
5232
5475
|
|
|
5233
5476
|
// src/use-agent-chat.ts
|
|
5234
|
-
var
|
|
5235
|
-
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
|
|
5236
5634
|
var EMPTY_QUEUE = { items: [], paused: null };
|
|
5237
5635
|
var localQueueSequence = 0;
|
|
5238
5636
|
function queuedUserMessage(turn) {
|
|
@@ -5287,13 +5685,16 @@ function localChatId() {
|
|
|
5287
5685
|
return `local-chat-${localChatSequence}`;
|
|
5288
5686
|
}
|
|
5289
5687
|
function useAgentChat(options = {}) {
|
|
5290
|
-
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);
|
|
5291
5692
|
latest.current = options;
|
|
5292
5693
|
const resolved = useAgentBackend(options.backend);
|
|
5293
|
-
const client = (0,
|
|
5294
|
-
const createdThreadId = (0,
|
|
5295
|
-
const chatIdRef = (0,
|
|
5296
|
-
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);
|
|
5297
5698
|
if (options.threadId !== boundThreadRef.current) {
|
|
5298
5699
|
boundThreadRef.current = options.threadId;
|
|
5299
5700
|
const adopting = options.threadId !== void 0 && options.threadId === createdThreadId.current;
|
|
@@ -5303,39 +5704,43 @@ function useAgentChat(options = {}) {
|
|
|
5303
5704
|
}
|
|
5304
5705
|
}
|
|
5305
5706
|
const chatId = chatIdRef.current;
|
|
5306
|
-
const [runId, setRunId] = (0,
|
|
5307
|
-
const runIdRef = (0,
|
|
5707
|
+
const [runId, setRunId] = (0, import_react24.useState)(options.resumeRunId);
|
|
5708
|
+
const runIdRef = (0, import_react24.useRef)(runId);
|
|
5308
5709
|
runIdRef.current = runId;
|
|
5309
|
-
const settlingRunIdRef = (0,
|
|
5310
|
-
const autoResumeRunIdRef = (0,
|
|
5311
|
-
const [activeRunId, setActiveRunId] = (0,
|
|
5312
|
-
const [historyFor, setHistoryFor] = (0,
|
|
5313
|
-
const [historyError, setHistoryError] = (0,
|
|
5314
|
-
const [runError, setRunError] = (0,
|
|
5315
|
-
const [threadModel, setThreadModel] = (0,
|
|
5316
|
-
const [
|
|
5317
|
-
const
|
|
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);
|
|
5318
5720
|
pickedModelRef.current = pickedModel;
|
|
5319
|
-
const lockedRef = (0,
|
|
5320
|
-
const pendingPin = (0,
|
|
5321
|
-
const regenerateNext = (0,
|
|
5322
|
-
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)(
|
|
5323
5725
|
() => latest.current.threadId ?? createdThreadId.current,
|
|
5324
5726
|
[]
|
|
5325
5727
|
);
|
|
5326
|
-
const [queueState, setQueueState] = (0,
|
|
5327
|
-
const queueStateRef = (0,
|
|
5328
|
-
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) => {
|
|
5329
5731
|
queueStateRef.current = next;
|
|
5330
5732
|
setQueueState(next);
|
|
5331
5733
|
}, []);
|
|
5332
|
-
const [pendingSends, setPendingSends] = (0,
|
|
5333
|
-
const [queueError, setQueueError] = (0,
|
|
5334
|
-
const handoff = (0,
|
|
5335
|
-
const queuedSend = (0,
|
|
5336
|
-
const
|
|
5337
|
-
|
|
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)(() => {
|
|
5338
5742
|
const current = latest.current;
|
|
5743
|
+
if (current.persona !== void 0) setThreadPersona(current.persona);
|
|
5339
5744
|
const pageContext = current.getPageContext?.() ?? null;
|
|
5340
5745
|
const threadId = currentThreadId();
|
|
5341
5746
|
const model = current.model ?? (lockedRef.current ? void 0 : pickedModelRef.current);
|
|
@@ -5343,14 +5748,16 @@ function useAgentChat(options = {}) {
|
|
|
5343
5748
|
// Read per send: a host that switches agents before the first message (a picker on a new
|
|
5344
5749
|
// chat) sends the one picked now, not the one this chat mounted with.
|
|
5345
5750
|
...current.agent !== void 0 ? { agent: current.agent } : {},
|
|
5751
|
+
...current.persona !== void 0 ? { persona: current.persona } : {},
|
|
5346
5752
|
...threadId !== void 0 ? { threadId } : {},
|
|
5347
5753
|
...model !== void 0 ? { model } : {},
|
|
5348
|
-
...pageContext ? { pageContext } : {}
|
|
5754
|
+
...pageContext ? { pageContext } : {},
|
|
5755
|
+
...(current.uiCapabilities ?? capabilitiesRef.current) === void 0 ? {} : { uiCapabilities: current.uiCapabilities ?? capabilitiesRef.current }
|
|
5349
5756
|
};
|
|
5350
5757
|
}, [currentThreadId]);
|
|
5351
|
-
const [connection, setConnection] = (0,
|
|
5352
|
-
const resyncAfterSettle = (0,
|
|
5353
|
-
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)(() => {
|
|
5354
5761
|
function onMeta(meta) {
|
|
5355
5762
|
settlingRunIdRef.current = meta.runId;
|
|
5356
5763
|
setRunId(meta.runId);
|
|
@@ -5402,14 +5809,15 @@ function useAgentChat(options = {}) {
|
|
|
5402
5809
|
}
|
|
5403
5810
|
});
|
|
5404
5811
|
}, []);
|
|
5405
|
-
const backgroundRef = (0,
|
|
5406
|
-
const chat = (0,
|
|
5812
|
+
const backgroundRef = (0, import_react24.useRef)(() => Promise.resolve());
|
|
5813
|
+
const chat = (0, import_react23.useChat)({
|
|
5407
5814
|
transport,
|
|
5408
5815
|
id: chatId,
|
|
5409
5816
|
resume: options.resumeRunId !== void 0,
|
|
5410
5817
|
...options.initialMessages !== void 0 ? { messages: options.initialMessages } : {},
|
|
5411
5818
|
onData: (part) => {
|
|
5412
5819
|
latest.current.onData?.(part);
|
|
5820
|
+
if (part.type === "data-proposal-decision") void proposalRefreshRef.current();
|
|
5413
5821
|
if (part.type === "data-queue") {
|
|
5414
5822
|
onQueueData(part.data);
|
|
5415
5823
|
}
|
|
@@ -5456,7 +5864,7 @@ function useAgentChat(options = {}) {
|
|
|
5456
5864
|
}
|
|
5457
5865
|
}
|
|
5458
5866
|
});
|
|
5459
|
-
const chatRef = (0,
|
|
5867
|
+
const chatRef = (0, import_react24.useRef)(chat);
|
|
5460
5868
|
chatRef.current = chat;
|
|
5461
5869
|
function onQueueData(data) {
|
|
5462
5870
|
const frame = data ?? {};
|
|
@@ -5504,13 +5912,14 @@ function useAgentChat(options = {}) {
|
|
|
5504
5912
|
} catch {
|
|
5505
5913
|
}
|
|
5506
5914
|
}
|
|
5507
|
-
const firstChatId = (0,
|
|
5508
|
-
(0,
|
|
5915
|
+
const firstChatId = (0, import_react24.useRef)(chatId);
|
|
5916
|
+
(0, import_react24.useEffect)(() => {
|
|
5509
5917
|
if (chatId === firstChatId.current) return;
|
|
5510
5918
|
firstChatId.current = chatId;
|
|
5511
5919
|
setRunId(void 0);
|
|
5512
5920
|
setActiveRunId(null);
|
|
5513
5921
|
setThreadModel(null);
|
|
5922
|
+
setThreadPersona(null);
|
|
5514
5923
|
setPickedModel(void 0);
|
|
5515
5924
|
setBackgroundRuns([]);
|
|
5516
5925
|
setHistoryError(null);
|
|
@@ -5523,7 +5932,7 @@ function useAgentChat(options = {}) {
|
|
|
5523
5932
|
handoff.current = void 0;
|
|
5524
5933
|
queuedSend.current = void 0;
|
|
5525
5934
|
}, [chatId]);
|
|
5526
|
-
(0,
|
|
5935
|
+
(0, import_react24.useEffect)(() => {
|
|
5527
5936
|
const threadId = options.threadId;
|
|
5528
5937
|
if (threadId === void 0) return;
|
|
5529
5938
|
if (threadId === createdThreadId.current) return;
|
|
@@ -5539,6 +5948,7 @@ function useAgentChat(options = {}) {
|
|
|
5539
5948
|
const stored = Array.isArray(thread.messages) ? thread.messages : [];
|
|
5540
5949
|
setActiveRunId(active);
|
|
5541
5950
|
setThreadModel(thread.model ?? null);
|
|
5951
|
+
setThreadPersona(thread.persona ?? null);
|
|
5542
5952
|
setHistoryError(null);
|
|
5543
5953
|
const queue2 = thread.queue ?? EMPTY_QUEUE;
|
|
5544
5954
|
applyQueue(queue2);
|
|
@@ -5569,8 +5979,8 @@ function useAgentChat(options = {}) {
|
|
|
5569
5979
|
};
|
|
5570
5980
|
}, [client, chatId, options.threadId]);
|
|
5571
5981
|
const isLoadingHistory = options.threadId !== void 0 && options.threadId !== createdThreadId.current && options.history !== false && options.initialMessages === void 0 && historyFor !== options.threadId;
|
|
5572
|
-
const turnInFlight = (0,
|
|
5573
|
-
const isTurnInFlight = (0,
|
|
5982
|
+
const turnInFlight = (0, import_react24.useRef)(false);
|
|
5983
|
+
const isTurnInFlight = (0, import_react24.useCallback)(
|
|
5574
5984
|
() => turnInFlight.current || transport.isAttemptLive,
|
|
5575
5985
|
[transport]
|
|
5576
5986
|
);
|
|
@@ -5579,20 +5989,20 @@ function useAgentChat(options = {}) {
|
|
|
5579
5989
|
enabled: options.quota !== false && typeof client.getQuota === "function"
|
|
5580
5990
|
});
|
|
5581
5991
|
const blocked = options.blocked !== void 0 ? options.blocked : quota.blocked;
|
|
5582
|
-
const blockedRef = (0,
|
|
5992
|
+
const blockedRef = (0, import_react24.useRef)(blocked);
|
|
5583
5993
|
blockedRef.current = blocked;
|
|
5584
5994
|
const whileRunning = typeof client.enqueueMessage === "function" ? options.whileRunning ?? "queue" : "block";
|
|
5585
|
-
const whileRunningRef = (0,
|
|
5995
|
+
const whileRunningRef = (0, import_react24.useRef)(whileRunning);
|
|
5586
5996
|
whileRunningRef.current = whileRunning;
|
|
5587
|
-
const canQueueRef = (0,
|
|
5997
|
+
const canQueueRef = (0, import_react24.useRef)(false);
|
|
5588
5998
|
canQueueRef.current = typeof client.enqueueMessage === "function";
|
|
5589
|
-
const threadForQueue = (0,
|
|
5999
|
+
const threadForQueue = (0, import_react24.useCallback)(async () => {
|
|
5590
6000
|
const known = currentThreadId();
|
|
5591
6001
|
if (known !== void 0) return known;
|
|
5592
6002
|
if (!isTurnInFlight()) throw new Error("queue: this chat has no thread yet");
|
|
5593
6003
|
return new Promise((resolve) => threadWaiters.current.push(resolve));
|
|
5594
6004
|
}, [currentThreadId, isTurnInFlight]);
|
|
5595
|
-
const queueCall = (0,
|
|
6005
|
+
const queueCall = (0, import_react24.useCallback)(async (run) => {
|
|
5596
6006
|
try {
|
|
5597
6007
|
const result = await run();
|
|
5598
6008
|
setQueueError(null);
|
|
@@ -5602,7 +6012,7 @@ function useAgentChat(options = {}) {
|
|
|
5602
6012
|
throw error;
|
|
5603
6013
|
}
|
|
5604
6014
|
}, []);
|
|
5605
|
-
const enqueue = (0,
|
|
6015
|
+
const enqueue = (0, import_react24.useCallback)(
|
|
5606
6016
|
async (text2, {
|
|
5607
6017
|
attachments = [],
|
|
5608
6018
|
mode = "queue"
|
|
@@ -5650,7 +6060,7 @@ function useAgentChat(options = {}) {
|
|
|
5650
6060
|
},
|
|
5651
6061
|
[client, queueCall, threadForQueue, turnBody, applyQueue, isTurnInFlight]
|
|
5652
6062
|
);
|
|
5653
|
-
const sendMessage = (0,
|
|
6063
|
+
const sendMessage = (0, import_react24.useCallback)(
|
|
5654
6064
|
async (message, options2) => {
|
|
5655
6065
|
const block = blockedRef.current;
|
|
5656
6066
|
if (block != null) throw new QuotaBlockedError(block);
|
|
@@ -5674,7 +6084,7 @@ function useAgentChat(options = {}) {
|
|
|
5674
6084
|
},
|
|
5675
6085
|
[isTurnInFlight, enqueue]
|
|
5676
6086
|
);
|
|
5677
|
-
const removeQueued = (0,
|
|
6087
|
+
const removeQueued = (0, import_react24.useCallback)(
|
|
5678
6088
|
async (id) => {
|
|
5679
6089
|
const previous = queueStateRef.current;
|
|
5680
6090
|
applyQueue({ ...previous, items: previous.items.filter((item) => item.id !== id) });
|
|
@@ -5687,7 +6097,7 @@ function useAgentChat(options = {}) {
|
|
|
5687
6097
|
},
|
|
5688
6098
|
[client, queueCall, applyQueue]
|
|
5689
6099
|
);
|
|
5690
|
-
const interruptQueued = (0,
|
|
6100
|
+
const interruptQueued = (0, import_react24.useCallback)(
|
|
5691
6101
|
async (id) => {
|
|
5692
6102
|
const previous = queueStateRef.current;
|
|
5693
6103
|
const moving = previous.items.find((item) => item.id === id);
|
|
@@ -5722,7 +6132,7 @@ function useAgentChat(options = {}) {
|
|
|
5722
6132
|
},
|
|
5723
6133
|
[client, queueCall, applyQueue, isTurnInFlight]
|
|
5724
6134
|
);
|
|
5725
|
-
const editQueued = (0,
|
|
6135
|
+
const editQueued = (0, import_react24.useCallback)(
|
|
5726
6136
|
async (id, text2) => {
|
|
5727
6137
|
applyQueue(
|
|
5728
6138
|
await queueCall(
|
|
@@ -5732,7 +6142,7 @@ function useAgentChat(options = {}) {
|
|
|
5732
6142
|
},
|
|
5733
6143
|
[client, queueCall, applyQueue]
|
|
5734
6144
|
);
|
|
5735
|
-
const moveQueued = (0,
|
|
6145
|
+
const moveQueued = (0, import_react24.useCallback)(
|
|
5736
6146
|
async (id, index) => {
|
|
5737
6147
|
const previous = queueStateRef.current;
|
|
5738
6148
|
const moving = previous.items.find((item) => item.id === id);
|
|
@@ -5754,12 +6164,12 @@ function useAgentChat(options = {}) {
|
|
|
5754
6164
|
},
|
|
5755
6165
|
[client, queueCall, applyQueue]
|
|
5756
6166
|
);
|
|
5757
|
-
const clearQueue = (0,
|
|
6167
|
+
const clearQueue = (0, import_react24.useCallback)(async () => {
|
|
5758
6168
|
const threadId = currentThreadId();
|
|
5759
6169
|
if (threadId === void 0) return;
|
|
5760
6170
|
applyQueue(await queueCall(() => requireBackendMethod(client, "clearQueue")(threadId)));
|
|
5761
6171
|
}, [client, queueCall, currentThreadId, applyQueue]);
|
|
5762
|
-
const resumeQueue = (0,
|
|
6172
|
+
const resumeQueue = (0, import_react24.useCallback)(async () => {
|
|
5763
6173
|
const threadId = currentThreadId();
|
|
5764
6174
|
if (threadId === void 0) return;
|
|
5765
6175
|
const before = queueStateRef.current;
|
|
@@ -5777,7 +6187,7 @@ function useAgentChat(options = {}) {
|
|
|
5777
6187
|
else attachTo(turn);
|
|
5778
6188
|
}
|
|
5779
6189
|
}, [client, queueCall, currentThreadId, applyQueue, isTurnInFlight]);
|
|
5780
|
-
const resumeQueueRef = (0,
|
|
6190
|
+
const resumeQueueRef = (0, import_react24.useRef)(resumeQueue);
|
|
5781
6191
|
resumeQueueRef.current = resumeQueue;
|
|
5782
6192
|
const queuedItems = [
|
|
5783
6193
|
...pendingSends.filter((item) => item.interrupt),
|
|
@@ -5807,7 +6217,7 @@ function useAgentChat(options = {}) {
|
|
|
5807
6217
|
resume: resumeQueue,
|
|
5808
6218
|
error: queueError
|
|
5809
6219
|
};
|
|
5810
|
-
const addToolResult = (0,
|
|
6220
|
+
const addToolResult = (0, import_react24.useCallback)(
|
|
5811
6221
|
({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
5812
6222
|
tool,
|
|
5813
6223
|
toolCallId,
|
|
@@ -5815,8 +6225,8 @@ function useAgentChat(options = {}) {
|
|
|
5815
6225
|
}),
|
|
5816
6226
|
[]
|
|
5817
6227
|
);
|
|
5818
|
-
const [backgroundRuns, setBackgroundRuns] = (0,
|
|
5819
|
-
const refreshBackground = (0,
|
|
6228
|
+
const [backgroundRuns, setBackgroundRuns] = (0, import_react24.useState)([]);
|
|
6229
|
+
const refreshBackground = (0, import_react24.useCallback)(async () => {
|
|
5820
6230
|
const threadId = currentThreadId();
|
|
5821
6231
|
if (threadId === void 0) {
|
|
5822
6232
|
return;
|
|
@@ -5836,13 +6246,13 @@ function useAgentChat(options = {}) {
|
|
|
5836
6246
|
}, [client, currentThreadId]);
|
|
5837
6247
|
backgroundRef.current = refreshBackground;
|
|
5838
6248
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
5839
|
-
(0,
|
|
6249
|
+
(0, import_react24.useEffect)(() => {
|
|
5840
6250
|
if (options.background !== true || options.threadId === void 0) {
|
|
5841
6251
|
return;
|
|
5842
6252
|
}
|
|
5843
6253
|
void refreshBackground();
|
|
5844
6254
|
}, [options.background, options.threadId, chatId, refreshBackground]);
|
|
5845
|
-
(0,
|
|
6255
|
+
(0, import_react24.useEffect)(() => {
|
|
5846
6256
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
5847
6257
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
5848
6258
|
return;
|
|
@@ -5850,7 +6260,15 @@ function useAgentChat(options = {}) {
|
|
|
5850
6260
|
const timer = setInterval(() => void refreshBackground(), every);
|
|
5851
6261
|
return () => clearInterval(timer);
|
|
5852
6262
|
}, [isWorking, refreshBackground]);
|
|
5853
|
-
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 () => {
|
|
5854
6272
|
chatRef.current.stop();
|
|
5855
6273
|
const active = runIdRef.current;
|
|
5856
6274
|
if (active) {
|
|
@@ -5867,8 +6285,23 @@ function useAgentChat(options = {}) {
|
|
|
5867
6285
|
}
|
|
5868
6286
|
}
|
|
5869
6287
|
}, [client, currentThreadId, applyQueue]);
|
|
5870
|
-
const approve = (0,
|
|
5871
|
-
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
|
+
}
|
|
5872
6305
|
await requireBackendMethod(
|
|
5873
6306
|
client,
|
|
5874
6307
|
"approveToolCall"
|
|
@@ -5878,10 +6311,25 @@ function useAgentChat(options = {}) {
|
|
|
5878
6311
|
...via !== void 0 ? { via } : {}
|
|
5879
6312
|
});
|
|
5880
6313
|
},
|
|
5881
|
-
[client]
|
|
6314
|
+
[client, currentThreadId, proposals.refresh]
|
|
5882
6315
|
);
|
|
5883
|
-
const reject = (0,
|
|
5884
|
-
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
|
+
}
|
|
5885
6333
|
await requireBackendMethod(
|
|
5886
6334
|
client,
|
|
5887
6335
|
"rejectToolCall"
|
|
@@ -5891,9 +6339,9 @@ function useAgentChat(options = {}) {
|
|
|
5891
6339
|
...via !== void 0 ? { via } : {}
|
|
5892
6340
|
});
|
|
5893
6341
|
},
|
|
5894
|
-
[client]
|
|
6342
|
+
[client, currentThreadId, proposals.refresh]
|
|
5895
6343
|
);
|
|
5896
|
-
const answer = (0,
|
|
6344
|
+
const answer = (0, import_react24.useCallback)(
|
|
5897
6345
|
async ({ toolCallId, answers, via }) => {
|
|
5898
6346
|
await requireBackendMethod(
|
|
5899
6347
|
client,
|
|
@@ -5906,7 +6354,7 @@ function useAgentChat(options = {}) {
|
|
|
5906
6354
|
},
|
|
5907
6355
|
[client]
|
|
5908
6356
|
);
|
|
5909
|
-
const skip = (0,
|
|
6357
|
+
const skip = (0, import_react24.useCallback)(
|
|
5910
6358
|
async ({ toolCallId, via }) => {
|
|
5911
6359
|
await requireBackendMethod(
|
|
5912
6360
|
client,
|
|
@@ -5915,7 +6363,7 @@ function useAgentChat(options = {}) {
|
|
|
5915
6363
|
},
|
|
5916
6364
|
[client]
|
|
5917
6365
|
);
|
|
5918
|
-
const regenerate = (0,
|
|
6366
|
+
const regenerate = (0, import_react24.useCallback)(
|
|
5919
6367
|
(_input) => {
|
|
5920
6368
|
const block = blockedRef.current;
|
|
5921
6369
|
if (block != null) throw new QuotaBlockedError(block);
|
|
@@ -5928,7 +6376,7 @@ function useAgentChat(options = {}) {
|
|
|
5928
6376
|
},
|
|
5929
6377
|
[isTurnInFlight]
|
|
5930
6378
|
);
|
|
5931
|
-
const storedIdOf = (0,
|
|
6379
|
+
const storedIdOf = (0, import_react24.useCallback)(
|
|
5932
6380
|
async (messageId, threadId) => {
|
|
5933
6381
|
const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);
|
|
5934
6382
|
const runOf = message?.metadata?.runId;
|
|
@@ -5939,7 +6387,7 @@ function useAgentChat(options = {}) {
|
|
|
5939
6387
|
},
|
|
5940
6388
|
[client]
|
|
5941
6389
|
);
|
|
5942
|
-
const fork = (0,
|
|
6390
|
+
const fork = (0, import_react24.useCallback)(
|
|
5943
6391
|
async ({
|
|
5944
6392
|
messageId,
|
|
5945
6393
|
threadId
|
|
@@ -5954,7 +6402,7 @@ function useAgentChat(options = {}) {
|
|
|
5954
6402
|
},
|
|
5955
6403
|
[client, currentThreadId, storedIdOf]
|
|
5956
6404
|
);
|
|
5957
|
-
const truncateFrom = (0,
|
|
6405
|
+
const truncateFrom = (0, import_react24.useCallback)(
|
|
5958
6406
|
async ({ messageId, threadId }) => {
|
|
5959
6407
|
const target = threadId ?? currentThreadId();
|
|
5960
6408
|
if (target === void 0) throw new Error("truncateFrom: this chat has no thread yet");
|
|
@@ -5963,7 +6411,7 @@ function useAgentChat(options = {}) {
|
|
|
5963
6411
|
},
|
|
5964
6412
|
[client, currentThreadId, storedIdOf]
|
|
5965
6413
|
);
|
|
5966
|
-
const promote = (0,
|
|
6414
|
+
const promote = (0, import_react24.useCallback)(
|
|
5967
6415
|
async ({ threadId } = {}) => {
|
|
5968
6416
|
const target = threadId ?? currentThreadId();
|
|
5969
6417
|
if (target === void 0) throw new Error("promote: this chat has no thread yet");
|
|
@@ -5972,24 +6420,24 @@ function useAgentChat(options = {}) {
|
|
|
5972
6420
|
},
|
|
5973
6421
|
[client, currentThreadId]
|
|
5974
6422
|
);
|
|
5975
|
-
const [modelsWanted, setModelsWanted] = (0,
|
|
5976
|
-
const modelsWantedRef = (0,
|
|
6423
|
+
const [modelsWanted, setModelsWanted] = (0, import_react24.useState)(false);
|
|
6424
|
+
const modelsWantedRef = (0, import_react24.useRef)(modelsWanted);
|
|
5977
6425
|
modelsWantedRef.current = modelsWanted;
|
|
5978
6426
|
const catalog = useModels({
|
|
5979
6427
|
backend: client,
|
|
5980
6428
|
...options.agent !== void 0 ? { agent: options.agent } : {},
|
|
5981
6429
|
enabled: modelsWanted && typeof client.listModels === "function"
|
|
5982
6430
|
});
|
|
5983
|
-
const wantModels = (0,
|
|
6431
|
+
const wantModels = (0, import_react24.useCallback)(() => {
|
|
5984
6432
|
if (modelsWantedRef.current) return;
|
|
5985
6433
|
modelsWantedRef.current = true;
|
|
5986
6434
|
queueMicrotask(() => setModelsWanted(true));
|
|
5987
6435
|
}, []);
|
|
5988
6436
|
lockedRef.current = catalog.locked !== null;
|
|
5989
|
-
const selectModel = (0,
|
|
6437
|
+
const selectModel = (0, import_react24.useCallback)((id) => {
|
|
5990
6438
|
if (!lockedRef.current) setPickedModel(id);
|
|
5991
6439
|
}, []);
|
|
5992
|
-
const pinToThread = (0,
|
|
6440
|
+
const pinToThread = (0, import_react24.useCallback)(
|
|
5993
6441
|
async (model) => {
|
|
5994
6442
|
const threadId = currentThreadId();
|
|
5995
6443
|
setThreadModel(model);
|
|
@@ -6029,14 +6477,14 @@ function useAgentChat(options = {}) {
|
|
|
6029
6477
|
};
|
|
6030
6478
|
const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
|
|
6031
6479
|
const isBusy = status === "submitted" || status === "streaming" || status === "reconnecting";
|
|
6032
|
-
const isBusyRef = (0,
|
|
6480
|
+
const isBusyRef = (0, import_react24.useRef)(isBusy);
|
|
6033
6481
|
isBusyRef.current = isBusy;
|
|
6034
6482
|
const files = useAttachments({ ...options.composer, backend: client });
|
|
6035
|
-
const [text, setText] = (0,
|
|
6483
|
+
const [text, setText] = (0, import_react24.useState)("");
|
|
6036
6484
|
const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy && whileRunning === "block" ? "busy" : text.trim().length === 0 && files.refs.length === 0 ? "empty" : null;
|
|
6037
|
-
const composerRef = (0,
|
|
6485
|
+
const composerRef = (0, import_react24.useRef)({ text, files, blockedBy });
|
|
6038
6486
|
composerRef.current = { text, files, blockedBy };
|
|
6039
|
-
const submit = (0,
|
|
6487
|
+
const submit = (0, import_react24.useCallback)(
|
|
6040
6488
|
async (options2) => {
|
|
6041
6489
|
const current = composerRef.current;
|
|
6042
6490
|
const asked = canQueueRef.current ? options2?.mode : void 0;
|
|
@@ -6118,6 +6566,7 @@ function useAgentChat(options = {}) {
|
|
|
6118
6566
|
addToolResult,
|
|
6119
6567
|
/** Sub-agents this conversation started and did not wait for. */
|
|
6120
6568
|
background,
|
|
6569
|
+
proposals,
|
|
6121
6570
|
runId,
|
|
6122
6571
|
/** The loaded thread's running turn, or `null` once read with none. */
|
|
6123
6572
|
activeRunId,
|
|
@@ -6150,6 +6599,11 @@ function useAgentChat(options = {}) {
|
|
|
6150
6599
|
queue,
|
|
6151
6600
|
/** The model picker: `list`, `selected`, `select(id)`, `pinToThread(id)`. */
|
|
6152
6601
|
models,
|
|
6602
|
+
/**
|
|
6603
|
+
* The persona pinned on this thread (`ThreadSummary.persona`), or `null` when none is — what a
|
|
6604
|
+
* persona picker on a reopened thread starts from (`?? agent.defaultPersona`).
|
|
6605
|
+
*/
|
|
6606
|
+
threadPersona,
|
|
6153
6607
|
/** The caller's budget (`GET <base>/quota`); `quota.blocked` gates sends. */
|
|
6154
6608
|
quota,
|
|
6155
6609
|
/** The window blocking sends right now (the `blocked` option, else the quota report's). */
|
|
@@ -6237,8 +6691,10 @@ function isRunNotActiveError(error) {
|
|
|
6237
6691
|
onThreadsEvent,
|
|
6238
6692
|
persistSpeechLang,
|
|
6239
6693
|
phraseFor,
|
|
6694
|
+
proposalNeedsPolling,
|
|
6240
6695
|
readPath,
|
|
6241
6696
|
readReasoningMs,
|
|
6697
|
+
reconcileProposalMessages,
|
|
6242
6698
|
reframeAgUiStream,
|
|
6243
6699
|
requireBackendMethod,
|
|
6244
6700
|
resolveResultView,
|
|
@@ -6246,6 +6702,7 @@ function isRunNotActiveError(error) {
|
|
|
6246
6702
|
storedThreadToUiMessages,
|
|
6247
6703
|
toolCallState,
|
|
6248
6704
|
toolCatalogFrom,
|
|
6705
|
+
useActionProposals,
|
|
6249
6706
|
useAgentBackend,
|
|
6250
6707
|
useAgentChat,
|
|
6251
6708
|
useAgentConfig,
|