@copilotkitnext/core 0.0.11 → 0.0.13-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -20,18 +20,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ AgentRegistry: () => AgentRegistry,
24
+ ContextStore: () => ContextStore,
23
25
  CopilotKitCore: () => CopilotKitCore,
24
26
  CopilotKitCoreErrorCode: () => CopilotKitCoreErrorCode,
25
27
  CopilotKitCoreRuntimeConnectionStatus: () => CopilotKitCoreRuntimeConnectionStatus,
26
28
  ProxiedCopilotRuntimeAgent: () => ProxiedCopilotRuntimeAgent,
29
+ RunHandler: () => RunHandler,
30
+ SuggestionEngine: () => SuggestionEngine,
27
31
  ToolCallStatus: () => ToolCallStatus,
28
32
  completePartialMarkdown: () => completePartialMarkdown
29
33
  });
30
34
  module.exports = __toCommonJS(index_exports);
31
35
 
32
- // src/core.ts
33
- var import_shared = require("@copilotkitnext/shared");
36
+ // src/core/agent-registry.ts
34
37
  var import_client2 = require("@ag-ui/client");
38
+ var import_shared = require("@copilotkitnext/shared");
35
39
 
36
40
  // src/agent.ts
37
41
  var import_client = require("@ag-ui/client");
@@ -53,179 +57,133 @@ var ProxiedCopilotRuntimeAgent = class extends import_client.HttpAgent {
53
57
  }
54
58
  };
55
59
 
56
- // src/core.ts
57
- var import_zod_to_json_schema = require("zod-to-json-schema");
58
- var CopilotKitCoreErrorCode = /* @__PURE__ */ ((CopilotKitCoreErrorCode2) => {
59
- CopilotKitCoreErrorCode2["RUNTIME_INFO_FETCH_FAILED"] = "runtime_info_fetch_failed";
60
- CopilotKitCoreErrorCode2["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
61
- CopilotKitCoreErrorCode2["AGENT_RUN_FAILED"] = "agent_run_failed";
62
- CopilotKitCoreErrorCode2["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
63
- CopilotKitCoreErrorCode2["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
64
- CopilotKitCoreErrorCode2["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
65
- CopilotKitCoreErrorCode2["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
66
- return CopilotKitCoreErrorCode2;
67
- })(CopilotKitCoreErrorCode || {});
68
- var CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ ((CopilotKitCoreRuntimeConnectionStatus2) => {
69
- CopilotKitCoreRuntimeConnectionStatus2["Disconnected"] = "disconnected";
70
- CopilotKitCoreRuntimeConnectionStatus2["Connected"] = "connected";
71
- CopilotKitCoreRuntimeConnectionStatus2["Connecting"] = "connecting";
72
- CopilotKitCoreRuntimeConnectionStatus2["Error"] = "error";
73
- return CopilotKitCoreRuntimeConnectionStatus2;
74
- })(CopilotKitCoreRuntimeConnectionStatus || {});
75
- var CopilotKitCore = class {
76
- headers;
77
- properties;
78
- _context = {};
60
+ // src/core/agent-registry.ts
61
+ var AgentRegistry = class {
62
+ constructor(core) {
63
+ this.core = core;
64
+ }
79
65
  _agents = {};
80
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
- _tools = [];
82
66
  localAgents = {};
83
67
  remoteAgents = {};
84
- subscribers = /* @__PURE__ */ new Set();
85
68
  _runtimeUrl;
86
69
  _runtimeVersion;
87
70
  _runtimeConnectionStatus = "disconnected" /* Disconnected */;
88
- constructor({
89
- runtimeUrl,
90
- headers = {},
91
- properties = {},
92
- agents = {},
93
- tools = []
94
- }) {
95
- this.headers = headers;
96
- this.properties = properties;
71
+ /**
72
+ * Get all agents as a readonly record
73
+ */
74
+ get agents() {
75
+ return this._agents;
76
+ }
77
+ get runtimeUrl() {
78
+ return this._runtimeUrl;
79
+ }
80
+ get runtimeVersion() {
81
+ return this._runtimeVersion;
82
+ }
83
+ get runtimeConnectionStatus() {
84
+ return this._runtimeConnectionStatus;
85
+ }
86
+ /**
87
+ * Initialize agents from configuration
88
+ */
89
+ initialize(agents) {
97
90
  this.localAgents = this.assignAgentIds(agents);
98
91
  this.applyHeadersToAgents(this.localAgents);
99
92
  this._agents = this.localAgents;
100
- this._tools = tools;
101
- this.setRuntimeUrl(runtimeUrl);
102
93
  }
103
- applyHeadersToAgent(agent) {
104
- if (agent instanceof import_client2.HttpAgent) {
105
- agent.headers = { ...this.headers };
94
+ /**
95
+ * Set the runtime URL and update connection
96
+ */
97
+ setRuntimeUrl(runtimeUrl) {
98
+ const normalizedRuntimeUrl = runtimeUrl ? runtimeUrl.replace(/\/$/, "") : void 0;
99
+ if (this._runtimeUrl === normalizedRuntimeUrl) {
100
+ return;
106
101
  }
102
+ this._runtimeUrl = normalizedRuntimeUrl;
103
+ void this.updateRuntimeConnection();
107
104
  }
108
- applyHeadersToAgents(agents) {
109
- Object.values(agents).forEach((agent) => {
110
- this.applyHeadersToAgent(agent);
111
- });
112
- }
113
- assignAgentIds(agents) {
105
+ /**
106
+ * Set all agents at once (for development use)
107
+ */
108
+ setAgents__unsafe_dev_only(agents) {
114
109
  Object.entries(agents).forEach(([id, agent]) => {
115
- if (agent && !agent.agentId) {
116
- agent.agentId = id;
110
+ if (agent) {
111
+ this.validateAndAssignAgentId(id, agent);
117
112
  }
118
113
  });
119
- return agents;
114
+ this.localAgents = agents;
115
+ this._agents = { ...this.localAgents, ...this.remoteAgents };
116
+ this.applyHeadersToAgents(this._agents);
117
+ void this.notifyAgentsChanged();
120
118
  }
121
- async notifySubscribers(handler, errorMessage) {
122
- await Promise.all(
123
- Array.from(this.subscribers).map(async (subscriber) => {
124
- try {
125
- await handler(subscriber);
126
- } catch (error) {
127
- import_shared.logger.error(errorMessage, error);
128
- }
129
- })
130
- );
119
+ /**
120
+ * Add a single agent (for development use)
121
+ */
122
+ addAgent__unsafe_dev_only({ id, agent }) {
123
+ this.validateAndAssignAgentId(id, agent);
124
+ this.localAgents[id] = agent;
125
+ this.applyHeadersToAgent(agent);
126
+ this._agents = { ...this.localAgents, ...this.remoteAgents };
127
+ void this.notifyAgentsChanged();
131
128
  }
132
- async emitError({
133
- error,
134
- code,
135
- context = {}
136
- }) {
137
- await this.notifySubscribers(
138
- (subscriber) => subscriber.onError?.({
139
- copilotkit: this,
140
- error,
141
- code,
142
- context
143
- }),
144
- "Subscriber onError error:"
145
- );
129
+ /**
130
+ * Remove an agent by ID (for development use)
131
+ */
132
+ removeAgent__unsafe_dev_only(id) {
133
+ delete this.localAgents[id];
134
+ this._agents = { ...this.localAgents, ...this.remoteAgents };
135
+ void this.notifyAgentsChanged();
146
136
  }
147
- resolveAgentId(agent, providedAgentId) {
148
- if (providedAgentId) {
149
- return providedAgentId;
150
- }
151
- if (agent.agentId) {
152
- return agent.agentId;
137
+ /**
138
+ * Get an agent by ID
139
+ */
140
+ getAgent(id) {
141
+ if (id in this._agents) {
142
+ return this._agents[id];
153
143
  }
154
- const found = Object.entries(this._agents).find(([, storedAgent]) => {
155
- return storedAgent === agent;
156
- });
157
- if (found) {
158
- agent.agentId = found[0];
159
- return found[0];
144
+ if (this.runtimeUrl !== void 0 && (this.runtimeConnectionStatus === "disconnected" /* Disconnected */ || this.runtimeConnectionStatus === "connecting" /* Connecting */)) {
145
+ return void 0;
160
146
  }
161
- agent.agentId = import_shared.DEFAULT_AGENT_ID;
162
- return import_shared.DEFAULT_AGENT_ID;
147
+ console.warn(`Agent ${id} not found`);
148
+ return void 0;
163
149
  }
164
150
  /**
165
- * Snapshot accessors
151
+ * Apply current headers to an agent
166
152
  */
167
- get context() {
168
- return this._context;
169
- }
170
- get agents() {
171
- return this._agents;
172
- }
173
- get tools() {
174
- return this._tools;
175
- }
176
- get runtimeUrl() {
177
- return this._runtimeUrl;
178
- }
179
- setRuntimeUrl(runtimeUrl) {
180
- const normalizedRuntimeUrl = runtimeUrl ? runtimeUrl.replace(/\/$/, "") : void 0;
181
- if (this._runtimeUrl === normalizedRuntimeUrl) {
182
- return;
153
+ applyHeadersToAgent(agent) {
154
+ if (agent instanceof import_client2.HttpAgent) {
155
+ agent.headers = { ...this.core.headers };
183
156
  }
184
- this._runtimeUrl = normalizedRuntimeUrl;
185
- void this.updateRuntimeConnection();
186
- }
187
- get runtimeVersion() {
188
- return this._runtimeVersion;
189
157
  }
190
- get runtimeConnectionStatus() {
191
- return this._runtimeConnectionStatus;
158
+ /**
159
+ * Apply current headers to all agents
160
+ */
161
+ applyHeadersToAgents(agents) {
162
+ Object.values(agents).forEach((agent) => {
163
+ this.applyHeadersToAgent(agent);
164
+ });
192
165
  }
193
166
  /**
194
- * Runtime connection
167
+ * Update runtime connection and fetch remote agents
195
168
  */
196
169
  async updateRuntimeConnection() {
170
+ if (typeof window === "undefined") {
171
+ return;
172
+ }
197
173
  if (!this.runtimeUrl) {
198
174
  this._runtimeConnectionStatus = "disconnected" /* Disconnected */;
199
175
  this._runtimeVersion = void 0;
200
176
  this.remoteAgents = {};
201
177
  this._agents = this.localAgents;
202
- await this.notifySubscribers(
203
- (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
204
- copilotkit: this,
205
- status: "disconnected" /* Disconnected */
206
- }),
207
- "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
208
- );
209
- await this.notifySubscribers(
210
- (subscriber) => subscriber.onAgentsChanged?.({
211
- copilotkit: this,
212
- agents: this._agents
213
- }),
214
- "Subscriber onAgentsChanged error:"
215
- );
178
+ await this.notifyRuntimeStatusChanged("disconnected" /* Disconnected */);
179
+ await this.notifyAgentsChanged();
216
180
  return;
217
181
  }
218
182
  this._runtimeConnectionStatus = "connecting" /* Connecting */;
219
- await this.notifySubscribers(
220
- (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
221
- copilotkit: this,
222
- status: "connecting" /* Connecting */
223
- }),
224
- "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
225
- );
183
+ await this.notifyRuntimeStatusChanged("connecting" /* Connecting */);
226
184
  try {
227
185
  const response = await fetch(`${this.runtimeUrl}/info`, {
228
- headers: this.headers
186
+ headers: this.core.headers
229
187
  });
230
188
  const {
231
189
  version,
@@ -236,6 +194,7 @@ var CopilotKitCore = class {
236
194
  const agent = new ProxiedCopilotRuntimeAgent({
237
195
  runtimeUrl: this.runtimeUrl,
238
196
  agentId: id,
197
+ // Runtime agents always have their ID set correctly
239
198
  description
240
199
  });
241
200
  this.applyHeadersToAgent(agent);
@@ -246,45 +205,19 @@ var CopilotKitCore = class {
246
205
  this._agents = { ...this.localAgents, ...this.remoteAgents };
247
206
  this._runtimeConnectionStatus = "connected" /* Connected */;
248
207
  this._runtimeVersion = version;
249
- await this.notifySubscribers(
250
- (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
251
- copilotkit: this,
252
- status: "connected" /* Connected */
253
- }),
254
- "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
255
- );
256
- await this.notifySubscribers(
257
- (subscriber) => subscriber.onAgentsChanged?.({
258
- copilotkit: this,
259
- agents: this._agents
260
- }),
261
- "Subscriber onAgentsChanged error:"
262
- );
208
+ await this.notifyRuntimeStatusChanged("connected" /* Connected */);
209
+ await this.notifyAgentsChanged();
263
210
  } catch (error) {
264
211
  this._runtimeConnectionStatus = "error" /* Error */;
265
212
  this._runtimeVersion = void 0;
266
213
  this.remoteAgents = {};
267
214
  this._agents = this.localAgents;
268
- await this.notifySubscribers(
269
- (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
270
- copilotkit: this,
271
- status: "error" /* Error */
272
- }),
273
- "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
274
- );
275
- await this.notifySubscribers(
276
- (subscriber) => subscriber.onAgentsChanged?.({
277
- copilotkit: this,
278
- agents: this._agents
279
- }),
280
- "Subscriber onAgentsChanged error:"
281
- );
215
+ await this.notifyRuntimeStatusChanged("error" /* Error */);
216
+ await this.notifyAgentsChanged();
282
217
  const message = error instanceof Error ? error.message : JSON.stringify(error);
283
- import_shared.logger.warn(
284
- `Failed to load runtime info (${this.runtimeUrl}/info): ${message}`
285
- );
218
+ import_shared.logger.warn(`Failed to load runtime info (${this.runtimeUrl}/info): ${message}`);
286
219
  const runtimeError = error instanceof Error ? error : new Error(String(error));
287
- await this.emitError({
220
+ await this.core.emitError({
288
221
  error: runtimeError,
289
222
  code: "runtime_info_fetch_failed" /* RUNTIME_INFO_FETCH_FAILED */,
290
223
  context: {
@@ -294,118 +227,479 @@ var CopilotKitCore = class {
294
227
  }
295
228
  }
296
229
  /**
297
- * Configuration updates
230
+ * Assign agent IDs to a record of agents
298
231
  */
299
- setHeaders(headers) {
300
- this.headers = headers;
301
- this.applyHeadersToAgents(this._agents);
302
- void this.notifySubscribers(
303
- (subscriber) => subscriber.onHeadersChanged?.({
304
- copilotkit: this,
305
- headers: this.headers
306
- }),
307
- "Subscriber onHeadersChanged error:"
308
- );
309
- }
310
- setProperties(properties) {
311
- this.properties = properties;
312
- void this.notifySubscribers(
313
- (subscriber) => subscriber.onPropertiesChanged?.({
314
- copilotkit: this,
315
- properties: this.properties
316
- }),
317
- "Subscriber onPropertiesChanged error:"
318
- );
319
- }
320
- setAgents(agents) {
321
- this.localAgents = this.assignAgentIds(agents);
322
- this._agents = { ...this.localAgents, ...this.remoteAgents };
323
- this.applyHeadersToAgents(this._agents);
324
- void this.notifySubscribers(
325
- (subscriber) => subscriber.onAgentsChanged?.({
326
- copilotkit: this,
327
- agents: this._agents
328
- }),
329
- "Subscriber onAgentsChanged error:"
330
- );
232
+ assignAgentIds(agents) {
233
+ Object.entries(agents).forEach(([id, agent]) => {
234
+ if (agent) {
235
+ this.validateAndAssignAgentId(id, agent);
236
+ }
237
+ });
238
+ return agents;
331
239
  }
332
- addAgent({ id, agent }) {
333
- this.localAgents[id] = agent;
240
+ /**
241
+ * Validate and assign an agent ID
242
+ */
243
+ validateAndAssignAgentId(registrationId, agent) {
244
+ if (agent.agentId && agent.agentId !== registrationId) {
245
+ throw new Error(
246
+ `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.`
247
+ );
248
+ }
334
249
  if (!agent.agentId) {
335
- agent.agentId = id;
250
+ agent.agentId = registrationId;
336
251
  }
337
- this.applyHeadersToAgent(agent);
338
- this._agents = { ...this.localAgents, ...this.remoteAgents };
339
- void this.notifySubscribers(
340
- (subscriber) => subscriber.onAgentsChanged?.({
341
- copilotkit: this,
342
- agents: this._agents
252
+ }
253
+ /**
254
+ * Notify subscribers of runtime status changes
255
+ */
256
+ async notifyRuntimeStatusChanged(status) {
257
+ await this.core.notifySubscribers(
258
+ (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
259
+ copilotkit: this.core,
260
+ status
343
261
  }),
344
- "Subscriber onAgentsChanged error:"
262
+ "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
345
263
  );
346
264
  }
347
- removeAgent(id) {
348
- delete this.localAgents[id];
349
- this._agents = { ...this.localAgents, ...this.remoteAgents };
350
- void this.notifySubscribers(
265
+ /**
266
+ * Notify subscribers of agent changes
267
+ */
268
+ async notifyAgentsChanged() {
269
+ await this.core.notifySubscribers(
351
270
  (subscriber) => subscriber.onAgentsChanged?.({
352
- copilotkit: this,
271
+ copilotkit: this.core,
353
272
  agents: this._agents
354
273
  }),
355
274
  "Subscriber onAgentsChanged error:"
356
275
  );
357
276
  }
358
- getAgent(id) {
359
- if (id in this._agents) {
360
- return this._agents[id];
361
- }
362
- if (this.runtimeUrl !== void 0 && (this.runtimeConnectionStatus === "disconnected" /* Disconnected */ || this.runtimeConnectionStatus === "connecting" /* Connecting */)) {
363
- return void 0;
364
- } else {
365
- console.warn(`Agent ${id} not found`);
366
- return void 0;
367
- }
277
+ };
278
+
279
+ // src/core/context-store.ts
280
+ var import_shared2 = require("@copilotkitnext/shared");
281
+ var ContextStore = class {
282
+ constructor(core) {
283
+ this.core = core;
284
+ }
285
+ _context = {};
286
+ /**
287
+ * Get all context entries as a readonly record
288
+ */
289
+ get context() {
290
+ return this._context;
368
291
  }
369
292
  /**
370
- * Context management
293
+ * Add a new context entry
294
+ * @returns The ID of the created context entry
371
295
  */
372
296
  addContext({ description, value }) {
373
- const id = (0, import_shared.randomUUID)();
297
+ const id = (0, import_shared2.randomUUID)();
374
298
  this._context[id] = { description, value };
375
- void this.notifySubscribers(
376
- (subscriber) => subscriber.onContextChanged?.({
377
- copilotkit: this,
378
- context: this._context
379
- }),
380
- "Subscriber onContextChanged error:"
381
- );
299
+ void this.notifySubscribers();
382
300
  return id;
383
301
  }
302
+ /**
303
+ * Remove a context entry by ID
304
+ */
384
305
  removeContext(id) {
385
306
  delete this._context[id];
386
- void this.notifySubscribers(
307
+ void this.notifySubscribers();
308
+ }
309
+ /**
310
+ * Notify all subscribers of context changes
311
+ */
312
+ async notifySubscribers() {
313
+ await this.core.notifySubscribers(
387
314
  (subscriber) => subscriber.onContextChanged?.({
388
- copilotkit: this,
315
+ copilotkit: this.core,
389
316
  context: this._context
390
317
  }),
391
318
  "Subscriber onContextChanged error:"
392
319
  );
393
320
  }
321
+ };
322
+
323
+ // src/core/suggestion-engine.ts
324
+ var import_shared3 = require("@copilotkitnext/shared");
325
+ var SuggestionEngine = class {
326
+ constructor(core) {
327
+ this.core = core;
328
+ }
329
+ _suggestionsConfig = {};
330
+ _suggestions = {};
331
+ _runningSuggestions = {};
332
+ /**
333
+ * Initialize with suggestion configs
334
+ */
335
+ initialize(suggestionsConfig) {
336
+ for (const config of suggestionsConfig) {
337
+ this._suggestionsConfig[(0, import_shared3.randomUUID)()] = config;
338
+ }
339
+ }
340
+ /**
341
+ * Add a suggestion configuration
342
+ * @returns The ID of the created config
343
+ */
344
+ addSuggestionsConfig(config) {
345
+ const id = (0, import_shared3.randomUUID)();
346
+ this._suggestionsConfig[id] = config;
347
+ void this.notifySuggestionsConfigChanged();
348
+ return id;
349
+ }
350
+ /**
351
+ * Remove a suggestion configuration by ID
352
+ */
353
+ removeSuggestionsConfig(id) {
354
+ delete this._suggestionsConfig[id];
355
+ void this.notifySuggestionsConfigChanged();
356
+ }
357
+ /**
358
+ * Reload suggestions for a specific agent
359
+ * This triggers generation of new suggestions based on current configs
360
+ */
361
+ reloadSuggestions(agentId) {
362
+ this.clearSuggestions(agentId);
363
+ const agent = this.core.getAgent(agentId);
364
+ if (!agent) {
365
+ return;
366
+ }
367
+ const messageCount = agent.messages?.length ?? 0;
368
+ let hasAnySuggestions = false;
369
+ for (const config of Object.values(this._suggestionsConfig)) {
370
+ if (config.consumerAgentId !== void 0 && config.consumerAgentId !== "*" && config.consumerAgentId !== agentId) {
371
+ continue;
372
+ }
373
+ if (!this.shouldShowSuggestions(config, messageCount)) {
374
+ continue;
375
+ }
376
+ const suggestionId = (0, import_shared3.randomUUID)();
377
+ if (isDynamicSuggestionsConfig(config)) {
378
+ if (!hasAnySuggestions) {
379
+ hasAnySuggestions = true;
380
+ void this.notifySuggestionsStartedLoading(agentId);
381
+ }
382
+ void this.generateSuggestions(suggestionId, config, agentId);
383
+ } else if (isStaticSuggestionsConfig(config)) {
384
+ this.addStaticSuggestions(suggestionId, config, agentId);
385
+ }
386
+ }
387
+ }
388
+ /**
389
+ * Clear all suggestions for a specific agent
390
+ */
391
+ clearSuggestions(agentId) {
392
+ const runningAgents = this._runningSuggestions[agentId];
393
+ if (runningAgents) {
394
+ for (const agent of runningAgents) {
395
+ agent.abortRun();
396
+ }
397
+ delete this._runningSuggestions[agentId];
398
+ }
399
+ this._suggestions[agentId] = {};
400
+ void this.notifySuggestionsChanged(agentId, []);
401
+ }
402
+ /**
403
+ * Get current suggestions for an agent
404
+ */
405
+ getSuggestions(agentId) {
406
+ const suggestions = Object.values(this._suggestions[agentId] ?? {}).flat();
407
+ const isLoading = (this._runningSuggestions[agentId]?.length ?? 0) > 0;
408
+ return { suggestions, isLoading };
409
+ }
410
+ /**
411
+ * Generate suggestions using a provider agent
412
+ */
413
+ async generateSuggestions(suggestionId, config, consumerAgentId) {
414
+ let agent = void 0;
415
+ try {
416
+ const suggestionsProviderAgent = this.core.getAgent(config.providerAgentId ?? "default");
417
+ if (!suggestionsProviderAgent) {
418
+ throw new Error(`Suggestions provider agent not found: ${config.providerAgentId}`);
419
+ }
420
+ const suggestionsConsumerAgent = this.core.getAgent(consumerAgentId);
421
+ if (!suggestionsConsumerAgent) {
422
+ throw new Error(`Suggestions consumer agent not found: ${consumerAgentId}`);
423
+ }
424
+ const clonedAgent = suggestionsProviderAgent.clone();
425
+ agent = clonedAgent;
426
+ agent.agentId = suggestionId;
427
+ agent.threadId = suggestionId;
428
+ agent.messages = JSON.parse(JSON.stringify(suggestionsConsumerAgent.messages));
429
+ agent.state = JSON.parse(JSON.stringify(suggestionsConsumerAgent.state));
430
+ this._suggestions[consumerAgentId] = {
431
+ ...this._suggestions[consumerAgentId] ?? {},
432
+ [suggestionId]: []
433
+ };
434
+ this._runningSuggestions[consumerAgentId] = [...this._runningSuggestions[consumerAgentId] ?? [], agent];
435
+ agent.addMessage({
436
+ id: suggestionId,
437
+ role: "user",
438
+ content: [
439
+ `Suggest what the user could say next. Provide clear, highly relevant suggestions by calling the \`copilotkitSuggest\` tool.`,
440
+ `Provide at least ${config.minSuggestions ?? 1} and at most ${config.maxSuggestions ?? 3} suggestions.`,
441
+ `The user has the following tools available: ${JSON.stringify(this.core.buildFrontendTools(consumerAgentId))}.`,
442
+ ` ${config.instructions}`
443
+ ].join("\n")
444
+ });
445
+ await agent.runAgent(
446
+ {
447
+ context: Object.values(this.core.context),
448
+ forwardedProps: {
449
+ ...this.core.properties,
450
+ toolChoice: { type: "function", function: { name: "copilotkitSuggest" } }
451
+ },
452
+ tools: [SUGGEST_TOOL]
453
+ },
454
+ {
455
+ onMessagesChanged: ({ messages }) => {
456
+ this.extractSuggestions(messages, suggestionId, consumerAgentId, true);
457
+ }
458
+ }
459
+ );
460
+ } catch (error) {
461
+ console.warn("Error generating suggestions:", error);
462
+ } finally {
463
+ this.finalizeSuggestions(suggestionId, consumerAgentId);
464
+ const runningAgents = this._runningSuggestions[consumerAgentId];
465
+ if (agent && runningAgents) {
466
+ const filteredAgents = runningAgents.filter((a) => a !== agent);
467
+ this._runningSuggestions[consumerAgentId] = filteredAgents;
468
+ if (filteredAgents.length === 0) {
469
+ delete this._runningSuggestions[consumerAgentId];
470
+ await this.notifySuggestionsFinishedLoading(consumerAgentId);
471
+ }
472
+ }
473
+ }
474
+ }
475
+ /**
476
+ * Finalize suggestions by marking them as no longer loading
477
+ */
478
+ finalizeSuggestions(suggestionId, consumerAgentId) {
479
+ const agentSuggestions = this._suggestions[consumerAgentId];
480
+ const currentSuggestions = agentSuggestions?.[suggestionId];
481
+ if (agentSuggestions && currentSuggestions && currentSuggestions.length > 0) {
482
+ const finalizedSuggestions = currentSuggestions.filter((suggestion) => suggestion.title !== "" || suggestion.message !== "").map((suggestion) => ({
483
+ ...suggestion,
484
+ isLoading: false
485
+ }));
486
+ if (finalizedSuggestions.length > 0) {
487
+ agentSuggestions[suggestionId] = finalizedSuggestions;
488
+ } else {
489
+ delete agentSuggestions[suggestionId];
490
+ }
491
+ const allSuggestions = Object.values(this._suggestions[consumerAgentId] ?? {}).flat();
492
+ void this.notifySuggestionsChanged(consumerAgentId, allSuggestions, "finalized");
493
+ }
494
+ }
495
+ /**
496
+ * Extract suggestions from messages (called during streaming)
497
+ */
498
+ extractSuggestions(messages, suggestionId, consumerAgentId, isRunning) {
499
+ const idx = messages.findIndex((message) => message.id === suggestionId);
500
+ if (idx == -1) {
501
+ return;
502
+ }
503
+ const suggestions = [];
504
+ const newMessages = messages.slice(idx + 1);
505
+ for (const message of newMessages) {
506
+ if (message.role === "assistant" && message.toolCalls) {
507
+ for (const toolCall of message.toolCalls) {
508
+ if (toolCall.function.name === "copilotkitSuggest") {
509
+ const fullArgs = Array.isArray(toolCall.function.arguments) ? toolCall.function.arguments.join("") : toolCall.function.arguments;
510
+ const parsed = (0, import_shared3.partialJSONParse)(fullArgs);
511
+ if (parsed && typeof parsed === "object" && "suggestions" in parsed) {
512
+ const parsedSuggestions = parsed.suggestions;
513
+ if (Array.isArray(parsedSuggestions)) {
514
+ for (const item of parsedSuggestions) {
515
+ if (item && typeof item === "object" && "title" in item) {
516
+ suggestions.push({
517
+ title: item.title ?? "",
518
+ message: item.message ?? "",
519
+ isLoading: false
520
+ // Will be set correctly below
521
+ });
522
+ }
523
+ }
524
+ }
525
+ }
526
+ }
527
+ }
528
+ }
529
+ }
530
+ if (isRunning && suggestions.length > 0) {
531
+ suggestions[suggestions.length - 1].isLoading = true;
532
+ }
533
+ const agentSuggestions = this._suggestions[consumerAgentId];
534
+ if (agentSuggestions) {
535
+ agentSuggestions[suggestionId] = suggestions;
536
+ const allSuggestions = Object.values(this._suggestions[consumerAgentId] ?? {}).flat();
537
+ void this.notifySuggestionsChanged(consumerAgentId, allSuggestions, "suggestions changed");
538
+ }
539
+ }
540
+ /**
541
+ * Notify subscribers of suggestions config changes
542
+ */
543
+ async notifySuggestionsConfigChanged() {
544
+ await this.core.notifySubscribers(
545
+ (subscriber) => subscriber.onSuggestionsConfigChanged?.({
546
+ copilotkit: this.core,
547
+ suggestionsConfig: this._suggestionsConfig
548
+ }),
549
+ "Subscriber onSuggestionsConfigChanged error:"
550
+ );
551
+ }
552
+ /**
553
+ * Notify subscribers of suggestions changes
554
+ */
555
+ async notifySuggestionsChanged(agentId, suggestions, context = "") {
556
+ await this.core.notifySubscribers(
557
+ (subscriber) => subscriber.onSuggestionsChanged?.({
558
+ copilotkit: this.core,
559
+ agentId,
560
+ suggestions
561
+ }),
562
+ `Subscriber onSuggestionsChanged error: ${context}`
563
+ );
564
+ }
565
+ /**
566
+ * Notify subscribers that suggestions started loading
567
+ */
568
+ async notifySuggestionsStartedLoading(agentId) {
569
+ await this.core.notifySubscribers(
570
+ (subscriber) => subscriber.onSuggestionsStartedLoading?.({
571
+ copilotkit: this.core,
572
+ agentId
573
+ }),
574
+ "Subscriber onSuggestionsStartedLoading error:"
575
+ );
576
+ }
577
+ /**
578
+ * Notify subscribers that suggestions finished loading
579
+ */
580
+ async notifySuggestionsFinishedLoading(agentId) {
581
+ await this.core.notifySubscribers(
582
+ (subscriber) => subscriber.onSuggestionsFinishedLoading?.({
583
+ copilotkit: this.core,
584
+ agentId
585
+ }),
586
+ "Subscriber onSuggestionsFinishedLoading error:"
587
+ );
588
+ }
589
+ /**
590
+ * Check if suggestions should be shown based on availability and message count
591
+ */
592
+ shouldShowSuggestions(config, messageCount) {
593
+ const availability = config.available;
594
+ if (!availability) {
595
+ if (isDynamicSuggestionsConfig(config)) {
596
+ return messageCount > 0;
597
+ } else {
598
+ return messageCount === 0;
599
+ }
600
+ }
601
+ switch (availability) {
602
+ case "disabled":
603
+ return false;
604
+ case "before-first-message":
605
+ return messageCount === 0;
606
+ case "after-first-message":
607
+ return messageCount > 0;
608
+ case "always":
609
+ return true;
610
+ default:
611
+ return false;
612
+ }
613
+ }
614
+ /**
615
+ * Add static suggestions directly without AI generation
616
+ */
617
+ addStaticSuggestions(suggestionId, config, consumerAgentId) {
618
+ const suggestions = config.suggestions.map((s) => ({
619
+ ...s,
620
+ isLoading: false
621
+ }));
622
+ this._suggestions[consumerAgentId] = {
623
+ ...this._suggestions[consumerAgentId] ?? {},
624
+ [suggestionId]: suggestions
625
+ };
626
+ const allSuggestions = Object.values(this._suggestions[consumerAgentId] ?? {}).flat();
627
+ void this.notifySuggestionsChanged(consumerAgentId, allSuggestions, "static suggestions added");
628
+ }
629
+ };
630
+ function isDynamicSuggestionsConfig(config) {
631
+ return "instructions" in config;
632
+ }
633
+ function isStaticSuggestionsConfig(config) {
634
+ return "suggestions" in config;
635
+ }
636
+ var SUGGEST_TOOL = {
637
+ name: "copilotkitSuggest",
638
+ description: "Suggest what the user could say next",
639
+ parameters: {
640
+ type: "object",
641
+ properties: {
642
+ suggestions: {
643
+ type: "array",
644
+ description: "List of suggestions shown to the user as buttons.",
645
+ items: {
646
+ type: "object",
647
+ properties: {
648
+ title: {
649
+ type: "string",
650
+ description: "The title of the suggestion. This is shown as a button and should be short."
651
+ },
652
+ message: {
653
+ type: "string",
654
+ 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."
655
+ }
656
+ },
657
+ required: ["title", "message"],
658
+ additionalProperties: false
659
+ }
660
+ }
661
+ },
662
+ required: ["suggestions"],
663
+ additionalProperties: false
664
+ }
665
+ };
666
+
667
+ // src/core/run-handler.ts
668
+ var import_client3 = require("@ag-ui/client");
669
+ var import_shared4 = require("@copilotkitnext/shared");
670
+ var import_zod_to_json_schema = require("zod-to-json-schema");
671
+ var RunHandler = class {
672
+ constructor(core) {
673
+ this.core = core;
674
+ }
675
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
676
+ _tools = [];
677
+ /**
678
+ * Get all tools as a readonly array
679
+ */
680
+ get tools() {
681
+ return this._tools;
682
+ }
683
+ /**
684
+ * Initialize with tools
685
+ */
686
+ initialize(tools) {
687
+ this._tools = tools;
688
+ }
394
689
  /**
395
- * Tool management
690
+ * Add a tool to the registry
396
691
  */
397
692
  addTool(tool) {
398
- const existingToolIndex = this._tools.findIndex(
399
- (t) => t.name === tool.name && t.agentId === tool.agentId
400
- );
693
+ const existingToolIndex = this._tools.findIndex((t) => t.name === tool.name && t.agentId === tool.agentId);
401
694
  if (existingToolIndex !== -1) {
402
- import_shared.logger.warn(
403
- `Tool already exists: '${tool.name}' for agent '${tool.agentId || "global"}', skipping.`
404
- );
695
+ import_shared4.logger.warn(`Tool already exists: '${tool.name}' for agent '${tool.agentId || "global"}', skipping.`);
405
696
  return;
406
697
  }
407
698
  this._tools.push(tool);
408
699
  }
700
+ /**
701
+ * Remove a tool by name and optionally by agentId
702
+ */
409
703
  removeTool(id, agentId) {
410
704
  this._tools = this._tools.filter((tool) => {
411
705
  if (agentId !== void 0) {
@@ -422,9 +716,7 @@ var CopilotKitCore = class {
422
716
  getTool(params) {
423
717
  const { toolName, agentId } = params;
424
718
  if (agentId) {
425
- const agentTool = this._tools.find(
426
- (tool) => tool.name === toolName && tool.agentId === agentId
427
- );
719
+ const agentTool = this._tools.find((tool) => tool.name === toolName && tool.agentId === agentId);
428
720
  if (agentTool) {
429
721
  return agentTool;
430
722
  }
@@ -438,43 +730,28 @@ var CopilotKitCore = class {
438
730
  this._tools = [...tools];
439
731
  }
440
732
  /**
441
- * Subscription lifecycle
442
- */
443
- subscribe(subscriber) {
444
- this.subscribers.add(subscriber);
445
- return () => {
446
- this.unsubscribe(subscriber);
447
- };
448
- }
449
- unsubscribe(subscriber) {
450
- this.subscribers.delete(subscriber);
451
- }
452
- /**
453
- * Agent connectivity
733
+ * Connect an agent (establish initial connection)
454
734
  */
455
- async connectAgent({
456
- agent,
457
- agentId
458
- }) {
735
+ async connectAgent({ agent }) {
459
736
  try {
460
- if (agent instanceof import_client2.HttpAgent) {
461
- agent.headers = { ...this.headers };
737
+ if (agent instanceof import_client3.HttpAgent) {
738
+ agent.headers = { ...this.core.headers };
462
739
  }
463
740
  const runAgentResult = await agent.connectAgent(
464
741
  {
465
- forwardedProps: this.properties,
466
- tools: this.buildFrontendTools(agentId)
742
+ forwardedProps: this.core.properties,
743
+ tools: this.buildFrontendTools(agent.agentId)
467
744
  },
468
- this.createAgentErrorSubscriber(agent, agentId)
745
+ this.createAgentErrorSubscriber(agent)
469
746
  );
470
- return this.processAgentResult({ runAgentResult, agent, agentId });
747
+ return this.processAgentResult({ runAgentResult, agent });
471
748
  } catch (error) {
472
749
  const connectError = error instanceof Error ? error : new Error(String(error));
473
750
  const context = {};
474
- if (agentId ?? agent.agentId) {
475
- context.agentId = agentId ?? agent.agentId;
751
+ if (agent.agentId) {
752
+ context.agentId = agent.agentId;
476
753
  }
477
- await this.emitError({
754
+ await this.core.emitError({
478
755
  error: connectError,
479
756
  code: "agent_connect_failed" /* AGENT_CONNECT_FAILED */,
480
757
  context
@@ -482,13 +759,13 @@ var CopilotKitCore = class {
482
759
  throw error;
483
760
  }
484
761
  }
485
- async runAgent({
486
- agent,
487
- withMessages,
488
- agentId
489
- }) {
490
- if (agent instanceof import_client2.HttpAgent) {
491
- agent.headers = { ...this.headers };
762
+ /**
763
+ * Run an agent
764
+ */
765
+ async runAgent({ agent, withMessages }) {
766
+ void this.core.suggestionEngine.clearSuggestions(agent.agentId);
767
+ if (agent instanceof import_client3.HttpAgent) {
768
+ agent.headers = { ...this.core.headers };
492
769
  }
493
770
  if (withMessages) {
494
771
  agent.addMessages(withMessages);
@@ -496,22 +773,22 @@ var CopilotKitCore = class {
496
773
  try {
497
774
  const runAgentResult = await agent.runAgent(
498
775
  {
499
- forwardedProps: this.properties,
500
- tools: this.buildFrontendTools(agentId)
776
+ forwardedProps: this.core.properties,
777
+ tools: this.buildFrontendTools(agent.agentId)
501
778
  },
502
- this.createAgentErrorSubscriber(agent, agentId)
779
+ this.createAgentErrorSubscriber(agent)
503
780
  );
504
- return this.processAgentResult({ runAgentResult, agent, agentId });
781
+ return this.processAgentResult({ runAgentResult, agent });
505
782
  } catch (error) {
506
783
  const runError = error instanceof Error ? error : new Error(String(error));
507
784
  const context = {};
508
- if (agentId ?? agent.agentId) {
509
- context.agentId = agentId ?? agent.agentId;
785
+ if (agent.agentId) {
786
+ context.agentId = agent.agentId;
510
787
  }
511
788
  if (withMessages) {
512
789
  context.messageCount = withMessages.length;
513
790
  }
514
- await this.emitError({
791
+ await this.core.emitError({
515
792
  error: runError,
516
793
  code: "agent_run_failed" /* AGENT_RUN_FAILED */,
517
794
  context
@@ -519,231 +796,35 @@ var CopilotKitCore = class {
519
796
  throw error;
520
797
  }
521
798
  }
799
+ /**
800
+ * Process agent result and execute tools
801
+ */
522
802
  async processAgentResult({
523
803
  runAgentResult,
524
- agent,
525
- agentId
804
+ agent
526
805
  }) {
527
806
  const { newMessages } = runAgentResult;
528
- const effectiveAgentId = this.resolveAgentId(agent, agentId);
807
+ const agentId = agent.agentId;
529
808
  let needsFollowUp = false;
530
809
  for (const message of newMessages) {
531
810
  if (message.role === "assistant") {
532
811
  for (const toolCall of message.toolCalls || []) {
533
- if (newMessages.findIndex(
534
- (m) => m.role === "tool" && m.toolCallId === toolCall.id
535
- ) === -1) {
812
+ if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
536
813
  const tool = this.getTool({
537
814
  toolName: toolCall.function.name,
538
- agentId
815
+ agentId: agent.agentId
539
816
  });
540
817
  if (tool) {
541
- if (tool?.agentId && tool.agentId !== agentId) {
542
- continue;
543
- }
544
- let toolCallResult = "";
545
- let errorMessage;
546
- let isArgumentError = false;
547
- if (tool?.handler) {
548
- let parsedArgs;
549
- try {
550
- parsedArgs = JSON.parse(toolCall.function.arguments);
551
- } catch (error) {
552
- const parseError = error instanceof Error ? error : new Error(String(error));
553
- errorMessage = parseError.message;
554
- isArgumentError = true;
555
- await this.emitError({
556
- error: parseError,
557
- code: "tool_argument_parse_failed" /* TOOL_ARGUMENT_PARSE_FAILED */,
558
- context: {
559
- agentId: effectiveAgentId,
560
- toolCallId: toolCall.id,
561
- toolName: toolCall.function.name,
562
- rawArguments: toolCall.function.arguments,
563
- toolType: "specific",
564
- messageId: message.id
565
- }
566
- });
567
- }
568
- await this.notifySubscribers(
569
- (subscriber) => subscriber.onToolExecutionStart?.({
570
- copilotkit: this,
571
- toolCallId: toolCall.id,
572
- agentId: effectiveAgentId,
573
- toolName: toolCall.function.name,
574
- args: parsedArgs
575
- }),
576
- "Subscriber onToolExecutionStart error:"
577
- );
578
- if (!errorMessage) {
579
- try {
580
- const result = await tool.handler(
581
- parsedArgs,
582
- toolCall
583
- );
584
- if (result === void 0 || result === null) {
585
- toolCallResult = "";
586
- } else if (typeof result === "string") {
587
- toolCallResult = result;
588
- } else {
589
- toolCallResult = JSON.stringify(result);
590
- }
591
- } catch (error) {
592
- const handlerError = error instanceof Error ? error : new Error(String(error));
593
- errorMessage = handlerError.message;
594
- await this.emitError({
595
- error: handlerError,
596
- code: "tool_handler_failed" /* TOOL_HANDLER_FAILED */,
597
- context: {
598
- agentId: effectiveAgentId,
599
- toolCallId: toolCall.id,
600
- toolName: toolCall.function.name,
601
- parsedArgs,
602
- toolType: "specific",
603
- messageId: message.id
604
- }
605
- });
606
- }
607
- }
608
- if (errorMessage) {
609
- toolCallResult = `Error: ${errorMessage}`;
610
- }
611
- await this.notifySubscribers(
612
- (subscriber) => subscriber.onToolExecutionEnd?.({
613
- copilotkit: this,
614
- toolCallId: toolCall.id,
615
- agentId: effectiveAgentId,
616
- toolName: toolCall.function.name,
617
- result: errorMessage ? "" : toolCallResult,
618
- error: errorMessage
619
- }),
620
- "Subscriber onToolExecutionEnd error:"
621
- );
622
- if (isArgumentError) {
623
- throw new Error(errorMessage ?? "Tool execution failed");
624
- }
625
- }
626
- if (!errorMessage || !isArgumentError) {
627
- const messageIndex = agent.messages.findIndex(
628
- (m) => m.id === message.id
629
- );
630
- const toolMessage = {
631
- id: (0, import_shared.randomUUID)(),
632
- role: "tool",
633
- toolCallId: toolCall.id,
634
- content: toolCallResult
635
- };
636
- agent.messages.splice(messageIndex + 1, 0, toolMessage);
637
- if (!errorMessage && tool?.followUp !== false) {
638
- needsFollowUp = true;
639
- }
818
+ const followUp = await this.executeSpecificTool(tool, toolCall, message, agent, agentId);
819
+ if (followUp) {
820
+ needsFollowUp = true;
640
821
  }
641
822
  } else {
642
- const wildcardTool = this.getTool({ toolName: "*", agentId });
823
+ const wildcardTool = this.getTool({ toolName: "*", agentId: agent.agentId });
643
824
  if (wildcardTool) {
644
- if (wildcardTool?.agentId && wildcardTool.agentId !== agentId) {
645
- continue;
646
- }
647
- let toolCallResult = "";
648
- let errorMessage;
649
- let isArgumentError = false;
650
- if (wildcardTool?.handler) {
651
- let parsedArgs;
652
- try {
653
- parsedArgs = JSON.parse(toolCall.function.arguments);
654
- } catch (error) {
655
- const parseError = error instanceof Error ? error : new Error(String(error));
656
- errorMessage = parseError.message;
657
- isArgumentError = true;
658
- await this.emitError({
659
- error: parseError,
660
- code: "tool_argument_parse_failed" /* TOOL_ARGUMENT_PARSE_FAILED */,
661
- context: {
662
- agentId: effectiveAgentId,
663
- toolCallId: toolCall.id,
664
- toolName: toolCall.function.name,
665
- rawArguments: toolCall.function.arguments,
666
- toolType: "wildcard",
667
- messageId: message.id
668
- }
669
- });
670
- }
671
- const wildcardArgs = {
672
- toolName: toolCall.function.name,
673
- args: parsedArgs
674
- };
675
- await this.notifySubscribers(
676
- (subscriber) => subscriber.onToolExecutionStart?.({
677
- copilotkit: this,
678
- toolCallId: toolCall.id,
679
- agentId: effectiveAgentId,
680
- toolName: toolCall.function.name,
681
- args: wildcardArgs
682
- }),
683
- "Subscriber onToolExecutionStart error:"
684
- );
685
- if (!errorMessage) {
686
- try {
687
- const result = await wildcardTool.handler(
688
- wildcardArgs,
689
- toolCall
690
- );
691
- if (result === void 0 || result === null) {
692
- toolCallResult = "";
693
- } else if (typeof result === "string") {
694
- toolCallResult = result;
695
- } else {
696
- toolCallResult = JSON.stringify(result);
697
- }
698
- } catch (error) {
699
- const handlerError = error instanceof Error ? error : new Error(String(error));
700
- errorMessage = handlerError.message;
701
- await this.emitError({
702
- error: handlerError,
703
- code: "tool_handler_failed" /* TOOL_HANDLER_FAILED */,
704
- context: {
705
- agentId: effectiveAgentId,
706
- toolCallId: toolCall.id,
707
- toolName: toolCall.function.name,
708
- parsedArgs: wildcardArgs,
709
- toolType: "wildcard",
710
- messageId: message.id
711
- }
712
- });
713
- }
714
- }
715
- if (errorMessage) {
716
- toolCallResult = `Error: ${errorMessage}`;
717
- }
718
- await this.notifySubscribers(
719
- (subscriber) => subscriber.onToolExecutionEnd?.({
720
- copilotkit: this,
721
- toolCallId: toolCall.id,
722
- agentId: effectiveAgentId,
723
- toolName: toolCall.function.name,
724
- result: errorMessage ? "" : toolCallResult,
725
- error: errorMessage
726
- }),
727
- "Subscriber onToolExecutionEnd error:"
728
- );
729
- if (isArgumentError) {
730
- throw new Error(errorMessage ?? "Tool execution failed");
731
- }
732
- }
733
- if (!errorMessage || !isArgumentError) {
734
- const messageIndex = agent.messages.findIndex(
735
- (m) => m.id === message.id
736
- );
737
- const toolMessage = {
738
- id: (0, import_shared.randomUUID)(),
739
- role: "tool",
740
- toolCallId: toolCall.id,
741
- content: toolCallResult
742
- };
743
- agent.messages.splice(messageIndex + 1, 0, toolMessage);
744
- if (!errorMessage && wildcardTool?.followUp !== false) {
745
- needsFollowUp = true;
746
- }
825
+ const followUp = await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId);
826
+ if (followUp) {
827
+ needsFollowUp = true;
747
828
  }
748
829
  }
749
830
  }
@@ -752,10 +833,220 @@ var CopilotKitCore = class {
752
833
  }
753
834
  }
754
835
  if (needsFollowUp) {
755
- return await this.runAgent({ agent, agentId });
836
+ return await this.runAgent({ agent });
756
837
  }
838
+ void this.core.suggestionEngine.reloadSuggestions(agentId);
757
839
  return runAgentResult;
758
840
  }
841
+ /**
842
+ * Execute a specific tool
843
+ */
844
+ async executeSpecificTool(tool, toolCall, message, agent, agentId) {
845
+ if (tool?.agentId && tool.agentId !== agent.agentId) {
846
+ return false;
847
+ }
848
+ let toolCallResult = "";
849
+ let errorMessage;
850
+ let isArgumentError = false;
851
+ if (tool?.handler) {
852
+ let parsedArgs;
853
+ try {
854
+ parsedArgs = JSON.parse(toolCall.function.arguments);
855
+ } catch (error) {
856
+ const parseError = error instanceof Error ? error : new Error(String(error));
857
+ errorMessage = parseError.message;
858
+ isArgumentError = true;
859
+ await this.core.emitError({
860
+ error: parseError,
861
+ code: "tool_argument_parse_failed" /* TOOL_ARGUMENT_PARSE_FAILED */,
862
+ context: {
863
+ agentId,
864
+ toolCallId: toolCall.id,
865
+ toolName: toolCall.function.name,
866
+ rawArguments: toolCall.function.arguments,
867
+ toolType: "specific",
868
+ messageId: message.id
869
+ }
870
+ });
871
+ }
872
+ await this.core.notifySubscribers(
873
+ (subscriber) => subscriber.onToolExecutionStart?.({
874
+ copilotkit: this.core,
875
+ toolCallId: toolCall.id,
876
+ agentId,
877
+ toolName: toolCall.function.name,
878
+ args: parsedArgs
879
+ }),
880
+ "Subscriber onToolExecutionStart error:"
881
+ );
882
+ if (!errorMessage) {
883
+ try {
884
+ const result = await tool.handler(parsedArgs, toolCall);
885
+ if (result === void 0 || result === null) {
886
+ toolCallResult = "";
887
+ } else if (typeof result === "string") {
888
+ toolCallResult = result;
889
+ } else {
890
+ toolCallResult = JSON.stringify(result);
891
+ }
892
+ } catch (error) {
893
+ const handlerError = error instanceof Error ? error : new Error(String(error));
894
+ errorMessage = handlerError.message;
895
+ await this.core.emitError({
896
+ error: handlerError,
897
+ code: "tool_handler_failed" /* TOOL_HANDLER_FAILED */,
898
+ context: {
899
+ agentId,
900
+ toolCallId: toolCall.id,
901
+ toolName: toolCall.function.name,
902
+ parsedArgs,
903
+ toolType: "specific",
904
+ messageId: message.id
905
+ }
906
+ });
907
+ }
908
+ }
909
+ if (errorMessage) {
910
+ toolCallResult = `Error: ${errorMessage}`;
911
+ }
912
+ await this.core.notifySubscribers(
913
+ (subscriber) => subscriber.onToolExecutionEnd?.({
914
+ copilotkit: this.core,
915
+ toolCallId: toolCall.id,
916
+ agentId,
917
+ toolName: toolCall.function.name,
918
+ result: errorMessage ? "" : toolCallResult,
919
+ error: errorMessage
920
+ }),
921
+ "Subscriber onToolExecutionEnd error:"
922
+ );
923
+ if (isArgumentError) {
924
+ throw new Error(errorMessage ?? "Tool execution failed");
925
+ }
926
+ }
927
+ if (!errorMessage || !isArgumentError) {
928
+ const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
929
+ const toolMessage = {
930
+ id: (0, import_shared4.randomUUID)(),
931
+ role: "tool",
932
+ toolCallId: toolCall.id,
933
+ content: toolCallResult
934
+ };
935
+ agent.messages.splice(messageIndex + 1, 0, toolMessage);
936
+ if (!errorMessage && tool?.followUp !== false) {
937
+ return true;
938
+ }
939
+ }
940
+ return false;
941
+ }
942
+ /**
943
+ * Execute a wildcard tool
944
+ */
945
+ async executeWildcardTool(wildcardTool, toolCall, message, agent, agentId) {
946
+ if (wildcardTool?.agentId && wildcardTool.agentId !== agent.agentId) {
947
+ return false;
948
+ }
949
+ let toolCallResult = "";
950
+ let errorMessage;
951
+ let isArgumentError = false;
952
+ if (wildcardTool?.handler) {
953
+ let parsedArgs;
954
+ try {
955
+ parsedArgs = JSON.parse(toolCall.function.arguments);
956
+ } catch (error) {
957
+ const parseError = error instanceof Error ? error : new Error(String(error));
958
+ errorMessage = parseError.message;
959
+ isArgumentError = true;
960
+ await this.core.emitError({
961
+ error: parseError,
962
+ code: "tool_argument_parse_failed" /* TOOL_ARGUMENT_PARSE_FAILED */,
963
+ context: {
964
+ agentId,
965
+ toolCallId: toolCall.id,
966
+ toolName: toolCall.function.name,
967
+ rawArguments: toolCall.function.arguments,
968
+ toolType: "wildcard",
969
+ messageId: message.id
970
+ }
971
+ });
972
+ }
973
+ const wildcardArgs = {
974
+ toolName: toolCall.function.name,
975
+ args: parsedArgs
976
+ };
977
+ await this.core.notifySubscribers(
978
+ (subscriber) => subscriber.onToolExecutionStart?.({
979
+ copilotkit: this.core,
980
+ toolCallId: toolCall.id,
981
+ agentId,
982
+ toolName: toolCall.function.name,
983
+ args: wildcardArgs
984
+ }),
985
+ "Subscriber onToolExecutionStart error:"
986
+ );
987
+ if (!errorMessage) {
988
+ try {
989
+ const result = await wildcardTool.handler(wildcardArgs, toolCall);
990
+ if (result === void 0 || result === null) {
991
+ toolCallResult = "";
992
+ } else if (typeof result === "string") {
993
+ toolCallResult = result;
994
+ } else {
995
+ toolCallResult = JSON.stringify(result);
996
+ }
997
+ } catch (error) {
998
+ const handlerError = error instanceof Error ? error : new Error(String(error));
999
+ errorMessage = handlerError.message;
1000
+ await this.core.emitError({
1001
+ error: handlerError,
1002
+ code: "tool_handler_failed" /* TOOL_HANDLER_FAILED */,
1003
+ context: {
1004
+ agentId,
1005
+ toolCallId: toolCall.id,
1006
+ toolName: toolCall.function.name,
1007
+ parsedArgs: wildcardArgs,
1008
+ toolType: "wildcard",
1009
+ messageId: message.id
1010
+ }
1011
+ });
1012
+ }
1013
+ }
1014
+ if (errorMessage) {
1015
+ toolCallResult = `Error: ${errorMessage}`;
1016
+ }
1017
+ await this.core.notifySubscribers(
1018
+ (subscriber) => subscriber.onToolExecutionEnd?.({
1019
+ copilotkit: this.core,
1020
+ toolCallId: toolCall.id,
1021
+ agentId,
1022
+ toolName: toolCall.function.name,
1023
+ result: errorMessage ? "" : toolCallResult,
1024
+ error: errorMessage
1025
+ }),
1026
+ "Subscriber onToolExecutionEnd error:"
1027
+ );
1028
+ if (isArgumentError) {
1029
+ throw new Error(errorMessage ?? "Tool execution failed");
1030
+ }
1031
+ }
1032
+ if (!errorMessage || !isArgumentError) {
1033
+ const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
1034
+ const toolMessage = {
1035
+ id: (0, import_shared4.randomUUID)(),
1036
+ role: "tool",
1037
+ toolCallId: toolCall.id,
1038
+ content: toolCallResult
1039
+ };
1040
+ agent.messages.splice(messageIndex + 1, 0, toolMessage);
1041
+ if (!errorMessage && wildcardTool?.followUp !== false) {
1042
+ return true;
1043
+ }
1044
+ }
1045
+ return false;
1046
+ }
1047
+ /**
1048
+ * Build frontend tools for an agent
1049
+ */
759
1050
  buildFrontendTools(agentId) {
760
1051
  return this._tools.filter((tool) => !tool.agentId || tool.agentId === agentId).map((tool) => ({
761
1052
  name: tool.name,
@@ -763,13 +1054,16 @@ var CopilotKitCore = class {
763
1054
  parameters: createToolSchema(tool)
764
1055
  }));
765
1056
  }
766
- createAgentErrorSubscriber(agent, agentId) {
1057
+ /**
1058
+ * Create an agent error subscriber
1059
+ */
1060
+ createAgentErrorSubscriber(agent) {
767
1061
  const emitAgentError = async (error, code, extraContext = {}) => {
768
1062
  const context = { ...extraContext };
769
- if (agentId ?? agent.agentId) {
770
- context.agentId = agentId ?? agent.agentId;
1063
+ if (agent.agentId) {
1064
+ context.agentId = agent.agentId;
771
1065
  }
772
- await this.emitError({
1066
+ await this.core.emitError({
773
1067
  error,
774
1068
  code,
775
1069
  context
@@ -777,13 +1071,9 @@ var CopilotKitCore = class {
777
1071
  };
778
1072
  return {
779
1073
  onRunFailed: async ({ error }) => {
780
- await emitAgentError(
781
- error,
782
- "agent_run_failed_event" /* AGENT_RUN_FAILED_EVENT */,
783
- {
784
- source: "onRunFailed"
785
- }
786
- );
1074
+ await emitAgentError(error, "agent_run_failed_event" /* AGENT_RUN_FAILED_EVENT */, {
1075
+ source: "onRunFailed"
1076
+ });
787
1077
  },
788
1078
  onRunErrorEvent: async ({ event }) => {
789
1079
  const eventError = event?.rawEvent instanceof Error ? event.rawEvent : event?.rawEvent?.error instanceof Error ? event.rawEvent.error : void 0;
@@ -792,15 +1082,11 @@ var CopilotKitCore = class {
792
1082
  if (event?.code && !rawError.code) {
793
1083
  rawError.code = event.code;
794
1084
  }
795
- await emitAgentError(
796
- rawError,
797
- "agent_run_error_event" /* AGENT_RUN_ERROR_EVENT */,
798
- {
799
- source: "onRunErrorEvent",
800
- event,
801
- runtimeErrorCode: event?.code
802
- }
803
- );
1085
+ await emitAgentError(rawError, "agent_run_error_event" /* AGENT_RUN_ERROR_EVENT */, {
1086
+ source: "onRunErrorEvent",
1087
+ event,
1088
+ runtimeErrorCode: event?.code
1089
+ });
804
1090
  }
805
1091
  };
806
1092
  }
@@ -833,6 +1119,224 @@ function createToolSchema(tool) {
833
1119
  return schema;
834
1120
  }
835
1121
 
1122
+ // src/core/core.ts
1123
+ var CopilotKitCoreErrorCode = /* @__PURE__ */ ((CopilotKitCoreErrorCode2) => {
1124
+ CopilotKitCoreErrorCode2["RUNTIME_INFO_FETCH_FAILED"] = "runtime_info_fetch_failed";
1125
+ CopilotKitCoreErrorCode2["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
1126
+ CopilotKitCoreErrorCode2["AGENT_RUN_FAILED"] = "agent_run_failed";
1127
+ CopilotKitCoreErrorCode2["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
1128
+ CopilotKitCoreErrorCode2["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
1129
+ CopilotKitCoreErrorCode2["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
1130
+ CopilotKitCoreErrorCode2["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
1131
+ return CopilotKitCoreErrorCode2;
1132
+ })(CopilotKitCoreErrorCode || {});
1133
+ var CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ ((CopilotKitCoreRuntimeConnectionStatus2) => {
1134
+ CopilotKitCoreRuntimeConnectionStatus2["Disconnected"] = "disconnected";
1135
+ CopilotKitCoreRuntimeConnectionStatus2["Connected"] = "connected";
1136
+ CopilotKitCoreRuntimeConnectionStatus2["Connecting"] = "connecting";
1137
+ CopilotKitCoreRuntimeConnectionStatus2["Error"] = "error";
1138
+ return CopilotKitCoreRuntimeConnectionStatus2;
1139
+ })(CopilotKitCoreRuntimeConnectionStatus || {});
1140
+ var CopilotKitCore = class {
1141
+ _headers;
1142
+ _properties;
1143
+ subscribers = /* @__PURE__ */ new Set();
1144
+ // Delegate classes
1145
+ agentRegistry;
1146
+ contextStore;
1147
+ suggestionEngine;
1148
+ runHandler;
1149
+ constructor({
1150
+ runtimeUrl,
1151
+ headers = {},
1152
+ properties = {},
1153
+ agents__unsafe_dev_only = {},
1154
+ tools = [],
1155
+ suggestionsConfig = []
1156
+ }) {
1157
+ this._headers = headers;
1158
+ this._properties = properties;
1159
+ this.agentRegistry = new AgentRegistry(this);
1160
+ this.contextStore = new ContextStore(this);
1161
+ this.suggestionEngine = new SuggestionEngine(this);
1162
+ this.runHandler = new RunHandler(this);
1163
+ this.agentRegistry.initialize(agents__unsafe_dev_only);
1164
+ this.runHandler.initialize(tools);
1165
+ this.suggestionEngine.initialize(suggestionsConfig);
1166
+ this.agentRegistry.setRuntimeUrl(runtimeUrl);
1167
+ }
1168
+ /**
1169
+ * Internal method used by delegate classes to notify subscribers
1170
+ */
1171
+ async notifySubscribers(handler, errorMessage) {
1172
+ await Promise.all(
1173
+ Array.from(this.subscribers).map(async (subscriber) => {
1174
+ try {
1175
+ await handler(subscriber);
1176
+ } catch (error) {
1177
+ console.error(errorMessage, error);
1178
+ }
1179
+ })
1180
+ );
1181
+ }
1182
+ /**
1183
+ * Internal method used by delegate classes to emit errors
1184
+ */
1185
+ async emitError({
1186
+ error,
1187
+ code,
1188
+ context = {}
1189
+ }) {
1190
+ await this.notifySubscribers(
1191
+ (subscriber) => subscriber.onError?.({
1192
+ copilotkit: this,
1193
+ error,
1194
+ code,
1195
+ context
1196
+ }),
1197
+ "Subscriber onError error:"
1198
+ );
1199
+ }
1200
+ /**
1201
+ * Snapshot accessors
1202
+ */
1203
+ get context() {
1204
+ return this.contextStore.context;
1205
+ }
1206
+ get agents() {
1207
+ return this.agentRegistry.agents;
1208
+ }
1209
+ get tools() {
1210
+ return this.runHandler.tools;
1211
+ }
1212
+ get runtimeUrl() {
1213
+ return this.agentRegistry.runtimeUrl;
1214
+ }
1215
+ setRuntimeUrl(runtimeUrl) {
1216
+ this.agentRegistry.setRuntimeUrl(runtimeUrl);
1217
+ }
1218
+ get runtimeVersion() {
1219
+ return this.agentRegistry.runtimeVersion;
1220
+ }
1221
+ get headers() {
1222
+ return this._headers;
1223
+ }
1224
+ get properties() {
1225
+ return this._properties;
1226
+ }
1227
+ get runtimeConnectionStatus() {
1228
+ return this.agentRegistry.runtimeConnectionStatus;
1229
+ }
1230
+ /**
1231
+ * Configuration updates
1232
+ */
1233
+ setHeaders(headers) {
1234
+ this._headers = headers;
1235
+ this.agentRegistry.applyHeadersToAgents(this.agentRegistry.agents);
1236
+ void this.notifySubscribers(
1237
+ (subscriber) => subscriber.onHeadersChanged?.({
1238
+ copilotkit: this,
1239
+ headers: this.headers
1240
+ }),
1241
+ "Subscriber onHeadersChanged error:"
1242
+ );
1243
+ }
1244
+ setProperties(properties) {
1245
+ this._properties = properties;
1246
+ void this.notifySubscribers(
1247
+ (subscriber) => subscriber.onPropertiesChanged?.({
1248
+ copilotkit: this,
1249
+ properties: this.properties
1250
+ }),
1251
+ "Subscriber onPropertiesChanged error:"
1252
+ );
1253
+ }
1254
+ /**
1255
+ * Agent management (delegated to AgentRegistry)
1256
+ */
1257
+ setAgents__unsafe_dev_only(agents) {
1258
+ this.agentRegistry.setAgents__unsafe_dev_only(agents);
1259
+ }
1260
+ addAgent__unsafe_dev_only(params) {
1261
+ this.agentRegistry.addAgent__unsafe_dev_only(params);
1262
+ }
1263
+ removeAgent__unsafe_dev_only(id) {
1264
+ this.agentRegistry.removeAgent__unsafe_dev_only(id);
1265
+ }
1266
+ getAgent(id) {
1267
+ return this.agentRegistry.getAgent(id);
1268
+ }
1269
+ /**
1270
+ * Context management (delegated to ContextStore)
1271
+ */
1272
+ addContext(context) {
1273
+ return this.contextStore.addContext(context);
1274
+ }
1275
+ removeContext(id) {
1276
+ this.contextStore.removeContext(id);
1277
+ }
1278
+ /**
1279
+ * Suggestions management (delegated to SuggestionEngine)
1280
+ */
1281
+ addSuggestionsConfig(config) {
1282
+ return this.suggestionEngine.addSuggestionsConfig(config);
1283
+ }
1284
+ removeSuggestionsConfig(id) {
1285
+ this.suggestionEngine.removeSuggestionsConfig(id);
1286
+ }
1287
+ reloadSuggestions(agentId) {
1288
+ this.suggestionEngine.reloadSuggestions(agentId);
1289
+ }
1290
+ clearSuggestions(agentId) {
1291
+ this.suggestionEngine.clearSuggestions(agentId);
1292
+ }
1293
+ getSuggestions(agentId) {
1294
+ return this.suggestionEngine.getSuggestions(agentId);
1295
+ }
1296
+ /**
1297
+ * Tool management (delegated to RunHandler)
1298
+ */
1299
+ addTool(tool) {
1300
+ this.runHandler.addTool(tool);
1301
+ }
1302
+ removeTool(id, agentId) {
1303
+ this.runHandler.removeTool(id, agentId);
1304
+ }
1305
+ getTool(params) {
1306
+ return this.runHandler.getTool(params);
1307
+ }
1308
+ setTools(tools) {
1309
+ this.runHandler.setTools(tools);
1310
+ }
1311
+ /**
1312
+ * Subscription lifecycle
1313
+ */
1314
+ subscribe(subscriber) {
1315
+ this.subscribers.add(subscriber);
1316
+ return () => {
1317
+ this.unsubscribe(subscriber);
1318
+ };
1319
+ }
1320
+ unsubscribe(subscriber) {
1321
+ this.subscribers.delete(subscriber);
1322
+ }
1323
+ /**
1324
+ * Agent connectivity (delegated to RunHandler)
1325
+ */
1326
+ async connectAgent(params) {
1327
+ return this.runHandler.connectAgent(params);
1328
+ }
1329
+ async runAgent(params) {
1330
+ return this.runHandler.runAgent(params);
1331
+ }
1332
+ /**
1333
+ * Internal method used by RunHandler to build frontend tools
1334
+ */
1335
+ buildFrontendTools(agentId) {
1336
+ return this.runHandler.buildFrontendTools(agentId);
1337
+ }
1338
+ };
1339
+
836
1340
  // src/types.ts
837
1341
  var ToolCallStatus = /* @__PURE__ */ ((ToolCallStatus2) => {
838
1342
  ToolCallStatus2["InProgress"] = "inProgress";
@@ -1058,10 +1562,14 @@ ${indent}${fence}`;
1058
1562
  }
1059
1563
  // Annotate the CommonJS export names for ESM import in node:
1060
1564
  0 && (module.exports = {
1565
+ AgentRegistry,
1566
+ ContextStore,
1061
1567
  CopilotKitCore,
1062
1568
  CopilotKitCoreErrorCode,
1063
1569
  CopilotKitCoreRuntimeConnectionStatus,
1064
1570
  ProxiedCopilotRuntimeAgent,
1571
+ RunHandler,
1572
+ SuggestionEngine,
1065
1573
  ToolCallStatus,
1066
1574
  completePartialMarkdown
1067
1575
  });