@dudousxd/nestjs-agent-react 0.7.4 → 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 +8 -8
package/dist/index.js
CHANGED
|
@@ -140,7 +140,8 @@ var AgentChatTransport = class {
|
|
|
140
140
|
* Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.
|
|
141
141
|
* Recognized frames:
|
|
142
142
|
* - `event: meta` `data: {"runId","threadId"}` → records identity
|
|
143
|
-
* - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool
|
|
143
|
+
* - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool /
|
|
144
|
+
* `data-*`; see {@link AgentChatTransport} docs)
|
|
144
145
|
* - `event: done` `data: {}` → terminates
|
|
145
146
|
* - `event: error` `data: {code,message}` → error chunk
|
|
146
147
|
*
|
|
@@ -157,7 +158,10 @@ var AgentChatTransport = class {
|
|
|
157
158
|
let stepIndex = 0;
|
|
158
159
|
let textId = null;
|
|
159
160
|
let reasoningId = null;
|
|
161
|
+
let textSeq = 0;
|
|
162
|
+
let reasoningSeq = 0;
|
|
160
163
|
const announced = /* @__PURE__ */ new Set();
|
|
164
|
+
const toolMetadata = /* @__PURE__ */ new Map();
|
|
161
165
|
const record = /* @__PURE__ */ __name((meta) => this.recordMeta(meta), "record");
|
|
162
166
|
const endAttempt = /* @__PURE__ */ __name(() => {
|
|
163
167
|
this.attemptLive = false;
|
|
@@ -179,6 +183,8 @@ var AgentChatTransport = class {
|
|
|
179
183
|
stepIndex += 1;
|
|
180
184
|
textId = null;
|
|
181
185
|
reasoningId = null;
|
|
186
|
+
textSeq = 0;
|
|
187
|
+
reasoningSeq = 0;
|
|
182
188
|
controller.enqueue({
|
|
183
189
|
type: "start-step"
|
|
184
190
|
});
|
|
@@ -188,8 +194,7 @@ var AgentChatTransport = class {
|
|
|
188
194
|
if (!stepOpen) openStep();
|
|
189
195
|
}
|
|
190
196
|
__name(ensureStep, "ensureStep");
|
|
191
|
-
function
|
|
192
|
-
if (!stepOpen) return;
|
|
197
|
+
function closeRuns() {
|
|
193
198
|
if (textId !== null) {
|
|
194
199
|
controller.enqueue({
|
|
195
200
|
type: "text-end",
|
|
@@ -204,12 +209,43 @@ var AgentChatTransport = class {
|
|
|
204
209
|
});
|
|
205
210
|
reasoningId = null;
|
|
206
211
|
}
|
|
212
|
+
}
|
|
213
|
+
__name(closeRuns, "closeRuns");
|
|
214
|
+
function closeStep() {
|
|
215
|
+
if (!stepOpen) return;
|
|
216
|
+
closeRuns();
|
|
207
217
|
controller.enqueue({
|
|
208
218
|
type: "finish-step"
|
|
209
219
|
});
|
|
210
220
|
stepOpen = false;
|
|
211
221
|
}
|
|
212
222
|
__name(closeStep, "closeStep");
|
|
223
|
+
function metadataFor(id, toolKind2, parentId) {
|
|
224
|
+
const merged = {
|
|
225
|
+
...toolMetadata.get(id)
|
|
226
|
+
};
|
|
227
|
+
if (toolKind2 !== void 0) merged.toolKind = toolKind2;
|
|
228
|
+
if (parentId !== void 0 && merged.parentId === void 0) merged.parentId = parentId;
|
|
229
|
+
if (Object.keys(merged).length === 0) return void 0;
|
|
230
|
+
toolMetadata.set(id, merged);
|
|
231
|
+
return merged;
|
|
232
|
+
}
|
|
233
|
+
__name(metadataFor, "metadataFor");
|
|
234
|
+
function forwardAsData(event, transient) {
|
|
235
|
+
ensureStarted();
|
|
236
|
+
const { kind, ...data } = event;
|
|
237
|
+
controller.enqueue({
|
|
238
|
+
type: `data-${kind}`,
|
|
239
|
+
...typeof data.id === "string" ? {
|
|
240
|
+
id: data.id
|
|
241
|
+
} : {},
|
|
242
|
+
data,
|
|
243
|
+
...transient ? {
|
|
244
|
+
transient: true
|
|
245
|
+
} : {}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
__name(forwardAsData, "forwardAsData");
|
|
213
249
|
function emit(event) {
|
|
214
250
|
switch (event.kind) {
|
|
215
251
|
case "step-start":
|
|
@@ -229,7 +265,8 @@ var AgentChatTransport = class {
|
|
|
229
265
|
case "text":
|
|
230
266
|
ensureStep();
|
|
231
267
|
if (textId === null) {
|
|
232
|
-
textId = `txt-${stepIndex}`;
|
|
268
|
+
textId = textSeq === 0 ? `txt-${stepIndex}` : `txt-${stepIndex}.${textSeq}`;
|
|
269
|
+
textSeq += 1;
|
|
233
270
|
controller.enqueue({
|
|
234
271
|
type: "text-start",
|
|
235
272
|
id: textId
|
|
@@ -244,7 +281,8 @@ var AgentChatTransport = class {
|
|
|
244
281
|
case "reasoning":
|
|
245
282
|
ensureStep();
|
|
246
283
|
if (reasoningId === null) {
|
|
247
|
-
reasoningId = `rsn-${stepIndex}`;
|
|
284
|
+
reasoningId = reasoningSeq === 0 ? `rsn-${stepIndex}` : `rsn-${stepIndex}.${reasoningSeq}`;
|
|
285
|
+
reasoningSeq += 1;
|
|
248
286
|
controller.enqueue({
|
|
249
287
|
type: "reasoning-start",
|
|
250
288
|
id: reasoningId
|
|
@@ -256,23 +294,20 @@ var AgentChatTransport = class {
|
|
|
256
294
|
delta: event.text
|
|
257
295
|
});
|
|
258
296
|
break;
|
|
259
|
-
case "tool-input-start":
|
|
297
|
+
case "tool-input-start": {
|
|
260
298
|
ensureStep();
|
|
261
299
|
announced.add(event.id);
|
|
300
|
+
const metadata = metadataFor(event.id, event.toolKind, event.parentId);
|
|
262
301
|
controller.enqueue({
|
|
263
302
|
type: "tool-input-start",
|
|
264
303
|
toolCallId: event.id,
|
|
265
304
|
toolName: event.name,
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
// UI gate approval affordances on `kind === 'action'` without hardcoding tool names.
|
|
269
|
-
...event.toolKind !== void 0 ? {
|
|
270
|
-
toolMetadata: {
|
|
271
|
-
toolKind: event.toolKind
|
|
272
|
-
}
|
|
305
|
+
...metadata !== void 0 ? {
|
|
306
|
+
toolMetadata: metadata
|
|
273
307
|
} : {}
|
|
274
308
|
});
|
|
275
309
|
break;
|
|
310
|
+
}
|
|
276
311
|
case "tool-input-delta":
|
|
277
312
|
ensureStep();
|
|
278
313
|
controller.enqueue({
|
|
@@ -281,21 +316,21 @@ var AgentChatTransport = class {
|
|
|
281
316
|
inputTextDelta: event.delta
|
|
282
317
|
});
|
|
283
318
|
break;
|
|
284
|
-
case "tool-input-available":
|
|
319
|
+
case "tool-input-available": {
|
|
285
320
|
ensureStep();
|
|
286
321
|
announced.add(event.id);
|
|
322
|
+
const metadata = metadataFor(event.id, event.toolKind, event.parentId);
|
|
287
323
|
controller.enqueue({
|
|
288
324
|
type: "tool-input-available",
|
|
289
325
|
toolCallId: event.id,
|
|
290
326
|
toolName: event.name,
|
|
291
327
|
input: event.input,
|
|
292
|
-
...
|
|
293
|
-
toolMetadata:
|
|
294
|
-
toolKind: event.toolKind
|
|
295
|
-
}
|
|
328
|
+
...metadata !== void 0 ? {
|
|
329
|
+
toolMetadata: metadata
|
|
296
330
|
} : {}
|
|
297
331
|
});
|
|
298
332
|
break;
|
|
333
|
+
}
|
|
299
334
|
case "elicitation":
|
|
300
335
|
ensureStep();
|
|
301
336
|
if (!announced.has(event.id)) {
|
|
@@ -336,7 +371,39 @@ var AgentChatTransport = class {
|
|
|
336
371
|
toolCallId: event.id
|
|
337
372
|
});
|
|
338
373
|
break;
|
|
374
|
+
case "approval-requested":
|
|
375
|
+
ensureStep();
|
|
376
|
+
forwardAsData(event, false);
|
|
377
|
+
if (announced.has(event.id)) {
|
|
378
|
+
controller.enqueue({
|
|
379
|
+
type: "tool-approval-request",
|
|
380
|
+
approvalId: event.id,
|
|
381
|
+
toolCallId: event.id
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
break;
|
|
385
|
+
case "ui":
|
|
386
|
+
ensureStep();
|
|
387
|
+
closeRuns();
|
|
388
|
+
controller.enqueue({
|
|
389
|
+
type: "data-ui",
|
|
390
|
+
id: event.id,
|
|
391
|
+
data: {
|
|
392
|
+
id: event.id,
|
|
393
|
+
component: event.component,
|
|
394
|
+
props: event.props,
|
|
395
|
+
...event.version !== void 0 ? {
|
|
396
|
+
version: event.version
|
|
397
|
+
} : {}
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
break;
|
|
401
|
+
case "title":
|
|
402
|
+
case "cancelled":
|
|
403
|
+
forwardAsData(event, true);
|
|
404
|
+
break;
|
|
339
405
|
default:
|
|
406
|
+
forwardAsData(event, false);
|
|
340
407
|
break;
|
|
341
408
|
}
|
|
342
409
|
}
|
|
@@ -832,7 +899,7 @@ import React3 from "react";
|
|
|
832
899
|
import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
|
|
833
900
|
|
|
834
901
|
// src/transcript/model.ts
|
|
835
|
-
import { getToolName, isFileUIPart, isReasoningUIPart, isTextUIPart, isToolUIPart } from "ai";
|
|
902
|
+
import { getToolName, isDataUIPart, isFileUIPart, isReasoningUIPart, isTextUIPart, isToolUIPart } from "ai";
|
|
836
903
|
function buildTranscriptBlocks(message, options) {
|
|
837
904
|
const blocks = [];
|
|
838
905
|
let toolBuffer = [];
|
|
@@ -844,15 +911,18 @@ function buildTranscriptBlocks(message, options) {
|
|
|
844
911
|
let reasoningCounter = 0;
|
|
845
912
|
let sourcesCounter = 0;
|
|
846
913
|
let elicitationCounter = 0;
|
|
914
|
+
const approvals = readApprovals(message.parts ?? []);
|
|
847
915
|
function flushTools() {
|
|
848
916
|
if (toolBuffer.length === 0) {
|
|
849
917
|
return;
|
|
850
918
|
}
|
|
919
|
+
const calls = toolBuffer.map((part) => buildToolCall(part, options.approval, approvals.get(part.toolCallId) ?? null));
|
|
851
920
|
blocks.push({
|
|
852
921
|
kind: "tools",
|
|
853
922
|
key: `${message.id}-tools-${toolCounter++}`,
|
|
854
923
|
parts: toolBuffer,
|
|
855
|
-
calls
|
|
924
|
+
calls,
|
|
925
|
+
roots: nestToolCalls(calls)
|
|
856
926
|
});
|
|
857
927
|
toolBuffer = [];
|
|
858
928
|
}
|
|
@@ -915,7 +985,21 @@ function buildTranscriptBlocks(message, options) {
|
|
|
915
985
|
fileBuffer.push(part);
|
|
916
986
|
continue;
|
|
917
987
|
}
|
|
988
|
+
if (part.type === APPROVAL_PART) {
|
|
989
|
+
continue;
|
|
990
|
+
}
|
|
918
991
|
flushAll();
|
|
992
|
+
if (isDataUIPart(part)) {
|
|
993
|
+
const ui = part.type === UI_PART ? readUiComponent(part) : null;
|
|
994
|
+
if (ui !== null) {
|
|
995
|
+
blocks.push({
|
|
996
|
+
kind: "ui",
|
|
997
|
+
key: `${message.id}-ui-${ui.id}`,
|
|
998
|
+
...ui
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
continue;
|
|
1002
|
+
}
|
|
919
1003
|
if (isTextUIPart(part)) {
|
|
920
1004
|
blocks.push({
|
|
921
1005
|
kind: "text",
|
|
@@ -999,7 +1083,42 @@ function isAwaitingApproval(part) {
|
|
|
999
1083
|
return toolKind(part) === "action" && readElicitationRequest(part) === null;
|
|
1000
1084
|
}
|
|
1001
1085
|
__name(isAwaitingApproval, "isAwaitingApproval");
|
|
1002
|
-
function
|
|
1086
|
+
function toolParentId(part) {
|
|
1087
|
+
const metadata = part.toolMetadata;
|
|
1088
|
+
return isRecord(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
|
|
1089
|
+
}
|
|
1090
|
+
__name(toolParentId, "toolParentId");
|
|
1091
|
+
function nestToolCalls(calls) {
|
|
1092
|
+
const byId = new Map(calls.map((call) => [
|
|
1093
|
+
call.toolCallId,
|
|
1094
|
+
call
|
|
1095
|
+
]));
|
|
1096
|
+
const roots = [];
|
|
1097
|
+
for (const call of calls) {
|
|
1098
|
+
const parent = call.parentId !== null ? byId.get(call.parentId) : void 0;
|
|
1099
|
+
if (parent === void 0 || isAncestor(call, parent, byId)) {
|
|
1100
|
+
roots.push(call);
|
|
1101
|
+
continue;
|
|
1102
|
+
}
|
|
1103
|
+
parent.children.push(call);
|
|
1104
|
+
}
|
|
1105
|
+
return roots;
|
|
1106
|
+
}
|
|
1107
|
+
__name(nestToolCalls, "nestToolCalls");
|
|
1108
|
+
function isAncestor(call, candidate, byId) {
|
|
1109
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1110
|
+
let current = candidate;
|
|
1111
|
+
while (current !== void 0 && !seen.has(current.toolCallId)) {
|
|
1112
|
+
if (current.toolCallId === call.toolCallId) {
|
|
1113
|
+
return true;
|
|
1114
|
+
}
|
|
1115
|
+
seen.add(current.toolCallId);
|
|
1116
|
+
current = current.parentId !== null ? byId.get(current.parentId) : void 0;
|
|
1117
|
+
}
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
__name(isAncestor, "isAncestor");
|
|
1121
|
+
function buildToolCall(part, options, approval) {
|
|
1003
1122
|
const toolCallId = part.toolCallId;
|
|
1004
1123
|
const awaiting = isAwaitingApproval(part);
|
|
1005
1124
|
const sending = awaiting ? options?.submitting(toolCallId) ?? null : null;
|
|
@@ -1007,6 +1126,10 @@ function buildToolCall(part, options) {
|
|
|
1007
1126
|
part,
|
|
1008
1127
|
toolCallId,
|
|
1009
1128
|
name: getToolName(part),
|
|
1129
|
+
toolKind: toolKind(part) ?? null,
|
|
1130
|
+
parentId: toolParentId(part),
|
|
1131
|
+
children: [],
|
|
1132
|
+
approval,
|
|
1010
1133
|
isAwaitingApproval: awaiting,
|
|
1011
1134
|
approve: {
|
|
1012
1135
|
available: awaiting && options?.canApprove === true,
|
|
@@ -1137,6 +1260,44 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
1137
1260
|
};
|
|
1138
1261
|
}
|
|
1139
1262
|
__name(buildElicitationBlock, "buildElicitationBlock");
|
|
1263
|
+
var UI_PART = "data-ui";
|
|
1264
|
+
var APPROVAL_PART = "data-approval-requested";
|
|
1265
|
+
function readApprovals(parts) {
|
|
1266
|
+
const out = /* @__PURE__ */ new Map();
|
|
1267
|
+
for (const part of parts) {
|
|
1268
|
+
if (part.type !== APPROVAL_PART) {
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
const data = part.data;
|
|
1272
|
+
if (!isRecord(data) || typeof data.id !== "string" || typeof data.approver !== "string") {
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
out.set(data.id, {
|
|
1276
|
+
approver: data.approver,
|
|
1277
|
+
expiresAt: typeof data.expiresAt === "string" ? data.expiresAt : null,
|
|
1278
|
+
reason: typeof data.reason === "string" ? data.reason : null
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
return out;
|
|
1282
|
+
}
|
|
1283
|
+
__name(readApprovals, "readApprovals");
|
|
1284
|
+
function readUiComponent(part) {
|
|
1285
|
+
const data = part.data;
|
|
1286
|
+
if (!isRecord(data) || typeof data.component !== "string") {
|
|
1287
|
+
return null;
|
|
1288
|
+
}
|
|
1289
|
+
const id = typeof data.id === "string" ? data.id : part.id;
|
|
1290
|
+
if (id === void 0) {
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
return {
|
|
1294
|
+
id,
|
|
1295
|
+
component: data.component,
|
|
1296
|
+
props: isRecord(data.props) ? data.props : {},
|
|
1297
|
+
version: typeof data.version === "number" ? data.version : null
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
__name(readUiComponent, "readUiComponent");
|
|
1140
1301
|
function isRecord(value) {
|
|
1141
1302
|
return typeof value === "object" && value !== null;
|
|
1142
1303
|
}
|
|
@@ -1830,6 +1991,14 @@ function renderBlocks(item, slots) {
|
|
|
1830
1991
|
}
|
|
1831
1992
|
if (block.kind === "tools") {
|
|
1832
1993
|
nodes.push(...renderToolBlock(item, block, slots));
|
|
1994
|
+
continue;
|
|
1995
|
+
}
|
|
1996
|
+
if (block.kind === "ui" && slots.renderUi) {
|
|
1997
|
+
nodes.push(/* @__PURE__ */ React3.createElement("div", {
|
|
1998
|
+
key: block.key,
|
|
1999
|
+
"data-slot": "ui",
|
|
2000
|
+
"data-component": block.component
|
|
2001
|
+
}, slots.renderUi(block)));
|
|
1833
2002
|
}
|
|
1834
2003
|
}
|
|
1835
2004
|
return nodes;
|
|
@@ -1937,7 +2106,7 @@ function joinClasses(...entries) {
|
|
|
1937
2106
|
__name(joinClasses, "joinClasses");
|
|
1938
2107
|
|
|
1939
2108
|
// src/components/message-list.tsx
|
|
1940
|
-
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 }) {
|
|
2109
|
+
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 }) {
|
|
1941
2110
|
const transcript = useChatTranscript({
|
|
1942
2111
|
messages,
|
|
1943
2112
|
status,
|
|
@@ -1987,6 +2156,9 @@ function MessageList({ messages, status, renderToolPart, renderToolGroup, render
|
|
|
1987
2156
|
...renderFiles ? {
|
|
1988
2157
|
renderFiles
|
|
1989
2158
|
} : {},
|
|
2159
|
+
...renderUi ? {
|
|
2160
|
+
renderUi
|
|
2161
|
+
} : {},
|
|
1990
2162
|
...reasoningLabel !== void 0 ? {
|
|
1991
2163
|
reasoningLabel
|
|
1992
2164
|
} : {},
|
|
@@ -2641,6 +2813,13 @@ function useAgentChat(options) {
|
|
|
2641
2813
|
...options.initialMessages !== void 0 ? {
|
|
2642
2814
|
messages: options.initialMessages
|
|
2643
2815
|
} : {},
|
|
2816
|
+
onData: /* @__PURE__ */ __name((part) => {
|
|
2817
|
+
latest.current.onData?.(part);
|
|
2818
|
+
if (part.type === "data-title") {
|
|
2819
|
+
const title = part.data?.title;
|
|
2820
|
+
if (typeof title === "string") latest.current.onTitle?.(title);
|
|
2821
|
+
}
|
|
2822
|
+
}, "onData"),
|
|
2644
2823
|
onFinish: /* @__PURE__ */ __name(({ isError }) => {
|
|
2645
2824
|
latest.current.onFinish?.();
|
|
2646
2825
|
if (latest.current.background === true) {
|