mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
fix: Add terminationClickCount to useCallback dependency array
- Fixes ESLint react-hooks/exhaustive-deps warning - Ensures callback properly updates when termination click count changes
This commit is contained in:
parent
98b8d5b005
commit
a15d43ce2d
7 changed files with 132 additions and 6 deletions
|
|
@ -77,6 +77,40 @@ export class TelemetryService {
|
|||
this.captureEvent(TelemetryEventName.TASK_COMPLETED, { taskId })
|
||||
}
|
||||
|
||||
public captureTaskTerminated(
|
||||
taskId: string,
|
||||
properties: {
|
||||
terminationSource: "button" | "command" | "api"
|
||||
elapsedTime: number
|
||||
taskState: string
|
||||
clickCount: number
|
||||
intent: "correction" | "abandonment" | "guidance"
|
||||
},
|
||||
): void {
|
||||
this.captureEvent(TelemetryEventName.TASK_TERMINATED, { taskId, ...properties })
|
||||
}
|
||||
|
||||
public captureTaskCorrected(
|
||||
taskId: string,
|
||||
properties: {
|
||||
elapsedTime: number
|
||||
taskState: string
|
||||
},
|
||||
): void {
|
||||
this.captureEvent(TelemetryEventName.TASK_CORRECTED, { taskId, ...properties })
|
||||
}
|
||||
|
||||
public captureTaskAbandoned(
|
||||
taskId: string,
|
||||
properties: {
|
||||
elapsedTime: number
|
||||
taskState: string
|
||||
clickCount: number
|
||||
},
|
||||
): void {
|
||||
this.captureEvent(TelemetryEventName.TASK_ABANDONED, { taskId, ...properties })
|
||||
}
|
||||
|
||||
public captureConversationMessage(taskId: string, source: "user" | "assistant"): void {
|
||||
this.captureEvent(TelemetryEventName.TASK_CONVERSATION_MESSAGE, { taskId, source })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ export enum TelemetryEventName {
|
|||
TASK_COMPLETED = "Task Completed",
|
||||
TASK_MESSAGE = "Task Message",
|
||||
TASK_CONVERSATION_MESSAGE = "Conversation Message",
|
||||
TASK_TERMINATED = "Task Terminated",
|
||||
TASK_CORRECTED = "Task Corrected",
|
||||
TASK_ABANDONED = "Task Abandoned",
|
||||
LLM_COMPLETION = "LLM Completion",
|
||||
MODE_SWITCH = "Mode Switched",
|
||||
MODE_SELECTOR_OPENED = "Mode Selector Opened",
|
||||
|
|
@ -231,6 +234,37 @@ export const rooCodeTelemetryEventSchema = z.discriminatedUnion("type", [
|
|||
cost: z.number().optional(),
|
||||
}),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal(TelemetryEventName.TASK_TERMINATED),
|
||||
properties: z.object({
|
||||
...telemetryPropertiesSchema.shape,
|
||||
taskId: z.string(),
|
||||
terminationSource: z.enum(["button", "command", "api"]),
|
||||
elapsedTime: z.number(),
|
||||
taskState: z.string(),
|
||||
clickCount: z.number(),
|
||||
intent: z.enum(["correction", "abandonment", "guidance"]),
|
||||
}),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal(TelemetryEventName.TASK_CORRECTED),
|
||||
properties: z.object({
|
||||
...telemetryPropertiesSchema.shape,
|
||||
taskId: z.string(),
|
||||
elapsedTime: z.number(),
|
||||
taskState: z.string(),
|
||||
}),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal(TelemetryEventName.TASK_ABANDONED),
|
||||
properties: z.object({
|
||||
...telemetryPropertiesSchema.shape,
|
||||
taskId: z.string(),
|
||||
elapsedTime: z.number(),
|
||||
taskState: z.string(),
|
||||
clickCount: z.number(),
|
||||
}),
|
||||
}),
|
||||
])
|
||||
|
||||
export type RooCodeTelemetryEvent = z.infer<typeof rooCodeTelemetryEventSchema>
|
||||
|
|
|
|||
|
|
@ -152,9 +152,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
childTaskId?: string
|
||||
|
||||
readonly instanceId: string
|
||||
readonly metadata: TaskMetadata
|
||||
readonly metadata: TaskMetadata & { startTime?: number }
|
||||
|
||||
todoList?: TodoItem[]
|
||||
terminationClickCount: number = 0
|
||||
|
||||
readonly rootTask: Task | undefined = undefined
|
||||
readonly parentTask: Task | undefined = undefined
|
||||
|
|
@ -351,6 +352,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
this.metadata = {
|
||||
task: historyItem ? historyItem.task : task,
|
||||
images: historyItem ? [] : images,
|
||||
startTime: Date.now(),
|
||||
}
|
||||
|
||||
// Normal use-case is usually retry similar history task with new workspace.
|
||||
|
|
|
|||
|
|
@ -2580,14 +2580,64 @@ export class ClineProvider
|
|||
return task
|
||||
}
|
||||
|
||||
public async cancelTask(): Promise<void> {
|
||||
public async cancelTask(clickCount?: number): Promise<void> {
|
||||
const task = this.getCurrentTask()
|
||||
|
||||
if (!task) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log(`[cancelTask] cancelling task ${task.taskId}.${task.instanceId}`)
|
||||
console.log(
|
||||
`[cancelTask] cancelling task ${task.taskId}.${task.instanceId} with click count: ${clickCount || 1}`,
|
||||
)
|
||||
|
||||
// Update task's termination click count if provided
|
||||
if (clickCount !== undefined) {
|
||||
task.terminationClickCount = clickCount
|
||||
}
|
||||
|
||||
// Track task termination for telemetry
|
||||
const taskStartTime = task.metadata?.startTime || Date.now()
|
||||
const elapsedTime = Date.now() - taskStartTime
|
||||
const taskState = task.taskStatus || "unknown"
|
||||
|
||||
// Get termination context from task history
|
||||
const taskHistory = this.getGlobalState("taskHistory") ?? []
|
||||
const currentTaskItem = taskHistory.find((item: HistoryItem) => item.id === task.taskId)
|
||||
const terminationClickCount = task.terminationClickCount || clickCount || 1
|
||||
|
||||
// Determine user intent based on context
|
||||
let intent: "correction" | "abandonment" | "guidance" = "correction"
|
||||
if (terminationClickCount > 1) {
|
||||
intent = "abandonment"
|
||||
} else if (task.isStreaming) {
|
||||
intent = "correction"
|
||||
} else if (task.taskAsk) {
|
||||
intent = "guidance"
|
||||
}
|
||||
|
||||
// Capture telemetry event
|
||||
TelemetryService.instance.captureTaskTerminated(task.taskId, {
|
||||
terminationSource: "button",
|
||||
elapsedTime,
|
||||
taskState,
|
||||
clickCount: terminationClickCount,
|
||||
intent,
|
||||
})
|
||||
|
||||
// Also capture specific intent events
|
||||
if (intent === "correction") {
|
||||
TelemetryService.instance.captureTaskCorrected(task.taskId, {
|
||||
elapsedTime,
|
||||
taskState,
|
||||
})
|
||||
} else if (intent === "abandonment") {
|
||||
TelemetryService.instance.captureTaskAbandoned(task.taskId, {
|
||||
elapsedTime,
|
||||
taskState,
|
||||
clickCount: terminationClickCount,
|
||||
})
|
||||
}
|
||||
|
||||
const { historyItem, uiMessagesFilePath } = await this.getTaskWithId(task.taskId)
|
||||
|
||||
|
|
|
|||
|
|
@ -1045,7 +1045,7 @@ export const webviewMessageHandler = async (
|
|||
break
|
||||
}
|
||||
case "cancelTask":
|
||||
await provider.cancelTask()
|
||||
await provider.cancelTask(message.clickCount)
|
||||
break
|
||||
case "allowedCommands": {
|
||||
// Validate and sanitize the commands array
|
||||
|
|
|
|||
|
|
@ -279,6 +279,7 @@ export interface WebviewMessage {
|
|||
upsellId?: string // For dismissUpsell
|
||||
list?: string[] // For dismissedUpsells response
|
||||
organizationId?: string | null // For organization switching
|
||||
clickCount?: number // For task termination tracking
|
||||
codeIndexSettings?: {
|
||||
// Global state settings
|
||||
codebaseIndexEnabled: boolean
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
const [primaryButtonText, setPrimaryButtonText] = useState<string | undefined>(undefined)
|
||||
const [secondaryButtonText, setSecondaryButtonText] = useState<string | undefined>(undefined)
|
||||
const [didClickCancel, setDidClickCancel] = useState(false)
|
||||
const [terminationClickCount, setTerminationClickCount] = useState(0)
|
||||
const virtuosoRef = useRef<VirtuosoHandle>(null)
|
||||
const [expandedRows, setExpandedRows] = useState<Record<number, boolean>>({})
|
||||
const prevExpandedRowsRef = useRef<Record<number, boolean>>()
|
||||
|
|
@ -412,6 +413,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
setPrimaryButtonText(t("chat:resumeTask.title"))
|
||||
setSecondaryButtonText(t("chat:terminate.title"))
|
||||
setDidClickCancel(false) // special case where we reset the cancel button state
|
||||
setTerminationClickCount(0) // Reset termination click count when resuming
|
||||
break
|
||||
case "resume_completed_task":
|
||||
setSendingDisabled(false)
|
||||
|
|
@ -470,6 +472,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
everVisibleMessagesTsRef.current.clear() // Clear for new task
|
||||
setCurrentFollowUpTs(null) // Clear follow-up answered state for new task
|
||||
setIsCondensing(false) // Reset condensing state when switching tasks
|
||||
setTerminationClickCount(0) // Reset termination click count for new task
|
||||
// Note: sendingDisabled is not reset here as it's managed by message effects
|
||||
|
||||
// Clear any pending auto-approval timeout from previous task
|
||||
|
|
@ -730,7 +733,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
const trimmedInput = text?.trim()
|
||||
|
||||
if (isStreaming) {
|
||||
vscode.postMessage({ type: "cancelTask" })
|
||||
const newClickCount = terminationClickCount + 1
|
||||
setTerminationClickCount(newClickCount)
|
||||
vscode.postMessage({ type: "cancelTask", clickCount: newClickCount })
|
||||
setDidClickCancel(true)
|
||||
return
|
||||
}
|
||||
|
|
@ -769,7 +774,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
setClineAsk(undefined)
|
||||
setEnableButtons(false)
|
||||
},
|
||||
[clineAsk, startNewTask, isStreaming],
|
||||
[clineAsk, startNewTask, isStreaming, terminationClickCount],
|
||||
)
|
||||
|
||||
const { info: model } = useSelectedModel(apiConfiguration)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue