aia 0.9.22 → 0.9.24

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: e34cfc1092812c76266e11c14b10c7df0d06268e57945ad984ea28b2bebd4ac2
4
- data.tar.gz: a1f3bb8530c55fae801aae161173f61a0902d183db3f77bbb04440c7e4bb2204
3
+ metadata.gz: f9592d9ea1bbbbdc04f92dc822cfbdae91c1e04084530583e50f6cdb8a90460d
4
+ data.tar.gz: 897e53ec02de0fcc46a0e5ddcf15ca13a462b7cc20e4f355950f5872e5b04f00
5
5
  SHA512:
6
- metadata.gz: 7a91f8b0fbaad8d2bcbe476aacd37d894746bb1773a1c8fe2a3c8fec28ecea5c577ed002f42a7f34278a0ab1163ee9dc63385f083d018ac87ad9179d8f2bdcfc
7
- data.tar.gz: 2ebba9e5b65df0caf6acab01dc6fe4740e8671a4a522dbced54f411356d4cea94e0459a5f446a040228929574c79e898267c8ee42bd0cf8c21444e3ac37c7233
6
+ metadata.gz: 5e8b63a8ca892346e4dd1090ef487e4fc6dc6b9395238ecc6208128d8908a5dca87d730a9193a15b05dbb005b8d9eb84e2bb7f63100982130eeec69e0bb9483d
7
+ data.tar.gz: 660c1c40117300223a7bd88c67ec826225a44ada72d459ee6c8fd3e3c015e81a7874a9618220c4dc7caf3de930ee140d29ef1c7c8dfc205ecfeedef8e629b36a
data/.version CHANGED
@@ -1 +1 @@
1
- 0.9.22
1
+ 0.9.24
data/CHANGELOG.md CHANGED
@@ -1,6 +1,66 @@
1
1
  # Changelog
2
2
  ## [Unreleased]
3
3
 
4
+ ## [0.9.24] 2025-12-17
5
+ ### Fixes
6
+ - Ran into a problem with the `shared_tools` gem and the --require parameter of AIA which required changes to both gems.
7
+
8
+ ### Improvements
9
+ - **`//tools` Directive Filter**: Added optional filter parameter to the `//tools` directive
10
+ - Filter tools by name substring (case-insensitive)
11
+ - Example: `//tools error` lists only tools with "error" in the name
12
+ - Shows "No tools match the filter: [filter]" when no matches found
13
+ - Header indicates when filtering is active: "Available Tools (filtered by 'filter')"
14
+
15
+ ## [0.9.23] 2025-12-06
16
+
17
+ ### New Features
18
+ - **MCP Server Configuration**: Added native support for defining MCP (Model Context Protocol) servers in the config file
19
+ - Configure MCP servers in `~/.aia/config.yml` under the `mcp_servers` key
20
+ - Supports `name`, `command`, `args`, `env`, and `timeout` options per server
21
+ - Automatic PATH resolution for commands (no absolute paths required)
22
+ - Configurable timeouts for slow-starting servers (default: 8000ms)
23
+ - Environment variable support for MCP server processes
24
+
25
+ ### Improvements
26
+ - **Robot Display**: Added MCP server names to the robot ASCII art display
27
+ - Shows "MCP: server1, server2, ..." when MCP servers are configured
28
+
29
+ ### Technical Changes
30
+ - Added `load_mcp_servers` method to `lib/aia/config/base.rb` for automatic MCP client registration
31
+ - Added `resolve_command_path` method for PATH-based command resolution
32
+ - Added `mcp_servers?` and `mcp_server_names` helper methods to `lib/aia/utility.rb`
33
+ - Fixed `OpenStruct.merge` to skip nil values, preventing config file values from being overwritten
34
+ - Added `mcp_servers: nil` default to prevent merge issues with empty arrays
35
+
36
+ ### Configuration Example
37
+ ```yaml
38
+ # ~/.aia/config.yml
39
+ :mcp_servers:
40
+ - name: "my-server"
41
+ command: "my_mcp_server.rb"
42
+ args: ["stdio"]
43
+ timeout: 30000
44
+ env:
45
+ MY_VAR: "value"
46
+ ```
47
+
48
+ ## [0.9.22] 2025-11-12
49
+
50
+ ### Bug Fixes
51
+ - **TEST SUITE**: Fixed all Mocha test isolation issues causing stub contamination between tests
52
+ - Added proper teardown methods with `super` calls to 13 test files to ensure Mocha cleanup
53
+ - Fixed PromptHandlerTest missing teardown and config fields (erb, shell, roles_dir)
54
+ - Fixed ModelsDirectiveTest to use consistent stubbing approach instead of mixing real and stubbed config
55
+ - Fixed MultiModelIsolationTest to use stubs instead of direct instance variable manipulation
56
+ - Fixed AIAIntegrationTest, ChatProcessorServiceTest, ContextManagerTest, DirectiveProcessorTest, RubyLLMAdapterTest, SessionTest, LocalProvidersTest, UtilityTest, AIAMockingTest, and AIAPropertyBasedTest to include proper Mocha cleanup
57
+ - Test results improved from 2 failures, 2 errors to 0 failures, 0 errors (325 runs, 1018 assertions)
58
+
59
+ ### Technical Changes
60
+ - Enhanced test isolation by ensuring all tests using Mocha stubs properly clean up via `super` in teardown
61
+ - Standardized stub usage pattern across test suite for consistency
62
+ - Eliminated stub leakage that caused "unexpected invocation" and "AIA was instantiated in one test but receiving invocations in another" errors
63
+
4
64
  ## [0.9.21] 2025-10-08
5
65
  ### Bug Fixes
6
66
  - **Checkpoint Directive Output**: Fixed `//checkpoint` directive to return empty string instead of status message (lib/aia/directives/configuration.rb:155)
data/README.md CHANGED
@@ -100,6 +100,7 @@ For more information on AIA visit these locations:
100
100
  - [Example Workflow](#example-workflow)
101
101
  - [Roles and System Prompts](#roles-and-system-prompts)
102
102
  - [RubyLLM::Tool Support](#rubyllmtool-support)
103
+ - [MCP Server Configuration](#mcp-server-configuration)
103
104
  - [Examples & Tips](#examples--tips)
104
105
  - [Practical Examples](#practical-examples)
105
106
  - [Code Review Prompt](#code-review-prompt)
@@ -350,7 +351,7 @@ Directives are special commands in prompt files that begin with `//` and provide
350
351
  | `//help` | Show available directives | `//help` |
351
352
  | `//model` | Show current model configuration | `//model` |
352
353
  | `//available_models` | List available models | `//available_models` |
353
- | `//tools` | Show a list of available tools and their description | `//tools` |
354
+ | `//tools` | Show available tools (optional filter by name) | `//tools` or `//tools file` |
354
355
  | `//review` | Review current context with checkpoint markers | `//review` |
355
356
 
356
357
  Directives can also be used in the interactive chat sessions.
@@ -922,6 +923,177 @@ aia --tools examples/tools/mcp/imcp.rb --chat
922
923
 
923
924
  These MCP clients require the `ruby_llm-mcp` gem and provide access to external services and data sources through the Model Context Protocol.
924
925
 
926
+ ### MCP Server Configuration
927
+
928
+ AIA supports defining MCP (Model Context Protocol) servers directly in your configuration file. This allows MCP tools to be automatically loaded at startup without needing to specify them on the command line each time.
929
+
930
+ #### Configuration Format
931
+
932
+ Add MCP servers to your `~/.aia/config.yml` file:
933
+
934
+ ```yaml
935
+ :mcp_servers:
936
+ - name: "server-name"
937
+ command: "server_command"
938
+ args: ["arg1", "arg2"]
939
+ timeout: 30000 # milliseconds (default: 8000)
940
+ env:
941
+ ENV_VAR: "value"
942
+ ```
943
+
944
+ #### Configuration Options
945
+
946
+ | Option | Required | Default | Description |
947
+ |--------|----------|---------|-------------|
948
+ | `name` | Yes | - | Unique identifier for the MCP server |
949
+ | `command` | Yes | - | Executable command (absolute path or found in PATH) |
950
+ | `args` | No | `[]` | Array of command-line arguments |
951
+ | `timeout` | No | `8000` | Connection timeout in milliseconds |
952
+ | `env` | No | `{}` | Environment variables for the server process |
953
+
954
+ #### Example: GitHub MCP Server
955
+
956
+ The GitHub MCP server provides access to GitHub repositories, issues, pull requests, and more:
957
+
958
+ ```yaml
959
+ # ~/.aia/config.yml
960
+ :mcp_servers:
961
+ - name: "github"
962
+ command: "github-mcp-server"
963
+ args: ["stdio"]
964
+ timeout: 15000
965
+ env:
966
+ GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_your_token_here"
967
+ ```
968
+
969
+ **Setup:**
970
+ ```bash
971
+ # Install GitHub MCP server (macOS)
972
+ brew install github-mcp-server
973
+
974
+ # Or via npm
975
+ npm install -g @anthropic/github-mcp-server
976
+
977
+ # Set your GitHub token (recommended: use environment variable instead of config)
978
+ export GITHUB_PERSONAL_ACCESS_TOKEN="ghp_your_token_here"
979
+ ```
980
+
981
+ #### Example: Hierarchical Temporal Memory (HTM)
982
+
983
+ ```shell
984
+ gem install htm
985
+ ```
986
+
987
+ See the [full HTM documentation](https://madbomber.github.io/htm) for database configuration and system environment variable usage.
988
+
989
+ A custom Ruby-based MCP server for accessing database-backed long term memory:
990
+
991
+ ```yaml
992
+ # ~/.aia/config.yml
993
+ :mcp_servers:
994
+ - name: "htm"
995
+ command: "htm_mcp.rb"
996
+ args: ["stdio"]
997
+ timeout: 30000
998
+ env:
999
+ HTM_DBURL: "postgres://localhost:5432/htm_development"
1000
+ ...
1001
+ ```
1002
+
1003
+ **Notes:**
1004
+ - The `command` can be just the executable name if it's in your PATH
1005
+ - AIA automatically resolves command paths, so you don't need absolute paths
1006
+ - Environment variables in the `env` section are passed only to that MCP server process
1007
+
1008
+ #### Example: Multiple MCP Servers
1009
+
1010
+ You can configure multiple MCP servers to provide different capabilities:
1011
+
1012
+ ```yaml
1013
+ # ~/.aia/config.yml
1014
+ :mcp_servers:
1015
+ - name: "github"
1016
+ command: "github-mcp-server"
1017
+ args: ["stdio"]
1018
+ env:
1019
+ GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_your_token_here"
1020
+
1021
+ - name: "htm"
1022
+ command: "htm_mcp.rb"
1023
+ args: ["stdio"]
1024
+ timeout: 30000
1025
+ env:
1026
+ HTM_DBURL: "postgres://localhost:5432/htm_development"
1027
+
1028
+ - name: "filesystem"
1029
+ command: "filesystem-mcp-server"
1030
+ args: ["stdio", "--root", "/Users/me/projects"]
1031
+ ```
1032
+
1033
+ #### Verifying MCP Server Configuration
1034
+
1035
+ When MCP servers are configured, AIA displays them in the startup robot:
1036
+
1037
+ ```
1038
+ , ,
1039
+ (\____/) AI Assistant (v0.9.23) is Online
1040
+ (_oo_) gpt-4o-mini (supports tools)
1041
+ (O) using ruby_llm (v1.9.0 MCP v0.6.1)
1042
+ __||__ \) model db was last refreshed on
1043
+ [/______\] / 2025-06-03
1044
+ / \__AI__/ \/ You can share my tools
1045
+ / /__\ MCP: github, htm
1046
+ (\ /____\
1047
+ ```
1048
+
1049
+ Use the `//tools` directive in chat mode to see all available tools including those from MCP servers:
1050
+
1051
+ ```bash
1052
+ aia --chat
1053
+ > //tools
1054
+
1055
+ Available Tools:
1056
+ - github_create_issue: Create a new GitHub issue
1057
+ - github_list_repos: List repositories for the authenticated user
1058
+ - htm_query: Execute a query against the HTM database
1059
+ - htm_insert: Insert a record into HTM
1060
+ ...
1061
+
1062
+ # Filter tools by name (case-insensitive)
1063
+ > //tools github
1064
+
1065
+ Available Tools (filtered by 'github')
1066
+ - github_create_issue: Create a new GitHub issue
1067
+ - github_list_repos: List repositories for the authenticated user
1068
+ ```
1069
+
1070
+ #### Troubleshooting MCP Servers
1071
+
1072
+ If an MCP server fails to load, AIA will display a warning:
1073
+
1074
+ ```
1075
+ WARNING: MCP server 'github' command not found: github-mcp-server
1076
+ WARNING: MCP server entry missing name or command: {...}
1077
+ ERROR: Failed to load MCP server 'htm': Connection timeout
1078
+ ```
1079
+
1080
+ **Common Issues:**
1081
+
1082
+ | Problem | Solution |
1083
+ |---------|----------|
1084
+ | Command not found | Ensure the command is in your PATH or use absolute path |
1085
+ | Connection timeout | Increase the `timeout` value |
1086
+ | Missing environment variables | Add required env vars to the `env` section |
1087
+ | Server hangs on startup | Check that all required environment variables are set |
1088
+
1089
+ **Debug Mode:**
1090
+
1091
+ Enable debug mode to see detailed MCP server loading information:
1092
+
1093
+ ```bash
1094
+ aia --debug --chat
1095
+ ```
1096
+
925
1097
  **Shared Tools Collection:**
926
1098
  AIA can use the [shared_tools gem](https://github.com/madbomber/shared_tools) which provides a curated collection of commonly-used tools (aka functions) via the --require option.
927
1099
 
@@ -214,11 +214,21 @@ Speak text using system text-to-speech (macOS/Linux).
214
214
  ## Utility Directives
215
215
 
216
216
  ### `//tools`
217
- Display available RubyLLM tools.
217
+ Display available RubyLLM tools with optional filtering.
218
218
 
219
- **Syntax**: `//tools`
219
+ **Syntax**: `//tools [filter]`
220
220
 
221
- **Example Output**:
221
+ **Parameters**:
222
+ - `filter` (optional) - Case-insensitive substring to filter tool names
223
+
224
+ **Examples**:
225
+ ```markdown
226
+ //tools # List all available tools
227
+ //tools file # List tools with "file" in the name
228
+ //tools analyzer # List tools with "analyzer" in the name
229
+ ```
230
+
231
+ **Example Output** (unfiltered):
222
232
  ```
223
233
  Available Tools
224
234
  ===============
@@ -234,6 +244,21 @@ WebScraper
234
244
  selectors and filters.
235
245
  ```
236
246
 
247
+ **Example Output** (filtered with `//tools file`):
248
+ ```
249
+ Available Tools (filtered by 'file')
250
+ ====================================
251
+
252
+ FileReader
253
+ ----------
254
+ Read and analyze file contents with support for multiple formats
255
+ including text, JSON, YAML, and CSV files.
256
+ ```
257
+
258
+ **Notes**:
259
+ - When no tools match the filter, displays "No tools match the filter: [filter]"
260
+ - Filtering is case-insensitive (e.g., "File", "FILE", and "file" all match)
261
+
237
262
  ### `//next`
238
263
  Set the next prompt to execute in a workflow.
239
264
 
@@ -509,11 +534,6 @@ SyntaxError: unexpected token
509
534
  ERROR: PUREMD_API_KEY is required in order to include a webpage
510
535
  ```
511
536
 
512
- **Missing Context Manager**:
513
- ```
514
- Error: Context manager not available for //clear directive.
515
- ```
516
-
517
537
  ### Custom Directives
518
538
 
519
539
  You can extend AIA with custom directives by creating Ruby files that define new directive methods:
data/docs/index.md CHANGED
@@ -126,13 +126,13 @@ graph TD
126
126
  - **AIA::PromptHandler** - Main prompt processing orchestrator
127
127
  - **AIA::ChatProcessorService** - Interactive chat session management
128
128
  - **AIA::DirectiveProcessor** - Processes embedded directives (`//command params`)
129
- - **AIA::ContextManager** - Manages conversation context and history
130
- - **AIA::RubyLLMAdapter** - Interfaces with the ruby_llm gem for AI model communication
129
+ - **AIA::RubyLLMAdapter** - Interfaces with the ruby_llm gem for AI model communication (manages conversation history via RubyLLM's Chat.@messages)
131
130
  - **AIA::ShellCommandExecutor** - Executes shell commands safely within prompts
132
131
  - **AIA::HistoryManager** - Manages prompt parameter history and user input
133
132
  - **AIA::UIPresenter** - Terminal output formatting and presentation
134
133
  - **AIA::Session** - Manages chat sessions and state
135
134
  - **AIA::Fzf** - Fuzzy finder integration for prompt selection
135
+ - **AIA::Directives::Checkpoint** - Manages conversation checkpoints, restore, clear, and review operations
136
136
 
137
137
  ### External Dependencies
138
138
 
@@ -140,6 +140,7 @@ module AIA
140
140
  config = tailor_the_config(config)
141
141
  load_libraries(config)
142
142
  load_tools(config)
143
+ load_mcp_servers(config)
143
144
 
144
145
  if config.dump_file
145
146
  dump_config(config, config.dump_file)
@@ -156,6 +157,9 @@ module AIA
156
157
  config.require_libs.each do |library|
157
158
  begin
158
159
  require(library)
160
+ # Check if the library provides tools that need eager loading
161
+ # Convert library name to module constant (e.g., 'shared_tools' -> 'SharedTools')
162
+ eager_load_tools_from_library(library)
159
163
  rescue => e
160
164
  STDERR.puts "Error loading library '#{library}' #{e.message}"
161
165
  exit_on_error = true
@@ -167,6 +171,23 @@ module AIA
167
171
  config
168
172
  end
169
173
 
174
+ # Attempt to eager load tools from a required library
175
+ # Libraries that use Zeitwerk need their tools eager loaded so they
176
+ # appear in ObjectSpace for AIA's tool discovery
177
+ def eager_load_tools_from_library(library)
178
+ # Convert library name to module constant (e.g., 'shared_tools' -> 'SharedTools')
179
+ module_name = library.split('/').first.split('_').map(&:capitalize).join
180
+
181
+ begin
182
+ mod = Object.const_get(module_name)
183
+ if mod.respond_to?(:load_all_tools)
184
+ mod.load_all_tools
185
+ end
186
+ rescue NameError
187
+ # Module doesn't exist with expected name, skip
188
+ end
189
+ end
190
+
170
191
  def load_tools(config)
171
192
  return if config.tool_paths.empty?
172
193
 
@@ -192,6 +213,64 @@ module AIA
192
213
  exit(1) if exit_on_error
193
214
  end
194
215
 
216
+ def load_mcp_servers(config)
217
+ servers = config.mcp_servers
218
+
219
+ return config if servers.nil? || (servers.respond_to?(:empty?) && servers.empty?)
220
+
221
+ servers.each do |server|
222
+ name = server[:name] || server["name"]
223
+ command = server[:command] || server["command"]
224
+ args = server[:args] || server["args"] || []
225
+ env = server[:env] || server["env"] || {}
226
+ timeout = server[:timeout] || server["timeout"] || 8000 # default 8 seconds in ms
227
+
228
+ unless name && command
229
+ STDERR.puts "WARNING: MCP server entry missing name or command: #{server.inspect}"
230
+ next
231
+ end
232
+
233
+ # Resolve command path if not absolute
234
+ resolved_command = resolve_command_path(command)
235
+ unless resolved_command
236
+ STDERR.puts "WARNING: MCP server '#{name}' command not found: #{command}"
237
+ next
238
+ end
239
+
240
+ begin
241
+ RubyLLM::MCP.add_client(
242
+ name: name,
243
+ transport_type: :stdio,
244
+ request_timeout: timeout,
245
+ config: {
246
+ command: resolved_command,
247
+ args: args,
248
+ env: env
249
+ }
250
+ )
251
+ rescue => e
252
+ STDERR.puts "ERROR: Failed to load MCP server '#{name}': #{e.message}"
253
+ end
254
+ end
255
+
256
+ config
257
+ end
258
+
259
+ def resolve_command_path(command)
260
+ # If already absolute path, verify it exists
261
+ if command.start_with?('/')
262
+ return File.executable?(command) ? command : nil
263
+ end
264
+
265
+ # Search in PATH
266
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
267
+ full_path = File.join(dir, command)
268
+ return full_path if File.executable?(full_path)
269
+ end
270
+
271
+ nil
272
+ end
273
+
195
274
  # envar values are always String object so need other config
196
275
  # layers to know the prompter type for each key's value
197
276
  def envar_options(default, cli_config)
@@ -82,6 +82,9 @@ module AIA
82
82
 
83
83
  # Ruby libraries to require for Ruby binding
84
84
  require_libs: [],
85
+
86
+ # MCP Servers (nil means not configured, set in config file)
87
+ mcp_servers: nil,
85
88
  }).freeze
86
89
  end
87
90
  end