{"id":24299359,"url":"https://github.com/alchaplinsky/regent","last_synced_at":"2025-04-05T00:04:41.795Z","repository":{"id":270207658,"uuid":"906934349","full_name":"alchaplinsky/regent","owner":"alchaplinsky","description":"✨ Building AI Agents 🤖 with Ruby 💎","archived":false,"fork":false,"pushed_at":"2025-02-08T08:37:07.000Z","size":143,"stargazers_count":92,"open_issues_count":1,"forks_count":12,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-28T16:43:24.698Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alchaplinsky.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-22T10:57:55.000Z","updated_at":"2025-03-26T07:52:36.000Z","dependencies_parsed_at":"2025-01-20T10:40:53.719Z","dependency_job_id":null,"html_url":"https://github.com/alchaplinsky/regent","commit_stats":null,"previous_names":["alchaplinsky/regent"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alchaplinsky%2Fregent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alchaplinsky%2Fregent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alchaplinsky%2Fregent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alchaplinsky%2Fregent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alchaplinsky","download_url":"https://codeload.github.com/alchaplinsky/regent/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247266563,"owners_count":20910836,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-16T21:38:18.548Z","updated_at":"2025-04-05T00:04:41.772Z","avatar_url":"https://github.com/alchaplinsky.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"![regent_light](https://github.com/user-attachments/assets/62564dac-b8d7-4dc0-9b63-64c6841b5872)\n\n\u003cdiv align=\"center\"\u003e\n\n# Regent\n\n[![Gem Version](https://badge.fury.io/rb/regent.svg)](https://badge.fury.io/rb/regent)\n[![Build](https://github.com/alchaplinsky/regent/actions/workflows/main.yml/badge.svg)](https://github.com/alchaplinsky/regent/actions/workflows/main.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n\u003c/div\u003e\n\n**Regent** is a small and elegant Ruby framework for building AI agents that can think, reason, and take actions through tools. It provides a clean, intuitive interface for creating agents that can solve complex problems by breaking them down into logical steps.\n\n\u003e [!NOTE]\n\u003e Regent is currently an experiment intended to explore patterns for building easily traceable and debuggable AI agents of different architectures. It is not yet intended to be used in production and is currently in development.\n\u003e \n\u003e Read more about Regent in a Medium article: [Building AI Agent from scratch with Ruby](https://medium.com/towards-artificial-intelligence/building-ai-agent-from-scratch-with-ruby-c6260dad45b7)\n\n## Key Features\n\n- **ReAct Pattern Implementation**: Agents follow the Reasoning-Action pattern, making decisions through a clear thought process before taking actions\n- **Multi-LLM Support**: Seamlessly works with:\n  - OpenAI (GPT models)\n  - Anthropic (Claude models)\n  - Google (Gemini models)\n- **Extensible Tool System**: Create custom tools that agents can use to interact with external services, APIs, or perform specific tasks\n- **Built-in Tracing**: Every agent interaction is traced and can be replayed, making debugging and monitoring straightforward\n- **Clean Ruby Interface**: Designed to feel natural to Ruby developers while maintaining powerful capabilities\n\n## Showcase\n\nA basic Regnt Agent extended with a `price_tool` that allows for retrieving cryptocurrency prices from coingecko.com.\n\n![Screen_gif](https://github.com/user-attachments/assets/63c8c923-0c1e-48db-99f6-33758411623f)\n\n## Quick Start\n\n```bash\ngem install regent\n```\n\nor add regent to the Gemfile:\n\n```ruby\ngem 'regent'\n```\n\nand run\n\n```bash\nbundle install\n```\n\n## Usage\n\n### Quick Example\n\nCreate your first weather agent:\n\n```ruby\n# Define agent class\nclass WeatherAgent \u003c Regent::Agent\n  tool(:weather_tool, \"Get current weather for a location\")\n\n  def weather_tool(location)\n    \"Currently 72°F and sunny in #{location}\"\n  end\nend\n\n# Instantiate an agent\nagent = WeatherAgent.new(\"You are a helpful weather assistant\", model: \"gpt-4o\")\n\n# Execute a query\nagent.run(\"What's the weather like in Tokyo?\") # =\u003e \"It is currently 72°F and sunny in Tokyo.\"\n```\n\n### LLMs\nRegent provides an interface for invoking an LLM through an instance of `Regent::LLM` class. Even though Agent initializer allows you to pass a modal name as a string, sometimes it is useful to create a model instance if you want to tune model params before passing it to the agent. Or if you need to invoke a model directly without passing it to an Agent you can do that by creating an instance of LLM class:\n\n```ruby\nmodel = Regent::LLM.new(\"gemini-1.5-flash\")\n# or with options\nmodel = Regent::LLM.new(\"gemini-1.5-flash\", temperature: 0.5) # supports options that are supported by the model\n```\n\n#### API keys\nBy default, **Regent** will try to fetch API keys for corresponding models from environment variables. Make sure that the following ENV variables are set depending on your model choice:\n\n| Model series | ENV variable name   |\n|--------------|---------------------|\n| `gpt-`       | `OPENAI_API_KEY`    |\n| `gemini-`    | `GEMINI_API_KEY`    |\n| `claude-`    | `ANTHROPIC_API_KEY` |\n\nBut you can also pass an `api_key` option to the` Regent::LLM` constructor should you need to override this behavior:\n\n```ruby\nmodel = Regent::LLM.new(\"gemini-1.5-flash\", api_key: \"AIza...\")\n```\n\n\u003e [!NOTE]\n\u003e Currently **Regent** supports only `gpt-`, `gemini-` and `claude-` models series and local **ollama** models. But you can build, your custom model classes that conform to the Regent's interface and pass those instances to the Agent.\n\n#### Calling LLM\nOnce your model is instantiated you can call the `invoke` method:\n\n```ruby\nmodel.invoke(\"Hello!\") \n```\n\nAlternatively, you can pass message history to the `invoke` method. Messages need to follow OpenAI's message format (eg. `{role: \"user\", content: \"...\"}`)\n\n```ruby\nmodel.invoke([\n  {role: \"system\", content: \"You are a helpful assistant\"},\n  {role: \"user\", content: \"Hello!\"}\n])\n```\n\nThis method returns an instance of the `Regent::LLM::Result` class, giving access to the content or error and token usage stats.\n\n```ruby\nresult = model.invoke(\"Hello!\")\n\nresult.content # =\u003e Hello there! How can I help you today?\nresult.input_tokens # =\u003e 2\nresult.output_tokens # =\u003e 11\nresult.error # =\u003e nil\n```\n\n### Tools\n\nThere are multiple ways how you can give agents tools for performing actions and retrieving additional information. First of all you can define a **function tool** directly on the agent class:\n\n```ruby\nclass MyAgent \u003c Regent::Agent\n  # define the tool by giving a unique name and description\n  tool :search_web, \"Search for information on the web\" \n\n  def search_web(query)\n    # Implement tool logic within the method with the same name\n  end\nend\n```\n\nFor more complex tools we can define a dedicated class with a `call` method that will get called. And then pass an instance of this tool to an agent:\n\n```ruby\nclass SearchTool \u003c Regent::Tool\n  def call(query)\n    # Implement tool logic\n  end\nend\n\nagent = Regent::Agent.new(\"Find information and answer any question\", {\n  model: \"gpt-4o\",\n  tools: [SearchTool.new]\n})\n\n```\n\n### Agent\n\n**Agent** class is the core of the library. To crate an agent, you can use `Regent::Agent` class directly if you don't need to add any business logic. Or you can create your own class inheriting from `Regent::Agent`. To instantiate an agent you need to pass a **purpose** of an agent and a model it should use.\n\n```ruby\nagent = Regent::Agent.new(\"You are a helpful assistant\", model: \"gpt-4o-mini\")\n```\n\nAdditionally, you can pass a list of Tools to extend the agent's capabilities. Those should be instances of classes that inherit from `Regent::Tool` class:\n\n```ruby\nclass SearchTool \u003c Regent::Tool\n  def call\n    # make a call to search API\n  end\nend\n\nclass CalculatorTool \u003c Regent::Tool\n  def call\n    # perform calculations\n  end\nend\n\ntools = [SearchTool.new, CalculatorTool.new]\n\nagent = Regent::Agent.new(\"You are a helpful assistant\", model: \"gpt-4o-mini\", tools: tools)\n```\n\nEach agent run creates a **session** that contains every operation that is performed by the agent while working on a task. Sessions can be replayed and drilled down into while debugging.\n```ruby\nagent.sessions # =\u003e Returns all sessions performed by the agent\nagent.session # =\u003e Returns last session performed by the agent\nagent.session.result # =\u003e Returns result of latest agent run\n```\n\nWhile running agent logs all session spans (all operations) to the console with all sorts of useful information, that helps to understand what the agent was doing and why it took a certain path.\n```ruby\nweather_agent.run(\"What is the weather in San Francisco?\")\n```\n\nOutputs:\n```console\n[✔] [INPUT][0.0s]: What is the weather in San Francisco?\n ├──[✔] [LLM ❯ gpt-4o-mini][242 → 30 tokens][0.02s]: What is the weather in San Francisco?\n ├──[✔] [TOOL ❯ get_weather][0.0s]: [\"San Francisco\"] → The weather in San Francisco is 70 degrees and sunny.\n ├──[✔] [LLM ❯ gpt-4o-mini][294 → 26 tokens][0.01s]: Observation: The weather in San Francisco is 70 degrees and sunny.\n[✔] [ANSWER ❯ success][0.03s]: It is 70 degrees and sunny in San Francisco.\n```\n\n### Engine\nBy default, Regent uses ReAct agent architecture. You can see the [details of its implementation](https://github.com/alchaplinsky/regent/blob/main/lib/regent/engine/react.rb). However, Agent constructor accepts an `engine` option that allows you to swap agent engine when instantiating an Agent. This way you can implement your own agent architecture that can be plugged in and user within Regent framework.\n\n```ruby\nagent = CustomAgent.new(\"You are a self-correcting assistant\", model: \"gpt-4o\", engine: CustomEngine)\n```\n\nIn order to implement your own engine you need to define a class that inherits from `Regent::Engine::Base` class and implements `reason` method:\n\n```ruby\nclass CustomEngine \u003c Regent::Engine::Base\n  def reason(task)\n    # Your implementation of an Agent lifecycle\n  end\nend\n```\n\nNote that Base class already handles `max_iteration` check, so you won't end up in an infinite loop. Also, it allows you to use `llm_call_response` and `tool_call_response` methods for agent reasoning as well as `success_answer` and `error_answer` for the final result.\n\nFor any other operation that happens in your agent architecture that you want to track separately call it within the `session.exec` block. See examples in `Regent::Engine::Base` class.\n\n\n---\n## Why Regent?\n\n- **Transparent Decision Making**: Watch your agent's thought process as it reasons through problems\n- **Flexible Architecture**: Easy to extend with custom tools and adapt to different use cases\n- **Ruby-First Design**: Takes advantage of Ruby's elegant syntax and conventions\n- **Transparent Execution**: Built with tracing, error handling, and clean abstractions\n\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/alchaplinsky/regent. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/alchaplinsky/regent/blob/main/CODE_OF_CONDUCT.md).\n\n## Code of Conduct\n\nEveryone interacting in the Regent project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/alchaplinsky/regent/blob/main/CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falchaplinsky%2Fregent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falchaplinsky%2Fregent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falchaplinsky%2Fregent/lists"}