Sublayer
repository·main·Indexed 41 days ago
https://github.com/sublayerapp/sublayerA model-agnostic Ruby framework for building AI agents. Sublayer provides structured base classes for creating Generators (content creation), Actions (operations), and Agents (autonomous workflows) to build AI-powered applications. It supports multiple AI providers including OpenAI, Claude, and Gemini, and includes a CLI for scaffolding projects and components.
What's inside Sublayer
- Generators are specialized classes responsible for producing specific outputs from input data. They are designed to focus on a single, narrow generation task without performing side effects or complex logic. They serve as the primary building blocks for more complex Agent behaviors.
What are Agents and Triggers in Sublayer?
mainAgents are the high-level autonomous entities in the framework. They are tasked with monitoring systems or performing complex workflows. Agents rely on Triggers to determine their activation lifecycle. A Trigger is a mechanism that decides when an agent's task should be executed (for example, reacting to a file change or a specific time interval).What are Actions in Sublayer?
mainActions are operational units that interact with the outside world or the Generator lifecycle. They are used to either fetch data required by a Generator or to execute the results produced by a Generator. Actions do not involve complex decision-making logic.How Generators, Actions, and Agents work together
mainSublayer is built on several core abstractions that compose to create autonomous AI workflows:
- Generators: The fundamental building blocks. They are responsible for a single generation task (e.g., generating code from a description) based on input data. They do not perform actions or complex decision-making.
- Actions: These perform specific operations to either provide inputs for a Generator or consume the output of a Generator (e.g.,
WriteFileActionto save output to a file). - Agents: Autonomous entities designed to perform specific tasks or monitor systems. They orchestrate the use of Generators and Actions.
- Triggers: Used within Agents to decide when an agent should be activated (e.g., a
FileChangetrigger that activates an agent when a file is modified).
Install the Sublayer gem
mainYou can install Sublayer by running the gem command or by adding it to your Gemfile. Because the project is currently in pre-1.0 development, it is recommended to pin the version to a specific minor version to avoid breaking changes.
# In your Gemfile gem 'sublayer', '~> 0.2'What is a Sublayer Action?
mainA Sublayer Action is an implementation of the command pattern used within the Sublayer AI framework to perform operations in the external world, such as file system manipulation or making API calls.
Actions serve two primary purposes in the framework:
- Data Retrieval: Used by a
Generatorto fetch data required for processing. - Post-Generation Execution: Used to perform tasks based on the output of a
Generator(e.g., saving a generated file to disk).
Implementation Pattern
Every action must be a subclass of
Sublayer::Action::Base. An action is initialized with its required state and must implement acallmethod to execute the logic.- Data Retrieval: Used by a
Configure LLM output structure with llm_output_adapter
mainWhen defining a
Sublayer::Generator, use thellm_output_adapterdirective to instruct the LLM on the specific structure of the data it should return. This ensures the LLM output is parsed into a predictable format.Available adapter types include:
:named_strings: Returns a single object with specific named attributes.:list_of_named_strings: Returns an array of objects, where each object has named attributes.:list_of_strings: Returns an array of simple strings.:single_string: Returns a single string.:single_integer: Returns a single integer.:string_selection_from_list: Returns a single string that must be chosen from a provided list of options.
# Example: Generating a list of movie reviews with specific attributes llm_output_adapter type: :list_of_named_strings, name: "review_summaries", description: "List of movie reviews", item_name: "review", attributes: [ { name: "movie_title", description: "The title of the movie" }, { name: "reviewer_name", description: "The name of the reviewer" }, { name: "rating", description: "The rating given by the reviewer (out of 5 stars)" }, { name: "brief_comment", description: "A brief summary of the movie" } ]Configure an AI Model Provider
mainSublayer is model-agnostic. You must configure the
ai_providerandai_modelin theSublayer.configurationobject. Each provider requires a specific environment variable to be set for authentication.OpenAI (Default)
Requires
OPENAI_API_KEY.Gemini [UNSTABLE]
Requires
GEMINI_API_KEY. Note that Gemini's function calling API is in beta and not recommended for production.Claude
Requires
ANTHROPIC_API_KEY.# OpenAI Sublayer.configuration.ai_provider = Sublayer::Providers::OpenAI Sublayer.configuration.ai_model = "gpt-4o" # Gemini Sublayer.configuration.ai_provider = Sublayer::Providers::Gemini Sublayer.configuration.ai_model = "gemini-1.5-pro" # Claude Sublayer.configuration.ai_provider = Sublayer::Providers::Claude Sublayer.configuration.ai_model = "claude-3-5-sonnet-20240620"Implement a Sublayer::Generator
mainA
Sublayer::Generatoris a class that abstracts sending a request to an LLM and receiving structured data. To create one:- Inherit from
Sublayer::Generators::Base. - Define an
llm_output_adapterto specify the output schema. - Implement a
promptmethod that returns a string describing the task and providing necessary context. - Implement a
generatemethod (you can callsuperto use the base implementation).
class MyCustomGenerator < Sublayer::Generators::Base llm_output_adapter type: :single_string, name: "summary", description: "A summary" def generate super end def prompt "Summarize the following text: #{some_context}" end end- Inherit from
Understand the Sublayer Agent DSL
mainA Sublayer agent is a Ruby-based DSL designed to define a feedback loop for an AI agent. Agents run as daemons, triggered by specific events, and iteratively execute steps to reach a defined goal while checking their status along the way.
The DSL consists of four primary components:
trigger: Defines what starts the agent. Built-in triggers includetrigger_on_files_changed. Custom triggers can be created by subclassingSublayer::Triggers::Base, implementing aninitializemethod, and asetup(agent)method that callsactivate(agent)when conditions are met.goal: A block that returns a boolean indicating whether the agent's objective has been achieved.check_status: A method used to examine the state of the world or update the goal condition to monitor progress.step: The core execution method. This method encapsulates the logic used to work toward the goal, typically leveragingSublayer::Actions(to interact with the outside world) andSublayer::Generators(to make LLM calls and receive structured data).
Agents interact with the framework using:
Sublayer::Actions: For side effects like saving files, making API calls, or retrieving data.Sublayer::Generators: For structured LLM interactions.
Implement a custom Generator
mainTo create a custom Generator in Sublayer, inherit from
Sublayer::Generators::Base. You must implement thepromptmethod to define the instructions sent to the LLM. You can also use thellm_output_adaptermacro to define how the LLM's response should be structured and named in the output.Note that the
generatemethod can be overridden to callsuperor add custom logic, and theinitializemethod is used to capture input data required for the prompt.module YourProjectName module Generators class ExampleGenerator < Sublayer::Generators::Base # Define how the LLM output is mapped llm_output_adapter type: :single_string, name: "generated_text", description: "A simple generated text" def initialize(input:) @input = input end def generate super end def prompt <<-"PROMPT" Generate a simple story based on this input: #{@input} PROMPT end end end endGenerate a Sublayer Agent
mainUse the
sublayer_agentgenerator to create a new Sublayer agent based on a natural language description and specific logic requirements. The generator uses an LLM to produce a Ruby file containing a Sublayer agent implementation that follows the Sublayer DSL pattern.To generate an agent, you must provide the following parameters:
- Description: A high-level description of what the agent does.
- Trigger: The condition that starts the agent (e.g.,
trigger_on_files_changed). - Goal: The logic (returning a boolean) that defines when the agent has achieved its objective.
- Check Status: The method used to monitor progress toward the goal.
- Step: The method containing the core logic/actions the agent performs to move toward the goal.
# Note: This is a conceptual representation of the generator's required inputs. # The actual CLI command would be invoked via the sublayer CLI. sublayer generate sublayer_agent \ --description "An agent that fixes linting errors" \ --trigger "trigger_on_files_changed" \ --goal "lambda { |agent| !agent.has_lint_errors? }" \ --check_status "check_lint_status" \ --step "run_autofix_step"