{- |
Module:      Langchain.Callback
Copyright:   (c) 2025 Tushar Adhatrao
License:     MIT
Maintainer:  Tushar Adhatrao <tusharadhatrao@gmail.com>
Stability:   experimental

This module provides a callback system for Langchain's language model operations.
Callbacks allow users to perform actions at different stages of an LLM operation,
such as when it starts, completes, or encounters an error. This is useful for
logging, monitoring, or integrating with external systems.

The callback system is inspired by the Langchain Python library's callback
functionality: [Langchain Callbacks](https://python.langchain.com/docs/concepts/callbacks/).

== Examples

See the documentation for 'stdOutCallback' for a basic example, or check the
examples for 'generate', 'chat', and 'stream' in the 'Langchain.LLM.Ollama' module
for practical usage in LLM operations.
-}
module Langchain.Callback
  ( -- * Event Types
    Event (..)

    -- * Callback Interface
  , Callback

    -- * Standard Implementations
  , stdOutCallback
  ) where

{- | Represents different events that can occur during a language model operation.
These events can be used to trigger callbacks at various stages.
-}
data Event
  = -- | Indicates the start of an LLM operation, such as generating text or chatting.
    LLMStart
  | -- | Indicates the successful completion of an LLM operation.
    LLMEnd
  | -- | Indicates an error occurred during the LLM operation, with the error message.
    LLMError String
  deriving (Int -> Event -> ShowS
[Event] -> ShowS
Event -> String
(Int -> Event -> ShowS)
-> (Event -> String) -> ([Event] -> ShowS) -> Show Event
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Event -> ShowS
showsPrec :: Int -> Event -> ShowS
$cshow :: Event -> String
show :: Event -> String
$cshowList :: [Event] -> ShowS
showList :: [Event] -> ShowS
Show, Event -> Event -> Bool
(Event -> Event -> Bool) -> (Event -> Event -> Bool) -> Eq Event
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Event -> Event -> Bool
== :: Event -> Event -> Bool
$c/= :: Event -> Event -> Bool
/= :: Event -> Event -> Bool
Eq)

{- | A callback is a function that takes an 'Event' and performs some IO action.
This allows users to react to different stages of LLM operations, such as logging
or updating a UI.

=== Examples

To create a custom callback that logs events to a file:

@
import System.IO
myCallback :: Callback
myCallback event = do
  handle <- openFile "llm_log.txt" AppendMode
  case event of
    LLMStart -> hPutStrLn handle "LLM operation started"
    LLMEnd -> hPutStrLn handle "LLM operation completed"
    LLMError err -> hPutStrLn handle $ "LLM error: " ++ err
  hClose handle
@
-}
type Callback = Event -> IO ()

{- | A standard callback that prints event messages to the standard output.
This is useful for simple debugging or monitoring of LLM operations.

=== Examples

Using 'stdOutCallback' in an LLM operation:

@
let callbacks = [stdOutCallback]
result <- generate (Ollama "llama3.2:latest" callbacks) "What is 2+2?" Nothing
-- Output will include:
-- Model operation started
-- Model completed with
-- (depending on success or error)
@
-}
stdOutCallback :: Callback
stdOutCallback :: Callback
stdOutCallback Event
event = case Event
event of
  Event
LLMStart -> String -> IO ()
putStrLn String
"Model operation started"
  Event
LLMEnd -> String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Model completed with"
  LLMError String
err -> String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Error occurred: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
err