cofree-bot is a toolkit for building chat bots compositionally. Bots
can be defined over arbitrary inputs or outputs, combined together and
then "lifted" to operate in any context.
Supported Chat Protocols:
- Matrix
- Discord
- IRC
- Slack
- Zulip
- CLI REPL
The Bot type
newtype Bot m s i o = Bot {runBot :: s -> i -> ListT m (o, s)}
Building bot behaviors
helloBot :: Monad m => Bot m s Text Text helloBot = Bot $ \s msg -> let name = "cofree-bot" in if name `T.isInfixOf` msg then pure ("Are you talking to me, punk?", s) else emptyListT
Lifting Bots Over more complex inputs and outputs
embedTextBot :: Functor m => Bot m s Text Text -> Bot m s (RoomID, Event) (RoomID, Event) embedTextBot (Bot bot) = Bot $ \s (rid, i) -> fmap (\(i', s') -> ((rid, mkMsg i'), s')) $ bot s (viewBody i) viewBody :: Event -> T.Text viewBody = view (_EventRoomMessage . _RoomMessageText . _mtBody) mkMsg :: T.Text -> Event mkMsg msg = EventRoomMessage $ RoomMessageText $ MessageText msg TextType Nothing Nothing
Combining Bot Behaviors
type (/\) = (,) type (\/) = Either type a /+\ b = These a b type a \*/ b = Maybe (Either a b) (/\) :: Monad m => Bot m s i o -> Bot m s' i o' -> Bot m (s /\ s') i (o /\ o') (/+\) :: Monad m => Bot m s i o -> Bot m s' i o' -> Bot m (s /\ s') i (o /+\ o') (/.\) :: Monad m => Bot m s i o -> Bot m s' i o -> Bot m (s /\ s') i o (\/) :: Monad m => Bot m s i o -> Bot m s i' o' -> Bot m s (i \/ i') (o \/ o') nudge :: Monad m => Bot m s i o \/ Bot m s i' o' -> Bot m s (i \/ i') (o \*/ o') nudgeLeft :: Monad m => Bot m s i o -> Bot m s (i \/ i') (o \*/ o') nudgeRight :: Monad m => Bot m s i' o' -> Bot m s (i \/ i') (o \*/ o')