@dudousxd/nestjs-agent-react 0.29.2 → 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/dist/index.js CHANGED
@@ -1821,6 +1821,339 @@ function useAttachments(options = {}) {
1821
1821
  }, [items, add, remove, retry, clear, inputProps, dropZoneProps, dragDepth, onPaste]);
1822
1822
  }
1823
1823
 
1824
+ // src/ag-ui-backend.ts
1825
+ function newId() {
1826
+ return globalThis.crypto.randomUUID();
1827
+ }
1828
+ function isRecord2(value) {
1829
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1830
+ }
1831
+ async function defaultRefusal(response) {
1832
+ try {
1833
+ const body = await response.json();
1834
+ if (typeof body.message === "string" && body.message.length > 0) return new Error(body.message);
1835
+ } catch {
1836
+ }
1837
+ return new Error(`The agent refused the request (${response.status}).`);
1838
+ }
1839
+ function defaultForwardedProps(body) {
1840
+ const out = {};
1841
+ for (const key of ["pageContext", "agent", "model"]) {
1842
+ if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
1843
+ }
1844
+ return Object.keys(out).length > 0 ? out : void 0;
1845
+ }
1846
+ async function agUiChatStream(request, options) {
1847
+ const body = request.body;
1848
+ const threadId = typeof body.threadId === "string" ? body.threadId : newId();
1849
+ const message = typeof body.message === "string" ? body.message : "";
1850
+ const forwarded = (options.forwardedProps ?? defaultForwardedProps)(body);
1851
+ const input = {
1852
+ threadId,
1853
+ runId: newId(),
1854
+ protocolVersion: "1.0",
1855
+ messages: [{ id: newId(), role: "user", content: options.content?.(body) ?? message }],
1856
+ ...forwarded !== void 0 ? { forwardedProps: forwarded } : {}
1857
+ };
1858
+ const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
1859
+ const response = await doFetch(options.url, {
1860
+ method: "POST",
1861
+ credentials: "same-origin",
1862
+ headers: {
1863
+ "content-type": "application/json",
1864
+ accept: "text/event-stream",
1865
+ ...options.headers,
1866
+ ...request.headers
1867
+ },
1868
+ body: JSON.stringify(input),
1869
+ ...request.signal !== void 0 ? { signal: request.signal } : {}
1870
+ });
1871
+ if (!response.ok || response.body === null) {
1872
+ throw await (options.refusal ?? defaultRefusal)(response);
1873
+ }
1874
+ const runId = response.headers.get("x-agent-run-id") ?? void 0;
1875
+ return {
1876
+ body: reframeAgUiStream(response.body, { threadId }),
1877
+ threadId,
1878
+ ...runId !== void 0 ? { runId } : {}
1879
+ };
1880
+ }
1881
+ function reframeAgUiStream(source, ids) {
1882
+ const encoder = new TextEncoder();
1883
+ const decoder = new TextDecoder();
1884
+ const reframer = createReframer(ids.threadId);
1885
+ const reader = source.getReader();
1886
+ let buffer = "";
1887
+ return new ReadableStream({
1888
+ async pull(controller) {
1889
+ for (; ; ) {
1890
+ const { value, done } = await reader.read();
1891
+ if (done) {
1892
+ controller.close();
1893
+ return;
1894
+ }
1895
+ buffer += decoder.decode(value, { stream: true }).replace(/\r\n?/g, "\n");
1896
+ let out = "";
1897
+ let separator = buffer.indexOf("\n\n");
1898
+ while (separator !== -1) {
1899
+ const block = buffer.slice(0, separator);
1900
+ buffer = buffer.slice(separator + 2);
1901
+ separator = buffer.indexOf("\n\n");
1902
+ const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
1903
+ if (data.length === 0) continue;
1904
+ let event;
1905
+ try {
1906
+ event = JSON.parse(data);
1907
+ } catch {
1908
+ continue;
1909
+ }
1910
+ if (isRecord2(event) && typeof event.type === "string") {
1911
+ out += reframer.push(event);
1912
+ }
1913
+ if (reframer.closed) break;
1914
+ }
1915
+ if (out.length > 0) controller.enqueue(encoder.encode(out));
1916
+ if (reframer.closed) {
1917
+ void reader.cancel().catch(() => void 0);
1918
+ controller.close();
1919
+ return;
1920
+ }
1921
+ if (out.length > 0) return;
1922
+ }
1923
+ },
1924
+ cancel(reason) {
1925
+ return reader.cancel(reason).catch(() => void 0);
1926
+ }
1927
+ });
1928
+ }
1929
+ function createReframer(threadId) {
1930
+ const activities = /* @__PURE__ */ new Map();
1931
+ let seq = 0;
1932
+ let metaSent = false;
1933
+ const tools = /* @__PURE__ */ new Map();
1934
+ const state = {
1935
+ closed: false,
1936
+ push(event) {
1937
+ if (state.closed) return "";
1938
+ let out = "";
1939
+ const frame = (streamEvent) => {
1940
+ seq += 1;
1941
+ out += `id: ${seq}
1942
+ data: ${JSON.stringify(streamEvent)}
1943
+
1944
+ `;
1945
+ };
1946
+ const meta = (runId, thread) => {
1947
+ if (metaSent) return;
1948
+ metaSent = true;
1949
+ out += `event: meta
1950
+ data: ${JSON.stringify({
1951
+ runId: typeof runId === "string" ? runId : "",
1952
+ threadId: typeof thread === "string" ? thread : threadId
1953
+ })}
1954
+
1955
+ `;
1956
+ };
1957
+ switch (event.type) {
1958
+ case "RUN_STARTED":
1959
+ pendingStart = { runId: event.runId, threadId: event.threadId };
1960
+ return out;
1961
+ case "CUSTOM": {
1962
+ const value = event.value;
1963
+ if (event.name === "agora.run" && isRecord2(value)) {
1964
+ meta(value.runId, pendingStart?.threadId ?? value.threadId);
1965
+ pendingStart = void 0;
1966
+ return out;
1967
+ }
1968
+ flushStart();
1969
+ if (!isRecord2(value)) return out;
1970
+ if (event.name === "agora.ui") frame({ kind: "ui", ...value });
1971
+ else if (event.name === "agora.title" && typeof value.title === "string") {
1972
+ frame({ kind: "title", title: value.title });
1973
+ } else if (event.name === "agora.queue") frame({ kind: "queue", ...value });
1974
+ else if (event.name === "agora.approval-requested") {
1975
+ frame({ ...value, kind: "approval-requested" });
1976
+ } else if (event.name === "agora.approval-settled") {
1977
+ frame({ ...value, kind: "approval-settled" });
1978
+ }
1979
+ return out;
1980
+ }
1981
+ default:
1982
+ flushStart();
1983
+ }
1984
+ switch (event.type) {
1985
+ case "TEXT_MESSAGE_CONTENT":
1986
+ case "TEXT_MESSAGE_CHUNK":
1987
+ if (typeof event.delta === "string" && event.delta.length > 0) {
1988
+ frame({ kind: "text", text: event.delta });
1989
+ }
1990
+ break;
1991
+ case "REASONING_MESSAGE_CONTENT":
1992
+ case "REASONING_MESSAGE_CHUNK":
1993
+ if (typeof event.delta === "string" && event.delta.length > 0) {
1994
+ frame({ kind: "reasoning", text: event.delta });
1995
+ }
1996
+ break;
1997
+ case "STEP_STARTED":
1998
+ frame({ kind: "step-start" });
1999
+ break;
2000
+ case "STEP_FINISHED":
2001
+ frame({ kind: "step-finish" });
2002
+ break;
2003
+ case "TOOL_CALL_START":
2004
+ case "TOOL_CALL_CHUNK": {
2005
+ const id = String(event.toolCallId ?? "");
2006
+ if (id === "") break;
2007
+ if (!tools.has(id)) {
2008
+ const name = typeof event.toolCallName === "string" ? event.toolCallName : "";
2009
+ tools.set(id, { name, args: "" });
2010
+ frame({ kind: "tool-input-start", id, name, toolKind: "read" });
2011
+ }
2012
+ if (event.type === "TOOL_CALL_CHUNK" && typeof event.delta === "string") {
2013
+ tools.get(id).args += event.delta;
2014
+ frame({ kind: "tool-input-delta", id, delta: event.delta });
2015
+ }
2016
+ break;
2017
+ }
2018
+ case "TOOL_CALL_ARGS": {
2019
+ const call = tools.get(String(event.toolCallId));
2020
+ if (call === void 0 || typeof event.delta !== "string") break;
2021
+ call.args += event.delta;
2022
+ frame({ kind: "tool-input-delta", id: String(event.toolCallId), delta: event.delta });
2023
+ break;
2024
+ }
2025
+ case "TOOL_CALL_END": {
2026
+ const id = String(event.toolCallId);
2027
+ const call = tools.get(id);
2028
+ if (call === void 0) break;
2029
+ frame({
2030
+ kind: "tool-input-available",
2031
+ id,
2032
+ name: call.name,
2033
+ input: parseJson(call.args, {}),
2034
+ toolKind: "read"
2035
+ });
2036
+ break;
2037
+ }
2038
+ case "TOOL_CALL_RESULT": {
2039
+ const id = String(event.toolCallId);
2040
+ const content = contentText(event.content);
2041
+ const outcome = isRecord2(event.metadata) ? event.metadata["agora.outcome"] : void 0;
2042
+ if (outcome === "error") frame({ kind: "tool-output-error", id, error: content });
2043
+ else if (outcome === "denied") frame({ kind: "tool-output-denied", id, reason: content });
2044
+ else frame({ kind: "tool-output", id, output: parseJson(content, content) });
2045
+ break;
2046
+ }
2047
+ case "ACTIVITY_SNAPSHOT":
2048
+ case "ACTIVITY_DELTA": {
2049
+ const messageId = typeof event.messageId === "string" ? event.messageId : "";
2050
+ if (messageId === "") break;
2051
+ const known = activities.get(messageId);
2052
+ const activityType = typeof event.activityType === "string" ? event.activityType : known?.activityType ?? "";
2053
+ let content;
2054
+ if (event.type === "ACTIVITY_SNAPSHOT") {
2055
+ if (known !== void 0 && event.replace === false) break;
2056
+ content = isRecord2(event.content) ? event.content : {};
2057
+ } else {
2058
+ if (known === void 0 || !Array.isArray(event.patch)) break;
2059
+ content = applyPatch(known.content, event.patch);
2060
+ if (content === void 0) break;
2061
+ }
2062
+ activities.set(messageId, { activityType, content });
2063
+ frame({
2064
+ kind: "ui",
2065
+ id: `activity:${messageId}`,
2066
+ component: "AgUiActivity",
2067
+ props: { activityType, content }
2068
+ });
2069
+ break;
2070
+ }
2071
+ case "RUN_ERROR":
2072
+ state.closed = true;
2073
+ out += `event: error
2074
+ data: ${JSON.stringify({
2075
+ code: typeof event.code === "string" ? event.code : "run_failed",
2076
+ message: typeof event.message === "string" ? event.message : "The run failed."
2077
+ })}
2078
+
2079
+ `;
2080
+ break;
2081
+ case "RUN_FINISHED": {
2082
+ const outcome = isRecord2(event.outcome) ? event.outcome : void 0;
2083
+ if (outcome?.type === "cancelled") frame({ kind: "cancelled" });
2084
+ if (outcome?.type === "interrupt" && Array.isArray(outcome.interrupts)) {
2085
+ frame({
2086
+ kind: "ui",
2087
+ id: `ag-ui:interrupt:${String(event.runId ?? "")}`,
2088
+ component: "AgUiInterrupt",
2089
+ props: { interrupts: outcome.interrupts }
2090
+ });
2091
+ }
2092
+ state.closed = true;
2093
+ out += "event: done\ndata: {}\n\n";
2094
+ break;
2095
+ }
2096
+ default:
2097
+ break;
2098
+ }
2099
+ return out;
2100
+ function flushStart() {
2101
+ if (pendingStart !== void 0) {
2102
+ meta(pendingStart.runId, pendingStart.threadId);
2103
+ pendingStart = void 0;
2104
+ }
2105
+ }
2106
+ }
2107
+ };
2108
+ let pendingStart;
2109
+ return state;
2110
+ }
2111
+ function parseJson(text, fallback2) {
2112
+ if (text.trim().length === 0) return fallback2;
2113
+ try {
2114
+ return JSON.parse(text);
2115
+ } catch {
2116
+ return fallback2;
2117
+ }
2118
+ }
2119
+ function contentText(content) {
2120
+ if (typeof content === "string") return content;
2121
+ if (!Array.isArray(content)) return "";
2122
+ return content.filter((part) => isRecord2(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
2123
+ }
2124
+ function applyPatch(target, patch) {
2125
+ const doc = structuredClone(target);
2126
+ for (const operation of patch) {
2127
+ if (!isRecord2(operation) || typeof operation.path !== "string") return void 0;
2128
+ const tokens = operation.path.split("/").slice(1).map((token) => token.replace(/~1/g, "/").replace(/~0/g, "~"));
2129
+ const key = tokens.pop();
2130
+ if (key === void 0) return void 0;
2131
+ let parent = doc;
2132
+ for (const token of tokens) {
2133
+ parent = Array.isArray(parent) ? parent[Number(token)] : isRecord2(parent) ? parent[token] : void 0;
2134
+ if (parent === void 0) return void 0;
2135
+ }
2136
+ if (Array.isArray(parent)) {
2137
+ const index = key === "-" ? parent.length : Number(key);
2138
+ if (!Number.isInteger(index) || index < 0 || index > parent.length) return void 0;
2139
+ if (operation.op === "add") parent.splice(index, 0, operation.value);
2140
+ else if (operation.op === "replace" && index < parent.length) parent[index] = operation.value;
2141
+ else if (operation.op === "remove" && index < parent.length) parent.splice(index, 1);
2142
+ else if (operation.op === "test") {
2143
+ if (JSON.stringify(parent[index]) !== JSON.stringify(operation.value)) return void 0;
2144
+ } else return void 0;
2145
+ } else if (isRecord2(parent)) {
2146
+ if (operation.op === "add" || operation.op === "replace" && key in parent) {
2147
+ parent[key] = operation.value;
2148
+ } else if (operation.op === "remove" && key in parent) delete parent[key];
2149
+ else if (operation.op === "test") {
2150
+ if (JSON.stringify(parent[key]) !== JSON.stringify(operation.value)) return void 0;
2151
+ } else return void 0;
2152
+ } else return void 0;
2153
+ }
2154
+ return doc;
2155
+ }
2156
+
1824
2157
  // src/catalog/use-agents.ts
1825
2158
  import { useMemo as useMemo5 } from "react";
1826
2159
 
@@ -2473,7 +2806,7 @@ function phraseFor(presentation, input, isSettled2, fallback2 = { running: "Work
2473
2806
  }
2474
2807
 
2475
2808
  // src/presentation/result-view.ts
2476
- function isRecord2(value) {
2809
+ function isRecord3(value) {
2477
2810
  return typeof value === "object" && value !== null && !Array.isArray(value);
2478
2811
  }
2479
2812
  function toText(value) {
@@ -2485,18 +2818,18 @@ function toText(value) {
2485
2818
  return "\u2014";
2486
2819
  }
2487
2820
  function inferResultView(output) {
2488
- if (!isRecord2(output)) return void 0;
2821
+ if (!isRecord3(output)) return void 0;
2489
2822
  for (const [key, value] of Object.entries(output)) {
2490
2823
  if (!Array.isArray(value) || value.length === 0) continue;
2491
2824
  if (value.every((entry) => typeof entry === "string")) {
2492
2825
  return { kind: "log", lines: key };
2493
2826
  }
2494
- if (value.every(isRecord2)) {
2827
+ if (value.every(isRecord3)) {
2495
2828
  const first = value[0];
2496
2829
  return {
2497
2830
  kind: "table",
2498
2831
  rows: key,
2499
- columns: Object.keys(first).filter((column) => !isRecord2(first[column])).map((column) => ({ path: column, label: column }))
2832
+ columns: Object.keys(first).filter((column) => !isRecord3(first[column])).map((column) => ({ path: column, label: column }))
2500
2833
  };
2501
2834
  }
2502
2835
  }
@@ -2823,7 +3156,7 @@ function isSettled(state) {
2823
3156
  }
2824
3157
  function toolKind(part) {
2825
3158
  const metadata = part.toolMetadata;
2826
- return isRecord3(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
3159
+ return isRecord4(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
2827
3160
  }
2828
3161
  function isAwaitingApproval(part) {
2829
3162
  if (part.state === "approval-requested") {
@@ -2836,7 +3169,7 @@ function isAwaitingApproval(part) {
2836
3169
  }
2837
3170
  function toolParentId(part) {
2838
3171
  const metadata = part.toolMetadata;
2839
- return isRecord3(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
3172
+ return isRecord4(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
2840
3173
  }
2841
3174
  function nestToolCalls(calls) {
2842
3175
  const byId = new Map(calls.map((call) => [call.toolCallId, call]));
@@ -2895,12 +3228,12 @@ function buildToolCall(part, options, approval, catalog) {
2895
3228
  }
2896
3229
  function readElicitationRequest(part) {
2897
3230
  const input = part.input;
2898
- if (!isRecord3(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
3231
+ if (!isRecord4(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
2899
3232
  return null;
2900
3233
  }
2901
3234
  const questions = [];
2902
3235
  for (const candidate of input.questions) {
2903
- if (!isRecord3(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string") {
3236
+ if (!isRecord4(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string") {
2904
3237
  return null;
2905
3238
  }
2906
3239
  const input2 = readElicitationInput(candidate.input) ?? null;
@@ -2910,7 +3243,7 @@ function readElicitationRequest(part) {
2910
3243
  }
2911
3244
  const options = [];
2912
3245
  for (const option of rawOptions) {
2913
- if (!isRecord3(option) || typeof option.value !== "string" || typeof option.label !== "string") {
3246
+ if (!isRecord4(option) || typeof option.value !== "string" || typeof option.label !== "string") {
2914
3247
  return null;
2915
3248
  }
2916
3249
  options.push({
@@ -2937,7 +3270,7 @@ function readElicitationRequest(part) {
2937
3270
  }
2938
3271
  function readElicitationOutcome(part) {
2939
3272
  const output = part.output;
2940
- if (!isRecord3(output) || !isRecord3(output.answers) || typeof output.skipped !== "boolean") {
3273
+ if (!isRecord4(output) || !isRecord4(output.answers) || typeof output.skipped !== "boolean") {
2941
3274
  return null;
2942
3275
  }
2943
3276
  const answers = {};
@@ -3062,7 +3395,7 @@ function readApprovals(parts) {
3062
3395
  continue;
3063
3396
  }
3064
3397
  const data = part.data;
3065
- if (!isRecord3(data) || typeof data.id !== "string") {
3398
+ if (!isRecord4(data) || typeof data.id !== "string") {
3066
3399
  continue;
3067
3400
  }
3068
3401
  const approval = entry(data.id);
@@ -3115,7 +3448,7 @@ function statusFromPart(call) {
3115
3448
  }
3116
3449
  function readUiComponent(part) {
3117
3450
  const data = part.data;
3118
- if (!isRecord3(data) || typeof data.component !== "string") {
3451
+ if (!isRecord4(data) || typeof data.component !== "string") {
3119
3452
  return null;
3120
3453
  }
3121
3454
  const id = typeof data.id === "string" ? data.id : part.id;
@@ -3125,29 +3458,29 @@ function readUiComponent(part) {
3125
3458
  return {
3126
3459
  id,
3127
3460
  component: data.component,
3128
- props: isRecord3(data.props) ? data.props : {},
3461
+ props: isRecord4(data.props) ? data.props : {},
3129
3462
  version: typeof data.version === "number" ? data.version : null,
3130
3463
  toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
3131
3464
  };
3132
3465
  }
3133
- function isRecord3(value) {
3466
+ function isRecord4(value) {
3134
3467
  return typeof value === "object" && value !== null;
3135
3468
  }
3136
3469
  function readQuery(part) {
3137
3470
  const input = part.input;
3138
- if (!isRecord3(input) || typeof input.query !== "string") {
3471
+ if (!isRecord4(input) || typeof input.query !== "string") {
3139
3472
  return null;
3140
3473
  }
3141
3474
  return input.query;
3142
3475
  }
3143
3476
  function readPassages(part) {
3144
3477
  const output = part.output;
3145
- if (!isRecord3(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
3478
+ if (!isRecord4(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
3146
3479
  return null;
3147
3480
  }
3148
3481
  const passages = [];
3149
3482
  for (const candidate of output.passages) {
3150
- if (!isRecord3(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
3483
+ if (!isRecord4(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
3151
3484
  return null;
3152
3485
  }
3153
3486
  passages.push({
@@ -3155,7 +3488,7 @@ function readPassages(part) {
3155
3488
  text: candidate.text,
3156
3489
  score: typeof candidate.score === "number" ? candidate.score : 0,
3157
3490
  ...typeof candidate.source === "string" ? { source: candidate.source } : {},
3158
- ...isRecord3(candidate.metadata) ? { metadata: candidate.metadata } : {}
3491
+ ...isRecord4(candidate.metadata) ? { metadata: candidate.metadata } : {}
3159
3492
  });
3160
3493
  }
3161
3494
  return passages;
@@ -5781,6 +6114,7 @@ export {
5781
6114
  RUN_NOT_ACTIVE_CODE,
5782
6115
  SPEECH_LANGUAGES,
5783
6116
  acceptsFile,
6117
+ agUiChatStream,
5784
6118
  applyCompletion,
5785
6119
  approvalCountdown,
5786
6120
  attachmentFile,
@@ -5813,6 +6147,7 @@ export {
5813
6147
  phraseFor,
5814
6148
  readPath,
5815
6149
  readReasoningMs,
6150
+ reframeAgUiStream,
5816
6151
  requireBackendMethod,
5817
6152
  resolveResultView,
5818
6153
  storedMessageToUiMessage,