@dudousxd/nestjs-agent-react 0.3.2 → 0.3.3

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/index.cjs CHANGED
@@ -147,18 +147,26 @@ var AgentChatTransport = class {
147
147
  this.options.onMeta?.(meta);
148
148
  }
149
149
  /**
150
- * Parse the backend's SSE byte stream and synthesize a valid v7
151
- * UI-message chunk stream. Recognized backend frames:
152
- * - `event: meta` `data: {"runId","threadId"}` → records identity
153
- * - `data: {"delta":"..."}` → `text-delta`
154
- * - `event: done` `data: {}` → terminates
150
+ * Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.
151
+ * Recognized frames:
152
+ * - `event: meta` `data: {"runId","threadId"}` → records identity
153
+ * - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool)
154
+ * - `event: done` `data: {}` → terminates
155
+ * - `event: error` `data: {code,message}` → error chunk
156
+ *
157
+ * A run is ONE UI message with N steps. Each `step-start`/`step-finish` pair brackets a model
158
+ * call plus its tool execution; text and reasoning open lazily and close at the step boundary, so
159
+ * tool-call cards (input streaming → output) render live between the prose.
155
160
  */
156
161
  toChunkStream(source) {
157
162
  const reader = source.getReader();
158
163
  const decoder = new TextDecoder();
159
- const textId = `txt-${Math.random().toString(36).slice(2)}`;
160
164
  let buffer = "";
161
165
  let started = false;
166
+ let stepOpen = false;
167
+ let stepIndex = 0;
168
+ let textId = null;
169
+ let reasoningId = null;
162
170
  const record = /* @__PURE__ */ __name((meta) => this.recordMeta(meta), "record");
163
171
  return new ReadableStream({
164
172
  async pull(controller) {
@@ -168,24 +176,133 @@ var AgentChatTransport = class {
168
176
  controller.enqueue({
169
177
  type: "start"
170
178
  });
171
- controller.enqueue({
172
- type: "start-step"
173
- });
174
- controller.enqueue({
175
- type: "text-start",
176
- id: textId
177
- });
178
179
  }
179
180
  __name(ensureStarted, "ensureStarted");
180
- function finish() {
181
+ function openStep() {
181
182
  ensureStarted();
183
+ if (stepOpen) closeStep();
184
+ stepOpen = true;
185
+ stepIndex += 1;
186
+ textId = null;
187
+ reasoningId = null;
182
188
  controller.enqueue({
183
- type: "text-end",
184
- id: textId
189
+ type: "start-step"
185
190
  });
191
+ }
192
+ __name(openStep, "openStep");
193
+ function ensureStep() {
194
+ if (!stepOpen) openStep();
195
+ }
196
+ __name(ensureStep, "ensureStep");
197
+ function closeStep() {
198
+ if (!stepOpen) return;
199
+ if (textId !== null) {
200
+ controller.enqueue({
201
+ type: "text-end",
202
+ id: textId
203
+ });
204
+ textId = null;
205
+ }
206
+ if (reasoningId !== null) {
207
+ controller.enqueue({
208
+ type: "reasoning-end",
209
+ id: reasoningId
210
+ });
211
+ reasoningId = null;
212
+ }
186
213
  controller.enqueue({
187
214
  type: "finish-step"
188
215
  });
216
+ stepOpen = false;
217
+ }
218
+ __name(closeStep, "closeStep");
219
+ function emit(event) {
220
+ switch (event.kind) {
221
+ case "step-start":
222
+ openStep();
223
+ break;
224
+ case "step-finish":
225
+ closeStep();
226
+ break;
227
+ case "text":
228
+ ensureStep();
229
+ if (textId === null) {
230
+ textId = `txt-${stepIndex}`;
231
+ controller.enqueue({
232
+ type: "text-start",
233
+ id: textId
234
+ });
235
+ }
236
+ controller.enqueue({
237
+ type: "text-delta",
238
+ id: textId,
239
+ delta: event.text
240
+ });
241
+ break;
242
+ case "reasoning":
243
+ ensureStep();
244
+ if (reasoningId === null) {
245
+ reasoningId = `rsn-${stepIndex}`;
246
+ controller.enqueue({
247
+ type: "reasoning-start",
248
+ id: reasoningId
249
+ });
250
+ }
251
+ controller.enqueue({
252
+ type: "reasoning-delta",
253
+ id: reasoningId,
254
+ delta: event.text
255
+ });
256
+ break;
257
+ case "tool-input-start":
258
+ ensureStep();
259
+ controller.enqueue({
260
+ type: "tool-input-start",
261
+ toolCallId: event.id,
262
+ toolName: event.name
263
+ });
264
+ break;
265
+ case "tool-input-delta":
266
+ ensureStep();
267
+ controller.enqueue({
268
+ type: "tool-input-delta",
269
+ toolCallId: event.id,
270
+ inputTextDelta: event.delta
271
+ });
272
+ break;
273
+ case "tool-input-available":
274
+ ensureStep();
275
+ controller.enqueue({
276
+ type: "tool-input-available",
277
+ toolCallId: event.id,
278
+ toolName: event.name,
279
+ input: event.input
280
+ });
281
+ break;
282
+ case "tool-output":
283
+ ensureStep();
284
+ controller.enqueue({
285
+ type: "tool-output-available",
286
+ toolCallId: event.id,
287
+ output: event.output
288
+ });
289
+ break;
290
+ case "tool-output-error":
291
+ ensureStep();
292
+ controller.enqueue({
293
+ type: "tool-output-error",
294
+ toolCallId: event.id,
295
+ errorText: event.error
296
+ });
297
+ break;
298
+ default:
299
+ break;
300
+ }
301
+ }
302
+ __name(emit, "emit");
303
+ function finish() {
304
+ ensureStarted();
305
+ closeStep();
189
306
  controller.enqueue({
190
307
  type: "finish"
191
308
  });
@@ -224,15 +341,8 @@ var AgentChatTransport = class {
224
341
  const meta = parseMeta(frame.data);
225
342
  if (meta) record(meta);
226
343
  } else if (frame.data) {
227
- const delta = parseDelta(frame.data);
228
- if (delta) {
229
- ensureStarted();
230
- controller.enqueue({
231
- type: "text-delta",
232
- id: textId,
233
- delta
234
- });
235
- }
344
+ const event = parseEvent(frame.data);
345
+ if (event) emit(event);
236
346
  }
237
347
  separator = buffer.indexOf("\n\n");
238
348
  }
@@ -294,17 +404,17 @@ function parseErrorText(data) {
294
404
  return "Agent run failed";
295
405
  }
296
406
  __name(parseErrorText, "parseErrorText");
297
- function parseDelta(data) {
407
+ function parseEvent(data) {
298
408
  try {
299
409
  const parsed = JSON.parse(data);
300
- if (parsed !== null && typeof parsed === "object" && "delta" in parsed && typeof parsed.delta === "string") {
301
- return parsed.delta;
410
+ if (parsed !== null && typeof parsed === "object" && "kind" in parsed) {
411
+ return parsed;
302
412
  }
303
413
  } catch {
304
414
  }
305
415
  return null;
306
416
  }
307
- __name(parseDelta, "parseDelta");
417
+ __name(parseEvent, "parseEvent");
308
418
  function extractText(message) {
309
419
  let text = "";
310
420
  for (const part of message.parts ?? []) {
@@ -411,6 +521,7 @@ function useAgentChat(options) {
411
521
  const runIdRef = (0, import_react2.useRef)(runId);
412
522
  runIdRef.current = runId;
413
523
  const regenerateNext = (0, import_react2.useRef)(false);
524
+ const createdThreadId = (0, import_react2.useRef)(void 0);
414
525
  const client = (0, import_react2.useMemo)(() => {
415
526
  if (options.client) return options.client;
416
527
  return new AgentClient({
@@ -429,6 +540,10 @@ function useAgentChat(options) {
429
540
  const transport = (0, import_react2.useMemo)(() => {
430
541
  function onMeta(meta) {
431
542
  setRunId(meta.runId);
543
+ if (latest.current.threadId === void 0 && meta.threadId && createdThreadId.current !== meta.threadId) {
544
+ createdThreadId.current = meta.threadId;
545
+ latest.current.onThreadCreated?.(meta.threadId);
546
+ }
432
547
  }
433
548
  __name(onMeta, "onMeta");
434
549
  return new AgentChatTransport({
@@ -450,9 +565,10 @@ function useAgentChat(options) {
450
565
  const pageContext = current.getPageContext?.() ?? null;
451
566
  const regenerate2 = regenerateNext.current;
452
567
  regenerateNext.current = false;
568
+ const threadId = current.threadId ?? createdThreadId.current;
453
569
  return {
454
- ...current.threadId !== void 0 ? {
455
- threadId: current.threadId
570
+ ...threadId !== void 0 ? {
571
+ threadId
456
572
  } : {},
457
573
  ...pageContext ? {
458
574
  pageContext