Sublayer

repository·main·Indexed 41 days ago

https://github.com/sublayerapp/sublayer

A 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.

Tokens
10.7K
Snippets
42
Records
50
Agent score
51%

What's inside Sublayer

  1. What are Generators in Sublayer?

    main
    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.
  2. What are Agents and Triggers in Sublayer?

    main
    Agents 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).
  3. What are Actions in Sublayer?

    main
    Actions 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.
  4. How Generators, Actions, and Agents work together

    main

    Sublayer 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., WriteFileAction to 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 FileChange trigger that activates an agent when a file is modified).
  5. Install the Sublayer gem

    main

    You 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'
  6. What is a Sublayer Action?

    main

    A 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:

    1. Data Retrieval: Used by a Generator to fetch data required for processing.
    2. 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 a call method to execute the logic.

  7. Configure LLM output structure with llm_output_adapter

    main

    When defining a Sublayer::Generator, use the llm_output_adapter directive 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" }
      ]
  8. Configure an AI Model Provider

    main

    Sublayer is model-agnostic. You must configure the ai_provider and ai_model in the Sublayer.configuration object. 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"
  9. Implement a Sublayer::Generator

    main

    A Sublayer::Generator is a class that abstracts sending a request to an LLM and receiving structured data. To create one:

    1. Inherit from Sublayer::Generators::Base.
    2. Define an llm_output_adapter to specify the output schema.
    3. Implement a prompt method that returns a string describing the task and providing necessary context.
    4. Implement a generate method (you can call super to 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
  10. Understand the Sublayer Agent DSL

    main

    A 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:

    1. trigger: Defines what starts the agent. Built-in triggers include trigger_on_files_changed. Custom triggers can be created by subclassing Sublayer::Triggers::Base, implementing an initialize method, and a setup(agent) method that calls activate(agent) when conditions are met.
    2. goal: A block that returns a boolean indicating whether the agent's objective has been achieved.
    3. check_status: A method used to examine the state of the world or update the goal condition to monitor progress.
    4. step: The core execution method. This method encapsulates the logic used to work toward the goal, typically leveraging Sublayer::Actions (to interact with the outside world) and Sublayer::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.
  11. Implement a custom Generator

    main

    To create a custom Generator in Sublayer, inherit from Sublayer::Generators::Base. You must implement the prompt method to define the instructions sent to the LLM. You can also use the llm_output_adapter macro to define how the LLM's response should be structured and named in the output.

    Note that the generate method can be overridden to call super or add custom logic, and the initialize method 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
    end
  12. Generate a Sublayer Agent

    main

    Use the sublayer_agent generator 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"