Skip to content

Add OpenRouter Data Extraction Support #160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.test.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
OPENAI_ACCESS_TOKEN=your_openai_api_key_here
OPEN_ROUTER_ACCESS_TOKEN=your_openrouter_api_key_here
ANTHROPIC_ACCESS_TOKEN=your_anthropic_api_key_here
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ test/dummy/config/master.key
docs/.vitepress/dist
docs/.vitepress/cache
docs/parts/examples/*.md

.env*
!.env.*.example
168 changes: 168 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Contributing to Active Agent

Thank you for your interest in contributing to Active Agent! This guide will help you get started with setting up your development environment and running tests.

## Getting Started

### Prerequisites

- Ruby 3.0 or higher
- Rails 7.0 or higher
- Git

### Environment Setup

1. **Fork and clone the repository**
```bash
git clone https://github.com/your-username/activeagent.git
cd activeagent
```

2. **Install dependencies**
```bash
bundle install
```

3. **Set up environment variables**

Copy the example environment file:
```bash
cp .env.test.example .env.test
```

Edit `.env.test` and add your API keys:
```bash
OPENAI_ACCESS_TOKEN=your_openai_api_key_here
OPEN_ROUTER_ACCESS_TOKEN=your_openrouter_api_key_here
ANTHROPIC_ACCESS_TOKEN=your_anthropic_api_key_here
```

### Running Tests

To run the full test suite:

```bash
./bin/test
```

You can also run specific test files:

```bash
./bin/test test/agents/application_agent_test.rb
```

Or run tests with specific patterns:

```bash
./bin/test -n test_generation
```

### Code Quality

Before submitting your changes, make sure to run the linting tools:

```bash
./bin/rubocop
```

To auto-fix most style issues:

```bash
./bin/rubocop -a
```

## Making Changes

### Development Workflow

1. **Create a feature branch**
```bash
git checkout -b feature/your-feature-name
```

2. **Make your changes**
- Write tests for new functionality
- Update documentation if needed
- Follow the existing code style

3. **Test your changes**
```bash
./bin/test
./bin/rubocop
```

4. **Commit your changes**
```bash
git add .
git commit -m "Add descriptive commit message"
```

5. **Push to your fork**
```bash
git push origin feature/your-feature-name
```

6. **Create a Pull Request**
- Go to the original repository on GitHub
- Click "New Pull Request"
- Select your branch and provide a clear description

### Testing Guidelines

- Write tests for all new functionality
- Ensure existing tests continue to pass
- Use descriptive test names that explain what is being tested
- Use VCR to Mock external API calls

### Code Style

- Follow Ruby community standards
- Use descriptive variable and method names
- Add comments for complex logic
- Keep methods focused and single-purpose

## Types of Contributions

We welcome various types of contributions:

- **Bug fixes**: Help us identify and fix issues
- **Feature additions**: Add new functionality to the framework
- **Documentation**: Improve existing docs or add new examples
- **Tests**: Increase test coverage
- **Performance improvements**: Optimize existing code

## Getting Help

If you need help or have questions:

- Check the [documentation](https://docs.activeagents.ai)
- Open an issue on GitHub for bugs or feature requests
- Start a discussion for general questions

## API Key Setup

For testing different providers, you'll need API keys:

### OpenAI
1. Visit [OpenAI Platform](https://platform.openai.com/)
2. Create an account or sign in
3. Navigate to API Keys section
4. Create a new API key

### Anthropic
1. Visit [Anthropic Console](https://console.anthropic.com/)
2. Create an account or sign in
3. Navigate to API Keys section
4. Create a new API key

### OpenRouter
1. Visit [OpenRouter](https://openrouter.ai/)
2. Create an account or sign in
3. Navigate to Keys section
4. Create a new API key

## License

By contributing to Active Agent, you agree that your contributions will be licensed under the [MIT License](LICENSE).

Thank you for contributing to Active Agent! 🚀
4 changes: 4 additions & 0 deletions bin/test
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#!/usr/bin/env ruby
require "pry"
require "dotenv"
Dotenv.load(".env.test")

$: << File.expand_path("../test", __dir__)

require "bundler/setup"
Expand Down
1 change: 1 addition & 0 deletions lib/active_agent.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "yaml"
require "abstract_controller"
require "active_agent/errors"
require "active_agent/generation_provider"
require "active_agent/version"
require "active_agent/deprecator"
Expand Down
28 changes: 24 additions & 4 deletions lib/active_agent/action_prompt/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require "active_support/core_ext/string/inflections"
require "active_support/core_ext/hash/except"
require "active_support/core_ext/module/anonymous"
require "active_agent/errors"

# require "active_agent/log_subscriber"
require "active_agent/rescuable"
Expand Down Expand Up @@ -321,7 +322,7 @@ def prompt(headers = {}, &block)
context.params = params
context.action_name = action_name

context.output_schema = load_schema(headers[:output_schema], set_prefixes(headers[:output_schema], lookup_context.prefixes))
context.output_schema = schema_load_output(headers[:output_schema], set_prefixes(headers[:output_schema], lookup_context.prefixes))

context.charset = charset = headers[:charset]

Expand Down Expand Up @@ -350,7 +351,7 @@ def action_schemas
prefixes = set_prefixes(action_name, lookup_context.prefixes)

action_methods.map do |action|
load_schema(action, prefixes)
schema_load_action(action, prefixes)
end.compact
end

Expand Down Expand Up @@ -388,9 +389,28 @@ def set_prefixes(action, prefixes)
prefixes = lookup_context.prefixes | [ self.class.agent_name ]
end

def load_schema(action_name, prefixes)
return unless lookup_context.template_exists?(action_name, prefixes, false, formats: [ :json ])
def schema_load_action(action_name, prefixes)
schema_load(action_name, prefixes) if schema_exists?(action_name, prefixes)
end

def schema_load_output(action_name, prefixes)
return unless action_name

if schema_exists?(action_name, prefixes)
schema_load(action_name, prefixes)
else
raise ActiveAgent::Errors::SchemaNotFoundError.new(
schema_name: action_name,
prefixes: prefixes
)
end
end

def schema_exists?(action_name, prefixes)
lookup_context.template_exists?(action_name, prefixes, false, formats: [ :json ])
end

def schema_load(action_name, prefixes)
JSON.parse render_to_string(locals: { action_name: action_name }, action: action_name, formats: :json)
end

Expand Down
59 changes: 59 additions & 0 deletions lib/active_agent/errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

module ActiveAgent
# = Active Agent Errors
#
# This module defines all custom error classes used throughout the ActiveAgent gem.
# All custom errors inherit from ActiveAgentError which provides a common base
# for catching any ActiveAgent-specific errors.
module Errors
# Base error class for all ActiveAgent errors
class ActiveAgentError < StandardError; end

# Base error for all generation provider related errors
class GenerationProviderError < ActiveAgentError; end

# Error raised when a provider API returns an error response
# This includes HTTP errors, API key issues, rate limiting, model not found, etc.
class ProviderApiError < ActiveAgentError
attr_reader :provider_name, :status_code, :error_type

def initialize(message, provider_name: nil, status_code: nil, error_type: nil)
@provider_name = provider_name
@status_code = status_code
@error_type = error_type
super(message)
end

def to_s
parts = [super]

Check failure on line 29 in lib/active_agent/errors.rb

View workflow job for this annotation

GitHub Actions / lint

Layout/SpaceInsideArrayLiteralBrackets: Use space inside array brackets.

Check failure on line 29 in lib/active_agent/errors.rb

View workflow job for this annotation

GitHub Actions / lint

Layout/SpaceInsideArrayLiteralBrackets: Use space inside array brackets.
parts << "(Provider: #{provider_name})" if provider_name
parts << "(Status: #{status_code})" if status_code
parts << "(Type: #{error_type})" if error_type
parts.join(" ")
end
end

# Error raised when an output schema template cannot be found or loaded
class SchemaNotFoundError < ActiveAgentError
attr_reader :schema_name, :prefixes

def initialize(message = nil, schema_name: nil, prefixes: nil)
@schema_name = schema_name
@prefixes = prefixes

message ||= build_default_message
super(message)
end

private

def build_default_message
parts = ["Output schema not found"]

Check failure on line 52 in lib/active_agent/errors.rb

View workflow job for this annotation

GitHub Actions / lint

Layout/SpaceInsideArrayLiteralBrackets: Use space inside array brackets.

Check failure on line 52 in lib/active_agent/errors.rb

View workflow job for this annotation

GitHub Actions / lint

Layout/SpaceInsideArrayLiteralBrackets: Use space inside array brackets.
parts << "for '#{schema_name}'" if schema_name
parts << "in #{prefixes}" if prefixes && prefixes.any?
parts.join(" ")
end
end
end
end
8 changes: 6 additions & 2 deletions lib/active_agent/generation_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ module ActiveAgent
module GenerationProvider
extend ActiveSupport::Concern

# Make error classes available in the GenerationProvider namespace
GenerationProviderError = ActiveAgent::Errors::GenerationProviderError
ProviderApiError = ActiveAgent::Errors::ProviderApiError

included do
class_attribute :_generation_provider_name, instance_accessor: false, instance_predicate: false
class_attribute :_generation_provider, instance_accessor: false, instance_predicate: false
Expand All @@ -19,8 +23,8 @@ def configuration(name_or_provider, **options)
config.merge!(options)
raise "Failed to load provider #{name_or_provider}: configuration not found for provider" if config["service"].nil?
configure_provider(config)
rescue LoadError => e
raise RuntimeError, "Failed to load provider #{name_or_provider}: #{e.message}"
rescue LoadError => exception
raise RuntimeError, "Failed to load provider #{name_or_provider}: #{exception.message}", exception.backtrace
end

def configure_provider(config)
Expand Down
10 changes: 5 additions & 5 deletions lib/active_agent/generation_provider/anthropic_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
begin
gem "ruby-anthropic", "~> 0.4.2"
require "anthropic"
rescue LoadError
raise LoadError, "The 'ruby-anthropic' gem is required for AnthropicProvider. Please add it to your Gemfile and run `bundle install`."
rescue LoadError => exception
raise LoadError, "The 'ruby-anthropic' gem is required for AnthropicProvider. Please add it to your Gemfile and run `bundle install`.", exception.backtrace
end

require "active_agent/action_prompt/action"
Expand All @@ -24,9 +24,9 @@ def generate(prompt)
@prompt = prompt

chat_prompt(parameters: prompt_parameters)
rescue => e
error_message = e.respond_to?(:message) ? e.message : e.to_s
raise GenerationProviderError, error_message
rescue => exception
error_message = exception.respond_to?(:message) ? exception.message : exception.to_s
raise GenerationProviderError, error_message, exception.backtrace
end

def chat_prompt(parameters: prompt_parameters)
Expand Down
1 change: 0 additions & 1 deletion lib/active_agent/generation_provider/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module ActiveAgent
module GenerationProvider
class Base
class GenerationProviderError < StandardError; end
attr_reader :client, :config, :prompt, :response, :access_token, :model_name

def initialize(config)
Expand Down
Loading
Loading