Skip to content

Commit f3354e4

Browse files
committed
Tool definition
1 parent d7a9661 commit f3354e4

3 files changed

Lines changed: 166 additions & 0 deletions

File tree

.rubocop.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,12 @@ Metrics/MethodLength:
2323

2424
Metrics/ParameterLists:
2525
Enabled: false
26+
27+
RSpec/ExampleLength:
28+
Enabled: false
29+
30+
RSpec/MultipleExpectations:
31+
Enabled: false
32+
33+
Style/Documentation:
34+
Enabled: false

lib/tool_forge/tool_definition.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# frozen_string_literal: true
2+
3+
module ToolForge
4+
class ToolDefinition
5+
attr_reader :name, :params, :execute_block
6+
7+
def initialize(name, &)
8+
@name = name
9+
@description = nil
10+
@params = []
11+
@execute_block = nil
12+
13+
instance_eval(&) if block_given?
14+
end
15+
16+
def description(text = nil)
17+
if text
18+
@description = text
19+
else
20+
@description
21+
end
22+
end
23+
24+
def param(name, type: :string, description: nil, required: true, default: nil)
25+
@params << {
26+
name: name,
27+
type: type,
28+
description: description,
29+
required: required,
30+
default: default
31+
}
32+
end
33+
34+
def execute(&block)
35+
@execute_block = block
36+
end
37+
end
38+
end
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe ToolForge::ToolDefinition do
4+
describe '#initialize' do
5+
it 'can be created with a name' do
6+
tool = described_class.new(:my_tool)
7+
expect(tool.name).to eq(:my_tool)
8+
end
9+
10+
it 'accepts a block for configuration' do
11+
tool = described_class.new(:my_tool) do
12+
description 'Does something cool'
13+
end
14+
expect(tool.description).to eq('Does something cool')
15+
end
16+
end
17+
18+
describe '#description' do
19+
it 'sets and returns the description' do
20+
tool = described_class.new(:my_tool)
21+
tool.description 'A helpful tool'
22+
expect(tool.description).to eq('A helpful tool')
23+
end
24+
end
25+
26+
describe '#param' do
27+
it 'adds a parameter with basic attributes' do
28+
tool = described_class.new(:my_tool) do
29+
param :name, type: :string, description: 'The name'
30+
end
31+
32+
expect(tool.params.size).to eq(1)
33+
expect(tool.params.first[:name]).to eq(:name)
34+
expect(tool.params.first[:type]).to eq(:string)
35+
expect(tool.params.first[:description]).to eq('The name')
36+
end
37+
38+
it 'accepts required flag' do
39+
tool = described_class.new(:my_tool) do
40+
param :id, required: true
41+
param :optional_field, required: false
42+
end
43+
44+
expect(tool.params[0][:required]).to be true
45+
expect(tool.params[1][:required]).to be false
46+
end
47+
48+
it 'defaults required to true' do
49+
tool = described_class.new(:my_tool) do
50+
param :id
51+
end
52+
53+
expect(tool.params.first[:required]).to be true
54+
end
55+
56+
it 'accepts default values' do
57+
tool = described_class.new(:my_tool) do
58+
param :count, type: :integer, default: 10
59+
end
60+
61+
expect(tool.params.first[:default]).to eq(10)
62+
end
63+
64+
it 'supports multiple parameter types' do
65+
tool = described_class.new(:my_tool) do
66+
param :name, type: :string
67+
param :count, type: :integer
68+
param :active, type: :boolean
69+
param :tags, type: :array
70+
param :metadata, type: :object
71+
end
72+
73+
types = tool.params.map { |p| p[:type] }
74+
expect(types).to eq(%i[string integer boolean array object])
75+
end
76+
end
77+
78+
describe '#execute' do
79+
it 'stores the execution block' do
80+
tool = described_class.new(:my_tool) do
81+
execute { |name:| "Hello, #{name}!" }
82+
end
83+
84+
expect(tool.execute_block).to be_a(Proc)
85+
end
86+
87+
it 'can call the execution block' do
88+
tool = described_class.new(:my_tool) do
89+
execute { |name:| "Hello, #{name}!" }
90+
end
91+
92+
result = tool.execute_block.call(name: 'World')
93+
expect(result).to eq('Hello, World!')
94+
end
95+
end
96+
97+
describe 'complete tool definition' do
98+
it 'can define a complete tool with all features' do
99+
tool = described_class.new(:greet_user) do
100+
description 'Greets a user by name'
101+
102+
param :name, type: :string, description: 'User name', required: true
103+
param :greeting, type: :string, description: 'Greeting type', required: false, default: 'Hello'
104+
param :enthusiastic, type: :boolean, description: 'Add excitement', default: false
105+
106+
execute do |name:, greeting: 'Hello', enthusiastic: false|
107+
result = "#{greeting}, #{name}"
108+
result += '!' if enthusiastic
109+
result
110+
end
111+
end
112+
113+
expect(tool.name).to eq(:greet_user)
114+
expect(tool.description).to eq('Greets a user by name')
115+
expect(tool.params.size).to eq(3)
116+
expect(tool.execute_block.call(name: 'Alice', enthusiastic: true)).to eq('Hello, Alice!')
117+
end
118+
end
119+
end

0 commit comments

Comments
 (0)