Tool execution in the agent runtime does not catch exceptions. If any tool throws an IO exception (file not found, network error, permission denied, etc.), the entire agent crashes. This makes the runtime fragile and prevents agents from recovering from errors.
File: Omni/Agent/Engine.hs
Function: executeToolCallsWithTracking (around line 795)
The problematic line:
resultValue <- toolExecute tool args -- If this throws, agent dies
Wrap all toolExecute calls in exception handlers. Return errors as structured JSON so the agent can reason about them and potentially recover.
import Control.Exception (SomeException, catch)
-- Add this helper function
executeToolSafe :: Engine.Tool -> Aeson.Value -> IO Aeson.Value
executeToolSafe tool args =
catch
(toolExecute tool args)
(\(e :: SomeException) -> pure $ Aeson.object
[ "error" .= ("Tool execution failed: " <> tshow e)
, "tool" .= toolName tool
, "exception_type" .= (show (typeOf e))
])
Then replace the direct toolExecute tool args call with executeToolSafe tool args.
1. Omni/Agent/Engine.hs - Main change
2. Check if Omni/Agent/Subagent.hs has similar patterns that need the same fix
1. Create a test tool that throws an exception
2. Verify the agent receives the error as JSON instead of crashing
3. Verify existing tools still work normally
4. Run bild --test Omni/Agent/Engine.hs
toolExecute calls wrapped in exception handlers