Compare commits

...

11 Commits

Author SHA1 Message Date
Toshii ed8e2415de Merge branch 'main' into ft/sl-command-condense-new 2025-04-24 11:16:31 -07:00
0xtoshii 4017d5780c comments 2025-04-24 11:09:07 -07:00
Toshii 0d19fe06a9 Update src/core/prompts/commands.ts
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-04-23 15:59:21 -07:00
0xtoshii c7e682d8ae dup new task resp 2025-04-23 15:54:29 -07:00
0xtoshii 2812b24fe3 changeset 2025-04-23 15:49:15 -07:00
0xtoshii 9f78a1e7f3 base 2 2025-04-23 15:48:23 -07:00
0xtoshii f79d64a24c full truncate 2025-04-22 18:50:01 -07:00
0xtoshii bc226f0d24 smol 2025-04-22 15:02:59 -07:00
0xtoshii 68326780c6 prompt 2025-04-22 14:17:26 -07:00
0xtoshii f8345f1f26 button callback 2025-04-22 12:31:17 -07:00
0xtoshii 3ca4f27b5b base 2025-04-21 19:53:24 -07:00
13 changed files with 213 additions and 4 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": minor
---
add smol command
+1
View File
@@ -24,6 +24,7 @@ export const toolUseNames = [
"load_mcp_documentation",
"attempt_completion",
"new_task",
"condense",
] as const
// Converts array of tool call names into a union type ("execute_command" | "read_file" | ...)
@@ -193,14 +193,20 @@ export class ContextManager {
public getNextTruncationRange(
apiMessages: Anthropic.Messages.MessageParam[],
currentDeletedRange: [number, number] | undefined,
keep: "half" | "quarter",
keep: "none" | "lastTwo" | "half" | "quarter",
): [number, number] {
// We always keep the first user-assistant pairing, and truncate an even number of messages from there
const rangeStartIndex = 2 // index 0 and 1 are kept
const startOfRest = currentDeletedRange ? currentDeletedRange[1] + 1 : 2 // inclusive starting index
let messagesToRemove: number
if (keep === "half") {
if (keep === "none") {
// Removes all messages beyond the first core user/assistant message pair
messagesToRemove = Math.max(apiMessages.length - startOfRest, 0)
} else if (keep === "lastTwo") {
// Keep the last user-assistant pair in addition to the first core user/assistant message pair
messagesToRemove = Math.max(apiMessages.length - startOfRest - 2, 0)
} else if (keep === "half") {
// Remove half of remaining user-assistant pairs
// We first calculate half of the messages then divide by 2 to get the number of pairs.
// After flooring, we multiply by 2 to get the number of messages.
@@ -382,6 +388,17 @@ export class ContextManager {
return [contextHistoryUpdated, uniqueFileReadIndices]
}
/**
* Public function for triggering potentially setting the truncation message
* If the truncation message already exists, does nothing, otherwise adds the message
*/
async triggerApplyStandardContextTruncationNoticeChange(timestamp: number, taskDirectory: string) {
const updated = this.applyStandardContextTruncationNoticeChange(timestamp)
if (updated) {
await this.saveContextHistory(taskDirectory)
}
}
/**
* if there is any truncation and there is no other alteration already set, alter the assistant message to indicate this occurred
*/
+14
View File
@@ -274,6 +274,20 @@ export class Controller {
})
break
}
case "newTask":
// Code that should run in response to the hello message command
//vscode.window.showInformationMessage(message.text!)
// Send a message to our webview.
// You can send any JSON serializable data.
// Could also do this in extension .ts
//this.postMessageToWebview({ type: "text", text: `Extension: ${Date.now()}` })
// initializing new instance of Cline will make sure that any agentically running promises in old instance don't affect our new task. this essentially creates a fresh slate for the new task
await this.initTask(message.text, message.images)
break
case "condense":
this.task?.handleWebviewAskResponse("yesButtonClicked")
break
case "apiConfiguration":
if (message.apiConfiguration) {
await updateApiConfiguration(this.context, message.apiConfiguration)
+62
View File
@@ -25,3 +25,65 @@ Usage:
Below is the the user's input when they indicated that they wanted to create a new task.
</explicit_instructions>\n
`
export const condenseToolResponse = () =>
`<explicit_instructions type="condense">
The user has explicitly asked you to create a detailed summary of the conversation so far, which will be used to compact the current context window while retaining key information. The user may have provided instructions or additional information for you to consider when summarizing the conversation.
Irrespective of whether additional information or instructions are given, you are only allowed to respond to this message by calling the condense tool.
The condense tool is defined below:
Description:
Your task is to create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions. This summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing with the conversation and supporting any continuing tasks.
The user will be presented with a preview of your generated summary and can choose to use it to compact their context window or keep chatting in the current conversation.
Users may refer to this tool as 'smol' or 'compact' as well. You should consider these to be equivalent to 'condense' when used in a similar context.
Parameters:
- Context: (required) The context to continue the conversation with. If applicable based on the current task, this should include:
1. Previous Conversation: High level details about what was discussed throughout the entire conversation with the user. This should be written to allow someone to be able to follow the general overarching conversation flow.
2. Current Work: Describe in detail what was being worked on prior to this request to compact the context window. Pay special attention to the more recent messages / conversation.
3. Key Technical Concepts: List all important technical concepts, technologies, coding conventions, and frameworks discussed, which might be relevant for continuing with this work.
4. Relevant Files and Code: If applicable, enumerate specific files and code sections examined, modified, or created for the task continuation. Pay special attention to the most recent messages and changes.
5. Problem Solving: Document problems solved thus far and any ongoing troubleshooting efforts.
6. Pending Tasks and Next Steps: Outline all pending tasks that you have explicitly been asked to work on, as well as list the next steps you will take for all outstanding work, if applicable. Include code snippets where they add clarity. For any next steps, include direct quotes from the most recent conversation showing exactly what task you were working on and where you left off. This should be verbatim to ensure there's no information loss in context between tasks.
Usage:
<condense>
<context>Your detailed summary</context>
</condense>
Example:
<condense>
<context>
1. Previous Conversation:
[Detailed description]
2. Current Work:
[Detailed description]
3. Key Technical Concepts:
- [Concept 1]
- [Concept 2]
- [...]
4. Relevant Files and Code:
- [File Name 1]
- [Summary of why this file is important]
- [Summary of the changes made to this file, if any]
- [Important Code Snippet]
- [File Name 2]
- [Important Code Snippet]
- [...]
5. Problem Solving:
[Detailed description]
6. Pending Tasks and Next Steps:
- [Task 1 details & next steps]
- [Task 2 details & next steps]
- [...]
</context>
</condense>
</explicit_instructions>\n
`
+3
View File
@@ -10,6 +10,9 @@ export const formatResponse = {
contextTruncationNotice: () =>
`[NOTE] Some previous conversation history with the user has been removed to maintain optimal context window length. The initial user task and the most recent exchanges have been retained for continuity, while intermediate conversation history has been removed. Please keep this in mind as you continue assisting the user.`,
condense: () =>
`The user has accepted the condensed conversation summary you generated. This summary covers important details of the historical conversation with the user which has been truncated.\n<explicit_instructions type="condense_response">It's crucial that you respond by ONLY asking the user what you should work on next. You should NOT take any initiative or make any assumptions about continuing with work. For example you should NOT suggest file changes or attempt to read any files.\nWhen asking the user what you should work on next, you can reference information in the summary which was just generated. However, you should NOT reference information outside of what's contained in the summary for this response. Keep this response CONCISE.</explicit_instructions>`,
toolDenied: () => `The user denied this operation.`,
toolError: (error?: string) => `The tool execution failed with the following error:\n<error>\n${error}\n</error>`,
+3 -2
View File
@@ -1,14 +1,15 @@
import { newTaskToolResponse } from "../prompts/commands"
import { newTaskToolResponse, condenseToolResponse } from "../prompts/commands"
/**
* Processes text for slash commands and transforms them with appropriate instructions
* This is called after parseMentions() to process any slash commands in the user's message
*/
export function parseSlashCommands(text: string): string {
const SUPPORTED_COMMANDS = ["newtask"]
const SUPPORTED_COMMANDS = ["newtask", "smol"]
const commandReplacements: Record<string, string> = {
newtask: newTaskToolResponse(),
smol: condenseToolResponse(),
}
// this currently allows matching prepended whitespace prior to /slash-command
+61
View File
@@ -1676,6 +1676,8 @@ export class Task {
return `[${block.name}]`
case "new_task":
return `[${block.name} for creating a new task]`
case "condense":
return `[${block.name}]`
}
}
@@ -3013,6 +3015,65 @@ export class Task {
break
}
}
case "condense": {
const context: string | undefined = block.params.context
try {
if (block.partial) {
await this.ask("condense", removeClosingTag("context", context), block.partial).catch(() => {})
break
} else {
if (!context) {
this.consecutiveMistakeCount++
pushToolResult(await this.sayAndCreateMissingParamError("condense", "context"))
break
}
this.consecutiveMistakeCount = 0
if (this.autoApprovalSettings.enabled && this.autoApprovalSettings.enableNotifications) {
showSystemNotification({
subtitle: "Cline wants to condense the conversation...",
message: `Cline is suggesting to condense your conversation with: ${context}`,
})
}
const { text, images } = await this.ask("condense", context, false)
// If the user provided a response, treat it as feedback
if (text || images?.length) {
await this.say("user_feedback", text ?? "", images)
pushToolResult(
formatResponse.toolResult(
`The user provided feedback on the condensed conversation summary:\n<feedback>\n${text}\n</feedback>`,
images,
),
)
} else {
// If no response, the user accepted the condensed version
pushToolResult(formatResponse.toolResult(formatResponse.condense()))
const lastMessage = this.apiConversationHistory[this.apiConversationHistory.length - 1]
const summaryAlreadyAppended = lastMessage && lastMessage.role === "assistant"
const keepStrategy = summaryAlreadyAppended ? "lastTwo" : "none"
// clear the context history at this point in time
this.conversationHistoryDeletedRange = this.contextManager.getNextTruncationRange(
this.apiConversationHistory,
this.conversationHistoryDeletedRange,
keepStrategy,
)
await this.saveClineMessagesAndUpdateHistory()
await this.contextManager.triggerApplyStandardContextTruncationNoticeChange(
Date.now(),
await ensureTaskDirectoryExists(this.getContext(), this.taskId),
)
}
break
}
} catch (error) {
await handleError("condensing context window", error)
break
}
}
case "plan_mode_respond": {
const response: string | undefined = block.params.response
const optionsRaw: string | undefined = block.params.options
+1
View File
@@ -183,6 +183,7 @@ export type ClineAsk =
| "browser_action_launch"
| "use_mcp_server"
| "new_task"
| "condense"
export type ClineSay =
| "task"
+2
View File
@@ -12,6 +12,8 @@ export interface WebviewMessage {
| "addRemoteServer"
| "apiConfiguration"
| "webviewDidLaunch"
| "newTask"
| "condense"
| "askResponse"
| "didShowAnnouncement"
| "selectImages"
@@ -1271,6 +1271,23 @@ export const ChatRowContent = ({
<NewTaskPreview context={message.text || ""} />
</>
)
case "condense":
return (
<>
<div style={headerStyle}>
<span
className="codicon codicon-new-file"
style={{
color: normalColor,
marginBottom: "-1.5px",
}}></span>
<span style={{ color: normalColor, fontWeight: "bold" }}>
Cline wants to condense your conversation:
</span>
</div>
<NewTaskPreview context={message.text || ""} />
</>
)
case "plan_mode_respond": {
let response: string | undefined
let options: string[] | undefined
@@ -203,6 +203,13 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
setPrimaryButtonText("Start New Task with Context")
setSecondaryButtonText(undefined)
break
case "condense":
setTextAreaDisabled(isPartial)
setClineAsk("condense")
setEnableButtons(!isPartial)
setPrimaryButtonText("Condense Conversation")
setSecondaryButtonText(undefined)
break
}
break
case "say":
@@ -312,6 +319,14 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
images,
})
break
case "condense":
vscode.postMessage({
type: "askResponse",
askResponse: "messageResponse",
text,
images,
})
break
// there is no other case that a textfield should be enabled
}
}
@@ -377,6 +392,12 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
images: [],
})
break
case "condense":
vscode.postMessage({
type: "condense",
text: lastMessage?.text,
})
break
}
setTextAreaDisabled(true)
setClineAsk(undefined)
+4
View File
@@ -8,6 +8,10 @@ export const SUPPORTED_SLASH_COMMANDS: SlashCommand[] = [
name: "newtask",
description: "Create a new task with context from the current task",
},
{
name: "smol",
description: "Condenses your current context window",
},
]
// Regex for detecting slash commands in text