Skip to content

Commit f2da1f8

Browse files
committed
add attempt complete
1 parent f1af005 commit f2da1f8

File tree

6 files changed

+213
-52
lines changed

6 files changed

+213
-52
lines changed

src/core/Cline.ts

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,19 +2439,19 @@ export class Cline {
24392439
}
24402440
}
24412441
case "prompt_suggest": {
2442-
const result: string | undefined = block.params.result
2442+
const values: string | undefined = block.params.values
24432443
try {
24442444
if (block.partial) {
24452445
await this.ask(
24462446
"prompt_suggest",
2447-
removeClosingTag("result", result),
2447+
removeClosingTag("result", values),
24482448
block.partial,
24492449
).catch(() => {})
24502450
break
24512451
} else {
2452-
if (!result) {
2452+
if (!values) {
24532453
this.consecutiveMistakeCount++
2454-
pushToolResult(await this.sayAndCreateMissingParamError("prompt_suggest", "result"))
2454+
pushToolResult(await this.sayAndCreateMissingParamError("prompt_suggest", "values"))
24552455
break
24562456
}
24572457

@@ -2464,7 +2464,7 @@ export class Cline {
24642464
}
24652465

24662466
try {
2467-
parsedSuggest = parseXml(result, ["result.suggest"]) as {
2467+
parsedSuggest = parseXml(values, ["suggest"]) as {
24682468
suggest: Suggest[] | Suggest
24692469
}
24702470
} catch (error) {
@@ -2655,6 +2655,7 @@ export class Cline {
26552655
*/
26562656
const result: string | undefined = block.params.result
26572657
const command: string | undefined = block.params.command
2658+
const values: string | undefined = block.params.values
26582659
try {
26592660
const lastMessage = this.clineMessages.at(-1)
26602661
if (block.partial) {
@@ -2703,7 +2704,41 @@ export class Cline {
27032704
)
27042705
break
27052706
}
2706-
this.consecutiveMistakeCount = 0
2707+
2708+
let normalizedSuggest = null
2709+
2710+
if (values) {
2711+
console.log("values", values)
2712+
type Suggest = {
2713+
suggest: string
2714+
}
2715+
2716+
let parsedSuggest: {
2717+
suggest: Suggest[] | Suggest
2718+
}
2719+
2720+
try {
2721+
parsedSuggest = parseXml(values, ["values.suggest"]) as {
2722+
suggest: Suggest[] | Suggest
2723+
}
2724+
console.log("parsedSuggest", parsedSuggest)
2725+
} catch (error) {
2726+
this.consecutiveMistakeCount++
2727+
await this.say("error", `Failed to parse operations: ${error.message}`)
2728+
pushToolResult(formatResponse.toolError("Invalid operations xml format"))
2729+
break
2730+
}
2731+
2732+
this.consecutiveMistakeCount = 0
2733+
2734+
normalizedSuggest = Array.isArray(parsedSuggest?.suggest)
2735+
? parsedSuggest.suggest
2736+
: [parsedSuggest?.suggest].filter((sug): sug is Suggest => sug !== undefined)
2737+
2738+
console.log("normalizedSuggest", normalizedSuggest)
2739+
} else {
2740+
this.consecutiveMistakeCount = 0
2741+
}
27072742

27082743
let commandResult: ToolResponse | undefined
27092744
if (command) {
@@ -2729,32 +2764,45 @@ export class Cline {
27292764
await this.say("completion_result", result, undefined, false)
27302765
}
27312766

2732-
// we already sent completion_result says, an empty string asks relinquishes control over button and field
2733-
const { response, text, images } = await this.ask("completion_result", "", false)
2734-
if (response === "yesButtonClicked") {
2735-
pushToolResult("") // signals to recursive loop to stop (for now this never happens since yesButtonClicked will trigger a new task)
2736-
break
2737-
}
2738-
await this.say("user_feedback", text ?? "", images)
2739-
27402767
const toolResults: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] = []
2741-
if (commandResult) {
2742-
if (typeof commandResult === "string") {
2743-
toolResults.push({ type: "text", text: commandResult })
2744-
} else if (Array.isArray(commandResult)) {
2745-
toolResults.push(...commandResult)
2768+
if (normalizedSuggest) {
2769+
console.log("normalizedSuggest", normalizedSuggest)
2770+
const { text, images } = await this.ask(
2771+
"prompt_suggest",
2772+
JSON.stringify(normalizedSuggest),
2773+
false,
2774+
)
2775+
await this.say("user_feedback", text ?? "", images)
2776+
pushToolResult(
2777+
formatResponse.toolResult(`<user_feedback>\n${text}\n</user_feedback>`, images),
2778+
)
2779+
} else {
2780+
// we already sent completion_result says, an empty string asks relinquishes control over button and field
2781+
const { response, text, images } = await this.ask("completion_result", "", false)
2782+
if (response === "yesButtonClicked") {
2783+
pushToolResult("") // signals to recursive loop to stop (for now this never happens since yesButtonClicked will trigger a new task)
2784+
break
27462785
}
2786+
await this.say("user_feedback", text ?? "", images)
2787+
2788+
if (commandResult) {
2789+
if (typeof commandResult === "string") {
2790+
toolResults.push({ type: "text", text: commandResult })
2791+
} else if (Array.isArray(commandResult)) {
2792+
toolResults.push(...commandResult)
2793+
}
2794+
}
2795+
toolResults.push({
2796+
type: "text",
2797+
text: `The user has provided feedback on the results. Consider their input to continue the task, and then attempt completion again.\n<feedback>\n${text}\n</feedback>`,
2798+
})
2799+
toolResults.push(...formatResponse.imageBlocks(images))
2800+
this.userMessageContent.push({
2801+
type: "text",
2802+
text: `${toolDescription()} Result:`,
2803+
})
2804+
this.userMessageContent.push(...toolResults)
27472805
}
2748-
toolResults.push({
2749-
type: "text",
2750-
text: `The user has provided feedback on the results. Consider their input to continue the task, and then attempt completion again.\n<feedback>\n${text}\n</feedback>`,
2751-
})
2752-
toolResults.push(...formatResponse.imageBlocks(images))
2753-
this.userMessageContent.push({
2754-
type: "text",
2755-
text: `${toolDescription()} Result:`,
2756-
})
2757-
this.userMessageContent.push(...toolResults)
27582806

27592807
break
27602808
}

src/core/assistant-message/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export const toolParamNames = [
5757
"operations",
5858
"mode",
5959
"message",
60+
"values",
6061
] as const
6162

6263
export type ToolParamName = (typeof toolParamNames)[number]
@@ -127,7 +128,7 @@ export interface AskFollowupQuestionToolUse extends ToolUse {
127128

128129
export interface AttemptCompletionToolUse extends ToolUse {
129130
name: "attempt_completion"
130-
params: Partial<Pick<Record<ToolParamName, string>, "result" | "command">>
131+
params: Partial<Pick<Record<ToolParamName, string>, "result" | "command" | "values">>
131132
}
132133

133134
export interface SwitchModeToolUse extends ToolUse {
@@ -142,5 +143,5 @@ export interface NewTaskToolUse extends ToolUse {
142143

143144
export interface PromptSuggestToolUse extends ToolUse {
144145
name: "prompt_suggest"
145-
params: Partial<Pick<Record<ToolParamName, string>, "result">>
146+
params: Partial<Pick<Record<ToolParamName, string>, "values">>
146147
}
Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,35 @@
1-
export function getAttemptCompletionDescription(): string {
1+
import { ToolArgs } from "./types"
2+
3+
export function getAttemptCompletionDescription({ experiments }: ToolArgs): string {
24
return `## attempt_completion
35
Description: After each tool use, the user will respond with the result of that tool use, i.e. if it succeeded or failed, along with any reasons for failure. Once you've received the results of tool uses and can confirm that the task is complete, use this tool to present the result of your work to the user. Optionally you may provide a CLI command to showcase the result of your work. The user may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again.
46
IMPORTANT NOTE: This tool CANNOT be used until you've confirmed from the user that any previous tool uses were successful. Failure to do so will result in code corruption and system failure. Before using this tool, you must ask yourself in <thinking></thinking> tags if you've confirmed from the user that any previous tool uses were successful. If not, then DO NOT use this tool.
57
Parameters:
68
- result: (required) The result of the task. Formulate this result in a way that is final and does not require further input from the user. Don't end your result with questions or offers for further assistance.
7-
- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use \`open index.html\` to display a created html website, or \`open localhost:3000\` to display a locally running development server. But DO NOT use commands like \`echo\` or \`cat\` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
9+
- command: (optional) A CLI command to execute to show a live demo of the result to the user. For example, use \`open index.html\` to display a created html website, or \`open localhost:3000\` to display a locally running development server. But DO NOT use commands like \`echo\` or \`cat\` that merely print text. This command should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.${
10+
experiments?.["prompt_suggest"]
11+
? `
12+
- values: (optional) A list of suggested prompt/task/question for user as XML elements. The order of suggestion is important, the order of suggestion is the same with the order that show to user.. Each suggested can have these elements:
13+
* suggest: A suggestion to display to the user. Each suggestion must be provided in its own <suggest> tag. Each suggestion can be multiple line.`
14+
: ``
15+
}
816
Usage:
917
<attempt_completion>
1018
<result>
1119
Your final result description here
12-
</result>
20+
</result>${
21+
experiments?.["prompt_suggest"]
22+
? `
23+
<values>
24+
<suggest>
25+
- Suggested prompt or task 1
26+
</suggest>
27+
<suggest>
28+
- Suggested prompt or task 2
29+
</suggest>
30+
</values>`
31+
: ``
32+
}
1333
<command>Command to demonstrate result (optional)</command>
1434
</attempt_completion>
1535
@@ -19,5 +39,95 @@ Example: Requesting to attempt completion with a result and command
1939
I've updated the CSS
2040
</result>
2141
<command>open index.html</command>
42+
</attempt_completion>${
43+
experiments?.["prompt_suggest"]
44+
? `
45+
46+
Example: Completion with suggestions after implementing a feature
47+
<attempt_completion>
48+
<result>
49+
I've implemented the user authentication feature with email and password login
50+
</result>
51+
<values>
52+
<suggest>
53+
- Add unit tests for the authentication service
54+
</suggest>
55+
<suggest>
56+
- Implement password reset functionality
57+
</suggest>
58+
<suggest>
59+
- Add social login providers (Google, GitHub)
60+
</suggest>
61+
<suggest>
62+
- Update API documentation with auth endpoints
63+
</suggest>
64+
</values>
65+
<command>npm run dev</command>
66+
</attempt_completion>
67+
68+
Example: Completion with suggestions after fixing a bug
69+
<attempt_completion>
70+
<result>
71+
I've fixed the memory leak in the WebSocket connection handling
72+
</result>
73+
<values>
74+
<suggest>
75+
- Add monitoring for WebSocket connection counts
76+
</suggest>
77+
<suggest>
78+
- Write regression tests to prevent future leaks
79+
</suggest>
80+
<suggest>
81+
- Review other WebSocket usage for similar issues
82+
</suggest>
83+
<suggest>
84+
- Document the fix in CHANGELOG.md
85+
</suggest>
86+
</values>
87+
</attempt_completion>
88+
89+
Example: Completion with task split suggestions
90+
<attempt_completion>
91+
<result>
92+
I've completed the initial database schema design
93+
</result>
94+
<values>
95+
<suggest>
96+
- Split into new task using new_task: Implement database migration system
97+
</suggest>
98+
<suggest>
99+
- Split into new task using new_task: Create data access layer
100+
</suggest>
101+
<suggest>
102+
- Document schema design decisions and constraints
103+
</suggest>
104+
<suggest>
105+
- Review schema for optimization opportunities
106+
</suggest>
107+
</values>
108+
</attempt_completion>
109+
110+
Example: Completion with documentation suggestions
111+
<attempt_completion>
112+
<result>
113+
I've created the API endpoints for the user management system
114+
</result>
115+
<values>
116+
<suggest>
117+
- Create OpenAPI/Swagger documentation
118+
</suggest>
119+
<suggest>
120+
- Write integration tests for all endpoints
121+
</suggest>
122+
<suggest>
123+
- Add rate limiting and security headers
124+
</suggest>
125+
<suggest>
126+
- Split into new task using new_task: Create user management API guide
127+
</suggest>
128+
</values>
129+
<command>npm run docs</command>
22130
</attempt_completion>`
131+
: ``
132+
}`
23133
}

src/core/prompts/tools/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const toolDescriptionMap: Record<string, (args: ToolArgs) => string | undefined>
3030
list_code_definition_names: (args) => getListCodeDefinitionNamesDescription(args),
3131
browser_action: (args) => getBrowserActionDescription(args),
3232
ask_followup_question: () => getAskFollowupQuestionDescription(),
33-
attempt_completion: () => getAttemptCompletionDescription(),
33+
attempt_completion: (args) => getAttemptCompletionDescription(args),
3434
use_mcp_tool: (args) => getUseMcpToolDescription(args),
3535
access_mcp_resource: (args) => getAccessMcpResourceDescription(args),
3636
switch_mode: () => getSwitchModeDescription(),
@@ -59,6 +59,7 @@ export function getToolDescriptionsForMode(
5959
diffStrategy,
6060
browserViewportSize,
6161
mcpHub,
62+
experiments,
6263
}
6364

6465
const tools = new Set<string>()

0 commit comments

Comments
 (0)