A complete LLM agent in ~30 lines of TypeScript. An LLM in a loop, with one tool. That's it. That's an agent.
Inspired by Thomas Ptacek's You Should Write An Agent on the Fly.io blog — go read it, it's great.
Open main.ts and hit Run. The agent will fetch the Hacker News front page and tell you the top story:
tool: fetch_url({"url":"https://news.ycombinator.com/"})
>>> The top story on Hacker News right now is titled "..."
You didn't write a loop to fetch URLs. You gave the model permission to fetch, and it figured out the rest.
Rendering mermaid diagram...
The whole thing:
- Build a
messagesarray (the "context window" — just a list of strings). - Call the LLM with the messages and a list of tools.
- If the response has
tool_calls, run them, append the results tomessages, loop. - Otherwise, print the answer and exit.
The LLM is stateless. The conversation is an illusion we cast on ourselves by replaying the whole transcript every turn.
- Add a tool. Append another entry to the
toolsarray and a branch inrun(). Tryread_sqlite,send_email,roll_dice, whatever. - Make it interactive. Wrap the loop in a
for awaitoverDeno.stdinlines (or turn it into an HTTP val with a chat UI). - Give it memory. Persist
messagesinstd/sqlitebetween runs. - Sub-agents. Spawn another
messagesarray with different tools. Have them talk. - Swap the model. Change
gpt-4o-minito anything elsestd/openaisupports.
Your wackiest idea will probably (1) work and (2) take 30 minutes to code. — tqbf
All credit for the framing and most of the prose-worth ideas goes to Thomas Ptacek (@tqbf) and the Fly.io blog: https://fly.io/blog/everyone-write-an-agent/. This val is just a Val Town / TypeScript port of the spirit of that post.