In my mind LLM "agents" are just event-driven programs (or as
@karpathy would say "Software 3.0" programs)
1) They can receive new events (e.g. a "user message")
2) Some events trigger a "computation" (i.e. an LLM request)
3) This produces additional events (e.g. an "assistant message") that other actors can subscribe to
Under the hood the agents maintain an append-only immutable log and a reducer function that turns the event log into usable state - most importantly the input args for an LLM request (model options, system prompt, message history, tools)
Modelling agents this way makes it easy to implement all manner of fun asynchronous interactions. Handoffs to other agents. Async tool calls (that complete in the far future). Scheduled events. Consuming webhooks / messages from third parties etc. And it's easy to do forking, snapshotting, time travel, debugging etc. And normal techniques (e.g. debouncing) from event driven programming (i.e. Javascript) are then easy to use, too.
One thing I've recently been thinking is that you could even use a reactive querying mechanism like livestore or convex and give the agent a tool to query data. And then when the data changes the agent gets a new event.
Are there any existing agent libraries that encourage this design pattern?