aia 0.9.8 → 0.9.10
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 +15 -0
- data/README.md +62 -5
- data/Rakefile +16 -8
- data/examples/directives/ask.rb +21 -0
- data/examples/tools/edit_file.rb +2 -0
- data/examples/tools/incomplete/calculator_tool.rb +70 -0
- data/examples/tools/incomplete/composite_analysis_tool.rb +89 -0
- data/examples/tools/incomplete/data_science_kit.rb +128 -0
- data/examples/tools/incomplete/database_query_tool.rb +100 -0
- data/examples/tools/incomplete/devops_toolkit.rb +112 -0
- data/examples/tools/incomplete/error_handling_tool.rb +109 -0
- data/examples/tools/{pdf_page_reader.rb → incomplete/pdf_page_reader.rb} +2 -0
- data/examples/tools/incomplete/secure_tool_template.rb +117 -0
- data/examples/tools/incomplete/weather_tool.rb +110 -0
- data/examples/tools/incomplete/workflow_manager_tool.rb +145 -0
- data/examples/tools/list_files.rb +2 -0
- data/examples/tools/mcp/README.md +1 -0
- data/examples/tools/mcp/github_mcp_server.rb +41 -0
- data/examples/tools/mcp/imcp.rb +15 -0
- data/examples/tools/read_file.rb +2 -0
- data/examples/tools/run_shell_command.rb +2 -0
- data/justfile +3 -25
- data/lib/aia/chat_processor_service.rb +0 -3
- data/lib/aia/config.rb +542 -436
- data/lib/aia/context_manager.rb +3 -8
- data/lib/aia/directive_processor.rb +21 -10
- data/lib/aia/ruby_llm_adapter.rb +78 -10
- data/lib/aia/session.rb +187 -138
- data/lib/aia/ui_presenter.rb +7 -5
- data/lib/aia/utility.rb +26 -6
- data/lib/aia.rb +5 -1
- data/main.just +3 -25
- metadata +31 -12
- data/lib/aia/shell_command_executor.rb +0 -109
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c3bcf7e4888283a1ce66733f83d4d3ec1dc95420a7898462cc571ff6ccb134c
|
4
|
+
data.tar.gz: 07733fe911886e651569e1310a078474abf61f7f9cdeb16cfd9154758d936af5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94beb5af35dfcd044c7932eca574ab3c5c7a8451c303a99786e84096458927090a1886aefc83e02bf530e5bf6bcee0cba7ea7cbb5177efca1f3042670b8df8ff
|
7
|
+
data.tar.gz: 99e1f1ea2a751176d828f9c0cc18224875866977a21b91a8adceff6d8b339ac09632b55b8858ff3b4231e4d0e83180f9adfc340d3e0d76144f284288831317f3
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.10
|
data/CHANGELOG.md
CHANGED
@@ -3,10 +3,25 @@
|
|
3
3
|
|
4
4
|
## Released
|
5
5
|
|
6
|
+
### [0.9.10] 2025-07-18
|
7
|
+
- updated ruby_llm-mcp to version 0.6.1 which solves problems with MCP tools not being installed
|
8
|
+
|
9
|
+
### [0.9.9] 2025-07-10
|
10
|
+
- refactored the Session and Config classes into more testable method_missing
|
11
|
+
- updated the test suire for both the Session and Config classes
|
12
|
+
- added support for MCP servers coming into AIA via the shared_tools gem
|
13
|
+
- added +RubyLLM::MCP.support_complex_parameters! to patch ruby_llm gem until such time as it supports the more complex optional parameters in tool calls
|
14
|
+
- added an examples/tools/mcp directory with 2 MCP client definitions
|
15
|
+
- updated to ruby_llm-mcp gem version 0.5.1
|
16
|
+
- //model directive now dumps full model details
|
17
|
+
- //available_models now has context window size and capabilities for each model returned
|
18
|
+
|
19
|
+
|
6
20
|
### [0.9.8] 2025-06-25
|
7
21
|
- fixing an issue with pipelined prompts
|
8
22
|
- now showing the complete modality of the model on the processing line.
|
9
23
|
- changed -p option from prompts_dir to pipeline
|
24
|
+
- found problem with simple cov and deep cov w/r/t their reported test coverage; they have problems with heredoc and complex conditionals.
|
10
25
|
|
11
26
|
### [0.9.7] 2025-06-20
|
12
27
|
|
data/README.md
CHANGED
@@ -6,9 +6,15 @@
|
|
6
6
|
|
7
7
|
AIA is a command-line utility that facilitates interaction with AI models through dynamic prompt management. It automates the management of pre-compositional prompts and executes generative AI commands with enhanced features including embedded directives, shell integration, embedded Ruby, history management, interactive chat, and prompt workflows.
|
8
8
|
|
9
|
-
AIA leverages the
|
9
|
+
AIA leverages the following Ruby gems:
|
10
10
|
|
11
|
-
**
|
11
|
+
- **[prompt_manager](https://github.com/madbomber/prompt_manager)** to manage prompts,
|
12
|
+
- **[ruby_llm](https://rubyllm.com)** to access LLM providers,
|
13
|
+
- **[ruby_llm-mcp](https://www.rubyllm-mcp.com)** for Model Context Protocol (MCP) support,
|
14
|
+
- and can use the **[shared_tools gem](https://github.com/madbomber/shared_tools)** which provides a collection of common ready-to-use MCP clients and functions for use with LLMs that support tools.
|
15
|
+
|
16
|
+
**Wiki**: [Checkout the AIA Wiki](https://github.com/MadBomber/aia/wiki)<br />
|
17
|
+
**BLOG**: [Series on AIA](https://madbomber.github.io/blog/engineering/AIA-Philosophy/)
|
12
18
|
|
13
19
|
## Quick Start
|
14
20
|
|
@@ -74,6 +80,7 @@ AIA leverages the [prompt_manager gem](https://github.com/madbomber/prompt_manag
|
|
74
80
|
- [Prompt Directives](#prompt-directives)
|
75
81
|
- [Configuration Directive Examples](#configuration-directive-examples)
|
76
82
|
- [Dynamic Content Examples](#dynamic-content-examples)
|
83
|
+
- [Custom Directive Examples](#custom-directive-examples)
|
77
84
|
- [Shell Integration](#shell-integration)
|
78
85
|
- [Embedded Ruby (ERB)](#embedded-ruby-erb)
|
79
86
|
- [Prompt Sequences](#prompt-sequences)
|
@@ -112,6 +119,7 @@ AIA leverages the [prompt_manager gem](https://github.com/madbomber/prompt_manag
|
|
112
119
|
- [Areas for Improvement](#areas-for-improvement)
|
113
120
|
- [Roadmap](#roadmap)
|
114
121
|
- [License](#license)
|
122
|
+
- [Articles on AIA](#articles-on-aia)
|
115
123
|
|
116
124
|
<!-- Tocer[finish]: Auto-generated, don't remove. -->
|
117
125
|
|
@@ -358,6 +366,33 @@ Your prompt content here...
|
|
358
366
|
Analyze the above information and provide insights.
|
359
367
|
```
|
360
368
|
|
369
|
+
#### Custom Directive Examples
|
370
|
+
|
371
|
+
You can extend AIA with custom directives by creating Ruby files that define new directive methods:
|
372
|
+
|
373
|
+
```ruby
|
374
|
+
# examples/directives/ask.rb
|
375
|
+
module AIA
|
376
|
+
class DirectiveProcessor
|
377
|
+
private
|
378
|
+
desc "A meta-prompt to LLM making its response available as part of the primary prompt"
|
379
|
+
def ask(args, context_manager=nil)
|
380
|
+
meta_prompt = args.empty? ? "What is meta-prompting?" : args.join(' ')
|
381
|
+
AIA.config.client.chat(meta_prompt)
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
385
|
+
```
|
386
|
+
|
387
|
+
**Usage:** Use the --tools option to specific a specific directive file or a directory full of files
|
388
|
+
```bash
|
389
|
+
# Load custom directive
|
390
|
+
aia --tools examples/directives/ask.rb --chat
|
391
|
+
|
392
|
+
# Use the results of the custom directive as input to a prompt
|
393
|
+
//ask gather the latest closing data for the DOW, NASDAQ, and S&P 500
|
394
|
+
```
|
395
|
+
|
361
396
|
### Shell Integration
|
362
397
|
|
363
398
|
AIA automatically processes shell patterns in prompts:
|
@@ -499,6 +534,22 @@ aia --tools ~/tools/ --rejected_tools deprecated
|
|
499
534
|
- API integrations
|
500
535
|
- Data processing utilities
|
501
536
|
|
537
|
+
**MCP Client Examples** (see `examples/tools/mcp/` directory):
|
538
|
+
|
539
|
+
AIA supports Model Context Protocol (MCP) clients for extended functionality:
|
540
|
+
|
541
|
+
```bash
|
542
|
+
# GitHub MCP Server (requires: brew install github-mcp-server)
|
543
|
+
# Set GITHUB_PERSONAL_ACCESS_TOKEN environment variable
|
544
|
+
aia --tools examples/tools/mcp/github_mcp_server.rb --chat
|
545
|
+
|
546
|
+
# iMCP for macOS (requires: brew install --cask loopwork/tap/iMCP)
|
547
|
+
# Provides access to Notes, Calendar, Contacts, etc.
|
548
|
+
aia --tools examples/tools/mcp/imcp.rb --chat
|
549
|
+
```
|
550
|
+
|
551
|
+
These MCP clients require the `ruby_llm-mcp` gem and provide access to external services and data sources through the Model Context Protocol.
|
552
|
+
|
502
553
|
**Shared Tools Collection:**
|
503
554
|
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.
|
504
555
|
|
@@ -806,11 +857,17 @@ rake test
|
|
806
857
|
## Roadmap
|
807
858
|
|
808
859
|
- **Enhanced Search**: Restore full-text search within prompt files
|
809
|
-
- **Model Context Protocol**: Continue integration with ruby_llm gem
|
810
860
|
- **UI Improvements**: Better configuration management for fzf and rg tools
|
811
|
-
- **
|
812
|
-
- **Security**: Enhanced sandboxing for shell command execution
|
861
|
+
- **Logging**: Enhanced logging using Ruby Logger class; integration with RubyLLM and RubyLLM::MCP logging
|
813
862
|
|
814
863
|
## License
|
815
864
|
|
816
865
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
866
|
+
|
867
|
+
## Articles on AIA
|
868
|
+
|
869
|
+
1. [The Philosophy of Prompt-Driven Development with AIA](https://madbomber.github.io/blog/engineering/AIA-Philosophy/)
|
870
|
+
2. [Mastering AIA's Batch Mode: From Simple Questions to Complex Workflows](https://madbomber.github.io/blog/engineering/AIA-Batch-Mode/)
|
871
|
+
3. [Building AI Workflows: AIA's Prompt Sequencing and Pipelines](https://madbomber.github.io/blog/engineering/AIA-Workflows/)
|
872
|
+
4. [Interactive AI Sessions: Mastering AIA's Chat Mode](https://madbomber.github.io/blog/engineering/AIA-Chat-Mode/)
|
873
|
+
5. [From Dynamic Prompts to Advanced Tool Integration](https://madbomber.github.io/blog/engineering/AIA-Advanced-Tool-Integration/)
|
data/Rakefile
CHANGED
@@ -2,23 +2,31 @@
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require "tocer/rake/register"
|
5
|
-
|
6
|
-
|
5
|
+
Tocer::Rake::Register.call
|
6
|
+
rescue LoadError, StandardError => e
|
7
|
+
warn "Skipping tocer tasks: #{e.message}"
|
7
8
|
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
begin
|
11
|
+
require 'kramdown/man/task'
|
12
|
+
Kramdown::Man::Task.new
|
13
|
+
rescue LoadError, StandardError => e
|
14
|
+
warn "Skipping kramdown man task: #{e.message}"
|
15
|
+
end
|
13
16
|
|
14
|
-
|
17
|
+
begin
|
18
|
+
require "bundler/gem_tasks"
|
19
|
+
rescue LoadError, StandardError => e
|
20
|
+
warn "Skipping bundler/gem_tasks: #{e.message}"
|
21
|
+
end
|
15
22
|
require "minitest/test_task"
|
16
23
|
|
17
24
|
Minitest::TestTask.create(:test) do |t|
|
18
25
|
t.libs << "test"
|
19
26
|
t.libs << "lib"
|
20
27
|
t.warning = false
|
21
|
-
|
28
|
+
# Include all unit tests under test/, excluding integration tests
|
29
|
+
t.test_globs = ["test/**/*_test.rb", "!test/integration/**/*_test.rb"]
|
22
30
|
end
|
23
31
|
|
24
32
|
Minitest::TestTask.create(:integration) do |t|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# ~/examples/directives/ask.rb
|
2
|
+
# Desc: An example of how to extend the AIA directives
|
3
|
+
# Usage: aia <options> --require path/to/ask.rb
|
4
|
+
#
|
5
|
+
# A directive is just a private method of the AIA::DirectiveProcessor class. its
|
6
|
+
# definition is preceeded by the `desc` method which has a single String parameter
|
7
|
+
# that is a description of the directive. This discription is shown with the
|
8
|
+
# directive's name in the --chat mode with the //help directive is used.
|
9
|
+
|
10
|
+
module AIA
|
11
|
+
class DirectiveProcessor
|
12
|
+
private
|
13
|
+
desc "A meta-prompt to LLM making its response available as part of the primary prompt"
|
14
|
+
# args is an Array of Strings
|
15
|
+
# context_manager is an optional parameter TBD
|
16
|
+
def ask(args, context_manager=nil)
|
17
|
+
meta_prompt = args.empty? ? "What is meta-prompting?" : args.join(' ')
|
18
|
+
AIA.config.client.chat(meta_prompt)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/examples/tools/edit_file.rb
CHANGED
@@ -0,0 +1,70 @@
|
|
1
|
+
# calculator_tool.rb - Simple custom tool example
|
2
|
+
require 'ruby_llm/tool'
|
3
|
+
|
4
|
+
module Tools
|
5
|
+
class Calculator < RubyLLM::Tool
|
6
|
+
def self.name = "calculator"
|
7
|
+
|
8
|
+
description <<~DESCRIPTION
|
9
|
+
Perform advanced mathematical calculations with comprehensive error handling and validation.
|
10
|
+
This tool supports basic arithmetic operations, parentheses, and common mathematical functions.
|
11
|
+
It provides safe evaluation of mathematical expressions without executing arbitrary code,
|
12
|
+
making it suitable for use in AI-assisted calculations where security is important.
|
13
|
+
The tool returns formatted results with configurable precision and helpful error messages
|
14
|
+
when invalid expressions are provided.
|
15
|
+
DESCRIPTION
|
16
|
+
|
17
|
+
param :expression,
|
18
|
+
desc: <<~DESC,
|
19
|
+
Mathematical expression to evaluate using standard arithmetic operators and parentheses.
|
20
|
+
Supported operations include: addition (+), subtraction (-), multiplication (*), division (/),
|
21
|
+
and parentheses for grouping. Examples: '2 + 2', '(10 * 5) / 2', '15.5 - 3.2'.
|
22
|
+
Only numeric characters, operators, parentheses, decimal points, and spaces are allowed
|
23
|
+
for security reasons. Complex mathematical functions are not supported in this version.
|
24
|
+
DESC
|
25
|
+
type: :string,
|
26
|
+
required: true
|
27
|
+
|
28
|
+
param :precision,
|
29
|
+
desc: <<~DESC,
|
30
|
+
Number of decimal places to display in the result. Must be a non-negative integer.
|
31
|
+
Set to 0 for whole numbers only, or higher values for more precise decimal results.
|
32
|
+
Default is 2 decimal places, which works well for most financial and general calculations.
|
33
|
+
Maximum precision is limited to 10 decimal places to prevent excessive output.
|
34
|
+
DESC
|
35
|
+
type: :integer,
|
36
|
+
default: 2
|
37
|
+
|
38
|
+
def execute(expression:, precision: 2)
|
39
|
+
begin
|
40
|
+
# Use safe evaluation instead of raw eval
|
41
|
+
result = safe_eval(expression)
|
42
|
+
formatted_result = result.round(precision)
|
43
|
+
|
44
|
+
{
|
45
|
+
success: true,
|
46
|
+
result: formatted_result,
|
47
|
+
expression: expression,
|
48
|
+
precision: precision
|
49
|
+
}
|
50
|
+
rescue => e
|
51
|
+
{
|
52
|
+
success: false,
|
53
|
+
error: "Invalid expression: #{e.message}",
|
54
|
+
expression: expression,
|
55
|
+
suggestion: "Try expressions like '2 + 2' or '10 * 5'"
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def safe_eval(expression)
|
63
|
+
# Implement safe mathematical evaluation
|
64
|
+
# This is a simplified example - use a proper math parser in production
|
65
|
+
allowed_chars = /\A[0-9+\-*\/\(\)\.\s]+\z/
|
66
|
+
raise "Invalid characters in expression" unless expression.match?(allowed_chars)
|
67
|
+
eval(expression)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# composite_analysis_tool.rb - Tool that uses other tools
|
2
|
+
require 'ruby_llm/tool'
|
3
|
+
|
4
|
+
module Tools
|
5
|
+
class CompositeAnalysis < RubyLLM::Tool
|
6
|
+
def self.name = "composite_analysis"
|
7
|
+
|
8
|
+
description <<~DESCRIPTION
|
9
|
+
Perform comprehensive multi-stage data analysis by orchestrating multiple specialized tools
|
10
|
+
to provide complete insights from various data sources. This composite tool automatically
|
11
|
+
determines the appropriate data fetching method (web scraping for URLs, file reading for
|
12
|
+
local paths), analyzes data structure and content, generates statistical insights,
|
13
|
+
and suggests appropriate visualizations based on the data characteristics.
|
14
|
+
Ideal for exploratory data analysis workflows where you need a complete picture
|
15
|
+
from initial data loading through final insights.
|
16
|
+
DESCRIPTION
|
17
|
+
|
18
|
+
param :data_source,
|
19
|
+
desc: <<~DESC,
|
20
|
+
Primary data source to analyze. Can be either a local file path or a web URL.
|
21
|
+
For files: Use relative or absolute paths to CSV, JSON, XML, or text files.
|
22
|
+
For URLs: Use complete HTTP/HTTPS URLs to accessible data endpoints or web pages.
|
23
|
+
The tool automatically detects the source type and uses appropriate fetching methods.
|
24
|
+
Examples: './data/sales.csv', '/home/user/data.json', 'https://api.example.com/data'
|
25
|
+
DESC
|
26
|
+
type: :string,
|
27
|
+
required: true
|
28
|
+
|
29
|
+
def execute(data_source:)
|
30
|
+
results = {}
|
31
|
+
|
32
|
+
begin
|
33
|
+
# Step 1: Fetch data using appropriate tool
|
34
|
+
if data_source.start_with?('http')
|
35
|
+
results[:data] = fetch_web_data(data_source)
|
36
|
+
else
|
37
|
+
results[:data] = read_file_data(data_source)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Step 2: Analyze data structure
|
41
|
+
results[:structure] = analyze_data_structure(results[:data])
|
42
|
+
|
43
|
+
# Step 3: Generate insights
|
44
|
+
results[:insights] = generate_insights(results[:data], results[:structure])
|
45
|
+
|
46
|
+
# Step 4: Create visualizations if applicable
|
47
|
+
if results[:structure][:numeric_columns]&.any?
|
48
|
+
results[:visualizations] = suggest_visualizations(results[:structure])
|
49
|
+
end
|
50
|
+
|
51
|
+
{
|
52
|
+
success: true,
|
53
|
+
analysis: results,
|
54
|
+
data_source: data_source,
|
55
|
+
analyzed_at: Time.now.iso8601
|
56
|
+
}
|
57
|
+
rescue => e
|
58
|
+
{
|
59
|
+
success: false,
|
60
|
+
error: e.message,
|
61
|
+
data_source: data_source,
|
62
|
+
partial_results: results
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def fetch_web_data(url)
|
70
|
+
# TODO: Use shared web tools or custom HTTP client
|
71
|
+
end
|
72
|
+
|
73
|
+
def read_file_data(file_path)
|
74
|
+
# TODO: Use shared file tools
|
75
|
+
end
|
76
|
+
|
77
|
+
def analyze_data_structure(data)
|
78
|
+
# TODO: Implementation for data structure analysis
|
79
|
+
end
|
80
|
+
|
81
|
+
def generate_insights(data, structure)
|
82
|
+
# TODO: Implementation for insight generation
|
83
|
+
end
|
84
|
+
|
85
|
+
def suggest_visualizations(structure)
|
86
|
+
# TODO:Implementation for visualization suggestions
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# data_science_kit.rb - Analytics and ML tools
|
2
|
+
require 'ruby_llm/tool'
|
3
|
+
|
4
|
+
module Tools
|
5
|
+
class DataScienceKit < RubyLLM::Tool
|
6
|
+
def self.name = "data_science_kit"
|
7
|
+
|
8
|
+
description <<~DESCRIPTION
|
9
|
+
Comprehensive data science and analytics toolkit for performing statistical analysis,
|
10
|
+
machine learning tasks, and data exploration on various data sources. This tool provides
|
11
|
+
a unified interface for common data science operations including descriptive statistics,
|
12
|
+
correlation analysis, time series analysis, clustering algorithms, and predictive modeling.
|
13
|
+
It automatically handles data loading, validation, preprocessing, and result formatting.
|
14
|
+
Supports multiple data formats and provides detailed analysis results with visualizations
|
15
|
+
recommendations and statistical significance testing where applicable.
|
16
|
+
DESCRIPTION
|
17
|
+
|
18
|
+
param :analysis_type,
|
19
|
+
desc: <<~DESC,
|
20
|
+
Type of data science analysis to perform:
|
21
|
+
- 'statistical_summary': Descriptive statistics, distributions, outlier detection
|
22
|
+
- 'correlation_analysis': Correlation matrices, feature relationships, dependency analysis
|
23
|
+
- 'time_series': Trend analysis, seasonality detection, forecasting
|
24
|
+
- 'clustering': K-means, hierarchical clustering, cluster analysis
|
25
|
+
- 'prediction': Regression analysis, classification, predictive modeling
|
26
|
+
Each analysis type requires specific data formats and optional parameters.
|
27
|
+
DESC
|
28
|
+
type: :string,
|
29
|
+
required: true,
|
30
|
+
enum: ["statistical_summary", "correlation_analysis", "time_series", "clustering", "prediction"]
|
31
|
+
|
32
|
+
param :data_source,
|
33
|
+
desc: <<~DESC,
|
34
|
+
Data source specification for analysis. Can be:
|
35
|
+
- File path: Relative or absolute path to CSV, JSON, Excel, or Parquet files
|
36
|
+
- Database query: SQL SELECT statement for database-sourced data
|
37
|
+
- API endpoint: HTTP URL for REST API data sources
|
38
|
+
The tool automatically detects the format and applies appropriate parsing.
|
39
|
+
Examples: './sales_data.csv', 'SELECT * FROM transactions', 'https://api.company.com/data'
|
40
|
+
DESC
|
41
|
+
type: :string,
|
42
|
+
required: true
|
43
|
+
|
44
|
+
param :parameters,
|
45
|
+
desc: <<~DESC,
|
46
|
+
Hash of analysis-specific parameters and configuration options:
|
47
|
+
- statistical_summary: confidence_level, include_quartiles, outlier_method
|
48
|
+
- correlation_analysis: method (pearson/spearman), significance_level
|
49
|
+
- time_series: date_column, value_column, frequency, forecast_periods
|
50
|
+
- clustering: n_clusters, algorithm (kmeans/hierarchical), distance_metric
|
51
|
+
- prediction: target_column, feature_columns, model_type, validation_split
|
52
|
+
Default empty hash uses standard parameters for each analysis type.
|
53
|
+
DESC
|
54
|
+
type: :hash,
|
55
|
+
default: {}
|
56
|
+
|
57
|
+
def execute(analysis_type:, data_source:, parameters: {})
|
58
|
+
begin
|
59
|
+
# Load and validate data
|
60
|
+
data = load_data(data_source)
|
61
|
+
validate_data_for_analysis(data, analysis_type)
|
62
|
+
|
63
|
+
# Perform analysis
|
64
|
+
result = case analysis_type
|
65
|
+
when "statistical_summary"
|
66
|
+
generate_statistical_summary(data, parameters)
|
67
|
+
when "correlation_analysis"
|
68
|
+
perform_correlation_analysis(data, parameters)
|
69
|
+
when "time_series"
|
70
|
+
analyze_time_series(data, parameters)
|
71
|
+
when "clustering"
|
72
|
+
perform_clustering(data, parameters)
|
73
|
+
when "prediction"
|
74
|
+
generate_predictions(data, parameters)
|
75
|
+
end
|
76
|
+
|
77
|
+
{
|
78
|
+
success: true,
|
79
|
+
analysis_type: analysis_type,
|
80
|
+
result: result,
|
81
|
+
data_summary: summarize_data(data),
|
82
|
+
analyzed_at: Time.now.iso8601
|
83
|
+
}
|
84
|
+
rescue => e
|
85
|
+
{
|
86
|
+
success: false,
|
87
|
+
error: e.message,
|
88
|
+
analysis_type: analysis_type,
|
89
|
+
data_source: data_source
|
90
|
+
}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def load_data(source)
|
97
|
+
# TODO: Implementation for data loading from various sources
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_data_for_analysis(data, analysis_type)
|
101
|
+
# TODO: Implementation for data validation
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate_statistical_summary(data, parameters)
|
105
|
+
# TODO: Implementation for statistical summary
|
106
|
+
end
|
107
|
+
|
108
|
+
def perform_correlation_analysis(data, parameters)
|
109
|
+
# TODO: Implementation for correlation analysis
|
110
|
+
end
|
111
|
+
|
112
|
+
def analyze_time_series(data, parameters)
|
113
|
+
# TODO: Implementation for time series analysis
|
114
|
+
end
|
115
|
+
|
116
|
+
def perform_clustering(data, parameters)
|
117
|
+
# TODO: Implementation for clustering
|
118
|
+
end
|
119
|
+
|
120
|
+
def generate_predictions(data, parameters)
|
121
|
+
# TODO: Implementation for prediction
|
122
|
+
end
|
123
|
+
|
124
|
+
def summarize_data(data)
|
125
|
+
# TODO: Implementation for data summary
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# database_query_tool.rb - Database interaction example
|
2
|
+
require 'ruby_llm/tool'
|
3
|
+
require 'sequel'
|
4
|
+
|
5
|
+
module Tools
|
6
|
+
class DatabaseQuery < RubyLLM::Tool
|
7
|
+
def self.name = "database_query"
|
8
|
+
|
9
|
+
description <<~DESCRIPTION
|
10
|
+
Execute safe, read-only database queries with automatic connection management and security controls.
|
11
|
+
This tool is designed for secure data retrieval operations only, restricting access to SELECT statements
|
12
|
+
to prevent any data modification. It includes automatic connection pooling, query result limiting,
|
13
|
+
and comprehensive error handling. The tool supports multiple database configurations through
|
14
|
+
environment variables and ensures all connections are properly closed after use.
|
15
|
+
Perfect for AI-assisted data analysis and reporting workflows where read-only access is required.
|
16
|
+
DESCRIPTION
|
17
|
+
|
18
|
+
param :query,
|
19
|
+
desc: <<~DESC,
|
20
|
+
SQL SELECT query to execute against the database. Only SELECT statements are permitted
|
21
|
+
for security reasons - INSERT, UPDATE, DELETE, and DDL statements will be rejected.
|
22
|
+
The query should be well-formed SQL appropriate for the target database system.
|
23
|
+
Examples: 'SELECT * FROM users WHERE active = true', 'SELECT COUNT(*) FROM orders'.
|
24
|
+
Table and column names should match the database schema exactly.
|
25
|
+
DESC
|
26
|
+
type: :string,
|
27
|
+
required: true
|
28
|
+
|
29
|
+
param :database,
|
30
|
+
desc: <<~DESC,
|
31
|
+
Database configuration name to use for the connection. This corresponds to environment
|
32
|
+
variables like DATABASE_URL, STAGING_DATABASE_URL, etc. The tool will look for
|
33
|
+
an environment variable named {DATABASE_NAME}_DATABASE_URL (uppercase).
|
34
|
+
Default is 'default' which looks for DEFAULT_DATABASE_URL environment variable.
|
35
|
+
Common values: 'default', 'staging', 'analytics', 'reporting'.
|
36
|
+
DESC
|
37
|
+
type: :string,
|
38
|
+
default: "default"
|
39
|
+
|
40
|
+
param :limit,
|
41
|
+
desc: <<~DESC,
|
42
|
+
Maximum number of rows to return from the query to prevent excessive memory usage
|
43
|
+
and long response times. The tool automatically adds a LIMIT clause if one is not
|
44
|
+
present in the original query. Set to a reasonable value based on expected data size.
|
45
|
+
Minimum: 1, Maximum: 10000, Default: 100. For large datasets, consider using
|
46
|
+
pagination or more specific WHERE clauses.
|
47
|
+
DESC
|
48
|
+
type: :integer,
|
49
|
+
default: 100
|
50
|
+
|
51
|
+
def execute(query:, database: "default", limit: 100)
|
52
|
+
begin
|
53
|
+
# Security: Only allow SELECT queries
|
54
|
+
normalized_query = query.strip.downcase
|
55
|
+
unless normalized_query.start_with?('select')
|
56
|
+
raise "Only SELECT queries are allowed for security"
|
57
|
+
end
|
58
|
+
|
59
|
+
db = connect_to_database(database)
|
60
|
+
limited_query = add_limit_to_query(query, limit)
|
61
|
+
|
62
|
+
results = db[limited_query].all
|
63
|
+
|
64
|
+
{
|
65
|
+
success: true,
|
66
|
+
query: limited_query,
|
67
|
+
row_count: results.length,
|
68
|
+
data: results,
|
69
|
+
database: database,
|
70
|
+
executed_at: Time.now.iso8601
|
71
|
+
}
|
72
|
+
rescue => e
|
73
|
+
{
|
74
|
+
success: false,
|
75
|
+
error: e.message,
|
76
|
+
query: query,
|
77
|
+
database: database
|
78
|
+
}
|
79
|
+
ensure
|
80
|
+
db&.disconnect
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def connect_to_database(database_name)
|
87
|
+
# Implementation depends on your database setup
|
88
|
+
connection_string = ENV["#{database_name.upcase}_DATABASE_URL"]
|
89
|
+
raise "Database connection not configured for #{database_name}" unless connection_string
|
90
|
+
|
91
|
+
Sequel.connect(connection_string)
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_limit_to_query(query, limit)
|
95
|
+
# Add LIMIT clause if not present
|
96
|
+
query += " LIMIT #{limit}" unless query.downcase.include?('limit')
|
97
|
+
query
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|