Agent.cr - an agentic framework for OpenAI protocol

Hey all,

I had a project that needed a proper AI-assistant layer, and after digging through the shards ecosystem I couldn’t find anything that fit, so I built my own: agent.cr.

It’s heavily inspired by the excellent RubyLLM gem (kudos to them! A lot of the ergonomics are stolen with love :sweat_smile:).
It wraps any OpenAI-compatible streaming endpoint behind a fiber-based async interface, so #ask never blocks your code.

What it does today:

  • Tools / function calling with automatic resolution (no manual while-loop), plus enable/disable mid-conversation
  • Attachments — images, audio, text files, auto-detected by extension
  • Streamed content with typed chunks (content, reasoning tokens, tool-call deltas)
  • Multi-turn agentic loop with automatic history tracking + trimming
  • Dump / restore a session (history, tool state, and prompt-cache affinity preserved)
  • A middleware-style handler chain that wraps each pipeline stage: turn, streamed chunk, tool call, error… so you can inspect, mutate, or short-circuit. Handy for gating tool calls behind user confirmation, enforcing a token budget, or rewriting content in-flight.
  • Pluggable provider abstraction (anything OpenAI-compatible: OpenAI, OpenRouter, local llama.cpp, Ollama…). The architecture is open for non-OpenAI protocols (Anthropic) but I’m not planning to implement them in the near future.

What it doesn’t do: MCP. No plan in the near term; I don’t run MCP servers for this project. Maybe later for customer integrations, but not a priority.

Next up: embedding and STT endpoints as “extra” features, then I’ll tag 0.1.

There are a couple of self-contained examples in examples/. The fun one is a stupid little text-based RPG where the LLM is your Dungeon Master and Crystal tools enforce the rules. No cheating, not even for the DM:

crystal run examples/rpg.cr # Note: Setup in .env.local first your ENV variable to your LLM

There’s also examples/handlers.cr if you want to see the middleware chain in action (token budgeting, tool confirmation, in-flight word replacement).

Tested both locally (Strix Halo box running Qwen3.6) and over OpenRouter (Deepseek v4 & GLM5.2).

Repo: GitHub - anykeyh/agent.cr: Agentic in Crystal Lang · GitHub

The code was written with AI-assistance, but not vibe-coded (e.g. control on each steps). For those interested, globally AI is working well with Crystal Lang, except some confusions with Ruby methods.

Would love to hear what you think !

very cool :+1: