mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
Add mode switch event
This commit is contained in:
parent
9164e5e203
commit
238a4137d3
11 changed files with 62 additions and 67 deletions
|
|
@ -71,6 +71,11 @@ export const taskEventSchema = z.discriminatedUnion("eventName", [
|
|||
payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskStarted],
|
||||
taskId: z.number().optional(),
|
||||
}),
|
||||
z.object({
|
||||
eventName: z.literal(RooCodeEventName.TaskModeSwitched),
|
||||
payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskModeSwitched],
|
||||
taskId: z.number().optional(),
|
||||
}),
|
||||
z.object({
|
||||
eventName: z.literal(RooCodeEventName.TaskPaused),
|
||||
payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskPaused],
|
||||
|
|
|
|||
|
|
@ -795,6 +795,7 @@ export enum RooCodeEventName {
|
|||
Message = "message",
|
||||
TaskCreated = "taskCreated",
|
||||
TaskStarted = "taskStarted",
|
||||
TaskModeSwitched = "taskModeSwitched",
|
||||
TaskPaused = "taskPaused",
|
||||
TaskUnpaused = "taskUnpaused",
|
||||
TaskAskResponded = "taskAskResponded",
|
||||
|
|
@ -814,6 +815,7 @@ export const rooCodeEventsSchema = z.object({
|
|||
]),
|
||||
[RooCodeEventName.TaskCreated]: z.tuple([z.string()]),
|
||||
[RooCodeEventName.TaskStarted]: z.tuple([z.string()]),
|
||||
[RooCodeEventName.TaskModeSwitched]: z.tuple([z.string(), z.string()]),
|
||||
[RooCodeEventName.TaskPaused]: z.tuple([z.string()]),
|
||||
[RooCodeEventName.TaskUnpaused]: z.tuple([z.string()]),
|
||||
[RooCodeEventName.TaskAskResponded]: z.tuple([z.string()]),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
menu() {
|
||||
echo -e "\nWhich eval types would you like to support?\n"
|
||||
echo -e "\n📋 Which eval types would you like to support?\n"
|
||||
|
||||
for i in ${!options[@]}; do
|
||||
printf "%d %6s [%s]" $((i + 1)) "${options[i]}" "${choices[i]:- }"
|
||||
printf " %d) %-6s [%s]" $((i + 1)) "${options[i]}" "${choices[i]:- }"
|
||||
|
||||
if [[ $i == 0 ]]; then
|
||||
printf " (required)"
|
||||
|
|
@ -13,11 +13,11 @@ menu() {
|
|||
printf "\n"
|
||||
done
|
||||
|
||||
echo
|
||||
echo -e " q) quit\n"
|
||||
}
|
||||
|
||||
build_extension() {
|
||||
echo "Building the Roo Code extension..."
|
||||
echo "🔨 Building the Roo Code extension..."
|
||||
cd ..
|
||||
mkdir -p bin
|
||||
npm run install-extension -- --silent --no-audit || exit 1
|
||||
|
|
@ -29,7 +29,7 @@ build_extension() {
|
|||
}
|
||||
|
||||
if [[ "$(uname -s)" != "Darwin" ]]; then
|
||||
echo "Only macOS is currently supported."
|
||||
echo "⚠️ Only macOS is currently supported."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -43,19 +43,11 @@ for i in "${!options[@]}"; do
|
|||
choices[i]="*"
|
||||
done
|
||||
|
||||
prompt="Type 🔢 to select, 'a' for all, 'q' to quit, ⏎ to continue: "
|
||||
prompt="Type 1-5 to select, 'q' to quit, ⏎ to continue: "
|
||||
|
||||
while menu && read -rp "$prompt" num && [[ "$num" ]]; do
|
||||
[[ "$num" == "q" ]] && exit 0
|
||||
|
||||
[[ "$num" == "a" ]] && {
|
||||
for i in ${!options[@]}; do
|
||||
choices[i]="*"
|
||||
done
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
[[ "$num" != *[![:digit:]]* ]] &&
|
||||
((num > 1 && num <= ${#options[@]})) ||
|
||||
{
|
||||
|
|
@ -81,14 +73,14 @@ printf "\n"
|
|||
|
||||
if ! command -v brew &>/dev/null; then
|
||||
if [[ -f "/opt/homebrew/bin/brew" ]]; then
|
||||
echo "Homebrew is installed but not in your PATH"
|
||||
echo "⚠️ Homebrew is installed but not in your PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
read -p "Homebrew (https://brew.sh) is required. Install it? (Y/n): " install_brew
|
||||
read -p "🍺 Homebrew (https://brew.sh) is required. Install it? (Y/n): " install_brew
|
||||
|
||||
if [[ "$install_brew" =~ ^[Yy]|^$ ]]; then
|
||||
echo "☕ Installing Homebrew..."
|
||||
echo "🍺 Installing Homebrew..."
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || exit 1
|
||||
# Can be undone with:
|
||||
# /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)" && sudo rm -rvf /opt/homebrew
|
||||
|
|
@ -119,14 +111,14 @@ ASDF_PATH="$(brew --prefix asdf)/libexec/asdf.sh"
|
|||
|
||||
if ! command -v asdf &>/dev/null; then
|
||||
if [[ -f "$ASDF_PATH" ]]; then
|
||||
echo "asdf is installed but not in your PATH"
|
||||
echo "⚠️ asdf is installed but not in your PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
read -p "asdf (https://asdf-vm.com) is required. Install it? (Y/n): " install_asdf
|
||||
read -p "🛠️ asdf (https://asdf-vm.com) is required. Install it? (Y/n): " install_asdf
|
||||
|
||||
if [[ "$install_asdf" =~ ^[Yy]|^$ ]]; then
|
||||
echo "Installing asdf..."
|
||||
echo "🛠️ Installing asdf..."
|
||||
brew install asdf || exit 1
|
||||
# Can be undone with:
|
||||
# brew uninstall asdf
|
||||
|
|
@ -152,7 +144,7 @@ else
|
|||
fi
|
||||
|
||||
if ! command -v gh &>/dev/null; then
|
||||
read -p "GitHub cli is needed to submit evals results. Install it? (Y/n): " install_gh
|
||||
read -p "👨💻 GitHub cli is needed to submit evals results. Install it? (Y/n): " install_gh
|
||||
|
||||
if [[ "$install_gh" =~ ^[Yy]|^$ ]]; then
|
||||
brew install gh || exit 1
|
||||
|
|
@ -173,9 +165,9 @@ for i in "${!options[@]}"; do
|
|||
|
||||
if [[ "${has_asdf_plugin[$plugin]}" == "true" ]]; then
|
||||
if ! asdf plugin list | grep -q "^${plugin}$" && ! command -v "${binary}" &>/dev/null; then
|
||||
echo "Installing ${plugin} asdf plugin..."
|
||||
echo "📦 Installing ${plugin} asdf plugin..."
|
||||
asdf plugin add "${plugin}" || exit 1
|
||||
echo "✅ asdf ${plugin} plugin installed"
|
||||
echo "✅ asdf ${plugin} plugin installed successfully"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
@ -194,7 +186,7 @@ for i in "${!options[@]}"; do
|
|||
if [[ $(node --version) != "v20.18.1" ]]; then
|
||||
NODE_VERSION=$(node --version)
|
||||
echo "🚨 You have the wrong version of node installed ($NODE_VERSION)."
|
||||
echo "If you are using nvm then run 'nvm install' to install the version specified by the repo's .nvmrc."
|
||||
echo "💡 If you are using nvm then run 'nvm install' to install the version specified by the repo's .nvmrc."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
|
@ -246,7 +238,7 @@ for i in "${!options[@]}"; do
|
|||
|
||||
"java")
|
||||
if ! command -v javac &>/dev/null || ! javac --version &>/dev/null; then
|
||||
echo "Installing Java..."
|
||||
echo "☕ Installing Java..."
|
||||
brew install openjdk@17 || exit 1
|
||||
|
||||
export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"
|
||||
|
|
@ -280,7 +272,7 @@ pnpm install --silent || exit 1
|
|||
|
||||
if [[ ! -d "../../evals" ]]; then
|
||||
if gh auth status &>/dev/null; then
|
||||
read -p "Would you like to be able to share eval results? (Y/n): " fork_evals
|
||||
read -p "🔗 Would you like to be able to share eval results? (Y/n): " fork_evals
|
||||
|
||||
if [[ "$fork_evals" =~ ^[Yy]|^$ ]]; then
|
||||
gh repo fork cte/evals ../../evals || exit 1
|
||||
|
|
@ -297,14 +289,14 @@ if [[ ! -s .env ]]; then
|
|||
fi
|
||||
|
||||
if ! grep -q "OPENROUTER_API_KEY" .env; then
|
||||
read -p "Enter your OpenRouter API Key (sk-or-v1-...): " openrouter_api_key
|
||||
echo "Validating OpenRouter API Key..."
|
||||
curl --silent --fail https://openrouter.ai/api/v1/key -H "Authorization: Bearer $openrouter_api_key" | jq || exit 1
|
||||
read -p "🔐 Enter your OpenRouter API key (sk-or-v1-...): " openrouter_api_key
|
||||
echo "🔑 Validating..."
|
||||
curl --silent --fail https://openrouter.ai/api/v1/key -H "Authorization: Bearer $openrouter_api_key" || echo "⚠️ Invalid API key" && exit 1
|
||||
echo "OPENROUTER_API_KEY=$openrouter_api_key" >>.env
|
||||
fi
|
||||
|
||||
if ! command -v code &>/dev/null; then
|
||||
echo "Visual Studio Code cli is not installed"
|
||||
echo "⚠️ Visual Studio Code cli is not installed"
|
||||
exit 1
|
||||
else
|
||||
VSCODE_VERSION=$(code --version | head -n 1)
|
||||
|
|
@ -314,7 +306,7 @@ fi
|
|||
if [[ ! -s "../bin/roo-code-latest.vsix" ]]; then
|
||||
build_extension
|
||||
else
|
||||
read -p "Do you want to build a new version of the Roo Code extension? (y/N): " build_extension
|
||||
read -p "💻 Do you want to build a new version of the Roo Code extension? (y/N): " build_extension
|
||||
|
||||
if [[ "$build_extension" =~ ^[Yy]$ ]]; then
|
||||
build_extension
|
||||
|
|
@ -323,16 +315,16 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
echo -e "\n🤘 You're ready to rock and roll!\n"
|
||||
echo -e "\n🚀 You're ready to rock and roll! \n"
|
||||
|
||||
if ! nc -z localhost 3000; then
|
||||
read -p "Would you like to start the evals web app? (y/N): " start_evals
|
||||
read -p "🚀 Would you like to start the evals web app? (y/N): " start_evals
|
||||
|
||||
if [[ "$start_evals" =~ ^[Yy]$ ]]; then
|
||||
pnpm web
|
||||
else
|
||||
echo "You can start it anytime with 'pnpm web'."
|
||||
echo "💡 You can start it anytime with 'pnpm web'."
|
||||
fi
|
||||
else
|
||||
echo "🤖 The evals web app is running at http://localhost:3000"
|
||||
echo "🌐 The evals web app is running at http://localhost:3000"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -13,11 +13,17 @@ suite("Roo Code Modes", () => {
|
|||
*/
|
||||
|
||||
const switchModesPrompt =
|
||||
"For each mode (Code, Architect, Ask) respond with the mode name and what it specializes in after switching to that mode. " +
|
||||
"Do not start with the current mode."
|
||||
"For each mode (Architect, Ask, Debug) respond with the mode name and what it specializes in after switching to that mode."
|
||||
|
||||
let messages: ClineMessage[] = []
|
||||
|
||||
const modeSwitches: string[] = []
|
||||
|
||||
api.on("taskModeSwitched", (_taskId, mode) => {
|
||||
console.log("taskModeSwitched", mode)
|
||||
modeSwitches.push(mode)
|
||||
})
|
||||
|
||||
api.on("message", ({ message }) => {
|
||||
if (message.type === "say" && message.partial === false) {
|
||||
messages.push(message)
|
||||
|
|
@ -25,36 +31,13 @@ suite("Roo Code Modes", () => {
|
|||
})
|
||||
|
||||
const switchModesTaskId = await api.startNewTask({
|
||||
configuration: { mode: "Code", alwaysAllowModeSwitch: true, autoApprovalEnabled: true },
|
||||
configuration: { mode: "code", alwaysAllowModeSwitch: true, autoApprovalEnabled: true },
|
||||
text: switchModesPrompt,
|
||||
})
|
||||
|
||||
await waitUntilCompleted({ api, taskId: switchModesTaskId, timeout: 60_000 })
|
||||
|
||||
/**
|
||||
* Grade the response.
|
||||
*/
|
||||
|
||||
const response = messages
|
||||
.filter(({ type, say, partial }) => say === "text")
|
||||
.map(({ text }) => text ?? "")
|
||||
.join("\n")
|
||||
|
||||
const gradePrompt = `Given this prompt: ${switchModesPrompt} grade the response from 1 to 10 in the format of "Grade: (1-10)". For example: Grade 7\n\nResponse: ${response}`
|
||||
|
||||
messages = []
|
||||
|
||||
const gradeTaskId = await api.startNewTask({ configuration: { mode: "Ask" }, text: gradePrompt })
|
||||
await waitUntilCompleted({ api, taskId: gradeTaskId })
|
||||
|
||||
const completion = messages.find(({ type, say, partial }) => say === "completion_result")
|
||||
const match = completion?.text?.match(/Grade: (\d+)/)
|
||||
const score = parseInt(match?.[1] ?? "0")
|
||||
assert.ok(
|
||||
score >= 7 && score <= 10,
|
||||
`Grade must be between 7 and 10. DEBUG: score = ${score}, completion = ${completion?.text}`,
|
||||
)
|
||||
|
||||
await waitUntilCompleted({ api, taskId: switchModesTaskId })
|
||||
await api.cancelCurrentTask()
|
||||
|
||||
assert.deepEqual(modeSwitches.sort(), ["architect", "ask", "debug"])
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ type UserContent = Array<Anthropic.Messages.ContentBlockParam>
|
|||
export type ClineEvents = {
|
||||
message: [{ action: "created" | "updated"; message: ClineMessage }]
|
||||
taskStarted: []
|
||||
taskModeSwitched: [taskId: string, mode: string]
|
||||
taskPaused: []
|
||||
taskUnpaused: []
|
||||
taskAskResponded: []
|
||||
|
|
|
|||
|
|
@ -740,10 +740,11 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
*/
|
||||
public async handleModeSwitch(newMode: Mode) {
|
||||
// Capture mode switch telemetry event
|
||||
const currentTaskId = this.getCurrentCline()?.taskId
|
||||
const cline = this.getCurrentCline()
|
||||
|
||||
if (currentTaskId) {
|
||||
telemetryService.captureModeSwitch(currentTaskId, newMode)
|
||||
if (cline) {
|
||||
telemetryService.captureModeSwitch(cline.taskId, newMode)
|
||||
cline.emit("taskModeSwitched", cline.taskId, newMode)
|
||||
}
|
||||
|
||||
await this.updateGlobalState("mode", newMode)
|
||||
|
|
|
|||
|
|
@ -176,6 +176,8 @@ export class API extends EventEmitter<RooCodeEvents> implements RooCodeAPI {
|
|||
|
||||
cline.on("message", (message) => this.emit(RooCodeEventName.Message, { taskId: cline.taskId, ...message }))
|
||||
|
||||
cline.on("taskModeSwitched", (taskId, mode) => this.emit(RooCodeEventName.TaskModeSwitched, taskId, mode))
|
||||
|
||||
cline.on("taskTokenUsageUpdated", (_, usage) =>
|
||||
this.emit(RooCodeEventName.TaskTokenUsageUpdated, cline.taskId, usage),
|
||||
)
|
||||
|
|
|
|||
2
src/exports/roo-code.d.ts
vendored
2
src/exports/roo-code.d.ts
vendored
|
|
@ -470,6 +470,7 @@ type RooCodeEvents = {
|
|||
]
|
||||
taskCreated: [string]
|
||||
taskStarted: [string]
|
||||
taskModeSwitched: [string, string]
|
||||
taskPaused: [string]
|
||||
taskUnpaused: [string]
|
||||
taskAskResponded: [string]
|
||||
|
|
@ -506,6 +507,7 @@ declare enum RooCodeEventName {
|
|||
Message = "message",
|
||||
TaskCreated = "taskCreated",
|
||||
TaskStarted = "taskStarted",
|
||||
TaskModeSwitched = "taskModeSwitched",
|
||||
TaskPaused = "taskPaused",
|
||||
TaskUnpaused = "taskUnpaused",
|
||||
TaskAskResponded = "taskAskResponded",
|
||||
|
|
|
|||
|
|
@ -479,6 +479,7 @@ type RooCodeEvents = {
|
|||
]
|
||||
taskCreated: [string]
|
||||
taskStarted: [string]
|
||||
taskModeSwitched: [string, string]
|
||||
taskPaused: [string]
|
||||
taskUnpaused: [string]
|
||||
taskAskResponded: [string]
|
||||
|
|
|
|||
|
|
@ -797,6 +797,7 @@ export enum RooCodeEventName {
|
|||
Message = "message",
|
||||
TaskCreated = "taskCreated",
|
||||
TaskStarted = "taskStarted",
|
||||
TaskModeSwitched = "taskModeSwitched",
|
||||
TaskPaused = "taskPaused",
|
||||
TaskUnpaused = "taskUnpaused",
|
||||
TaskAskResponded = "taskAskResponded",
|
||||
|
|
@ -816,6 +817,7 @@ export const rooCodeEventsSchema = z.object({
|
|||
]),
|
||||
[RooCodeEventName.TaskCreated]: z.tuple([z.string()]),
|
||||
[RooCodeEventName.TaskStarted]: z.tuple([z.string()]),
|
||||
[RooCodeEventName.TaskModeSwitched]: z.tuple([z.string(), z.string()]),
|
||||
[RooCodeEventName.TaskPaused]: z.tuple([z.string()]),
|
||||
[RooCodeEventName.TaskUnpaused]: z.tuple([z.string()]),
|
||||
[RooCodeEventName.TaskAskResponded]: z.tuple([z.string()]),
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ export const taskEventSchema = z.discriminatedUnion("eventName", [
|
|||
eventName: z.literal(RooCodeEventName.TaskStarted),
|
||||
payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskStarted],
|
||||
}),
|
||||
z.object({
|
||||
eventName: z.literal(RooCodeEventName.TaskModeSwitched),
|
||||
payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskModeSwitched],
|
||||
}),
|
||||
z.object({
|
||||
eventName: z.literal(RooCodeEventName.TaskPaused),
|
||||
payload: rooCodeEventsSchema.shape[RooCodeEventName.TaskPaused],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue