@dudousxd/nestjs-agent-react 0.30.0 → 0.31.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 CHANGED
@@ -648,6 +648,11 @@ const backend: AgentBackend = {
648
648
  answering it is a new run with `resume`, which the app sends through its own backend.
649
649
  - A send without a `threadId` gets a new one (AG-UI's thread id is the consumer's), returned as
650
650
  the stream's `threadId`, so `onThreadCreated` fires as usual.
651
+ - Activity (`ACTIVITY_SNAPSHOT` / `ACTIVITY_DELTA`) arrives as a `ui` part, component `AgUiActivity`,
652
+ id `activity:<messageId>`, props `{ activityType, content }`: the whole content each time (the
653
+ delta's JSON Patch applied), so the widget updates in place.
654
+ - `content: (body) => parts` sends a file with the message as AG-UI content parts (`image`,
655
+ `document`… by inline `data`), next to the text part.
651
656
  - `reframeAgUiStream(body, { threadId })` is the re-framing alone, for a backend that fetches itself.
652
657
 
653
658
  ### Typing ahead: the message queue
package/dist/index.cjs CHANGED
@@ -1958,7 +1958,7 @@ async function agUiChatStream(request, options) {
1958
1958
  threadId,
1959
1959
  runId: newId(),
1960
1960
  protocolVersion: "1.0",
1961
- messages: [{ id: newId(), role: "user", content: message }],
1961
+ messages: [{ id: newId(), role: "user", content: options.content?.(body) ?? message }],
1962
1962
  ...forwarded !== void 0 ? { forwardedProps: forwarded } : {}
1963
1963
  };
1964
1964
  const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
@@ -2033,6 +2033,7 @@ function reframeAgUiStream(source, ids) {
2033
2033
  });
2034
2034
  }
2035
2035
  function createReframer(threadId) {
2036
+ const activities = /* @__PURE__ */ new Map();
2036
2037
  let seq = 0;
2037
2038
  let metaSent = false;
2038
2039
  const tools = /* @__PURE__ */ new Map();
@@ -2149,6 +2150,30 @@ data: ${JSON.stringify({
2149
2150
  else frame({ kind: "tool-output", id, output: parseJson(content, content) });
2150
2151
  break;
2151
2152
  }
2153
+ case "ACTIVITY_SNAPSHOT":
2154
+ case "ACTIVITY_DELTA": {
2155
+ const messageId = typeof event.messageId === "string" ? event.messageId : "";
2156
+ if (messageId === "") break;
2157
+ const known = activities.get(messageId);
2158
+ const activityType = typeof event.activityType === "string" ? event.activityType : known?.activityType ?? "";
2159
+ let content;
2160
+ if (event.type === "ACTIVITY_SNAPSHOT") {
2161
+ if (known !== void 0 && event.replace === false) break;
2162
+ content = isRecord2(event.content) ? event.content : {};
2163
+ } else {
2164
+ if (known === void 0 || !Array.isArray(event.patch)) break;
2165
+ content = applyPatch(known.content, event.patch);
2166
+ if (content === void 0) break;
2167
+ }
2168
+ activities.set(messageId, { activityType, content });
2169
+ frame({
2170
+ kind: "ui",
2171
+ id: `activity:${messageId}`,
2172
+ component: "AgUiActivity",
2173
+ props: { activityType, content }
2174
+ });
2175
+ break;
2176
+ }
2152
2177
  case "RUN_ERROR":
2153
2178
  state.closed = true;
2154
2179
  out += `event: error
@@ -2202,6 +2227,38 @@ function contentText(content) {
2202
2227
  if (!Array.isArray(content)) return "";
2203
2228
  return content.filter((part) => isRecord2(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
2204
2229
  }
2230
+ function applyPatch(target, patch) {
2231
+ const doc = structuredClone(target);
2232
+ for (const operation of patch) {
2233
+ if (!isRecord2(operation) || typeof operation.path !== "string") return void 0;
2234
+ const tokens = operation.path.split("/").slice(1).map((token) => token.replace(/~1/g, "/").replace(/~0/g, "~"));
2235
+ const key = tokens.pop();
2236
+ if (key === void 0) return void 0;
2237
+ let parent = doc;
2238
+ for (const token of tokens) {
2239
+ parent = Array.isArray(parent) ? parent[Number(token)] : isRecord2(parent) ? parent[token] : void 0;
2240
+ if (parent === void 0) return void 0;
2241
+ }
2242
+ if (Array.isArray(parent)) {
2243
+ const index = key === "-" ? parent.length : Number(key);
2244
+ if (!Number.isInteger(index) || index < 0 || index > parent.length) return void 0;
2245
+ if (operation.op === "add") parent.splice(index, 0, operation.value);
2246
+ else if (operation.op === "replace" && index < parent.length) parent[index] = operation.value;
2247
+ else if (operation.op === "remove" && index < parent.length) parent.splice(index, 1);
2248
+ else if (operation.op === "test") {
2249
+ if (JSON.stringify(parent[index]) !== JSON.stringify(operation.value)) return void 0;
2250
+ } else return void 0;
2251
+ } else if (isRecord2(parent)) {
2252
+ if (operation.op === "add" || operation.op === "replace" && key in parent) {
2253
+ parent[key] = operation.value;
2254
+ } else if (operation.op === "remove" && key in parent) delete parent[key];
2255
+ else if (operation.op === "test") {
2256
+ if (JSON.stringify(parent[key]) !== JSON.stringify(operation.value)) return void 0;
2257
+ } else return void 0;
2258
+ } else return void 0;
2259
+ }
2260
+ return doc;
2261
+ }
2205
2262
 
2206
2263
  // src/catalog/use-agents.ts
2207
2264
  var import_react9 = require("react");