@dudousxd/nestjs-agent-react 0.34.1 → 0.34.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
@@ -1064,7 +1064,10 @@ var AgentChatTransport = class {
1064
1064
  forwardAsData(event, true);
1065
1065
  break;
1066
1066
  default:
1067
- forwardAsData(event, false);
1067
+ forwardAsData(
1068
+ event,
1069
+ event.kind === "proposal-decision"
1070
+ );
1068
1071
  break;
1069
1072
  }
1070
1073
  }
@@ -2079,8 +2082,33 @@ function defaultForwardedProps(body) {
2079
2082
  for (const key of ["pageContext", "agent", "model", "persona", "uiCapabilities"]) {
2080
2083
  if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
2081
2084
  }
2085
+ if (body.regenerate === true) out.regenerate = true;
2082
2086
  return Object.keys(out).length > 0 ? out : void 0;
2083
2087
  }
2088
+ var MEDIA_PROVIDER = "nestjs-agent";
2089
+ function partTypeFor(contentType) {
2090
+ const major = contentType?.split("/")[0]?.toLowerCase();
2091
+ return major === "image" || major === "audio" || major === "video" ? major : "document";
2092
+ }
2093
+ function defaultContent(body, message) {
2094
+ const attachments = Array.isArray(body.attachments) ? body.attachments : [];
2095
+ const files = [];
2096
+ for (const attachment of attachments) {
2097
+ if (!isRecord2(attachment) || typeof attachment.mediaId !== "string") continue;
2098
+ const contentType = typeof attachment.contentType === "string" ? attachment.contentType : void 0;
2099
+ files.push({
2100
+ type: partTypeFor(contentType),
2101
+ source: {
2102
+ type: "file",
2103
+ value: attachment.mediaId,
2104
+ provider: MEDIA_PROVIDER,
2105
+ ...contentType !== void 0 ? { mimeType: contentType } : {}
2106
+ }
2107
+ });
2108
+ }
2109
+ if (files.length === 0) return message;
2110
+ return [...message.length > 0 ? [{ type: "text", text: message }] : [], ...files];
2111
+ }
2084
2112
  async function agUiChatStream(request, options) {
2085
2113
  const body = request.body;
2086
2114
  const threadId = typeof body.threadId === "string" ? body.threadId : newId();
@@ -2090,7 +2118,13 @@ async function agUiChatStream(request, options) {
2090
2118
  threadId,
2091
2119
  runId: newId(),
2092
2120
  protocolVersion: "1.0",
2093
- messages: [{ id: newId(), role: "user", content: options.content?.(body) ?? message }],
2121
+ messages: [
2122
+ {
2123
+ id: newId(),
2124
+ role: "user",
2125
+ content: options.content?.(body) ?? defaultContent(body, message)
2126
+ }
2127
+ ],
2094
2128
  ...forwarded !== void 0 ? { forwardedProps: forwarded } : {}
2095
2129
  };
2096
2130
  const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
@@ -2127,6 +2161,8 @@ function reframeAgUiStream(source, ids) {
2127
2161
  for (; ; ) {
2128
2162
  const { value, done } = await reader.read();
2129
2163
  if (done) {
2164
+ const rest = reframer.flush();
2165
+ if (rest.length > 0) controller.enqueue(encoder.encode(rest));
2130
2166
  controller.close();
2131
2167
  return;
2132
2168
  }
@@ -2137,7 +2173,10 @@ function reframeAgUiStream(source, ids) {
2137
2173
  const block = buffer.slice(0, separator);
2138
2174
  buffer = buffer.slice(separator + 2);
2139
2175
  separator = buffer.indexOf("\n\n");
2140
- const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
2176
+ const lines = block.split("\n");
2177
+ const idLine = lines.find((line) => line.startsWith("id:"));
2178
+ const id = idLine === void 0 ? void 0 : Number(idLine.slice(3).trim());
2179
+ const data = lines.filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
2141
2180
  if (data.length === 0) continue;
2142
2181
  let event;
2143
2182
  try {
@@ -2146,7 +2185,10 @@ function reframeAgUiStream(source, ids) {
2146
2185
  continue;
2147
2186
  }
2148
2187
  if (isRecord2(event) && typeof event.type === "string") {
2149
- out += reframer.push(event);
2188
+ out += reframer.push(
2189
+ event,
2190
+ id !== void 0 && Number.isSafeInteger(id) && id > 0 ? id : void 0
2191
+ );
2150
2192
  }
2151
2193
  if (reframer.closed) break;
2152
2194
  }
@@ -2166,21 +2208,55 @@ function reframeAgUiStream(source, ids) {
2166
2208
  }
2167
2209
  function createReframer(threadId) {
2168
2210
  const activities = /* @__PURE__ */ new Map();
2169
- let seq = 0;
2170
2211
  let metaSent = false;
2171
2212
  const tools = /* @__PURE__ */ new Map();
2213
+ let pendingStep;
2214
+ const encodeFrame = (streamEvent) => `data: ${JSON.stringify(streamEvent)}
2215
+
2216
+ `;
2217
+ const flushStep = () => {
2218
+ if (pendingStep === void 0) return "";
2219
+ const step = pendingStep;
2220
+ pendingStep = void 0;
2221
+ return encodeFrame(step);
2222
+ };
2223
+ let current;
2224
+ let written;
2225
+ const cursor = () => {
2226
+ if (current === void 0 || current === written) return "";
2227
+ written = current;
2228
+ return `${flushStep()}id: ${current}
2229
+
2230
+ `;
2231
+ };
2232
+ const shown = /* @__PURE__ */ new Set();
2233
+ let decision;
2172
2234
  const state = {
2173
2235
  closed: false,
2174
- push(event) {
2236
+ flush() {
2237
+ return state.closed ? "" : `${flushStep()}${cursor()}`;
2238
+ },
2239
+ push(event, id) {
2175
2240
  if (state.closed) return "";
2176
2241
  let out = "";
2242
+ if (id !== void 0) {
2243
+ if (current !== void 0 && id > current) out += cursor();
2244
+ current = id;
2245
+ }
2177
2246
  const frame = (streamEvent) => {
2178
- seq += 1;
2179
- out += `id: ${seq}
2180
- data: ${JSON.stringify(streamEvent)}
2181
-
2182
- `;
2247
+ out += encodeFrame(streamEvent);
2183
2248
  };
2249
+ if (event.type === "CUSTOM" && event.name === "agora.step-usage" && pendingStep !== void 0 && isRecord2(event.value)) {
2250
+ const value = event.value;
2251
+ if (isRecord2(value.usage)) pendingStep.usage = value.usage;
2252
+ if (typeof value.costUsd === "number" || value.costUsd === null) {
2253
+ pendingStep.costUsd = value.costUsd;
2254
+ }
2255
+ if (typeof value.reasoningMs === "number") pendingStep.reasoningMs = value.reasoningMs;
2256
+ out += flushStep();
2257
+ return out;
2258
+ }
2259
+ out += flushStep();
2184
2260
  const meta = (runId, thread) => {
2185
2261
  if (metaSent) return;
2186
2262
  metaSent = true;
@@ -2210,9 +2286,24 @@ data: ${JSON.stringify({
2210
2286
  frame({ kind: "title", title: value.title });
2211
2287
  } else if (event.name === "agora.queue") frame({ kind: "queue", ...value });
2212
2288
  else if (event.name === "agora.approval-requested") {
2289
+ if (typeof value.id === "string") shown.add(value.id);
2213
2290
  frame({ ...value, kind: "approval-requested" });
2214
2291
  } else if (event.name === "agora.approval-settled") {
2215
2292
  frame({ ...value, kind: "approval-settled" });
2293
+ } else if (event.name === "agora.elicitation" && typeof value.id === "string" && isRecord2(value.request) && Array.isArray(value.request.questions)) {
2294
+ shown.add(value.id);
2295
+ if (typeof value.request.id === "string") shown.add(value.request.id);
2296
+ frame({
2297
+ kind: "elicitation",
2298
+ id: value.id,
2299
+ request: value.request
2300
+ });
2301
+ } else if (event.name === "agora.action-proposal-decision") {
2302
+ decision = {
2303
+ threadId: value.threadId,
2304
+ proposalDecision: value.proposalDecision,
2305
+ text: ""
2306
+ };
2216
2307
  }
2217
2308
  return out;
2218
2309
  }
@@ -2222,6 +2313,9 @@ data: ${JSON.stringify({
2222
2313
  switch (event.type) {
2223
2314
  case "TEXT_MESSAGE_CONTENT":
2224
2315
  case "TEXT_MESSAGE_CHUNK":
2316
+ if (decision !== void 0 && typeof event.delta === "string") {
2317
+ decision.text += event.delta;
2318
+ }
2225
2319
  if (typeof event.delta === "string" && event.delta.length > 0) {
2226
2320
  frame({ kind: "text", text: event.delta });
2227
2321
  }
@@ -2236,20 +2330,34 @@ data: ${JSON.stringify({
2236
2330
  frame({ kind: "step-start" });
2237
2331
  break;
2238
2332
  case "STEP_FINISHED":
2239
- frame({ kind: "step-finish" });
2333
+ pendingStep = { kind: "step-finish" };
2240
2334
  break;
2241
2335
  case "TOOL_CALL_START":
2242
2336
  case "TOOL_CALL_CHUNK": {
2243
- const id = String(event.toolCallId ?? "");
2244
- if (id === "") break;
2245
- if (!tools.has(id)) {
2337
+ const id2 = String(event.toolCallId ?? "");
2338
+ if (id2 === "") break;
2339
+ if (!tools.has(id2)) {
2246
2340
  const name = typeof event.toolCallName === "string" ? event.toolCallName : "";
2247
- tools.set(id, { name, args: "" });
2248
- frame({ kind: "tool-input-start", id, name, toolKind: "read" });
2341
+ const metadata = isRecord2(event.metadata) ? event.metadata : {};
2342
+ const toolKind2 = metadata["agora.toolKind"] === "action" ? "action" : "read";
2343
+ const parentId = typeof metadata["agora.parentId"] === "string" ? metadata["agora.parentId"] : void 0;
2344
+ tools.set(id2, {
2345
+ name,
2346
+ args: "",
2347
+ toolKind: toolKind2,
2348
+ ...parentId !== void 0 ? { parentId } : {}
2349
+ });
2350
+ frame({
2351
+ kind: "tool-input-start",
2352
+ id: id2,
2353
+ name,
2354
+ toolKind: toolKind2,
2355
+ ...parentId !== void 0 ? { parentId } : {}
2356
+ });
2249
2357
  }
2250
2358
  if (event.type === "TOOL_CALL_CHUNK" && typeof event.delta === "string") {
2251
- tools.get(id).args += event.delta;
2252
- frame({ kind: "tool-input-delta", id, delta: event.delta });
2359
+ tools.get(id2).args += event.delta;
2360
+ frame({ kind: "tool-input-delta", id: id2, delta: event.delta });
2253
2361
  }
2254
2362
  break;
2255
2363
  }
@@ -2261,25 +2369,26 @@ data: ${JSON.stringify({
2261
2369
  break;
2262
2370
  }
2263
2371
  case "TOOL_CALL_END": {
2264
- const id = String(event.toolCallId);
2265
- const call = tools.get(id);
2372
+ const id2 = String(event.toolCallId);
2373
+ const call = tools.get(id2);
2266
2374
  if (call === void 0) break;
2267
2375
  frame({
2268
2376
  kind: "tool-input-available",
2269
- id,
2377
+ id: id2,
2270
2378
  name: call.name,
2271
2379
  input: parseJson(call.args, {}),
2272
- toolKind: "read"
2380
+ toolKind: call.toolKind,
2381
+ ...call.parentId !== void 0 ? { parentId: call.parentId } : {}
2273
2382
  });
2274
2383
  break;
2275
2384
  }
2276
2385
  case "TOOL_CALL_RESULT": {
2277
- const id = String(event.toolCallId);
2386
+ const id2 = String(event.toolCallId);
2278
2387
  const content = contentText(event.content);
2279
2388
  const outcome = isRecord2(event.metadata) ? event.metadata["agora.outcome"] : void 0;
2280
- if (outcome === "error") frame({ kind: "tool-output-error", id, error: content });
2281
- else if (outcome === "denied") frame({ kind: "tool-output-denied", id, reason: content });
2282
- else frame({ kind: "tool-output", id, output: parseJson(content, content) });
2389
+ if (outcome === "error") frame({ kind: "tool-output-error", id: id2, error: content });
2390
+ else if (outcome === "denied") frame({ kind: "tool-output-denied", id: id2, reason: content });
2391
+ else frame({ kind: "tool-output", id: id2, output: parseJson(content, content) });
2283
2392
  break;
2284
2393
  }
2285
2394
  case "ACTIVITY_SNAPSHOT":
@@ -2318,15 +2427,26 @@ data: ${JSON.stringify({
2318
2427
  break;
2319
2428
  case "RUN_FINISHED": {
2320
2429
  const outcome = isRecord2(event.outcome) ? event.outcome : void 0;
2430
+ if (decision !== void 0) {
2431
+ frame({ kind: "proposal-decision", ...decision });
2432
+ decision = void 0;
2433
+ }
2321
2434
  if (outcome?.type === "cancelled") frame({ kind: "cancelled" });
2322
2435
  if (outcome?.type === "interrupt" && Array.isArray(outcome.interrupts)) {
2436
+ const unseen = outcome.interrupts.filter((interrupt) => !isShown(interrupt, shown));
2437
+ if (unseen.length === 0) {
2438
+ out += cursor();
2439
+ state.closed = true;
2440
+ break;
2441
+ }
2323
2442
  frame({
2324
2443
  kind: "ui",
2325
2444
  id: `ag-ui:interrupt:${String(event.runId ?? "")}`,
2326
2445
  component: "AgUiInterrupt",
2327
- props: { interrupts: outcome.interrupts }
2446
+ props: { interrupts: unseen }
2328
2447
  });
2329
2448
  }
2449
+ out += cursor();
2330
2450
  state.closed = true;
2331
2451
  out += "event: done\ndata: {}\n\n";
2332
2452
  break;
@@ -2346,6 +2466,13 @@ data: ${JSON.stringify({
2346
2466
  let pendingStart;
2347
2467
  return state;
2348
2468
  }
2469
+ function isShown(interrupt, shown) {
2470
+ if (!isRecord2(interrupt)) return false;
2471
+ if (typeof interrupt.toolCallId === "string" && shown.has(interrupt.toolCallId)) return true;
2472
+ const metadata = isRecord2(interrupt.metadata) ? interrupt.metadata : void 0;
2473
+ const request = isRecord2(metadata?.["agora.request"]) ? metadata["agora.request"] : void 0;
2474
+ return typeof request?.id === "string" && shown.has(request.id);
2475
+ }
2349
2476
  function parseJson(text, fallback2) {
2350
2477
  if (text.trim().length === 0) return fallback2;
2351
2478
  try {