@dudousxd/nestjs-agent-react 0.10.0 → 0.11.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 +16 -2
- package/dist/index.cjs +222 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -9
- package/dist/index.d.ts +72 -9
- package/dist/index.js +200 -34
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -112,7 +112,7 @@ function Chat() {
|
|
|
112
112
|
|---|---|
|
|
113
113
|
| `items` | The mounted window, oldest first. Each item carries `blocks`, `text`, `usage`, `timestamp`, `isStreaming`, `isLastAssistant`, and its action machines. |
|
|
114
114
|
| `items[i].blocks` | `{ kind: 'text' \| 'reasoning' \| 'tools' \| 'sources' \| 'elicitation' \| 'ui' }`. A `ui` block is a component the server pushed (`{ id, component, props, version }`) — look `component` up in your own registry. A `tools` block is a run of CONSECUTIVE tool parts — any other part between two calls (including a `step-start` marker) ends the run. A `reasoning` block carries `isOpen`/`toggle`, open while it streams. A `sources` block appears only under `sources: true`, an `elicitation` block only under `onAnswer` — see below. |
|
|
115
|
-
| `items[i].blocks[n]` (`tools`) | Also carries `calls`: the same parts, each with `{ toolCallId, name, toolKind, parentId, children, approval, isAwaitingApproval, approve, reject, error }`, and `roots`: the same calls as a tree (a call nested under another by the stream's `parentId` sits in its parent's `children`). `approval` is `{ approver, expiresAt, reason }` when the runner said who has to decide, else `null`. |
|
|
115
|
+
| `items[i].blocks[n]` (`tools`) | Also carries `calls`: the same parts, each with `{ toolCallId, name, toolKind, parentId, children, approval, isAwaitingApproval, approve, reject, error }`, and `roots`: the same calls as a tree (a call nested under another by the stream's `parentId` sits in its parent's `children`). `approval` is `{ approver, expiresAt, reason, status, remember, decidedBy, decidedVia, decisionReason }` when the runner said who has to decide, else `null` — `status` is `pending` / `approved` / `rejected` / `expired`. |
|
|
116
116
|
| `items[i].copy` | `{ available, copied, copy() }` — `copied` flashes for `copyResetMs` (default 1500). |
|
|
117
117
|
| `items[i].edit` | `{ available, isEditing, draft, canSave, start(), cancel(), setDraft(), save(), getTextareaProps() }`. The prop-getter focuses with the caret at the end, saves on Enter, cancels on Escape. |
|
|
118
118
|
| `items[i].fork` / `.regenerate` | `{ available, run() }`. Regenerate is offered on the last assistant message only. |
|
|
@@ -223,7 +223,20 @@ An `action` tool's input lands and its output never follows on its own — the l
|
|
|
223
223
|
between the two — so a call stuck at `input-available` IS the pending approval. A question set parks
|
|
224
224
|
the same way and is deliberately excluded: approving one settles nothing.
|
|
225
225
|
|
|
226
|
-
|
|
226
|
+
`call.approve.run({ remember: true })` approves this tool for the rest of the thread (the server
|
|
227
|
+
stops asking); `call.approval` says who has to decide and, once settled, who did and through what.
|
|
228
|
+
For a request with an expiry, `useApprovalCountdown(call.approval?.expiresAt)` ticks the time left
|
|
229
|
+
(`{ remainingMs, isExpired }`, headless — pair it with `formatElapsed`):
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
function ApprovalDeadline({ expiresAt }: { expiresAt: string | null }) {
|
|
233
|
+
const { remainingMs, isExpired } = useApprovalCountdown(expiresAt);
|
|
234
|
+
if (remainingMs === null) return null;
|
|
235
|
+
return <span>{isExpired ? 'Expired' : `${formatElapsed(remainingMs)} left`}</span>;
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
A refused settlement (403 "not your thread" or "not your approval", 410 "expired", a network failure) lands on `block.error` /
|
|
227
240
|
`call.error` with the affordance still live, rather than escaping as an unhandled rejection. Render
|
|
228
241
|
it — a button that silently does nothing is indistinguishable from a broken one.
|
|
229
242
|
|
|
@@ -420,6 +433,7 @@ data parts, which `useChat`'s `onData` (and `useAgentChat({ onData })`) sees as
|
|
|
420
433
|
|---|---|
|
|
421
434
|
| `ui` | a `data-ui` part keyed by the component id (a repeat id updates it in place) |
|
|
422
435
|
| `approval-requested` | a `data-approval-requested` part keyed by the call id, plus the SDK's native approval request — the tool part moves to `state: 'approval-requested'` |
|
|
436
|
+
| `approval-settled` | a `data-approval-settled` part keyed by the call id — who decided, through what, remembered or not; folded into `call.approval` |
|
|
423
437
|
| `title` / `cancelled` | transient `data-title` / `data-cancelled` (never stored on the message); `useAgentChat({ onTitle })` |
|
|
424
438
|
| a kind this version does not know | a `data-<kind>` part — forwarded, never dropped |
|
|
425
439
|
|
package/dist/index.cjs
CHANGED
|
@@ -41,6 +41,7 @@ __export(src_exports, {
|
|
|
41
41
|
MessageList: () => MessageList,
|
|
42
42
|
SPEECH_LANGUAGES: () => SPEECH_LANGUAGES,
|
|
43
43
|
applyCompletion: () => applyCompletion,
|
|
44
|
+
approvalCountdown: () => approvalCountdown,
|
|
44
45
|
backgroundRunsFromThread: () => backgroundRunsFromThread,
|
|
45
46
|
buildTranscriptBlocks: () => buildTranscriptBlocks,
|
|
46
47
|
correctedCallIds: () => correctedCallIds,
|
|
@@ -68,6 +69,7 @@ __export(src_exports, {
|
|
|
68
69
|
toolCallState: () => toolCallState,
|
|
69
70
|
toolCatalogFrom: () => toolCatalogFrom,
|
|
70
71
|
useAgentChat: () => useAgentChat,
|
|
72
|
+
useApprovalCountdown: () => useApprovalCountdown,
|
|
71
73
|
useChatTranscript: () => useChatTranscript,
|
|
72
74
|
useComposerAutocomplete: () => useComposerAutocomplete,
|
|
73
75
|
useElapsed: () => useElapsed,
|
|
@@ -521,6 +523,10 @@ var AgentChatTransport = class {
|
|
|
521
523
|
});
|
|
522
524
|
}
|
|
523
525
|
break;
|
|
526
|
+
case "approval-settled":
|
|
527
|
+
ensureStep();
|
|
528
|
+
forwardAsData(event, false);
|
|
529
|
+
break;
|
|
524
530
|
case "ui":
|
|
525
531
|
ensureStep();
|
|
526
532
|
closeRuns();
|
|
@@ -820,6 +826,10 @@ var AgentClient = class {
|
|
|
820
826
|
cancelStream(runId) {
|
|
821
827
|
return this.request("POST", `/agent/chat/${encodeURIComponent(runId)}/cancel`);
|
|
822
828
|
}
|
|
829
|
+
/**
|
|
830
|
+
* `remember` approves later calls of the same tool in the same thread; `via` names the surface
|
|
831
|
+
* the decision came through (the server records `'web'` when omitted).
|
|
832
|
+
*/
|
|
823
833
|
approveToolCall(input) {
|
|
824
834
|
return this.request("POST", "/agent/tool-call/approve", input);
|
|
825
835
|
}
|
|
@@ -1337,7 +1347,7 @@ function buildTranscriptBlocks(message, options) {
|
|
|
1337
1347
|
if (toolBuffer.length === 0) {
|
|
1338
1348
|
return;
|
|
1339
1349
|
}
|
|
1340
|
-
const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId)
|
|
1350
|
+
const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvalOf(approvals.get(part.toolCallId), part), options.toolCatalog));
|
|
1341
1351
|
const roots = nestToolCalls(calls);
|
|
1342
1352
|
blocks.push({
|
|
1343
1353
|
kind: "tools",
|
|
@@ -1412,7 +1422,7 @@ function buildTranscriptBlocks(message, options) {
|
|
|
1412
1422
|
fileBuffer.push(part);
|
|
1413
1423
|
continue;
|
|
1414
1424
|
}
|
|
1415
|
-
if (part.type === APPROVAL_PART) {
|
|
1425
|
+
if (part.type === APPROVAL_PART || part.type === SETTLED_PART) {
|
|
1416
1426
|
continue;
|
|
1417
1427
|
}
|
|
1418
1428
|
flushAll();
|
|
@@ -1563,7 +1573,11 @@ function buildToolCall(part, options, approval, catalog) {
|
|
|
1563
1573
|
approve: {
|
|
1564
1574
|
available: awaiting && options?.canApprove === true,
|
|
1565
1575
|
isSubmitting: sending === "approve",
|
|
1566
|
-
|
|
1576
|
+
// Read by field, not passed through: `onClick={call.approve.run}` hands this a click event,
|
|
1577
|
+
// and a host's handler must not receive that as its options.
|
|
1578
|
+
run: /* @__PURE__ */ __name((approveOptions) => approveOptions?.remember === true ? options?.approve(toolCallId, {
|
|
1579
|
+
remember: true
|
|
1580
|
+
}) : options?.approve(toolCallId), "run")
|
|
1567
1581
|
},
|
|
1568
1582
|
reject: {
|
|
1569
1583
|
available: awaiting && options?.canReject === true,
|
|
@@ -1691,25 +1705,90 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
1691
1705
|
__name(buildElicitationBlock, "buildElicitationBlock");
|
|
1692
1706
|
var UI_PART = "data-ui";
|
|
1693
1707
|
var APPROVAL_PART = "data-approval-requested";
|
|
1708
|
+
var SETTLED_PART = "data-approval-settled";
|
|
1709
|
+
var SETTLED_STATUSES = [
|
|
1710
|
+
"approved",
|
|
1711
|
+
"rejected",
|
|
1712
|
+
"expired"
|
|
1713
|
+
];
|
|
1694
1714
|
function readApprovals(parts) {
|
|
1695
1715
|
const out = /* @__PURE__ */ new Map();
|
|
1716
|
+
const entry = /* @__PURE__ */ __name((id) => {
|
|
1717
|
+
let found = out.get(id);
|
|
1718
|
+
if (found === void 0) {
|
|
1719
|
+
found = {
|
|
1720
|
+
approver: null,
|
|
1721
|
+
expiresAt: null,
|
|
1722
|
+
reason: null,
|
|
1723
|
+
status: null,
|
|
1724
|
+
remember: false,
|
|
1725
|
+
decidedBy: null,
|
|
1726
|
+
decidedVia: null,
|
|
1727
|
+
decisionReason: null
|
|
1728
|
+
};
|
|
1729
|
+
out.set(id, found);
|
|
1730
|
+
}
|
|
1731
|
+
return found;
|
|
1732
|
+
}, "entry");
|
|
1696
1733
|
for (const part of parts) {
|
|
1697
|
-
if (part.type !== APPROVAL_PART) {
|
|
1734
|
+
if (part.type !== APPROVAL_PART && part.type !== SETTLED_PART) {
|
|
1698
1735
|
continue;
|
|
1699
1736
|
}
|
|
1700
1737
|
const data = part.data;
|
|
1701
|
-
if (!isRecord2(data) || typeof data.id !== "string"
|
|
1738
|
+
if (!isRecord2(data) || typeof data.id !== "string") {
|
|
1702
1739
|
continue;
|
|
1703
1740
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1741
|
+
const approval = entry(data.id);
|
|
1742
|
+
if (part.type === APPROVAL_PART) {
|
|
1743
|
+
if (typeof data.approver !== "string") {
|
|
1744
|
+
continue;
|
|
1745
|
+
}
|
|
1746
|
+
approval.approver = data.approver;
|
|
1747
|
+
approval.expiresAt = typeof data.expiresAt === "string" ? data.expiresAt : null;
|
|
1748
|
+
approval.reason = typeof data.reason === "string" ? data.reason : null;
|
|
1749
|
+
continue;
|
|
1750
|
+
}
|
|
1751
|
+
if (typeof data.status !== "string" || !SETTLED_STATUSES.includes(data.status)) {
|
|
1752
|
+
continue;
|
|
1753
|
+
}
|
|
1754
|
+
approval.status = data.status;
|
|
1755
|
+
if (approval.approver === null && typeof data.approver === "string") {
|
|
1756
|
+
approval.approver = data.approver;
|
|
1757
|
+
}
|
|
1758
|
+
approval.remember = data.remember === true;
|
|
1759
|
+
approval.decidedBy = typeof data.decidedBy === "string" ? data.decidedBy : null;
|
|
1760
|
+
approval.decidedVia = typeof data.decidedVia === "string" ? data.decidedVia : null;
|
|
1761
|
+
approval.decisionReason = typeof data.reason === "string" ? data.reason : null;
|
|
1709
1762
|
}
|
|
1710
1763
|
return out;
|
|
1711
1764
|
}
|
|
1712
1765
|
__name(readApprovals, "readApprovals");
|
|
1766
|
+
function approvalOf(parts, call) {
|
|
1767
|
+
if (parts === void 0 || parts.approver === null) {
|
|
1768
|
+
return null;
|
|
1769
|
+
}
|
|
1770
|
+
return {
|
|
1771
|
+
approver: parts.approver,
|
|
1772
|
+
expiresAt: parts.expiresAt,
|
|
1773
|
+
reason: parts.reason,
|
|
1774
|
+
status: parts.status ?? statusFromPart(call),
|
|
1775
|
+
remember: parts.remember,
|
|
1776
|
+
decidedBy: parts.decidedBy,
|
|
1777
|
+
decidedVia: parts.decidedVia,
|
|
1778
|
+
decisionReason: parts.decisionReason
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
__name(approvalOf, "approvalOf");
|
|
1782
|
+
function statusFromPart(call) {
|
|
1783
|
+
if (call.state === "output-denied") {
|
|
1784
|
+
return "rejected";
|
|
1785
|
+
}
|
|
1786
|
+
if (call.state === "output-available" || call.state === "output-error") {
|
|
1787
|
+
return "approved";
|
|
1788
|
+
}
|
|
1789
|
+
return "pending";
|
|
1790
|
+
}
|
|
1791
|
+
__name(statusFromPart, "statusFromPart");
|
|
1713
1792
|
function readUiComponent(part) {
|
|
1714
1793
|
const data = part.data;
|
|
1715
1794
|
if (!isRecord2(data) || typeof data.component !== "string") {
|
|
@@ -2095,10 +2174,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2095
2174
|
}, [
|
|
2096
2175
|
settle
|
|
2097
2176
|
]);
|
|
2098
|
-
const approve = (0, import_react5.useCallback)((toolCallId) => {
|
|
2177
|
+
const approve = (0, import_react5.useCallback)((toolCallId, options2) => {
|
|
2099
2178
|
const onApprove = latest.current.options.onApprove;
|
|
2100
2179
|
if (onApprove) {
|
|
2101
|
-
settle(toolCallId, "approve", () => onApprove(toolCallId));
|
|
2180
|
+
settle(toolCallId, "approve", () => options2 === void 0 ? onApprove(toolCallId) : onApprove(toolCallId, options2));
|
|
2102
2181
|
}
|
|
2103
2182
|
}, [
|
|
2104
2183
|
settle
|
|
@@ -3073,6 +3152,49 @@ function useToolCatalog(options) {
|
|
|
3073
3152
|
}
|
|
3074
3153
|
__name(useToolCatalog, "useToolCatalog");
|
|
3075
3154
|
|
|
3155
|
+
// src/approvals/countdown.ts
|
|
3156
|
+
var import_react9 = require("react");
|
|
3157
|
+
function approvalCountdown(expiresAt, now = Date.now()) {
|
|
3158
|
+
const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
|
|
3159
|
+
if (!Number.isFinite(deadline)) {
|
|
3160
|
+
return {
|
|
3161
|
+
remainingMs: null,
|
|
3162
|
+
isExpired: false
|
|
3163
|
+
};
|
|
3164
|
+
}
|
|
3165
|
+
const remainingMs = Math.max(0, deadline - now);
|
|
3166
|
+
return {
|
|
3167
|
+
remainingMs,
|
|
3168
|
+
isExpired: remainingMs === 0
|
|
3169
|
+
};
|
|
3170
|
+
}
|
|
3171
|
+
__name(approvalCountdown, "approvalCountdown");
|
|
3172
|
+
function useApprovalCountdown(expiresAt, options = {}) {
|
|
3173
|
+
const { intervalMs = 1e3 } = options;
|
|
3174
|
+
const nowRef = (0, import_react9.useRef)(options.now ?? Date.now);
|
|
3175
|
+
nowRef.current = options.now ?? Date.now;
|
|
3176
|
+
const [state, setState] = (0, import_react9.useState)(() => approvalCountdown(expiresAt, nowRef.current()));
|
|
3177
|
+
(0, import_react9.useEffect)(() => {
|
|
3178
|
+
const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
|
|
3179
|
+
const first = read();
|
|
3180
|
+
setState(first);
|
|
3181
|
+
if (first.remainingMs === null || first.isExpired) {
|
|
3182
|
+
return;
|
|
3183
|
+
}
|
|
3184
|
+
const timer = setInterval(() => {
|
|
3185
|
+
const next = read();
|
|
3186
|
+
setState(next);
|
|
3187
|
+
if (next.isExpired) clearInterval(timer);
|
|
3188
|
+
}, intervalMs);
|
|
3189
|
+
return () => clearInterval(timer);
|
|
3190
|
+
}, [
|
|
3191
|
+
expiresAt,
|
|
3192
|
+
intervalMs
|
|
3193
|
+
]);
|
|
3194
|
+
return state;
|
|
3195
|
+
}
|
|
3196
|
+
__name(useApprovalCountdown, "useApprovalCountdown");
|
|
3197
|
+
|
|
3076
3198
|
// src/stored-message-to-ui-message.ts
|
|
3077
3199
|
var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
|
|
3078
3200
|
function isRefusal(result) {
|
|
@@ -3132,6 +3254,41 @@ function storedMessageToUiMessage(message) {
|
|
|
3132
3254
|
}
|
|
3133
3255
|
});
|
|
3134
3256
|
}
|
|
3257
|
+
for (const approval of message.approvals ?? []) {
|
|
3258
|
+
parts.push({
|
|
3259
|
+
type: "data-approval-requested",
|
|
3260
|
+
id: approval.toolCallId,
|
|
3261
|
+
data: {
|
|
3262
|
+
id: approval.toolCallId,
|
|
3263
|
+
approver: approval.approver,
|
|
3264
|
+
...approval.expiresAt !== void 0 ? {
|
|
3265
|
+
expiresAt: approval.expiresAt
|
|
3266
|
+
} : {}
|
|
3267
|
+
}
|
|
3268
|
+
});
|
|
3269
|
+
if (approval.status !== "pending") {
|
|
3270
|
+
parts.push({
|
|
3271
|
+
type: "data-approval-settled",
|
|
3272
|
+
id: approval.toolCallId,
|
|
3273
|
+
data: {
|
|
3274
|
+
id: approval.toolCallId,
|
|
3275
|
+
status: approval.status,
|
|
3276
|
+
...approval.decidedBy !== void 0 ? {
|
|
3277
|
+
decidedBy: approval.decidedBy
|
|
3278
|
+
} : {},
|
|
3279
|
+
...approval.decidedVia !== void 0 ? {
|
|
3280
|
+
decidedVia: approval.decidedVia
|
|
3281
|
+
} : {},
|
|
3282
|
+
...approval.remember === true ? {
|
|
3283
|
+
remember: true
|
|
3284
|
+
} : {},
|
|
3285
|
+
...approval.reason !== void 0 ? {
|
|
3286
|
+
reason: approval.reason
|
|
3287
|
+
} : {}
|
|
3288
|
+
}
|
|
3289
|
+
});
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3135
3292
|
for (const call of message.toolCalls ?? []) {
|
|
3136
3293
|
const result = message.toolResults?.find((candidate) => candidate.id === call.id);
|
|
3137
3294
|
const toolKind2 = call.kind;
|
|
@@ -3233,21 +3390,21 @@ function sumUsage(rows) {
|
|
|
3233
3390
|
__name(sumUsage, "sumUsage");
|
|
3234
3391
|
|
|
3235
3392
|
// src/use-agent-chat.ts
|
|
3236
|
-
var
|
|
3237
|
-
var
|
|
3393
|
+
var import_react10 = require("@ai-sdk/react");
|
|
3394
|
+
var import_react11 = require("react");
|
|
3238
3395
|
function useAgentChat(options) {
|
|
3239
|
-
const latest = (0,
|
|
3396
|
+
const latest = (0, import_react11.useRef)(options);
|
|
3240
3397
|
latest.current = options;
|
|
3241
|
-
const [runId, setRunId] = (0,
|
|
3242
|
-
const runIdRef = (0,
|
|
3398
|
+
const [runId, setRunId] = (0, import_react11.useState)(options.resumeRunId);
|
|
3399
|
+
const runIdRef = (0, import_react11.useRef)(runId);
|
|
3243
3400
|
runIdRef.current = runId;
|
|
3244
|
-
const settlingRunIdRef = (0,
|
|
3245
|
-
const autoResumeRunIdRef = (0,
|
|
3246
|
-
const [autoResume, setAutoResume] = (0,
|
|
3247
|
-
const [activeRunId, setActiveRunId] = (0,
|
|
3248
|
-
const regenerateNext = (0,
|
|
3249
|
-
const createdThreadId = (0,
|
|
3250
|
-
const client = (0,
|
|
3401
|
+
const settlingRunIdRef = (0, import_react11.useRef)(void 0);
|
|
3402
|
+
const autoResumeRunIdRef = (0, import_react11.useRef)(void 0);
|
|
3403
|
+
const [autoResume, setAutoResume] = (0, import_react11.useState)(false);
|
|
3404
|
+
const [activeRunId, setActiveRunId] = (0, import_react11.useState)(null);
|
|
3405
|
+
const regenerateNext = (0, import_react11.useRef)(false);
|
|
3406
|
+
const createdThreadId = (0, import_react11.useRef)(void 0);
|
|
3407
|
+
const client = (0, import_react11.useMemo)(() => {
|
|
3251
3408
|
if (options.client) return options.client;
|
|
3252
3409
|
return new AgentClient({
|
|
3253
3410
|
...options.baseUrl !== void 0 ? {
|
|
@@ -3262,7 +3419,7 @@ function useAgentChat(options) {
|
|
|
3262
3419
|
getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
|
|
3263
3420
|
});
|
|
3264
3421
|
}, []);
|
|
3265
|
-
(0,
|
|
3422
|
+
(0, import_react11.useEffect)(() => {
|
|
3266
3423
|
if (!options.resume || options.threadId === void 0) return;
|
|
3267
3424
|
let cancelled = false;
|
|
3268
3425
|
const threadId = options.threadId;
|
|
@@ -3282,7 +3439,7 @@ function useAgentChat(options) {
|
|
|
3282
3439
|
options.resume,
|
|
3283
3440
|
options.threadId
|
|
3284
3441
|
]);
|
|
3285
|
-
const transport = (0,
|
|
3442
|
+
const transport = (0, import_react11.useMemo)(() => {
|
|
3286
3443
|
function onMeta(meta) {
|
|
3287
3444
|
settlingRunIdRef.current = meta.runId;
|
|
3288
3445
|
setRunId(meta.runId);
|
|
@@ -3331,8 +3488,8 @@ function useAgentChat(options) {
|
|
|
3331
3488
|
}, "onAttemptStart")
|
|
3332
3489
|
});
|
|
3333
3490
|
}, []);
|
|
3334
|
-
const backgroundRef = (0,
|
|
3335
|
-
const chat = (0,
|
|
3491
|
+
const backgroundRef = (0, import_react11.useRef)(() => Promise.resolve());
|
|
3492
|
+
const chat = (0, import_react10.useChat)({
|
|
3336
3493
|
transport,
|
|
3337
3494
|
resume: options.resumeRunId !== void 0 || autoResume,
|
|
3338
3495
|
...options.threadId !== void 0 ? {
|
|
@@ -3362,13 +3519,13 @@ function useAgentChat(options) {
|
|
|
3362
3519
|
}
|
|
3363
3520
|
}, "onFinish")
|
|
3364
3521
|
});
|
|
3365
|
-
const chatRef = (0,
|
|
3522
|
+
const chatRef = (0, import_react11.useRef)(chat);
|
|
3366
3523
|
chatRef.current = chat;
|
|
3367
|
-
const turnInFlight = (0,
|
|
3368
|
-
const isTurnInFlight = (0,
|
|
3524
|
+
const turnInFlight = (0, import_react11.useRef)(false);
|
|
3525
|
+
const isTurnInFlight = (0, import_react11.useCallback)(() => turnInFlight.current || transport.isAttemptLive, [
|
|
3369
3526
|
transport
|
|
3370
3527
|
]);
|
|
3371
|
-
const sendMessage = (0,
|
|
3528
|
+
const sendMessage = (0, import_react11.useCallback)(async (...args) => {
|
|
3372
3529
|
if (isTurnInFlight()) return;
|
|
3373
3530
|
turnInFlight.current = true;
|
|
3374
3531
|
try {
|
|
@@ -3379,15 +3536,15 @@ function useAgentChat(options) {
|
|
|
3379
3536
|
}, [
|
|
3380
3537
|
isTurnInFlight
|
|
3381
3538
|
]);
|
|
3382
|
-
const addToolResult = (0,
|
|
3539
|
+
const addToolResult = (0, import_react11.useCallback)(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
3383
3540
|
tool,
|
|
3384
3541
|
toolCallId,
|
|
3385
3542
|
output
|
|
3386
3543
|
}), []);
|
|
3387
|
-
const [threads, setThreads] = (0,
|
|
3388
|
-
const [quota, setQuota] = (0,
|
|
3389
|
-
const [backgroundRuns, setBackgroundRuns] = (0,
|
|
3390
|
-
const refreshBackground = (0,
|
|
3544
|
+
const [threads, setThreads] = (0, import_react11.useState)([]);
|
|
3545
|
+
const [quota, setQuota] = (0, import_react11.useState)(null);
|
|
3546
|
+
const [backgroundRuns, setBackgroundRuns] = (0, import_react11.useState)([]);
|
|
3547
|
+
const refreshBackground = (0, import_react11.useCallback)(async () => {
|
|
3391
3548
|
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
3392
3549
|
if (threadId === void 0) {
|
|
3393
3550
|
return;
|
|
@@ -3412,7 +3569,7 @@ function useAgentChat(options) {
|
|
|
3412
3569
|
]);
|
|
3413
3570
|
backgroundRef.current = refreshBackground;
|
|
3414
3571
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
3415
|
-
(0,
|
|
3572
|
+
(0, import_react11.useEffect)(() => {
|
|
3416
3573
|
if (options.background !== true || options.threadId === void 0) {
|
|
3417
3574
|
return;
|
|
3418
3575
|
}
|
|
@@ -3422,7 +3579,7 @@ function useAgentChat(options) {
|
|
|
3422
3579
|
options.threadId,
|
|
3423
3580
|
refreshBackground
|
|
3424
3581
|
]);
|
|
3425
|
-
(0,
|
|
3582
|
+
(0, import_react11.useEffect)(() => {
|
|
3426
3583
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
3427
3584
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
3428
3585
|
return;
|
|
@@ -3433,26 +3590,26 @@ function useAgentChat(options) {
|
|
|
3433
3590
|
isWorking,
|
|
3434
3591
|
refreshBackground
|
|
3435
3592
|
]);
|
|
3436
|
-
const loadThreads = (0,
|
|
3593
|
+
const loadThreads = (0, import_react11.useCallback)(async () => {
|
|
3437
3594
|
const list = await client.listThreads();
|
|
3438
3595
|
setThreads(list);
|
|
3439
3596
|
return list;
|
|
3440
3597
|
}, [
|
|
3441
3598
|
client
|
|
3442
3599
|
]);
|
|
3443
|
-
const loadThread = (0,
|
|
3600
|
+
const loadThread = (0, import_react11.useCallback)((id) => client.getThread(id), [
|
|
3444
3601
|
client
|
|
3445
3602
|
]);
|
|
3446
|
-
const deleteThread = (0,
|
|
3603
|
+
const deleteThread = (0, import_react11.useCallback)(async (id) => {
|
|
3447
3604
|
await client.deleteThread(id);
|
|
3448
3605
|
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
3449
3606
|
}, [
|
|
3450
3607
|
client
|
|
3451
3608
|
]);
|
|
3452
|
-
const forkThread = (0,
|
|
3609
|
+
const forkThread = (0, import_react11.useCallback)((threadId, messageId) => client.forkFromMessage(threadId, messageId), [
|
|
3453
3610
|
client
|
|
3454
3611
|
]);
|
|
3455
|
-
const renameThread = (0,
|
|
3612
|
+
const renameThread = (0, import_react11.useCallback)(async (id, title) => {
|
|
3456
3613
|
await client.renameThread(id, title);
|
|
3457
3614
|
setThreads((current) => current.map((thread) => thread.id === id ? {
|
|
3458
3615
|
...thread,
|
|
@@ -3461,24 +3618,24 @@ function useAgentChat(options) {
|
|
|
3461
3618
|
}, [
|
|
3462
3619
|
client
|
|
3463
3620
|
]);
|
|
3464
|
-
const promoteThread = (0,
|
|
3621
|
+
const promoteThread = (0, import_react11.useCallback)(async (id) => {
|
|
3465
3622
|
await client.promoteThread(id);
|
|
3466
3623
|
await loadThreads();
|
|
3467
3624
|
}, [
|
|
3468
3625
|
client,
|
|
3469
3626
|
loadThreads
|
|
3470
3627
|
]);
|
|
3471
|
-
const truncateFromMessage = (0,
|
|
3628
|
+
const truncateFromMessage = (0, import_react11.useCallback)((threadId, messageId) => client.truncateFromMessage(threadId, messageId).then(() => void 0), [
|
|
3472
3629
|
client
|
|
3473
3630
|
]);
|
|
3474
|
-
const loadQuota = (0,
|
|
3631
|
+
const loadQuota = (0, import_react11.useCallback)(async () => {
|
|
3475
3632
|
const today = await client.getQuotaToday();
|
|
3476
3633
|
setQuota(today);
|
|
3477
3634
|
return today;
|
|
3478
3635
|
}, [
|
|
3479
3636
|
client
|
|
3480
3637
|
]);
|
|
3481
|
-
const cancel = (0,
|
|
3638
|
+
const cancel = (0, import_react11.useCallback)(async () => {
|
|
3482
3639
|
chatRef.current.stop();
|
|
3483
3640
|
const activeRunId2 = runIdRef.current;
|
|
3484
3641
|
if (activeRunId2) {
|
|
@@ -3490,24 +3647,33 @@ function useAgentChat(options) {
|
|
|
3490
3647
|
}, [
|
|
3491
3648
|
client
|
|
3492
3649
|
]);
|
|
3493
|
-
const approve = (0,
|
|
3650
|
+
const approve = (0, import_react11.useCallback)(async ({ toolCallId, remember, via }) => {
|
|
3494
3651
|
await client.approveToolCall({
|
|
3495
|
-
toolCallId
|
|
3652
|
+
toolCallId,
|
|
3653
|
+
...remember === true ? {
|
|
3654
|
+
remember: true
|
|
3655
|
+
} : {},
|
|
3656
|
+
...via !== void 0 ? {
|
|
3657
|
+
via
|
|
3658
|
+
} : {}
|
|
3496
3659
|
});
|
|
3497
3660
|
}, [
|
|
3498
3661
|
client
|
|
3499
3662
|
]);
|
|
3500
|
-
const reject = (0,
|
|
3663
|
+
const reject = (0, import_react11.useCallback)(async ({ toolCallId, reason, via }) => {
|
|
3501
3664
|
await client.rejectToolCall({
|
|
3502
3665
|
toolCallId,
|
|
3503
3666
|
...reason !== void 0 ? {
|
|
3504
3667
|
reason
|
|
3668
|
+
} : {},
|
|
3669
|
+
...via !== void 0 ? {
|
|
3670
|
+
via
|
|
3505
3671
|
} : {}
|
|
3506
3672
|
});
|
|
3507
3673
|
}, [
|
|
3508
3674
|
client
|
|
3509
3675
|
]);
|
|
3510
|
-
const answer = (0,
|
|
3676
|
+
const answer = (0, import_react11.useCallback)(async ({ toolCallId, answers }) => {
|
|
3511
3677
|
await client.answerToolCall({
|
|
3512
3678
|
toolCallId,
|
|
3513
3679
|
...answers !== void 0 ? {
|
|
@@ -3517,14 +3683,14 @@ function useAgentChat(options) {
|
|
|
3517
3683
|
}, [
|
|
3518
3684
|
client
|
|
3519
3685
|
]);
|
|
3520
|
-
const skip = (0,
|
|
3686
|
+
const skip = (0, import_react11.useCallback)(async ({ toolCallId }) => {
|
|
3521
3687
|
await client.skipToolCall({
|
|
3522
3688
|
toolCallId
|
|
3523
3689
|
});
|
|
3524
3690
|
}, [
|
|
3525
3691
|
client
|
|
3526
3692
|
]);
|
|
3527
|
-
const regenerate = (0,
|
|
3693
|
+
const regenerate = (0, import_react11.useCallback)(() => {
|
|
3528
3694
|
if (isTurnInFlight()) return;
|
|
3529
3695
|
regenerateNext.current = true;
|
|
3530
3696
|
turnInFlight.current = true;
|
|
@@ -3588,6 +3754,7 @@ __name(mergeHeaders, "mergeHeaders");
|
|
|
3588
3754
|
MessageList,
|
|
3589
3755
|
SPEECH_LANGUAGES,
|
|
3590
3756
|
applyCompletion,
|
|
3757
|
+
approvalCountdown,
|
|
3591
3758
|
backgroundRunsFromThread,
|
|
3592
3759
|
buildTranscriptBlocks,
|
|
3593
3760
|
correctedCallIds,
|
|
@@ -3615,6 +3782,7 @@ __name(mergeHeaders, "mergeHeaders");
|
|
|
3615
3782
|
toolCallState,
|
|
3616
3783
|
toolCatalogFrom,
|
|
3617
3784
|
useAgentChat,
|
|
3785
|
+
useApprovalCountdown,
|
|
3618
3786
|
useChatTranscript,
|
|
3619
3787
|
useComposerAutocomplete,
|
|
3620
3788
|
useElapsed,
|