{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}

{- |
Module      : Langchain.Agents.Core
Description : Core implementation of LangChain agents
Copyright   : (c) 2025 Tushar Adhatrao
License     : MIT
Maintainer  : Tushar Adhatrao <tusharadhatrao@gmail.com>

Agents use LLMs as reasoning engines to determine actions dynamically
This module implements the core agent execution loop and interfaces,
supporting tool interaction and memory management.

Example agent execution flow:

> executor <- AgentExecutor
>   { executor = myAgent
>   , executorMemory = emptyMemory
>   , maxIterations = 5
>   , returnIntermediateSteps = True
>   }
> result <- runAgentExecutor executor "Explain quantum computing"
-}
module Langchain.Agents.Core
  ( AgentAction (..)
  , AgentFinish (..)
  , AgentStep (..)
  , Agent (..)
  , AnyTool (..)
  , AgentState (..)
  , AgentExecutor (..)
  , runAgent
  , runAgentLoop
  , runAgentExecutor
  , executeTool
  , runSingleStep
  , customAnyTool
  ) where

import Control.Exception (SomeException, try)
import Data.List (find)
import qualified Data.Map.Strict as Map
import Data.Text (Text)
import qualified Data.Text as T
import Langchain.LLM.Core (Message (Message), Role (..), defaultMessageData)
import Langchain.Memory.Core (BaseMemory (..))
import Langchain.PromptTemplate (PromptTemplate)
import qualified Langchain.Runnable.Core as Run
import Langchain.Tool.Core (Tool (..))

{- |
Represents an action to be taken by the agent
-}
data AgentAction = AgentAction
  { AgentAction -> Text
actionToolName :: Text
  -- ^ Tool name
  , AgentAction -> Text
actionInput :: Text
  -- ^ Input
  , AgentAction -> Text
actionLog :: Text
  -- ^ Execution log
  }
  deriving (AgentAction -> AgentAction -> Bool
(AgentAction -> AgentAction -> Bool)
-> (AgentAction -> AgentAction -> Bool) -> Eq AgentAction
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: AgentAction -> AgentAction -> Bool
== :: AgentAction -> AgentAction -> Bool
$c/= :: AgentAction -> AgentAction -> Bool
/= :: AgentAction -> AgentAction -> Bool
Eq, Int -> AgentAction -> ShowS
[AgentAction] -> ShowS
AgentAction -> String
(Int -> AgentAction -> ShowS)
-> (AgentAction -> String)
-> ([AgentAction] -> ShowS)
-> Show AgentAction
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AgentAction -> ShowS
showsPrec :: Int -> AgentAction -> ShowS
$cshow :: AgentAction -> String
show :: AgentAction -> String
$cshowList :: [AgentAction] -> ShowS
showList :: [AgentAction] -> ShowS
Show)

-- | Represents that agent has finished work with final value
data AgentFinish = AgentFinish
  { AgentFinish -> Map Text Text
returnValues :: Map.Map Text Text 
  , AgentFinish -> Text
finishLog :: Text
  }
  deriving (Int -> AgentFinish -> ShowS
[AgentFinish] -> ShowS
AgentFinish -> String
(Int -> AgentFinish -> ShowS)
-> (AgentFinish -> String)
-> ([AgentFinish] -> ShowS)
-> Show AgentFinish
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AgentFinish -> ShowS
showsPrec :: Int -> AgentFinish -> ShowS
$cshow :: AgentFinish -> String
show :: AgentFinish -> String
$cshowList :: [AgentFinish] -> ShowS
showList :: [AgentFinish] -> ShowS
Show, AgentFinish -> AgentFinish -> Bool
(AgentFinish -> AgentFinish -> Bool)
-> (AgentFinish -> AgentFinish -> Bool) -> Eq AgentFinish
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: AgentFinish -> AgentFinish -> Bool
== :: AgentFinish -> AgentFinish -> Bool
$c/= :: AgentFinish -> AgentFinish -> Bool
/= :: AgentFinish -> AgentFinish -> Bool
Eq)

-- | Type that will be return from LLM 
-- Could be either Continue, making another call to LLM or Finish with final value
data AgentStep
  = Continue AgentAction
  | Finish AgentFinish
  deriving (AgentStep -> AgentStep -> Bool
(AgentStep -> AgentStep -> Bool)
-> (AgentStep -> AgentStep -> Bool) -> Eq AgentStep
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: AgentStep -> AgentStep -> Bool
== :: AgentStep -> AgentStep -> Bool
$c/= :: AgentStep -> AgentStep -> Bool
/= :: AgentStep -> AgentStep -> Bool
Eq, Int -> AgentStep -> ShowS
[AgentStep] -> ShowS
AgentStep -> String
(Int -> AgentStep -> ShowS)
-> (AgentStep -> String)
-> ([AgentStep] -> ShowS)
-> Show AgentStep
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AgentStep -> ShowS
showsPrec :: Int -> AgentStep -> ShowS
$cshow :: AgentStep -> String
show :: AgentStep -> String
$cshowList :: [AgentStep] -> ShowS
showList :: [AgentStep] -> ShowS
Show)

-- | Type for maintaining state of the agent 
data (BaseMemory m) => AgentState m = AgentState
  { forall m. BaseMemory m => AgentState m -> m
agentMemory :: m -- ^ Memory for storing chat history
  , forall m. BaseMemory m => AgentState m -> [(Text, Text)]
agentToolResults :: [(Text, Text)] -- ^ Tool results
  , forall m. BaseMemory m => AgentState m -> [AgentAction]
agentSteps :: [AgentAction] -- ^ Agent steps happened so far
  }
  deriving (AgentState m -> AgentState m -> Bool
(AgentState m -> AgentState m -> Bool)
-> (AgentState m -> AgentState m -> Bool) -> Eq (AgentState m)
forall m.
(BaseMemory m, Eq m) =>
AgentState m -> AgentState m -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall m.
(BaseMemory m, Eq m) =>
AgentState m -> AgentState m -> Bool
== :: AgentState m -> AgentState m -> Bool
$c/= :: forall m.
(BaseMemory m, Eq m) =>
AgentState m -> AgentState m -> Bool
/= :: AgentState m -> AgentState m -> Bool
Eq, Int -> AgentState m -> ShowS
[AgentState m] -> ShowS
AgentState m -> String
(Int -> AgentState m -> ShowS)
-> (AgentState m -> String)
-> ([AgentState m] -> ShowS)
-> Show (AgentState m)
forall m. (BaseMemory m, Show m) => Int -> AgentState m -> ShowS
forall m. (BaseMemory m, Show m) => [AgentState m] -> ShowS
forall m. (BaseMemory m, Show m) => AgentState m -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall m. (BaseMemory m, Show m) => Int -> AgentState m -> ShowS
showsPrec :: Int -> AgentState m -> ShowS
$cshow :: forall m. (BaseMemory m, Show m) => AgentState m -> String
show :: AgentState m -> String
$cshowList :: forall m. (BaseMemory m, Show m) => [AgentState m] -> ShowS
showList :: [AgentState m] -> ShowS
Show)

{- |
Dynamic tool wrapper allowing heterogeneous tool collections
Converts between Text and tool-specific input/output types.

Example usage:

> calculatorTool :: AnyTool
> calculatorTool = customAnyTool
>   Calculator
>   (\t -> read (T.unpack t) :: (Int, Int))
>   (T.pack . show)
-}
data AnyTool = forall a. Tool a => AnyTool
  { ()
anyTool :: a
  , ()
textToInput :: Text -> Input a
  , ()
outputToText :: Output a -> Text
  }

{- |
Core agent class defining required operations

* Plan next action based on state
* Provide prompt template
* Expose available tools
-}
class Agent a where
  planNextAction :: BaseMemory m => a -> AgentState m -> IO (Either String AgentStep)
  agentPrompt :: a -> IO PromptTemplate
  agentTools :: a -> IO [AnyTool]

{- |
Agent execution engine
-}
data AgentExecutor a m = AgentExecutor
  { forall a m. AgentExecutor a m -> a
executor :: a -- Agent instance
  , forall a m. AgentExecutor a m -> m
executorMemory :: m
  -- ^ Memory state
  , forall a m. AgentExecutor a m -> Int
maxIterations :: Int
  -- ^ Iteration limits
  , forall a m. AgentExecutor a m -> Bool
returnIntermediateSteps :: Bool
  -- ^ Step tracking
  }
  deriving (AgentExecutor a m -> AgentExecutor a m -> Bool
(AgentExecutor a m -> AgentExecutor a m -> Bool)
-> (AgentExecutor a m -> AgentExecutor a m -> Bool)
-> Eq (AgentExecutor a m)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall a m.
(Eq a, Eq m) =>
AgentExecutor a m -> AgentExecutor a m -> Bool
$c== :: forall a m.
(Eq a, Eq m) =>
AgentExecutor a m -> AgentExecutor a m -> Bool
== :: AgentExecutor a m -> AgentExecutor a m -> Bool
$c/= :: forall a m.
(Eq a, Eq m) =>
AgentExecutor a m -> AgentExecutor a m -> Bool
/= :: AgentExecutor a m -> AgentExecutor a m -> Bool
Eq, Int -> AgentExecutor a m -> ShowS
[AgentExecutor a m] -> ShowS
AgentExecutor a m -> String
(Int -> AgentExecutor a m -> ShowS)
-> (AgentExecutor a m -> String)
-> ([AgentExecutor a m] -> ShowS)
-> Show (AgentExecutor a m)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall a m. (Show a, Show m) => Int -> AgentExecutor a m -> ShowS
forall a m. (Show a, Show m) => [AgentExecutor a m] -> ShowS
forall a m. (Show a, Show m) => AgentExecutor a m -> String
$cshowsPrec :: forall a m. (Show a, Show m) => Int -> AgentExecutor a m -> ShowS
showsPrec :: Int -> AgentExecutor a m -> ShowS
$cshow :: forall a m. (Show a, Show m) => AgentExecutor a m -> String
show :: AgentExecutor a m -> String
$cshowList :: forall a m. (Show a, Show m) => [AgentExecutor a m] -> ShowS
showList :: [AgentExecutor a m] -> ShowS
Show)

{- |
Run the full agent execution loop
Handles:

1. Memory updates
2. Action planning
3. Tool execution
4. Iteration control

Example flow:

1. User input -> memory
2. Plan action -> execute tool
3. Store result -> memory
4. Repeat until finish

Throws errors for:

- Tool not found [[5]]
- Execution errors
- Iteration limits
-}
runAgent :: (Agent a, BaseMemory m) => a -> AgentState m -> Text -> IO (Either String AgentFinish)
runAgent :: forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> Text -> IO (Either String AgentFinish)
runAgent a
agent initialState :: AgentState m
initialState@AgentState {m
[(Text, Text)]
[AgentAction]
agentMemory :: forall m. BaseMemory m => AgentState m -> m
agentToolResults :: forall m. BaseMemory m => AgentState m -> [(Text, Text)]
agentSteps :: forall m. BaseMemory m => AgentState m -> [AgentAction]
agentMemory :: m
agentToolResults :: [(Text, Text)]
agentSteps :: [AgentAction]
..} Text
initialInput = do
  Either String m
memWithInput <- m -> Text -> IO (Either String m)
forall m. BaseMemory m => m -> Text -> IO (Either String m)
addUserMessage m
agentMemory Text
initialInput
  case Either String m
memWithInput of
    Left String
err -> Either String AgentFinish -> IO (Either String AgentFinish)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String AgentFinish -> IO (Either String AgentFinish))
-> Either String AgentFinish -> IO (Either String AgentFinish)
forall a b. (a -> b) -> a -> b
$ String -> Either String AgentFinish
forall a b. a -> Either a b
Left String
err
    Right m
updatedMem ->
      let newState :: AgentState m
newState = AgentState m
initialState {agentMemory = updatedMem}
       in a -> AgentState m -> Int -> Int -> IO (Either String AgentFinish)
forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> Int -> Int -> IO (Either String AgentFinish)
runAgentLoop a
agent AgentState m
newState Int
0 Int
10

-- | Helper function for runAgent
runAgentLoop ::
  (Agent a, BaseMemory m) => a -> AgentState m -> Int -> Int -> IO (Either String AgentFinish)
runAgentLoop :: forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> Int -> Int -> IO (Either String AgentFinish)
runAgentLoop a
agent agentState :: AgentState m
agentState@AgentState {m
[(Text, Text)]
[AgentAction]
agentMemory :: forall m. BaseMemory m => AgentState m -> m
agentToolResults :: forall m. BaseMemory m => AgentState m -> [(Text, Text)]
agentSteps :: forall m. BaseMemory m => AgentState m -> [AgentAction]
agentMemory :: m
agentToolResults :: [(Text, Text)]
agentSteps :: [AgentAction]
..} Int
currIter Int
maxIter
  | Int
currIter Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxIter = Either String AgentFinish -> IO (Either String AgentFinish)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String AgentFinish -> IO (Either String AgentFinish))
-> Either String AgentFinish -> IO (Either String AgentFinish)
forall a b. (a -> b) -> a -> b
$ String -> Either String AgentFinish
forall a b. a -> Either a b
Left String
"Max iterations excedded"
  | Bool
otherwise = do
      Either String AgentStep
eStepResult <- a -> AgentState m -> IO (Either String AgentStep)
forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> IO (Either String AgentStep)
runSingleStep a
agent AgentState m
agentState
      case Either String AgentStep
eStepResult of
        Left String
err -> Either String AgentFinish -> IO (Either String AgentFinish)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String AgentFinish -> IO (Either String AgentFinish))
-> Either String AgentFinish -> IO (Either String AgentFinish)
forall a b. (a -> b) -> a -> b
$ String -> Either String AgentFinish
forall a b. a -> Either a b
Left String
err
        Right (Finish AgentFinish
agentFinish) -> Either String AgentFinish -> IO (Either String AgentFinish)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String AgentFinish -> IO (Either String AgentFinish))
-> Either String AgentFinish -> IO (Either String AgentFinish)
forall a b. (a -> b) -> a -> b
$ AgentFinish -> Either String AgentFinish
forall a b. b -> Either a b
Right AgentFinish
agentFinish
        Right (Continue act :: AgentAction
act@AgentAction {Text
actionToolName :: AgentAction -> Text
actionInput :: AgentAction -> Text
actionLog :: AgentAction -> Text
actionToolName :: Text
actionInput :: Text
actionLog :: Text
..}) -> do
          [AnyTool]
toolList <- a -> IO [AnyTool]
forall a. Agent a => a -> IO [AnyTool]
agentTools a
agent
          Either String Text
toolResult <- [AnyTool] -> Text -> Text -> IO (Either String Text)
executeTool [AnyTool]
toolList Text
actionToolName Text
actionInput
          case Either String Text
toolResult of
            Left String
err -> Either String AgentFinish -> IO (Either String AgentFinish)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String AgentFinish -> IO (Either String AgentFinish))
-> Either String AgentFinish -> IO (Either String AgentFinish)
forall a b. (a -> b) -> a -> b
$ String -> Either String AgentFinish
forall a b. a -> Either a b
Left String
err
            Right Text
result -> do
              -- Add the tool result to memory as a tool message
              let toolMsg :: Message
toolMsg = Role -> Text -> MessageData -> Message
Message Role
Tool Text
result MessageData
defaultMessageData
              Either String m
updatedMemResult <- m -> Message -> IO (Either String m)
forall m. BaseMemory m => m -> Message -> IO (Either String m)
addMessage m
agentMemory Message
toolMsg
              case Either String m
updatedMemResult of
                Left String
err -> Either String AgentFinish -> IO (Either String AgentFinish)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String AgentFinish -> IO (Either String AgentFinish))
-> Either String AgentFinish -> IO (Either String AgentFinish)
forall a b. (a -> b) -> a -> b
$ String -> Either String AgentFinish
forall a b. a -> Either a b
Left String
err
                Right m
updatedMem ->
                  let updatedState :: AgentState m
updatedState =
                        AgentState m
agentState
                          { agentMemory = updatedMem
                          , agentToolResults = agentToolResults ++ [(actionToolName, result)]
                          , agentSteps = agentSteps ++ [act]
                          }
                   in a -> AgentState m -> Int -> Int -> IO (Either String AgentFinish)
forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> Int -> Int -> IO (Either String AgentFinish)
runAgentLoop a
agent AgentState m
updatedState (Int
currIter Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int
maxIter

-- | Alias for planNextAction
runSingleStep :: (Agent a, BaseMemory m) => a -> AgentState m -> IO (Either String AgentStep)
runSingleStep :: forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> IO (Either String AgentStep)
runSingleStep = a -> AgentState m -> IO (Either String AgentStep)
forall m.
BaseMemory m =>
a -> AgentState m -> IO (Either String AgentStep)
forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> IO (Either String AgentStep)
planNextAction

{- |
Execute a single tool call
Handles tool lookup and input/output conversion.

Example:

> tools = [calculatorTool, wikipediaTool]
> executeTool tools "calculator" "(5, 3)"
> -- Returns Right "8"
-}
executeTool :: [AnyTool] -> Text -> Text -> IO (Either String Text)
executeTool :: [AnyTool] -> Text -> Text -> IO (Either String Text)
executeTool [AnyTool]
tools Text
toolName_ Text
input =
  case (AnyTool -> Bool) -> [AnyTool] -> Maybe AnyTool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (\(AnyTool a
t Text -> Input a
_ Output a -> Text
_) -> a -> Text
forall a. Tool a => a -> Text
toolName a
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
toolName_) [AnyTool]
tools of
    Maybe AnyTool
Nothing -> Either String Text -> IO (Either String Text)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String Text -> IO (Either String Text))
-> Either String Text -> IO (Either String Text)
forall a b. (a -> b) -> a -> b
$ String -> Either String Text
forall a b. a -> Either a b
Left (String -> Either String Text) -> String -> Either String Text
forall a b. (a -> b) -> a -> b
$ String
"Tool not found: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
T.unpack Text
toolName_
    Just (AnyTool {a
Text -> Input a
Output a -> Text
anyTool :: ()
textToInput :: ()
outputToText :: ()
anyTool :: a
textToInput :: Text -> Input a
outputToText :: Output a -> Text
..}) -> do
      Either SomeException Text
resultE <- IO Text -> IO (Either SomeException Text)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO Text -> IO (Either SomeException Text))
-> IO Text -> IO (Either SomeException Text)
forall a b. (a -> b) -> a -> b
$ do
        let typedInput :: Input a
typedInput = Text -> Input a
textToInput Text
input
        Output a
result <- a -> Input a -> IO (Output a)
forall a. Tool a => a -> Input a -> IO (Output a)
runTool a
anyTool Input a
typedInput
        Text -> IO Text
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> IO Text) -> Text -> IO Text
forall a b. (a -> b) -> a -> b
$ Output a -> Text
outputToText Output a
result
      case Either SomeException Text
resultE of
        Left SomeException
ex -> Either String Text -> IO (Either String Text)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String Text -> IO (Either String Text))
-> Either String Text -> IO (Either String Text)
forall a b. (a -> b) -> a -> b
$ String -> Either String Text
forall a b. a -> Either a b
Left (String -> Either String Text) -> String -> Either String Text
forall a b. (a -> b) -> a -> b
$ String
"Tool execution error: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> SomeException -> String
forall a. Show a => a -> String
show (SomeException
ex :: SomeException)
        Right Text
output -> Either String Text -> IO (Either String Text)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String Text -> IO (Either String Text))
-> Either String Text -> IO (Either String Text)
forall a b. (a -> b) -> a -> b
$ Text -> Either String Text
forall a b. b -> Either a b
Right Text
output

{- |
Helper for creating custom tool wrappers
Requires conversion functions between Text and tool-specific types.

Example:

> weatherTool = customAnyTool
>   WeatherAPI
>   parseLocation
>   formatWeatherResponse
-}
customAnyTool :: Tool a => a -> (Text -> Input a) -> (Output a -> Text) -> AnyTool
customAnyTool :: forall a.
Tool a =>
a -> (Text -> Input a) -> (Output a -> Text) -> AnyTool
customAnyTool a
tool Text -> Input a
inputConv Output a -> Text
outputConv = a -> (Text -> Input a) -> (Output a -> Text) -> AnyTool
forall a.
Tool a =>
a -> (Text -> Input a) -> (Output a -> Text) -> AnyTool
AnyTool a
tool Text -> Input a
inputConv Output a -> Text
outputConv

-- | Similar to runAgent, but for AgentExecutor
runAgentExecutor ::
  (Agent a, BaseMemory m) => AgentExecutor a m -> Text -> IO (Either String (Maybe AgentFinish))
runAgentExecutor :: forall a m.
(Agent a, BaseMemory m) =>
AgentExecutor a m -> Text -> IO (Either String (Maybe AgentFinish))
runAgentExecutor AgentExecutor {a
m
Bool
Int
executor :: forall a m. AgentExecutor a m -> a
executorMemory :: forall a m. AgentExecutor a m -> m
maxIterations :: forall a m. AgentExecutor a m -> Int
returnIntermediateSteps :: forall a m. AgentExecutor a m -> Bool
executor :: a
executorMemory :: m
maxIterations :: Int
returnIntermediateSteps :: Bool
..} Text
input = do
  let initialState :: AgentState m
initialState =
        AgentState
          { agentMemory :: m
agentMemory = m
executorMemory
          , agentToolResults :: [(Text, Text)]
agentToolResults = []
          , agentSteps :: [AgentAction]
agentSteps = []
          }
  Either String AgentFinish
result <- a -> AgentState m -> Text -> IO (Either String AgentFinish)
forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> Text -> IO (Either String AgentFinish)
runAgent a
executor AgentState m
initialState Text
input
  case Either String AgentFinish
result of
    Left String
err -> Either String (Maybe AgentFinish)
-> IO (Either String (Maybe AgentFinish))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (Maybe AgentFinish)
 -> IO (Either String (Maybe AgentFinish)))
-> Either String (Maybe AgentFinish)
-> IO (Either String (Maybe AgentFinish))
forall a b. (a -> b) -> a -> b
$ String -> Either String (Maybe AgentFinish)
forall a b. a -> Either a b
Left String
err
    Right AgentFinish
a ->
      if Bool
returnIntermediateSteps
        then Either String (Maybe AgentFinish)
-> IO (Either String (Maybe AgentFinish))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (Maybe AgentFinish)
 -> IO (Either String (Maybe AgentFinish)))
-> Either String (Maybe AgentFinish)
-> IO (Either String (Maybe AgentFinish))
forall a b. (a -> b) -> a -> b
$ Maybe AgentFinish -> Either String (Maybe AgentFinish)
forall a b. b -> Either a b
Right (Maybe AgentFinish -> Either String (Maybe AgentFinish))
-> Maybe AgentFinish -> Either String (Maybe AgentFinish)
forall a b. (a -> b) -> a -> b
$ AgentFinish -> Maybe AgentFinish
forall a. a -> Maybe a
Just AgentFinish
a
        else Either String (Maybe AgentFinish)
-> IO (Either String (Maybe AgentFinish))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String (Maybe AgentFinish)
 -> IO (Either String (Maybe AgentFinish)))
-> Either String (Maybe AgentFinish)
-> IO (Either String (Maybe AgentFinish))
forall a b. (a -> b) -> a -> b
$ Maybe AgentFinish -> Either String (Maybe AgentFinish)
forall a b. b -> Either a b
Right Maybe AgentFinish
forall a. Maybe a
Nothing

{- |
Runnable instance for agent execution
Allows integration with LangChain workflows.

Example:

> response <- invoke myAgentExecutor "Solve 5+3"
> case response of
>   Right result -> print result
>   Left err -> print err
-}
instance (Agent a, BaseMemory m) => Run.Runnable (AgentExecutor a m) where
  type RunnableInput (AgentExecutor a m) = Text
  type RunnableOutput (AgentExecutor a m) = AgentFinish

  invoke :: AgentExecutor a m
-> RunnableInput (AgentExecutor a m)
-> IO (Either String (RunnableOutput (AgentExecutor a m)))
invoke AgentExecutor {a
m
Bool
Int
executor :: forall a m. AgentExecutor a m -> a
executorMemory :: forall a m. AgentExecutor a m -> m
maxIterations :: forall a m. AgentExecutor a m -> Int
returnIntermediateSteps :: forall a m. AgentExecutor a m -> Bool
executor :: a
executorMemory :: m
maxIterations :: Int
returnIntermediateSteps :: Bool
..} RunnableInput (AgentExecutor a m)
input = do
    let initialState :: AgentState m
initialState =
          AgentState
            { agentMemory :: m
agentMemory = m
executorMemory
            , agentToolResults :: [(Text, Text)]
agentToolResults = []
            , agentSteps :: [AgentAction]
agentSteps = []
            }
    a -> AgentState m -> Text -> IO (Either String AgentFinish)
forall a m.
(Agent a, BaseMemory m) =>
a -> AgentState m -> Text -> IO (Either String AgentFinish)
runAgent a
executor AgentState m
initialState Text
RunnableInput (AgentExecutor a m)
input