open_router_enhanced 1.0.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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +1 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +13 -0
  5. data/.rubocop_todo.yml +130 -0
  6. data/.ruby-version +1 -0
  7. data/CHANGELOG.md +41 -0
  8. data/CODE_OF_CONDUCT.md +84 -0
  9. data/CONTRIBUTING.md +384 -0
  10. data/Gemfile +22 -0
  11. data/Gemfile.lock +138 -0
  12. data/LICENSE.txt +21 -0
  13. data/MIGRATION.md +556 -0
  14. data/README.md +1660 -0
  15. data/Rakefile +334 -0
  16. data/SECURITY.md +150 -0
  17. data/VCR_CONFIGURATION.md +80 -0
  18. data/docs/model_selection.md +637 -0
  19. data/docs/observability.md +430 -0
  20. data/docs/prompt_templates.md +422 -0
  21. data/docs/streaming.md +467 -0
  22. data/docs/structured_outputs.md +466 -0
  23. data/docs/tools.md +1016 -0
  24. data/examples/basic_completion.rb +122 -0
  25. data/examples/model_selection_example.rb +141 -0
  26. data/examples/observability_example.rb +199 -0
  27. data/examples/prompt_template_example.rb +184 -0
  28. data/examples/smart_completion_example.rb +89 -0
  29. data/examples/streaming_example.rb +176 -0
  30. data/examples/structured_outputs_example.rb +191 -0
  31. data/examples/tool_calling_example.rb +149 -0
  32. data/lib/open_router/client.rb +552 -0
  33. data/lib/open_router/http.rb +118 -0
  34. data/lib/open_router/json_healer.rb +263 -0
  35. data/lib/open_router/model_registry.rb +378 -0
  36. data/lib/open_router/model_selector.rb +462 -0
  37. data/lib/open_router/prompt_template.rb +290 -0
  38. data/lib/open_router/response.rb +371 -0
  39. data/lib/open_router/schema.rb +288 -0
  40. data/lib/open_router/streaming_client.rb +210 -0
  41. data/lib/open_router/tool.rb +221 -0
  42. data/lib/open_router/tool_call.rb +180 -0
  43. data/lib/open_router/usage_tracker.rb +277 -0
  44. data/lib/open_router/version.rb +5 -0
  45. data/lib/open_router.rb +123 -0
  46. data/sig/open_router.rbs +20 -0
  47. metadata +186 -0
@@ -0,0 +1,430 @@
1
+ # Observability & Analytics
2
+
3
+ The OpenRouter gem provides comprehensive observability features to help you monitor usage, costs, performance, and errors in your AI applications.
4
+
5
+ ## Quick Start
6
+
7
+ ```ruby
8
+ # Create client with automatic usage tracking
9
+ client = OpenRouter::Client.new(track_usage: true)
10
+
11
+ # Make some API calls
12
+ response = client.complete(
13
+ [{ role: "user", content: "Hello world" }],
14
+ model: "openai/gpt-4o-mini"
15
+ )
16
+
17
+ # View usage summary
18
+ puts "Used #{response.total_tokens} tokens"
19
+ puts "Cost: $#{response.cost_estimate}"
20
+ puts "Cache hit rate: #{client.usage_tracker.cache_hit_rate}%"
21
+
22
+ # Print detailed usage report
23
+ client.usage_tracker.print_summary
24
+ ```
25
+
26
+ ## Features Overview
27
+
28
+ ### 1. Response Metadata
29
+ Enhanced response objects provide detailed metadata:
30
+
31
+ ```ruby
32
+ response = client.complete(messages, model: "openai/gpt-4o-mini")
33
+
34
+ # Token usage
35
+ response.prompt_tokens # => 150
36
+ response.completion_tokens # => 75
37
+ response.total_tokens # => 225
38
+ response.cached_tokens # => 50
39
+
40
+ # Cost information
41
+ response.cost_estimate # => 0.0023
42
+
43
+ # Provider and model info
44
+ response.provider # => "OpenAI"
45
+ response.model # => "openai/gpt-4o-mini"
46
+ response.system_fingerprint # => "fp_abc123"
47
+ response.finish_reason # => "stop"
48
+ ```
49
+
50
+ ### 2. Usage Tracking
51
+ Automatic tracking of token usage and costs across all API calls:
52
+
53
+ ```ruby
54
+ # Enable usage tracking (default: true)
55
+ client = OpenRouter::Client.new(track_usage: true)
56
+
57
+ # Access usage tracker
58
+ tracker = client.usage_tracker
59
+
60
+ # Key metrics
61
+ tracker.total_tokens # Total tokens across all requests
62
+ tracker.total_cost # Total estimated cost
63
+ tracker.request_count # Number of API calls made
64
+ tracker.cache_hit_rate # Percentage of tokens served from cache
65
+ tracker.session_duration # Time since tracker initialization
66
+
67
+ # Performance metrics
68
+ tracker.tokens_per_second # Processing speed
69
+ tracker.average_cost_per_request
70
+ tracker.average_tokens_per_request
71
+
72
+ # Model insights
73
+ tracker.most_used_model # Model with most requests
74
+ tracker.most_expensive_model # Model with highest total cost
75
+ ```
76
+
77
+ ### 3. Callback System
78
+ Event-driven observability with callbacks for key events:
79
+
80
+ ```ruby
81
+ client = OpenRouter::Client.new
82
+
83
+ # Register callbacks for different events
84
+ client.on(:before_request) do |params|
85
+ puts "Making request to model: #{params[:model]}"
86
+ end
87
+
88
+ client.on(:after_response) do |response|
89
+ puts "Response received: #{response.total_tokens} tokens"
90
+ puts "Cost: $#{response.cost_estimate}"
91
+ end
92
+
93
+ client.on(:on_tool_call) do |tool_calls|
94
+ tool_calls.each do |tc|
95
+ puts "Tool called: #{tc.name}"
96
+ end
97
+ end
98
+
99
+ client.on(:on_error) do |error|
100
+ puts "Error occurred: #{error.message}"
101
+ # Log to monitoring system, send alerts, etc.
102
+ end
103
+
104
+ client.on(:on_healing) do |healing_data|
105
+ if healing_data[:healed]
106
+ puts "Successfully healed JSON response"
107
+ else
108
+ puts "JSON healing failed: #{healing_data[:error]}"
109
+ end
110
+ end
111
+ ```
112
+
113
+ ### 4. Streaming Observability
114
+ Enhanced streaming support with detailed event callbacks:
115
+
116
+ ```ruby
117
+ streaming_client = OpenRouter::StreamingClient.new
118
+
119
+ streaming_client.on_stream(:on_start) do |data|
120
+ puts "Starting stream with model: #{data[:model]}"
121
+ end
122
+
123
+ streaming_client.on_stream(:on_chunk) do |chunk|
124
+ # Log chunk details, measure latency, etc.
125
+ puts "Chunk received: #{chunk.dig('choices', 0, 'delta', 'content')}"
126
+ end
127
+
128
+ streaming_client.on_stream(:on_finish) do |final_response|
129
+ puts "Stream completed. Total tokens: #{final_response&.total_tokens}"
130
+ end
131
+
132
+ streaming_client.on_stream(:on_tool_call_chunk) do |chunk|
133
+ # Track tool calling progress
134
+ puts "Tool call chunk received"
135
+ end
136
+
137
+ # Stream with accumulation
138
+ response = streaming_client.stream_complete(
139
+ messages,
140
+ model: "openai/gpt-4o-mini",
141
+ accumulate_response: true
142
+ )
143
+ ```
144
+
145
+ ## Usage Analytics
146
+
147
+ ### Detailed Reporting
148
+ Get comprehensive usage summaries:
149
+
150
+ ```ruby
151
+ summary = client.usage_tracker.summary
152
+
153
+ # Returns structured data:
154
+ {
155
+ session: {
156
+ start: Time,
157
+ duration_seconds: Float,
158
+ requests: Integer
159
+ },
160
+ tokens: {
161
+ total: Integer,
162
+ prompt: Integer,
163
+ completion: Integer,
164
+ cached: Integer,
165
+ cache_hit_rate: String # "15.2%"
166
+ },
167
+ cost: {
168
+ total: Float,
169
+ average_per_request: Float
170
+ },
171
+ performance: {
172
+ tokens_per_second: Float,
173
+ average_tokens_per_request: Float
174
+ },
175
+ models: {
176
+ most_used: String,
177
+ most_expensive: String,
178
+ breakdown: Hash # Per-model stats
179
+ }
180
+ }
181
+ ```
182
+
183
+ ### Model Breakdown
184
+ Analyze usage by model:
185
+
186
+ ```ruby
187
+ breakdown = client.usage_tracker.model_breakdown
188
+
189
+ # Returns:
190
+ {
191
+ "openai/gpt-4o-mini" => {
192
+ requests: 15,
193
+ tokens: 2500,
194
+ cost: 0.025,
195
+ cached_tokens: 200
196
+ },
197
+ "anthropic/claude-3-haiku" => {
198
+ requests: 8,
199
+ tokens: 1800,
200
+ cost: 0.018,
201
+ cached_tokens: 150
202
+ }
203
+ }
204
+ ```
205
+
206
+ ### Export Options
207
+ Export usage data for external analysis:
208
+
209
+ ```ruby
210
+ # Export as CSV
211
+ csv_data = client.usage_tracker.export_csv
212
+ File.write("usage_report.csv", csv_data)
213
+
214
+ # Get raw history
215
+ history = client.usage_tracker.history(limit: 100)
216
+ history.each do |entry|
217
+ puts "#{entry[:timestamp]}: #{entry[:model]} - #{entry[:tokens]} tokens"
218
+ end
219
+
220
+ # Reset tracking
221
+ client.usage_tracker.reset!
222
+ ```
223
+
224
+ ## Performance Monitoring
225
+
226
+ ### Cache Optimization
227
+ Monitor cache effectiveness:
228
+
229
+ ```ruby
230
+ # Check cache performance
231
+ tracker = client.usage_tracker
232
+ puts "Cache hit rate: #{tracker.cache_hit_rate}%"
233
+ puts "Cached tokens: #{tracker.total_cached_tokens}"
234
+ puts "Savings: #{tracker.cache_savings_estimate}"
235
+
236
+ # Per-model cache analysis
237
+ tracker.model_breakdown.each do |model, stats|
238
+ cache_rate = (stats[:cached_tokens].to_f / stats[:prompt_tokens]) * 100
239
+ puts "#{model}: #{cache_rate.round(1)}% cache hit rate"
240
+ end
241
+ ```
242
+
243
+ ### Response Time Tracking
244
+ Monitor API response times:
245
+
246
+ ```ruby
247
+ client.on(:before_request) do |params|
248
+ @request_start = Time.now
249
+ end
250
+
251
+ client.on(:after_response) do |response|
252
+ duration = Time.now - @request_start
253
+ puts "Request took #{duration.round(3)}s"
254
+ puts "Processing speed: #{response.total_tokens / duration} tokens/sec"
255
+ end
256
+ ```
257
+
258
+ ## Error Monitoring
259
+
260
+ ### Comprehensive Error Tracking
261
+ Monitor and respond to different error types:
262
+
263
+ ```ruby
264
+ client.on(:on_error) do |error|
265
+ case error
266
+ when Faraday::UnauthorizedError
267
+ # Handle authentication issues
268
+ alert_system("Authentication failed")
269
+ when Faraday::TooManyRequestsError
270
+ # Handle rate limiting
271
+ exponential_backoff()
272
+ when OpenRouter::ServerError
273
+ # Handle server errors
274
+ log_error(error)
275
+ end
276
+ end
277
+
278
+ client.on(:on_healing) do |healing_data|
279
+ if healing_data[:healed] == false
280
+ # JSON healing failed - may indicate model issues
281
+ alert_system("JSON healing failed for #{healing_data[:original]}")
282
+ end
283
+ end
284
+ ```
285
+
286
+ ### Health Checks
287
+ Monitor system health:
288
+
289
+ ```ruby
290
+ def health_check
291
+ tracker = client.usage_tracker
292
+
293
+ health_status = {
294
+ uptime: tracker.session_duration,
295
+ total_requests: tracker.request_count,
296
+ error_rate: calculate_error_rate(),
297
+ avg_response_time: calculate_avg_response_time(),
298
+ cache_hit_rate: tracker.cache_hit_rate,
299
+ total_cost: tracker.total_cost
300
+ }
301
+
302
+ # Alert if metrics exceed thresholds
303
+ alert_if_unhealthy(health_status)
304
+
305
+ health_status
306
+ end
307
+ ```
308
+
309
+ ## Integration Examples
310
+
311
+ ### Datadog Integration
312
+ Send metrics to Datadog:
313
+
314
+ ```ruby
315
+ require 'dogapi'
316
+
317
+ dog = Dogapi::Client.new(api_key, app_key)
318
+
319
+ client.on(:after_response) do |response|
320
+ dog.emit_point('openrouter.tokens.total', response.total_tokens)
321
+ dog.emit_point('openrouter.cost.estimate', response.cost_estimate)
322
+ dog.emit_point('openrouter.cache.hit_rate',
323
+ response.cached_tokens.to_f / response.prompt_tokens * 100)
324
+ end
325
+ ```
326
+
327
+ ### Prometheus Metrics
328
+ Export Prometheus metrics:
329
+
330
+ ```ruby
331
+ require 'prometheus/client'
332
+
333
+ prometheus = Prometheus::Client.registry
334
+
335
+ tokens_counter = prometheus.counter(
336
+ :openrouter_tokens_total,
337
+ docstring: 'Total tokens processed'
338
+ )
339
+
340
+ cost_counter = prometheus.counter(
341
+ :openrouter_cost_total,
342
+ docstring: 'Total estimated cost'
343
+ )
344
+
345
+ client.on(:after_response) do |response|
346
+ tokens_counter.increment(by: response.total_tokens,
347
+ labels: { model: response.model })
348
+ cost_counter.increment(by: response.cost_estimate || 0,
349
+ labels: { model: response.model })
350
+ end
351
+ ```
352
+
353
+ ### Custom Analytics Dashboard
354
+ Build real-time analytics:
355
+
356
+ ```ruby
357
+ class OpenRouterAnalytics
358
+ def initialize(client)
359
+ @client = client
360
+ @metrics = {}
361
+
362
+ setup_callbacks
363
+ end
364
+
365
+ private
366
+
367
+ def setup_callbacks
368
+ @client.on(:after_response) do |response|
369
+ update_metrics(response)
370
+ broadcast_update(response)
371
+ end
372
+
373
+ @client.on(:on_error) do |error|
374
+ track_error(error)
375
+ end
376
+ end
377
+
378
+ def update_metrics(response)
379
+ @metrics[:requests] ||= 0
380
+ @metrics[:tokens] ||= 0
381
+ @metrics[:cost] ||= 0
382
+
383
+ @metrics[:requests] += 1
384
+ @metrics[:tokens] += response.total_tokens
385
+ @metrics[:cost] += response.cost_estimate || 0
386
+ end
387
+
388
+ def broadcast_update(response)
389
+ # Send to WebSocket, EventSource, etc.
390
+ ActionCable.server.broadcast("analytics_channel", {
391
+ type: "response_completed",
392
+ tokens: response.total_tokens,
393
+ cost: response.cost_estimate,
394
+ model: response.model,
395
+ timestamp: Time.now.iso8601
396
+ })
397
+ end
398
+ end
399
+
400
+ # Usage
401
+ analytics = OpenRouterAnalytics.new(client)
402
+ ```
403
+
404
+ ## Best Practices
405
+
406
+ ### 1. Monitoring Setup
407
+ - Enable usage tracking in production
408
+ - Set up alerts for cost thresholds
409
+ - Monitor cache hit rates for optimization opportunities
410
+ - Track error rates and response times
411
+
412
+ ### 2. Cost Management
413
+ - Set budget alerts using usage tracker
414
+ - Monitor per-model costs to optimize model selection
415
+ - Track cache effectiveness to reduce costs
416
+ - Use fallback models for cost optimization
417
+
418
+ ### 3. Performance Optimization
419
+ - Monitor tokens per second for performance
420
+ - Track cache hit rates by model
421
+ - Use streaming for better perceived performance
422
+ - Monitor healing frequency to identify model issues
423
+
424
+ ### 4. Error Handling
425
+ - Implement comprehensive error callbacks
426
+ - Set up alerting for authentication failures
427
+ - Monitor rate limiting and implement backoff
428
+ - Track healing failures as quality indicators
429
+
430
+ The OpenRouter gem's observability features provide everything you need to monitor, optimize, and maintain reliable AI applications at scale.