@dudousxd/nestjs-agent-react 0.29.1 → 0.30.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 +29 -0
- package/dist/{client-DhHEJi7c.d.cts → client-BuobfZtx.d.cts} +1 -1
- package/dist/{client-DhHEJi7c.d.ts → client-BuobfZtx.d.ts} +1 -1
- package/dist/index.cjs +321 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -3
- package/dist/index.d.ts +62 -3
- package/dist/index.js +319 -19
- package/dist/index.js.map +1 -1
- package/dist/media.d.cts +1 -1
- package/dist/media.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -621,6 +621,35 @@ const readCookie = (name: string) =>
|
|
|
621
621
|
</AgentProvider>;
|
|
622
622
|
```
|
|
623
623
|
|
|
624
|
+
|
|
625
|
+
### An AG-UI agent (`agUiChatStream`)
|
|
626
|
+
|
|
627
|
+
`useAgentChat` can drive any [AG-UI 1.0](https://docs.ag-ui.com/spec/1.0) producer — this library's
|
|
628
|
+
own (`@adonis-agora/agent/ag-ui`), CopilotKit's, a Python or .NET agent. Put `agUiChatStream` behind
|
|
629
|
+
`openChatStream`: it POSTs a `RunAgentInput` (the send's text as the user message, `pageContext`,
|
|
630
|
+
`agent` and `model` in `forwardedProps`) and hands the transport the answer re-framed in this
|
|
631
|
+
library's stream protocol, so the transcript, tool activity and generative UI render unchanged.
|
|
632
|
+
|
|
633
|
+
```ts
|
|
634
|
+
import { agUiChatStream, type AgentBackend } from '@dudousxd/nestjs-agent-react';
|
|
635
|
+
|
|
636
|
+
const backend: AgentBackend = {
|
|
637
|
+
...myBackend,
|
|
638
|
+
openChatStream: (request) =>
|
|
639
|
+
agUiChatStream(request, { url: '/agent/ag-ui', headers: { 'x-csrf-token': csrf } }),
|
|
640
|
+
};
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
- Text, reasoning, steps, tool calls and tool results map one to one; `RUN_ERROR` is the stream's
|
|
644
|
+
error, a cancelled outcome writes `cancelled`.
|
|
645
|
+
- `CUSTOM` events named `agora.*` (generative UI, title, queue, approvals) become the frames they
|
|
646
|
+
stand for; any other `CUSTOM` is ignored, as the protocol requires.
|
|
647
|
+
- An interrupt outcome arrives as a `ui` part, component `AgUiInterrupt`, props `{ interrupts }`:
|
|
648
|
+
answering it is a new run with `resume`, which the app sends through its own backend.
|
|
649
|
+
- A send without a `threadId` gets a new one (AG-UI's thread id is the consumer's), returned as
|
|
650
|
+
the stream's `threadId`, so `onThreadCreated` fires as usual.
|
|
651
|
+
- `reframeAgUiStream(body, { threadId })` is the re-framing alone, for a backend that fetches itself.
|
|
652
|
+
|
|
624
653
|
### Typing ahead: the message queue
|
|
625
654
|
|
|
626
655
|
Send while a turn is still answering and the message waits in the thread's queue — server-side, so
|
|
@@ -436,4 +436,4 @@ declare class AgentClient implements AgentBackend {
|
|
|
436
436
|
private handleResponse;
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
-
export { type AgentRequestError as A, type
|
|
439
|
+
export { type AgentRequestError as A, type ChatStreamRequest as C, type ErrorAnswer as E, type HttpErrorListener as H, type MessageFeedbackInput as M, type QueuedMessageUpdate as Q, type ResumeStreamRequest as R, type ThreadPatch as T, type UploadAttachmentOptions as U, type AgentBackend as a, type ChatStreamResponse as b, type AttachmentUploadStrategy as c, AgentBackendUnsupportedError as d, AgentClient as e, type AgentClientOptions as f, type AgentConnection as g, AgentHttpError as h, type CancelResult as i, type QueuedSendResult as j, requireBackendMethod as r };
|
|
@@ -436,4 +436,4 @@ declare class AgentClient implements AgentBackend {
|
|
|
436
436
|
private handleResponse;
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
-
export { type AgentRequestError as A, type
|
|
439
|
+
export { type AgentRequestError as A, type ChatStreamRequest as C, type ErrorAnswer as E, type HttpErrorListener as H, type MessageFeedbackInput as M, type QueuedMessageUpdate as Q, type ResumeStreamRequest as R, type ThreadPatch as T, type UploadAttachmentOptions as U, type AgentBackend as a, type ChatStreamResponse as b, type AttachmentUploadStrategy as c, AgentBackendUnsupportedError as d, AgentClient as e, type AgentClientOptions as f, type AgentConnection as g, AgentHttpError as h, type CancelResult as i, type QueuedSendResult as j, requireBackendMethod as r };
|
package/dist/index.cjs
CHANGED
|
@@ -47,6 +47,7 @@ __export(src_exports, {
|
|
|
47
47
|
RUN_NOT_ACTIVE_CODE: () => RUN_NOT_ACTIVE_CODE,
|
|
48
48
|
SPEECH_LANGUAGES: () => SPEECH_LANGUAGES,
|
|
49
49
|
acceptsFile: () => acceptsFile,
|
|
50
|
+
agUiChatStream: () => agUiChatStream,
|
|
50
51
|
applyCompletion: () => applyCompletion,
|
|
51
52
|
approvalCountdown: () => approvalCountdown,
|
|
52
53
|
attachmentFile: () => attachmentFile,
|
|
@@ -79,6 +80,7 @@ __export(src_exports, {
|
|
|
79
80
|
phraseFor: () => phraseFor,
|
|
80
81
|
readPath: () => readPath,
|
|
81
82
|
readReasoningMs: () => readReasoningMs,
|
|
83
|
+
reframeAgUiStream: () => reframeAgUiStream,
|
|
82
84
|
requireBackendMethod: () => requireBackendMethod,
|
|
83
85
|
resolveResultView: () => resolveResultView,
|
|
84
86
|
storedMessageToUiMessage: () => storedMessageToUiMessage,
|
|
@@ -679,6 +681,7 @@ var AgentChatTransport = class {
|
|
|
679
681
|
return null;
|
|
680
682
|
}
|
|
681
683
|
this.captureHeaderMeta(response);
|
|
684
|
+
this.options.onResumeAttached?.(response.runId ?? runId);
|
|
682
685
|
return this.toChunkStream(response, {
|
|
683
686
|
runId,
|
|
684
687
|
...headers !== void 0 ? { headers } : {}
|
|
@@ -1924,6 +1927,282 @@ function useAttachments(options = {}) {
|
|
|
1924
1927
|
}, [items, add, remove, retry, clear, inputProps, dropZoneProps, dragDepth, onPaste]);
|
|
1925
1928
|
}
|
|
1926
1929
|
|
|
1930
|
+
// src/ag-ui-backend.ts
|
|
1931
|
+
function newId() {
|
|
1932
|
+
return globalThis.crypto.randomUUID();
|
|
1933
|
+
}
|
|
1934
|
+
function isRecord2(value) {
|
|
1935
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1936
|
+
}
|
|
1937
|
+
async function defaultRefusal(response) {
|
|
1938
|
+
try {
|
|
1939
|
+
const body = await response.json();
|
|
1940
|
+
if (typeof body.message === "string" && body.message.length > 0) return new Error(body.message);
|
|
1941
|
+
} catch {
|
|
1942
|
+
}
|
|
1943
|
+
return new Error(`The agent refused the request (${response.status}).`);
|
|
1944
|
+
}
|
|
1945
|
+
function defaultForwardedProps(body) {
|
|
1946
|
+
const out = {};
|
|
1947
|
+
for (const key of ["pageContext", "agent", "model"]) {
|
|
1948
|
+
if (body[key] !== void 0 && body[key] !== null) out[key] = body[key];
|
|
1949
|
+
}
|
|
1950
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1951
|
+
}
|
|
1952
|
+
async function agUiChatStream(request, options) {
|
|
1953
|
+
const body = request.body;
|
|
1954
|
+
const threadId = typeof body.threadId === "string" ? body.threadId : newId();
|
|
1955
|
+
const message = typeof body.message === "string" ? body.message : "";
|
|
1956
|
+
const forwarded = (options.forwardedProps ?? defaultForwardedProps)(body);
|
|
1957
|
+
const input = {
|
|
1958
|
+
threadId,
|
|
1959
|
+
runId: newId(),
|
|
1960
|
+
protocolVersion: "1.0",
|
|
1961
|
+
messages: [{ id: newId(), role: "user", content: message }],
|
|
1962
|
+
...forwarded !== void 0 ? { forwardedProps: forwarded } : {}
|
|
1963
|
+
};
|
|
1964
|
+
const doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
1965
|
+
const response = await doFetch(options.url, {
|
|
1966
|
+
method: "POST",
|
|
1967
|
+
credentials: "same-origin",
|
|
1968
|
+
headers: {
|
|
1969
|
+
"content-type": "application/json",
|
|
1970
|
+
accept: "text/event-stream",
|
|
1971
|
+
...options.headers,
|
|
1972
|
+
...request.headers
|
|
1973
|
+
},
|
|
1974
|
+
body: JSON.stringify(input),
|
|
1975
|
+
...request.signal !== void 0 ? { signal: request.signal } : {}
|
|
1976
|
+
});
|
|
1977
|
+
if (!response.ok || response.body === null) {
|
|
1978
|
+
throw await (options.refusal ?? defaultRefusal)(response);
|
|
1979
|
+
}
|
|
1980
|
+
const runId = response.headers.get("x-agent-run-id") ?? void 0;
|
|
1981
|
+
return {
|
|
1982
|
+
body: reframeAgUiStream(response.body, { threadId }),
|
|
1983
|
+
threadId,
|
|
1984
|
+
...runId !== void 0 ? { runId } : {}
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
function reframeAgUiStream(source, ids) {
|
|
1988
|
+
const encoder = new TextEncoder();
|
|
1989
|
+
const decoder = new TextDecoder();
|
|
1990
|
+
const reframer = createReframer(ids.threadId);
|
|
1991
|
+
const reader = source.getReader();
|
|
1992
|
+
let buffer = "";
|
|
1993
|
+
return new ReadableStream({
|
|
1994
|
+
async pull(controller) {
|
|
1995
|
+
for (; ; ) {
|
|
1996
|
+
const { value, done } = await reader.read();
|
|
1997
|
+
if (done) {
|
|
1998
|
+
controller.close();
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
2001
|
+
buffer += decoder.decode(value, { stream: true }).replace(/\r\n?/g, "\n");
|
|
2002
|
+
let out = "";
|
|
2003
|
+
let separator = buffer.indexOf("\n\n");
|
|
2004
|
+
while (separator !== -1) {
|
|
2005
|
+
const block = buffer.slice(0, separator);
|
|
2006
|
+
buffer = buffer.slice(separator + 2);
|
|
2007
|
+
separator = buffer.indexOf("\n\n");
|
|
2008
|
+
const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
|
|
2009
|
+
if (data.length === 0) continue;
|
|
2010
|
+
let event;
|
|
2011
|
+
try {
|
|
2012
|
+
event = JSON.parse(data);
|
|
2013
|
+
} catch {
|
|
2014
|
+
continue;
|
|
2015
|
+
}
|
|
2016
|
+
if (isRecord2(event) && typeof event.type === "string") {
|
|
2017
|
+
out += reframer.push(event);
|
|
2018
|
+
}
|
|
2019
|
+
if (reframer.closed) break;
|
|
2020
|
+
}
|
|
2021
|
+
if (out.length > 0) controller.enqueue(encoder.encode(out));
|
|
2022
|
+
if (reframer.closed) {
|
|
2023
|
+
void reader.cancel().catch(() => void 0);
|
|
2024
|
+
controller.close();
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
if (out.length > 0) return;
|
|
2028
|
+
}
|
|
2029
|
+
},
|
|
2030
|
+
cancel(reason) {
|
|
2031
|
+
return reader.cancel(reason).catch(() => void 0);
|
|
2032
|
+
}
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
function createReframer(threadId) {
|
|
2036
|
+
let seq = 0;
|
|
2037
|
+
let metaSent = false;
|
|
2038
|
+
const tools = /* @__PURE__ */ new Map();
|
|
2039
|
+
const state = {
|
|
2040
|
+
closed: false,
|
|
2041
|
+
push(event) {
|
|
2042
|
+
if (state.closed) return "";
|
|
2043
|
+
let out = "";
|
|
2044
|
+
const frame = (streamEvent) => {
|
|
2045
|
+
seq += 1;
|
|
2046
|
+
out += `id: ${seq}
|
|
2047
|
+
data: ${JSON.stringify(streamEvent)}
|
|
2048
|
+
|
|
2049
|
+
`;
|
|
2050
|
+
};
|
|
2051
|
+
const meta = (runId, thread) => {
|
|
2052
|
+
if (metaSent) return;
|
|
2053
|
+
metaSent = true;
|
|
2054
|
+
out += `event: meta
|
|
2055
|
+
data: ${JSON.stringify({
|
|
2056
|
+
runId: typeof runId === "string" ? runId : "",
|
|
2057
|
+
threadId: typeof thread === "string" ? thread : threadId
|
|
2058
|
+
})}
|
|
2059
|
+
|
|
2060
|
+
`;
|
|
2061
|
+
};
|
|
2062
|
+
switch (event.type) {
|
|
2063
|
+
case "RUN_STARTED":
|
|
2064
|
+
pendingStart = { runId: event.runId, threadId: event.threadId };
|
|
2065
|
+
return out;
|
|
2066
|
+
case "CUSTOM": {
|
|
2067
|
+
const value = event.value;
|
|
2068
|
+
if (event.name === "agora.run" && isRecord2(value)) {
|
|
2069
|
+
meta(value.runId, pendingStart?.threadId ?? value.threadId);
|
|
2070
|
+
pendingStart = void 0;
|
|
2071
|
+
return out;
|
|
2072
|
+
}
|
|
2073
|
+
flushStart();
|
|
2074
|
+
if (!isRecord2(value)) return out;
|
|
2075
|
+
if (event.name === "agora.ui") frame({ kind: "ui", ...value });
|
|
2076
|
+
else if (event.name === "agora.title" && typeof value.title === "string") {
|
|
2077
|
+
frame({ kind: "title", title: value.title });
|
|
2078
|
+
} else if (event.name === "agora.queue") frame({ kind: "queue", ...value });
|
|
2079
|
+
else if (event.name === "agora.approval-requested") {
|
|
2080
|
+
frame({ ...value, kind: "approval-requested" });
|
|
2081
|
+
} else if (event.name === "agora.approval-settled") {
|
|
2082
|
+
frame({ ...value, kind: "approval-settled" });
|
|
2083
|
+
}
|
|
2084
|
+
return out;
|
|
2085
|
+
}
|
|
2086
|
+
default:
|
|
2087
|
+
flushStart();
|
|
2088
|
+
}
|
|
2089
|
+
switch (event.type) {
|
|
2090
|
+
case "TEXT_MESSAGE_CONTENT":
|
|
2091
|
+
case "TEXT_MESSAGE_CHUNK":
|
|
2092
|
+
if (typeof event.delta === "string" && event.delta.length > 0) {
|
|
2093
|
+
frame({ kind: "text", text: event.delta });
|
|
2094
|
+
}
|
|
2095
|
+
break;
|
|
2096
|
+
case "REASONING_MESSAGE_CONTENT":
|
|
2097
|
+
case "REASONING_MESSAGE_CHUNK":
|
|
2098
|
+
if (typeof event.delta === "string" && event.delta.length > 0) {
|
|
2099
|
+
frame({ kind: "reasoning", text: event.delta });
|
|
2100
|
+
}
|
|
2101
|
+
break;
|
|
2102
|
+
case "STEP_STARTED":
|
|
2103
|
+
frame({ kind: "step-start" });
|
|
2104
|
+
break;
|
|
2105
|
+
case "STEP_FINISHED":
|
|
2106
|
+
frame({ kind: "step-finish" });
|
|
2107
|
+
break;
|
|
2108
|
+
case "TOOL_CALL_START":
|
|
2109
|
+
case "TOOL_CALL_CHUNK": {
|
|
2110
|
+
const id = String(event.toolCallId ?? "");
|
|
2111
|
+
if (id === "") break;
|
|
2112
|
+
if (!tools.has(id)) {
|
|
2113
|
+
const name = typeof event.toolCallName === "string" ? event.toolCallName : "";
|
|
2114
|
+
tools.set(id, { name, args: "" });
|
|
2115
|
+
frame({ kind: "tool-input-start", id, name, toolKind: "read" });
|
|
2116
|
+
}
|
|
2117
|
+
if (event.type === "TOOL_CALL_CHUNK" && typeof event.delta === "string") {
|
|
2118
|
+
tools.get(id).args += event.delta;
|
|
2119
|
+
frame({ kind: "tool-input-delta", id, delta: event.delta });
|
|
2120
|
+
}
|
|
2121
|
+
break;
|
|
2122
|
+
}
|
|
2123
|
+
case "TOOL_CALL_ARGS": {
|
|
2124
|
+
const call = tools.get(String(event.toolCallId));
|
|
2125
|
+
if (call === void 0 || typeof event.delta !== "string") break;
|
|
2126
|
+
call.args += event.delta;
|
|
2127
|
+
frame({ kind: "tool-input-delta", id: String(event.toolCallId), delta: event.delta });
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
case "TOOL_CALL_END": {
|
|
2131
|
+
const id = String(event.toolCallId);
|
|
2132
|
+
const call = tools.get(id);
|
|
2133
|
+
if (call === void 0) break;
|
|
2134
|
+
frame({
|
|
2135
|
+
kind: "tool-input-available",
|
|
2136
|
+
id,
|
|
2137
|
+
name: call.name,
|
|
2138
|
+
input: parseJson(call.args, {}),
|
|
2139
|
+
toolKind: "read"
|
|
2140
|
+
});
|
|
2141
|
+
break;
|
|
2142
|
+
}
|
|
2143
|
+
case "TOOL_CALL_RESULT": {
|
|
2144
|
+
const id = String(event.toolCallId);
|
|
2145
|
+
const content = contentText(event.content);
|
|
2146
|
+
const outcome = isRecord2(event.metadata) ? event.metadata["agora.outcome"] : void 0;
|
|
2147
|
+
if (outcome === "error") frame({ kind: "tool-output-error", id, error: content });
|
|
2148
|
+
else if (outcome === "denied") frame({ kind: "tool-output-denied", id, reason: content });
|
|
2149
|
+
else frame({ kind: "tool-output", id, output: parseJson(content, content) });
|
|
2150
|
+
break;
|
|
2151
|
+
}
|
|
2152
|
+
case "RUN_ERROR":
|
|
2153
|
+
state.closed = true;
|
|
2154
|
+
out += `event: error
|
|
2155
|
+
data: ${JSON.stringify({
|
|
2156
|
+
code: typeof event.code === "string" ? event.code : "run_failed",
|
|
2157
|
+
message: typeof event.message === "string" ? event.message : "The run failed."
|
|
2158
|
+
})}
|
|
2159
|
+
|
|
2160
|
+
`;
|
|
2161
|
+
break;
|
|
2162
|
+
case "RUN_FINISHED": {
|
|
2163
|
+
const outcome = isRecord2(event.outcome) ? event.outcome : void 0;
|
|
2164
|
+
if (outcome?.type === "cancelled") frame({ kind: "cancelled" });
|
|
2165
|
+
if (outcome?.type === "interrupt" && Array.isArray(outcome.interrupts)) {
|
|
2166
|
+
frame({
|
|
2167
|
+
kind: "ui",
|
|
2168
|
+
id: `ag-ui:interrupt:${String(event.runId ?? "")}`,
|
|
2169
|
+
component: "AgUiInterrupt",
|
|
2170
|
+
props: { interrupts: outcome.interrupts }
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
state.closed = true;
|
|
2174
|
+
out += "event: done\ndata: {}\n\n";
|
|
2175
|
+
break;
|
|
2176
|
+
}
|
|
2177
|
+
default:
|
|
2178
|
+
break;
|
|
2179
|
+
}
|
|
2180
|
+
return out;
|
|
2181
|
+
function flushStart() {
|
|
2182
|
+
if (pendingStart !== void 0) {
|
|
2183
|
+
meta(pendingStart.runId, pendingStart.threadId);
|
|
2184
|
+
pendingStart = void 0;
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2189
|
+
let pendingStart;
|
|
2190
|
+
return state;
|
|
2191
|
+
}
|
|
2192
|
+
function parseJson(text, fallback2) {
|
|
2193
|
+
if (text.trim().length === 0) return fallback2;
|
|
2194
|
+
try {
|
|
2195
|
+
return JSON.parse(text);
|
|
2196
|
+
} catch {
|
|
2197
|
+
return fallback2;
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
function contentText(content) {
|
|
2201
|
+
if (typeof content === "string") return content;
|
|
2202
|
+
if (!Array.isArray(content)) return "";
|
|
2203
|
+
return content.filter((part) => isRecord2(part) && part.type === "text" && typeof part.text === "string").map((part) => part.text).join("");
|
|
2204
|
+
}
|
|
2205
|
+
|
|
1927
2206
|
// src/catalog/use-agents.ts
|
|
1928
2207
|
var import_react9 = require("react");
|
|
1929
2208
|
|
|
@@ -2561,7 +2840,7 @@ function phraseFor(presentation, input, isSettled2, fallback2 = { running: "Work
|
|
|
2561
2840
|
}
|
|
2562
2841
|
|
|
2563
2842
|
// src/presentation/result-view.ts
|
|
2564
|
-
function
|
|
2843
|
+
function isRecord3(value) {
|
|
2565
2844
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2566
2845
|
}
|
|
2567
2846
|
function toText(value) {
|
|
@@ -2573,18 +2852,18 @@ function toText(value) {
|
|
|
2573
2852
|
return "\u2014";
|
|
2574
2853
|
}
|
|
2575
2854
|
function inferResultView(output) {
|
|
2576
|
-
if (!
|
|
2855
|
+
if (!isRecord3(output)) return void 0;
|
|
2577
2856
|
for (const [key, value] of Object.entries(output)) {
|
|
2578
2857
|
if (!Array.isArray(value) || value.length === 0) continue;
|
|
2579
2858
|
if (value.every((entry) => typeof entry === "string")) {
|
|
2580
2859
|
return { kind: "log", lines: key };
|
|
2581
2860
|
}
|
|
2582
|
-
if (value.every(
|
|
2861
|
+
if (value.every(isRecord3)) {
|
|
2583
2862
|
const first = value[0];
|
|
2584
2863
|
return {
|
|
2585
2864
|
kind: "table",
|
|
2586
2865
|
rows: key,
|
|
2587
|
-
columns: Object.keys(first).filter((column) => !
|
|
2866
|
+
columns: Object.keys(first).filter((column) => !isRecord3(first[column])).map((column) => ({ path: column, label: column }))
|
|
2588
2867
|
};
|
|
2589
2868
|
}
|
|
2590
2869
|
}
|
|
@@ -2911,7 +3190,7 @@ function isSettled(state) {
|
|
|
2911
3190
|
}
|
|
2912
3191
|
function toolKind(part) {
|
|
2913
3192
|
const metadata = part.toolMetadata;
|
|
2914
|
-
return
|
|
3193
|
+
return isRecord4(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
|
|
2915
3194
|
}
|
|
2916
3195
|
function isAwaitingApproval(part) {
|
|
2917
3196
|
if (part.state === "approval-requested") {
|
|
@@ -2924,7 +3203,7 @@ function isAwaitingApproval(part) {
|
|
|
2924
3203
|
}
|
|
2925
3204
|
function toolParentId(part) {
|
|
2926
3205
|
const metadata = part.toolMetadata;
|
|
2927
|
-
return
|
|
3206
|
+
return isRecord4(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
|
|
2928
3207
|
}
|
|
2929
3208
|
function nestToolCalls(calls) {
|
|
2930
3209
|
const byId = new Map(calls.map((call) => [call.toolCallId, call]));
|
|
@@ -2983,12 +3262,12 @@ function buildToolCall(part, options, approval, catalog) {
|
|
|
2983
3262
|
}
|
|
2984
3263
|
function readElicitationRequest(part) {
|
|
2985
3264
|
const input = part.input;
|
|
2986
|
-
if (!
|
|
3265
|
+
if (!isRecord4(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
|
|
2987
3266
|
return null;
|
|
2988
3267
|
}
|
|
2989
3268
|
const questions = [];
|
|
2990
3269
|
for (const candidate of input.questions) {
|
|
2991
|
-
if (!
|
|
3270
|
+
if (!isRecord4(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string") {
|
|
2992
3271
|
return null;
|
|
2993
3272
|
}
|
|
2994
3273
|
const input2 = (0, import_nestjs_agent_core3.readElicitationInput)(candidate.input) ?? null;
|
|
@@ -2998,7 +3277,7 @@ function readElicitationRequest(part) {
|
|
|
2998
3277
|
}
|
|
2999
3278
|
const options = [];
|
|
3000
3279
|
for (const option of rawOptions) {
|
|
3001
|
-
if (!
|
|
3280
|
+
if (!isRecord4(option) || typeof option.value !== "string" || typeof option.label !== "string") {
|
|
3002
3281
|
return null;
|
|
3003
3282
|
}
|
|
3004
3283
|
options.push({
|
|
@@ -3025,7 +3304,7 @@ function readElicitationRequest(part) {
|
|
|
3025
3304
|
}
|
|
3026
3305
|
function readElicitationOutcome(part) {
|
|
3027
3306
|
const output = part.output;
|
|
3028
|
-
if (!
|
|
3307
|
+
if (!isRecord4(output) || !isRecord4(output.answers) || typeof output.skipped !== "boolean") {
|
|
3029
3308
|
return null;
|
|
3030
3309
|
}
|
|
3031
3310
|
const answers = {};
|
|
@@ -3150,7 +3429,7 @@ function readApprovals(parts) {
|
|
|
3150
3429
|
continue;
|
|
3151
3430
|
}
|
|
3152
3431
|
const data = part.data;
|
|
3153
|
-
if (!
|
|
3432
|
+
if (!isRecord4(data) || typeof data.id !== "string") {
|
|
3154
3433
|
continue;
|
|
3155
3434
|
}
|
|
3156
3435
|
const approval = entry(data.id);
|
|
@@ -3203,7 +3482,7 @@ function statusFromPart(call) {
|
|
|
3203
3482
|
}
|
|
3204
3483
|
function readUiComponent(part) {
|
|
3205
3484
|
const data = part.data;
|
|
3206
|
-
if (!
|
|
3485
|
+
if (!isRecord4(data) || typeof data.component !== "string") {
|
|
3207
3486
|
return null;
|
|
3208
3487
|
}
|
|
3209
3488
|
const id = typeof data.id === "string" ? data.id : part.id;
|
|
@@ -3213,29 +3492,29 @@ function readUiComponent(part) {
|
|
|
3213
3492
|
return {
|
|
3214
3493
|
id,
|
|
3215
3494
|
component: data.component,
|
|
3216
|
-
props:
|
|
3495
|
+
props: isRecord4(data.props) ? data.props : {},
|
|
3217
3496
|
version: typeof data.version === "number" ? data.version : null,
|
|
3218
3497
|
toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
|
|
3219
3498
|
};
|
|
3220
3499
|
}
|
|
3221
|
-
function
|
|
3500
|
+
function isRecord4(value) {
|
|
3222
3501
|
return typeof value === "object" && value !== null;
|
|
3223
3502
|
}
|
|
3224
3503
|
function readQuery(part) {
|
|
3225
3504
|
const input = part.input;
|
|
3226
|
-
if (!
|
|
3505
|
+
if (!isRecord4(input) || typeof input.query !== "string") {
|
|
3227
3506
|
return null;
|
|
3228
3507
|
}
|
|
3229
3508
|
return input.query;
|
|
3230
3509
|
}
|
|
3231
3510
|
function readPassages(part) {
|
|
3232
3511
|
const output = part.output;
|
|
3233
|
-
if (!
|
|
3512
|
+
if (!isRecord4(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
|
|
3234
3513
|
return null;
|
|
3235
3514
|
}
|
|
3236
3515
|
const passages = [];
|
|
3237
3516
|
for (const candidate of output.passages) {
|
|
3238
|
-
if (!
|
|
3517
|
+
if (!isRecord4(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
|
|
3239
3518
|
return null;
|
|
3240
3519
|
}
|
|
3241
3520
|
passages.push({
|
|
@@ -3243,7 +3522,7 @@ function readPassages(part) {
|
|
|
3243
3522
|
text: candidate.text,
|
|
3244
3523
|
score: typeof candidate.score === "number" ? candidate.score : 0,
|
|
3245
3524
|
...typeof candidate.source === "string" ? { source: candidate.source } : {},
|
|
3246
|
-
...
|
|
3525
|
+
...isRecord4(candidate.metadata) ? { metadata: candidate.metadata } : {}
|
|
3247
3526
|
});
|
|
3248
3527
|
}
|
|
3249
3528
|
return passages;
|
|
@@ -4803,6 +5082,14 @@ function storedMessageToUiMessage(message) {
|
|
|
4803
5082
|
approved: false,
|
|
4804
5083
|
...refusalReason(result) !== void 0 ? { reason: refusalReason(result) } : {}
|
|
4805
5084
|
}
|
|
5085
|
+
} : typeof result.error === "string" && result.error !== "" ? {
|
|
5086
|
+
// A call that FAILED — the tool threw, its input was refused, or its turn died
|
|
5087
|
+
// before it was settled — is not an available output either. The live stream says
|
|
5088
|
+
// so with `tool-output-error`; a reloaded thread has to say the same, or the card of
|
|
5089
|
+
// an action that never ran comes back reading as one that completed.
|
|
5090
|
+
state: "output-error",
|
|
5091
|
+
input: call.input,
|
|
5092
|
+
errorText: result.error
|
|
4806
5093
|
} : { state: "output-available", input: call.input, output: result.output } : { state: "input-available", input: call.input }
|
|
4807
5094
|
});
|
|
4808
5095
|
parts.push(...pushedByCall.get(call.id) ?? []);
|
|
@@ -5040,6 +5327,12 @@ function useAgentChat(options = {}) {
|
|
|
5040
5327
|
return { ...turnBody(), ...regenerate2 ? { regenerate: true } : {} };
|
|
5041
5328
|
},
|
|
5042
5329
|
getResumeRunId: () => latest.current.resumeRunId ?? autoResumeRunIdRef.current,
|
|
5330
|
+
// A stream attached to after a reload carries no `meta` frame: without this the chat would
|
|
5331
|
+
// be reading a run it cannot name, and `cancel()` would stop nothing.
|
|
5332
|
+
onResumeAttached: (resumedRunId) => {
|
|
5333
|
+
settlingRunIdRef.current = resumedRunId;
|
|
5334
|
+
setRunId(resumedRunId);
|
|
5335
|
+
},
|
|
5043
5336
|
onMeta,
|
|
5044
5337
|
onAttemptStart: () => {
|
|
5045
5338
|
settlingRunIdRef.current = void 0;
|
|
@@ -5509,7 +5802,14 @@ function useAgentChat(options = {}) {
|
|
|
5509
5802
|
} catch {
|
|
5510
5803
|
}
|
|
5511
5804
|
}
|
|
5512
|
-
|
|
5805
|
+
const threadId = currentThreadId();
|
|
5806
|
+
if (threadId !== void 0 && queueStateRef.current.items.length > 0 && typeof client.getQueue === "function") {
|
|
5807
|
+
try {
|
|
5808
|
+
applyQueue(await client.getQueue(threadId));
|
|
5809
|
+
} catch {
|
|
5810
|
+
}
|
|
5811
|
+
}
|
|
5812
|
+
}, [client, currentThreadId, applyQueue]);
|
|
5513
5813
|
const approve = (0, import_react23.useCallback)(
|
|
5514
5814
|
async ({ toolCallId, remember, via }) => {
|
|
5515
5815
|
await requireBackendMethod(
|
|
@@ -5849,6 +6149,7 @@ function isRunNotActiveError(error) {
|
|
|
5849
6149
|
RUN_NOT_ACTIVE_CODE,
|
|
5850
6150
|
SPEECH_LANGUAGES,
|
|
5851
6151
|
acceptsFile,
|
|
6152
|
+
agUiChatStream,
|
|
5852
6153
|
applyCompletion,
|
|
5853
6154
|
approvalCountdown,
|
|
5854
6155
|
attachmentFile,
|
|
@@ -5881,6 +6182,7 @@ function isRunNotActiveError(error) {
|
|
|
5881
6182
|
phraseFor,
|
|
5882
6183
|
readPath,
|
|
5883
6184
|
readReasoningMs,
|
|
6185
|
+
reframeAgUiStream,
|
|
5884
6186
|
requireBackendMethod,
|
|
5885
6187
|
resolveResultView,
|
|
5886
6188
|
storedMessageToUiMessage,
|