diff --git a/frontend/src/assets/confirm.tsx b/frontend/src/assets/confirm.tsx new file mode 100644 index 000000000000..f982f14cef38 --- /dev/null +++ b/frontend/src/assets/confirm.tsx @@ -0,0 +1,18 @@ +import React from "react"; + +function ConfirmIcon(): JSX.Element { + return ( + + + + ); +} + +export default ConfirmIcon; diff --git a/frontend/src/assets/reject.tsx b/frontend/src/assets/reject.tsx new file mode 100644 index 000000000000..1713d93cd5b5 --- /dev/null +++ b/frontend/src/assets/reject.tsx @@ -0,0 +1,22 @@ +import React from "react"; + +function RejectIcon(): JSX.Element { + return ( + + + + ); +} + +export default RejectIcon; diff --git a/frontend/src/components/AgentControlBar.tsx b/frontend/src/components/AgentControlBar.tsx index e33dd8d9e265..04f1775b2323 100644 --- a/frontend/src/components/AgentControlBar.tsx +++ b/frontend/src/components/AgentControlBar.tsx @@ -17,6 +17,7 @@ const IgnoreTaskStateMap: { [k: string]: AgentState[] } = { AgentState.FINISHED, AgentState.REJECTED, AgentState.AWAITING_USER_INPUT, + AgentState.AWAITING_USER_CONFIRMATION, ], [AgentState.RUNNING]: [ AgentState.INIT, @@ -25,8 +26,12 @@ const IgnoreTaskStateMap: { [k: string]: AgentState[] } = { AgentState.FINISHED, AgentState.REJECTED, AgentState.AWAITING_USER_INPUT, + AgentState.AWAITING_USER_CONFIRMATION, ], [AgentState.STOPPED]: [AgentState.INIT, AgentState.STOPPED], + [AgentState.USER_CONFIRMED]: [AgentState.RUNNING], + [AgentState.USER_REJECTED]: [AgentState.RUNNING], + [AgentState.AWAITING_USER_CONFIRMATION]: [], }; interface ButtonProps { @@ -101,42 +106,44 @@ function AgentControlBar() { }, [curAgentState]); return ( -
- {curAgentState === AgentState.PAUSED ? ( +
+
+ {curAgentState === AgentState.PAUSED ? ( + + + + ) : ( + + + + )} - + - ) : ( - - - - )} - - - +
); } diff --git a/frontend/src/components/AgentStatusBar.tsx b/frontend/src/components/AgentStatusBar.tsx index bdcb3e6773d9..9c38e3e20bf6 100644 --- a/frontend/src/components/AgentStatusBar.tsx +++ b/frontend/src/components/AgentStatusBar.tsx @@ -58,6 +58,20 @@ function AgentStatusBar() { message: t(I18nKey.CHAT_INTERFACE$AGENT_ERROR_MESSAGE), indicator: IndicatorColor.RED, }, + [AgentState.AWAITING_USER_CONFIRMATION]: { + message: t( + I18nKey.CHAT_INTERFACE$AGENT_AWAITING_USER_CONFIRMATION_MESSAGE, + ), + indicator: IndicatorColor.ORANGE, + }, + [AgentState.USER_CONFIRMED]: { + message: t(I18nKey.CHAT_INTERFACE$AGENT_ACTION_USER_CONFIRMED_MESSAGE), + indicator: IndicatorColor.GREEN, + }, + [AgentState.USER_REJECTED]: { + message: t(I18nKey.CHAT_INTERFACE$AGENT_ACTION_USER_REJECTED_MESSAGE), + indicator: IndicatorColor.RED, + }, }; // TODO: Extend the agent status, e.g.: diff --git a/frontend/src/components/chat/Chat.test.tsx b/frontend/src/components/chat/Chat.test.tsx index eee37dd4bd6e..1753236c8afa 100644 --- a/frontend/src/components/chat/Chat.test.tsx +++ b/frontend/src/components/chat/Chat.test.tsx @@ -1,6 +1,7 @@ import React from "react"; -import { render, screen } from "@testing-library/react"; +import { screen } from "@testing-library/react"; import { describe, expect, it } from "vitest"; +import { renderWithProviders } from "test-utils"; import Chat from "./Chat"; const MESSAGES: Message[] = [ @@ -13,7 +14,7 @@ HTMLElement.prototype.scrollTo = vi.fn(() => {}); describe("Chat", () => { it("should render chat messages", () => { - render(); + renderWithProviders(); const messages = screen.getAllByTestId("message"); diff --git a/frontend/src/components/chat/Chat.tsx b/frontend/src/components/chat/Chat.tsx index 4f82d1889efc..06122b4d8879 100644 --- a/frontend/src/components/chat/Chat.tsx +++ b/frontend/src/components/chat/Chat.tsx @@ -1,15 +1,24 @@ import React from "react"; import ChatMessage from "./ChatMessage"; +import AgentState from "#/types/AgentState"; interface ChatProps { messages: Message[]; + curAgentState?: AgentState; } -function Chat({ messages }: ChatProps) { +function Chat({ messages, curAgentState }: ChatProps) { return (
{messages.map((message, index) => ( - + ))}
); diff --git a/frontend/src/components/chat/ChatInterface.tsx b/frontend/src/components/chat/ChatInterface.tsx index c4fde682af2f..5dcdae3c8f91 100644 --- a/frontend/src/components/chat/ChatInterface.tsx +++ b/frontend/src/components/chat/ChatInterface.tsx @@ -123,7 +123,7 @@ function ChatInterface() { className="overflow-y-auto p-3" onScroll={(e) => onChatBodyScroll(e.currentTarget)} > - +
@@ -169,7 +169,10 @@ function ChatInterface() { ({ describe("Message", () => { it("should render a user message", () => { - render(); + render( + , + ); expect(screen.getByTestId("message")).toBeInTheDocument(); expect(screen.getByTestId("message")).toHaveClass("self-end"); // user message should be on the right side }); it("should render an assistant message", () => { - render(); + render( + , + ); expect(screen.getByTestId("message")).toBeInTheDocument(); expect(screen.getByTestId("message")).not.toHaveClass("self-end"); // assistant message should be on the left side @@ -30,6 +40,7 @@ describe("Message", () => { sender: "user", content: "```js\nconsole.log('Hello')\n```", }} + isLastMessage={false} />, ); diff --git a/frontend/src/components/chat/ChatMessage.tsx b/frontend/src/components/chat/ChatMessage.tsx index 522696195f37..a78eaef738a0 100644 --- a/frontend/src/components/chat/ChatMessage.tsx +++ b/frontend/src/components/chat/ChatMessage.tsx @@ -3,15 +3,26 @@ import Markdown from "react-markdown"; import { FaClipboard, FaClipboardCheck } from "react-icons/fa"; import { twMerge } from "tailwind-merge"; import { useTranslation } from "react-i18next"; +import { Tooltip } from "@nextui-org/react"; +import AgentState from "#/types/AgentState"; import { code } from "../markdown/code"; import toast from "#/utils/toast"; import { I18nKey } from "#/i18n/declaration"; +import ConfirmIcon from "#/assets/confirm"; +import RejectIcon from "#/assets/reject"; +import { changeAgentState } from "#/services/agentStateService"; interface MessageProps { message: Message; + isLastMessage?: boolean; + awaitingUserConfirmation?: boolean; } -function ChatMessage({ message }: MessageProps) { +function ChatMessage({ + message, + isLastMessage, + awaitingUserConfirmation, +}: MessageProps) { const [isCopy, setIsCopy] = useState(false); const [isHovering, setIsHovering] = useState(false); @@ -58,6 +69,45 @@ function ChatMessage({ message }: MessageProps) { )} {message.content} + {isLastMessage && + message.sender === "assistant" && + awaitingUserConfirmation && ( +
+

{t(I18nKey.CHAT_INTERFACE$USER_ASK_CONFIRMATION)}

+
+ + + + + + +
+
+ )} ); } diff --git a/frontend/src/components/modals/settings/SettingsForm.test.tsx b/frontend/src/components/modals/settings/SettingsForm.test.tsx index af44d9ad40ab..e8ade8dcf0cb 100644 --- a/frontend/src/components/modals/settings/SettingsForm.test.tsx +++ b/frontend/src/components/modals/settings/SettingsForm.test.tsx @@ -9,6 +9,7 @@ const onModelChangeMock = vi.fn(); const onAgentChangeMock = vi.fn(); const onLanguageChangeMock = vi.fn(); const onAPIKeyChangeMock = vi.fn(); +const onConfirmationModeChangeMock = vi.fn(); const renderSettingsForm = (settings?: Settings) => { renderWithProviders( @@ -20,6 +21,7 @@ const renderSettingsForm = (settings?: Settings) => { AGENT: "agent1", LANGUAGE: "en", LLM_API_KEY: "sk-...", + CONFIRMATION_MODE: true, } } models={["model1", "model2", "model3"]} @@ -28,6 +30,7 @@ const renderSettingsForm = (settings?: Settings) => { onAgentChange={onAgentChangeMock} onLanguageChange={onLanguageChangeMock} onAPIKeyChange={onAPIKeyChangeMock} + onConfirmationModeChange={onConfirmationModeChangeMock} />, ); }; @@ -40,11 +43,13 @@ describe("SettingsForm", () => { const agentInput = screen.getByRole("combobox", { name: "agent" }); const languageInput = screen.getByRole("combobox", { name: "language" }); const apiKeyInput = screen.getByTestId("apikey"); + const confirmationModeInput = screen.getByTestId("confirmationmode"); expect(modelInput).toHaveValue("model1"); expect(agentInput).toHaveValue("agent1"); expect(languageInput).toHaveValue("English"); expect(apiKeyInput).toHaveValue("sk-..."); + expect(confirmationModeInput).toHaveAttribute("data-selected", "true"); }); it("should display the existing values if it they are present", () => { @@ -53,6 +58,7 @@ describe("SettingsForm", () => { AGENT: "agent2", LANGUAGE: "es", LLM_API_KEY: "sk-...", + CONFIRMATION_MODE: true, }); const modelInput = screen.getByRole("combobox", { name: "model" }); @@ -72,6 +78,7 @@ describe("SettingsForm", () => { AGENT: "agent1", LANGUAGE: "en", LLM_API_KEY: "sk-...", + CONFIRMATION_MODE: true, }} models={["model1", "model2", "model3"]} agents={["agent1", "agent2", "agent3"]} @@ -80,15 +87,18 @@ describe("SettingsForm", () => { onAgentChange={onAgentChangeMock} onLanguageChange={onLanguageChangeMock} onAPIKeyChange={onAPIKeyChangeMock} + onConfirmationModeChange={onConfirmationModeChangeMock} />, ); const modelInput = screen.getByRole("combobox", { name: "model" }); const agentInput = screen.getByRole("combobox", { name: "agent" }); const languageInput = screen.getByRole("combobox", { name: "language" }); + const confirmationModeInput = screen.getByTestId("confirmationmode"); expect(modelInput).toBeDisabled(); expect(agentInput).toBeDisabled(); expect(languageInput).toBeDisabled(); + expect(confirmationModeInput).toHaveAttribute("data-disabled", "true"); }); describe("onChange handlers", () => { diff --git a/frontend/src/components/modals/settings/SettingsForm.tsx b/frontend/src/components/modals/settings/SettingsForm.tsx index 62b47bafeb00..927db98883c2 100644 --- a/frontend/src/components/modals/settings/SettingsForm.tsx +++ b/frontend/src/components/modals/settings/SettingsForm.tsx @@ -1,4 +1,4 @@ -import { Input, useDisclosure } from "@nextui-org/react"; +import { Input, Switch, Tooltip, useDisclosure } from "@nextui-org/react"; import React from "react"; import { useTranslation } from "react-i18next"; import { FaEye, FaEyeSlash } from "react-icons/fa"; @@ -17,6 +17,7 @@ interface SettingsFormProps { onAPIKeyChange: (apiKey: string) => void; onAgentChange: (agent: string) => void; onLanguageChange: (language: string) => void; + onConfirmationModeChange: (confirmationMode: boolean) => void; } function SettingsForm({ @@ -28,6 +29,7 @@ function SettingsForm({ onAPIKeyChange, onAgentChange, onLanguageChange, + onConfirmationModeChange, }: SettingsFormProps) { const { t } = useTranslation(); const { isOpen: isVisible, onOpenChange: onVisibleChange } = useDisclosure(); @@ -86,6 +88,21 @@ function SettingsForm({ tooltip={t(I18nKey.SETTINGS$LANGUAGE_TOOLTIP)} disabled={disabled} /> + + + {t(I18nKey.SETTINGS$CONFIRMATION_MODE)} + + ); } diff --git a/frontend/src/components/modals/settings/SettingsModal.test.tsx b/frontend/src/components/modals/settings/SettingsModal.test.tsx index 7af0f9e55792..45dbad06f2ed 100644 --- a/frontend/src/components/modals/settings/SettingsModal.test.tsx +++ b/frontend/src/components/modals/settings/SettingsModal.test.tsx @@ -27,12 +27,14 @@ vi.mock("#/services/settings", async (importOriginal) => ({ AGENT: "CodeActAgent", LANGUAGE: "en", LLM_API_KEY: "sk-...", + CONFIRMATION_MODE: true, }), getDefaultSettings: vi.fn().mockReturnValue({ LLM_MODEL: "gpt-4o", AGENT: "CodeActAgent", LANGUAGE: "en", LLM_API_KEY: "", + CONFIRMATION_MODE: false, }), settingsAreUpToDate: vi.fn().mockReturnValue(true), saveSettings: vi.fn(), @@ -107,6 +109,7 @@ describe("SettingsModal", () => { AGENT: "CodeActAgent", LANGUAGE: "en", LLM_API_KEY: "sk-...", + CONFIRMATION_MODE: true, }; it("should save the settings", async () => { @@ -196,7 +199,7 @@ describe("SettingsModal", () => { await userEvent.click(saveButton); }); - expect(toastSpy).toHaveBeenCalledTimes(2); + expect(toastSpy).toHaveBeenCalledTimes(3); }); it("should change the language", async () => { diff --git a/frontend/src/components/modals/settings/SettingsModal.tsx b/frontend/src/components/modals/settings/SettingsModal.tsx index 3eecccb2c547..45ce2adcff8f 100644 --- a/frontend/src/components/modals/settings/SettingsModal.tsx +++ b/frontend/src/components/modals/settings/SettingsModal.tsx @@ -48,7 +48,8 @@ function SettingsModal({ isOpen, onOpenChange }: SettingsProps) { const isRunning = curAgentState === AgentState.RUNNING || curAgentState === AgentState.PAUSED || - curAgentState === AgentState.AWAITING_USER_INPUT; + curAgentState === AgentState.AWAITING_USER_INPUT || + curAgentState === AgentState.AWAITING_USER_CONFIRMATION; setAgentIsRunning(isRunning); }, [curAgentState]); @@ -89,6 +90,10 @@ function SettingsModal({ isOpen, onOpenChange }: SettingsProps) { setSettings((prev) => ({ ...prev, LLM_API_KEY: key })); }; + const handleConfirmationModeChange = (confirmationMode: boolean) => { + setSettings((prev) => ({ ...prev, CONFIRMATION_MODE: confirmationMode })); + }; + const handleResetSettings = () => { setSettings(getDefaultSettings); }; @@ -170,6 +175,7 @@ function SettingsModal({ isOpen, onOpenChange }: SettingsProps) { onAgentChange={handleAgentChange} onLanguageChange={handleLanguageChange} onAPIKeyChange={handleAPIKeyChange} + onConfirmationModeChange={handleConfirmationModeChange} /> )} diff --git a/frontend/src/i18n/translation.json b/frontend/src/i18n/translation.json index 745fffb97e7b..487b4535ed13 100644 --- a/frontend/src/i18n/translation.json +++ b/frontend/src/i18n/translation.json @@ -567,6 +567,21 @@ "de": "Agent ist auf einen Fehler gelaufen.", "zh-CN": "智能体遇到错误" }, + "CHAT_INTERFACE$AGENT_AWAITING_USER_CONFIRMATION_MESSAGE": { + "en": "Agent is awaiting user confirmation for the pending action.", + "de": "Agent wartet auf die Bestätigung des Benutzers für die ausstehende Aktion.", + "zh-CN": "代理正在等待用户确认待处理的操作。" + }, + "CHAT_INTERFACE$AGENT_ACTION_USER_CONFIRMED_MESSAGE": { + "en": "Agent action has been confirmed!", + "de": "Die Aktion des Agenten wurde bestätigt!", + "zh-CN": "代理操作已确认!" + }, + "CHAT_INTERFACE$AGENT_ACTION_USER_REJECTED_MESSAGE": { + "en": "Agent action has been rejected!", + "de": "Die Aktion des Agenten wurde abgelehnt!", + "zh-CN": "代理操作已被拒绝!" + }, "CHAT_INTERFACE$INPUT_PLACEHOLDER": { "en": "Message assistant...", "zh-CN": "给助理发消息", @@ -586,6 +601,21 @@ "zh-CN": "继续", "de": "Fortfahren" }, + "CHAT_INTERFACE$USER_ASK_CONFIRMATION": { + "en": "Do you want to continue with this action?", + "de": "Möchten Sie mit dieser Aktion fortfahren?", + "zh-CN": "您要继续此操作吗?" + }, + "CHAT_INTERFACE$USER_CONFIRMED": { + "en": "Confirm the requested action", + "de": "Bestätigen Sie die angeforderte Aktion", + "zh-CN": "确认请求的操作" + }, + "CHAT_INTERFACE$USER_REJECTED": { + "en": "Reject the requested action", + "de": "Lehnen Sie die angeforderte Aktion ab", + "zh-CN": "拒绝请求的操作" + }, "CHAT_INTERFACE$INPUT_SEND_MESSAGE_BUTTON_CONTENT": { "en": "Send", "zh-CN": "发送", @@ -681,6 +711,16 @@ "zh-TW": "輸入您的 API 金鑰。", "de": "Modell API Schlüssel." }, + "SETTINGS$CONFIRMATION_MODE": { + "en": "Enable Confirmation Mode", + "de": "Bestätigungsmodus aktivieren", + "zh-CN": "启用确认模式" + }, + "SETTINGS$CONFIRMATION_MODE_TOOLTIP": { + "en": "Awaits for user confirmation before executing code.", + "de": "Wartet auf die Bestätigung des Benutzers, bevor der Code ausgeführt wird.", + "zh-CN": "在执行代码之前等待用户确认。" + }, "BROWSER$EMPTY_MESSAGE": { "en": "No page loaded.", "zh-CN": "页面未加载", diff --git a/frontend/src/services/actions.ts b/frontend/src/services/actions.ts index 64c424572956..b1d91f5485fc 100644 --- a/frontend/src/services/actions.ts +++ b/frontend/src/services/actions.ts @@ -46,13 +46,23 @@ const messageActions = { if (message.args.thought) { store.dispatch(addAssistantMessage(message.args.thought)); } - store.dispatch(appendInput(message.args.command)); + if ( + !message.args.is_confirmed || + message.args.is_confirmed !== "rejected" + ) { + store.dispatch(appendInput(message.args.command)); + } }, [ActionType.RUN_IPYTHON]: (message: ActionMessage) => { if (message.args.thought) { store.dispatch(addAssistantMessage(message.args.thought)); } - store.dispatch(appendJupyterInput(message.args.code)); + if ( + !message.args.is_confirmed || + message.args.is_confirmed !== "rejected" + ) { + store.dispatch(appendJupyterInput(message.args.code)); + } }, [ActionType.ADD_TASK]: () => { getRootTask().then((fetchedRootTask) => @@ -67,6 +77,32 @@ const messageActions = { }; export function handleActionMessage(message: ActionMessage) { + if ( + (message.action === ActionType.RUN || + message.action === ActionType.RUN_IPYTHON) && + message.args.is_confirmed === "awaiting_confirmation" + ) { + if (message.args.thought) { + store.dispatch(addAssistantMessage(message.args.thought)); + } + if (message.args.command) { + store.dispatch( + addAssistantMessage( + `Running this command now: \n\`\`\`\`bash\n${message.args.command}\n\`\`\`\`\n`, + ), + ); + } else if (message.args.code) { + store.dispatch( + addAssistantMessage( + `Running this code now: \n\`\`\`\`python\n${message.args.code}\n\`\`\`\`\n`, + ), + ); + } else { + store.dispatch(addAssistantMessage(message.message)); + } + return; + } + if (message.action in messageActions) { const actionFn = messageActions[message.action as keyof typeof messageActions]; diff --git a/frontend/src/services/session.test.ts b/frontend/src/services/session.test.ts index bf23b06bf5a0..194ef0a9b85b 100644 --- a/frontend/src/services/session.test.ts +++ b/frontend/src/services/session.test.ts @@ -20,6 +20,7 @@ describe("startNewSession", () => { AGENT: "agent_value", LANGUAGE: "language_value", LLM_API_KEY: "sk-...", + CONFIRMATION_MODE: true, }; const event = { diff --git a/frontend/src/services/settings.test.ts b/frontend/src/services/settings.test.ts index eebda7aadcae..7f62e690b070 100644 --- a/frontend/src/services/settings.test.ts +++ b/frontend/src/services/settings.test.ts @@ -20,7 +20,8 @@ describe("getSettings", () => { .mockReturnValueOnce("llm_value") .mockReturnValueOnce("agent_value") .mockReturnValueOnce("language_value") - .mockReturnValueOnce("api_key"); + .mockReturnValueOnce("api_key") + .mockReturnValueOnce("true"); const settings = getSettings(); @@ -29,6 +30,7 @@ describe("getSettings", () => { AGENT: "agent_value", LANGUAGE: "language_value", LLM_API_KEY: "api_key", + CONFIRMATION_MODE: true, }); }); @@ -46,6 +48,7 @@ describe("getSettings", () => { AGENT: DEFAULT_SETTINGS.AGENT, LANGUAGE: DEFAULT_SETTINGS.LANGUAGE, LLM_API_KEY: "", + CONFIRMATION_MODE: DEFAULT_SETTINGS.CONFIRMATION_MODE, }); }); }); @@ -57,6 +60,7 @@ describe("saveSettings", () => { AGENT: "agent_value", LANGUAGE: "language_value", LLM_API_KEY: "some_key", + CONFIRMATION_MODE: true, }; saveSettings(settings); diff --git a/frontend/src/services/settings.ts b/frontend/src/services/settings.ts index 310a420d198a..b3fc85a862af 100644 --- a/frontend/src/services/settings.ts +++ b/frontend/src/services/settings.ts @@ -5,13 +5,17 @@ export type Settings = { AGENT: string; LANGUAGE: string; LLM_API_KEY: string; + CONFIRMATION_MODE: boolean; }; +type SettingsInput = Settings[keyof Settings]; + export const DEFAULT_SETTINGS: Settings = { LLM_MODEL: "gpt-4o", AGENT: "CodeActAgent", LANGUAGE: "en", LLM_API_KEY: "", + CONFIRMATION_MODE: false, }; const validKeys = Object.keys(DEFAULT_SETTINGS) as (keyof Settings)[]; @@ -51,12 +55,14 @@ export const getSettings = (): Settings => { const agent = localStorage.getItem("AGENT"); const language = localStorage.getItem("LANGUAGE"); const apiKey = localStorage.getItem("LLM_API_KEY"); + const confirmationMode = localStorage.getItem("CONFIRMATION_MODE") === "true"; return { LLM_MODEL: model || DEFAULT_SETTINGS.LLM_MODEL, AGENT: agent || DEFAULT_SETTINGS.AGENT, LANGUAGE: language || DEFAULT_SETTINGS.LANGUAGE, LLM_API_KEY: apiKey || DEFAULT_SETTINGS.LLM_API_KEY, + CONFIRMATION_MODE: confirmationMode || DEFAULT_SETTINGS.CONFIRMATION_MODE, }; }; @@ -69,7 +75,8 @@ export const saveSettings = (settings: Partial) => { const isValid = validKeys.includes(key as keyof Settings); const value = settings[key as keyof Settings]; - if (isValid && value) localStorage.setItem(key, value); + if (isValid && (value || typeof value === "boolean")) + localStorage.setItem(key, value.toString()); }); localStorage.setItem("SETTINGS_VERSION", LATEST_SETTINGS_VERSION.toString()); }; @@ -91,11 +98,14 @@ export const getSettingsDifference = (settings: Partial) => { const updatedSettings: Partial = {}; Object.keys(settings).forEach((key) => { + const typedKey = key as keyof Settings; if ( - validKeys.includes(key as keyof Settings) && - settings[key as keyof Settings] !== currentSettings[key as keyof Settings] + validKeys.includes(typedKey) && + settings[typedKey] !== currentSettings[typedKey] ) { - updatedSettings[key as keyof Settings] = settings[key as keyof Settings]; + (updatedSettings[typedKey] as SettingsInput) = settings[ + typedKey + ] as SettingsInput; } }); diff --git a/frontend/src/types/AgentState.tsx b/frontend/src/types/AgentState.tsx index 61db70d53aac..d2751627df09 100644 --- a/frontend/src/types/AgentState.tsx +++ b/frontend/src/types/AgentState.tsx @@ -8,6 +8,9 @@ enum AgentState { FINISHED = "finished", REJECTED = "rejected", ERROR = "error", + AWAITING_USER_CONFIRMATION = "awaiting_user_confirmation", + USER_CONFIRMED = "user_confirmed", + USER_REJECTED = "user_rejected", } export default AgentState; diff --git a/opendevin/controller/agent_controller.py b/opendevin/controller/agent_controller.py index 9b66bf6b705e..73ce2fac1730 100644 --- a/opendevin/controller/agent_controller.py +++ b/opendevin/controller/agent_controller.py @@ -16,11 +16,14 @@ from opendevin.events import EventSource, EventStream, EventStreamSubscriber from opendevin.events.action import ( Action, + ActionConfirmationStatus, AddTaskAction, AgentDelegateAction, AgentFinishAction, AgentRejectAction, ChangeAgentStateAction, + CmdRunAction, + IPythonRunCellAction, MessageAction, ModifyTaskAction, NullAction, @@ -49,6 +52,7 @@ class AgentController: max_iterations: int event_stream: EventStream state: State + confirmation_mode: bool agent_task: Optional[asyncio.Task] = None parent: 'AgentController | None' = None delegate: 'AgentController | None' = None @@ -60,6 +64,7 @@ def __init__( event_stream: EventStream, sid: str = 'default', max_iterations: int | None = MAX_ITERATIONS, + confirmation_mode: bool = False, max_budget_per_task: float | None = MAX_BUDGET_PER_TASK, initial_state: State | None = None, is_delegate: bool = False, @@ -92,6 +97,7 @@ def __init__( self.set_initial_state( state=initial_state, max_iterations=max_iterations, + confirmation_mode=confirmation_mode, ) self.max_budget_per_task = max_budget_per_task @@ -170,8 +176,19 @@ async def on_event(self, event: Event): self.state.outputs = event.outputs # type: ignore[attr-defined] await self.set_agent_state_to(AgentState.REJECTED) elif isinstance(event, Observation): + if ( + self._pending_action + and hasattr(self._pending_action, 'is_confirmed') + and self._pending_action.is_confirmed + == ActionConfirmationStatus.AWAITING_CONFIRMATION + ): + return if self._pending_action and self._pending_action.id == event.cause: self._pending_action = None + if self.state.agent_state == AgentState.USER_CONFIRMED: + await self.set_agent_state_to(AgentState.RUNNING) + if self.state.agent_state == AgentState.USER_REJECTED: + await self.set_agent_state_to(AgentState.AWAITING_USER_INPUT) logger.info(event, extra={'msg_type': 'OBSERVATION'}) elif isinstance(event, CmdOutputObservation): logger.info(event, extra={'msg_type': 'OBSERVATION'}) @@ -205,6 +222,18 @@ async def set_agent_state_to(self, new_state: AgentState): if new_state == AgentState.STOPPED or new_state == AgentState.ERROR: self.reset_task() + if self._pending_action is not None and ( + new_state == AgentState.USER_CONFIRMED + or new_state == AgentState.USER_REJECTED + ): + if hasattr(self._pending_action, 'thought'): + self._pending_action.thought = '' # type: ignore[union-attr] + if new_state == AgentState.USER_CONFIRMED: + self._pending_action.is_confirmed = ActionConfirmationStatus.CONFIRMED # type: ignore[attr-defined] + else: + self._pending_action.is_confirmed = ActionConfirmationStatus.REJECTED # type: ignore[attr-defined] + self.event_stream.add_event(self._pending_action, EventSource.AGENT) + self.event_stream.add_event( AgentStateChangedObservation('', self.state.agent_state), EventSource.AGENT ) @@ -346,9 +375,19 @@ async def _step(self): return if action.runnable: + if self.state.confirmation_mode and ( + type(action) is CmdRunAction or type(action) is IPythonRunCellAction + ): + action.is_confirmed = ActionConfirmationStatus.AWAITING_CONFIRMATION self._pending_action = action if not isinstance(action, NullAction): + if ( + hasattr(action, 'is_confirmed') + and action.is_confirmed + == ActionConfirmationStatus.AWAITING_CONFIRMATION + ): + await self.set_agent_state_to(AgentState.AWAITING_USER_CONFIRMATION) self.event_stream.add_event(action, EventSource.AGENT) await self.update_state_after_step() @@ -362,12 +401,19 @@ def get_state(self): return self.state def set_initial_state( - self, state: State | None, max_iterations: int = MAX_ITERATIONS + self, + state: State | None, + max_iterations: int = MAX_ITERATIONS, + confirmation_mode: bool = False, ): # state from the previous session, state from a parent agent, or a new state # note that this is called twice when restoring a previous session, first with state=None if state is None: - self.state = State(inputs={}, max_iterations=max_iterations) + self.state = State( + inputs={}, + max_iterations=max_iterations, + confirmation_mode=confirmation_mode, + ) else: self.state = state diff --git a/opendevin/controller/state/state.py b/opendevin/controller/state/state.py index 06c35811e1ba..30269ca5863a 100644 --- a/opendevin/controller/state/state.py +++ b/opendevin/controller/state/state.py @@ -39,6 +39,7 @@ class State: root_task: RootTask = field(default_factory=RootTask) iteration: int = 0 max_iterations: int = 100 + confirmation_mode: bool = False history: ShortTermHistory = field(default_factory=ShortTermHistory) inputs: dict = field(default_factory=dict) outputs: dict = field(default_factory=dict) diff --git a/opendevin/core/config.py b/opendevin/core/config.py index 1163074d7fc1..1f7a2e4d4866 100644 --- a/opendevin/core/config.py +++ b/opendevin/core/config.py @@ -223,6 +223,7 @@ class AppConfig(metaclass=Singleton): workspace_mount_rewrite: str | None = None cache_dir: str = '/tmp/cache' run_as_devin: bool = True + confirmation_mode: bool = False max_iterations: int = 100 max_budget_per_task: float | None = None e2b_api_key: str = '' diff --git a/opendevin/core/schema/agent.py b/opendevin/core/schema/agent.py index 64742b8f2ac6..4ea09d7afc2a 100644 --- a/opendevin/core/schema/agent.py +++ b/opendevin/core/schema/agent.py @@ -37,3 +37,15 @@ class AgentState(str, Enum): ERROR = 'error' """An error occurred during the task. """ + + AWAITING_USER_CONFIRMATION = 'awaiting_user_confirmation' + """The agent is awaiting user confirmation. + """ + + USER_CONFIRMED = 'user_confirmed' + """The user confirmed the agent's action. + """ + + USER_REJECTED = 'user_rejected' + """The user rejected the agent's action. + """ diff --git a/opendevin/core/schema/config.py b/opendevin/core/schema/config.py index b6bb71bdccba..4b8c05c4aca3 100644 --- a/opendevin/core/schema/config.py +++ b/opendevin/core/schema/config.py @@ -20,6 +20,7 @@ class ConfigType(str, Enum): WORKSPACE_MOUNT_PATH_IN_SANDBOX = 'WORKSPACE_MOUNT_PATH_IN_SANDBOX' CACHE_DIR = 'CACHE_DIR' LLM_MODEL = 'LLM_MODEL' + CONFIRMATION_MODE = 'CONFIRMATION_MODE' SANDBOX_CONTAINER_IMAGE = 'SANDBOX_CONTAINER_IMAGE' RUN_AS_DEVIN = 'RUN_AS_DEVIN' LLM_EMBEDDING_MODEL = 'LLM_EMBEDDING_MODEL' diff --git a/opendevin/core/schema/observation.py b/opendevin/core/schema/observation.py index 0a8afbc9a9db..3a2ec0e01979 100644 --- a/opendevin/core/schema/observation.py +++ b/opendevin/core/schema/observation.py @@ -44,5 +44,7 @@ class ObservationTypeSchema(BaseModel): AGENT_STATE_CHANGED: str = Field(default='agent_state_changed') + USER_REJECTED: str = Field(default='user_rejected') + ObservationType = ObservationTypeSchema() diff --git a/opendevin/events/action/__init__.py b/opendevin/events/action/__init__.py index 16bf6ccf0f31..cbb4a134525c 100644 --- a/opendevin/events/action/__init__.py +++ b/opendevin/events/action/__init__.py @@ -1,4 +1,4 @@ -from .action import Action +from .action import Action, ActionConfirmationStatus from .agent import ( AgentDelegateAction, AgentFinishAction, @@ -32,4 +32,5 @@ 'ChangeAgentStateAction', 'IPythonRunCellAction', 'MessageAction', + 'ActionConfirmationStatus', ] diff --git a/opendevin/events/action/action.py b/opendevin/events/action/action.py index 386e64146d65..f6d7d65f4c69 100644 --- a/opendevin/events/action/action.py +++ b/opendevin/events/action/action.py @@ -1,9 +1,16 @@ from dataclasses import dataclass +from enum import Enum from typing import ClassVar from opendevin.events.event import Event +class ActionConfirmationStatus(str, Enum): + CONFIRMED = 'confirmed' + REJECTED = 'rejected' + AWAITING_CONFIRMATION = 'awaiting_confirmation' + + @dataclass class Action(Event): runnable: ClassVar[bool] = False diff --git a/opendevin/events/action/commands.py b/opendevin/events/action/commands.py index 451da57310df..0edccf82982e 100644 --- a/opendevin/events/action/commands.py +++ b/opendevin/events/action/commands.py @@ -3,7 +3,7 @@ from opendevin.core.schema import ActionType -from .action import Action +from .action import Action, ActionConfirmationStatus @dataclass @@ -12,6 +12,7 @@ class CmdRunAction(Action): thought: str = '' action: str = ActionType.RUN runnable: ClassVar[bool] = True + is_confirmed: ActionConfirmationStatus = ActionConfirmationStatus.CONFIRMED @property def message(self) -> str: @@ -31,6 +32,7 @@ class IPythonRunCellAction(Action): thought: str = '' action: str = ActionType.RUN_IPYTHON runnable: ClassVar[bool] = True + is_confirmed: ActionConfirmationStatus = ActionConfirmationStatus.CONFIRMED kernel_init_code: str = '' # code to run in the kernel (if the kernel is restarted) def __str__(self) -> str: diff --git a/opendevin/events/observation/__init__.py b/opendevin/events/observation/__init__.py index 34a93c60fac3..67fa1ccacd60 100644 --- a/opendevin/events/observation/__init__.py +++ b/opendevin/events/observation/__init__.py @@ -7,6 +7,7 @@ from .files import FileReadObservation, FileWriteObservation from .observation import Observation from .recall import AgentRecallObservation +from .reject import RejectObservation from .success import SuccessObservation __all__ = [ @@ -22,4 +23,5 @@ 'AgentStateChangedObservation', 'AgentDelegateObservation', 'SuccessObservation', + 'RejectObservation', ] diff --git a/opendevin/events/observation/reject.py b/opendevin/events/observation/reject.py new file mode 100644 index 000000000000..81b32fefe57d --- /dev/null +++ b/opendevin/events/observation/reject.py @@ -0,0 +1,18 @@ +from dataclasses import dataclass + +from opendevin.core.schema import ObservationType + +from .observation import Observation + + +@dataclass +class RejectObservation(Observation): + """ + This data class represents the result of a successful action. + """ + + observation: str = ObservationType.USER_REJECTED + + @property + def message(self) -> str: + return self.content diff --git a/opendevin/events/serialization/observation.py b/opendevin/events/serialization/observation.py index 5bec2ff0be62..97d167144c8a 100644 --- a/opendevin/events/serialization/observation.py +++ b/opendevin/events/serialization/observation.py @@ -10,6 +10,7 @@ from opendevin.events.observation.files import FileReadObservation, FileWriteObservation from opendevin.events.observation.observation import Observation from opendevin.events.observation.recall import AgentRecallObservation +from opendevin.events.observation.reject import RejectObservation from opendevin.events.observation.success import SuccessObservation observations = ( @@ -24,6 +25,7 @@ SuccessObservation, ErrorObservation, AgentStateChangedObservation, + RejectObservation, ) OBSERVATION_TYPE_TO_CLASS = { diff --git a/opendevin/runtime/runtime.py b/opendevin/runtime/runtime.py index fecaf431ea61..9b3410b49921 100644 --- a/opendevin/runtime/runtime.py +++ b/opendevin/runtime/runtime.py @@ -7,6 +7,7 @@ from opendevin.events import EventStream, EventStreamSubscriber from opendevin.events.action import ( Action, + ActionConfirmationStatus, AgentRecallAction, BrowseInteractiveAction, BrowseURLAction, @@ -20,6 +21,7 @@ ErrorObservation, NullObservation, Observation, + RejectObservation, ) from opendevin.events.serialization.action import ACTION_TYPE_TO_CLASS from opendevin.runtime import ( @@ -115,6 +117,11 @@ async def run_action(self, action: Action) -> Observation: """ if not action.runnable: return NullObservation('') + if ( + hasattr(action, 'is_confirmed') + and action.is_confirmed == ActionConfirmationStatus.AWAITING_CONFIRMATION + ): + return NullObservation('') action_type = action.action # type: ignore[attr-defined] if action_type not in ACTION_TYPE_TO_CLASS: return ErrorObservation(f'Action {action_type} does not exist.') @@ -122,6 +129,13 @@ async def run_action(self, action: Action) -> Observation: return ErrorObservation( f'Action {action_type} is not supported in the current runtime.' ) + if ( + hasattr(action, 'is_confirmed') + and action.is_confirmed == ActionConfirmationStatus.REJECTED + ): + return RejectObservation( + 'Action has been rejected by the user! Waiting for further user input.' + ) observation = await getattr(self, action_type)(action) observation._parent = action.id # type: ignore[attr-defined] return observation diff --git a/opendevin/server/listen.py b/opendevin/server/listen.py index ca94c87bea78..b43eb785f041 100644 --- a/opendevin/server/listen.py +++ b/opendevin/server/listen.py @@ -217,7 +217,7 @@ async def websocket_endpoint(websocket: WebSocket): ``` - Run a command: ```json - {"action": "run", "args": {"command": "ls -l", "thought": ""}} + {"action": "run", "args": {"command": "ls -l", "thought": "", "is_confirmed": "confirmed"}} ``` - Run an IPython command: ```json diff --git a/opendevin/server/session/agent.py b/opendevin/server/session/agent.py index e75a93cca304..a5e614f14484 100644 --- a/opendevin/server/session/agent.py +++ b/opendevin/server/session/agent.py @@ -91,6 +91,9 @@ async def _create_controller(self, start_event: dict): model = args.get(ConfigType.LLM_MODEL, llm_config.model) api_key = args.get(ConfigType.LLM_API_KEY, llm_config.api_key) api_base = llm_config.base_url + confirmation_mode = args.get( + ConfigType.CONFIRMATION_MODE, config.confirmation_mode + ) max_iterations = args.get(ConfigType.MAX_ITERATIONS, config.max_iterations) logger.info(f'Creating agent {agent_cls} using LLM {model}') @@ -110,6 +113,7 @@ async def _create_controller(self, start_event: dict): event_stream=self.event_stream, agent=agent, max_iterations=int(max_iterations), + confirmation_mode=confirmation_mode, ) try: agent_state = State.restore_from_session(self.sid) diff --git a/tests/integration/mock/DelegatorAgent/test_edits/prompt_002.log b/tests/integration/mock/DelegatorAgent/test_edits/prompt_002.log index 828f19341a6e..af5206d72018 100644 --- a/tests/integration/mock/DelegatorAgent/test_edits/prompt_002.log +++ b/tests/integration/mock/DelegatorAgent/test_edits/prompt_002.log @@ -41,7 +41,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "run", "args": {"command": "ls", "thought": ""}}, {"source": "agent", "observation": "run", "content": "bad.txt", "extras": {"command_id": -1, "command": "ls", "exit_code": 0}}] +[{"source": "agent", "action": "run", "args": {"command": "ls", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "bad.txt", "extras": {"command_id": -1, "command": "ls", "exit_code": 0}}] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/DelegatorAgent/test_edits/prompt_003.log b/tests/integration/mock/DelegatorAgent/test_edits/prompt_003.log index 3f0b617a875f..5019fbdf7fef 100644 --- a/tests/integration/mock/DelegatorAgent/test_edits/prompt_003.log +++ b/tests/integration/mock/DelegatorAgent/test_edits/prompt_003.log @@ -41,7 +41,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "run", "args": {"command": "ls", "thought": ""}}, {"source": "agent", "observation": "run", "content": "bad.txt", "extras": {"command_id": -1, "command": "ls", "exit_code": 0}}, {"source": "agent", "action": "read", "args": {"path": "bad.txt", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "read", "content": "This is a stupid typoo.\nReally?\nNo mor typos!\nEnjoy!\n", "extras": {"path": "bad.txt"}}] +[{"source": "agent", "action": "run", "args": {"command": "ls", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "bad.txt", "extras": {"command_id": -1, "command": "ls", "exit_code": 0}}, {"source": "agent", "action": "read", "args": {"path": "bad.txt", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "read", "content": "This is a stupid typoo.\nReally?\nNo mor typos!\nEnjoy!\n", "extras": {"path": "bad.txt"}}] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_002.log b/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_002.log index a646e046dce8..e7d8a3babee5 100644 --- a/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_002.log +++ b/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_002.log @@ -41,7 +41,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "run", "args": {"command": "ls", "thought": ""}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "ls", "exit_code": 0}}] +[{"source": "agent", "action": "run", "args": {"command": "ls", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "ls", "exit_code": 0}}] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_005.log b/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_005.log index afab1bb7d405..86546d623227 100644 --- a/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_005.log +++ b/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_005.log @@ -41,7 +41,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "write", "args": {"path": "hello.sh", "content": "#!/bin/bash\n\n# Print hello\necho 'hello'", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "write", "content": "", "extras": {"path": "hello.sh"}}, {"source": "agent", "action": "run", "args": {"command": "chmod +x hello.sh", "thought": ""}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "chmod +x hello.sh", "exit_code": 0}}] +[{"source": "agent", "action": "write", "args": {"path": "hello.sh", "content": "#!/bin/bash\n\n# Print hello\necho 'hello'", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "write", "content": "", "extras": {"path": "hello.sh"}}, {"source": "agent", "action": "run", "args": {"command": "chmod +x hello.sh", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "chmod +x hello.sh", "exit_code": 0}}] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_006.log b/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_006.log index 49ccb65d13d2..8567550de535 100644 --- a/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_006.log +++ b/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_006.log @@ -41,7 +41,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "write", "args": {"path": "hello.sh", "content": "#!/bin/bash\n\n# Print hello\necho 'hello'", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "write", "content": "", "extras": {"path": "hello.sh"}}, {"source": "agent", "action": "run", "args": {"command": "chmod +x hello.sh", "thought": ""}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "chmod +x hello.sh", "exit_code": 0}}, {"source": "agent", "action": "run", "args": {"command": "./hello.sh", "thought": ""}}, {"source": "agent", "observation": "run", "content": "hello", "extras": {"command_id": -1, "command": "./hello.sh", "exit_code": 0}}] +[{"source": "agent", "action": "write", "args": {"path": "hello.sh", "content": "#!/bin/bash\n\n# Print hello\necho 'hello'", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "write", "content": "", "extras": {"path": "hello.sh"}}, {"source": "agent", "action": "run", "args": {"command": "chmod +x hello.sh", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "chmod +x hello.sh", "exit_code": 0}}, {"source": "agent", "action": "run", "args": {"command": "./hello.sh", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "hello", "extras": {"command_id": -1, "command": "./hello.sh", "exit_code": 0}}] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_009.log b/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_009.log index e44c5d635456..20b2296e332f 100644 --- a/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_009.log +++ b/tests/integration/mock/DelegatorAgent/test_write_simple_script/prompt_009.log @@ -39,7 +39,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "read", "args": {"path": "hello.sh", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "read", "content": "#!/bin/bash\n\n# Print hello\necho 'hello'\n", "extras": {"path": "hello.sh"}}, {"source": "agent", "action": "run", "args": {"command": "bash hello.sh", "thought": ""}}, {"source": "agent", "observation": "run", "content": "hello", "extras": {"command_id": -1, "command": "bash hello.sh", "exit_code": 0}}] +[{"source": "agent", "action": "read", "args": {"path": "hello.sh", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "read", "content": "#!/bin/bash\n\n# Print hello\necho 'hello'\n", "extras": {"path": "hello.sh"}}, {"source": "agent", "action": "run", "args": {"command": "bash hello.sh", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "hello", "extras": {"command_id": -1, "command": "bash hello.sh", "exit_code": 0}}] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_003.log b/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_003.log index d53f4a40ec80..14893e42170b 100644 --- a/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_003.log +++ b/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_003.log @@ -28,7 +28,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "run", "args": {"command": "git status", "thought": ""}}, {"source": "agent", "observation": "run", "content": "fatal: not a git repository (or any parent up to mount point /)\r\nStopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", "extras": {"command_id": -1, "command": "git status", "exit_code": 128}}] +[{"source": "agent", "action": "run", "args": {"command": "git status", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "fatal: not a git repository (or any parent up to mount point /)\r\nStopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", "extras": {"command_id": -1, "command": "git status", "exit_code": 128}}] If the last item in the history is an error, you should try to fix it. diff --git a/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_004.log b/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_004.log index 614284723122..29f1dc839254 100644 --- a/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_004.log +++ b/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_004.log @@ -28,7 +28,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "run", "args": {"command": "git status", "thought": ""}}, {"source": "agent", "observation": "run", "content": "fatal: not a git repository (or any parent up to mount point /)\r\nStopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", "extras": {"command_id": -1, "command": "git status", "exit_code": 128}}, {"source": "agent", "observation": "error", "content": "action={'action': 'reject', 'args': {'reason': 'Not a valid git repository.'}} has the wrong arguments", "extras": {}}] +[{"source": "agent", "action": "run", "args": {"command": "git status", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "fatal: not a git repository (or any parent up to mount point /)\r\nStopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", "extras": {"command_id": -1, "command": "git status", "exit_code": 128}}, {"source": "agent", "observation": "error", "content": "action={'action': 'reject', 'args': {'reason': 'Not a valid git repository.'}} has the wrong arguments", "extras": {}}] If the last item in the history is an error, you should try to fix it. diff --git a/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_005.log b/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_005.log index e66ff7490809..07713e2d3ba6 100644 --- a/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_005.log +++ b/tests/integration/mock/ManagerAgent/test_simple_task_rejection/prompt_005.log @@ -28,7 +28,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[{"source": "agent", "action": "run", "args": {"command": "git status", "thought": ""}}, {"source": "agent", "observation": "run", "content": "fatal: not a git repository (or any parent up to mount point /)\r\nStopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", "extras": {"command_id": -1, "command": "git status", "exit_code": 128}}, {"source": "agent", "observation": "error", "content": "action={'action': 'reject', 'args': {'reason': 'Not a valid git repository.'}} has the wrong arguments", "extras": {}}, {"source": "agent", "observation": "error", "content": "action={'action': 'reject', 'args': {'reason': 'Not a valid git repository.'}} has the wrong arguments", "extras": {}}] +[{"source": "agent", "action": "run", "args": {"command": "git status", "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "fatal: not a git repository (or any parent up to mount point /)\r\nStopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).", "extras": {"command_id": -1, "command": "git status", "exit_code": 128}}, {"source": "agent", "observation": "error", "content": "action={'action': 'reject', 'args': {'reason': 'Not a valid git repository.'}} has the wrong arguments", "extras": {}}, {"source": "agent", "observation": "error", "content": "action={'action': 'reject', 'args': {'reason': 'Not a valid git repository.'}} has the wrong arguments", "extras": {}}] If the last item in the history is an error, you should try to fix it. diff --git a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_004.log b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_004.log index 5bc5b3e102cb..d7463dbaf3e5 100644 --- a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_004.log +++ b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_004.log @@ -38,7 +38,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[[{"source": "agent", "action": "write", "args": {"path": "hello.sh", "content": "#!/bin/bash\n\n# Print 'hello'\necho 'hello'", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "write", "content": "", "extras": {"path": "hello.sh"}}], [{"source": "agent", "action": "run", "args": {"command": "chmod +x hello.sh", "background": false, "thought": ""}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "chmod +x hello.sh", "exit_code": 0}}]] +[[{"source": "agent", "action": "write", "args": {"path": "hello.sh", "content": "#!/bin/bash\n\n# Print 'hello'\necho 'hello'", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "write", "content": "", "extras": {"path": "hello.sh"}}], [{"source": "agent", "action": "run", "args": {"command": "chmod +x hello.sh", "background": false, "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "chmod +x hello.sh", "exit_code": 0}}]] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_005.log b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_005.log index b0bf89e29b39..b12e03344f5d 100644 --- a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_005.log +++ b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_005.log @@ -38,7 +38,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[[{"source": "agent", "action": "write", "args": {"path": "hello.sh", "content": "#!/bin/bash\n\n# Print 'hello'\necho 'hello'", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "write", "content": "", "extras": {"path": "hello.sh"}}], [{"source": "agent", "action": "run", "args": {"command": "chmod +x hello.sh", "background": false, "thought": ""}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "chmod +x hello.sh", "exit_code": 0}}], [{"source": "agent", "action": "run", "args": {"command": "./hello.sh", "background": false, "thought": ""}}, {"source": "agent", "observation": "run", "content": "hello", "extras": {"command_id": -1, "command": "./hello.sh", "exit_code": 0}}]] +[[{"source": "agent", "action": "write", "args": {"path": "hello.sh", "content": "#!/bin/bash\n\n# Print 'hello'\necho 'hello'", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "write", "content": "", "extras": {"path": "hello.sh"}}], [{"source": "agent", "action": "run", "args": {"command": "chmod +x hello.sh", "background": false, "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "", "extras": {"command_id": -1, "command": "chmod +x hello.sh", "exit_code": 0}}], [{"source": "agent", "action": "run", "args": {"command": "./hello.sh", "background": false, "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "hello", "extras": {"command_id": -1, "command": "./hello.sh", "exit_code": 0}}]] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_006.log b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_006.log index 5877182c2266..5c732af1da22 100644 --- a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_006.log +++ b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_006.log @@ -60,7 +60,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[[{"source": "user", "action": "message", "args": {"content": "Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point.", "wait_for_response": false}}, {"observation": "null", "content": "", "extras": {}}], [{"source": "agent", "action": "delegate", "args": {"agent": "CoderAgent", "inputs": {"task": "Write a shell script 'hello.sh' that prints 'hello'.", "summary": ""}, "thought": ""}}, {"observation": "null", "content": "", "extras": {}}], [{"action": "null", "args": {}}, {"source": "agent", "observation": "delegate", "content": "", "extras": {"outputs": {}}}]] +[[{"source": "user", "action": "message", "args": {"content": "Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point.", "wait_for_response": false}}, {"observation": "null", "content": "", "extras": {}}], [{"source": "agent", "action": "delegate", "args": {"agent": "CoderAgent", "inputs": {"task": "Write a shell script 'hello.sh' that prints 'hello'.", "summary": ""}, "thought": "", "is_confirmed": "confirmed"}}, {"observation": "null", "content": "", "extras": {}}], [{"action": "null", "args": {}}, {"source": "agent", "observation": "delegate", "content": "", "extras": {"outputs": {}}}]] ## Available Actions * `delegate` - send a task to another agent from the list provided. Arguments: diff --git a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_009.log b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_009.log index 62475ca12ab0..c04a8cd0e889 100644 --- a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_009.log +++ b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_009.log @@ -40,7 +40,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[[{"source": "agent", "action": "read", "args": {"path": "hello.sh", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "read", "content": "#!/bin/bash\n\n# Print 'hello'\necho 'hello'\n", "extras": {"path": "hello.sh"}}], [{"source": "agent", "action": "run", "args": {"command": "bash hello.sh", "background": false, "thought": ""}}, {"source": "agent", "observation": "run", "content": "hello", "extras": {"command_id": -1, "command": "bash hello.sh", "exit_code": 0}}]] +[[{"source": "agent", "action": "read", "args": {"path": "hello.sh", "start": 0, "end": -1, "thought": ""}}, {"source": "agent", "observation": "read", "content": "#!/bin/bash\n\n# Print 'hello'\necho 'hello'\n", "extras": {"path": "hello.sh"}}], [{"source": "agent", "action": "run", "args": {"command": "bash hello.sh", "background": false, "thought": "", "is_confirmed": "confirmed"}}, {"source": "agent", "observation": "run", "content": "hello", "extras": {"command_id": -1, "command": "bash hello.sh", "exit_code": 0}}]] ## Format Your response MUST be in JSON format. It must be an object, and it must contain two fields: diff --git a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_010.log b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_010.log index daac6cb7ab2d..a8d42cbf75ea 100644 --- a/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_010.log +++ b/tests/integration/mock/ManagerAgent/test_write_simple_script/prompt_010.log @@ -60,7 +60,7 @@ as well as observations you've made. This only includes the MOST RECENT actions and observations--more may have happened before that. They are time-ordered, with your most recent action at the bottom. -[[{"source": "user", "action": "message", "args": {"content": "Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point.", "wait_for_response": false}}, {"observation": "null", "content": "", "extras": {}}], [{"source": "agent", "action": "delegate", "args": {"agent": "CoderAgent", "inputs": {"task": "Write a shell script 'hello.sh' that prints 'hello'.", "summary": ""}, "thought": ""}}, {"observation": "null", "content": "", "extras": {}}], [{"action": "null", "args": {}}, {"source": "agent", "observation": "delegate", "content": "", "extras": {"outputs": {}}}], [{"source": "agent", "action": "delegate", "args": {"agent": "VerifierAgent", "inputs": {"task": "Verify that the shell script 'hello.sh' prints 'hello'."}, "thought": ""}}, {"observation": "null", "content": "", "extras": {}}], [{"action": "null", "args": {}}, {"source": "agent", "observation": "delegate", "content": "", "extras": {"outputs": {"completed": true}}}]] +[[{"source": "user", "action": "message", "args": {"content": "Write a shell script 'hello.sh' that prints 'hello'. Do not ask me for confirmation at any point.", "wait_for_response": false}}, {"observation": "null", "content": "", "extras": {}}], [{"source": "agent", "action": "delegate", "args": {"agent": "CoderAgent", "inputs": {"task": "Write a shell script 'hello.sh' that prints 'hello'.", "summary": ""}, "thought": "", "is_confirmed": "confirmed"}}, {"observation": "null", "content": "", "extras": {}}], [{"action": "null", "args": {}}, {"source": "agent", "observation": "delegate", "content": "", "extras": {"outputs": {}}}], [{"source": "agent", "action": "delegate", "args": {"agent": "VerifierAgent", "inputs": {"task": "Verify that the shell script 'hello.sh' prints 'hello'."}, "thought": "", "is_confirmed": "confirmed"}}, {"observation": "null", "content": "", "extras": {}}], [{"action": "null", "args": {}}, {"source": "agent", "observation": "delegate", "content": "", "extras": {"outputs": {"completed": true}}}]] ## Available Actions * `delegate` - send a task to another agent from the list provided. Arguments: diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_001.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_001.log index 235daf8e7573..d992f863f829 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_001.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_001.log @@ -135,7 +135,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "echo \"hello world\"", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -182,7 +183,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "node test.js", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_002.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_002.log index ebe37d8806dd..1ae7016724dc 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_002.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_002.log @@ -135,7 +135,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "echo \"hello world\"", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -182,7 +183,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "node test.js", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -330,7 +332,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "pwd", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_003.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_003.log index 694a381b2cd8..62ee248ac452 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_003.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_003.log @@ -135,7 +135,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "echo \"hello world\"", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -182,7 +183,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "node test.js", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -330,7 +332,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "pwd", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -348,7 +351,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "ls", - "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better." + "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better.", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_004.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_004.log index c50bb57bff38..03d6ac76fd8f 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_004.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_004.log @@ -135,7 +135,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "echo \"hello world\"", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -182,7 +183,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "node test.js", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -330,7 +332,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "pwd", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -348,7 +351,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "ls", - "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better." + "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better.", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_005.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_005.log index 294026f0ead5..f66f36ecfee7 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_005.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_005.log @@ -135,7 +135,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "echo \"hello world\"", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -182,7 +183,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "node test.js", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -330,7 +332,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "pwd", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -348,7 +351,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "ls", - "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better." + "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better.", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_006.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_006.log index 9c3ddc704e55..5c64143d9235 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_006.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_006.log @@ -135,7 +135,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "echo \"hello world\"", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -182,7 +183,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "node test.js", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -330,7 +332,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "pwd", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -348,7 +351,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "ls", - "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better." + "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better.", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_007.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_007.log index c511644ff1c5..17efe8a9a2c7 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_007.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_007.log @@ -135,7 +135,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "echo \"hello world\"", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -182,7 +183,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "node test.js", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -330,7 +332,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "pwd", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -348,7 +351,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "ls", - "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better." + "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better.", + "is_confirmed": "confirmed" } }, { @@ -401,7 +405,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "chmod +x hello.sh", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_008.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_008.log index 8caa1d6c53f1..84723709d2e6 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_008.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/prompt_008.log @@ -135,7 +135,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "echo \"hello world\"", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -182,7 +183,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "node test.js", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -330,7 +332,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "pwd", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -348,7 +351,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "ls", - "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better." + "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better.", + "is_confirmed": "confirmed" } }, { @@ -401,7 +405,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "chmod +x hello.sh", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { @@ -419,7 +424,8 @@ This is your internal monologue, in JSON format: "action": "run", "args": { "command": "./hello.sh", - "thought": "I need to run the 'hello.sh' script to verify that it prints 'hello'." + "thought": "I need to run the 'hello.sh' script to verify that it prints 'hello'.", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/MonologueAgent/test_write_simple_script/response_002.log b/tests/integration/mock/MonologueAgent/test_write_simple_script/response_002.log index f37c6b4aa7cb..a610d3e35900 100644 --- a/tests/integration/mock/MonologueAgent/test_write_simple_script/response_002.log +++ b/tests/integration/mock/MonologueAgent/test_write_simple_script/response_002.log @@ -3,7 +3,8 @@ "action": "run", "args": { "command": "ls", - "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better." + "thought": "I need to see the contents of the current directory to ensure there are no conflicts and to understand the environment better.", + "is_confirmed": "confirmed" } } ``` diff --git a/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_010.log b/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_010.log index e2666fca9d41..c3211d8b7131 100644 --- a/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_010.log +++ b/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_010.log @@ -196,7 +196,8 @@ ten actions--more happened before that. "action": "run", "args": { "command": "bash hello.sh", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { diff --git a/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_011.log b/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_011.log index 92fa4bd751d5..f576303ee15f 100644 --- a/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_011.log +++ b/tests/integration/mock/PlannerAgent/test_write_simple_script/prompt_011.log @@ -195,7 +195,8 @@ ten actions--more happened before that. "action": "run", "args": { "command": "bash hello.sh", - "thought": "" + "thought": "", + "is_confirmed": "confirmed" } }, { diff --git a/tests/unit/test_action_serialization.py b/tests/unit/test_action_serialization.py index ceb0db5ccfc1..969a3212d0a5 100644 --- a/tests/unit/test_action_serialization.py +++ b/tests/unit/test_action_serialization.py @@ -13,6 +13,7 @@ MessageAction, ModifyTaskAction, ) +from opendevin.events.action.action import ActionConfirmationStatus from opendevin.events.serialization import ( event_from_dict, event_to_dict, @@ -90,7 +91,11 @@ def test_agent_reject_action_serialization_deserialization(): def test_cmd_run_action_serialization_deserialization(): original_action_dict = { 'action': 'run', - 'args': {'command': 'echo "Hello world"', 'thought': ''}, + 'args': { + 'command': 'echo "Hello world"', + 'thought': '', + 'is_confirmed': ActionConfirmationStatus.CONFIRMED, + }, } serialization_deserialization(original_action_dict, CmdRunAction)