Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/types/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ export const clineSays = [
"condense_context_error",
"codebase_search_result",
"user_edit_todos",
"offer_pr",
"pr_reviewer_upsell",
] as const

export const clineSaySchema = z.enum(clineSays)
Expand Down
12 changes: 12 additions & 0 deletions packages/types/src/mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,16 @@ export const DEFAULT_MODES: readonly ModeConfig[] = [
customInstructions:
"Your role is to coordinate complex workflows by delegating tasks to specialized modes. As an orchestrator, you should:\n\n1. When given a complex task, break it down into logical subtasks that can be delegated to appropriate specialized modes.\n\n2. For each subtask, use the `new_task` tool to delegate. Choose the most appropriate mode for the subtask's specific goal and provide comprehensive instructions in the `message` parameter. These instructions must include:\n * All necessary context from the parent task or previous subtasks required to complete the work.\n * A clearly defined scope, specifying exactly what the subtask should accomplish.\n * An explicit statement that the subtask should *only* perform the work outlined in these instructions and not deviate.\n * An instruction for the subtask to signal completion by using the `attempt_completion` tool, providing a concise yet thorough summary of the outcome in the `result` parameter, keeping in mind that this summary will be the source of truth used to keep track of what was completed on this project.\n * A statement that these specific instructions supersede any conflicting general instructions the subtask's mode might have.\n\n3. Track and manage the progress of all subtasks. When a subtask is completed, analyze its results and determine the next steps.\n\n4. Help the user understand how the different subtasks fit together in the overall workflow. Provide clear reasoning about why you're delegating specific tasks to specific modes.\n\n5. When all subtasks are completed, synthesize the results and provide a comprehensive overview of what was accomplished.\n\n6. Ask clarifying questions when necessary to better understand how to break down complex tasks effectively.\n\n7. Suggest improvements to the workflow based on the results of completed subtasks.\n\nUse subtasks to maintain clarity. If a request significantly shifts focus or requires a different expertise (mode), consider creating a subtask rather than overloading the current one.",
},
{
slug: "pr-creator",
name: "📝 PR Creator",
roleDefinition:
"You are Roo, a pull request documentation specialist focused on creating comprehensive, well-structured PR descriptions that follow conventional commit standards and best practices.",
whenToUse:
"Use this mode when you need to create a pull request. Analyzes git changes, commit history, and test coverage to generate professional PR descriptions with proper commit prefixes.",
description: "Create professional pull request descriptions",
groups: ["read", "command"],
customInstructions:
"Your workflow:\n\n1. Analyze the current branch and changes:\n - Run 'git branch --show-current' to get current branch\n - Run 'git diff origin/main...HEAD' to see all changes\n - Run 'git log origin/main..HEAD --oneline' to see commits\n\n2. Determine the commit type prefix by analyzing changes:\n - feat: New features or capabilities\n - fix: Bug fixes\n - ux: User experience improvements\n - docs: Documentation changes\n - chore: Maintenance tasks\n - refactor: Code restructuring\n - test: Test additions or updates\n - perf: Performance improvements\n - style: Code style/formatting changes\n\n3. Create a comprehensive PR description with:\n - Clear title with conventional commit prefix\n - Summary of changes (what & why)\n - Key modifications organized by category\n - Test coverage summary (new tests, modified tests, coverage %)\n - Breaking changes section (if applicable)\n - Related issues/tickets\n\n4. Execute PR creation:\n - Use: gh pr create --repo OWNER/REPO --head <current-branch> --base main --title \"<prefix>: <summary>\" --body \"<description>\"\n - Always target 'main' as base branch\n - Ensure title follows conventional commits format\n\n5. After successful PR creation:\n - Report the PR URL\n - Summarize what was included\n - Use attempt_completion to finish\n\nStay focused on PR creation - do not switch modes or perform other tasks.",
},
] as const
8 changes: 8 additions & 0 deletions src/core/tools/attemptCompletionTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ export async function attemptCompletionTool(
return
}

// Send offer_pr message if not in PR Creator mode
if (cline.taskMode !== "pr-creator") {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential race condition: For new tasks (not from history), taskMode is initialized asynchronously but accessed synchronously here. The taskMode getter throws an error if accessed before initialization completes. While this may work in practice due to the async nature of the LLM request loop, it's not guaranteed that taskModeReady will resolve before attempt_completion is called. Consider using await cline.getTaskMode() instead to safely handle the async initialization.

await cline.say("offer_pr", "", undefined, false)
} else {
// In PR Creator mode, send PR Reviewer upsell after completion
await cline.say("pr_reviewer_upsell", "", undefined, false)
}

// We already sent completion_result says, an
// empty string asks relinquishes control over
// button and field.
Expand Down
46 changes: 45 additions & 1 deletion webview-ui/src/components/chat/ChatRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import {
FolderTree,
TerminalSquare,
MessageCircle,
GitPullRequest,
} from "lucide-react"
import { cn } from "@/lib/utils"

Expand Down Expand Up @@ -130,8 +131,14 @@ export const ChatRowContent = ({
}: ChatRowContentProps) => {
const { t } = useTranslation()

const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode, apiConfiguration } = useExtensionState()
const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode, apiConfiguration, cloudApiUrl, cloudIsAuthenticated } =
useExtensionState()
const { info: model } = useSelectedModel(apiConfiguration)

// Function to switch modes
const switchToMode = useCallback((modeSlug: string) => {
vscode.postMessage({ type: "mode", text: modeSlug })
}, [])
const [isEditing, setIsEditing] = useState(false)
const [editedContent, setEditedContent] = useState("")
const [editMode, setEditMode] = useState<Mode>(mode || "code")
Expand Down Expand Up @@ -1254,6 +1261,43 @@ export const ChatRowContent = ({
return <CodebaseSearchResultsDisplay results={results} />
case "user_edit_todos":
return <UpdateTodoListToolBlock userEdited onChange={() => {}} />
case "offer_pr":
return (
<>
<div style={headerStyle}>
<GitPullRequest className="w-4 shrink-0" aria-label="Pull request icon" />
<span style={{ fontWeight: "bold" }}>{t("chat:offerPr.title")}</span>
</div>
<div className="ml-6 flex items-center gap-2">
<span>{t("chat:offerPr.description")}</span>
<button
onClick={() => switchToMode("pr-creator")}
className="text-vscode-textLink-foreground hover:underline cursor-pointer bg-transparent border-none p-0">
{t("chat:offerPr.switchToPrCreator")}
</button>
</div>
</>
)
case "pr_reviewer_upsell":
// Only show if user is authenticated to Cloud
if (!cloudIsAuthenticated) {
return null
}
return (
<div className="ml-6 text-sm mt-2">
{t("chat:prReviewerUpsell.message")}{" "}
<button
onClick={() => {
vscode.postMessage({
type: "openExternal",
url: `${cloudApiUrl}/cloud-agents/create`,
})
}}
className="text-vscode-textLink-foreground hover:underline cursor-pointer bg-transparent border-none p-0">
[{t("chat:prReviewerUpsell.createLink")}]
</button>
</div>
)
case "tool" as any:
// Handle say tool messages
const sayTool = safeJsonParse<ClineSayTool>(message.text)
Expand Down
11 changes: 10 additions & 1 deletion webview-ui/src/i18n/locales/en/chat.json
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,17 @@
"cloudAgents": {
"create": "Create",
"title": "Cloud Agents",
"description": "You havent created any Cloud Agents yet.",
"description": "You haven't created any Cloud Agents yet.",
"createFirst": "Create your first",
"clickToRun": "Click to run {{name}}"
},
"offerPr": {
"title": "Create Pull Request",
"description": "Would you like to create a pull request for these changes?",
"switchToPrCreator": "Switch to PR Creator"
},
"prReviewerUpsell": {
"message": "Get Roo to review this in the Cloud",
"createLink": "Create a PR Reviewer Agent"
}
}
Loading