@copilotkit/runtime 1.50.0-beta.1 → 1.50.0-beta.3
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 +6 -0
- package/dist/index.d.ts +76 -286
- package/dist/index.js +306 -281
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +299 -270
- package/dist/index.mjs.map +1 -1
- package/dist/langgraph.d.ts +284 -0
- package/dist/langgraph.js +211 -0
- package/dist/langgraph.js.map +1 -0
- package/dist/langgraph.mjs +206 -0
- package/dist/langgraph.mjs.map +1 -0
- package/dist/v2/index.d.ts +1 -0
- package/dist/v2/index.js +7 -0
- package/dist/v2/index.js.map +1 -1
- package/dist/v2/index.mjs +1 -0
- package/dist/v2/index.mjs.map +1 -1
- package/package.json +55 -17
- package/src/graphql/message-conversion/agui-to-gql.test.ts +2 -2
- package/src/graphql/message-conversion/gql-to-agui.test.ts +30 -28
- package/src/graphql/message-conversion/roundtrip-conversion.test.ts +8 -8
- package/src/langgraph.ts +1 -0
- package/src/lib/index.ts +41 -1
- package/src/lib/integrations/nextjs/app-router.ts +3 -1
- package/src/lib/integrations/node-http/index.ts +132 -11
- package/src/lib/integrations/shared.ts +2 -2
- package/src/lib/runtime/agent-integrations/{langgraph.agent.ts → langgraph/agent.ts} +5 -30
- package/src/lib/runtime/agent-integrations/langgraph/consts.ts +34 -0
- package/src/lib/runtime/agent-integrations/langgraph/index.ts +2 -0
- package/src/lib/runtime/copilot-runtime.ts +25 -46
- package/src/service-adapters/anthropic/anthropic-adapter.ts +16 -3
- package/src/service-adapters/bedrock/bedrock-adapter.ts +4 -1
- package/src/service-adapters/experimental/ollama/ollama-adapter.ts +2 -1
- package/src/service-adapters/google/google-genai-adapter.ts +9 -4
- package/src/service-adapters/groq/groq-adapter.ts +16 -3
- package/src/service-adapters/langchain/langchain-adapter.ts +5 -3
- package/src/service-adapters/langchain/langserve.ts +2 -1
- package/src/service-adapters/openai/openai-adapter.ts +17 -3
- package/src/service-adapters/openai/openai-assistant-adapter.ts +26 -11
- package/src/service-adapters/unify/unify-adapter.ts +3 -1
- package/src/v2/index.ts +1 -0
- package/tsup.config.ts +5 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, test, expect
|
|
1
|
+
import { describe, test, expect } from "@jest/globals";
|
|
2
2
|
import * as gql from "../types/converted/index";
|
|
3
3
|
import agui from "@copilotkit/shared";
|
|
4
4
|
import { aguiToGQL } from "./agui-to-gql";
|
|
@@ -131,7 +131,7 @@ describe("roundtrip message conversion", () => {
|
|
|
131
131
|
});
|
|
132
132
|
|
|
133
133
|
test("action execution with render function roundtrip", () => {
|
|
134
|
-
const mockRender =
|
|
134
|
+
const mockRender = jest.fn();
|
|
135
135
|
const aguiMsg: agui.Message = {
|
|
136
136
|
id: "assistant-1",
|
|
137
137
|
role: "assistant",
|
|
@@ -211,7 +211,7 @@ describe("roundtrip message conversion", () => {
|
|
|
211
211
|
});
|
|
212
212
|
|
|
213
213
|
test("wild card action roundtrip conversion", () => {
|
|
214
|
-
const mockRender =
|
|
214
|
+
const mockRender = jest.fn((props) => `Wildcard rendered: ${props.args.test}`);
|
|
215
215
|
const aguiMsg: agui.Message = {
|
|
216
216
|
id: "assistant-wildcard-1",
|
|
217
217
|
role: "assistant",
|
|
@@ -256,7 +256,7 @@ describe("roundtrip message conversion", () => {
|
|
|
256
256
|
});
|
|
257
257
|
|
|
258
258
|
test("wild card action with specific action priority roundtrip", () => {
|
|
259
|
-
const mockRender =
|
|
259
|
+
const mockRender = jest.fn((props) => `Specific action rendered: ${props.args.test}`);
|
|
260
260
|
const aguiMsg: agui.Message = {
|
|
261
261
|
id: "assistant-priority-1",
|
|
262
262
|
role: "assistant",
|
|
@@ -313,7 +313,7 @@ describe("roundtrip message conversion", () => {
|
|
|
313
313
|
const actions: Record<string, any> = {
|
|
314
314
|
"*": {
|
|
315
315
|
name: "*",
|
|
316
|
-
render:
|
|
316
|
+
render: jest.fn((props) => `GQL wildcard rendered: ${props.args.test}`),
|
|
317
317
|
},
|
|
318
318
|
};
|
|
319
319
|
|
|
@@ -379,7 +379,7 @@ describe("roundtrip message conversion", () => {
|
|
|
379
379
|
});
|
|
380
380
|
|
|
381
381
|
test("roundtrip conversion with action execution and result parsing", () => {
|
|
382
|
-
const mockRender =
|
|
382
|
+
const mockRender = jest.fn((props) => `Rendered: ${JSON.stringify(props.result)}`);
|
|
383
383
|
|
|
384
384
|
// Create action execution message
|
|
385
385
|
const actionExecMsg = new gql.ActionExecutionMessage({
|
|
@@ -439,7 +439,7 @@ describe("roundtrip message conversion", () => {
|
|
|
439
439
|
});
|
|
440
440
|
|
|
441
441
|
test("roundtrip conversion verifies correct property distribution for regular actions", () => {
|
|
442
|
-
const mockRender =
|
|
442
|
+
const mockRender = jest.fn((props) => `Regular action: ${JSON.stringify(props.args)}`);
|
|
443
443
|
|
|
444
444
|
const actionExecMsg = new gql.ActionExecutionMessage({
|
|
445
445
|
id: "regular-action-test",
|
|
@@ -481,7 +481,7 @@ describe("roundtrip message conversion", () => {
|
|
|
481
481
|
});
|
|
482
482
|
|
|
483
483
|
test("roundtrip conversion verifies correct property distribution for wildcard actions", () => {
|
|
484
|
-
const mockRender =
|
|
484
|
+
const mockRender = jest.fn(
|
|
485
485
|
(props) => `Wildcard action: ${props.name} with ${JSON.stringify(props.args)}`,
|
|
486
486
|
);
|
|
487
487
|
|
package/src/langgraph.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./lib/runtime/agent-integrations/langgraph";
|
package/src/lib/index.ts
CHANGED
|
@@ -8,4 +8,44 @@ export * from "./integrations";
|
|
|
8
8
|
export * from "./logger";
|
|
9
9
|
export * from "./runtime/copilot-runtime";
|
|
10
10
|
export * from "./runtime/mcp-tools-utils";
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
// The below re-exports "dummy" classes and types, to get a deprecation warning redirecting the users to import these from the correct, new route
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated LangGraphAgent import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
|
|
16
|
+
*/
|
|
17
|
+
export class LangGraphAgent {
|
|
18
|
+
constructor() {
|
|
19
|
+
throw new Error(
|
|
20
|
+
"LangGraphAgent import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead",
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated LangGraphHttpAgent import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
|
|
27
|
+
*/
|
|
28
|
+
export class LangGraphHttpAgent {
|
|
29
|
+
constructor() {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"LangGraphHttpAgent import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead",
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @deprecated TextMessageEvents import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
|
|
38
|
+
*/
|
|
39
|
+
export type TextMessageEvents = any;
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated ToolCallEvents import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
|
|
42
|
+
*/
|
|
43
|
+
export type ToolCallEvents = any;
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated CustomEventNames import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
|
|
46
|
+
*/
|
|
47
|
+
export type CustomEventNames = any;
|
|
48
|
+
/**
|
|
49
|
+
* @deprecated PredictStateTool import from @copilotkit/runtime is deprecated. Please import it from @copilotkit/runtime/langgraph instead
|
|
50
|
+
*/
|
|
51
|
+
export type PredictStateTool = any;
|
|
@@ -24,7 +24,9 @@ export function copilotRuntimeNextJSAppRouterEndpoint(options: CreateCopilotRunt
|
|
|
24
24
|
logger.debug("Creating NextJS App Router endpoint");
|
|
25
25
|
|
|
26
26
|
const serviceAdapter = options.serviceAdapter;
|
|
27
|
-
|
|
27
|
+
if (serviceAdapter) {
|
|
28
|
+
options.runtime.handleServiceAdapter(serviceAdapter);
|
|
29
|
+
}
|
|
28
30
|
|
|
29
31
|
const copilotRoute = createCopilotEndpointSingleRoute({
|
|
30
32
|
runtime: options.runtime.instance,
|
|
@@ -4,6 +4,8 @@ import { createCopilotEndpointSingleRoute } from "@copilotkitnext/runtime";
|
|
|
4
4
|
import { IncomingMessage, ServerResponse } from "http";
|
|
5
5
|
import { Readable } from "node:stream";
|
|
6
6
|
|
|
7
|
+
type IncomingWithBody = IncomingMessage & { body?: unknown; complete?: boolean };
|
|
8
|
+
|
|
7
9
|
export function readableStreamToNodeStream(webStream: ReadableStream): Readable {
|
|
8
10
|
const reader = webStream.getReader();
|
|
9
11
|
|
|
@@ -24,7 +26,10 @@ export function readableStreamToNodeStream(webStream: ReadableStream): Readable
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
function getFullUrl(req: IncomingMessage): string {
|
|
27
|
-
const
|
|
29
|
+
const expressPath =
|
|
30
|
+
(req as any).originalUrl ??
|
|
31
|
+
((req as any).baseUrl ? `${(req as any).baseUrl}${req.url ?? ""}` : undefined);
|
|
32
|
+
const path = expressPath || req.url || "/";
|
|
28
33
|
const host =
|
|
29
34
|
(req.headers["x-forwarded-host"] as string) || (req.headers.host as string) || "localhost";
|
|
30
35
|
const proto =
|
|
@@ -34,6 +39,61 @@ function getFullUrl(req: IncomingMessage): string {
|
|
|
34
39
|
return `${proto}://${host}${path}`;
|
|
35
40
|
}
|
|
36
41
|
|
|
42
|
+
function toHeaders(rawHeaders: IncomingMessage["headers"]): Headers {
|
|
43
|
+
const headers = new Headers();
|
|
44
|
+
|
|
45
|
+
for (const [key, value] of Object.entries(rawHeaders)) {
|
|
46
|
+
if (value === undefined) continue;
|
|
47
|
+
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
value.forEach((entry) => headers.append(key, entry));
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
headers.append(key, value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return headers;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isStreamConsumed(req: IncomingWithBody): boolean {
|
|
60
|
+
const readableState = (req as any)._readableState;
|
|
61
|
+
|
|
62
|
+
return Boolean(
|
|
63
|
+
req.readableEnded || req.complete || readableState?.ended || readableState?.endEmitted,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function synthesizeBodyFromParsedBody(
|
|
68
|
+
parsedBody: unknown,
|
|
69
|
+
headers: Headers,
|
|
70
|
+
): { body: BodyInit | null; contentType?: string } {
|
|
71
|
+
if (parsedBody === null || parsedBody === undefined) {
|
|
72
|
+
return { body: null };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (parsedBody instanceof Buffer || parsedBody instanceof Uint8Array) {
|
|
76
|
+
return { body: parsedBody };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (typeof parsedBody === "string") {
|
|
80
|
+
return { body: parsedBody, contentType: headers.get("content-type") ?? "text/plain" };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
body: JSON.stringify(parsedBody),
|
|
85
|
+
contentType: "application/json",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isDisturbedOrLockedError(error: unknown): boolean {
|
|
90
|
+
return (
|
|
91
|
+
error instanceof TypeError &&
|
|
92
|
+
typeof error.message === "string" &&
|
|
93
|
+
(error.message.includes("disturbed") || error.message.includes("locked"))
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
37
97
|
export function copilotRuntimeNodeHttpEndpoint(options: CreateCopilotRuntimeServerOptions) {
|
|
38
98
|
const commonConfig = getCommonConfig(options);
|
|
39
99
|
|
|
@@ -55,26 +115,87 @@ export function copilotRuntimeNodeHttpEndpoint(options: CreateCopilotRuntimeServ
|
|
|
55
115
|
logger.debug("Creating Node HTTP endpoint");
|
|
56
116
|
|
|
57
117
|
const serviceAdapter = options.serviceAdapter;
|
|
58
|
-
|
|
118
|
+
if (serviceAdapter) {
|
|
119
|
+
options.runtime.handleServiceAdapter(serviceAdapter);
|
|
120
|
+
}
|
|
59
121
|
|
|
60
122
|
const honoApp = createCopilotEndpointSingleRoute({
|
|
61
123
|
runtime: options.runtime.instance,
|
|
62
124
|
basePath: options.baseUrl ?? options.endpoint,
|
|
63
125
|
});
|
|
64
126
|
|
|
65
|
-
return async function handler(req:
|
|
127
|
+
return async function handler(req: IncomingWithBody, res: ServerResponse) {
|
|
66
128
|
const url = getFullUrl(req);
|
|
67
129
|
const hasBody = req.method !== "GET" && req.method !== "HEAD";
|
|
68
130
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
duplex: hasBody ? "half" : undefined,
|
|
75
|
-
} as any);
|
|
131
|
+
const baseHeaders = toHeaders(req.headers);
|
|
132
|
+
const parsedBody = req.body;
|
|
133
|
+
|
|
134
|
+
const streamConsumed = isStreamConsumed(req) || parsedBody !== undefined;
|
|
135
|
+
const canStream = hasBody && !streamConsumed;
|
|
76
136
|
|
|
77
|
-
|
|
137
|
+
let requestBody: BodyInit | null | undefined = undefined;
|
|
138
|
+
let useDuplex = false;
|
|
139
|
+
|
|
140
|
+
if (hasBody && canStream) {
|
|
141
|
+
requestBody = req as unknown as BodyInit;
|
|
142
|
+
useDuplex = true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (hasBody && streamConsumed) {
|
|
146
|
+
if (parsedBody !== undefined) {
|
|
147
|
+
const synthesized = synthesizeBodyFromParsedBody(parsedBody, baseHeaders);
|
|
148
|
+
requestBody = synthesized.body ?? undefined;
|
|
149
|
+
baseHeaders.delete("content-length");
|
|
150
|
+
|
|
151
|
+
if (synthesized.contentType) {
|
|
152
|
+
baseHeaders.set("content-type", synthesized.contentType);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
logger.debug("Request stream already consumed; using parsed req.body to rebuild request.");
|
|
156
|
+
} else {
|
|
157
|
+
logger.warn("Request stream consumed with no available body; sending empty payload.");
|
|
158
|
+
requestBody = undefined;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const buildRequest = (body: BodyInit | null | undefined, headers: Headers, duplex: boolean) =>
|
|
163
|
+
new Request(url, {
|
|
164
|
+
method: req.method,
|
|
165
|
+
headers,
|
|
166
|
+
body,
|
|
167
|
+
duplex: duplex ? "half" : undefined,
|
|
168
|
+
} as RequestInit);
|
|
169
|
+
|
|
170
|
+
let response: Response;
|
|
171
|
+
try {
|
|
172
|
+
response = await honoApp.fetch(buildRequest(requestBody, baseHeaders, useDuplex));
|
|
173
|
+
} catch (error) {
|
|
174
|
+
if (isDisturbedOrLockedError(error) && hasBody) {
|
|
175
|
+
logger.warn(
|
|
176
|
+
"Encountered disturbed/locked request body; rebuilding request using parsed body or empty payload.",
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const fallbackHeaders = new Headers(baseHeaders);
|
|
180
|
+
let fallbackBody: BodyInit | null | undefined;
|
|
181
|
+
|
|
182
|
+
if (parsedBody !== undefined) {
|
|
183
|
+
const synthesized = synthesizeBodyFromParsedBody(parsedBody, fallbackHeaders);
|
|
184
|
+
fallbackBody = synthesized.body ?? undefined;
|
|
185
|
+
fallbackHeaders.delete("content-length");
|
|
186
|
+
|
|
187
|
+
if (synthesized.contentType) {
|
|
188
|
+
fallbackHeaders.set("content-type", synthesized.contentType);
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
fallbackBody = undefined;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
response = await honoApp.fetch(buildRequest(fallbackBody, fallbackHeaders, false));
|
|
195
|
+
} else {
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
78
199
|
|
|
79
200
|
res.statusCode = response.status;
|
|
80
201
|
response.headers.forEach((value, key) => {
|
|
@@ -34,8 +34,8 @@ export type GraphQLContext = YogaInitialContext & {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export interface CreateCopilotRuntimeServerOptions {
|
|
37
|
-
runtime: CopilotRuntime
|
|
38
|
-
serviceAdapter
|
|
37
|
+
runtime: CopilotRuntime<any>;
|
|
38
|
+
serviceAdapter?: CopilotServiceAdapter;
|
|
39
39
|
endpoint: string;
|
|
40
40
|
baseUrl?: string;
|
|
41
41
|
cloud?: CopilotCloudOptions;
|
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
RunAgentInput,
|
|
3
|
-
EventType,
|
|
4
|
-
CustomEvent,
|
|
5
|
-
TextMessageStartEvent,
|
|
6
|
-
TextMessageContentEvent,
|
|
7
|
-
TextMessageEndEvent,
|
|
8
|
-
ToolCallStartEvent,
|
|
9
|
-
ToolCallArgsEvent,
|
|
10
|
-
ToolCallEndEvent,
|
|
11
|
-
} from "@ag-ui/client";
|
|
12
1
|
import { map } from "rxjs";
|
|
13
|
-
import { LangGraphEventTypes } from "
|
|
2
|
+
import { LangGraphEventTypes } from "../../../../agents/langgraph/events";
|
|
14
3
|
import { RawEvent } from "@ag-ui/core";
|
|
15
4
|
import {
|
|
16
5
|
LangGraphAgent as AGUILangGraphAgent,
|
|
@@ -31,25 +20,11 @@ interface CopilotKitStateEnrichment {
|
|
|
31
20
|
};
|
|
32
21
|
}
|
|
33
22
|
|
|
34
|
-
|
|
35
|
-
tool: string;
|
|
36
|
-
state_key: string;
|
|
37
|
-
tool_argument: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export type TextMessageEvents =
|
|
41
|
-
| TextMessageStartEvent
|
|
42
|
-
| TextMessageContentEvent
|
|
43
|
-
| TextMessageEndEvent;
|
|
23
|
+
import { RunAgentInput, EventType, CustomEvent } from "@ag-ui/client";
|
|
44
24
|
|
|
45
|
-
export
|
|
46
|
-
|
|
47
|
-
export
|
|
48
|
-
CopilotKitManuallyEmitMessage = "copilotkit_manually_emit_message",
|
|
49
|
-
CopilotKitManuallyEmitToolCall = "copilotkit_manually_emit_tool_call",
|
|
50
|
-
CopilotKitManuallyEmitIntermediateState = "copilotkit_manually_emit_intermediate_state",
|
|
51
|
-
CopilotKitExit = "copilotkit_exit",
|
|
52
|
-
}
|
|
25
|
+
// Import and re-export from separate file to maintain API compatibility
|
|
26
|
+
import { CustomEventNames, TextMessageEvents, ToolCallEvents, PredictStateTool } from "./consts";
|
|
27
|
+
export { CustomEventNames };
|
|
53
28
|
|
|
54
29
|
export class LangGraphAgent extends AGUILangGraphAgent {
|
|
55
30
|
constructor(config: LangGraphAgentConfig) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for LangGraph integration.
|
|
3
|
+
* This file is separate from langgraph.agent.ts to avoid pulling in @ag-ui/langgraph
|
|
4
|
+
* when only these constants are needed.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
TextMessageStartEvent,
|
|
9
|
+
TextMessageContentEvent,
|
|
10
|
+
TextMessageEndEvent,
|
|
11
|
+
ToolCallStartEvent,
|
|
12
|
+
ToolCallArgsEvent,
|
|
13
|
+
ToolCallEndEvent,
|
|
14
|
+
} from "@ag-ui/client";
|
|
15
|
+
|
|
16
|
+
export type TextMessageEvents =
|
|
17
|
+
| TextMessageStartEvent
|
|
18
|
+
| TextMessageContentEvent
|
|
19
|
+
| TextMessageEndEvent;
|
|
20
|
+
|
|
21
|
+
export type ToolCallEvents = ToolCallStartEvent | ToolCallArgsEvent | ToolCallEndEvent;
|
|
22
|
+
|
|
23
|
+
export enum CustomEventNames {
|
|
24
|
+
CopilotKitManuallyEmitMessage = "copilotkit_manually_emit_message",
|
|
25
|
+
CopilotKitManuallyEmitToolCall = "copilotkit_manually_emit_tool_call",
|
|
26
|
+
CopilotKitManuallyEmitIntermediateState = "copilotkit_manually_emit_intermediate_state",
|
|
27
|
+
CopilotKitExit = "copilotkit_exit",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface PredictStateTool {
|
|
31
|
+
tool: string;
|
|
32
|
+
state_key: string;
|
|
33
|
+
tool_argument: string;
|
|
34
|
+
}
|
|
@@ -34,10 +34,7 @@ import {
|
|
|
34
34
|
} from "@copilotkitnext/runtime";
|
|
35
35
|
|
|
36
36
|
import { MessageInput } from "../../graphql/inputs/message.input";
|
|
37
|
-
import { ActionInput } from "../../graphql/inputs/action.input";
|
|
38
|
-
import { RuntimeEventSource } from "../../service-adapters/events";
|
|
39
37
|
import { Message } from "../../graphql/types/converted";
|
|
40
|
-
import { ForwardedParametersInput } from "../../graphql/inputs/forwarded-parameters.input";
|
|
41
38
|
|
|
42
39
|
import {
|
|
43
40
|
EndpointType,
|
|
@@ -46,19 +43,7 @@ import {
|
|
|
46
43
|
LangGraphPlatformEndpoint,
|
|
47
44
|
} from "./types";
|
|
48
45
|
|
|
49
|
-
import {
|
|
50
|
-
import { AgentSessionInput } from "../../graphql/inputs/agent-session.input";
|
|
51
|
-
import { AgentStateInput } from "../../graphql/inputs/agent-state.input";
|
|
52
|
-
import { Agent } from "../../graphql/types/agents-response.type";
|
|
53
|
-
import { ExtensionsInput } from "../../graphql/inputs/extensions.input";
|
|
54
|
-
import { ExtensionsResponse } from "../../graphql/types/extensions-response.type";
|
|
55
|
-
import { MetaEventInput } from "../../graphql/inputs/meta-event.input";
|
|
56
|
-
import {
|
|
57
|
-
CopilotObservabilityConfig,
|
|
58
|
-
LLMRequestData,
|
|
59
|
-
LLMResponseData,
|
|
60
|
-
LLMErrorData,
|
|
61
|
-
} from "../observability";
|
|
46
|
+
import { CopilotObservabilityConfig, LLMRequestData, LLMResponseData } from "../observability";
|
|
62
47
|
import { AbstractAgent } from "@ag-ui/client";
|
|
63
48
|
|
|
64
49
|
// +++ MCP Imports +++
|
|
@@ -67,10 +52,7 @@ import {
|
|
|
67
52
|
MCPEndpointConfig,
|
|
68
53
|
MCPTool,
|
|
69
54
|
extractParametersFromSchema,
|
|
70
|
-
convertMCPToolsToActions,
|
|
71
|
-
generateMcpToolInstructions,
|
|
72
55
|
} from "./mcp-tools-utils";
|
|
73
|
-
import { LangGraphAgent } from "./agent-integrations/langgraph.agent";
|
|
74
56
|
import { BasicAgent, BasicAgentConfiguration } from "@copilotkitnext/agent";
|
|
75
57
|
// Define the function type alias here or import if defined elsewhere
|
|
76
58
|
type CreateMCPClientFunction = (config: MCPEndpointConfig) => Promise<MCPClient>;
|
|
@@ -312,8 +294,8 @@ interface CopilotRuntimeConstructorParams<T extends Parameter[] | [] = []>
|
|
|
312
294
|
/**
|
|
313
295
|
* Central runtime object passed to all request handlers.
|
|
314
296
|
*/
|
|
315
|
-
export class CopilotRuntime {
|
|
316
|
-
params?: CopilotRuntimeConstructorParams
|
|
297
|
+
export class CopilotRuntime<const T extends Parameter[] | [] = []> {
|
|
298
|
+
params?: CopilotRuntimeConstructorParams<T>;
|
|
317
299
|
private observability?: CopilotObservabilityConfig;
|
|
318
300
|
// Cache MCP tools per endpoint to avoid re-fetching repeatedly
|
|
319
301
|
private mcpToolsCache: Map<string, BasicAgentConfiguration["tools"]> = new Map();
|
|
@@ -321,11 +303,13 @@ export class CopilotRuntime {
|
|
|
321
303
|
private _instance: CopilotRuntimeVNext;
|
|
322
304
|
|
|
323
305
|
constructor(
|
|
324
|
-
params?: CopilotRuntimeConstructorParams & PartialBy<CopilotRuntimeOptions, "agents">,
|
|
306
|
+
params?: CopilotRuntimeConstructorParams<T> & PartialBy<CopilotRuntimeOptions, "agents">,
|
|
325
307
|
) {
|
|
326
308
|
const agents = params?.agents ?? {};
|
|
309
|
+
const endpointAgents = this.assignEndpointsToAgents(params?.remoteEndpoints ?? []);
|
|
310
|
+
|
|
327
311
|
this.runtimeArgs = {
|
|
328
|
-
agents: { ...
|
|
312
|
+
agents: { ...endpointAgents, ...agents },
|
|
329
313
|
runner: params?.runner ?? new InMemoryAgentRunnerVNext(),
|
|
330
314
|
// TODO: add support for transcriptionService from CopilotRuntimeOptionsVNext once it is ready
|
|
331
315
|
// transcriptionService: params?.transcriptionService,
|
|
@@ -345,28 +329,23 @@ export class CopilotRuntime {
|
|
|
345
329
|
return this._instance;
|
|
346
330
|
}
|
|
347
331
|
|
|
348
|
-
private assignEndpointsToAgents(
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const lgEndpoint = endpoint as LangGraphPlatformEndpoint;
|
|
353
|
-
lgEndpoint.agents.forEach((agent) => {
|
|
354
|
-
const graphId = agent.assistantId ?? agent.name;
|
|
355
|
-
lgAgents[graphId] = new LangGraphAgent({
|
|
356
|
-
deploymentUrl: lgEndpoint.deploymentUrl,
|
|
357
|
-
langsmithApiKey: lgEndpoint.langsmithApiKey,
|
|
358
|
-
graphId,
|
|
359
|
-
});
|
|
360
|
-
});
|
|
332
|
+
private assignEndpointsToAgents(
|
|
333
|
+
endpoints: CopilotRuntimeConstructorParams<T>["remoteEndpoints"],
|
|
334
|
+
): Record<string, AbstractAgent> {
|
|
335
|
+
let result: Record<string, AbstractAgent> = {};
|
|
361
336
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
337
|
+
if (
|
|
338
|
+
endpoints.some((endpoint) => resolveEndpointType(endpoint) == EndpointType.LangGraphPlatform)
|
|
339
|
+
) {
|
|
340
|
+
throw new CopilotKitMisuseError({
|
|
341
|
+
message:
|
|
342
|
+
"LangGraphPlatformEndpoint in remoteEndpoints is deprecated. " +
|
|
343
|
+
'Please use the "agents" option instead with LangGraphAgent from "@copilotkit/runtime/langgraph". ' +
|
|
344
|
+
'Example: agents: { myAgent: new LangGraphAgent({ deploymentUrl: "...", graphId: "..." }) }',
|
|
345
|
+
});
|
|
346
|
+
}
|
|
367
347
|
|
|
368
|
-
|
|
369
|
-
}, {});
|
|
348
|
+
return result;
|
|
370
349
|
}
|
|
371
350
|
|
|
372
351
|
handleServiceAdapter(serviceAdapter: CopilotServiceAdapter) {
|
|
@@ -393,7 +372,7 @@ export class CopilotRuntime {
|
|
|
393
372
|
});
|
|
394
373
|
}
|
|
395
374
|
|
|
396
|
-
if (this.params.actions
|
|
375
|
+
if (this.params.actions) {
|
|
397
376
|
const mcpTools = await this.getToolsFromMCP();
|
|
398
377
|
agentsList = this.assignToolsToAgents(agents, [
|
|
399
378
|
...this.getToolsFromActions(this.params.actions),
|
|
@@ -454,7 +433,7 @@ export class CopilotRuntime {
|
|
|
454
433
|
}
|
|
455
434
|
|
|
456
435
|
private createOnBeforeRequestHandler(
|
|
457
|
-
params?: CopilotRuntimeConstructorParams & PartialBy<CopilotRuntimeOptions, "agents">,
|
|
436
|
+
params?: CopilotRuntimeConstructorParams<T> & PartialBy<CopilotRuntimeOptions, "agents">,
|
|
458
437
|
) {
|
|
459
438
|
return async (hookParams: BeforeRequestMiddlewareFnParameters[0]) => {
|
|
460
439
|
// TODO: get public api key and run with expected data
|
|
@@ -492,7 +471,7 @@ export class CopilotRuntime {
|
|
|
492
471
|
}
|
|
493
472
|
|
|
494
473
|
private createOnAfterRequestHandler(
|
|
495
|
-
params?: CopilotRuntimeConstructorParams & PartialBy<CopilotRuntimeOptions, "agents">,
|
|
474
|
+
params?: CopilotRuntimeConstructorParams<T> & PartialBy<CopilotRuntimeOptions, "agents">,
|
|
496
475
|
) {
|
|
497
476
|
return async (hookParams: AfterRequestMiddlewareFnParameters[0]) => {
|
|
498
477
|
// TODO: get public api key and run with expected data
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* });
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
-
import Anthropic from "@anthropic-ai/sdk";
|
|
25
|
+
import type Anthropic from "@anthropic-ai/sdk";
|
|
26
26
|
import {
|
|
27
27
|
CopilotServiceAdapter,
|
|
28
28
|
CopilotRuntimeChatCompletionRequest,
|
|
@@ -84,13 +84,25 @@ export class AnthropicAdapter implements CopilotServiceAdapter {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
constructor(params?: AnthropicAdapterParams) {
|
|
87
|
-
|
|
87
|
+
if (params?.anthropic) {
|
|
88
|
+
this._anthropic = params.anthropic;
|
|
89
|
+
}
|
|
90
|
+
// If no instance provided, we'll lazy-load in ensureAnthropic()
|
|
88
91
|
if (params?.model) {
|
|
89
92
|
this.model = params.model;
|
|
90
93
|
}
|
|
91
94
|
this.promptCaching = params?.promptCaching || { enabled: false };
|
|
92
95
|
}
|
|
93
96
|
|
|
97
|
+
private ensureAnthropic(): Anthropic {
|
|
98
|
+
if (!this._anthropic) {
|
|
99
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
100
|
+
const Anthropic = require("@anthropic-ai/sdk").default;
|
|
101
|
+
this._anthropic = new Anthropic({});
|
|
102
|
+
}
|
|
103
|
+
return this._anthropic;
|
|
104
|
+
}
|
|
105
|
+
|
|
94
106
|
/**
|
|
95
107
|
* Adds cache control to system prompt
|
|
96
108
|
*/
|
|
@@ -306,7 +318,8 @@ export class AnthropicAdapter implements CopilotServiceAdapter {
|
|
|
306
318
|
stream: true,
|
|
307
319
|
};
|
|
308
320
|
|
|
309
|
-
const
|
|
321
|
+
const anthropic = this.ensureAnthropic();
|
|
322
|
+
const stream = await anthropic.messages.create(createParams);
|
|
310
323
|
|
|
311
324
|
eventSource.stream(async (eventStream$) => {
|
|
312
325
|
let mode: "function" | "message" | null = null;
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { ChatBedrockConverse } from "@langchain/aws";
|
|
23
22
|
import { LangChainAdapter } from "../langchain/langchain-adapter";
|
|
24
23
|
|
|
25
24
|
export interface BedrockAdapterParams {
|
|
@@ -52,6 +51,10 @@ export class BedrockAdapter extends LangChainAdapter {
|
|
|
52
51
|
constructor(options?: BedrockAdapterParams) {
|
|
53
52
|
super({
|
|
54
53
|
chainFn: async ({ messages, tools, threadId }) => {
|
|
54
|
+
// Lazy require for optional peer dependency
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
56
|
+
const { ChatBedrockConverse } = require("@langchain/aws");
|
|
57
|
+
|
|
55
58
|
this.model = options?.model ?? "amazon.nova-lite-v1:0";
|
|
56
59
|
const model = new ChatBedrockConverse({
|
|
57
60
|
model: this.model,
|
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
CopilotRuntimeChatCompletionRequest,
|
|
24
24
|
CopilotRuntimeChatCompletionResponse,
|
|
25
25
|
} from "../../service-adapter";
|
|
26
|
-
import { Ollama } from "@langchain/community/llms/ollama";
|
|
27
26
|
import { randomId, randomUUID } from "@copilotkit/shared";
|
|
28
27
|
|
|
29
28
|
const DEFAULT_MODEL = "llama3:latest";
|
|
@@ -53,6 +52,8 @@ export class ExperimentalOllamaAdapter implements CopilotServiceAdapter {
|
|
|
53
52
|
const { messages, actions, eventSource } = request;
|
|
54
53
|
// const messages = this.transformMessages(forwardedProps.messages);
|
|
55
54
|
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
56
|
+
const { Ollama } = require("@langchain/community/llms/ollama");
|
|
56
57
|
const ollama = new Ollama({
|
|
57
58
|
model: this.model,
|
|
58
59
|
});
|
|
@@ -14,9 +14,7 @@
|
|
|
14
14
|
* return new GoogleGenerativeAIAdapter({ model: "gemini-1.5-pro" });
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
import { ChatGoogle } from "@langchain/google-gauth";
|
|
18
17
|
import { LangChainAdapter } from "../langchain/langchain-adapter";
|
|
19
|
-
import { AIMessage } from "@langchain/core/messages";
|
|
20
18
|
|
|
21
19
|
interface GoogleGenerativeAIAdapterOptions {
|
|
22
20
|
/**
|
|
@@ -38,6 +36,12 @@ export class GoogleGenerativeAIAdapter extends LangChainAdapter {
|
|
|
38
36
|
constructor(options?: GoogleGenerativeAIAdapterOptions) {
|
|
39
37
|
super({
|
|
40
38
|
chainFn: async ({ messages, tools, threadId }) => {
|
|
39
|
+
// Lazy require for optional peer dependencies
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
41
|
+
const { ChatGoogle } = require("@langchain/google-gauth");
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
43
|
+
const { AIMessage } = require("@langchain/core/messages");
|
|
44
|
+
|
|
41
45
|
// Filter out empty assistant messages to prevent Gemini validation errors
|
|
42
46
|
// Gemini specifically rejects conversations containing AIMessages with empty content
|
|
43
47
|
const filteredMessages = messages.filter((message) => {
|
|
@@ -48,9 +52,10 @@ export class GoogleGenerativeAIAdapter extends LangChainAdapter {
|
|
|
48
52
|
|
|
49
53
|
// For AIMessages, only keep those with non-empty content
|
|
50
54
|
// Also keep AIMessages with tool_calls even if content is empty
|
|
55
|
+
const aiMsg = message as any;
|
|
51
56
|
return (
|
|
52
|
-
(
|
|
53
|
-
(
|
|
57
|
+
(aiMsg.content && String(aiMsg.content).trim().length > 0) ||
|
|
58
|
+
(aiMsg.tool_calls && aiMsg.tool_calls.length > 0)
|
|
54
59
|
);
|
|
55
60
|
});
|
|
56
61
|
|