@copilotkit/runtime 1.9.2-next.9 → 1.9.3-next.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +176 -0
  2. package/dist/{chunk-Z5GYTKMD.mjs → chunk-EK5RTZVJ.mjs} +225 -149
  3. package/dist/chunk-EK5RTZVJ.mjs.map +1 -0
  4. package/dist/{chunk-SMDVD4VG.mjs → chunk-KCYFFRJY.mjs} +2 -2
  5. package/dist/{chunk-4JBKY7XT.mjs → chunk-QLLV2QVK.mjs} +48 -28
  6. package/dist/chunk-QLLV2QVK.mjs.map +1 -0
  7. package/dist/{chunk-5YGKE5SN.mjs → chunk-R5D7D7YN.mjs} +2 -2
  8. package/dist/{chunk-UUXRYAB4.mjs → chunk-RCCT2GOF.mjs} +2 -2
  9. package/dist/{chunk-ALZ5H3VD.mjs → chunk-YGS5B7PN.mjs} +2 -2
  10. package/dist/{groq-adapter-172a2ca4.d.ts → groq-adapter-742818f2.d.ts} +5 -1
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +267 -171
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +9 -9
  15. package/dist/{langserve-fc5cac89.d.ts → langserve-3e8d0e06.d.ts} +6 -0
  16. package/dist/lib/index.d.ts +155 -5
  17. package/dist/lib/index.js +221 -168
  18. package/dist/lib/index.js.map +1 -1
  19. package/dist/lib/index.mjs +9 -9
  20. package/dist/lib/integrations/index.d.ts +3 -3
  21. package/dist/lib/integrations/index.js +11 -11
  22. package/dist/lib/integrations/index.js.map +1 -1
  23. package/dist/lib/integrations/index.mjs +8 -8
  24. package/dist/lib/integrations/nest/index.d.ts +2 -2
  25. package/dist/lib/integrations/nest/index.js +11 -11
  26. package/dist/lib/integrations/nest/index.js.map +1 -1
  27. package/dist/lib/integrations/nest/index.mjs +4 -4
  28. package/dist/lib/integrations/node-express/index.d.ts +2 -2
  29. package/dist/lib/integrations/node-express/index.js +11 -11
  30. package/dist/lib/integrations/node-express/index.js.map +1 -1
  31. package/dist/lib/integrations/node-express/index.mjs +4 -4
  32. package/dist/lib/integrations/node-http/index.d.ts +2 -2
  33. package/dist/lib/integrations/node-http/index.js +11 -11
  34. package/dist/lib/integrations/node-http/index.js.map +1 -1
  35. package/dist/lib/integrations/node-http/index.mjs +3 -3
  36. package/dist/service-adapters/index.d.ts +5 -4
  37. package/dist/service-adapters/index.js +47 -27
  38. package/dist/service-adapters/index.js.map +1 -1
  39. package/dist/service-adapters/index.mjs +1 -1
  40. package/dist/{shared-bd953ebf.d.ts → shared-96b46379.d.ts} +16 -18
  41. package/package.json +11 -11
  42. package/src/graphql/resolvers/copilot.resolver.ts +1 -2
  43. package/src/lib/runtime/__tests__/{copilot-runtime-trace.test.ts → copilot-runtime-error.test.ts} +27 -27
  44. package/src/lib/runtime/__tests__/mcp-tools-utils.test.ts +464 -0
  45. package/src/lib/runtime/agui-action.ts +9 -3
  46. package/src/lib/runtime/copilot-runtime.ts +112 -124
  47. package/src/lib/runtime/mcp-tools-utils.ts +84 -18
  48. package/src/lib/runtime/remote-actions.ts +6 -0
  49. package/src/service-adapters/anthropic/anthropic-adapter.ts +64 -4
  50. package/src/service-adapters/anthropic/utils.ts +3 -8
  51. package/src/service-adapters/events.ts +40 -1
  52. package/src/service-adapters/google/google-genai-adapter.ts +5 -0
  53. package/src/service-adapters/openai/openai-adapter.ts +0 -14
  54. package/tests/service-adapters/anthropic/anthropic-adapter.test.ts +172 -387
  55. package/dist/chunk-4JBKY7XT.mjs.map +0 -1
  56. package/dist/chunk-Z5GYTKMD.mjs.map +0 -1
  57. /package/dist/{chunk-SMDVD4VG.mjs.map → chunk-KCYFFRJY.mjs.map} +0 -0
  58. /package/dist/{chunk-5YGKE5SN.mjs.map → chunk-R5D7D7YN.mjs.map} +0 -0
  59. /package/dist/{chunk-UUXRYAB4.mjs.map → chunk-RCCT2GOF.mjs.map} +0 -0
  60. /package/dist/{chunk-ALZ5H3VD.mjs.map → chunk-YGS5B7PN.mjs.map} +0 -0
@@ -20,13 +20,12 @@ import {
20
20
  CopilotKitApiDiscoveryError,
21
21
  randomId,
22
22
  CopilotKitError,
23
- CopilotKitRemoteEndpointDiscoveryError,
24
23
  CopilotKitAgentDiscoveryError,
25
24
  CopilotKitMisuseError,
26
25
  CopilotKitErrorCode,
27
26
  CopilotKitLowLevelError,
28
- CopilotTraceHandler,
29
- CopilotTraceEvent,
27
+ CopilotErrorHandler,
28
+ CopilotErrorEvent,
30
29
  CopilotRequestContext,
31
30
  ensureStructuredError,
32
31
  } from "@copilotkit/shared";
@@ -66,7 +65,7 @@ import { ExtensionsInput } from "../../graphql/inputs/extensions.input";
66
65
  import { ExtensionsResponse } from "../../graphql/types/extensions-response.type";
67
66
  import { LoadAgentStateResponse } from "../../graphql/types/load-agent-state-response.type";
68
67
  import { Client as LangGraphClient } from "@langchain/langgraph-sdk";
69
- import { langchainMessagesToCopilotKit, isUserConfigurationError } from "./remote-lg-action";
68
+ import { langchainMessagesToCopilotKit } from "./remote-lg-action";
70
69
  import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
71
70
  import {
72
71
  CopilotObservabilityConfig,
@@ -283,23 +282,23 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
283
282
  createMCPClient?: CreateMCPClientFunction;
284
283
 
285
284
  /**
286
- * Optional trace handler for comprehensive debugging and observability.
285
+ * Optional error handler for comprehensive debugging and observability.
287
286
  *
288
- * **Requires publicApiKey**: Tracing only works when requests include a valid publicApiKey.
287
+ * **Requires publicApiKey**: Error handling only works when requests include a valid publicApiKey.
289
288
  * This is a premium CopilotKit Cloud feature.
290
289
  *
291
- * @param traceEvent - Structured trace event with rich debugging context
290
+ * @param errorEvent - Structured error event with rich debugging context
292
291
  *
293
292
  * @example
294
293
  * ```typescript
295
294
  * const runtime = new CopilotRuntime({
296
- * onTrace: (traceEvent) => {
297
- * debugDashboard.capture(traceEvent);
295
+ * onError: (errorEvent) => {
296
+ * debugDashboard.capture(errorEvent);
298
297
  * }
299
298
  * });
300
299
  * ```
301
300
  */
302
- onTrace?: CopilotTraceHandler;
301
+ onError?: CopilotErrorHandler;
303
302
  }
304
303
 
305
304
  export class CopilotRuntime<const T extends Parameter[] | [] = []> {
@@ -312,8 +311,8 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
312
311
  private delegateAgentProcessingToServiceAdapter: boolean;
313
312
  private observability?: CopilotObservabilityConfig;
314
313
  private availableAgents: Pick<AgentWithEndpoint, "name" | "id">[];
315
- private onTrace?: CopilotTraceHandler;
316
- private hasWarnedAboutTracing = false;
314
+ private onError?: CopilotErrorHandler;
315
+ private hasWarnedAboutError = false;
317
316
 
318
317
  // +++ MCP Properties +++
319
318
  private readonly mcpServersConfig?: MCPEndpointConfig[];
@@ -362,7 +361,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
362
361
  params?.delegateAgentProcessingToServiceAdapter || false;
363
362
  this.observability = params?.observability_c;
364
363
  this.agents = params?.agents ?? {};
365
- this.onTrace = params?.onTrace;
364
+ this.onError = params?.onError;
366
365
  // +++ MCP Initialization +++
367
366
  this.mcpServersConfig = params?.mcpServers;
368
367
  this.createMCPClientImpl = params?.createMCPClient;
@@ -440,9 +439,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
440
439
  }
441
440
 
442
441
  const instructions =
443
- "You have access to the following tools provided by external Model Context Protocol (MCP) servers:\n" +
444
- mcpToolInstructions +
445
- "\nUse them when appropriate to fulfill the user's request.";
442
+ mcpToolInstructions + "\nUse them when appropriate to fulfill the user's request.";
446
443
 
447
444
  const systemMessageIndex = messages.findIndex((msg) => msg.textMessage?.role === "system");
448
445
 
@@ -489,16 +486,11 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
489
486
  publicApiKey,
490
487
  } = request;
491
488
 
492
- const eventSource = new RuntimeEventSource();
493
- // Track request start time for logging
494
- const requestStartTime = Date.now();
495
- // For storing streamed chunks if progressive logging is enabled
496
- const streamedChunks: any[] = [];
497
-
498
- // Trace request start
499
- await this.trace(
500
- "request",
501
- {
489
+ const eventSource = new RuntimeEventSource({
490
+ errorHandler: async (error, context) => {
491
+ await this.error("error", context, error, publicApiKey);
492
+ },
493
+ errorContext: {
502
494
  threadId,
503
495
  runId,
504
496
  source: "runtime",
@@ -506,20 +498,18 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
506
498
  operation: "processRuntimeRequest",
507
499
  method: "POST",
508
500
  url: url,
509
- startTime: requestStartTime,
501
+ startTime: Date.now(),
510
502
  },
511
503
  agent: agentSession ? { name: agentSession.agentName } : undefined,
512
- messages: {
513
- input: rawMessages,
514
- messageCount: rawMessages.length,
515
- },
516
504
  technical: {
517
505
  environment: process.env.NODE_ENV,
518
506
  },
519
507
  },
520
- undefined,
521
- publicApiKey,
522
- );
508
+ });
509
+ // Track request start time for logging
510
+ const requestStartTime = Date.now();
511
+ // For storing streamed chunks if progressive logging is enabled
512
+ const streamedChunks: any[] = [];
523
513
 
524
514
  try {
525
515
  if (
@@ -755,8 +745,8 @@ please use an LLM adapter instead.`,
755
745
  );
756
746
  }
757
747
 
758
- // Trace the error
759
- await this.trace(
748
+ // Track the error
749
+ await this.error(
760
750
  "error",
761
751
  {
762
752
  threadId,
@@ -787,10 +777,8 @@ please use an LLM adapter instead.`,
787
777
  }
788
778
 
789
779
  async getAllAgents(graphqlContext: GraphQLContext): Promise<(AgentWithEndpoint | Agent)[]> {
790
- const [agentsWithEndpoints, aguiAgents] = await Promise.all([
791
- this.discoverAgentsFromEndpoints(graphqlContext),
792
- this.discoverAgentsFromAgui(),
793
- ]);
780
+ const agentsWithEndpoints = await this.discoverAgentsFromEndpoints(graphqlContext);
781
+ const aguiAgents = this.discoverAgentsFromAgui();
794
782
 
795
783
  this.availableAgents = [...agentsWithEndpoints, ...aguiAgents].map((a) => ({
796
784
  name: a.name,
@@ -885,39 +873,12 @@ please use an LLM adapter instead.`,
885
873
  return agents;
886
874
  }
887
875
 
888
- async discoverAgentsFromAgui(): Promise<AgentWithEndpoint[]> {
889
- const agents: Promise<AgentWithEndpoint[]> = Object.values(this.agents ?? []).reduce(
890
- async (acc: Promise<Agent[]>, agent: LangGraphAgent) => {
891
- const agents = await acc;
892
-
893
- const client = agent.client;
894
- let data: Array<{ assistant_id: string; graph_id: string }> | { detail: string } = [];
895
- try {
896
- data = await client.assistants.search();
897
-
898
- if (data && "detail" in data && (data.detail as string).toLowerCase() === "not found") {
899
- throw new CopilotKitAgentDiscoveryError({ availableAgents: this.availableAgents });
900
- }
901
- } catch (e) {
902
- throw new CopilotKitMisuseError({
903
- message: `
904
- Failed to find or contact agent ${agent.graphId}.
905
- Make sure the LangGraph API is running and the agent is defined in langgraph.json
906
-
907
- See more: https://docs.copilotkit.ai/troubleshooting/common-issues`,
908
- });
909
- }
910
- const endpointAgents = data.map((entry) => ({
911
- name: entry.graph_id,
912
- id: entry.assistant_id,
913
- description: "",
914
- }));
915
- return [...agents, ...endpointAgents];
916
- },
917
- Promise.resolve([]),
918
- );
919
-
920
- return agents;
876
+ discoverAgentsFromAgui(): Agent[] {
877
+ return Object.entries(this.agents ?? []).map(([key, agent]: [string, AbstractAgent]) => ({
878
+ name: (agent as any).agentName ?? key,
879
+ id: agent.agentId ?? key,
880
+ description: agent.description ?? "",
881
+ }));
921
882
  }
922
883
 
923
884
  async loadAgentState(
@@ -992,37 +953,43 @@ please use an LLM adapter instead.`,
992
953
  ? { authorization: `Bearer ${graphqlContext.properties.authorization}` }
993
954
  : null;
994
955
 
995
- let client: LangGraphClient;
996
- if ("endpoint" in agent && agent.endpoint.type === EndpointType.LangGraphPlatform) {
997
- client = new LangGraphClient({
998
- apiUrl: agent.endpoint.deploymentUrl,
999
- apiKey: agent.endpoint.langsmithApiKey,
1000
- defaultHeaders: { ...propertyHeaders },
1001
- });
1002
- } else {
1003
- const aguiAgent = graphqlContext._copilotkit.runtime.agents[agent.name] as LangGraphAgent;
1004
- if (!aguiAgent) {
1005
- throw new Error(`Agent: ${agent.name} could not be resolved`);
1006
- }
1007
- // @ts-expect-error -- both clients are the same
1008
- client = aguiAgent.client;
1009
- }
1010
956
  let state: any = {};
1011
957
  try {
1012
- state = (await client.threads.getState(threadId)).values as any;
958
+ let client: LangGraphClient | null;
959
+ if ("endpoint" in agent && agent.endpoint.type === EndpointType.LangGraphPlatform) {
960
+ client = new LangGraphClient({
961
+ apiUrl: agent.endpoint.deploymentUrl,
962
+ apiKey: agent.endpoint.langsmithApiKey,
963
+ defaultHeaders: { ...propertyHeaders },
964
+ });
965
+ } else {
966
+ const aguiAgent = graphqlContext._copilotkit.runtime.agents[agent.name] as LangGraphAgent;
967
+ if (!aguiAgent) {
968
+ throw new Error(`Agent: ${agent.name} could not be resolved`);
969
+ }
970
+ // @ts-expect-error -- both clients are the same
971
+ client = aguiAgent.client ?? null;
972
+ }
973
+
974
+ state = client ? ((await client.threads.getState(threadId)).values as any) : {};
1013
975
  } catch (error) {
1014
976
  // All errors from agent state loading are user configuration issues
1015
977
  const errorMessage = error instanceof Error ? error.message : String(error);
978
+ const errorStatus = error?.response?.status || error?.status;
1016
979
 
1017
- // Log user configuration errors at debug level to reduce noise
1018
- console.debug(`Agent '${agentName}' configuration issue: ${errorMessage}`);
1019
-
1020
- // Throw a configuration error - all agent state loading failures are user setup issues
1021
- throw new ResolvedCopilotKitError({
1022
- status: 400,
1023
- message: `Agent '${agentName}' failed to execute: ${errorMessage}`,
1024
- code: CopilotKitErrorCode.CONFIGURATION_ERROR,
1025
- });
980
+ if (errorStatus === 404) {
981
+ state = {};
982
+ } else {
983
+ // Log user configuration errors at debug level to reduce noise
984
+ console.debug(`Agent '${agentName}' configuration issue: ${errorMessage}`);
985
+
986
+ // Throw a configuration error - all agent state loading failures are user setup issues
987
+ throw new ResolvedCopilotKitError({
988
+ status: 400,
989
+ message: `Agent '${agentName}' failed to execute: ${errorMessage}`,
990
+ code: CopilotKitErrorCode.CONFIGURATION_ERROR,
991
+ });
992
+ }
1026
993
  }
1027
994
 
1028
995
  if (Object.keys(state).length === 0) {
@@ -1069,8 +1036,8 @@ please use an LLM adapter instead.`,
1069
1036
  // for backwards compatibility, deal with the case when no threadId is provided
1070
1037
  const threadId = threadIdFromRequest ?? agentSession.threadId;
1071
1038
 
1072
- // Trace agent request start
1073
- await this.trace(
1039
+ // Track agent request start
1040
+ await this.error(
1074
1041
  "agent_state",
1075
1042
  {
1076
1043
  threadId,
@@ -1160,7 +1127,27 @@ please use an LLM adapter instead.`,
1160
1127
  });
1161
1128
 
1162
1129
  try {
1163
- const eventSource = new RuntimeEventSource();
1130
+ const eventSource = new RuntimeEventSource({
1131
+ errorHandler: async (error, context) => {
1132
+ await this.error("error", context, error, publicApiKey);
1133
+ },
1134
+ errorContext: {
1135
+ threadId,
1136
+ source: "agent",
1137
+ request: {
1138
+ operation: "processAgentRequest",
1139
+ method: "POST",
1140
+ startTime: requestStartTime,
1141
+ },
1142
+ agent: {
1143
+ name: agentName,
1144
+ nodeName: nodeName,
1145
+ },
1146
+ technical: {
1147
+ environment: process.env.NODE_ENV,
1148
+ },
1149
+ },
1150
+ });
1164
1151
  const stream = await currentAgent.remoteAgentHandler({
1165
1152
  name: agentName,
1166
1153
  threadId,
@@ -1250,8 +1237,8 @@ please use an LLM adapter instead.`,
1250
1237
  this.convertStreamingErrorToStructured(error),
1251
1238
  );
1252
1239
 
1253
- // Trace streaming errors
1254
- await this.trace(
1240
+ // Track streaming errors
1241
+ await this.error(
1255
1242
  "error",
1256
1243
  {
1257
1244
  threadId,
@@ -1360,8 +1347,8 @@ please use an LLM adapter instead.`,
1360
1347
  this.convertStreamingErrorToStructured(err),
1361
1348
  );
1362
1349
 
1363
- // Trace the agent error
1364
- await this.trace(
1350
+ // Track the agent error
1351
+ await this.error(
1365
1352
  "error",
1366
1353
  {
1367
1354
  threadId,
@@ -1420,6 +1407,7 @@ please use an LLM adapter instead.`,
1420
1407
  frontendUrl: url,
1421
1408
  agents: this.agents,
1422
1409
  metaEvents: request.metaEvents,
1410
+ nodeName: request.agentSession?.nodeName,
1423
1411
  });
1424
1412
 
1425
1413
  const configuredActions =
@@ -1533,45 +1521,45 @@ please use an LLM adapter instead.`,
1533
1521
  });
1534
1522
  }
1535
1523
 
1536
- private async trace(
1537
- type: CopilotTraceEvent["type"],
1524
+ private async error(
1525
+ type: CopilotErrorEvent["type"],
1538
1526
  context: CopilotRequestContext,
1539
1527
  error?: any,
1540
1528
  publicApiKey?: string,
1541
1529
  ): Promise<void> {
1542
- if (!this.onTrace) return;
1530
+ if (!this.onError) return;
1543
1531
 
1544
1532
  // Just check if publicApiKey is defined (regardless of validity)
1545
1533
  if (!publicApiKey) {
1546
- if (!this.hasWarnedAboutTracing) {
1534
+ if (!this.hasWarnedAboutError) {
1547
1535
  console.warn(
1548
- "CopilotKit: onTrace handler provided but requires publicApiKey to be defined for tracing to work.",
1536
+ "CopilotKit: onError handler provided but requires publicApiKey to be defined for error handling to work.",
1549
1537
  );
1550
- this.hasWarnedAboutTracing = true;
1538
+ this.hasWarnedAboutError = true;
1551
1539
  }
1552
1540
  return;
1553
1541
  }
1554
1542
 
1555
1543
  try {
1556
- const traceEvent: CopilotTraceEvent = {
1544
+ const errorEvent: CopilotErrorEvent = {
1557
1545
  type,
1558
1546
  timestamp: Date.now(),
1559
1547
  context,
1560
1548
  ...(error && { error }),
1561
1549
  };
1562
1550
 
1563
- await this.onTrace(traceEvent);
1564
- } catch (traceError) {
1565
- // Don't let trace errors break the main flow
1566
- console.error("Error in onTrace handler:", traceError);
1551
+ await this.onError(errorEvent);
1552
+ } catch (errorHandlerError) {
1553
+ // Don't let error handler errors break the main flow
1554
+ console.error("Error in onError handler:", errorHandlerError);
1567
1555
  }
1568
1556
  }
1569
1557
 
1570
1558
  /**
1571
- * Public method to trace GraphQL validation errors
1572
- * This allows the GraphQL resolver to send validation errors through the trace system
1559
+ * Public method to handle GraphQL validation errors
1560
+ * This allows the GraphQL resolver to send validation errors through the error system
1573
1561
  */
1574
- public async traceGraphQLError(
1562
+ public async errorGraphQLError(
1575
1563
  error: { message: string; code: string; type: string },
1576
1564
  context: {
1577
1565
  operation: string;
@@ -1579,10 +1567,10 @@ please use an LLM adapter instead.`,
1579
1567
  guardrailsEnabled: boolean;
1580
1568
  },
1581
1569
  ): Promise<void> {
1582
- if (!this.onTrace) return;
1570
+ if (!this.onError) return;
1583
1571
 
1584
1572
  try {
1585
- await this.onTrace({
1573
+ await this.onError({
1586
1574
  type: "error",
1587
1575
  timestamp: Date.now(),
1588
1576
  context: {
@@ -1602,9 +1590,9 @@ please use an LLM adapter instead.`,
1602
1590
  },
1603
1591
  error,
1604
1592
  });
1605
- } catch (traceError) {
1606
- // Don't let trace errors break the main flow
1607
- console.error("Error in onTrace handler:", traceError);
1593
+ } catch (errorHandlerError) {
1594
+ // Don't let error handler errors break the main flow
1595
+ console.error("Error in onError handler:", errorHandlerError);
1608
1596
  }
1609
1597
  }
1610
1598
  }
@@ -14,7 +14,7 @@ export interface MCPTool {
14
14
  };
15
15
  };
16
16
  /** The function to call to execute the tool on the MCP server. */
17
- execute(options: { params: any }): Promise<any>;
17
+ execute(params: any): Promise<any>;
18
18
  }
19
19
 
20
20
  /**
@@ -51,7 +51,7 @@ export function extractParametersFromSchema(
51
51
  ? (toolOrSchema as MCPTool).schema
52
52
  : (toolOrSchema as MCPTool["schema"]);
53
53
 
54
- const toolParameters = schema?.parameters || schema?.parameters?.jsonSchema;
54
+ const toolParameters = schema?.parameters?.jsonSchema || schema?.parameters;
55
55
  const properties = toolParameters?.properties;
56
56
  const requiredParams = new Set(toolParameters?.required || []);
57
57
 
@@ -62,15 +62,45 @@ export function extractParametersFromSchema(
62
62
  for (const paramName in properties) {
63
63
  if (Object.prototype.hasOwnProperty.call(properties, paramName)) {
64
64
  const paramDef = properties[paramName];
65
+
66
+ // Enhanced type extraction with support for complex types
67
+ let type = paramDef.type || "string";
68
+ let description = paramDef.description || "";
69
+
70
+ // Handle arrays with items
71
+ if (type === "array" && paramDef.items) {
72
+ const itemType = paramDef.items.type || "object";
73
+ if (itemType === "object" && paramDef.items.properties) {
74
+ // For arrays of objects, describe the structure
75
+ const itemProperties = Object.keys(paramDef.items.properties).join(", ");
76
+ description =
77
+ description +
78
+ (description ? " " : "") +
79
+ `Array of objects with properties: ${itemProperties}`;
80
+ } else {
81
+ // For arrays of primitives
82
+ type = `array<${itemType}>`;
83
+ }
84
+ }
85
+
86
+ // Handle enums
87
+ if (paramDef.enum && Array.isArray(paramDef.enum)) {
88
+ const enumValues = paramDef.enum.join(" | ");
89
+ description = description + (description ? " " : "") + `Allowed values: ${enumValues}`;
90
+ }
91
+
92
+ // Handle objects with properties
93
+ if (type === "object" && paramDef.properties) {
94
+ const objectProperties = Object.keys(paramDef.properties).join(", ");
95
+ description =
96
+ description + (description ? " " : "") + `Object with properties: ${objectProperties}`;
97
+ }
98
+
65
99
  parameters.push({
66
100
  name: paramName,
67
- // Infer type, default to string. MCP schemas might have more complex types.
68
- // This might need refinement based on common MCP schema practices.
69
- type: paramDef.type || "string",
70
- description: paramDef.description,
101
+ type: type,
102
+ description: description,
71
103
  required: requiredParams.has(paramName),
72
- // Attributes might not directly map, handle if necessary
73
- // attributes: paramDef.attributes || undefined,
74
104
  });
75
105
  }
76
106
  }
@@ -95,7 +125,7 @@ export function convertMCPToolsToActions(
95
125
 
96
126
  const handler = async (params: any): Promise<any> => {
97
127
  try {
98
- const result = await tool.execute({ params });
128
+ const result = await tool.execute(params);
99
129
  // Ensure the result is a string or stringify it, as required by many LLMs.
100
130
  // This might need adjustment depending on how different LLMs handle tool results.
101
131
  return typeof result === "string" ? result : JSON.stringify(result);
@@ -148,16 +178,49 @@ export function generateMcpToolInstructions(toolsMap: Record<string, MCPTool>):
148
178
  if (tool.schema && typeof tool.schema === "object") {
149
179
  const schema = tool.schema as any;
150
180
 
151
- // Extract parameters from JSON Schema
152
- if (schema.properties) {
153
- const requiredParams = schema.required || [];
181
+ // Extract parameters from JSON Schema - check both schema.parameters.properties and schema.properties
182
+ const toolParameters = schema.parameters?.jsonSchema || schema.parameters;
183
+ const properties = toolParameters?.properties || schema.properties;
184
+ const requiredParams = toolParameters?.required || schema.required || [];
154
185
 
155
- // Build parameter documentation from properties
156
- const paramsList = Object.entries(schema.properties).map(([paramName, propSchema]) => {
186
+ if (properties) {
187
+ // Build parameter documentation from properties with enhanced type information
188
+ const paramsList = Object.entries(properties).map(([paramName, propSchema]) => {
157
189
  const propDetails = propSchema as any;
158
190
  const requiredMark = requiredParams.includes(paramName) ? "*" : "";
159
- const typeInfo = propDetails.type || "any";
160
- const description = propDetails.description ? ` - ${propDetails.description}` : "";
191
+ let typeInfo = propDetails.type || "any";
192
+ let description = propDetails.description ? ` - ${propDetails.description}` : "";
193
+
194
+ // Enhanced type display for complex schemas
195
+ if (typeInfo === "array" && propDetails.items) {
196
+ const itemType = propDetails.items.type || "object";
197
+ if (itemType === "object" && propDetails.items.properties) {
198
+ const itemProps = Object.keys(propDetails.items.properties).join(", ");
199
+ typeInfo = `array<object>`;
200
+ description =
201
+ description +
202
+ (description ? " " : " - ") +
203
+ `Array of objects with properties: ${itemProps}`;
204
+ } else {
205
+ typeInfo = `array<${itemType}>`;
206
+ }
207
+ }
208
+
209
+ // Handle enums
210
+ if (propDetails.enum && Array.isArray(propDetails.enum)) {
211
+ const enumValues = propDetails.enum.join(" | ");
212
+ description =
213
+ description + (description ? " " : " - ") + `Allowed values: ${enumValues}`;
214
+ }
215
+
216
+ // Handle objects
217
+ if (typeInfo === "object" && propDetails.properties) {
218
+ const objectProps = Object.keys(propDetails.properties).join(", ");
219
+ description =
220
+ description +
221
+ (description ? " " : " - ") +
222
+ `Object with properties: ${objectProps}`;
223
+ }
161
224
 
162
225
  return ` - ${paramName}${requiredMark} (${typeInfo})${description}`;
163
226
  });
@@ -183,6 +246,9 @@ ${toolsDoc}
183
246
  When using these tools:
184
247
  1. Only provide valid parameters according to their type requirements
185
248
  2. Required parameters are marked with *
186
- 3. Format API calls correctly with the expected parameter structure
187
- 4. Always check tool responses to determine your next action`;
249
+ 3. For array parameters, provide data in the correct array format
250
+ 4. For object parameters, include all required nested properties
251
+ 5. For enum parameters, use only the allowed values listed
252
+ 6. Format API calls correctly with the expected parameter structure
253
+ 7. Always check tool responses to determine your next action`;
188
254
  }
@@ -131,6 +131,7 @@ export async function setupRemoteActions({
131
131
  frontendUrl,
132
132
  agents,
133
133
  metaEvents,
134
+ nodeName,
134
135
  }: {
135
136
  remoteEndpointDefinitions: EndpointDefinition[];
136
137
  graphqlContext: GraphQLContext;
@@ -139,10 +140,13 @@ export async function setupRemoteActions({
139
140
  frontendUrl?: string;
140
141
  agents: Record<string, AbstractAgent>;
141
142
  metaEvents?: MetaEventInput[];
143
+ nodeName?: string;
142
144
  }): Promise<Action[]> {
143
145
  const logger = graphqlContext.logger.child({ component: "remote-actions.fetchRemoteActions" });
144
146
  logger.debug({ remoteEndpointDefinitions }, "Fetching from remote endpoints");
145
147
 
148
+ const threadMetadata = (graphqlContext.properties?.threadMetadata as Record<string, any>) || {};
149
+
146
150
  // Remove duplicates of remoteEndpointDefinitions.url
147
151
  const filtered = remoteEndpointDefinitions.filter((value, index, self) => {
148
152
  if (value.type === EndpointType.LangGraphPlatform) {
@@ -204,6 +208,8 @@ export async function setupRemoteActions({
204
208
  agentStates,
205
209
  agent: agent,
206
210
  metaEvents,
211
+ threadMetadata,
212
+ nodeName,
207
213
  }),
208
214
  );
209
215
  }