@copilotkit/core 1.55.0-next.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,3321 @@
1
+ import { AbstractAgent, EventType, HttpAgent, randomUUID, runHttpRequest, structuredClone_, transformChunks, transformHttpEventStream } from "@ag-ui/client";
2
+ import { RUNTIME_MODE_INTELLIGENCE, RUNTIME_MODE_SSE, logger, partialJSONParse, phoenixExponentialBackoff, randomUUID as randomUUID$1, schemaToJsonSchema } from "@copilotkit/shared";
3
+ import { BehaviorSubject, EMPTY, NEVER, Notification, Observable, Subject, Subscription, asapScheduler, concat, defer, dematerialize, firstValueFrom, from, lastValueFrom, merge, of, switchMap, throwError } from "rxjs";
4
+ import { catchError, distinctUntilChanged, endWith, filter, finalize, ignoreElements, map, mergeMap, observeOn, scan, share, shareReplay, switchMap as switchMap$1, take, takeUntil, tap, timeout, withLatestFrom } from "rxjs/operators";
5
+ import { Socket } from "phoenix";
6
+ import { zodToJsonSchema } from "zod-to-json-schema";
7
+ import { fromFetch } from "rxjs/fetch";
8
+
9
+ //#region src/utils/phoenix-observable.ts
10
+ /**
11
+ * Adapt Phoenix socket open/error callbacks into an observable signal stream.
12
+ *
13
+ * The returned observable is shared and replayable by the caller when needed,
14
+ * but this helper itself does not own socket connection teardown.
15
+ */
16
+ function ɵcreatePhoenixSocketSignals$(socket) {
17
+ return new Observable((observer) => {
18
+ socket.onOpen(() => observer.next({ type: "open" }));
19
+ socket.onError((error) => observer.next({
20
+ type: "error",
21
+ error
22
+ }));
23
+ });
24
+ }
25
+ /**
26
+ * Adapt a Phoenix channel join attempt into a single-outcome observable.
27
+ */
28
+ function ɵcreatePhoenixJoinOutcome$(channel) {
29
+ return new Observable((observer) => {
30
+ channel.join().receive("ok", () => {
31
+ observer.next({ type: "joined" });
32
+ observer.complete();
33
+ }).receive("error", (response) => {
34
+ observer.next({
35
+ type: "error",
36
+ response
37
+ });
38
+ observer.complete();
39
+ }).receive("timeout", () => {
40
+ observer.next({ type: "timeout" });
41
+ observer.complete();
42
+ });
43
+ });
44
+ }
45
+ /**
46
+ * Create a cold Phoenix socket session.
47
+ *
48
+ * The socket is constructed and connected on subscription, and disconnected on
49
+ * teardown. Each subscription creates an isolated socket instance.
50
+ */
51
+ function ɵphoenixSocket$(options) {
52
+ return defer(() => {
53
+ const socket = new Socket(options.url, options.options);
54
+ const signals$ = ɵcreatePhoenixSocketSignals$(socket).pipe(shareReplay({
55
+ bufferSize: 1,
56
+ refCount: true
57
+ }));
58
+ socket.connect();
59
+ return concat(of({
60
+ socket,
61
+ signals$
62
+ }), NEVER).pipe(finalize(() => socket.disconnect()));
63
+ });
64
+ }
65
+ /**
66
+ * Create a cold Phoenix channel session from a socket session stream.
67
+ *
68
+ * A channel is created and joined for each active socket session. If the
69
+ * upstream socket session changes, the previous channel is left before the
70
+ * next one becomes active.
71
+ */
72
+ function ɵphoenixChannel$(options) {
73
+ return options.socket$.pipe(switchMap$1(({ socket }) => defer(() => {
74
+ const channel = socket.channel(options.topic, options.params);
75
+ return concat(of({
76
+ channel,
77
+ joinOutcome$: ɵcreatePhoenixJoinOutcome$(channel).pipe(shareReplay({
78
+ bufferSize: 1,
79
+ refCount: true
80
+ }))
81
+ }), NEVER).pipe(finalize(() => {
82
+ if (options.leaveOnUnsubscribe !== false) channel.leave();
83
+ }));
84
+ })));
85
+ }
86
+ /**
87
+ * Observe a named Phoenix channel event as an observable payload stream.
88
+ */
89
+ function ɵobservePhoenixEvent$(channel, eventName) {
90
+ return new Observable((observer) => {
91
+ const ref = channel.on(eventName, (payload) => observer.next(payload));
92
+ return () => {
93
+ channel.off(eventName, ref);
94
+ };
95
+ });
96
+ }
97
+ /**
98
+ * Flatten channel sessions into their join-outcome stream.
99
+ */
100
+ function ɵobservePhoenixJoinOutcome$(channel$) {
101
+ return channel$.pipe(switchMap$1((session) => session.joinOutcome$));
102
+ }
103
+ /**
104
+ * Complete when a channel joins successfully, or error if the join fails.
105
+ */
106
+ function ɵjoinPhoenixChannel$(channel$) {
107
+ return ɵobservePhoenixJoinOutcome$(channel$).pipe(take(1), mergeMap((outcome) => {
108
+ if (outcome.type === "joined") return EMPTY;
109
+ throw outcome.type === "timeout" ? /* @__PURE__ */ new Error("Timed out joining channel") : /* @__PURE__ */ new Error(`Failed to join channel: ${JSON.stringify(outcome.response)}`);
110
+ }));
111
+ }
112
+ /**
113
+ * Flatten socket sessions into their lifecycle signal stream.
114
+ */
115
+ function ɵobservePhoenixSocketSignals$(socket$) {
116
+ return socket$.pipe(switchMap$1((session) => session.signals$));
117
+ }
118
+ /**
119
+ * Error after a socket emits the configured number of consecutive error
120
+ * signals, resetting the counter after each successful open signal.
121
+ */
122
+ function ɵobservePhoenixSocketHealth$(socketSignals$, maxConsecutiveErrors) {
123
+ return socketSignals$.pipe(scan((consecutiveErrors, signal) => signal.type === "open" ? 0 : consecutiveErrors + 1, 0), filter((consecutiveErrors) => consecutiveErrors >= maxConsecutiveErrors), take(1), mergeMap((consecutiveErrors) => throwError(() => /* @__PURE__ */ new Error(`WebSocket connection failed after ${consecutiveErrors} consecutive errors`))));
124
+ }
125
+
126
+ //#endregion
127
+ //#region src/intelligence-agent.ts
128
+ const CLIENT_AG_UI_EVENT = "ag_ui_event";
129
+ const STOP_RUN_EVENT = "stop_run";
130
+ var AgentThreadLockedError = class extends Error {
131
+ constructor(threadId) {
132
+ super(threadId ? `Thread ${threadId} is locked` : "Thread is locked");
133
+ this.name = "AgentThreadLockedError";
134
+ }
135
+ };
136
+ var IntelligenceAgent = class IntelligenceAgent extends AbstractAgent {
137
+ config;
138
+ socket = null;
139
+ activeChannel = null;
140
+ runId = null;
141
+ sharedState;
142
+ constructor(config, sharedState = { lastSeenEventIds: /* @__PURE__ */ new Map() }) {
143
+ super();
144
+ this.config = config;
145
+ this.sharedState = sharedState;
146
+ }
147
+ clone() {
148
+ return new IntelligenceAgent(this.config, this.sharedState);
149
+ }
150
+ /**
151
+ * Override of AbstractAgent.connectAgent that removes the `verifyEvents` step.
152
+ *
153
+ * Background: AbstractAgent's connectAgent pipeline runs events through
154
+ * `verifyEvents`, which validates that the stream follows the AG-UI protocol
155
+ * lifecycle — specifically, it expects a RUN_STARTED event before any content
156
+ * events and a RUN_FINISHED/RUN_ERROR event to complete the stream.
157
+ *
158
+ * IntelligenceAgent uses long-lived WebSocket connections rather than
159
+ * request-scoped SSE streams. When connecting to replay historical messages
160
+ * for an existing thread, the connection semantics don't map to a single
161
+ * agent run start/stop cycle. The replayed events may not include
162
+ * RUN_STARTED/RUN_FINISHED bookends (or may contain events from multiple
163
+ * past runs), which causes verifyEvents to either never complete or to
164
+ * error out.
165
+ *
166
+ * This override replicates the base connectAgent implementation exactly,
167
+ * substituting only `transformChunks` (which is still needed for message
168
+ * reassembly) and omitting `verifyEvents`.
169
+ *
170
+ * TODO: Remove this override once AG-UI's AbstractAgent supports opting out
171
+ * of verifyEvents for transports with different connection life-cycles.
172
+ */
173
+ async connectAgent(parameters, subscriber) {
174
+ const self = this;
175
+ try {
176
+ this.isRunning = true;
177
+ this.agentId = this.agentId ?? randomUUID();
178
+ const input = this.prepareRunAgentInput(parameters);
179
+ let result;
180
+ const previousMessageIds = new Set(this.messages.map((m) => m.id));
181
+ const subscribers = [
182
+ { onRunFinishedEvent: (event) => {
183
+ result = event.result;
184
+ } },
185
+ ...this.subscribers,
186
+ subscriber ?? {}
187
+ ];
188
+ await this.onInitialize(input, subscribers);
189
+ self.activeRunDetach$ = new Subject();
190
+ let resolveCompletion;
191
+ self.activeRunCompletionPromise = new Promise((resolve) => {
192
+ resolveCompletion = resolve;
193
+ });
194
+ const source$ = defer(() => this.connect(input)).pipe(transformChunks(this.debug), takeUntil(self.activeRunDetach$));
195
+ const applied$ = this.apply(input, source$, subscribers);
196
+ await lastValueFrom(this.processApplyEvents(input, applied$, subscribers).pipe(catchError((error) => {
197
+ this.isRunning = false;
198
+ return this.onError(input, error, subscribers);
199
+ }), finalize(() => {
200
+ this.isRunning = false;
201
+ this.onFinalize(input, subscribers);
202
+ resolveCompletion?.();
203
+ resolveCompletion = void 0;
204
+ self.activeRunCompletionPromise = void 0;
205
+ self.activeRunDetach$ = void 0;
206
+ })), { defaultValue: void 0 });
207
+ const newMessages = structuredClone_(this.messages).filter((m) => !previousMessageIds.has(m.id));
208
+ return {
209
+ result,
210
+ newMessages
211
+ };
212
+ } finally {
213
+ this.isRunning = false;
214
+ }
215
+ }
216
+ abortRun() {
217
+ if (this.activeChannel && this.runId) {
218
+ const fallback = setTimeout(() => clear(), 5e3);
219
+ const clear = () => {
220
+ clearTimeout(fallback);
221
+ this.detachActiveRun();
222
+ this.cleanup();
223
+ };
224
+ this.activeChannel.push(STOP_RUN_EVENT, { run_id: this.runId }).receive("ok", clear).receive("error", clear).receive("timeout", clear);
225
+ } else {
226
+ this.detachActiveRun();
227
+ this.cleanup();
228
+ }
229
+ }
230
+ /**
231
+ * Trigger the run via REST, then join the realtime thread channel and relay
232
+ * server-pushed AG-UI events to the Observable subscriber.
233
+ */
234
+ run(input) {
235
+ this.threadId = input.threadId;
236
+ this.runId = input.runId;
237
+ return defer(() => this.requestJoinCredentials$("run", input)).pipe(switchMap((credentials) => this.observeThread$(input, credentials, {
238
+ completeOnRunError: false,
239
+ streamMode: "run"
240
+ })));
241
+ }
242
+ /**
243
+ * Reconnect to an existing thread by fetching websocket credentials and
244
+ * joining the realtime thread channel.
245
+ */
246
+ connect(input) {
247
+ this.threadId = input.threadId;
248
+ this.runId = input.runId;
249
+ return defer(() => this.requestConnectPlan$(input)).pipe(switchMap((plan) => {
250
+ if (plan === null) return EMPTY;
251
+ if (plan.mode === "bootstrap") {
252
+ this.setLastSeenEventId(input.threadId, plan.latestEventId);
253
+ for (const event of plan.events) this.updateRunIdFromEvent(event);
254
+ return from(plan.events);
255
+ }
256
+ this.setLastSeenEventId(input.threadId, plan.joinFromEventId);
257
+ for (const event of plan.events) this.updateRunIdFromEvent(event);
258
+ return concat(from(plan.events), this.observeThread$(input, { joinToken: plan.joinToken }, {
259
+ completeOnRunError: true,
260
+ streamMode: "connect",
261
+ replayCursor: plan.joinFromEventId
262
+ }));
263
+ }));
264
+ }
265
+ /**
266
+ * Tear down a specific channel + socket pair that belongs to one pipeline.
267
+ * Only nulls instance references when they still point to the owned resource,
268
+ * so a concurrent pipeline's resources are never clobbered.
269
+ */
270
+ cleanupOwned(ownChannel, ownSocket) {
271
+ if (ownChannel) {
272
+ ownChannel.leave();
273
+ if (this.activeChannel === ownChannel) this.activeChannel = null;
274
+ }
275
+ if (ownSocket) {
276
+ ownSocket.disconnect();
277
+ if (this.socket === ownSocket) this.socket = null;
278
+ }
279
+ if (this.threadId) this.sharedState.lastSeenEventIds.delete(this.threadId);
280
+ this.runId = null;
281
+ }
282
+ cleanup() {
283
+ this.cleanupOwned(this.activeChannel, this.socket);
284
+ }
285
+ requestJoinCredentials$(mode, input) {
286
+ return defer(async () => {
287
+ try {
288
+ const response = await fetch(this.buildRuntimeUrl(mode), {
289
+ method: "POST",
290
+ headers: {
291
+ "Content-Type": "application/json",
292
+ ...this.config.headers
293
+ },
294
+ body: JSON.stringify({
295
+ threadId: input.threadId,
296
+ runId: input.runId,
297
+ messages: input.messages,
298
+ tools: input.tools,
299
+ context: input.context,
300
+ state: input.state,
301
+ forwardedProps: input.forwardedProps
302
+ }),
303
+ ...this.config.credentials ? { credentials: this.config.credentials } : {}
304
+ });
305
+ if (response.status === 409) throw new AgentThreadLockedError(input.threadId);
306
+ if (!response.ok) {
307
+ const text = await response.text().catch(() => "");
308
+ throw new Error(text || response.statusText || String(response.status));
309
+ }
310
+ const payload = await response.json();
311
+ if (!payload.joinToken) throw new Error("missing joinToken");
312
+ return { joinToken: payload.joinToken };
313
+ } catch (error) {
314
+ if (error instanceof AgentThreadLockedError) throw error;
315
+ throw new Error(`REST ${mode} request failed: ${error instanceof Error ? error.message : String(error)}`);
316
+ }
317
+ });
318
+ }
319
+ requestConnectPlan$(input) {
320
+ return defer(async () => {
321
+ try {
322
+ const response = await fetch(this.buildRuntimeUrl("connect"), {
323
+ method: "POST",
324
+ headers: {
325
+ "Content-Type": "application/json",
326
+ ...this.config.headers
327
+ },
328
+ body: JSON.stringify({
329
+ threadId: input.threadId,
330
+ runId: input.runId,
331
+ messages: input.messages,
332
+ tools: input.tools,
333
+ context: input.context,
334
+ state: input.state,
335
+ forwardedProps: input.forwardedProps,
336
+ lastSeenEventId: this.getReconnectCursor(input)
337
+ }),
338
+ ...this.config.credentials ? { credentials: this.config.credentials } : {}
339
+ });
340
+ if (response.status === 204) return null;
341
+ if (!response.ok) {
342
+ const text = await response.text().catch(() => "");
343
+ throw new Error(text || response.statusText || String(response.status));
344
+ }
345
+ return this.normalizeConnectPlan(await response.json());
346
+ } catch (error) {
347
+ throw new Error(`REST connect request failed: ${error instanceof Error ? error.message : String(error)}`);
348
+ }
349
+ });
350
+ }
351
+ normalizeConnectPlan(payload) {
352
+ const envelope = payload && typeof payload === "object" ? payload : null;
353
+ if (envelope?.mode === "bootstrap") return {
354
+ mode: "bootstrap",
355
+ latestEventId: typeof envelope.latestEventId === "string" ? envelope.latestEventId : null,
356
+ events: Array.isArray(envelope.events) ? envelope.events : []
357
+ };
358
+ if (envelope?.mode === "live") {
359
+ if (typeof envelope.joinToken !== "string" || envelope.joinToken.length === 0) throw new Error("missing joinToken");
360
+ return {
361
+ mode: "live",
362
+ joinToken: envelope.joinToken,
363
+ joinFromEventId: typeof envelope.joinFromEventId === "string" ? envelope.joinFromEventId : null,
364
+ events: Array.isArray(envelope.events) ? envelope.events : []
365
+ };
366
+ }
367
+ throw new Error("invalid connect plan");
368
+ }
369
+ observeThread$(input, credentials, options) {
370
+ return defer(() => {
371
+ let ownSocket = null;
372
+ let ownChannel = null;
373
+ const socket$ = ɵphoenixSocket$({
374
+ url: this.config.url,
375
+ options: {
376
+ params: {
377
+ ...this.config.socketParams ?? {},
378
+ join_token: credentials.joinToken
379
+ },
380
+ reconnectAfterMs: phoenixExponentialBackoff(100, 1e4),
381
+ rejoinAfterMs: phoenixExponentialBackoff(1e3, 3e4)
382
+ }
383
+ }).pipe(tap(({ socket }) => {
384
+ ownSocket = socket;
385
+ this.socket = ownSocket;
386
+ }), shareReplay({
387
+ bufferSize: 1,
388
+ refCount: true
389
+ }));
390
+ const { topic, params } = this.createThreadChannelDescriptor(input, options.streamMode, options.replayCursor);
391
+ const channel$ = ɵphoenixChannel$({
392
+ socket$,
393
+ topic,
394
+ params
395
+ }).pipe(tap(({ channel }) => {
396
+ ownChannel = channel;
397
+ this.activeChannel = ownChannel;
398
+ }), shareReplay({
399
+ bufferSize: 1,
400
+ refCount: true
401
+ }));
402
+ const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe(share());
403
+ const threadCompleted$ = threadEvents$.pipe(ignoreElements(), endWith(null), take(1));
404
+ return merge(this.joinThreadChannel$(channel$), this.observeSocketHealth$(socket$).pipe(takeUntil(threadCompleted$)), threadEvents$).pipe(finalize(() => this.cleanupOwned(ownChannel, ownSocket)));
405
+ });
406
+ }
407
+ joinThreadChannel$(channel$) {
408
+ return ɵjoinPhoenixChannel$(channel$);
409
+ }
410
+ observeSocketHealth$(socket$) {
411
+ return ɵobservePhoenixSocketHealth$(ɵobservePhoenixSocketSignals$(socket$), 5);
412
+ }
413
+ observeThreadEvents$(threadId, channel$, options) {
414
+ return channel$.pipe(switchMap$1(({ channel }) => this.observeChannelEvent$(channel, CLIENT_AG_UI_EVENT)), tap((payload) => {
415
+ this.updateLastSeenEventId(threadId, payload);
416
+ this.updateRunIdFromEvent(payload);
417
+ }), mergeMap((payload) => from(this.createThreadNotifications(payload, options.completeOnRunError))), dematerialize());
418
+ }
419
+ observeChannelEvent$(channel, eventName) {
420
+ return ɵobservePhoenixEvent$(channel, eventName);
421
+ }
422
+ createThreadNotifications(payload, completeOnRunError) {
423
+ if (payload.type === EventType.RUN_FINISHED) return [Notification.createNext(payload), Notification.createComplete()];
424
+ if (payload.type === EventType.RUN_ERROR) {
425
+ const errorMessage = payload.message ?? "Run error";
426
+ return completeOnRunError ? [Notification.createNext(payload), Notification.createComplete()] : [Notification.createNext(payload), Notification.createError(new Error(errorMessage))];
427
+ }
428
+ return [Notification.createNext(payload)];
429
+ }
430
+ buildRuntimeUrl(mode) {
431
+ const path = `${this.config.runtimeUrl}/agent/${encodeURIComponent(this.config.agentId)}/${mode}`;
432
+ const origin = typeof window !== "undefined" && window.location ? window.location.origin : "http://localhost";
433
+ return new URL(path, new URL(this.config.runtimeUrl, origin)).toString();
434
+ }
435
+ createThreadChannelDescriptor(input, streamMode, replayCursor) {
436
+ const params = streamMode === "run" ? {
437
+ stream_mode: "run",
438
+ run_id: input.runId
439
+ } : {
440
+ stream_mode: "connect",
441
+ last_seen_event_id: replayCursor === void 0 ? this.getReconnectCursor(input) : replayCursor
442
+ };
443
+ return {
444
+ topic: `thread:${input.threadId}`,
445
+ params
446
+ };
447
+ }
448
+ getLastSeenEventId(threadId) {
449
+ return this.sharedState.lastSeenEventIds.get(threadId) ?? null;
450
+ }
451
+ getReconnectCursor(input) {
452
+ return this.hasLocalThreadMessages(input) ? this.getLastSeenEventId(input.threadId) : null;
453
+ }
454
+ hasLocalThreadMessages(input) {
455
+ return Array.isArray(input.messages) && input.messages.length > 0;
456
+ }
457
+ updateLastSeenEventId(threadId, payload) {
458
+ const eventId = this.readEventId(payload);
459
+ if (!eventId) return;
460
+ this.sharedState.lastSeenEventIds.set(threadId, eventId);
461
+ }
462
+ setLastSeenEventId(threadId, eventId) {
463
+ if (!eventId) return;
464
+ this.sharedState.lastSeenEventIds.set(threadId, eventId);
465
+ }
466
+ /**
467
+ * Keep `this.runId` in sync with the backend's actual run ID.
468
+ *
469
+ * During a `connect` (resume) flow the client generates a fresh `runId`
470
+ * via `prepareRunAgentInput`, but the backend is running under its own
471
+ * run ID. If the client later sends `STOP_RUN_EVENT` with the wrong
472
+ * `runId`, the gateway's runner channel will not match it and the agent
473
+ * keeps running. Extracting the run ID from live events fixes this.
474
+ *
475
+ * The runner normalises events to `run_id` (snake_case) before pushing
476
+ * to the gateway, so we check both `runId` and `run_id`.
477
+ */
478
+ updateRunIdFromEvent(payload) {
479
+ const record = payload;
480
+ const eventRunId = record.runId ?? record.run_id;
481
+ if (typeof eventRunId === "string" && eventRunId.length > 0) this.runId = eventRunId;
482
+ }
483
+ readEventId(payload) {
484
+ const metadata = payload.metadata;
485
+ if (!metadata || typeof metadata !== "object") return null;
486
+ const runnerEventId = metadata.cpki_event_id;
487
+ return typeof runnerEventId === "string" ? runnerEventId : null;
488
+ }
489
+ };
490
+
491
+ //#endregion
492
+ //#region src/agent.ts
493
+ function hasHeaders(agent) {
494
+ return "headers" in agent;
495
+ }
496
+ function hasCredentials(agent) {
497
+ return "credentials" in agent;
498
+ }
499
+ function isZodError(error) {
500
+ return error !== null && typeof error === "object" && "name" in error && error.name === "ZodError";
501
+ }
502
+ function isAbortError(error) {
503
+ return (error instanceof DOMException || error instanceof Error) && error.name === "AbortError";
504
+ }
505
+ function withAbortErrorHandling(observable) {
506
+ return observable.pipe(catchError((error) => {
507
+ if (isZodError(error) || isAbortError(error)) return EMPTY;
508
+ throw error;
509
+ }));
510
+ }
511
+ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAgent {
512
+ runtimeUrl;
513
+ credentials;
514
+ transport;
515
+ singleEndpointUrl;
516
+ runtimeMode;
517
+ intelligence;
518
+ delegate;
519
+ runtimeInfoPromise;
520
+ constructor(config) {
521
+ const normalizedRuntimeUrl = config.runtimeUrl ? config.runtimeUrl.replace(/\/$/, "") : void 0;
522
+ const transport = config.transport ?? "rest";
523
+ const runUrl = transport === "single" ? normalizedRuntimeUrl ?? config.runtimeUrl ?? "" : `${normalizedRuntimeUrl ?? config.runtimeUrl}/agent/${encodeURIComponent(config.agentId ?? "")}/run`;
524
+ if (!runUrl) throw new Error("ProxiedCopilotRuntimeAgent requires a runtimeUrl when transport is set to 'single'.");
525
+ super({
526
+ ...config,
527
+ url: runUrl
528
+ });
529
+ this.runtimeUrl = normalizedRuntimeUrl ?? config.runtimeUrl;
530
+ this.credentials = config.credentials;
531
+ this.transport = transport;
532
+ this.runtimeMode = config.runtimeMode ?? RUNTIME_MODE_SSE;
533
+ this.intelligence = config.intelligence;
534
+ if (this.transport === "single") this.singleEndpointUrl = this.runtimeUrl;
535
+ }
536
+ async detachActiveRun() {
537
+ if (this.delegate) await this.delegate.detachActiveRun();
538
+ await super.detachActiveRun();
539
+ }
540
+ abortRun() {
541
+ if (this.delegate) {
542
+ this.syncDelegate(this.delegate);
543
+ this.delegate.abortRun();
544
+ this.detachActiveRun();
545
+ return;
546
+ }
547
+ if (!this.agentId || !this.threadId) return;
548
+ if (typeof fetch === "undefined") return;
549
+ if (this.transport === "single") {
550
+ if (!this.singleEndpointUrl) return;
551
+ const headers = new Headers({
552
+ ...this.headers,
553
+ "Content-Type": "application/json"
554
+ });
555
+ fetch(this.singleEndpointUrl, {
556
+ method: "POST",
557
+ headers,
558
+ body: JSON.stringify({
559
+ method: "agent/stop",
560
+ params: {
561
+ agentId: this.agentId,
562
+ threadId: this.threadId
563
+ }
564
+ }),
565
+ ...this.credentials ? { credentials: this.credentials } : {}
566
+ }).catch((error) => {
567
+ console.error("ProxiedCopilotRuntimeAgent: stop request failed", error);
568
+ });
569
+ return;
570
+ }
571
+ if (!this.runtimeUrl) return;
572
+ const stopPath = `${this.runtimeUrl}/agent/${encodeURIComponent(this.agentId)}/stop/${encodeURIComponent(this.threadId)}`;
573
+ const origin = typeof window !== "undefined" && window.location ? window.location.origin : "http://localhost";
574
+ const base = new URL(this.runtimeUrl, origin);
575
+ const stopUrl = new URL(stopPath, base);
576
+ fetch(stopUrl.toString(), {
577
+ method: "POST",
578
+ headers: {
579
+ "Content-Type": "application/json",
580
+ ...this.headers
581
+ },
582
+ ...this.credentials ? { credentials: this.credentials } : {}
583
+ }).catch((error) => {
584
+ console.error("ProxiedCopilotRuntimeAgent: stop request failed", error);
585
+ });
586
+ }
587
+ async connectAgent(parameters, subscriber) {
588
+ if (this.runtimeMode !== RUNTIME_MODE_INTELLIGENCE) return super.connectAgent(parameters, subscriber);
589
+ if (this.delegate) await this.delegate.detachActiveRun();
590
+ await this.resolveDelegate();
591
+ const delegate = this.delegate;
592
+ const bridgeSub = delegate.subscribe({
593
+ onMessagesChanged: () => {
594
+ this.setMessages([...delegate.messages]);
595
+ },
596
+ onStateChanged: () => {
597
+ this.setState({ ...delegate.state });
598
+ },
599
+ onRunInitialized: () => {
600
+ this.isRunning = true;
601
+ },
602
+ onRunFinalized: () => {
603
+ this.isRunning = false;
604
+ },
605
+ onRunFailed: () => {
606
+ this.isRunning = false;
607
+ }
608
+ });
609
+ const forwardedSubs = this.subscribers.map((s) => delegate.subscribe(s));
610
+ try {
611
+ const result = await delegate.connectAgent(parameters, subscriber);
612
+ this.setMessages([...delegate.messages]);
613
+ this.setState({ ...delegate.state });
614
+ return result;
615
+ } finally {
616
+ this.isRunning = false;
617
+ bridgeSub.unsubscribe();
618
+ for (const sub of forwardedSubs) sub.unsubscribe();
619
+ }
620
+ }
621
+ connect(input) {
622
+ if (this.runtimeMode === RUNTIME_MODE_INTELLIGENCE) return this.#connectViaDelegate(input);
623
+ return this.#connectViaHttp(input);
624
+ }
625
+ run(input) {
626
+ if (this.runtimeMode === RUNTIME_MODE_INTELLIGENCE) return this.#runViaDelegate(input);
627
+ return this.#runViaHttp(input);
628
+ }
629
+ #connectViaDelegate(input) {
630
+ return defer(() => from(this.resolveDelegate())).pipe(switchMap$1((delegate) => withAbortErrorHandling(delegate.connect(input))));
631
+ }
632
+ #connectViaHttp(input) {
633
+ if (this.transport === "single") {
634
+ if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
635
+ const requestInit = this.createSingleRouteRequestInit(input, "agent/connect", { agentId: this.agentId });
636
+ return withAbortErrorHandling(transformHttpEventStream(runHttpRequest(this.singleEndpointUrl, requestInit)));
637
+ }
638
+ return withAbortErrorHandling(transformHttpEventStream(runHttpRequest(`${this.runtimeUrl}/agent/${this.agentId}/connect`, this.requestInit(input))));
639
+ }
640
+ #runViaDelegate(input) {
641
+ return defer(() => from(this.resolveDelegate())).pipe(switchMap$1((delegate) => withAbortErrorHandling(delegate.run(input))));
642
+ }
643
+ #runViaHttp(input) {
644
+ if (this.transport === "single") {
645
+ if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
646
+ const requestInit = this.createSingleRouteRequestInit(input, "agent/run", { agentId: this.agentId });
647
+ return withAbortErrorHandling(transformHttpEventStream(runHttpRequest(this.singleEndpointUrl, requestInit)));
648
+ }
649
+ return withAbortErrorHandling(super.run(input));
650
+ }
651
+ clone() {
652
+ const cloned = new ProxiedCopilotRuntimeAgent({
653
+ runtimeUrl: this.runtimeUrl,
654
+ agentId: this.agentId,
655
+ description: this.description,
656
+ headers: { ...this.headers },
657
+ credentials: this.credentials,
658
+ transport: this.transport,
659
+ runtimeMode: this.runtimeMode,
660
+ intelligence: this.intelligence
661
+ });
662
+ cloned.threadId = this.threadId;
663
+ cloned.setState(this.state);
664
+ cloned.setMessages(this.messages);
665
+ if (this.delegate) {
666
+ cloned.delegate = this.delegate.clone();
667
+ cloned.syncDelegate(cloned.delegate);
668
+ }
669
+ return cloned;
670
+ }
671
+ async resolveDelegate() {
672
+ await this.ensureRuntimeMode();
673
+ if (!this.delegate) {
674
+ if (this.runtimeMode !== RUNTIME_MODE_INTELLIGENCE) throw new Error("A delegate is only created for Intelligence mode");
675
+ this.delegate = this.createIntelligenceDelegate();
676
+ }
677
+ this.syncDelegate(this.delegate);
678
+ return this.delegate;
679
+ }
680
+ async ensureRuntimeMode() {
681
+ if (this.runtimeMode !== "pending") return;
682
+ if (!this.runtimeUrl) throw new Error("Runtime URL is not set");
683
+ this.runtimeInfoPromise ??= this.fetchRuntimeInfo().then((runtimeInfo) => {
684
+ this.runtimeMode = runtimeInfo.mode ?? RUNTIME_MODE_SSE;
685
+ this.intelligence = runtimeInfo.intelligence;
686
+ });
687
+ await this.runtimeInfoPromise;
688
+ }
689
+ async fetchRuntimeInfo() {
690
+ const headers = { ...this.headers };
691
+ let init;
692
+ let url;
693
+ if (this.transport === "single") {
694
+ if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
695
+ if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
696
+ url = this.runtimeUrl;
697
+ init = {
698
+ method: "POST",
699
+ body: JSON.stringify({ method: "info" })
700
+ };
701
+ } else {
702
+ url = `${this.runtimeUrl}/info`;
703
+ init = {};
704
+ }
705
+ const response = await fetch(url, {
706
+ ...init,
707
+ headers,
708
+ ...this.credentials ? { credentials: this.credentials } : {}
709
+ });
710
+ if (!response.ok) throw new Error(`Runtime info request failed with status ${response.status}`);
711
+ return await response.json();
712
+ }
713
+ createSingleRouteRequestInit(input, method, params) {
714
+ if (!this.agentId) throw new Error("ProxiedCopilotRuntimeAgent requires agentId to make runtime requests");
715
+ const baseInit = super.requestInit(input);
716
+ const headers = new Headers(baseInit.headers ?? {});
717
+ headers.set("Content-Type", "application/json");
718
+ headers.set("Accept", headers.get("Accept") ?? "text/event-stream");
719
+ let originalBody = void 0;
720
+ if (typeof baseInit.body === "string") try {
721
+ originalBody = JSON.parse(baseInit.body);
722
+ } catch (error) {
723
+ console.warn("ProxiedCopilotRuntimeAgent: failed to parse request body for single route transport", error);
724
+ }
725
+ const envelope = { method };
726
+ if (params && Object.keys(params).length > 0) envelope.params = params;
727
+ if (originalBody !== void 0) envelope.body = originalBody;
728
+ return {
729
+ ...baseInit,
730
+ headers,
731
+ body: JSON.stringify(envelope),
732
+ ...this.credentials ? { credentials: this.credentials } : {}
733
+ };
734
+ }
735
+ createIntelligenceDelegate() {
736
+ if (!this.runtimeUrl || !this.agentId || !this.intelligence?.wsUrl) throw new Error("Intelligence mode requires runtimeUrl, agentId, and intelligence websocket metadata");
737
+ return new IntelligenceAgent({
738
+ url: this.intelligence.wsUrl,
739
+ runtimeUrl: this.runtimeUrl,
740
+ agentId: this.agentId,
741
+ headers: { ...this.headers },
742
+ credentials: this.credentials
743
+ });
744
+ }
745
+ syncDelegate(delegate) {
746
+ delegate.agentId = this.agentId;
747
+ delegate.description = this.description;
748
+ delegate.threadId = this.threadId;
749
+ delegate.setMessages(this.messages);
750
+ delegate.setState(this.state);
751
+ if (hasHeaders(delegate)) delegate.headers = { ...this.headers };
752
+ if (hasCredentials(delegate)) delegate.credentials = this.credentials;
753
+ }
754
+ };
755
+
756
+ //#endregion
757
+ //#region src/core/agent-registry.ts
758
+ /**
759
+ * Manages agent registration, lifecycle, and runtime connectivity for CopilotKitCore.
760
+ * Handles both local development agents and remote runtime agents.
761
+ */
762
+ var AgentRegistry = class {
763
+ _agents = {};
764
+ localAgents = {};
765
+ remoteAgents = {};
766
+ _runtimeUrl;
767
+ _runtimeVersion;
768
+ _runtimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus.Disconnected;
769
+ _runtimeTransport = "rest";
770
+ _audioFileTranscriptionEnabled = false;
771
+ _runtimeMode = RUNTIME_MODE_SSE;
772
+ _intelligence;
773
+ _a2uiEnabled = false;
774
+ _licenseStatus;
775
+ constructor(core) {
776
+ this.core = core;
777
+ }
778
+ /**
779
+ * Get all agents as a readonly record
780
+ */
781
+ get agents() {
782
+ return this._agents;
783
+ }
784
+ get runtimeUrl() {
785
+ return this._runtimeUrl;
786
+ }
787
+ get runtimeVersion() {
788
+ return this._runtimeVersion;
789
+ }
790
+ get runtimeConnectionStatus() {
791
+ return this._runtimeConnectionStatus;
792
+ }
793
+ get runtimeTransport() {
794
+ return this._runtimeTransport;
795
+ }
796
+ get audioFileTranscriptionEnabled() {
797
+ return this._audioFileTranscriptionEnabled;
798
+ }
799
+ get runtimeMode() {
800
+ return this._runtimeMode;
801
+ }
802
+ get intelligence() {
803
+ return this._intelligence;
804
+ }
805
+ get a2uiEnabled() {
806
+ return this._a2uiEnabled;
807
+ }
808
+ get licenseStatus() {
809
+ return this._licenseStatus;
810
+ }
811
+ /**
812
+ * Initialize agents from configuration
813
+ */
814
+ initialize(agents) {
815
+ this.localAgents = this.assignAgentIds(agents);
816
+ this.applyHeadersToAgents(this.localAgents);
817
+ this._agents = this.localAgents;
818
+ }
819
+ /**
820
+ * Set the runtime URL and update connection
821
+ */
822
+ setRuntimeUrl(runtimeUrl) {
823
+ const normalizedRuntimeUrl = runtimeUrl ? runtimeUrl.replace(/\/$/, "") : void 0;
824
+ if (this._runtimeUrl === normalizedRuntimeUrl) return;
825
+ this._runtimeUrl = normalizedRuntimeUrl;
826
+ this.updateRuntimeConnection();
827
+ }
828
+ setRuntimeTransport(runtimeTransport) {
829
+ if (this._runtimeTransport === runtimeTransport) return;
830
+ this._runtimeTransport = runtimeTransport;
831
+ this.updateRuntimeConnection();
832
+ }
833
+ /**
834
+ * Set all agents at once (for development use)
835
+ */
836
+ setAgents__unsafe_dev_only(agents) {
837
+ Object.entries(agents).forEach(([id, agent]) => {
838
+ if (agent) this.validateAndAssignAgentId(id, agent);
839
+ });
840
+ this.localAgents = agents;
841
+ this._agents = {
842
+ ...this.localAgents,
843
+ ...this.remoteAgents
844
+ };
845
+ this.applyHeadersToAgents(this._agents);
846
+ this.notifyAgentsChanged();
847
+ }
848
+ /**
849
+ * Add a single agent (for development use)
850
+ */
851
+ addAgent__unsafe_dev_only({ id, agent }) {
852
+ this.validateAndAssignAgentId(id, agent);
853
+ this.localAgents[id] = agent;
854
+ this.applyHeadersToAgent(agent);
855
+ this._agents = {
856
+ ...this.localAgents,
857
+ ...this.remoteAgents
858
+ };
859
+ this.notifyAgentsChanged();
860
+ }
861
+ /**
862
+ * Remove an agent by ID (for development use)
863
+ */
864
+ removeAgent__unsafe_dev_only(id) {
865
+ delete this.localAgents[id];
866
+ this._agents = {
867
+ ...this.localAgents,
868
+ ...this.remoteAgents
869
+ };
870
+ this.notifyAgentsChanged();
871
+ }
872
+ /**
873
+ * Get an agent by ID
874
+ */
875
+ getAgent(id) {
876
+ if (id in this._agents) return this._agents[id];
877
+ if (this.runtimeUrl !== void 0 && (this.runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Disconnected || this.runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Connecting)) return;
878
+ console.warn(`Agent ${id} not found`);
879
+ }
880
+ /**
881
+ * Apply current headers to an agent
882
+ */
883
+ applyHeadersToAgent(agent) {
884
+ if (agent instanceof HttpAgent) agent.headers = { ...this.core.headers };
885
+ }
886
+ /**
887
+ * Apply current headers to all agents
888
+ */
889
+ applyHeadersToAgents(agents) {
890
+ Object.values(agents).forEach((agent) => {
891
+ this.applyHeadersToAgent(agent);
892
+ });
893
+ }
894
+ /**
895
+ * Apply current credentials to an agent
896
+ */
897
+ applyCredentialsToAgent(agent) {
898
+ if (agent instanceof ProxiedCopilotRuntimeAgent) agent.credentials = this.core.credentials;
899
+ }
900
+ /**
901
+ * Apply current credentials to all agents
902
+ */
903
+ applyCredentialsToAgents(agents) {
904
+ Object.values(agents).forEach((agent) => {
905
+ this.applyCredentialsToAgent(agent);
906
+ });
907
+ }
908
+ /**
909
+ * Update runtime connection and fetch remote agents
910
+ */
911
+ async updateRuntimeConnection() {
912
+ if (typeof window === "undefined") return;
913
+ if (!this.runtimeUrl) {
914
+ this._runtimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus.Disconnected;
915
+ this._runtimeVersion = void 0;
916
+ this._audioFileTranscriptionEnabled = false;
917
+ this._runtimeMode = RUNTIME_MODE_SSE;
918
+ this._intelligence = void 0;
919
+ this._a2uiEnabled = false;
920
+ this.remoteAgents = {};
921
+ this._agents = this.localAgents;
922
+ await this.notifyRuntimeStatusChanged(CopilotKitCoreRuntimeConnectionStatus.Disconnected);
923
+ await this.notifyAgentsChanged();
924
+ return;
925
+ }
926
+ this._runtimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus.Connecting;
927
+ await this.notifyRuntimeStatusChanged(CopilotKitCoreRuntimeConnectionStatus.Connecting);
928
+ try {
929
+ const runtimeInfoResponse = await this.fetchRuntimeInfo();
930
+ const { version, ...runtimeInfo } = runtimeInfoResponse;
931
+ const credentials = this.core.credentials;
932
+ this.remoteAgents = Object.fromEntries(Object.entries(runtimeInfo.agents).map(([id, { description }]) => {
933
+ const agent = new ProxiedCopilotRuntimeAgent({
934
+ runtimeUrl: this.runtimeUrl,
935
+ agentId: id,
936
+ description,
937
+ transport: this._runtimeTransport,
938
+ credentials,
939
+ runtimeMode: runtimeInfoResponse.mode ?? RUNTIME_MODE_SSE,
940
+ intelligence: runtimeInfoResponse.intelligence
941
+ });
942
+ this.applyHeadersToAgent(agent);
943
+ return [id, agent];
944
+ }));
945
+ this._agents = {
946
+ ...this.localAgents,
947
+ ...this.remoteAgents
948
+ };
949
+ this._runtimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus.Connected;
950
+ this._runtimeVersion = version;
951
+ this._audioFileTranscriptionEnabled = runtimeInfoResponse.audioFileTranscriptionEnabled ?? false;
952
+ this._runtimeMode = runtimeInfoResponse.mode ?? RUNTIME_MODE_SSE;
953
+ this._intelligence = runtimeInfoResponse.intelligence;
954
+ this._a2uiEnabled = runtimeInfoResponse.a2uiEnabled ?? false;
955
+ this._licenseStatus = runtimeInfoResponse.licenseStatus;
956
+ await this.notifyRuntimeStatusChanged(CopilotKitCoreRuntimeConnectionStatus.Connected);
957
+ await this.notifyAgentsChanged();
958
+ } catch (error) {
959
+ this._runtimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus.Error;
960
+ this._runtimeVersion = void 0;
961
+ this._audioFileTranscriptionEnabled = false;
962
+ this._runtimeMode = RUNTIME_MODE_SSE;
963
+ this._intelligence = void 0;
964
+ this._a2uiEnabled = false;
965
+ this.remoteAgents = {};
966
+ this._agents = this.localAgents;
967
+ await this.notifyRuntimeStatusChanged(CopilotKitCoreRuntimeConnectionStatus.Error);
968
+ await this.notifyAgentsChanged();
969
+ const message = error instanceof Error ? error.message : JSON.stringify(error);
970
+ logger.warn(`Failed to load runtime info (${this.runtimeUrl}/info): ${message}`);
971
+ const runtimeError = error instanceof Error ? error : new Error(String(error));
972
+ await this.core.emitError({
973
+ error: runtimeError,
974
+ code: CopilotKitCoreErrorCode.RUNTIME_INFO_FETCH_FAILED,
975
+ context: { runtimeUrl: this.runtimeUrl }
976
+ });
977
+ }
978
+ }
979
+ async fetchRuntimeInfo() {
980
+ if (!this.runtimeUrl) throw new Error("Runtime URL is not set");
981
+ const baseHeaders = this.core.headers;
982
+ const credentials = this.core.credentials;
983
+ const headers = { ...baseHeaders };
984
+ if (this._runtimeTransport === "single") {
985
+ if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
986
+ const response = await fetch(this.runtimeUrl, {
987
+ method: "POST",
988
+ headers,
989
+ body: JSON.stringify({ method: "info" }),
990
+ ...credentials ? { credentials } : {}
991
+ });
992
+ if ("ok" in response && !response.ok) throw new Error(`Runtime info request failed with status ${response.status}`);
993
+ return await response.json();
994
+ }
995
+ const response = await fetch(`${this.runtimeUrl}/info`, {
996
+ headers,
997
+ ...credentials ? { credentials } : {}
998
+ });
999
+ if ("ok" in response && !response.ok) throw new Error(`Runtime info request failed with status ${response.status}`);
1000
+ return await response.json();
1001
+ }
1002
+ /**
1003
+ * Assign agent IDs to a record of agents
1004
+ */
1005
+ assignAgentIds(agents) {
1006
+ Object.entries(agents).forEach(([id, agent]) => {
1007
+ if (agent) this.validateAndAssignAgentId(id, agent);
1008
+ });
1009
+ return agents;
1010
+ }
1011
+ /**
1012
+ * Validate and assign an agent ID
1013
+ */
1014
+ validateAndAssignAgentId(registrationId, agent) {
1015
+ if (agent.agentId && agent.agentId !== registrationId) throw new Error(`Agent registration mismatch: Agent with ID "${agent.agentId}" cannot be registered under key "${registrationId}". The agent ID must match the registration key or be undefined.`);
1016
+ if (!agent.agentId) agent.agentId = registrationId;
1017
+ }
1018
+ /**
1019
+ * Notify subscribers of runtime status changes
1020
+ */
1021
+ async notifyRuntimeStatusChanged(status) {
1022
+ await this.core.notifySubscribers((subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
1023
+ copilotkit: this.core,
1024
+ status
1025
+ }), "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):");
1026
+ }
1027
+ /**
1028
+ * Notify subscribers of agent changes
1029
+ */
1030
+ async notifyAgentsChanged() {
1031
+ await this.core.notifySubscribers((subscriber) => subscriber.onAgentsChanged?.({
1032
+ copilotkit: this.core,
1033
+ agents: this._agents
1034
+ }), "Subscriber onAgentsChanged error:");
1035
+ }
1036
+ };
1037
+
1038
+ //#endregion
1039
+ //#region src/core/context-store.ts
1040
+ /**
1041
+ * Manages context storage and lifecycle for CopilotKitCore.
1042
+ * Context represents additional information available to agents during execution.
1043
+ */
1044
+ var ContextStore = class {
1045
+ _context = {};
1046
+ constructor(core) {
1047
+ this.core = core;
1048
+ }
1049
+ /**
1050
+ * Get all context entries as a readonly record
1051
+ */
1052
+ get context() {
1053
+ return this._context;
1054
+ }
1055
+ /**
1056
+ * Add a new context entry
1057
+ * @returns The ID of the created context entry
1058
+ */
1059
+ addContext({ description, value }) {
1060
+ const id = randomUUID$1();
1061
+ this._context[id] = {
1062
+ description,
1063
+ value
1064
+ };
1065
+ this.notifySubscribers();
1066
+ return id;
1067
+ }
1068
+ /**
1069
+ * Remove a context entry by ID
1070
+ */
1071
+ removeContext(id) {
1072
+ delete this._context[id];
1073
+ this.notifySubscribers();
1074
+ }
1075
+ /**
1076
+ * Notify all subscribers of context changes
1077
+ */
1078
+ async notifySubscribers() {
1079
+ await this.core.notifySubscribers((subscriber) => subscriber.onContextChanged?.({
1080
+ copilotkit: this.core,
1081
+ context: this._context
1082
+ }), "Subscriber onContextChanged error:");
1083
+ }
1084
+ };
1085
+
1086
+ //#endregion
1087
+ //#region src/core/suggestion-engine.ts
1088
+ /**
1089
+ * Manages suggestion generation, streaming, and lifecycle for CopilotKitCore.
1090
+ * Handles both dynamic (AI-generated) and static suggestions.
1091
+ */
1092
+ var SuggestionEngine = class {
1093
+ _suggestionsConfig = {};
1094
+ _suggestions = {};
1095
+ _runningSuggestions = {};
1096
+ constructor(core) {
1097
+ this.core = core;
1098
+ }
1099
+ /**
1100
+ * Initialize with suggestion configs
1101
+ */
1102
+ initialize(suggestionsConfig) {
1103
+ for (const config of suggestionsConfig) this._suggestionsConfig[randomUUID$1()] = config;
1104
+ }
1105
+ /**
1106
+ * Add a suggestion configuration
1107
+ * @returns The ID of the created config
1108
+ */
1109
+ addSuggestionsConfig(config) {
1110
+ const id = randomUUID$1();
1111
+ this._suggestionsConfig[id] = config;
1112
+ this.notifySuggestionsConfigChanged();
1113
+ return id;
1114
+ }
1115
+ /**
1116
+ * Remove a suggestion configuration by ID
1117
+ */
1118
+ removeSuggestionsConfig(id) {
1119
+ delete this._suggestionsConfig[id];
1120
+ this.notifySuggestionsConfigChanged();
1121
+ }
1122
+ /**
1123
+ * Reload suggestions for a specific agent
1124
+ * This triggers generation of new suggestions based on current configs
1125
+ */
1126
+ reloadSuggestions(agentId) {
1127
+ this.clearSuggestions(agentId);
1128
+ const agent = this.core.getAgent(agentId);
1129
+ if (!agent) return;
1130
+ const messageCount = agent.messages?.length ?? 0;
1131
+ let hasAnySuggestions = false;
1132
+ for (const config of Object.values(this._suggestionsConfig)) {
1133
+ if (config.consumerAgentId !== void 0 && config.consumerAgentId !== "*" && config.consumerAgentId !== agentId) continue;
1134
+ if (!this.shouldShowSuggestions(config, messageCount)) continue;
1135
+ const suggestionId = randomUUID$1();
1136
+ if (isDynamicSuggestionsConfig(config)) {
1137
+ if (!hasAnySuggestions) {
1138
+ hasAnySuggestions = true;
1139
+ this.notifySuggestionsStartedLoading(agentId);
1140
+ }
1141
+ this.generateSuggestions(suggestionId, config, agentId);
1142
+ } else if (isStaticSuggestionsConfig(config)) this.addStaticSuggestions(suggestionId, config, agentId);
1143
+ }
1144
+ }
1145
+ /**
1146
+ * Clear all suggestions for a specific agent
1147
+ */
1148
+ clearSuggestions(agentId) {
1149
+ const runningAgents = this._runningSuggestions[agentId];
1150
+ if (runningAgents) {
1151
+ for (const agent of runningAgents) agent.abortRun();
1152
+ delete this._runningSuggestions[agentId];
1153
+ }
1154
+ this._suggestions[agentId] = {};
1155
+ this.notifySuggestionsChanged(agentId, []);
1156
+ }
1157
+ /**
1158
+ * Get current suggestions for an agent
1159
+ */
1160
+ getSuggestions(agentId) {
1161
+ return {
1162
+ suggestions: Object.values(this._suggestions[agentId] ?? {}).flat(),
1163
+ isLoading: (this._runningSuggestions[agentId]?.length ?? 0) > 0
1164
+ };
1165
+ }
1166
+ /**
1167
+ * Generate suggestions using a provider agent
1168
+ */
1169
+ async generateSuggestions(suggestionId, config, consumerAgentId) {
1170
+ let agent = void 0;
1171
+ try {
1172
+ const suggestionsProviderAgent = this.core.getAgent(config.providerAgentId ?? "default");
1173
+ if (!suggestionsProviderAgent) throw new Error(`Suggestions provider agent not found: ${config.providerAgentId}`);
1174
+ const suggestionsConsumerAgent = this.core.getAgent(consumerAgentId);
1175
+ if (!suggestionsConsumerAgent) throw new Error(`Suggestions consumer agent not found: ${consumerAgentId}`);
1176
+ agent = suggestionsProviderAgent.clone();
1177
+ agent.threadId = suggestionId;
1178
+ agent.messages = JSON.parse(JSON.stringify(suggestionsConsumerAgent.messages));
1179
+ agent.state = JSON.parse(JSON.stringify(suggestionsConsumerAgent.state));
1180
+ this._suggestions[consumerAgentId] = {
1181
+ ...this._suggestions[consumerAgentId] ?? {},
1182
+ [suggestionId]: []
1183
+ };
1184
+ this._runningSuggestions[consumerAgentId] = [...this._runningSuggestions[consumerAgentId] ?? [], agent];
1185
+ agent.addMessage({
1186
+ id: suggestionId,
1187
+ role: "user",
1188
+ content: [
1189
+ `Suggest what the user could say next. Provide clear, highly relevant suggestions by calling the \`copilotkitSuggest\` tool.`,
1190
+ `Provide at least ${config.minSuggestions ?? 1} and at most ${config.maxSuggestions ?? 3} suggestions.`,
1191
+ `The user has the following tools available: ${JSON.stringify(this.core.buildFrontendTools(consumerAgentId))}.`,
1192
+ ` ${config.instructions}`
1193
+ ].join("\n")
1194
+ });
1195
+ await agent.runAgent({
1196
+ context: Object.values(this.core.context),
1197
+ forwardedProps: {
1198
+ ...this.core.properties,
1199
+ toolChoice: {
1200
+ type: "function",
1201
+ function: { name: "copilotkitSuggest" }
1202
+ }
1203
+ },
1204
+ tools: [SUGGEST_TOOL]
1205
+ }, { onMessagesChanged: ({ messages }) => {
1206
+ this.extractSuggestions(messages, suggestionId, consumerAgentId, true);
1207
+ } });
1208
+ } catch (error) {
1209
+ console.warn("Error generating suggestions:", error);
1210
+ } finally {
1211
+ this.finalizeSuggestions(suggestionId, consumerAgentId);
1212
+ const runningAgents = this._runningSuggestions[consumerAgentId];
1213
+ if (agent && runningAgents) {
1214
+ const filteredAgents = runningAgents.filter((a) => a !== agent);
1215
+ this._runningSuggestions[consumerAgentId] = filteredAgents;
1216
+ if (filteredAgents.length === 0) {
1217
+ delete this._runningSuggestions[consumerAgentId];
1218
+ await this.notifySuggestionsFinishedLoading(consumerAgentId);
1219
+ }
1220
+ }
1221
+ }
1222
+ }
1223
+ /**
1224
+ * Finalize suggestions by marking them as no longer loading
1225
+ */
1226
+ finalizeSuggestions(suggestionId, consumerAgentId) {
1227
+ const agentSuggestions = this._suggestions[consumerAgentId];
1228
+ const currentSuggestions = agentSuggestions?.[suggestionId];
1229
+ if (agentSuggestions && currentSuggestions && currentSuggestions.length > 0) {
1230
+ const finalizedSuggestions = currentSuggestions.filter((suggestion) => suggestion.title !== "" || suggestion.message !== "").map((suggestion) => ({
1231
+ ...suggestion,
1232
+ isLoading: false
1233
+ }));
1234
+ if (finalizedSuggestions.length > 0) agentSuggestions[suggestionId] = finalizedSuggestions;
1235
+ else delete agentSuggestions[suggestionId];
1236
+ const allSuggestions = Object.values(this._suggestions[consumerAgentId] ?? {}).flat();
1237
+ this.notifySuggestionsChanged(consumerAgentId, allSuggestions, "finalized");
1238
+ }
1239
+ }
1240
+ /**
1241
+ * Extract suggestions from messages (called during streaming)
1242
+ */
1243
+ extractSuggestions(messages, suggestionId, consumerAgentId, isRunning) {
1244
+ const idx = messages.findIndex((message) => message.id === suggestionId);
1245
+ if (idx == -1) return;
1246
+ const suggestions = [];
1247
+ const newMessages = messages.slice(idx + 1);
1248
+ for (const message of newMessages) if (message.role === "assistant" && message.toolCalls) {
1249
+ for (const toolCall of message.toolCalls) if (toolCall.function.name === "copilotkitSuggest") {
1250
+ const parsed = partialJSONParse(Array.isArray(toolCall.function.arguments) ? toolCall.function.arguments.join("") : toolCall.function.arguments);
1251
+ if (parsed && typeof parsed === "object" && "suggestions" in parsed) {
1252
+ const parsedSuggestions = parsed.suggestions;
1253
+ if (Array.isArray(parsedSuggestions)) {
1254
+ for (const item of parsedSuggestions) if (item && typeof item === "object" && "title" in item) suggestions.push({
1255
+ title: item.title ?? "",
1256
+ message: item.message ?? "",
1257
+ isLoading: false
1258
+ });
1259
+ }
1260
+ }
1261
+ }
1262
+ }
1263
+ if (isRunning && suggestions.length > 0) suggestions[suggestions.length - 1].isLoading = true;
1264
+ const agentSuggestions = this._suggestions[consumerAgentId];
1265
+ if (agentSuggestions) {
1266
+ agentSuggestions[suggestionId] = suggestions;
1267
+ const allSuggestions = Object.values(this._suggestions[consumerAgentId] ?? {}).flat();
1268
+ this.notifySuggestionsChanged(consumerAgentId, allSuggestions, "suggestions changed");
1269
+ }
1270
+ }
1271
+ /**
1272
+ * Notify subscribers of suggestions config changes
1273
+ */
1274
+ async notifySuggestionsConfigChanged() {
1275
+ await this.core.notifySubscribers((subscriber) => subscriber.onSuggestionsConfigChanged?.({
1276
+ copilotkit: this.core,
1277
+ suggestionsConfig: this._suggestionsConfig
1278
+ }), "Subscriber onSuggestionsConfigChanged error:");
1279
+ }
1280
+ /**
1281
+ * Notify subscribers of suggestions changes
1282
+ */
1283
+ async notifySuggestionsChanged(agentId, suggestions, context = "") {
1284
+ await this.core.notifySubscribers((subscriber) => subscriber.onSuggestionsChanged?.({
1285
+ copilotkit: this.core,
1286
+ agentId,
1287
+ suggestions
1288
+ }), `Subscriber onSuggestionsChanged error: ${context}`);
1289
+ }
1290
+ /**
1291
+ * Notify subscribers that suggestions started loading
1292
+ */
1293
+ async notifySuggestionsStartedLoading(agentId) {
1294
+ await this.core.notifySubscribers((subscriber) => subscriber.onSuggestionsStartedLoading?.({
1295
+ copilotkit: this.core,
1296
+ agentId
1297
+ }), "Subscriber onSuggestionsStartedLoading error:");
1298
+ }
1299
+ /**
1300
+ * Notify subscribers that suggestions finished loading
1301
+ */
1302
+ async notifySuggestionsFinishedLoading(agentId) {
1303
+ await this.core.notifySubscribers((subscriber) => subscriber.onSuggestionsFinishedLoading?.({
1304
+ copilotkit: this.core,
1305
+ agentId
1306
+ }), "Subscriber onSuggestionsFinishedLoading error:");
1307
+ }
1308
+ /**
1309
+ * Check if suggestions should be shown based on availability and message count
1310
+ */
1311
+ shouldShowSuggestions(config, messageCount) {
1312
+ const availability = config.available;
1313
+ if (!availability) if (isDynamicSuggestionsConfig(config)) return messageCount > 0;
1314
+ else return messageCount === 0;
1315
+ switch (availability) {
1316
+ case "disabled": return false;
1317
+ case "before-first-message": return messageCount === 0;
1318
+ case "after-first-message": return messageCount > 0;
1319
+ case "always": return true;
1320
+ default: return false;
1321
+ }
1322
+ }
1323
+ /**
1324
+ * Add static suggestions directly without AI generation
1325
+ */
1326
+ addStaticSuggestions(suggestionId, config, consumerAgentId) {
1327
+ const suggestions = config.suggestions.map((s) => ({
1328
+ ...s,
1329
+ isLoading: false
1330
+ }));
1331
+ this._suggestions[consumerAgentId] = {
1332
+ ...this._suggestions[consumerAgentId] ?? {},
1333
+ [suggestionId]: suggestions
1334
+ };
1335
+ const allSuggestions = Object.values(this._suggestions[consumerAgentId] ?? {}).flat();
1336
+ this.notifySuggestionsChanged(consumerAgentId, allSuggestions, "static suggestions added");
1337
+ }
1338
+ };
1339
+ /**
1340
+ * Type guard for dynamic suggestions config
1341
+ */
1342
+ function isDynamicSuggestionsConfig(config) {
1343
+ return "instructions" in config;
1344
+ }
1345
+ /**
1346
+ * Type guard for static suggestions config
1347
+ */
1348
+ function isStaticSuggestionsConfig(config) {
1349
+ return "suggestions" in config;
1350
+ }
1351
+ /**
1352
+ * The tool definition for AI-generated suggestions
1353
+ */
1354
+ const SUGGEST_TOOL = {
1355
+ name: "copilotkitSuggest",
1356
+ description: "Suggest what the user could say next",
1357
+ parameters: {
1358
+ type: "object",
1359
+ properties: { suggestions: {
1360
+ type: "array",
1361
+ description: "List of suggestions shown to the user as buttons.",
1362
+ items: {
1363
+ type: "object",
1364
+ properties: {
1365
+ title: {
1366
+ type: "string",
1367
+ description: "The title of the suggestion. This is shown as a button and should be short."
1368
+ },
1369
+ message: {
1370
+ type: "string",
1371
+ description: "The message to send when the suggestion is clicked. This should be a clear, complete sentence and will be sent as an instruction to the AI."
1372
+ }
1373
+ },
1374
+ required: ["title", "message"]
1375
+ }
1376
+ } },
1377
+ required: ["suggestions"]
1378
+ }
1379
+ };
1380
+
1381
+ //#endregion
1382
+ //#region src/core/run-handler.ts
1383
+ /**
1384
+ * Handles agent execution, tool calling, and agent connectivity for CopilotKitCore.
1385
+ * Manages the complete lifecycle of agent runs including tool execution and follow-ups.
1386
+ */
1387
+ var RunHandler = class {
1388
+ _tools = [];
1389
+ /**
1390
+ * Tracks whether the current run (including in-flight tool execution)
1391
+ * has been aborted via `stopAgent()` or `agent.abortRun()`. Created
1392
+ * fresh in `runAgent()`, aborted by `abortCurrentRun()`.
1393
+ */
1394
+ _runAbortController = null;
1395
+ /**
1396
+ * Tracks recursive `runAgent` depth so that the abort controller and
1397
+ * `agent.abortRun()` intercept are only set up / torn down at the
1398
+ * top-level call, not on follow-up recursive calls from
1399
+ * `processAgentResult`.
1400
+ */
1401
+ _runDepth = 0;
1402
+ constructor(core) {
1403
+ this.core = core;
1404
+ }
1405
+ /**
1406
+ * Abort the current run. Called by `CopilotKitCore.stopAgent()` to signal
1407
+ * that in-flight tool handlers should stop and `processAgentResult` should
1408
+ * not start a follow-up run.
1409
+ */
1410
+ abortCurrentRun() {
1411
+ this._runAbortController?.abort();
1412
+ }
1413
+ /**
1414
+ * Typed access to CopilotKitCore's internal ("friend") methods.
1415
+ * Centralises the single unavoidable cast so call-sites stay clean.
1416
+ */
1417
+ get _internal() {
1418
+ return this.core;
1419
+ }
1420
+ /**
1421
+ * Get all tools as a readonly array
1422
+ */
1423
+ get tools() {
1424
+ return this._tools;
1425
+ }
1426
+ /**
1427
+ * Initialize with tools
1428
+ */
1429
+ initialize(tools) {
1430
+ this._tools = tools;
1431
+ }
1432
+ /**
1433
+ * Add a tool to the registry
1434
+ */
1435
+ addTool(tool) {
1436
+ if (this._tools.findIndex((t) => t.name === tool.name && t.agentId === tool.agentId) !== -1) {
1437
+ logger.warn(`Tool already exists: '${tool.name}' for agent '${tool.agentId || "global"}', skipping.`);
1438
+ return;
1439
+ }
1440
+ this._tools.push(tool);
1441
+ }
1442
+ /**
1443
+ * Remove a tool by name and optionally by agentId
1444
+ */
1445
+ removeTool(id, agentId) {
1446
+ this._tools = this._tools.filter((tool) => {
1447
+ if (agentId !== void 0) return !(tool.name === id && tool.agentId === agentId);
1448
+ return !(tool.name === id && !tool.agentId);
1449
+ });
1450
+ }
1451
+ /**
1452
+ * Get a tool by name and optionally by agentId.
1453
+ * If agentId is provided, it will first look for an agent-specific tool,
1454
+ * then fall back to a global tool with the same name.
1455
+ */
1456
+ getTool(params) {
1457
+ const { toolName, agentId } = params;
1458
+ if (agentId) {
1459
+ const agentTool = this._tools.find((tool) => tool.name === toolName && tool.agentId === agentId);
1460
+ if (agentTool) return agentTool;
1461
+ }
1462
+ return this._tools.find((tool) => tool.name === toolName && !tool.agentId);
1463
+ }
1464
+ /**
1465
+ * Set all tools at once. Replaces existing tools.
1466
+ */
1467
+ setTools(tools) {
1468
+ this._tools = [...tools];
1469
+ }
1470
+ /**
1471
+ * Connect an agent (establish initial connection)
1472
+ */
1473
+ async connectAgent({ agent }) {
1474
+ try {
1475
+ await agent.detachActiveRun();
1476
+ agent.setMessages([]);
1477
+ agent.setState({});
1478
+ if (agent instanceof HttpAgent) agent.headers = { ...this._internal.headers };
1479
+ const runAgentResult = await agent.connectAgent({
1480
+ forwardedProps: this._internal.properties,
1481
+ tools: this.buildFrontendTools(agent.agentId),
1482
+ context: Object.values(this._internal.context)
1483
+ }, this.createAgentErrorSubscriber(agent));
1484
+ return this.processAgentResult({
1485
+ runAgentResult,
1486
+ agent
1487
+ });
1488
+ } catch (error) {
1489
+ const connectError = error instanceof Error ? error : new Error(String(error));
1490
+ const context = {};
1491
+ if (agent.agentId) context.agentId = agent.agentId;
1492
+ await this._internal.emitError({
1493
+ error: connectError,
1494
+ code: CopilotKitCoreErrorCode.AGENT_CONNECT_FAILED,
1495
+ context
1496
+ });
1497
+ return { newMessages: [] };
1498
+ }
1499
+ }
1500
+ /**
1501
+ * Run an agent
1502
+ */
1503
+ async runAgent({ agent, forwardedProps }) {
1504
+ if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
1505
+ if (agent instanceof HttpAgent) agent.headers = { ...this._internal.headers };
1506
+ if (agent.detachActiveRun) await agent.detachActiveRun();
1507
+ const isTopLevel = this._runDepth === 0;
1508
+ let originalAbortRun;
1509
+ if (isTopLevel) {
1510
+ this._runAbortController = new AbortController();
1511
+ const controller = this._runAbortController;
1512
+ originalAbortRun = agent.abortRun.bind(agent);
1513
+ agent.abortRun = () => {
1514
+ controller.abort();
1515
+ originalAbortRun();
1516
+ };
1517
+ }
1518
+ this._runDepth++;
1519
+ try {
1520
+ const runAgentResult = await agent.runAgent({
1521
+ forwardedProps: {
1522
+ ...this._internal.properties,
1523
+ ...forwardedProps
1524
+ },
1525
+ tools: this.buildFrontendTools(agent.agentId),
1526
+ context: Object.values(this._internal.context)
1527
+ }, this.createAgentErrorSubscriber(agent));
1528
+ return await this.processAgentResult({
1529
+ runAgentResult,
1530
+ agent
1531
+ });
1532
+ } catch (error) {
1533
+ const runError = error instanceof Error ? error : new Error(String(error));
1534
+ const context = {};
1535
+ if (agent.agentId) context.agentId = agent.agentId;
1536
+ await this._internal.emitError({
1537
+ error: runError,
1538
+ code: CopilotKitCoreErrorCode.AGENT_RUN_FAILED,
1539
+ context
1540
+ });
1541
+ return { newMessages: [] };
1542
+ } finally {
1543
+ this._runDepth--;
1544
+ if (isTopLevel && originalAbortRun) agent.abortRun = originalAbortRun;
1545
+ }
1546
+ }
1547
+ /**
1548
+ * Process agent result and execute tools
1549
+ */
1550
+ async processAgentResult({ runAgentResult, agent }) {
1551
+ const { newMessages } = runAgentResult;
1552
+ const agentId = agent.agentId;
1553
+ let needsFollowUp = false;
1554
+ for (const message of newMessages) if (message.role === "assistant") {
1555
+ for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
1556
+ const tool = this.getTool({
1557
+ toolName: toolCall.function.name,
1558
+ agentId: agent.agentId
1559
+ });
1560
+ if (tool) {
1561
+ if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
1562
+ } else {
1563
+ const wildcardTool = this.getTool({
1564
+ toolName: "*",
1565
+ agentId: agent.agentId
1566
+ });
1567
+ if (wildcardTool) {
1568
+ if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
1569
+ }
1570
+ }
1571
+ }
1572
+ }
1573
+ if (needsFollowUp && !this._runAbortController?.signal.aborted) {
1574
+ await this._internal.waitForPendingFrameworkUpdates();
1575
+ return await this.runAgent({ agent });
1576
+ }
1577
+ this._internal.suggestionEngine.reloadSuggestions(agentId);
1578
+ return runAgentResult;
1579
+ }
1580
+ /**
1581
+ * Shared handler execution logic used by executeSpecificTool, executeWildcardTool, and runTool.
1582
+ * Handles arg parsing, subscriber notifications, handler invocation, result stringification,
1583
+ * and error handling.
1584
+ */
1585
+ async executeToolHandler({ tool, toolCall, agent, agentId, handlerArgs, toolType, messageId }) {
1586
+ let toolCallResult = "";
1587
+ let errorMessage;
1588
+ let isArgumentError = false;
1589
+ let parsedArgs;
1590
+ try {
1591
+ parsedArgs = parseToolArguments(handlerArgs, toolCall.function.name);
1592
+ } catch (error) {
1593
+ const parseError = error instanceof Error ? error : new Error(String(error));
1594
+ errorMessage = parseError.message;
1595
+ isArgumentError = true;
1596
+ await this._internal.emitError({
1597
+ error: parseError,
1598
+ code: CopilotKitCoreErrorCode.TOOL_ARGUMENT_PARSE_FAILED,
1599
+ context: {
1600
+ agentId,
1601
+ toolCallId: toolCall.id,
1602
+ toolName: toolCall.function.name,
1603
+ rawArguments: handlerArgs,
1604
+ toolType,
1605
+ ...messageId ? { messageId } : {}
1606
+ }
1607
+ });
1608
+ }
1609
+ await this._internal.notifySubscribers((subscriber) => subscriber.onToolExecutionStart?.({
1610
+ copilotkit: this.core,
1611
+ toolCallId: toolCall.id,
1612
+ agentId,
1613
+ toolName: toolCall.function.name,
1614
+ args: parsedArgs
1615
+ }), "Subscriber onToolExecutionStart error:");
1616
+ if (!errorMessage) try {
1617
+ const result = await tool.handler(parsedArgs, {
1618
+ toolCall,
1619
+ agent,
1620
+ signal: this._runAbortController?.signal
1621
+ });
1622
+ if (result === void 0 || result === null) toolCallResult = "";
1623
+ else if (typeof result === "string") toolCallResult = result;
1624
+ else toolCallResult = JSON.stringify(result);
1625
+ } catch (error) {
1626
+ const handlerError = error instanceof Error ? error : new Error(String(error));
1627
+ errorMessage = handlerError.message;
1628
+ await this._internal.emitError({
1629
+ error: handlerError,
1630
+ code: CopilotKitCoreErrorCode.TOOL_HANDLER_FAILED,
1631
+ context: {
1632
+ agentId,
1633
+ toolCallId: toolCall.id,
1634
+ toolName: toolCall.function.name,
1635
+ parsedArgs,
1636
+ toolType,
1637
+ ...messageId ? { messageId } : {}
1638
+ }
1639
+ });
1640
+ }
1641
+ if (errorMessage) toolCallResult = `Error: ${errorMessage}`;
1642
+ await this._internal.notifySubscribers((subscriber) => subscriber.onToolExecutionEnd?.({
1643
+ copilotkit: this.core,
1644
+ toolCallId: toolCall.id,
1645
+ agentId,
1646
+ toolName: toolCall.function.name,
1647
+ result: errorMessage ? "" : toolCallResult,
1648
+ error: errorMessage
1649
+ }), "Subscriber onToolExecutionEnd error:");
1650
+ return {
1651
+ result: toolCallResult,
1652
+ error: errorMessage,
1653
+ isArgumentError
1654
+ };
1655
+ }
1656
+ /**
1657
+ * Execute a specific tool
1658
+ */
1659
+ async executeSpecificTool(tool, toolCall, message, agent, agentId) {
1660
+ if (tool?.agentId && tool.agentId !== agent.agentId) return false;
1661
+ let handlerResult = {
1662
+ result: "",
1663
+ error: void 0,
1664
+ isArgumentError: false
1665
+ };
1666
+ if (tool?.handler) handlerResult = await this.executeToolHandler({
1667
+ tool,
1668
+ toolCall,
1669
+ agent,
1670
+ agentId,
1671
+ handlerArgs: toolCall.function.arguments,
1672
+ toolType: "specific",
1673
+ messageId: message.id
1674
+ });
1675
+ {
1676
+ const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
1677
+ if (messageIndex === -1) return false;
1678
+ const toolMessage = {
1679
+ id: randomUUID$1(),
1680
+ role: "tool",
1681
+ toolCallId: toolCall.id,
1682
+ content: handlerResult.result
1683
+ };
1684
+ agent.messages.splice(messageIndex + 1, 0, toolMessage);
1685
+ if (!handlerResult.error && tool?.followUp !== false) return true;
1686
+ }
1687
+ return false;
1688
+ }
1689
+ /**
1690
+ * Execute a wildcard tool.
1691
+ * Wildcard tools receive args wrapped as `{toolName, args}`, which differs from
1692
+ * specific tools, so this method keeps its own arg-wrapping logic rather than
1693
+ * delegating to `executeToolHandler`.
1694
+ */
1695
+ async executeWildcardTool(wildcardTool, toolCall, message, agent, agentId) {
1696
+ if (wildcardTool?.agentId && wildcardTool.agentId !== agent.agentId) return false;
1697
+ let toolCallResult = "";
1698
+ let errorMessage;
1699
+ if (wildcardTool?.handler) {
1700
+ let parsedArgs;
1701
+ try {
1702
+ parsedArgs = parseToolArguments(toolCall.function.arguments, toolCall.function.name);
1703
+ } catch (error) {
1704
+ const parseError = error instanceof Error ? error : new Error(String(error));
1705
+ errorMessage = parseError.message;
1706
+ await this._internal.emitError({
1707
+ error: parseError,
1708
+ code: CopilotKitCoreErrorCode.TOOL_ARGUMENT_PARSE_FAILED,
1709
+ context: {
1710
+ agentId,
1711
+ toolCallId: toolCall.id,
1712
+ toolName: toolCall.function.name,
1713
+ rawArguments: toolCall.function.arguments,
1714
+ toolType: "wildcard",
1715
+ messageId: message.id
1716
+ }
1717
+ });
1718
+ }
1719
+ const wildcardArgs = {
1720
+ toolName: toolCall.function.name,
1721
+ args: parsedArgs
1722
+ };
1723
+ await this._internal.notifySubscribers((subscriber) => subscriber.onToolExecutionStart?.({
1724
+ copilotkit: this.core,
1725
+ toolCallId: toolCall.id,
1726
+ agentId,
1727
+ toolName: toolCall.function.name,
1728
+ args: wildcardArgs
1729
+ }), "Subscriber onToolExecutionStart error:");
1730
+ if (!errorMessage) try {
1731
+ const result = await wildcardTool.handler(wildcardArgs, {
1732
+ toolCall,
1733
+ agent
1734
+ });
1735
+ if (result === void 0 || result === null) toolCallResult = "";
1736
+ else if (typeof result === "string") toolCallResult = result;
1737
+ else toolCallResult = JSON.stringify(result);
1738
+ } catch (error) {
1739
+ const handlerError = error instanceof Error ? error : new Error(String(error));
1740
+ errorMessage = handlerError.message;
1741
+ await this._internal.emitError({
1742
+ error: handlerError,
1743
+ code: CopilotKitCoreErrorCode.TOOL_HANDLER_FAILED,
1744
+ context: {
1745
+ agentId,
1746
+ toolCallId: toolCall.id,
1747
+ toolName: toolCall.function.name,
1748
+ parsedArgs: wildcardArgs,
1749
+ toolType: "wildcard",
1750
+ messageId: message.id
1751
+ }
1752
+ });
1753
+ }
1754
+ if (errorMessage) toolCallResult = `Error: ${errorMessage}`;
1755
+ await this._internal.notifySubscribers((subscriber) => subscriber.onToolExecutionEnd?.({
1756
+ copilotkit: this.core,
1757
+ toolCallId: toolCall.id,
1758
+ agentId,
1759
+ toolName: toolCall.function.name,
1760
+ result: errorMessage ? "" : toolCallResult,
1761
+ error: errorMessage
1762
+ }), "Subscriber onToolExecutionEnd error:");
1763
+ }
1764
+ {
1765
+ const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
1766
+ if (messageIndex === -1) return false;
1767
+ const toolMessage = {
1768
+ id: randomUUID$1(),
1769
+ role: "tool",
1770
+ toolCallId: toolCall.id,
1771
+ content: toolCallResult
1772
+ };
1773
+ agent.messages.splice(messageIndex + 1, 0, toolMessage);
1774
+ if (!errorMessage && wildcardTool?.followUp !== false) return true;
1775
+ }
1776
+ return false;
1777
+ }
1778
+ /**
1779
+ * Programmatically execute a registered frontend tool without going through an LLM turn.
1780
+ * The handler runs, render components show up in the UI, and both the tool call and
1781
+ * result messages are added to `agent.messages`.
1782
+ */
1783
+ async runTool(params) {
1784
+ const { name, agentId, parameters = {}, followUp = false } = params;
1785
+ const tool = this.getTool({
1786
+ toolName: name,
1787
+ agentId
1788
+ });
1789
+ if (!tool) {
1790
+ const error = /* @__PURE__ */ new Error(`Tool not found: ${name}`);
1791
+ await this._internal.emitError({
1792
+ error,
1793
+ code: CopilotKitCoreErrorCode.TOOL_NOT_FOUND,
1794
+ context: {
1795
+ toolName: name,
1796
+ agentId
1797
+ }
1798
+ });
1799
+ throw error;
1800
+ }
1801
+ const resolvedAgentId = agentId ?? "default";
1802
+ const agent = this._internal.getAgent(resolvedAgentId);
1803
+ if (!agent) {
1804
+ const error = /* @__PURE__ */ new Error(`Agent not found: ${resolvedAgentId}`);
1805
+ await this._internal.emitError({
1806
+ error,
1807
+ code: CopilotKitCoreErrorCode.AGENT_NOT_FOUND,
1808
+ context: { agentId: resolvedAgentId }
1809
+ });
1810
+ throw error;
1811
+ }
1812
+ const toolCallId = randomUUID$1();
1813
+ const assistantMessage = {
1814
+ id: randomUUID$1(),
1815
+ role: "assistant",
1816
+ content: "",
1817
+ toolCalls: [{
1818
+ id: toolCallId,
1819
+ type: "function",
1820
+ function: {
1821
+ name,
1822
+ arguments: JSON.stringify(parameters)
1823
+ }
1824
+ }]
1825
+ };
1826
+ agent.messages.push(assistantMessage);
1827
+ let handlerResult = {
1828
+ result: "",
1829
+ error: void 0,
1830
+ isArgumentError: false
1831
+ };
1832
+ if (tool.handler) handlerResult = await this.executeToolHandler({
1833
+ tool,
1834
+ toolCall: assistantMessage.toolCalls[0],
1835
+ agent,
1836
+ agentId: resolvedAgentId,
1837
+ handlerArgs: parameters,
1838
+ toolType: "runTool"
1839
+ });
1840
+ const toolResultMessage = {
1841
+ id: randomUUID$1(),
1842
+ role: "tool",
1843
+ toolCallId,
1844
+ content: handlerResult.result
1845
+ };
1846
+ const assistantIndex = agent.messages.findIndex((m) => m.id === assistantMessage.id);
1847
+ if (assistantIndex !== -1) agent.messages.splice(assistantIndex + 1, 0, toolResultMessage);
1848
+ else agent.messages.push(toolResultMessage);
1849
+ if (!handlerResult.error && followUp !== false) {
1850
+ if (typeof followUp === "string" && followUp !== "generate") {
1851
+ const userMessage = {
1852
+ id: randomUUID$1(),
1853
+ role: "user",
1854
+ content: followUp
1855
+ };
1856
+ agent.messages.push(userMessage);
1857
+ }
1858
+ await this._internal.waitForPendingFrameworkUpdates();
1859
+ await this.runAgent({ agent });
1860
+ }
1861
+ return {
1862
+ toolCallId,
1863
+ result: handlerResult.result,
1864
+ error: handlerResult.error
1865
+ };
1866
+ }
1867
+ /**
1868
+ * Build frontend tools for an agent
1869
+ */
1870
+ buildFrontendTools(agentId) {
1871
+ return this._tools.filter((tool) => tool.available !== false && (!tool.agentId || tool.agentId === agentId)).map((tool) => ({
1872
+ name: tool.name,
1873
+ description: tool.description ?? "",
1874
+ parameters: createToolSchema(tool)
1875
+ }));
1876
+ }
1877
+ /**
1878
+ * Create an agent error subscriber
1879
+ */
1880
+ createAgentErrorSubscriber(agent) {
1881
+ const emitAgentError = async (error, code, extraContext = {}) => {
1882
+ const context = { ...extraContext };
1883
+ if (agent.agentId) context.agentId = agent.agentId;
1884
+ await this._internal.emitError({
1885
+ error,
1886
+ code,
1887
+ context
1888
+ });
1889
+ };
1890
+ return {
1891
+ onRunFailed: async ({ error }) => {
1892
+ await emitAgentError(error, error instanceof AgentThreadLockedError ? CopilotKitCoreErrorCode.AGENT_THREAD_LOCKED : CopilotKitCoreErrorCode.AGENT_RUN_FAILED_EVENT, { source: "onRunFailed" });
1893
+ },
1894
+ onRunErrorEvent: async ({ event }) => {
1895
+ const eventError = event?.rawEvent instanceof Error ? event.rawEvent : event?.rawEvent?.error instanceof Error ? event.rawEvent.error : void 0;
1896
+ const errorMessage = typeof event?.rawEvent?.error === "string" ? event.rawEvent.error : event?.message ?? "Agent run error";
1897
+ const rawError = eventError ?? new Error(errorMessage);
1898
+ if (event?.code && !rawError.code) rawError.code = event.code;
1899
+ await emitAgentError(rawError, CopilotKitCoreErrorCode.AGENT_RUN_ERROR_EVENT, {
1900
+ source: "onRunErrorEvent",
1901
+ event,
1902
+ runtimeErrorCode: event?.code
1903
+ });
1904
+ }
1905
+ };
1906
+ }
1907
+ };
1908
+ /**
1909
+ * Empty tool schema constant
1910
+ */
1911
+ const EMPTY_TOOL_SCHEMA = {
1912
+ type: "object",
1913
+ properties: {}
1914
+ };
1915
+ /**
1916
+ * Create a JSON schema from a tool's parameters
1917
+ */
1918
+ function createToolSchema(tool) {
1919
+ if (!tool.parameters) return { ...EMPTY_TOOL_SCHEMA };
1920
+ const rawSchema = schemaToJsonSchema(tool.parameters, { zodToJsonSchema });
1921
+ if (!rawSchema || typeof rawSchema !== "object") return { ...EMPTY_TOOL_SCHEMA };
1922
+ const { $schema, ...schema } = rawSchema;
1923
+ if (typeof schema.type !== "string") schema.type = "object";
1924
+ if (typeof schema.properties !== "object" || schema.properties === null) schema.properties = {};
1925
+ stripAdditionalProperties(schema);
1926
+ return schema;
1927
+ }
1928
+ function stripAdditionalProperties(schema) {
1929
+ if (!schema || typeof schema !== "object") return;
1930
+ if (Array.isArray(schema)) {
1931
+ schema.forEach(stripAdditionalProperties);
1932
+ return;
1933
+ }
1934
+ const record = schema;
1935
+ if (record.additionalProperties !== void 0) delete record.additionalProperties;
1936
+ for (const value of Object.values(record)) stripAdditionalProperties(value);
1937
+ }
1938
+ /**
1939
+ * Ensures parsed tool arguments are a plain object.
1940
+ * Throws for non-object values so the caller's catch block can emit
1941
+ * a structured TOOL_ARGUMENT_PARSE_FAILED error.
1942
+ *
1943
+ * @internal Exported for testing only.
1944
+ */
1945
+ function ensureObjectArgs(parsed, toolName) {
1946
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
1947
+ throw new Error(`Tool arguments for ${toolName} parsed to non-object (${typeof parsed})`);
1948
+ }
1949
+ /**
1950
+ * Parses raw tool call arguments into a validated object.
1951
+ *
1952
+ * Some LLM providers (e.g. @ai-sdk/openai-compatible) may send empty string "",
1953
+ * null, or undefined instead of "{}". This function normalises those cases to an
1954
+ * empty object so callers don't crash on JSON.parse("").
1955
+ *
1956
+ * A debug-level warning is emitted when the fallback triggers so silent coercion
1957
+ * is observable in logs.
1958
+ *
1959
+ * @internal Exported for testing only.
1960
+ */
1961
+ function parseToolArguments(rawArgs, toolName) {
1962
+ if (rawArgs === "" || rawArgs === null || rawArgs === void 0) {
1963
+ logger.debug(`[parseToolArguments] Tool "${toolName}" received empty/null/undefined arguments — defaulting to {}`);
1964
+ return {};
1965
+ }
1966
+ return ensureObjectArgs(typeof rawArgs === "string" ? JSON.parse(rawArgs) : rawArgs, toolName);
1967
+ }
1968
+
1969
+ //#endregion
1970
+ //#region src/core/state-manager.ts
1971
+ /**
1972
+ * Manages state and message tracking by run for CopilotKitCore.
1973
+ * Tracks agent state snapshots and message-to-run associations.
1974
+ */
1975
+ var StateManager = class {
1976
+ stateByRun = /* @__PURE__ */ new Map();
1977
+ messageToRun = /* @__PURE__ */ new Map();
1978
+ agentSubscriptions = /* @__PURE__ */ new Map();
1979
+ constructor(core) {
1980
+ this.core = core;
1981
+ }
1982
+ /**
1983
+ * Initialize state tracking for an agent
1984
+ */
1985
+ initialize() {}
1986
+ /**
1987
+ * Subscribe to an agent's events to track state and messages
1988
+ */
1989
+ subscribeToAgent(agent) {
1990
+ if (!agent.agentId) return;
1991
+ const agentId = agent.agentId;
1992
+ this.unsubscribeFromAgent(agentId);
1993
+ const { unsubscribe } = agent.subscribe({
1994
+ onRunStartedEvent: ({ event, state }) => {
1995
+ this.handleRunStarted(agent, event, state);
1996
+ },
1997
+ onRunFinishedEvent: ({ event, state }) => {
1998
+ this.handleRunFinished(agent, event, state);
1999
+ },
2000
+ onStateSnapshotEvent: ({ event, input, state }) => {
2001
+ this.handleStateSnapshot(agent, event, input, state);
2002
+ },
2003
+ onStateDeltaEvent: ({ event, input, state }) => {
2004
+ this.handleStateDelta(agent, event, input, state);
2005
+ },
2006
+ onMessagesSnapshotEvent: ({ event, input, messages }) => {
2007
+ this.handleMessagesSnapshot(agent, event, input, messages);
2008
+ },
2009
+ onNewMessage: ({ message, input }) => {
2010
+ this.handleNewMessage(agent, message, input);
2011
+ }
2012
+ });
2013
+ this.agentSubscriptions.set(agentId, unsubscribe);
2014
+ }
2015
+ /**
2016
+ * Unsubscribe from an agent's events
2017
+ */
2018
+ unsubscribeFromAgent(agentId) {
2019
+ const unsubscribe = this.agentSubscriptions.get(agentId);
2020
+ if (unsubscribe) {
2021
+ unsubscribe();
2022
+ this.agentSubscriptions.delete(agentId);
2023
+ }
2024
+ }
2025
+ /**
2026
+ * Get state for a specific run
2027
+ * Returns a deep copy to prevent external mutations
2028
+ */
2029
+ getStateByRun(agentId, threadId, runId) {
2030
+ const state = this.stateByRun.get(agentId)?.get(threadId)?.get(runId);
2031
+ if (!state) return void 0;
2032
+ return JSON.parse(JSON.stringify(state));
2033
+ }
2034
+ /**
2035
+ * Get runId associated with a message
2036
+ */
2037
+ getRunIdForMessage(agentId, threadId, messageId) {
2038
+ return this.messageToRun.get(agentId)?.get(threadId)?.get(messageId);
2039
+ }
2040
+ /**
2041
+ * Get all states for an agent's thread
2042
+ */
2043
+ getStatesForThread(agentId, threadId) {
2044
+ return this.stateByRun.get(agentId)?.get(threadId) ?? /* @__PURE__ */ new Map();
2045
+ }
2046
+ /**
2047
+ * Get all run IDs for an agent's thread
2048
+ */
2049
+ getRunIdsForThread(agentId, threadId) {
2050
+ const threadStates = this.stateByRun.get(agentId)?.get(threadId);
2051
+ return threadStates ? Array.from(threadStates.keys()) : [];
2052
+ }
2053
+ /**
2054
+ * Handle run started event
2055
+ */
2056
+ handleRunStarted(agent, event, state) {
2057
+ if (!agent.agentId) return;
2058
+ const { threadId, runId } = event;
2059
+ this.saveState(agent.agentId, threadId, runId, state);
2060
+ }
2061
+ /**
2062
+ * Handle run finished event
2063
+ */
2064
+ handleRunFinished(agent, event, state) {
2065
+ if (!agent.agentId) return;
2066
+ const { threadId, runId } = event;
2067
+ this.saveState(agent.agentId, threadId, runId, state);
2068
+ }
2069
+ /**
2070
+ * Handle state snapshot event
2071
+ */
2072
+ handleStateSnapshot(agent, event, input, state) {
2073
+ if (!agent.agentId) return;
2074
+ const { threadId, runId } = input;
2075
+ const mergedState = {
2076
+ ...state,
2077
+ ...event.snapshot
2078
+ };
2079
+ this.saveState(agent.agentId, threadId, runId, mergedState);
2080
+ }
2081
+ /**
2082
+ * Handle state delta event
2083
+ */
2084
+ handleStateDelta(agent, event, input, state) {
2085
+ if (!agent.agentId) return;
2086
+ const { threadId, runId } = input;
2087
+ this.saveState(agent.agentId, threadId, runId, state);
2088
+ }
2089
+ /**
2090
+ * Handle messages snapshot event
2091
+ */
2092
+ handleMessagesSnapshot(agent, event, input, messages) {
2093
+ if (!agent.agentId) return;
2094
+ const { threadId, runId } = input;
2095
+ for (const message of event.messages) this.associateMessageWithRun(agent.agentId, threadId, message.id, runId);
2096
+ }
2097
+ /**
2098
+ * Handle new message event
2099
+ */
2100
+ handleNewMessage(agent, message, input) {
2101
+ if (!agent.agentId || !input) return;
2102
+ const { threadId, runId } = input;
2103
+ this.associateMessageWithRun(agent.agentId, threadId, message.id, runId);
2104
+ }
2105
+ /**
2106
+ * Save state for a specific run
2107
+ */
2108
+ saveState(agentId, threadId, runId, state) {
2109
+ if (!this.stateByRun.has(agentId)) this.stateByRun.set(agentId, /* @__PURE__ */ new Map());
2110
+ const agentStates = this.stateByRun.get(agentId);
2111
+ if (!agentStates.has(threadId)) agentStates.set(threadId, /* @__PURE__ */ new Map());
2112
+ agentStates.get(threadId).set(runId, JSON.parse(JSON.stringify(state)));
2113
+ }
2114
+ /**
2115
+ * Associate a message with a run
2116
+ */
2117
+ associateMessageWithRun(agentId, threadId, messageId, runId) {
2118
+ if (!this.messageToRun.has(agentId)) this.messageToRun.set(agentId, /* @__PURE__ */ new Map());
2119
+ const agentMessages = this.messageToRun.get(agentId);
2120
+ if (!agentMessages.has(threadId)) agentMessages.set(threadId, /* @__PURE__ */ new Map());
2121
+ agentMessages.get(threadId).set(messageId, runId);
2122
+ }
2123
+ /**
2124
+ * Clear all state for an agent
2125
+ */
2126
+ clearAgentState(agentId) {
2127
+ this.stateByRun.delete(agentId);
2128
+ this.messageToRun.delete(agentId);
2129
+ }
2130
+ /**
2131
+ * Clear all state for a thread
2132
+ */
2133
+ clearThreadState(agentId, threadId) {
2134
+ this.stateByRun.get(agentId)?.delete(threadId);
2135
+ this.messageToRun.get(agentId)?.delete(threadId);
2136
+ }
2137
+ };
2138
+
2139
+ //#endregion
2140
+ //#region src/core/core.ts
2141
+ let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode) {
2142
+ CopilotKitCoreErrorCode["RUNTIME_INFO_FETCH_FAILED"] = "runtime_info_fetch_failed";
2143
+ CopilotKitCoreErrorCode["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
2144
+ CopilotKitCoreErrorCode["AGENT_RUN_FAILED"] = "agent_run_failed";
2145
+ CopilotKitCoreErrorCode["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
2146
+ CopilotKitCoreErrorCode["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
2147
+ CopilotKitCoreErrorCode["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
2148
+ CopilotKitCoreErrorCode["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
2149
+ CopilotKitCoreErrorCode["TOOL_NOT_FOUND"] = "tool_not_found";
2150
+ CopilotKitCoreErrorCode["AGENT_NOT_FOUND"] = "agent_not_found";
2151
+ /**
2152
+ * Emitted when an agent run fails because the thread is already locked
2153
+ * by another active run.
2154
+ *
2155
+ * @example
2156
+ * ```tsx
2157
+ * <CopilotKitProvider
2158
+ * onError={({ code, error, context }) => {
2159
+ * if (code === "agent_thread_locked") {
2160
+ * // Show "Agent is busy, retry?" UI
2161
+ * }
2162
+ * }}
2163
+ * />
2164
+ * ```
2165
+ */
2166
+ CopilotKitCoreErrorCode["AGENT_THREAD_LOCKED"] = "agent_thread_locked";
2167
+ CopilotKitCoreErrorCode["TRANSCRIPTION_FAILED"] = "transcription_failed";
2168
+ CopilotKitCoreErrorCode["TRANSCRIPTION_SERVICE_NOT_CONFIGURED"] = "transcription_service_not_configured";
2169
+ CopilotKitCoreErrorCode["TRANSCRIPTION_INVALID_AUDIO"] = "transcription_invalid_audio";
2170
+ CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
2171
+ CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
2172
+ CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
2173
+ return CopilotKitCoreErrorCode;
2174
+ }({});
2175
+ let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
2176
+ CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
2177
+ CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
2178
+ CopilotKitCoreRuntimeConnectionStatus["Connecting"] = "connecting";
2179
+ CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
2180
+ return CopilotKitCoreRuntimeConnectionStatus;
2181
+ }({});
2182
+ var CopilotKitCore = class {
2183
+ _headers;
2184
+ _credentials;
2185
+ _properties;
2186
+ subscribers = /* @__PURE__ */ new Set();
2187
+ agentRegistry;
2188
+ contextStore;
2189
+ suggestionEngine;
2190
+ runHandler;
2191
+ stateManager;
2192
+ constructor({ runtimeUrl, runtimeTransport = "rest", headers = {}, credentials, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [] }) {
2193
+ this._headers = headers;
2194
+ this._credentials = credentials;
2195
+ this._properties = properties;
2196
+ this.agentRegistry = new AgentRegistry(this);
2197
+ this.contextStore = new ContextStore(this);
2198
+ this.suggestionEngine = new SuggestionEngine(this);
2199
+ this.runHandler = new RunHandler(this);
2200
+ this.stateManager = new StateManager(this);
2201
+ this.agentRegistry.initialize(agents__unsafe_dev_only);
2202
+ this.runHandler.initialize(tools);
2203
+ this.suggestionEngine.initialize(suggestionsConfig);
2204
+ this.stateManager.initialize();
2205
+ this.agentRegistry.setRuntimeTransport(runtimeTransport);
2206
+ this.agentRegistry.setRuntimeUrl(runtimeUrl);
2207
+ this.subscribe({ onAgentsChanged: ({ agents }) => {
2208
+ Object.values(agents).forEach((agent) => {
2209
+ if (agent.agentId) this.stateManager.subscribeToAgent(agent);
2210
+ });
2211
+ } });
2212
+ }
2213
+ /**
2214
+ * Internal method used by delegate classes and subclasses to notify subscribers
2215
+ */
2216
+ async notifySubscribers(handler, errorMessage) {
2217
+ await Promise.all(Array.from(this.subscribers).map(async (subscriber) => {
2218
+ try {
2219
+ await handler(subscriber);
2220
+ } catch (error) {
2221
+ console.error(errorMessage, error);
2222
+ }
2223
+ }));
2224
+ }
2225
+ /**
2226
+ * Internal method used by delegate classes to emit errors
2227
+ */
2228
+ async emitError({ error, code, context = {} }) {
2229
+ await this.notifySubscribers((subscriber) => subscriber.onError?.({
2230
+ copilotkit: this,
2231
+ error,
2232
+ code,
2233
+ context
2234
+ }), "Subscriber onError error:");
2235
+ }
2236
+ /**
2237
+ * Snapshot accessors
2238
+ */
2239
+ get context() {
2240
+ return this.contextStore.context;
2241
+ }
2242
+ get agents() {
2243
+ return this.agentRegistry.agents;
2244
+ }
2245
+ get tools() {
2246
+ return this.runHandler.tools;
2247
+ }
2248
+ get runtimeUrl() {
2249
+ return this.agentRegistry.runtimeUrl;
2250
+ }
2251
+ setRuntimeUrl(runtimeUrl) {
2252
+ this.agentRegistry.setRuntimeUrl(runtimeUrl);
2253
+ }
2254
+ get runtimeTransport() {
2255
+ return this.agentRegistry.runtimeTransport;
2256
+ }
2257
+ setRuntimeTransport(runtimeTransport) {
2258
+ this.agentRegistry.setRuntimeTransport(runtimeTransport);
2259
+ }
2260
+ get runtimeVersion() {
2261
+ return this.agentRegistry.runtimeVersion;
2262
+ }
2263
+ get headers() {
2264
+ return this._headers;
2265
+ }
2266
+ get credentials() {
2267
+ return this._credentials;
2268
+ }
2269
+ get properties() {
2270
+ return this._properties;
2271
+ }
2272
+ get runtimeConnectionStatus() {
2273
+ return this.agentRegistry.runtimeConnectionStatus;
2274
+ }
2275
+ get audioFileTranscriptionEnabled() {
2276
+ return this.agentRegistry.audioFileTranscriptionEnabled;
2277
+ }
2278
+ get runtimeMode() {
2279
+ return this.agentRegistry.runtimeMode;
2280
+ }
2281
+ get intelligence() {
2282
+ return this.agentRegistry.intelligence;
2283
+ }
2284
+ get a2uiEnabled() {
2285
+ return this.agentRegistry.a2uiEnabled;
2286
+ }
2287
+ get licenseStatus() {
2288
+ return this.agentRegistry.licenseStatus;
2289
+ }
2290
+ /**
2291
+ * Configuration updates
2292
+ */
2293
+ setHeaders(headers) {
2294
+ this._headers = headers;
2295
+ this.agentRegistry.applyHeadersToAgents(this.agentRegistry.agents);
2296
+ this.notifySubscribers((subscriber) => subscriber.onHeadersChanged?.({
2297
+ copilotkit: this,
2298
+ headers: this.headers
2299
+ }), "Subscriber onHeadersChanged error:");
2300
+ }
2301
+ setCredentials(credentials) {
2302
+ this._credentials = credentials;
2303
+ this.agentRegistry.applyCredentialsToAgents(this.agentRegistry.agents);
2304
+ }
2305
+ setProperties(properties) {
2306
+ this._properties = properties;
2307
+ this.notifySubscribers((subscriber) => subscriber.onPropertiesChanged?.({
2308
+ copilotkit: this,
2309
+ properties: this.properties
2310
+ }), "Subscriber onPropertiesChanged error:");
2311
+ }
2312
+ /**
2313
+ * Agent management (delegated to AgentRegistry)
2314
+ */
2315
+ setAgents__unsafe_dev_only(agents) {
2316
+ this.agentRegistry.setAgents__unsafe_dev_only(agents);
2317
+ }
2318
+ addAgent__unsafe_dev_only(params) {
2319
+ this.agentRegistry.addAgent__unsafe_dev_only(params);
2320
+ }
2321
+ removeAgent__unsafe_dev_only(id) {
2322
+ this.agentRegistry.removeAgent__unsafe_dev_only(id);
2323
+ }
2324
+ getAgent(id) {
2325
+ return this.agentRegistry.getAgent(id);
2326
+ }
2327
+ /**
2328
+ * Context management (delegated to ContextStore)
2329
+ */
2330
+ addContext(context) {
2331
+ return this.contextStore.addContext(context);
2332
+ }
2333
+ removeContext(id) {
2334
+ this.contextStore.removeContext(id);
2335
+ }
2336
+ /**
2337
+ * Suggestions management (delegated to SuggestionEngine)
2338
+ */
2339
+ addSuggestionsConfig(config) {
2340
+ return this.suggestionEngine.addSuggestionsConfig(config);
2341
+ }
2342
+ removeSuggestionsConfig(id) {
2343
+ this.suggestionEngine.removeSuggestionsConfig(id);
2344
+ }
2345
+ reloadSuggestions(agentId) {
2346
+ this.suggestionEngine.reloadSuggestions(agentId);
2347
+ }
2348
+ clearSuggestions(agentId) {
2349
+ this.suggestionEngine.clearSuggestions(agentId);
2350
+ }
2351
+ getSuggestions(agentId) {
2352
+ return this.suggestionEngine.getSuggestions(agentId);
2353
+ }
2354
+ /**
2355
+ * Tool management (delegated to RunHandler)
2356
+ */
2357
+ addTool(tool) {
2358
+ this.runHandler.addTool(tool);
2359
+ }
2360
+ removeTool(id, agentId) {
2361
+ this.runHandler.removeTool(id, agentId);
2362
+ }
2363
+ getTool(params) {
2364
+ return this.runHandler.getTool(params);
2365
+ }
2366
+ setTools(tools) {
2367
+ this.runHandler.setTools(tools);
2368
+ }
2369
+ /**
2370
+ * Subscription lifecycle
2371
+ */
2372
+ subscribe(subscriber) {
2373
+ this.subscribers.add(subscriber);
2374
+ return { unsubscribe: () => {
2375
+ this.subscribers.delete(subscriber);
2376
+ } };
2377
+ }
2378
+ /**
2379
+ * Agent connectivity (delegated to RunHandler)
2380
+ */
2381
+ async connectAgent(params) {
2382
+ return this.runHandler.connectAgent(params);
2383
+ }
2384
+ stopAgent(params) {
2385
+ this.runHandler.abortCurrentRun();
2386
+ params.agent.abortRun();
2387
+ }
2388
+ async runAgent(params) {
2389
+ return this.runHandler.runAgent(params);
2390
+ }
2391
+ /**
2392
+ * Programmatically execute a registered frontend tool without going through an LLM turn.
2393
+ * The handler runs, render components show up in the UI, and both the tool call and
2394
+ * result messages are added to `agent.messages`.
2395
+ */
2396
+ async runTool(params) {
2397
+ return this.runHandler.runTool(params);
2398
+ }
2399
+ /**
2400
+ * State management (delegated to StateManager)
2401
+ */
2402
+ getStateByRun(agentId, threadId, runId) {
2403
+ return this.stateManager.getStateByRun(agentId, threadId, runId);
2404
+ }
2405
+ getRunIdForMessage(agentId, threadId, messageId) {
2406
+ return this.stateManager.getRunIdForMessage(agentId, threadId, messageId);
2407
+ }
2408
+ getRunIdsForThread(agentId, threadId) {
2409
+ return this.stateManager.getRunIdsForThread(agentId, threadId);
2410
+ }
2411
+ /**
2412
+ * Internal method used by RunHandler to build frontend tools
2413
+ */
2414
+ buildFrontendTools(agentId) {
2415
+ return this.runHandler.buildFrontendTools(agentId);
2416
+ }
2417
+ /**
2418
+ * Called before each follow-up agent run (after tool execution).
2419
+ *
2420
+ * When a frontend tool handler calls framework state setters (e.g. React's
2421
+ * setState), those updates are batched and deferred — they do not take effect
2422
+ * until the framework's scheduler runs (React uses MessageChannel).
2423
+ * useAgentContext registers context via useLayoutEffect, which runs
2424
+ * synchronously after React commits that deferred batch.
2425
+ *
2426
+ * Without yielding here, the follow-up runAgent reads the context store
2427
+ * synchronously while the deferred updates are still pending, producing stale
2428
+ * context for the next agent turn.
2429
+ *
2430
+ * Override in framework-specific subclasses to yield to the framework
2431
+ * scheduler before the follow-up run. The base implementation is a no-op
2432
+ * because non-React environments have no deferred state to flush.
2433
+ */
2434
+ async waitForPendingFrameworkUpdates() {}
2435
+ };
2436
+
2437
+ //#endregion
2438
+ //#region src/types.ts
2439
+ /**
2440
+ * Status of a tool call execution
2441
+ */
2442
+ let ToolCallStatus = /* @__PURE__ */ function(ToolCallStatus) {
2443
+ ToolCallStatus["InProgress"] = "inProgress";
2444
+ ToolCallStatus["Executing"] = "executing";
2445
+ ToolCallStatus["Complete"] = "complete";
2446
+ return ToolCallStatus;
2447
+ }({});
2448
+
2449
+ //#endregion
2450
+ //#region src/utils/markdown.ts
2451
+ function completePartialMarkdown(input) {
2452
+ let s = input;
2453
+ const fenceMatches = Array.from(s.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
2454
+ if (fenceMatches.length % 2 === 1) {
2455
+ const [, indent, fence] = fenceMatches[0];
2456
+ s += `\n${indent}${fence}`;
2457
+ }
2458
+ if (s.match(/\[([^\]]*)\]\(([^)]*)$/)) s += ")";
2459
+ const openElements = [];
2460
+ const chars = Array.from(s);
2461
+ const codeBlockRanges = [];
2462
+ const inlineCodeRanges = [];
2463
+ let tempCodeFenceCount = 0;
2464
+ let currentCodeBlockStart = -1;
2465
+ for (let i = 0; i < chars.length; i++) if (i === 0 || chars[i - 1] === "\n") {
2466
+ const lineMatch = s.substring(i).match(/^(\s*)(`{3,}|~{3,})/);
2467
+ if (lineMatch) {
2468
+ tempCodeFenceCount++;
2469
+ if (tempCodeFenceCount % 2 === 1) currentCodeBlockStart = i;
2470
+ else if (currentCodeBlockStart !== -1) {
2471
+ codeBlockRanges.push({
2472
+ start: currentCodeBlockStart,
2473
+ end: i + lineMatch[0].length
2474
+ });
2475
+ currentCodeBlockStart = -1;
2476
+ }
2477
+ i += lineMatch[0].length - 1;
2478
+ }
2479
+ }
2480
+ for (let i = 0; i < chars.length; i++) if (chars[i] === "`") {
2481
+ let backslashCount = 0;
2482
+ for (let j = i - 1; j >= 0 && chars[j] === "\\"; j--) backslashCount++;
2483
+ if (backslashCount % 2 === 0) {
2484
+ for (let j = i + 1; j < chars.length; j++) if (chars[j] === "`") {
2485
+ let closingBackslashCount = 0;
2486
+ for (let k = j - 1; k >= 0 && chars[k] === "\\"; k--) closingBackslashCount++;
2487
+ if (closingBackslashCount % 2 === 0) {
2488
+ inlineCodeRanges.push({
2489
+ start: i,
2490
+ end: j + 1
2491
+ });
2492
+ i = j;
2493
+ break;
2494
+ }
2495
+ }
2496
+ }
2497
+ }
2498
+ const isInCode = (pos) => {
2499
+ return codeBlockRanges.some((range) => pos >= range.start && pos < range.end) || inlineCodeRanges.some((range) => pos >= range.start && pos < range.end);
2500
+ };
2501
+ for (let i = 0; i < chars.length; i++) {
2502
+ const char = chars[i];
2503
+ const nextChar = chars[i + 1];
2504
+ const prevChar = chars[i - 1];
2505
+ if (isInCode(i)) continue;
2506
+ if (char === "[") {
2507
+ let isCompleteLink = false;
2508
+ let bracketDepth = 1;
2509
+ let j = i + 1;
2510
+ while (j < chars.length && bracketDepth > 0) {
2511
+ if (chars[j] === "[" && !isInCode(j)) bracketDepth++;
2512
+ if (chars[j] === "]" && !isInCode(j)) bracketDepth--;
2513
+ j++;
2514
+ }
2515
+ if (bracketDepth === 0 && chars[j] === "(") {
2516
+ let parenDepth = 1;
2517
+ j++;
2518
+ while (j < chars.length && parenDepth > 0) {
2519
+ if (chars[j] === "(" && !isInCode(j)) parenDepth++;
2520
+ if (chars[j] === ")" && !isInCode(j)) parenDepth--;
2521
+ j++;
2522
+ }
2523
+ if (parenDepth === 0) {
2524
+ isCompleteLink = true;
2525
+ i = j - 1;
2526
+ continue;
2527
+ }
2528
+ }
2529
+ if (!isCompleteLink) {
2530
+ const existingIndex = openElements.findIndex((el) => el.type === "bracket");
2531
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
2532
+ else openElements.push({
2533
+ type: "bracket",
2534
+ marker: "[",
2535
+ position: i
2536
+ });
2537
+ }
2538
+ } else if (char === "*" && nextChar === "*") {
2539
+ const existingIndex = openElements.findIndex((el) => el.type === "bold_star");
2540
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
2541
+ else openElements.push({
2542
+ type: "bold_star",
2543
+ marker: "**",
2544
+ position: i
2545
+ });
2546
+ i++;
2547
+ } else if (char === "_" && nextChar === "_") {
2548
+ const existingIndex = openElements.findIndex((el) => el.type === "bold_underscore");
2549
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
2550
+ else openElements.push({
2551
+ type: "bold_underscore",
2552
+ marker: "__",
2553
+ position: i
2554
+ });
2555
+ i++;
2556
+ } else if (char === "~" && nextChar === "~") {
2557
+ const existingIndex = openElements.findIndex((el) => el.type === "strike");
2558
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
2559
+ else openElements.push({
2560
+ type: "strike",
2561
+ marker: "~~",
2562
+ position: i
2563
+ });
2564
+ i++;
2565
+ } else if (char === "*" && prevChar !== "*" && nextChar !== "*") {
2566
+ const existingIndex = openElements.findIndex((el) => el.type === "italic_star");
2567
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
2568
+ else openElements.push({
2569
+ type: "italic_star",
2570
+ marker: "*",
2571
+ position: i
2572
+ });
2573
+ } else if (char === "_" && prevChar !== "_" && nextChar !== "_") {
2574
+ const existingIndex = openElements.findIndex((el) => el.type === "italic_underscore");
2575
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
2576
+ else openElements.push({
2577
+ type: "italic_underscore",
2578
+ marker: "_",
2579
+ position: i
2580
+ });
2581
+ }
2582
+ }
2583
+ let backtickCount = 0;
2584
+ for (let i = 0; i < chars.length; i++) if (chars[i] === "`" && !isInCode(i)) backtickCount++;
2585
+ if (backtickCount % 2 === 1) s += "`";
2586
+ openElements.sort((a, b) => b.position - a.position);
2587
+ const closers = openElements.map((el) => {
2588
+ switch (el.type) {
2589
+ case "bracket": return "]";
2590
+ case "bold_star": return "**";
2591
+ case "bold_underscore": return "__";
2592
+ case "strike": return "~~";
2593
+ case "italic_star": return "*";
2594
+ case "italic_underscore": return "_";
2595
+ default: return "";
2596
+ }
2597
+ });
2598
+ let result = s + closers.join("");
2599
+ const finalFenceMatches = Array.from(result.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
2600
+ const hasUnclosedBacktick = (result.match(/`/g) || []).length % 2 === 1;
2601
+ const hasUnclosedCodeFence = finalFenceMatches.length % 2 === 1;
2602
+ let shouldCloseParens = !hasUnclosedBacktick && !hasUnclosedCodeFence;
2603
+ if (shouldCloseParens) {
2604
+ const lastOpenParen = result.lastIndexOf("(");
2605
+ if (lastOpenParen !== -1) {
2606
+ if ((result.substring(0, lastOpenParen).match(/`/g) || []).length % 2 === 1) shouldCloseParens = false;
2607
+ }
2608
+ }
2609
+ if (shouldCloseParens) {
2610
+ const openParens = (result.match(/\(/g) || []).length;
2611
+ const closeParens = (result.match(/\)/g) || []).length;
2612
+ if (openParens > closeParens) result += ")".repeat(openParens - closeParens);
2613
+ }
2614
+ return result;
2615
+ }
2616
+
2617
+ //#endregion
2618
+ //#region src/utils/micro-redux.ts
2619
+ const INTERNAL_ACTION_TYPES = {
2620
+ boot: "@@micro-redux/boot",
2621
+ init: "@@micro-redux/init",
2622
+ stop: "@@micro-redux/stop"
2623
+ };
2624
+ const INTERNAL_BOOT_ACTION = { type: INTERNAL_ACTION_TYPES.boot };
2625
+ /**
2626
+ * Builds a typed action creator from a type string and payload factory.
2627
+ */
2628
+ function createTypedActionCreator(type, factory) {
2629
+ const creator = ((...args) => ({
2630
+ ...factory(...args),
2631
+ type
2632
+ }));
2633
+ creator.type = type;
2634
+ creator.match = (action) => action.type === type;
2635
+ return creator;
2636
+ }
2637
+ /**
2638
+ * Declares a payload-based action config for `createActionGroup`.
2639
+ *
2640
+ * @example
2641
+ * ```ts
2642
+ * const actions = createActionGroup("User", {
2643
+ * loaded: props<{ id: string }>(),
2644
+ * });
2645
+ * ```
2646
+ */
2647
+ function props() {
2648
+ return { kind: "props" };
2649
+ }
2650
+ /**
2651
+ * Declares a no-payload action config for `createActionGroup`.
2652
+ *
2653
+ * @example
2654
+ * ```ts
2655
+ * const actions = createActionGroup("User", {
2656
+ * reset: empty(),
2657
+ * });
2658
+ * ```
2659
+ */
2660
+ function empty() {
2661
+ return { kind: "empty" };
2662
+ }
2663
+ /**
2664
+ * Creates a namespaced group of typed action creators.
2665
+ *
2666
+ * Action types are formatted as: `[Source] actionName`.
2667
+ */
2668
+ function createActionGroup(source, config) {
2669
+ const group = {};
2670
+ for (const eventName of Object.keys(config)) {
2671
+ const eventConfig = config[eventName];
2672
+ if (!eventConfig) continue;
2673
+ const actionType = `[${source}] ${eventName}`;
2674
+ if (eventConfig.kind === "props") {
2675
+ group[eventName] = createTypedActionCreator(actionType, (payload) => ({ ...payload }));
2676
+ continue;
2677
+ }
2678
+ group[eventName] = createTypedActionCreator(actionType, () => ({}));
2679
+ }
2680
+ return group;
2681
+ }
2682
+ /**
2683
+ * Registers one reducer handler for one or more action creators.
2684
+ *
2685
+ * @throws Error when called without at least one action creator and reducer.
2686
+ */
2687
+ function on(...args) {
2688
+ if (args.length < 2) throw new Error("on requires at least one action creator and one reducer");
2689
+ const reducer = args[args.length - 1];
2690
+ return {
2691
+ creators: args.slice(0, -1),
2692
+ reducer
2693
+ };
2694
+ }
2695
+ /**
2696
+ * Creates a reducer from an initial state and `on(...)` handler entries.
2697
+ *
2698
+ * Unknown action types return the current state unchanged.
2699
+ */
2700
+ function createReducer(initialState, ...entries) {
2701
+ const reducerMap = /* @__PURE__ */ new Map();
2702
+ for (const entry of entries) for (const creator of entry.creators) {
2703
+ const handlers = reducerMap.get(creator.type) ?? [];
2704
+ handlers.push(entry.reducer);
2705
+ reducerMap.set(creator.type, handlers);
2706
+ }
2707
+ return (state, action) => {
2708
+ const currentState = state ?? initialState;
2709
+ const handlers = reducerMap.get(action.type);
2710
+ if (!handlers || handlers.length === 0) return currentState;
2711
+ let nextState = currentState;
2712
+ for (const handler of handlers) nextState = handler(nextState, action);
2713
+ return nextState;
2714
+ };
2715
+ }
2716
+ /**
2717
+ * Creates a selector that caches and reuses the last computed result
2718
+ * when all input references are unchanged.
2719
+ */
2720
+ function createSelector(...args) {
2721
+ if (args.length === 1) {
2722
+ const projector = args[0];
2723
+ let hasCached = false;
2724
+ let lastState;
2725
+ let lastResult;
2726
+ return (state) => {
2727
+ if (hasCached && state === lastState) return lastResult;
2728
+ lastState = state;
2729
+ lastResult = projector(state);
2730
+ hasCached = true;
2731
+ return lastResult;
2732
+ };
2733
+ }
2734
+ const projector = args[args.length - 1];
2735
+ const selectors = args.slice(0, -1);
2736
+ let hasCached = false;
2737
+ let lastInputs = [];
2738
+ let lastResult;
2739
+ return (state) => {
2740
+ const inputs = selectors.map((selector) => selector(state));
2741
+ if (hasCached && inputs.length === lastInputs.length && inputs.every((value, index) => value === lastInputs[index])) return lastResult;
2742
+ lastInputs = inputs;
2743
+ lastResult = projector(...inputs);
2744
+ hasCached = true;
2745
+ return lastResult;
2746
+ };
2747
+ }
2748
+ /**
2749
+ * RxJS operator that maps state emissions through a selector and suppresses
2750
+ * unchanged projected values via reference equality.
2751
+ */
2752
+ function select(selector) {
2753
+ return (source$) => source$.pipe(map(selector), distinctUntilChanged());
2754
+ }
2755
+ /**
2756
+ * RxJS operator that filters an action stream by action creators and narrows
2757
+ * the output action type to the matched creator union.
2758
+ *
2759
+ * @throws Error when called without at least one action creator.
2760
+ */
2761
+ function ofType(...creators) {
2762
+ if (creators.length === 0) throw new Error("ofType requires at least one action creator");
2763
+ const actionTypes = new Set(creators.map((creator) => creator.type));
2764
+ return (source$) => {
2765
+ return source$.pipe(filter((action) => {
2766
+ return actionTypes.has(action.type);
2767
+ }));
2768
+ };
2769
+ }
2770
+ /**
2771
+ * Creates an effect descriptor consumed by `createStore`.
2772
+ */
2773
+ function createEffect(factory, options = {}) {
2774
+ if (options.dispatch === false) return {
2775
+ run: factory,
2776
+ dispatch: false
2777
+ };
2778
+ return {
2779
+ run: factory,
2780
+ dispatch: true
2781
+ };
2782
+ }
2783
+ /**
2784
+ * Creates a small observable store with reducer + effects.
2785
+ *
2786
+ * Behavior:
2787
+ * - `init()` starts effects and dispatches `@@micro-redux/init`.
2788
+ * - `stop()` dispatches `@@micro-redux/stop` and unsubscribes all effects.
2789
+ * - Effect action observation is scheduled on `asapScheduler` to avoid
2790
+ * synchronous re-entrancy in the effect loop.
2791
+ * - Any effect error triggers fail-fast teardown and errors both `actions$`
2792
+ * and `state$`.
2793
+ */
2794
+ function createStore(options) {
2795
+ const reducer = options.reducer;
2796
+ const effects = options.effects ?? [];
2797
+ let hasFatalError = false;
2798
+ let isRunning = false;
2799
+ let effectSubscriptions = new Subscription();
2800
+ let currentState = reducer(void 0, INTERNAL_BOOT_ACTION);
2801
+ const stateSubject = new BehaviorSubject(currentState);
2802
+ const actionsSubject = new Subject();
2803
+ const dispatchInternal = (action) => {
2804
+ if (hasFatalError) throw new Error("Store is in a failed state due to an effect error");
2805
+ currentState = reducer(currentState, action);
2806
+ stateSubject.next(currentState);
2807
+ actionsSubject.next(action);
2808
+ };
2809
+ const failFast = (error) => {
2810
+ if (hasFatalError) return;
2811
+ hasFatalError = true;
2812
+ isRunning = false;
2813
+ effectSubscriptions.unsubscribe();
2814
+ effectSubscriptions = new Subscription();
2815
+ actionsSubject.error(error);
2816
+ stateSubject.error(error);
2817
+ };
2818
+ const startEffects = () => {
2819
+ for (const effect of effects) {
2820
+ const scheduledActions$ = actionsSubject.asObservable().pipe(observeOn(asapScheduler));
2821
+ const state$ = stateSubject.asObservable();
2822
+ if (effect.dispatch) {
2823
+ const subscription = effect.run(scheduledActions$, state$).subscribe({
2824
+ next: (effectAction) => {
2825
+ if (hasFatalError) return;
2826
+ dispatchInternal(effectAction);
2827
+ },
2828
+ error: (error) => {
2829
+ failFast(error);
2830
+ }
2831
+ });
2832
+ effectSubscriptions.add(subscription);
2833
+ continue;
2834
+ }
2835
+ const subscription = effect.run(scheduledActions$, state$).subscribe({ error: (error) => {
2836
+ failFast(error);
2837
+ } });
2838
+ effectSubscriptions.add(subscription);
2839
+ }
2840
+ };
2841
+ return {
2842
+ dispatch(action) {
2843
+ dispatchInternal(action);
2844
+ },
2845
+ getState() {
2846
+ return currentState;
2847
+ },
2848
+ get state$() {
2849
+ return stateSubject.asObservable();
2850
+ },
2851
+ get actions$() {
2852
+ return actionsSubject.asObservable();
2853
+ },
2854
+ select(selector) {
2855
+ return stateSubject.asObservable().pipe(select(selector));
2856
+ },
2857
+ init() {
2858
+ if (hasFatalError || isRunning) return;
2859
+ isRunning = true;
2860
+ startEffects();
2861
+ if (hasFatalError) return;
2862
+ dispatchInternal({ type: INTERNAL_ACTION_TYPES.init });
2863
+ },
2864
+ stop() {
2865
+ if (hasFatalError || !isRunning) return;
2866
+ dispatchInternal({ type: INTERNAL_ACTION_TYPES.stop });
2867
+ effectSubscriptions.unsubscribe();
2868
+ effectSubscriptions = new Subscription();
2869
+ isRunning = false;
2870
+ }
2871
+ };
2872
+ }
2873
+
2874
+ //#endregion
2875
+ //#region src/threads.ts
2876
+ const THREADS_CHANNEL_EVENT = "thread_metadata";
2877
+ const THREAD_SUBSCRIBE_PATH = "/threads/subscribe";
2878
+ const MAX_SOCKET_RETRIES = 5;
2879
+ const REQUEST_TIMEOUT_MS = 15e3;
2880
+ const initialThreadState = {
2881
+ threads: [],
2882
+ isLoading: false,
2883
+ isFetchingNextPage: false,
2884
+ error: null,
2885
+ context: null,
2886
+ sessionId: 0,
2887
+ metadataCredentialsRequested: false,
2888
+ metadataJoinCode: null,
2889
+ nextCursor: null
2890
+ };
2891
+ const threadAdapterEvents = createActionGroup("Thread Adapter", {
2892
+ started: empty(),
2893
+ stopped: empty(),
2894
+ contextChanged: props(),
2895
+ fetchNextPageRequested: empty(),
2896
+ renameRequested: props(),
2897
+ archiveRequested: props(),
2898
+ deleteRequested: props()
2899
+ });
2900
+ const threadRestEvents = createActionGroup("Thread REST", {
2901
+ listRequested: props(),
2902
+ listSucceeded: props(),
2903
+ listFailed: props(),
2904
+ nextPageSucceeded: props(),
2905
+ nextPageFailed: props(),
2906
+ metadataCredentialsRequested: props(),
2907
+ metadataCredentialsSucceeded: props(),
2908
+ metadataCredentialsFailed: props(),
2909
+ mutationFinished: props()
2910
+ });
2911
+ const threadSocketEvents = createActionGroup("Thread Socket", {
2912
+ opened: props(),
2913
+ errored: props(),
2914
+ joinFailed: props(),
2915
+ joinTimedOut: props(),
2916
+ metadataReceived: props()
2917
+ });
2918
+ const threadDomainEvents = createActionGroup("Thread Domain", {
2919
+ threadUpserted: props(),
2920
+ threadDeleted: props()
2921
+ });
2922
+ function sortThreadsByUpdatedAt(threads) {
2923
+ return [...threads].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
2924
+ }
2925
+ function upsertThread(threads, thread) {
2926
+ const existingIndex = threads.findIndex((item) => item.id === thread.id);
2927
+ if (existingIndex === -1) return sortThreadsByUpdatedAt([...threads, thread]);
2928
+ const next = [...threads];
2929
+ next[existingIndex] = thread;
2930
+ return sortThreadsByUpdatedAt(next);
2931
+ }
2932
+ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.contextChanged, (state, { context }) => ({
2933
+ ...state,
2934
+ context,
2935
+ sessionId: state.sessionId + 1,
2936
+ threads: [],
2937
+ isLoading: Boolean(context),
2938
+ isFetchingNextPage: false,
2939
+ error: null,
2940
+ metadataCredentialsRequested: false,
2941
+ metadataJoinCode: null,
2942
+ nextCursor: null
2943
+ })), on(threadAdapterEvents.stopped, (state) => ({
2944
+ ...state,
2945
+ threads: [],
2946
+ isLoading: false,
2947
+ isFetchingNextPage: false,
2948
+ error: null,
2949
+ metadataCredentialsRequested: false,
2950
+ metadataJoinCode: null,
2951
+ nextCursor: null
2952
+ })), on(threadRestEvents.listRequested, (state, { sessionId }) => {
2953
+ if (sessionId !== state.sessionId || !state.context) return state;
2954
+ return {
2955
+ ...state,
2956
+ isLoading: true,
2957
+ error: null
2958
+ };
2959
+ }), on(threadRestEvents.listSucceeded, (state, { sessionId, threads, joinCode, nextCursor }) => {
2960
+ if (sessionId !== state.sessionId) return state;
2961
+ return {
2962
+ ...state,
2963
+ threads: sortThreadsByUpdatedAt(threads),
2964
+ isLoading: false,
2965
+ error: null,
2966
+ metadataJoinCode: joinCode,
2967
+ nextCursor
2968
+ };
2969
+ }), on(threadRestEvents.listFailed, (state, { sessionId, error }) => {
2970
+ if (sessionId !== state.sessionId) return state;
2971
+ return {
2972
+ ...state,
2973
+ isLoading: false,
2974
+ error
2975
+ };
2976
+ }), on(threadRestEvents.nextPageSucceeded, (state, { sessionId, threads, nextCursor }) => {
2977
+ if (sessionId !== state.sessionId) return state;
2978
+ let merged = state.threads;
2979
+ for (const thread of threads) merged = upsertThread(merged, thread);
2980
+ return {
2981
+ ...state,
2982
+ threads: merged,
2983
+ isFetchingNextPage: false,
2984
+ nextCursor
2985
+ };
2986
+ }), on(threadRestEvents.nextPageFailed, (state, { sessionId, error }) => {
2987
+ if (sessionId !== state.sessionId) return state;
2988
+ return {
2989
+ ...state,
2990
+ isFetchingNextPage: false,
2991
+ error
2992
+ };
2993
+ }), on(threadRestEvents.metadataCredentialsFailed, (state, { sessionId, error }) => {
2994
+ if (sessionId !== state.sessionId) return state;
2995
+ return {
2996
+ ...state,
2997
+ error
2998
+ };
2999
+ }), on(threadRestEvents.metadataCredentialsRequested, (state, { sessionId }) => {
3000
+ if (sessionId !== state.sessionId) return state;
3001
+ return {
3002
+ ...state,
3003
+ metadataCredentialsRequested: true
3004
+ };
3005
+ }), on(threadAdapterEvents.fetchNextPageRequested, (state) => {
3006
+ if (!state.nextCursor || state.isFetchingNextPage) return state;
3007
+ return {
3008
+ ...state,
3009
+ isFetchingNextPage: true
3010
+ };
3011
+ }), on(threadRestEvents.mutationFinished, (state, { outcome }) => ({
3012
+ ...state,
3013
+ error: outcome.ok ? state.error : outcome.error
3014
+ })), on(threadDomainEvents.threadUpserted, (state, { sessionId, thread }) => {
3015
+ if (sessionId !== state.sessionId) return state;
3016
+ return {
3017
+ ...state,
3018
+ threads: upsertThread(state.threads, thread)
3019
+ };
3020
+ }), on(threadDomainEvents.threadDeleted, (state, { sessionId, threadId }) => {
3021
+ if (sessionId !== state.sessionId) return state;
3022
+ return {
3023
+ ...state,
3024
+ threads: state.threads.filter((thread) => thread.id !== threadId)
3025
+ };
3026
+ }));
3027
+ const selectThreads = createSelector((state) => state.threads);
3028
+ const selectThreadsIsLoading = createSelector((state) => state.isLoading);
3029
+ const selectThreadsError = createSelector((state) => state.error);
3030
+ const selectHasNextPage = createSelector((state) => state.nextCursor != null);
3031
+ const selectIsFetchingNextPage = createSelector((state) => state.isFetchingNextPage);
3032
+ let threadRequestId = 0;
3033
+ function createThreadRequestId() {
3034
+ threadRequestId += 1;
3035
+ return `thread-request-${threadRequestId}`;
3036
+ }
3037
+ function createThreadFetchObservable(environment, context, sessionId) {
3038
+ return defer(() => {
3039
+ const params = { agentId: context.agentId };
3040
+ if (context.includeArchived) params.includeArchived = "true";
3041
+ if (context.limit != null) params.limit = String(context.limit);
3042
+ const qs = new URLSearchParams(params);
3043
+ return fromFetch(`${context.runtimeUrl}/threads?${qs.toString()}`, {
3044
+ selector: (response) => {
3045
+ if (!response.ok) throw new Error(`Failed to fetch threads: ${response.status}`);
3046
+ return response.json();
3047
+ },
3048
+ fetch: environment.fetch,
3049
+ method: "GET",
3050
+ headers: { ...context.headers }
3051
+ }).pipe(timeout({
3052
+ first: REQUEST_TIMEOUT_MS,
3053
+ with: () => {
3054
+ throw new Error("Request timed out");
3055
+ }
3056
+ }), map((data) => threadRestEvents.listSucceeded({
3057
+ sessionId,
3058
+ threads: data.threads,
3059
+ joinCode: typeof data.joinCode === "string" && data.joinCode.length > 0 ? data.joinCode : null,
3060
+ nextCursor: data.nextCursor ?? null
3061
+ })), catchError((error) => {
3062
+ return of(threadRestEvents.listFailed({
3063
+ sessionId,
3064
+ error: error instanceof Error ? error : new Error(String(error))
3065
+ }));
3066
+ }));
3067
+ });
3068
+ }
3069
+ function createThreadMetadataCredentialsObservable(environment, context, sessionId) {
3070
+ return defer(() => {
3071
+ return fromFetch(`${context.runtimeUrl}${THREAD_SUBSCRIBE_PATH}`, {
3072
+ selector: async (response) => {
3073
+ if (!response.ok) throw new Error(`Failed to fetch thread metadata credentials: ${response.status}`);
3074
+ return response.json();
3075
+ },
3076
+ fetch: environment.fetch,
3077
+ method: "POST",
3078
+ headers: {
3079
+ ...context.headers,
3080
+ "Content-Type": "application/json"
3081
+ },
3082
+ body: JSON.stringify({})
3083
+ }).pipe(timeout({
3084
+ first: REQUEST_TIMEOUT_MS,
3085
+ with: () => {
3086
+ throw new Error("Request timed out");
3087
+ }
3088
+ }), map((data) => {
3089
+ if (typeof data.joinToken !== "string" || data.joinToken.length === 0) throw new Error("missing joinToken");
3090
+ return threadRestEvents.metadataCredentialsSucceeded({
3091
+ sessionId,
3092
+ joinToken: data.joinToken
3093
+ });
3094
+ }), catchError((error) => {
3095
+ return of(threadRestEvents.metadataCredentialsFailed({
3096
+ sessionId,
3097
+ error: error instanceof Error ? error : new Error(String(error))
3098
+ }));
3099
+ }));
3100
+ });
3101
+ }
3102
+ function createThreadMutationObservable(environment, context, request) {
3103
+ return defer(() => {
3104
+ return fromFetch(`${context.runtimeUrl}${request.path}`, {
3105
+ selector: async (response) => {
3106
+ if (!response.ok) throw new Error(`Request failed: ${response.status}`);
3107
+ return null;
3108
+ },
3109
+ fetch: environment.fetch,
3110
+ method: request.method,
3111
+ headers: {
3112
+ ...context.headers,
3113
+ "Content-Type": "application/json"
3114
+ },
3115
+ body: JSON.stringify(request.body)
3116
+ }).pipe(map(() => threadRestEvents.mutationFinished({ outcome: {
3117
+ requestId: request.requestId,
3118
+ ok: true
3119
+ } })), catchError((error) => {
3120
+ return of(threadRestEvents.mutationFinished({ outcome: {
3121
+ requestId: request.requestId,
3122
+ ok: false,
3123
+ error: error instanceof Error ? error : new Error(String(error))
3124
+ } }));
3125
+ }));
3126
+ });
3127
+ }
3128
+ function createThreadStore(environment) {
3129
+ const store = createStore({
3130
+ reducer: threadReducer,
3131
+ effects: [
3132
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadAdapterEvents.contextChanged), withLatestFrom(state$), filter(([, state]) => Boolean(state.context)), map(([, state]) => threadRestEvents.listRequested({ sessionId: state.sessionId })))),
3133
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadRestEvents.listRequested), switchMap$1((action) => state$.pipe(map((state) => state.context), filter((context) => Boolean(context)), take(1), map((context) => ({
3134
+ action,
3135
+ context
3136
+ })), takeUntil(actions$.pipe(ofType(threadAdapterEvents.contextChanged, threadAdapterEvents.stopped))), switchMap$1(({ action: currentAction, context }) => createThreadFetchObservable(environment, context, currentAction.sessionId)))))),
3137
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadRestEvents.listSucceeded), withLatestFrom(state$), filter(([action, state]) => {
3138
+ return action.sessionId === state.sessionId && !state.metadataCredentialsRequested && Boolean(state.context?.wsUrl) && Boolean(state.metadataJoinCode);
3139
+ }), map(([action]) => threadRestEvents.metadataCredentialsRequested({ sessionId: action.sessionId })))),
3140
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadRestEvents.metadataCredentialsRequested), switchMap$1((action) => state$.pipe(map((state) => state.context), filter((context) => Boolean(context)), take(1), map((context) => ({
3141
+ action,
3142
+ context
3143
+ })), takeUntil(actions$.pipe(ofType(threadAdapterEvents.contextChanged, threadAdapterEvents.stopped))), switchMap$1(({ action: currentAction, context }) => createThreadMetadataCredentialsObservable(environment, context, currentAction.sessionId)))))),
3144
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadRestEvents.metadataCredentialsSucceeded), withLatestFrom(state$), filter(([action, state]) => {
3145
+ return action.sessionId === state.sessionId && Boolean(state.context?.wsUrl);
3146
+ }), switchMap$1(([action, state]) => {
3147
+ const context = state.context;
3148
+ const joinToken = action.joinToken;
3149
+ const joinCode = state.metadataJoinCode;
3150
+ const shutdown$ = actions$.pipe(ofType(threadAdapterEvents.contextChanged, threadAdapterEvents.stopped));
3151
+ return defer(() => {
3152
+ const socket$ = ɵphoenixSocket$({
3153
+ url: context.wsUrl,
3154
+ options: {
3155
+ params: { join_token: joinToken },
3156
+ reconnectAfterMs: phoenixExponentialBackoff(100, 1e4),
3157
+ rejoinAfterMs: phoenixExponentialBackoff(1e3, 3e4)
3158
+ }
3159
+ }).pipe(shareReplay({
3160
+ bufferSize: 1,
3161
+ refCount: true
3162
+ }));
3163
+ const channel$ = ɵphoenixChannel$({
3164
+ socket$,
3165
+ topic: `user_meta:${joinCode}`
3166
+ }).pipe(shareReplay({
3167
+ bufferSize: 1,
3168
+ refCount: true
3169
+ }));
3170
+ const socketSignals$ = ɵobservePhoenixSocketSignals$(socket$).pipe(share());
3171
+ const fatalSocketShutdown$ = ɵobservePhoenixSocketHealth$(socketSignals$, MAX_SOCKET_RETRIES).pipe(catchError(() => {
3172
+ console.warn(`[threads] WebSocket failed after ${MAX_SOCKET_RETRIES} attempts, giving up`);
3173
+ return of(void 0);
3174
+ }), share());
3175
+ return merge(socketSignals$.pipe(map((signal) => signal.type === "open" ? threadSocketEvents.opened({ sessionId: action.sessionId }) : threadSocketEvents.errored({ sessionId: action.sessionId }))), channel$.pipe(switchMap$1(({ channel }) => ɵobservePhoenixEvent$(channel, THREADS_CHANNEL_EVENT)), map((payload) => threadSocketEvents.metadataReceived({
3176
+ sessionId: action.sessionId,
3177
+ payload
3178
+ }))), ɵobservePhoenixJoinOutcome$(channel$).pipe(filter((outcome) => outcome.type !== "joined"), map((outcome) => outcome.type === "timeout" ? threadSocketEvents.joinTimedOut({ sessionId: action.sessionId }) : threadSocketEvents.joinFailed({ sessionId: action.sessionId })))).pipe(takeUntil(merge(shutdown$, fatalSocketShutdown$)));
3179
+ });
3180
+ }))),
3181
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadSocketEvents.metadataReceived), withLatestFrom(state$), filter(([action, state]) => action.sessionId === state.sessionId), map(([action, state]) => {
3182
+ if (action.payload.operation === "deleted") return threadDomainEvents.threadDeleted({
3183
+ sessionId: action.sessionId,
3184
+ threadId: action.payload.deleted.id
3185
+ });
3186
+ if (action.payload.operation === "archived" && !state.context?.includeArchived) return threadDomainEvents.threadDeleted({
3187
+ sessionId: action.sessionId,
3188
+ threadId: action.payload.threadId
3189
+ });
3190
+ return threadDomainEvents.threadUpserted({
3191
+ sessionId: action.sessionId,
3192
+ thread: action.payload.thread
3193
+ });
3194
+ }))),
3195
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadAdapterEvents.fetchNextPageRequested), withLatestFrom(state$), filter(([, state]) => Boolean(state.context) && Boolean(state.nextCursor)), switchMap$1(([, state]) => {
3196
+ const context = state.context;
3197
+ const params = {
3198
+ agentId: context.agentId,
3199
+ cursor: state.nextCursor
3200
+ };
3201
+ if (context.includeArchived) params.includeArchived = "true";
3202
+ if (context.limit != null) params.limit = String(context.limit);
3203
+ return fromFetch(`${context.runtimeUrl}/threads?${new URLSearchParams(params).toString()}`, {
3204
+ selector: (response) => {
3205
+ if (!response.ok) throw new Error(`Failed to fetch next page: ${response.status}`);
3206
+ return response.json();
3207
+ },
3208
+ fetch: environment.fetch,
3209
+ method: "GET",
3210
+ headers: { ...context.headers }
3211
+ }).pipe(timeout({
3212
+ first: REQUEST_TIMEOUT_MS,
3213
+ with: () => {
3214
+ throw new Error("Request timed out");
3215
+ }
3216
+ }), map((data) => threadRestEvents.nextPageSucceeded({
3217
+ sessionId: state.sessionId,
3218
+ threads: data.threads,
3219
+ nextCursor: data.nextCursor ?? null
3220
+ })), catchError((error) => of(threadRestEvents.nextPageFailed({
3221
+ sessionId: state.sessionId,
3222
+ error: error instanceof Error ? error : new Error(String(error))
3223
+ }))), takeUntil(actions$.pipe(ofType(threadAdapterEvents.contextChanged, threadAdapterEvents.stopped))));
3224
+ }))),
3225
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadAdapterEvents.renameRequested, threadAdapterEvents.archiveRequested, threadAdapterEvents.deleteRequested), withLatestFrom(state$), mergeMap(([action, state]) => {
3226
+ const context = state.context;
3227
+ if (!context?.runtimeUrl) {
3228
+ const requestId = action.requestId;
3229
+ return of(threadRestEvents.mutationFinished({ outcome: {
3230
+ requestId,
3231
+ ok: false,
3232
+ error: /* @__PURE__ */ new Error("Runtime URL is not configured")
3233
+ } }));
3234
+ }
3235
+ const commonBody = { agentId: context.agentId };
3236
+ if (threadAdapterEvents.renameRequested.match(action)) return createThreadMutationObservable(environment, context, {
3237
+ requestId: action.requestId,
3238
+ method: "PATCH",
3239
+ path: `/threads/${encodeURIComponent(action.threadId)}`,
3240
+ body: {
3241
+ ...commonBody,
3242
+ name: action.name
3243
+ }
3244
+ });
3245
+ if (threadAdapterEvents.archiveRequested.match(action)) return createThreadMutationObservable(environment, context, {
3246
+ requestId: action.requestId,
3247
+ method: "POST",
3248
+ path: `/threads/${encodeURIComponent(action.threadId)}/archive`,
3249
+ body: commonBody
3250
+ });
3251
+ return createThreadMutationObservable(environment, context, {
3252
+ requestId: action.requestId,
3253
+ method: "DELETE",
3254
+ path: `/threads/${encodeURIComponent(action.threadId)}`,
3255
+ body: commonBody
3256
+ });
3257
+ })))
3258
+ ]
3259
+ });
3260
+ function trackMutation(dispatchAction) {
3261
+ const resultPromise = firstValueFrom(merge(store.actions$.pipe(ofType(threadRestEvents.mutationFinished), filter((action) => action.outcome.requestId === dispatchAction.requestId), map((action) => action.outcome)), store.actions$.pipe(ofType(threadAdapterEvents.stopped), map(() => ({
3262
+ requestId: dispatchAction.requestId,
3263
+ ok: false,
3264
+ error: /* @__PURE__ */ new Error("Thread store stopped before mutation completed")
3265
+ })))).pipe(take(1))).then((outcome) => {
3266
+ if (outcome.ok) return;
3267
+ throw outcome.error;
3268
+ });
3269
+ store.dispatch(dispatchAction);
3270
+ return resultPromise;
3271
+ }
3272
+ return {
3273
+ start() {
3274
+ store.init();
3275
+ store.dispatch(threadAdapterEvents.started());
3276
+ },
3277
+ stop() {
3278
+ store.dispatch(threadAdapterEvents.stopped());
3279
+ store.stop();
3280
+ },
3281
+ setContext(context) {
3282
+ store.dispatch(threadAdapterEvents.contextChanged({ context }));
3283
+ },
3284
+ fetchNextPage() {
3285
+ store.dispatch(threadAdapterEvents.fetchNextPageRequested());
3286
+ },
3287
+ renameThread(threadId, name) {
3288
+ return trackMutation(threadAdapterEvents.renameRequested({
3289
+ requestId: createThreadRequestId(),
3290
+ threadId,
3291
+ name
3292
+ }));
3293
+ },
3294
+ archiveThread(threadId) {
3295
+ return trackMutation(threadAdapterEvents.archiveRequested({
3296
+ requestId: createThreadRequestId(),
3297
+ threadId
3298
+ }));
3299
+ },
3300
+ deleteThread(threadId) {
3301
+ return trackMutation(threadAdapterEvents.deleteRequested({
3302
+ requestId: createThreadRequestId(),
3303
+ threadId
3304
+ }));
3305
+ },
3306
+ getState() {
3307
+ return store.getState();
3308
+ },
3309
+ select: store.select.bind(store)
3310
+ };
3311
+ }
3312
+ const ɵthreadAdapterEvents = threadAdapterEvents;
3313
+ const ɵselectThreads = selectThreads;
3314
+ const ɵselectThreadsIsLoading = selectThreadsIsLoading;
3315
+ const ɵselectThreadsError = selectThreadsError;
3316
+ const ɵselectHasNextPage = selectHasNextPage;
3317
+ const ɵselectIsFetchingNextPage = selectIsFetchingNextPage;
3318
+
3319
+ //#endregion
3320
+ export { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCoreErrorCode, CopilotKitCoreRuntimeConnectionStatus, IntelligenceAgent, ProxiedCopilotRuntimeAgent, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, completePartialMarkdown, createActionGroup, createEffect, createReducer, createSelector, createStore, empty, ensureObjectArgs, ofType, on, parseToolArguments, props, select, createThreadStore as ɵcreateThreadStore, ɵjoinPhoenixChannel$, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading, ɵthreadAdapterEvents };
3321
+ //# sourceMappingURL=index.mjs.map