@copilotkit/runtime 1.6.0 → 1.7.0-next.1
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 +28 -0
- package/README.md +75 -0
- package/dist/{chunk-WUMAYJP3.mjs → chunk-D6YNY2XB.mjs} +2 -2
- package/dist/chunk-PTC5JN3P.mjs +1 -0
- package/dist/{chunk-DUW72ZZB.mjs → chunk-QTRO3GPV.mjs} +206 -70
- package/dist/chunk-QTRO3GPV.mjs.map +1 -0
- package/dist/{chunk-MPI4JZZR.mjs → chunk-QZ6X33MR.mjs} +2 -2
- package/dist/{chunk-2RP2NR4F.mjs → chunk-RQS3BGAT.mjs} +2 -2
- package/dist/{copilot-runtime-15bfc4f4.d.ts → copilot-runtime-5103c7e7.d.ts} +66 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +206 -69
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -5
- package/dist/index.mjs.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +206 -69
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +7 -5
- package/dist/lib/integrations/index.d.ts +2 -2
- package/dist/lib/integrations/index.js +4 -1
- package/dist/lib/integrations/index.js.map +1 -1
- package/dist/lib/integrations/index.mjs +4 -4
- package/dist/lib/integrations/nest/index.d.ts +1 -1
- package/dist/lib/integrations/nest/index.js +4 -1
- package/dist/lib/integrations/nest/index.js.map +1 -1
- package/dist/lib/integrations/nest/index.mjs +2 -2
- package/dist/lib/integrations/node-express/index.d.ts +1 -1
- package/dist/lib/integrations/node-express/index.js +4 -1
- package/dist/lib/integrations/node-express/index.js.map +1 -1
- package/dist/lib/integrations/node-express/index.mjs +2 -2
- package/dist/lib/integrations/node-http/index.d.ts +1 -1
- package/dist/lib/integrations/node-http/index.js +4 -1
- package/dist/lib/integrations/node-http/index.js.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +1 -1
- package/package.json +2 -2
- package/src/graphql/resolvers/copilot.resolver.ts +4 -0
- package/src/lib/index.ts +1 -0
- package/src/lib/logger.ts +48 -0
- package/src/lib/runtime/__tests__/remote-action-constructors.test.ts +45 -35
- package/src/lib/runtime/copilot-runtime.ts +176 -16
- package/src/lib/runtime/remote-action-constructors.ts +28 -68
- package/src/lib/runtime/remote-actions.ts +5 -5
- package/src/lib/streaming.ts +59 -0
- package/src/service-adapters/events.ts +3 -3
- package/dist/chunk-DFOKBSIS.mjs +0 -1
- package/dist/chunk-DUW72ZZB.mjs.map +0 -1
- /package/dist/{chunk-WUMAYJP3.mjs.map → chunk-D6YNY2XB.mjs.map} +0 -0
- /package/dist/{chunk-DFOKBSIS.mjs.map → chunk-PTC5JN3P.mjs.map} +0 -0
- /package/dist/{chunk-MPI4JZZR.mjs.map → chunk-QZ6X33MR.mjs.map} +0 -0
- /package/dist/{chunk-2RP2NR4F.mjs.map → chunk-RQS3BGAT.mjs.map} +0 -0
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
|
-
"version": "1.
|
|
12
|
+
"version": "1.7.0-next.1",
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"main": "./dist/index.js",
|
|
15
15
|
"module": "./dist/index.mjs",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"rxjs": "^7.8.1",
|
|
60
60
|
"type-graphql": "2.0.0-rc.1",
|
|
61
61
|
"zod": "^3.23.3",
|
|
62
|
-
"@copilotkit/shared": "1.
|
|
62
|
+
"@copilotkit/shared": "1.7.0-next.1"
|
|
63
63
|
},
|
|
64
64
|
"keywords": [
|
|
65
65
|
"copilotkit",
|
|
@@ -196,6 +196,10 @@ export class CopilotResolver {
|
|
|
196
196
|
rejectOutputMessagesPromise = reject;
|
|
197
197
|
});
|
|
198
198
|
|
|
199
|
+
if (copilotCloudPublicApiKey) {
|
|
200
|
+
ctx.properties["copilotCloudPublicApiKey"] = copilotCloudPublicApiKey;
|
|
201
|
+
}
|
|
202
|
+
|
|
199
203
|
logger.debug("Processing");
|
|
200
204
|
const {
|
|
201
205
|
eventSource,
|
package/src/lib/index.ts
CHANGED
package/src/lib/logger.ts
CHANGED
|
@@ -26,3 +26,51 @@ export function createLogger(options?: { level?: LogLevel; component?: string })
|
|
|
26
26
|
return logger;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
// LangFuse Logging Integration
|
|
31
|
+
export interface LogLLMRequestData {
|
|
32
|
+
threadId?: string;
|
|
33
|
+
runId?: string;
|
|
34
|
+
model?: string;
|
|
35
|
+
messages: any[];
|
|
36
|
+
actions?: any[];
|
|
37
|
+
forwardedParameters?: any;
|
|
38
|
+
timestamp: number;
|
|
39
|
+
provider?: string;
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface LogLLMResponseData {
|
|
44
|
+
threadId: string;
|
|
45
|
+
runId?: string;
|
|
46
|
+
model?: string;
|
|
47
|
+
output: any;
|
|
48
|
+
latency: number;
|
|
49
|
+
timestamp: number;
|
|
50
|
+
provider?: string;
|
|
51
|
+
isProgressiveChunk?: boolean;
|
|
52
|
+
isFinalResponse?: boolean;
|
|
53
|
+
[key: string]: any;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface LogLLMErrorData {
|
|
57
|
+
threadId?: string;
|
|
58
|
+
runId?: string;
|
|
59
|
+
model?: string;
|
|
60
|
+
error: Error | string;
|
|
61
|
+
timestamp: number;
|
|
62
|
+
provider?: string;
|
|
63
|
+
[key: string]: any;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface CopilotLoggerHooks {
|
|
67
|
+
logRequest: (data: LogLLMRequestData) => void | Promise<void>;
|
|
68
|
+
logResponse: (data: LogLLMResponseData) => void | Promise<void>;
|
|
69
|
+
logError: (data: LogLLMErrorData) => void | Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface CopilotLoggingConfig {
|
|
73
|
+
enabled: boolean;
|
|
74
|
+
progressive: boolean;
|
|
75
|
+
logger: CopilotLoggerHooks;
|
|
76
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
1
2
|
import { TextEncoder } from "util";
|
|
2
3
|
import { RemoteLangGraphEventSource } from "../../../agents/langgraph/event-source";
|
|
3
4
|
import telemetry from "../../telemetry-client";
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
createHeaders,
|
|
8
9
|
} from "../remote-action-constructors";
|
|
9
10
|
import { execute } from "../remote-lg-action";
|
|
11
|
+
import { ReplaySubject } from "rxjs";
|
|
10
12
|
|
|
11
13
|
// Mock external dependencies
|
|
12
14
|
jest.mock("../remote-lg-action", () => ({
|
|
@@ -49,7 +51,7 @@ beforeEach(() => {
|
|
|
49
51
|
|
|
50
52
|
describe("remote action constructors", () => {
|
|
51
53
|
describe("constructLGCRemoteAction", () => {
|
|
52
|
-
it("should create an agent with
|
|
54
|
+
it("should create an agent with remoteAgentHandler that processes events", async () => {
|
|
53
55
|
// Arrange: simulate execute returning a dummy ReadableStream
|
|
54
56
|
const dummyEncodedEvent = new TextEncoder().encode(JSON.stringify({ event: "test" }) + "\n");
|
|
55
57
|
const readerMock = {
|
|
@@ -72,7 +74,7 @@ describe("remote action constructors", () => {
|
|
|
72
74
|
processLangGraphEvents: processLangGraphEventsMock,
|
|
73
75
|
}));
|
|
74
76
|
|
|
75
|
-
// Act: build the action and call
|
|
77
|
+
// Act: build the action and call remoteAgentHandler
|
|
76
78
|
const actions = constructLGCRemoteAction({
|
|
77
79
|
endpoint,
|
|
78
80
|
graphqlContext,
|
|
@@ -84,7 +86,7 @@ describe("remote action constructors", () => {
|
|
|
84
86
|
const action = actions[0];
|
|
85
87
|
expect(action.name).toEqual(dummyAgent.name);
|
|
86
88
|
|
|
87
|
-
const result = await action.
|
|
89
|
+
const result = await action.remoteAgentHandler({
|
|
88
90
|
name: dummyAgent.name,
|
|
89
91
|
actionInputsWithoutAgents: [],
|
|
90
92
|
threadId: "thread1",
|
|
@@ -160,26 +162,46 @@ describe("remote action constructors", () => {
|
|
|
160
162
|
});
|
|
161
163
|
|
|
162
164
|
it("should create remote agent handler that processes events", async () => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
165
|
+
const json = {
|
|
166
|
+
agents: [
|
|
167
|
+
{
|
|
168
|
+
name: "agent2",
|
|
169
|
+
description: "agent desc",
|
|
170
|
+
type: "langgraph", // Add type to match RemoteAgentType.LangGraph
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
actions: [
|
|
174
|
+
{
|
|
175
|
+
name: "action1",
|
|
176
|
+
description: "action desc",
|
|
177
|
+
parameters: { param: "value" },
|
|
178
|
+
},
|
|
179
|
+
],
|
|
173
180
|
};
|
|
174
|
-
global.fetch = jest.fn().mockResolvedValue({
|
|
175
|
-
ok: true,
|
|
176
|
-
text: jest.fn().mockResolvedValue("ok"),
|
|
177
|
-
body: dummyStreamResponse,
|
|
178
|
-
});
|
|
179
181
|
|
|
180
|
-
const
|
|
182
|
+
const dummyEncodedAgentEvent = new TextEncoder().encode('{"type":"data","content":"test"}\n');
|
|
183
|
+
|
|
184
|
+
const mockResponse = new Response(
|
|
185
|
+
new ReadableStream({
|
|
186
|
+
start(controller) {
|
|
187
|
+
controller.enqueue(dummyEncodedAgentEvent);
|
|
188
|
+
controller.close();
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
{
|
|
192
|
+
status: 200,
|
|
193
|
+
statusText: "OK",
|
|
194
|
+
headers: new Headers({
|
|
195
|
+
"content-type": "application/json",
|
|
196
|
+
}),
|
|
197
|
+
},
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
global.fetch = jest.fn().mockResolvedValue(mockResponse);
|
|
201
|
+
|
|
202
|
+
const processLangGraphEventsMock = jest.fn().mockResolvedValue("agent events processed");
|
|
181
203
|
(RemoteLangGraphEventSource as jest.Mock).mockImplementation(() => ({
|
|
182
|
-
eventStream$:
|
|
204
|
+
eventStream$: new ReplaySubject(),
|
|
183
205
|
processLangGraphEvents: processLangGraphEventsMock,
|
|
184
206
|
}));
|
|
185
207
|
|
|
@@ -192,29 +214,17 @@ describe("remote action constructors", () => {
|
|
|
192
214
|
messages: [],
|
|
193
215
|
agentStates,
|
|
194
216
|
});
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const remoteAgentHandler = (actionsArray[1] as any).langGraphAgentHandler;
|
|
217
|
+
|
|
218
|
+
const remoteAgentHandler = (actionsArray[1] as any).remoteAgentHandler;
|
|
198
219
|
const result = await remoteAgentHandler({
|
|
199
220
|
name: "agent2",
|
|
200
221
|
actionInputsWithoutAgents: [],
|
|
201
222
|
threadId: "thread2",
|
|
202
223
|
nodeName: "node2",
|
|
203
|
-
additionalMessages: [],
|
|
204
|
-
metaEvents: [],
|
|
205
224
|
});
|
|
225
|
+
|
|
206
226
|
expect(processLangGraphEventsMock).toHaveBeenCalled();
|
|
207
227
|
expect(result).toBe("agent events processed");
|
|
208
|
-
|
|
209
|
-
// Check telemetry.capture for agent execution
|
|
210
|
-
expect(telemetry.capture).toHaveBeenCalledWith(
|
|
211
|
-
"oss.runtime.remote_action_executed",
|
|
212
|
-
expect.objectContaining({
|
|
213
|
-
agentExecution: true,
|
|
214
|
-
type: "self-hosted",
|
|
215
|
-
agentsAmount: 1,
|
|
216
|
-
}),
|
|
217
|
-
);
|
|
218
228
|
});
|
|
219
229
|
});
|
|
220
230
|
|
|
@@ -33,14 +33,14 @@ import {
|
|
|
33
33
|
|
|
34
34
|
import { MessageInput } from "../../graphql/inputs/message.input";
|
|
35
35
|
import { ActionInput } from "../../graphql/inputs/action.input";
|
|
36
|
-
import { RuntimeEventSource } from "../../service-adapters/events";
|
|
36
|
+
import { RuntimeEventSource, RuntimeEventTypes } from "../../service-adapters/events";
|
|
37
37
|
import { convertGqlInputToMessages } from "../../service-adapters/conversion";
|
|
38
38
|
import { Message } from "../../graphql/types/converted";
|
|
39
39
|
import { ForwardedParametersInput } from "../../graphql/inputs/forwarded-parameters.input";
|
|
40
40
|
|
|
41
41
|
import {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
isRemoteAgentAction,
|
|
43
|
+
RemoteAgentAction,
|
|
44
44
|
EndpointType,
|
|
45
45
|
setupRemoteActions,
|
|
46
46
|
EndpointDefinition,
|
|
@@ -61,6 +61,12 @@ import { LoadAgentStateResponse } from "../../graphql/types/load-agent-state-res
|
|
|
61
61
|
import { Client as LangGraphClient } from "@langchain/langgraph-sdk";
|
|
62
62
|
import { langchainMessagesToCopilotKit } from "./remote-lg-action";
|
|
63
63
|
import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
|
|
64
|
+
import {
|
|
65
|
+
CopilotLoggingConfig,
|
|
66
|
+
LogLLMRequestData,
|
|
67
|
+
LogLLMResponseData,
|
|
68
|
+
LogLLMErrorData,
|
|
69
|
+
} from "../logger";
|
|
64
70
|
|
|
65
71
|
interface CopilotRuntimeRequest {
|
|
66
72
|
serviceAdapter: CopilotServiceAdapter;
|
|
@@ -179,6 +185,23 @@ export interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []
|
|
|
179
185
|
* Instead, all processing will be handled by the service adapter.
|
|
180
186
|
*/
|
|
181
187
|
delegateAgentProcessingToServiceAdapter?: boolean;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Configuration for LLM request/response logging
|
|
191
|
+
*
|
|
192
|
+
* ```ts
|
|
193
|
+
* logging: {
|
|
194
|
+
* enabled: true, // Enable or disable logging
|
|
195
|
+
* progressive: true, // Set to false for buffered logging
|
|
196
|
+
* logger: {
|
|
197
|
+
* logRequest: (data) => langfuse.trace({ name: "LLM Request", input: data }),
|
|
198
|
+
* logResponse: (data) => langfuse.trace({ name: "LLM Response", output: data }),
|
|
199
|
+
* logError: (errorData) => langfuse.trace({ name: "LLM Error", metadata: errorData }),
|
|
200
|
+
* },
|
|
201
|
+
* }
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
logging?: CopilotLoggingConfig;
|
|
182
205
|
}
|
|
183
206
|
|
|
184
207
|
export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
@@ -188,6 +211,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
188
211
|
private onBeforeRequest?: OnBeforeRequestHandler;
|
|
189
212
|
private onAfterRequest?: OnAfterRequestHandler;
|
|
190
213
|
private delegateAgentProcessingToServiceAdapter: boolean;
|
|
214
|
+
private logging?: CopilotLoggingConfig;
|
|
191
215
|
|
|
192
216
|
constructor(params?: CopilotRuntimeConstructorParams<T>) {
|
|
193
217
|
// Do not register actions if endpoints are set
|
|
@@ -209,6 +233,7 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
209
233
|
this.onAfterRequest = params?.middleware?.onAfterRequest;
|
|
210
234
|
this.delegateAgentProcessingToServiceAdapter =
|
|
211
235
|
params?.delegateAgentProcessingToServiceAdapter || false;
|
|
236
|
+
this.logging = params?.logging;
|
|
212
237
|
}
|
|
213
238
|
|
|
214
239
|
async processRuntimeRequest(request: CopilotRuntimeRequest): Promise<CopilotRuntimeResponse> {
|
|
@@ -228,6 +253,10 @@ export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
|
228
253
|
} = request;
|
|
229
254
|
|
|
230
255
|
const eventSource = new RuntimeEventSource();
|
|
256
|
+
// Track request start time for logging
|
|
257
|
+
const requestStartTime = Date.now();
|
|
258
|
+
// For storing streamed chunks if progressive logging is enabled
|
|
259
|
+
const streamedChunks: any[] = [];
|
|
231
260
|
|
|
232
261
|
try {
|
|
233
262
|
if (agentSession && !this.delegateAgentProcessingToServiceAdapter) {
|
|
@@ -245,6 +274,26 @@ please use an LLM adapter instead.`,
|
|
|
245
274
|
const inputMessages = convertGqlInputToMessages(messages);
|
|
246
275
|
const serverSideActions = await this.getServerSideActions(request);
|
|
247
276
|
|
|
277
|
+
// Log LLM request if logging is enabled
|
|
278
|
+
if (this.logging?.enabled) {
|
|
279
|
+
try {
|
|
280
|
+
const requestData: LogLLMRequestData = {
|
|
281
|
+
threadId,
|
|
282
|
+
runId,
|
|
283
|
+
model: forwardedParameters?.model,
|
|
284
|
+
messages: inputMessages,
|
|
285
|
+
actions: clientSideActionsInput,
|
|
286
|
+
forwardedParameters,
|
|
287
|
+
timestamp: requestStartTime,
|
|
288
|
+
provider: this.detectProvider(serviceAdapter),
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
await this.logging.logger.logRequest(requestData);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error("Error logging LLM request:", error);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
248
297
|
const serverSideActionsInput: ActionInput[] = serverSideActions.map((action) => ({
|
|
249
298
|
name: action.name,
|
|
250
299
|
description: action.description,
|
|
@@ -296,6 +345,88 @@ please use an LLM adapter instead.`,
|
|
|
296
345
|
})
|
|
297
346
|
.catch((_error) => {});
|
|
298
347
|
|
|
348
|
+
// After getting the response, log it if logging is enabled
|
|
349
|
+
if (this.logging?.enabled) {
|
|
350
|
+
try {
|
|
351
|
+
outputMessagesPromise
|
|
352
|
+
.then((outputMessages) => {
|
|
353
|
+
const responseData: LogLLMResponseData = {
|
|
354
|
+
threadId: result.threadId,
|
|
355
|
+
runId: result.runId,
|
|
356
|
+
model: forwardedParameters?.model,
|
|
357
|
+
// Use collected chunks for progressive mode or outputMessages for regular mode
|
|
358
|
+
output: this.logging.progressive ? streamedChunks : outputMessages,
|
|
359
|
+
latency: Date.now() - requestStartTime,
|
|
360
|
+
timestamp: Date.now(),
|
|
361
|
+
provider: this.detectProvider(serviceAdapter),
|
|
362
|
+
// Indicate this is the final response
|
|
363
|
+
isFinalResponse: true,
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
this.logging?.logger.logResponse(responseData);
|
|
368
|
+
} catch (logError) {
|
|
369
|
+
console.error("Error logging LLM response:", logError);
|
|
370
|
+
}
|
|
371
|
+
})
|
|
372
|
+
.catch((error) => {
|
|
373
|
+
console.error("Failed to get output messages for logging:", error);
|
|
374
|
+
});
|
|
375
|
+
} catch (error) {
|
|
376
|
+
console.error("Error setting up logging for LLM response:", error);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Add progressive logging if enabled
|
|
381
|
+
if (this.logging?.enabled && this.logging.progressive) {
|
|
382
|
+
// Keep reference to original stream function
|
|
383
|
+
const originalStream = eventSource.stream.bind(eventSource);
|
|
384
|
+
|
|
385
|
+
// Wrap the stream function to intercept events
|
|
386
|
+
eventSource.stream = async (callback) => {
|
|
387
|
+
await originalStream(async (eventStream$) => {
|
|
388
|
+
// Create subscription to capture streaming events
|
|
389
|
+
eventStream$.subscribe({
|
|
390
|
+
next: (event) => {
|
|
391
|
+
// Only log content chunks
|
|
392
|
+
if (event.type === RuntimeEventTypes.TextMessageContent) {
|
|
393
|
+
// Store the chunk
|
|
394
|
+
streamedChunks.push(event.content);
|
|
395
|
+
|
|
396
|
+
// Log each chunk separately for progressive mode
|
|
397
|
+
try {
|
|
398
|
+
const progressiveData: LogLLMResponseData = {
|
|
399
|
+
threadId: threadId || "",
|
|
400
|
+
runId,
|
|
401
|
+
model: forwardedParameters?.model,
|
|
402
|
+
output: event.content,
|
|
403
|
+
latency: Date.now() - requestStartTime,
|
|
404
|
+
timestamp: Date.now(),
|
|
405
|
+
provider: this.detectProvider(serviceAdapter),
|
|
406
|
+
isProgressiveChunk: true,
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
// Use Promise to handle async logger without awaiting
|
|
410
|
+
Promise.resolve()
|
|
411
|
+
.then(() => {
|
|
412
|
+
this.logging?.logger.logResponse(progressiveData);
|
|
413
|
+
})
|
|
414
|
+
.catch((error) => {
|
|
415
|
+
console.error("Error in progressive logging:", error);
|
|
416
|
+
});
|
|
417
|
+
} catch (error) {
|
|
418
|
+
console.error("Error preparing progressive log data:", error);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Call the original callback with the event stream
|
|
425
|
+
await callback(eventStream$);
|
|
426
|
+
});
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
299
430
|
return {
|
|
300
431
|
threadId: nonEmptyThreadId,
|
|
301
432
|
runId: result.runId,
|
|
@@ -305,13 +436,32 @@ please use an LLM adapter instead.`,
|
|
|
305
436
|
(action) =>
|
|
306
437
|
// TODO-AGENTS: do not exclude ALL server side actions
|
|
307
438
|
!serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
|
|
308
|
-
// !
|
|
439
|
+
// !isRemoteAgentAction(
|
|
309
440
|
// serverSideActions.find((serverSideAction) => serverSideAction.name == action.name),
|
|
310
441
|
// ),
|
|
311
442
|
),
|
|
312
443
|
extensions: result.extensions,
|
|
313
444
|
};
|
|
314
445
|
} catch (error) {
|
|
446
|
+
// Log error if logging is enabled
|
|
447
|
+
if (this.logging?.enabled) {
|
|
448
|
+
try {
|
|
449
|
+
const errorData: LogLLMErrorData = {
|
|
450
|
+
threadId,
|
|
451
|
+
runId,
|
|
452
|
+
model: forwardedParameters?.model,
|
|
453
|
+
error: error instanceof Error ? error : String(error),
|
|
454
|
+
timestamp: Date.now(),
|
|
455
|
+
latency: Date.now() - requestStartTime,
|
|
456
|
+
provider: this.detectProvider(serviceAdapter),
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
await this.logging.logger.logError(errorData);
|
|
460
|
+
} catch (logError) {
|
|
461
|
+
console.error("Error logging LLM error:", logError);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
315
465
|
if (error instanceof CopilotKitError) {
|
|
316
466
|
throw error;
|
|
317
467
|
}
|
|
@@ -322,7 +472,6 @@ please use an LLM adapter instead.`,
|
|
|
322
472
|
}
|
|
323
473
|
|
|
324
474
|
async discoverAgentsFromEndpoints(graphqlContext: GraphQLContext): Promise<AgentWithEndpoint[]> {
|
|
325
|
-
const headers = createHeaders(null, graphqlContext);
|
|
326
475
|
const agents = this.remoteEndpointDefinitions.reduce(
|
|
327
476
|
async (acc: Promise<Agent[]>, endpoint) => {
|
|
328
477
|
const agents = await acc;
|
|
@@ -355,12 +504,12 @@ please use an LLM adapter instead.`,
|
|
|
355
504
|
description: string;
|
|
356
505
|
}>;
|
|
357
506
|
}
|
|
358
|
-
|
|
359
|
-
const fetchUrl = `${
|
|
507
|
+
const cpkEndpoint = endpoint as CopilotKitEndpoint;
|
|
508
|
+
const fetchUrl = `${endpoint.url}/info`;
|
|
360
509
|
try {
|
|
361
510
|
const response = await fetch(fetchUrl, {
|
|
362
511
|
method: "POST",
|
|
363
|
-
headers,
|
|
512
|
+
headers: createHeaders(cpkEndpoint.onBeforeRequest, graphqlContext),
|
|
364
513
|
body: JSON.stringify({ properties: graphqlContext.properties }),
|
|
365
514
|
});
|
|
366
515
|
if (!response.ok) {
|
|
@@ -406,7 +555,6 @@ please use an LLM adapter instead.`,
|
|
|
406
555
|
if (!agentWithEndpoint) {
|
|
407
556
|
throw new Error("Agent not found");
|
|
408
557
|
}
|
|
409
|
-
const headers = createHeaders(null, graphqlContext);
|
|
410
558
|
|
|
411
559
|
if (agentWithEndpoint.endpoint.type === EndpointType.LangGraphPlatform) {
|
|
412
560
|
const propertyHeaders = graphqlContext.properties.authorization
|
|
@@ -444,11 +592,12 @@ please use an LLM adapter instead.`,
|
|
|
444
592
|
agentWithEndpoint.endpoint.type === EndpointType.CopilotKit ||
|
|
445
593
|
!("type" in agentWithEndpoint.endpoint)
|
|
446
594
|
) {
|
|
447
|
-
const
|
|
595
|
+
const cpkEndpoint = agentWithEndpoint.endpoint as CopilotKitEndpoint;
|
|
596
|
+
const fetchUrl = `${cpkEndpoint.url}/agents/state`;
|
|
448
597
|
try {
|
|
449
598
|
const response = await fetch(fetchUrl, {
|
|
450
599
|
method: "POST",
|
|
451
|
-
headers,
|
|
600
|
+
headers: createHeaders(cpkEndpoint.onBeforeRequest, graphqlContext),
|
|
452
601
|
body: JSON.stringify({
|
|
453
602
|
properties: graphqlContext.properties,
|
|
454
603
|
threadId,
|
|
@@ -505,8 +654,8 @@ please use an LLM adapter instead.`,
|
|
|
505
654
|
const messages = convertGqlInputToMessages(rawMessages);
|
|
506
655
|
|
|
507
656
|
const currentAgent = serverSideActions.find(
|
|
508
|
-
(action) => action.name === agentName &&
|
|
509
|
-
) as
|
|
657
|
+
(action) => action.name === agentName && isRemoteAgentAction(action),
|
|
658
|
+
) as RemoteAgentAction;
|
|
510
659
|
|
|
511
660
|
if (!currentAgent) {
|
|
512
661
|
throw new CopilotKitAgentDiscoveryError({ agentName });
|
|
@@ -519,9 +668,9 @@ please use an LLM adapter instead.`,
|
|
|
519
668
|
.filter(
|
|
520
669
|
(action) =>
|
|
521
670
|
// Case 1: Keep all regular (non-agent) actions
|
|
522
|
-
!
|
|
671
|
+
!isRemoteAgentAction(action) ||
|
|
523
672
|
// Case 2: For agent actions, keep all except self (prevent infinite loops)
|
|
524
|
-
(
|
|
673
|
+
(isRemoteAgentAction(action) && action.name !== agentName) /* prevent self-calls */,
|
|
525
674
|
)
|
|
526
675
|
.map((action) => ({
|
|
527
676
|
name: action.name,
|
|
@@ -542,7 +691,7 @@ please use an LLM adapter instead.`,
|
|
|
542
691
|
});
|
|
543
692
|
try {
|
|
544
693
|
const eventSource = new RuntimeEventSource();
|
|
545
|
-
const stream = await currentAgent.
|
|
694
|
+
const stream = await currentAgent.remoteAgentHandler({
|
|
546
695
|
name: agentName,
|
|
547
696
|
threadId,
|
|
548
697
|
nodeName,
|
|
@@ -624,6 +773,17 @@ please use an LLM adapter instead.`,
|
|
|
624
773
|
|
|
625
774
|
return [...configuredActions, ...langserveFunctions, ...remoteActions];
|
|
626
775
|
}
|
|
776
|
+
|
|
777
|
+
// Add helper method to detect provider
|
|
778
|
+
private detectProvider(serviceAdapter: CopilotServiceAdapter): string | undefined {
|
|
779
|
+
const adapterName = serviceAdapter.constructor.name;
|
|
780
|
+
if (adapterName.includes("OpenAI")) return "openai";
|
|
781
|
+
if (adapterName.includes("Anthropic")) return "anthropic";
|
|
782
|
+
if (adapterName.includes("Google")) return "google";
|
|
783
|
+
if (adapterName.includes("Groq")) return "groq";
|
|
784
|
+
if (adapterName.includes("LangChain")) return "langchain";
|
|
785
|
+
return undefined;
|
|
786
|
+
}
|
|
627
787
|
}
|
|
628
788
|
|
|
629
789
|
export function flattenToolCallsNoDuplicates(toolsByPriority: ActionInput[]): ActionInput[] {
|