@copilotkitnext/core 0.0.12 → 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,129 +57,43 @@ 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__unsafe_dev_only = {},
93
- tools = []
94
- }) {
95
- this._headers = headers;
96
- this._properties = properties;
97
- this.localAgents = this.assignAgentIds(agents__unsafe_dev_only);
98
- this.applyHeadersToAgents(this.localAgents);
99
- this._agents = this.localAgents;
100
- this._tools = tools;
101
- this.setRuntimeUrl(runtimeUrl);
102
- }
103
- applyHeadersToAgent(agent) {
104
- if (agent instanceof import_client2.HttpAgent) {
105
- agent.headers = { ...this.headers };
106
- }
107
- }
108
- applyHeadersToAgents(agents) {
109
- Object.values(agents).forEach((agent) => {
110
- this.applyHeadersToAgent(agent);
111
- });
112
- }
113
- assignAgentIds(agents) {
114
- Object.entries(agents).forEach(([id, agent]) => {
115
- if (agent && !agent.agentId) {
116
- agent.agentId = id;
117
- }
118
- });
119
- return agents;
120
- }
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
- );
131
- }
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
- );
146
- }
147
- resolveAgentId(agent, providedAgentId) {
148
- if (providedAgentId) {
149
- return providedAgentId;
150
- }
151
- if (agent.agentId) {
152
- return agent.agentId;
153
- }
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];
160
- }
161
- agent.agentId = import_shared.DEFAULT_AGENT_ID;
162
- return import_shared.DEFAULT_AGENT_ID;
163
- }
164
71
  /**
165
- * Snapshot accessors
72
+ * Get all agents as a readonly record
166
73
  */
167
- get context() {
168
- return this._context;
169
- }
170
74
  get agents() {
171
75
  return this._agents;
172
76
  }
173
- get tools() {
174
- return this._tools;
175
- }
176
77
  get runtimeUrl() {
177
78
  return this._runtimeUrl;
178
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) {
90
+ this.localAgents = this.assignAgentIds(agents);
91
+ this.applyHeadersToAgents(this.localAgents);
92
+ this._agents = this.localAgents;
93
+ }
94
+ /**
95
+ * Set the runtime URL and update connection
96
+ */
179
97
  setRuntimeUrl(runtimeUrl) {
180
98
  const normalizedRuntimeUrl = runtimeUrl ? runtimeUrl.replace(/\/$/, "") : void 0;
181
99
  if (this._runtimeUrl === normalizedRuntimeUrl) {
@@ -184,54 +102,88 @@ var CopilotKitCore = class {
184
102
  this._runtimeUrl = normalizedRuntimeUrl;
185
103
  void this.updateRuntimeConnection();
186
104
  }
187
- get runtimeVersion() {
188
- return this._runtimeVersion;
105
+ /**
106
+ * Set all agents at once (for development use)
107
+ */
108
+ setAgents__unsafe_dev_only(agents) {
109
+ Object.entries(agents).forEach(([id, agent]) => {
110
+ if (agent) {
111
+ this.validateAndAssignAgentId(id, agent);
112
+ }
113
+ });
114
+ this.localAgents = agents;
115
+ this._agents = { ...this.localAgents, ...this.remoteAgents };
116
+ this.applyHeadersToAgents(this._agents);
117
+ void this.notifyAgentsChanged();
189
118
  }
190
- get headers() {
191
- return this._headers;
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();
192
128
  }
193
- get properties() {
194
- return this._properties;
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();
195
136
  }
196
- get runtimeConnectionStatus() {
197
- return this._runtimeConnectionStatus;
137
+ /**
138
+ * Get an agent by ID
139
+ */
140
+ getAgent(id) {
141
+ if (id in this._agents) {
142
+ return this._agents[id];
143
+ }
144
+ if (this.runtimeUrl !== void 0 && (this.runtimeConnectionStatus === "disconnected" /* Disconnected */ || this.runtimeConnectionStatus === "connecting" /* Connecting */)) {
145
+ return void 0;
146
+ }
147
+ console.warn(`Agent ${id} not found`);
148
+ return void 0;
198
149
  }
199
150
  /**
200
- * Runtime connection
151
+ * Apply current headers to an agent
152
+ */
153
+ applyHeadersToAgent(agent) {
154
+ if (agent instanceof import_client2.HttpAgent) {
155
+ agent.headers = { ...this.core.headers };
156
+ }
157
+ }
158
+ /**
159
+ * Apply current headers to all agents
160
+ */
161
+ applyHeadersToAgents(agents) {
162
+ Object.values(agents).forEach((agent) => {
163
+ this.applyHeadersToAgent(agent);
164
+ });
165
+ }
166
+ /**
167
+ * Update runtime connection and fetch remote agents
201
168
  */
202
169
  async updateRuntimeConnection() {
170
+ if (typeof window === "undefined") {
171
+ return;
172
+ }
203
173
  if (!this.runtimeUrl) {
204
174
  this._runtimeConnectionStatus = "disconnected" /* Disconnected */;
205
175
  this._runtimeVersion = void 0;
206
176
  this.remoteAgents = {};
207
177
  this._agents = this.localAgents;
208
- await this.notifySubscribers(
209
- (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
210
- copilotkit: this,
211
- status: "disconnected" /* Disconnected */
212
- }),
213
- "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
214
- );
215
- await this.notifySubscribers(
216
- (subscriber) => subscriber.onAgentsChanged?.({
217
- copilotkit: this,
218
- agents: this._agents
219
- }),
220
- "Subscriber onAgentsChanged error:"
221
- );
178
+ await this.notifyRuntimeStatusChanged("disconnected" /* Disconnected */);
179
+ await this.notifyAgentsChanged();
222
180
  return;
223
181
  }
224
182
  this._runtimeConnectionStatus = "connecting" /* Connecting */;
225
- await this.notifySubscribers(
226
- (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
227
- copilotkit: this,
228
- status: "connecting" /* Connecting */
229
- }),
230
- "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
231
- );
183
+ await this.notifyRuntimeStatusChanged("connecting" /* Connecting */);
232
184
  try {
233
185
  const response = await fetch(`${this.runtimeUrl}/info`, {
234
- headers: this.headers
186
+ headers: this.core.headers
235
187
  });
236
188
  const {
237
189
  version,
@@ -242,6 +194,7 @@ var CopilotKitCore = class {
242
194
  const agent = new ProxiedCopilotRuntimeAgent({
243
195
  runtimeUrl: this.runtimeUrl,
244
196
  agentId: id,
197
+ // Runtime agents always have their ID set correctly
245
198
  description
246
199
  });
247
200
  this.applyHeadersToAgent(agent);
@@ -252,43 +205,19 @@ var CopilotKitCore = class {
252
205
  this._agents = { ...this.localAgents, ...this.remoteAgents };
253
206
  this._runtimeConnectionStatus = "connected" /* Connected */;
254
207
  this._runtimeVersion = version;
255
- await this.notifySubscribers(
256
- (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
257
- copilotkit: this,
258
- status: "connected" /* Connected */
259
- }),
260
- "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
261
- );
262
- await this.notifySubscribers(
263
- (subscriber) => subscriber.onAgentsChanged?.({
264
- copilotkit: this,
265
- agents: this._agents
266
- }),
267
- "Subscriber onAgentsChanged error:"
268
- );
208
+ await this.notifyRuntimeStatusChanged("connected" /* Connected */);
209
+ await this.notifyAgentsChanged();
269
210
  } catch (error) {
270
211
  this._runtimeConnectionStatus = "error" /* Error */;
271
212
  this._runtimeVersion = void 0;
272
213
  this.remoteAgents = {};
273
214
  this._agents = this.localAgents;
274
- await this.notifySubscribers(
275
- (subscriber) => subscriber.onRuntimeConnectionStatusChanged?.({
276
- copilotkit: this,
277
- status: "error" /* Error */
278
- }),
279
- "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
280
- );
281
- await this.notifySubscribers(
282
- (subscriber) => subscriber.onAgentsChanged?.({
283
- copilotkit: this,
284
- agents: this._agents
285
- }),
286
- "Subscriber onAgentsChanged error:"
287
- );
215
+ await this.notifyRuntimeStatusChanged("error" /* Error */);
216
+ await this.notifyAgentsChanged();
288
217
  const message = error instanceof Error ? error.message : JSON.stringify(error);
289
218
  import_shared.logger.warn(`Failed to load runtime info (${this.runtimeUrl}/info): ${message}`);
290
219
  const runtimeError = error instanceof Error ? error : new Error(String(error));
291
- await this.emitError({
220
+ await this.core.emitError({
292
221
  error: runtimeError,
293
222
  code: "runtime_info_fetch_failed" /* RUNTIME_INFO_FETCH_FAILED */,
294
223
  context: {
@@ -298,114 +227,479 @@ var CopilotKitCore = class {
298
227
  }
299
228
  }
300
229
  /**
301
- * Configuration updates
230
+ * Assign agent IDs to a record of agents
302
231
  */
303
- setHeaders(headers) {
304
- this._headers = headers;
305
- this.applyHeadersToAgents(this._agents);
306
- void this.notifySubscribers(
307
- (subscriber) => subscriber.onHeadersChanged?.({
308
- copilotkit: this,
309
- headers: this.headers
310
- }),
311
- "Subscriber onHeadersChanged error:"
312
- );
313
- }
314
- setProperties(properties) {
315
- this._properties = properties;
316
- void this.notifySubscribers(
317
- (subscriber) => subscriber.onPropertiesChanged?.({
318
- copilotkit: this,
319
- properties: this.properties
320
- }),
321
- "Subscriber onPropertiesChanged error:"
322
- );
323
- }
324
- setAgents__unsafe_dev_only(agents) {
325
- this.localAgents = this.assignAgentIds(agents);
326
- this._agents = { ...this.localAgents, ...this.remoteAgents };
327
- this.applyHeadersToAgents(this._agents);
328
- void this.notifySubscribers(
329
- (subscriber) => subscriber.onAgentsChanged?.({
330
- copilotkit: this,
331
- agents: this._agents
332
- }),
333
- "Subscriber onAgentsChanged error:"
334
- );
232
+ assignAgentIds(agents) {
233
+ Object.entries(agents).forEach(([id, agent]) => {
234
+ if (agent) {
235
+ this.validateAndAssignAgentId(id, agent);
236
+ }
237
+ });
238
+ return agents;
335
239
  }
336
- addAgent__unsafe_dev_only({ id, agent }) {
337
- 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
+ }
338
249
  if (!agent.agentId) {
339
- agent.agentId = id;
250
+ agent.agentId = registrationId;
340
251
  }
341
- this.applyHeadersToAgent(agent);
342
- this._agents = { ...this.localAgents, ...this.remoteAgents };
343
- void this.notifySubscribers(
344
- (subscriber) => subscriber.onAgentsChanged?.({
345
- copilotkit: this,
346
- 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
347
261
  }),
348
- "Subscriber onAgentsChanged error:"
262
+ "Error in CopilotKitCore subscriber (onRuntimeConnectionStatusChanged):"
349
263
  );
350
264
  }
351
- removeAgent__unsafe_dev_only(id) {
352
- delete this.localAgents[id];
353
- this._agents = { ...this.localAgents, ...this.remoteAgents };
354
- void this.notifySubscribers(
265
+ /**
266
+ * Notify subscribers of agent changes
267
+ */
268
+ async notifyAgentsChanged() {
269
+ await this.core.notifySubscribers(
355
270
  (subscriber) => subscriber.onAgentsChanged?.({
356
- copilotkit: this,
271
+ copilotkit: this.core,
357
272
  agents: this._agents
358
273
  }),
359
274
  "Subscriber onAgentsChanged error:"
360
275
  );
361
276
  }
362
- getAgent(id) {
363
- if (id in this._agents) {
364
- return this._agents[id];
365
- }
366
- if (this.runtimeUrl !== void 0 && (this.runtimeConnectionStatus === "disconnected" /* Disconnected */ || this.runtimeConnectionStatus === "connecting" /* Connecting */)) {
367
- return void 0;
368
- } else {
369
- console.warn(`Agent ${id} not found`);
370
- return void 0;
371
- }
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;
372
291
  }
373
292
  /**
374
- * Context management
293
+ * Add a new context entry
294
+ * @returns The ID of the created context entry
375
295
  */
376
296
  addContext({ description, value }) {
377
- const id = (0, import_shared.randomUUID)();
297
+ const id = (0, import_shared2.randomUUID)();
378
298
  this._context[id] = { description, value };
379
- void this.notifySubscribers(
380
- (subscriber) => subscriber.onContextChanged?.({
381
- copilotkit: this,
382
- context: this._context
383
- }),
384
- "Subscriber onContextChanged error:"
385
- );
299
+ void this.notifySubscribers();
386
300
  return id;
387
301
  }
302
+ /**
303
+ * Remove a context entry by ID
304
+ */
388
305
  removeContext(id) {
389
306
  delete this._context[id];
390
- 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(
391
314
  (subscriber) => subscriber.onContextChanged?.({
392
- copilotkit: this,
315
+ copilotkit: this.core,
393
316
  context: this._context
394
317
  }),
395
318
  "Subscriber onContextChanged error:"
396
319
  );
397
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
+ }
398
689
  /**
399
- * Tool management
690
+ * Add a tool to the registry
400
691
  */
401
692
  addTool(tool) {
402
693
  const existingToolIndex = this._tools.findIndex((t) => t.name === tool.name && t.agentId === tool.agentId);
403
694
  if (existingToolIndex !== -1) {
404
- import_shared.logger.warn(`Tool already exists: '${tool.name}' for agent '${tool.agentId || "global"}', skipping.`);
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) {
@@ -436,40 +730,28 @@ var CopilotKitCore = class {
436
730
  this._tools = [...tools];
437
731
  }
438
732
  /**
439
- * Subscription lifecycle
440
- */
441
- subscribe(subscriber) {
442
- this.subscribers.add(subscriber);
443
- return () => {
444
- this.unsubscribe(subscriber);
445
- };
446
- }
447
- unsubscribe(subscriber) {
448
- this.subscribers.delete(subscriber);
449
- }
450
- /**
451
- * Agent connectivity
733
+ * Connect an agent (establish initial connection)
452
734
  */
453
- async connectAgent({ agent, agentId }) {
735
+ async connectAgent({ agent }) {
454
736
  try {
455
- if (agent instanceof import_client2.HttpAgent) {
456
- agent.headers = { ...this.headers };
737
+ if (agent instanceof import_client3.HttpAgent) {
738
+ agent.headers = { ...this.core.headers };
457
739
  }
458
740
  const runAgentResult = await agent.connectAgent(
459
741
  {
460
- forwardedProps: this.properties,
461
- tools: this.buildFrontendTools(agentId)
742
+ forwardedProps: this.core.properties,
743
+ tools: this.buildFrontendTools(agent.agentId)
462
744
  },
463
- this.createAgentErrorSubscriber(agent, agentId)
745
+ this.createAgentErrorSubscriber(agent)
464
746
  );
465
- return this.processAgentResult({ runAgentResult, agent, agentId });
747
+ return this.processAgentResult({ runAgentResult, agent });
466
748
  } catch (error) {
467
749
  const connectError = error instanceof Error ? error : new Error(String(error));
468
750
  const context = {};
469
- if (agentId ?? agent.agentId) {
470
- context.agentId = agentId ?? agent.agentId;
751
+ if (agent.agentId) {
752
+ context.agentId = agent.agentId;
471
753
  }
472
- await this.emitError({
754
+ await this.core.emitError({
473
755
  error: connectError,
474
756
  code: "agent_connect_failed" /* AGENT_CONNECT_FAILED */,
475
757
  context
@@ -477,9 +759,13 @@ var CopilotKitCore = class {
477
759
  throw error;
478
760
  }
479
761
  }
480
- async runAgent({ agent, withMessages, agentId }) {
481
- if (agent instanceof import_client2.HttpAgent) {
482
- 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 };
483
769
  }
484
770
  if (withMessages) {
485
771
  agent.addMessages(withMessages);
@@ -487,22 +773,22 @@ var CopilotKitCore = class {
487
773
  try {
488
774
  const runAgentResult = await agent.runAgent(
489
775
  {
490
- forwardedProps: this.properties,
491
- tools: this.buildFrontendTools(agentId)
776
+ forwardedProps: this.core.properties,
777
+ tools: this.buildFrontendTools(agent.agentId)
492
778
  },
493
- this.createAgentErrorSubscriber(agent, agentId)
779
+ this.createAgentErrorSubscriber(agent)
494
780
  );
495
- return this.processAgentResult({ runAgentResult, agent, agentId });
781
+ return this.processAgentResult({ runAgentResult, agent });
496
782
  } catch (error) {
497
783
  const runError = error instanceof Error ? error : new Error(String(error));
498
784
  const context = {};
499
- if (agentId ?? agent.agentId) {
500
- context.agentId = agentId ?? agent.agentId;
785
+ if (agent.agentId) {
786
+ context.agentId = agent.agentId;
501
787
  }
502
788
  if (withMessages) {
503
789
  context.messageCount = withMessages.length;
504
790
  }
505
- await this.emitError({
791
+ await this.core.emitError({
506
792
  error: runError,
507
793
  code: "agent_run_failed" /* AGENT_RUN_FAILED */,
508
794
  context
@@ -510,13 +796,15 @@ var CopilotKitCore = class {
510
796
  throw error;
511
797
  }
512
798
  }
799
+ /**
800
+ * Process agent result and execute tools
801
+ */
513
802
  async processAgentResult({
514
803
  runAgentResult,
515
- agent,
516
- agentId
804
+ agent
517
805
  }) {
518
806
  const { newMessages } = runAgentResult;
519
- const effectiveAgentId = this.resolveAgentId(agent, agentId);
807
+ const agentId = agent.agentId;
520
808
  let needsFollowUp = false;
521
809
  for (const message of newMessages) {
522
810
  if (message.role === "assistant") {
@@ -524,205 +812,19 @@ var CopilotKitCore = class {
524
812
  if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
525
813
  const tool = this.getTool({
526
814
  toolName: toolCall.function.name,
527
- agentId
815
+ agentId: agent.agentId
528
816
  });
529
817
  if (tool) {
530
- if (tool?.agentId && tool.agentId !== agentId) {
531
- continue;
532
- }
533
- let toolCallResult = "";
534
- let errorMessage;
535
- let isArgumentError = false;
536
- if (tool?.handler) {
537
- let parsedArgs;
538
- try {
539
- parsedArgs = JSON.parse(toolCall.function.arguments);
540
- } catch (error) {
541
- const parseError = error instanceof Error ? error : new Error(String(error));
542
- errorMessage = parseError.message;
543
- isArgumentError = true;
544
- await this.emitError({
545
- error: parseError,
546
- code: "tool_argument_parse_failed" /* TOOL_ARGUMENT_PARSE_FAILED */,
547
- context: {
548
- agentId: effectiveAgentId,
549
- toolCallId: toolCall.id,
550
- toolName: toolCall.function.name,
551
- rawArguments: toolCall.function.arguments,
552
- toolType: "specific",
553
- messageId: message.id
554
- }
555
- });
556
- }
557
- await this.notifySubscribers(
558
- (subscriber) => subscriber.onToolExecutionStart?.({
559
- copilotkit: this,
560
- toolCallId: toolCall.id,
561
- agentId: effectiveAgentId,
562
- toolName: toolCall.function.name,
563
- args: parsedArgs
564
- }),
565
- "Subscriber onToolExecutionStart error:"
566
- );
567
- if (!errorMessage) {
568
- try {
569
- const result = await tool.handler(parsedArgs, toolCall);
570
- if (result === void 0 || result === null) {
571
- toolCallResult = "";
572
- } else if (typeof result === "string") {
573
- toolCallResult = result;
574
- } else {
575
- toolCallResult = JSON.stringify(result);
576
- }
577
- } catch (error) {
578
- const handlerError = error instanceof Error ? error : new Error(String(error));
579
- errorMessage = handlerError.message;
580
- await this.emitError({
581
- error: handlerError,
582
- code: "tool_handler_failed" /* TOOL_HANDLER_FAILED */,
583
- context: {
584
- agentId: effectiveAgentId,
585
- toolCallId: toolCall.id,
586
- toolName: toolCall.function.name,
587
- parsedArgs,
588
- toolType: "specific",
589
- messageId: message.id
590
- }
591
- });
592
- }
593
- }
594
- if (errorMessage) {
595
- toolCallResult = `Error: ${errorMessage}`;
596
- }
597
- await this.notifySubscribers(
598
- (subscriber) => subscriber.onToolExecutionEnd?.({
599
- copilotkit: this,
600
- toolCallId: toolCall.id,
601
- agentId: effectiveAgentId,
602
- toolName: toolCall.function.name,
603
- result: errorMessage ? "" : toolCallResult,
604
- error: errorMessage
605
- }),
606
- "Subscriber onToolExecutionEnd error:"
607
- );
608
- if (isArgumentError) {
609
- throw new Error(errorMessage ?? "Tool execution failed");
610
- }
611
- }
612
- if (!errorMessage || !isArgumentError) {
613
- const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
614
- const toolMessage = {
615
- id: (0, import_shared.randomUUID)(),
616
- role: "tool",
617
- toolCallId: toolCall.id,
618
- content: toolCallResult
619
- };
620
- agent.messages.splice(messageIndex + 1, 0, toolMessage);
621
- if (!errorMessage && tool?.followUp !== false) {
622
- needsFollowUp = true;
623
- }
818
+ const followUp = await this.executeSpecificTool(tool, toolCall, message, agent, agentId);
819
+ if (followUp) {
820
+ needsFollowUp = true;
624
821
  }
625
822
  } else {
626
- const wildcardTool = this.getTool({ toolName: "*", agentId });
823
+ const wildcardTool = this.getTool({ toolName: "*", agentId: agent.agentId });
627
824
  if (wildcardTool) {
628
- if (wildcardTool?.agentId && wildcardTool.agentId !== agentId) {
629
- continue;
630
- }
631
- let toolCallResult = "";
632
- let errorMessage;
633
- let isArgumentError = false;
634
- if (wildcardTool?.handler) {
635
- let parsedArgs;
636
- try {
637
- parsedArgs = JSON.parse(toolCall.function.arguments);
638
- } catch (error) {
639
- const parseError = error instanceof Error ? error : new Error(String(error));
640
- errorMessage = parseError.message;
641
- isArgumentError = true;
642
- await this.emitError({
643
- error: parseError,
644
- code: "tool_argument_parse_failed" /* TOOL_ARGUMENT_PARSE_FAILED */,
645
- context: {
646
- agentId: effectiveAgentId,
647
- toolCallId: toolCall.id,
648
- toolName: toolCall.function.name,
649
- rawArguments: toolCall.function.arguments,
650
- toolType: "wildcard",
651
- messageId: message.id
652
- }
653
- });
654
- }
655
- const wildcardArgs = {
656
- toolName: toolCall.function.name,
657
- args: parsedArgs
658
- };
659
- await this.notifySubscribers(
660
- (subscriber) => subscriber.onToolExecutionStart?.({
661
- copilotkit: this,
662
- toolCallId: toolCall.id,
663
- agentId: effectiveAgentId,
664
- toolName: toolCall.function.name,
665
- args: wildcardArgs
666
- }),
667
- "Subscriber onToolExecutionStart error:"
668
- );
669
- if (!errorMessage) {
670
- try {
671
- const result = await wildcardTool.handler(wildcardArgs, toolCall);
672
- if (result === void 0 || result === null) {
673
- toolCallResult = "";
674
- } else if (typeof result === "string") {
675
- toolCallResult = result;
676
- } else {
677
- toolCallResult = JSON.stringify(result);
678
- }
679
- } catch (error) {
680
- const handlerError = error instanceof Error ? error : new Error(String(error));
681
- errorMessage = handlerError.message;
682
- await this.emitError({
683
- error: handlerError,
684
- code: "tool_handler_failed" /* TOOL_HANDLER_FAILED */,
685
- context: {
686
- agentId: effectiveAgentId,
687
- toolCallId: toolCall.id,
688
- toolName: toolCall.function.name,
689
- parsedArgs: wildcardArgs,
690
- toolType: "wildcard",
691
- messageId: message.id
692
- }
693
- });
694
- }
695
- }
696
- if (errorMessage) {
697
- toolCallResult = `Error: ${errorMessage}`;
698
- }
699
- await this.notifySubscribers(
700
- (subscriber) => subscriber.onToolExecutionEnd?.({
701
- copilotkit: this,
702
- toolCallId: toolCall.id,
703
- agentId: effectiveAgentId,
704
- toolName: toolCall.function.name,
705
- result: errorMessage ? "" : toolCallResult,
706
- error: errorMessage
707
- }),
708
- "Subscriber onToolExecutionEnd error:"
709
- );
710
- if (isArgumentError) {
711
- throw new Error(errorMessage ?? "Tool execution failed");
712
- }
713
- }
714
- if (!errorMessage || !isArgumentError) {
715
- const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
716
- const toolMessage = {
717
- id: (0, import_shared.randomUUID)(),
718
- role: "tool",
719
- toolCallId: toolCall.id,
720
- content: toolCallResult
721
- };
722
- agent.messages.splice(messageIndex + 1, 0, toolMessage);
723
- if (!errorMessage && wildcardTool?.followUp !== false) {
724
- needsFollowUp = true;
725
- }
825
+ const followUp = await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId);
826
+ if (followUp) {
827
+ needsFollowUp = true;
726
828
  }
727
829
  }
728
830
  }
@@ -731,10 +833,220 @@ var CopilotKitCore = class {
731
833
  }
732
834
  }
733
835
  if (needsFollowUp) {
734
- return await this.runAgent({ agent, agentId });
836
+ return await this.runAgent({ agent });
735
837
  }
838
+ void this.core.suggestionEngine.reloadSuggestions(agentId);
736
839
  return runAgentResult;
737
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
+ */
738
1050
  buildFrontendTools(agentId) {
739
1051
  return this._tools.filter((tool) => !tool.agentId || tool.agentId === agentId).map((tool) => ({
740
1052
  name: tool.name,
@@ -742,13 +1054,16 @@ var CopilotKitCore = class {
742
1054
  parameters: createToolSchema(tool)
743
1055
  }));
744
1056
  }
745
- createAgentErrorSubscriber(agent, agentId) {
1057
+ /**
1058
+ * Create an agent error subscriber
1059
+ */
1060
+ createAgentErrorSubscriber(agent) {
746
1061
  const emitAgentError = async (error, code, extraContext = {}) => {
747
1062
  const context = { ...extraContext };
748
- if (agentId ?? agent.agentId) {
749
- context.agentId = agentId ?? agent.agentId;
1063
+ if (agent.agentId) {
1064
+ context.agentId = agent.agentId;
750
1065
  }
751
- await this.emitError({
1066
+ await this.core.emitError({
752
1067
  error,
753
1068
  code,
754
1069
  context
@@ -804,6 +1119,224 @@ function createToolSchema(tool) {
804
1119
  return schema;
805
1120
  }
806
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
+
807
1340
  // src/types.ts
808
1341
  var ToolCallStatus = /* @__PURE__ */ ((ToolCallStatus2) => {
809
1342
  ToolCallStatus2["InProgress"] = "inProgress";
@@ -1029,10 +1562,14 @@ ${indent}${fence}`;
1029
1562
  }
1030
1563
  // Annotate the CommonJS export names for ESM import in node:
1031
1564
  0 && (module.exports = {
1565
+ AgentRegistry,
1566
+ ContextStore,
1032
1567
  CopilotKitCore,
1033
1568
  CopilotKitCoreErrorCode,
1034
1569
  CopilotKitCoreRuntimeConnectionStatus,
1035
1570
  ProxiedCopilotRuntimeAgent,
1571
+ RunHandler,
1572
+ SuggestionEngine,
1036
1573
  ToolCallStatus,
1037
1574
  completePartialMarkdown
1038
1575
  });