@copilotkit/runtime 1.9.2-next.2 → 1.9.2-next.21
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 +136 -0
- package/dist/{chunk-CD2SZGIZ.mjs → chunk-47L6Z7PJ.mjs} +2 -2
- package/dist/chunk-AMUJQ6IR.mjs +50 -0
- package/dist/chunk-AMUJQ6IR.mjs.map +1 -0
- package/dist/{chunk-DOWRU5U6.mjs → chunk-IBYPYIVX.mjs} +2353 -1854
- package/dist/chunk-IBYPYIVX.mjs.map +1 -0
- package/dist/{chunk-D3SPXEVJ.mjs → chunk-IXK4UOV6.mjs} +2 -2
- package/dist/{chunk-6TQCQ3WJ.mjs → chunk-P3HORCYJ.mjs} +2 -2
- package/dist/{chunk-IIXJVVTV.mjs → chunk-QLLV2QVK.mjs} +132 -78
- package/dist/chunk-QLLV2QVK.mjs.map +1 -0
- package/dist/{chunk-ODF35LFG.mjs → chunk-UPC6N4MV.mjs} +19 -2
- package/dist/chunk-UPC6N4MV.mjs.map +1 -0
- 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-098f97f6.d.ts} +5 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +3728 -3114
- 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 +5 -4
- package/dist/lib/index.js +2711 -2140
- 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 +160 -96
- 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 +160 -96
- 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 +160 -96
- 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 +160 -96
- 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 +202 -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-41d4988d.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 +2 -2
- package/src/agents/langgraph/event-source.ts +36 -38
- package/src/agents/langgraph/events.ts +19 -1
- package/src/graphql/resolvers/copilot.resolver.ts +107 -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-error.test.ts +169 -0
- package/src/lib/runtime/agui-action.ts +9 -3
- package/src/lib/runtime/copilot-runtime.ts +384 -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-actions.ts +6 -0
- 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/google/google-genai-adapter.ts +5 -0
- 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 +4 -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-DOWRU5U6.mjs.map +0 -1
- package/dist/chunk-IIXJVVTV.mjs.map +0 -1
- package/dist/chunk-ODF35LFG.mjs.map +0 -1
- package/dist/{chunk-CD2SZGIZ.mjs.map → chunk-47L6Z7PJ.mjs.map} +0 -0
- package/dist/{chunk-D3SPXEVJ.mjs.map → chunk-IXK4UOV6.mjs.map} +0 -0
- package/dist/{chunk-6TQCQ3WJ.mjs.map → chunk-P3HORCYJ.mjs.map} +0 -0
- package/dist/{langserve-4a5c9217.d.ts → langserve-fc5cac89.d.ts} +7 -7
|
@@ -22,12 +22,16 @@ export function constructAGUIRemoteAction({
|
|
|
22
22
|
agentStates,
|
|
23
23
|
agent,
|
|
24
24
|
metaEvents,
|
|
25
|
+
threadMetadata,
|
|
26
|
+
nodeName,
|
|
25
27
|
}: {
|
|
26
28
|
logger: Logger;
|
|
27
29
|
messages: Message[];
|
|
28
30
|
agentStates?: AgentStateInput[];
|
|
29
31
|
agent: AbstractAgent;
|
|
30
32
|
metaEvents?: MetaEventInput[];
|
|
33
|
+
threadMetadata?: Record<string, any>;
|
|
34
|
+
nodeName?: string;
|
|
31
35
|
}) {
|
|
32
36
|
const action = {
|
|
33
37
|
name: agent.agentId,
|
|
@@ -67,9 +71,11 @@ export function constructAGUIRemoteAction({
|
|
|
67
71
|
};
|
|
68
72
|
});
|
|
69
73
|
|
|
70
|
-
const forwardedProps =
|
|
71
|
-
? { command: { resume: metaEvents[0]?.response } }
|
|
72
|
-
:
|
|
74
|
+
const forwardedProps = {
|
|
75
|
+
...(metaEvents?.length ? { command: { resume: metaEvents[0]?.response } } : {}),
|
|
76
|
+
...(threadMetadata ? { threadMetadata } : {}),
|
|
77
|
+
...(nodeName ? { nodeName } : {}),
|
|
78
|
+
};
|
|
73
79
|
|
|
74
80
|
return agent.legacy_to_be_removed_runAgentBridged({
|
|
75
81
|
tools,
|
|
@@ -20,11 +20,14 @@ import {
|
|
|
20
20
|
CopilotKitApiDiscoveryError,
|
|
21
21
|
randomId,
|
|
22
22
|
CopilotKitError,
|
|
23
|
-
CopilotKitRemoteEndpointDiscoveryError,
|
|
24
23
|
CopilotKitAgentDiscoveryError,
|
|
25
24
|
CopilotKitMisuseError,
|
|
26
25
|
CopilotKitErrorCode,
|
|
27
26
|
CopilotKitLowLevelError,
|
|
27
|
+
CopilotErrorHandler,
|
|
28
|
+
CopilotErrorEvent,
|
|
29
|
+
CopilotRequestContext,
|
|
30
|
+
ensureStructuredError,
|
|
28
31
|
} from "@copilotkit/shared";
|
|
29
32
|
import {
|
|
30
33
|
CopilotServiceAdapter,
|
|
@@ -81,10 +84,13 @@ import {
|
|
|
81
84
|
convertMCPToolsToActions,
|
|
82
85
|
generateMcpToolInstructions,
|
|
83
86
|
} from "./mcp-tools-utils";
|
|
87
|
+
import { LangGraphAgent } from "./langgraph/langgraph-agent";
|
|
84
88
|
// Define the function type alias here or import if defined elsewhere
|
|
85
89
|
type CreateMCPClientFunction = (config: MCPEndpointConfig) => Promise<MCPClient>;
|
|
86
90
|
// --- MCP Imports ---
|
|
87
91
|
|
|
92
|
+
import { generateHelpfulErrorMessage } from "../streaming";
|
|
93
|
+
|
|
88
94
|
export interface CopilotRuntimeRequest {
|
|
89
95
|
serviceAdapter: CopilotServiceAdapter;
|
|
90
96
|
messages: MessageInput[];
|
|
@@ -274,6 +280,25 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
|
|
|
274
280
|
* ```
|
|
275
281
|
*/
|
|
276
282
|
createMCPClient?: CreateMCPClientFunction;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Optional error handler for comprehensive debugging and observability.
|
|
286
|
+
*
|
|
287
|
+
* **Requires publicApiKey**: Error handling only works when requests include a valid publicApiKey.
|
|
288
|
+
* This is a premium CopilotKit Cloud feature.
|
|
289
|
+
*
|
|
290
|
+
* @param errorEvent - Structured error event with rich debugging context
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```typescript
|
|
294
|
+
* const runtime = new CopilotRuntime({
|
|
295
|
+
* onError: (errorEvent) => {
|
|
296
|
+
* debugDashboard.capture(errorEvent);
|
|
297
|
+
* }
|
|
298
|
+
* });
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
onError?: CopilotErrorHandler;
|
|
277
302
|
}
|
|
278
303
|
|
|
279
304
|
export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
@@ -286,6 +311,8 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
286
311
|
private delegateAgentProcessingToServiceAdapter: boolean;
|
|
287
312
|
private observability?: CopilotObservabilityConfig;
|
|
288
313
|
private availableAgents: Pick<AgentWithEndpoint, "name" | "id">[];
|
|
314
|
+
private onError?: CopilotErrorHandler;
|
|
315
|
+
private hasWarnedAboutError = false;
|
|
289
316
|
|
|
290
317
|
// +++ MCP Properties +++
|
|
291
318
|
private readonly mcpServersConfig?: MCPEndpointConfig[];
|
|
@@ -303,7 +330,21 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
303
330
|
params?.remoteEndpoints.some((e) => e.type === EndpointType.LangGraphPlatform)
|
|
304
331
|
) {
|
|
305
332
|
console.warn("Actions set in runtime instance will not be available for the agent");
|
|
333
|
+
console.warn(
|
|
334
|
+
`LangGraph Platform remote endpoints are deprecated in favor of the "agents" property`,
|
|
335
|
+
);
|
|
306
336
|
}
|
|
337
|
+
|
|
338
|
+
// TODO: finalize
|
|
339
|
+
// if (
|
|
340
|
+
// params?.agents &&
|
|
341
|
+
// Object.values(params.agents).some((agent) => {
|
|
342
|
+
// return agent instanceof AguiLangGraphAgent && !(agent instanceof LangGraphAgent);
|
|
343
|
+
// })
|
|
344
|
+
// ) {
|
|
345
|
+
// console.warn('LangGraph Agent class should be imported from @copilotkit/runtime. ')
|
|
346
|
+
// }
|
|
347
|
+
|
|
307
348
|
this.actions = params?.actions || [];
|
|
308
349
|
this.availableAgents = [];
|
|
309
350
|
|
|
@@ -320,6 +361,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
320
361
|
params?.delegateAgentProcessingToServiceAdapter || false;
|
|
321
362
|
this.observability = params?.observability_c;
|
|
322
363
|
this.agents = params?.agents ?? {};
|
|
364
|
+
this.onError = params?.onError;
|
|
323
365
|
// +++ MCP Initialization +++
|
|
324
366
|
this.mcpServersConfig = params?.mcpServers;
|
|
325
367
|
this.createMCPClientImpl = params?.createMCPClient;
|
|
@@ -452,6 +494,32 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
452
494
|
// For storing streamed chunks if progressive logging is enabled
|
|
453
495
|
const streamedChunks: any[] = [];
|
|
454
496
|
|
|
497
|
+
// Track request start
|
|
498
|
+
await this.error(
|
|
499
|
+
"request",
|
|
500
|
+
{
|
|
501
|
+
threadId,
|
|
502
|
+
runId,
|
|
503
|
+
source: "runtime",
|
|
504
|
+
request: {
|
|
505
|
+
operation: "processRuntimeRequest",
|
|
506
|
+
method: "POST",
|
|
507
|
+
url: url,
|
|
508
|
+
startTime: requestStartTime,
|
|
509
|
+
},
|
|
510
|
+
agent: agentSession ? { name: agentSession.agentName } : undefined,
|
|
511
|
+
messages: {
|
|
512
|
+
input: rawMessages,
|
|
513
|
+
messageCount: rawMessages.length,
|
|
514
|
+
},
|
|
515
|
+
technical: {
|
|
516
|
+
environment: process.env.NODE_ENV,
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
undefined,
|
|
520
|
+
publicApiKey,
|
|
521
|
+
);
|
|
522
|
+
|
|
455
523
|
try {
|
|
456
524
|
if (
|
|
457
525
|
Object.keys(this.agents).length &&
|
|
@@ -675,17 +743,60 @@ please use an LLM adapter instead.`,
|
|
|
675
743
|
}
|
|
676
744
|
}
|
|
677
745
|
|
|
746
|
+
let structuredError: CopilotKitError;
|
|
747
|
+
|
|
678
748
|
if (error instanceof CopilotKitError) {
|
|
679
|
-
|
|
749
|
+
structuredError = error;
|
|
750
|
+
} else {
|
|
751
|
+
// Convert non-CopilotKitErrors to structured errors, but preserve already structured ones
|
|
752
|
+
structuredError = ensureStructuredError(error, (err) =>
|
|
753
|
+
this.convertStreamingErrorToStructured(err),
|
|
754
|
+
);
|
|
680
755
|
}
|
|
681
756
|
|
|
682
|
-
//
|
|
683
|
-
|
|
684
|
-
|
|
757
|
+
// Track the error
|
|
758
|
+
await this.error(
|
|
759
|
+
"error",
|
|
760
|
+
{
|
|
761
|
+
threadId,
|
|
762
|
+
runId,
|
|
763
|
+
source: "runtime",
|
|
764
|
+
request: {
|
|
765
|
+
operation: "processRuntimeRequest",
|
|
766
|
+
method: "POST",
|
|
767
|
+
url: url,
|
|
768
|
+
startTime: requestStartTime,
|
|
769
|
+
},
|
|
770
|
+
response: {
|
|
771
|
+
endTime: Date.now(),
|
|
772
|
+
latency: Date.now() - requestStartTime,
|
|
773
|
+
},
|
|
774
|
+
agent: agentSession ? { name: agentSession.agentName } : undefined,
|
|
775
|
+
technical: {
|
|
776
|
+
environment: process.env.NODE_ENV,
|
|
777
|
+
stackTrace: error instanceof Error ? error.stack : undefined,
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
structuredError,
|
|
781
|
+
publicApiKey,
|
|
782
|
+
);
|
|
783
|
+
|
|
685
784
|
throw structuredError;
|
|
686
785
|
}
|
|
687
786
|
}
|
|
688
787
|
|
|
788
|
+
async getAllAgents(graphqlContext: GraphQLContext): Promise<(AgentWithEndpoint | Agent)[]> {
|
|
789
|
+
const agentsWithEndpoints = await this.discoverAgentsFromEndpoints(graphqlContext);
|
|
790
|
+
const aguiAgents = this.discoverAgentsFromAgui();
|
|
791
|
+
|
|
792
|
+
this.availableAgents = [...agentsWithEndpoints, ...aguiAgents].map((a) => ({
|
|
793
|
+
name: a.name,
|
|
794
|
+
id: a.id,
|
|
795
|
+
}));
|
|
796
|
+
|
|
797
|
+
return [...agentsWithEndpoints, ...aguiAgents];
|
|
798
|
+
}
|
|
799
|
+
|
|
689
800
|
async discoverAgentsFromEndpoints(graphqlContext: GraphQLContext): Promise<AgentWithEndpoint[]> {
|
|
690
801
|
const agents: Promise<AgentWithEndpoint[]> = this.remoteEndpointDefinitions.reduce(
|
|
691
802
|
async (acc: Promise<Agent[]>, endpoint) => {
|
|
@@ -767,60 +878,35 @@ please use an LLM adapter instead.`,
|
|
|
767
878
|
},
|
|
768
879
|
Promise.resolve([]),
|
|
769
880
|
);
|
|
770
|
-
this.availableAgents = ((await agents) ?? []).map((a) => ({ name: a.name, id: a.id }));
|
|
771
881
|
|
|
772
882
|
return agents;
|
|
773
883
|
}
|
|
774
884
|
|
|
885
|
+
discoverAgentsFromAgui(): Agent[] {
|
|
886
|
+
return Object.entries(this.agents ?? []).map(([key, agent]: [string, AbstractAgent]) => ({
|
|
887
|
+
name: (agent as any).agentName ?? key,
|
|
888
|
+
id: agent.agentId ?? key,
|
|
889
|
+
description: agent.description ?? "",
|
|
890
|
+
}));
|
|
891
|
+
}
|
|
892
|
+
|
|
775
893
|
async loadAgentState(
|
|
776
894
|
graphqlContext: GraphQLContext,
|
|
777
895
|
threadId: string,
|
|
778
896
|
agentName: string,
|
|
779
897
|
): Promise<LoadAgentStateResponse> {
|
|
780
|
-
const
|
|
898
|
+
const agents = await this.getAllAgents(graphqlContext);
|
|
781
899
|
|
|
782
|
-
const
|
|
783
|
-
if (!
|
|
900
|
+
const agent = agents.find((agent) => agent.name === agentName);
|
|
901
|
+
if (!agent) {
|
|
784
902
|
throw new Error("Agent not found");
|
|
785
903
|
}
|
|
786
904
|
|
|
787
|
-
if (
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
: null;
|
|
791
|
-
|
|
792
|
-
const client = new LangGraphClient({
|
|
793
|
-
apiUrl: agentWithEndpoint.endpoint.deploymentUrl,
|
|
794
|
-
apiKey: agentWithEndpoint.endpoint.langsmithApiKey,
|
|
795
|
-
defaultHeaders: { ...propertyHeaders },
|
|
796
|
-
});
|
|
797
|
-
let state: any = {};
|
|
798
|
-
try {
|
|
799
|
-
state = (await client.threads.getState(threadId)).values as any;
|
|
800
|
-
} catch (error) {}
|
|
801
|
-
|
|
802
|
-
if (Object.keys(state).length === 0) {
|
|
803
|
-
return {
|
|
804
|
-
threadId: threadId || "",
|
|
805
|
-
threadExists: false,
|
|
806
|
-
state: JSON.stringify({}),
|
|
807
|
-
messages: JSON.stringify([]),
|
|
808
|
-
};
|
|
809
|
-
} else {
|
|
810
|
-
const { messages, ...stateWithoutMessages } = state;
|
|
811
|
-
const copilotkitMessages = langchainMessagesToCopilotKit(messages);
|
|
812
|
-
return {
|
|
813
|
-
threadId: threadId || "",
|
|
814
|
-
threadExists: true,
|
|
815
|
-
state: JSON.stringify(stateWithoutMessages),
|
|
816
|
-
messages: JSON.stringify(copilotkitMessages),
|
|
817
|
-
};
|
|
818
|
-
}
|
|
819
|
-
} else if (
|
|
820
|
-
agentWithEndpoint.endpoint.type === EndpointType.CopilotKit ||
|
|
821
|
-
!("type" in agentWithEndpoint.endpoint)
|
|
905
|
+
if (
|
|
906
|
+
"endpoint" in agent &&
|
|
907
|
+
(agent.endpoint.type === EndpointType.CopilotKit || !("type" in agent.endpoint))
|
|
822
908
|
) {
|
|
823
|
-
const cpkEndpoint =
|
|
909
|
+
const cpkEndpoint = agent.endpoint as CopilotKitEndpoint;
|
|
824
910
|
const fetchUrl = `${cpkEndpoint.url}/agents/state`;
|
|
825
911
|
try {
|
|
826
912
|
const response = await fetchWithRetry(fetchUrl, {
|
|
@@ -836,10 +922,24 @@ please use an LLM adapter instead.`,
|
|
|
836
922
|
if (response.status === 404) {
|
|
837
923
|
throw new CopilotKitApiDiscoveryError({ url: fetchUrl });
|
|
838
924
|
}
|
|
925
|
+
|
|
926
|
+
// Extract semantic error information from response body
|
|
927
|
+
let errorMessage = `HTTP ${response.status} error`;
|
|
928
|
+
try {
|
|
929
|
+
const errorBody = await response.text();
|
|
930
|
+
const parsedError = JSON.parse(errorBody);
|
|
931
|
+
if (parsedError.error && typeof parsedError.error === "string") {
|
|
932
|
+
errorMessage = parsedError.error;
|
|
933
|
+
}
|
|
934
|
+
} catch {
|
|
935
|
+
// If parsing fails, fall back to generic message
|
|
936
|
+
}
|
|
937
|
+
|
|
839
938
|
throw new ResolvedCopilotKitError({
|
|
840
939
|
status: response.status,
|
|
841
940
|
url: fetchUrl,
|
|
842
941
|
isRemoteEndpoint: true,
|
|
942
|
+
message: errorMessage,
|
|
843
943
|
});
|
|
844
944
|
}
|
|
845
945
|
|
|
@@ -856,9 +956,65 @@ please use an LLM adapter instead.`,
|
|
|
856
956
|
}
|
|
857
957
|
throw new CopilotKitLowLevelError({ error, url: fetchUrl });
|
|
858
958
|
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
const propertyHeaders = graphqlContext.properties.authorization
|
|
962
|
+
? { authorization: `Bearer ${graphqlContext.properties.authorization}` }
|
|
963
|
+
: null;
|
|
964
|
+
|
|
965
|
+
let state: any = {};
|
|
966
|
+
try {
|
|
967
|
+
let client: LangGraphClient | null;
|
|
968
|
+
if ("endpoint" in agent && agent.endpoint.type === EndpointType.LangGraphPlatform) {
|
|
969
|
+
client = new LangGraphClient({
|
|
970
|
+
apiUrl: agent.endpoint.deploymentUrl,
|
|
971
|
+
apiKey: agent.endpoint.langsmithApiKey,
|
|
972
|
+
defaultHeaders: { ...propertyHeaders },
|
|
973
|
+
});
|
|
974
|
+
} else {
|
|
975
|
+
const aguiAgent = graphqlContext._copilotkit.runtime.agents[agent.name] as LangGraphAgent;
|
|
976
|
+
if (!aguiAgent) {
|
|
977
|
+
throw new Error(`Agent: ${agent.name} could not be resolved`);
|
|
978
|
+
}
|
|
979
|
+
// @ts-expect-error -- both clients are the same
|
|
980
|
+
client = aguiAgent.client ?? null;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
state = client ? ((await client.threads.getState(threadId)).values as any) : {};
|
|
984
|
+
} catch (error) {
|
|
985
|
+
// All errors from agent state loading are user configuration issues
|
|
986
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
987
|
+
|
|
988
|
+
// Log user configuration errors at debug level to reduce noise
|
|
989
|
+
console.debug(`Agent '${agentName}' configuration issue: ${errorMessage}`);
|
|
990
|
+
|
|
991
|
+
// Throw a configuration error - all agent state loading failures are user setup issues
|
|
992
|
+
throw new ResolvedCopilotKitError({
|
|
993
|
+
status: 400,
|
|
994
|
+
message: `Agent '${agentName}' failed to execute: ${errorMessage}`,
|
|
995
|
+
code: CopilotKitErrorCode.CONFIGURATION_ERROR,
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if (Object.keys(state).length === 0) {
|
|
1000
|
+
return {
|
|
1001
|
+
threadId: threadId || "",
|
|
1002
|
+
threadExists: false,
|
|
1003
|
+
state: JSON.stringify({}),
|
|
1004
|
+
messages: JSON.stringify([]),
|
|
1005
|
+
};
|
|
859
1006
|
} else {
|
|
860
|
-
|
|
1007
|
+
const { messages, ...stateWithoutMessages } = state;
|
|
1008
|
+
const copilotkitMessages = langchainMessagesToCopilotKit(messages);
|
|
1009
|
+
return {
|
|
1010
|
+
threadId: threadId || "",
|
|
1011
|
+
threadExists: true,
|
|
1012
|
+
state: JSON.stringify(stateWithoutMessages),
|
|
1013
|
+
messages: JSON.stringify(copilotkitMessages),
|
|
1014
|
+
};
|
|
861
1015
|
}
|
|
1016
|
+
|
|
1017
|
+
throw new Error(`Agent: ${agent.name} could not be resolved`);
|
|
862
1018
|
}
|
|
863
1019
|
|
|
864
1020
|
private async processAgentRequest(
|
|
@@ -884,6 +1040,33 @@ please use an LLM adapter instead.`,
|
|
|
884
1040
|
// for backwards compatibility, deal with the case when no threadId is provided
|
|
885
1041
|
const threadId = threadIdFromRequest ?? agentSession.threadId;
|
|
886
1042
|
|
|
1043
|
+
// Track agent request start
|
|
1044
|
+
await this.error(
|
|
1045
|
+
"agent_state",
|
|
1046
|
+
{
|
|
1047
|
+
threadId,
|
|
1048
|
+
source: "agent",
|
|
1049
|
+
request: {
|
|
1050
|
+
operation: "processAgentRequest",
|
|
1051
|
+
method: "POST",
|
|
1052
|
+
startTime: requestStartTime,
|
|
1053
|
+
},
|
|
1054
|
+
agent: {
|
|
1055
|
+
name: agentName,
|
|
1056
|
+
nodeName: nodeName,
|
|
1057
|
+
},
|
|
1058
|
+
messages: {
|
|
1059
|
+
input: rawMessages,
|
|
1060
|
+
messageCount: rawMessages.length,
|
|
1061
|
+
},
|
|
1062
|
+
technical: {
|
|
1063
|
+
environment: process.env.NODE_ENV,
|
|
1064
|
+
},
|
|
1065
|
+
},
|
|
1066
|
+
undefined,
|
|
1067
|
+
publicApiKey,
|
|
1068
|
+
);
|
|
1069
|
+
|
|
887
1070
|
const serverSideActions = await this.getServerSideActions(request);
|
|
888
1071
|
|
|
889
1072
|
const messages = convertGqlInputToMessages(rawMessages);
|
|
@@ -1011,9 +1194,7 @@ please use an LLM adapter instead.`,
|
|
|
1011
1194
|
eventSource.stream(async (eventStream$) => {
|
|
1012
1195
|
from(stream).subscribe({
|
|
1013
1196
|
next: (event) => eventStream$.next(event),
|
|
1014
|
-
error: (err) => {
|
|
1015
|
-
console.error("Error in stream", err);
|
|
1016
|
-
|
|
1197
|
+
error: async (err) => {
|
|
1017
1198
|
// Log error with observability if enabled
|
|
1018
1199
|
if (this.observability?.enabled && publicApiKey) {
|
|
1019
1200
|
try {
|
|
@@ -1035,8 +1216,39 @@ please use an LLM adapter instead.`,
|
|
|
1035
1216
|
}
|
|
1036
1217
|
}
|
|
1037
1218
|
|
|
1038
|
-
//
|
|
1039
|
-
const structuredError =
|
|
1219
|
+
// Preserve structured CopilotKit errors, only convert unstructured errors
|
|
1220
|
+
const structuredError = ensureStructuredError(err, (error) =>
|
|
1221
|
+
this.convertStreamingErrorToStructured(error),
|
|
1222
|
+
);
|
|
1223
|
+
|
|
1224
|
+
// Track streaming errors
|
|
1225
|
+
await this.error(
|
|
1226
|
+
"error",
|
|
1227
|
+
{
|
|
1228
|
+
threadId,
|
|
1229
|
+
source: "agent",
|
|
1230
|
+
request: {
|
|
1231
|
+
operation: "processAgentRequest",
|
|
1232
|
+
method: "POST",
|
|
1233
|
+
startTime: requestStartTime,
|
|
1234
|
+
},
|
|
1235
|
+
response: {
|
|
1236
|
+
endTime: Date.now(),
|
|
1237
|
+
latency: Date.now() - requestStartTime,
|
|
1238
|
+
},
|
|
1239
|
+
agent: {
|
|
1240
|
+
name: agentName,
|
|
1241
|
+
nodeName: nodeName,
|
|
1242
|
+
},
|
|
1243
|
+
technical: {
|
|
1244
|
+
environment: process.env.NODE_ENV,
|
|
1245
|
+
stackTrace: err instanceof Error ? err.stack : undefined,
|
|
1246
|
+
},
|
|
1247
|
+
},
|
|
1248
|
+
structuredError,
|
|
1249
|
+
publicApiKey,
|
|
1250
|
+
);
|
|
1251
|
+
|
|
1040
1252
|
eventStream$.error(structuredError);
|
|
1041
1253
|
eventStream$.complete();
|
|
1042
1254
|
},
|
|
@@ -1114,8 +1326,41 @@ please use an LLM adapter instead.`,
|
|
|
1114
1326
|
}
|
|
1115
1327
|
}
|
|
1116
1328
|
|
|
1329
|
+
// Ensure error is structured
|
|
1330
|
+
const structuredError = ensureStructuredError(error, (err) =>
|
|
1331
|
+
this.convertStreamingErrorToStructured(err),
|
|
1332
|
+
);
|
|
1333
|
+
|
|
1334
|
+
// Track the agent error
|
|
1335
|
+
await this.error(
|
|
1336
|
+
"error",
|
|
1337
|
+
{
|
|
1338
|
+
threadId,
|
|
1339
|
+
source: "agent",
|
|
1340
|
+
request: {
|
|
1341
|
+
operation: "processAgentRequest",
|
|
1342
|
+
method: "POST",
|
|
1343
|
+
startTime: requestStartTime,
|
|
1344
|
+
},
|
|
1345
|
+
response: {
|
|
1346
|
+
endTime: Date.now(),
|
|
1347
|
+
latency: Date.now() - requestStartTime,
|
|
1348
|
+
},
|
|
1349
|
+
agent: {
|
|
1350
|
+
name: agentName,
|
|
1351
|
+
nodeName: nodeName,
|
|
1352
|
+
},
|
|
1353
|
+
technical: {
|
|
1354
|
+
environment: process.env.NODE_ENV,
|
|
1355
|
+
stackTrace: error instanceof Error ? error.stack : undefined,
|
|
1356
|
+
},
|
|
1357
|
+
},
|
|
1358
|
+
structuredError,
|
|
1359
|
+
publicApiKey,
|
|
1360
|
+
);
|
|
1361
|
+
|
|
1117
1362
|
console.error("Error getting response:", error);
|
|
1118
|
-
throw
|
|
1363
|
+
throw structuredError;
|
|
1119
1364
|
}
|
|
1120
1365
|
}
|
|
1121
1366
|
|
|
@@ -1146,6 +1391,7 @@ please use an LLM adapter instead.`,
|
|
|
1146
1391
|
frontendUrl: url,
|
|
1147
1392
|
agents: this.agents,
|
|
1148
1393
|
metaEvents: request.metaEvents,
|
|
1394
|
+
nodeName: request.agentSession?.nodeName,
|
|
1149
1395
|
});
|
|
1150
1396
|
|
|
1151
1397
|
const configuredActions =
|
|
@@ -1231,53 +1477,108 @@ please use an LLM adapter instead.`,
|
|
|
1231
1477
|
}
|
|
1232
1478
|
|
|
1233
1479
|
private convertStreamingErrorToStructured(error: any): CopilotKitError {
|
|
1234
|
-
//
|
|
1235
|
-
|
|
1236
|
-
error?.message?.includes("terminated") ||
|
|
1237
|
-
error?.cause?.code === "UND_ERR_SOCKET" ||
|
|
1238
|
-
error?.message?.includes("other side closed") ||
|
|
1239
|
-
error?.code === "UND_ERR_SOCKET"
|
|
1240
|
-
) {
|
|
1241
|
-
return new CopilotKitError({
|
|
1242
|
-
message:
|
|
1243
|
-
"Connection to agent was unexpectedly terminated. This may be due to the agent service being restarted or network issues. Please try again.",
|
|
1244
|
-
code: CopilotKitErrorCode.NETWORK_ERROR,
|
|
1245
|
-
});
|
|
1246
|
-
}
|
|
1480
|
+
// Determine a more helpful error message based on context
|
|
1481
|
+
let helpfulMessage = generateHelpfulErrorMessage(error, "agent streaming connection");
|
|
1247
1482
|
|
|
1248
|
-
//
|
|
1483
|
+
// For network-related errors, use CopilotKitLowLevelError to preserve the original error
|
|
1249
1484
|
if (
|
|
1250
1485
|
error?.message?.includes("fetch failed") ||
|
|
1251
1486
|
error?.message?.includes("ECONNREFUSED") ||
|
|
1252
1487
|
error?.message?.includes("ENOTFOUND") ||
|
|
1253
|
-
error?.message?.includes("ETIMEDOUT")
|
|
1488
|
+
error?.message?.includes("ETIMEDOUT") ||
|
|
1489
|
+
error?.message?.includes("terminated") ||
|
|
1490
|
+
error?.cause?.code === "UND_ERR_SOCKET" ||
|
|
1491
|
+
error?.message?.includes("other side closed") ||
|
|
1492
|
+
error?.code === "UND_ERR_SOCKET"
|
|
1254
1493
|
) {
|
|
1255
1494
|
return new CopilotKitLowLevelError({
|
|
1256
1495
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
1257
1496
|
url: "agent streaming connection",
|
|
1258
|
-
message:
|
|
1259
|
-
"Network error occurred during agent streaming. Please check your connection and try again.",
|
|
1497
|
+
message: helpfulMessage,
|
|
1260
1498
|
});
|
|
1261
1499
|
}
|
|
1262
1500
|
|
|
1263
|
-
//
|
|
1264
|
-
if (
|
|
1265
|
-
error?.message?.includes("aborted") ||
|
|
1266
|
-
error?.message?.includes("canceled") ||
|
|
1267
|
-
error?.message?.includes("signal is aborted")
|
|
1268
|
-
) {
|
|
1269
|
-
return new CopilotKitError({
|
|
1270
|
-
message: "Agent request was cancelled",
|
|
1271
|
-
code: CopilotKitErrorCode.UNKNOWN,
|
|
1272
|
-
});
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
// Default: convert unknown streaming errors
|
|
1501
|
+
// For all other errors, preserve the raw error in a basic CopilotKitError
|
|
1276
1502
|
return new CopilotKitError({
|
|
1277
|
-
message:
|
|
1503
|
+
message: helpfulMessage,
|
|
1278
1504
|
code: CopilotKitErrorCode.UNKNOWN,
|
|
1279
1505
|
});
|
|
1280
1506
|
}
|
|
1507
|
+
|
|
1508
|
+
private async error(
|
|
1509
|
+
type: CopilotErrorEvent["type"],
|
|
1510
|
+
context: CopilotRequestContext,
|
|
1511
|
+
error?: any,
|
|
1512
|
+
publicApiKey?: string,
|
|
1513
|
+
): Promise<void> {
|
|
1514
|
+
if (!this.onError) return;
|
|
1515
|
+
|
|
1516
|
+
// Just check if publicApiKey is defined (regardless of validity)
|
|
1517
|
+
if (!publicApiKey) {
|
|
1518
|
+
if (!this.hasWarnedAboutError) {
|
|
1519
|
+
console.warn(
|
|
1520
|
+
"CopilotKit: onError handler provided but requires publicApiKey to be defined for error handling to work.",
|
|
1521
|
+
);
|
|
1522
|
+
this.hasWarnedAboutError = true;
|
|
1523
|
+
}
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
try {
|
|
1528
|
+
const errorEvent: CopilotErrorEvent = {
|
|
1529
|
+
type,
|
|
1530
|
+
timestamp: Date.now(),
|
|
1531
|
+
context,
|
|
1532
|
+
...(error && { error }),
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
await this.onError(errorEvent);
|
|
1536
|
+
} catch (errorHandlerError) {
|
|
1537
|
+
// Don't let error handler errors break the main flow
|
|
1538
|
+
console.error("Error in onError handler:", errorHandlerError);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* Public method to handle GraphQL validation errors
|
|
1544
|
+
* This allows the GraphQL resolver to send validation errors through the error system
|
|
1545
|
+
*/
|
|
1546
|
+
public async errorGraphQLError(
|
|
1547
|
+
error: { message: string; code: string; type: string },
|
|
1548
|
+
context: {
|
|
1549
|
+
operation: string;
|
|
1550
|
+
cloudConfigPresent: boolean;
|
|
1551
|
+
guardrailsEnabled: boolean;
|
|
1552
|
+
},
|
|
1553
|
+
): Promise<void> {
|
|
1554
|
+
if (!this.onError) return;
|
|
1555
|
+
|
|
1556
|
+
try {
|
|
1557
|
+
await this.onError({
|
|
1558
|
+
type: "error",
|
|
1559
|
+
timestamp: Date.now(),
|
|
1560
|
+
context: {
|
|
1561
|
+
source: "runtime",
|
|
1562
|
+
request: {
|
|
1563
|
+
operation: context.operation,
|
|
1564
|
+
startTime: Date.now(),
|
|
1565
|
+
},
|
|
1566
|
+
technical: {
|
|
1567
|
+
environment: process.env.NODE_ENV,
|
|
1568
|
+
},
|
|
1569
|
+
metadata: {
|
|
1570
|
+
errorType: "GraphQLValidationError",
|
|
1571
|
+
cloudConfigPresent: context.cloudConfigPresent,
|
|
1572
|
+
guardrailsEnabled: context.guardrailsEnabled,
|
|
1573
|
+
},
|
|
1574
|
+
},
|
|
1575
|
+
error,
|
|
1576
|
+
});
|
|
1577
|
+
} catch (errorHandlerError) {
|
|
1578
|
+
// Don't let error handler errors break the main flow
|
|
1579
|
+
console.error("Error in onError handler:", errorHandlerError);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1281
1582
|
}
|
|
1282
1583
|
|
|
1283
1584
|
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
|
}
|