ask-agent
Agent runtime for the ask-rb ecosystem. Runs the core agent loop: think, call
tools, execute, feed results back, and repeat until the task is done. Built on
ask-core, ask-state-providers, ask-llm-providers, ask-tools, ask-skills, and
ask-instrumentation, and it powers the askr CLI.
Installation
gem "ask-agent"
Quick Start
require "ask-agent"
session = Ask::Agent::Session.new(model: "gpt-4o", max_turns: 25)
response = session.run("What files are in the current directory?")
puts response
Stream execution in real time with events:
session.on_event do |event|
case event
when Ask::Agent::Events::TextDelta
print event.content
when Ask::Agent::Events::ToolExecutionStart
puts "\nRunning #{event.name}..."
end
end
Declarative Agents
Agents follow a file convention. Each agent lives in a directory under
agents/ (or app/agents/ in Rails); the directory name is the agent name,
the file agent.rb defines the agent as a <Name>::Agent < Ask::Agent::Definition subclass, and a sibling instructions.md is
auto-loaded as the system prompt.
agents/
└── health_check/ # agent name: "health_check"
├── agent.rb # module HealthCheck; class Agent < Ask::Agent::Definition
├── instructions.md # auto-loaded system prompt
└── tools/ # per-agent tools (referenced with `tools :name`)
# agents/health_check/agent.rb
module HealthCheck
class Agent < Ask::Agent::Definition
model "gpt-4o"
tools :bash, :read, :grep
end
end
Run it by name:
agent = Ask::Agent.new("health_check")
response = agent.run("Check server health")
Shared tools for all agents go in agents/shared/tools/. Per-agent skills go
in agents/<name>/skills/, shared skills in agents/shared/skills/.
Essential API
| Entry point | Purpose | ||
|---|---|---|---|
Ask::Agent::Session.new(model:, tools: [], max_turns: 25, ...) |
Full agent loop: message, tool calls, results, follow-up | ||
session.run(message) |
Run the loop for one message | ||
| `session.on_event { \ | e\ | }` | Stream Ask::Agent::Events (text deltas, tool execution, evaluation) |
Ask::Agent.new("name") |
Build a session from a declarative agent definition | ||
Ask.chat(message) |
One-shot chat without instantiating a Session | ||
| `Ask::Agent.configure { \ | c\ | ... }` | Global defaults: model, provider, turns, compactor, middleware |
askr |
CLI: askr run <agent> [prompt], askr list, askr schedule, askr new, askr skills |
Configuration
Ask::Agent.configure do |c|
c.default_model = "claude-sonnet-4"
c.default_provider = :anthropic
c.default_max_turns = 50
c.compactor_enabled = true
c.compactor_threshold = 0.8
c.parallel_tool_execution = true
c.max_tool_retries = 3
end
default_provider pins which provider serves the default model when the model
name doesn't uniquely identify one (for example, the same model id registered
under multiple OpenAI-compatible providers). A provider: passed to
Session.new or declared in an agent Definition always wins over the global
default.
Full documentation
The full ask-rb documentation lives at https://ask-rb.github.io/ask-docs. https://ask-rb.github.io/ask-docs/core/agent covers ask-agent in depth, including the evaluator, middleware, extensions, cost tracking, and persistence. API reference: https://ask-rb.github.io/ask-docs/reference/api.
Development
bundle install bundle exec rake test
License
MIT