Skip to content

Commit edf3ca5

Browse files
committed
refactor: align ask_followup_question tool with current patterns
- Add early return for partial blocks with incomplete required params - Make follow_up parameter required and validate it properly - Add validation for empty suggestions array - Improve error messages to be more specific - Update prompt description to clarify follow_up is required - Align error handling with other tools (consecutiveMistakeCount, recordToolError) - Minor text improvements in prompt description
1 parent ad0e33e commit edf3ca5

File tree

2 files changed

+61
-43
lines changed

2 files changed

+61
-43
lines changed

src/core/prompts/tools/ask-followup-question.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,16 @@ Parameters:
55
- question: (required) The question to ask the user. This should be a clear, specific question that addresses the information you need.
66
- follow_up: (required) A list of 2-4 suggested answers that logically follow from the question, ordered by priority or logical sequence. Each suggestion must:
77
1. Be provided in its own <suggest> tag
8-
2. Be specific, actionable, and directly related to the completed task
8+
2. Be specific, actionable, and directly related to the question
99
3. Be a complete answer to the question - the user should not need to provide additional information or fill in any missing details. DO NOT include placeholders with brackets or parentheses.
1010
4. Optionally include a mode attribute to switch to a specific mode when the suggestion is selected: <suggest mode="mode-slug">suggestion text</suggest>
1111
- When using the mode attribute, focus the suggestion text on the action to be taken rather than mentioning the mode switch, as the mode change is handled automatically and indicated by a visual badge
1212
Usage:
1313
<ask_followup_question>
1414
<question>Your question here</question>
1515
<follow_up>
16-
<suggest>
17-
Your suggested answer here
18-
</suggest>
19-
<suggest mode="code">
20-
Implement the solution
21-
</suggest>
16+
<suggest>Your first suggested answer here</suggest>
17+
<suggest mode="code">Implement the solution</suggest>
2218
</follow_up>
2319
</ask_followup_question>
2420

src/core/tools/askFollowupQuestionTool.ts

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export async function askFollowupQuestionTool(
1616

1717
try {
1818
if (block.partial) {
19+
// Early return if required parameter is not yet available
20+
if (!question) {
21+
return
22+
}
23+
1924
await cline.ask("followup", removeClosingTag("question", question), block.partial).catch(() => {})
2025
return
2126
} else {
@@ -26,64 +31,81 @@ export async function askFollowupQuestionTool(
2631
return
2732
}
2833

34+
if (!follow_up) {
35+
cline.consecutiveMistakeCount++
36+
cline.recordToolError("ask_followup_question")
37+
pushToolResult(await cline.sayAndCreateMissingParamError("ask_followup_question", "follow_up"))
38+
return
39+
}
40+
41+
cline.consecutiveMistakeCount = 0
42+
2943
type Suggest = { answer: string; mode?: string }
3044

3145
let follow_up_json = {
3246
question,
3347
suggest: [] as Suggest[],
3448
}
3549

36-
if (follow_up) {
37-
// Define the actual structure returned by the XML parser
38-
type ParsedSuggestion = string | { "#text": string; "@_mode"?: string }
50+
// Define the actual structure returned by the XML parser
51+
type ParsedSuggestion = string | { "#text": string; "@_mode"?: string }
3952

40-
let parsedSuggest: {
53+
let parsedSuggest: {
54+
suggest: ParsedSuggestion[] | ParsedSuggestion
55+
}
56+
57+
try {
58+
parsedSuggest = parseXml(follow_up, ["suggest"]) as {
4159
suggest: ParsedSuggestion[] | ParsedSuggestion
4260
}
61+
} catch (error) {
62+
cline.consecutiveMistakeCount++
63+
cline.recordToolError("ask_followup_question")
64+
await cline.say("error", `Failed to parse follow_up suggestions: ${error.message}`)
65+
pushToolResult(formatResponse.toolError(`Invalid follow_up XML format: ${error.message}`))
66+
return
67+
}
4368

44-
try {
45-
parsedSuggest = parseXml(follow_up, ["suggest"]) as {
46-
suggest: ParsedSuggestion[] | ParsedSuggestion
47-
}
48-
} catch (error) {
49-
cline.consecutiveMistakeCount++
50-
cline.recordToolError("ask_followup_question")
51-
await cline.say("error", `Failed to parse operations: ${error.message}`)
52-
pushToolResult(formatResponse.toolError("Invalid operations xml format"))
53-
return
54-
}
69+
const rawSuggestions = Array.isArray(parsedSuggest?.suggest)
70+
? parsedSuggest.suggest
71+
: [parsedSuggest?.suggest].filter((sug): sug is ParsedSuggestion => sug !== undefined)
5572

56-
const rawSuggestions = Array.isArray(parsedSuggest?.suggest)
57-
? parsedSuggest.suggest
58-
: [parsedSuggest?.suggest].filter((sug): sug is ParsedSuggestion => sug !== undefined)
59-
60-
// Transform parsed XML to our Suggest format
61-
const normalizedSuggest: Suggest[] = rawSuggestions.map((sug) => {
62-
if (typeof sug === "string") {
63-
// Simple string suggestion (no mode attribute)
64-
return { answer: sug }
65-
} else {
66-
// XML object with text content and optional mode attribute
67-
const result: Suggest = { answer: sug["#text"] }
68-
if (sug["@_mode"]) {
69-
result.mode = sug["@_mode"]
70-
}
71-
return result
73+
// Validate that we have at least one suggestion
74+
if (rawSuggestions.length === 0) {
75+
cline.consecutiveMistakeCount++
76+
cline.recordToolError("ask_followup_question")
77+
await cline.say("error", "No suggestions found in follow_up parameter")
78+
pushToolResult(
79+
formatResponse.toolError("The follow_up parameter must contain at least one <suggest> tag"),
80+
)
81+
return
82+
}
83+
84+
// Transform parsed XML to our Suggest format
85+
const normalizedSuggest: Suggest[] = rawSuggestions.map((sug) => {
86+
if (typeof sug === "string") {
87+
// Simple string suggestion (no mode attribute)
88+
return { answer: sug }
89+
} else {
90+
// XML object with text content and optional mode attribute
91+
const result: Suggest = { answer: sug["#text"] }
92+
if (sug["@_mode"]) {
93+
result.mode = sug["@_mode"]
7294
}
73-
})
95+
return result
96+
}
97+
})
7498

75-
follow_up_json.suggest = normalizedSuggest
76-
}
99+
follow_up_json.suggest = normalizedSuggest
77100

78-
cline.consecutiveMistakeCount = 0
79101
const { text, images } = await cline.ask("followup", JSON.stringify(follow_up_json), false)
80102
await cline.say("user_feedback", text ?? "", images)
81103
pushToolResult(formatResponse.toolResult(`<answer>\n${text}\n</answer>`, images))
82104

83105
return
84106
}
85107
} catch (error) {
86-
await handleError("asking question", error)
108+
await handleError("asking followup question", error)
87109
return
88110
}
89111
}

0 commit comments

Comments
 (0)