@agents24/chat-react 0.5.32 → 0.5.34
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/compatibility.json +5 -5
- package/dist/{chunk-ZCNHLFRB.js → chunk-QG5XSK2Z.js} +15 -3
- package/dist/chunk-QG5XSK2Z.js.map +1 -0
- package/dist/index.cjs +14 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp-oauth.d.ts +1 -1
- package/dist/registry/agents24-chat.json +8 -8
- package/dist/runtime/index.cjs +216 -131
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.js +202 -130
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/use-agent-chat-hitl.d.ts +19 -0
- package/dist/types.d.ts +3 -0
- package/dist/ui/index.cjs +2 -10
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.js +2 -10
- package/dist/ui/index.js.map +1 -1
- package/package.json +3 -3
- package/scaffold/inherit.css +2 -0
- package/dist/chunk-ZCNHLFRB.js.map +0 -1
package/dist/runtime/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
createMcpPkceProof,
|
|
4
4
|
validateMcpCallbackResult,
|
|
5
5
|
waitForMcpOauthComplete
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-QG5XSK2Z.js";
|
|
7
7
|
import {
|
|
8
8
|
SUPPORTED_INPUT_MIME_TYPES,
|
|
9
9
|
attachmentFileAccept,
|
|
@@ -18,10 +18,155 @@ import {
|
|
|
18
18
|
// src/runtime/use-agent-chat-runtime.ts
|
|
19
19
|
import {
|
|
20
20
|
useAgentAttachments,
|
|
21
|
-
useAgentChat
|
|
22
|
-
useAgentMcp
|
|
21
|
+
useAgentChat
|
|
23
22
|
} from "@agents24/react";
|
|
23
|
+
import * as React2 from "react";
|
|
24
|
+
|
|
25
|
+
// src/runtime/use-agent-chat-hitl.ts
|
|
26
|
+
import { useAgentMcp } from "@agents24/react";
|
|
24
27
|
import * as React from "react";
|
|
28
|
+
function detach(operation) {
|
|
29
|
+
operation.abort.abort();
|
|
30
|
+
operation.popup?.close();
|
|
31
|
+
}
|
|
32
|
+
function useAgentChatHitl(options) {
|
|
33
|
+
const mcp = useAgentMcp();
|
|
34
|
+
const latest = React.useRef(options);
|
|
35
|
+
latest.current = options;
|
|
36
|
+
const mounted = React.useRef(true);
|
|
37
|
+
const operations = React.useRef(/* @__PURE__ */ new Map());
|
|
38
|
+
const [states, setStates] = React.useState({});
|
|
39
|
+
React.useEffect(() => {
|
|
40
|
+
mounted.current = true;
|
|
41
|
+
const active = operations.current;
|
|
42
|
+
return () => {
|
|
43
|
+
mounted.current = false;
|
|
44
|
+
for (const operation of active.values()) detach(operation);
|
|
45
|
+
active.clear();
|
|
46
|
+
};
|
|
47
|
+
}, []);
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
for (const [key, operation] of operations.current) {
|
|
50
|
+
if (operation.isCurrent()) continue;
|
|
51
|
+
detach(operation);
|
|
52
|
+
operations.current.delete(key);
|
|
53
|
+
setStates((current) => {
|
|
54
|
+
const next = { ...current };
|
|
55
|
+
delete next[key];
|
|
56
|
+
return next;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
React.useEffect(() => {
|
|
61
|
+
setStates({});
|
|
62
|
+
}, [options.client, options.controller.activeThreadId]);
|
|
63
|
+
const onHitlAction = React.useCallback(async (part, response) => {
|
|
64
|
+
const captured = latest.current;
|
|
65
|
+
const { controller, client, bootstrap, selectionGeneration } = captured;
|
|
66
|
+
const key = part.interruptId || part.id;
|
|
67
|
+
if (operations.current.has(key)) return;
|
|
68
|
+
const generation = selectionGeneration.current;
|
|
69
|
+
const threadId = controller.activeThreadId;
|
|
70
|
+
const runId = controller.messages.find((message) => message.parts.includes(part))?.runId || controller.activeRunId;
|
|
71
|
+
const operation = {
|
|
72
|
+
abort: new AbortController(),
|
|
73
|
+
phase: part.hitlKind === "mcp_auth" && response.action === "connect" ? "connecting" : "resuming",
|
|
74
|
+
isCurrent() {
|
|
75
|
+
const current = latest.current;
|
|
76
|
+
return mounted.current && !operation.abort.signal.aborted && current.client === client && current.selectionGeneration.current === generation && current.controller.activeThreadId === threadId && (!current.controller.activeRunId || current.controller.activeRunId === runId) && !["cancelling", "cancelled", "failed", "completed"].includes(current.controller.runState) && (operation.phase === "resuming" || current.controller.messages.some((message) => message.runId === runId && message.parts.some((candidate) => candidate.type === "hitl" && candidate.interruptId === part.interruptId && candidate.status === "pending")));
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
if (!operation.isCurrent()) return;
|
|
80
|
+
captured.clearOperationError();
|
|
81
|
+
operations.current.set(key, operation);
|
|
82
|
+
setStates((current) => ({ ...current, [key]: { action: response.action, status: operation.phase } }));
|
|
83
|
+
try {
|
|
84
|
+
if (operation.phase === "connecting") {
|
|
85
|
+
if (!runId) throw new Error("MCP authorization is missing its paused run.");
|
|
86
|
+
if (!bootstrap) throw new Error("MCP authorization requires runtime bootstrap.");
|
|
87
|
+
if (!captured.mcpRedirectUri) throw new Error("mcpRedirectUri is required for MCP Connect.");
|
|
88
|
+
const serverId = String(part.presentation.server_id || "").trim();
|
|
89
|
+
if (!serverId) throw new Error("MCP authorization is missing its server identity.");
|
|
90
|
+
const serverEmbed = bootstrap.authentication.modes.includes("server_embed");
|
|
91
|
+
const popupNonce = browserChatCrypto().randomUUID();
|
|
92
|
+
const popup = window.open("about:blank", "agents24-mcp", "popup,width=560,height=720");
|
|
93
|
+
if (!popup) throw new Error("Allow popups to connect this MCP account.");
|
|
94
|
+
operation.popup = popup;
|
|
95
|
+
popup.document.title = "Connecting to MCP";
|
|
96
|
+
popup.document.body.textContent = "Opening secure connection\u2026";
|
|
97
|
+
const proof = await createMcpPkceProof();
|
|
98
|
+
if (!operation.isCurrent()) return;
|
|
99
|
+
const started = await mcp.startAuthorization({
|
|
100
|
+
runId,
|
|
101
|
+
serverId,
|
|
102
|
+
interruptId: part.interruptId,
|
|
103
|
+
redirectUri: captured.mcpRedirectUri,
|
|
104
|
+
popupNonce,
|
|
105
|
+
codeChallenge: proof.challenge,
|
|
106
|
+
signal: operation.abort.signal
|
|
107
|
+
});
|
|
108
|
+
if (!operation.isCurrent()) return;
|
|
109
|
+
if (!started.callback_origin) throw new Error("MCP authorization did not return a callback origin.");
|
|
110
|
+
const completionPromise = waitForMcpOauthComplete({
|
|
111
|
+
popup,
|
|
112
|
+
callbackOrigin: started.callback_origin,
|
|
113
|
+
popupNonce,
|
|
114
|
+
serverId,
|
|
115
|
+
runId,
|
|
116
|
+
interruptId: part.interruptId,
|
|
117
|
+
signal: operation.abort.signal,
|
|
118
|
+
requireConnectionId: serverEmbed || Boolean(captured.completeMcpAuthorization)
|
|
119
|
+
});
|
|
120
|
+
void completionPromise.catch(() => void 0);
|
|
121
|
+
popup.location.replace(started.authorization_url);
|
|
122
|
+
const completion = await completionPromise;
|
|
123
|
+
if (!operation.isCurrent()) return;
|
|
124
|
+
if (captured.completeMcpAuthorization) {
|
|
125
|
+
await captured.completeMcpAuthorization({ completion, codeVerifier: proof.verifier, serverId });
|
|
126
|
+
} else if (serverEmbed) {
|
|
127
|
+
validateMcpCallbackResult({ server_id: completion.serverId, connection_id: completion.connectionId || "" }, serverId);
|
|
128
|
+
} else {
|
|
129
|
+
const redeemed = await mcp.redeemCallback({
|
|
130
|
+
code: completion.code,
|
|
131
|
+
codeVerifier: proof.verifier,
|
|
132
|
+
signal: operation.abort.signal
|
|
133
|
+
});
|
|
134
|
+
if (!operation.isCurrent()) return;
|
|
135
|
+
validateMcpCallbackResult(redeemed, serverId);
|
|
136
|
+
}
|
|
137
|
+
popup.close();
|
|
138
|
+
}
|
|
139
|
+
if (!operation.isCurrent()) return;
|
|
140
|
+
operation.phase = "resuming";
|
|
141
|
+
setStates((current) => ({ ...current, [key]: { action: response.action, status: "resuming" } }));
|
|
142
|
+
await controller.resumeHitl(part, response);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (!operation.isCurrent()) return;
|
|
145
|
+
captured.onError(error);
|
|
146
|
+
setStates((current) => ({ ...current, [key]: {
|
|
147
|
+
action: response.action,
|
|
148
|
+
status: "error",
|
|
149
|
+
error: error instanceof Error ? error.message : String(error)
|
|
150
|
+
} }));
|
|
151
|
+
throw error;
|
|
152
|
+
} finally {
|
|
153
|
+
const ownsState = operation.isCurrent();
|
|
154
|
+
detach(operation);
|
|
155
|
+
if (operations.current.get(key) === operation) {
|
|
156
|
+
operations.current.delete(key);
|
|
157
|
+
if (ownsState) setStates((current) => {
|
|
158
|
+
if (current[key]?.status === "error") return current;
|
|
159
|
+
const next = { ...current };
|
|
160
|
+
delete next[key];
|
|
161
|
+
return next;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}, [mcp]);
|
|
166
|
+
return { onHitlAction, getHitlActionState: (part) => states[part.interruptId || part.id] };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/runtime/use-agent-chat-runtime.ts
|
|
25
170
|
function agentChatRuntimeStateFromError(error) {
|
|
26
171
|
const typed = error;
|
|
27
172
|
if (typed?.kind === "authentication") return "expired";
|
|
@@ -60,9 +205,6 @@ function modelsFromEffectivePolicy(policy) {
|
|
|
60
205
|
models
|
|
61
206
|
};
|
|
62
207
|
}
|
|
63
|
-
function hitlKey(part) {
|
|
64
|
-
return part.interruptId || part.id;
|
|
65
|
-
}
|
|
66
208
|
function useAgentChatRuntime(options) {
|
|
67
209
|
const {
|
|
68
210
|
activeThreadId,
|
|
@@ -78,43 +220,39 @@ function useAgentChatRuntime(options) {
|
|
|
78
220
|
activeThreadId === void 0 ? { client } : { activeThreadId, client }
|
|
79
221
|
);
|
|
80
222
|
const attachments = useAgentAttachments();
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const bootstrapRef = React.useRef(bootstrap);
|
|
223
|
+
const [bootstrap, setBootstrap] = React2.useState(null);
|
|
224
|
+
const bootstrapRef = React2.useRef(bootstrap);
|
|
84
225
|
bootstrapRef.current = bootstrap;
|
|
85
|
-
const [effectivePolicy, setEffectivePolicy] =
|
|
86
|
-
const [isBootstrapping, setIsBootstrapping] =
|
|
87
|
-
const [bootstrapError, setBootstrapError] =
|
|
88
|
-
const [localOperationError, setLocalOperationError] =
|
|
89
|
-
const [selectedModelId, setSelectedModelId] =
|
|
90
|
-
const selectedModelIdRef =
|
|
226
|
+
const [effectivePolicy, setEffectivePolicy] = React2.useState(null);
|
|
227
|
+
const [isBootstrapping, setIsBootstrapping] = React2.useState(true);
|
|
228
|
+
const [bootstrapError, setBootstrapError] = React2.useState(null);
|
|
229
|
+
const [localOperationError, setLocalOperationError] = React2.useState(null);
|
|
230
|
+
const [selectedModelId, setSelectedModelId] = React2.useState(modelId ?? null);
|
|
231
|
+
const selectedModelIdRef = React2.useRef(selectedModelId);
|
|
91
232
|
selectedModelIdRef.current = selectedModelId;
|
|
92
|
-
const [selectedAgentId, setSelectedAgentId] =
|
|
93
|
-
const selectedAgentIdRef =
|
|
233
|
+
const [selectedAgentId, setSelectedAgentId] = React2.useState(null);
|
|
234
|
+
const selectedAgentIdRef = React2.useRef(null);
|
|
94
235
|
selectedAgentIdRef.current = selectedAgentId;
|
|
95
|
-
const [isChangingAgent, setIsChangingAgent] =
|
|
96
|
-
const agentChangePromiseRef =
|
|
97
|
-
const [isSubmitting, setIsSubmitting] =
|
|
98
|
-
const submitPromiseRef =
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
hitlStatesRef.current = hitlStates;
|
|
102
|
-
const mountedRef = React.useRef(true);
|
|
103
|
-
const clientRef = React.useRef(client);
|
|
236
|
+
const [isChangingAgent, setIsChangingAgent] = React2.useState(false);
|
|
237
|
+
const agentChangePromiseRef = React2.useRef(null);
|
|
238
|
+
const [isSubmitting, setIsSubmitting] = React2.useState(false);
|
|
239
|
+
const submitPromiseRef = React2.useRef(null);
|
|
240
|
+
const mountedRef = React2.useRef(true);
|
|
241
|
+
const clientRef = React2.useRef(client);
|
|
104
242
|
clientRef.current = client;
|
|
105
|
-
const bootstrapPromiseRef =
|
|
106
|
-
|
|
243
|
+
const bootstrapPromiseRef = React2.useRef(null);
|
|
244
|
+
React2.useEffect(() => {
|
|
107
245
|
mountedRef.current = true;
|
|
108
246
|
return () => {
|
|
109
247
|
mountedRef.current = false;
|
|
110
248
|
};
|
|
111
249
|
}, []);
|
|
112
|
-
const previousControlledThreadRef =
|
|
113
|
-
const threadSelectionGenerationRef =
|
|
114
|
-
const controlledSyncTargetRef =
|
|
115
|
-
const previousControllerThreadRef =
|
|
116
|
-
const pendingThreadTransitionRef =
|
|
117
|
-
const lastReportedThreadRef =
|
|
250
|
+
const previousControlledThreadRef = React2.useRef(activeThreadId);
|
|
251
|
+
const threadSelectionGenerationRef = React2.useRef(0);
|
|
252
|
+
const controlledSyncTargetRef = React2.useRef(null);
|
|
253
|
+
const previousControllerThreadRef = React2.useRef(controller.activeThreadId);
|
|
254
|
+
const pendingThreadTransitionRef = React2.useRef(null);
|
|
255
|
+
const lastReportedThreadRef = React2.useRef(activeThreadId ?? controller.activeThreadId);
|
|
118
256
|
if (activeThreadId !== previousControlledThreadRef.current) {
|
|
119
257
|
threadSelectionGenerationRef.current += 1;
|
|
120
258
|
previousControlledThreadRef.current = activeThreadId;
|
|
@@ -123,12 +261,12 @@ function useAgentChatRuntime(options) {
|
|
|
123
261
|
lastReportedThreadRef.current = activeThreadId;
|
|
124
262
|
}
|
|
125
263
|
}
|
|
126
|
-
const reportActiveThread =
|
|
264
|
+
const reportActiveThread = React2.useCallback((threadId, reason) => {
|
|
127
265
|
if (lastReportedThreadRef.current === threadId) return;
|
|
128
266
|
lastReportedThreadRef.current = threadId;
|
|
129
267
|
onActiveThreadIdChange?.({ threadId, reason });
|
|
130
268
|
}, [onActiveThreadIdChange]);
|
|
131
|
-
const retryBootstrap =
|
|
269
|
+
const retryBootstrap = React2.useCallback(() => {
|
|
132
270
|
if (bootstrapPromiseRef.current?.client === client) return bootstrapPromiseRef.current.promise;
|
|
133
271
|
const requestClient = client;
|
|
134
272
|
const request = (async () => {
|
|
@@ -166,7 +304,7 @@ function useAgentChatRuntime(options) {
|
|
|
166
304
|
});
|
|
167
305
|
return request;
|
|
168
306
|
}, [client, controller.refreshThreads, modelId]);
|
|
169
|
-
const refreshEffectivePolicy =
|
|
307
|
+
const refreshEffectivePolicy = React2.useCallback(async () => {
|
|
170
308
|
if (bootstrap?.features.agents) {
|
|
171
309
|
const refreshed = await client.bootstrap({ agentId: selectedAgentIdRef.current || void 0 });
|
|
172
310
|
if (!mountedRef.current || clientRef.current !== client) return;
|
|
@@ -183,22 +321,18 @@ function useAgentChatRuntime(options) {
|
|
|
183
321
|
setSelectedModelId((current) => available.models.some((item) => item.id === current) ? current : available.defaultModelId);
|
|
184
322
|
}
|
|
185
323
|
}, [bootstrap, client, modelId]);
|
|
186
|
-
|
|
324
|
+
React2.useEffect(() => {
|
|
187
325
|
void retryBootstrap();
|
|
188
326
|
}, [retryBootstrap]);
|
|
189
|
-
|
|
327
|
+
React2.useEffect(() => {
|
|
190
328
|
if (modelId !== void 0) setSelectedModelId(modelId);
|
|
191
329
|
}, [modelId]);
|
|
192
|
-
|
|
193
|
-
hitlStatesRef.current = {};
|
|
194
|
-
setHitlStates({});
|
|
195
|
-
}, [client, controller.activeThreadId]);
|
|
196
|
-
React.useEffect(() => {
|
|
330
|
+
React2.useEffect(() => {
|
|
197
331
|
if (controlledSyncTargetRef.current?.value === null && controller.activeThreadId) {
|
|
198
332
|
controller.startNewThread();
|
|
199
333
|
}
|
|
200
334
|
}, [activeThreadId, controller.activeThreadId, controller.startNewThread]);
|
|
201
|
-
|
|
335
|
+
React2.useEffect(() => {
|
|
202
336
|
const previous = previousControllerThreadRef.current;
|
|
203
337
|
const current = controller.activeThreadId;
|
|
204
338
|
previousControllerThreadRef.current = current;
|
|
@@ -211,11 +345,11 @@ function useAgentChatRuntime(options) {
|
|
|
211
345
|
if (pendingTransition && current === pendingTransition.value) return;
|
|
212
346
|
if (previous === null && current !== null) reportActiveThread(current, "created");
|
|
213
347
|
}, [activeThreadId, controller.activeThreadId, reportActiveThread]);
|
|
214
|
-
const clearOperationError =
|
|
348
|
+
const clearOperationError = React2.useCallback(() => {
|
|
215
349
|
setLocalOperationError(null);
|
|
216
350
|
controller.clearOperationError();
|
|
217
351
|
}, [controller.clearOperationError]);
|
|
218
|
-
const submit =
|
|
352
|
+
const submit = React2.useCallback((input) => {
|
|
219
353
|
if (submitPromiseRef.current) return submitPromiseRef.current;
|
|
220
354
|
clearOperationError();
|
|
221
355
|
setIsSubmitting(true);
|
|
@@ -256,86 +390,24 @@ function useAgentChatRuntime(options) {
|
|
|
256
390
|
void request.then(clearRequest, clearRequest);
|
|
257
391
|
return request;
|
|
258
392
|
}, [bootstrap, clearOperationError, controller.activeThreadId, controller.submit, refreshEffectivePolicy]);
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
popup.document.body.textContent = "Opening secure connection\u2026";
|
|
271
|
-
try {
|
|
272
|
-
const started = await mcp.startAuthorization({
|
|
273
|
-
runId,
|
|
274
|
-
serverId,
|
|
275
|
-
interruptId: part.interruptId,
|
|
276
|
-
redirectUri: mcpRedirectUri,
|
|
277
|
-
popupNonce,
|
|
278
|
-
codeChallenge: proof.challenge
|
|
279
|
-
});
|
|
280
|
-
if (!started.callback_origin) throw new Error("MCP authorization did not return a callback origin.");
|
|
281
|
-
popup.location.replace(started.authorization_url);
|
|
282
|
-
const completion = await waitForMcpOauthComplete({
|
|
283
|
-
popup,
|
|
284
|
-
callbackOrigin: started.callback_origin,
|
|
285
|
-
popupNonce,
|
|
286
|
-
requireConnectionId: Boolean(completeMcpAuthorization),
|
|
287
|
-
serverId
|
|
288
|
-
});
|
|
289
|
-
if (completeMcpAuthorization) {
|
|
290
|
-
await completeMcpAuthorization({ completion, codeVerifier: proof.verifier, serverId });
|
|
291
|
-
} else {
|
|
292
|
-
const redeemed = await mcp.redeemCallback({ code: completion.code, codeVerifier: proof.verifier });
|
|
293
|
-
validateMcpCallbackResult(redeemed, serverId);
|
|
294
|
-
}
|
|
295
|
-
} finally {
|
|
296
|
-
popup.close();
|
|
297
|
-
}
|
|
298
|
-
}, [completeMcpAuthorization, controller.activeRunId, controller.messages, mcp, mcpRedirectUri]);
|
|
299
|
-
const onHitlAction = React.useCallback(async (part, response) => {
|
|
300
|
-
const action = response.action;
|
|
301
|
-
const key = hitlKey(part);
|
|
302
|
-
const current = hitlStatesRef.current[key];
|
|
303
|
-
if (current?.status === "connecting" || current?.status === "resuming") return;
|
|
304
|
-
clearOperationError();
|
|
305
|
-
const pending = {
|
|
306
|
-
action,
|
|
307
|
-
status: part.hitlKind === "mcp_auth" && action === "connect" ? "connecting" : "resuming"
|
|
308
|
-
};
|
|
309
|
-
hitlStatesRef.current = { ...hitlStatesRef.current, [key]: pending };
|
|
310
|
-
setHitlStates(hitlStatesRef.current);
|
|
311
|
-
try {
|
|
312
|
-
if (part.hitlKind === "mcp_auth" && action === "connect") await completeMcp(part);
|
|
313
|
-
await controller.resumeHitl(part, response);
|
|
314
|
-
setHitlStates((states) => {
|
|
315
|
-
const next = { ...states };
|
|
316
|
-
delete next[key];
|
|
317
|
-
hitlStatesRef.current = next;
|
|
318
|
-
return next;
|
|
319
|
-
});
|
|
320
|
-
} catch (error) {
|
|
321
|
-
setLocalOperationError(error);
|
|
322
|
-
const failedState = {
|
|
323
|
-
...hitlStatesRef.current,
|
|
324
|
-
[key]: { action, error: agentChatRuntimeErrorMessage(error), status: "error" }
|
|
325
|
-
};
|
|
326
|
-
hitlStatesRef.current = failedState;
|
|
327
|
-
setHitlStates(failedState);
|
|
328
|
-
throw error;
|
|
329
|
-
}
|
|
330
|
-
}, [clearOperationError, completeMcp, controller.resumeHitl]);
|
|
331
|
-
const newThread = React.useCallback(() => {
|
|
393
|
+
const { onHitlAction, getHitlActionState } = useAgentChatHitl({
|
|
394
|
+
client,
|
|
395
|
+
bootstrap,
|
|
396
|
+
controller,
|
|
397
|
+
selectionGeneration: threadSelectionGenerationRef,
|
|
398
|
+
completeMcpAuthorization,
|
|
399
|
+
mcpRedirectUri,
|
|
400
|
+
clearOperationError,
|
|
401
|
+
onError: setLocalOperationError
|
|
402
|
+
});
|
|
403
|
+
const newThread = React2.useCallback(() => {
|
|
332
404
|
threadSelectionGenerationRef.current += 1;
|
|
333
405
|
clearOperationError();
|
|
334
406
|
pendingThreadTransitionRef.current = null;
|
|
335
407
|
reportActiveThread(null, "new");
|
|
336
408
|
controller.startNewThread();
|
|
337
409
|
}, [clearOperationError, controller.startNewThread, reportActiveThread]);
|
|
338
|
-
const openThread =
|
|
410
|
+
const openThread = React2.useCallback(async (threadId) => {
|
|
339
411
|
const requestGeneration = ++threadSelectionGenerationRef.current;
|
|
340
412
|
clearOperationError();
|
|
341
413
|
pendingThreadTransitionRef.current = { reason: "opened", value: threadId };
|
|
@@ -365,7 +437,7 @@ function useAgentChatRuntime(options) {
|
|
|
365
437
|
if (requestGeneration === threadSelectionGenerationRef.current) pendingThreadTransitionRef.current = null;
|
|
366
438
|
}
|
|
367
439
|
}, [clearOperationError, client, controller.openThread, reportActiveThread]);
|
|
368
|
-
const deleteThread =
|
|
440
|
+
const deleteThread = React2.useCallback(async (threadId) => {
|
|
369
441
|
clearOperationError();
|
|
370
442
|
const wasActive = controller.activeThreadId === threadId;
|
|
371
443
|
if (wasActive) threadSelectionGenerationRef.current += 1;
|
|
@@ -382,7 +454,7 @@ function useAgentChatRuntime(options) {
|
|
|
382
454
|
}
|
|
383
455
|
}
|
|
384
456
|
}, [clearOperationError, controller.activeThreadId, controller.deleteThread, reportActiveThread]);
|
|
385
|
-
const changeModel =
|
|
457
|
+
const changeModel = React2.useCallback((nextModelId) => {
|
|
386
458
|
if (modelId === void 0) setSelectedModelId(nextModelId);
|
|
387
459
|
onModelChange?.(nextModelId);
|
|
388
460
|
if (controller.activeThreadId && selectedAgentId && client.threads.setRuntimeSelection) {
|
|
@@ -393,7 +465,7 @@ function useAgentChatRuntime(options) {
|
|
|
393
465
|
}).catch(setLocalOperationError);
|
|
394
466
|
}
|
|
395
467
|
}, [client.threads, controller.activeThreadId, modelId, onModelChange, selectedAgentId]);
|
|
396
|
-
const resolveAttachmentContent =
|
|
468
|
+
const resolveAttachmentContent = React2.useCallback(async (attachment, signal) => {
|
|
397
469
|
const attachmentId = typeof attachment.id === "string" ? attachment.id.trim() : "";
|
|
398
470
|
if (!attachmentId) throw new Error("Attachment content identity is unavailable.");
|
|
399
471
|
const access = await attachments.createContentAccess({
|
|
@@ -403,7 +475,7 @@ function useAgentChatRuntime(options) {
|
|
|
403
475
|
});
|
|
404
476
|
return { url: access.url, validUntil: access.valid_until || null };
|
|
405
477
|
}, [attachments.createContentAccess]);
|
|
406
|
-
const changeAgent =
|
|
478
|
+
const changeAgent = React2.useCallback((nextAgentId) => {
|
|
407
479
|
if (agentChangePromiseRef.current) return agentChangePromiseRef.current;
|
|
408
480
|
if (nextAgentId === selectedAgentIdRef.current || !canChangeAgentRuntime(controller.runState, controller.activeRunId)) return Promise.resolve();
|
|
409
481
|
clearOperationError();
|
|
@@ -470,7 +542,7 @@ function useAgentChatRuntime(options) {
|
|
|
470
542
|
deleteThread,
|
|
471
543
|
errorMessage: agentChatRuntimeErrorMessage(fatalError || operationError),
|
|
472
544
|
fatalError,
|
|
473
|
-
getHitlActionState
|
|
545
|
+
getHitlActionState,
|
|
474
546
|
isBootstrapping,
|
|
475
547
|
isChangingAgent,
|
|
476
548
|
isSubmitting: isSubmitting || controller.isSubmitting,
|
|
@@ -489,11 +561,11 @@ function useAgentChatRuntime(options) {
|
|
|
489
561
|
}
|
|
490
562
|
|
|
491
563
|
// src/runtime/use-delegation-tasks.ts
|
|
492
|
-
import * as
|
|
564
|
+
import * as React3 from "react";
|
|
493
565
|
function useDelegationTasks({ threadId, source, pollIntervalMs = 2e3 }) {
|
|
494
|
-
const [state, setState] =
|
|
495
|
-
const [revision, refresh] =
|
|
496
|
-
|
|
566
|
+
const [state, setState] = React3.useState({ threadId: null, tasks: [], error: null, loading: false });
|
|
567
|
+
const [revision, refresh] = React3.useReducer((value) => value + 1, 0);
|
|
568
|
+
React3.useEffect(() => {
|
|
497
569
|
if (!threadId) {
|
|
498
570
|
setState({ threadId: null, tasks: [], error: null, loading: false });
|
|
499
571
|
return;
|