riffer 0.40.0 → 0.42.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 +4 -4
- data/{AGENTS.md → .claude/CLAUDE.md} +0 -8
- data/.claude/rules/comments.md +13 -0
- data/.claude/rules/rbs-inline.md +93 -0
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +22 -0
- data/README.md +20 -24
- data/docs/AGENTS.md +24 -14
- data/docs/AGENT_LIFECYCLE.md +2 -2
- data/docs/CONFIGURATION.md +105 -21
- data/docs/SERIALIZATION.md +4 -3
- data/docs/TOOLS.md +18 -1
- data/docs/providers/AMAZON_BEDROCK.md +14 -8
- data/docs/providers/ANTHROPIC.md +9 -7
- data/docs/providers/AZURE_OPENAI.md +12 -12
- data/docs/providers/CUSTOM_PROVIDERS.md +32 -16
- data/docs/providers/GEMINI.md +28 -5
- data/docs/providers/OPENAI.md +21 -5
- data/docs/providers/OPENROUTER.md +11 -6
- data/docs/providers/PROVIDERS.md +16 -1
- data/lib/riffer/agent/config.rb +0 -6
- data/lib/riffer/agent/run.rb +2 -4
- data/lib/riffer/agent/serializer.rb +0 -2
- data/lib/riffer/agent.rb +4 -26
- data/lib/riffer/config.rb +6 -6
- data/lib/riffer/evals/judge.rb +3 -5
- data/lib/riffer/guardrail.rb +1 -1
- data/lib/riffer/helpers/identifier.rb +41 -0
- data/lib/riffer/providers/amazon_bedrock.rb +31 -19
- data/lib/riffer/providers/anthropic.rb +23 -8
- data/lib/riffer/providers/azure_open_ai.rb +19 -11
- data/lib/riffer/providers/base.rb +32 -1
- data/lib/riffer/providers/gemini/client.rb +120 -0
- data/lib/riffer/providers/gemini.rb +13 -62
- data/lib/riffer/providers/mock.rb +5 -4
- data/lib/riffer/providers/open_ai.rb +23 -8
- data/lib/riffer/providers/open_router.rb +23 -9
- data/lib/riffer/registrable.rb +81 -0
- data/lib/riffer/tool.rb +1 -0
- data/lib/riffer/tools/toolable.rb +2 -3
- data/lib/riffer/version.rb +1 -1
- data/lib/riffer.rb +3 -0
- data/sig/_private/riffer/providers/amazon_bedrock.rbs +4 -2
- data/sig/_private/riffer/providers/anthropic.rbs +4 -2
- data/sig/_private/riffer/providers/gemini.rbs +7 -0
- data/sig/_private/riffer/providers/open_ai.rbs +4 -2
- data/sig/_private/riffer/providers/open_router.rbs +4 -2
- data/sig/generated/riffer/agent/config.rbs +1 -5
- data/sig/generated/riffer/agent.rbs +2 -18
- data/sig/generated/riffer/config.rbs +25 -15
- data/sig/generated/riffer/evals/judge.rbs +2 -4
- data/sig/generated/riffer/helpers/identifier.rbs +19 -0
- data/sig/generated/riffer/providers/amazon_bedrock.rbs +13 -2
- data/sig/generated/riffer/providers/anthropic.rbs +13 -2
- data/sig/generated/riffer/providers/azure_open_ai.rbs +14 -4
- data/sig/generated/riffer/providers/base.rbs +22 -0
- data/sig/generated/riffer/providers/gemini/client.rbs +65 -0
- data/sig/generated/riffer/providers/gemini.rbs +7 -23
- data/sig/generated/riffer/providers/mock.rbs +4 -3
- data/sig/generated/riffer/providers/open_ai.rbs +13 -2
- data/sig/generated/riffer/providers/open_router.rbs +16 -3
- data/sig/generated/riffer/registrable.rbs +51 -0
- data/sig/generated/riffer/tool.rbs +2 -0
- data/sig/generated/riffer/tools/toolable.rbs +3 -1
- data/sig/generated/riffer.rbs +4 -0
- data/sig/manual/riffer/agent.rbs +7 -0
- data/sig/manual/riffer/helpers/identifier.rbs +5 -0
- data/sig/manual/riffer/tool.rbs +7 -0
- metadata +14 -11
- data/.agents/architecture.md +0 -265
- data/.agents/code-style.md +0 -110
- data/.agents/providers.md +0 -45
- data/.agents/rbs-inline.md +0 -169
- data/.agents/testing.md +0 -60
- data/CLAUDE.md +0 -1
- data/lib/riffer/helpers/class_name_converter.rb +0 -22
- data/sig/generated/riffer/helpers/class_name_converter.rbs +0 -12
- data/sig/manual/riffer/helpers/class_name_converter.rbs +0 -5
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `client` is typed against the SDK, so this narrowing stays in _private (never ships)
|
|
2
2
|
class Riffer::Providers::AmazonBedrock
|
|
3
|
-
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def client: () -> ::Aws::BedrockRuntime::Client
|
|
4
6
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `client` is typed against the SDK, so this narrowing stays in _private (never ships)
|
|
2
2
|
class Riffer::Providers::Anthropic
|
|
3
|
-
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def client: () -> ::Anthropic::Client
|
|
4
6
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `client` is typed against the SDK, so this narrowing stays in _private (never ships)
|
|
2
2
|
class Riffer::Providers::OpenAI
|
|
3
|
-
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def client: () -> ::OpenAI::Client
|
|
4
6
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `client` is typed against the SDK, so this narrowing stays in _private (never ships)
|
|
2
2
|
class Riffer::Providers::OpenRouter
|
|
3
|
-
|
|
3
|
+
private
|
|
4
|
+
|
|
5
|
+
def client: () -> ::OpenAI::Client
|
|
4
6
|
end
|
|
@@ -15,9 +15,6 @@ class Riffer::Agent::Config
|
|
|
15
15
|
# The configured instructions.
|
|
16
16
|
attr_reader instructions: (String | Proc)?
|
|
17
17
|
|
|
18
|
-
# Options passed to the provider client.
|
|
19
|
-
attr_accessor provider_options: Hash[Symbol, untyped]
|
|
20
|
-
|
|
21
18
|
# Options passed to generate_text/stream_text.
|
|
22
19
|
attr_accessor model_options: Hash[Symbol, untyped]
|
|
23
20
|
|
|
@@ -49,7 +46,6 @@ class Riffer::Agent::Config
|
|
|
49
46
|
# ?identifier: String?,
|
|
50
47
|
# ?model: (String | Proc)?,
|
|
51
48
|
# ?instructions: (String | Proc)?,
|
|
52
|
-
# ?provider_options: Hash[Symbol, untyped],
|
|
53
49
|
# ?model_options: Hash[Symbol, untyped],
|
|
54
50
|
# ?structured_output: Riffer::Params?,
|
|
55
51
|
# ?max_steps: Numeric?,
|
|
@@ -59,7 +55,7 @@ class Riffer::Agent::Config
|
|
|
59
55
|
# ?skills_config: Riffer::Skills::Config?,
|
|
60
56
|
# ?guardrails: Hash[Symbol, Array[Hash[Symbol, untyped]]]
|
|
61
57
|
# ) -> void
|
|
62
|
-
def initialize: (?identifier: String?, ?model: (String | Proc)?, ?instructions: (String | Proc)?, ?
|
|
58
|
+
def initialize: (?identifier: String?, ?model: (String | Proc)?, ?instructions: (String | Proc)?, ?model_options: Hash[Symbol, untyped], ?structured_output: Riffer::Params?, ?max_steps: Numeric?, ?tools_config: (Array[singleton(Riffer::Tool)] | Proc)?, ?mcp_configs: Array[Hash[Symbol, untyped]], ?tool_runtime: singleton(Riffer::Tools::Runtime) | Riffer::Tools::Runtime | Proc, ?skills_config: Riffer::Skills::Config?, ?guardrails: Hash[Symbol, Array[Hash[Symbol, untyped]]]) -> void
|
|
63
59
|
|
|
64
60
|
# Sets +identifier+, coercing the value to String.
|
|
65
61
|
# --
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
# agent = MyAgent.new
|
|
12
12
|
# agent.generate('Hello!')
|
|
13
13
|
class Riffer::Agent
|
|
14
|
+
extend Riffer::Registrable
|
|
15
|
+
|
|
14
16
|
self.@config: Riffer::Agent::Config?
|
|
15
17
|
|
|
16
18
|
INTERRUPT_MAX_STEPS: Symbol
|
|
@@ -45,12 +47,6 @@ class Riffer::Agent
|
|
|
45
47
|
# : (?(String | Proc)?) -> (String | Proc)?
|
|
46
48
|
def self.instructions: (?(String | Proc)?) -> (String | Proc)?
|
|
47
49
|
|
|
48
|
-
# Gets or sets provider options passed to the provider client.
|
|
49
|
-
#
|
|
50
|
-
# --
|
|
51
|
-
# : (?Hash[Symbol, untyped]?) -> Hash[Symbol, untyped]
|
|
52
|
-
def self.provider_options: (?Hash[Symbol, untyped]?) -> Hash[Symbol, untyped]
|
|
53
|
-
|
|
54
50
|
# Gets or sets model options passed to generate_text/stream_text.
|
|
55
51
|
#
|
|
56
52
|
# --
|
|
@@ -110,18 +106,6 @@ class Riffer::Agent
|
|
|
110
106
|
# : () ?{ (Riffer::Skills::Config) [self: Riffer::Skills::Config] -> void } -> Riffer::Skills::Config?
|
|
111
107
|
def self.skills: () ?{ (Riffer::Skills::Config) [self: Riffer::Skills::Config] -> void } -> Riffer::Skills::Config?
|
|
112
108
|
|
|
113
|
-
# Finds an agent class by identifier.
|
|
114
|
-
#
|
|
115
|
-
# --
|
|
116
|
-
# : (String) -> singleton(Riffer::Agent)?
|
|
117
|
-
def self.find: (String) -> singleton(Riffer::Agent)?
|
|
118
|
-
|
|
119
|
-
# Returns all agent subclasses.
|
|
120
|
-
#
|
|
121
|
-
# --
|
|
122
|
-
# : () -> Array[singleton(Riffer::Agent)]
|
|
123
|
-
def self.all: () -> Array[singleton(Riffer::Agent)]
|
|
124
|
-
|
|
125
109
|
# Generates a response using a new agent instance.
|
|
126
110
|
# --
|
|
127
111
|
# : (?String?, ?files: Array[Hash[Symbol, untyped] | Riffer::Messages::FilePart]?, ?context: Hash[Symbol, untyped]?, ?tags: Hash[(String | Symbol), untyped]) -> Riffer::Agent::Response
|
|
@@ -7,15 +7,19 @@ class Riffer::Config
|
|
|
7
7
|
|
|
8
8
|
attr_accessor region(): untyped
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
attr_accessor client(): untyped
|
|
11
|
+
|
|
12
|
+
def self.new: (?untyped api_token, ?untyped region, ?untyped client) -> instance
|
|
13
|
+
| (?api_token: untyped, ?region: untyped, ?client: untyped) -> instance
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
class Anthropic < Struct[untyped]
|
|
15
17
|
attr_accessor api_key(): untyped
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
attr_accessor client(): untyped
|
|
20
|
+
|
|
21
|
+
def self.new: (?untyped api_key, ?untyped client) -> instance
|
|
22
|
+
| (?api_key: untyped, ?client: untyped) -> instance
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
class AzureOpenAI < Struct[untyped]
|
|
@@ -23,33 +27,39 @@ class Riffer::Config
|
|
|
23
27
|
|
|
24
28
|
attr_accessor endpoint(): untyped
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
attr_accessor client(): untyped
|
|
31
|
+
|
|
32
|
+
def self.new: (?untyped api_key, ?untyped endpoint, ?untyped client) -> instance
|
|
33
|
+
| (?api_key: untyped, ?endpoint: untyped, ?client: untyped) -> instance
|
|
28
34
|
end
|
|
29
35
|
|
|
30
36
|
class Gemini < Struct[untyped]
|
|
31
37
|
attr_accessor api_key(): untyped
|
|
32
38
|
|
|
33
|
-
attr_accessor
|
|
34
|
-
|
|
35
|
-
attr_accessor read_timeout(): untyped
|
|
39
|
+
attr_accessor client(): untyped
|
|
36
40
|
|
|
37
|
-
def self.new: (?untyped api_key, ?untyped
|
|
38
|
-
| (?api_key: untyped, ?
|
|
41
|
+
def self.new: (?untyped api_key, ?untyped client) -> instance
|
|
42
|
+
| (?api_key: untyped, ?client: untyped) -> instance
|
|
39
43
|
end
|
|
40
44
|
|
|
41
45
|
class OpenAI < Struct[untyped]
|
|
42
46
|
attr_accessor api_key(): untyped
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
attr_accessor base_url(): untyped
|
|
49
|
+
|
|
50
|
+
attr_accessor client(): untyped
|
|
51
|
+
|
|
52
|
+
def self.new: (?untyped api_key, ?untyped base_url, ?untyped client) -> instance
|
|
53
|
+
| (?api_key: untyped, ?base_url: untyped, ?client: untyped) -> instance
|
|
46
54
|
end
|
|
47
55
|
|
|
48
56
|
class OpenRouter < Struct[untyped]
|
|
49
57
|
attr_accessor api_key(): untyped
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
attr_accessor client(): untyped
|
|
60
|
+
|
|
61
|
+
def self.new: (?untyped api_key, ?untyped client) -> instance
|
|
62
|
+
| (?api_key: untyped, ?client: untyped) -> instance
|
|
53
63
|
end
|
|
54
64
|
|
|
55
65
|
class Evals < Struct[untyped]
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
# Executes LLM-as-judge evaluations, using tool calling internally to get
|
|
4
4
|
# structured output from the judge model.
|
|
5
5
|
class Riffer::Evals::Judge
|
|
6
|
-
@provider_options: Hash[Symbol, untyped]
|
|
7
|
-
|
|
8
6
|
@provider_instance: Riffer::Providers::Base?
|
|
9
7
|
|
|
10
8
|
@provider_name: String?
|
|
@@ -23,8 +21,8 @@ class Riffer::Evals::Judge
|
|
|
23
21
|
|
|
24
22
|
# Raises Riffer::ArgumentError unless +model+ is "provider/model" format.
|
|
25
23
|
# --
|
|
26
|
-
# : (model: String
|
|
27
|
-
def initialize: (model: String
|
|
24
|
+
# : (model: String) -> void
|
|
25
|
+
def initialize: (model: String) -> void
|
|
28
26
|
|
|
29
27
|
# Evaluates an input/output pair using the configured LLM.
|
|
30
28
|
# --
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Generated from lib/riffer/helpers/identifier.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
# Helper module for deriving snake_case identifiers from class names.
|
|
4
|
+
module Riffer::Helpers::Identifier
|
|
5
|
+
# Derives a snake_case identifier from a class name string.
|
|
6
|
+
#
|
|
7
|
+
# --
|
|
8
|
+
# : (String?) -> String
|
|
9
|
+
def derive: (String?) -> String
|
|
10
|
+
|
|
11
|
+
# Derives and memoizes the identifier for a class or module. Anonymous
|
|
12
|
+
# classes return "" without caching, so a class named later still derives its
|
|
13
|
+
# real identifier — a guard that must travel with the cache, so callers never
|
|
14
|
+
# memoize their own.
|
|
15
|
+
#
|
|
16
|
+
# --
|
|
17
|
+
# : (Module) -> String
|
|
18
|
+
def for: (Module) -> String
|
|
19
|
+
end
|
|
@@ -21,11 +21,22 @@ class Riffer::Providers::AmazonBedrock < Riffer::Providers::Base
|
|
|
21
21
|
def self.semconv_provider_name: () -> String
|
|
22
22
|
|
|
23
23
|
# --
|
|
24
|
-
# : (
|
|
25
|
-
def initialize: (
|
|
24
|
+
# : () -> void
|
|
25
|
+
def initialize: () -> void
|
|
26
26
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
|
+
# --
|
|
30
|
+
# : () -> untyped
|
|
31
|
+
def global_client: () -> untyped
|
|
32
|
+
|
|
33
|
+
# Compacted so an unset region stays absent: the AWS SDK resolves +AWS_REGION+
|
|
34
|
+
# and the shared config only for a missing argument, and raises
|
|
35
|
+
# +Aws::Errors::MissingRegionError+ on an explicit nil.
|
|
36
|
+
# --
|
|
37
|
+
# : () -> untyped
|
|
38
|
+
def build_client: () -> untyped
|
|
39
|
+
|
|
29
40
|
# --
|
|
30
41
|
# : (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
31
42
|
def build_request_params: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -19,11 +19,22 @@ class Riffer::Providers::Anthropic < Riffer::Providers::Base
|
|
|
19
19
|
def self.semconv_provider_name: () -> String
|
|
20
20
|
|
|
21
21
|
# --
|
|
22
|
-
# : (
|
|
23
|
-
def initialize: (
|
|
22
|
+
# : () -> void
|
|
23
|
+
def initialize: () -> void
|
|
24
24
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
|
+
# --
|
|
28
|
+
# : () -> untyped
|
|
29
|
+
def global_client: () -> untyped
|
|
30
|
+
|
|
31
|
+
# Compacted for the same reason as the other providers: never hand an SDK an
|
|
32
|
+
# explicit nil credential, so its own +ANTHROPIC_API_KEY+ resolution stays
|
|
33
|
+
# reachable regardless of how that SDK distinguishes nil from absent.
|
|
34
|
+
# --
|
|
35
|
+
# : () -> untyped
|
|
36
|
+
def build_client: () -> untyped
|
|
37
|
+
|
|
27
38
|
# --
|
|
28
39
|
# : (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
29
40
|
def build_request_params: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
# Generated from lib/riffer/providers/azure_open_ai.rb with RBS::Inline
|
|
2
2
|
|
|
3
3
|
# Azure OpenAI provider for GPT models hosted on Azure. Requires the +openai+
|
|
4
|
-
# gem. Credentials resolve from
|
|
5
|
-
# +
|
|
4
|
+
# gem. Credentials resolve from config, then +AZURE_OPENAI_API_KEY+ /
|
|
5
|
+
# +AZURE_OPENAI_ENDPOINT+.
|
|
6
6
|
class Riffer::Providers::AzureOpenAI < Riffer::Providers::OpenAI
|
|
7
7
|
# The GenAI semconv well-known provider name.
|
|
8
8
|
# --
|
|
9
9
|
# : () -> String
|
|
10
10
|
def self.semconv_provider_name: () -> String
|
|
11
11
|
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# --
|
|
15
|
+
# : () -> untyped
|
|
16
|
+
def global_client: () -> untyped
|
|
17
|
+
|
|
18
|
+
# Deliberately not compacted: this borrows the OpenAI SDK to talk to Azure, so
|
|
19
|
+
# omitting an unset argument would let the SDK fall back to +OPENAI_API_KEY+
|
|
20
|
+
# and +OPENAI_BASE_URL+ — sending Azure traffic, and an OpenAI credential, to
|
|
21
|
+
# whatever those name. Passing nil raises in the SDK instead.
|
|
12
22
|
# --
|
|
13
|
-
# : (
|
|
14
|
-
def
|
|
23
|
+
# : () -> untyped
|
|
24
|
+
def build_client: () -> untyped
|
|
15
25
|
end
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
# +extract_token_usage+, +extract_content+, +extract_tool_calls+) and the base
|
|
6
6
|
# class orchestrates them.
|
|
7
7
|
class Riffer::Providers::Base
|
|
8
|
+
self.@semconv_provider_name: String?
|
|
9
|
+
|
|
10
|
+
@client: untyped
|
|
11
|
+
|
|
8
12
|
@current_model: String?
|
|
9
13
|
|
|
10
14
|
@current_tools: Array[singleton(Riffer::Tool)]
|
|
@@ -42,6 +46,24 @@ class Riffer::Providers::Base
|
|
|
42
46
|
# : (String) -> true
|
|
43
47
|
def depends_on: (String) -> true
|
|
44
48
|
|
|
49
|
+
# Returns the client for the current LLM call. A configured client wins,
|
|
50
|
+
# resolved on every call so a Proc can vary the client by process or
|
|
51
|
+
# credential lifetime; otherwise the provider builds one from the configured
|
|
52
|
+
# credentials, memoized for the life of the provider.
|
|
53
|
+
# --
|
|
54
|
+
# : () -> untyped
|
|
55
|
+
def client: () -> untyped
|
|
56
|
+
|
|
57
|
+
# Returns the consumer-configured client for this provider; nil when none is
|
|
58
|
+
# configured, and for providers that take no configuration at all.
|
|
59
|
+
# --
|
|
60
|
+
# : () -> untyped
|
|
61
|
+
def global_client: () -> untyped
|
|
62
|
+
|
|
63
|
+
# --
|
|
64
|
+
# : () -> untyped
|
|
65
|
+
def build_client: () -> untyped
|
|
66
|
+
|
|
45
67
|
# --
|
|
46
68
|
# : (String) -> String
|
|
47
69
|
def encode_tool_name: (String) -> String
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Generated from lib/riffer/providers/gemini/client.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
# HTTP transport for the Gemini REST API. Riffer builds one from the
|
|
4
|
+
# configured +api_key+ by default; construct your own to tune the HTTP knobs
|
|
5
|
+
# and assign it to <tt>Riffer.config.gemini.client</tt>. Any object
|
|
6
|
+
# implementing +post+ and +post_stream+ with these contracts works there —
|
|
7
|
+
# the class is a default implementation, not a required base.
|
|
8
|
+
#
|
|
9
|
+
# Riffer.configure do |config|
|
|
10
|
+
# config.gemini.client = Riffer::Providers::Gemini::Client.new(
|
|
11
|
+
# api_key: ENV["GEMINI_API_KEY"],
|
|
12
|
+
# read_timeout: 120
|
|
13
|
+
# )
|
|
14
|
+
# end
|
|
15
|
+
class Riffer::Providers::Gemini::Client
|
|
16
|
+
@proxy_port: Integer?
|
|
17
|
+
|
|
18
|
+
@proxy_address: String?
|
|
19
|
+
|
|
20
|
+
@write_timeout: Integer?
|
|
21
|
+
|
|
22
|
+
@read_timeout: Integer
|
|
23
|
+
|
|
24
|
+
@open_timeout: Integer
|
|
25
|
+
|
|
26
|
+
@base_url: String
|
|
27
|
+
|
|
28
|
+
@api_key: String?
|
|
29
|
+
|
|
30
|
+
DEFAULT_BASE_URL: String
|
|
31
|
+
|
|
32
|
+
DEFAULT_OPEN_TIMEOUT: Integer
|
|
33
|
+
|
|
34
|
+
DEFAULT_READ_TIMEOUT: Integer
|
|
35
|
+
|
|
36
|
+
# : (?api_key: String?, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer?, ?proxy_address: String?, ?proxy_port: Integer?) -> void
|
|
37
|
+
def initialize: (?api_key: String?, ?base_url: String, ?open_timeout: Integer, ?read_timeout: Integer, ?write_timeout: Integer?, ?proxy_address: String?, ?proxy_port: Integer?) -> void
|
|
38
|
+
|
|
39
|
+
# POSTs a JSON body to an API path and returns the parsed response hash.
|
|
40
|
+
# Raises Riffer::Error when the API responds with a non-success status.
|
|
41
|
+
# --
|
|
42
|
+
# : (String, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
43
|
+
def post: (String, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
44
|
+
|
|
45
|
+
# POSTs a JSON body to an API path, yielding raw response body chunks as
|
|
46
|
+
# they arrive. Raises Riffer::Error when the API responds with a
|
|
47
|
+
# non-success status.
|
|
48
|
+
# --
|
|
49
|
+
# : (String, Hash[Symbol, untyped]) { (String) -> void } -> void
|
|
50
|
+
def post_stream: (String, Hash[Symbol, untyped]) { (String) -> void } -> void
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# --
|
|
55
|
+
# : (URI::Generic, Hash[Symbol, untyped]) -> Net::HTTP::Post
|
|
56
|
+
def build_request: (URI::Generic, Hash[Symbol, untyped]) -> Net::HTTP::Post
|
|
57
|
+
|
|
58
|
+
# --
|
|
59
|
+
# : [R] (URI::Generic) { (Net::HTTP) -> R } -> R
|
|
60
|
+
def start_http: [R] (URI::Generic) { (Net::HTTP) -> R } -> R
|
|
61
|
+
|
|
62
|
+
# --
|
|
63
|
+
# : (Net::HTTPResponse) -> void
|
|
64
|
+
def handle_api_error!: (Net::HTTPResponse) -> void
|
|
65
|
+
end
|
|
@@ -2,20 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
# Google Gemini provider for Gemini models via the Gemini REST API.
|
|
4
4
|
class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
5
|
-
@read_timeout: Integer
|
|
6
|
-
|
|
7
|
-
@open_timeout: Integer
|
|
8
|
-
|
|
9
|
-
@api_key: String?
|
|
10
|
-
|
|
11
|
-
BASE_URI: URI::Generic
|
|
12
|
-
|
|
13
5
|
VALID_MODEL_PATTERN: Regexp
|
|
14
6
|
|
|
15
|
-
DEFAULT_OPEN_TIMEOUT: Integer
|
|
16
|
-
|
|
17
|
-
DEFAULT_READ_TIMEOUT: Integer
|
|
18
|
-
|
|
19
7
|
FINISH_REASONS: Hash[String, Symbol]
|
|
20
8
|
|
|
21
9
|
# The GenAI semconv well-known provider name.
|
|
@@ -23,11 +11,15 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
23
11
|
# : () -> String
|
|
24
12
|
def self.semconv_provider_name: () -> String
|
|
25
13
|
|
|
14
|
+
private
|
|
15
|
+
|
|
26
16
|
# --
|
|
27
|
-
# : (
|
|
28
|
-
def
|
|
17
|
+
# : () -> untyped
|
|
18
|
+
def global_client: () -> untyped
|
|
29
19
|
|
|
30
|
-
|
|
20
|
+
# --
|
|
21
|
+
# : () -> untyped
|
|
22
|
+
def build_client: () -> untyped
|
|
31
23
|
|
|
32
24
|
# --
|
|
33
25
|
# : (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -89,10 +81,6 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
89
81
|
# : (untyped) -> String
|
|
90
82
|
def encode_tool_arguments: (untyped) -> String
|
|
91
83
|
|
|
92
|
-
# --
|
|
93
|
-
# : (String, Hash[Symbol, untyped]) -> Net::HTTPResponse
|
|
94
|
-
def post_request: (String, Hash[Symbol, untyped]) -> Net::HTTPResponse
|
|
95
|
-
|
|
96
84
|
# --
|
|
97
85
|
# : (String, String) -> String
|
|
98
86
|
def api_path: (String, String) -> String
|
|
@@ -104,8 +92,4 @@ class Riffer::Providers::Gemini < Riffer::Providers::Base
|
|
|
104
92
|
# --
|
|
105
93
|
# : (Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
106
94
|
def strip_additional_properties: (Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
107
|
-
|
|
108
|
-
# --
|
|
109
|
-
# : (Net::HTTPResponse) -> void
|
|
110
|
-
def handle_api_error!: (Net::HTTPResponse) -> void
|
|
111
95
|
end
|
|
@@ -23,7 +23,8 @@ class Riffer::Providers::Mock < Riffer::Providers::Base
|
|
|
23
23
|
attr_reader calls: Array[Hash[Symbol, untyped]]
|
|
24
24
|
|
|
25
25
|
# +responses:+ pre-configures canned responses (same shape as
|
|
26
|
-
# +#stub_response+)
|
|
26
|
+
# +#stub_response+) for standalone use; agent tests queue responses on
|
|
27
|
+
# <tt>agent.provider</tt> via +#stub_response+ instead.
|
|
27
28
|
#
|
|
28
29
|
# Riffer::Providers::Mock.new(responses: [
|
|
29
30
|
# {content: "", tool_calls: [{name: "tool_a", arguments: "{}"}]},
|
|
@@ -31,8 +32,8 @@ class Riffer::Providers::Mock < Riffer::Providers::Base
|
|
|
31
32
|
# ])
|
|
32
33
|
#
|
|
33
34
|
# --
|
|
34
|
-
# : (
|
|
35
|
-
def initialize: (
|
|
35
|
+
# : (?responses: Array[Hash[Symbol, untyped]]) -> void
|
|
36
|
+
def initialize: (?responses: Array[Hash[Symbol, untyped]]) -> void
|
|
36
37
|
|
|
37
38
|
# Stubs the next response; call repeatedly to queue several. +finish_reason+
|
|
38
39
|
# defaults to +:tool_calls+ when tool calls are present, else +:stop+.
|
|
@@ -10,11 +10,22 @@ class Riffer::Providers::OpenAI < Riffer::Providers::Base
|
|
|
10
10
|
def self.semconv_provider_name: () -> String
|
|
11
11
|
|
|
12
12
|
# --
|
|
13
|
-
# : (
|
|
14
|
-
def initialize: (
|
|
13
|
+
# : () -> void
|
|
14
|
+
def initialize: () -> void
|
|
15
15
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
|
+
# --
|
|
19
|
+
# : () -> untyped
|
|
20
|
+
def global_client: () -> untyped
|
|
21
|
+
|
|
22
|
+
# Compacted so an unset value stays absent: the SDK reads +OPENAI_API_KEY+ /
|
|
23
|
+
# +OPENAI_BASE_URL+ only for a missing argument, and an explicit nil would
|
|
24
|
+
# suppress that fallback.
|
|
25
|
+
# --
|
|
26
|
+
# : () -> untyped
|
|
27
|
+
def build_client: () -> untyped
|
|
28
|
+
|
|
18
29
|
# --
|
|
19
30
|
# : (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
20
31
|
def build_request_params: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# OpenRouter provider (https://openrouter.ai). Requires the +openai+ gem —
|
|
4
4
|
# OpenRouter exposes an OpenAI-compatible endpoint, so this reuses the OpenAI
|
|
5
|
-
# SDK with a +base_url+ override. +api_key+
|
|
5
|
+
# SDK with a +base_url+ override. +api_key+ resolves from config, then
|
|
6
6
|
# +OPENROUTER_API_KEY+.
|
|
7
7
|
class Riffer::Providers::OpenRouter < Riffer::Providers::Base
|
|
8
8
|
BASE_URL: String
|
|
@@ -15,11 +15,24 @@ class Riffer::Providers::OpenRouter < Riffer::Providers::Base
|
|
|
15
15
|
def self.semconv_provider_name: () -> String
|
|
16
16
|
|
|
17
17
|
# --
|
|
18
|
-
# : (
|
|
19
|
-
def initialize: (
|
|
18
|
+
# : () -> void
|
|
19
|
+
def initialize: () -> void
|
|
20
20
|
|
|
21
21
|
private
|
|
22
22
|
|
|
23
|
+
# --
|
|
24
|
+
# : () -> untyped
|
|
25
|
+
def global_client: () -> untyped
|
|
26
|
+
|
|
27
|
+
# Deliberately not compacted: this borrows the OpenAI SDK to talk to a
|
|
28
|
+
# different vendor, so omitting an unset +api_key+ would let the SDK fall
|
|
29
|
+
# back to +OPENAI_API_KEY+ and send an OpenAI credential to OpenRouter.
|
|
30
|
+
# Passing nil raises in the SDK instead. +OPENROUTER_API_KEY+ is read here
|
|
31
|
+
# rather than left to the SDK for the same reason.
|
|
32
|
+
# --
|
|
33
|
+
# : () -> untyped
|
|
34
|
+
def build_client: () -> untyped
|
|
35
|
+
|
|
23
36
|
# --
|
|
24
37
|
# : (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
25
38
|
def build_request_params: (Array[Riffer::Messages::Base], String?, Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Generated from lib/riffer/registrable.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
# Registry of a class's named direct subclasses, keyed by identifier. Extend it
|
|
4
|
+
# onto a base class to look up subclasses in constant time via +find+ and +all+.
|
|
5
|
+
#
|
|
6
|
+
# class Riffer::Tool
|
|
7
|
+
# extend Riffer::Registrable
|
|
8
|
+
# end
|
|
9
|
+
#
|
|
10
|
+
# Riffer::Tool.find("weather_tool") # => WeatherTool
|
|
11
|
+
#
|
|
12
|
+
# @rbs module-self Class
|
|
13
|
+
module Riffer::Registrable : Class
|
|
14
|
+
@identifier_registry: Hash[String, Class]?
|
|
15
|
+
|
|
16
|
+
# Finds a registered subclass by identifier, or +nil+ when none matches.
|
|
17
|
+
# Only *named direct* subclasses are registered: grandchildren are not
|
|
18
|
+
# visible to a grandparent's +find+ (call +find+ on their direct parent
|
|
19
|
+
# instead), anonymous classes are never registered, and duplicate identifiers
|
|
20
|
+
# raise Riffer::DuplicateIdentifierError at first lookup.
|
|
21
|
+
#
|
|
22
|
+
# --
|
|
23
|
+
# : (String | Symbol) -> Class?
|
|
24
|
+
def find: (String | Symbol) -> Class?
|
|
25
|
+
|
|
26
|
+
# Returns all registered subclasses. Only *named direct* subclasses are
|
|
27
|
+
# registered: grandchildren are not included (call +all+ on their direct
|
|
28
|
+
# parent instead), anonymous classes are never registered, and duplicate
|
|
29
|
+
# identifiers raise Riffer::DuplicateIdentifierError at first lookup.
|
|
30
|
+
#
|
|
31
|
+
# --
|
|
32
|
+
# : () -> Array[Class]
|
|
33
|
+
def all: () -> Array[Class]
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# Ruby invokes +inherited+ with +self+ bound to the direct superclass — the
|
|
38
|
+
# only registry the new subclass joins — so busting self's memo is exactly
|
|
39
|
+
# sufficient.
|
|
40
|
+
# --
|
|
41
|
+
# : (Class) -> void
|
|
42
|
+
def inherited: (Class) -> void
|
|
43
|
+
|
|
44
|
+
# --
|
|
45
|
+
# : () -> Hash[String, Class]
|
|
46
|
+
def identifier_registry: () -> Hash[String, Class]
|
|
47
|
+
|
|
48
|
+
# --
|
|
49
|
+
# : () -> Hash[String, Class]
|
|
50
|
+
def build_identifier_registry: () -> Hash[String, Class]
|
|
51
|
+
end
|
data/sig/generated/riffer.rbs
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# `Riffer::Agent` extends `Riffer::Registrable`, whose generic signatures return
|
|
2
|
+
# `Class`. Narrow them here so callers get the agent singleton type back.
|
|
3
|
+
class Riffer::Agent
|
|
4
|
+
def self.find: (String | Symbol) -> singleton(Riffer::Agent)?
|
|
5
|
+
|
|
6
|
+
def self.all: () -> Array[singleton(Riffer::Agent)]
|
|
7
|
+
end
|