Skip to content

Commit dbd232a

Browse files
committed
add test for MCP slash command
1 parent 1aa0b11 commit dbd232a

File tree

2 files changed

+316
-4
lines changed

2 files changed

+316
-4
lines changed

core/commands/slash/mcp.test.ts

+311
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
import { substituteLastUserMessage } from "./mcp";
2+
import { ChatMessage, MessagePart, SlashCommand, UserChatMessage } from "../../index.js";
3+
4+
/**
5+
* Test substitution of the prompt content into the history.
6+
* actual content collected from debugging actual chats.
7+
*/
8+
describe("substituteLastUserMessage", () => {
9+
const systemMessage: ChatMessage = {
10+
role: "system",
11+
content: "Your are..."
12+
};
13+
14+
const assistantEmptyMessage: ChatMessage = {
15+
role: "assistant",
16+
content: ""
17+
};
18+
19+
const mcpMessage: ChatMessage = {
20+
role: "user",
21+
content: [{ type: "text", text: "provide answer" }]
22+
};
23+
const mcpHeadMessage: ChatMessage = {
24+
role: "user",
25+
content: [{ type: "text", text: "this is important task" }]
26+
};
27+
const mcpAssistantMessage: ChatMessage = {
28+
role: "assistant",
29+
content: [{ type: "text", text: "I'm assistant" }]
30+
};
31+
32+
it("should handle only /echo on first question", () => {
33+
// Input: `/echo `
34+
const history: ChatMessage[] = [
35+
systemMessage,
36+
{
37+
role: "user",
38+
content: [{ type: "text", text: "/echo " }]
39+
},
40+
assistantEmptyMessage
41+
];
42+
43+
const expected: ChatMessage[] = [
44+
systemMessage,
45+
{
46+
role: "user",
47+
content: [{ type: "text", text: "provide answer" }, { type: "text", text: "" }]
48+
},
49+
assistantEmptyMessage
50+
];
51+
52+
const result = substituteLastUserMessage(history, "/echo ", [mcpMessage]);
53+
expect(result).toEqual(expected);
54+
});
55+
56+
it("should handle /echo with text on first question", () => {
57+
// Input: `/echo hello`
58+
const history: ChatMessage[] = [
59+
systemMessage,
60+
{
61+
role: "user",
62+
content: [{ type: "text", text: "/echo hello" }]
63+
},
64+
assistantEmptyMessage
65+
];
66+
67+
const expected: ChatMessage[] = [
68+
systemMessage,
69+
{
70+
role: "user",
71+
content: [{ type: "text", text: "provide answer" }, { type: "text", text: "hello" }]
72+
},
73+
assistantEmptyMessage
74+
];
75+
76+
const result = substituteLastUserMessage(history, "/echo ", [mcpMessage]);
77+
expect(result).toEqual(expected);
78+
});
79+
80+
it("should handle /echo with text and 1 context on first question", () => {
81+
// Input: `/echo explain text.ts code`
82+
const history: ChatMessage[] = [
83+
systemMessage,
84+
{
85+
role: "user",
86+
content: [
87+
{ type: "text", text: "text.ts code block" },
88+
{ type: "text", text: "/echo explain text.ts code" }
89+
]
90+
},
91+
assistantEmptyMessage
92+
];
93+
94+
const expected: ChatMessage[] = [
95+
systemMessage,
96+
{
97+
role: "user",
98+
content: [
99+
{ type: "text", text: "text.ts code block" },
100+
{ type: "text", text: "provide answer" },
101+
{ type: "text", text: "explain text.ts code" }
102+
]
103+
},
104+
assistantEmptyMessage
105+
];
106+
107+
const result = substituteLastUserMessage(history, "/echo ", [mcpMessage]);
108+
expect(result).toEqual(expected);
109+
});
110+
111+
it("should handle /echo with text and 2 contexts on first question", () => {
112+
// Input: `/echo explain test.ts and test.py`
113+
const history: ChatMessage[] = [
114+
systemMessage,
115+
{
116+
role: "user",
117+
content: [
118+
{ type: "text", text: "text.ts code block" },
119+
{ type: "text", text: "text.py code block" },
120+
{ type: "text", text: "/echo explain test.ts and test.py " }
121+
]
122+
},
123+
assistantEmptyMessage
124+
];
125+
126+
const expected: ChatMessage[] = [
127+
systemMessage,
128+
{
129+
role: "user",
130+
content: [
131+
{ type: "text", text: "text.ts code block" },
132+
{ type: "text", text: "text.py code block" },
133+
{ type: "text", text: "provide answer" },
134+
{ type: "text", text: "explain test.ts and test.py " }
135+
]
136+
},
137+
assistantEmptyMessage
138+
];
139+
140+
const result = substituteLastUserMessage(history, "/echo ", [mcpMessage]);
141+
expect(result).toEqual(expected);
142+
});
143+
144+
it("should handle /echo with text and image on first question", () => {
145+
// Input: `/echo explain`
146+
const history: ChatMessage[] = [
147+
systemMessage,
148+
{
149+
role: "user",
150+
content: [
151+
{ type: "imageUrl", imageUrl:{ url: "data:..."} },
152+
{ type: "text", text: "/echo explain" }
153+
]
154+
},
155+
assistantEmptyMessage
156+
];
157+
158+
const expected: ChatMessage[] = [
159+
systemMessage,
160+
{
161+
role: "user",
162+
content: [
163+
{ type: "imageUrl", imageUrl:{ url: "data:..."} },
164+
{ type: "text", text: "provide answer" },
165+
{ type: "text", text: "explain" }
166+
]
167+
},
168+
assistantEmptyMessage
169+
];
170+
171+
const result = substituteLastUserMessage(history, "/echo ", [mcpMessage]);
172+
expect(result).toEqual(expected);
173+
});
174+
175+
it("should handle /echo with text, image, and context on first question", () => {
176+
// Input: `/echo explain test.ts`
177+
const history: ChatMessage[] = [
178+
systemMessage,
179+
{
180+
role: "user",
181+
content: [
182+
{ type: "text", text: "text.ts code block" },
183+
{ type: "imageUrl", imageUrl:{ url: "data:..."} },
184+
{ type: "text", text: "/echo explain test.ts" }
185+
]
186+
},
187+
assistantEmptyMessage
188+
];
189+
190+
const expected: ChatMessage[] = [
191+
systemMessage,
192+
{
193+
role: "user",
194+
content: [
195+
{ type: "text", text: "text.ts code block" },
196+
{ type: "imageUrl", imageUrl:{ url: "data:..."} },
197+
{ type: "text", text: "provide answer" },
198+
{ type: "text", text: "explain test.ts" }
199+
]
200+
},
201+
assistantEmptyMessage
202+
];
203+
204+
const result = substituteLastUserMessage(history, "/echo ", [mcpMessage]);
205+
expect(result).toEqual(expected);
206+
});
207+
208+
it("should handle only /echo on second question", () => {
209+
// Input: `/echo `
210+
const history: ChatMessage[] = [
211+
systemMessage,
212+
{ role: "user", content: "first history" },
213+
{ role: "assistant", content: "answer" },
214+
{
215+
role: "user",
216+
content: [{ type: "text", text: "/echo " }]
217+
},
218+
assistantEmptyMessage
219+
];
220+
221+
const expected: ChatMessage[] = [
222+
systemMessage,
223+
{ role: "user", content: "first history" },
224+
{ role: "assistant", content: "answer" },
225+
{
226+
role: "user",
227+
content: [{ type: "text", text: "provide answer" }, { type: "text", text: "" }]
228+
},
229+
assistantEmptyMessage
230+
];
231+
232+
const result = substituteLastUserMessage(history, "/echo ", [mcpMessage]);
233+
expect(result).toEqual(expected);
234+
});
235+
236+
it("should handle /echo with text and resource on second question", () => {
237+
// Same as first question but with more history at the start
238+
const history: ChatMessage[] = [
239+
systemMessage,
240+
{ role: "user", content: "previous question" },
241+
{ role: "assistant", content: "previous answer" },
242+
{
243+
role: "user",
244+
content: [
245+
{ type: "text", text: "text.ts code block" },
246+
{ type: "imageUrl", imageUrl:{ url: "data:..."} },
247+
{ type: "text", text: "/echo explain test.ts" }
248+
]
249+
},
250+
assistantEmptyMessage
251+
];
252+
253+
const expected: ChatMessage[] = [
254+
systemMessage,
255+
{ role: "user", content: "previous question" },
256+
{ role: "assistant", content: "previous answer" },
257+
{
258+
role: "user",
259+
content: [
260+
{ type: "text", text: "text.ts code block" },
261+
{ type: "imageUrl", imageUrl:{ url: "data:..."}},
262+
{ type: "text", text: "provide answer" },
263+
{ type: "text", text: "explain test.ts" }
264+
]
265+
},
266+
assistantEmptyMessage
267+
];
268+
269+
const result = substituteLastUserMessage(history, "/echo ", [mcpMessage]);
270+
expect(result).toEqual(expected);
271+
});
272+
273+
it("should handle /echo with text and resource with multisection prompt", () => {
274+
// Same as first question but with more history at the start
275+
const history: ChatMessage[] = [
276+
systemMessage,
277+
{ role: "user", content: "previous question" },
278+
{ role: "assistant", content: "previous answer" },
279+
{
280+
role: "user",
281+
content: [
282+
{ type: "text", text: "text.ts code block" },
283+
{ type: "imageUrl", imageUrl:{ url: "data:..."} },
284+
{ type: "text", text: "/echo explain test.ts" }
285+
]
286+
},
287+
assistantEmptyMessage
288+
];
289+
290+
const expected: ChatMessage[] = [
291+
systemMessage,
292+
{ role: "user", content: "previous question" },
293+
{ role: "assistant", content: "previous answer" },
294+
mcpHeadMessage,
295+
mcpAssistantMessage,
296+
{
297+
role: "user",
298+
content: [
299+
{ type: "text", text: "text.ts code block" },
300+
{ type: "imageUrl", imageUrl:{ url: "data:..."}},
301+
{ type: "text", text: "provide answer" },
302+
{ type: "text", text: "explain test.ts" }
303+
]
304+
},
305+
assistantEmptyMessage
306+
];
307+
308+
const result = substituteLastUserMessage(history, "/echo ", [mcpHeadMessage,mcpAssistantMessage,mcpMessage]);
309+
expect(result).toEqual(expected);
310+
});
311+
});

core/commands/slash/mcp.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ function substituteContent(content: MessagePart[], input: string, prompt: Messag
7070
* @param prompt Replacement content to be inserted
7171
* @returns New array of messages with the substitution applied
7272
*/
73-
function substituteLastUserMessage(messages: ChatMessage[], input: string, prompt: ChatMessage[]): ChatMessage[] {
73+
export function substituteLastUserMessage(messages: ChatMessage[], input: string, prompt: ChatMessage[]): ChatMessage[] {
7474
// Create a copy of the messages array
7575
const newMessages = [...messages];
7676

7777
// Find the last user message
78-
const lastUserMessageIndex = findLastIndex(newMessages,(msg) => msg.role === "user");
78+
let lastUserMessageIndex = findLastIndex(newMessages,(msg) => msg.role === "user");
7979

8080
if (lastUserMessageIndex === -1) {
8181
// No user message found
@@ -95,10 +95,11 @@ function substituteLastUserMessage(messages: ChatMessage[], input: string, promp
9595
// No user messages in prompt, insert them before the last user message
9696
newMessages.splice(lastUserMessageIndex, 0, ...prompt);
9797
promptContent = [];
98-
} else {
98+
} else {
9999
// User messages in prompt, insert all but last user prompt before the last user message
100100
newMessages.splice(lastUserMessageIndex, 0, ...prompt.slice(0, lastUserPromptIndex ));
101101
promptContent = prompt[lastUserPromptIndex].content as MessagePart[];
102+
lastUserMessageIndex += lastUserPromptIndex
102103
}
103104
// Get the last user message
104105
const userMessage = newMessages[lastUserMessageIndex];
@@ -112,7 +113,7 @@ function substituteLastUserMessage(messages: ChatMessage[], input: string, promp
112113
contentAsArray = userMessage.content as MessagePart[];
113114
}
114115

115-
// Apply substituteContent function
116+
// replace command with prompt in content
116117
const newContent = substituteContent(contentAsArray, input, promptContent);
117118

118119
// Create a new user message with the substituted content

0 commit comments

Comments
 (0)