@agents24/chat-react 0.5.33 → 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/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.cjs
CHANGED
|
@@ -49,6 +49,10 @@ __export(runtime_exports, {
|
|
|
49
49
|
module.exports = __toCommonJS(runtime_exports);
|
|
50
50
|
|
|
51
51
|
// src/runtime/use-agent-chat-runtime.ts
|
|
52
|
+
var import_react2 = require("@agents24/react");
|
|
53
|
+
var React2 = __toESM(require("react"), 1);
|
|
54
|
+
|
|
55
|
+
// src/runtime/use-agent-chat-hitl.ts
|
|
52
56
|
var import_react = require("@agents24/react");
|
|
53
57
|
var React = __toESM(require("react"), 1);
|
|
54
58
|
|
|
@@ -106,6 +110,9 @@ function waitForMcpOauthComplete({
|
|
|
106
110
|
popupNonce,
|
|
107
111
|
requireConnectionId = false,
|
|
108
112
|
serverId,
|
|
113
|
+
runId,
|
|
114
|
+
interruptId,
|
|
115
|
+
signal,
|
|
109
116
|
timeoutMs = 12e4
|
|
110
117
|
}) {
|
|
111
118
|
if (!popup) return Promise.reject(new Error("Could not open the MCP authorization popup."));
|
|
@@ -114,6 +121,8 @@ function waitForMcpOauthComplete({
|
|
|
114
121
|
const expectedPopupNonce = String(popupNonce || "").trim();
|
|
115
122
|
if (!expectedServerId) return Promise.reject(new Error("MCP authorization is missing its server identity."));
|
|
116
123
|
if (!expectedPopupNonce) return Promise.reject(new Error("MCP authorization is missing its popup binding."));
|
|
124
|
+
const aborted = () => new DOMException("MCP authorization detached.", "AbortError");
|
|
125
|
+
if (signal?.aborted) return Promise.reject(aborted());
|
|
117
126
|
const returnFocusTo = typeof document !== "undefined" ? document.activeElement : null;
|
|
118
127
|
return new Promise((resolve, reject) => {
|
|
119
128
|
let settled = false;
|
|
@@ -123,14 +132,20 @@ function waitForMcpOauthComplete({
|
|
|
123
132
|
window.clearTimeout(timeout);
|
|
124
133
|
window.clearInterval(closeTimer);
|
|
125
134
|
window.removeEventListener("message", onMessage);
|
|
126
|
-
|
|
135
|
+
signal?.removeEventListener("abort", onAbort);
|
|
136
|
+
if (!signal?.aborted) returnFocusTo?.focus?.();
|
|
127
137
|
if (result instanceof Error) reject(result);
|
|
128
138
|
else resolve(result);
|
|
129
139
|
};
|
|
140
|
+
const onAbort = () => finish(aborted());
|
|
130
141
|
const onMessage = (event) => {
|
|
131
142
|
if (event.source !== popup || event.origin !== expectedOrigin) return;
|
|
132
143
|
const data = event.data;
|
|
133
|
-
if (data?.type !== "agents24.mcp.callback" || data.server_id !== expectedServerId || data.popup_nonce !== expectedPopupNonce) return;
|
|
144
|
+
if (data?.type !== "agents24.mcp.callback" || data.server_id !== expectedServerId || data.popup_nonce !== expectedPopupNonce || runId !== void 0 && data.run_id !== runId || interruptId !== void 0 && data.interrupt_id !== interruptId) return;
|
|
145
|
+
if (data.success === false) {
|
|
146
|
+
finish(new Error("MCP authorization could not be completed."));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
134
149
|
const code = String(data.code || "").trim();
|
|
135
150
|
if (!code || code.length > 2048) return;
|
|
136
151
|
const connectionId = String(data.connection_id || "").trim();
|
|
@@ -150,9 +165,152 @@ function waitForMcpOauthComplete({
|
|
|
150
165
|
if (popup.closed) finish(new Error("MCP authorization window was closed before connecting."));
|
|
151
166
|
}, 500);
|
|
152
167
|
window.addEventListener("message", onMessage);
|
|
168
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
153
169
|
});
|
|
154
170
|
}
|
|
155
171
|
|
|
172
|
+
// src/runtime/use-agent-chat-hitl.ts
|
|
173
|
+
function detach(operation) {
|
|
174
|
+
operation.abort.abort();
|
|
175
|
+
operation.popup?.close();
|
|
176
|
+
}
|
|
177
|
+
function useAgentChatHitl(options) {
|
|
178
|
+
const mcp = (0, import_react.useAgentMcp)();
|
|
179
|
+
const latest = React.useRef(options);
|
|
180
|
+
latest.current = options;
|
|
181
|
+
const mounted = React.useRef(true);
|
|
182
|
+
const operations = React.useRef(/* @__PURE__ */ new Map());
|
|
183
|
+
const [states, setStates] = React.useState({});
|
|
184
|
+
React.useEffect(() => {
|
|
185
|
+
mounted.current = true;
|
|
186
|
+
const active = operations.current;
|
|
187
|
+
return () => {
|
|
188
|
+
mounted.current = false;
|
|
189
|
+
for (const operation of active.values()) detach(operation);
|
|
190
|
+
active.clear();
|
|
191
|
+
};
|
|
192
|
+
}, []);
|
|
193
|
+
React.useEffect(() => {
|
|
194
|
+
for (const [key, operation] of operations.current) {
|
|
195
|
+
if (operation.isCurrent()) continue;
|
|
196
|
+
detach(operation);
|
|
197
|
+
operations.current.delete(key);
|
|
198
|
+
setStates((current) => {
|
|
199
|
+
const next = { ...current };
|
|
200
|
+
delete next[key];
|
|
201
|
+
return next;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
React.useEffect(() => {
|
|
206
|
+
setStates({});
|
|
207
|
+
}, [options.client, options.controller.activeThreadId]);
|
|
208
|
+
const onHitlAction = React.useCallback(async (part, response) => {
|
|
209
|
+
const captured = latest.current;
|
|
210
|
+
const { controller, client, bootstrap, selectionGeneration } = captured;
|
|
211
|
+
const key = part.interruptId || part.id;
|
|
212
|
+
if (operations.current.has(key)) return;
|
|
213
|
+
const generation = selectionGeneration.current;
|
|
214
|
+
const threadId = controller.activeThreadId;
|
|
215
|
+
const runId = controller.messages.find((message) => message.parts.includes(part))?.runId || controller.activeRunId;
|
|
216
|
+
const operation = {
|
|
217
|
+
abort: new AbortController(),
|
|
218
|
+
phase: part.hitlKind === "mcp_auth" && response.action === "connect" ? "connecting" : "resuming",
|
|
219
|
+
isCurrent() {
|
|
220
|
+
const current = latest.current;
|
|
221
|
+
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")));
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
if (!operation.isCurrent()) return;
|
|
225
|
+
captured.clearOperationError();
|
|
226
|
+
operations.current.set(key, operation);
|
|
227
|
+
setStates((current) => ({ ...current, [key]: { action: response.action, status: operation.phase } }));
|
|
228
|
+
try {
|
|
229
|
+
if (operation.phase === "connecting") {
|
|
230
|
+
if (!runId) throw new Error("MCP authorization is missing its paused run.");
|
|
231
|
+
if (!bootstrap) throw new Error("MCP authorization requires runtime bootstrap.");
|
|
232
|
+
if (!captured.mcpRedirectUri) throw new Error("mcpRedirectUri is required for MCP Connect.");
|
|
233
|
+
const serverId = String(part.presentation.server_id || "").trim();
|
|
234
|
+
if (!serverId) throw new Error("MCP authorization is missing its server identity.");
|
|
235
|
+
const serverEmbed = bootstrap.authentication.modes.includes("server_embed");
|
|
236
|
+
const popupNonce = browserChatCrypto().randomUUID();
|
|
237
|
+
const popup = window.open("about:blank", "agents24-mcp", "popup,width=560,height=720");
|
|
238
|
+
if (!popup) throw new Error("Allow popups to connect this MCP account.");
|
|
239
|
+
operation.popup = popup;
|
|
240
|
+
popup.document.title = "Connecting to MCP";
|
|
241
|
+
popup.document.body.textContent = "Opening secure connection\u2026";
|
|
242
|
+
const proof = await createMcpPkceProof();
|
|
243
|
+
if (!operation.isCurrent()) return;
|
|
244
|
+
const started = await mcp.startAuthorization({
|
|
245
|
+
runId,
|
|
246
|
+
serverId,
|
|
247
|
+
interruptId: part.interruptId,
|
|
248
|
+
redirectUri: captured.mcpRedirectUri,
|
|
249
|
+
popupNonce,
|
|
250
|
+
codeChallenge: proof.challenge,
|
|
251
|
+
signal: operation.abort.signal
|
|
252
|
+
});
|
|
253
|
+
if (!operation.isCurrent()) return;
|
|
254
|
+
if (!started.callback_origin) throw new Error("MCP authorization did not return a callback origin.");
|
|
255
|
+
const completionPromise = waitForMcpOauthComplete({
|
|
256
|
+
popup,
|
|
257
|
+
callbackOrigin: started.callback_origin,
|
|
258
|
+
popupNonce,
|
|
259
|
+
serverId,
|
|
260
|
+
runId,
|
|
261
|
+
interruptId: part.interruptId,
|
|
262
|
+
signal: operation.abort.signal,
|
|
263
|
+
requireConnectionId: serverEmbed || Boolean(captured.completeMcpAuthorization)
|
|
264
|
+
});
|
|
265
|
+
void completionPromise.catch(() => void 0);
|
|
266
|
+
popup.location.replace(started.authorization_url);
|
|
267
|
+
const completion = await completionPromise;
|
|
268
|
+
if (!operation.isCurrent()) return;
|
|
269
|
+
if (captured.completeMcpAuthorization) {
|
|
270
|
+
await captured.completeMcpAuthorization({ completion, codeVerifier: proof.verifier, serverId });
|
|
271
|
+
} else if (serverEmbed) {
|
|
272
|
+
validateMcpCallbackResult({ server_id: completion.serverId, connection_id: completion.connectionId || "" }, serverId);
|
|
273
|
+
} else {
|
|
274
|
+
const redeemed = await mcp.redeemCallback({
|
|
275
|
+
code: completion.code,
|
|
276
|
+
codeVerifier: proof.verifier,
|
|
277
|
+
signal: operation.abort.signal
|
|
278
|
+
});
|
|
279
|
+
if (!operation.isCurrent()) return;
|
|
280
|
+
validateMcpCallbackResult(redeemed, serverId);
|
|
281
|
+
}
|
|
282
|
+
popup.close();
|
|
283
|
+
}
|
|
284
|
+
if (!operation.isCurrent()) return;
|
|
285
|
+
operation.phase = "resuming";
|
|
286
|
+
setStates((current) => ({ ...current, [key]: { action: response.action, status: "resuming" } }));
|
|
287
|
+
await controller.resumeHitl(part, response);
|
|
288
|
+
} catch (error) {
|
|
289
|
+
if (!operation.isCurrent()) return;
|
|
290
|
+
captured.onError(error);
|
|
291
|
+
setStates((current) => ({ ...current, [key]: {
|
|
292
|
+
action: response.action,
|
|
293
|
+
status: "error",
|
|
294
|
+
error: error instanceof Error ? error.message : String(error)
|
|
295
|
+
} }));
|
|
296
|
+
throw error;
|
|
297
|
+
} finally {
|
|
298
|
+
const ownsState = operation.isCurrent();
|
|
299
|
+
detach(operation);
|
|
300
|
+
if (operations.current.get(key) === operation) {
|
|
301
|
+
operations.current.delete(key);
|
|
302
|
+
if (ownsState) setStates((current) => {
|
|
303
|
+
if (current[key]?.status === "error") return current;
|
|
304
|
+
const next = { ...current };
|
|
305
|
+
delete next[key];
|
|
306
|
+
return next;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}, [mcp]);
|
|
311
|
+
return { onHitlAction, getHitlActionState: (part) => states[part.interruptId || part.id] };
|
|
312
|
+
}
|
|
313
|
+
|
|
156
314
|
// src/runtime/input-contract.ts
|
|
157
315
|
var import_client = require("@agents24/client");
|
|
158
316
|
var import_client2 = require("@agents24/client");
|
|
@@ -267,9 +425,6 @@ function modelsFromEffectivePolicy(policy) {
|
|
|
267
425
|
models
|
|
268
426
|
};
|
|
269
427
|
}
|
|
270
|
-
function hitlKey(part) {
|
|
271
|
-
return part.interruptId || part.id;
|
|
272
|
-
}
|
|
273
428
|
function useAgentChatRuntime(options) {
|
|
274
429
|
const {
|
|
275
430
|
activeThreadId,
|
|
@@ -281,47 +436,43 @@ function useAgentChatRuntime(options) {
|
|
|
281
436
|
onActiveThreadIdChange,
|
|
282
437
|
onModelChange
|
|
283
438
|
} = options;
|
|
284
|
-
const controller = (0,
|
|
439
|
+
const controller = (0, import_react2.useAgentChat)(
|
|
285
440
|
activeThreadId === void 0 ? { client } : { activeThreadId, client }
|
|
286
441
|
);
|
|
287
|
-
const attachments = (0,
|
|
288
|
-
const
|
|
289
|
-
const
|
|
290
|
-
const bootstrapRef = React.useRef(bootstrap);
|
|
442
|
+
const attachments = (0, import_react2.useAgentAttachments)();
|
|
443
|
+
const [bootstrap, setBootstrap] = React2.useState(null);
|
|
444
|
+
const bootstrapRef = React2.useRef(bootstrap);
|
|
291
445
|
bootstrapRef.current = bootstrap;
|
|
292
|
-
const [effectivePolicy, setEffectivePolicy] =
|
|
293
|
-
const [isBootstrapping, setIsBootstrapping] =
|
|
294
|
-
const [bootstrapError, setBootstrapError] =
|
|
295
|
-
const [localOperationError, setLocalOperationError] =
|
|
296
|
-
const [selectedModelId, setSelectedModelId] =
|
|
297
|
-
const selectedModelIdRef =
|
|
446
|
+
const [effectivePolicy, setEffectivePolicy] = React2.useState(null);
|
|
447
|
+
const [isBootstrapping, setIsBootstrapping] = React2.useState(true);
|
|
448
|
+
const [bootstrapError, setBootstrapError] = React2.useState(null);
|
|
449
|
+
const [localOperationError, setLocalOperationError] = React2.useState(null);
|
|
450
|
+
const [selectedModelId, setSelectedModelId] = React2.useState(modelId ?? null);
|
|
451
|
+
const selectedModelIdRef = React2.useRef(selectedModelId);
|
|
298
452
|
selectedModelIdRef.current = selectedModelId;
|
|
299
|
-
const [selectedAgentId, setSelectedAgentId] =
|
|
300
|
-
const selectedAgentIdRef =
|
|
453
|
+
const [selectedAgentId, setSelectedAgentId] = React2.useState(null);
|
|
454
|
+
const selectedAgentIdRef = React2.useRef(null);
|
|
301
455
|
selectedAgentIdRef.current = selectedAgentId;
|
|
302
|
-
const [isChangingAgent, setIsChangingAgent] =
|
|
303
|
-
const agentChangePromiseRef =
|
|
304
|
-
const [isSubmitting, setIsSubmitting] =
|
|
305
|
-
const submitPromiseRef =
|
|
306
|
-
const
|
|
307
|
-
const
|
|
308
|
-
hitlStatesRef.current = hitlStates;
|
|
309
|
-
const mountedRef = React.useRef(true);
|
|
310
|
-
const clientRef = React.useRef(client);
|
|
456
|
+
const [isChangingAgent, setIsChangingAgent] = React2.useState(false);
|
|
457
|
+
const agentChangePromiseRef = React2.useRef(null);
|
|
458
|
+
const [isSubmitting, setIsSubmitting] = React2.useState(false);
|
|
459
|
+
const submitPromiseRef = React2.useRef(null);
|
|
460
|
+
const mountedRef = React2.useRef(true);
|
|
461
|
+
const clientRef = React2.useRef(client);
|
|
311
462
|
clientRef.current = client;
|
|
312
|
-
const bootstrapPromiseRef =
|
|
313
|
-
|
|
463
|
+
const bootstrapPromiseRef = React2.useRef(null);
|
|
464
|
+
React2.useEffect(() => {
|
|
314
465
|
mountedRef.current = true;
|
|
315
466
|
return () => {
|
|
316
467
|
mountedRef.current = false;
|
|
317
468
|
};
|
|
318
469
|
}, []);
|
|
319
|
-
const previousControlledThreadRef =
|
|
320
|
-
const threadSelectionGenerationRef =
|
|
321
|
-
const controlledSyncTargetRef =
|
|
322
|
-
const previousControllerThreadRef =
|
|
323
|
-
const pendingThreadTransitionRef =
|
|
324
|
-
const lastReportedThreadRef =
|
|
470
|
+
const previousControlledThreadRef = React2.useRef(activeThreadId);
|
|
471
|
+
const threadSelectionGenerationRef = React2.useRef(0);
|
|
472
|
+
const controlledSyncTargetRef = React2.useRef(null);
|
|
473
|
+
const previousControllerThreadRef = React2.useRef(controller.activeThreadId);
|
|
474
|
+
const pendingThreadTransitionRef = React2.useRef(null);
|
|
475
|
+
const lastReportedThreadRef = React2.useRef(activeThreadId ?? controller.activeThreadId);
|
|
325
476
|
if (activeThreadId !== previousControlledThreadRef.current) {
|
|
326
477
|
threadSelectionGenerationRef.current += 1;
|
|
327
478
|
previousControlledThreadRef.current = activeThreadId;
|
|
@@ -330,12 +481,12 @@ function useAgentChatRuntime(options) {
|
|
|
330
481
|
lastReportedThreadRef.current = activeThreadId;
|
|
331
482
|
}
|
|
332
483
|
}
|
|
333
|
-
const reportActiveThread =
|
|
484
|
+
const reportActiveThread = React2.useCallback((threadId, reason) => {
|
|
334
485
|
if (lastReportedThreadRef.current === threadId) return;
|
|
335
486
|
lastReportedThreadRef.current = threadId;
|
|
336
487
|
onActiveThreadIdChange?.({ threadId, reason });
|
|
337
488
|
}, [onActiveThreadIdChange]);
|
|
338
|
-
const retryBootstrap =
|
|
489
|
+
const retryBootstrap = React2.useCallback(() => {
|
|
339
490
|
if (bootstrapPromiseRef.current?.client === client) return bootstrapPromiseRef.current.promise;
|
|
340
491
|
const requestClient = client;
|
|
341
492
|
const request = (async () => {
|
|
@@ -373,7 +524,7 @@ function useAgentChatRuntime(options) {
|
|
|
373
524
|
});
|
|
374
525
|
return request;
|
|
375
526
|
}, [client, controller.refreshThreads, modelId]);
|
|
376
|
-
const refreshEffectivePolicy =
|
|
527
|
+
const refreshEffectivePolicy = React2.useCallback(async () => {
|
|
377
528
|
if (bootstrap?.features.agents) {
|
|
378
529
|
const refreshed = await client.bootstrap({ agentId: selectedAgentIdRef.current || void 0 });
|
|
379
530
|
if (!mountedRef.current || clientRef.current !== client) return;
|
|
@@ -390,22 +541,18 @@ function useAgentChatRuntime(options) {
|
|
|
390
541
|
setSelectedModelId((current) => available.models.some((item) => item.id === current) ? current : available.defaultModelId);
|
|
391
542
|
}
|
|
392
543
|
}, [bootstrap, client, modelId]);
|
|
393
|
-
|
|
544
|
+
React2.useEffect(() => {
|
|
394
545
|
void retryBootstrap();
|
|
395
546
|
}, [retryBootstrap]);
|
|
396
|
-
|
|
547
|
+
React2.useEffect(() => {
|
|
397
548
|
if (modelId !== void 0) setSelectedModelId(modelId);
|
|
398
549
|
}, [modelId]);
|
|
399
|
-
|
|
400
|
-
hitlStatesRef.current = {};
|
|
401
|
-
setHitlStates({});
|
|
402
|
-
}, [client, controller.activeThreadId]);
|
|
403
|
-
React.useEffect(() => {
|
|
550
|
+
React2.useEffect(() => {
|
|
404
551
|
if (controlledSyncTargetRef.current?.value === null && controller.activeThreadId) {
|
|
405
552
|
controller.startNewThread();
|
|
406
553
|
}
|
|
407
554
|
}, [activeThreadId, controller.activeThreadId, controller.startNewThread]);
|
|
408
|
-
|
|
555
|
+
React2.useEffect(() => {
|
|
409
556
|
const previous = previousControllerThreadRef.current;
|
|
410
557
|
const current = controller.activeThreadId;
|
|
411
558
|
previousControllerThreadRef.current = current;
|
|
@@ -418,11 +565,11 @@ function useAgentChatRuntime(options) {
|
|
|
418
565
|
if (pendingTransition && current === pendingTransition.value) return;
|
|
419
566
|
if (previous === null && current !== null) reportActiveThread(current, "created");
|
|
420
567
|
}, [activeThreadId, controller.activeThreadId, reportActiveThread]);
|
|
421
|
-
const clearOperationError =
|
|
568
|
+
const clearOperationError = React2.useCallback(() => {
|
|
422
569
|
setLocalOperationError(null);
|
|
423
570
|
controller.clearOperationError();
|
|
424
571
|
}, [controller.clearOperationError]);
|
|
425
|
-
const submit =
|
|
572
|
+
const submit = React2.useCallback((input) => {
|
|
426
573
|
if (submitPromiseRef.current) return submitPromiseRef.current;
|
|
427
574
|
clearOperationError();
|
|
428
575
|
setIsSubmitting(true);
|
|
@@ -463,86 +610,24 @@ function useAgentChatRuntime(options) {
|
|
|
463
610
|
void request.then(clearRequest, clearRequest);
|
|
464
611
|
return request;
|
|
465
612
|
}, [bootstrap, clearOperationError, controller.activeThreadId, controller.submit, refreshEffectivePolicy]);
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
popup.document.body.textContent = "Opening secure connection\u2026";
|
|
478
|
-
try {
|
|
479
|
-
const started = await mcp.startAuthorization({
|
|
480
|
-
runId,
|
|
481
|
-
serverId,
|
|
482
|
-
interruptId: part.interruptId,
|
|
483
|
-
redirectUri: mcpRedirectUri,
|
|
484
|
-
popupNonce,
|
|
485
|
-
codeChallenge: proof.challenge
|
|
486
|
-
});
|
|
487
|
-
if (!started.callback_origin) throw new Error("MCP authorization did not return a callback origin.");
|
|
488
|
-
popup.location.replace(started.authorization_url);
|
|
489
|
-
const completion = await waitForMcpOauthComplete({
|
|
490
|
-
popup,
|
|
491
|
-
callbackOrigin: started.callback_origin,
|
|
492
|
-
popupNonce,
|
|
493
|
-
requireConnectionId: Boolean(completeMcpAuthorization),
|
|
494
|
-
serverId
|
|
495
|
-
});
|
|
496
|
-
if (completeMcpAuthorization) {
|
|
497
|
-
await completeMcpAuthorization({ completion, codeVerifier: proof.verifier, serverId });
|
|
498
|
-
} else {
|
|
499
|
-
const redeemed = await mcp.redeemCallback({ code: completion.code, codeVerifier: proof.verifier });
|
|
500
|
-
validateMcpCallbackResult(redeemed, serverId);
|
|
501
|
-
}
|
|
502
|
-
} finally {
|
|
503
|
-
popup.close();
|
|
504
|
-
}
|
|
505
|
-
}, [completeMcpAuthorization, controller.activeRunId, controller.messages, mcp, mcpRedirectUri]);
|
|
506
|
-
const onHitlAction = React.useCallback(async (part, response) => {
|
|
507
|
-
const action = response.action;
|
|
508
|
-
const key = hitlKey(part);
|
|
509
|
-
const current = hitlStatesRef.current[key];
|
|
510
|
-
if (current?.status === "connecting" || current?.status === "resuming") return;
|
|
511
|
-
clearOperationError();
|
|
512
|
-
const pending = {
|
|
513
|
-
action,
|
|
514
|
-
status: part.hitlKind === "mcp_auth" && action === "connect" ? "connecting" : "resuming"
|
|
515
|
-
};
|
|
516
|
-
hitlStatesRef.current = { ...hitlStatesRef.current, [key]: pending };
|
|
517
|
-
setHitlStates(hitlStatesRef.current);
|
|
518
|
-
try {
|
|
519
|
-
if (part.hitlKind === "mcp_auth" && action === "connect") await completeMcp(part);
|
|
520
|
-
await controller.resumeHitl(part, response);
|
|
521
|
-
setHitlStates((states) => {
|
|
522
|
-
const next = { ...states };
|
|
523
|
-
delete next[key];
|
|
524
|
-
hitlStatesRef.current = next;
|
|
525
|
-
return next;
|
|
526
|
-
});
|
|
527
|
-
} catch (error) {
|
|
528
|
-
setLocalOperationError(error);
|
|
529
|
-
const failedState = {
|
|
530
|
-
...hitlStatesRef.current,
|
|
531
|
-
[key]: { action, error: agentChatRuntimeErrorMessage(error), status: "error" }
|
|
532
|
-
};
|
|
533
|
-
hitlStatesRef.current = failedState;
|
|
534
|
-
setHitlStates(failedState);
|
|
535
|
-
throw error;
|
|
536
|
-
}
|
|
537
|
-
}, [clearOperationError, completeMcp, controller.resumeHitl]);
|
|
538
|
-
const newThread = React.useCallback(() => {
|
|
613
|
+
const { onHitlAction, getHitlActionState } = useAgentChatHitl({
|
|
614
|
+
client,
|
|
615
|
+
bootstrap,
|
|
616
|
+
controller,
|
|
617
|
+
selectionGeneration: threadSelectionGenerationRef,
|
|
618
|
+
completeMcpAuthorization,
|
|
619
|
+
mcpRedirectUri,
|
|
620
|
+
clearOperationError,
|
|
621
|
+
onError: setLocalOperationError
|
|
622
|
+
});
|
|
623
|
+
const newThread = React2.useCallback(() => {
|
|
539
624
|
threadSelectionGenerationRef.current += 1;
|
|
540
625
|
clearOperationError();
|
|
541
626
|
pendingThreadTransitionRef.current = null;
|
|
542
627
|
reportActiveThread(null, "new");
|
|
543
628
|
controller.startNewThread();
|
|
544
629
|
}, [clearOperationError, controller.startNewThread, reportActiveThread]);
|
|
545
|
-
const openThread =
|
|
630
|
+
const openThread = React2.useCallback(async (threadId) => {
|
|
546
631
|
const requestGeneration = ++threadSelectionGenerationRef.current;
|
|
547
632
|
clearOperationError();
|
|
548
633
|
pendingThreadTransitionRef.current = { reason: "opened", value: threadId };
|
|
@@ -572,7 +657,7 @@ function useAgentChatRuntime(options) {
|
|
|
572
657
|
if (requestGeneration === threadSelectionGenerationRef.current) pendingThreadTransitionRef.current = null;
|
|
573
658
|
}
|
|
574
659
|
}, [clearOperationError, client, controller.openThread, reportActiveThread]);
|
|
575
|
-
const deleteThread =
|
|
660
|
+
const deleteThread = React2.useCallback(async (threadId) => {
|
|
576
661
|
clearOperationError();
|
|
577
662
|
const wasActive = controller.activeThreadId === threadId;
|
|
578
663
|
if (wasActive) threadSelectionGenerationRef.current += 1;
|
|
@@ -589,7 +674,7 @@ function useAgentChatRuntime(options) {
|
|
|
589
674
|
}
|
|
590
675
|
}
|
|
591
676
|
}, [clearOperationError, controller.activeThreadId, controller.deleteThread, reportActiveThread]);
|
|
592
|
-
const changeModel =
|
|
677
|
+
const changeModel = React2.useCallback((nextModelId) => {
|
|
593
678
|
if (modelId === void 0) setSelectedModelId(nextModelId);
|
|
594
679
|
onModelChange?.(nextModelId);
|
|
595
680
|
if (controller.activeThreadId && selectedAgentId && client.threads.setRuntimeSelection) {
|
|
@@ -600,7 +685,7 @@ function useAgentChatRuntime(options) {
|
|
|
600
685
|
}).catch(setLocalOperationError);
|
|
601
686
|
}
|
|
602
687
|
}, [client.threads, controller.activeThreadId, modelId, onModelChange, selectedAgentId]);
|
|
603
|
-
const resolveAttachmentContent =
|
|
688
|
+
const resolveAttachmentContent = React2.useCallback(async (attachment, signal) => {
|
|
604
689
|
const attachmentId = typeof attachment.id === "string" ? attachment.id.trim() : "";
|
|
605
690
|
if (!attachmentId) throw new Error("Attachment content identity is unavailable.");
|
|
606
691
|
const access = await attachments.createContentAccess({
|
|
@@ -610,7 +695,7 @@ function useAgentChatRuntime(options) {
|
|
|
610
695
|
});
|
|
611
696
|
return { url: access.url, validUntil: access.valid_until || null };
|
|
612
697
|
}, [attachments.createContentAccess]);
|
|
613
|
-
const changeAgent =
|
|
698
|
+
const changeAgent = React2.useCallback((nextAgentId) => {
|
|
614
699
|
if (agentChangePromiseRef.current) return agentChangePromiseRef.current;
|
|
615
700
|
if (nextAgentId === selectedAgentIdRef.current || !canChangeAgentRuntime(controller.runState, controller.activeRunId)) return Promise.resolve();
|
|
616
701
|
clearOperationError();
|
|
@@ -677,7 +762,7 @@ function useAgentChatRuntime(options) {
|
|
|
677
762
|
deleteThread,
|
|
678
763
|
errorMessage: agentChatRuntimeErrorMessage(fatalError || operationError),
|
|
679
764
|
fatalError,
|
|
680
|
-
getHitlActionState
|
|
765
|
+
getHitlActionState,
|
|
681
766
|
isBootstrapping,
|
|
682
767
|
isChangingAgent,
|
|
683
768
|
isSubmitting: isSubmitting || controller.isSubmitting,
|
|
@@ -696,11 +781,11 @@ function useAgentChatRuntime(options) {
|
|
|
696
781
|
}
|
|
697
782
|
|
|
698
783
|
// src/runtime/use-delegation-tasks.ts
|
|
699
|
-
var
|
|
784
|
+
var React3 = __toESM(require("react"), 1);
|
|
700
785
|
function useDelegationTasks({ threadId, source, pollIntervalMs = 2e3 }) {
|
|
701
|
-
const [state, setState] =
|
|
702
|
-
const [revision, refresh] =
|
|
703
|
-
|
|
786
|
+
const [state, setState] = React3.useState({ threadId: null, tasks: [], error: null, loading: false });
|
|
787
|
+
const [revision, refresh] = React3.useReducer((value) => value + 1, 0);
|
|
788
|
+
React3.useEffect(() => {
|
|
704
789
|
if (!threadId) {
|
|
705
790
|
setState({ threadId: null, tasks: [], error: null, loading: false });
|
|
706
791
|
return;
|