From 18d1eb669e5094272efa8da364e5c9c9447d8c2d Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Mon, 1 Dec 2025 03:27:01 -0500 Subject: Validate cwd exists before running bash commands run_bash tool now checks if the working directory exists before executing. Previously invalid cwd caused system-level chdir error. Now returns clean tool error the agent can understand and react to. --- Omni/Agent/Tools.hs | 66 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 22 deletions(-) (limited to 'Omni/Agent/Tools.hs') diff --git a/Omni/Agent/Tools.hs b/Omni/Agent/Tools.hs index 0312924..9664c76 100644 --- a/Omni/Agent/Tools.hs +++ b/Omni/Agent/Tools.hs @@ -160,6 +160,18 @@ test = toolResultSuccess tr Test.@=? True ("hello" `Text.isInfixOf` toolResultOutput tr) Test.@=? True Aeson.Error e -> Test.assertFailure e, + Test.unit "runBashTool validates cwd exists" <| do + let args = + Aeson.object + [ "command" .= ("echo test" :: Text), + "cwd" .= ("/nonexistent/path/that/does/not/exist" :: Text) + ] + result <- Engine.toolExecute runBashTool args + case Aeson.fromJSON result of + Aeson.Success (tr :: ToolResult) -> do + toolResultSuccess tr Test.@=? False + isJust (toolResultError tr) Test.@=? True + Aeson.Error e -> Test.assertFailure e, Test.unit "searchCodebaseTool returns structured results" <| do let args = Aeson.object @@ -474,29 +486,39 @@ executeRunBash v = Aeson.Error e -> pure <| mkError (Text.pack e) Aeson.Success args -> do let cmd = Text.unpack (runBashCommand args) - proc = - (Process.shell cmd) - { Process.cwd = Text.unpack Text.pack stderrStr - case exitCode of - Exit.ExitSuccess -> - pure - <| Aeson.toJSON - <| ToolResult - { toolResultSuccess = True, - toolResultOutput = output, - toolResultError = Nothing - } - Exit.ExitFailure code -> + maybeCwd = runBashCwd args + cwdValid <- case maybeCwd of + Nothing -> pure True + Just cwd -> Directory.doesDirectoryExist (Text.unpack cwd) + if not cwdValid + then pure - <| Aeson.toJSON - <| ToolResult - { toolResultSuccess = False, - toolResultOutput = output, - toolResultError = Just ("Exit code: " <> tshow code) - } + <| mkError + ("Working directory does not exist: " <> fromMaybe "" maybeCwd) + else do + let proc = + (Process.shell cmd) + { Process.cwd = Text.unpack Text.pack stderrStr + case exitCode of + Exit.ExitSuccess -> + pure + <| Aeson.toJSON + <| ToolResult + { toolResultSuccess = True, + toolResultOutput = output, + toolResultError = Nothing + } + Exit.ExitFailure code -> + pure + <| Aeson.toJSON + <| ToolResult + { toolResultSuccess = False, + toolResultOutput = output, + toolResultError = Just ("Exit code: " <> tshow code) + } data SearchCodebaseArgs = SearchCodebaseArgs { searchPattern :: Text, -- cgit v1.2.3