Skip to content

Commit 415558a

Browse files
authored
Add useAgent e2e tests and remove withMessages (#59)
* add e2e test for useAgent/setState and remove `withMessages` * Update use-agent.e2e.test.tsx
1 parent 6a0f006 commit 415558a

File tree

5 files changed

+148
-34
lines changed

5 files changed

+148
-34
lines changed

apps/docs/reference/copilotkit-core.mdx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,6 @@ runAgent(params: CopilotKitCoreRunAgentParams): Promise<RunAgentResult>
314314
```typescript
315315
interface CopilotKitCoreRunAgentParams {
316316
agent: AbstractAgent; // The agent to execute
317-
withMessages?: Message[]; // Initial messages to send to the agent
318-
agentId?: string; // Override the agent's default identifier
319317
}
320318
```
321319

packages/core/src/__tests__/core-basic-functionality.test.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,29 +35,6 @@ describe("CopilotKitCore.runAgent - Basic Functionality", () => {
3535
expect(agent.runAgentCalls[0].forwardedProps).toEqual({});
3636
});
3737

38-
it("should pass withMessages to agent.addMessages", async () => {
39-
const initialMessages = [createMessage({ content: "Initial" })];
40-
const newMessages = [createAssistantMessage({ content: "Response" })];
41-
const agent = new MockAgent({ newMessages });
42-
copilotKitCore.addAgent__unsafe_dev_only({ id: "test", agent: agent as any });
43-
44-
await copilotKitCore.runAgent({ agent: agent as any, withMessages: initialMessages });
45-
46-
expect(agent.addMessages).toHaveBeenCalledWith(initialMessages);
47-
expect(agent.messages).toContain(initialMessages[0]);
48-
});
49-
50-
it("should work without withMessages parameter", async () => {
51-
const newMessages = [createAssistantMessage({ content: "Response" })];
52-
const agent = new MockAgent({ newMessages });
53-
copilotKitCore.addAgent__unsafe_dev_only({ id: "test", agent: agent as any });
54-
55-
const result = await copilotKitCore.runAgent({ agent: agent as any });
56-
57-
expect(result.newMessages).toEqual(newMessages);
58-
expect(agent.addMessages).not.toHaveBeenCalled();
59-
});
60-
6138
it("should forward properties to agent.runAgent", async () => {
6239
const properties = { apiKey: "test-key", model: "gpt-4" };
6340
copilotKitCore = new CopilotKitCore({ properties });

packages/core/src/__tests__/core-suggestions-e2e.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,9 +815,9 @@ describe("CopilotKitCore - Suggestions E2E", () => {
815815
};
816816

817817
// Simulate user submitting a new message which triggers runAgent (and should clear/abort suggestions immediately)
818+
consumerAgent.addMessages([createMessage({ content: "User follow-up" })]);
818819
await copilotKitCore.runAgent({
819820
agent: consumerAgent as any,
820-
withMessages: [createMessage({ content: "User follow-up" })],
821821
});
822822

823823
// The in-flight suggestion run should be aborted

packages/core/src/core/run-handler.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { FrontendTool } from "../types";
77

88
export interface CopilotKitCoreRunAgentParams {
99
agent: AbstractAgent;
10-
withMessages?: Message[];
1110
}
1211

1312
export interface CopilotKitCoreConnectAgentParams {
@@ -140,7 +139,7 @@ export class RunHandler {
140139
/**
141140
* Run an agent
142141
*/
143-
async runAgent({ agent, withMessages }: CopilotKitCoreRunAgentParams): Promise<RunAgentResult> {
142+
async runAgent({ agent }: CopilotKitCoreRunAgentParams): Promise<RunAgentResult> {
144143
// Agent ID is guaranteed to be set by validateAndAssignAgentId
145144
if (agent.agentId) {
146145
void (this.core as unknown as CopilotKitCoreFriendsAccess).suggestionEngine.clearSuggestions(agent.agentId);
@@ -150,9 +149,6 @@ export class RunHandler {
150149
agent.headers = { ...(this.core as unknown as CopilotKitCoreFriendsAccess).headers };
151150
}
152151

153-
if (withMessages) {
154-
agent.addMessages(withMessages);
155-
}
156152
try {
157153
const runAgentResult = await agent.runAgent(
158154
{
@@ -169,9 +165,6 @@ export class RunHandler {
169165
if (agent.agentId) {
170166
context.agentId = agent.agentId;
171167
}
172-
if (withMessages) {
173-
context.messageCount = withMessages.length;
174-
}
175168
await (this.core as unknown as CopilotKitCoreFriendsAccess).emitError({
176169
error: runError,
177170
code: CopilotKitCoreErrorCode.AGENT_RUN_FAILED,
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import React from "react";
2+
import { screen, fireEvent, waitFor } from "@testing-library/react";
3+
import { describe, it, expect } from "vitest";
4+
import { type BaseEvent, type RunAgentInput } from "@ag-ui/client";
5+
import { Observable } from "rxjs";
6+
import {
7+
MockStepwiseAgent,
8+
renderWithCopilotKit,
9+
runStartedEvent,
10+
runFinishedEvent,
11+
textChunkEvent,
12+
testId,
13+
} from "@/__tests__/utils/test-helpers";
14+
import { useAgent } from "../use-agent";
15+
import { useCopilotKit } from "@/providers/CopilotKitProvider";
16+
import { CopilotChat } from "@/components/chat/CopilotChat";
17+
18+
/**
19+
* Mock agent that captures RunAgentInput to verify state is passed correctly
20+
*/
21+
class StateCapturingMockAgent extends MockStepwiseAgent {
22+
public lastRunInput?: RunAgentInput;
23+
24+
run(input: RunAgentInput): Observable<BaseEvent> {
25+
this.lastRunInput = input;
26+
return super.run(input);
27+
}
28+
}
29+
30+
describe("useAgent e2e", () => {
31+
describe("setState passes state to agent run", () => {
32+
it("agent receives state set via setState when runAgent is called", async () => {
33+
const agent = new StateCapturingMockAgent();
34+
35+
/**
36+
* Test component that:
37+
* 1. Gets agent via useAgent()
38+
* 2. Gets copilotkit via useCopilotKit()
39+
* 3. Sets state on agent and calls runAgent
40+
*/
41+
function StateTestComponent() {
42+
const { agent: hookAgent } = useAgent();
43+
const { copilotkit } = useCopilotKit();
44+
45+
const handleSetStateAndRun = async () => {
46+
hookAgent.setState({ testKey: "testValue", counter: 42 });
47+
await copilotkit.runAgent({ agent: hookAgent });
48+
};
49+
50+
return (
51+
<button data-testid="trigger-btn" onClick={handleSetStateAndRun}>
52+
Set State and Run
53+
</button>
54+
);
55+
}
56+
57+
renderWithCopilotKit({
58+
agent,
59+
children: <StateTestComponent />,
60+
});
61+
62+
// Click the button to set state and trigger runAgent
63+
const triggerBtn = await screen.findByTestId("trigger-btn");
64+
fireEvent.click(triggerBtn);
65+
66+
// Wait for the agent's run method to be called
67+
await waitFor(() => {
68+
expect(agent.lastRunInput).toBeDefined();
69+
});
70+
71+
// Complete the agent run
72+
agent.emit(runStartedEvent());
73+
agent.emit(runFinishedEvent());
74+
agent.complete();
75+
76+
// Verify the state was passed to the agent
77+
expect(agent.lastRunInput?.state).toEqual({
78+
testKey: "testValue",
79+
counter: 42,
80+
});
81+
});
82+
});
83+
84+
describe("addMessage + runAgent displays in CopilotChat", () => {
85+
it("messages added via useAgent show up in CopilotChat", async () => {
86+
const agent = new MockStepwiseAgent();
87+
88+
/**
89+
* Test component that:
90+
* 1. Gets agent via useAgent()
91+
* 2. Gets copilotkit via useCopilotKit()
92+
* 3. Adds a user message and calls runAgent
93+
*/
94+
function MessageTestComponent() {
95+
const { agent: hookAgent } = useAgent();
96+
const { copilotkit } = useCopilotKit();
97+
98+
const handleAddMessageAndRun = async () => {
99+
hookAgent.addMessage({
100+
id: testId("user-msg"),
101+
role: "user",
102+
content: "Hello from useAgent!",
103+
});
104+
await copilotkit.runAgent({ agent: hookAgent });
105+
};
106+
107+
return (
108+
<div>
109+
<button data-testid="send-btn" onClick={handleAddMessageAndRun}>
110+
Send Message
111+
</button>
112+
<div style={{ height: 400 }}>
113+
<CopilotChat />
114+
</div>
115+
</div>
116+
);
117+
}
118+
119+
renderWithCopilotKit({
120+
agent,
121+
children: <MessageTestComponent />,
122+
});
123+
124+
// Click the button to add message and trigger runAgent
125+
const sendBtn = await screen.findByTestId("send-btn");
126+
fireEvent.click(sendBtn);
127+
128+
// User message should appear in the chat
129+
await waitFor(() => {
130+
expect(screen.getByText("Hello from useAgent!")).toBeDefined();
131+
});
132+
133+
// Simulate agent response
134+
const responseId = testId("assistant-msg");
135+
agent.emit(runStartedEvent());
136+
agent.emit(textChunkEvent(responseId, "Hello! I received your message."));
137+
agent.emit(runFinishedEvent());
138+
agent.complete();
139+
140+
// Assistant response should appear in the chat
141+
await waitFor(() => {
142+
expect(screen.getByText("Hello! I received your message.")).toBeDefined();
143+
});
144+
});
145+
});
146+
});

0 commit comments

Comments
 (0)