diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 16e0c17e7ab..443842c856f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -84,7 +84,6 @@ body: - Google Gemini - Google Vertex AI - Groq - - Human Relay Provider - LiteLLM - LM Studio - Mistral AI diff --git a/.roo/rules-translate/instructions-zh-cn.md b/.roo/rules-translate/instructions-zh-cn.md index 6141038728c..b166a1e6a8d 100644 --- a/.roo/rules-translate/instructions-zh-cn.md +++ b/.roo/rules-translate/instructions-zh-cn.md @@ -16,7 +16,6 @@ | Auto-approve | 自动批准 | 始终批准 | 权限相关术语 | | Checkpoint | 存档点 | 检查点/快照 | 技术概念统一 | | MCP Server | MCP 服务 | MCP 服务器 | 技术组件 | -| Human Relay | 人工辅助模式 | 人工中继 | 功能描述清晰 | | Network Timeout | 请求超时 | 网络超时 | 更准确描述 | | Terminal | 终端 | 命令行 | 技术术语统一 | | diff | 差异更新 | 差分/补丁 | 代码变更 | diff --git a/apps/vscode-e2e/src/suite/extension.test.ts b/apps/vscode-e2e/src/suite/extension.test.ts index 5d59e003eff..c5340a882d6 100644 --- a/apps/vscode-e2e/src/suite/extension.test.ts +++ b/apps/vscode-e2e/src/suite/extension.test.ts @@ -19,10 +19,6 @@ suite("Roo Code Extension", function () { "openInNewTab", "settingsButtonClicked", "historyButtonClicked", - "showHumanRelayDialog", - "registerHumanRelayCallback", - "unregisterHumanRelayCallback", - "handleHumanRelayResponse", "newTask", "setCustomStoragePath", "focusInput", diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 95fbcf10c98..294e9f22e31 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -102,7 +102,7 @@ export const isCustomProvider = (key: string): key is CustomProvider => customPr * model lists. */ -export const fauxProviders = ["fake-ai", "human-relay"] as const +export const fauxProviders = ["fake-ai"] as const export type FauxProvider = (typeof fauxProviders)[number] @@ -344,8 +344,6 @@ const requestySchema = baseProviderSettingsSchema.extend({ requestyModelId: z.string().optional(), }) -const humanRelaySchema = baseProviderSettingsSchema - const fakeAiSchema = baseProviderSettingsSchema.extend({ fakeAi: z.unknown().optional(), }) @@ -447,7 +445,6 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv minimaxSchema.merge(z.object({ apiProvider: z.literal("minimax") })), unboundSchema.merge(z.object({ apiProvider: z.literal("unbound") })), requestySchema.merge(z.object({ apiProvider: z.literal("requesty") })), - humanRelaySchema.merge(z.object({ apiProvider: z.literal("human-relay") })), fakeAiSchema.merge(z.object({ apiProvider: z.literal("fake-ai") })), xaiSchema.merge(z.object({ apiProvider: z.literal("xai") })), groqSchema.merge(z.object({ apiProvider: z.literal("groq") })), @@ -489,7 +486,6 @@ export const providerSettingsSchema = z.object({ ...minimaxSchema.shape, ...unboundSchema.shape, ...requestySchema.shape, - ...humanRelaySchema.shape, ...fakeAiSchema.shape, ...xaiSchema.shape, ...groqSchema.shape, @@ -627,7 +623,7 @@ export const getApiProtocol = (provider: ProviderName | undefined, modelId?: str */ export const MODELS_BY_PROVIDER: Record< - Exclude, + Exclude, { id: ProviderName; label: string; models: string[] } > = { anthropic: { diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index ecd56bd41a4..a08d673e221 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -143,7 +143,6 @@ export function getProviderDefaultModelId( return vercelAiGatewayDefaultModelId case "anthropic": case "gemini-cli": - case "human-relay": case "fake-ai": default: return anthropicDefaultModelId diff --git a/packages/types/src/vscode.ts b/packages/types/src/vscode.ts index 98a633671c4..fd28f2e9945 100644 --- a/packages/types/src/vscode.ts +++ b/packages/types/src/vscode.ts @@ -38,11 +38,6 @@ export const commandIds = [ "openInNewTab", - "showHumanRelayDialog", - "registerHumanRelayCallback", - "unregisterHumanRelayCallback", - "handleHumanRelayResponse", - "newTask", "setCustomStoragePath", diff --git a/src/activate/humanRelay.ts b/src/activate/humanRelay.ts deleted file mode 100644 index ed87026aa73..00000000000 --- a/src/activate/humanRelay.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Callback mapping of human relay response. -const humanRelayCallbacks = new Map void>() - -/** - * Register a callback function for human relay response. - * @param requestId - * @param callback - */ -export const registerHumanRelayCallback = (requestId: string, callback: (response: string | undefined) => void) => - humanRelayCallbacks.set(requestId, callback) - -export const unregisterHumanRelayCallback = (requestId: string) => humanRelayCallbacks.delete(requestId) - -export const handleHumanRelayResponse = (response: { requestId: string; text?: string; cancelled?: boolean }) => { - const callback = humanRelayCallbacks.get(response.requestId) - - if (callback) { - if (response.cancelled) { - callback(undefined) - } else { - callback(response.text) - } - - humanRelayCallbacks.delete(response.requestId) - } -} diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts index ad75642406c..f02ee8309a3 100644 --- a/src/activate/registerCommands.ts +++ b/src/activate/registerCommands.ts @@ -9,8 +9,6 @@ import { getCommand } from "../utils/commands" import { ClineProvider } from "../core/webview/ClineProvider" import { ContextProxy } from "../core/config/ContextProxy" import { focusPanel } from "../utils/focusPanel" - -import { registerHumanRelayCallback, unregisterHumanRelayCallback, handleHumanRelayResponse } from "./humanRelay" import { handleNewTask } from "./handleTask" import { CodeIndexManager } from "../services/code-index/manager" import { importSettingsWithFeedback } from "../core/config/importExport" @@ -136,20 +134,6 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt if (!visibleProvider) return visibleProvider.postMessageToWebview({ type: "action", action: "marketplaceButtonClicked" }) }, - showHumanRelayDialog: (params: { requestId: string; promptText: string }) => { - const panel = getPanel() - - if (panel) { - panel?.webview.postMessage({ - type: "showHumanRelayDialog", - requestId: params.requestId, - promptText: params.promptText, - }) - } - }, - registerHumanRelayCallback: registerHumanRelayCallback, - unregisterHumanRelayCallback: unregisterHumanRelayCallback, - handleHumanRelayResponse: handleHumanRelayResponse, newTask: handleNewTask, setCustomStoragePath: async () => { const { promptForCustomStoragePath } = await import("../utils/storage") diff --git a/src/api/index.ts b/src/api/index.ts index b1bfc582548..2ee882ad72c 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -22,7 +22,6 @@ import { VsCodeLmHandler, UnboundHandler, RequestyHandler, - HumanRelayHandler, FakeAIHandler, XAIHandler, GroqHandler, @@ -159,8 +158,6 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { return new UnboundHandler(options) case "requesty": return new RequestyHandler(options) - case "human-relay": - return new HumanRelayHandler() case "fake-ai": return new FakeAIHandler(options) case "xai": @@ -198,7 +195,6 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { case "baseten": return new BasetenHandler(options) default: - apiProvider satisfies "gemini-cli" | undefined return new AnthropicHandler(options) } } diff --git a/src/api/providers/human-relay.ts b/src/api/providers/human-relay.ts deleted file mode 100644 index 54446bd3625..00000000000 --- a/src/api/providers/human-relay.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { Anthropic } from "@anthropic-ai/sdk" -import * as vscode from "vscode" - -import type { ModelInfo } from "@roo-code/types" - -import { getCommand } from "../../utils/commands" -import { ApiStream } from "../transform/stream" - -import type { ApiHandler, SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index" - -/** - * Human Relay API processor - * This processor does not directly call the API, but interacts with the model through human operations copy and paste. - */ -export class HumanRelayHandler implements ApiHandler, SingleCompletionHandler { - countTokens(_content: Array): Promise { - return Promise.resolve(0) - } - - /** - * Create a message processing flow, display a dialog box to request human assistance - * @param systemPrompt System prompt words - * @param messages Message list - * @param metadata Optional metadata - */ - async *createMessage( - systemPrompt: string, - messages: Anthropic.Messages.MessageParam[], - metadata?: ApiHandlerCreateMessageMetadata, - ): ApiStream { - // Get the most recent user message - const latestMessage = messages[messages.length - 1] - - if (!latestMessage) { - throw new Error("No message to relay") - } - - // If it is the first message, splice the system prompt word with the user message - let promptText = "" - if (messages.length === 1) { - promptText = `${systemPrompt}\n\n${getMessageContent(latestMessage)}` - } else { - promptText = getMessageContent(latestMessage) - } - - // Copy to clipboard - await vscode.env.clipboard.writeText(promptText) - - // A dialog box pops up to request user action - const response = await showHumanRelayDialog(promptText) - - if (!response) { - // The user canceled the operation - throw new Error("Human relay operation cancelled") - } - - // Return to the user input reply - yield { type: "text", text: response } - } - - /** - * Get model information - */ - getModel(): { id: string; info: ModelInfo } { - // Human relay does not depend on a specific model, here is a default configuration - return { - id: "human-relay", - info: { - maxTokens: 16384, - contextWindow: 100000, - supportsImages: true, - supportsPromptCache: false, - inputPrice: 0, - outputPrice: 0, - description: "Calling web-side AI model through human relay", - }, - } - } - - /** - * Implementation of a single prompt - * @param prompt Prompt content - */ - async completePrompt(prompt: string): Promise { - // Copy to clipboard - await vscode.env.clipboard.writeText(prompt) - - // A dialog box pops up to request user action - const response = await showHumanRelayDialog(prompt) - - if (!response) { - throw new Error("Human relay operation cancelled") - } - - return response - } -} - -/** - * Extract text content from message object - * @param message - */ -function getMessageContent(message: Anthropic.Messages.MessageParam): string { - if (typeof message.content === "string") { - return message.content - } else if (Array.isArray(message.content)) { - return message.content - .filter((item) => item.type === "text") - .map((item) => (item.type === "text" ? item.text : "")) - .join("\n") - } - return "" -} -/** - * Displays the human relay dialog and waits for user response. - * @param promptText The prompt text that needs to be copied. - * @returns The user's input response or undefined (if canceled). - */ -async function showHumanRelayDialog(promptText: string): Promise { - return new Promise((resolve) => { - // Create a unique request ID. - const requestId = Date.now().toString() - - // Register a global callback function. - vscode.commands.executeCommand( - getCommand("registerHumanRelayCallback"), - requestId, - (response: string | undefined) => resolve(response), - ) - - // Open the dialog box directly using the current panel. - vscode.commands.executeCommand(getCommand("showHumanRelayDialog"), { requestId, promptText }) - }) -} diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index 23ef40ee133..fe9388962f0 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -11,7 +11,6 @@ export { FakeAIHandler } from "./fake-ai" export { GeminiHandler } from "./gemini" export { GroqHandler } from "./groq" export { HuggingFaceHandler } from "./huggingface" -export { HumanRelayHandler } from "./human-relay" export { IOIntelligenceHandler } from "./io-intelligence" export { LiteLLMHandler } from "./lite-llm" export { LmStudioHandler } from "./lm-studio" diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 52ec8146552..35bf08e0486 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -2218,25 +2218,6 @@ export const webviewMessageHandler = async ( }) } break - case "humanRelayResponse": - if (message.requestId && message.text) { - vscode.commands.executeCommand(getCommand("handleHumanRelayResponse"), { - requestId: message.requestId, - text: message.text, - cancelled: false, - }) - } - break - - case "humanRelayCancel": - if (message.requestId) { - vscode.commands.executeCommand(getCommand("handleHumanRelayResponse"), { - requestId: message.requestId, - cancelled: true, - }) - } - break - case "telemetrySetting": { const telemetrySetting = message.text as TelemetrySetting const previousSetting = getGlobalState("telemetrySetting") || "unset" diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index c83cbc91543..759843ffebc 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -94,9 +94,6 @@ export interface ExtensionMessage { | "deleteCustomModeCheck" | "currentCheckpointUpdated" | "checkpointInitWarning" - | "showHumanRelayDialog" - | "humanRelayResponse" - | "humanRelayCancel" | "browserToolEnabled" | "browserConnectionResult" | "remoteBrowserEnabled" diff --git a/src/shared/ProfileValidator.ts b/src/shared/ProfileValidator.ts index c8a2c243c00..3ca5b5616d0 100644 --- a/src/shared/ProfileValidator.ts +++ b/src/shared/ProfileValidator.ts @@ -14,10 +14,6 @@ export class ProfileValidator { return false } - if (profile.apiProvider === "human-relay") { - return true - } - const modelId = this.getModelIdFromProfile(profile) if (!modelId) { @@ -90,7 +86,6 @@ export class ProfileValidator { return profile.ioIntelligenceModelId case "deepinfra": return profile.deepInfraModelId - case "human-relay": case "fake-ai": default: return undefined diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index d96fbd871ce..4c3e321dea8 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -113,8 +113,6 @@ export interface WebviewMessage { | "checkpointDiff" | "checkpointRestore" | "deleteMcpServer" - | "humanRelayResponse" - | "humanRelayCancel" | "codebaseIndexEnabled" | "telemetrySetting" | "testBrowserConnection" diff --git a/src/shared/__tests__/ProfileValidator.spec.ts b/src/shared/__tests__/ProfileValidator.spec.ts index d604cd95234..04bd171696e 100644 --- a/src/shared/__tests__/ProfileValidator.spec.ts +++ b/src/shared/__tests__/ProfileValidator.spec.ts @@ -47,20 +47,6 @@ describe("ProfileValidator", () => { expect(ProfileValidator.isProfileAllowed(profile, allowList)).toBe(false) }) - it("should allow human-relay provider regardless of model", () => { - const allowList: OrganizationAllowList = { - allowAll: false, - providers: { - "human-relay": { allowAll: false }, - }, - } - const profile: ProviderSettings = { - apiProvider: "human-relay", - } - - expect(ProfileValidator.isProfileAllowed(profile, allowList)).toBe(true) - }) - it("should allow providers with allowAll=true regardless of model", () => { const allowList: OrganizationAllowList = { allowAll: false, diff --git a/src/shared/checkExistApiConfig.ts b/src/shared/checkExistApiConfig.ts index 4b9af08d5af..37b468ce1ac 100644 --- a/src/shared/checkExistApiConfig.ts +++ b/src/shared/checkExistApiConfig.ts @@ -5,11 +5,8 @@ export function checkExistKey(config: ProviderSettings | undefined) { return false } - // Special case for human-relay, fake-ai, claude-code, qwen-code, and roo providers which don't need any configuration. - if ( - config.apiProvider && - ["human-relay", "fake-ai", "claude-code", "qwen-code", "roo"].includes(config.apiProvider) - ) { + // Special case for fake-ai, claude-code, qwen-code, and roo providers which don't need any configuration. + if (config.apiProvider && ["fake-ai", "claude-code", "qwen-code", "roo"].includes(config.apiProvider)) { return true } diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx index dbf26be7c53..04d9b76f2c7 100644 --- a/webview-ui/src/App.tsx +++ b/webview-ui/src/App.tsx @@ -16,7 +16,6 @@ import HistoryView from "./components/history/HistoryView" import SettingsView, { SettingsViewRef } from "./components/settings/SettingsView" import WelcomeView from "./components/welcome/WelcomeViewProvider" import { MarketplaceView } from "./components/marketplace/MarketplaceView" -import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog" import { CheckpointRestoreDialog } from "./components/chat/CheckpointRestoreDialog" import { DeleteMessageDialog, EditMessageDialog } from "./components/chat/MessageModificationConfirmationDialog" import ErrorBoundary from "./components/ErrorBoundary" @@ -27,12 +26,6 @@ import { STANDARD_TOOLTIP_DELAY } from "./components/ui/standard-tooltip" type Tab = "settings" | "history" | "chat" | "marketplace" | "cloud" -interface HumanRelayDialogState { - isOpen: boolean - requestId: string - promptText: string -} - interface DeleteMessageDialogState { isOpen: boolean messageTs: number @@ -51,8 +44,6 @@ interface EditMessageDialogState { const MemoizedDeleteMessageDialog = React.memo(DeleteMessageDialog) const MemoizedEditMessageDialog = React.memo(EditMessageDialog) const MemoizedCheckpointRestoreDialog = React.memo(CheckpointRestoreDialog) -const MemoizedHumanRelayDialog = React.memo(HumanRelayDialog) - const tabsByMessageAction: Partial, Tab>> = { chatButtonClicked: "chat", settingsButtonClicked: "settings", @@ -83,12 +74,6 @@ const App = () => { const [showAnnouncement, setShowAnnouncement] = useState(false) const [tab, setTab] = useState("chat") - const [humanRelayDialogState, setHumanRelayDialogState] = useState({ - isOpen: false, - requestId: "", - promptText: "", - }) - const [deleteMessageDialogState, setDeleteMessageDialogState] = useState({ isOpen: false, messageTs: 0, @@ -158,11 +143,6 @@ const App = () => { } } - if (message.type === "showHumanRelayDialog" && message.requestId && message.promptText) { - const { requestId, promptText } = message - setHumanRelayDialogState({ isOpen: true, requestId, promptText }) - } - if (message.type === "showDeleteMessageDialog" && message.messageTs) { setDeleteMessageDialogState({ isOpen: true, @@ -271,14 +251,6 @@ const App = () => { showAnnouncement={showAnnouncement} hideAnnouncement={() => setShowAnnouncement(false)} /> - setHumanRelayDialogState((prev) => ({ ...prev, isOpen: false }))} - onSubmit={(requestId, text) => vscode.postMessage({ type: "humanRelayResponse", requestId, text })} - onCancel={(requestId) => vscode.postMessage({ type: "humanRelayCancel", requestId })} - /> {deleteMessageDialogState.hasCheckpoint ? ( ({ const mockUseExtensionState = vi.fn() -// Mock the HumanRelayDialog component -vi.mock("@src/components/human-relay/HumanRelayDialog", () => ({ - HumanRelayDialog: ({ _children, isOpen, onClose }: any) => ( -
- Human Relay Dialog -
- ), -})) - // Mock i18next and react-i18next vi.mock("i18next", () => { const tFunction = (key: string) => key diff --git a/webview-ui/src/components/human-relay/HumanRelayDialog.tsx b/webview-ui/src/components/human-relay/HumanRelayDialog.tsx deleted file mode 100644 index a19a0037d0d..00000000000 --- a/webview-ui/src/components/human-relay/HumanRelayDialog.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import * as React from "react" -import { Button } from "../ui/button" -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../ui/dialog" -import { Textarea } from "../ui/textarea" -import { useClipboard } from "../ui/hooks" -import { Check, Copy, X } from "lucide-react" -import { useAppTranslation } from "@/i18n/TranslationContext" - -interface HumanRelayDialogProps { - isOpen: boolean - onClose: () => void - requestId: string - promptText: string - onSubmit: (requestId: string, text: string) => void - onCancel: (requestId: string) => void -} - -/** - * Human Relay Dialog Component - * Displays the prompt text that needs to be copied and provides an input box for the user to paste the AI's response. - */ -export const HumanRelayDialog: React.FC = ({ - isOpen, - onClose, - requestId, - promptText, - onSubmit, - onCancel, -}) => { - const { t } = useAppTranslation() - const [response, setResponse] = React.useState("") - const { copy } = useClipboard() - const [isCopyClicked, setIsCopyClicked] = React.useState(false) - - // Clear input when dialog opens - React.useEffect(() => { - if (isOpen) { - setResponse("") - setIsCopyClicked(false) - } - }, [isOpen]) - - // Copy to clipboard and show success message - const handleCopy = () => { - copy(promptText) - setIsCopyClicked(true) - setTimeout(() => { - setIsCopyClicked(false) - }, 2000) - } - - // Submit response - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault() - if (response.trim()) { - onSubmit(requestId, response) - onClose() - } - } - - // Cancel operation - const handleCancel = () => { - onCancel(requestId) - onClose() - } - - return ( - !open && handleCancel()}> - - - {t("humanRelay:dialogTitle")} - {t("humanRelay:dialogDescription")} - - -
-
-