riffer 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12e6843cdf4824294d9c9470c2dad55125bfa490b49389530145bd334041ce15
4
- data.tar.gz: 636133b4f5b2a046311a33a3b294ce2eb893bcb3a16292bd83198fc24f3dc500
3
+ metadata.gz: 414f5f9afaa98b3d19f1e649ea15aaa632fa60073d11ac940d6fdbb893b4356e
4
+ data.tar.gz: dd693e59f9acabd91f9bb4f7621aced10ca871d4f76d030ad6ab2ab743b9f2b9
5
5
  SHA512:
6
- metadata.gz: a26010e36c164851b3a9cbd6d3b7eebd9dcd935d4fdd405793998d2760b871b01a487724a8628eddc6bf366db164f924990ee12a2c93f99602e2c0f99c341d88
7
- data.tar.gz: 18428555a37e27ee29c35d21c7b1f6f00f988a22e02e6a25141d6a3d6b9d0c49da43a7bf408886d28734e485fd7ac32015643ac7d1c9fe2406bffd6d9a6602d7
6
+ metadata.gz: b4ee5e296e43d8727a2e9a214d8fe713bae89f0ba90c7e46ec6b7c1c3fae4cd2c8b0dc8efcbf771955a1c36b4a1ed5a4b591d034f9bf88b17ee99464590ed551
7
+ data.tar.gz: 1eb8e7c0ee9e381a78d5ddcbeb707f6bed15935bf8d45367da26a9f723372de7503dc14c7379d2e180c581b4aad6257571888eb46bc73e2dce190ef1bd8b823c
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.5.0"
2
+ ".": "0.6.0"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -5,75 +5,83 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [0.5.0](https://github.com/bottrall/riffer/compare/riffer/v0.4.2...riffer/v0.5.0) (2026-01-06)
8
+ ## [0.6.0](https://github.com/janeapp/riffer/compare/riffer/v0.5.1...riffer/v0.6.0) (2026-01-14)
9
9
 
10
10
 
11
11
  ### Features
12
12
 
13
- * streaming via agents ([#63](https://github.com/bottrall/riffer/issues/63)) ([b4171c2](https://github.com/bottrall/riffer/commit/b4171c20f64a7ada1264ce90ab5278c19ff8a47a))
13
+ * aws bedrock provider ([#73](https://github.com/janeapp/riffer/issues/73)) ([428ae90](https://github.com/janeapp/riffer/commit/428ae902db90c2d3765186ea06d76ee379b3eae7))
14
+ * reasoning support ([#75](https://github.com/janeapp/riffer/issues/75)) ([fcee502](https://github.com/janeapp/riffer/commit/fcee502054882f41d15ea312222a5538c8f04220))
14
15
 
15
- ## [0.4.2](https://github.com/bottrall/riffer/compare/riffer/v0.4.1...riffer/v0.4.2) (2025-12-29)
16
+ ## [0.5.1](https://github.com/janeapp/riffer/compare/riffer/v0.5.0...riffer/v0.5.1) (2026-01-10)
16
17
 
17
18
 
18
19
  ### Bug Fixes
19
20
 
20
- * update README for clarity on provider usage and examples ([#60](https://github.com/bottrall/riffer/issues/60)) ([b12835c](https://github.com/bottrall/riffer/commit/b12835ce71c29e02074a0897551db50283ac8be6))
21
+ * update Code of Conduct URL in README ([#67](https://github.com/janeapp/riffer/issues/67)) ([39ae1f5](https://github.com/janeapp/riffer/commit/39ae1f5025bcd36e1c5cab76fe8d312179f664ba))
22
+ * update gem details to reflect janeapp ownership ([#66](https://github.com/janeapp/riffer/issues/66)) ([06a008d](https://github.com/janeapp/riffer/commit/06a008d5ab050ca2c1afd4163104c6c95c9d248b))
23
+ * update GitHub Pages deployment action in release workflow ([#68](https://github.com/janeapp/riffer/issues/68)) ([e2f7961](https://github.com/janeapp/riffer/commit/e2f79616464101d90488f8f28aedcbdf4086277d))
21
24
 
22
- ## [0.4.1](https://github.com/bottrall/riffer/compare/riffer/v0.4.0...riffer/v0.4.1) (2025-12-29)
25
+ ## [0.5.0](https://github.com/janeapp/riffer/compare/riffer/v0.4.2...riffer/v0.5.0) (2026-01-06)
23
26
 
27
+ ### Features
28
+
29
+ - streaming via agents ([#63](https://github.com/janeapp/riffer/issues/63)) ([b4171c2](https://github.com/janeapp/riffer/commit/b4171c20f64a7ada1264ce90ab5278c19ff8a47a))
30
+
31
+ ## [0.4.2](https://github.com/janeapp/riffer/compare/riffer/v0.4.1...riffer/v0.4.2) (2025-12-29)
24
32
 
25
33
  ### Bug Fixes
26
34
 
27
- * add conditional check for docs job execution based on release creation ([#58](https://github.com/bottrall/riffer/issues/58)) ([97bc6f7](https://github.com/bottrall/riffer/commit/97bc6f79b20902f94edac35b7d9d25c2e033d8bd))
28
- * add permissions for contents in docs job ([#57](https://github.com/bottrall/riffer/issues/57)) ([1dd5f7a](https://github.com/bottrall/riffer/commit/1dd5f7a817d4f73c1a0cad1a93fee0148ef10705))
29
- * suppress output during documentation generation ([#53](https://github.com/bottrall/riffer/issues/53)) ([6b7f2d9](https://github.com/bottrall/riffer/commit/6b7f2d9aa7adb5450855097840c971dcf201d8c0))
30
- * update rdoc command to target the lib directory ([#56](https://github.com/bottrall/riffer/issues/56)) ([c319efe](https://github.com/bottrall/riffer/commit/c319efe039ddb118411ad9e270dc0994d3b8cf5c))
35
+ - update README for clarity on provider usage and examples ([#60](https://github.com/janeapp/riffer/issues/60)) ([b12835c](https://github.com/janeapp/riffer/commit/b12835ce71c29e02074a0897551db50283ac8be6))
31
36
 
32
- ## [0.4.0](https://github.com/bottrall/riffer/compare/riffer/v0.3.2...riffer/v0.4.0) (2025-12-29)
37
+ ## [0.4.1](https://github.com/janeapp/riffer/compare/riffer/v0.4.0...riffer/v0.4.1) (2025-12-29)
33
38
 
39
+ ### Bug Fixes
34
40
 
35
- ### Features
41
+ - add conditional check for docs job execution based on release creation ([#58](https://github.com/janeapp/riffer/issues/58)) ([97bc6f7](https://github.com/janeapp/riffer/commit/97bc6f79b20902f94edac35b7d9d25c2e033d8bd))
42
+ - add permissions for contents in docs job ([#57](https://github.com/janeapp/riffer/issues/57)) ([1dd5f7a](https://github.com/janeapp/riffer/commit/1dd5f7a817d4f73c1a0cad1a93fee0148ef10705))
43
+ - suppress output during documentation generation ([#53](https://github.com/janeapp/riffer/issues/53)) ([6b7f2d9](https://github.com/janeapp/riffer/commit/6b7f2d9aa7adb5450855097840c971dcf201d8c0))
44
+ - update rdoc command to target the lib directory ([#56](https://github.com/janeapp/riffer/issues/56)) ([c319efe](https://github.com/janeapp/riffer/commit/c319efe039ddb118411ad9e270dc0994d3b8cf5c))
36
45
 
37
- * add documentation generation and publishing workflow ([#51](https://github.com/bottrall/riffer/issues/51)) ([49e3b04](https://github.com/bottrall/riffer/commit/49e3b046c2011f56bb8803b76e152df9ffb26617))
46
+ ## [0.4.0](https://github.com/janeapp/riffer/compare/riffer/v0.3.2...riffer/v0.4.0) (2025-12-29)
38
47
 
39
- ## [0.3.2](https://github.com/bottrall/riffer/compare/riffer/v0.3.1...riffer/v0.3.2) (2025-12-29)
48
+ ### Features
40
49
 
50
+ - add documentation generation and publishing workflow ([#51](https://github.com/janeapp/riffer/issues/51)) ([49e3b04](https://github.com/janeapp/riffer/commit/49e3b046c2011f56bb8803b76e152df9ffb26617))
41
51
 
42
- ### Bug Fixes
52
+ ## [0.3.2](https://github.com/janeapp/riffer/compare/riffer/v0.3.1...riffer/v0.3.2) (2025-12-29)
43
53
 
44
- * add Rubygems credentials configuration step in release workflow ([#49](https://github.com/bottrall/riffer/issues/49)) ([dcc71e0](https://github.com/bottrall/riffer/commit/dcc71e01f541510ab73986237adaabfab1ef2401))
54
+ ### Bug Fixes
45
55
 
46
- ## [0.3.1](https://github.com/bottrall/riffer/compare/riffer/v0.3.0...riffer/v0.3.1) (2025-12-29)
56
+ - add Rubygems credentials configuration step in release workflow ([#49](https://github.com/janeapp/riffer/issues/49)) ([dcc71e0](https://github.com/janeapp/riffer/commit/dcc71e01f541510ab73986237adaabfab1ef2401))
47
57
 
58
+ ## [0.3.1](https://github.com/janeapp/riffer/compare/riffer/v0.3.0...riffer/v0.3.1) (2025-12-29)
48
59
 
49
60
  ### Bug Fixes
50
61
 
51
- * update checkout action version in release workflow ([#47](https://github.com/bottrall/riffer/issues/47)) ([c6b1361](https://github.com/bottrall/riffer/commit/c6b1361b20d7cc4522e20c46fa1a75ad3a8a80d7))
52
-
53
- ## [0.3.0](https://github.com/bottrall/riffer/compare/riffer-v0.2.0...riffer/v0.3.0) (2025-12-29)
62
+ - update checkout action version in release workflow ([#47](https://github.com/janeapp/riffer/issues/47)) ([c6b1361](https://github.com/janeapp/riffer/commit/c6b1361b20d7cc4522e20c46fa1a75ad3a8a80d7))
54
63
 
64
+ ## [0.3.0](https://github.com/janeapp/riffer/compare/riffer-v0.2.0...riffer/v0.3.0) (2025-12-29)
55
65
 
56
66
  ### Features
57
67
 
58
- * add release and publish workflows ([#35](https://github.com/bottrall/riffer/issues/35)) ([3eb0389](https://github.com/bottrall/riffer/commit/3eb03897d0e96c01ef1857c04b2bafa53e37dde0))
59
-
68
+ - add release and publish workflows ([#35](https://github.com/janeapp/riffer/issues/35)) ([3eb0389](https://github.com/janeapp/riffer/commit/3eb03897d0e96c01ef1857c04b2bafa53e37dde0))
60
69
 
61
70
  ### Bug Fixes
62
71
 
63
- * add manifest file to release configuration ([#43](https://github.com/bottrall/riffer/issues/43)) ([8d46135](https://github.com/bottrall/riffer/commit/8d46135ccd1c4315d624fa11a639e51aa1f1e5b8))
64
- * auto-publishing on new release ([#38](https://github.com/bottrall/riffer/issues/38)) ([5a1d267](https://github.com/bottrall/riffer/commit/5a1d267e046c1531e01c80b9e40b94eed216360c))
65
- * remove manifest file from release configuration ([#41](https://github.com/bottrall/riffer/issues/41)) ([2f898d8](https://github.com/bottrall/riffer/commit/2f898d8e1bdf6787583f22c83e83e90f2a75142e))
66
- * remove release-type configuration from release workflow ([#42](https://github.com/bottrall/riffer/issues/42)) ([e270a6c](https://github.com/bottrall/riffer/commit/e270a6c906f7e04f1b0ce57b7d29808c98e7dce8))
67
- * reset release manifest to empty object ([#44](https://github.com/bottrall/riffer/issues/44)) ([26f1b6d](https://github.com/bottrall/riffer/commit/26f1b6d2dcb622295026cc7fb247559156864d74))
68
- * restructure release configuration and update manifest format ([#45](https://github.com/bottrall/riffer/issues/45)) ([d07694c](https://github.com/bottrall/riffer/commit/d07694c05d49166740f3408a343c351d33749edf))
69
- * simplify release configuration by removing unnecessary package structure ([#40](https://github.com/bottrall/riffer/issues/40)) ([8472967](https://github.com/bottrall/riffer/commit/84729670fd202208256e6de69f1b81366ad0a688))
70
-
71
- ## [0.2.0](https://github.com/bottrall/riffer/compare/v0.1.0...v0.2.0) (2025-12-28)
72
+ - add manifest file to release configuration ([#43](https://github.com/janeapp/riffer/issues/43)) ([8d46135](https://github.com/janeapp/riffer/commit/8d46135ccd1c4315d624fa11a639e51aa1f1e5b8))
73
+ - auto-publishing on new release ([#38](https://github.com/janeapp/riffer/issues/38)) ([5a1d267](https://github.com/janeapp/riffer/commit/5a1d267e046c1531e01c80b9e40b94eed216360c))
74
+ - remove manifest file from release configuration ([#41](https://github.com/janeapp/riffer/issues/41)) ([2f898d8](https://github.com/janeapp/riffer/commit/2f898d8e1bdf6787583f22c83e83e90f2a75142e))
75
+ - remove release-type configuration from release workflow ([#42](https://github.com/janeapp/riffer/issues/42)) ([e270a6c](https://github.com/janeapp/riffer/commit/e270a6c906f7e04f1b0ce57b7d29808c98e7dce8))
76
+ - reset release manifest to empty object ([#44](https://github.com/janeapp/riffer/issues/44)) ([26f1b6d](https://github.com/janeapp/riffer/commit/26f1b6d2dcb622295026cc7fb247559156864d74))
77
+ - restructure release configuration and update manifest format ([#45](https://github.com/janeapp/riffer/issues/45)) ([d07694c](https://github.com/janeapp/riffer/commit/d07694c05d49166740f3408a343c351d33749edf))
78
+ - simplify release configuration by removing unnecessary package structure ([#40](https://github.com/janeapp/riffer/issues/40)) ([8472967](https://github.com/janeapp/riffer/commit/84729670fd202208256e6de69f1b81366ad0a688))
72
79
 
80
+ ## [0.2.0](https://github.com/janeapp/riffer/compare/v0.1.0...v0.2.0) (2025-12-28)
73
81
 
74
82
  ### Features
75
83
 
76
- * add release and publish workflows ([#35](https://github.com/bottrall/riffer/issues/35)) ([3eb0389](https://github.com/bottrall/riffer/commit/3eb03897d0e96c01ef1857c04b2bafa53e37dde0))
84
+ - add release and publish workflows ([#35](https://github.com/janeapp/riffer/issues/35)) ([3eb0389](https://github.com/janeapp/riffer/commit/3eb03897d0e96c01ef1857c04b2bafa53e37dde0))
77
85
 
78
86
  ## [0.1.0] - 2024-12-20
79
87
 
data/CLAUDE.md ADDED
@@ -0,0 +1,73 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ Riffer is a Ruby gem framework for building AI-powered applications and agents. It uses Zeitwerk for autoloading.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Install dependencies
13
+ bin/setup
14
+
15
+ # Run tests
16
+ bundle exec rake test
17
+
18
+ # Run a single test file
19
+ bundle exec ruby -Ilib:test test/riffer/agent_test.rb
20
+
21
+ # Run a specific test by name
22
+ bundle exec ruby -Ilib:test test/riffer/agent_test.rb --name "test_something"
23
+
24
+ # Check code style
25
+ bundle exec rake standard
26
+
27
+ # Auto-fix style issues
28
+ bundle exec rake standard:fix
29
+
30
+ # Run both tests and linting (default task)
31
+ bundle exec rake
32
+
33
+ # Interactive console
34
+ bin/console
35
+
36
+ # Generate documentation
37
+ bundle exec rake docs
38
+ ```
39
+
40
+ ## Architecture
41
+
42
+ ### Core Components
43
+
44
+ - **Agent** (`lib/riffer/agent.rb`): Base class for AI agents. Subclass and use DSL methods `model` and `instructions` to configure. Orchestrates message flow, LLM calls, and tool execution via a generate/stream loop.
45
+
46
+ - **Providers** (`lib/riffer/providers/`): Adapters for LLM APIs. Each provider extends `Riffer::Providers::Base` and implements `perform_generate_text` and `perform_stream_text`. Registered in `Repository` with identifier (e.g., `openai`).
47
+
48
+ - **Messages** (`lib/riffer/messages/`): Typed message objects (`System`, `User`, `Assistant`, `Tool`). All extend `Base`. The `Converter` module handles hash-to-object conversion.
49
+
50
+ - **StreamEvents** (`lib/riffer/stream_events/`): Structured events for streaming (`TextDelta`, `TextDone`).
51
+
52
+ ### Key Patterns
53
+
54
+ - Model strings use `provider/model` format (e.g., `openai/gpt-4`)
55
+ - Configuration via `Riffer.configure { |c| c.openai.api_key = "..." }`
56
+ - Providers use `depends_on` helper for runtime dependency checking
57
+ - Tests use VCR cassettes in `test/fixtures/vcr_cassettes/`
58
+
59
+ ### Adding a New Provider
60
+
61
+ 1. Create `lib/riffer/providers/your_provider.rb` extending `Riffer::Providers::Base`
62
+ 2. Implement `perform_generate_text(messages, model:)` returning `Riffer::Messages::Assistant`
63
+ 3. Implement `perform_stream_text(messages, model:)` returning an `Enumerator` yielding stream events
64
+ 4. Register in `Riffer::Providers::Repository::REPO`
65
+ 5. Add provider config to `Riffer::Config` if needed
66
+
67
+ ## Code Style
68
+
69
+ - Ruby 3.2+ required
70
+ - All files must have `# frozen_string_literal: true`
71
+ - StandardRB for formatting (double quotes, 2-space indent)
72
+ - Minitest with spec DSL for tests
73
+ - YARD-style documentation for public APIs
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2025 Jake Bottrall
3
+ Copyright (c) 2025 Jane Software Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -42,7 +42,7 @@ gem 'riffer'
42
42
  Install the development branch directly from GitHub:
43
43
 
44
44
  ```ruby
45
- gem 'riffer', git: 'https://github.com/bottrall/riffer.git'
45
+ gem 'riffer', git: 'https://github.com/janeapp/riffer.git'
46
46
  ```
47
47
 
48
48
  ## Quick Start
@@ -58,7 +58,6 @@ Riffer.configure do |config|
58
58
  end
59
59
 
60
60
  class EchoAgent < Riffer::Agent
61
- identifier 'echo'
62
61
  model 'openai/gpt-5-mini' # provider/model
63
62
  instructions 'You are an assistant that repeats what the user says.'
64
63
  end
@@ -110,7 +109,7 @@ bin/console
110
109
  2. Run tests and linters locally: `bundle exec rake`
111
110
  3. Submit a pull request with a clear description of the change
112
111
 
113
- Please follow the [Code of Conduct](https://github.com/bottrall/riffer/blob/main/CODE_OF_CONDUCT.md).
112
+ Please follow the [Code of Conduct](https://github.com/janeapp/riffer/blob/main/CODE_OF_CONDUCT.md).
114
113
 
115
114
  ## Changelog
116
115
 
data/lib/riffer/agent.rb CHANGED
@@ -11,13 +11,14 @@ class Riffer::Agent
11
11
  include Riffer::Messages::Converter
12
12
 
13
13
  class << self
14
+ include Riffer::Helpers::ClassNameConverter
14
15
  include Riffer::Helpers::Validations
15
16
 
16
17
  # Gets or sets the agent identifier
17
18
  # @param value [String, nil] the identifier to set, or nil to get
18
19
  # @return [String] the agent identifier
19
20
  def identifier(value = nil)
20
- return @identifier if value.nil?
21
+ return @identifier || class_name_to_path(name) if value.nil?
21
22
  @identifier = value.to_s
22
23
  end
23
24
 
@@ -39,6 +40,12 @@ class Riffer::Agent
39
40
  @instructions = instructions_text
40
41
  end
41
42
 
43
+ def reasoning(level = nil)
44
+ return @reasoning if level.nil?
45
+ validate_is_string!(level, "reasoning")
46
+ @reasoning = level
47
+ end
48
+
42
49
  # Finds an agent class by identifier
43
50
  # @param identifier [String] the identifier to search for
44
51
  # @return [Class, nil] the agent class, or nil if not found
@@ -64,6 +71,7 @@ class Riffer::Agent
64
71
  @messages = []
65
72
  @model_string = self.class.model
66
73
  @instructions_text = self.class.instructions
74
+ @reasoning = self.class.reasoning
67
75
 
68
76
  provider_name, model_name = @model_string.split("/", 2)
69
77
 
@@ -132,11 +140,11 @@ class Riffer::Agent
132
140
  end
133
141
 
134
142
  def call_llm
135
- provider_instance.generate_text(messages: @messages, model: @model_name)
143
+ provider_instance.generate_text(messages: @messages, model: @model_name, reasoning: @reasoning)
136
144
  end
137
145
 
138
146
  def call_llm_stream
139
- provider_instance.stream_text(messages: @messages, model: @model_name)
147
+ provider_instance.stream_text(messages: @messages, model: @model_name, reasoning: @reasoning)
140
148
  end
141
149
 
142
150
  def provider_instance
data/lib/riffer/config.rb CHANGED
@@ -6,14 +6,23 @@
6
6
  #
7
7
  # @example Setting the OpenAI API key
8
8
  # Riffer.config.openai.api_key = "sk-..."
9
+ #
10
+ # @example Setting Amazon Bedrock configuration
11
+ # Riffer.config.amazon_bedrock.region = "us-east-1"
12
+ # Riffer.config.amazon_bedrock.api_token = "..."
9
13
  class Riffer::Config
10
14
  # OpenAI configuration
11
15
  # @return [Struct]
12
16
  attr_reader :openai
13
17
 
18
+ # Amazon Bedrock configuration
19
+ # @return [Struct]
20
+ attr_reader :amazon_bedrock
21
+
14
22
  # Initializes the configuration
15
23
  # @return [void]
16
24
  def initialize
17
25
  @openai = Struct.new(:api_key).new
26
+ @amazon_bedrock = Struct.new(:api_token, :region).new
18
27
  end
19
28
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riffer::Helpers::ClassNameConverter
4
+ # Converts a class name to snake_case path format
5
+ # @param class_name [String] the class name (e.g., "Riffer::Agent")
6
+ # @return [String] the snake_case path (e.g., "riffer/agent")
7
+ def class_name_to_path(class_name)
8
+ class_name
9
+ .to_s
10
+ .gsub("::", "/")
11
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
12
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
13
+ .downcase
14
+ end
15
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
4
+ # Initializes the Amazon Bedrock provider.
5
+ #
6
+ # @param options [Hash] options passed to Aws::BedrockRuntime::Client
7
+ # @option options [String] :api_token Bearer token for API authentication (requires :region)
8
+ # @option options [String] :region AWS region
9
+ # @see https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/BedrockRuntime/Client.html
10
+ def initialize(api_token: nil, region: nil, **options)
11
+ depends_on "aws-sdk-bedrockruntime"
12
+
13
+ api_token ||= Riffer.config.amazon_bedrock.api_token
14
+ region ||= Riffer.config.amazon_bedrock.region
15
+
16
+ @client = if api_token && !api_token.empty?
17
+ Aws::BedrockRuntime::Client.new(
18
+ region: region,
19
+ token_provider: Aws::StaticTokenProvider.new(api_token),
20
+ auth_scheme_preference: ["httpBearerAuth"],
21
+ **options
22
+ )
23
+ else
24
+ Aws::BedrockRuntime::Client.new(region: region, **options)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def perform_generate_text(messages, model:, reasoning: nil)
31
+ partitioned_messages = partition_messages(messages)
32
+
33
+ params = {
34
+ model_id: model,
35
+ system: partitioned_messages[:system],
36
+ messages: partitioned_messages[:conversation]
37
+ }
38
+
39
+ response = @client.converse(**params)
40
+ extract_assistant_message(response)
41
+ end
42
+
43
+ def perform_stream_text(messages, model:, reasoning: nil)
44
+ Enumerator.new do |yielder|
45
+ partitioned_messages = partition_messages(messages)
46
+
47
+ params = {
48
+ model_id: model,
49
+ system: partitioned_messages[:system],
50
+ messages: partitioned_messages[:conversation]
51
+ }
52
+
53
+ accumulated_text = ""
54
+
55
+ @client.converse_stream(**params) do |stream|
56
+ stream.on_content_block_delta_event do |event|
57
+ if event.delta&.text
58
+ delta_text = event.delta.text
59
+ accumulated_text += delta_text
60
+ yielder << Riffer::StreamEvents::TextDelta.new(delta_text)
61
+ end
62
+ end
63
+
64
+ stream.on_message_stop_event do |_event|
65
+ yielder << Riffer::StreamEvents::TextDone.new(accumulated_text)
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def partition_messages(messages)
72
+ system_prompts = []
73
+ conversation_messages = []
74
+
75
+ messages.each do |message|
76
+ case message
77
+ when Riffer::Messages::System
78
+ system_prompts << {text: message.content}
79
+ when Riffer::Messages::User
80
+ conversation_messages << {role: "user", content: [{text: message.content}]}
81
+ when Riffer::Messages::Assistant
82
+ conversation_messages << {role: "assistant", content: [{text: message.content}]}
83
+ when Riffer::Messages::Tool
84
+ raise NotImplementedError, "Tool messages are not supported by Amazon Bedrock provider yet"
85
+ end
86
+ end
87
+
88
+ {
89
+ system: system_prompts,
90
+ conversation: conversation_messages
91
+ }
92
+ end
93
+
94
+ def extract_assistant_message(response)
95
+ output = response.output
96
+ raise Riffer::Error, "No output returned from Bedrock API" if output.nil? || output.message.nil?
97
+
98
+ content_blocks = output.message.content
99
+ raise Riffer::Error, "No content returned from Bedrock API" if content_blocks.nil? || content_blocks.empty?
100
+
101
+ text_block = content_blocks.find { |block| block.respond_to?(:text) && block.text }
102
+ raise Riffer::Error, "No text content returned from Bedrock API" if text_block.nil?
103
+
104
+ Riffer::Messages::Assistant.new(text_block.text)
105
+ end
106
+ end
@@ -10,12 +10,13 @@ class Riffer::Providers::Base
10
10
  # @param system [String, nil] an optional system message
11
11
  # @param messages [Array<Hash, Riffer::Messages::Base>, nil] optional messages array
12
12
  # @param model [String, nil] optional model string to override the configured model
13
+ # @param reasoning [String, nil] optional reasoning level or instructions
13
14
  # @return [Riffer::Messages::Assistant] the generated assistant message
14
- def generate_text(prompt: nil, system: nil, messages: nil, model: nil)
15
+ def generate_text(prompt: nil, system: nil, messages: nil, model: nil, reasoning: nil)
15
16
  validate_input!(prompt: prompt, system: system, messages: messages)
16
17
  normalized_messages = normalize_messages(prompt: prompt, system: system, messages: messages)
17
18
  validate_normalized_messages!(normalized_messages)
18
- perform_generate_text(normalized_messages, model: model)
19
+ perform_generate_text(normalized_messages, model: model, reasoning: reasoning)
19
20
  end
20
21
 
21
22
  # Streams text from the provider.
@@ -24,21 +25,22 @@ class Riffer::Providers::Base
24
25
  # @param system [String, nil] an optional system message
25
26
  # @param messages [Array<Hash, Riffer::Messages::Base>, nil] optional messages array
26
27
  # @param model [String, nil] optional model string to override the configured model
28
+ # @param reasoning [String, nil] optional reasoning level or instructions
27
29
  # @return [Enumerator] an enumerator yielding stream events or chunks (provider-specific)
28
- def stream_text(prompt: nil, system: nil, messages: nil, model: nil)
30
+ def stream_text(prompt: nil, system: nil, messages: nil, model: nil, reasoning: nil)
29
31
  validate_input!(prompt: prompt, system: system, messages: messages)
30
32
  normalized_messages = normalize_messages(prompt: prompt, system: system, messages: messages)
31
33
  validate_normalized_messages!(normalized_messages)
32
- perform_stream_text(normalized_messages, model: model)
34
+ perform_stream_text(normalized_messages, model: model, reasoning: reasoning)
33
35
  end
34
36
 
35
37
  private
36
38
 
37
- def perform_generate_text(messages, model: nil)
39
+ def perform_generate_text(messages, model: nil, reasoning: nil)
38
40
  raise NotImplementedError, "Subclasses must implement #perform_generate_text"
39
41
  end
40
42
 
41
- def perform_stream_text(messages, model: nil)
43
+ def perform_stream_text(messages, model: nil, reasoning: nil)
42
44
  raise NotImplementedError, "Subclasses must implement #perform_stream_text"
43
45
  end
44
46
 
@@ -17,8 +17,8 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
17
17
 
18
18
  private
19
19
 
20
- def perform_generate_text(messages, model:)
21
- params = build_request_params(messages, model)
20
+ def perform_generate_text(messages, model:, reasoning: nil)
21
+ params = build_request_params(messages, model, reasoning)
22
22
  response = @client.responses.create(params)
23
23
 
24
24
  output = response.output.find { |o| o.type == :message }
@@ -44,19 +44,23 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
44
44
  Riffer::Messages::Assistant.new(content.text)
45
45
  end
46
46
 
47
- def perform_stream_text(messages, model:)
47
+ def perform_stream_text(messages, model:, reasoning: nil)
48
48
  Enumerator.new do |yielder|
49
- params = build_request_params(messages, model)
49
+ params = build_request_params(messages, model, reasoning)
50
50
  stream = @client.responses.stream(params)
51
51
 
52
52
  process_stream_events(stream, yielder)
53
53
  end
54
54
  end
55
55
 
56
- def build_request_params(messages, model)
56
+ def build_request_params(messages, model, reasoning)
57
57
  {
58
+ input: convert_message_to_openai_format(messages),
58
59
  model: model,
59
- input: convert_message_to_openai_format(messages)
60
+ reasoning: reasoning && {
61
+ effort: reasoning,
62
+ summary: "auto"
63
+ }
60
64
  }
61
65
  end
62
66
 
@@ -91,6 +95,10 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
91
95
  Riffer::StreamEvents::TextDelta.new(event.delta)
92
96
  when :"response.output_text.done"
93
97
  Riffer::StreamEvents::TextDone.new(event.text)
98
+ when :"response.reasoning_summary_text.delta"
99
+ Riffer::StreamEvents::ReasoningDelta.new(event.delta)
100
+ when :"response.reasoning_summary_text.done"
101
+ Riffer::StreamEvents::ReasoningDone.new(event.text)
94
102
  end
95
103
  end
96
104
  end
@@ -1,6 +1,7 @@
1
1
  class Riffer::Providers::Repository
2
2
  REPO = {
3
3
  openai: -> { Riffer::Providers::OpenAI },
4
+ amazon_bedrock: -> { Riffer::Providers::AmazonBedrock },
4
5
  test: -> { Riffer::Providers::Test }
5
6
  }.freeze
6
7
 
@@ -8,16 +8,18 @@ class Riffer::Providers::Test < Riffer::Providers::Base
8
8
  @current_index = 0
9
9
  @calls = []
10
10
  @stubbed_response = nil
11
+ @stubbed_reasoning = nil
11
12
  end
12
13
 
13
- def stub_response(content, tool_calls: [])
14
+ def stub_response(content, tool_calls: [], reasoning: nil)
14
15
  @stubbed_response = {role: "assistant", content: content, tool_calls: tool_calls}
16
+ @stubbed_reasoning = reasoning
15
17
  end
16
18
 
17
19
  private
18
20
 
19
- def perform_generate_text(messages, model: nil)
20
- @calls << {messages: messages.map(&:to_h)}
21
+ def perform_generate_text(messages, model: nil, reasoning: nil)
22
+ @calls << {messages: messages.map(&:to_h), model: model, reasoning: reasoning}
21
23
  response = @stubbed_response || @responses[@current_index] || {role: "assistant", content: "Test response"}
22
24
  @current_index += 1
23
25
 
@@ -28,11 +30,21 @@ class Riffer::Providers::Test < Riffer::Providers::Base
28
30
  end
29
31
  end
30
32
 
31
- def perform_stream_text(messages, model: nil)
32
- @calls << {messages: messages.map(&:to_h)}
33
+ def perform_stream_text(messages, model: nil, reasoning: nil)
34
+ @calls << {messages: messages.map(&:to_h), model: model, reasoning: reasoning}
33
35
  response = @stubbed_response || @responses[@current_index] || {role: "assistant", content: "Test response"}
34
36
  @current_index += 1
35
37
  Enumerator.new do |yielder|
38
+ if @stubbed_reasoning
39
+ reasoning_parts = @stubbed_reasoning.split(". ").map { |part| part + (part.end_with?(".") ? "" : ".") }
40
+
41
+ reasoning_parts.each do |part|
42
+ yielder << Riffer::StreamEvents::ReasoningDelta.new(part + " ")
43
+ end
44
+
45
+ yielder << Riffer::StreamEvents::ReasoningDone.new(@stubbed_reasoning)
46
+ end
47
+
36
48
  full_content = response[:content]
37
49
  content_parts = full_content.split(". ").map { |part| part + (part.end_with?(".") ? "" : ".") }
38
50
 
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Riffer::StreamEvents::ReasoningDelta < Riffer::StreamEvents::Base
4
+ attr_reader :content
5
+
6
+ def initialize(content, role: "assistant")
7
+ super(role: role)
8
+ @content = content
9
+ end
10
+
11
+ def to_h
12
+ {role: @role, content: @content}
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Riffer::StreamEvents::ReasoningDone < Riffer::StreamEvents::Base
4
+ attr_reader :content
5
+
6
+ def initialize(content, role: "assistant")
7
+ super(role: role)
8
+ @content = content
9
+ end
10
+
11
+ def to_h
12
+ {role: @role, content: @content}
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Riffer
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riffer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jake Bottrall
@@ -29,20 +29,34 @@ dependencies:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
31
  version: 2.6.0
32
+ - !ruby/object:Gem::Dependency
33
+ name: aws-sdk-bedrockruntime
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '1.0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
32
46
  - !ruby/object:Gem::Dependency
33
47
  name: openai
34
48
  requirement: !ruby/object:Gem::Requirement
35
49
  requirements:
36
50
  - - "~>"
37
51
  - !ruby/object:Gem::Version
38
- version: 0.42.0
52
+ version: 0.43.0
39
53
  type: :development
40
54
  prerelease: false
41
55
  version_requirements: !ruby/object:Gem::Requirement
42
56
  requirements:
43
57
  - - "~>"
44
58
  - !ruby/object:Gem::Version
45
- version: 0.42.0
59
+ version: 0.43.0
46
60
  - !ruby/object:Gem::Dependency
47
61
  name: minitest
48
62
  requirement: !ruby/object:Gem::Requirement
@@ -130,6 +144,7 @@ files:
130
144
  - ".ruby-version"
131
145
  - ".standard.yml"
132
146
  - CHANGELOG.md
147
+ - CLAUDE.md
133
148
  - CODE_OF_CONDUCT.md
134
149
  - LICENSE.txt
135
150
  - README.md
@@ -138,6 +153,7 @@ files:
138
153
  - lib/riffer/agent.rb
139
154
  - lib/riffer/config.rb
140
155
  - lib/riffer/core.rb
156
+ - lib/riffer/helpers/class_name_converter.rb
141
157
  - lib/riffer/helpers/dependencies.rb
142
158
  - lib/riffer/helpers/validations.rb
143
159
  - lib/riffer/messages.rb
@@ -148,12 +164,15 @@ files:
148
164
  - lib/riffer/messages/tool.rb
149
165
  - lib/riffer/messages/user.rb
150
166
  - lib/riffer/providers.rb
167
+ - lib/riffer/providers/amazon_bedrock.rb
151
168
  - lib/riffer/providers/base.rb
152
169
  - lib/riffer/providers/open_ai.rb
153
170
  - lib/riffer/providers/repository.rb
154
171
  - lib/riffer/providers/test.rb
155
172
  - lib/riffer/stream_events.rb
156
173
  - lib/riffer/stream_events/base.rb
174
+ - lib/riffer/stream_events/reasoning_delta.rb
175
+ - lib/riffer/stream_events/reasoning_done.rb
157
176
  - lib/riffer/stream_events/text_delta.rb
158
177
  - lib/riffer/stream_events/text_done.rb
159
178
  - lib/riffer/version.rb
@@ -164,8 +183,8 @@ licenses:
164
183
  metadata:
165
184
  allowed_push_host: https://rubygems.org
166
185
  homepage_uri: https://riffer.ai
167
- source_code_uri: https://github.com/bottrall/riffer
168
- changelog_uri: https://github.com/bottrall/riffer/blob/main/CHANGELOG.md
186
+ source_code_uri: https://github.com/janeapp/riffer
187
+ changelog_uri: https://github.com/janeapp/riffer/blob/main/CHANGELOG.md
169
188
  rdoc_options:
170
189
  - "--main"
171
190
  - README.md