Readable. Debuggable. Yours.
Most frameworks bury their runtime under layers of abstraction. Aar does the opposite — the core loop is ~80 lines of plain Python. Every LLM call, every tool execution, every event is visible and timed.
response = await provider.complete(messages, tools)
if response.tool_calls:
results = await executor.execute(tool_calls)
session.append(results)
continue
session.append(response) # done