@dudousxd/nestjs-agent-react 0.20.0 → 0.22.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 +110 -85
- package/dist/{client-0Wd-WPsu.d.cts → client-CYlhK7XD.d.cts} +36 -24
- package/dist/{client-0Wd-WPsu.d.ts → client-CYlhK7XD.d.ts} +36 -24
- package/dist/{model-gHqjNjLJ.d.cts → generative-ui-9AJNVKBZ.d.cts} +165 -1
- package/dist/{model-gHqjNjLJ.d.ts → generative-ui-9AJNVKBZ.d.ts} +165 -1
- package/dist/genui-json-render.d.cts +1 -2
- package/dist/genui-json-render.d.ts +1 -2
- package/dist/genui.d.cts +2 -3
- package/dist/genui.d.ts +2 -3
- package/dist/index.cjs +1304 -491
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +259 -167
- package/dist/index.d.ts +259 -167
- package/dist/index.js +1264 -453
- package/dist/index.js.map +1 -1
- package/dist/media.cjs +13 -16
- package/dist/media.cjs.map +1 -1
- package/dist/media.d.cts +6 -23
- package/dist/media.d.ts +6 -23
- package/dist/media.js +12 -14
- package/dist/media.js.map +1 -1
- package/package.json +1 -1
- package/dist/generative-ui-BhXFni8j.d.ts +0 -167
- package/dist/generative-ui-C53b3FoA.d.cts +0 -167
package/dist/index.js
CHANGED
|
@@ -14,6 +14,11 @@ var AgentHttpError = class extends Error {
|
|
|
14
14
|
this.name = "AgentHttpError";
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
|
+
function normalizeAgentPath(path) {
|
|
18
|
+
const trimmed = (path ?? "agent").replace(/^\/+|\/+$/g, "");
|
|
19
|
+
return trimmed === "" ? "" : `/${trimmed}`;
|
|
20
|
+
}
|
|
21
|
+
__name(normalizeAgentPath, "normalizeAgentPath");
|
|
17
22
|
var HEADER_RUN_ID = "x-agent-run-id";
|
|
18
23
|
var HEADER_THREAD_ID = "x-agent-thread-id";
|
|
19
24
|
var AgentClient = class {
|
|
@@ -24,9 +29,9 @@ var AgentClient = class {
|
|
|
24
29
|
constructor(options = {}) {
|
|
25
30
|
this.options = options;
|
|
26
31
|
}
|
|
27
|
-
/** `POST
|
|
32
|
+
/** `POST <path>/chat` → the turn's SSE stream. Throws {@link AgentHttpError} on a non-2xx. */
|
|
28
33
|
async openChatStream(request) {
|
|
29
|
-
const response = await this.fetchImpl()(`${this.
|
|
34
|
+
const response = await this.fetchImpl()(`${this.root()}/chat`, {
|
|
30
35
|
method: "POST",
|
|
31
36
|
headers: {
|
|
32
37
|
"content-type": "application/json",
|
|
@@ -41,18 +46,18 @@ var AgentClient = class {
|
|
|
41
46
|
} : {}
|
|
42
47
|
});
|
|
43
48
|
if (!response.ok || !response.body) {
|
|
44
|
-
throw new AgentHttpError(response.status, "POST",
|
|
49
|
+
throw new AgentHttpError(response.status, "POST", `${this.agentPath()}/chat`, response.statusText);
|
|
45
50
|
}
|
|
46
51
|
return streamResponse(response);
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
49
|
-
* `GET
|
|
54
|
+
* `GET <path>/chat/:runId/stream[?after=<seq>]` → the run's SSE stream, or `null` when nothing is
|
|
50
55
|
* streaming under that id (404).
|
|
51
56
|
*/
|
|
52
57
|
async resumeChatStream(request) {
|
|
53
|
-
const path = `/
|
|
58
|
+
const path = `/chat/${encodeURIComponent(request.runId)}/stream`;
|
|
54
59
|
const query = request.after !== void 0 && request.after > 0 ? `?after=${request.after}` : "";
|
|
55
|
-
const response = await this.fetchImpl()(`${this.
|
|
60
|
+
const response = await this.fetchImpl()(`${this.root()}${path}${query}`, {
|
|
56
61
|
method: "GET",
|
|
57
62
|
headers: {
|
|
58
63
|
accept: "text/event-stream",
|
|
@@ -68,7 +73,7 @@ var AgentClient = class {
|
|
|
68
73
|
return null;
|
|
69
74
|
}
|
|
70
75
|
if (!response.ok || !response.body) {
|
|
71
|
-
throw new AgentHttpError(response.status, "GET", path
|
|
76
|
+
throw new AgentHttpError(response.status, "GET", `${this.agentPath()}${path}`, response.statusText);
|
|
72
77
|
}
|
|
73
78
|
return streamResponse(response);
|
|
74
79
|
}
|
|
@@ -77,10 +82,10 @@ var AgentClient = class {
|
|
|
77
82
|
* the stored rating.
|
|
78
83
|
*/
|
|
79
84
|
setMessageFeedback(messageId, input) {
|
|
80
|
-
return this.request("POST", `/
|
|
85
|
+
return this.request("POST", `/messages/${encodeURIComponent(messageId)}/feedback`, input);
|
|
81
86
|
}
|
|
82
87
|
listThreads() {
|
|
83
|
-
return this.request("GET", "/
|
|
88
|
+
return this.request("GET", "/threads");
|
|
84
89
|
}
|
|
85
90
|
/**
|
|
86
91
|
* The skills this caller can invoke right now, scope-resolved — the same list, built by the same
|
|
@@ -90,7 +95,7 @@ var AgentClient = class {
|
|
|
90
95
|
*/
|
|
91
96
|
listSkills(threadId) {
|
|
92
97
|
const query = threadId === void 0 ? "" : `?threadId=${encodeURIComponent(threadId)}`;
|
|
93
|
-
return this.request("GET", `/
|
|
98
|
+
return this.request("GET", `/skills${query}`);
|
|
94
99
|
}
|
|
95
100
|
/**
|
|
96
101
|
* The tools this caller can reach through `agent` (the default agent when omitted), each with the
|
|
@@ -99,41 +104,37 @@ var AgentClient = class {
|
|
|
99
104
|
*/
|
|
100
105
|
listTools(agent) {
|
|
101
106
|
const query = agent === void 0 ? "" : `?agent=${encodeURIComponent(agent)}`;
|
|
102
|
-
return this.request("GET", `/
|
|
107
|
+
return this.request("GET", `/tools${query}`);
|
|
103
108
|
}
|
|
104
109
|
getThread(id) {
|
|
105
|
-
return this.request("GET", `/
|
|
110
|
+
return this.request("GET", `/threads/${encodeURIComponent(id)}`);
|
|
106
111
|
}
|
|
107
112
|
deleteThread(id) {
|
|
108
|
-
return this.request("DELETE", `/
|
|
113
|
+
return this.request("DELETE", `/threads/${encodeURIComponent(id)}`);
|
|
109
114
|
}
|
|
110
115
|
forkFromMessage(threadId, messageId) {
|
|
111
|
-
return this.request("POST", `/
|
|
112
|
-
}
|
|
113
|
-
renameThread(id, title) {
|
|
114
|
-
return this.updateThread(id, {
|
|
115
|
-
title
|
|
116
|
-
});
|
|
116
|
+
return this.request("POST", `/threads/${encodeURIComponent(threadId)}/fork-from/${encodeURIComponent(messageId)}`);
|
|
117
117
|
}
|
|
118
|
-
/** General `PATCH
|
|
118
|
+
/** General `PATCH <path>/threads/:threadId` — title and/or the thread's pinned default agent. */
|
|
119
119
|
updateThread(id, patch) {
|
|
120
|
-
return this.request("PATCH", `/
|
|
120
|
+
return this.request("PATCH", `/threads/${encodeURIComponent(id)}`, patch);
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
123
|
* Uploads a file (image/PDF) for a vision-capable model turn. Multipart, field name `file` —
|
|
124
|
-
* mirrors the backend's `POST
|
|
124
|
+
* mirrors the backend's `POST <path>/attachments`. The returned {@link MessageAttachment} is
|
|
125
125
|
* what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
|
|
126
126
|
*/
|
|
127
127
|
async uploadAttachment(file, options = {}) {
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
const upload = this.options.attachments?.upload;
|
|
129
|
+
if (upload !== void 0) {
|
|
130
|
+
return upload(file, options, this.connection());
|
|
130
131
|
}
|
|
131
132
|
if (options.onProgress !== void 0 && this.options.fetch === void 0 && typeof XMLHttpRequest !== "undefined") {
|
|
132
133
|
return this.uploadWithProgress(file, options);
|
|
133
134
|
}
|
|
134
135
|
const formData = new FormData();
|
|
135
136
|
formData.append("file", file);
|
|
136
|
-
const response = await this.fetchImpl()(`${this.
|
|
137
|
+
const response = await this.fetchImpl()(`${this.root()}/attachments`, {
|
|
137
138
|
method: "POST",
|
|
138
139
|
headers: {
|
|
139
140
|
accept: "application/json",
|
|
@@ -145,7 +146,7 @@ var AgentClient = class {
|
|
|
145
146
|
signal: options.signal
|
|
146
147
|
} : {}
|
|
147
148
|
});
|
|
148
|
-
const attachment = await this.handleResponse(response, "POST",
|
|
149
|
+
const attachment = await this.handleResponse(response, "POST", `${this.agentPath()}/attachments`);
|
|
149
150
|
options.onProgress?.(1);
|
|
150
151
|
return attachment;
|
|
151
152
|
}
|
|
@@ -154,7 +155,7 @@ var AgentClient = class {
|
|
|
154
155
|
accept: "application/json",
|
|
155
156
|
...await this.resolveHeaders()
|
|
156
157
|
};
|
|
157
|
-
const url = `${this.
|
|
158
|
+
const url = `${this.root()}/attachments`;
|
|
158
159
|
return new Promise((resolve, reject) => {
|
|
159
160
|
const xhr = new XMLHttpRequest();
|
|
160
161
|
xhr.open("POST", url);
|
|
@@ -165,7 +166,7 @@ var AgentClient = class {
|
|
|
165
166
|
};
|
|
166
167
|
xhr.onload = () => {
|
|
167
168
|
if (xhr.status < 200 || xhr.status >= 300) {
|
|
168
|
-
reject(new AgentHttpError(xhr.status, "POST",
|
|
169
|
+
reject(new AgentHttpError(xhr.status, "POST", `${this.agentPath()}/attachments`, xhr.statusText));
|
|
169
170
|
return;
|
|
170
171
|
}
|
|
171
172
|
onProgress?.(1);
|
|
@@ -188,39 +189,36 @@ var AgentClient = class {
|
|
|
188
189
|
});
|
|
189
190
|
}
|
|
190
191
|
promoteThread(id) {
|
|
191
|
-
return this.request("POST", `/
|
|
192
|
+
return this.request("POST", `/threads/${encodeURIComponent(id)}/promote`);
|
|
192
193
|
}
|
|
193
194
|
truncateFromMessage(threadId, messageId) {
|
|
194
|
-
return this.request("DELETE", `/
|
|
195
|
+
return this.request("DELETE", `/threads/${encodeURIComponent(threadId)}/from/${encodeURIComponent(messageId)}`);
|
|
195
196
|
}
|
|
196
|
-
/** `GET
|
|
197
|
+
/** `GET <path>/models?agent=` — the models this caller may pick, grouped by provider. */
|
|
197
198
|
listModels(agent) {
|
|
198
199
|
const query = agent === void 0 ? "" : `?agent=${encodeURIComponent(agent)}`;
|
|
199
|
-
return this.request("GET", `/
|
|
200
|
+
return this.request("GET", `/models${query}`);
|
|
200
201
|
}
|
|
201
|
-
/** `GET
|
|
202
|
+
/** `GET <path>/agents` — the registered agents, the default one flagged. */
|
|
202
203
|
listAgents() {
|
|
203
|
-
return this.request("GET", "/
|
|
204
|
+
return this.request("GET", "/agents");
|
|
204
205
|
}
|
|
205
|
-
/** `GET
|
|
206
|
+
/** `GET <path>/quota` — the caller's budget windows and the one blocking sends, if any. */
|
|
206
207
|
getQuota() {
|
|
207
|
-
return this.request("GET", "/
|
|
208
|
-
}
|
|
209
|
-
getQuotaToday() {
|
|
210
|
-
return this.request("GET", "/agent/quota/today");
|
|
208
|
+
return this.request("GET", "/quota");
|
|
211
209
|
}
|
|
212
210
|
cancelStream(runId) {
|
|
213
|
-
return this.request("POST", `/
|
|
211
|
+
return this.request("POST", `/chat/${encodeURIComponent(runId)}/cancel`);
|
|
214
212
|
}
|
|
215
213
|
/**
|
|
216
214
|
* `remember` approves later calls of the same tool in the same thread; `via` names the surface
|
|
217
215
|
* the decision came through (the server records `'web'` when omitted).
|
|
218
216
|
*/
|
|
219
217
|
approveToolCall(input) {
|
|
220
|
-
return this.request("POST", "/
|
|
218
|
+
return this.request("POST", "/tool-call/approve", input);
|
|
221
219
|
}
|
|
222
220
|
rejectToolCall(input) {
|
|
223
|
-
return this.request("POST", "/
|
|
221
|
+
return this.request("POST", "/tool-call/reject", input);
|
|
224
222
|
}
|
|
225
223
|
/**
|
|
226
224
|
* Settle a parked question set. `answers` is questionId → chosen option values; a question left
|
|
@@ -229,7 +227,7 @@ var AgentClient = class {
|
|
|
229
227
|
* answer — which is the point of the surface, so it is a valid submission rather than a blank.
|
|
230
228
|
*/
|
|
231
229
|
answerToolCall(input) {
|
|
232
|
-
return this.request("POST", "/
|
|
230
|
+
return this.request("POST", "/tool-call/answer", input);
|
|
233
231
|
}
|
|
234
232
|
/**
|
|
235
233
|
* Decline to answer and let the agent proceed on its own pre-picked values. Lands on the same
|
|
@@ -237,7 +235,7 @@ var AgentClient = class {
|
|
|
237
235
|
* evidence the user chose them.
|
|
238
236
|
*/
|
|
239
237
|
skipToolCall(input) {
|
|
240
|
-
return this.request("POST", "/
|
|
238
|
+
return this.request("POST", "/tool-call/skip", input);
|
|
241
239
|
}
|
|
242
240
|
fetchImpl() {
|
|
243
241
|
return this.options.fetch ?? globalThis.fetch;
|
|
@@ -246,13 +244,21 @@ var AgentClient = class {
|
|
|
246
244
|
connection() {
|
|
247
245
|
return {
|
|
248
246
|
baseUrl: this.baseUrl(),
|
|
247
|
+
path: this.agentPath(),
|
|
249
248
|
headers: /* @__PURE__ */ __name(() => this.resolveHeaders(), "headers"),
|
|
250
249
|
fetch: this.fetchImpl(),
|
|
251
250
|
...this.credentials()
|
|
252
251
|
};
|
|
253
252
|
}
|
|
254
253
|
baseUrl() {
|
|
255
|
-
return (this.options.baseUrl ?? "").replace(
|
|
254
|
+
return (this.options.baseUrl ?? "").replace(/\/+$/, "");
|
|
255
|
+
}
|
|
256
|
+
agentPath() {
|
|
257
|
+
return normalizeAgentPath(this.options.path);
|
|
258
|
+
}
|
|
259
|
+
/** Origin + agent path: what every route hangs off. */
|
|
260
|
+
root() {
|
|
261
|
+
return `${this.baseUrl()}${this.agentPath()}`;
|
|
256
262
|
}
|
|
257
263
|
async resolveHeaders() {
|
|
258
264
|
const dynamic = await this.options.getHeaders?.() ?? {};
|
|
@@ -266,7 +272,8 @@ var AgentClient = class {
|
|
|
266
272
|
credentials: this.options.credentials
|
|
267
273
|
} : {};
|
|
268
274
|
}
|
|
269
|
-
async request(method,
|
|
275
|
+
async request(method, route, body) {
|
|
276
|
+
const path = `${this.agentPath()}${route}`;
|
|
270
277
|
const response = await this.fetchImpl()(`${this.baseUrl()}${path}`, {
|
|
271
278
|
method,
|
|
272
279
|
headers: {
|
|
@@ -397,6 +404,9 @@ var AgentChatTransport = class {
|
|
|
397
404
|
...options.baseUrl !== void 0 ? {
|
|
398
405
|
baseUrl: options.baseUrl
|
|
399
406
|
} : {},
|
|
407
|
+
...options.path !== void 0 ? {
|
|
408
|
+
path: options.path
|
|
409
|
+
} : {},
|
|
400
410
|
...options.headers !== void 0 ? {
|
|
401
411
|
headers: options.headers
|
|
402
412
|
} : {},
|
|
@@ -608,13 +618,14 @@ var AgentChatTransport = class {
|
|
|
608
618
|
function ensureStarted() {
|
|
609
619
|
if (started) return;
|
|
610
620
|
started = true;
|
|
611
|
-
controller.enqueue(
|
|
621
|
+
controller.enqueue({
|
|
612
622
|
type: "start",
|
|
613
623
|
messageMetadata: {
|
|
614
|
-
|
|
624
|
+
...streamRunId !== void 0 ? {
|
|
625
|
+
runId: streamRunId
|
|
626
|
+
} : {},
|
|
627
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
615
628
|
}
|
|
616
|
-
} : {
|
|
617
|
-
type: "start"
|
|
618
629
|
});
|
|
619
630
|
}
|
|
620
631
|
__name(ensureStarted, "ensureStarted");
|
|
@@ -1102,7 +1113,7 @@ function dragHasFiles(data) {
|
|
|
1102
1113
|
__name(dragHasFiles, "dragHasFiles");
|
|
1103
1114
|
|
|
1104
1115
|
// src/attachments/use-attachments.ts
|
|
1105
|
-
import { useCallback, useEffect as
|
|
1116
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo4, useRef as useRef3, useState as useState3 } from "react";
|
|
1106
1117
|
|
|
1107
1118
|
// src/backend.ts
|
|
1108
1119
|
var AgentBackendUnsupportedError = class extends Error {
|
|
@@ -1124,6 +1135,570 @@ function requireBackendMethod(backend, name) {
|
|
|
1124
1135
|
}
|
|
1125
1136
|
__name(requireBackendMethod, "requireBackendMethod");
|
|
1126
1137
|
|
|
1138
|
+
// src/provider.tsx
|
|
1139
|
+
import { useContext as useContext3, useMemo as useMemo3, useRef as useRef2 } from "react";
|
|
1140
|
+
|
|
1141
|
+
// src/components/ambient-ui.ts
|
|
1142
|
+
import { createContext, useContext } from "react";
|
|
1143
|
+
function sharedContext(key) {
|
|
1144
|
+
const symbol = Symbol.for(key);
|
|
1145
|
+
const holder = globalThis;
|
|
1146
|
+
const existing = holder[symbol];
|
|
1147
|
+
if (existing !== void 0) return existing;
|
|
1148
|
+
const created = createContext(null);
|
|
1149
|
+
holder[symbol] = created;
|
|
1150
|
+
return created;
|
|
1151
|
+
}
|
|
1152
|
+
__name(sharedContext, "sharedContext");
|
|
1153
|
+
var AmbientRenderUiContext = sharedContext("@dudousxd/nestjs-agent-react:ambient-render-ui");
|
|
1154
|
+
function useAmbientRenderUi() {
|
|
1155
|
+
return useContext(AmbientRenderUiContext);
|
|
1156
|
+
}
|
|
1157
|
+
__name(useAmbientRenderUi, "useAmbientRenderUi");
|
|
1158
|
+
|
|
1159
|
+
// src/genui/generative-ui.tsx
|
|
1160
|
+
import { Component, createContext as createContext2, useCallback, useContext as useContext2, useMemo as useMemo2 } from "react";
|
|
1161
|
+
|
|
1162
|
+
// src/genui/use-generative-ui.ts
|
|
1163
|
+
import { useEffect as useEffect2, useMemo, useState as useState2 } from "react";
|
|
1164
|
+
|
|
1165
|
+
// src/genui/types.ts
|
|
1166
|
+
var GENUI_TREE_COMPONENT = "genui:tree";
|
|
1167
|
+
|
|
1168
|
+
// src/genui/use-generative-ui.ts
|
|
1169
|
+
function isRecord(value) {
|
|
1170
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1171
|
+
}
|
|
1172
|
+
__name(isRecord, "isRecord");
|
|
1173
|
+
function toGenerativeUIItem(part) {
|
|
1174
|
+
if (!isRecord(part)) return null;
|
|
1175
|
+
const source = part.type === "data-ui" && isRecord(part.data) ? part.data : part;
|
|
1176
|
+
if (typeof source.component !== "string") return null;
|
|
1177
|
+
const id = typeof source.id === "string" ? source.id : typeof part.id === "string" ? part.id : null;
|
|
1178
|
+
if (id === null) return null;
|
|
1179
|
+
return {
|
|
1180
|
+
id,
|
|
1181
|
+
component: source.component,
|
|
1182
|
+
props: isRecord(source.props) ? source.props : {},
|
|
1183
|
+
version: typeof source.version === "number" ? source.version : null,
|
|
1184
|
+
toolCallId: typeof source.toolCallId === "string" ? source.toolCallId : null
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
__name(toGenerativeUIItem, "toGenerativeUIItem");
|
|
1188
|
+
var resolverCaches = /* @__PURE__ */ new WeakMap();
|
|
1189
|
+
function resolveCached(resolve, name, version) {
|
|
1190
|
+
let cache = resolverCaches.get(resolve);
|
|
1191
|
+
if (cache === void 0) {
|
|
1192
|
+
cache = /* @__PURE__ */ new Map();
|
|
1193
|
+
resolverCaches.set(resolve, cache);
|
|
1194
|
+
}
|
|
1195
|
+
const key = `${name}@${version ?? ""}`;
|
|
1196
|
+
const hit = cache.get(key);
|
|
1197
|
+
if (hit !== void 0) return hit;
|
|
1198
|
+
let entry;
|
|
1199
|
+
try {
|
|
1200
|
+
const result = resolve(name, version);
|
|
1201
|
+
if (result instanceof Promise) {
|
|
1202
|
+
entry = {
|
|
1203
|
+
resolution: {
|
|
1204
|
+
status: "loading"
|
|
1205
|
+
},
|
|
1206
|
+
settled: null
|
|
1207
|
+
};
|
|
1208
|
+
entry.settled = result.then((Component2) => {
|
|
1209
|
+
entry.resolution = Component2 ? {
|
|
1210
|
+
status: "ready",
|
|
1211
|
+
Component: Component2
|
|
1212
|
+
} : {
|
|
1213
|
+
status: "unknown"
|
|
1214
|
+
};
|
|
1215
|
+
}, (error) => {
|
|
1216
|
+
entry.resolution = {
|
|
1217
|
+
status: "error",
|
|
1218
|
+
error
|
|
1219
|
+
};
|
|
1220
|
+
});
|
|
1221
|
+
} else {
|
|
1222
|
+
entry = {
|
|
1223
|
+
resolution: result ? {
|
|
1224
|
+
status: "ready",
|
|
1225
|
+
Component: result
|
|
1226
|
+
} : {
|
|
1227
|
+
status: "unknown"
|
|
1228
|
+
},
|
|
1229
|
+
settled: null
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
} catch (error) {
|
|
1233
|
+
entry = {
|
|
1234
|
+
resolution: {
|
|
1235
|
+
status: "error",
|
|
1236
|
+
error
|
|
1237
|
+
},
|
|
1238
|
+
settled: null
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
cache.set(key, entry);
|
|
1242
|
+
return entry;
|
|
1243
|
+
}
|
|
1244
|
+
__name(resolveCached, "resolveCached");
|
|
1245
|
+
function useResolvedComponent(name, version, registry, resolve, fallbackTree) {
|
|
1246
|
+
const [, setTick] = useState2(0);
|
|
1247
|
+
const own = registry[name];
|
|
1248
|
+
const entry = own !== void 0 || resolve === void 0 ? null : resolveCached(resolve, name, version);
|
|
1249
|
+
const pending = entry?.resolution.status === "loading" ? entry.settled : null;
|
|
1250
|
+
useEffect2(() => {
|
|
1251
|
+
if (pending === null) return;
|
|
1252
|
+
let live = true;
|
|
1253
|
+
void pending.then(() => {
|
|
1254
|
+
if (live) setTick((tick) => tick + 1);
|
|
1255
|
+
});
|
|
1256
|
+
return () => {
|
|
1257
|
+
live = false;
|
|
1258
|
+
};
|
|
1259
|
+
}, [
|
|
1260
|
+
pending
|
|
1261
|
+
]);
|
|
1262
|
+
if (own !== void 0) return {
|
|
1263
|
+
status: "ready",
|
|
1264
|
+
Component: own
|
|
1265
|
+
};
|
|
1266
|
+
if (entry !== null && entry.resolution.status !== "unknown") return entry.resolution;
|
|
1267
|
+
if (name === GENUI_TREE_COMPONENT && fallbackTree !== void 0) {
|
|
1268
|
+
return {
|
|
1269
|
+
status: "ready",
|
|
1270
|
+
Component: fallbackTree
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
return {
|
|
1274
|
+
status: "unknown"
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
__name(useResolvedComponent, "useResolvedComponent");
|
|
1278
|
+
function useValidatedProps(catalog, name, props) {
|
|
1279
|
+
const checked = catalog?.has(name) === true;
|
|
1280
|
+
const immediate = useMemo(() => {
|
|
1281
|
+
if (!checked || catalog === void 0) return {
|
|
1282
|
+
status: "ok",
|
|
1283
|
+
props
|
|
1284
|
+
};
|
|
1285
|
+
const result = catalog.validateSync?.(name, props);
|
|
1286
|
+
if (result === void 0) return null;
|
|
1287
|
+
return result.ok ? {
|
|
1288
|
+
status: "ok",
|
|
1289
|
+
props: result.value
|
|
1290
|
+
} : {
|
|
1291
|
+
status: "invalid",
|
|
1292
|
+
issues: result.issues
|
|
1293
|
+
};
|
|
1294
|
+
}, [
|
|
1295
|
+
checked,
|
|
1296
|
+
catalog,
|
|
1297
|
+
name,
|
|
1298
|
+
props
|
|
1299
|
+
]);
|
|
1300
|
+
const [late, setLate] = useState2(null);
|
|
1301
|
+
useEffect2(() => {
|
|
1302
|
+
if (immediate !== null || catalog === void 0) return;
|
|
1303
|
+
let live = true;
|
|
1304
|
+
catalog.validate(name, props).then((result) => {
|
|
1305
|
+
if (!live) return;
|
|
1306
|
+
setLate({
|
|
1307
|
+
props,
|
|
1308
|
+
result: result.ok ? {
|
|
1309
|
+
status: "ok",
|
|
1310
|
+
props: result.value
|
|
1311
|
+
} : {
|
|
1312
|
+
status: "invalid",
|
|
1313
|
+
issues: result.issues
|
|
1314
|
+
}
|
|
1315
|
+
});
|
|
1316
|
+
}, (error) => {
|
|
1317
|
+
if (!live) return;
|
|
1318
|
+
setLate({
|
|
1319
|
+
props,
|
|
1320
|
+
result: {
|
|
1321
|
+
status: "invalid",
|
|
1322
|
+
issues: [
|
|
1323
|
+
{
|
|
1324
|
+
path: [],
|
|
1325
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1326
|
+
}
|
|
1327
|
+
]
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
});
|
|
1331
|
+
return () => {
|
|
1332
|
+
live = false;
|
|
1333
|
+
};
|
|
1334
|
+
}, [
|
|
1335
|
+
immediate,
|
|
1336
|
+
catalog,
|
|
1337
|
+
name,
|
|
1338
|
+
props
|
|
1339
|
+
]);
|
|
1340
|
+
if (immediate !== null) return immediate;
|
|
1341
|
+
return late !== null && late.props === props ? late.result : {
|
|
1342
|
+
status: "pending"
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
__name(useValidatedProps, "useValidatedProps");
|
|
1346
|
+
function useGenerativeUIState(part, options, fallbackTree) {
|
|
1347
|
+
const item = useMemo(() => toGenerativeUIItem(part), [
|
|
1348
|
+
part
|
|
1349
|
+
]);
|
|
1350
|
+
const name = item?.component ?? "";
|
|
1351
|
+
const resolution = useResolvedComponent(name, item?.version ?? null, options.registry, item === null ? void 0 : options.resolveComponent, fallbackTree);
|
|
1352
|
+
const empty = useMemo(() => ({}), []);
|
|
1353
|
+
const validation = useValidatedProps(item === null || name === GENUI_TREE_COMPONENT ? void 0 : options.catalog, name, item?.props ?? empty);
|
|
1354
|
+
if (item === null) return null;
|
|
1355
|
+
if (resolution.status === "loading") return {
|
|
1356
|
+
status: "loading",
|
|
1357
|
+
item
|
|
1358
|
+
};
|
|
1359
|
+
if (resolution.status === "unknown") return {
|
|
1360
|
+
status: "problem",
|
|
1361
|
+
reason: "unknown",
|
|
1362
|
+
item
|
|
1363
|
+
};
|
|
1364
|
+
if (resolution.status === "error") {
|
|
1365
|
+
return {
|
|
1366
|
+
status: "problem",
|
|
1367
|
+
reason: "error",
|
|
1368
|
+
item,
|
|
1369
|
+
error: resolution.error
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
if (validation.status === "pending") return {
|
|
1373
|
+
status: "loading",
|
|
1374
|
+
item
|
|
1375
|
+
};
|
|
1376
|
+
if (validation.status === "invalid") {
|
|
1377
|
+
return {
|
|
1378
|
+
status: "problem",
|
|
1379
|
+
reason: "invalid",
|
|
1380
|
+
item,
|
|
1381
|
+
issues: validation.issues
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
return {
|
|
1385
|
+
status: "ready",
|
|
1386
|
+
item,
|
|
1387
|
+
Component: resolution.Component,
|
|
1388
|
+
props: validation.props
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
__name(useGenerativeUIState, "useGenerativeUIState");
|
|
1392
|
+
|
|
1393
|
+
// src/genui/generative-ui.tsx
|
|
1394
|
+
var TreeScopeContext = /* @__PURE__ */ createContext2(null);
|
|
1395
|
+
function renderFallback(fallback2, problem) {
|
|
1396
|
+
if (typeof fallback2 === "function") return fallback2(problem);
|
|
1397
|
+
return fallback2 ?? null;
|
|
1398
|
+
}
|
|
1399
|
+
__name(renderFallback, "renderFallback");
|
|
1400
|
+
var ItemBoundary = class ItemBoundary2 extends Component {
|
|
1401
|
+
static {
|
|
1402
|
+
__name(this, "ItemBoundary");
|
|
1403
|
+
}
|
|
1404
|
+
state = {
|
|
1405
|
+
error: void 0,
|
|
1406
|
+
failed: false
|
|
1407
|
+
};
|
|
1408
|
+
static getDerivedStateFromError(error) {
|
|
1409
|
+
return {
|
|
1410
|
+
error,
|
|
1411
|
+
failed: true
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
componentDidCatch(error, _info) {
|
|
1415
|
+
this.props.onError?.(error, this.props.item);
|
|
1416
|
+
}
|
|
1417
|
+
componentDidUpdate(previous) {
|
|
1418
|
+
if (this.state.failed && previous.item !== this.props.item) {
|
|
1419
|
+
this.setState({
|
|
1420
|
+
error: void 0,
|
|
1421
|
+
failed: false
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
render() {
|
|
1426
|
+
if (this.state.failed) {
|
|
1427
|
+
return renderFallback(this.props.fallback, {
|
|
1428
|
+
reason: "error",
|
|
1429
|
+
item: this.props.item,
|
|
1430
|
+
error: this.state.error
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
return this.props.children;
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
function nodeItem(node, id) {
|
|
1437
|
+
return {
|
|
1438
|
+
id,
|
|
1439
|
+
component: node.type,
|
|
1440
|
+
props: node.props ?? {},
|
|
1441
|
+
version: null,
|
|
1442
|
+
toolCallId: null
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
__name(nodeItem, "nodeItem");
|
|
1446
|
+
function TreeNode({ node, id }) {
|
|
1447
|
+
const scope = useContext2(TreeScopeContext);
|
|
1448
|
+
const item = useMemo2(() => nodeItem(node, id), [
|
|
1449
|
+
node,
|
|
1450
|
+
id
|
|
1451
|
+
]);
|
|
1452
|
+
const resolution = useResolvedComponent(node.type, null, scope?.options.registry ?? {}, scope?.options.resolveComponent);
|
|
1453
|
+
const validation = useValidatedProps(scope?.options.catalog, node.type, item.props);
|
|
1454
|
+
if (scope === null) return null;
|
|
1455
|
+
if (resolution.status === "loading" || validation.status === "pending") return scope.loading;
|
|
1456
|
+
if (resolution.status === "unknown") {
|
|
1457
|
+
return renderFallback(scope.fallback, {
|
|
1458
|
+
reason: "unknown",
|
|
1459
|
+
item
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
if (resolution.status === "error") {
|
|
1463
|
+
return renderFallback(scope.fallback, {
|
|
1464
|
+
reason: "error",
|
|
1465
|
+
item,
|
|
1466
|
+
error: resolution.error
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
if (validation.status === "invalid") {
|
|
1470
|
+
return renderFallback(scope.fallback, {
|
|
1471
|
+
reason: "invalid",
|
|
1472
|
+
item,
|
|
1473
|
+
issues: validation.issues
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1476
|
+
const Renderer = resolution.Component;
|
|
1477
|
+
const children = Array.isArray(node.children) ? node.children : [];
|
|
1478
|
+
return /* @__PURE__ */ React.createElement(Renderer, validation.props, children.length > 0 ? children.map((child, index) => {
|
|
1479
|
+
const childId = `${id}.${index}`;
|
|
1480
|
+
return /* @__PURE__ */ React.createElement(ItemBoundary, {
|
|
1481
|
+
key: childId,
|
|
1482
|
+
item: nodeItem(child, childId),
|
|
1483
|
+
fallback: scope.fallback,
|
|
1484
|
+
onError: scope.onError
|
|
1485
|
+
}, /* @__PURE__ */ React.createElement(TreeNode, {
|
|
1486
|
+
node: child,
|
|
1487
|
+
id: childId
|
|
1488
|
+
}));
|
|
1489
|
+
}) : void 0);
|
|
1490
|
+
}
|
|
1491
|
+
__name(TreeNode, "TreeNode");
|
|
1492
|
+
function GenuiTree({ root }) {
|
|
1493
|
+
if (root === void 0 || root === null || typeof root.type !== "string") return null;
|
|
1494
|
+
return /* @__PURE__ */ React.createElement(TreeNode, {
|
|
1495
|
+
node: root,
|
|
1496
|
+
id: "root"
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
__name(GenuiTree, "GenuiTree");
|
|
1500
|
+
function GenerativeUIScope({ registry, catalog, resolveComponent, fallback: fallback2, loading = null, onError, children }) {
|
|
1501
|
+
const scope = useMemo2(() => ({
|
|
1502
|
+
options: {
|
|
1503
|
+
registry,
|
|
1504
|
+
...catalog !== void 0 ? {
|
|
1505
|
+
catalog
|
|
1506
|
+
} : {},
|
|
1507
|
+
...resolveComponent !== void 0 ? {
|
|
1508
|
+
resolveComponent
|
|
1509
|
+
} : {}
|
|
1510
|
+
},
|
|
1511
|
+
fallback: fallback2,
|
|
1512
|
+
loading,
|
|
1513
|
+
onError
|
|
1514
|
+
}), [
|
|
1515
|
+
registry,
|
|
1516
|
+
catalog,
|
|
1517
|
+
resolveComponent,
|
|
1518
|
+
fallback2,
|
|
1519
|
+
loading,
|
|
1520
|
+
onError
|
|
1521
|
+
]);
|
|
1522
|
+
return /* @__PURE__ */ React.createElement(TreeScopeContext.Provider, {
|
|
1523
|
+
value: scope
|
|
1524
|
+
}, children);
|
|
1525
|
+
}
|
|
1526
|
+
__name(GenerativeUIScope, "GenerativeUIScope");
|
|
1527
|
+
var GenuiContext = sharedContext("@dudousxd/nestjs-agent-react:genui-provider");
|
|
1528
|
+
function GenuiProvider({ registry, catalog, resolveComponent, treeRenderer, fallback: fallback2, loading, onError, children }) {
|
|
1529
|
+
const value = useMemo2(() => ({
|
|
1530
|
+
...registry !== void 0 ? {
|
|
1531
|
+
registry
|
|
1532
|
+
} : {},
|
|
1533
|
+
...catalog !== void 0 ? {
|
|
1534
|
+
catalog
|
|
1535
|
+
} : {},
|
|
1536
|
+
...resolveComponent !== void 0 ? {
|
|
1537
|
+
resolveComponent
|
|
1538
|
+
} : {},
|
|
1539
|
+
...treeRenderer !== void 0 ? {
|
|
1540
|
+
treeRenderer
|
|
1541
|
+
} : {},
|
|
1542
|
+
...fallback2 !== void 0 ? {
|
|
1543
|
+
fallback: fallback2
|
|
1544
|
+
} : {},
|
|
1545
|
+
...loading !== void 0 ? {
|
|
1546
|
+
loading
|
|
1547
|
+
} : {},
|
|
1548
|
+
...onError !== void 0 ? {
|
|
1549
|
+
onError
|
|
1550
|
+
} : {}
|
|
1551
|
+
}), [
|
|
1552
|
+
registry,
|
|
1553
|
+
catalog,
|
|
1554
|
+
resolveComponent,
|
|
1555
|
+
treeRenderer,
|
|
1556
|
+
fallback2,
|
|
1557
|
+
loading,
|
|
1558
|
+
onError
|
|
1559
|
+
]);
|
|
1560
|
+
const renderUi = useCallback((block) => /* @__PURE__ */ React.createElement(GenerativeUI, {
|
|
1561
|
+
part: block
|
|
1562
|
+
}), []);
|
|
1563
|
+
return /* @__PURE__ */ React.createElement(GenuiContext.Provider, {
|
|
1564
|
+
value
|
|
1565
|
+
}, /* @__PURE__ */ React.createElement(AmbientRenderUiContext.Provider, {
|
|
1566
|
+
value: renderUi
|
|
1567
|
+
}, children));
|
|
1568
|
+
}
|
|
1569
|
+
__name(GenuiProvider, "GenuiProvider");
|
|
1570
|
+
var NO_REGISTRY = {};
|
|
1571
|
+
function useMergedOptions(own) {
|
|
1572
|
+
const provided = useContext2(GenuiContext);
|
|
1573
|
+
const registry = own.registry ?? provided?.registry ?? NO_REGISTRY;
|
|
1574
|
+
const catalog = own.catalog ?? provided?.catalog;
|
|
1575
|
+
const resolveComponent = own.resolveComponent ?? provided?.resolveComponent;
|
|
1576
|
+
const treeRenderer = own.treeRenderer ?? provided?.treeRenderer;
|
|
1577
|
+
return useMemo2(() => ({
|
|
1578
|
+
registry,
|
|
1579
|
+
...catalog !== void 0 ? {
|
|
1580
|
+
catalog
|
|
1581
|
+
} : {},
|
|
1582
|
+
...resolveComponent !== void 0 ? {
|
|
1583
|
+
resolveComponent
|
|
1584
|
+
} : {},
|
|
1585
|
+
...treeRenderer !== void 0 ? {
|
|
1586
|
+
treeRenderer
|
|
1587
|
+
} : {}
|
|
1588
|
+
}), [
|
|
1589
|
+
registry,
|
|
1590
|
+
catalog,
|
|
1591
|
+
resolveComponent,
|
|
1592
|
+
treeRenderer
|
|
1593
|
+
]);
|
|
1594
|
+
}
|
|
1595
|
+
__name(useMergedOptions, "useMergedOptions");
|
|
1596
|
+
function GenerativeUI({ part, registry, catalog, resolveComponent, treeRenderer, fallback: ownFallback, loading: ownLoading, onError: ownOnError }) {
|
|
1597
|
+
const provided = useContext2(GenuiContext);
|
|
1598
|
+
const fallback2 = ownFallback ?? provided?.fallback;
|
|
1599
|
+
const loading = ownLoading ?? provided?.loading ?? null;
|
|
1600
|
+
const onError = ownOnError ?? provided?.onError;
|
|
1601
|
+
const options = useMergedOptions({
|
|
1602
|
+
...registry !== void 0 ? {
|
|
1603
|
+
registry
|
|
1604
|
+
} : {},
|
|
1605
|
+
...catalog !== void 0 ? {
|
|
1606
|
+
catalog
|
|
1607
|
+
} : {},
|
|
1608
|
+
...resolveComponent !== void 0 ? {
|
|
1609
|
+
resolveComponent
|
|
1610
|
+
} : {},
|
|
1611
|
+
...treeRenderer !== void 0 ? {
|
|
1612
|
+
treeRenderer
|
|
1613
|
+
} : {}
|
|
1614
|
+
});
|
|
1615
|
+
const state = useGenerativeUIState(part, options, options.treeRenderer ?? GenuiTree);
|
|
1616
|
+
if (state === null) return null;
|
|
1617
|
+
if (state.status === "loading") return loading;
|
|
1618
|
+
if (state.status === "problem") {
|
|
1619
|
+
const { status: _status, ...problem } = state;
|
|
1620
|
+
return renderFallback(fallback2, problem);
|
|
1621
|
+
}
|
|
1622
|
+
const Renderer = state.Component;
|
|
1623
|
+
return /* @__PURE__ */ React.createElement(GenerativeUIScope, {
|
|
1624
|
+
...options,
|
|
1625
|
+
fallback: fallback2,
|
|
1626
|
+
loading,
|
|
1627
|
+
...onError !== void 0 ? {
|
|
1628
|
+
onError
|
|
1629
|
+
} : {}
|
|
1630
|
+
}, /* @__PURE__ */ React.createElement(ItemBoundary, {
|
|
1631
|
+
item: state.item,
|
|
1632
|
+
fallback: fallback2,
|
|
1633
|
+
onError
|
|
1634
|
+
}, /* @__PURE__ */ React.createElement(Renderer, state.props)));
|
|
1635
|
+
}
|
|
1636
|
+
__name(GenerativeUI, "GenerativeUI");
|
|
1637
|
+
|
|
1638
|
+
// src/provider.tsx
|
|
1639
|
+
var AgentBackendContext = sharedContext("@dudousxd/nestjs-agent-react:agent-backend");
|
|
1640
|
+
function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credentials, fetch, attachments, genui, children }) {
|
|
1641
|
+
const latestHeaders = useRef2({
|
|
1642
|
+
headers,
|
|
1643
|
+
getHeaders
|
|
1644
|
+
});
|
|
1645
|
+
latestHeaders.current = {
|
|
1646
|
+
headers,
|
|
1647
|
+
getHeaders
|
|
1648
|
+
};
|
|
1649
|
+
const upload = attachments?.upload;
|
|
1650
|
+
const value = useMemo3(() => backend ?? new AgentClient({
|
|
1651
|
+
...baseUrl !== void 0 ? {
|
|
1652
|
+
baseUrl
|
|
1653
|
+
} : {},
|
|
1654
|
+
...path !== void 0 ? {
|
|
1655
|
+
path
|
|
1656
|
+
} : {},
|
|
1657
|
+
...credentials !== void 0 ? {
|
|
1658
|
+
credentials
|
|
1659
|
+
} : {},
|
|
1660
|
+
...fetch !== void 0 ? {
|
|
1661
|
+
fetch
|
|
1662
|
+
} : {},
|
|
1663
|
+
...upload !== void 0 ? {
|
|
1664
|
+
attachments: {
|
|
1665
|
+
upload
|
|
1666
|
+
}
|
|
1667
|
+
} : {},
|
|
1668
|
+
getHeaders: /* @__PURE__ */ __name(async () => {
|
|
1669
|
+
const current = latestHeaders.current;
|
|
1670
|
+
const dynamic = await current.getHeaders?.() ?? {};
|
|
1671
|
+
return {
|
|
1672
|
+
...current.headers,
|
|
1673
|
+
...dynamic
|
|
1674
|
+
};
|
|
1675
|
+
}, "getHeaders")
|
|
1676
|
+
}), [
|
|
1677
|
+
backend,
|
|
1678
|
+
baseUrl,
|
|
1679
|
+
path,
|
|
1680
|
+
credentials,
|
|
1681
|
+
fetch,
|
|
1682
|
+
upload
|
|
1683
|
+
]);
|
|
1684
|
+
const content = genui !== void 0 ? /* @__PURE__ */ React.createElement(GenuiProvider, genui, children) : children;
|
|
1685
|
+
return /* @__PURE__ */ React.createElement(AgentBackendContext.Provider, {
|
|
1686
|
+
value
|
|
1687
|
+
}, content);
|
|
1688
|
+
}
|
|
1689
|
+
__name(AgentProvider, "AgentProvider");
|
|
1690
|
+
var fallback;
|
|
1691
|
+
function defaultBackend() {
|
|
1692
|
+
fallback ??= new AgentClient();
|
|
1693
|
+
return fallback;
|
|
1694
|
+
}
|
|
1695
|
+
__name(defaultBackend, "defaultBackend");
|
|
1696
|
+
function useAgentBackend(own) {
|
|
1697
|
+
const provided = useContext3(AgentBackendContext);
|
|
1698
|
+
return own ?? provided ?? defaultBackend();
|
|
1699
|
+
}
|
|
1700
|
+
__name(useAgentBackend, "useAgentBackend");
|
|
1701
|
+
|
|
1127
1702
|
// src/attachments/use-attachments.ts
|
|
1128
1703
|
var DEFAULT_REJECTION = {
|
|
1129
1704
|
type: /* @__PURE__ */ __name((file) => `${file.name} is not a supported file type`, "type"),
|
|
@@ -1131,23 +1706,30 @@ var DEFAULT_REJECTION = {
|
|
|
1131
1706
|
count: /* @__PURE__ */ __name(() => "Too many files", "count")
|
|
1132
1707
|
};
|
|
1133
1708
|
var sequence = 0;
|
|
1134
|
-
function useAttachments(options) {
|
|
1135
|
-
const
|
|
1136
|
-
latest
|
|
1137
|
-
|
|
1138
|
-
|
|
1709
|
+
function useAttachments(options = {}) {
|
|
1710
|
+
const backend = useAgentBackend(options.backend);
|
|
1711
|
+
const latest = useRef3({
|
|
1712
|
+
...options,
|
|
1713
|
+
backend
|
|
1714
|
+
});
|
|
1715
|
+
latest.current = {
|
|
1716
|
+
...options,
|
|
1717
|
+
backend
|
|
1718
|
+
};
|
|
1719
|
+
const [items, setItems] = useState3([]);
|
|
1720
|
+
const itemsRef = useRef3(items);
|
|
1139
1721
|
itemsRef.current = items;
|
|
1140
|
-
const controllers =
|
|
1141
|
-
const [dragDepth, setDragDepth] =
|
|
1142
|
-
const patch =
|
|
1722
|
+
const controllers = useRef3(/* @__PURE__ */ new Map());
|
|
1723
|
+
const [dragDepth, setDragDepth] = useState3(0);
|
|
1724
|
+
const patch = useCallback2((id, change) => {
|
|
1143
1725
|
setItems((current) => current.map((item) => item.id === id ? {
|
|
1144
1726
|
...item,
|
|
1145
1727
|
...change
|
|
1146
1728
|
} : item));
|
|
1147
1729
|
}, []);
|
|
1148
|
-
const start =
|
|
1149
|
-
const { upload, backend } = latest.current;
|
|
1150
|
-
const run = upload ?? (
|
|
1730
|
+
const start = useCallback2((item) => {
|
|
1731
|
+
const { upload, backend: backend2 } = latest.current;
|
|
1732
|
+
const run = upload ?? (backend2.uploadAttachment !== void 0 ? backend2.uploadAttachment.bind(backend2) : void 0);
|
|
1151
1733
|
if (run === void 0) {
|
|
1152
1734
|
patch(item.id, {
|
|
1153
1735
|
status: "error",
|
|
@@ -1181,7 +1763,7 @@ function useAttachments(options) {
|
|
|
1181
1763
|
}, [
|
|
1182
1764
|
patch
|
|
1183
1765
|
]);
|
|
1184
|
-
const add =
|
|
1766
|
+
const add = useCallback2((files) => {
|
|
1185
1767
|
if (files == null) return;
|
|
1186
1768
|
const { accept: accept2, maxBytes, maxFiles, describeRejection } = latest.current;
|
|
1187
1769
|
const describe = /* @__PURE__ */ __name((reason, file) => describeRejection?.(reason, file) ?? DEFAULT_REJECTION[reason](file), "describe");
|
|
@@ -1227,7 +1809,7 @@ function useAttachments(options) {
|
|
|
1227
1809
|
}, [
|
|
1228
1810
|
start
|
|
1229
1811
|
]);
|
|
1230
|
-
const release =
|
|
1812
|
+
const release = useCallback2((item) => {
|
|
1231
1813
|
if (item === void 0) return;
|
|
1232
1814
|
controllers.current.get(item.id)?.abort();
|
|
1233
1815
|
controllers.current.delete(item.id);
|
|
@@ -1235,19 +1817,19 @@ function useAttachments(options) {
|
|
|
1235
1817
|
URL.revokeObjectURL(item.previewUrl);
|
|
1236
1818
|
}
|
|
1237
1819
|
}, []);
|
|
1238
|
-
const remove =
|
|
1820
|
+
const remove = useCallback2((id) => {
|
|
1239
1821
|
release(itemsRef.current.find((item) => item.id === id));
|
|
1240
1822
|
setItems((current) => current.filter((item) => item.id !== id));
|
|
1241
1823
|
}, [
|
|
1242
1824
|
release
|
|
1243
1825
|
]);
|
|
1244
|
-
const clear =
|
|
1826
|
+
const clear = useCallback2(() => {
|
|
1245
1827
|
for (const item of itemsRef.current) release(item);
|
|
1246
1828
|
setItems([]);
|
|
1247
1829
|
}, [
|
|
1248
1830
|
release
|
|
1249
1831
|
]);
|
|
1250
|
-
const retry =
|
|
1832
|
+
const retry = useCallback2((id) => {
|
|
1251
1833
|
const item = itemsRef.current.find((candidate) => candidate.id === id);
|
|
1252
1834
|
if (item === void 0 || item.status !== "error") return;
|
|
1253
1835
|
const { error: _previous, ...rest } = item;
|
|
@@ -1261,12 +1843,12 @@ function useAttachments(options) {
|
|
|
1261
1843
|
}, [
|
|
1262
1844
|
start
|
|
1263
1845
|
]);
|
|
1264
|
-
|
|
1846
|
+
useEffect3(() => () => {
|
|
1265
1847
|
for (const item of itemsRef.current) release(item);
|
|
1266
1848
|
}, [
|
|
1267
1849
|
release
|
|
1268
1850
|
]);
|
|
1269
|
-
const onPaste =
|
|
1851
|
+
const onPaste = useCallback2((event) => {
|
|
1270
1852
|
const files = filesFromClipboard(event.clipboardData);
|
|
1271
1853
|
if (files.length === 0) return;
|
|
1272
1854
|
event.preventDefault();
|
|
@@ -1274,7 +1856,7 @@ function useAttachments(options) {
|
|
|
1274
1856
|
}, [
|
|
1275
1857
|
add
|
|
1276
1858
|
]);
|
|
1277
|
-
const dropZoneProps =
|
|
1859
|
+
const dropZoneProps = useMemo4(() => ({
|
|
1278
1860
|
onDragEnter: /* @__PURE__ */ __name((event) => {
|
|
1279
1861
|
if (!dragHasFiles(event.dataTransfer)) return;
|
|
1280
1862
|
event.preventDefault();
|
|
@@ -1297,7 +1879,7 @@ function useAttachments(options) {
|
|
|
1297
1879
|
add
|
|
1298
1880
|
]);
|
|
1299
1881
|
const accept = options.accept;
|
|
1300
|
-
const inputProps =
|
|
1882
|
+
const inputProps = useMemo4(() => ({
|
|
1301
1883
|
type: "file",
|
|
1302
1884
|
accept: typeof accept === "string" ? accept : accept?.join(","),
|
|
1303
1885
|
multiple: options.maxFiles === void 0 || options.maxFiles > 1,
|
|
@@ -1311,7 +1893,7 @@ function useAttachments(options) {
|
|
|
1311
1893
|
options.maxFiles,
|
|
1312
1894
|
add
|
|
1313
1895
|
]);
|
|
1314
|
-
return
|
|
1896
|
+
return useMemo4(() => {
|
|
1315
1897
|
const ready = items.filter((item) => item.status === "ready" && item.attachment !== void 0);
|
|
1316
1898
|
const attachments = ready.map((item) => item.attachment);
|
|
1317
1899
|
return {
|
|
@@ -1345,18 +1927,18 @@ function useAttachments(options) {
|
|
|
1345
1927
|
__name(useAttachments, "useAttachments");
|
|
1346
1928
|
|
|
1347
1929
|
// src/catalog/use-agents.ts
|
|
1348
|
-
import { useMemo as
|
|
1930
|
+
import { useMemo as useMemo5 } from "react";
|
|
1349
1931
|
|
|
1350
1932
|
// src/catalog/use-resource.ts
|
|
1351
|
-
import { useCallback as
|
|
1933
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
|
|
1352
1934
|
function useResource(load2, key, enabled) {
|
|
1353
|
-
const [data, setData] =
|
|
1354
|
-
const [isLoading, setIsLoading] =
|
|
1355
|
-
const [error, setError] =
|
|
1356
|
-
const loadRef =
|
|
1935
|
+
const [data, setData] = useState4(void 0);
|
|
1936
|
+
const [isLoading, setIsLoading] = useState4(enabled);
|
|
1937
|
+
const [error, setError] = useState4(null);
|
|
1938
|
+
const loadRef = useRef4(load2);
|
|
1357
1939
|
loadRef.current = load2;
|
|
1358
|
-
const generation =
|
|
1359
|
-
const refresh =
|
|
1940
|
+
const generation = useRef4(0);
|
|
1941
|
+
const refresh = useCallback3(async () => {
|
|
1360
1942
|
const mine = ++generation.current;
|
|
1361
1943
|
setIsLoading(true);
|
|
1362
1944
|
try {
|
|
@@ -1371,7 +1953,7 @@ function useResource(load2, key, enabled) {
|
|
|
1371
1953
|
if (mine === generation.current) setIsLoading(false);
|
|
1372
1954
|
}
|
|
1373
1955
|
}, []);
|
|
1374
|
-
|
|
1956
|
+
useEffect4(() => {
|
|
1375
1957
|
if (!enabled) return;
|
|
1376
1958
|
void refresh();
|
|
1377
1959
|
}, [
|
|
@@ -1389,10 +1971,11 @@ function useResource(load2, key, enabled) {
|
|
|
1389
1971
|
__name(useResource, "useResource");
|
|
1390
1972
|
|
|
1391
1973
|
// src/catalog/use-agents.ts
|
|
1392
|
-
function useAgents(options) {
|
|
1393
|
-
const {
|
|
1974
|
+
function useAgents(options = {}) {
|
|
1975
|
+
const { enabled = true } = options;
|
|
1976
|
+
const backend = useAgentBackend(options.backend);
|
|
1394
1977
|
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listAgents")(), "", enabled);
|
|
1395
|
-
return
|
|
1978
|
+
return useMemo5(() => {
|
|
1396
1979
|
const agents = data ?? [];
|
|
1397
1980
|
return {
|
|
1398
1981
|
agents,
|
|
@@ -1411,11 +1994,12 @@ function useAgents(options) {
|
|
|
1411
1994
|
__name(useAgents, "useAgents");
|
|
1412
1995
|
|
|
1413
1996
|
// src/catalog/use-models.ts
|
|
1414
|
-
import { useMemo as
|
|
1415
|
-
function useModels(options) {
|
|
1416
|
-
const {
|
|
1997
|
+
import { useMemo as useMemo6 } from "react";
|
|
1998
|
+
function useModels(options = {}) {
|
|
1999
|
+
const { agent, enabled = true } = options;
|
|
2000
|
+
const backend = useAgentBackend(options.backend);
|
|
1417
2001
|
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listModels")(agent), `${agent ?? ""}`, enabled);
|
|
1418
|
-
return
|
|
2002
|
+
return useMemo6(() => {
|
|
1419
2003
|
const providers = data?.providers ?? [];
|
|
1420
2004
|
const models = providers.flatMap((provider) => provider.models.map((model) => ({
|
|
1421
2005
|
...model,
|
|
@@ -1445,7 +2029,7 @@ function useModels(options) {
|
|
|
1445
2029
|
__name(useModels, "useModels");
|
|
1446
2030
|
|
|
1447
2031
|
// src/quota/use-quota.ts
|
|
1448
|
-
import { useEffect as
|
|
2032
|
+
import { useEffect as useEffect5, useMemo as useMemo7 } from "react";
|
|
1449
2033
|
|
|
1450
2034
|
// src/threads/threads-events.ts
|
|
1451
2035
|
var listeners = /* @__PURE__ */ new WeakMap();
|
|
@@ -1469,10 +2053,11 @@ function onThreadsEvent(backend, listener) {
|
|
|
1469
2053
|
__name(onThreadsEvent, "onThreadsEvent");
|
|
1470
2054
|
|
|
1471
2055
|
// src/quota/use-quota.ts
|
|
1472
|
-
function useQuota(options) {
|
|
1473
|
-
const {
|
|
2056
|
+
function useQuota(options = {}) {
|
|
2057
|
+
const { enabled = true, pollMs } = options;
|
|
2058
|
+
const backend = useAgentBackend(options.backend);
|
|
1474
2059
|
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "getQuota")(), "", enabled);
|
|
1475
|
-
|
|
2060
|
+
useEffect5(() => {
|
|
1476
2061
|
if (!enabled) return;
|
|
1477
2062
|
return onThreadsEvent(backend, (event) => {
|
|
1478
2063
|
if (event.type === "changed") void refresh();
|
|
@@ -1482,7 +2067,7 @@ function useQuota(options) {
|
|
|
1482
2067
|
enabled,
|
|
1483
2068
|
refresh
|
|
1484
2069
|
]);
|
|
1485
|
-
|
|
2070
|
+
useEffect5(() => {
|
|
1486
2071
|
if (!enabled || pollMs === void 0 || pollMs <= 0) return;
|
|
1487
2072
|
const timer = setInterval(() => void refresh(), pollMs);
|
|
1488
2073
|
return () => clearInterval(timer);
|
|
@@ -1491,7 +2076,7 @@ function useQuota(options) {
|
|
|
1491
2076
|
pollMs,
|
|
1492
2077
|
refresh
|
|
1493
2078
|
]);
|
|
1494
|
-
return
|
|
2079
|
+
return useMemo7(() => {
|
|
1495
2080
|
const windows = data?.windows ?? [];
|
|
1496
2081
|
return {
|
|
1497
2082
|
report: data,
|
|
@@ -1513,37 +2098,44 @@ function useQuota(options) {
|
|
|
1513
2098
|
__name(useQuota, "useQuota");
|
|
1514
2099
|
|
|
1515
2100
|
// src/feedback/use-message-feedback.ts
|
|
1516
|
-
import { useCallback as
|
|
1517
|
-
function useMessageFeedback(options) {
|
|
1518
|
-
const
|
|
1519
|
-
latest
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
2101
|
+
import { useCallback as useCallback4, useRef as useRef5, useState as useState5 } from "react";
|
|
2102
|
+
function useMessageFeedback(options = {}) {
|
|
2103
|
+
const backend = useAgentBackend(options.backend);
|
|
2104
|
+
const latest = useRef5({
|
|
2105
|
+
...options,
|
|
2106
|
+
backend
|
|
2107
|
+
});
|
|
2108
|
+
latest.current = {
|
|
2109
|
+
...options,
|
|
2110
|
+
backend
|
|
2111
|
+
};
|
|
2112
|
+
const [local, setLocal] = useState5(/* @__PURE__ */ new Map());
|
|
2113
|
+
const [pending, setPending] = useState5(/* @__PURE__ */ new Set());
|
|
2114
|
+
const [error, setError] = useState5(null);
|
|
2115
|
+
const localRef = useRef5(local);
|
|
1524
2116
|
localRef.current = local;
|
|
1525
|
-
const resolved =
|
|
1526
|
-
const feedbackOf =
|
|
2117
|
+
const resolved = useRef5(/* @__PURE__ */ new Map());
|
|
2118
|
+
const feedbackOf = useCallback4((message) => {
|
|
1527
2119
|
const mine = local.get(message.id);
|
|
1528
2120
|
if (mine !== void 0) return mine.feedback;
|
|
1529
2121
|
return metadataOf(message).feedback ?? null;
|
|
1530
2122
|
}, [
|
|
1531
2123
|
local
|
|
1532
2124
|
]);
|
|
1533
|
-
const isPending =
|
|
2125
|
+
const isPending = useCallback4((message) => pending.has(message.id), [
|
|
1534
2126
|
pending
|
|
1535
2127
|
]);
|
|
1536
|
-
const storedIdFor =
|
|
2128
|
+
const storedIdFor = useCallback4(async (message) => {
|
|
1537
2129
|
const runId = metadataOf(message).runId;
|
|
1538
2130
|
if (runId === void 0) return message.id;
|
|
1539
2131
|
const known = resolved.current.get(message.id);
|
|
1540
2132
|
if (known !== void 0) return known;
|
|
1541
|
-
const { backend, threadId } = latest.current;
|
|
2133
|
+
const { backend: backend2, threadId } = latest.current;
|
|
1542
2134
|
const thread = typeof threadId === "function" ? threadId() : threadId;
|
|
1543
2135
|
if (thread === void 0) {
|
|
1544
2136
|
throw new Error("useMessageFeedback: a streamed message needs `threadId` to be rated");
|
|
1545
2137
|
}
|
|
1546
|
-
const detail = await
|
|
2138
|
+
const detail = await backend2.getThread(thread);
|
|
1547
2139
|
const row = [
|
|
1548
2140
|
...detail.messages
|
|
1549
2141
|
].reverse().find((candidate) => candidate.role === "assistant" && candidate.runId === runId);
|
|
@@ -1553,7 +2145,7 @@ function useMessageFeedback(options) {
|
|
|
1553
2145
|
resolved.current.set(message.id, row.id);
|
|
1554
2146
|
return row.id;
|
|
1555
2147
|
}, []);
|
|
1556
|
-
const rate =
|
|
2148
|
+
const rate = useCallback4(async (message, value, comment) => {
|
|
1557
2149
|
const setFeedback = requireBackendMethod(latest.current.backend, "setMessageFeedback");
|
|
1558
2150
|
const had = localRef.current.get(message.id);
|
|
1559
2151
|
const optimistic = value === null ? null : {
|
|
@@ -1599,7 +2191,7 @@ function useMessageFeedback(options) {
|
|
|
1599
2191
|
}, [
|
|
1600
2192
|
storedIdFor
|
|
1601
2193
|
]);
|
|
1602
|
-
const toggle =
|
|
2194
|
+
const toggle = useCallback4((message, value) => {
|
|
1603
2195
|
const mine = localRef.current.get(message.id);
|
|
1604
2196
|
const current = mine !== void 0 ? mine.feedback : metadataOf(message).feedback ?? null;
|
|
1605
2197
|
return rate(message, current?.value === value ? null : value);
|
|
@@ -1622,16 +2214,17 @@ function metadataOf(message) {
|
|
|
1622
2214
|
__name(metadataOf, "metadataOf");
|
|
1623
2215
|
|
|
1624
2216
|
// src/threads/use-threads.ts
|
|
1625
|
-
import { useCallback as
|
|
1626
|
-
function useThreads(options) {
|
|
1627
|
-
const {
|
|
1628
|
-
const
|
|
1629
|
-
const [
|
|
1630
|
-
const [
|
|
1631
|
-
const
|
|
2217
|
+
import { useCallback as useCallback5, useEffect as useEffect6, useRef as useRef6, useState as useState6 } from "react";
|
|
2218
|
+
function useThreads(options = {}) {
|
|
2219
|
+
const { enabled = true } = options;
|
|
2220
|
+
const backend = useAgentBackend(options.backend);
|
|
2221
|
+
const [threads, setThreads] = useState6([]);
|
|
2222
|
+
const [isLoading, setIsLoading] = useState6(enabled);
|
|
2223
|
+
const [error, setError] = useState6(null);
|
|
2224
|
+
const threadsRef = useRef6(threads);
|
|
1632
2225
|
threadsRef.current = threads;
|
|
1633
|
-
const generation =
|
|
1634
|
-
const refresh =
|
|
2226
|
+
const generation = useRef6(0);
|
|
2227
|
+
const refresh = useCallback5(async () => {
|
|
1635
2228
|
const mine = ++generation.current;
|
|
1636
2229
|
setIsLoading(true);
|
|
1637
2230
|
try {
|
|
@@ -1648,7 +2241,7 @@ function useThreads(options) {
|
|
|
1648
2241
|
}, [
|
|
1649
2242
|
backend
|
|
1650
2243
|
]);
|
|
1651
|
-
|
|
2244
|
+
useEffect6(() => {
|
|
1652
2245
|
if (!enabled) return;
|
|
1653
2246
|
void refresh();
|
|
1654
2247
|
return onThreadsEvent(backend, (event) => {
|
|
@@ -1668,7 +2261,7 @@ function useThreads(options) {
|
|
|
1668
2261
|
enabled,
|
|
1669
2262
|
refresh
|
|
1670
2263
|
]);
|
|
1671
|
-
const rename =
|
|
2264
|
+
const rename = useCallback5(async (id, title) => {
|
|
1672
2265
|
const before = threadsRef.current;
|
|
1673
2266
|
setThreads((current) => current.map((thread) => thread.id === id ? {
|
|
1674
2267
|
...thread,
|
|
@@ -1690,7 +2283,7 @@ function useThreads(options) {
|
|
|
1690
2283
|
}, [
|
|
1691
2284
|
backend
|
|
1692
2285
|
]);
|
|
1693
|
-
const remove =
|
|
2286
|
+
const remove = useCallback5(async (id) => {
|
|
1694
2287
|
const before = threadsRef.current;
|
|
1695
2288
|
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
1696
2289
|
try {
|
|
@@ -1764,29 +2357,11 @@ function backgroundRunsFromThread(messages) {
|
|
|
1764
2357
|
}
|
|
1765
2358
|
__name(backgroundRunsFromThread, "backgroundRunsFromThread");
|
|
1766
2359
|
|
|
1767
|
-
// src/components/ambient-ui.ts
|
|
1768
|
-
import { createContext, useContext } from "react";
|
|
1769
|
-
function sharedContext(key) {
|
|
1770
|
-
const symbol = Symbol.for(key);
|
|
1771
|
-
const holder = globalThis;
|
|
1772
|
-
const existing = holder[symbol];
|
|
1773
|
-
if (existing !== void 0) return existing;
|
|
1774
|
-
const created = createContext(null);
|
|
1775
|
-
holder[symbol] = created;
|
|
1776
|
-
return created;
|
|
1777
|
-
}
|
|
1778
|
-
__name(sharedContext, "sharedContext");
|
|
1779
|
-
var AmbientRenderUiContext = sharedContext("@dudousxd/nestjs-agent-react:ambient-render-ui");
|
|
1780
|
-
function useAmbientRenderUi() {
|
|
1781
|
-
return useContext(AmbientRenderUiContext);
|
|
1782
|
-
}
|
|
1783
|
-
__name(useAmbientRenderUi, "useAmbientRenderUi");
|
|
1784
|
-
|
|
1785
2360
|
// src/components/chat-input.tsx
|
|
1786
|
-
import React2, { useEffect as
|
|
2361
|
+
import React2, { useEffect as useEffect8, useState as useState8 } from "react";
|
|
1787
2362
|
|
|
1788
2363
|
// src/components/use-speech-recognition.ts
|
|
1789
|
-
import { useCallback as
|
|
2364
|
+
import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo8, useRef as useRef7, useState as useState7 } from "react";
|
|
1790
2365
|
function getRecognitionCtor() {
|
|
1791
2366
|
if (typeof window === "undefined") return null;
|
|
1792
2367
|
const scope = window;
|
|
@@ -1794,15 +2369,15 @@ function getRecognitionCtor() {
|
|
|
1794
2369
|
}
|
|
1795
2370
|
__name(getRecognitionCtor, "getRecognitionCtor");
|
|
1796
2371
|
function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
|
|
1797
|
-
const recognitionRef =
|
|
1798
|
-
const [isListening, setIsListening] =
|
|
1799
|
-
const ctor =
|
|
2372
|
+
const recognitionRef = useRef7(null);
|
|
2373
|
+
const [isListening, setIsListening] = useState7(false);
|
|
2374
|
+
const ctor = useMemo8(() => getRecognitionCtor(), []);
|
|
1800
2375
|
const isSupported = ctor !== null;
|
|
1801
|
-
const finalRef =
|
|
1802
|
-
const interimRef =
|
|
2376
|
+
const finalRef = useRef7(onFinalTranscript);
|
|
2377
|
+
const interimRef = useRef7(onInterimTranscript);
|
|
1803
2378
|
finalRef.current = onFinalTranscript;
|
|
1804
2379
|
interimRef.current = onInterimTranscript;
|
|
1805
|
-
|
|
2380
|
+
useEffect7(() => {
|
|
1806
2381
|
if (!ctor) return;
|
|
1807
2382
|
const recognition = new ctor();
|
|
1808
2383
|
recognition.lang = lang;
|
|
@@ -1841,7 +2416,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
|
|
|
1841
2416
|
ctor,
|
|
1842
2417
|
lang
|
|
1843
2418
|
]);
|
|
1844
|
-
const start =
|
|
2419
|
+
const start = useCallback6(() => {
|
|
1845
2420
|
const recognition = recognitionRef.current;
|
|
1846
2421
|
if (!recognition) return;
|
|
1847
2422
|
try {
|
|
@@ -1851,7 +2426,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
|
|
|
1851
2426
|
console.warn("SpeechRecognition start failed", error);
|
|
1852
2427
|
}
|
|
1853
2428
|
}, []);
|
|
1854
|
-
const stop =
|
|
2429
|
+
const stop = useCallback6(() => {
|
|
1855
2430
|
const recognition = recognitionRef.current;
|
|
1856
2431
|
if (!recognition) return;
|
|
1857
2432
|
try {
|
|
@@ -1870,8 +2445,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
|
|
|
1870
2445
|
|
|
1871
2446
|
// src/components/chat-input.tsx
|
|
1872
2447
|
function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = true, speechLang = "en-US", sendLabel = "Send", onStop, isStreaming = false, stopLabel = "Stop generating", className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic }) {
|
|
1873
|
-
const [value, setValue] =
|
|
1874
|
-
const [interim, setInterim] =
|
|
2448
|
+
const [value, setValue] = useState8("");
|
|
2449
|
+
const [interim, setInterim] = useState8("");
|
|
1875
2450
|
const speech = useSpeechRecognition({
|
|
1876
2451
|
lang: speechLang,
|
|
1877
2452
|
onFinalTranscript: /* @__PURE__ */ __name((text) => {
|
|
@@ -1882,7 +2457,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
|
|
|
1882
2457
|
}, "onFinalTranscript"),
|
|
1883
2458
|
onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
|
|
1884
2459
|
});
|
|
1885
|
-
|
|
2460
|
+
useEffect8(() => {
|
|
1886
2461
|
if (!speech.isListening) setInterim("");
|
|
1887
2462
|
}, [
|
|
1888
2463
|
speech.isListening
|
|
@@ -1949,7 +2524,7 @@ __name(ChatInput, "ChatInput");
|
|
|
1949
2524
|
import React3 from "react";
|
|
1950
2525
|
|
|
1951
2526
|
// src/transcript/use-chat-transcript.ts
|
|
1952
|
-
import { useCallback as
|
|
2527
|
+
import { useCallback as useCallback8, useEffect as useEffect10, useRef as useRef9, useState as useState10 } from "react";
|
|
1953
2528
|
|
|
1954
2529
|
// src/transcript/model.ts
|
|
1955
2530
|
import { readElicitationInput, validateElicitationAnswer as validateElicitationAnswer2 } from "@dudousxd/nestjs-agent-core";
|
|
@@ -2046,21 +2621,21 @@ function fillTemplate(template, context) {
|
|
|
2046
2621
|
}).replace(/\s{2,}/g, " ").trim();
|
|
2047
2622
|
}
|
|
2048
2623
|
__name(fillTemplate, "fillTemplate");
|
|
2049
|
-
function phraseFor(presentation, input, isSettled2,
|
|
2624
|
+
function phraseFor(presentation, input, isSettled2, fallback2 = {
|
|
2050
2625
|
running: "Working",
|
|
2051
2626
|
done: "Done"
|
|
2052
2627
|
}) {
|
|
2053
|
-
if (presentation === void 0) return isSettled2 ?
|
|
2628
|
+
if (presentation === void 0) return isSettled2 ? fallback2.done : fallback2.running;
|
|
2054
2629
|
const filled = fillTemplate(isSettled2 ? presentation.done : presentation.running, input);
|
|
2055
2630
|
return filled === "" ? presentation.label : filled;
|
|
2056
2631
|
}
|
|
2057
2632
|
__name(phraseFor, "phraseFor");
|
|
2058
2633
|
|
|
2059
2634
|
// src/presentation/result-view.ts
|
|
2060
|
-
function
|
|
2635
|
+
function isRecord2(value) {
|
|
2061
2636
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2062
2637
|
}
|
|
2063
|
-
__name(
|
|
2638
|
+
__name(isRecord2, "isRecord");
|
|
2064
2639
|
function toText(value) {
|
|
2065
2640
|
if (value === null || value === void 0) return "\u2014";
|
|
2066
2641
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
@@ -2071,7 +2646,7 @@ function toText(value) {
|
|
|
2071
2646
|
}
|
|
2072
2647
|
__name(toText, "toText");
|
|
2073
2648
|
function inferResultView(output) {
|
|
2074
|
-
if (!
|
|
2649
|
+
if (!isRecord2(output)) return void 0;
|
|
2075
2650
|
for (const [key, value] of Object.entries(output)) {
|
|
2076
2651
|
if (!Array.isArray(value) || value.length === 0) continue;
|
|
2077
2652
|
if (value.every((entry) => typeof entry === "string")) {
|
|
@@ -2080,12 +2655,12 @@ function inferResultView(output) {
|
|
|
2080
2655
|
lines: key
|
|
2081
2656
|
};
|
|
2082
2657
|
}
|
|
2083
|
-
if (value.every(
|
|
2658
|
+
if (value.every(isRecord2)) {
|
|
2084
2659
|
const first = value[0];
|
|
2085
2660
|
return {
|
|
2086
2661
|
kind: "table",
|
|
2087
2662
|
rows: key,
|
|
2088
|
-
columns: Object.keys(first).filter((column) => !
|
|
2663
|
+
columns: Object.keys(first).filter((column) => !isRecord2(first[column])).map((column) => ({
|
|
2089
2664
|
path: column,
|
|
2090
2665
|
label: column
|
|
2091
2666
|
}))
|
|
@@ -2461,7 +3036,7 @@ function isSettled(state) {
|
|
|
2461
3036
|
__name(isSettled, "isSettled");
|
|
2462
3037
|
function toolKind(part) {
|
|
2463
3038
|
const metadata = part.toolMetadata;
|
|
2464
|
-
return
|
|
3039
|
+
return isRecord3(metadata) && typeof metadata.toolKind === "string" ? metadata.toolKind : void 0;
|
|
2465
3040
|
}
|
|
2466
3041
|
__name(toolKind, "toolKind");
|
|
2467
3042
|
function isAwaitingApproval(part) {
|
|
@@ -2476,7 +3051,7 @@ function isAwaitingApproval(part) {
|
|
|
2476
3051
|
__name(isAwaitingApproval, "isAwaitingApproval");
|
|
2477
3052
|
function toolParentId(part) {
|
|
2478
3053
|
const metadata = part.toolMetadata;
|
|
2479
|
-
return
|
|
3054
|
+
return isRecord3(metadata) && typeof metadata.parentId === "string" ? metadata.parentId : null;
|
|
2480
3055
|
}
|
|
2481
3056
|
__name(toolParentId, "toolParentId");
|
|
2482
3057
|
function nestToolCalls(calls) {
|
|
@@ -2543,12 +3118,12 @@ function buildToolCall(part, options, approval, catalog) {
|
|
|
2543
3118
|
__name(buildToolCall, "buildToolCall");
|
|
2544
3119
|
function readElicitationRequest(part) {
|
|
2545
3120
|
const input = part.input;
|
|
2546
|
-
if (!
|
|
3121
|
+
if (!isRecord3(input) || !Array.isArray(input.questions) || input.questions.length === 0) {
|
|
2547
3122
|
return null;
|
|
2548
3123
|
}
|
|
2549
3124
|
const questions = [];
|
|
2550
3125
|
for (const candidate of input.questions) {
|
|
2551
|
-
if (!
|
|
3126
|
+
if (!isRecord3(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string") {
|
|
2552
3127
|
return null;
|
|
2553
3128
|
}
|
|
2554
3129
|
const input2 = readElicitationInput(candidate.input) ?? null;
|
|
@@ -2558,7 +3133,7 @@ function readElicitationRequest(part) {
|
|
|
2558
3133
|
}
|
|
2559
3134
|
const options = [];
|
|
2560
3135
|
for (const option of rawOptions) {
|
|
2561
|
-
if (!
|
|
3136
|
+
if (!isRecord3(option) || typeof option.value !== "string" || typeof option.label !== "string") {
|
|
2562
3137
|
return null;
|
|
2563
3138
|
}
|
|
2564
3139
|
options.push({
|
|
@@ -2586,7 +3161,7 @@ function readElicitationRequest(part) {
|
|
|
2586
3161
|
__name(readElicitationRequest, "readElicitationRequest");
|
|
2587
3162
|
function readElicitationOutcome(part) {
|
|
2588
3163
|
const output = part.output;
|
|
2589
|
-
if (!
|
|
3164
|
+
if (!isRecord3(output) || !isRecord3(output.answers) || typeof output.skipped !== "boolean") {
|
|
2590
3165
|
return null;
|
|
2591
3166
|
}
|
|
2592
3167
|
const answers = {};
|
|
@@ -2723,7 +3298,7 @@ function readApprovals(parts) {
|
|
|
2723
3298
|
continue;
|
|
2724
3299
|
}
|
|
2725
3300
|
const data = part.data;
|
|
2726
|
-
if (!
|
|
3301
|
+
if (!isRecord3(data) || typeof data.id !== "string") {
|
|
2727
3302
|
continue;
|
|
2728
3303
|
}
|
|
2729
3304
|
const approval = entry(data.id);
|
|
@@ -2779,7 +3354,7 @@ function statusFromPart(call) {
|
|
|
2779
3354
|
__name(statusFromPart, "statusFromPart");
|
|
2780
3355
|
function readUiComponent(part) {
|
|
2781
3356
|
const data = part.data;
|
|
2782
|
-
if (!
|
|
3357
|
+
if (!isRecord3(data) || typeof data.component !== "string") {
|
|
2783
3358
|
return null;
|
|
2784
3359
|
}
|
|
2785
3360
|
const id = typeof data.id === "string" ? data.id : part.id;
|
|
@@ -2789,19 +3364,19 @@ function readUiComponent(part) {
|
|
|
2789
3364
|
return {
|
|
2790
3365
|
id,
|
|
2791
3366
|
component: data.component,
|
|
2792
|
-
props:
|
|
3367
|
+
props: isRecord3(data.props) ? data.props : {},
|
|
2793
3368
|
version: typeof data.version === "number" ? data.version : null,
|
|
2794
3369
|
toolCallId: typeof data.toolCallId === "string" ? data.toolCallId : null
|
|
2795
3370
|
};
|
|
2796
3371
|
}
|
|
2797
3372
|
__name(readUiComponent, "readUiComponent");
|
|
2798
|
-
function
|
|
3373
|
+
function isRecord3(value) {
|
|
2799
3374
|
return typeof value === "object" && value !== null;
|
|
2800
3375
|
}
|
|
2801
|
-
__name(
|
|
3376
|
+
__name(isRecord3, "isRecord");
|
|
2802
3377
|
function readQuery(part) {
|
|
2803
3378
|
const input = part.input;
|
|
2804
|
-
if (!
|
|
3379
|
+
if (!isRecord3(input) || typeof input.query !== "string") {
|
|
2805
3380
|
return null;
|
|
2806
3381
|
}
|
|
2807
3382
|
return input.query;
|
|
@@ -2809,12 +3384,12 @@ function readQuery(part) {
|
|
|
2809
3384
|
__name(readQuery, "readQuery");
|
|
2810
3385
|
function readPassages(part) {
|
|
2811
3386
|
const output = part.output;
|
|
2812
|
-
if (!
|
|
3387
|
+
if (!isRecord3(output) || !Array.isArray(output.passages) || output.passages.length === 0) {
|
|
2813
3388
|
return null;
|
|
2814
3389
|
}
|
|
2815
3390
|
const passages = [];
|
|
2816
3391
|
for (const candidate of output.passages) {
|
|
2817
|
-
if (!
|
|
3392
|
+
if (!isRecord3(candidate) || typeof candidate.id !== "string" || typeof candidate.text !== "string") {
|
|
2818
3393
|
return null;
|
|
2819
3394
|
}
|
|
2820
3395
|
passages.push({
|
|
@@ -2824,7 +3399,7 @@ function readPassages(part) {
|
|
|
2824
3399
|
...typeof candidate.source === "string" ? {
|
|
2825
3400
|
source: candidate.source
|
|
2826
3401
|
} : {},
|
|
2827
|
-
...
|
|
3402
|
+
...isRecord3(candidate.metadata) ? {
|
|
2828
3403
|
metadata: candidate.metadata
|
|
2829
3404
|
} : {}
|
|
2830
3405
|
});
|
|
@@ -2926,11 +3501,11 @@ function formatCostUsd(cost) {
|
|
|
2926
3501
|
__name(formatCostUsd, "formatCostUsd");
|
|
2927
3502
|
|
|
2928
3503
|
// src/transcript/use-stick-to-bottom.ts
|
|
2929
|
-
import { useCallback as
|
|
3504
|
+
import { useCallback as useCallback7, useEffect as useEffect9, useRef as useRef8, useState as useState9 } from "react";
|
|
2930
3505
|
function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
2931
|
-
const containerRef =
|
|
2932
|
-
const [isAtBottom, setIsAtBottom] =
|
|
2933
|
-
const measure =
|
|
3506
|
+
const containerRef = useRef8(null);
|
|
3507
|
+
const [isAtBottom, setIsAtBottom] = useState9(true);
|
|
3508
|
+
const measure = useCallback7(() => {
|
|
2934
3509
|
const element = containerRef.current;
|
|
2935
3510
|
if (!element) {
|
|
2936
3511
|
return;
|
|
@@ -2940,7 +3515,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2940
3515
|
}, [
|
|
2941
3516
|
threshold
|
|
2942
3517
|
]);
|
|
2943
|
-
const scrollToBottom =
|
|
3518
|
+
const scrollToBottom = useCallback7(() => {
|
|
2944
3519
|
const element = containerRef.current;
|
|
2945
3520
|
if (!element) {
|
|
2946
3521
|
return;
|
|
@@ -2948,7 +3523,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2948
3523
|
element.scrollTop = element.scrollHeight;
|
|
2949
3524
|
setIsAtBottom(true);
|
|
2950
3525
|
}, []);
|
|
2951
|
-
const setContainer =
|
|
3526
|
+
const setContainer = useCallback7((element) => {
|
|
2952
3527
|
containerRef.current = element;
|
|
2953
3528
|
if (element) {
|
|
2954
3529
|
measure();
|
|
@@ -2956,7 +3531,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2956
3531
|
}, [
|
|
2957
3532
|
measure
|
|
2958
3533
|
]);
|
|
2959
|
-
|
|
3534
|
+
useEffect9(() => {
|
|
2960
3535
|
if (isAtBottom) {
|
|
2961
3536
|
scrollToBottom();
|
|
2962
3537
|
}
|
|
@@ -2965,7 +3540,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2965
3540
|
isAtBottom,
|
|
2966
3541
|
scrollToBottom
|
|
2967
3542
|
]);
|
|
2968
|
-
const getContainerProps =
|
|
3543
|
+
const getContainerProps = useCallback7(() => ({
|
|
2969
3544
|
ref: setContainer,
|
|
2970
3545
|
onScroll: measure
|
|
2971
3546
|
}), [
|
|
@@ -2987,14 +3562,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
|
|
|
2987
3562
|
var DEFAULT_COPY_RESET_MS = 1500;
|
|
2988
3563
|
function useChatTranscript(options) {
|
|
2989
3564
|
const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
|
|
2990
|
-
const latest =
|
|
3565
|
+
const latest = useRef9(options);
|
|
2991
3566
|
latest.current = options;
|
|
2992
|
-
const [visibleCount, setVisibleCount] =
|
|
2993
|
-
const [stopRequested, setStopRequested] =
|
|
3567
|
+
const [visibleCount, setVisibleCount] = useState10(initialVisibleCount);
|
|
3568
|
+
const [stopRequested, setStopRequested] = useState10(false);
|
|
2994
3569
|
const isStreaming = status === "streaming" || status === "reconnecting";
|
|
2995
3570
|
const isBusy = status === "submitted" || isStreaming;
|
|
2996
3571
|
const isEmpty = messages.length === 0;
|
|
2997
|
-
|
|
3572
|
+
useEffect10(() => {
|
|
2998
3573
|
if (!isBusy) {
|
|
2999
3574
|
setStopRequested(false);
|
|
3000
3575
|
}
|
|
@@ -3011,7 +3586,7 @@ function useChatTranscript(options) {
|
|
|
3011
3586
|
streamingMessageId,
|
|
3012
3587
|
options
|
|
3013
3588
|
});
|
|
3014
|
-
const stop =
|
|
3589
|
+
const stop = useCallback8(() => {
|
|
3015
3590
|
const current = latest.current;
|
|
3016
3591
|
if (current.status !== "submitted" && current.status !== "streaming" && current.status !== "reconnecting") {
|
|
3017
3592
|
return;
|
|
@@ -3019,8 +3594,8 @@ function useChatTranscript(options) {
|
|
|
3019
3594
|
setStopRequested(true);
|
|
3020
3595
|
void current.onStop?.();
|
|
3021
3596
|
}, []);
|
|
3022
|
-
const loadEarlier =
|
|
3023
|
-
const showAll =
|
|
3597
|
+
const loadEarlier = useCallback8(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
|
|
3598
|
+
const showAll = useCallback8(() => setVisibleCount(latest.current.messages.length), []);
|
|
3024
3599
|
const scroll = useStickToBottom({
|
|
3025
3600
|
contentKey: contentSignature(messages),
|
|
3026
3601
|
...stickToBottomThreshold !== void 0 ? {
|
|
@@ -3056,7 +3631,7 @@ function useChatTranscript(options) {
|
|
|
3056
3631
|
__name(useChatTranscript, "useChatTranscript");
|
|
3057
3632
|
function useTranscriptItem(options) {
|
|
3058
3633
|
const { message, isStreaming = false } = options;
|
|
3059
|
-
const messagesRef =
|
|
3634
|
+
const messagesRef = useRef9([
|
|
3060
3635
|
message
|
|
3061
3636
|
]);
|
|
3062
3637
|
if (messagesRef.current[0] !== message) {
|
|
@@ -3074,41 +3649,45 @@ function useTranscriptItem(options) {
|
|
|
3074
3649
|
}
|
|
3075
3650
|
__name(useTranscriptItem, "useTranscriptItem");
|
|
3076
3651
|
function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
|
|
3077
|
-
const [drafts, setDrafts] =
|
|
3078
|
-
const [copied, setCopied] =
|
|
3079
|
-
const [openReasoning, setOpenReasoning] =
|
|
3080
|
-
const [picks, setPicks] =
|
|
3081
|
-
const [settling, setSettling] =
|
|
3082
|
-
const [settleErrors, setSettleErrors] =
|
|
3083
|
-
const
|
|
3652
|
+
const [drafts, setDrafts] = useState10(() => /* @__PURE__ */ new Map());
|
|
3653
|
+
const [copied, setCopied] = useState10(() => /* @__PURE__ */ new Set());
|
|
3654
|
+
const [openReasoning, setOpenReasoning] = useState10(() => /* @__PURE__ */ new Map());
|
|
3655
|
+
const [picks, setPicks] = useState10(() => /* @__PURE__ */ new Map());
|
|
3656
|
+
const [settling, setSettling] = useState10(() => /* @__PURE__ */ new Map());
|
|
3657
|
+
const [settleErrors, setSettleErrors] = useState10(() => /* @__PURE__ */ new Map());
|
|
3658
|
+
const backend = useAgentBackend();
|
|
3659
|
+
const handlers = settleHandlers(options, backend);
|
|
3660
|
+
const latest = useRef9({
|
|
3084
3661
|
options,
|
|
3662
|
+
handlers,
|
|
3085
3663
|
drafts,
|
|
3086
3664
|
picks,
|
|
3087
3665
|
messages
|
|
3088
3666
|
});
|
|
3089
3667
|
latest.current = {
|
|
3090
3668
|
options,
|
|
3669
|
+
handlers,
|
|
3091
3670
|
drafts,
|
|
3092
3671
|
picks,
|
|
3093
3672
|
messages
|
|
3094
3673
|
};
|
|
3095
|
-
const copyTimers =
|
|
3096
|
-
|
|
3674
|
+
const copyTimers = useRef9(/* @__PURE__ */ new Map());
|
|
3675
|
+
useEffect10(() => () => {
|
|
3097
3676
|
for (const timer of copyTimers.current.values()) {
|
|
3098
3677
|
clearTimeout(timer);
|
|
3099
3678
|
}
|
|
3100
3679
|
copyTimers.current.clear();
|
|
3101
3680
|
}, []);
|
|
3102
|
-
const callbackCache =
|
|
3103
|
-
const reasoningToggleCache =
|
|
3104
|
-
const toggleReasoning =
|
|
3681
|
+
const callbackCache = useRef9(/* @__PURE__ */ new Map());
|
|
3682
|
+
const reasoningToggleCache = useRef9(/* @__PURE__ */ new Map());
|
|
3683
|
+
const toggleReasoning = useCallback8((key, open) => {
|
|
3105
3684
|
setOpenReasoning((current) => {
|
|
3106
3685
|
const next = new Map(current);
|
|
3107
3686
|
next.set(key, open ?? !(current.get(key) ?? false));
|
|
3108
3687
|
return next;
|
|
3109
3688
|
});
|
|
3110
3689
|
}, []);
|
|
3111
|
-
const stableToggle =
|
|
3690
|
+
const stableToggle = useCallback8((key) => {
|
|
3112
3691
|
let cached = reasoningToggleCache.current.get(key);
|
|
3113
3692
|
if (!cached) {
|
|
3114
3693
|
cached = /* @__PURE__ */ __name((open) => toggleReasoning(key, open), "cached");
|
|
@@ -3118,10 +3697,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
3118
3697
|
}, [
|
|
3119
3698
|
toggleReasoning
|
|
3120
3699
|
]);
|
|
3121
|
-
const pick =
|
|
3700
|
+
const pick = useCallback8((toolCallId, questionId, values) => {
|
|
3122
3701
|
setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));
|
|
3123
3702
|
}, []);
|
|
3124
|
-
const settle =
|
|
3703
|
+
const settle = useCallback8((toolCallId, action, send) => {
|
|
3125
3704
|
setSettleErrors((current) => {
|
|
3126
3705
|
if (!current.has(toolCallId)) {
|
|
3127
3706
|
return current;
|
|
@@ -3145,41 +3724,53 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
3145
3724
|
failed(error);
|
|
3146
3725
|
}
|
|
3147
3726
|
}, []);
|
|
3148
|
-
const answer =
|
|
3727
|
+
const answer = useCallback8((toolCallId) => {
|
|
3149
3728
|
const current = latest.current;
|
|
3150
|
-
const onAnswer = current.
|
|
3729
|
+
const onAnswer = current.handlers.onAnswer;
|
|
3151
3730
|
if (!onAnswer) {
|
|
3152
3731
|
return;
|
|
3153
3732
|
}
|
|
3154
|
-
settle(toolCallId, "answer", () => onAnswer(
|
|
3733
|
+
settle(toolCallId, "answer", () => onAnswer({
|
|
3734
|
+
toolCallId,
|
|
3735
|
+
answers: answersFor(current.picks, toolCallId)
|
|
3736
|
+
}));
|
|
3155
3737
|
}, [
|
|
3156
3738
|
settle
|
|
3157
3739
|
]);
|
|
3158
|
-
const skip =
|
|
3159
|
-
const onSkip = latest.current.
|
|
3740
|
+
const skip = useCallback8((toolCallId) => {
|
|
3741
|
+
const onSkip = latest.current.handlers.onSkip;
|
|
3160
3742
|
if (onSkip) {
|
|
3161
|
-
settle(toolCallId, "skip", () => onSkip(
|
|
3743
|
+
settle(toolCallId, "skip", () => onSkip({
|
|
3744
|
+
toolCallId
|
|
3745
|
+
}));
|
|
3162
3746
|
}
|
|
3163
3747
|
}, [
|
|
3164
3748
|
settle
|
|
3165
3749
|
]);
|
|
3166
|
-
const approve =
|
|
3167
|
-
const onApprove = latest.current.
|
|
3750
|
+
const approve = useCallback8((toolCallId, options2) => {
|
|
3751
|
+
const onApprove = latest.current.handlers.onApprove;
|
|
3168
3752
|
if (onApprove) {
|
|
3169
|
-
settle(toolCallId, "approve", () =>
|
|
3753
|
+
settle(toolCallId, "approve", () => onApprove({
|
|
3754
|
+
toolCallId,
|
|
3755
|
+
...options2?.remember === true ? {
|
|
3756
|
+
remember: true
|
|
3757
|
+
} : {}
|
|
3758
|
+
}));
|
|
3170
3759
|
}
|
|
3171
3760
|
}, [
|
|
3172
3761
|
settle
|
|
3173
3762
|
]);
|
|
3174
|
-
const reject =
|
|
3175
|
-
const onReject = latest.current.
|
|
3763
|
+
const reject = useCallback8((toolCallId) => {
|
|
3764
|
+
const onReject = latest.current.handlers.onReject;
|
|
3176
3765
|
if (onReject) {
|
|
3177
|
-
settle(toolCallId, "reject", () => onReject(
|
|
3766
|
+
settle(toolCallId, "reject", () => onReject({
|
|
3767
|
+
toolCallId
|
|
3768
|
+
}));
|
|
3178
3769
|
}
|
|
3179
3770
|
}, [
|
|
3180
3771
|
settle
|
|
3181
3772
|
]);
|
|
3182
|
-
const callbacksFor =
|
|
3773
|
+
const callbacksFor = useCallback8((id) => {
|
|
3183
3774
|
const cached = callbackCache.current.get(id);
|
|
3184
3775
|
if (cached) {
|
|
3185
3776
|
return cached;
|
|
@@ -3229,13 +3820,20 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
3229
3820
|
return;
|
|
3230
3821
|
}
|
|
3231
3822
|
created.cancelEdit();
|
|
3232
|
-
void latest.current.options.onEditSubmit?.(
|
|
3823
|
+
void latest.current.options.onEditSubmit?.({
|
|
3824
|
+
messageId: id,
|
|
3825
|
+
text: next
|
|
3826
|
+
});
|
|
3233
3827
|
}, "save"),
|
|
3234
3828
|
fork: /* @__PURE__ */ __name(() => {
|
|
3235
|
-
void latest.current.options.onFork?.(
|
|
3829
|
+
void latest.current.options.onFork?.({
|
|
3830
|
+
messageId: id
|
|
3831
|
+
});
|
|
3236
3832
|
}, "fork"),
|
|
3237
3833
|
regenerate: /* @__PURE__ */ __name(() => {
|
|
3238
|
-
void latest.current.options.onRegenerate?.(
|
|
3834
|
+
void latest.current.options.onRegenerate?.({
|
|
3835
|
+
messageId: id
|
|
3836
|
+
});
|
|
3239
3837
|
}, "regenerate"),
|
|
3240
3838
|
textareaRef: /* @__PURE__ */ __name((element) => {
|
|
3241
3839
|
if (!element) {
|
|
@@ -3272,7 +3870,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
3272
3870
|
const draft = drafts.get(message.id);
|
|
3273
3871
|
const isEditing = draft !== void 0;
|
|
3274
3872
|
const text = extractMessageText(message.parts);
|
|
3275
|
-
const usage = options.getUsage
|
|
3873
|
+
const usage = (options.getUsage ?? usageFromMetadata)(message);
|
|
3276
3874
|
const isUser = message.role === "user";
|
|
3277
3875
|
const isAssistant = message.role === "assistant";
|
|
3278
3876
|
const isLastAssistant = isAssistant && message.id === lastAssistantId;
|
|
@@ -3294,22 +3892,22 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
3294
3892
|
...options.toolCatalog !== void 0 ? {
|
|
3295
3893
|
toolCatalog: options.toolCatalog
|
|
3296
3894
|
} : {},
|
|
3297
|
-
...
|
|
3895
|
+
...handlers.onAnswer !== void 0 ? {
|
|
3298
3896
|
elicitation: {
|
|
3299
3897
|
picked: /* @__PURE__ */ __name((toolCallId, questionId) => picks.get(pickKey(toolCallId, questionId)), "picked"),
|
|
3300
3898
|
pick,
|
|
3301
3899
|
canAnswer: true,
|
|
3302
|
-
canSkip:
|
|
3900
|
+
canSkip: handlers.onSkip !== void 0,
|
|
3303
3901
|
answer,
|
|
3304
3902
|
skip,
|
|
3305
3903
|
submitting: /* @__PURE__ */ __name((toolCallId) => settling.get(toolCallId) ?? null, "submitting"),
|
|
3306
3904
|
errorOf: /* @__PURE__ */ __name((toolCallId) => settleErrors.get(toolCallId) ?? null, "errorOf")
|
|
3307
3905
|
}
|
|
3308
3906
|
} : {},
|
|
3309
|
-
...
|
|
3907
|
+
...handlers.onApprove !== void 0 || handlers.onReject !== void 0 ? {
|
|
3310
3908
|
approval: {
|
|
3311
|
-
canApprove:
|
|
3312
|
-
canReject:
|
|
3909
|
+
canApprove: handlers.onApprove !== void 0,
|
|
3910
|
+
canReject: handlers.onReject !== void 0,
|
|
3313
3911
|
approve,
|
|
3314
3912
|
reject,
|
|
3315
3913
|
submitting: /* @__PURE__ */ __name((toolCallId) => settling.get(toolCallId) ?? null, "submitting"),
|
|
@@ -3319,7 +3917,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
3319
3917
|
}),
|
|
3320
3918
|
text,
|
|
3321
3919
|
usage: usage ? describeUsage(usage) : null,
|
|
3322
|
-
timestamp: describeTimestamp(options.getCreatedAt
|
|
3920
|
+
timestamp: describeTimestamp((options.getCreatedAt ?? createdAtFromMetadata)(message)),
|
|
3323
3921
|
copy: {
|
|
3324
3922
|
available: text.length > 0,
|
|
3325
3923
|
copied: copied.has(message.id),
|
|
@@ -3354,6 +3952,43 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
3354
3952
|
return items;
|
|
3355
3953
|
}
|
|
3356
3954
|
__name(useTranscriptItems, "useTranscriptItems");
|
|
3955
|
+
function settleHandlers(options, backend) {
|
|
3956
|
+
const pick = /* @__PURE__ */ __name((own, fallback2) => own === null ? void 0 : own ?? fallback2, "pick");
|
|
3957
|
+
return {
|
|
3958
|
+
onAnswer: pick(options.onAnswer, backend.answerToolCall ? async (input) => {
|
|
3959
|
+
await backend.answerToolCall?.(input);
|
|
3960
|
+
} : void 0),
|
|
3961
|
+
onSkip: pick(options.onSkip, backend.skipToolCall ? async (input) => {
|
|
3962
|
+
await backend.skipToolCall?.(input);
|
|
3963
|
+
} : void 0),
|
|
3964
|
+
onApprove: pick(options.onApprove, backend.approveToolCall ? async (input) => {
|
|
3965
|
+
await backend.approveToolCall?.(input);
|
|
3966
|
+
} : void 0),
|
|
3967
|
+
onReject: pick(options.onReject, backend.rejectToolCall ? async (input) => {
|
|
3968
|
+
await backend.rejectToolCall?.(input);
|
|
3969
|
+
} : void 0)
|
|
3970
|
+
};
|
|
3971
|
+
}
|
|
3972
|
+
__name(settleHandlers, "settleHandlers");
|
|
3973
|
+
function metadataOf2(message) {
|
|
3974
|
+
const metadata = message.metadata;
|
|
3975
|
+
return metadata !== null && typeof metadata === "object" ? metadata : {};
|
|
3976
|
+
}
|
|
3977
|
+
__name(metadataOf2, "metadataOf");
|
|
3978
|
+
function usageFromMetadata(message) {
|
|
3979
|
+
const usage = metadataOf2(message).usage;
|
|
3980
|
+
if (usage === void 0) return null;
|
|
3981
|
+
return {
|
|
3982
|
+
inputTokens: usage.inputTokens,
|
|
3983
|
+
outputTokens: usage.outputTokens,
|
|
3984
|
+
costUsd: usage.costUsd ?? null
|
|
3985
|
+
};
|
|
3986
|
+
}
|
|
3987
|
+
__name(usageFromMetadata, "usageFromMetadata");
|
|
3988
|
+
function createdAtFromMetadata(message) {
|
|
3989
|
+
return metadataOf2(message).createdAt ?? null;
|
|
3990
|
+
}
|
|
3991
|
+
__name(createdAtFromMetadata, "createdAtFromMetadata");
|
|
3357
3992
|
function pickKey(toolCallId, questionId) {
|
|
3358
3993
|
return `${toolCallId}|${questionId}`;
|
|
3359
3994
|
}
|
|
@@ -3403,7 +4038,7 @@ function MessageItem({ message, isStreaming = false, editable, onEditSubmit, reg
|
|
|
3403
4038
|
editable
|
|
3404
4039
|
} : {},
|
|
3405
4040
|
...onEditSubmit ? {
|
|
3406
|
-
onEditSubmit
|
|
4041
|
+
onEditSubmit
|
|
3407
4042
|
} : {},
|
|
3408
4043
|
...onFork ? {
|
|
3409
4044
|
onFork
|
|
@@ -3412,7 +4047,7 @@ function MessageItem({ message, isStreaming = false, editable, onEditSubmit, reg
|
|
|
3412
4047
|
regeneratable
|
|
3413
4048
|
} : {},
|
|
3414
4049
|
...onRegenerate ? {
|
|
3415
|
-
onRegenerate
|
|
4050
|
+
onRegenerate
|
|
3416
4051
|
} : {},
|
|
3417
4052
|
...usage != null ? {
|
|
3418
4053
|
getUsage: /* @__PURE__ */ __name(() => usage, "getUsage")
|
|
@@ -3807,11 +4442,11 @@ function createSkillsSource(options) {
|
|
|
3807
4442
|
if (cached) {
|
|
3808
4443
|
return cached;
|
|
3809
4444
|
}
|
|
3810
|
-
const listSkills = options.
|
|
4445
|
+
const listSkills = options.backend.listSkills;
|
|
3811
4446
|
if (listSkills === void 0) {
|
|
3812
4447
|
return Promise.reject(new AgentBackendUnsupportedError("listSkills"));
|
|
3813
4448
|
}
|
|
3814
|
-
const pending = listSkills.call(options.
|
|
4449
|
+
const pending = listSkills.call(options.backend, threadId).then((entries) => entries.map(toItem)).catch((error) => {
|
|
3815
4450
|
byThread.delete(key);
|
|
3816
4451
|
throw error;
|
|
3817
4452
|
});
|
|
@@ -3841,35 +4476,35 @@ function toItem(entry) {
|
|
|
3841
4476
|
__name(toItem, "toItem");
|
|
3842
4477
|
|
|
3843
4478
|
// src/composer/use-composer-autocomplete.ts
|
|
3844
|
-
import { useCallback as
|
|
4479
|
+
import { useCallback as useCallback9, useEffect as useEffect11, useId, useLayoutEffect, useMemo as useMemo9, useRef as useRef10, useState as useState11 } from "react";
|
|
3845
4480
|
function useComposerAutocomplete(options) {
|
|
3846
4481
|
const { value, sources, acceptOnTab = true } = options;
|
|
3847
|
-
const latest =
|
|
4482
|
+
const latest = useRef10(options);
|
|
3848
4483
|
latest.current = options;
|
|
3849
|
-
const inputRef =
|
|
3850
|
-
const [caret, setCaret] =
|
|
3851
|
-
const [items, setItems] =
|
|
3852
|
-
const [isLoading, setLoading] =
|
|
3853
|
-
const [error, setError] =
|
|
3854
|
-
const [activeIndex, setActiveIndex] =
|
|
3855
|
-
const [dismissedIndex, setDismissedIndex] =
|
|
4484
|
+
const inputRef = useRef10(null);
|
|
4485
|
+
const [caret, setCaret] = useState11(value.length);
|
|
4486
|
+
const [items, setItems] = useState11([]);
|
|
4487
|
+
const [isLoading, setLoading] = useState11(false);
|
|
4488
|
+
const [error, setError] = useState11(null);
|
|
4489
|
+
const [activeIndex, setActiveIndex] = useState11(0);
|
|
4490
|
+
const [dismissedIndex, setDismissedIndex] = useState11(null);
|
|
3856
4491
|
const safeCaret = Math.min(caret, value.length);
|
|
3857
|
-
const match =
|
|
4492
|
+
const match = useMemo9(() => findActiveTrigger(value, safeCaret, sources), [
|
|
3858
4493
|
value,
|
|
3859
4494
|
safeCaret,
|
|
3860
4495
|
sources
|
|
3861
4496
|
]);
|
|
3862
4497
|
const isActive = match !== null && dismissedIndex !== match.index;
|
|
3863
|
-
const matchRef =
|
|
4498
|
+
const matchRef = useRef10(match);
|
|
3864
4499
|
matchRef.current = match;
|
|
3865
|
-
const caretRef =
|
|
4500
|
+
const caretRef = useRef10(safeCaret);
|
|
3866
4501
|
caretRef.current = safeCaret;
|
|
3867
|
-
const itemsRef =
|
|
4502
|
+
const itemsRef = useRef10(items);
|
|
3868
4503
|
itemsRef.current = items;
|
|
3869
|
-
const activeIndexRef =
|
|
4504
|
+
const activeIndexRef = useRef10(activeIndex);
|
|
3870
4505
|
activeIndexRef.current = activeIndex;
|
|
3871
4506
|
const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
|
|
3872
|
-
|
|
4507
|
+
useEffect11(() => {
|
|
3873
4508
|
const current = matchRef.current;
|
|
3874
4509
|
if (requestKey === null || current === null) {
|
|
3875
4510
|
setItems([]);
|
|
@@ -3919,23 +4554,23 @@ function useComposerAutocomplete(options) {
|
|
|
3919
4554
|
const activeItem = isOpen ? items[activeIndex] ?? null : null;
|
|
3920
4555
|
const reactId = useId();
|
|
3921
4556
|
const listboxId = options.id ?? `agent-autocomplete-${reactId}`;
|
|
3922
|
-
const optionId =
|
|
4557
|
+
const optionId = useCallback9((index) => `${listboxId}-option-${index}`, [
|
|
3923
4558
|
listboxId
|
|
3924
4559
|
]);
|
|
3925
|
-
const highlight =
|
|
4560
|
+
const highlight = useCallback9((index) => {
|
|
3926
4561
|
const total = itemsRef.current.length;
|
|
3927
4562
|
if (total === 0) return;
|
|
3928
4563
|
setActiveIndex((index % total + total) % total);
|
|
3929
4564
|
}, []);
|
|
3930
|
-
const moveHighlight =
|
|
4565
|
+
const moveHighlight = useCallback9((delta) => highlight(activeIndexRef.current + delta), [
|
|
3931
4566
|
highlight
|
|
3932
4567
|
]);
|
|
3933
|
-
const dismiss =
|
|
4568
|
+
const dismiss = useCallback9(() => {
|
|
3934
4569
|
const current = matchRef.current;
|
|
3935
4570
|
if (current) setDismissedIndex(current.index);
|
|
3936
4571
|
}, []);
|
|
3937
|
-
const pendingCaret =
|
|
3938
|
-
const accept =
|
|
4572
|
+
const pendingCaret = useRef10(null);
|
|
4573
|
+
const accept = useCallback9((item) => {
|
|
3939
4574
|
const current = matchRef.current;
|
|
3940
4575
|
if (!current) return;
|
|
3941
4576
|
const chosen = item ?? itemsRef.current[activeIndexRef.current];
|
|
@@ -3952,10 +4587,10 @@ function useComposerAutocomplete(options) {
|
|
|
3952
4587
|
pendingCaret.current = null;
|
|
3953
4588
|
inputRef.current?.setSelectionRange(position, position);
|
|
3954
4589
|
});
|
|
3955
|
-
const readCaret =
|
|
4590
|
+
const readCaret = useCallback9((element) => {
|
|
3956
4591
|
setCaret(element.selectionStart ?? element.value.length);
|
|
3957
4592
|
}, []);
|
|
3958
|
-
const onKeyDown =
|
|
4593
|
+
const onKeyDown = useCallback9((event) => {
|
|
3959
4594
|
if (!isOpen) return;
|
|
3960
4595
|
const hasItems = itemsRef.current.length > 0;
|
|
3961
4596
|
switch (event.key) {
|
|
@@ -3993,23 +4628,23 @@ function useComposerAutocomplete(options) {
|
|
|
3993
4628
|
dismiss,
|
|
3994
4629
|
moveHighlight
|
|
3995
4630
|
]);
|
|
3996
|
-
const onChange =
|
|
4631
|
+
const onChange = useCallback9((event) => {
|
|
3997
4632
|
readCaret(event.target);
|
|
3998
4633
|
const next = findActiveTrigger(event.target.value, event.target.selectionStart ?? event.target.value.length, latest.current.sources);
|
|
3999
4634
|
setDismissedIndex((current) => current !== null && next?.index === current ? current : null);
|
|
4000
4635
|
}, [
|
|
4001
4636
|
readCaret
|
|
4002
4637
|
]);
|
|
4003
|
-
const onSelect =
|
|
4638
|
+
const onSelect = useCallback9((event) => readCaret(event.currentTarget), [
|
|
4004
4639
|
readCaret
|
|
4005
4640
|
]);
|
|
4006
|
-
const onClick =
|
|
4641
|
+
const onClick = useCallback9((event) => readCaret(event.currentTarget), [
|
|
4007
4642
|
readCaret
|
|
4008
4643
|
]);
|
|
4009
|
-
const setInput =
|
|
4644
|
+
const setInput = useCallback9((element) => {
|
|
4010
4645
|
inputRef.current = element;
|
|
4011
4646
|
}, []);
|
|
4012
|
-
const getInputProps =
|
|
4647
|
+
const getInputProps = useCallback9(() => ({
|
|
4013
4648
|
ref: setInput,
|
|
4014
4649
|
onChange,
|
|
4015
4650
|
onKeyDown,
|
|
@@ -4037,7 +4672,7 @@ function useComposerAutocomplete(options) {
|
|
|
4037
4672
|
activeIndex,
|
|
4038
4673
|
optionId
|
|
4039
4674
|
]);
|
|
4040
|
-
const getListboxProps =
|
|
4675
|
+
const getListboxProps = useCallback9(() => ({
|
|
4041
4676
|
id: listboxId,
|
|
4042
4677
|
role: "listbox",
|
|
4043
4678
|
"aria-label": match?.source.label ?? match?.source.id ?? "Suggestions"
|
|
@@ -4045,7 +4680,7 @@ function useComposerAutocomplete(options) {
|
|
|
4045
4680
|
listboxId,
|
|
4046
4681
|
match
|
|
4047
4682
|
]);
|
|
4048
|
-
const getOptionProps =
|
|
4683
|
+
const getOptionProps = useCallback9((index) => ({
|
|
4049
4684
|
id: optionId(index),
|
|
4050
4685
|
role: "option",
|
|
4051
4686
|
"aria-selected": index === activeIndex
|
|
@@ -4079,7 +4714,7 @@ function isPromise(value) {
|
|
|
4079
4714
|
__name(isPromise, "isPromise");
|
|
4080
4715
|
|
|
4081
4716
|
// src/presentation/use-tool-catalog.ts
|
|
4082
|
-
import { useCallback as
|
|
4717
|
+
import { useCallback as useCallback10, useEffect as useEffect12, useMemo as useMemo10, useState as useState12 } from "react";
|
|
4083
4718
|
var shared = /* @__PURE__ */ new WeakMap();
|
|
4084
4719
|
function load(client, agent) {
|
|
4085
4720
|
let byAgent = shared.get(client);
|
|
@@ -4101,13 +4736,14 @@ function load(client, agent) {
|
|
|
4101
4736
|
return request;
|
|
4102
4737
|
}
|
|
4103
4738
|
__name(load, "load");
|
|
4104
|
-
function useToolCatalog(options) {
|
|
4105
|
-
const {
|
|
4106
|
-
const
|
|
4107
|
-
const [
|
|
4108
|
-
const [
|
|
4109
|
-
const [
|
|
4110
|
-
|
|
4739
|
+
function useToolCatalog(options = {}) {
|
|
4740
|
+
const { agent, enabled = true } = options;
|
|
4741
|
+
const client = useAgentBackend(options.backend);
|
|
4742
|
+
const [entries, setEntries] = useState12([]);
|
|
4743
|
+
const [isLoading, setLoading] = useState12(enabled);
|
|
4744
|
+
const [error, setError] = useState12(null);
|
|
4745
|
+
const [generation, setGeneration] = useState12(0);
|
|
4746
|
+
useEffect12(() => {
|
|
4111
4747
|
if (!enabled) {
|
|
4112
4748
|
setLoading(false);
|
|
4113
4749
|
return;
|
|
@@ -4116,7 +4752,7 @@ function useToolCatalog(options) {
|
|
|
4116
4752
|
setLoading(true);
|
|
4117
4753
|
load(client, agent).then((loaded) => {
|
|
4118
4754
|
if (cancelled) return;
|
|
4119
|
-
setEntries(loaded);
|
|
4755
|
+
setEntries(Array.isArray(loaded) ? loaded : []);
|
|
4120
4756
|
setError(null);
|
|
4121
4757
|
setLoading(false);
|
|
4122
4758
|
}, (failure) => {
|
|
@@ -4133,14 +4769,14 @@ function useToolCatalog(options) {
|
|
|
4133
4769
|
enabled,
|
|
4134
4770
|
generation
|
|
4135
4771
|
]);
|
|
4136
|
-
const refresh =
|
|
4772
|
+
const refresh = useCallback10(() => {
|
|
4137
4773
|
shared.get(client)?.delete(agent ?? "");
|
|
4138
4774
|
setGeneration((current) => current + 1);
|
|
4139
4775
|
}, [
|
|
4140
4776
|
client,
|
|
4141
4777
|
agent
|
|
4142
4778
|
]);
|
|
4143
|
-
const catalog =
|
|
4779
|
+
const catalog = useMemo10(() => toolCatalogFrom(entries), [
|
|
4144
4780
|
entries
|
|
4145
4781
|
]);
|
|
4146
4782
|
return {
|
|
@@ -4154,7 +4790,7 @@ function useToolCatalog(options) {
|
|
|
4154
4790
|
__name(useToolCatalog, "useToolCatalog");
|
|
4155
4791
|
|
|
4156
4792
|
// src/approvals/countdown.ts
|
|
4157
|
-
import { useEffect as
|
|
4793
|
+
import { useEffect as useEffect13, useRef as useRef11, useState as useState13 } from "react";
|
|
4158
4794
|
function approvalCountdown(expiresAt, now = Date.now()) {
|
|
4159
4795
|
const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
|
|
4160
4796
|
if (!Number.isFinite(deadline)) {
|
|
@@ -4172,10 +4808,10 @@ function approvalCountdown(expiresAt, now = Date.now()) {
|
|
|
4172
4808
|
__name(approvalCountdown, "approvalCountdown");
|
|
4173
4809
|
function useApprovalCountdown(expiresAt, options = {}) {
|
|
4174
4810
|
const { intervalMs = 1e3 } = options;
|
|
4175
|
-
const nowRef =
|
|
4811
|
+
const nowRef = useRef11(options.now ?? Date.now);
|
|
4176
4812
|
nowRef.current = options.now ?? Date.now;
|
|
4177
|
-
const [state, setState] =
|
|
4178
|
-
|
|
4813
|
+
const [state, setState] = useState13(() => approvalCountdown(expiresAt, nowRef.current()));
|
|
4814
|
+
useEffect13(() => {
|
|
4179
4815
|
const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
|
|
4180
4816
|
const first = read();
|
|
4181
4817
|
setState(first);
|
|
@@ -4344,14 +4980,27 @@ function storedMessageToUiMessage(message) {
|
|
|
4344
4980
|
});
|
|
4345
4981
|
parts.push(...pushedByCall.get(call.id) ?? []);
|
|
4346
4982
|
}
|
|
4983
|
+
const metadata = {
|
|
4984
|
+
...message.feedback !== void 0 ? {
|
|
4985
|
+
feedback: message.feedback
|
|
4986
|
+
} : {},
|
|
4987
|
+
...message.createdAt ? {
|
|
4988
|
+
createdAt: message.createdAt
|
|
4989
|
+
} : {},
|
|
4990
|
+
...message.usage !== void 0 ? {
|
|
4991
|
+
usage: {
|
|
4992
|
+
inputTokens: message.usage.inputTokens,
|
|
4993
|
+
outputTokens: message.usage.outputTokens,
|
|
4994
|
+
costUsd: message.usage.costUsd ?? null
|
|
4995
|
+
}
|
|
4996
|
+
} : {}
|
|
4997
|
+
};
|
|
4347
4998
|
return {
|
|
4348
4999
|
id: message.id,
|
|
4349
5000
|
role: message.role,
|
|
4350
5001
|
parts,
|
|
4351
|
-
...
|
|
4352
|
-
metadata
|
|
4353
|
-
feedback: message.feedback
|
|
4354
|
-
}
|
|
5002
|
+
...Object.keys(metadata).length > 0 ? {
|
|
5003
|
+
metadata
|
|
4355
5004
|
} : {}
|
|
4356
5005
|
};
|
|
4357
5006
|
}
|
|
@@ -4389,12 +5038,16 @@ function mergeTurn(rows) {
|
|
|
4389
5038
|
const parts = rows.flatMap((row) => storedMessageToUiMessage(row).parts);
|
|
4390
5039
|
const usage = sumUsage(rows);
|
|
4391
5040
|
const feedback = lastRow.feedback;
|
|
5041
|
+
const createdAt = rows[0]?.createdAt;
|
|
4392
5042
|
const metadata = {
|
|
4393
5043
|
...usage !== void 0 ? {
|
|
4394
5044
|
usage
|
|
4395
5045
|
} : {},
|
|
4396
5046
|
...feedback !== void 0 ? {
|
|
4397
5047
|
feedback
|
|
5048
|
+
} : {},
|
|
5049
|
+
...createdAt ? {
|
|
5050
|
+
createdAt
|
|
4398
5051
|
} : {}
|
|
4399
5052
|
};
|
|
4400
5053
|
return {
|
|
@@ -4423,68 +5076,62 @@ __name(sumUsage, "sumUsage");
|
|
|
4423
5076
|
|
|
4424
5077
|
// src/use-agent-chat.ts
|
|
4425
5078
|
import { useChat } from "@ai-sdk/react";
|
|
4426
|
-
import { useCallback as
|
|
4427
|
-
|
|
4428
|
-
|
|
5079
|
+
import { useCallback as useCallback11, useEffect as useEffect14, useMemo as useMemo11, useRef as useRef12, useState as useState14 } from "react";
|
|
5080
|
+
var localChatSequence = 0;
|
|
5081
|
+
function localChatId() {
|
|
5082
|
+
localChatSequence += 1;
|
|
5083
|
+
return `local-chat-${localChatSequence}`;
|
|
5084
|
+
}
|
|
5085
|
+
__name(localChatId, "localChatId");
|
|
5086
|
+
function useAgentChat(options = {}) {
|
|
5087
|
+
const latest = useRef12(options);
|
|
4429
5088
|
latest.current = options;
|
|
4430
|
-
const
|
|
4431
|
-
const
|
|
5089
|
+
const resolved = useAgentBackend(options.backend);
|
|
5090
|
+
const client = useRef12(resolved).current;
|
|
5091
|
+
const createdThreadId = useRef12(void 0);
|
|
5092
|
+
const chatIdRef = useRef12(options.threadId ?? localChatId());
|
|
5093
|
+
const boundThreadRef = useRef12(options.threadId);
|
|
5094
|
+
if (options.threadId !== boundThreadRef.current) {
|
|
5095
|
+
boundThreadRef.current = options.threadId;
|
|
5096
|
+
const adopting = options.threadId !== void 0 && options.threadId === createdThreadId.current;
|
|
5097
|
+
if (!adopting) {
|
|
5098
|
+
chatIdRef.current = options.threadId ?? localChatId();
|
|
5099
|
+
createdThreadId.current = void 0;
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
const chatId = chatIdRef.current;
|
|
5103
|
+
const [runId, setRunId] = useState14(options.resumeRunId);
|
|
5104
|
+
const runIdRef = useRef12(runId);
|
|
4432
5105
|
runIdRef.current = runId;
|
|
4433
|
-
const settlingRunIdRef =
|
|
4434
|
-
const autoResumeRunIdRef =
|
|
4435
|
-
const [
|
|
4436
|
-
const [
|
|
4437
|
-
const
|
|
4438
|
-
const
|
|
4439
|
-
const
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
...options.credentials !== void 0 ? {
|
|
4447
|
-
credentials: options.credentials
|
|
4448
|
-
} : {},
|
|
4449
|
-
...options.fetch !== void 0 ? {
|
|
4450
|
-
fetch: options.fetch
|
|
4451
|
-
} : {},
|
|
4452
|
-
...options.attachments !== void 0 ? {
|
|
4453
|
-
attachments: options.attachments
|
|
4454
|
-
} : {},
|
|
4455
|
-
getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
|
|
4456
|
-
});
|
|
4457
|
-
}, []);
|
|
4458
|
-
const [connection, setConnection] = useState13({
|
|
5106
|
+
const settlingRunIdRef = useRef12(void 0);
|
|
5107
|
+
const autoResumeRunIdRef = useRef12(void 0);
|
|
5108
|
+
const [activeRunId, setActiveRunId] = useState14(null);
|
|
5109
|
+
const [isLoadingHistory, setIsLoadingHistory] = useState14(false);
|
|
5110
|
+
const [historyError, setHistoryError] = useState14(null);
|
|
5111
|
+
const [threadModel, setThreadModel] = useState14(null);
|
|
5112
|
+
const [pickedModel, setPickedModel] = useState14(void 0);
|
|
5113
|
+
const pickedModelRef = useRef12(pickedModel);
|
|
5114
|
+
pickedModelRef.current = pickedModel;
|
|
5115
|
+
const pendingPin = useRef12(void 0);
|
|
5116
|
+
const regenerateNext = useRef12(false);
|
|
5117
|
+
const currentThreadId = useCallback11(() => latest.current.threadId ?? createdThreadId.current, []);
|
|
5118
|
+
const [connection, setConnection] = useState14({
|
|
4459
5119
|
status: "live"
|
|
4460
5120
|
});
|
|
4461
|
-
const resyncAfterSettle =
|
|
4462
|
-
|
|
4463
|
-
if (!options.resume || options.threadId === void 0) return;
|
|
4464
|
-
let cancelled = false;
|
|
4465
|
-
const threadId = options.threadId;
|
|
4466
|
-
void client.getThread(threadId).then((thread) => {
|
|
4467
|
-
if (cancelled) return;
|
|
4468
|
-
setActiveRunId(thread.activeRunId ?? null);
|
|
4469
|
-
if (thread.activeRunId != null) {
|
|
4470
|
-
autoResumeRunIdRef.current = thread.activeRunId;
|
|
4471
|
-
setAutoResume(true);
|
|
4472
|
-
}
|
|
4473
|
-
});
|
|
4474
|
-
return () => {
|
|
4475
|
-
cancelled = true;
|
|
4476
|
-
};
|
|
4477
|
-
}, [
|
|
4478
|
-
client,
|
|
4479
|
-
options.resume,
|
|
4480
|
-
options.threadId
|
|
4481
|
-
]);
|
|
4482
|
-
const transport = useMemo8(() => {
|
|
5121
|
+
const resyncAfterSettle = useRef12(false);
|
|
5122
|
+
const transport = useMemo11(() => {
|
|
4483
5123
|
function onMeta(meta) {
|
|
4484
5124
|
settlingRunIdRef.current = meta.runId;
|
|
4485
5125
|
setRunId(meta.runId);
|
|
4486
5126
|
if (latest.current.threadId === void 0 && meta.threadId && createdThreadId.current !== meta.threadId) {
|
|
4487
5127
|
createdThreadId.current = meta.threadId;
|
|
5128
|
+
const pin = pendingPin.current;
|
|
5129
|
+
if (pin !== void 0) {
|
|
5130
|
+
pendingPin.current = void 0;
|
|
5131
|
+
void client.updateThread(meta.threadId, {
|
|
5132
|
+
model: pin.model
|
|
5133
|
+
}).catch(() => void 0);
|
|
5134
|
+
}
|
|
4488
5135
|
latest.current.onThreadCreated?.(meta.threadId);
|
|
4489
5136
|
notifyThreads(client, {
|
|
4490
5137
|
type: "changed"
|
|
@@ -4511,13 +5158,14 @@ function useAgentChat(options) {
|
|
|
4511
5158
|
const pageContext = current.getPageContext?.() ?? null;
|
|
4512
5159
|
const regenerate2 = regenerateNext.current;
|
|
4513
5160
|
regenerateNext.current = false;
|
|
4514
|
-
const threadId =
|
|
5161
|
+
const threadId = currentThreadId();
|
|
5162
|
+
const model = current.model ?? pickedModelRef.current;
|
|
4515
5163
|
return {
|
|
4516
5164
|
...threadId !== void 0 ? {
|
|
4517
5165
|
threadId
|
|
4518
5166
|
} : {},
|
|
4519
|
-
...
|
|
4520
|
-
model
|
|
5167
|
+
...model !== void 0 ? {
|
|
5168
|
+
model
|
|
4521
5169
|
} : {},
|
|
4522
5170
|
...pageContext ? {
|
|
4523
5171
|
pageContext
|
|
@@ -4534,13 +5182,11 @@ function useAgentChat(options) {
|
|
|
4534
5182
|
}, "onAttemptStart")
|
|
4535
5183
|
});
|
|
4536
5184
|
}, []);
|
|
4537
|
-
const backgroundRef =
|
|
5185
|
+
const backgroundRef = useRef12(() => Promise.resolve());
|
|
4538
5186
|
const chat = useChat({
|
|
4539
5187
|
transport,
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
id: options.threadId
|
|
4543
|
-
} : {},
|
|
5188
|
+
id: chatId,
|
|
5189
|
+
resume: options.resumeRunId !== void 0,
|
|
4544
5190
|
...options.initialMessages !== void 0 ? {
|
|
4545
5191
|
messages: options.initialMessages
|
|
4546
5192
|
} : {},
|
|
@@ -4550,7 +5196,7 @@ function useAgentChat(options) {
|
|
|
4550
5196
|
const title = part.data?.title;
|
|
4551
5197
|
if (typeof title === "string") {
|
|
4552
5198
|
latest.current.onTitle?.(title);
|
|
4553
|
-
const threadId =
|
|
5199
|
+
const threadId = currentThreadId();
|
|
4554
5200
|
if (threadId !== void 0) notifyThreads(client, {
|
|
4555
5201
|
type: "title",
|
|
4556
5202
|
threadId,
|
|
@@ -4583,10 +5229,10 @@ function useAgentChat(options) {
|
|
|
4583
5229
|
}
|
|
4584
5230
|
}, "onFinish")
|
|
4585
5231
|
});
|
|
4586
|
-
const chatRef =
|
|
5232
|
+
const chatRef = useRef12(chat);
|
|
4587
5233
|
chatRef.current = chat;
|
|
4588
5234
|
async function resyncFromThread() {
|
|
4589
|
-
const threadId =
|
|
5235
|
+
const threadId = currentThreadId();
|
|
4590
5236
|
if (threadId === void 0) return;
|
|
4591
5237
|
try {
|
|
4592
5238
|
const thread = await client.getThread(threadId);
|
|
@@ -4595,13 +5241,75 @@ function useAgentChat(options) {
|
|
|
4595
5241
|
}
|
|
4596
5242
|
}
|
|
4597
5243
|
__name(resyncFromThread, "resyncFromThread");
|
|
4598
|
-
const
|
|
4599
|
-
|
|
5244
|
+
const firstChatId = useRef12(chatId);
|
|
5245
|
+
useEffect14(() => {
|
|
5246
|
+
if (chatId === firstChatId.current) return;
|
|
5247
|
+
firstChatId.current = chatId;
|
|
5248
|
+
setRunId(void 0);
|
|
5249
|
+
setActiveRunId(null);
|
|
5250
|
+
setThreadModel(null);
|
|
5251
|
+
setBackgroundRuns([]);
|
|
5252
|
+
setHistoryError(null);
|
|
5253
|
+
autoResumeRunIdRef.current = void 0;
|
|
5254
|
+
pendingPin.current = void 0;
|
|
5255
|
+
}, [
|
|
5256
|
+
chatId
|
|
5257
|
+
]);
|
|
5258
|
+
useEffect14(() => {
|
|
5259
|
+
const threadId = options.threadId;
|
|
5260
|
+
if (threadId === void 0) return;
|
|
5261
|
+
if (threadId === createdThreadId.current) return;
|
|
5262
|
+
const current = latest.current;
|
|
5263
|
+
const wantHistory = current.history !== false && current.initialMessages === void 0;
|
|
5264
|
+
const wantResume = current.resume !== false && current.resumeRunId === void 0;
|
|
5265
|
+
if (!wantHistory && !wantResume) return;
|
|
5266
|
+
let cancelled = false;
|
|
5267
|
+
if (wantHistory) setIsLoadingHistory(true);
|
|
5268
|
+
client.getThread(threadId).then((thread) => {
|
|
5269
|
+
if (cancelled || thread == null) return;
|
|
5270
|
+
const active = thread.activeRunId ?? null;
|
|
5271
|
+
const stored = Array.isArray(thread.messages) ? thread.messages : [];
|
|
5272
|
+
setActiveRunId(active);
|
|
5273
|
+
setThreadModel(thread.model ?? null);
|
|
5274
|
+
setHistoryError(null);
|
|
5275
|
+
const resuming = wantResume && active !== null;
|
|
5276
|
+
if (wantHistory && chatRef.current.messages.length === 0) {
|
|
5277
|
+
const rows = resuming ? stored.filter((message) => !(message.role === "assistant" && message.runId === active)) : stored;
|
|
5278
|
+
chatRef.current.setMessages(storedThreadToUiMessages(rows));
|
|
5279
|
+
}
|
|
5280
|
+
if (resuming) {
|
|
5281
|
+
autoResumeRunIdRef.current = active;
|
|
5282
|
+
void chatRef.current.resumeStream();
|
|
5283
|
+
}
|
|
5284
|
+
}, (error) => {
|
|
5285
|
+
if (cancelled) return;
|
|
5286
|
+
setHistoryError(error instanceof Error ? error : new Error(String(error)));
|
|
5287
|
+
}).finally(() => {
|
|
5288
|
+
if (!cancelled) setIsLoadingHistory(false);
|
|
5289
|
+
});
|
|
5290
|
+
return () => {
|
|
5291
|
+
cancelled = true;
|
|
5292
|
+
setIsLoadingHistory(false);
|
|
5293
|
+
};
|
|
5294
|
+
}, [
|
|
5295
|
+
client,
|
|
5296
|
+
chatId,
|
|
5297
|
+
options.threadId
|
|
5298
|
+
]);
|
|
5299
|
+
const turnInFlight = useRef12(false);
|
|
5300
|
+
const isTurnInFlight = useCallback11(() => turnInFlight.current || transport.isAttemptLive, [
|
|
4600
5301
|
transport
|
|
4601
5302
|
]);
|
|
4602
|
-
const
|
|
4603
|
-
|
|
4604
|
-
|
|
5303
|
+
const quota = useQuota({
|
|
5304
|
+
backend: client,
|
|
5305
|
+
enabled: options.quota !== false && typeof client.getQuota === "function"
|
|
5306
|
+
});
|
|
5307
|
+
const blocked = options.blocked !== void 0 ? options.blocked : quota.blocked;
|
|
5308
|
+
const blockedRef = useRef12(blocked);
|
|
5309
|
+
blockedRef.current = blocked;
|
|
5310
|
+
const sendMessage = useCallback11(async (...args) => {
|
|
5311
|
+
const block = blockedRef.current;
|
|
5312
|
+
if (block != null) throw new QuotaBlockedError(block);
|
|
4605
5313
|
if (isTurnInFlight()) return;
|
|
4606
5314
|
turnInFlight.current = true;
|
|
4607
5315
|
try {
|
|
@@ -4612,16 +5320,14 @@ function useAgentChat(options) {
|
|
|
4612
5320
|
}, [
|
|
4613
5321
|
isTurnInFlight
|
|
4614
5322
|
]);
|
|
4615
|
-
const addToolResult =
|
|
5323
|
+
const addToolResult = useCallback11(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
4616
5324
|
tool,
|
|
4617
5325
|
toolCallId,
|
|
4618
5326
|
output
|
|
4619
5327
|
}), []);
|
|
4620
|
-
const [
|
|
4621
|
-
const
|
|
4622
|
-
|
|
4623
|
-
const refreshBackground = useCallback10(async () => {
|
|
4624
|
-
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
5328
|
+
const [backgroundRuns, setBackgroundRuns] = useState14([]);
|
|
5329
|
+
const refreshBackground = useCallback11(async () => {
|
|
5330
|
+
const threadId = currentThreadId();
|
|
4625
5331
|
if (threadId === void 0) {
|
|
4626
5332
|
return;
|
|
4627
5333
|
}
|
|
@@ -4641,11 +5347,12 @@ function useAgentChat(options) {
|
|
|
4641
5347
|
];
|
|
4642
5348
|
});
|
|
4643
5349
|
}, [
|
|
4644
|
-
client
|
|
5350
|
+
client,
|
|
5351
|
+
currentThreadId
|
|
4645
5352
|
]);
|
|
4646
5353
|
backgroundRef.current = refreshBackground;
|
|
4647
5354
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
4648
|
-
|
|
5355
|
+
useEffect14(() => {
|
|
4649
5356
|
if (options.background !== true || options.threadId === void 0) {
|
|
4650
5357
|
return;
|
|
4651
5358
|
}
|
|
@@ -4653,9 +5360,10 @@ function useAgentChat(options) {
|
|
|
4653
5360
|
}, [
|
|
4654
5361
|
options.background,
|
|
4655
5362
|
options.threadId,
|
|
5363
|
+
chatId,
|
|
4656
5364
|
refreshBackground
|
|
4657
5365
|
]);
|
|
4658
|
-
|
|
5366
|
+
useEffect14(() => {
|
|
4659
5367
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
4660
5368
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
4661
5369
|
return;
|
|
@@ -4666,66 +5374,19 @@ function useAgentChat(options) {
|
|
|
4666
5374
|
isWorking,
|
|
4667
5375
|
refreshBackground
|
|
4668
5376
|
]);
|
|
4669
|
-
const
|
|
4670
|
-
const list = await client.listThreads();
|
|
4671
|
-
setThreads(list);
|
|
4672
|
-
return list;
|
|
4673
|
-
}, [
|
|
4674
|
-
client
|
|
4675
|
-
]);
|
|
4676
|
-
const loadThread = useCallback10((id) => client.getThread(id), [
|
|
4677
|
-
client
|
|
4678
|
-
]);
|
|
4679
|
-
const deleteThread = useCallback10(async (id) => {
|
|
4680
|
-
await client.deleteThread(id);
|
|
4681
|
-
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
4682
|
-
}, [
|
|
4683
|
-
client
|
|
4684
|
-
]);
|
|
4685
|
-
const forkThread = useCallback10((threadId, messageId) => requireBackendMethod(client, "forkFromMessage")(threadId, messageId), [
|
|
4686
|
-
client
|
|
4687
|
-
]);
|
|
4688
|
-
const renameThread = useCallback10(async (id, title) => {
|
|
4689
|
-
await client.updateThread(id, {
|
|
4690
|
-
title
|
|
4691
|
-
});
|
|
4692
|
-
setThreads((current) => current.map((thread) => thread.id === id ? {
|
|
4693
|
-
...thread,
|
|
4694
|
-
title
|
|
4695
|
-
} : thread));
|
|
4696
|
-
}, [
|
|
4697
|
-
client
|
|
4698
|
-
]);
|
|
4699
|
-
const promoteThread = useCallback10(async (id) => {
|
|
4700
|
-
await requireBackendMethod(client, "promoteThread")(id);
|
|
4701
|
-
await loadThreads();
|
|
4702
|
-
}, [
|
|
4703
|
-
client,
|
|
4704
|
-
loadThreads
|
|
4705
|
-
]);
|
|
4706
|
-
const truncateFromMessage = useCallback10((threadId, messageId) => requireBackendMethod(client, "truncateFromMessage")(threadId, messageId).then(() => void 0), [
|
|
4707
|
-
client
|
|
4708
|
-
]);
|
|
4709
|
-
const loadQuota = useCallback10(async () => {
|
|
4710
|
-
const today = await requireBackendMethod(client, "getQuotaToday")();
|
|
4711
|
-
setQuota(today);
|
|
4712
|
-
return today;
|
|
4713
|
-
}, [
|
|
4714
|
-
client
|
|
4715
|
-
]);
|
|
4716
|
-
const cancel = useCallback10(async () => {
|
|
5377
|
+
const cancel = useCallback11(async () => {
|
|
4717
5378
|
chatRef.current.stop();
|
|
4718
|
-
const
|
|
4719
|
-
if (
|
|
5379
|
+
const active = runIdRef.current;
|
|
5380
|
+
if (active) {
|
|
4720
5381
|
try {
|
|
4721
|
-
await client.cancelStream(
|
|
5382
|
+
await client.cancelStream(active);
|
|
4722
5383
|
} catch {
|
|
4723
5384
|
}
|
|
4724
5385
|
}
|
|
4725
5386
|
}, [
|
|
4726
5387
|
client
|
|
4727
5388
|
]);
|
|
4728
|
-
const approve =
|
|
5389
|
+
const approve = useCallback11(async ({ toolCallId, remember, via }) => {
|
|
4729
5390
|
await requireBackendMethod(client, "approveToolCall")({
|
|
4730
5391
|
toolCallId,
|
|
4731
5392
|
...remember === true ? {
|
|
@@ -4738,7 +5399,7 @@ function useAgentChat(options) {
|
|
|
4738
5399
|
}, [
|
|
4739
5400
|
client
|
|
4740
5401
|
]);
|
|
4741
|
-
const reject =
|
|
5402
|
+
const reject = useCallback11(async ({ toolCallId, reason, via }) => {
|
|
4742
5403
|
await requireBackendMethod(client, "rejectToolCall")({
|
|
4743
5404
|
toolCallId,
|
|
4744
5405
|
...reason !== void 0 ? {
|
|
@@ -4751,7 +5412,7 @@ function useAgentChat(options) {
|
|
|
4751
5412
|
}, [
|
|
4752
5413
|
client
|
|
4753
5414
|
]);
|
|
4754
|
-
const answer =
|
|
5415
|
+
const answer = useCallback11(async ({ toolCallId, answers }) => {
|
|
4755
5416
|
await requireBackendMethod(client, "answerToolCall")({
|
|
4756
5417
|
toolCallId,
|
|
4757
5418
|
...answers !== void 0 ? {
|
|
@@ -4761,16 +5422,16 @@ function useAgentChat(options) {
|
|
|
4761
5422
|
}, [
|
|
4762
5423
|
client
|
|
4763
5424
|
]);
|
|
4764
|
-
const skip =
|
|
5425
|
+
const skip = useCallback11(async ({ toolCallId }) => {
|
|
4765
5426
|
await requireBackendMethod(client, "skipToolCall")({
|
|
4766
5427
|
toolCallId
|
|
4767
5428
|
});
|
|
4768
5429
|
}, [
|
|
4769
5430
|
client
|
|
4770
5431
|
]);
|
|
4771
|
-
const regenerate =
|
|
4772
|
-
const
|
|
4773
|
-
if (
|
|
5432
|
+
const regenerate = useCallback11((_input) => {
|
|
5433
|
+
const block = blockedRef.current;
|
|
5434
|
+
if (block != null) throw new QuotaBlockedError(block);
|
|
4774
5435
|
if (isTurnInFlight()) return;
|
|
4775
5436
|
regenerateNext.current = true;
|
|
4776
5437
|
turnInFlight.current = true;
|
|
@@ -4780,15 +5441,78 @@ function useAgentChat(options) {
|
|
|
4780
5441
|
}, [
|
|
4781
5442
|
isTurnInFlight
|
|
4782
5443
|
]);
|
|
4783
|
-
const
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
5444
|
+
const storedIdOf = useCallback11(async (messageId, threadId) => {
|
|
5445
|
+
const message = chatRef.current.messages.find((candidate) => candidate.id === messageId);
|
|
5446
|
+
const runOf = message?.metadata?.runId;
|
|
5447
|
+
if (runOf === void 0) return messageId;
|
|
5448
|
+
const thread = await client.getThread(threadId);
|
|
5449
|
+
const row = [
|
|
5450
|
+
...thread.messages
|
|
5451
|
+
].reverse().find((candidate) => candidate.role === "assistant" && candidate.runId === runOf);
|
|
5452
|
+
return row?.id ?? messageId;
|
|
5453
|
+
}, [
|
|
5454
|
+
client
|
|
5455
|
+
]);
|
|
5456
|
+
const fork = useCallback11(async ({ messageId, threadId }) => {
|
|
5457
|
+
const source = threadId ?? currentThreadId();
|
|
5458
|
+
if (source === void 0) throw new Error("fork: this chat has no thread yet");
|
|
5459
|
+
const stored = await storedIdOf(messageId, source);
|
|
5460
|
+
const forked = await requireBackendMethod(client, "forkFromMessage")(source, stored);
|
|
5461
|
+
notifyThreads(client, {
|
|
5462
|
+
type: "changed"
|
|
5463
|
+
});
|
|
5464
|
+
latest.current.onThreadCreated?.(forked.id);
|
|
5465
|
+
return forked;
|
|
5466
|
+
}, [
|
|
5467
|
+
client,
|
|
5468
|
+
currentThreadId,
|
|
5469
|
+
storedIdOf
|
|
5470
|
+
]);
|
|
5471
|
+
const truncateFrom = useCallback11(async ({ messageId, threadId }) => {
|
|
5472
|
+
const target = threadId ?? currentThreadId();
|
|
5473
|
+
if (target === void 0) throw new Error("truncateFrom: this chat has no thread yet");
|
|
5474
|
+
const stored = await storedIdOf(messageId, target);
|
|
5475
|
+
await requireBackendMethod(client, "truncateFromMessage")(target, stored);
|
|
5476
|
+
}, [
|
|
5477
|
+
client,
|
|
5478
|
+
currentThreadId,
|
|
5479
|
+
storedIdOf
|
|
5480
|
+
]);
|
|
5481
|
+
const promote = useCallback11(async ({ threadId } = {}) => {
|
|
5482
|
+
const target = threadId ?? currentThreadId();
|
|
5483
|
+
if (target === void 0) throw new Error("promote: this chat has no thread yet");
|
|
5484
|
+
await requireBackendMethod(client, "promoteThread")(target);
|
|
5485
|
+
notifyThreads(client, {
|
|
5486
|
+
type: "changed"
|
|
5487
|
+
});
|
|
5488
|
+
}, [
|
|
5489
|
+
client,
|
|
5490
|
+
currentThreadId
|
|
5491
|
+
]);
|
|
5492
|
+
const [modelsWanted, setModelsWanted] = useState14(false);
|
|
5493
|
+
const modelsWantedRef = useRef12(modelsWanted);
|
|
5494
|
+
modelsWantedRef.current = modelsWanted;
|
|
5495
|
+
const catalog = useModels({
|
|
5496
|
+
backend: client,
|
|
5497
|
+
...options.agent !== void 0 ? {
|
|
5498
|
+
agent: options.agent
|
|
5499
|
+
} : {},
|
|
5500
|
+
enabled: modelsWanted && typeof client.listModels === "function"
|
|
5501
|
+
});
|
|
5502
|
+
const wantModels = useCallback11(() => {
|
|
5503
|
+
if (modelsWantedRef.current) return;
|
|
5504
|
+
modelsWantedRef.current = true;
|
|
5505
|
+
queueMicrotask(() => setModelsWanted(true));
|
|
5506
|
+
}, []);
|
|
5507
|
+
const selectModel = useCallback11((id) => setPickedModel(id), []);
|
|
5508
|
+
const pinToThread = useCallback11(async (model) => {
|
|
5509
|
+
const threadId = currentThreadId();
|
|
5510
|
+
setThreadModel(model);
|
|
4790
5511
|
if (threadId === void 0) {
|
|
4791
|
-
|
|
5512
|
+
pendingPin.current = {
|
|
5513
|
+
model
|
|
5514
|
+
};
|
|
5515
|
+
return;
|
|
4792
5516
|
}
|
|
4793
5517
|
await client.updateThread(threadId, {
|
|
4794
5518
|
model
|
|
@@ -4797,10 +5521,99 @@ function useAgentChat(options) {
|
|
|
4797
5521
|
type: "changed"
|
|
4798
5522
|
});
|
|
4799
5523
|
}, [
|
|
4800
|
-
client
|
|
5524
|
+
client,
|
|
5525
|
+
currentThreadId
|
|
4801
5526
|
]);
|
|
4802
|
-
const
|
|
5527
|
+
const models = {
|
|
5528
|
+
get list() {
|
|
5529
|
+
wantModels();
|
|
5530
|
+
return catalog.models;
|
|
5531
|
+
},
|
|
5532
|
+
get providers() {
|
|
5533
|
+
wantModels();
|
|
5534
|
+
return catalog.providers;
|
|
5535
|
+
},
|
|
5536
|
+
selected: options.model ?? pickedModel ?? threadModel ?? catalog.defaultModel ?? null,
|
|
5537
|
+
select: selectModel,
|
|
5538
|
+
pinToThread,
|
|
5539
|
+
isLoading: modelsWanted && catalog.isLoading,
|
|
5540
|
+
error: catalog.error
|
|
5541
|
+
};
|
|
4803
5542
|
const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
|
|
5543
|
+
const isBusy = status === "submitted" || status === "streaming" || status === "reconnecting";
|
|
5544
|
+
const files = useAttachments({
|
|
5545
|
+
...options.composer,
|
|
5546
|
+
backend: client
|
|
5547
|
+
});
|
|
5548
|
+
const [text, setText] = useState14("");
|
|
5549
|
+
const blockedBy = blocked != null ? "quota" : files.isUploading ? "uploading" : isBusy ? "busy" : text.trim().length === 0 && files.attachments.length === 0 ? "empty" : null;
|
|
5550
|
+
const composerRef = useRef12({
|
|
5551
|
+
text,
|
|
5552
|
+
files,
|
|
5553
|
+
blockedBy
|
|
5554
|
+
});
|
|
5555
|
+
composerRef.current = {
|
|
5556
|
+
text,
|
|
5557
|
+
files,
|
|
5558
|
+
blockedBy
|
|
5559
|
+
};
|
|
5560
|
+
const submit = useCallback11(async () => {
|
|
5561
|
+
const current = composerRef.current;
|
|
5562
|
+
if (current.blockedBy !== null) return;
|
|
5563
|
+
const refs = current.files.refs;
|
|
5564
|
+
const draft = current.text.trim();
|
|
5565
|
+
setText("");
|
|
5566
|
+
current.files.clear();
|
|
5567
|
+
await sendMessage({
|
|
5568
|
+
text: draft
|
|
5569
|
+
}, refs.length > 0 ? {
|
|
5570
|
+
body: {
|
|
5571
|
+
attachments: refs
|
|
5572
|
+
}
|
|
5573
|
+
} : void 0);
|
|
5574
|
+
}, [
|
|
5575
|
+
sendMessage
|
|
5576
|
+
]);
|
|
5577
|
+
const composer = {
|
|
5578
|
+
text,
|
|
5579
|
+
setText,
|
|
5580
|
+
files,
|
|
5581
|
+
canSend: blockedBy === null,
|
|
5582
|
+
blockedBy,
|
|
5583
|
+
submit
|
|
5584
|
+
};
|
|
5585
|
+
const ownCatalog = options.transcript?.toolCatalog;
|
|
5586
|
+
const tools = useToolCatalog({
|
|
5587
|
+
backend: client,
|
|
5588
|
+
...options.agent !== void 0 ? {
|
|
5589
|
+
agent: options.agent
|
|
5590
|
+
} : {},
|
|
5591
|
+
enabled: ownCatalog === void 0 && typeof client.listTools === "function"
|
|
5592
|
+
});
|
|
5593
|
+
const canFork = typeof client.forkFromMessage === "function";
|
|
5594
|
+
const transcript = useChatTranscript({
|
|
5595
|
+
messages: chat.messages,
|
|
5596
|
+
status,
|
|
5597
|
+
onStop: cancel,
|
|
5598
|
+
onApprove: approve,
|
|
5599
|
+
onReject: reject,
|
|
5600
|
+
onAnswer: answer,
|
|
5601
|
+
onSkip: skip,
|
|
5602
|
+
regeneratable: true,
|
|
5603
|
+
onRegenerate: regenerate,
|
|
5604
|
+
...canFork ? {
|
|
5605
|
+
onFork: /* @__PURE__ */ __name((input) => fork(input).then(() => void 0), "onFork")
|
|
5606
|
+
} : {},
|
|
5607
|
+
...ownCatalog === void 0 ? {
|
|
5608
|
+
toolCatalog: tools.catalog
|
|
5609
|
+
} : {},
|
|
5610
|
+
...options.transcript
|
|
5611
|
+
});
|
|
5612
|
+
const background = {
|
|
5613
|
+
runs: backgroundRuns,
|
|
5614
|
+
isWorking,
|
|
5615
|
+
refresh: refreshBackground
|
|
5616
|
+
};
|
|
4804
5617
|
return {
|
|
4805
5618
|
...chat,
|
|
4806
5619
|
status,
|
|
@@ -4811,34 +5624,38 @@ function useAgentChat(options) {
|
|
|
4811
5624
|
/** Sub-agents this conversation started and did not wait for. */
|
|
4812
5625
|
background,
|
|
4813
5626
|
runId,
|
|
4814
|
-
/** The
|
|
5627
|
+
/** The loaded thread's running turn, or `null` once read with none. */
|
|
4815
5628
|
activeRunId,
|
|
5629
|
+
/** The thread's history is being read. */
|
|
5630
|
+
isLoadingHistory,
|
|
5631
|
+
/** Reading the thread's history failed. */
|
|
5632
|
+
historyError,
|
|
4816
5633
|
/**
|
|
4817
5634
|
* The thread this chat is on right now: the `threadId` option, else the one the backend created
|
|
4818
5635
|
* on the first send. A getter, because the created id is learned mid-stream.
|
|
4819
5636
|
*/
|
|
4820
|
-
getThreadId,
|
|
4821
|
-
|
|
4822
|
-
/** The backend this chat talks to — pass it to `useThreads`, `useMessageFeedback`, … */
|
|
5637
|
+
getThreadId: currentThreadId,
|
|
5638
|
+
/** The backend this chat talks to — the same one every other hook under the provider uses. */
|
|
4823
5639
|
backend: client,
|
|
4824
|
-
/**
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
renameThread,
|
|
4832
|
-
promoteThread,
|
|
4833
|
-
truncateFromMessage,
|
|
5640
|
+
/** The transcript model, with every action already bound to this chat. */
|
|
5641
|
+
transcript,
|
|
5642
|
+
/** A headless composer: draft, files, send gate, `submit()`. */
|
|
5643
|
+
composer,
|
|
5644
|
+
/** The model picker: `list`, `selected`, `select(id)`, `pinToThread(id)`. */
|
|
5645
|
+
models,
|
|
5646
|
+
/** The caller's budget (`GET <base>/quota`); `quota.blocked` gates sends. */
|
|
4834
5647
|
quota,
|
|
4835
|
-
|
|
5648
|
+
/** The window blocking sends right now (the `blocked` option, else the quota report's). */
|
|
5649
|
+
blocked,
|
|
4836
5650
|
cancel,
|
|
4837
5651
|
approve,
|
|
4838
5652
|
reject,
|
|
4839
5653
|
answer,
|
|
4840
5654
|
skip,
|
|
4841
|
-
regenerate
|
|
5655
|
+
regenerate,
|
|
5656
|
+
fork,
|
|
5657
|
+
truncateFrom,
|
|
5658
|
+
promote
|
|
4842
5659
|
};
|
|
4843
5660
|
}
|
|
4844
5661
|
__name(useAgentChat, "useAgentChat");
|
|
@@ -4852,19 +5669,12 @@ var QuotaBlockedError = class extends Error {
|
|
|
4852
5669
|
this.name = "QuotaBlockedError";
|
|
4853
5670
|
}
|
|
4854
5671
|
};
|
|
4855
|
-
async function mergeHeaders(options) {
|
|
4856
|
-
const dynamic = await options.getHeaders?.() ?? {};
|
|
4857
|
-
return {
|
|
4858
|
-
...options.headers,
|
|
4859
|
-
...dynamic
|
|
4860
|
-
};
|
|
4861
|
-
}
|
|
4862
|
-
__name(mergeHeaders, "mergeHeaders");
|
|
4863
5672
|
export {
|
|
4864
5673
|
AgentBackendUnsupportedError,
|
|
4865
5674
|
AgentChatTransport,
|
|
4866
5675
|
AgentClient,
|
|
4867
5676
|
AgentHttpError,
|
|
5677
|
+
AgentProvider,
|
|
4868
5678
|
AmbientRenderUiContext,
|
|
4869
5679
|
ChatInput,
|
|
4870
5680
|
DEFAULT_SPEECH_LANG,
|
|
@@ -4910,6 +5720,7 @@ export {
|
|
|
4910
5720
|
storedThreadToUiMessages,
|
|
4911
5721
|
toolCallState,
|
|
4912
5722
|
toolCatalogFrom,
|
|
5723
|
+
useAgentBackend,
|
|
4913
5724
|
useAgentChat,
|
|
4914
5725
|
useAgents,
|
|
4915
5726
|
useAmbientRenderUi,
|