@dudousxd/nestjs-agent-react 0.7.5 → 0.8.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 +20 -2
- package/dist/index.cjs +200 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -12
- package/dist/index.d.ts +87 -12
- package/dist/index.js +201 -22
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -111,8 +111,8 @@ function Chat() {
|
|
|
111
111
|
| On the instance | What it is |
|
|
112
112
|
|---|---|
|
|
113
113
|
| `items` | The mounted window, oldest first. Each item carries `blocks`, `text`, `usage`, `timestamp`, `isStreaming`, `isLastAssistant`, and its action machines. |
|
|
114
|
-
| `items[i].blocks` | `{ kind: 'text' \| 'reasoning' \| 'tools' \| 'sources' \| 'elicitation' }`. 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, isAwaitingApproval, approve, reject, error }`. |
|
|
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`. |
|
|
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. |
|
|
@@ -324,6 +324,10 @@ function CustomChat({ threadId }: { threadId?: string }) {
|
|
|
324
324
|
onRunSettled: ({ status }) => {
|
|
325
325
|
if (status === 'completed') refetchThreadList();
|
|
326
326
|
},
|
|
327
|
+
// The server named (or renamed) the thread mid-stream — update the header now.
|
|
328
|
+
onTitle: (title) => setHeaderTitle(title),
|
|
329
|
+
// Every data part as it arrives: pushed `data-ui` components, `data-approval-requested`, …
|
|
330
|
+
onData: (part) => analytics.track(part.type),
|
|
327
331
|
});
|
|
328
332
|
|
|
329
333
|
return (
|
|
@@ -381,6 +385,20 @@ const transport = new AgentChatTransport({
|
|
|
381
385
|
const chat = useChat({ transport });
|
|
382
386
|
```
|
|
383
387
|
|
|
388
|
+
Beyond text, reasoning and tool calls, the transport maps the rest of the stream vocabulary to AI SDK
|
|
389
|
+
data parts, which `useChat`'s `onData` (and `useAgentChat({ onData })`) sees as they arrive:
|
|
390
|
+
|
|
391
|
+
| Stream frame | Becomes |
|
|
392
|
+
|---|---|
|
|
393
|
+
| `ui` | a `data-ui` part keyed by the component id (a repeat id updates it in place) |
|
|
394
|
+
| `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'` |
|
|
395
|
+
| `title` / `cancelled` | transient `data-title` / `data-cancelled` (never stored on the message); `useAgentChat({ onTitle })` |
|
|
396
|
+
| a kind this version does not know | a `data-<kind>` part — forwarded, never dropped |
|
|
397
|
+
|
|
398
|
+
`parentId` on a tool frame rides the part's `toolMetadata` next to `toolKind`. The full wire
|
|
399
|
+
contract — for a backend that serves these routes without this library's loop — is
|
|
400
|
+
[docs/stream-protocol.md](../../docs/stream-protocol.md).
|
|
401
|
+
|
|
384
402
|
### Loading persisted history
|
|
385
403
|
|
|
386
404
|
A reloaded thread's `StoredMessage[]` (from `AgentClient.getThread`) needs converting to `UIMessage[]`
|
package/dist/index.cjs
CHANGED
|
@@ -202,7 +202,8 @@ var AgentChatTransport = class {
|
|
|
202
202
|
* Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.
|
|
203
203
|
* Recognized frames:
|
|
204
204
|
* - `event: meta` `data: {"runId","threadId"}` → records identity
|
|
205
|
-
* - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool
|
|
205
|
+
* - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool /
|
|
206
|
+
* `data-*`; see {@link AgentChatTransport} docs)
|
|
206
207
|
* - `event: done` `data: {}` → terminates
|
|
207
208
|
* - `event: error` `data: {code,message}` → error chunk
|
|
208
209
|
*
|
|
@@ -219,7 +220,10 @@ var AgentChatTransport = class {
|
|
|
219
220
|
let stepIndex = 0;
|
|
220
221
|
let textId = null;
|
|
221
222
|
let reasoningId = null;
|
|
223
|
+
let textSeq = 0;
|
|
224
|
+
let reasoningSeq = 0;
|
|
222
225
|
const announced = /* @__PURE__ */ new Set();
|
|
226
|
+
const toolMetadata = /* @__PURE__ */ new Map();
|
|
223
227
|
const record = /* @__PURE__ */ __name((meta) => this.recordMeta(meta), "record");
|
|
224
228
|
const endAttempt = /* @__PURE__ */ __name(() => {
|
|
225
229
|
this.attemptLive = false;
|
|
@@ -241,6 +245,8 @@ var AgentChatTransport = class {
|
|
|
241
245
|
stepIndex += 1;
|
|
242
246
|
textId = null;
|
|
243
247
|
reasoningId = null;
|
|
248
|
+
textSeq = 0;
|
|
249
|
+
reasoningSeq = 0;
|
|
244
250
|
controller.enqueue({
|
|
245
251
|
type: "start-step"
|
|
246
252
|
});
|
|
@@ -250,8 +256,7 @@ var AgentChatTransport = class {
|
|
|
250
256
|
if (!stepOpen) openStep();
|
|
251
257
|
}
|
|
252
258
|
__name(ensureStep, "ensureStep");
|
|
253
|
-
function
|
|
254
|
-
if (!stepOpen) return;
|
|
259
|
+
function closeRuns() {
|
|
255
260
|
if (textId !== null) {
|
|
256
261
|
controller.enqueue({
|
|
257
262
|
type: "text-end",
|
|
@@ -266,12 +271,43 @@ var AgentChatTransport = class {
|
|
|
266
271
|
});
|
|
267
272
|
reasoningId = null;
|
|
268
273
|
}
|
|
274
|
+
}
|
|
275
|
+
__name(closeRuns, "closeRuns");
|
|
276
|
+
function closeStep() {
|
|
277
|
+
if (!stepOpen) return;
|
|
278
|
+
closeRuns();
|
|
269
279
|
controller.enqueue({
|
|
270
280
|
type: "finish-step"
|
|
271
281
|
});
|
|
272
282
|
stepOpen = false;
|
|
273
283
|
}
|
|
274
284
|
__name(closeStep, "closeStep");
|
|
285
|
+
function metadataFor(id, toolKind2, parentId) {
|
|
286
|
+
const merged = {
|
|
287
|
+
...toolMetadata.get(id)
|
|
288
|
+
};
|
|
289
|
+
if (toolKind2 !== void 0) merged.toolKind = toolKind2;
|
|
290
|
+
if (parentId !== void 0 && merged.parentId === void 0) merged.parentId = parentId;
|
|
291
|
+
if (Object.keys(merged).length === 0) return void 0;
|
|
292
|
+
toolMetadata.set(id, merged);
|
|
293
|
+
return merged;
|
|
294
|
+
}
|
|
295
|
+
__name(metadataFor, "metadataFor");
|
|
296
|
+
function forwardAsData(event, transient) {
|
|
297
|
+
ensureStarted();
|
|
298
|
+
const { kind, ...data } = event;
|
|
299
|
+
controller.enqueue({
|
|
300
|
+
type: `data-${kind}`,
|
|
301
|
+
...typeof data.id === "string" ? {
|
|
302
|
+
id: data.id
|
|
303
|
+
} : {},
|
|
304
|
+
data,
|
|
305
|
+
...transient ? {
|
|
306
|
+
transient: true
|
|
307
|
+
} : {}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
__name(forwardAsData, "forwardAsData");
|
|
275
311
|
function emit(event) {
|
|
276
312
|
switch (event.kind) {
|
|
277
313
|
case "step-start":
|
|
@@ -291,7 +327,8 @@ var AgentChatTransport = class {
|
|
|
291
327
|
case "text":
|
|
292
328
|
ensureStep();
|
|
293
329
|
if (textId === null) {
|
|
294
|
-
textId = `txt-${stepIndex}`;
|
|
330
|
+
textId = textSeq === 0 ? `txt-${stepIndex}` : `txt-${stepIndex}.${textSeq}`;
|
|
331
|
+
textSeq += 1;
|
|
295
332
|
controller.enqueue({
|
|
296
333
|
type: "text-start",
|
|
297
334
|
id: textId
|
|
@@ -306,7 +343,8 @@ var AgentChatTransport = class {
|
|
|
306
343
|
case "reasoning":
|
|
307
344
|
ensureStep();
|
|
308
345
|
if (reasoningId === null) {
|
|
309
|
-
reasoningId = `rsn-${stepIndex}`;
|
|
346
|
+
reasoningId = reasoningSeq === 0 ? `rsn-${stepIndex}` : `rsn-${stepIndex}.${reasoningSeq}`;
|
|
347
|
+
reasoningSeq += 1;
|
|
310
348
|
controller.enqueue({
|
|
311
349
|
type: "reasoning-start",
|
|
312
350
|
id: reasoningId
|
|
@@ -318,23 +356,20 @@ var AgentChatTransport = class {
|
|
|
318
356
|
delta: event.text
|
|
319
357
|
});
|
|
320
358
|
break;
|
|
321
|
-
case "tool-input-start":
|
|
359
|
+
case "tool-input-start": {
|
|
322
360
|
ensureStep();
|
|
323
361
|
announced.add(event.id);
|
|
362
|
+
const metadata = metadataFor(event.id, event.toolKind, event.parentId);
|
|
324
363
|
controller.enqueue({
|
|
325
364
|
type: "tool-input-start",
|
|
326
365
|
toolCallId: event.id,
|
|
327
366
|
toolName: event.name,
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
// UI gate approval affordances on `kind === 'action'` without hardcoding tool names.
|
|
331
|
-
...event.toolKind !== void 0 ? {
|
|
332
|
-
toolMetadata: {
|
|
333
|
-
toolKind: event.toolKind
|
|
334
|
-
}
|
|
367
|
+
...metadata !== void 0 ? {
|
|
368
|
+
toolMetadata: metadata
|
|
335
369
|
} : {}
|
|
336
370
|
});
|
|
337
371
|
break;
|
|
372
|
+
}
|
|
338
373
|
case "tool-input-delta":
|
|
339
374
|
ensureStep();
|
|
340
375
|
controller.enqueue({
|
|
@@ -343,21 +378,21 @@ var AgentChatTransport = class {
|
|
|
343
378
|
inputTextDelta: event.delta
|
|
344
379
|
});
|
|
345
380
|
break;
|
|
346
|
-
case "tool-input-available":
|
|
381
|
+
case "tool-input-available": {
|
|
347
382
|
ensureStep();
|
|
348
383
|
announced.add(event.id);
|
|
384
|
+
const metadata = metadataFor(event.id, event.toolKind, event.parentId);
|
|
349
385
|
controller.enqueue({
|
|
350
386
|
type: "tool-input-available",
|
|
351
387
|
toolCallId: event.id,
|
|
352
388
|
toolName: event.name,
|
|
353
389
|
input: event.input,
|
|
354
|
-
...
|
|
355
|
-
toolMetadata:
|
|
356
|
-
toolKind: event.toolKind
|
|
357
|
-
}
|
|
390
|
+
...metadata !== void 0 ? {
|
|
391
|
+
toolMetadata: metadata
|
|
358
392
|
} : {}
|
|
359
393
|
});
|
|
360
394
|
break;
|
|
395
|
+
}
|
|
361
396
|
case "elicitation":
|
|
362
397
|
ensureStep();
|
|
363
398
|
if (!announced.has(event.id)) {
|
|
@@ -398,7 +433,39 @@ var AgentChatTransport = class {
|
|
|
398
433
|
toolCallId: event.id
|
|
399
434
|
});
|
|
400
435
|
break;
|
|
436
|
+
case "approval-requested":
|
|
437
|
+
ensureStep();
|
|
438
|
+
forwardAsData(event, false);
|
|
439
|
+
if (announced.has(event.id)) {
|
|
440
|
+
controller.enqueue({
|
|
441
|
+
type: "tool-approval-request",
|
|
442
|
+
approvalId: event.id,
|
|
443
|
+
toolCallId: event.id
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
break;
|
|
447
|
+
case "ui":
|
|
448
|
+
ensureStep();
|
|
449
|
+
closeRuns();
|
|
450
|
+
controller.enqueue({
|
|
451
|
+
type: "data-ui",
|
|
452
|
+
id: event.id,
|
|
453
|
+
data: {
|
|
454
|
+
id: event.id,
|
|
455
|
+
component: event.component,
|
|
456
|
+
props: event.props,
|
|
457
|
+
...event.version !== void 0 ? {
|
|
458
|
+
version: event.version
|
|
459
|
+
} : {}
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
break;
|
|
463
|
+
case "title":
|
|
464
|
+
case "cancelled":
|
|
465
|
+
forwardAsData(event, true);
|
|
466
|
+
break;
|
|
401
467
|
default:
|
|
468
|
+
forwardAsData(event, false);
|
|
402
469
|
break;
|
|
403
470
|
}
|
|
404
471
|
}
|
|
@@ -906,15 +973,18 @@ function buildTranscriptBlocks(message, options) {
|
|
|
906
973
|
let reasoningCounter = 0;
|
|
907
974
|
let sourcesCounter = 0;
|
|
908
975
|
let elicitationCounter = 0;
|
|
976
|
+
const approvals = readApprovals(message.parts ?? []);
|
|
909
977
|
function flushTools() {
|
|
910
978
|
if (toolBuffer.length === 0) {
|
|
911
979
|
return;
|
|
912
980
|
}
|
|
981
|
+
const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId) ?? null));
|
|
913
982
|
blocks.push({
|
|
914
983
|
kind: "tools",
|
|
915
984
|
key: `${message.id}-tools-${toolCounter++}`,
|
|
916
985
|
parts: toolBuffer,
|
|
917
|
-
calls
|
|
986
|
+
calls,
|
|
987
|
+
roots: nestToolCalls(calls)
|
|
918
988
|
});
|
|
919
989
|
toolBuffer = [];
|
|
920
990
|
}
|
|
@@ -977,7 +1047,21 @@ function buildTranscriptBlocks(message, options) {
|
|
|
977
1047
|
fileBuffer.push(part);
|
|
978
1048
|
continue;
|
|
979
1049
|
}
|
|
1050
|
+
if (part.type === APPROVAL_PART) {
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
980
1053
|
flushAll();
|
|
1054
|
+
if ((0, import_ai.isDataUIPart)(part)) {
|
|
1055
|
+
const ui = part.type === UI_PART ? readUiComponent(part) : null;
|
|
1056
|
+
if (ui !== null) {
|
|
1057
|
+
blocks.push({
|
|
1058
|
+
kind: "ui",
|
|
1059
|
+
key: `${message.id}-ui-${ui.id}`,
|
|
1060
|
+
...ui
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
continue;
|
|
1064
|
+
}
|
|
981
1065
|
if ((0, import_ai.isTextUIPart)(part)) {
|
|
982
1066
|
blocks.push({
|
|
983
1067
|
kind: "text",
|
|
@@ -1061,7 +1145,42 @@ function isAwaitingApproval(part) {
|
|
|
1061
1145
|
return toolKind(part) === "action" && readElicitationRequest(part) === null;
|
|
1062
1146
|
}
|
|
1063
1147
|
__name(isAwaitingApproval, "isAwaitingApproval");
|
|
1064
|
-
function
|
|
1148
|
+
function toolParentId(part) {
|
|
1149
|
+
const metadata = part.toolMetadata;
|
|
1150
|
+
return isRecord(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
|
|
1151
|
+
}
|
|
1152
|
+
__name(toolParentId, "toolParentId");
|
|
1153
|
+
function nestToolCalls(calls) {
|
|
1154
|
+
const byId = new Map(calls.map((call) => [
|
|
1155
|
+
call.toolCallId,
|
|
1156
|
+
call
|
|
1157
|
+
]));
|
|
1158
|
+
const roots = [];
|
|
1159
|
+
for (const call of calls) {
|
|
1160
|
+
const parent = call.parentId !== null ? byId.get(call.parentId) : void 0;
|
|
1161
|
+
if (parent === void 0 || isAncestor(call, parent, byId)) {
|
|
1162
|
+
roots.push(call);
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
parent.children.push(call);
|
|
1166
|
+
}
|
|
1167
|
+
return roots;
|
|
1168
|
+
}
|
|
1169
|
+
__name(nestToolCalls, "nestToolCalls");
|
|
1170
|
+
function isAncestor(call, candidate, byId) {
|
|
1171
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1172
|
+
let current = candidate;
|
|
1173
|
+
while (current !== void 0 && !seen.has(current.toolCallId)) {
|
|
1174
|
+
if (current.toolCallId === call.toolCallId) {
|
|
1175
|
+
return true;
|
|
1176
|
+
}
|
|
1177
|
+
seen.add(current.toolCallId);
|
|
1178
|
+
current = current.parentId !== null ? byId.get(current.parentId) : void 0;
|
|
1179
|
+
}
|
|
1180
|
+
return false;
|
|
1181
|
+
}
|
|
1182
|
+
__name(isAncestor, "isAncestor");
|
|
1183
|
+
function buildToolCall(part, options, approval) {
|
|
1065
1184
|
const toolCallId = part.toolCallId;
|
|
1066
1185
|
const awaiting = isAwaitingApproval(part);
|
|
1067
1186
|
const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
|
|
@@ -1069,6 +1188,10 @@ function buildToolCall(part, options) {
|
|
|
1069
1188
|
part,
|
|
1070
1189
|
toolCallId,
|
|
1071
1190
|
name: (0, import_ai.getToolName)(part),
|
|
1191
|
+
toolKind: toolKind(part) ?? null,
|
|
1192
|
+
parentId: toolParentId(part),
|
|
1193
|
+
children: [],
|
|
1194
|
+
approval,
|
|
1072
1195
|
isAwaitingApproval: awaiting,
|
|
1073
1196
|
approve: {
|
|
1074
1197
|
available: awaiting && options?.canApprove === true,
|
|
@@ -1199,6 +1322,44 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
1199
1322
|
};
|
|
1200
1323
|
}
|
|
1201
1324
|
__name(buildElicitationBlock, "buildElicitationBlock");
|
|
1325
|
+
var UI_PART = "data-ui";
|
|
1326
|
+
var APPROVAL_PART = "data-approval-requested";
|
|
1327
|
+
function readApprovals(parts) {
|
|
1328
|
+
const out = /* @__PURE__ */ new Map();
|
|
1329
|
+
for (const part of parts) {
|
|
1330
|
+
if (part.type !== APPROVAL_PART) {
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
const data = part.data;
|
|
1334
|
+
if (!isRecord(data) || typeof data.id !== "string" || typeof data.approver !== "string") {
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
1337
|
+
out.set(data.id, {
|
|
1338
|
+
approver: data.approver,
|
|
1339
|
+
expiresAt: typeof data.expiresAt === "string" ? data.expiresAt : null,
|
|
1340
|
+
reason: typeof data.reason === "string" ? data.reason : null
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
return out;
|
|
1344
|
+
}
|
|
1345
|
+
__name(readApprovals, "readApprovals");
|
|
1346
|
+
function readUiComponent(part) {
|
|
1347
|
+
const data = part.data;
|
|
1348
|
+
if (!isRecord(data) || typeof data.component !== "string") {
|
|
1349
|
+
return null;
|
|
1350
|
+
}
|
|
1351
|
+
const id = typeof data.id === "string" ? data.id : part.id;
|
|
1352
|
+
if (id === void 0) {
|
|
1353
|
+
return null;
|
|
1354
|
+
}
|
|
1355
|
+
return {
|
|
1356
|
+
id,
|
|
1357
|
+
component: data.component,
|
|
1358
|
+
props: isRecord(data.props) ? data.props : {},
|
|
1359
|
+
version: typeof data.version === "number" ? data.version : null
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
__name(readUiComponent, "readUiComponent");
|
|
1202
1363
|
function isRecord(value) {
|
|
1203
1364
|
return typeof value === "object" && value !== null;
|
|
1204
1365
|
}
|
|
@@ -1892,6 +2053,14 @@ function renderBlocks(item, slots) {
|
|
|
1892
2053
|
}
|
|
1893
2054
|
if (block.kind === "tools") {
|
|
1894
2055
|
nodes.push(...renderToolBlock(item, block, slots));
|
|
2056
|
+
continue;
|
|
2057
|
+
}
|
|
2058
|
+
if (block.kind === "ui" && slots.renderUi) {
|
|
2059
|
+
nodes.push(/* @__PURE__ */ import_react5.default.createElement("div", {
|
|
2060
|
+
key: block.key,
|
|
2061
|
+
"data-slot": "ui",
|
|
2062
|
+
"data-component": block.component
|
|
2063
|
+
}, slots.renderUi(block)));
|
|
1895
2064
|
}
|
|
1896
2065
|
}
|
|
1897
2066
|
return nodes;
|
|
@@ -1999,7 +2168,7 @@ function joinClasses(...entries) {
|
|
|
1999
2168
|
__name(joinClasses, "joinClasses");
|
|
2000
2169
|
|
|
2001
2170
|
// src/components/message-list.tsx
|
|
2002
|
-
function MessageList({ messages, status, renderToolPart, renderToolGroup, renderText, renderReasoning, renderFiles, reasoningLabel, getMeta, onFork, editable, onEditSubmit, regeneratable, onRegenerate, getUsage, getCreatedAt, emptyState, typingIndicator, followUps, onFollowUpClick, error, onRetry, classNames }) {
|
|
2171
|
+
function MessageList({ messages, status, renderToolPart, renderToolGroup, renderText, renderReasoning, renderFiles, renderUi, reasoningLabel, getMeta, onFork, editable, onEditSubmit, regeneratable, onRegenerate, getUsage, getCreatedAt, emptyState, typingIndicator, followUps, onFollowUpClick, error, onRetry, classNames }) {
|
|
2003
2172
|
const transcript = useChatTranscript({
|
|
2004
2173
|
messages,
|
|
2005
2174
|
status,
|
|
@@ -2049,6 +2218,9 @@ function MessageList({ messages, status, renderToolPart, renderToolGroup, render
|
|
|
2049
2218
|
...renderFiles ? {
|
|
2050
2219
|
renderFiles
|
|
2051
2220
|
} : {},
|
|
2221
|
+
...renderUi ? {
|
|
2222
|
+
renderUi
|
|
2223
|
+
} : {},
|
|
2052
2224
|
...reasoningLabel !== void 0 ? {
|
|
2053
2225
|
reasoningLabel
|
|
2054
2226
|
} : {},
|
|
@@ -2703,6 +2875,13 @@ function useAgentChat(options) {
|
|
|
2703
2875
|
...options.initialMessages !== void 0 ? {
|
|
2704
2876
|
messages: options.initialMessages
|
|
2705
2877
|
} : {},
|
|
2878
|
+
onData: /* @__PURE__ */ __name((part) => {
|
|
2879
|
+
latest.current.onData?.(part);
|
|
2880
|
+
if (part.type === "data-title") {
|
|
2881
|
+
const title = part.data?.title;
|
|
2882
|
+
if (typeof title === "string") latest.current.onTitle?.(title);
|
|
2883
|
+
}
|
|
2884
|
+
}, "onData"),
|
|
2706
2885
|
onFinish: /* @__PURE__ */ __name(({ isError }) => {
|
|
2707
2886
|
latest.current.onFinish?.();
|
|
2708
2887
|
if (latest.current.background === true) {
|