riffer 0.7.0 → 0.9.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/architecture.md +113 -0
- data/.agents/code-style.md +42 -0
- data/.agents/providers.md +46 -0
- data/.agents/rdoc.md +51 -0
- data/.agents/testing.md +56 -0
- data/.release-please-manifest.json +1 -1
- data/AGENTS.md +21 -308
- data/CHANGELOG.md +17 -0
- data/README.md +21 -112
- data/Rakefile +1 -1
- data/docs/01_OVERVIEW.md +106 -0
- data/docs/02_GETTING_STARTED.md +128 -0
- data/docs/03_AGENTS.md +226 -0
- data/docs/04_TOOLS.md +342 -0
- data/docs/05_MESSAGES.md +173 -0
- data/docs/06_STREAM_EVENTS.md +191 -0
- data/docs/07_CONFIGURATION.md +195 -0
- data/docs_providers/01_PROVIDERS.md +168 -0
- data/docs_providers/02_AMAZON_BEDROCK.md +196 -0
- data/docs_providers/03_ANTHROPIC.md +211 -0
- data/docs_providers/04_OPENAI.md +157 -0
- data/docs_providers/05_TEST_PROVIDER.md +163 -0
- data/docs_providers/06_CUSTOM_PROVIDERS.md +304 -0
- data/lib/riffer/agent.rb +103 -63
- data/lib/riffer/config.rb +20 -12
- data/lib/riffer/core.rb +7 -7
- data/lib/riffer/helpers/class_name_converter.rb +6 -3
- data/lib/riffer/helpers/dependencies.rb +18 -0
- data/lib/riffer/helpers/validations.rb +9 -0
- data/lib/riffer/messages/assistant.rb +23 -1
- data/lib/riffer/messages/base.rb +15 -0
- data/lib/riffer/messages/converter.rb +15 -5
- data/lib/riffer/messages/system.rb +8 -1
- data/lib/riffer/messages/tool.rb +45 -2
- data/lib/riffer/messages/user.rb +8 -1
- data/lib/riffer/messages.rb +7 -0
- data/lib/riffer/providers/amazon_bedrock.rb +8 -4
- data/lib/riffer/providers/anthropic.rb +209 -0
- data/lib/riffer/providers/base.rb +17 -12
- data/lib/riffer/providers/open_ai.rb +7 -1
- data/lib/riffer/providers/repository.rb +9 -4
- data/lib/riffer/providers/test.rb +25 -7
- data/lib/riffer/providers.rb +6 -0
- data/lib/riffer/stream_events/base.rb +13 -1
- data/lib/riffer/stream_events/reasoning_delta.rb +15 -1
- data/lib/riffer/stream_events/reasoning_done.rb +15 -1
- data/lib/riffer/stream_events/text_delta.rb +14 -1
- data/lib/riffer/stream_events/text_done.rb +14 -1
- data/lib/riffer/stream_events/tool_call_delta.rb +18 -11
- data/lib/riffer/stream_events/tool_call_done.rb +22 -12
- data/lib/riffer/stream_events.rb +9 -0
- data/lib/riffer/tool.rb +92 -25
- data/lib/riffer/tools/param.rb +19 -16
- data/lib/riffer/tools/params.rb +28 -22
- data/lib/riffer/tools/response.rb +90 -0
- data/lib/riffer/tools.rb +6 -0
- data/lib/riffer/version.rb +1 -1
- data/lib/riffer.rb +21 -21
- metadata +35 -1
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Base class for all streaming events in the Riffer framework.
|
|
4
|
+
#
|
|
5
|
+
# Subclasses must implement the +to_h+ method.
|
|
3
6
|
class Riffer::StreamEvents::Base
|
|
7
|
+
# The message role (typically :assistant).
|
|
8
|
+
#
|
|
9
|
+
# Returns Symbol.
|
|
4
10
|
attr_reader :role
|
|
5
11
|
|
|
6
|
-
|
|
12
|
+
# Creates a new stream event.
|
|
13
|
+
#
|
|
14
|
+
# role:: Symbol - the message role (defaults to :assistant)
|
|
15
|
+
def initialize(role: :assistant)
|
|
7
16
|
@role = role
|
|
8
17
|
end
|
|
9
18
|
|
|
19
|
+
# Converts the event to a hash.
|
|
20
|
+
#
|
|
21
|
+
# Raises NotImplementedError if not implemented by subclass.
|
|
10
22
|
def to_h
|
|
11
23
|
raise NotImplementedError, "Subclasses must implement #to_h"
|
|
12
24
|
end
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Represents an incremental reasoning chunk during streaming.
|
|
4
|
+
#
|
|
5
|
+
# Emitted when the LLM produces reasoning/thinking content incrementally.
|
|
6
|
+
# Only available with providers that support reasoning (e.g., OpenAI with reasoning option).
|
|
3
7
|
class Riffer::StreamEvents::ReasoningDelta < Riffer::StreamEvents::Base
|
|
8
|
+
# The incremental reasoning content.
|
|
9
|
+
#
|
|
10
|
+
# Returns String.
|
|
4
11
|
attr_reader :content
|
|
5
12
|
|
|
6
|
-
|
|
13
|
+
# Creates a new reasoning delta event.
|
|
14
|
+
#
|
|
15
|
+
# content:: String - the incremental reasoning content
|
|
16
|
+
# role:: Symbol - the message role (defaults to :assistant)
|
|
17
|
+
def initialize(content, role: :assistant)
|
|
7
18
|
super(role: role)
|
|
8
19
|
@content = content
|
|
9
20
|
end
|
|
10
21
|
|
|
22
|
+
# Converts the event to a hash.
|
|
23
|
+
#
|
|
24
|
+
# Returns Hash with +:role+ and +:content+ keys.
|
|
11
25
|
def to_h
|
|
12
26
|
{role: @role, content: @content}
|
|
13
27
|
end
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Represents completion of reasoning during streaming.
|
|
4
|
+
#
|
|
5
|
+
# Emitted when the LLM has finished producing reasoning/thinking content.
|
|
6
|
+
# Only available with providers that support reasoning (e.g., OpenAI with reasoning option).
|
|
3
7
|
class Riffer::StreamEvents::ReasoningDone < Riffer::StreamEvents::Base
|
|
8
|
+
# The complete reasoning content.
|
|
9
|
+
#
|
|
10
|
+
# Returns String.
|
|
4
11
|
attr_reader :content
|
|
5
12
|
|
|
6
|
-
|
|
13
|
+
# Creates a new reasoning done event.
|
|
14
|
+
#
|
|
15
|
+
# content:: String - the complete reasoning content
|
|
16
|
+
# role:: Symbol - the message role (defaults to :assistant)
|
|
17
|
+
def initialize(content, role: :assistant)
|
|
7
18
|
super(role: role)
|
|
8
19
|
@content = content
|
|
9
20
|
end
|
|
10
21
|
|
|
22
|
+
# Converts the event to a hash.
|
|
23
|
+
#
|
|
24
|
+
# Returns Hash with +:role+ and +:content+ keys.
|
|
11
25
|
def to_h
|
|
12
26
|
{role: @role, content: @content}
|
|
13
27
|
end
|
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Represents an incremental text chunk during streaming.
|
|
4
|
+
#
|
|
5
|
+
# Emitted when the LLM produces text content incrementally.
|
|
3
6
|
class Riffer::StreamEvents::TextDelta < Riffer::StreamEvents::Base
|
|
7
|
+
# The incremental text content.
|
|
8
|
+
#
|
|
9
|
+
# Returns String.
|
|
4
10
|
attr_reader :content
|
|
5
11
|
|
|
6
|
-
|
|
12
|
+
# Creates a new text delta event.
|
|
13
|
+
#
|
|
14
|
+
# content:: String - the incremental text content
|
|
15
|
+
# role:: Symbol - the message role (defaults to :assistant)
|
|
16
|
+
def initialize(content, role: :assistant)
|
|
7
17
|
super(role: role)
|
|
8
18
|
@content = content
|
|
9
19
|
end
|
|
10
20
|
|
|
21
|
+
# Converts the event to a hash.
|
|
22
|
+
#
|
|
23
|
+
# Returns Hash with +:role+ and +:content+ keys.
|
|
11
24
|
def to_h
|
|
12
25
|
{role: @role, content: @content}
|
|
13
26
|
end
|
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Represents completion of text generation during streaming.
|
|
4
|
+
#
|
|
5
|
+
# Emitted when the LLM has finished producing text content.
|
|
3
6
|
class Riffer::StreamEvents::TextDone < Riffer::StreamEvents::Base
|
|
7
|
+
# The complete text content.
|
|
8
|
+
#
|
|
9
|
+
# Returns String.
|
|
4
10
|
attr_reader :content
|
|
5
11
|
|
|
6
|
-
|
|
12
|
+
# Creates a new text done event.
|
|
13
|
+
#
|
|
14
|
+
# content:: String - the complete text content
|
|
15
|
+
# role:: Symbol - the message role (defaults to :assistant)
|
|
16
|
+
def initialize(content, role: :assistant)
|
|
7
17
|
super(role: role)
|
|
8
18
|
@content = content
|
|
9
19
|
end
|
|
10
20
|
|
|
21
|
+
# Converts the event to a hash.
|
|
22
|
+
#
|
|
23
|
+
# Returns Hash with +:role+ and +:content+ keys.
|
|
11
24
|
def to_h
|
|
12
25
|
{role: @role, content: @content}
|
|
13
26
|
end
|
|
@@ -3,25 +3,32 @@
|
|
|
3
3
|
# Riffer::StreamEvents::ToolCallDelta represents an incremental tool call chunk during streaming.
|
|
4
4
|
#
|
|
5
5
|
# Emitted when the LLM is building a tool call, containing partial argument data.
|
|
6
|
-
#
|
|
7
|
-
# @api public
|
|
8
6
|
class Riffer::StreamEvents::ToolCallDelta < Riffer::StreamEvents::Base
|
|
9
|
-
|
|
7
|
+
# The tool call item identifier.
|
|
8
|
+
attr_reader :item_id
|
|
9
|
+
|
|
10
|
+
# The tool name (may only be present in first delta).
|
|
11
|
+
attr_reader :name
|
|
12
|
+
|
|
13
|
+
# The incremental arguments JSON fragment.
|
|
14
|
+
attr_reader :arguments_delta
|
|
10
15
|
|
|
11
|
-
# Creates a new tool call delta event
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
|
|
16
|
+
# Creates a new tool call delta event.
|
|
17
|
+
#
|
|
18
|
+
# item_id:: String - the tool call item identifier
|
|
19
|
+
# name:: String or nil - the tool name (may only be present in first delta)
|
|
20
|
+
# arguments_delta:: String - the incremental arguments JSON fragment
|
|
21
|
+
# role:: Symbol - the message role (defaults to :assistant)
|
|
22
|
+
def initialize(item_id:, arguments_delta:, name: nil, role: :assistant)
|
|
17
23
|
super(role: role)
|
|
18
24
|
@item_id = item_id
|
|
19
25
|
@name = name
|
|
20
26
|
@arguments_delta = arguments_delta
|
|
21
27
|
end
|
|
22
28
|
|
|
23
|
-
# Converts the event to a hash
|
|
24
|
-
#
|
|
29
|
+
# Converts the event to a hash.
|
|
30
|
+
#
|
|
31
|
+
# Returns Hash - the event data.
|
|
25
32
|
def to_h
|
|
26
33
|
{role: @role, item_id: @item_id, name: @name, arguments_delta: @arguments_delta}.compact
|
|
27
34
|
end
|
|
@@ -3,18 +3,27 @@
|
|
|
3
3
|
# Riffer::StreamEvents::ToolCallDone represents a completed tool call during streaming.
|
|
4
4
|
#
|
|
5
5
|
# Emitted when the LLM has finished building a tool call with complete arguments.
|
|
6
|
-
#
|
|
7
|
-
# @api public
|
|
8
6
|
class Riffer::StreamEvents::ToolCallDone < Riffer::StreamEvents::Base
|
|
9
|
-
|
|
7
|
+
# The tool call item identifier.
|
|
8
|
+
attr_reader :item_id
|
|
9
|
+
|
|
10
|
+
# The call identifier for response matching.
|
|
11
|
+
attr_reader :call_id
|
|
12
|
+
|
|
13
|
+
# The tool name.
|
|
14
|
+
attr_reader :name
|
|
15
|
+
|
|
16
|
+
# The complete arguments JSON string.
|
|
17
|
+
attr_reader :arguments
|
|
10
18
|
|
|
11
|
-
# Creates a new tool call done event
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
|
|
19
|
+
# Creates a new tool call done event.
|
|
20
|
+
#
|
|
21
|
+
# item_id:: String - the tool call item identifier
|
|
22
|
+
# call_id:: String - the call identifier for response matching
|
|
23
|
+
# name:: String - the tool name
|
|
24
|
+
# arguments:: String - the complete arguments JSON string
|
|
25
|
+
# role:: Symbol - the message role (defaults to :assistant)
|
|
26
|
+
def initialize(item_id:, call_id:, name:, arguments:, role: :assistant)
|
|
18
27
|
super(role: role)
|
|
19
28
|
@item_id = item_id
|
|
20
29
|
@call_id = call_id
|
|
@@ -22,8 +31,9 @@ class Riffer::StreamEvents::ToolCallDone < Riffer::StreamEvents::Base
|
|
|
22
31
|
@arguments = arguments
|
|
23
32
|
end
|
|
24
33
|
|
|
25
|
-
# Converts the event to a hash
|
|
26
|
-
#
|
|
34
|
+
# Converts the event to a hash.
|
|
35
|
+
#
|
|
36
|
+
# Returns Hash - the event data.
|
|
27
37
|
def to_h
|
|
28
38
|
{role: @role, item_id: @item_id, call_id: @call_id, name: @name, arguments: @arguments}
|
|
29
39
|
end
|
data/lib/riffer/stream_events.rb
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Namespace for streaming event types in the Riffer framework.
|
|
4
|
+
#
|
|
5
|
+
# When streaming responses, these events are yielded to represent incremental updates:
|
|
6
|
+
# - Riffer::StreamEvents::TextDelta - Incremental text content
|
|
7
|
+
# - Riffer::StreamEvents::TextDone - Complete text content
|
|
8
|
+
# - Riffer::StreamEvents::ToolCallDelta - Incremental tool call arguments
|
|
9
|
+
# - Riffer::StreamEvents::ToolCallDone - Complete tool call
|
|
10
|
+
# - Riffer::StreamEvents::ReasoningDelta - Incremental reasoning content
|
|
11
|
+
# - Riffer::StreamEvents::ReasoningDone - Complete reasoning content
|
|
3
12
|
module Riffer::StreamEvents
|
|
4
13
|
end
|
data/lib/riffer/tool.rb
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "timeout"
|
|
4
|
+
|
|
3
5
|
# Riffer::Tool is the base class for all tools in the Riffer framework.
|
|
4
6
|
#
|
|
5
7
|
# Provides a DSL for defining tool description and parameters.
|
|
8
|
+
# Subclasses must implement the +call+ method.
|
|
6
9
|
#
|
|
7
|
-
#
|
|
10
|
+
# See Riffer::Agent.
|
|
8
11
|
#
|
|
9
|
-
# @example
|
|
10
12
|
# class WeatherLookupTool < Riffer::Tool
|
|
11
13
|
# description "Provides current weather information for a specified city."
|
|
12
14
|
#
|
|
@@ -20,22 +22,27 @@
|
|
|
20
22
|
# end
|
|
21
23
|
# end
|
|
22
24
|
#
|
|
23
|
-
# @see Riffer::Agent
|
|
24
25
|
class Riffer::Tool
|
|
26
|
+
DEFAULT_TIMEOUT = 10
|
|
27
|
+
|
|
25
28
|
class << self
|
|
26
29
|
include Riffer::Helpers::ClassNameConverter
|
|
27
30
|
|
|
28
|
-
# Gets or sets the tool description
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
+
# Gets or sets the tool description.
|
|
32
|
+
#
|
|
33
|
+
# value:: String or nil - the description to set, or nil to get
|
|
34
|
+
#
|
|
35
|
+
# Returns String or nil - the tool description.
|
|
31
36
|
def description(value = nil)
|
|
32
37
|
return @description if value.nil?
|
|
33
38
|
@description = value.to_s
|
|
34
39
|
end
|
|
35
40
|
|
|
36
|
-
# Gets or sets the tool identifier/name
|
|
37
|
-
#
|
|
38
|
-
#
|
|
41
|
+
# Gets or sets the tool identifier/name.
|
|
42
|
+
#
|
|
43
|
+
# value:: String or nil - the identifier to set, or nil to get
|
|
44
|
+
#
|
|
45
|
+
# Returns String - the tool identifier (defaults to snake_case class name).
|
|
39
46
|
def identifier(value = nil)
|
|
40
47
|
return @identifier || class_name_to_path(Module.instance_method(:name).bind_call(self)) if value.nil?
|
|
41
48
|
@identifier = value.to_s
|
|
@@ -44,17 +51,30 @@ class Riffer::Tool
|
|
|
44
51
|
# Alias for identifier - used by providers
|
|
45
52
|
alias_method :name, :identifier
|
|
46
53
|
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
54
|
+
# Gets or sets the tool timeout in seconds.
|
|
55
|
+
#
|
|
56
|
+
# value:: Numeric or nil - the timeout to set in seconds, or nil to get
|
|
57
|
+
#
|
|
58
|
+
# Returns Numeric - the tool timeout (defaults to 10).
|
|
59
|
+
def timeout(value = nil)
|
|
60
|
+
return @timeout || DEFAULT_TIMEOUT if value.nil?
|
|
61
|
+
@timeout = value.to_f
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Defines parameters using the Params DSL.
|
|
65
|
+
#
|
|
66
|
+
# Yields to the parameter definition block.
|
|
67
|
+
#
|
|
68
|
+
# Returns Riffer::Tools::Params or nil - the params builder.
|
|
50
69
|
def params(&block)
|
|
51
70
|
return @params_builder if block.nil?
|
|
52
71
|
@params_builder = Riffer::Tools::Params.new
|
|
53
72
|
@params_builder.instance_eval(&block)
|
|
54
73
|
end
|
|
55
74
|
|
|
56
|
-
# Returns the JSON Schema for the tool's parameters
|
|
57
|
-
#
|
|
75
|
+
# Returns the JSON Schema for the tool's parameters.
|
|
76
|
+
#
|
|
77
|
+
# Returns Hash - the JSON Schema.
|
|
58
78
|
def parameters_schema
|
|
59
79
|
@params_builder&.to_json_schema || empty_schema
|
|
60
80
|
end
|
|
@@ -66,23 +86,70 @@ class Riffer::Tool
|
|
|
66
86
|
end
|
|
67
87
|
end
|
|
68
88
|
|
|
69
|
-
# Executes the tool with the given arguments
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
89
|
+
# Executes the tool with the given arguments.
|
|
90
|
+
#
|
|
91
|
+
# context:: Object or nil - optional context passed from the agent
|
|
92
|
+
# kwargs:: Hash - the tool arguments
|
|
93
|
+
#
|
|
94
|
+
# Returns Object - the tool result.
|
|
95
|
+
#
|
|
96
|
+
# Raises NotImplementedError if not implemented by subclass.
|
|
74
97
|
def call(context:, **kwargs)
|
|
75
98
|
raise NotImplementedError, "#{self.class} must implement #call"
|
|
76
99
|
end
|
|
77
100
|
|
|
78
|
-
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
101
|
+
# Creates a text response. Shorthand for Riffer::Tools::Response.text.
|
|
102
|
+
#
|
|
103
|
+
# result:: Object - the tool result (converted via to_s)
|
|
104
|
+
#
|
|
105
|
+
# Returns Riffer::Tools::Response.
|
|
106
|
+
def text(result)
|
|
107
|
+
Riffer::Tools::Response.text(result)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Creates a JSON response. Shorthand for Riffer::Tools::Response.json.
|
|
111
|
+
#
|
|
112
|
+
# result:: Object - the tool result (converted via JSON.generate)
|
|
113
|
+
#
|
|
114
|
+
# Returns Riffer::Tools::Response.
|
|
115
|
+
def json(result)
|
|
116
|
+
Riffer::Tools::Response.json(result)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Creates an error response. Shorthand for Riffer::Tools::Response.error.
|
|
120
|
+
#
|
|
121
|
+
# message:: String - the error message
|
|
122
|
+
# type:: Symbol - the error type (default: :execution_error)
|
|
123
|
+
#
|
|
124
|
+
# Returns Riffer::Tools::Response.
|
|
125
|
+
def error(message, type: :execution_error)
|
|
126
|
+
Riffer::Tools::Response.error(message, type: type)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Executes the tool with validation and timeout (used by Agent).
|
|
130
|
+
#
|
|
131
|
+
# context:: Object or nil - context passed from the agent
|
|
132
|
+
# kwargs:: Hash - the tool arguments
|
|
133
|
+
#
|
|
134
|
+
# Returns Riffer::Tools::Response - the tool response.
|
|
135
|
+
#
|
|
136
|
+
# Raises Riffer::ValidationError if validation fails.
|
|
137
|
+
# Raises Riffer::TimeoutError if execution exceeds the configured timeout.
|
|
138
|
+
# Raises Riffer::Error if the tool does not return a Response object.
|
|
83
139
|
def call_with_validation(context:, **kwargs)
|
|
84
140
|
params_builder = self.class.params
|
|
85
141
|
validated_args = params_builder ? params_builder.validate(kwargs) : kwargs
|
|
86
|
-
|
|
142
|
+
|
|
143
|
+
result = Timeout.timeout(self.class.timeout) do
|
|
144
|
+
call(context: context, **validated_args)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
unless result.is_a?(Riffer::Tools::Response)
|
|
148
|
+
raise Riffer::Error, "#{self.class} must return a Riffer::Tools::Response from #call"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
result
|
|
152
|
+
rescue Timeout::Error
|
|
153
|
+
raise Riffer::TimeoutError, "Tool execution timed out after #{self.class.timeout} seconds"
|
|
87
154
|
end
|
|
88
155
|
end
|
data/lib/riffer/tools/param.rb
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
# Riffer::Tools::Param represents a single parameter definition for a tool.
|
|
4
4
|
#
|
|
5
5
|
# Handles type validation and JSON Schema generation for individual parameters.
|
|
6
|
-
#
|
|
7
|
-
# @api private
|
|
8
6
|
class Riffer::Tools::Param
|
|
9
7
|
# Maps Ruby types to JSON Schema type strings
|
|
10
8
|
TYPE_MAPPINGS = {
|
|
@@ -19,13 +17,14 @@ class Riffer::Tools::Param
|
|
|
19
17
|
|
|
20
18
|
attr_reader :name, :type, :required, :description, :enum, :default
|
|
21
19
|
|
|
22
|
-
# Creates a new parameter definition
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
20
|
+
# Creates a new parameter definition.
|
|
21
|
+
#
|
|
22
|
+
# name:: Symbol - the parameter name
|
|
23
|
+
# type:: Class - the expected Ruby type
|
|
24
|
+
# required:: Boolean - whether the parameter is required
|
|
25
|
+
# description:: String or nil - optional description for the parameter
|
|
26
|
+
# enum:: Array or nil - optional list of allowed values
|
|
27
|
+
# default:: Object or nil - optional default value for optional parameters
|
|
29
28
|
def initialize(name:, type:, required:, description: nil, enum: nil, default: nil)
|
|
30
29
|
@name = name.to_sym
|
|
31
30
|
@type = type
|
|
@@ -35,9 +34,11 @@ class Riffer::Tools::Param
|
|
|
35
34
|
@default = default
|
|
36
35
|
end
|
|
37
36
|
|
|
38
|
-
# Validates that a value matches the expected type
|
|
39
|
-
#
|
|
40
|
-
#
|
|
37
|
+
# Validates that a value matches the expected type.
|
|
38
|
+
#
|
|
39
|
+
# value:: Object - the value to validate
|
|
40
|
+
#
|
|
41
|
+
# Returns Boolean - true if valid, false otherwise.
|
|
41
42
|
def valid_type?(value)
|
|
42
43
|
return true if value.nil? && !required
|
|
43
44
|
|
|
@@ -48,14 +49,16 @@ class Riffer::Tools::Param
|
|
|
48
49
|
end
|
|
49
50
|
end
|
|
50
51
|
|
|
51
|
-
# Returns the JSON Schema type name for this parameter
|
|
52
|
-
#
|
|
52
|
+
# Returns the JSON Schema type name for this parameter.
|
|
53
|
+
#
|
|
54
|
+
# Returns String - the JSON Schema type.
|
|
53
55
|
def type_name
|
|
54
56
|
TYPE_MAPPINGS[type] || type.to_s.downcase
|
|
55
57
|
end
|
|
56
58
|
|
|
57
|
-
# Converts this parameter to JSON Schema format
|
|
58
|
-
#
|
|
59
|
+
# Converts this parameter to JSON Schema format.
|
|
60
|
+
#
|
|
61
|
+
# Returns Hash - the JSON Schema representation.
|
|
59
62
|
def to_json_schema
|
|
60
63
|
schema = {type: type_name}
|
|
61
64
|
schema[:description] = description if description
|
data/lib/riffer/tools/params.rb
CHANGED
|
@@ -2,15 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
# Riffer::Tools::Params provides a DSL for defining tool parameters.
|
|
4
4
|
#
|
|
5
|
-
# Used within a Tool's
|
|
5
|
+
# Used within a Tool's +params+ block to define required and optional parameters.
|
|
6
6
|
#
|
|
7
|
-
# @example
|
|
8
7
|
# params do
|
|
9
8
|
# required :city, String, description: "The city name"
|
|
10
9
|
# optional :units, String, default: "celsius", enum: ["celsius", "fahrenheit"]
|
|
11
10
|
# end
|
|
12
11
|
#
|
|
13
|
-
# @api private
|
|
14
12
|
class Riffer::Tools::Params
|
|
15
13
|
attr_reader :parameters
|
|
16
14
|
|
|
@@ -18,12 +16,14 @@ class Riffer::Tools::Params
|
|
|
18
16
|
@parameters = []
|
|
19
17
|
end
|
|
20
18
|
|
|
21
|
-
# Defines a required parameter
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
19
|
+
# Defines a required parameter.
|
|
20
|
+
#
|
|
21
|
+
# name:: Symbol - the parameter name
|
|
22
|
+
# type:: Class - the expected Ruby type
|
|
23
|
+
# description:: String or nil - optional description
|
|
24
|
+
# enum:: Array or nil - optional list of allowed values
|
|
25
|
+
#
|
|
26
|
+
# Returns void.
|
|
27
27
|
def required(name, type, description: nil, enum: nil)
|
|
28
28
|
@parameters << Riffer::Tools::Param.new(
|
|
29
29
|
name: name,
|
|
@@ -34,13 +34,15 @@ class Riffer::Tools::Params
|
|
|
34
34
|
)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
# Defines an optional parameter
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
37
|
+
# Defines an optional parameter.
|
|
38
|
+
#
|
|
39
|
+
# name:: Symbol - the parameter name
|
|
40
|
+
# type:: Class - the expected Ruby type
|
|
41
|
+
# description:: String or nil - optional description
|
|
42
|
+
# enum:: Array or nil - optional list of allowed values
|
|
43
|
+
# default:: Object or nil - default value when not provided
|
|
44
|
+
#
|
|
45
|
+
# Returns void.
|
|
44
46
|
def optional(name, type, description: nil, enum: nil, default: nil)
|
|
45
47
|
@parameters << Riffer::Tools::Param.new(
|
|
46
48
|
name: name,
|
|
@@ -52,10 +54,13 @@ class Riffer::Tools::Params
|
|
|
52
54
|
)
|
|
53
55
|
end
|
|
54
56
|
|
|
55
|
-
# Validates arguments against parameter definitions
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
57
|
+
# Validates arguments against parameter definitions.
|
|
58
|
+
#
|
|
59
|
+
# arguments:: Hash - the arguments to validate
|
|
60
|
+
#
|
|
61
|
+
# Returns Hash - validated arguments with defaults applied.
|
|
62
|
+
#
|
|
63
|
+
# Raises Riffer::ValidationError if validation fails.
|
|
59
64
|
def validate(arguments)
|
|
60
65
|
validated = {}
|
|
61
66
|
errors = []
|
|
@@ -91,8 +96,9 @@ class Riffer::Tools::Params
|
|
|
91
96
|
validated
|
|
92
97
|
end
|
|
93
98
|
|
|
94
|
-
# Converts all parameters to JSON Schema format
|
|
95
|
-
#
|
|
99
|
+
# Converts all parameters to JSON Schema format.
|
|
100
|
+
#
|
|
101
|
+
# Returns Hash - the JSON Schema representation.
|
|
96
102
|
def to_json_schema
|
|
97
103
|
properties = {}
|
|
98
104
|
required_params = []
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
# Riffer::Tools::Response represents the result of a tool execution.
|
|
6
|
+
#
|
|
7
|
+
# All tools must return a Response object from their +call+ method.
|
|
8
|
+
# Use +Response.success+ for successful results and +Response.error+ for failures.
|
|
9
|
+
#
|
|
10
|
+
# class MyTool < Riffer::Tool
|
|
11
|
+
# def call(context:, **kwargs)
|
|
12
|
+
# result = perform_operation
|
|
13
|
+
# Riffer::Tools::Response.success(result)
|
|
14
|
+
# rescue MyError => e
|
|
15
|
+
# Riffer::Tools::Response.error(e.message)
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
class Riffer::Tools::Response
|
|
20
|
+
VALID_FORMATS = %i[text json].freeze
|
|
21
|
+
|
|
22
|
+
attr_reader :content, :error_message, :error_type
|
|
23
|
+
|
|
24
|
+
# Creates a success response.
|
|
25
|
+
#
|
|
26
|
+
# result:: Object - the tool result
|
|
27
|
+
# format:: Symbol - the format (:text or :json; default: :text)
|
|
28
|
+
#
|
|
29
|
+
# Returns Riffer::Tools::Response.
|
|
30
|
+
#
|
|
31
|
+
# Raises Riffer::ArgumentError if format is invalid.
|
|
32
|
+
def self.success(result, format: :text)
|
|
33
|
+
unless VALID_FORMATS.include?(format)
|
|
34
|
+
raise Riffer::ArgumentError, "Invalid format: #{format}. Must be one of: #{VALID_FORMATS.join(", ")}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
content = (format == :json) ? result.to_json : result.to_s
|
|
38
|
+
new(content: content, success: true)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Creates a success response with text format.
|
|
42
|
+
#
|
|
43
|
+
# result:: Object - the tool result (converted via to_s)
|
|
44
|
+
#
|
|
45
|
+
# Returns Riffer::Tools::Response.
|
|
46
|
+
def self.text(result)
|
|
47
|
+
success(result, format: :text)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Creates a success response with JSON format.
|
|
51
|
+
#
|
|
52
|
+
# result:: Object - the tool result (converted via to_json)
|
|
53
|
+
#
|
|
54
|
+
# Returns Riffer::Tools::Response.
|
|
55
|
+
def self.json(result)
|
|
56
|
+
success(result, format: :json)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Creates an error response.
|
|
60
|
+
#
|
|
61
|
+
# message:: String - the error message
|
|
62
|
+
# type:: Symbol - the error type (default: :execution_error)
|
|
63
|
+
#
|
|
64
|
+
# Returns Riffer::Tools::Response.
|
|
65
|
+
def self.error(message, type: :execution_error)
|
|
66
|
+
new(content: message, success: false, error_message: message, error_type: type)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns true if the response is successful.
|
|
70
|
+
def success? = @success
|
|
71
|
+
|
|
72
|
+
# Returns true if the response is an error.
|
|
73
|
+
def error? = !@success
|
|
74
|
+
|
|
75
|
+
# Returns a hash representation of the response.
|
|
76
|
+
#
|
|
77
|
+
# Returns Hash with :content, :error, and :error_type keys.
|
|
78
|
+
def to_h
|
|
79
|
+
{content: @content, error: @error_message, error_type: @error_type}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def initialize(content:, success:, error_message: nil, error_type: nil)
|
|
85
|
+
@content = content
|
|
86
|
+
@success = success
|
|
87
|
+
@error_message = error_message
|
|
88
|
+
@error_type = error_type
|
|
89
|
+
end
|
|
90
|
+
end
|