@copilotkit/runtime 1.8.14-next.3 → 1.8.14-next.5
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 +16 -0
- package/dist/{chunk-6P6VMQLZ.mjs → chunk-A6TYJF5H.mjs} +9 -5
- package/dist/chunk-A6TYJF5H.mjs.map +1 -0
- package/dist/{chunk-MVKCCH5U.mjs → chunk-GEZX4PJT.mjs} +16 -3
- package/dist/chunk-GEZX4PJT.mjs.map +1 -0
- package/dist/{chunk-T2RKWYXN.mjs → chunk-QNIEFAO6.mjs} +2 -2
- package/dist/{chunk-BMA7V5T7.mjs → chunk-XNS4UOAA.mjs} +2 -2
- package/dist/{chunk-C7XHY7LW.mjs → chunk-Y6MICBVG.mjs} +2 -2
- package/dist/index.js +24 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/lib/index.js +17 -6
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +5 -5
- package/dist/lib/integrations/index.js +1 -1
- package/dist/lib/integrations/index.js.map +1 -1
- package/dist/lib/integrations/index.mjs +5 -5
- package/dist/lib/integrations/nest/index.js +1 -1
- package/dist/lib/integrations/nest/index.js.map +1 -1
- package/dist/lib/integrations/nest/index.mjs +3 -3
- package/dist/lib/integrations/node-express/index.js +1 -1
- package/dist/lib/integrations/node-express/index.js.map +1 -1
- package/dist/lib/integrations/node-express/index.mjs +3 -3
- package/dist/lib/integrations/node-http/index.js +1 -1
- package/dist/lib/integrations/node-http/index.js.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +2 -2
- package/dist/service-adapters/index.js +15 -2
- package/dist/service-adapters/index.js.map +1 -1
- package/dist/service-adapters/index.mjs +1 -1
- package/package.json +2 -2
- package/src/lib/runtime/agui-action.ts +5 -2
- package/src/service-adapters/anthropic/anthropic-adapter.ts +14 -1
- package/src/service-adapters/google/google-genai-adapter.test.ts +104 -0
- package/src/service-adapters/google/google-genai-adapter.ts +19 -1
- package/dist/chunk-6P6VMQLZ.mjs.map +0 -1
- package/dist/chunk-MVKCCH5U.mjs.map +0 -1
- /package/dist/{chunk-T2RKWYXN.mjs.map → chunk-QNIEFAO6.mjs.map} +0 -0
- /package/dist/{chunk-BMA7V5T7.mjs.map → chunk-XNS4UOAA.mjs.map} +0 -0
- /package/dist/{chunk-C7XHY7LW.mjs.map → chunk-Y6MICBVG.mjs.map} +0 -0
|
@@ -67,10 +67,13 @@ export function constructAGUIRemoteAction({
|
|
|
67
67
|
};
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
+
const forwardedProps = metaEvents.length
|
|
71
|
+
? { command: { resume: metaEvents[0]?.response } }
|
|
72
|
+
: undefined;
|
|
73
|
+
|
|
70
74
|
return agent.legacy_to_be_removed_runAgentBridged({
|
|
71
75
|
tools,
|
|
72
|
-
|
|
73
|
-
resume: metaEvents[0]?.response,
|
|
76
|
+
forwardedProps,
|
|
74
77
|
}) as Observable<RuntimeEvent>;
|
|
75
78
|
},
|
|
76
79
|
};
|
|
@@ -121,7 +121,20 @@ export class AnthropicAdapter implements CopilotServiceAdapter {
|
|
|
121
121
|
// For non-tool-result messages, convert normally
|
|
122
122
|
return convertMessageToAnthropicMessage(message);
|
|
123
123
|
})
|
|
124
|
-
.filter(Boolean)
|
|
124
|
+
.filter(Boolean) // Remove nulls
|
|
125
|
+
.filter((msg) => {
|
|
126
|
+
// Filter out assistant messages with empty text content
|
|
127
|
+
if (msg.role === "assistant" && Array.isArray(msg.content)) {
|
|
128
|
+
const hasEmptyTextOnly =
|
|
129
|
+
msg.content.length === 1 &&
|
|
130
|
+
msg.content[0].type === "text" &&
|
|
131
|
+
(!(msg.content[0] as any).text || (msg.content[0] as any).text.trim() === "");
|
|
132
|
+
|
|
133
|
+
// Keep messages that have tool_use or non-empty text
|
|
134
|
+
return !hasEmptyTextOnly;
|
|
135
|
+
}
|
|
136
|
+
return true;
|
|
137
|
+
}) as Anthropic.Messages.MessageParam[];
|
|
125
138
|
|
|
126
139
|
// Apply token limits
|
|
127
140
|
const limitedMessages = limitMessagesToTokenCount(anthropicMessages, tools, model);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { GoogleGenerativeAIAdapter } from "./google-genai-adapter";
|
|
2
|
+
import { AIMessage, HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
3
|
+
|
|
4
|
+
// Mock ChatGoogle to capture what messages are passed to it
|
|
5
|
+
jest.mock("@langchain/google-gauth", () => ({
|
|
6
|
+
ChatGoogle: jest.fn().mockImplementation(() => ({
|
|
7
|
+
bindTools: jest.fn().mockReturnThis(),
|
|
8
|
+
stream: jest.fn().mockImplementation((messages) => {
|
|
9
|
+
// Return the messages so we can verify filtering
|
|
10
|
+
return Promise.resolve({ filteredMessages: messages });
|
|
11
|
+
}),
|
|
12
|
+
})),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
describe("GoogleGenerativeAIAdapter", () => {
|
|
16
|
+
it("should filter out empty AIMessages to prevent Gemini validation errors", async () => {
|
|
17
|
+
const adapter = new GoogleGenerativeAIAdapter();
|
|
18
|
+
|
|
19
|
+
// Create a mix of messages including an empty AIMessage (the problematic case)
|
|
20
|
+
const messages = [
|
|
21
|
+
new HumanMessage("Hello"),
|
|
22
|
+
new AIMessage(""), // This should be filtered out
|
|
23
|
+
new HumanMessage("How are you?"),
|
|
24
|
+
new AIMessage("I'm doing well!"), // This should be kept
|
|
25
|
+
new SystemMessage("You are a helpful assistant"), // This should be kept
|
|
26
|
+
new AIMessage(""), // Another empty one to filter out
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
// Access the internal chainFn to test the filtering logic
|
|
30
|
+
const chainFnResult = await (adapter as any).options.chainFn({
|
|
31
|
+
messages,
|
|
32
|
+
tools: [],
|
|
33
|
+
threadId: "test-thread",
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// The result should be filtered messages passed to ChatGoogle.stream()
|
|
37
|
+
const { filteredMessages } = chainFnResult;
|
|
38
|
+
|
|
39
|
+
// Should only contain non-empty messages
|
|
40
|
+
expect(filteredMessages).toHaveLength(4);
|
|
41
|
+
expect(filteredMessages[0]).toBeInstanceOf(HumanMessage);
|
|
42
|
+
expect(filteredMessages[0].content).toBe("Hello");
|
|
43
|
+
expect(filteredMessages[1]).toBeInstanceOf(HumanMessage);
|
|
44
|
+
expect(filteredMessages[1].content).toBe("How are you?");
|
|
45
|
+
expect(filteredMessages[2]).toBeInstanceOf(AIMessage);
|
|
46
|
+
expect(filteredMessages[2].content).toBe("I'm doing well!");
|
|
47
|
+
expect(filteredMessages[3]).toBeInstanceOf(SystemMessage);
|
|
48
|
+
expect(filteredMessages[3].content).toBe("You are a helpful assistant");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should keep AIMessages with tool_calls even if content is empty", async () => {
|
|
52
|
+
const adapter = new GoogleGenerativeAIAdapter();
|
|
53
|
+
|
|
54
|
+
const messagesWithToolCalls = [
|
|
55
|
+
new HumanMessage("Execute a function"),
|
|
56
|
+
new AIMessage({
|
|
57
|
+
content: "", // Empty content but has tool calls
|
|
58
|
+
tool_calls: [
|
|
59
|
+
{
|
|
60
|
+
id: "call_123",
|
|
61
|
+
name: "test_function",
|
|
62
|
+
args: { param: "value" },
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
}),
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const chainFnResult = await (adapter as any).options.chainFn({
|
|
69
|
+
messages: messagesWithToolCalls,
|
|
70
|
+
tools: [],
|
|
71
|
+
threadId: "test-thread",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const { filteredMessages } = chainFnResult;
|
|
75
|
+
|
|
76
|
+
// Should keep both messages - the AIMessage has tool_calls so it's valid
|
|
77
|
+
expect(filteredMessages).toHaveLength(2);
|
|
78
|
+
expect(filteredMessages[1]).toBeInstanceOf(AIMessage);
|
|
79
|
+
expect(filteredMessages[1].tool_calls).toHaveLength(1);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should keep all non-AIMessage types regardless of content", async () => {
|
|
83
|
+
const adapter = new GoogleGenerativeAIAdapter();
|
|
84
|
+
|
|
85
|
+
const messages = [
|
|
86
|
+
new HumanMessage(""), // Empty human message should be kept
|
|
87
|
+
new SystemMessage(""), // Empty system message should be kept
|
|
88
|
+
new AIMessage(""), // Empty AI message should be filtered
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const chainFnResult = await (adapter as any).options.chainFn({
|
|
92
|
+
messages,
|
|
93
|
+
tools: [],
|
|
94
|
+
threadId: "test-thread",
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const { filteredMessages } = chainFnResult;
|
|
98
|
+
|
|
99
|
+
// Should keep HumanMessage and SystemMessage, filter out empty AIMessage
|
|
100
|
+
expect(filteredMessages).toHaveLength(2);
|
|
101
|
+
expect(filteredMessages[0]).toBeInstanceOf(HumanMessage);
|
|
102
|
+
expect(filteredMessages[1]).toBeInstanceOf(SystemMessage);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { ChatGoogle } from "@langchain/google-gauth";
|
|
18
18
|
import { LangChainAdapter } from "../langchain/langchain-adapter";
|
|
19
|
+
import { AIMessage } from "@langchain/core/messages";
|
|
19
20
|
|
|
20
21
|
interface GoogleGenerativeAIAdapterOptions {
|
|
21
22
|
/**
|
|
@@ -28,11 +29,28 @@ export class GoogleGenerativeAIAdapter extends LangChainAdapter {
|
|
|
28
29
|
constructor(options?: GoogleGenerativeAIAdapterOptions) {
|
|
29
30
|
super({
|
|
30
31
|
chainFn: async ({ messages, tools, threadId }) => {
|
|
32
|
+
// Filter out empty assistant messages to prevent Gemini validation errors
|
|
33
|
+
// Gemini specifically rejects conversations containing AIMessages with empty content
|
|
34
|
+
const filteredMessages = messages.filter((message) => {
|
|
35
|
+
// Keep all non-AI messages (HumanMessage, SystemMessage, ToolMessage, etc.)
|
|
36
|
+
if (!(message instanceof AIMessage)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// For AIMessages, only keep those with non-empty content
|
|
41
|
+
// Also keep AIMessages with tool_calls even if content is empty
|
|
42
|
+
return (
|
|
43
|
+
(message.content && String(message.content).trim().length > 0) ||
|
|
44
|
+
(message.tool_calls && message.tool_calls.length > 0)
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
31
48
|
const model = new ChatGoogle({
|
|
32
49
|
modelName: options?.model ?? "gemini-1.5-pro",
|
|
33
50
|
apiVersion: "v1beta",
|
|
34
51
|
}).bindTools(tools);
|
|
35
|
-
|
|
52
|
+
|
|
53
|
+
return model.stream(filteredMessages, { metadata: { conversation_id: threadId } });
|
|
36
54
|
},
|
|
37
55
|
});
|
|
38
56
|
}
|