aia 0.9.1 → 0.9.3rc1
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/.version +1 -1
- data/CHANGELOG.md +16 -0
- data/README.md +98 -57
- data/examples/tools/edit_file.rb +26 -0
- data/examples/tools/list_files.rb +18 -0
- data/examples/tools/read_file.rb +16 -0
- data/examples/tools/run_shell_command.rb +21 -0
- data/lib/aia/chat_processor_service.rb +8 -6
- data/lib/aia/config.rb +288 -291
- data/lib/aia/context_manager.rb +1 -1
- data/lib/aia/directive_processor.rb +6 -1
- data/lib/aia/ruby_llm_adapter.rb +175 -137
- data/lib/aia/session.rb +7 -8
- data/lib/aia/utility.rb +17 -7
- data/lib/aia.rb +11 -5
- metadata +16 -27
- data/lib/extensions/ruby_llm/chat.rb +0 -197
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.3rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dewayne VanHoozer
|
@@ -37,50 +37,36 @@ dependencies:
|
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0'
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: os
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - ">="
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '0'
|
47
|
-
type: :runtime
|
48
|
-
prerelease: false
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
40
|
- !ruby/object:Gem::Dependency
|
55
41
|
name: prompt_manager
|
56
42
|
requirement: !ruby/object:Gem::Requirement
|
57
43
|
requirements:
|
58
44
|
- - ">="
|
59
45
|
- !ruby/object:Gem::Version
|
60
|
-
version: 0.5.
|
46
|
+
version: 0.5.4
|
61
47
|
type: :runtime
|
62
48
|
prerelease: false
|
63
49
|
version_requirements: !ruby/object:Gem::Requirement
|
64
50
|
requirements:
|
65
51
|
- - ">="
|
66
52
|
- !ruby/object:Gem::Version
|
67
|
-
version: 0.5.
|
53
|
+
version: 0.5.4
|
68
54
|
- !ruby/object:Gem::Dependency
|
69
55
|
name: ruby_llm
|
70
56
|
requirement: !ruby/object:Gem::Requirement
|
71
57
|
requirements:
|
72
58
|
- - ">="
|
73
59
|
- !ruby/object:Gem::Version
|
74
|
-
version: 1.
|
60
|
+
version: 1.3.0rc1
|
75
61
|
type: :runtime
|
76
62
|
prerelease: false
|
77
63
|
version_requirements: !ruby/object:Gem::Requirement
|
78
64
|
requirements:
|
79
65
|
- - ">="
|
80
66
|
- !ruby/object:Gem::Version
|
81
|
-
version: 1.
|
67
|
+
version: 1.3.0rc1
|
82
68
|
- !ruby/object:Gem::Dependency
|
83
|
-
name:
|
69
|
+
name: reline
|
84
70
|
requirement: !ruby/object:Gem::Requirement
|
85
71
|
requirements:
|
86
72
|
- - ">="
|
@@ -94,7 +80,7 @@ dependencies:
|
|
94
80
|
- !ruby/object:Gem::Version
|
95
81
|
version: '0'
|
96
82
|
- !ruby/object:Gem::Dependency
|
97
|
-
name:
|
83
|
+
name: shellwords
|
98
84
|
requirement: !ruby/object:Gem::Requirement
|
99
85
|
requirements:
|
100
86
|
- - ">="
|
@@ -108,7 +94,7 @@ dependencies:
|
|
108
94
|
- !ruby/object:Gem::Version
|
109
95
|
version: '0'
|
110
96
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
97
|
+
name: toml-rb
|
112
98
|
requirement: !ruby/object:Gem::Requirement
|
113
99
|
requirements:
|
114
100
|
- - ">="
|
@@ -122,7 +108,7 @@ dependencies:
|
|
122
108
|
- !ruby/object:Gem::Version
|
123
109
|
version: '0'
|
124
110
|
- !ruby/object:Gem::Dependency
|
125
|
-
name:
|
111
|
+
name: tty-screen
|
126
112
|
requirement: !ruby/object:Gem::Requirement
|
127
113
|
requirements:
|
128
114
|
- - ">="
|
@@ -136,7 +122,7 @@ dependencies:
|
|
136
122
|
- !ruby/object:Gem::Version
|
137
123
|
version: '0'
|
138
124
|
- !ruby/object:Gem::Dependency
|
139
|
-
name: tty-
|
125
|
+
name: tty-spinner
|
140
126
|
requirement: !ruby/object:Gem::Requirement
|
141
127
|
requirements:
|
142
128
|
- - ">="
|
@@ -150,7 +136,7 @@ dependencies:
|
|
150
136
|
- !ruby/object:Gem::Version
|
151
137
|
version: '0'
|
152
138
|
- !ruby/object:Gem::Dependency
|
153
|
-
name:
|
139
|
+
name: versionaire
|
154
140
|
requirement: !ruby/object:Gem::Requirement
|
155
141
|
requirements:
|
156
142
|
- - ">="
|
@@ -164,7 +150,7 @@ dependencies:
|
|
164
150
|
- !ruby/object:Gem::Version
|
165
151
|
version: '0'
|
166
152
|
- !ruby/object:Gem::Dependency
|
167
|
-
name:
|
153
|
+
name: word_wrapper
|
168
154
|
requirement: !ruby/object:Gem::Requirement
|
169
155
|
requirements:
|
170
156
|
- - ">="
|
@@ -302,6 +288,10 @@ files:
|
|
302
288
|
- bin/aia
|
303
289
|
- examples/README.md
|
304
290
|
- examples/headlines
|
291
|
+
- examples/tools/edit_file.rb
|
292
|
+
- examples/tools/list_files.rb
|
293
|
+
- examples/tools/read_file.rb
|
294
|
+
- examples/tools/run_shell_command.rb
|
305
295
|
- justfile
|
306
296
|
- lib/aia.rb
|
307
297
|
- lib/aia/aia_completion.bash
|
@@ -321,7 +311,6 @@ files:
|
|
321
311
|
- lib/aia/utility.rb
|
322
312
|
- lib/aia/version.rb
|
323
313
|
- lib/extensions/openstruct_merge.rb
|
324
|
-
- lib/extensions/ruby_llm/chat.rb
|
325
314
|
- main.just
|
326
315
|
- mcp_servers/README.md
|
327
316
|
- mcp_servers/filesystem.json
|
@@ -1,197 +0,0 @@
|
|
1
|
-
# lib/extensions/ruby_llm/chat.rb
|
2
|
-
|
3
|
-
module RubyLLM
|
4
|
-
class Chat
|
5
|
-
class << self
|
6
|
-
# Sets up Model Control Protocol (MCP) tools
|
7
|
-
#
|
8
|
-
# @param client [instance object] MCP client instance to use
|
9
|
-
# @param call_tool_method [Symbol] Method name to use for tool execution
|
10
|
-
# @param tools [Array<Hash>] Array of MCP tool definitions
|
11
|
-
#
|
12
|
-
# @return [self] Returns self for method chaining
|
13
|
-
#
|
14
|
-
def with_mcp(client:, call_tool_method:, tools:)
|
15
|
-
# Validate all required parameters are present
|
16
|
-
if client.nil?
|
17
|
-
RubyLLM.logger.error "MCP setup failed: client must be provided"
|
18
|
-
return clear_mcp_state
|
19
|
-
end
|
20
|
-
|
21
|
-
if call_tool_method.nil?
|
22
|
-
RubyLLM.logger.error "MCP setup failed: call_tool_method must be provided"
|
23
|
-
return clear_mcp_state
|
24
|
-
end
|
25
|
-
|
26
|
-
if tools.nil?
|
27
|
-
RubyLLM.logger.error "MCP setup failed: tools must be provided"
|
28
|
-
return clear_mcp_state
|
29
|
-
end
|
30
|
-
|
31
|
-
# Validate call_tool_method type
|
32
|
-
unless call_tool_method.is_a?(Symbol) || call_tool_method.is_a?(String)
|
33
|
-
RubyLLM.logger.error "MCP setup failed: call_tool_method must be a Symbol or String, got #{call_tool_method.class}"
|
34
|
-
return clear_mcp_state
|
35
|
-
end
|
36
|
-
|
37
|
-
# Validate client responds to the method
|
38
|
-
unless client.respond_to?(call_tool_method)
|
39
|
-
RubyLLM.logger.error "MCP setup failed: client instance does not respond to call_tool_method #{call_tool_method}"
|
40
|
-
return clear_mcp_state
|
41
|
-
end
|
42
|
-
|
43
|
-
# Set MCP configuration
|
44
|
-
@mcp_client = client
|
45
|
-
@mcp_call_tool = call_tool_method.to_sym
|
46
|
-
@mcp_tools = tools
|
47
|
-
|
48
|
-
self
|
49
|
-
end
|
50
|
-
|
51
|
-
# Get the MCP client instance if configured
|
52
|
-
# @return [MCPClient::Client, nil] The MCP client instance or nil if not configured
|
53
|
-
def mcp_client
|
54
|
-
@mcp_client
|
55
|
-
end
|
56
|
-
|
57
|
-
# Get the method name to use for tool execution if configured
|
58
|
-
# @return [Symbol, nil] The method name or nil if not configured
|
59
|
-
def mcp_call_tool
|
60
|
-
@mcp_call_tool
|
61
|
-
end
|
62
|
-
|
63
|
-
# Get the MCP tool definitions if configured
|
64
|
-
# @return [Array<Hash>] The MCP tool definitions or empty array if not configured
|
65
|
-
def mcp_tools
|
66
|
-
@mcp_tools || []
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
# Clear all MCP state and return self
|
72
|
-
# @return [self]
|
73
|
-
def clear_mcp_state
|
74
|
-
@mcp_client = nil
|
75
|
-
@mcp_call_tool = nil
|
76
|
-
@mcp_tools = []
|
77
|
-
self
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# Prepend a module to add MCP tool support
|
82
|
-
module MCPSupport
|
83
|
-
def initialize(...)
|
84
|
-
super
|
85
|
-
add_mcp_tools
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def add_mcp_tools
|
91
|
-
self.class.mcp_tools.each do |tool_def|
|
92
|
-
debug_me{[ :tool_def ]}
|
93
|
-
tool_name = tool_def.dig(:function, :name).to_sym
|
94
|
-
next if @tools.key?(tool_name) # Skip if local or MCP tool exists with same name
|
95
|
-
|
96
|
-
@tools[tool_name] = MCPToolWrapper.new(tool_def)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Add MCP support to the Chat class
|
102
|
-
prepend MCPSupport
|
103
|
-
end
|
104
|
-
|
105
|
-
# Wraps an MCP tool definition to match the RubyLLM::Tool interface
|
106
|
-
class MCPToolWrapper
|
107
|
-
def initialize(mcp_tool)
|
108
|
-
@mcp_tool = mcp_tool
|
109
|
-
end
|
110
|
-
|
111
|
-
def name
|
112
|
-
@mcp_tool.dig(:function, :name)
|
113
|
-
end
|
114
|
-
|
115
|
-
def description
|
116
|
-
@mcp_tool.dig(:function, :description)
|
117
|
-
end
|
118
|
-
|
119
|
-
# Simple parameter class that implements the interface expected by RubyLLM::Providers::OpenAI::Tools#param_schema
|
120
|
-
class Parameter
|
121
|
-
attr_reader :type, :description, :required
|
122
|
-
|
123
|
-
def initialize(type, description, required)
|
124
|
-
@type = type || 'string'
|
125
|
-
@description = description
|
126
|
-
@required = required
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def parameters
|
131
|
-
@parameters ||= begin
|
132
|
-
props = @mcp_tool.dig(:function, :parameters, "properties") || {}
|
133
|
-
required_params = @mcp_tool.dig(:function, :parameters, "required") || []
|
134
|
-
|
135
|
-
# Create Parameter objects with the expected interface
|
136
|
-
# The parameter name is the key in the properties hash
|
137
|
-
result = {}
|
138
|
-
props.each do |param_name, param_def|
|
139
|
-
result[param_name.to_sym] = Parameter.new(
|
140
|
-
param_def["type"],
|
141
|
-
param_def["description"],
|
142
|
-
required_params.include?(param_name)
|
143
|
-
)
|
144
|
-
end
|
145
|
-
result
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def call(args)
|
150
|
-
# Log the tool call with arguments
|
151
|
-
RubyLLM.logger.debug "Tool #{name} called with: #{args.inspect}"
|
152
|
-
|
153
|
-
# Verify MCP client is configured properly
|
154
|
-
unless Chat.mcp_client && Chat.mcp_call_tool
|
155
|
-
error = { error: "MCP client not properly configured" }
|
156
|
-
RubyLLM.logger.error error[:error]
|
157
|
-
return error
|
158
|
-
end
|
159
|
-
|
160
|
-
# Handle tool calls that require non-string parameters
|
161
|
-
normalized_args = {}
|
162
|
-
args.each do |key, value|
|
163
|
-
# Convert string numbers to actual numbers when needed
|
164
|
-
if value.is_a?(String) && value.match?(/\A-?\d+(\.\d+)?\z/)
|
165
|
-
param_type = @mcp_tool.dig(:function, :parameters, "properties", key.to_s, "type")
|
166
|
-
if param_type == "number" || param_type == "integer"
|
167
|
-
normalized_args[key] = value.include?('.') ? value.to_f : value.to_i
|
168
|
-
next
|
169
|
-
end
|
170
|
-
end
|
171
|
-
normalized_args[key] = value
|
172
|
-
end
|
173
|
-
|
174
|
-
# Execute the tool via the MCP client with a timeout
|
175
|
-
timeout = 10 # seconds
|
176
|
-
result = nil
|
177
|
-
|
178
|
-
begin
|
179
|
-
Timeout.timeout(timeout) do
|
180
|
-
result = Chat.mcp_client.send(Chat.mcp_call_tool, name, normalized_args)
|
181
|
-
end
|
182
|
-
rescue Timeout::Error
|
183
|
-
error = { error: "MCP tool execution timed out after #{timeout} seconds" }
|
184
|
-
RubyLLM.logger.error error[:error]
|
185
|
-
return error
|
186
|
-
rescue StandardError => e
|
187
|
-
error = { error: "MCP tool execution failed: #{e.message}" }
|
188
|
-
RubyLLM.logger.error error[:error]
|
189
|
-
return error
|
190
|
-
end
|
191
|
-
|
192
|
-
# Log the result
|
193
|
-
RubyLLM.logger.debug "Tool #{name} returned: #{result.inspect}"
|
194
|
-
result
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|