Add consult advisor row

This commit is contained in:
Saoud Rizwan 2025-01-17 20:35:05 -08:00
parent f4ae4c66df
commit 43bf383784
8 changed files with 262 additions and 4 deletions

View file

@ -31,6 +31,7 @@ import {
ClineApiReqInfo,
ClineAsk,
ClineAskUseMcpServer,
ClineConsultAdvisor,
ClineMessage,
ClineSay,
ClineSayBrowserAction,
@ -1060,6 +1061,8 @@ export class Cline {
message.ask === "followup" ||
message.say === "use_mcp_server" ||
message.ask === "use_mcp_server" ||
message.say === "consult_advisor" ||
message.ask === "consult_advisor" ||
message.say === "browser_action" ||
message.say === "browser_action_launch" ||
message.ask === "browser_action_launch"
@ -1170,6 +1173,8 @@ export class Cline {
case "access_mcp_resource":
case "use_mcp_tool":
return this.autoApprovalSettings.actions.useMcp
case "consult_advisor":
return this.autoApprovalSettings.actions.consultAdvisor ?? false
}
}
return false
@ -1388,6 +1393,8 @@ export class Cline {
return `[${block.name} for '${block.params.server_name}']`
case "access_mcp_resource":
return `[${block.name} for '${block.params.server_name}']`
case "consult_advisor":
return `[${block.name} for '${block.params.problem}']`
case "ask_followup_question":
return `[${block.name} for '${block.params.question}']`
case "attempt_completion":
@ -2474,6 +2481,66 @@ export class Cline {
break
}
}
case "consult_advisor": {
const problem: string | undefined = block.params.problem
try {
if (block.partial) {
const partialMessage = JSON.stringify({
problem: removeClosingTag("problem", problem),
} satisfies ClineConsultAdvisor)
if (this.shouldAutoApproveTool(block.name)) {
this.removeLastPartialMessageIfExistsWithType("ask", "consult_advisor")
await this.say("consult_advisor", partialMessage, undefined, block.partial)
} else {
this.removeLastPartialMessageIfExistsWithType("say", "consult_advisor")
await this.ask("consult_advisor", partialMessage, block.partial).catch(() => {})
}
break
} else {
if (!problem) {
this.consecutiveMistakeCount++
pushToolResult(await this.sayAndCreateMissingParamError("consult_advisor", "problem"))
await this.saveCheckpoint()
break
}
this.consecutiveMistakeCount = 0
const completeMessage = JSON.stringify({
problem: removeClosingTag("problem", problem),
} satisfies ClineConsultAdvisor)
if (this.shouldAutoApproveTool(block.name)) {
this.removeLastPartialMessageIfExistsWithType("ask", "consult_advisor")
await this.say("consult_advisor", completeMessage, undefined, false)
this.consecutiveAutoApprovedRequestsCount++
} else {
showNotificationForApprovalIfAutoApprovalEnabled(
`Cline wants to consult the Advisor model about: ${problem}`,
)
this.removeLastPartialMessageIfExistsWithType("say", "consult_advisor")
const didApprove = await askApproval("consult_advisor", completeMessage)
if (!didApprove) {
await this.saveCheckpoint()
break
}
}
// now execute the tool
await this.say("consult_advisor_request_started")
const resourceResult = "Just try again bro." //await this.providerRef.deref()?.mcpHub?.readResource(server_name, uri)
await this.say("consult_advisor_response", resourceResult)
pushToolResult(formatResponse.toolResult(resourceResult))
await this.saveCheckpoint()
break
}
} catch (error) {
await handleError("consulting advisor", error)
await this.saveCheckpoint()
break
}
}
case "ask_followup_question": {
const question: string | undefined = block.params.question
try {

View file

@ -19,6 +19,7 @@ export const toolUseNames = [
"browser_action",
"use_mcp_tool",
"access_mcp_resource",
"consult_advisor",
"ask_followup_question",
"attempt_completion",
] as const
@ -43,6 +44,7 @@ export const toolParamNames = [
"tool_name",
"arguments",
"uri",
"problem",
"question",
"result",
] as const

View file

@ -206,6 +206,15 @@ Usage:
<uri>resource URI here</uri>
</access_mcp_resource>
## consult_advisor
Description: Request to consult a higher-reasoning advisor model about a problem or question you are facing. This can be used to outline a plan, discuss potential solutions, or resolve errors you are stuck on. The relevant conversation history leading to the problem will also be provided to the advisor for additional context.
Parameters:
- problem: (required) A string describing the issue, question, or context you want the advisor to address.
Usage:
<consult_advisor>
<problem>Your problem or question here</problem>
</consult_advisor>
## ask_followup_question
Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.
Parameters:
@ -816,6 +825,83 @@ You have access to two tools for working with files: **write_to_file** and **rep
By thoughtfully selecting between write_to_file and replace_in_file, you can make your file editing process smoother, safer, and more efficient.
====
CONSULTING THE ADVISOR MODEL
You can use the consult_advisor tool to get higher-level reasoning or suggestions from an advisor model. The advisor is a more powerful AI model that can provide strategic guidance and help solve complex problems. The conversation history that led to the current situation is automatically passed to the advisor, allowing it to provide contextually relevant guidance based on the full picture of the task at hand.
# When to Use the Advisor
1. Architecting Complex Tasks
- Before starting implementation of large features or systems
- When planning new applications or major refactors
- To break down complex requirements into actionable steps
- To identify potential technical challenges early
- To evaluate different technical approaches and their tradeoffs
- When the solution requires careful consideration of multiple system components
2. Resolving Challenging Bugs
- When stuck on persistent bugs that you cannot resolve
- If you've tried multiple approaches without success
- When facing complex type errors or package incompatibilities
- When debugging intricate interactions between multiple systems
- If you need deeper insight into system behavior that may not be apparent
# How to Use Effectively
1. Provide Clear Context
- Explain the current situation and challenge
- Include relevant code snippets or error messages
- Describe what you've already tried
- Specify what kind of guidance you're seeking
2. Ask Specific Questions
- Instead of "Why isn't this working?"
- Better: "I'm encountering this specific type error when integrating these packages, here's what I've tried..."
Example Usage:
<consult_advisor>
<problem>
I'm encountering persistent type errors while working with @types/react-query v4.0.0:
Error: Type 'QueryClient' is not assignable to parameter of type 'never'.
The types of 'getQueryCache().notify' are incompatible between these types.
I've tried:
- Checking package versions compatibility
- Explicitly typing the QueryClient instance
- Updating @types/react and @types/react-query
Current package versions:
react-query: ^3.39.3
@types/react-query: ^4.0.0
react: ^18.2.0
typescript: ^4.9.5
The error persists despite these attempts. Could this be due to version mismatches or breaking changes I'm not aware of?
</problem>
</consult_advisor>
# Benefits of Using the Advisor
1. Strategic Guidance
- Get high-level architectural direction
- Identify potential pitfalls early
- Make informed technical decisions
- Consider long-term implications
2. Problem Resolution
- Break through debugging roadblocks
- Get fresh perspectives on complex issues
- Understand root causes of persistent bugs
- Solve challenging technical issues
Remember: While you should attempt to solve problems with your own reasoning first, the advisor is a powerful resource available when you're either planning complex systems or truly stuck on a bug. Don't hesitate to consult it when:
- The scope of the task requires careful architectural planning
- You've hit a persistent roadblock that you cannot resolve
- You need deeper insight into complex system interactions
====
CAPABILITIES

View file

@ -8,6 +8,7 @@ export interface AutoApprovalSettings {
executeCommands: boolean // Execute safe commands
useBrowser: boolean // Use browser
useMcp: boolean // Use MCP servers
consultAdvisor?: boolean // Consult the advisor model
}
// Global settings
maxRequests: number // Maximum number of auto-approved requests
@ -22,6 +23,7 @@ export const DEFAULT_AUTO_APPROVAL_SETTINGS: AutoApprovalSettings = {
executeCommands: false,
useBrowser: false,
useMcp: false,
consultAdvisor: false,
},
maxRequests: 20,
enableNotifications: false,

View file

@ -74,6 +74,7 @@ export type ClineAsk =
| "auto_approval_max_req_reached"
| "browser_action_launch"
| "use_mcp_server"
| "consult_advisor"
export type ClineSay =
| "task"
@ -95,6 +96,9 @@ export type ClineSay =
| "mcp_server_request_started"
| "mcp_server_response"
| "use_mcp_server"
| "consult_advisor"
| "consult_advisor_request_started"
| "consult_advisor_response"
| "diff_error"
| "deleted_api_reqs"
@ -139,6 +143,10 @@ export interface ClineAskUseMcpServer {
uri?: string
}
export interface ClineConsultAdvisor {
problem: string
}
export interface ClineApiReqInfo {
request?: string
tokensIn?: number

View file

@ -46,16 +46,25 @@ const ACTION_METADATA: {
shortName: "MCP",
description: "Allows use of configured MCP servers which may modify filesystem or interact with APIs.",
},
{
id: "consultAdvisor",
label: "Consult the Advisor model",
shortName: "Advisor",
description: "Allows Cline to consult the Advisor model to get advice on how to proceed.",
},
]
const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
const { autoApprovalSettings } = useExtensionState()
const { autoApprovalSettings, apiConfiguration } = useExtensionState()
const [isExpanded, setIsExpanded] = useState(false)
const [isHoveringCollapsibleSection, setIsHoveringCollapsibleSection] = useState(false)
// Careful not to use partials to mutate since spread operator only does shallow copy
const enabledActions = ACTION_METADATA.filter((action) => autoApprovalSettings.actions[action.id])
const supportsAdvisor = apiConfiguration?.apiProvider === "openrouter"
const actionMetadata = ACTION_METADATA.filter((action) => supportsAdvisor || action.id !== "consultAdvisor")
const enabledActions = actionMetadata.filter((action) => autoApprovalSettings.actions[action.id])
const enabledActionsList = enabledActions.map((action) => action.shortName).join(", ")
const hasEnabledActions = enabledActions.length > 0
@ -219,7 +228,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
Auto-approve allows Cline to perform the following actions without asking for permission. Please use with
caution and only enable if you understand the risks.
</div>
{ACTION_METADATA.map((action) => (
{actionMetadata.map((action) => (
<div key={action.id} style={{ margin: "6px 0" }}>
<VSCodeCheckbox
checked={autoApprovalSettings.actions[action.id]}

View file

@ -10,6 +10,7 @@ import {
ClineSayTool,
ExtensionMessage,
COMPLETION_RESULT_CHANGES_FLAG,
ClineConsultAdvisor,
} from "../../../../src/shared/ExtensionMessage"
import { COMMAND_OUTPUT_STRING, COMMAND_REQ_APP_STRING } from "../../../../src/shared/combineCommandSequences"
import { useExtensionState } from "../../context/ExtensionStateContext"
@ -62,7 +63,9 @@ const ChatRow = memo(
message.say === "completion_result" ||
message.ask === "completion_result" ||
message.say === "use_mcp_server" ||
message.ask === "use_mcp_server")
message.ask === "use_mcp_server" ||
message.say === "consult_advisor" ||
message.ask === "consult_advisor")
if (shouldShowCheckpoints && isLast) {
shouldShowCheckpoints =
@ -121,6 +124,7 @@ export const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifi
lastModifiedMessage?.text?.includes(COMMAND_OUTPUT_STRING)
const isMcpServerResponding = isLast && lastModifiedMessage?.say === "mcp_server_request_started"
const isConsultAdvisorResponding = isLast && lastModifiedMessage?.say === "consult_advisor_request_started"
const type = message.type === "ask" ? message.ask : message.say
@ -216,6 +220,27 @@ export const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifi
)}
</span>,
]
case "consult_advisor":
// const consultAdvisor = JSON.parse(message.text || "{}") as ClineConsultAdvisor
return [
isConsultAdvisorResponding ? (
<ProgressIndicator />
) : (
<span
className="codicon codicon-server"
style={{
color: normalColor,
marginBottom: "-1.5px",
}}></span>
),
<span style={{ color: normalColor, fontWeight: "bold" }}>
{message.type === "ask" ? (
<>Cline wants to consult the Advisor model about:</>
) : (
<>Cline consulted the Advisor model about:</>
)}
</span>,
]
case "completion_result":
return [
<span
@ -718,6 +743,29 @@ export const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifi
)
}
if (message.ask === "consult_advisor" || message.say === "consult_advisor") {
const consultAdvisor = JSON.parse(message.text || "{}") as ClineConsultAdvisor
// const server = mcpServers.find((server) => server.name === useMcpServer.serverName)
return (
<>
<div style={headerStyle}>
{icon}
{title}
</div>
<div
style={{
background: "var(--vscode-textCodeBlock-background)",
borderRadius: "3px",
padding: "8px 10px",
marginTop: "8px",
}}>
{consultAdvisor.problem}
</div>
</>
)
}
switch (message.type) {
case "say":
switch (message.say) {
@ -1041,6 +1089,28 @@ export const ChatRowContent = ({ message, isExpanded, onToggleExpand, lastModifi
</div>
</>
)
case "consult_advisor_response":
return (
<>
<div style={{ paddingTop: 0 }}>
<div
style={{
marginBottom: "4px",
opacity: 0.8,
fontSize: "12px",
textTransform: "uppercase",
}}>
Response
</div>
<CodeAccordian
code={message.text}
language="json"
isExpanded={true}
onToggleExpand={onToggleExpand}
/>
</div>
</>
)
default:
return (
<>

View file

@ -148,6 +148,13 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
setPrimaryButtonText("Approve")
setSecondaryButtonText("Reject")
break
case "consult_advisor":
setTextAreaDisabled(isPartial)
setClineAsk("consult_advisor")
setEnableButtons(!isPartial)
setPrimaryButtonText("Approve")
setSecondaryButtonText("Reject")
break
case "completion_result":
// extension waiting for feedback. but we can just present a new task button
setTextAreaDisabled(isPartial)
@ -196,9 +203,12 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
case "browser_action_launch":
case "command":
case "use_mcp_server":
case "consult_advisor":
case "command_output":
case "mcp_server_request_started":
case "mcp_server_response":
case "consult_advisor_request_started":
case "consult_advisor_response":
case "completion_result":
case "tool":
break
@ -267,6 +277,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
case "command": // user can provide feedback to a tool or command use
case "command_output": // user can send input to command stdin
case "use_mcp_server":
case "consult_advisor":
case "completion_result": // if this happens then the user has feedback for the completion result
case "resume_task":
case "resume_completed_task":
@ -309,6 +320,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
case "tool":
case "browser_action_launch":
case "use_mcp_server":
case "consult_advisor":
case "resume_task":
case "mistake_limit_reached":
case "auto_approval_max_req_reached":
@ -348,6 +360,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
case "tool":
case "browser_action_launch":
case "use_mcp_server":
case "consult_advisor":
// responds to the API with a "This operation failed" and lets it try again
vscode.postMessage({
type: "askResponse",
@ -459,6 +472,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
}
break
case "mcp_server_request_started":
case "consult_advisor_request_started":
return false
}
return true