Browse Source

Add a mode switched event, better mode switch e2e test (#2237)

Chris Estreich 9 months ago
parent
commit
42f7465666

+ 14 - 29
e2e/src/suite/modes.test.ts

@@ -13,11 +13,17 @@ suite("Roo Code Modes", () => {
 		 */
 
 		const switchModesPrompt =
-			"For each mode (Code, Architect, Ask) respond with the mode name and what it specializes in after switching to that mode. " +
-			"Do not start with the current mode."
+			"For each mode (Architect, Ask, Debug) respond with the mode name and what it specializes in after switching to that mode."
 
 		let messages: ClineMessage[] = []
 
+		const modeSwitches: string[] = []
+
+		api.on("taskModeSwitched", (_taskId, mode) => {
+			console.log("taskModeSwitched", mode)
+			modeSwitches.push(mode)
+		})
+
 		api.on("message", ({ message }) => {
 			if (message.type === "say" && message.partial === false) {
 				messages.push(message)
@@ -25,36 +31,15 @@ suite("Roo Code Modes", () => {
 		})
 
 		const switchModesTaskId = await api.startNewTask({
-			configuration: { mode: "Code", alwaysAllowModeSwitch: true, autoApprovalEnabled: true },
+			configuration: { mode: "code", alwaysAllowModeSwitch: true, autoApprovalEnabled: true },
 			text: switchModesPrompt,
 		})
 
-		await waitUntilCompleted({ api, taskId: switchModesTaskId, timeout: 60_000 })
-
-		/**
-		 * Grade the response.
-		 */
-
-		const response = messages
-			.filter(({ type, say, partial }) => say === "text")
-			.map(({ text }) => text ?? "")
-			.join("\n")
-
-		const gradePrompt = `Given this prompt: ${switchModesPrompt} grade the response from 1 to 10 in the format of "Grade: (1-10)". For example: Grade 7\n\nResponse: ${response}`
-
-		messages = []
-
-		const gradeTaskId = await api.startNewTask({ configuration: { mode: "Ask" }, text: gradePrompt })
-		await waitUntilCompleted({ api, taskId: gradeTaskId })
-
-		const completion = messages.find(({ type, say, partial }) => say === "completion_result")
-		const match = completion?.text?.match(/Grade: (\d+)/)
-		const score = parseInt(match?.[1] ?? "0")
-		assert.ok(
-			score >= 7 && score <= 10,
-			`Grade must be between 7 and 10. DEBUG: score = ${score}, completion = ${completion?.text}`,
-		)
-
+		await waitUntilCompleted({ api, taskId: switchModesTaskId })
 		await api.cancelCurrentTask()
+
+		assert.ok(modeSwitches.includes("architect"))
+		assert.ok(modeSwitches.includes("ask"))
+		assert.ok(modeSwitches.includes("debug"))
 	})
 })

+ 1 - 0
src/core/Cline.ts

@@ -87,6 +87,7 @@ type UserContent = Array<Anthropic.Messages.ContentBlockParam>
 export type ClineEvents = {
 	message: [{ action: "created" | "updated"; message: ClineMessage }]
 	taskStarted: []
+	taskModeSwitched: [taskId: string, mode: string]
 	taskPaused: []
 	taskUnpaused: []
 	taskAskResponded: []

+ 4 - 3
src/core/webview/ClineProvider.ts

@@ -740,10 +740,11 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
 	 */
 	public async handleModeSwitch(newMode: Mode) {
 		// Capture mode switch telemetry event
-		const currentTaskId = this.getCurrentCline()?.taskId
+		const cline = this.getCurrentCline()
 
-		if (currentTaskId) {
-			telemetryService.captureModeSwitch(currentTaskId, newMode)
+		if (cline) {
+			telemetryService.captureModeSwitch(cline.taskId, newMode)
+			cline.emit("taskModeSwitched", cline.taskId, newMode)
 		}
 
 		await this.updateGlobalState("mode", newMode)

+ 2 - 0
src/exports/api.ts

@@ -176,6 +176,8 @@ export class API extends EventEmitter<RooCodeEvents> implements RooCodeAPI {
 
 			cline.on("message", (message) => this.emit(RooCodeEventName.Message, { taskId: cline.taskId, ...message }))
 
+			cline.on("taskModeSwitched", (taskId, mode) => this.emit(RooCodeEventName.TaskModeSwitched, taskId, mode))
+
 			cline.on("taskTokenUsageUpdated", (_, usage) =>
 				this.emit(RooCodeEventName.TaskTokenUsageUpdated, cline.taskId, usage),
 			)

+ 2 - 0
src/exports/roo-code.d.ts

@@ -470,6 +470,7 @@ type RooCodeEvents = {
 	]
 	taskCreated: [string]
 	taskStarted: [string]
+	taskModeSwitched: [string, string]
 	taskPaused: [string]
 	taskUnpaused: [string]
 	taskAskResponded: [string]
@@ -506,6 +507,7 @@ declare enum RooCodeEventName {
 	Message = "message",
 	TaskCreated = "taskCreated",
 	TaskStarted = "taskStarted",
+	TaskModeSwitched = "taskModeSwitched",
 	TaskPaused = "taskPaused",
 	TaskUnpaused = "taskUnpaused",
 	TaskAskResponded = "taskAskResponded",

+ 1 - 0
src/exports/types.ts

@@ -479,6 +479,7 @@ type RooCodeEvents = {
 	]
 	taskCreated: [string]
 	taskStarted: [string]
+	taskModeSwitched: [string, string]
 	taskPaused: [string]
 	taskUnpaused: [string]
 	taskAskResponded: [string]

+ 2 - 0
src/schemas/index.ts

@@ -797,6 +797,7 @@ export enum RooCodeEventName {
 	Message = "message",
 	TaskCreated = "taskCreated",
 	TaskStarted = "taskStarted",
+	TaskModeSwitched = "taskModeSwitched",
 	TaskPaused = "taskPaused",
 	TaskUnpaused = "taskUnpaused",
 	TaskAskResponded = "taskAskResponded",
@@ -816,6 +817,7 @@ export const rooCodeEventsSchema = z.object({
 	]),
 	[RooCodeEventName.TaskCreated]: z.tuple([z.string()]),
 	[RooCodeEventName.TaskStarted]: z.tuple([z.string()]),
+	[RooCodeEventName.TaskModeSwitched]: z.tuple([z.string(), z.string()]),
 	[RooCodeEventName.TaskPaused]: z.tuple([z.string()]),
 	[RooCodeEventName.TaskUnpaused]: z.tuple([z.string()]),
 	[RooCodeEventName.TaskAskResponded]: z.tuple([z.string()]),

+ 4 - 0
src/schemas/ipc.ts

@@ -63,6 +63,10 @@ export const taskEventSchema = z.discriminatedUnion("eventName", [
 		eventName: z.literal(RooCodeEventName.TaskStarted),
 		payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskStarted],
 	}),
+	z.object({
+		eventName: z.literal(RooCodeEventName.TaskModeSwitched),
+		payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskModeSwitched],
+	}),
 	z.object({
 		eventName: z.literal(RooCodeEventName.TaskPaused),
 		payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskPaused],