rubycode 0.1.3 → 0.1.4
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/.env.example +38 -0
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +52 -0
- data/README.md +101 -23
- data/USAGE.md +1 -23
- data/config/locales/en.yml +208 -1
- data/config/system_prompt.md +6 -1
- data/config/tools/bash.json +1 -1
- data/config/tools/fetch.json +22 -0
- data/config/tools/websearch.json +22 -0
- data/docs/images/demo.png +0 -0
- data/lib/rubycode/adapters/base.rb +92 -2
- data/lib/rubycode/adapters/concerns/debugging.rb +32 -0
- data/lib/rubycode/adapters/concerns/error_handling.rb +89 -0
- data/lib/rubycode/adapters/concerns/http_client.rb +67 -0
- data/lib/rubycode/adapters/deepseek.rb +97 -0
- data/lib/rubycode/adapters/gemini.rb +133 -0
- data/lib/rubycode/adapters/ollama.rb +114 -82
- data/lib/rubycode/adapters/openai.rb +97 -0
- data/lib/rubycode/adapters/openrouter.rb +102 -0
- data/lib/rubycode/agent_loop.rb +110 -18
- data/lib/rubycode/client/approval_handler.rb +14 -0
- data/lib/rubycode/client/display_formatter.rb +18 -10
- data/lib/rubycode/client/response_handler.rb +4 -23
- data/lib/rubycode/client.rb +9 -0
- data/lib/rubycode/config_manager.rb +81 -0
- data/lib/rubycode/configuration.rb +21 -10
- data/lib/rubycode/database.rb +19 -0
- data/lib/rubycode/errors.rb +12 -0
- data/lib/rubycode/models/api_key.rb +118 -0
- data/lib/rubycode/models/memory.rb +84 -10
- data/lib/rubycode/models.rb +1 -0
- data/lib/rubycode/pricing.rb +59 -0
- data/lib/rubycode/search_providers/base.rb +66 -0
- data/lib/rubycode/search_providers/brave_search.rb +60 -0
- data/lib/rubycode/search_providers/concerns/debugging.rb +37 -0
- data/lib/rubycode/search_providers/concerns/error_handling.rb +64 -0
- data/lib/rubycode/search_providers/concerns/http_client.rb +67 -0
- data/lib/rubycode/search_providers/duckduckgo_instant.rb +98 -0
- data/lib/rubycode/search_providers/exa_ai.rb +171 -0
- data/lib/rubycode/search_providers/multi_provider.rb +47 -0
- data/lib/rubycode/token_counter.rb +41 -0
- data/lib/rubycode/tools/bash.rb +38 -8
- data/lib/rubycode/tools/fetch.rb +120 -0
- data/lib/rubycode/tools/web_search.rb +122 -0
- data/lib/rubycode/tools.rb +5 -1
- data/lib/rubycode/value_objects.rb +8 -4
- data/lib/rubycode/version.rb +1 -1
- data/lib/rubycode/views/adapter/debug_delay.rb +20 -0
- data/lib/rubycode/views/adapter/debug_request.rb +33 -0
- data/lib/rubycode/views/adapter/debug_response.rb +31 -0
- data/lib/rubycode/views/agent_loop/token_summary.rb +54 -0
- data/lib/rubycode/views/agent_loop.rb +2 -0
- data/lib/rubycode/views/cli/api_key_missing.rb +37 -0
- data/lib/rubycode/views/cli/config_saved.rb +17 -0
- data/lib/rubycode/views/cli/configuration_table.rb +3 -3
- data/lib/rubycode/views/cli/first_time_setup.rb +17 -0
- data/lib/rubycode/views/cli/restart_message.rb +17 -0
- data/lib/rubycode/views/cli/setup_title.rb +17 -0
- data/lib/rubycode/views/cli.rb +5 -0
- data/lib/rubycode/views/formatter/fetch_summary.rb +54 -0
- data/lib/rubycode/views/formatter/web_search_summary.rb +53 -0
- data/lib/rubycode/views/formatter.rb +2 -0
- data/lib/rubycode/views/search_provider/debug_request.rb +30 -0
- data/lib/rubycode/views/search_provider/debug_response.rb +31 -0
- data/lib/rubycode/views/web_search_approval.rb +29 -0
- data/lib/rubycode/views.rb +5 -0
- data/lib/rubycode.rb +10 -0
- data/rubycode_cli.rb +228 -32
- metadata +81 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 38eb208124cc78e03b6a8fb2778309dc17999ed1ab50270fbbfc3635f5d144d2
|
|
4
|
+
data.tar.gz: c02ee8d739bf3162d2e3e2fb5e16adcd00d9a373b3223e6e3d2ae6694f75c22d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29a2f388ff00077112e5f3697a1fbca342ba5a9974bf7b306c862f4b97f78585c3357366c6980ca5c71c21944e191243ac4e84e59f6451492e140fb711d15314
|
|
7
|
+
data.tar.gz: bc30616c062dd24865f4ec9d2c93cae55569dec5d17c0648d39d6c6aa3059ca91d736b7867e4f0b7015de514182d145b47a5b93e7b297832134f26e922e6e93b
|
data/.env.example
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# RubyCode Environment Variables
|
|
2
|
+
# Copy this file to .env and fill in your API keys
|
|
3
|
+
|
|
4
|
+
# ====================================
|
|
5
|
+
# LLM Providers
|
|
6
|
+
# ====================================
|
|
7
|
+
|
|
8
|
+
# Ollama API Key (required if using Ollama adapter)
|
|
9
|
+
# Get your key: https://ollama.ai/
|
|
10
|
+
# OLLAMA_API_KEY=your_ollama_api_key_here
|
|
11
|
+
|
|
12
|
+
# DeepSeek API Key (required if using DeepSeek adapter)
|
|
13
|
+
# Get your key: https://platform.deepseek.com/api_keys
|
|
14
|
+
# DEEPSEEK_API_KEY=your_deepseek_api_key_here
|
|
15
|
+
|
|
16
|
+
# Gemini API Key (required if using Gemini adapter)
|
|
17
|
+
# Get your key: https://makersuite.google.com/app/apikey
|
|
18
|
+
# GEMINI_API_KEY=your_gemini_api_key_here
|
|
19
|
+
|
|
20
|
+
# OpenAI API Key (required if using OpenAI adapter)
|
|
21
|
+
# Get your key: https://platform.openai.com/api-keys
|
|
22
|
+
# OPENAI_API_KEY=your_openai_api_key_here
|
|
23
|
+
|
|
24
|
+
# OpenRouter API Key (required if using OpenRouter adapter)
|
|
25
|
+
# Get your key: https://openrouter.ai/keys
|
|
26
|
+
# OPENROUTER_API_KEY=your_openrouter_api_key_here
|
|
27
|
+
|
|
28
|
+
# ====================================
|
|
29
|
+
# Web Search Providers
|
|
30
|
+
# ====================================
|
|
31
|
+
|
|
32
|
+
# Exa.ai API Key (optional - enables AI-native web search)
|
|
33
|
+
# Get your key: https://exa.ai/api
|
|
34
|
+
# EXA_API_KEY=your_exa_api_key_here
|
|
35
|
+
|
|
36
|
+
# Brave Search API Key (optional - alternative search provider)
|
|
37
|
+
# Get your key: https://brave.com/search/api/
|
|
38
|
+
# BRAVE_API_KEY=your_brave_api_key_here
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.1.4] - 2026-03-07
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Multiple Cloud LLM Adapters**: Support for 5 cloud providers (Ollama Cloud, DeepSeek, Gemini, OpenAI, OpenRouter)
|
|
7
|
+
- **Web Search & Fetch Tools**: Internet search via DuckDuckGo, Brave, and Exa.ai with automatic fallback
|
|
8
|
+
- **Interactive Setup Wizard**: First-time configuration with provider/model selection and API key management
|
|
9
|
+
- **Encrypted API Key Storage**: Secure database storage for API keys with AES-256-GCM encryption
|
|
10
|
+
- **Configuration Persistence**: Automatic saving and loading of user preferences
|
|
11
|
+
- **Search Provider Architecture**: Base class with concerns for HTTP client, error handling, and debugging
|
|
12
|
+
- **Adapter Architecture**: Refactored with base class and shared concerns (66% code reduction)
|
|
13
|
+
- **Debug Mode**: Comprehensive request/response logging for adapters and search providers
|
|
14
|
+
- **Rate Limit Handling**: Automatic detection and retry with 3-attempt limit for 429 errors
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **Bash Tool**: Improved with real-time output streaming and non-interactive execution
|
|
18
|
+
- **System Prompt**: Added web_search and fetch tool documentation for LLM awareness
|
|
19
|
+
- **View Layer**: Enhanced web_search and fetch summaries with full URLs and metadata
|
|
20
|
+
- **Search Providers**: Reduced code duplication from ~100 lines per provider to shared base class
|
|
21
|
+
- **Adapters**: Reduced from ~900 lines to ~300 lines with shared concerns
|
|
22
|
+
- **Memory Management**: Clear conversation history on session start to prevent payload size issues
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **Agent Loop Exit Bug**: Agent now properly stops when `done` tool is called, even if tool execution fails
|
|
26
|
+
- **Bash Tool stdin_data Error**: Removed invalid stdin_data option from Open3.popen2e
|
|
27
|
+
- **Search Provider Transparency**: Now displays which provider (DuckDuckGo/Brave/Exa) returned results
|
|
28
|
+
- **RuboCop Compliance**: Reduced violations from 45 to 39 (all acceptable complexity metrics)
|
|
29
|
+
- **Test Suite**: Expanded coverage to 141 tests (379 assertions) including adapter and agent loop tests
|
|
30
|
+
|
|
31
|
+
## [0.1.3] - 2026-03-05
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- **Write & Update Tools**: New file creation and editing capabilities with user approval workflow
|
|
35
|
+
- **Persistent Memory**: SQLite-backed conversation history using Sequel ORM
|
|
36
|
+
- **Network Resilience**: Automatic retry with exponential backoff for failed LLM requests (configurable timeouts and retries)
|
|
37
|
+
- **Enhanced CLI**: TTY-based interface with formatted output, progress indicators, and approval prompts
|
|
38
|
+
- **I18n Support**: Internationalized error messages and system prompts
|
|
39
|
+
- **Comprehensive Test Suite**: Added test coverage for Database, Memory, and Models::Base classes
|
|
40
|
+
- **Configuration Options**: HTTP timeout settings (read_timeout, open_timeout, max_retries, retry_base_delay)
|
|
41
|
+
- **Cross-platform Support**: Added Linux platform support for CI/CD environments
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- Migrated from raw SQLite3 to Sequel ORM for better database abstraction
|
|
45
|
+
- Separated database connection management from model classes
|
|
46
|
+
- Refactored view layer with dedicated view classes for all UI components
|
|
47
|
+
- Improved error handling with adapter-specific error classes
|
|
48
|
+
- Updated gemspec description to be more comprehensive
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
- Approval prompt now properly waits for user input instead of auto-declining
|
|
52
|
+
- Models::Base.last now properly orders by ID before retrieving
|
|
53
|
+
- RuboCop compliance across entire codebase
|
|
54
|
+
|
|
3
55
|
## [0.1.0] - 2026-02-28
|
|
4
56
|
|
|
5
57
|
- Initial release
|
data/README.md
CHANGED
|
@@ -16,19 +16,28 @@ A Ruby-native AI coding assistant with pluggable LLM adapters. RubyCode provides
|
|
|
16
16
|
## Features
|
|
17
17
|
|
|
18
18
|
- **AI Agent Loop**: Autonomous task execution with tool calling
|
|
19
|
-
- **
|
|
19
|
+
- **Multiple Cloud LLM Adapters**: Support for Ollama Cloud, DeepSeek, Gemini, OpenAI, and OpenRouter
|
|
20
|
+
- **Interactive Setup Wizard**: First-time configuration with provider selection and API key management
|
|
20
21
|
- **Built-in Tools**:
|
|
21
22
|
- `bash`: Execute safe bash commands for filesystem exploration
|
|
22
23
|
- `search`: Search file contents using grep with regex support
|
|
23
24
|
- `read`: Read files and directories with line numbers
|
|
24
25
|
- `write`: Create new files with user approval
|
|
25
26
|
- `update`: Edit existing files with user approval
|
|
27
|
+
- `web_search`: Search the internet with automatic provider fallback (DuckDuckGo/Brave/Exa)
|
|
28
|
+
- `fetch`: Fetch content from URLs
|
|
26
29
|
- `done`: Signal task completion with final answer
|
|
27
30
|
- **Persistent Memory**: SQLite-backed conversation history with Sequel ORM
|
|
31
|
+
- **Encrypted API Key Storage**: Secure database storage with AES-256-GCM encryption
|
|
32
|
+
- **Configuration Persistence**: Automatic saving and loading of preferences
|
|
28
33
|
- **Enhanced CLI**: TTY-based interface with formatted output, progress indicators, and approval workflows
|
|
29
|
-
- **Resilient Network**: Automatic retry with exponential backoff
|
|
34
|
+
- **Resilient Network**: Automatic retry with exponential backoff and rate limit handling
|
|
35
|
+
- **Debug Mode**: Comprehensive request/response logging for adapters and search providers
|
|
30
36
|
- **I18n Support**: Internationalized error messages and UI text
|
|
31
|
-
|
|
37
|
+
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
- Ruby 3.1 or higher
|
|
32
41
|
|
|
33
42
|
## Installation
|
|
34
43
|
|
|
@@ -54,16 +63,30 @@ bundle install
|
|
|
54
63
|
|
|
55
64
|
### Basic Usage
|
|
56
65
|
|
|
66
|
+
#### Interactive CLI (Recommended)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
rubycode
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The first time you run RubyCode, an interactive setup wizard will guide you through:
|
|
73
|
+
1. Selecting your LLM provider (Ollama Cloud, DeepSeek, Gemini, OpenAI, or OpenRouter)
|
|
74
|
+
2. Choosing a model
|
|
75
|
+
3. Entering API keys (saved securely with encryption)
|
|
76
|
+
|
|
77
|
+
Your configuration is automatically saved and reloaded on subsequent runs.
|
|
78
|
+
|
|
79
|
+
#### Programmatic Usage
|
|
80
|
+
|
|
57
81
|
```ruby
|
|
58
82
|
require "rubycode"
|
|
59
83
|
|
|
60
84
|
# Configure the LLM adapter
|
|
61
85
|
RubyCode.configure do |config|
|
|
62
86
|
config.adapter = :ollama
|
|
63
|
-
config.url = "
|
|
64
|
-
config.model = "
|
|
87
|
+
config.url = "https://api.ollama.com"
|
|
88
|
+
config.model = "qwen3-coder:480b-cloud"
|
|
65
89
|
config.root_path = Dir.pwd
|
|
66
|
-
config.debug = false
|
|
67
90
|
end
|
|
68
91
|
|
|
69
92
|
# Create a client and ask a question
|
|
@@ -76,14 +99,13 @@ puts response
|
|
|
76
99
|
|
|
77
100
|
```ruby
|
|
78
101
|
RubyCode.configure do |config|
|
|
79
|
-
|
|
80
|
-
config.
|
|
81
|
-
config.
|
|
102
|
+
# LLM Provider Settings
|
|
103
|
+
config.adapter = :ollama # :ollama, :deepseek, :gemini, :openai, :openrouter
|
|
104
|
+
config.url = "https://api.ollama.com" # Provider API URL
|
|
105
|
+
config.model = "qwen3-coder:480b-cloud" # Model name
|
|
82
106
|
config.root_path = Dir.pwd # Project root directory
|
|
83
|
-
config.debug = false # Enable debug output
|
|
84
|
-
config.enable_tool_injection_workaround = true # Force tool usage (enabled by default)
|
|
85
107
|
|
|
86
|
-
# HTTP timeout and retry settings
|
|
108
|
+
# HTTP timeout and retry settings
|
|
87
109
|
config.http_read_timeout = 120 # Request timeout in seconds (default: 120)
|
|
88
110
|
config.http_open_timeout = 10 # Connection timeout in seconds (default: 10)
|
|
89
111
|
config.max_retries = 3 # Number of retry attempts (default: 3)
|
|
@@ -91,9 +113,19 @@ RubyCode.configure do |config|
|
|
|
91
113
|
end
|
|
92
114
|
```
|
|
93
115
|
|
|
116
|
+
### Supported LLM Providers
|
|
117
|
+
|
|
118
|
+
| Provider | Models | API Key Required | Notes |
|
|
119
|
+
|----------|--------|------------------|-------|
|
|
120
|
+
| **Ollama Cloud** | qwen3-coder, deepseek-v3.1, gpt-oss | Yes | Cloud-hosted Ollama models |
|
|
121
|
+
| **DeepSeek** | deepseek-chat, deepseek-reasoner | Yes | Fast reasoning models |
|
|
122
|
+
| **Google Gemini** | gemini-2.5-flash, gemini-2.5-pro, gemini-3-flash-preview | Yes | Multimodal support |
|
|
123
|
+
| **OpenAI** | gpt-4o, gpt-4o-mini, o1 | Yes | GPT models with reasoning |
|
|
124
|
+
| **OpenRouter** | claude-sonnet-4.5, claude-opus-4.6, gpt-4o | Yes | Access to multiple providers |
|
|
125
|
+
|
|
94
126
|
### Available Tools
|
|
95
127
|
|
|
96
|
-
The agent has access to
|
|
128
|
+
The agent has access to several built-in tools:
|
|
97
129
|
|
|
98
130
|
1. **bash**: Execute safe bash commands including:
|
|
99
131
|
- Directory exploration: `ls`, `pwd`, `find`, `tree`
|
|
@@ -104,25 +136,71 @@ The agent has access to six built-in tools:
|
|
|
104
136
|
3. **read**: Read files with line numbers or list directory contents
|
|
105
137
|
4. **write**: Create new files (requires user approval)
|
|
106
138
|
5. **update**: Edit existing files with exact string replacement (requires user approval)
|
|
107
|
-
6. **
|
|
139
|
+
6. **web_search**: Search the internet with automatic provider fallback (requires user approval):
|
|
140
|
+
- Primary: Exa.ai (AI-native search, optional with API key)
|
|
141
|
+
- Fallback 1: DuckDuckGo Instant Answer API (free, no API key)
|
|
142
|
+
- Fallback 2: Brave Search API (optional, for better results)
|
|
143
|
+
7. **fetch**: Fetch and extract text content from URLs (requires user approval)
|
|
144
|
+
8. **done**: Signal completion and provide the final answer
|
|
108
145
|
|
|
109
146
|
**Note**: Tool schemas are externalized in `config/tools/*.json` for easy customization.
|
|
110
147
|
|
|
111
|
-
|
|
148
|
+
#### Web Search Configuration
|
|
149
|
+
|
|
150
|
+
**By default** (no setup needed):
|
|
151
|
+
- Uses DuckDuckGo Instant Answer API (free, no CAPTCHA)
|
|
152
|
+
- Good for factual queries and summaries
|
|
153
|
+
|
|
154
|
+
**For AI-native search** (optional, recommended):
|
|
155
|
+
```bash
|
|
156
|
+
# Sign up at https://exa.ai/api
|
|
157
|
+
export EXA_API_KEY=your_api_key_here
|
|
158
|
+
```
|
|
112
159
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
160
|
+
**For better web results** (optional):
|
|
161
|
+
```bash
|
|
162
|
+
# Sign up at https://brave.com/search/api/
|
|
163
|
+
export BRAVE_API_KEY=your_api_key_here
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### New in 0.1.4
|
|
167
|
+
|
|
168
|
+
- **Bug Fix**: Agent now properly stops when `done` tool is called, even if tool execution fails
|
|
169
|
+
- **Multiple Cloud LLM Adapters**: Support for 5 providers (Ollama Cloud, DeepSeek, Gemini, OpenAI, OpenRouter)
|
|
170
|
+
- **Web Search & Fetch Tools**: Internet search with automatic fallback (Exa/DuckDuckGo/Brave)
|
|
171
|
+
- **Interactive Setup Wizard**: First-time configuration with guided setup
|
|
172
|
+
- **Encrypted API Key Storage**: Secure database storage with AES-256-GCM
|
|
173
|
+
- **Configuration Persistence**: Automatic saving/loading of preferences
|
|
174
|
+
- **Search Provider Architecture**: Refactored with base class and shared concerns
|
|
175
|
+
- **Adapter Architecture**: 66% code reduction with shared HTTP/error handling
|
|
176
|
+
- **Debug Mode**: Comprehensive request/response logging
|
|
177
|
+
- **Rate Limit Handling**: Automatic retry with 3-attempt limit for 429 errors
|
|
178
|
+
- **Expanded Test Coverage**: 141 tests covering adapters, agent loop, configuration, and tools
|
|
179
|
+
- **Memory Optimization**: Configurable memory window with tool result pruning
|
|
120
180
|
|
|
121
181
|
## Development
|
|
122
182
|
|
|
123
183
|
After checking out the repo, run `bundle install` to install dependencies.
|
|
124
184
|
|
|
125
|
-
|
|
185
|
+
### Running Tests
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Run all tests
|
|
189
|
+
bundle exec rake test
|
|
190
|
+
|
|
191
|
+
# Run tests without warnings
|
|
192
|
+
bundle exec rake test 2>/dev/null
|
|
193
|
+
|
|
194
|
+
# Run specific test file
|
|
195
|
+
bundle exec rake test TEST=test/test_adapters.rb
|
|
196
|
+
|
|
197
|
+
# Run with RuboCop
|
|
198
|
+
bundle exec rake
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Installing Locally
|
|
202
|
+
|
|
203
|
+
To install this gem onto your local machine:
|
|
126
204
|
|
|
127
205
|
```bash
|
|
128
206
|
bundle exec rake install
|
data/USAGE.md
CHANGED
|
@@ -67,27 +67,5 @@ The agent autonomously decides which tools to use to:
|
|
|
67
67
|
Built following OpenCode's design:
|
|
68
68
|
- **Tools**: Controlled, safe operations with validation
|
|
69
69
|
- **Agent Loop**: LLM calls tools, we execute, loop until done
|
|
70
|
-
- **History**: Maintains conversation context
|
|
70
|
+
- **History**: Maintains conversation context including tool calls
|
|
71
71
|
- **JSON Visibility**: Full transparency in debug mode
|
|
72
|
-
|
|
73
|
-
## Workaround for Weak Tool-Calling Models
|
|
74
|
-
|
|
75
|
-
If you're testing with models that have poor tool-calling capabilities (like qwen3-coder), enable the injection workaround:
|
|
76
|
-
|
|
77
|
-
```ruby
|
|
78
|
-
Rubycode.configure do |config|
|
|
79
|
-
config.enable_tool_injection_workaround = true
|
|
80
|
-
end
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
**What this does:**
|
|
84
|
-
- When the model generates text instead of calling a tool, it injects a reminder message
|
|
85
|
-
- Forces the model to keep calling tools until it finds the answer
|
|
86
|
-
- **OpenCode does NOT use this** - they rely on strong tool-calling models (Claude, GPT-4)
|
|
87
|
-
- This is ONLY for testing/development with weaker models
|
|
88
|
-
|
|
89
|
-
**When to disable:**
|
|
90
|
-
- When using Claude (Anthropic)
|
|
91
|
-
- When using GPT-4 (OpenAI)
|
|
92
|
-
- When using Gemini (Google)
|
|
93
|
-
- In production
|
data/config/locales/en.yml
CHANGED
|
@@ -11,7 +11,115 @@ en:
|
|
|
11
11
|
subtitle: "AI Ruby/Rails Code Assistant"
|
|
12
12
|
built_with: "Built with: %{stack}"
|
|
13
13
|
stack: "Ollama + DeepSeek + TTY Toolkit"
|
|
14
|
-
commands: "Commands: exit, quit, clear"
|
|
14
|
+
commands: "Commands: exit, quit, clear, config"
|
|
15
|
+
|
|
16
|
+
setup:
|
|
17
|
+
title: "🔧 Configuration Setup"
|
|
18
|
+
first_time: "👋 First-time setup!"
|
|
19
|
+
adapter_prompt: "Select LLM provider:"
|
|
20
|
+
model_prompt: "Select model:"
|
|
21
|
+
custom_model_prompt: "Enter model name:"
|
|
22
|
+
url_prompt: "Ollama URL:"
|
|
23
|
+
api_key_prompt: "%{adapter} API Key:"
|
|
24
|
+
api_key_optional: "(press Enter to use environment variable)"
|
|
25
|
+
api_key_missing: "⚠️ %{adapter}_API_KEY not set!"
|
|
26
|
+
api_key_help: "Get your key: %{url}\nThen either:\n 1. Set environment variable: export %{env_var}='...'\n 2. Enter it when prompted during setup"
|
|
27
|
+
api_key_required: "API key is required to continue."
|
|
28
|
+
use_saved_api_key: "Use saved %{adapter} API key?"
|
|
29
|
+
save_env_key_to_db: "Save %{adapter} API key from environment to database?"
|
|
30
|
+
config_saved: "✓ Configuration saved to %{path}"
|
|
31
|
+
use_saved: "Use saved configuration (%{adapter}/%{model})?"
|
|
32
|
+
reconfigure: "Reconfigure?"
|
|
33
|
+
restart_message: "Restart rubycode to apply new configuration."
|
|
34
|
+
configure_exa: "Configure Exa.ai for web search? (Optional - AI-native search, requires API key)"
|
|
35
|
+
|
|
36
|
+
models:
|
|
37
|
+
ollama:
|
|
38
|
+
default: "qwen3-coder:480b-cloud"
|
|
39
|
+
powerful:
|
|
40
|
+
name: "qwen3-coder:480b-cloud"
|
|
41
|
+
label: "Qwen3 Coder 480B (Best for coding, cloud)"
|
|
42
|
+
advanced:
|
|
43
|
+
name: "gpt-oss:120b-cloud"
|
|
44
|
+
label: "GPT-OSS 120B (Reasoning, cloud)"
|
|
45
|
+
reasoning:
|
|
46
|
+
name: "deepseek-v3.1:671b-cloud"
|
|
47
|
+
label: "DeepSeek v3.1 671B (Advanced reasoning, cloud)"
|
|
48
|
+
fast:
|
|
49
|
+
name: "gpt-oss:20b-cloud"
|
|
50
|
+
label: "GPT-OSS 20B (Fast, cloud)"
|
|
51
|
+
deepseek:
|
|
52
|
+
default: "deepseek-chat"
|
|
53
|
+
fast:
|
|
54
|
+
name: "deepseek-chat"
|
|
55
|
+
label: "DeepSeek Chat (Fast, reasoning)"
|
|
56
|
+
reasoning:
|
|
57
|
+
name: "deepseek-reasoner"
|
|
58
|
+
label: "DeepSeek Reasoner (Advanced, chain-of-thought)"
|
|
59
|
+
gemini:
|
|
60
|
+
default: "gemini-2.5-flash"
|
|
61
|
+
fast:
|
|
62
|
+
name: "gemini-2.5-flash"
|
|
63
|
+
label: "Gemini 2.5 Flash (Fast, latest)"
|
|
64
|
+
lite:
|
|
65
|
+
name: "gemini-2.5-flash-lite"
|
|
66
|
+
label: "Gemini 2.5 Flash Lite (Fastest)"
|
|
67
|
+
powerful:
|
|
68
|
+
name: "gemini-2.5-pro"
|
|
69
|
+
label: "Gemini 2.5 Pro (Most capable)"
|
|
70
|
+
experimental:
|
|
71
|
+
name: "gemini-3-flash-preview"
|
|
72
|
+
label: "Gemini 3 Flash Preview (Experimental)"
|
|
73
|
+
openai:
|
|
74
|
+
default: "gpt-4o"
|
|
75
|
+
fast:
|
|
76
|
+
name: "gpt-4o-mini"
|
|
77
|
+
label: "GPT-4o Mini (Fast, cheap)"
|
|
78
|
+
balanced:
|
|
79
|
+
name: "gpt-4o"
|
|
80
|
+
label: "GPT-4o (Balanced)"
|
|
81
|
+
reasoning:
|
|
82
|
+
name: "o1"
|
|
83
|
+
label: "O1 (Advanced reasoning)"
|
|
84
|
+
openrouter:
|
|
85
|
+
default: "anthropic/claude-sonnet-4.5"
|
|
86
|
+
fast:
|
|
87
|
+
name: "anthropic/claude-haiku-4.5"
|
|
88
|
+
label: "Claude 4.5 Haiku (Fast, cheap)"
|
|
89
|
+
balanced:
|
|
90
|
+
name: "anthropic/claude-sonnet-4.5"
|
|
91
|
+
label: "Claude 4.5 Sonnet (Balanced)"
|
|
92
|
+
powerful:
|
|
93
|
+
name: "anthropic/claude-opus-4.6"
|
|
94
|
+
label: "Claude 4.6 Opus (Most capable)"
|
|
95
|
+
alternative:
|
|
96
|
+
name: "openai/gpt-4o"
|
|
97
|
+
label: "GPT-4o (OpenAI)"
|
|
98
|
+
adapters:
|
|
99
|
+
ollama:
|
|
100
|
+
name: "Ollama (Cloud)"
|
|
101
|
+
api_key_url: "https://ollama.ai/"
|
|
102
|
+
requires_key: true
|
|
103
|
+
deepseek:
|
|
104
|
+
name: "DeepSeek (Cloud - Reasoning Models)"
|
|
105
|
+
api_key_url: "https://platform.deepseek.com/api_keys"
|
|
106
|
+
requires_key: true
|
|
107
|
+
gemini:
|
|
108
|
+
name: "Google Gemini (Cloud - Multimodal)"
|
|
109
|
+
api_key_url: "https://makersuite.google.com/app/apikey"
|
|
110
|
+
requires_key: true
|
|
111
|
+
openai:
|
|
112
|
+
name: "OpenAI (Cloud - GPT Models)"
|
|
113
|
+
api_key_url: "https://platform.openai.com/api-keys"
|
|
114
|
+
requires_key: true
|
|
115
|
+
openrouter:
|
|
116
|
+
name: "OpenRouter (Cloud - Multiple Models)"
|
|
117
|
+
api_key_url: "https://openrouter.ai/keys"
|
|
118
|
+
requires_key: true
|
|
119
|
+
exa:
|
|
120
|
+
name: "Exa.ai (Web Search)"
|
|
121
|
+
api_key_url: "https://exa.ai/api"
|
|
122
|
+
requires_key: true
|
|
15
123
|
|
|
16
124
|
approval:
|
|
17
125
|
bash:
|
|
@@ -69,6 +177,16 @@ en:
|
|
|
69
177
|
debug_prefix: "[DEBUG]"
|
|
70
178
|
error_prefix: "[ERROR]"
|
|
71
179
|
|
|
180
|
+
debug:
|
|
181
|
+
request_title: "📤 REQUEST TO LLM"
|
|
182
|
+
request_title_adapter: "📤 REQUEST TO LLM (%{adapter})"
|
|
183
|
+
response_title: "📥 RESPONSE FROM LLM"
|
|
184
|
+
response_title_adapter: "📥 RESPONSE FROM LLM (%{adapter})"
|
|
185
|
+
url_label: "URL: %{url}"
|
|
186
|
+
model_label: "Model: %{model}"
|
|
187
|
+
payload_label: "Payload:"
|
|
188
|
+
separator: "================================================================================"
|
|
189
|
+
|
|
72
190
|
errors:
|
|
73
191
|
unknown_adapter: "Unknown Adapter"
|
|
74
192
|
file_not_found: "File '%{path}' not found"
|
|
@@ -85,3 +203,92 @@ en:
|
|
|
85
203
|
adapter_connection: "Cannot connect to LLM at %{url}: %{error}"
|
|
86
204
|
adapter_retry: "Request failed: %{error}. Retrying in %{delay}s... (attempt %{attempt}/%{max_retries})"
|
|
87
205
|
adapter_failed: "LLM adapter failed: %{error}"
|
|
206
|
+
adapter_retry_exhausted: "All retry attempts failed: %{error}\nPlease check your LLM server connection and try again."
|
|
207
|
+
rate_limit_exhausted: "Rate limit exceeded after %{max_attempts} consecutive attempts. Please wait a few minutes before trying again."
|
|
208
|
+
user_cancelled_search: "USER CANCELLED: The user declined web search for '%{query}'. Do not retry this search. Ask the user if they want to search for something else or call 'done' to finish."
|
|
209
|
+
network_error: "Network error: %{message}"
|
|
210
|
+
http_error: "HTTP %{code}: %{message}"
|
|
211
|
+
url_error: "Invalid URL: %{url}"
|
|
212
|
+
tools_not_supported: |
|
|
213
|
+
Model '%{model}' does not support tool calling.
|
|
214
|
+
|
|
215
|
+
RubyCode requires a model with function/tool calling capabilities.
|
|
216
|
+
|
|
217
|
+
Suggested models that support tools:
|
|
218
|
+
• qwen2.5-coder:7b (pull with: ollama pull qwen2.5-coder:7b)
|
|
219
|
+
• llama3.1:8b (pull with: ollama pull llama3.1:8b)
|
|
220
|
+
• mistral:7b (pull with: ollama pull mistral:7b)
|
|
221
|
+
|
|
222
|
+
Update your configuration in lib/rubycode/configuration.rb to use a compatible model.
|
|
223
|
+
|
|
224
|
+
# Adapter-specific errors
|
|
225
|
+
adapter:
|
|
226
|
+
retry_failed: "Failed after %{max_retries} retries: %{error}"
|
|
227
|
+
invalid_json: "Invalid JSON response from server: %{error}"
|
|
228
|
+
unexpected_error: "Unexpected error: %{error}"
|
|
229
|
+
read_timeout: "Request timed out after %{timeout}s: %{error}"
|
|
230
|
+
open_timeout: "Connection timed out after %{timeout}s: %{error}"
|
|
231
|
+
connection_refused: "Connection refused to %{uri}: %{error}"
|
|
232
|
+
connection_timeout: "Connection timed out to %{uri}: %{error}"
|
|
233
|
+
host_unreachable: "Cannot resolve host %{hostname}: %{error}"
|
|
234
|
+
rate_limited: "Rate limited (%{code}): %{message}"
|
|
235
|
+
server_error: "Server error (%{code}): %{message}"
|
|
236
|
+
http_error: "HTTP error (%{code}): %{message}"
|
|
237
|
+
auth_failed: "Authentication failed (%{code}): Check your %{adapter_name}_API_KEY"
|
|
238
|
+
no_choices: "No choices in response"
|
|
239
|
+
no_message: "No message in choice"
|
|
240
|
+
|
|
241
|
+
# Gemini-specific errors
|
|
242
|
+
gemini:
|
|
243
|
+
api_key_missing: |
|
|
244
|
+
GEMINI_API_KEY environment variable not set.
|
|
245
|
+
|
|
246
|
+
Get your API key:
|
|
247
|
+
https://makersuite.google.com/app/apikey
|
|
248
|
+
|
|
249
|
+
Then set it:
|
|
250
|
+
export GEMINI_API_KEY='...'
|
|
251
|
+
|
|
252
|
+
# OpenAI-specific errors
|
|
253
|
+
openai:
|
|
254
|
+
api_key_missing: |
|
|
255
|
+
OPENAI_API_KEY environment variable not set.
|
|
256
|
+
|
|
257
|
+
Get your API key:
|
|
258
|
+
https://platform.openai.com/api-keys
|
|
259
|
+
|
|
260
|
+
Then set it:
|
|
261
|
+
export OPENAI_API_KEY='sk-...'
|
|
262
|
+
|
|
263
|
+
# OpenRouter-specific errors
|
|
264
|
+
openrouter:
|
|
265
|
+
api_key_missing: |
|
|
266
|
+
OPENROUTER_API_KEY environment variable not set.
|
|
267
|
+
|
|
268
|
+
Get your API key:
|
|
269
|
+
https://openrouter.ai/keys
|
|
270
|
+
|
|
271
|
+
Then set it:
|
|
272
|
+
export OPENROUTER_API_KEY='sk-or-v1-...'
|
|
273
|
+
|
|
274
|
+
# Ollama-specific errors
|
|
275
|
+
ollama:
|
|
276
|
+
api_key_missing: |
|
|
277
|
+
OLLAMA_API_KEY environment variable not set.
|
|
278
|
+
|
|
279
|
+
Get your API key:
|
|
280
|
+
https://ollama.ai/
|
|
281
|
+
|
|
282
|
+
Then set it:
|
|
283
|
+
export OLLAMA_API_KEY='your-api-key'
|
|
284
|
+
|
|
285
|
+
# DeepSeek-specific errors
|
|
286
|
+
deepseek:
|
|
287
|
+
api_key_missing: |
|
|
288
|
+
DEEPSEEK_API_KEY environment variable not set.
|
|
289
|
+
|
|
290
|
+
Get your API key:
|
|
291
|
+
https://platform.deepseek.com/api_keys
|
|
292
|
+
|
|
293
|
+
Then set it:
|
|
294
|
+
export DEEPSEEK_API_KEY='sk-...'
|
data/config/system_prompt.md
CHANGED
|
@@ -14,6 +14,8 @@ You MUST call a tool in EVERY response. You MUST NEVER respond with just text.
|
|
|
14
14
|
- **read**: view file contents with line numbers
|
|
15
15
|
- **write**: create new files (requires approval, errors if file exists)
|
|
16
16
|
- **update**: modify existing files (auto-reads if needed, requires approval)
|
|
17
|
+
- **web_search**: search the internet when you cannot find the answer in the codebase or need current information (requires approval)
|
|
18
|
+
- **fetch**: fetch content from URLs to read documentation or resources (requires approval)
|
|
17
19
|
- **done**: MUST call when task is complete (see below)
|
|
18
20
|
|
|
19
21
|
## Recommended workflow
|
|
@@ -22,7 +24,10 @@ You MUST call a tool in EVERY response. You MUST NEVER respond with just text.
|
|
|
22
24
|
2. Use bash with find to locate files: `find . -name "*.rb"`
|
|
23
25
|
3. Once found → use read to see the file
|
|
24
26
|
4. Make changes with write/update if needed
|
|
25
|
-
5.
|
|
27
|
+
5. If you cannot find the answer in the codebase or need current/external information:
|
|
28
|
+
- Use web_search to find information on the internet
|
|
29
|
+
- Use fetch to read documentation from URLs
|
|
30
|
+
6. IMMEDIATELY call done when finished - do not continue exploring
|
|
26
31
|
|
|
27
32
|
## CRITICAL: When to call 'done'
|
|
28
33
|
|
data/config/tools/bash.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"type": "function",
|
|
3
3
|
"function": {
|
|
4
4
|
"name": "bash",
|
|
5
|
-
"description": "Execute
|
|
5
|
+
"description": "Execute bash commands and wait for completion. Commands run non-interactively (stdin is closed).\n\nUse this for:\n- Directory exploration: ls, find, tree\n- File inspection: cat, head, tail, wc, file\n- Content search: grep, rg\n- Development tools: bundle, rails, rake, ruby, gem, node, npm, yarn, git (requires approval)\n\nIMPORTANT: For Rails generators and similar tools, always use --force or --skip flags to avoid interactive prompts:\n- rails generate authentication --force (overwrites files)\n- rails generate model User --force\n- bundle install --quiet\n\nExamples:\n- grep -rn 'button' app/views\n- find . -name '*.rb' -type f\n- rails generate authentication --force\n- git status\n\nAuto-approved commands (no user confirmation needed): ls, pwd, find, tree, cat, head, tail, wc, file, which, echo, grep, rg",
|
|
6
6
|
"parameters": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"properties": {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "fetch",
|
|
5
|
+
"description": "Fetch HTML content from a URL.\n\n- Retrieves web page content via HTTP/HTTPS\n- Optionally extracts text-only content (strips HTML tags)\n- No user approval required\n- 30 second timeout for requests\n- Returns raw HTML or extracted text",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"url": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "The URL to fetch (must be http:// or https://)"
|
|
12
|
+
},
|
|
13
|
+
"extract_text": {
|
|
14
|
+
"type": "boolean",
|
|
15
|
+
"description": "Extract only text content, removing HTML tags. Default: false",
|
|
16
|
+
"default": false
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["url"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "web_search",
|
|
5
|
+
"description": "Search the web for information and return relevant links.\n\n- Primary provider: DuckDuckGo Instant Answer API (free, no API key needed)\n- Fallback provider: Brave Search API (optional, for better results if BRAVE_API_KEY is set)\n- Verifies each link exists before returning (HEAD request)\n- Returns title, URL, and snippet for each result\n- Filters out dead or inaccessible links\n- Requires user approval before making web requests\n- No CAPTCHA issues with API-based providers",
|
|
6
|
+
"parameters": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"query": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "The search query to look up on the web"
|
|
12
|
+
},
|
|
13
|
+
"max_results": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"description": "Maximum number of verified results to return. Default: 5",
|
|
16
|
+
"default": 5
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"required": ["query"]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
data/docs/images/demo.png
CHANGED
|
Binary file
|