coolhand 0.1.5 โ 0.2.0
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/.rubocop.yml +2 -1
- data/CHANGELOG.md +46 -0
- data/README.md +29 -30
- data/docs/anthropic.md +518 -0
- data/lib/coolhand/ruby/anthropic_interceptor.rb +300 -0
- data/lib/coolhand/ruby/api_service.rb +17 -2
- data/lib/coolhand/ruby/base_interceptor.rb +148 -0
- data/lib/coolhand/ruby/faraday_interceptor.rb +129 -0
- data/lib/coolhand/ruby/version.rb +1 -1
- data/lib/coolhand/ruby.rb +38 -7
- metadata +12 -7
- data/coolhand-ruby.gemspec +0 -42
- data/lib/coolhand/ruby/interceptor.rb +0 -119
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fc0fc356a6cf69d4a0c67a906000cab9590d9fc2a452efec8037a7f541efa561
|
|
4
|
+
data.tar.gz: ec6f7a136ae1d8e139bf638175b81a2dda063b9bf19d0199ab7f7135cf6d833d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 131465dcaf94ae8cc4b5dce47252fe92effc9693ba4de6e61247714c682a717934fa3144cf3228bf754fe89a53803051f32a895c3a42fd3c07990d4cf74286a5
|
|
7
|
+
data.tar.gz: 26e03d0f27b9acbeb36ff6a0e0ee11cca55b8142cd17d494972013534ba4d8b3753b29fb3565dedb8c0f8daf1e26d7af443353999f5956f5b1b7b8d7ea139585
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,52 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.0] - 2025-12-16
|
|
9
|
+
|
|
10
|
+
### โจ Major New Features
|
|
11
|
+
- **Official Anthropic Gem Support** - Added comprehensive monitoring support for the official `anthropic` gem (v1.8+) through direct Net::HTTP interception
|
|
12
|
+
- **Dual Gem Compatibility** - Support for both `anthropic` (official) and `ruby-anthropic` (community) gems with automatic detection and appropriate interceptor selection
|
|
13
|
+
- **Streaming Response Support** - Enhanced SSE (Server-Sent Events) parsing for Anthropic streaming responses with proper message accumulation and reconstruction
|
|
14
|
+
- **Graceful Gem Conflict Handling** - Automatic detection when both anthropic gems are installed, with graceful degradation to ruby-anthropic monitoring
|
|
15
|
+
|
|
16
|
+
### ๐๏ธ Architecture Improvements
|
|
17
|
+
- **AnthropicInterceptor Module** - New dedicated interceptor for official anthropic gem requests with streaming response support
|
|
18
|
+
- **BaseInterceptor Module** - Shared functionality across interceptors with unified API logging format and DRY principles
|
|
19
|
+
- **Modular Design** - Moved from single `interceptor.rb` to specialized interceptors (`faraday_interceptor.rb`, `anthropic_interceptor.rb`)
|
|
20
|
+
- **Enhanced Configuration** - Automatic gem detection in `configure` block with appropriate interceptor selection
|
|
21
|
+
|
|
22
|
+
### ๐ง API & Format Changes
|
|
23
|
+
- **Unified Logging Format** - Standardized API request/response logging with `raw_request` wrapper and collector data integration
|
|
24
|
+
- **Headers Field Update** - API logs now use `headers` instead of `request_headers` for consistency
|
|
25
|
+
- **Silent Mode Override** - Critical warnings (like gem conflicts) now always display regardless of silent mode settings
|
|
26
|
+
|
|
27
|
+
### ๐งช Testing & Quality
|
|
28
|
+
- **Comprehensive Test Coverage** - Added 16 new specs covering all interceptor scenarios including gem conflict handling
|
|
29
|
+
- **RuboCop Compliance** - Applied linting with proper line length, verified doubles, and RSpec best practices
|
|
30
|
+
- **Thread Safety** - Enhanced request correlation with thread-local storage for streaming requests
|
|
31
|
+
|
|
32
|
+
### ๐๏ธ Supported Environments
|
|
33
|
+
- **Development Environment** - Uses official `anthropic` gem for Net::HTTP-based requests
|
|
34
|
+
- **AR_Dev Environment** - Uses `ruby-anthropic` gem for Faraday-based requests
|
|
35
|
+
- **Automatic Detection** - Coolhand detects which gem is loaded and applies appropriate interception
|
|
36
|
+
|
|
37
|
+
### ๐ Breaking Changes
|
|
38
|
+
- **Removed** - `lib/coolhand/ruby/interceptor.rb` replaced by specialized interceptor modules
|
|
39
|
+
- **API Change** - Logging format now uses `headers` field instead of `request_headers`
|
|
40
|
+
|
|
41
|
+
### ๐ Migration Guide
|
|
42
|
+
For users upgrading from v0.1.x:
|
|
43
|
+
- No code changes required for basic usage
|
|
44
|
+
- If depending on old `interceptor.rb` directly, update imports to use `faraday_interceptor.rb` or `anthropic_interceptor.rb`
|
|
45
|
+
- API log consumers should expect `headers` field instead of `request_headers`
|
|
46
|
+
|
|
47
|
+
### ๐ Compatibility Matrix
|
|
48
|
+
| Gem | Version | Interceptor | Status |
|
|
49
|
+
|-----|---------|-------------|--------|
|
|
50
|
+
| `anthropic` | 1.8+ | AnthropicInterceptor | โ
Full Support |
|
|
51
|
+
| `ruby-anthropic` | 0.4+ | FaradayInterceptor | โ
Full Support |
|
|
52
|
+
| Both gems | Any | FaradayInterceptor | โ ๏ธ Graceful Degradation |
|
|
53
|
+
|
|
8
54
|
## [0.1.5] - 2024-12-09
|
|
9
55
|
|
|
10
56
|
### ๐ Critical Bug Fixes
|
data/README.md
CHANGED
|
@@ -186,29 +186,7 @@ puts response.dig("choices", 0, "message", "content")
|
|
|
186
186
|
# The request and response have been automatically logged to Coolhand!
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
```ruby
|
|
192
|
-
require 'anthropic'
|
|
193
|
-
require 'coolhand/ruby'
|
|
194
|
-
|
|
195
|
-
# Configure Coolhand
|
|
196
|
-
Coolhand.configure do |config|
|
|
197
|
-
config.api_key = 'your_api_key_here'
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
# Use Anthropic normally - requests are automatically logged
|
|
201
|
-
anthropic = Anthropic::Client.new(access_token: ENV['ANTHROPIC_API_KEY'])
|
|
202
|
-
|
|
203
|
-
response = anthropic.messages(
|
|
204
|
-
model: "claude-3-opus",
|
|
205
|
-
max_tokens: 1024,
|
|
206
|
-
messages: [{ role: "user", content: "Hello, Claude!" }]
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
puts response["content"]
|
|
210
|
-
# Automatically logged to Coolhand!
|
|
211
|
-
```
|
|
189
|
+
๐ **[Complete Anthropic Integration Guide โ](docs/anthropic.md)** - Supports both official and community gems with automatic detection
|
|
212
190
|
|
|
213
191
|
## Logging Inbound Webhooks
|
|
214
192
|
|
|
@@ -285,23 +263,43 @@ The filtering is automatic and applies to all monitored API calls and webhook lo
|
|
|
285
263
|
|
|
286
264
|
## Supported Libraries
|
|
287
265
|
|
|
288
|
-
The monitor works with
|
|
266
|
+
The monitor works with multiple transport layers and Ruby libraries:
|
|
289
267
|
|
|
268
|
+
**Faraday-based libraries:**
|
|
290
269
|
- OpenAI Ruby SDK
|
|
291
|
-
- Anthropic
|
|
270
|
+
- ruby-anthropic gem (community Anthropic gem)
|
|
292
271
|
- ruby-openai gem
|
|
293
272
|
- LangChain.rb
|
|
294
273
|
- Direct Faraday requests
|
|
295
274
|
- Any other Faraday-based HTTP client
|
|
296
275
|
|
|
276
|
+
**Native HTTP libraries:**
|
|
277
|
+
- Official Anthropic Ruby SDK (using Net::HTTP)
|
|
278
|
+
- Any library using Net::HTTP directly
|
|
279
|
+
|
|
280
|
+
**Auto-detection**: Coolhand automatically detects which transport layer your libraries use and applies the appropriate monitoring strategy.
|
|
281
|
+
|
|
297
282
|
## How It Works
|
|
298
283
|
|
|
299
|
-
|
|
284
|
+
Coolhand uses a dual-interceptor strategy to monitor different HTTP transport layers:
|
|
285
|
+
|
|
286
|
+
### Faraday Interceptor
|
|
287
|
+
- Patches Faraday connections using middleware injection
|
|
288
|
+
- Monitors: OpenAI SDK, ruby-anthropic, LangChain.rb, and other Faraday-based libraries
|
|
289
|
+
- Handles: Standard HTTP requests and Server-Sent Events (SSE) for streaming
|
|
290
|
+
|
|
291
|
+
### Anthropic Interceptor
|
|
292
|
+
- Patches the official Anthropic gem's internal HTTP transport (Net::HTTP)
|
|
293
|
+
- Monitors: Official Anthropic Ruby SDK requests
|
|
294
|
+
|
|
295
|
+
### Request Flow
|
|
296
|
+
When a request matches configured LLM endpoints:
|
|
300
297
|
|
|
301
|
-
1. The original request executes normally
|
|
302
|
-
2. Request and response data (body, headers, status) are captured
|
|
303
|
-
3.
|
|
304
|
-
4.
|
|
298
|
+
1. The original request executes normally with zero performance impact
|
|
299
|
+
2. Request and response data (body, headers, status) are captured by the appropriate interceptor
|
|
300
|
+
3. For streaming requests, the complete accumulated response is captured (not individual chunks)
|
|
301
|
+
4. Data is sent to the Coolhand API asynchronously in a background thread
|
|
302
|
+
5. Your application continues without interruption
|
|
305
303
|
|
|
306
304
|
For non-matching endpoints, requests pass through unchanged.
|
|
307
305
|
|
|
@@ -369,6 +367,7 @@ The monitor handles errors gracefully:
|
|
|
369
367
|
|
|
370
368
|
## Integration Guides
|
|
371
369
|
|
|
370
|
+
- **[Anthropic Integration](docs/anthropic.md)** - Complete guide for both official and community Anthropic gems, including streaming, dual gem handling, and troubleshooting
|
|
372
371
|
- **[ElevenLabs Integration](docs/elevenlabs.md)** - Complete guide for integrating ElevenLabs Conversational AI with webhook capture and feedback submission
|
|
373
372
|
|
|
374
373
|
## Security
|
data/docs/anthropic.md
ADDED
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
# Anthropic Integration Guide
|
|
2
|
+
|
|
3
|
+
Coolhand provides comprehensive monitoring for Anthropic's Claude API through support for both the official and community Ruby gems. This guide covers setup, usage, streaming, and troubleshooting.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Coolhand automatically detects which Anthropic gem you're using and applies the appropriate monitoring strategy:
|
|
8
|
+
|
|
9
|
+
- **Official Anthropic Gem** (`anthropic`): Uses Net::HTTP transport, monitored via AnthropicInterceptor
|
|
10
|
+
- **Community Ruby-Anthropic Gem** (`ruby-anthropic`): Uses Faraday transport, monitored via FaradayInterceptor
|
|
11
|
+
- **Dual Installation**: Automatically handles conflicts and prevents duplicate logging
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Basic Configuration
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
require 'coolhand/ruby'
|
|
19
|
+
|
|
20
|
+
Coolhand.configure do |config|
|
|
21
|
+
config.api_key = 'your_coolhand_api_key_here'
|
|
22
|
+
config.silent = true # Set to false for debug output
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
That's it! All Anthropic API calls are now automatically monitored.
|
|
27
|
+
|
|
28
|
+
## Official Anthropic Gem
|
|
29
|
+
|
|
30
|
+
### Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
gem install anthropic
|
|
34
|
+
# or add to Gemfile
|
|
35
|
+
gem 'anthropic'
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Basic Usage
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
require 'anthropic'
|
|
42
|
+
require 'coolhand/ruby'
|
|
43
|
+
|
|
44
|
+
# Configure Coolhand
|
|
45
|
+
Coolhand.configure do |config|
|
|
46
|
+
config.api_key = 'your_coolhand_api_key'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Use official Anthropic gem normally
|
|
50
|
+
client = Anthropic::Client.new
|
|
51
|
+
|
|
52
|
+
response = client.messages(
|
|
53
|
+
parameters: {
|
|
54
|
+
model: "claude-3-sonnet-20240229",
|
|
55
|
+
max_tokens: 1024,
|
|
56
|
+
messages: [{ role: "user", content: "Hello, Claude!" }]
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
puts response.content.first.text
|
|
61
|
+
# โ
Request and response automatically logged to Coolhand
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Streaming with Official Gem
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
# Streaming is automatically detected and properly logged
|
|
68
|
+
response = client.messages(
|
|
69
|
+
parameters: {
|
|
70
|
+
model: "claude-3-sonnet-20240229",
|
|
71
|
+
max_tokens: 1024,
|
|
72
|
+
messages: [{ role: "user", content: "Write a haiku about Ruby" }],
|
|
73
|
+
stream: true # โ
Streaming automatically detected
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Process streaming response
|
|
78
|
+
accumulated_text = ""
|
|
79
|
+
response.each do |chunk|
|
|
80
|
+
if chunk.delta&.text
|
|
81
|
+
print chunk.delta.text
|
|
82
|
+
accumulated_text += chunk.delta.text
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# โ
Complete accumulated response logged to Coolhand (not individual chunks)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Advanced Configuration
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
client = Anthropic::Client.new
|
|
93
|
+
|
|
94
|
+
# All parameters are automatically captured and logged
|
|
95
|
+
response = client.messages(
|
|
96
|
+
parameters: {
|
|
97
|
+
model: "claude-3-opus-20240229",
|
|
98
|
+
max_tokens: 2000,
|
|
99
|
+
temperature: 0.7,
|
|
100
|
+
top_p: 0.9,
|
|
101
|
+
system: "You are a helpful assistant specializing in Ruby programming.",
|
|
102
|
+
messages: [
|
|
103
|
+
{ role: "user", content: "Explain Ruby metaprogramming" }
|
|
104
|
+
],
|
|
105
|
+
# Streaming works automatically
|
|
106
|
+
stream: true
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# โ
All parameters (model, temperature, top_p, system, etc.) logged
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Community Ruby-Anthropic Gem
|
|
114
|
+
|
|
115
|
+
### Installation
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
gem install ruby-anthropic
|
|
119
|
+
# or add to Gemfile
|
|
120
|
+
gem 'ruby-anthropic'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Basic Usage
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
require 'ruby-anthropic'
|
|
127
|
+
require 'coolhand/ruby'
|
|
128
|
+
|
|
129
|
+
# Configure Coolhand
|
|
130
|
+
Coolhand.configure do |config|
|
|
131
|
+
config.api_key = 'your_coolhand_api_key'
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Use ruby-anthropic gem normally - monitored via Faraday
|
|
135
|
+
client = Anthropic::Client.new(access_token: ENV['ANTHROPIC_API_KEY'])
|
|
136
|
+
|
|
137
|
+
response = client.messages(
|
|
138
|
+
model: "claude-3-sonnet-20240229",
|
|
139
|
+
max_tokens: 1024,
|
|
140
|
+
messages: [{ role: "user", content: "Hello, Claude!" }]
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
puts response.dig("content", 0, "text")
|
|
144
|
+
# โ
Automatically logged via FaradayInterceptor
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Streaming with Ruby-Anthropic
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
# Streaming works seamlessly via Faraday monitoring
|
|
151
|
+
response = client.messages(
|
|
152
|
+
model: "claude-3-sonnet-20240229",
|
|
153
|
+
max_tokens: 1024,
|
|
154
|
+
messages: [{ role: "user", content: "Count to 10 slowly" }],
|
|
155
|
+
stream: true
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Process Server-Sent Events
|
|
159
|
+
response.each do |event|
|
|
160
|
+
puts event if event.start_with?("data:")
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# โ
Complete conversation logged to Coolhand
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Dual Gem Installation
|
|
167
|
+
|
|
168
|
+
### Automatic Conflict Resolution
|
|
169
|
+
|
|
170
|
+
When both gems are installed, Coolhand automatically handles the conflict:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
require 'anthropic' # Official gem
|
|
174
|
+
require 'ruby-anthropic' # Community gem
|
|
175
|
+
require 'coolhand/ruby'
|
|
176
|
+
|
|
177
|
+
Coolhand.configure do |config|
|
|
178
|
+
config.api_key = 'your_coolhand_api_key'
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# โ ๏ธ Warning displayed:
|
|
182
|
+
# "Both 'anthropic' and 'ruby-anthropic' gems are installed.
|
|
183
|
+
# Coolhand will only monitor ruby-anthropic (Faraday-based) requests.
|
|
184
|
+
# Official anthropic gem monitoring has been disabled."
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Recommendation**: Use only one gem to avoid confusion. Choose based on your needs:
|
|
188
|
+
- **Official gem**: Latest features, official support, Net::HTTP transport
|
|
189
|
+
- **Community gem**: Faraday-based, may have community contributions
|
|
190
|
+
|
|
191
|
+
### Manual Conflict Resolution
|
|
192
|
+
|
|
193
|
+
To explicitly use the official gem when both are installed:
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
# Temporarily hide the community gem
|
|
197
|
+
begin
|
|
198
|
+
# Remove ruby-anthropic from the load path
|
|
199
|
+
$LOAD_PATH.reject! { |path| path.include?('ruby-anthropic') }
|
|
200
|
+
|
|
201
|
+
require 'anthropic'
|
|
202
|
+
require 'coolhand/ruby'
|
|
203
|
+
|
|
204
|
+
Coolhand.configure do |config|
|
|
205
|
+
config.api_key = 'your_coolhand_api_key'
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Now only the official gem will be monitored
|
|
209
|
+
client = Anthropic::Client.new
|
|
210
|
+
# ... use official gem
|
|
211
|
+
end
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Rails Integration
|
|
215
|
+
|
|
216
|
+
### Initializer Setup
|
|
217
|
+
|
|
218
|
+
```ruby
|
|
219
|
+
# config/initializers/coolhand.rb
|
|
220
|
+
Coolhand.configure do |config|
|
|
221
|
+
# Use Rails credentials for API key
|
|
222
|
+
config.api_key = Rails.application.credentials.coolhand_api_key
|
|
223
|
+
|
|
224
|
+
# Suppress console output in production
|
|
225
|
+
config.silent = Rails.env.production?
|
|
226
|
+
|
|
227
|
+
# Ensure Anthropic endpoints are monitored (default behavior)
|
|
228
|
+
# config.intercept_addresses = ["api.openai.com", "api.anthropic.com"]
|
|
229
|
+
end
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Service Object Pattern
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
# app/services/claude_chat_service.rb
|
|
236
|
+
class ClaudeChatService
|
|
237
|
+
def initialize
|
|
238
|
+
@client = Anthropic::Client.new
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def generate_response(user_message, context: nil)
|
|
242
|
+
messages = []
|
|
243
|
+
messages << { role: "system", content: context } if context
|
|
244
|
+
messages << { role: "user", content: user_message }
|
|
245
|
+
|
|
246
|
+
response = @client.messages(
|
|
247
|
+
parameters: {
|
|
248
|
+
model: "claude-3-sonnet-20240229",
|
|
249
|
+
max_tokens: 1500,
|
|
250
|
+
messages: messages
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
response.content.first.text
|
|
255
|
+
# โ
Automatically logged to Coolhand with all context
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def stream_response(user_message)
|
|
259
|
+
response = @client.messages(
|
|
260
|
+
parameters: {
|
|
261
|
+
model: "claude-3-sonnet-20240229",
|
|
262
|
+
max_tokens: 1500,
|
|
263
|
+
messages: [{ role: "user", content: user_message }],
|
|
264
|
+
stream: true
|
|
265
|
+
}
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
Enumerator.new do |yielder|
|
|
269
|
+
response.each do |chunk|
|
|
270
|
+
if chunk.delta&.text
|
|
271
|
+
yielder << chunk.delta.text
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
# โ
Complete streaming conversation logged
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Background Job Example
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
# app/jobs/claude_analysis_job.rb
|
|
284
|
+
class ClaudeAnalysisJob < ApplicationJob
|
|
285
|
+
def perform(document_id, analysis_type)
|
|
286
|
+
document = Document.find(document_id)
|
|
287
|
+
|
|
288
|
+
client = Anthropic::Client.new
|
|
289
|
+
|
|
290
|
+
response = client.messages(
|
|
291
|
+
parameters: {
|
|
292
|
+
model: "claude-3-opus-20240229",
|
|
293
|
+
max_tokens: 2000,
|
|
294
|
+
system: "You are an expert document analyzer.",
|
|
295
|
+
messages: [
|
|
296
|
+
{
|
|
297
|
+
role: "user",
|
|
298
|
+
content: "Analyze this document: #{document.content}"
|
|
299
|
+
}
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
document.update!(
|
|
305
|
+
analysis: response.content.first.text,
|
|
306
|
+
analysis_type: analysis_type
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# โ
Analysis request logged with document context
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Advanced Features
|
|
315
|
+
|
|
316
|
+
### Thread-Safe Concurrent Requests
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
# Coolhand handles concurrent requests safely
|
|
320
|
+
threads = []
|
|
321
|
+
|
|
322
|
+
10.times do |i|
|
|
323
|
+
threads << Thread.new do
|
|
324
|
+
client = Anthropic::Client.new
|
|
325
|
+
|
|
326
|
+
response = client.messages(
|
|
327
|
+
parameters: {
|
|
328
|
+
model: "claude-3-sonnet-20240229",
|
|
329
|
+
max_tokens: 500,
|
|
330
|
+
messages: [{ role: "user", content: "Request #{i}" }]
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
puts "Response #{i}: #{response.content.first.text}"
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
threads.each(&:join)
|
|
339
|
+
# โ
All 10 requests logged correctly without conflicts
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Request Correlation
|
|
343
|
+
|
|
344
|
+
Access the current request ID for correlation:
|
|
345
|
+
|
|
346
|
+
```ruby
|
|
347
|
+
client = Anthropic::Client.new
|
|
348
|
+
|
|
349
|
+
response = client.messages(
|
|
350
|
+
parameters: {
|
|
351
|
+
model: "claude-3-sonnet-20240229",
|
|
352
|
+
max_tokens: 1000,
|
|
353
|
+
messages: [{ role: "user", content: "Hello" }]
|
|
354
|
+
}
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
# Get the request ID that was logged to Coolhand
|
|
358
|
+
request_id = Thread.current[:coolhand_current_request_id]
|
|
359
|
+
puts "Logged to Coolhand with ID: #{request_id}"
|
|
360
|
+
|
|
361
|
+
# Use this ID for feedback or debugging
|
|
362
|
+
feedback_service = Coolhand::Ruby::FeedbackService.new(Coolhand.configuration)
|
|
363
|
+
feedback_service.create_feedback(
|
|
364
|
+
llm_request_log_id: request_id,
|
|
365
|
+
like: true,
|
|
366
|
+
explanation: "Great response quality"
|
|
367
|
+
)
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Troubleshooting
|
|
371
|
+
|
|
372
|
+
### Debug Mode
|
|
373
|
+
|
|
374
|
+
Enable verbose logging to see what's being intercepted:
|
|
375
|
+
|
|
376
|
+
```ruby
|
|
377
|
+
Coolhand.configure do |config|
|
|
378
|
+
config.api_key = 'your_api_key'
|
|
379
|
+
config.silent = false # Enable debug output
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
# Now you'll see console output like:
|
|
383
|
+
# "โ
Coolhand ready - will log OpenAI and Anthropic (official gem) calls"
|
|
384
|
+
# "COOLHAND: โ ๏ธ Warning: Both 'anthropic' and 'ruby-anthropic' gems are installed..."
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Common Issues
|
|
388
|
+
|
|
389
|
+
#### 1. Gem Not Detected
|
|
390
|
+
|
|
391
|
+
**Problem**: Coolhand says "Anthropic gem not loaded"
|
|
392
|
+
|
|
393
|
+
**Solution**: Ensure you require the gem before configuring Coolhand:
|
|
394
|
+
|
|
395
|
+
```ruby
|
|
396
|
+
require 'anthropic' # Must come before coolhand/ruby
|
|
397
|
+
require 'coolhand/ruby'
|
|
398
|
+
|
|
399
|
+
Coolhand.configure do |config|
|
|
400
|
+
config.api_key = 'your_api_key'
|
|
401
|
+
end
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
#### 2. Duplicate Requests
|
|
405
|
+
|
|
406
|
+
**Problem**: Seeing requests logged twice in dashboard
|
|
407
|
+
|
|
408
|
+
**Cause**: Usually indicates both gems are installed and conflicting
|
|
409
|
+
|
|
410
|
+
**Solution**: Choose one gem and uninstall the other:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# Keep official gem
|
|
414
|
+
gem uninstall ruby-anthropic
|
|
415
|
+
|
|
416
|
+
# OR keep community gem
|
|
417
|
+
gem uninstall anthropic
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
#### 3. Missing Streaming Data
|
|
421
|
+
|
|
422
|
+
**Problem**: Only seeing individual chunks, not complete response
|
|
423
|
+
|
|
424
|
+
**Cause**: Custom streaming handling interfering with automatic detection
|
|
425
|
+
|
|
426
|
+
**Solution**: Let Coolhand handle streaming automatically:
|
|
427
|
+
|
|
428
|
+
```ruby
|
|
429
|
+
# โ Don't manually collect chunks for logging
|
|
430
|
+
response = client.messages(parameters: { stream: true })
|
|
431
|
+
manual_collection = ""
|
|
432
|
+
response.each { |chunk| manual_collection += chunk.delta.text }
|
|
433
|
+
|
|
434
|
+
# โ
Just process chunks normally - Coolhand handles logging
|
|
435
|
+
response = client.messages(parameters: { stream: true })
|
|
436
|
+
response.each { |chunk| print chunk.delta.text }
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### 4. Performance Concerns
|
|
440
|
+
|
|
441
|
+
**Problem**: Worried about monitoring overhead
|
|
442
|
+
|
|
443
|
+
**Solution**: Monitoring is asynchronous and negligible:
|
|
444
|
+
|
|
445
|
+
```ruby
|
|
446
|
+
# Monitoring happens in background threads
|
|
447
|
+
# Your application performance is unaffected
|
|
448
|
+
require 'benchmark'
|
|
449
|
+
|
|
450
|
+
time = Benchmark.measure do
|
|
451
|
+
1000.times do
|
|
452
|
+
client.messages(
|
|
453
|
+
parameters: {
|
|
454
|
+
model: "claude-3-haiku-20240307", # Fast model for testing
|
|
455
|
+
max_tokens: 100,
|
|
456
|
+
messages: [{ role: "user", content: "Hi" }]
|
|
457
|
+
}
|
|
458
|
+
)
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
puts "Time with monitoring: #{time.real}s"
|
|
463
|
+
# Overhead is typically < 1ms per request
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Testing
|
|
467
|
+
|
|
468
|
+
#### Test Environment Setup
|
|
469
|
+
|
|
470
|
+
```ruby
|
|
471
|
+
# spec/spec_helper.rb or test/test_helper.rb
|
|
472
|
+
if Rails.env.test?
|
|
473
|
+
Coolhand.configure do |config|
|
|
474
|
+
config.api_key = 'test_key_do_not_send_requests'
|
|
475
|
+
config.silent = true
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
#### Mocking for Tests
|
|
481
|
+
|
|
482
|
+
```ruby
|
|
483
|
+
# spec/support/anthropic_mock.rb
|
|
484
|
+
RSpec.configure do |config|
|
|
485
|
+
config.before(:each) do
|
|
486
|
+
# Mock Anthropic responses to avoid real API calls
|
|
487
|
+
allow_any_instance_of(Anthropic::Client).to receive(:messages).and_return(
|
|
488
|
+
double(
|
|
489
|
+
content: [double(text: "Mocked response")],
|
|
490
|
+
model: "claude-3-sonnet-20240229"
|
|
491
|
+
)
|
|
492
|
+
)
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Best Practices
|
|
498
|
+
|
|
499
|
+
1. **Choose One Gem**: Avoid installing both `anthropic` and `ruby-anthropic` gems
|
|
500
|
+
2. **Secure API Keys**: Use environment variables or Rails credentials, never commit keys
|
|
501
|
+
3. **Silent in Production**: Set `config.silent = true` in production environments
|
|
502
|
+
4. **Monitor Performance**: Use fast models (haiku) for high-frequency requests
|
|
503
|
+
5. **Request Correlation**: Use thread-local request IDs for debugging and feedback
|
|
504
|
+
6. **Streaming Efficiency**: Let Coolhand handle streaming accumulation automatically
|
|
505
|
+
7. **Test Safely**: Mock API responses in test environments to avoid real charges
|
|
506
|
+
|
|
507
|
+
## API Reference
|
|
508
|
+
|
|
509
|
+
For complete API documentation, see:
|
|
510
|
+
- [Official Anthropic Gem](https://github.com/anthropics/anthropic-sdk-ruby)
|
|
511
|
+
- [Community Ruby-Anthropic Gem](https://github.com/alexrudall/ruby-anthropic)
|
|
512
|
+
- [Coolhand Feedback API](../README.md#feedback-api)
|
|
513
|
+
|
|
514
|
+
## Support
|
|
515
|
+
|
|
516
|
+
- **Coolhand Issues**: [GitHub Issues](https://github.com/Coolhand-Labs/coolhand-ruby/issues)
|
|
517
|
+
- **Anthropic API**: [Anthropic Documentation](https://docs.anthropic.com/)
|
|
518
|
+
- **Gem Conflicts**: Check this guide's troubleshooting section
|