@copilotkit/runtime 1.9.2-next.0 → 1.9.2-next.10
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/CHANGELOG.md +74 -0
- package/dist/{chunk-O6KXX5R5.mjs → chunk-5OK4GLKL.mjs} +19 -2
- package/dist/chunk-5OK4GLKL.mjs.map +1 -0
- package/dist/{chunk-44FYLJJJ.mjs → chunk-6RUTA76W.mjs} +2 -2
- package/dist/chunk-AMUJQ6IR.mjs +50 -0
- package/dist/chunk-AMUJQ6IR.mjs.map +1 -0
- package/dist/{chunk-IIXJVVTV.mjs → chunk-GS7DO47Q.mjs} +155 -78
- package/dist/chunk-GS7DO47Q.mjs.map +1 -0
- package/dist/{chunk-YMIOUUPV.mjs → chunk-PMIAGZGS.mjs} +2374 -1855
- package/dist/chunk-PMIAGZGS.mjs.map +1 -0
- package/dist/{chunk-ESXPDYNT.mjs → chunk-TOBFVWZU.mjs} +2 -2
- package/dist/{chunk-YXL4PSJM.mjs → chunk-VBXBFZEL.mjs} +2 -2
- package/dist/{chunk-5BIEM2UU.mjs → chunk-XWBDEXDA.mjs} +4 -3
- package/dist/{chunk-5BIEM2UU.mjs.map → chunk-XWBDEXDA.mjs.map} +1 -1
- package/dist/{groq-adapter-25a2bd35.d.ts → groq-adapter-172a2ca4.d.ts} +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3765 -3108
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +12 -8
- package/dist/index.mjs.map +1 -1
- package/dist/lib/index.d.ts +7 -133
- package/dist/lib/index.js +3357 -2743
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +9 -8
- package/dist/lib/integrations/index.d.ts +3 -3
- package/dist/lib/integrations/index.js +162 -98
- package/dist/lib/integrations/index.js.map +1 -1
- package/dist/lib/integrations/index.mjs +7 -6
- package/dist/lib/integrations/nest/index.d.ts +2 -2
- package/dist/lib/integrations/nest/index.js +162 -98
- package/dist/lib/integrations/nest/index.js.map +1 -1
- package/dist/lib/integrations/nest/index.mjs +5 -4
- package/dist/lib/integrations/node-express/index.d.ts +2 -2
- package/dist/lib/integrations/node-express/index.js +162 -98
- package/dist/lib/integrations/node-express/index.js.map +1 -1
- package/dist/lib/integrations/node-express/index.mjs +5 -4
- package/dist/lib/integrations/node-http/index.d.ts +2 -2
- package/dist/lib/integrations/node-http/index.js +162 -98
- package/dist/lib/integrations/node-http/index.js.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +4 -3
- package/dist/service-adapters/index.d.ts +6 -4
- package/dist/service-adapters/index.js +225 -107
- package/dist/service-adapters/index.js.map +1 -1
- package/dist/service-adapters/index.mjs +6 -2
- package/dist/service-adapters/shared/index.d.ts +9 -0
- package/dist/service-adapters/shared/index.js +72 -0
- package/dist/service-adapters/shared/index.js.map +1 -0
- package/dist/service-adapters/shared/index.mjs +8 -0
- package/dist/service-adapters/shared/index.mjs.map +1 -0
- package/dist/{shared-e272b15a.d.ts → shared-bd953ebf.d.ts} +45 -5
- package/dist/utils/index.d.ts +17 -1
- package/dist/utils/index.js +3 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +1 -1
- package/package.json +4 -4
- package/src/agents/langgraph/event-source.ts +36 -38
- package/src/agents/langgraph/events.ts +19 -1
- package/src/graphql/resolvers/copilot.resolver.ts +108 -45
- package/src/graphql/resolvers/state.resolver.ts +3 -3
- package/src/lib/error-messages.ts +200 -0
- package/src/lib/integrations/shared.ts +43 -0
- package/src/lib/runtime/__tests__/copilot-runtime-trace.test.ts +169 -0
- package/src/lib/runtime/copilot-runtime.ts +420 -83
- package/src/lib/runtime/langgraph/langgraph-agent.ts +12 -0
- package/src/lib/runtime/remote-action-constructors.ts +28 -3
- package/src/lib/runtime/remote-lg-action.ts +130 -40
- package/src/lib/streaming.ts +125 -36
- package/src/service-adapters/anthropic/anthropic-adapter.ts +67 -8
- package/src/service-adapters/anthropic/utils.ts +3 -8
- package/src/service-adapters/events.ts +37 -81
- package/src/service-adapters/groq/groq-adapter.ts +66 -56
- package/src/service-adapters/index.ts +1 -0
- package/src/service-adapters/openai/openai-adapter.ts +18 -3
- package/src/service-adapters/shared/error-utils.ts +61 -0
- package/src/service-adapters/shared/index.ts +1 -0
- package/src/utils/failed-response-status-reasons.ts +23 -1
- package/tests/service-adapters/anthropic/anthropic-adapter.test.ts +172 -387
- package/dist/chunk-IIXJVVTV.mjs.map +0 -1
- package/dist/chunk-O6KXX5R5.mjs.map +0 -1
- package/dist/chunk-YMIOUUPV.mjs.map +0 -1
- package/dist/{chunk-44FYLJJJ.mjs.map → chunk-6RUTA76W.mjs.map} +0 -0
- package/dist/{chunk-ESXPDYNT.mjs.map → chunk-TOBFVWZU.mjs.map} +0 -0
- package/dist/{chunk-YXL4PSJM.mjs.map → chunk-VBXBFZEL.mjs.map} +0 -0
- package/dist/{langserve-4a5c9217.d.ts → langserve-fc5cac89.d.ts} +7 -7
|
@@ -25,6 +25,10 @@ import {
|
|
|
25
25
|
CopilotKitMisuseError,
|
|
26
26
|
CopilotKitErrorCode,
|
|
27
27
|
CopilotKitLowLevelError,
|
|
28
|
+
CopilotTraceHandler,
|
|
29
|
+
CopilotTraceEvent,
|
|
30
|
+
CopilotRequestContext,
|
|
31
|
+
ensureStructuredError,
|
|
28
32
|
} from "@copilotkit/shared";
|
|
29
33
|
import {
|
|
30
34
|
CopilotServiceAdapter,
|
|
@@ -62,7 +66,7 @@ import { ExtensionsInput } from "../../graphql/inputs/extensions.input";
|
|
|
62
66
|
import { ExtensionsResponse } from "../../graphql/types/extensions-response.type";
|
|
63
67
|
import { LoadAgentStateResponse } from "../../graphql/types/load-agent-state-response.type";
|
|
64
68
|
import { Client as LangGraphClient } from "@langchain/langgraph-sdk";
|
|
65
|
-
import { langchainMessagesToCopilotKit } from "./remote-lg-action";
|
|
69
|
+
import { langchainMessagesToCopilotKit, isUserConfigurationError } from "./remote-lg-action";
|
|
66
70
|
import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
|
|
67
71
|
import {
|
|
68
72
|
CopilotObservabilityConfig,
|
|
@@ -81,10 +85,13 @@ import {
|
|
|
81
85
|
convertMCPToolsToActions,
|
|
82
86
|
generateMcpToolInstructions,
|
|
83
87
|
} from "./mcp-tools-utils";
|
|
88
|
+
import { LangGraphAgent } from "./langgraph/langgraph-agent";
|
|
84
89
|
// Define the function type alias here or import if defined elsewhere
|
|
85
90
|
type CreateMCPClientFunction = (config: MCPEndpointConfig) => Promise<MCPClient>;
|
|
86
91
|
// --- MCP Imports ---
|
|
87
92
|
|
|
93
|
+
import { generateHelpfulErrorMessage } from "../streaming";
|
|
94
|
+
|
|
88
95
|
export interface CopilotRuntimeRequest {
|
|
89
96
|
serviceAdapter: CopilotServiceAdapter;
|
|
90
97
|
messages: MessageInput[];
|
|
@@ -274,6 +281,25 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
|
|
|
274
281
|
* ```
|
|
275
282
|
*/
|
|
276
283
|
createMCPClient?: CreateMCPClientFunction;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Optional trace handler for comprehensive debugging and observability.
|
|
287
|
+
*
|
|
288
|
+
* **Requires publicApiKey**: Tracing only works when requests include a valid publicApiKey.
|
|
289
|
+
* This is a premium CopilotKit Cloud feature.
|
|
290
|
+
*
|
|
291
|
+
* @param traceEvent - Structured trace event with rich debugging context
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```typescript
|
|
295
|
+
* const runtime = new CopilotRuntime({
|
|
296
|
+
* onTrace: (traceEvent) => {
|
|
297
|
+
* debugDashboard.capture(traceEvent);
|
|
298
|
+
* }
|
|
299
|
+
* });
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
onTrace?: CopilotTraceHandler;
|
|
277
303
|
}
|
|
278
304
|
|
|
279
305
|
export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
@@ -286,6 +312,8 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
286
312
|
private delegateAgentProcessingToServiceAdapter: boolean;
|
|
287
313
|
private observability?: CopilotObservabilityConfig;
|
|
288
314
|
private availableAgents: Pick<AgentWithEndpoint, "name" | "id">[];
|
|
315
|
+
private onTrace?: CopilotTraceHandler;
|
|
316
|
+
private hasWarnedAboutTracing = false;
|
|
289
317
|
|
|
290
318
|
// +++ MCP Properties +++
|
|
291
319
|
private readonly mcpServersConfig?: MCPEndpointConfig[];
|
|
@@ -303,7 +331,21 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
303
331
|
params?.remoteEndpoints.some((e) => e.type === EndpointType.LangGraphPlatform)
|
|
304
332
|
) {
|
|
305
333
|
console.warn("Actions set in runtime instance will not be available for the agent");
|
|
334
|
+
console.warn(
|
|
335
|
+
`LangGraph Platform remote endpoints are deprecated in favor of the "agents" property`,
|
|
336
|
+
);
|
|
306
337
|
}
|
|
338
|
+
|
|
339
|
+
// TODO: finalize
|
|
340
|
+
// if (
|
|
341
|
+
// params?.agents &&
|
|
342
|
+
// Object.values(params.agents).some((agent) => {
|
|
343
|
+
// return agent instanceof AguiLangGraphAgent && !(agent instanceof LangGraphAgent);
|
|
344
|
+
// })
|
|
345
|
+
// ) {
|
|
346
|
+
// console.warn('LangGraph Agent class should be imported from @copilotkit/runtime. ')
|
|
347
|
+
// }
|
|
348
|
+
|
|
307
349
|
this.actions = params?.actions || [];
|
|
308
350
|
this.availableAgents = [];
|
|
309
351
|
|
|
@@ -320,6 +362,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
320
362
|
params?.delegateAgentProcessingToServiceAdapter || false;
|
|
321
363
|
this.observability = params?.observability_c;
|
|
322
364
|
this.agents = params?.agents ?? {};
|
|
365
|
+
this.onTrace = params?.onTrace;
|
|
323
366
|
// +++ MCP Initialization +++
|
|
324
367
|
this.mcpServersConfig = params?.mcpServers;
|
|
325
368
|
this.createMCPClientImpl = params?.createMCPClient;
|
|
@@ -452,7 +495,41 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
452
495
|
// For storing streamed chunks if progressive logging is enabled
|
|
453
496
|
const streamedChunks: any[] = [];
|
|
454
497
|
|
|
498
|
+
// Trace request start
|
|
499
|
+
await this.trace(
|
|
500
|
+
"request",
|
|
501
|
+
{
|
|
502
|
+
threadId,
|
|
503
|
+
runId,
|
|
504
|
+
source: "runtime",
|
|
505
|
+
request: {
|
|
506
|
+
operation: "processRuntimeRequest",
|
|
507
|
+
method: "POST",
|
|
508
|
+
url: url,
|
|
509
|
+
startTime: requestStartTime,
|
|
510
|
+
},
|
|
511
|
+
agent: agentSession ? { name: agentSession.agentName } : undefined,
|
|
512
|
+
messages: {
|
|
513
|
+
input: rawMessages,
|
|
514
|
+
messageCount: rawMessages.length,
|
|
515
|
+
},
|
|
516
|
+
technical: {
|
|
517
|
+
environment: process.env.NODE_ENV,
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
undefined,
|
|
521
|
+
publicApiKey,
|
|
522
|
+
);
|
|
523
|
+
|
|
455
524
|
try {
|
|
525
|
+
if (
|
|
526
|
+
Object.keys(this.agents).length &&
|
|
527
|
+
agentSession?.agentName &&
|
|
528
|
+
!this.delegateAgentProcessingToServiceAdapter
|
|
529
|
+
) {
|
|
530
|
+
this.agents = { [agentSession.agentName]: this.agents[agentSession.agentName] };
|
|
531
|
+
}
|
|
532
|
+
|
|
456
533
|
if (agentSession && !this.delegateAgentProcessingToServiceAdapter) {
|
|
457
534
|
return await this.processAgentRequest(request);
|
|
458
535
|
}
|
|
@@ -667,17 +744,62 @@ please use an LLM adapter instead.`,
|
|
|
667
744
|
}
|
|
668
745
|
}
|
|
669
746
|
|
|
747
|
+
let structuredError: CopilotKitError;
|
|
748
|
+
|
|
670
749
|
if (error instanceof CopilotKitError) {
|
|
671
|
-
|
|
750
|
+
structuredError = error;
|
|
751
|
+
} else {
|
|
752
|
+
// Convert non-CopilotKitErrors to structured errors, but preserve already structured ones
|
|
753
|
+
structuredError = ensureStructuredError(error, (err) =>
|
|
754
|
+
this.convertStreamingErrorToStructured(err),
|
|
755
|
+
);
|
|
672
756
|
}
|
|
673
757
|
|
|
674
|
-
//
|
|
675
|
-
|
|
676
|
-
|
|
758
|
+
// Trace the error
|
|
759
|
+
await this.trace(
|
|
760
|
+
"error",
|
|
761
|
+
{
|
|
762
|
+
threadId,
|
|
763
|
+
runId,
|
|
764
|
+
source: "runtime",
|
|
765
|
+
request: {
|
|
766
|
+
operation: "processRuntimeRequest",
|
|
767
|
+
method: "POST",
|
|
768
|
+
url: url,
|
|
769
|
+
startTime: requestStartTime,
|
|
770
|
+
},
|
|
771
|
+
response: {
|
|
772
|
+
endTime: Date.now(),
|
|
773
|
+
latency: Date.now() - requestStartTime,
|
|
774
|
+
},
|
|
775
|
+
agent: agentSession ? { name: agentSession.agentName } : undefined,
|
|
776
|
+
technical: {
|
|
777
|
+
environment: process.env.NODE_ENV,
|
|
778
|
+
stackTrace: error instanceof Error ? error.stack : undefined,
|
|
779
|
+
},
|
|
780
|
+
},
|
|
781
|
+
structuredError,
|
|
782
|
+
publicApiKey,
|
|
783
|
+
);
|
|
784
|
+
|
|
677
785
|
throw structuredError;
|
|
678
786
|
}
|
|
679
787
|
}
|
|
680
788
|
|
|
789
|
+
async getAllAgents(graphqlContext: GraphQLContext): Promise<(AgentWithEndpoint | Agent)[]> {
|
|
790
|
+
const [agentsWithEndpoints, aguiAgents] = await Promise.all([
|
|
791
|
+
this.discoverAgentsFromEndpoints(graphqlContext),
|
|
792
|
+
this.discoverAgentsFromAgui(),
|
|
793
|
+
]);
|
|
794
|
+
|
|
795
|
+
this.availableAgents = [...agentsWithEndpoints, ...aguiAgents].map((a) => ({
|
|
796
|
+
name: a.name,
|
|
797
|
+
id: a.id,
|
|
798
|
+
}));
|
|
799
|
+
|
|
800
|
+
return [...agentsWithEndpoints, ...aguiAgents];
|
|
801
|
+
}
|
|
802
|
+
|
|
681
803
|
async discoverAgentsFromEndpoints(graphqlContext: GraphQLContext): Promise<AgentWithEndpoint[]> {
|
|
682
804
|
const agents: Promise<AgentWithEndpoint[]> = this.remoteEndpointDefinitions.reduce(
|
|
683
805
|
async (acc: Promise<Agent[]>, endpoint) => {
|
|
@@ -759,7 +881,41 @@ please use an LLM adapter instead.`,
|
|
|
759
881
|
},
|
|
760
882
|
Promise.resolve([]),
|
|
761
883
|
);
|
|
762
|
-
|
|
884
|
+
|
|
885
|
+
return agents;
|
|
886
|
+
}
|
|
887
|
+
|
|
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
|
+
);
|
|
763
919
|
|
|
764
920
|
return agents;
|
|
765
921
|
}
|
|
@@ -769,50 +925,18 @@ please use an LLM adapter instead.`,
|
|
|
769
925
|
threadId: string,
|
|
770
926
|
agentName: string,
|
|
771
927
|
): Promise<LoadAgentStateResponse> {
|
|
772
|
-
const
|
|
928
|
+
const agents = await this.getAllAgents(graphqlContext);
|
|
773
929
|
|
|
774
|
-
const
|
|
775
|
-
if (!
|
|
930
|
+
const agent = agents.find((agent) => agent.name === agentName);
|
|
931
|
+
if (!agent) {
|
|
776
932
|
throw new Error("Agent not found");
|
|
777
933
|
}
|
|
778
934
|
|
|
779
|
-
if (
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
: null;
|
|
783
|
-
|
|
784
|
-
const client = new LangGraphClient({
|
|
785
|
-
apiUrl: agentWithEndpoint.endpoint.deploymentUrl,
|
|
786
|
-
apiKey: agentWithEndpoint.endpoint.langsmithApiKey,
|
|
787
|
-
defaultHeaders: { ...propertyHeaders },
|
|
788
|
-
});
|
|
789
|
-
let state: any = {};
|
|
790
|
-
try {
|
|
791
|
-
state = (await client.threads.getState(threadId)).values as any;
|
|
792
|
-
} catch (error) {}
|
|
793
|
-
|
|
794
|
-
if (Object.keys(state).length === 0) {
|
|
795
|
-
return {
|
|
796
|
-
threadId: threadId || "",
|
|
797
|
-
threadExists: false,
|
|
798
|
-
state: JSON.stringify({}),
|
|
799
|
-
messages: JSON.stringify([]),
|
|
800
|
-
};
|
|
801
|
-
} else {
|
|
802
|
-
const { messages, ...stateWithoutMessages } = state;
|
|
803
|
-
const copilotkitMessages = langchainMessagesToCopilotKit(messages);
|
|
804
|
-
return {
|
|
805
|
-
threadId: threadId || "",
|
|
806
|
-
threadExists: true,
|
|
807
|
-
state: JSON.stringify(stateWithoutMessages),
|
|
808
|
-
messages: JSON.stringify(copilotkitMessages),
|
|
809
|
-
};
|
|
810
|
-
}
|
|
811
|
-
} else if (
|
|
812
|
-
agentWithEndpoint.endpoint.type === EndpointType.CopilotKit ||
|
|
813
|
-
!("type" in agentWithEndpoint.endpoint)
|
|
935
|
+
if (
|
|
936
|
+
"endpoint" in agent &&
|
|
937
|
+
(agent.endpoint.type === EndpointType.CopilotKit || !("type" in agent.endpoint))
|
|
814
938
|
) {
|
|
815
|
-
const cpkEndpoint =
|
|
939
|
+
const cpkEndpoint = agent.endpoint as CopilotKitEndpoint;
|
|
816
940
|
const fetchUrl = `${cpkEndpoint.url}/agents/state`;
|
|
817
941
|
try {
|
|
818
942
|
const response = await fetchWithRetry(fetchUrl, {
|
|
@@ -828,10 +952,24 @@ please use an LLM adapter instead.`,
|
|
|
828
952
|
if (response.status === 404) {
|
|
829
953
|
throw new CopilotKitApiDiscoveryError({ url: fetchUrl });
|
|
830
954
|
}
|
|
955
|
+
|
|
956
|
+
// Extract semantic error information from response body
|
|
957
|
+
let errorMessage = `HTTP ${response.status} error`;
|
|
958
|
+
try {
|
|
959
|
+
const errorBody = await response.text();
|
|
960
|
+
const parsedError = JSON.parse(errorBody);
|
|
961
|
+
if (parsedError.error && typeof parsedError.error === "string") {
|
|
962
|
+
errorMessage = parsedError.error;
|
|
963
|
+
}
|
|
964
|
+
} catch {
|
|
965
|
+
// If parsing fails, fall back to generic message
|
|
966
|
+
}
|
|
967
|
+
|
|
831
968
|
throw new ResolvedCopilotKitError({
|
|
832
969
|
status: response.status,
|
|
833
970
|
url: fetchUrl,
|
|
834
971
|
isRemoteEndpoint: true,
|
|
972
|
+
message: errorMessage,
|
|
835
973
|
});
|
|
836
974
|
}
|
|
837
975
|
|
|
@@ -848,9 +986,64 @@ please use an LLM adapter instead.`,
|
|
|
848
986
|
}
|
|
849
987
|
throw new CopilotKitLowLevelError({ error, url: fetchUrl });
|
|
850
988
|
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const propertyHeaders = graphqlContext.properties.authorization
|
|
992
|
+
? { authorization: `Bearer ${graphqlContext.properties.authorization}` }
|
|
993
|
+
: null;
|
|
994
|
+
|
|
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
|
+
});
|
|
851
1002
|
} else {
|
|
852
|
-
|
|
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;
|
|
853
1009
|
}
|
|
1010
|
+
let state: any = {};
|
|
1011
|
+
try {
|
|
1012
|
+
state = (await client.threads.getState(threadId)).values as any;
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
// All errors from agent state loading are user configuration issues
|
|
1015
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1016
|
+
|
|
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
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
if (Object.keys(state).length === 0) {
|
|
1029
|
+
return {
|
|
1030
|
+
threadId: threadId || "",
|
|
1031
|
+
threadExists: false,
|
|
1032
|
+
state: JSON.stringify({}),
|
|
1033
|
+
messages: JSON.stringify([]),
|
|
1034
|
+
};
|
|
1035
|
+
} else {
|
|
1036
|
+
const { messages, ...stateWithoutMessages } = state;
|
|
1037
|
+
const copilotkitMessages = langchainMessagesToCopilotKit(messages);
|
|
1038
|
+
return {
|
|
1039
|
+
threadId: threadId || "",
|
|
1040
|
+
threadExists: true,
|
|
1041
|
+
state: JSON.stringify(stateWithoutMessages),
|
|
1042
|
+
messages: JSON.stringify(copilotkitMessages),
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
throw new Error(`Agent: ${agent.name} could not be resolved`);
|
|
854
1047
|
}
|
|
855
1048
|
|
|
856
1049
|
private async processAgentRequest(
|
|
@@ -876,6 +1069,33 @@ please use an LLM adapter instead.`,
|
|
|
876
1069
|
// for backwards compatibility, deal with the case when no threadId is provided
|
|
877
1070
|
const threadId = threadIdFromRequest ?? agentSession.threadId;
|
|
878
1071
|
|
|
1072
|
+
// Trace agent request start
|
|
1073
|
+
await this.trace(
|
|
1074
|
+
"agent_state",
|
|
1075
|
+
{
|
|
1076
|
+
threadId,
|
|
1077
|
+
source: "agent",
|
|
1078
|
+
request: {
|
|
1079
|
+
operation: "processAgentRequest",
|
|
1080
|
+
method: "POST",
|
|
1081
|
+
startTime: requestStartTime,
|
|
1082
|
+
},
|
|
1083
|
+
agent: {
|
|
1084
|
+
name: agentName,
|
|
1085
|
+
nodeName: nodeName,
|
|
1086
|
+
},
|
|
1087
|
+
messages: {
|
|
1088
|
+
input: rawMessages,
|
|
1089
|
+
messageCount: rawMessages.length,
|
|
1090
|
+
},
|
|
1091
|
+
technical: {
|
|
1092
|
+
environment: process.env.NODE_ENV,
|
|
1093
|
+
},
|
|
1094
|
+
},
|
|
1095
|
+
undefined,
|
|
1096
|
+
publicApiKey,
|
|
1097
|
+
);
|
|
1098
|
+
|
|
879
1099
|
const serverSideActions = await this.getServerSideActions(request);
|
|
880
1100
|
|
|
881
1101
|
const messages = convertGqlInputToMessages(rawMessages);
|
|
@@ -1003,9 +1223,7 @@ please use an LLM adapter instead.`,
|
|
|
1003
1223
|
eventSource.stream(async (eventStream$) => {
|
|
1004
1224
|
from(stream).subscribe({
|
|
1005
1225
|
next: (event) => eventStream$.next(event),
|
|
1006
|
-
error: (err) => {
|
|
1007
|
-
console.error("Error in stream", err);
|
|
1008
|
-
|
|
1226
|
+
error: async (err) => {
|
|
1009
1227
|
// Log error with observability if enabled
|
|
1010
1228
|
if (this.observability?.enabled && publicApiKey) {
|
|
1011
1229
|
try {
|
|
@@ -1027,8 +1245,39 @@ please use an LLM adapter instead.`,
|
|
|
1027
1245
|
}
|
|
1028
1246
|
}
|
|
1029
1247
|
|
|
1030
|
-
//
|
|
1031
|
-
const structuredError =
|
|
1248
|
+
// Preserve structured CopilotKit errors, only convert unstructured errors
|
|
1249
|
+
const structuredError = ensureStructuredError(err, (error) =>
|
|
1250
|
+
this.convertStreamingErrorToStructured(error),
|
|
1251
|
+
);
|
|
1252
|
+
|
|
1253
|
+
// Trace streaming errors
|
|
1254
|
+
await this.trace(
|
|
1255
|
+
"error",
|
|
1256
|
+
{
|
|
1257
|
+
threadId,
|
|
1258
|
+
source: "agent",
|
|
1259
|
+
request: {
|
|
1260
|
+
operation: "processAgentRequest",
|
|
1261
|
+
method: "POST",
|
|
1262
|
+
startTime: requestStartTime,
|
|
1263
|
+
},
|
|
1264
|
+
response: {
|
|
1265
|
+
endTime: Date.now(),
|
|
1266
|
+
latency: Date.now() - requestStartTime,
|
|
1267
|
+
},
|
|
1268
|
+
agent: {
|
|
1269
|
+
name: agentName,
|
|
1270
|
+
nodeName: nodeName,
|
|
1271
|
+
},
|
|
1272
|
+
technical: {
|
|
1273
|
+
environment: process.env.NODE_ENV,
|
|
1274
|
+
stackTrace: err instanceof Error ? err.stack : undefined,
|
|
1275
|
+
},
|
|
1276
|
+
},
|
|
1277
|
+
structuredError,
|
|
1278
|
+
publicApiKey,
|
|
1279
|
+
);
|
|
1280
|
+
|
|
1032
1281
|
eventStream$.error(structuredError);
|
|
1033
1282
|
eventStream$.complete();
|
|
1034
1283
|
},
|
|
@@ -1106,8 +1355,41 @@ please use an LLM adapter instead.`,
|
|
|
1106
1355
|
}
|
|
1107
1356
|
}
|
|
1108
1357
|
|
|
1358
|
+
// Ensure error is structured
|
|
1359
|
+
const structuredError = ensureStructuredError(error, (err) =>
|
|
1360
|
+
this.convertStreamingErrorToStructured(err),
|
|
1361
|
+
);
|
|
1362
|
+
|
|
1363
|
+
// Trace the agent error
|
|
1364
|
+
await this.trace(
|
|
1365
|
+
"error",
|
|
1366
|
+
{
|
|
1367
|
+
threadId,
|
|
1368
|
+
source: "agent",
|
|
1369
|
+
request: {
|
|
1370
|
+
operation: "processAgentRequest",
|
|
1371
|
+
method: "POST",
|
|
1372
|
+
startTime: requestStartTime,
|
|
1373
|
+
},
|
|
1374
|
+
response: {
|
|
1375
|
+
endTime: Date.now(),
|
|
1376
|
+
latency: Date.now() - requestStartTime,
|
|
1377
|
+
},
|
|
1378
|
+
agent: {
|
|
1379
|
+
name: agentName,
|
|
1380
|
+
nodeName: nodeName,
|
|
1381
|
+
},
|
|
1382
|
+
technical: {
|
|
1383
|
+
environment: process.env.NODE_ENV,
|
|
1384
|
+
stackTrace: error instanceof Error ? error.stack : undefined,
|
|
1385
|
+
},
|
|
1386
|
+
},
|
|
1387
|
+
structuredError,
|
|
1388
|
+
publicApiKey,
|
|
1389
|
+
);
|
|
1390
|
+
|
|
1109
1391
|
console.error("Error getting response:", error);
|
|
1110
|
-
throw
|
|
1392
|
+
throw structuredError;
|
|
1111
1393
|
}
|
|
1112
1394
|
}
|
|
1113
1395
|
|
|
@@ -1223,53 +1505,108 @@ please use an LLM adapter instead.`,
|
|
|
1223
1505
|
}
|
|
1224
1506
|
|
|
1225
1507
|
private convertStreamingErrorToStructured(error: any): CopilotKitError {
|
|
1226
|
-
//
|
|
1227
|
-
|
|
1228
|
-
error?.message?.includes("terminated") ||
|
|
1229
|
-
error?.cause?.code === "UND_ERR_SOCKET" ||
|
|
1230
|
-
error?.message?.includes("other side closed") ||
|
|
1231
|
-
error?.code === "UND_ERR_SOCKET"
|
|
1232
|
-
) {
|
|
1233
|
-
return new CopilotKitError({
|
|
1234
|
-
message:
|
|
1235
|
-
"Connection to agent was unexpectedly terminated. This may be due to the agent service being restarted or network issues. Please try again.",
|
|
1236
|
-
code: CopilotKitErrorCode.NETWORK_ERROR,
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1508
|
+
// Determine a more helpful error message based on context
|
|
1509
|
+
let helpfulMessage = generateHelpfulErrorMessage(error, "agent streaming connection");
|
|
1239
1510
|
|
|
1240
|
-
//
|
|
1511
|
+
// For network-related errors, use CopilotKitLowLevelError to preserve the original error
|
|
1241
1512
|
if (
|
|
1242
1513
|
error?.message?.includes("fetch failed") ||
|
|
1243
1514
|
error?.message?.includes("ECONNREFUSED") ||
|
|
1244
1515
|
error?.message?.includes("ENOTFOUND") ||
|
|
1245
|
-
error?.message?.includes("ETIMEDOUT")
|
|
1516
|
+
error?.message?.includes("ETIMEDOUT") ||
|
|
1517
|
+
error?.message?.includes("terminated") ||
|
|
1518
|
+
error?.cause?.code === "UND_ERR_SOCKET" ||
|
|
1519
|
+
error?.message?.includes("other side closed") ||
|
|
1520
|
+
error?.code === "UND_ERR_SOCKET"
|
|
1246
1521
|
) {
|
|
1247
1522
|
return new CopilotKitLowLevelError({
|
|
1248
1523
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
1249
1524
|
url: "agent streaming connection",
|
|
1250
|
-
message:
|
|
1251
|
-
"Network error occurred during agent streaming. Please check your connection and try again.",
|
|
1252
|
-
});
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
// Handle abort/cancellation errors (these are usually normal)
|
|
1256
|
-
if (
|
|
1257
|
-
error?.message?.includes("aborted") ||
|
|
1258
|
-
error?.message?.includes("canceled") ||
|
|
1259
|
-
error?.message?.includes("signal is aborted")
|
|
1260
|
-
) {
|
|
1261
|
-
return new CopilotKitError({
|
|
1262
|
-
message: "Agent request was cancelled",
|
|
1263
|
-
code: CopilotKitErrorCode.UNKNOWN,
|
|
1525
|
+
message: helpfulMessage,
|
|
1264
1526
|
});
|
|
1265
1527
|
}
|
|
1266
1528
|
|
|
1267
|
-
//
|
|
1529
|
+
// For all other errors, preserve the raw error in a basic CopilotKitError
|
|
1268
1530
|
return new CopilotKitError({
|
|
1269
|
-
message:
|
|
1531
|
+
message: helpfulMessage,
|
|
1270
1532
|
code: CopilotKitErrorCode.UNKNOWN,
|
|
1271
1533
|
});
|
|
1272
1534
|
}
|
|
1535
|
+
|
|
1536
|
+
private async trace(
|
|
1537
|
+
type: CopilotTraceEvent["type"],
|
|
1538
|
+
context: CopilotRequestContext,
|
|
1539
|
+
error?: any,
|
|
1540
|
+
publicApiKey?: string,
|
|
1541
|
+
): Promise<void> {
|
|
1542
|
+
if (!this.onTrace) return;
|
|
1543
|
+
|
|
1544
|
+
// Just check if publicApiKey is defined (regardless of validity)
|
|
1545
|
+
if (!publicApiKey) {
|
|
1546
|
+
if (!this.hasWarnedAboutTracing) {
|
|
1547
|
+
console.warn(
|
|
1548
|
+
"CopilotKit: onTrace handler provided but requires publicApiKey to be defined for tracing to work.",
|
|
1549
|
+
);
|
|
1550
|
+
this.hasWarnedAboutTracing = true;
|
|
1551
|
+
}
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
try {
|
|
1556
|
+
const traceEvent: CopilotTraceEvent = {
|
|
1557
|
+
type,
|
|
1558
|
+
timestamp: Date.now(),
|
|
1559
|
+
context,
|
|
1560
|
+
...(error && { error }),
|
|
1561
|
+
};
|
|
1562
|
+
|
|
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);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
/**
|
|
1571
|
+
* Public method to trace GraphQL validation errors
|
|
1572
|
+
* This allows the GraphQL resolver to send validation errors through the trace system
|
|
1573
|
+
*/
|
|
1574
|
+
public async traceGraphQLError(
|
|
1575
|
+
error: { message: string; code: string; type: string },
|
|
1576
|
+
context: {
|
|
1577
|
+
operation: string;
|
|
1578
|
+
cloudConfigPresent: boolean;
|
|
1579
|
+
guardrailsEnabled: boolean;
|
|
1580
|
+
},
|
|
1581
|
+
): Promise<void> {
|
|
1582
|
+
if (!this.onTrace) return;
|
|
1583
|
+
|
|
1584
|
+
try {
|
|
1585
|
+
await this.onTrace({
|
|
1586
|
+
type: "error",
|
|
1587
|
+
timestamp: Date.now(),
|
|
1588
|
+
context: {
|
|
1589
|
+
source: "runtime",
|
|
1590
|
+
request: {
|
|
1591
|
+
operation: context.operation,
|
|
1592
|
+
startTime: Date.now(),
|
|
1593
|
+
},
|
|
1594
|
+
technical: {
|
|
1595
|
+
environment: process.env.NODE_ENV,
|
|
1596
|
+
},
|
|
1597
|
+
metadata: {
|
|
1598
|
+
errorType: "GraphQLValidationError",
|
|
1599
|
+
cloudConfigPresent: context.cloudConfigPresent,
|
|
1600
|
+
guardrailsEnabled: context.guardrailsEnabled,
|
|
1601
|
+
},
|
|
1602
|
+
},
|
|
1603
|
+
error,
|
|
1604
|
+
});
|
|
1605
|
+
} catch (traceError) {
|
|
1606
|
+
// Don't let trace errors break the main flow
|
|
1607
|
+
console.error("Error in onTrace handler:", traceError);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1273
1610
|
}
|
|
1274
1611
|
|
|
1275
1612
|
export function flattenToolCallsNoDuplicates(toolsByPriority: ActionInput[]): ActionInput[] {
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
LangGraphAgent as AGUILangGraphAgent,
|
|
17
17
|
type LangGraphAgentConfig,
|
|
18
18
|
ProcessedEvents,
|
|
19
|
+
SchemaKeys,
|
|
19
20
|
} from "@ag-ui/langgraph";
|
|
20
21
|
import { Message as LangGraphMessage } from "@langchain/langgraph-sdk/dist/types.messages";
|
|
21
22
|
|
|
@@ -180,6 +181,7 @@ export class LangGraphAgent extends AGUILangGraphAgent {
|
|
|
180
181
|
messages,
|
|
181
182
|
tools,
|
|
182
183
|
);
|
|
184
|
+
|
|
183
185
|
return {
|
|
184
186
|
...rest,
|
|
185
187
|
copilotkit: {
|
|
@@ -187,4 +189,14 @@ export class LangGraphAgent extends AGUILangGraphAgent {
|
|
|
187
189
|
},
|
|
188
190
|
};
|
|
189
191
|
}
|
|
192
|
+
|
|
193
|
+
async getSchemaKeys(): Promise<SchemaKeys> {
|
|
194
|
+
const CONSTANT_KEYS = ["copilotkit"];
|
|
195
|
+
const schemaKeys = await super.getSchemaKeys();
|
|
196
|
+
return {
|
|
197
|
+
config: schemaKeys.config,
|
|
198
|
+
input: schemaKeys.input ? [...schemaKeys.input, ...CONSTANT_KEYS] : null,
|
|
199
|
+
output: schemaKeys.output ? [...schemaKeys.output, ...CONSTANT_KEYS] : null,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
190
202
|
}
|