coolhand 0.1.4 → 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.
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