diff --git a/.changeset/many-results-read.md b/.changeset/many-results-read.md new file mode 100644 index 00000000000..ab2194808a6 --- /dev/null +++ b/.changeset/many-results-read.md @@ -0,0 +1,5 @@ +--- +"kilo-code": minor +--- + +feat(mode): implement Ralph mode for infinite task loops diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 1568bc2af92..4688d03b62b 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -244,6 +244,10 @@ export const globalSettingsSchema = z.object({ lastModeExportPath: z.string().optional(), lastModeImportPath: z.string().optional(), appendSystemPrompt: z.string().optional(), // kilocode_change: Custom text to append to system prompt (CLI only) + alwaysAllowRalph: z.boolean().optional(), // kilocode_change + ralphEnabled: z.boolean().optional(), // kilocode_change + ralphLoopLimit: z.number().int().min(0).optional(), // kilocode_change + ralphCompletionDelimiter: z.string().optional(), // kilocode_change }) export type GlobalSettings = z.infer @@ -368,6 +372,9 @@ export const EVALS_SETTINGS: RooCodeSettings = { alwaysAllowModeSwitch: true, alwaysAllowSubtasks: true, alwaysAllowExecute: true, + alwaysAllowRalph: false, // kilocode_change + ralphLoopLimit: 5, // kilocode_change + ralphCompletionDelimiter: "COMPLETED", // kilocode_change alwaysAllowFollowupQuestions: true, followupAutoApproveTimeoutMs: 0, allowedCommands: ["*"], diff --git a/packages/types/src/task.ts b/packages/types/src/task.ts index 327e2a32866..e0bb48e21c8 100644 --- a/packages/types/src/task.ts +++ b/packages/types/src/task.ts @@ -97,6 +97,7 @@ export interface CreateTaskOptions { initialTodos?: TodoItem[] /** Initial status for the task's history item (e.g., "active" for child tasks) */ initialStatus?: "active" | "delegated" | "completed" + ralphLoopCount?: number // kilocode_change } export enum TaskStatus { @@ -110,6 +111,7 @@ export enum TaskStatus { export const taskMetadataSchema = z.object({ task: z.string().optional(), images: z.array(z.string()).optional(), + ralphLoopCount: z.number().int().min(0).optional(), // kilocode_change }) export type TaskMetadata = z.infer diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts index 40beeb88563..ba48c4bb50d 100644 --- a/src/core/assistant-message/presentAssistantMessage.ts +++ b/src/core/assistant-message/presentAssistantMessage.ts @@ -888,11 +888,16 @@ export async function presentAssistantMessage(cline: Task) { // If execution is not allowed, notify user and break. if (!repetitionCheck.allowExecution && repetitionCheck.askUser) { // Handle repetition similar to mistake_limit_reached pattern. - const { response, text, images } = await cline.ask( - repetitionCheck.askUser.messageKey as ClineAsk, + const result = await cline.handleMistakeLimitReached( repetitionCheck.askUser.messageDetail.replace("{toolName}", block.name), ) + if (!result) { + return + } + + const { response, text, images } = result + if (response === "messageResponse") { // Add user feedback to userContent. cline.userMessageContent.push( diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 92af0fca97b..f0e2a2461f6 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -154,6 +154,7 @@ const MAX_CONTEXT_WINDOW_RETRIES = 3 // Maximum retries for context window error export interface TaskOptions extends CreateTaskOptions { context: vscode.ExtensionContext // kilocode_change provider: ClineProvider + ralphLoopCount?: number // kilocode_change apiConfiguration: ProviderSettings enableDiff?: boolean enableCheckpoints?: boolean @@ -438,6 +439,7 @@ export class Task extends EventEmitter implements TaskLike { initialTodos, workspacePath, initialStatus, + ralphLoopCount, // kilocode_change }: TaskOptions) { super() this.context = context // kilocode_change @@ -469,6 +471,7 @@ export class Task extends EventEmitter implements TaskLike { this.metadata = { task: historyItem ? historyItem.task : task, images: historyItem ? [] : images, + ralphLoopCount: ralphLoopCount ?? 0, // kilocode_change } // Normal use-case is usually retry similar history task with new workspace. @@ -2489,6 +2492,82 @@ export class Task extends EventEmitter implements TaskLike { } } + // kilocode_change start + /** + * Handles the Ralph mode restart logic. + * If Ralph mode is enabled and within limits, restarts the task. + * + * @param result Optional completion result to check for delimiter + * @returns true if task was restarted, false otherwise + */ + public async handleRalphRestart(result?: string): Promise { + const provider = this.providerRef.deref() + const state = await provider?.getState() + if (provider && state?.alwaysAllowRalph && state?.ralphEnabled) { + const delimiter = state.ralphCompletionDelimiter + + // Check delimiter if configured and result is provided + if (result !== undefined && delimiter && delimiter.trim() !== "") { + if (result.indexOf(delimiter) !== -1) { + return false + } + + const assistantMessages = this.apiConversationHistory.filter((m) => m.role === "assistant").slice(-5) + + for (const m of assistantMessages) { + const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content) + if (content.indexOf(delimiter) !== -1) { + return false + } + } + } + + const loopLimit = state.ralphLoopLimit ?? 5 + const currentLoopCount = this.metadata.ralphLoopCount ?? 0 + + if (loopLimit <= 0 || currentLoopCount + 1 < loopLimit) { + const firstPrompt = this.metadata.task + const images = this.metadata.images + + setTimeout(async () => { + try { + await provider.createTask(firstPrompt, images, undefined, { + ralphLoopCount: currentLoopCount + 1, + }) + await provider.postMessageToWebview({ type: "invoke", invoke: "newChat" }) + } catch (error) { + console.error("[Task] Failed to restart task in Ralph mode:", error) + } + }, 1000) + + await this.abortTask() + return true + } + } + return false + } + + /** + * Handles the case where the mistake limit has been reached. + * If Ralph mode is enabled and within limits, restarts the task. + * Otherwise, asks the user for guidance. + * + * @param guidance Optional guidance text to show the user + * @returns Object containing the user's response if Ralph restart didn't happen + */ + public async handleMistakeLimitReached( + guidance: string = t("common:errors.mistake_limit_guidance"), + ): Promise<{ response: ClineAskResponse; text?: string; images?: string[] } | undefined> { + const restarted = await this.handleRalphRestart() + if (restarted) { + await this.say("error", "Mistake limit reached. Ralph mode is restarting the task...") + return undefined + } + + return await this.ask("mistake_limit_reached", guidance) + } + // kilocode_change end + public async recursivelyMakeClineRequests( userContent: Anthropic.Messages.ContentBlockParam[], includeFileDetails: boolean = false, @@ -2530,10 +2609,13 @@ export class Task extends EventEmitter implements TaskLike { ), ) - const { response, text, images } = await this.ask( - "mistake_limit_reached", - t("common:errors.mistake_limit_guidance"), - ) + const result = await this.handleMistakeLimitReached() + + if (!result) { + return true + } + + const { response, text, images } = result if (response === "messageResponse") { currentUserContent.push( diff --git a/src/core/tools/AttemptCompletionTool.ts b/src/core/tools/AttemptCompletionTool.ts index 0def86fc606..367a35fe038 100644 --- a/src/core/tools/AttemptCompletionTool.ts +++ b/src/core/tools/AttemptCompletionTool.ts @@ -169,6 +169,13 @@ export class AttemptCompletionTool extends BaseTool<"attempt_completion"> { } } + // kilocode_change start + const restarted = await task.handleRalphRestart(result) + if (restarted) { + return + } + // kilocode_change end + const { response, text, images } = await task.ask("completion_result", "", false) if (response === "yesButtonClicked") { diff --git a/src/core/tools/__tests__/AttemptCompletionToolRalph.spec.ts b/src/core/tools/__tests__/AttemptCompletionToolRalph.spec.ts new file mode 100644 index 00000000000..8fa3470acc3 --- /dev/null +++ b/src/core/tools/__tests__/AttemptCompletionToolRalph.spec.ts @@ -0,0 +1,219 @@ +import { AttemptCompletionToolUse } from "../../../shared/tools" +import { attemptCompletionTool, AttemptCompletionCallbacks } from "../AttemptCompletionTool" +import { Task } from "../../task/Task" + +// Mock the formatResponse module +vi.mock("../../prompts/responses", () => ({ + formatResponse: { + toolError: vi.fn((msg: string) => `Error: ${msg}`), + toolResult: vi.fn((text: string) => text), + }, +})) + +// Mock vscode module +vi.mock("vscode", () => ({ + workspace: { + getConfiguration: vi.fn(() => ({ + get: vi.fn((key: string, defaultValue: any) => defaultValue), + })), + }, + window: { + showErrorMessage: vi.fn(), + createTextEditorDecorationType: vi.fn(() => ({ dispose: vi.fn() })), + }, +})) + +// Mock Package module +vi.mock("../../../shared/package", () => ({ + Package: { + name: "kilo-code", + }, +})) + +describe("AttemptCompletionTool Ralph Mode", () => { + let mockTask: any + let mockProvider: any + let mockCallbacks: AttemptCompletionCallbacks + + beforeEach(() => { + mockProvider = { + getState: vi.fn(), + createTask: vi.fn(), + postMessageToWebview: vi.fn(), + } + + mockTask = { + taskId: "test-task-id", + consecutiveMistakeCount: 0, + recordToolError: vi.fn(), + todoList: undefined, + didToolFailInCurrentTurn: false, + providerRef: { + deref: () => mockProvider, + }, + metadata: { + task: "initial prompt", + images: [], + ralphLoopCount: 0, + }, + apiConversationHistory: [], + clineMessages: [], + say: vi.fn(), + emit: vi.fn(), + getTokenUsage: vi.fn(() => ({})), + emitFinalTokenUsageUpdate: vi.fn(), + ask: vi.fn(() => Promise.resolve({ response: "yesButtonClicked" })), + } + + mockCallbacks = { + askApproval: vi.fn(), + handleError: vi.fn(), + pushToolResult: vi.fn(), + removeClosingTag: vi.fn(), + askFinishSubTaskApproval: vi.fn(), + toolDescription: vi.fn(), + toolProtocol: "xml", + } + + vi.useFakeTimers() + }) + + afterEach(() => { + vi.useRealTimers() + }) + + it("should restart task in Ralph mode when enabled", async () => { + mockProvider.getState.mockResolvedValue({ ralphEnabled: true }) + + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed" }, + partial: false, + } + + await attemptCompletionTool.handle(mockTask as Task, block, mockCallbacks) + + // Fast-forward 1 second for the setTimeout + vi.advanceTimersByTime(1000) + + expect(mockProvider.createTask).toHaveBeenCalledWith( + "initial prompt", + [], + undefined, + expect.objectContaining({ ralphLoopCount: 1 }), + ) + expect(mockProvider.postMessageToWebview).toHaveBeenCalledWith({ type: "invoke", invoke: "newChat" }) + }) + + it("should stop Ralph mode when loop limit is reached", async () => { + mockProvider.getState.mockResolvedValue({ + ralphEnabled: true, + ralphLoopLimit: 2, + }) + mockTask.metadata.ralphLoopCount = 1 // Already ran once, this is the second time + + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed" }, + partial: false, + } + + await attemptCompletionTool.handle(mockTask as Task, block, mockCallbacks) + + vi.advanceTimersByTime(1000) + + // Should NOT restart the task because loop limit (2) is reached + expect(mockProvider.createTask).not.toHaveBeenCalled() + // Should instead call task.ask to show completion result to user + expect(mockTask.ask).toHaveBeenCalledWith("completion_result", "", false) + }) + + it("should stop Ralph mode when custom delimiter is found in result", async () => { + mockProvider.getState.mockResolvedValue({ + ralphEnabled: true, + ralphCompletionDelimiter: "COMPLETED", + }) + + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Here is the result COMPLETED" }, + partial: false, + } + + await attemptCompletionTool.handle(mockTask as Task, block, mockCallbacks) + + vi.advanceTimersByTime(1000) + + // Should NOT restart the task because delimiter is found + expect(mockProvider.createTask).not.toHaveBeenCalled() + expect(mockTask.ask).toHaveBeenCalled() + }) + + it("should stop Ralph mode when custom delimiter is found in previous messages", async () => { + mockProvider.getState.mockResolvedValue({ + ralphEnabled: true, + ralphCompletionDelimiter: "STOP_NOW", + }) + + // Delimiter is in a previous message (e.g., a file write) + mockTask.apiConversationHistory = [ + { + role: "assistant", + content: [ + { + type: "tool_use", + name: "write_to_file", + id: "1", + input: { content: "Some content with STOP_NOW delimiter" }, + }, + ], + }, + ] + + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Finalizing task" }, + partial: false, + } + + await attemptCompletionTool.handle(mockTask as Task, block, mockCallbacks) + + vi.advanceTimersByTime(1000) + + // Should NOT restart the task because delimiter is found in history + expect(mockProvider.createTask).not.toHaveBeenCalled() + expect(mockTask.ask).toHaveBeenCalled() + }) + + it("should continue Ralph mode when custom delimiter is NOT found anywhere", async () => { + mockProvider.getState.mockResolvedValue({ + ralphEnabled: true, + ralphCompletionDelimiter: "COMPLETED", + }) + + mockTask.apiConversationHistory = [ + { + role: "assistant", + content: "Just a regular message", + }, + ] + + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task not yet fully done" }, + partial: false, + } + + await attemptCompletionTool.handle(mockTask as Task, block, mockCallbacks) + + vi.advanceTimersByTime(1000) + + // Should restart the task + expect(mockProvider.createTask).toHaveBeenCalled() + }) +}) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index f896a382c5c..498a9ed771d 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2078,6 +2078,7 @@ export class ClineProvider alwaysAllowWriteOutsideWorkspace, alwaysAllowWriteProtected, alwaysAllowDelete, // kilocode_change + alwaysAllowRalph, // kilocode_change alwaysAllowExecute, allowedCommands, deniedCommands, @@ -2186,6 +2187,9 @@ export class ClineProvider yoloGatekeeperApiConfigId, // kilocode_change: AI gatekeeper for YOLO mode selectedMicrophoneDevice, // kilocode_change: Selected microphone device for STT isBrowserSessionActive, + ralphEnabled, // kilocode_change + ralphLoopLimit, // kilocode_change + ralphCompletionDelimiter, // kilocode_change } = await this.getState() // kilocode_change start: Get active model for virtual quota fallback UI display @@ -2250,6 +2254,7 @@ export class ClineProvider alwaysAllowWriteOutsideWorkspace: alwaysAllowWriteOutsideWorkspace ?? false, alwaysAllowWriteProtected: alwaysAllowWriteProtected ?? false, alwaysAllowDelete: alwaysAllowDelete ?? false, // kilocode_change + alwaysAllowRalph: alwaysAllowRalph ?? false, // kilocode_change alwaysAllowExecute: alwaysAllowExecute ?? false, alwaysAllowBrowser: alwaysAllowBrowser ?? false, alwaysAllowMcp: alwaysAllowMcp ?? false, @@ -2433,6 +2438,9 @@ export class ClineProvider } })(), debug: vscode.workspace.getConfiguration(Package.name).get("debug", false), + ralphEnabled: ralphEnabled ?? false, // kilocode_change + ralphLoopLimit: ralphLoopLimit ?? 5, // kilocode_change + ralphCompletionDelimiter: ralphCompletionDelimiter !== undefined ? ralphCompletionDelimiter : "COMPLETED", // kilocode_change } } @@ -2563,6 +2571,7 @@ export class ClineProvider alwaysAllowWriteOutsideWorkspace: stateValues.alwaysAllowWriteOutsideWorkspace ?? false, alwaysAllowWriteProtected: stateValues.alwaysAllowWriteProtected ?? false, alwaysAllowDelete: stateValues.alwaysAllowDelete ?? false, // kilocode_change + alwaysAllowRalph: stateValues.alwaysAllowRalph ?? false, // kilocode_change alwaysAllowExecute: stateValues.alwaysAllowExecute ?? true, alwaysAllowBrowser: stateValues.alwaysAllowBrowser ?? true, alwaysAllowMcp: stateValues.alwaysAllowMcp ?? true, @@ -2736,6 +2745,9 @@ export class ClineProvider } })(), appendSystemPrompt: stateValues.appendSystemPrompt, // kilocode_change: CLI append system prompt + ralphEnabled: stateValues.ralphEnabled ?? false, // kilocode_change + ralphLoopLimit: stateValues.ralphLoopLimit ?? 5, // kilocode_change + ralphCompletionDelimiter: stateValues.ralphCompletionDelimiter !== undefined ? stateValues.ralphCompletionDelimiter : "COMPLETED", // kilocode_change } } diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index f988f2aab5e..846a769738e 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -1953,6 +1953,20 @@ export const webviewMessageHandler = async ( await provider.postStateToWebview() break // kilocode_change end + // kilocode_change start + case "ralphEnabled": + await updateGlobalState("ralphEnabled", message.bool ?? false) + await provider.postStateToWebview() + break + case "ralphLoopLimit": + await updateGlobalState("ralphLoopLimit", message.value ?? 5) + await provider.postStateToWebview() + break + case "ralphCompletionDelimiter": + await updateGlobalState("ralphCompletionDelimiter", message.text !== undefined ? message.text : "COMPLETED") + await provider.postStateToWebview() + break + // kilocode_change end case "enhancePrompt": if (message.text) { try { diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 79a9e6628dc..e537abaaa8e 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -393,6 +393,7 @@ export type ExtensionState = Pick< | "alwaysAllowSubtasks" | "alwaysAllowFollowupQuestions" | "alwaysAllowExecute" + | "alwaysAllowRalph" // kilocode_change | "followupAutoApproveTimeoutMs" | "allowedCommands" | "deniedCommands" @@ -468,6 +469,9 @@ export type ExtensionState = Pick< | "maxGitStatusFiles" | "requestDelaySeconds" | "selectedMicrophoneDevice" // kilocode_change: Selected microphone device for STT + | "ralphEnabled" // kilocode_change + | "ralphLoopLimit" // kilocode_change + | "ralphCompletionDelimiter" // kilocode_change > & { version: string clineMessages: ClineMessage[] diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index a468d1dd923..8be0d19eec7 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -299,6 +299,9 @@ export interface WebviewMessage { | "downloadErrorDiagnostics" | "requestClaudeCodeRateLimits" | "refreshCustomTools" + | "ralphEnabled" // kilocode_change + | "ralphLoopLimit" // kilocode_change + | "ralphCompletionDelimiter" // kilocode_change text?: string suggestionLength?: number // kilocode_change: Length of accepted suggestion for telemetry completionRequestId?: string // kilocode_change diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index 86f0afc3f26..6d2efa4e14d 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -31,7 +31,7 @@ import { KiloProfileSelector } from "../kilocode/chat/KiloProfileSelector" import { MAX_IMAGES_PER_MESSAGE } from "./ChatView" import ContextMenu from "./ContextMenu" import { ImageWarningBanner } from "./ImageWarningBanner" -import { VolumeX, Pin, Check, WandSparkles, SendHorizontal, Paperclip, MessageSquareX } from "lucide-react" +import { VolumeX, Pin, Check, WandSparkles, SendHorizontal, Paperclip, MessageSquareX, Infinity } from "lucide-react" import { IndexingStatusBadge } from "./IndexingStatusBadge" import { MicrophoneButton } from "./MicrophoneButton" // kilocode_change: STT microphone button import { VolumeVisualizer } from "./VolumeVisualizer" // kilocode_change: STT volume level visual @@ -164,6 +164,9 @@ export const ChatTextArea = forwardRef( ghostServiceSettings, // kilocode_change language, // User's VSCode display language experiments, // kilocode_change: For speechToText experiment flag + ralphEnabled, // kilocode_change + setRalphEnabled, // kilocode_change + alwaysAllowRalph, // kilocode_change } = useExtensionState() // kilocode_change start: Manage STT status and error state with auto-clearing @@ -1930,6 +1933,35 @@ export const ChatTextArea = forwardRef( {/* kilocode_change end */} + {/* kilocode_change start */} + {alwaysAllowRalph && ( + + + + )} + {/* kilocode_change end */} + & { alwaysAllowModeSwitch?: boolean alwaysAllowSubtasks?: boolean alwaysAllowExecute?: boolean + alwaysAllowRalph?: boolean // kilocode_change + ralphLoopLimit?: number // kilocode_change + ralphCompletionDelimiter?: string // kilocode_change alwaysAllowFollowupQuestions?: boolean followupAutoApproveTimeoutMs?: number allowedCommands?: string[] @@ -49,6 +52,9 @@ type AutoApproveSettingsProps = HTMLAttributes & { | "alwaysAllowModeSwitch" | "alwaysAllowSubtasks" | "alwaysAllowExecute" + | "alwaysAllowRalph" // kilocode_change + | "ralphLoopLimit" // kilocode_change + | "ralphCompletionDelimiter" // kilocode_change | "alwaysAllowFollowupQuestions" | "followupAutoApproveTimeoutMs" | "allowedCommands" @@ -72,6 +78,9 @@ export const AutoApproveSettings = ({ alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysAllowExecute, + alwaysAllowRalph, // kilocode_change + ralphLoopLimit, // kilocode_change + ralphCompletionDelimiter, // kilocode_change alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs = 60000, allowedCommands, @@ -196,6 +205,7 @@ export const AutoApproveSettings = ({ alwaysAllowModeSwitch={alwaysAllowModeSwitch} alwaysAllowSubtasks={alwaysAllowSubtasks} alwaysAllowExecute={alwaysAllowExecute} + alwaysAllowRalph={alwaysAllowRalph} // kilocode_change alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions} onToggle={(key, value) => setCachedStateField(key, value)} /> @@ -412,6 +422,53 @@ export const AutoApproveSettings = ({ )} + + {/* kilocode_change start */} + {alwaysAllowRalph && ( +
+
+ +
{t("settings:autoApprove.ralph.label")}
+
+
+
+ +
+ setCachedStateField("ralphLoopLimit", value)} + /> + + {ralphLoopLimit === 0 ? "∞" : ralphLoopLimit} + +
+
+ {t("settings:autoApprove.ralph.loopLimit.description")} +
+
+
+ + setCachedStateField("ralphCompletionDelimiter", e.target.value)} + placeholder="e.g., COMPLETED" + className="w-full" + /> +
+ {t("settings:autoApprove.ralph.completionDelimiter.description")} +
+
+
+
+ )} + {/* kilocode_change end */} {/* kilocode_change start */} diff --git a/webview-ui/src/components/settings/AutoApproveToggle.tsx b/webview-ui/src/components/settings/AutoApproveToggle.tsx index 6bdc12bc715..5b3cc05e45b 100644 --- a/webview-ui/src/components/settings/AutoApproveToggle.tsx +++ b/webview-ui/src/components/settings/AutoApproveToggle.tsx @@ -2,6 +2,7 @@ import type { GlobalSettings } from "@roo-code/types" import { useAppTranslation } from "@/i18n/TranslationContext" import { cn } from "@/lib/utils" +import { Infinity } from "lucide-react" // kilocode_change import { Button, StandardTooltip } from "@/components/ui" type AutoApproveToggles = Pick< @@ -14,6 +15,7 @@ type AutoApproveToggles = Pick< | "alwaysAllowModeSwitch" | "alwaysAllowSubtasks" | "alwaysAllowExecute" + | "alwaysAllowRalph" // kilocode_change | "alwaysAllowFollowupQuestions" > @@ -93,6 +95,15 @@ export const autoApproveSettingsConfig: Record - + {icon === "infinity" ? ( + + ) : ( + + )} {t(labelKey)} diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 7138902cfee..32a24195c7d 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -175,6 +175,9 @@ const SettingsView = forwardRef((props, ref) language, alwaysAllowBrowser, alwaysAllowExecute, + alwaysAllowRalph, // kilocode_change + ralphLoopLimit, // kilocode_change + ralphCompletionDelimiter, // kilocode_change alwaysAllowMcp, alwaysAllowModeSwitch, alwaysAllowSubtasks, @@ -519,6 +522,9 @@ const SettingsView = forwardRef((props, ref) alwaysAllowWriteOutsideWorkspace: alwaysAllowWriteOutsideWorkspace ?? undefined, alwaysAllowWriteProtected: alwaysAllowWriteProtected ?? undefined, alwaysAllowExecute: alwaysAllowExecute ?? undefined, + alwaysAllowRalph: alwaysAllowRalph ?? undefined, // kilocode_change + ralphLoopLimit: ralphLoopLimit ?? 5, // kilocode_change + ralphCompletionDelimiter: ralphCompletionDelimiter !== undefined ? ralphCompletionDelimiter : "COMPLETED", // kilocode_change alwaysAllowBrowser: alwaysAllowBrowser ?? undefined, alwaysAllowMcp, alwaysAllowModeSwitch, @@ -1027,6 +1033,9 @@ const SettingsView = forwardRef((props, ref) alwaysAllowWriteProtected={alwaysAllowWriteProtected} alwaysAllowBrowser={alwaysAllowBrowser} alwaysAllowMcp={alwaysAllowMcp} + alwaysAllowRalph={alwaysAllowRalph} // kilocode_change + ralphLoopLimit={ralphLoopLimit} // kilocode_change + ralphCompletionDelimiter={ralphCompletionDelimiter} // kilocode_change alwaysAllowModeSwitch={alwaysAllowModeSwitch} alwaysAllowSubtasks={alwaysAllowSubtasks} alwaysAllowExecute={alwaysAllowExecute} diff --git a/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx b/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx index bd423e7bf56..2b2d6cd0d20 100644 --- a/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx @@ -20,6 +20,7 @@ describe("AutoApproveToggle", () => { alwaysAllowReadOnly: true, alwaysAllowWrite: false, alwaysAllowDelete: false, // kilocode_change + alwaysAllowRalph: false, // kilocode_change alwaysAllowBrowser: false, alwaysAllowMcp: false, alwaysAllowModeSwitch: true, diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index 679059f68a1..5c7c4f6924e 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -49,6 +49,8 @@ export interface ExtensionStateContextType extends ExtensionState { dismissedNotificationIds: string[] // kilocode_change yoloMode?: boolean // kilocode_change setYoloMode: (value: boolean) => void // kilocode_Change + ralphEnabled?: boolean // kilocode_change + setRalphEnabled: (value: boolean) => void // kilocode_change // kilocode_change start - Auto-purge settings autoPurgeEnabled?: boolean setAutoPurgeEnabled: (value: boolean) => void @@ -114,6 +116,8 @@ export interface ExtensionStateContextType extends ExtensionState { setAlwaysAllowWriteOutsideWorkspace: (value: boolean) => void setAlwaysAllowDelete: (value: boolean) => void // kilocode_change setAlwaysAllowExecute: (value: boolean) => void + alwaysAllowRalph?: boolean // kilocode_change + setAlwaysAllowRalph: (value: boolean) => void // kilocode_change setAlwaysAllowBrowser: (value: boolean) => void setAlwaysAllowMcp: (value: boolean) => void setAlwaysAllowModeSwitch: (value: boolean) => void @@ -288,6 +292,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode customCondensingPrompt: "", // Default empty string for custom condensing prompt yoloGatekeeperApiConfigId: "", // kilocode_change: Default empty string for gatekeeper API config ID hasOpenedModeSelector: false, // Default to false (not opened yet) + ralphEnabled: false, // kilocode_change autoApprovalEnabled: true, customModes: [], maxOpenTabsContext: 20, @@ -597,6 +602,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setState((prevState) => ({ ...prevState, alwaysAllowWriteOutsideWorkspace: value })), setAlwaysAllowDelete: (value) => setState((prevState) => ({ ...prevState, alwaysAllowDelete: value })), // kilocode_change setAlwaysAllowExecute: (value) => setState((prevState) => ({ ...prevState, alwaysAllowExecute: value })), + setAlwaysAllowRalph: (value) => setState((prevState) => ({ ...prevState, alwaysAllowRalph: value })), // kilocode_change setAlwaysAllowBrowser: (value) => setState((prevState) => ({ ...prevState, alwaysAllowBrowser: value })), setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })), setAlwaysAllowModeSwitch: (value) => setState((prevState) => ({ ...prevState, alwaysAllowModeSwitch: value })), @@ -665,6 +671,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setShowTimestamps: (value) => setState((prevState) => ({ ...prevState, showTimestamps: value })), setShowDiffStats: (value) => setState((prevState) => ({ ...prevState, showDiffStats: value })), // kilocode_change setYoloMode: (value) => setState((prevState) => ({ ...prevState, yoloMode: value })), // kilocode_change + setRalphEnabled: (value) => setState((prevState) => ({ ...prevState, ralphEnabled: value })), // kilocode_change // kilocode_change end setAutoApprovalEnabled: (value) => setState((prevState) => ({ ...prevState, autoApprovalEnabled: value })), setCustomModes: (value) => setState((prevState) => ({ ...prevState, customModes: value })), diff --git a/webview-ui/src/hooks/useAutoApprovalToggles.ts b/webview-ui/src/hooks/useAutoApprovalToggles.ts index d52ad373b69..ab908c169c8 100644 --- a/webview-ui/src/hooks/useAutoApprovalToggles.ts +++ b/webview-ui/src/hooks/useAutoApprovalToggles.ts @@ -15,6 +15,7 @@ export function useAutoApprovalToggles() { alwaysAllowMcp, alwaysAllowModeSwitch, alwaysAllowSubtasks, + alwaysAllowRalph, // kilocode_change alwaysAllowFollowupQuestions, } = useExtensionState() @@ -28,6 +29,7 @@ export function useAutoApprovalToggles() { alwaysAllowMcp, alwaysAllowModeSwitch, alwaysAllowSubtasks, + alwaysAllowRalph, // kilocode_change alwaysAllowFollowupQuestions, }), [ @@ -39,6 +41,7 @@ export function useAutoApprovalToggles() { alwaysAllowMcp, alwaysAllowModeSwitch, alwaysAllowSubtasks, + alwaysAllowRalph, // kilocode_change alwaysAllowFollowupQuestions, ], ) diff --git a/webview-ui/src/i18n/locales/ar/settings.json b/webview-ui/src/i18n/locales/ar/settings.json index a9633496af6..3cfbbab87cd 100644 --- a/webview-ui/src/i18n/locales/ar/settings.json +++ b/webview-ui/src/i18n/locales/ar/settings.json @@ -266,6 +266,18 @@ "description": "اختيار الإجابة الأولى المقترحة تلقائيًا بعد المهلة المحددة", "timeoutLabel": "وقت الانتظار قبل الاختيار التلقائي للإجابة الأولى" }, + "ralph": { + "label": "Ralph", + "description": "إظهار زر Ralph في وضع الدردشة الذي يمكّن قدرة حلقة الوكيل المستقل", + "loopLimit": { + "label": "حد الحلقة", + "description": "الحد الأقصى لعدد المرات التي سيقوم فيها Ralph بإعادة تشغيل المهمة تلقائيًا. اضبط على 0 للحلقات غير المحدودة." + }, + "completionDelimiter": { + "label": "محدد الاكتمال", + "description": "إذا تم العثور على هذا النص في نتيجة الاكتمال، سيتوقف Ralph عن التكرار." + } + }, "execute": { "label": "تشغيل", "description": "تنفيذ أوامر الطرفية المسموحة تلقائيًا", diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index ecf29893c58..6a8332cdf99 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -227,6 +227,18 @@ "description": "Seleccionar automàticament la primera resposta suggerida per a preguntes de seguiment després del temps d'espera configurat", "timeoutLabel": "Temps d'espera abans de seleccionar automàticament la primera resposta" }, + "ralph": { + "label": "Ralph", + "description": "Mostra el botó Ralph al mode xat que habilita la capacitat de bucle d'agent autònom", + "loopLimit": { + "label": "Límit de bucle", + "description": "Nombre màxim de vegades que Ralph reiniciarà automàticament la tasca. Estableix a 0 per a bucles il·limitats." + }, + "completionDelimiter": { + "label": "Delimitador de finalització", + "description": "Si es troba aquest text en el resultat de la finalització, Ralph deixarà de fer bucles." + } + }, "execute": { "label": "Executar", "description": "Executar automàticament comandes de terminal permeses sense requerir aprovació", diff --git a/webview-ui/src/i18n/locales/cs/settings.json b/webview-ui/src/i18n/locales/cs/settings.json index 26513fdcf39..09b36efa3bd 100644 --- a/webview-ui/src/i18n/locales/cs/settings.json +++ b/webview-ui/src/i18n/locales/cs/settings.json @@ -250,7 +250,19 @@ "followupQuestions": { "label": "Otázka", "description": "Automaticky vybrat první navrhovanou odpověď pro následné otázky po uplynutí nastaveného časového limitu", - "timeoutLabel": "Doba čekání před automatickým výběrem první odpovědi" + "timeoutLabel": "Doba čekání przed automatickým výběrem první odpovědi" + }, + "ralph": { + "label": "Ralph", + "description": "Zobrazit tlačítko Ralph v režimu chatu, které umožňuje schopnost smyčky autonomního agenta", + "loopLimit": { + "label": "Limit smyčky", + "description": "Maximální počet opakování, kdy Ralph automaticky restartuje úkol. Nastavte na 0 pro neomezené smyčky." + }, + "completionDelimiter": { + "label": "Oddělovač dokončení", + "description": "Pokud je tento text nalezen ve výsledku dokončení, Ralph přestane opakovat smyčku." + } }, "execute": { "label": "Spustit", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 0a3cda94989..9e8695ccc37 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -227,6 +227,18 @@ "description": "Automatisch die erste vorgeschlagene Antwort für Folgefragen nach der konfigurierten Zeitüberschreitung auswählen", "timeoutLabel": "Wartezeit vor der automatischen Auswahl der ersten Antwort" }, + "ralph": { + "label": "Ralph", + "description": "Zeige Ralph-Button im Chat-Modus, der die autonome Agenten-Schleifen-Fähigkeit aktiviert", + "loopLimit": { + "label": "Schleifenlimit", + "description": "Maximale Anzahl der Male, die Ralph die Aufgabe automatisch neu startet. Auf 0 setzen für unbegrenzte Schleifen." + }, + "completionDelimiter": { + "label": "Abschluss-Trennzeichen", + "description": "Wenn dieser Text im Abschlussergebnis gefunden wird, stoppt Ralph die Schleife." + } + }, "execute": { "label": "Ausführen", "description": "Erlaubte Terminal-Befehle automatisch ohne Genehmigung ausführen", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 9e487e9b312..1412fa11278 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -239,6 +239,18 @@ "description": "Automatically select the first suggested answer for follow-up questions after the configured timeout", "timeoutLabel": "Time to wait before auto-selecting the first answer" }, + "ralph": { + "label": "Ralph", + "description": "Show Ralph button in chat mode that enable autonomous agent loop ability", + "loopLimit": { + "label": "Loop Limit", + "description": "Maximum number of times Ralph will automatically restart the task. Set to 0 for unlimited loops." + }, + "completionDelimiter": { + "label": "Completion Delimiter", + "description": "If this text is found in the completion result, Ralph will stop looping." + } + }, "execute": { "label": "Execute", "description": "Automatically execute allowed terminal commands without requiring approval", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 95efa64153c..0d23d944905 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -231,6 +231,18 @@ "description": "Seleccionar automáticamente la primera respuesta sugerida para preguntas de seguimiento después del tiempo de espera configurado", "timeoutLabel": "Tiempo de espera antes de seleccionar automáticamente la primera respuesta" }, + "ralph": { + "label": "Ralph", + "description": "Mostrar el botón Ralph en el modo chat que habilita la capacidad de bucle del agente autónomo", + "loopLimit": { + "label": "Límite de bucles", + "description": "Número máximo de veces que Ralph reiniciará automáticamente la tarea. Establecer en 0 para bucles ilimitados." + }, + "completionDelimiter": { + "label": "Delimitador de finalización", + "description": "Si se encuentra este texto en el resultado de la finalización, Ralph dejará de hacer bucles." + } + }, "execute": { "label": "Ejecutar", "description": "Ejecutar automáticamente comandos de terminal permitidos sin requerir aprobación", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 17551bd6c7f..ab364a26dd2 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -232,6 +232,18 @@ "description": "Sélectionner automatiquement la première réponse suggérée pour les questions de suivi après le délai configuré", "timeoutLabel": "Temps d'attente avant la sélection automatique de la première réponse" }, + "ralph": { + "label": "Ralph", + "description": "Afficher le bouton Ralph en mode chat pour activer la capacité de boucle de l'agent autonome", + "loopLimit": { + "label": "Limite de boucles", + "description": "Nombre maximum de fois que Ralph redémarrera automatiquement la tâche. Réglez sur 0 choisis pour des boucles illimitées." + }, + "completionDelimiter": { + "label": "Délimiteur d'achèvement", + "description": "Si ce texte est trouvé dans le résultat final, Ralph arrêtera de boucler." + } + }, "execute": { "label": "Exécuter", "description": "Exécuter automatiquement les commandes de terminal autorisées sans nécessiter d'approbation", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index adf8b7e3b02..05867d22190 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -231,6 +231,18 @@ "description": "कॉन्फ़िगर किए गए टाइमआउट के बाद अनुवर्ती प्रश्नों के लिए पहले सुझाए गए उत्तर को स्वचालित रूप से चुनें", "timeoutLabel": "पहले उत्तर को स्वचालित रूप से चुनने से पहले प्रतीक्षा करने का समय" }, + "ralph": { + "label": "Ralph", + "description": "चैट मोड में Ralph बटन दिखाएं जो स्वायत्त एजेंट लूप क्षमता को सक्षम करता है", + "loopLimit": { + "label": "लूप सीमा", + "description": "Ralph द्वारा कार्य को स्वचालित रूप से पुनरारंभ करने की अधिकतम संख्या। असीमित लूप के लिए 0 पर सेट करें।" + }, + "completionDelimiter": { + "label": "पूर्णता सीमांकक", + "description": "यदि पूर्णता परिणाम में यह टेक्स्ट मिलता है, तो Ralph लूपिंग बंद कर देगा।" + } + }, "execute": { "label": "निष्पादित करें", "description": "अनुमोदन की आवश्यकता के बिना स्वचालित रूप से अनुमत टर्मिनल कमांड निष्पादित करें", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index c8a9423af68..9195b44279b 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -231,6 +231,18 @@ "description": "Secara otomatis memilih jawaban pertama yang disarankan untuk pertanyaan lanjutan setelah batas waktu yang dikonfigurasi", "timeoutLabel": "Waktu tunggu sebelum otomatis memilih jawaban pertama" }, + "ralph": { + "label": "Ralph", + "description": "Tampilkan tombol Ralph dalam mode chat yang mengaktifkan kemampuan loop agen otonom", + "loopLimit": { + "label": "Batas Loop", + "description": "Jumlah maksimum kali Ralph akan secara otomatis memulai ulang tugas. Atur ke 0 untuk loop tak terbatas." + }, + "completionDelimiter": { + "label": "Pemisah Penyelesaian", + "description": "Jika teks ini ditemukan dalam hasil penyelesaian, Ralph akan berhenti melakukan looping." + } + }, "execute": { "label": "Eksekusi", "description": "Secara otomatis mengeksekusi perintah terminal yang diizinkan tanpa memerlukan persetujuan", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 779e6fcbdd8..7211c049a77 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -237,6 +237,18 @@ "description": "Seleziona automaticamente la prima risposta suggerita per le domande di follow-up dopo il timeout configurato", "timeoutLabel": "Tempo di attesa prima di selezionare automaticamente la prima risposta" }, + "ralph": { + "label": "Ralph", + "description": "Mostra il pulsante Ralph in modalità chat che abilita la capacità di loop dell'agente autonomo", + "loopLimit": { + "label": "Limite di loop", + "description": "Numero massimo di volte in cui Ralph riavvierà automaticamente l'attività. Impostare a 0 per loop illimitati." + }, + "completionDelimiter": { + "label": "Delimitatore di completamento", + "description": "Se questo testo viene trovato nel risultato del completamento, Ralph smetterà di eseguire il loop." + } + }, "execute": { "label": "Esegui", "description": "Esegui automaticamente i comandi del terminale consentiti senza richiedere approvazione", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index b35add6fcc7..0129b0f5038 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -237,6 +237,18 @@ "description": "設定された時間が経過すると、フォローアップ質問の最初の提案回答を自動的に選択します", "timeoutLabel": "最初の回答を自動選択するまでの待機時間" }, + "ralph": { + "label": "Ralph", + "description": "チャットモードで自律型エージェントのループ機能を有効にするRalphボタンを表示します", + "loopLimit": { + "label": "ループ制限", + "description": "Ralphがタスクを自動的に再開する最大回数。無制限のループにするには0に設定してください。" + }, + "completionDelimiter": { + "label": "完了デリミタ", + "description": "完了結果にこのテキストが含まれている場合、Ralphはループを停止します。" + } + }, "execute": { "label": "実行", "description": "承認なしで自動的に許可されたターミナルコマンドを実行", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index ffb6c92024a..0bb069956dd 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -231,6 +231,18 @@ "description": "설정된 시간이 지나면 후속 질문에 대한 첫 번째 제안 답변을 자동으로 선택합니다", "timeoutLabel": "첫 번째 답변을 자동 선택하기 전 대기 시간" }, + "ralph": { + "label": "Ralph", + "description": "자율 에이전트 루프 기능을 활성화하는 Ralph 버튼을 채팅 모드에서 표시합니다", + "loopLimit": { + "label": "루프 제한", + "description": "Ralph가 작업을 자동으로 재시작하는 최대 횟수입니다. 무제한 루프를 위해 0으로 설정하십시오." + }, + "completionDelimiter": { + "label": "완료 구분 기호", + "description": "완료 결과에서 이 텍스트가 발견되면 Ralph는 루프를 중지합니다." + } + }, "execute": { "label": "실행", "description": "승인 없이 자동으로 허용된 터미널 명령 실행", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 90d01fb4fe9..612aed56592 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -231,6 +231,18 @@ "description": "Selecteer automatisch het eerste voorgestelde antwoord voor vervolgvragen na de geconfigureerde time-out", "timeoutLabel": "Wachttijd voordat het eerste antwoord automatisch wordt geselecteerd" }, + "ralph": { + "label": "Ralph", + "description": "Toon de Ralph-knop in de chatmodus die de autonome agent-loop-mogelijkheid activeert", + "loopLimit": { + "label": "Loop-limiet", + "description": "Maximaal aantal keren dat Ralph de taak automatisch herstart. Stel in op 0 voor onbeperkte loops." + }, + "completionDelimiter": { + "label": "Voltooiingsscheidingsteken", + "description": "Als deze tekst wordt gevonden in het voltooiingsresultaat, stopt Ralph met loopen." + } + }, "execute": { "label": "Uitvoeren", "description": "Automatisch toegestane terminalcommando's uitvoeren zonder goedkeuring", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index a4484a5389d..d22067773a7 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -231,6 +231,18 @@ "description": "Automatycznie wybierz pierwszą sugerowaną odpowiedź na pytania uzupełniające po skonfigurowanym limicie czasu", "timeoutLabel": "Czas oczekiwania przed automatycznym wybraniem pierwszej odpowiedzi" }, + "ralph": { + "label": "Ralph", + "description": "Pokaż przycisk Ralph w trybie czatu, który umożliwia autonomiczną pętlę agenta", + "loopLimit": { + "label": "Limit pętli", + "description": "Maksymalna liczba automatycznych restartów zadania przez Ralpha. Ustaw na 0 dla nieograniczonej liczby pętli." + }, + "completionDelimiter": { + "label": "Separator zakończenia", + "description": "Jeśli ten tekst zostanie znaleziony w wyniku zakończenia, Ralph przestanie zapętlać." + } + }, "execute": { "label": "Wykonaj", "description": "Automatycznie wykonuj dozwolone polecenia terminala bez konieczności zatwierdzania", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 0b826365bf7..2b2f82a3f86 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -231,6 +231,18 @@ "description": "Selecionar automaticamente a primeira resposta sugerida para perguntas de acompanhamento após o tempo limite configurado", "timeoutLabel": "Tempo de espera antes de selecionar automaticamente a primeira resposta" }, + "ralph": { + "label": "Ralph", + "description": "Mostrar o botão Ralph no modo chat que habilita a capacidade de loop do agente autônomo", + "loopLimit": { + "label": "Limite de Loop", + "description": "Número máximo de vezes que o Ralph reiniciará automaticamente a tarefa. Defina como 0 para loops ilimitados." + }, + "completionDelimiter": { + "label": "Delimitador de Conclusão", + "description": "Se este texto for encontrado no resultado da conclusão, o Ralph parará de repetir o loop." + } + }, "execute": { "label": "Executar", "description": "Executar automaticamente comandos de terminal permitidos sem exigir aprovação", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 4a7f783c049..a8156cbd4b0 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -231,6 +231,18 @@ "description": "Автоматически выбирать первый предложенный ответ на дополнительные вопросы после настроенного тайм-аута", "timeoutLabel": "Время ожидания перед автоматическим выбором первого ответа" }, + "ralph": { + "label": "Ralph", + "description": "Показать кнопку Ralph в режиме чата, которая включает возможность цикла автономного агента", + "loopLimit": { + "label": "Лимит циклов", + "description": "Максимальное количество автоматических перезапусков задачи Ralph. Установите 0 для неограниченных циклов." + }, + "completionDelimiter": { + "label": "Разделитель завершения", + "description": "Если этот текст найден в результате завершения, Ralph прекратит циклическое выполнение." + } + }, "execute": { "label": "Выполнение", "description": "Автоматически выполнять разрешённые команды терминала без необходимости одобрения", diff --git a/webview-ui/src/i18n/locales/th/settings.json b/webview-ui/src/i18n/locales/th/settings.json index 128d387bee1..3c62013c6c2 100644 --- a/webview-ui/src/i18n/locales/th/settings.json +++ b/webview-ui/src/i18n/locales/th/settings.json @@ -263,6 +263,18 @@ "description": "เลือกคำตอบแรกที่แนะนำสำหรับคำถามติดตามโดยอัตโนมัติหลังจากหมดเวลาที่กำหนด", "timeoutLabel": "เวลารอก่อนเลือกคำตอบแรกโดยอัตโนมัติ" }, + "ralph": { + "label": "Ralph", + "description": "แสดงปุ่ม Ralph ในโหมดแชทที่เปิดใช้งานความสามารถในการวนซ้ำของตัวแทนอิสระ", + "loopLimit": { + "label": "จำกัดการวนซ้ำ", + "description": "จำนวนครั้งสูงสุดที่ Ralph จะเริ่มงานใหม่โดยอัตโนมัติ ตั้งค่าเป็น 0 สำหรับการวนซ้ำไม่จำกัด" + }, + "completionDelimiter": { + "label": "ตัวคั่นการเสร็จสิ้น", + "description": "หากพบข้อความนี้ในผลลัพธ์การเสร็จสิ้น Ralph จะหยุดการวนซ้ำ" + } + }, "execute": { "label": "ดำเนินการ", "description": "ดำเนินการคำสั่งเทอร์มินัลที่อนุญาตโดยอัตโนมัติโดยไม่ต้องขออนุมัติ", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index d7923a9d0d6..6683a4bc4dd 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -232,6 +232,18 @@ "description": "Yapılandırılan zaman aşımından sonra takip sorularına ilişkin ilk önerilen yanıtı otomatik olarak seç", "timeoutLabel": "İlk yanıtı otomatik olarak seçmeden önce beklenecek süre" }, + "ralph": { + "label": "Ralph", + "description": "Sohbet modunda otonom ajan döngü yeteneğini etkinleştiren Ralph düğmesini göster", + "loopLimit": { + "label": "Döngü Sınırı", + "description": "Ralph'ın görevi otomatik olarak yeniden başlatma maksimum sayısı. Sınırsız döngü için 0 olarak ayarlayın." + }, + "completionDelimiter": { + "label": "Tamamlama Sınırlayıcı", + "description": "Tamamlama sonucunda bu metin bulunursa, Ralph döngüyü durduracaktır." + } + }, "execute": { "label": "Yürüt", "description": "Onay gerektirmeden otomatik olarak izin verilen terminal komutlarını yürüt", diff --git a/webview-ui/src/i18n/locales/uk/settings.json b/webview-ui/src/i18n/locales/uk/settings.json index 5a999828dd4..49138dba259 100644 --- a/webview-ui/src/i18n/locales/uk/settings.json +++ b/webview-ui/src/i18n/locales/uk/settings.json @@ -269,6 +269,18 @@ "description": "Автоматично вибирати першу запропоновану відповідь на додаткові питання після налаштованого тайм-ауту", "timeoutLabel": "Час очікування перед автоматичним вибором першої відповіді" }, + "ralph": { + "label": "Ralph", + "description": "Показувати кнопку Ralph у режимі чату, що вмикає можливість циклу автономного агента", + "loopLimit": { + "label": "Ліміт циклів", + "description": "Максимальна кількість разів, коли Ralph автоматично перезапускатиме завдання. Встановіть 0 для необмеженої кількості циклів." + }, + "completionDelimiter": { + "label": "Розділювач завершення", + "description": "Якщо цей текст буде знайдено в результаті завершення, Ralph припинить циклічне виконання." + } + }, "execute": { "label": "Виконати", "description": "Автоматично виконувати дозволені команди терміналу без необхідності затвердження", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 7c104bde29b..9589f7f9dd8 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -231,6 +231,18 @@ "description": "Tự động chọn câu trả lời đầu tiên được đề xuất cho các câu hỏi tiếp theo sau thời gian chờ đã cấu hình", "timeoutLabel": "Thời gian chờ trước khi tự động chọn câu trả lời đầu tiên" }, + "ralph": { + "label": "Ralph", + "description": "Hiển thị nút Ralph trong chế độ chat để kích hoạt khả năng vòng lặp tác nhân tự trị", + "loopLimit": { + "label": "Giới hạn vòng lặp", + "description": "Số lần tối đa Ralph sẽ tự động khởi động lại tác vụ. Đặt thành 0 cho các vòng lặp không giới hạn." + }, + "completionDelimiter": { + "label": "Dấu phân cách hoàn thành", + "description": "Nếu văn bản này được tìm thấy trong kết quả hoàn thành, Ralph sẽ ngừng lặp lại." + } + }, "execute": { "label": "Thực thi", "description": "Tự động thực thi các lệnh terminal được phép mà không cần phê duyệt", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 419198ec64b..9cff46d2a0e 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -231,6 +231,18 @@ "description": "在配置的超时时间后自动选择后续问题的第一个建议答案", "timeoutLabel": "自动选择第一个答案前的等待时间" }, + "ralph": { + "label": "Ralph", + "description": "在聊天模式下显示 Ralph 按钮,启用自主代理循环能力", + "loopLimit": { + "label": "循环限制", + "description": "Ralph 自动重启任务的最大次数。设置为 0 表示无限循环。" + }, + "completionDelimiter": { + "label": "完成分隔符", + "description": "如果在完成结果中找到此文本,Ralph 将停止循环。" + } + }, "execute": { "label": "执行", "description": "自动执行白名单中的命令而无需批准", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 9746890711b..1a9f7e41fca 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -228,6 +228,18 @@ "description": "在設定的逾時時間後自動選擇後續問題的第一個建議答案", "timeoutLabel": "自動選擇第一個答案前的等待時間" }, + "ralph": { + "label": "Ralph", + "description": "在聊天模式下顯示 Ralph 按鈕,啟用自主代理循環能力", + "loopLimit": { + "label": "循環限制", + "description": "Ralph 自動重啟任務的最大次數。設置為 0 表示無限循環。" + }, + "completionDelimiter": { + "label": "完成分隔符", + "description": "如果在完成結果中找到此文本,Ralph 將停止循環。" + } + }, "execute": { "label": "執行", "description": "自動執行允許的終端機命令而無需核准",