ollama-client 0.2.5 → 0.2.7
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/CHANGELOG.md +22 -0
- data/README.md +336 -91
- data/RELEASE_NOTES_v0.2.6.md +41 -0
- data/docs/AREAS_FOR_CONSIDERATION.md +325 -0
- data/docs/EXAMPLE_REORGANIZATION.md +412 -0
- data/docs/FEATURES_ADDED.md +12 -1
- data/docs/GETTING_STARTED.md +361 -0
- data/docs/INTEGRATION_TESTING.md +170 -0
- data/docs/NEXT_STEPS_SUMMARY.md +114 -0
- data/docs/PERSONAS.md +383 -0
- data/docs/QUICK_START.md +195 -0
- data/docs/TESTING.md +392 -170
- data/docs/TEST_CHECKLIST.md +450 -0
- data/examples/README.md +62 -63
- data/examples/basic_chat.rb +33 -0
- data/examples/basic_generate.rb +29 -0
- data/examples/mcp_executor.rb +39 -0
- data/examples/mcp_http_executor.rb +45 -0
- data/examples/tool_calling_parsing.rb +59 -0
- data/examples/tool_dto_example.rb +0 -0
- data/exe/ollama-client +128 -1
- data/lib/ollama/agent/planner.rb +7 -2
- data/lib/ollama/chat_session.rb +101 -0
- data/lib/ollama/client.rb +41 -35
- data/lib/ollama/config.rb +9 -4
- data/lib/ollama/document_loader.rb +1 -1
- data/lib/ollama/embeddings.rb +61 -28
- data/lib/ollama/errors.rb +1 -0
- data/lib/ollama/mcp/http_client.rb +149 -0
- data/lib/ollama/mcp/stdio_client.rb +146 -0
- data/lib/ollama/mcp/tools_bridge.rb +72 -0
- data/lib/ollama/mcp.rb +31 -0
- data/lib/ollama/options.rb +3 -1
- data/lib/ollama/personas.rb +287 -0
- data/lib/ollama/version.rb +1 -1
- data/lib/ollama_client.rb +17 -5
- metadata +22 -48
- data/examples/advanced_complex_schemas.rb +0 -366
- data/examples/advanced_edge_cases.rb +0 -241
- data/examples/advanced_error_handling.rb +0 -200
- data/examples/advanced_multi_step_agent.rb +0 -341
- data/examples/advanced_performance_testing.rb +0 -186
- data/examples/chat_console.rb +0 -143
- data/examples/complete_workflow.rb +0 -245
- data/examples/dhan_console.rb +0 -843
- data/examples/dhanhq/README.md +0 -236
- data/examples/dhanhq/agents/base_agent.rb +0 -74
- data/examples/dhanhq/agents/data_agent.rb +0 -66
- data/examples/dhanhq/agents/orchestrator_agent.rb +0 -120
- data/examples/dhanhq/agents/technical_analysis_agent.rb +0 -252
- data/examples/dhanhq/agents/trading_agent.rb +0 -81
- data/examples/dhanhq/analysis/market_structure.rb +0 -138
- data/examples/dhanhq/analysis/pattern_recognizer.rb +0 -192
- data/examples/dhanhq/analysis/trend_analyzer.rb +0 -88
- data/examples/dhanhq/builders/market_context_builder.rb +0 -67
- data/examples/dhanhq/dhanhq_agent.rb +0 -829
- data/examples/dhanhq/indicators/technical_indicators.rb +0 -158
- data/examples/dhanhq/scanners/intraday_options_scanner.rb +0 -492
- data/examples/dhanhq/scanners/swing_scanner.rb +0 -247
- data/examples/dhanhq/schemas/agent_schemas.rb +0 -61
- data/examples/dhanhq/services/base_service.rb +0 -46
- data/examples/dhanhq/services/data_service.rb +0 -118
- data/examples/dhanhq/services/trading_service.rb +0 -59
- data/examples/dhanhq/technical_analysis_agentic_runner.rb +0 -411
- data/examples/dhanhq/technical_analysis_runner.rb +0 -420
- data/examples/dhanhq/test_tool_calling.rb +0 -538
- data/examples/dhanhq/test_tool_calling_verbose.rb +0 -251
- data/examples/dhanhq/utils/instrument_helper.rb +0 -32
- data/examples/dhanhq/utils/parameter_cleaner.rb +0 -28
- data/examples/dhanhq/utils/parameter_normalizer.rb +0 -45
- data/examples/dhanhq/utils/rate_limiter.rb +0 -23
- data/examples/dhanhq/utils/trading_parameter_normalizer.rb +0 -72
- data/examples/dhanhq_agent.rb +0 -964
- data/examples/dhanhq_tools.rb +0 -1663
- data/examples/multi_step_agent_with_external_data.rb +0 -368
- data/examples/structured_outputs_chat.rb +0 -72
- data/examples/structured_tools.rb +0 -89
- data/examples/test_dhanhq_tool_calling.rb +0 -375
- data/examples/test_tool_calling.rb +0 -160
- data/examples/tool_calling_direct.rb +0 -124
- data/examples/tool_calling_pattern.rb +0 -269
- data/exe/dhan_console +0 -4
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Advanced Example: Edge Cases and Boundary Testing
|
|
5
|
-
# Demonstrates: Empty responses, malformed schemas, extreme values, special characters
|
|
6
|
-
|
|
7
|
-
require "json"
|
|
8
|
-
require_relative "../lib/ollama_client"
|
|
9
|
-
|
|
10
|
-
class EdgeCaseTester
|
|
11
|
-
def initialize(client:)
|
|
12
|
-
@client = client
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def test_empty_prompt
|
|
16
|
-
puts "Test 1: Empty prompt"
|
|
17
|
-
schema = {
|
|
18
|
-
"type" => "object",
|
|
19
|
-
"properties" => {
|
|
20
|
-
"response" => { "type" => "string" }
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
begin
|
|
25
|
-
result = @client.generate(prompt: "", schema: schema)
|
|
26
|
-
puts " ✅ Handled empty prompt: #{result.inspect[0..100]}"
|
|
27
|
-
rescue Ollama::Error => e
|
|
28
|
-
puts " ❌ Error: #{e.class} - #{e.message}"
|
|
29
|
-
end
|
|
30
|
-
puts
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def test_very_long_prompt
|
|
34
|
-
puts "Test 2: Very long prompt (10KB+)"
|
|
35
|
-
long_prompt = "Repeat this sentence. " * 500
|
|
36
|
-
schema = {
|
|
37
|
-
"type" => "object",
|
|
38
|
-
"properties" => {
|
|
39
|
-
"summary" => { "type" => "string" }
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
begin
|
|
44
|
-
@client.generate(prompt: long_prompt, schema: schema)
|
|
45
|
-
puts " ✅ Handled long prompt (#{long_prompt.length} chars)"
|
|
46
|
-
rescue Ollama::Error => e
|
|
47
|
-
puts " ❌ Error: #{e.class} - #{e.message}"
|
|
48
|
-
end
|
|
49
|
-
puts
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def test_special_characters
|
|
53
|
-
puts "Test 3: Special characters in prompt"
|
|
54
|
-
special_prompt = "Analyze: !@#$%^&*()_+-=[]{}|;':\",./<>?`~"
|
|
55
|
-
schema = {
|
|
56
|
-
"type" => "object",
|
|
57
|
-
"properties" => {
|
|
58
|
-
"analysis" => { "type" => "string" }
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
begin
|
|
63
|
-
@client.generate(prompt: special_prompt, schema: schema)
|
|
64
|
-
puts " ✅ Handled special characters"
|
|
65
|
-
rescue Ollama::Error => e
|
|
66
|
-
puts " ❌ Error: #{e.class} - #{e.message}"
|
|
67
|
-
end
|
|
68
|
-
puts
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def test_unicode_characters
|
|
72
|
-
puts "Test 4: Unicode characters"
|
|
73
|
-
unicode_prompt = "Analyze: 你好世界 🌍 🚀 émojis and spéciál chäracters"
|
|
74
|
-
schema = {
|
|
75
|
-
"type" => "object",
|
|
76
|
-
"properties" => {
|
|
77
|
-
"analysis" => { "type" => "string" }
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
begin
|
|
82
|
-
@client.generate(prompt: unicode_prompt, schema: schema)
|
|
83
|
-
puts " ✅ Handled unicode characters"
|
|
84
|
-
rescue Ollama::Error => e
|
|
85
|
-
puts " ❌ Error: #{e.class} - #{e.message}"
|
|
86
|
-
end
|
|
87
|
-
puts
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def test_minimal_schema
|
|
91
|
-
puts "Test 5: Minimal schema (no required fields)"
|
|
92
|
-
schema = {
|
|
93
|
-
"type" => "object",
|
|
94
|
-
"additionalProperties" => true
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
begin
|
|
98
|
-
result = @client.generate(
|
|
99
|
-
prompt: "Return any JSON object",
|
|
100
|
-
schema: schema
|
|
101
|
-
)
|
|
102
|
-
puts " ✅ Handled minimal schema: #{result.keys.join(', ')}"
|
|
103
|
-
rescue Ollama::Error => e
|
|
104
|
-
puts " ❌ Error: #{e.class} - #{e.message}"
|
|
105
|
-
end
|
|
106
|
-
puts
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def test_strict_schema
|
|
110
|
-
puts "Test 6: Strict schema with many constraints"
|
|
111
|
-
strict_schema = {
|
|
112
|
-
"type" => "object",
|
|
113
|
-
"required" => ["id", "name", "values"],
|
|
114
|
-
"properties" => {
|
|
115
|
-
"id" => {
|
|
116
|
-
"type" => "integer",
|
|
117
|
-
"minimum" => 1,
|
|
118
|
-
"maximum" => 1000
|
|
119
|
-
},
|
|
120
|
-
"name" => {
|
|
121
|
-
"type" => "string",
|
|
122
|
-
"minLength" => 3,
|
|
123
|
-
"maxLength" => 20,
|
|
124
|
-
"pattern" => "^[A-Za-z0-9_]+$"
|
|
125
|
-
},
|
|
126
|
-
"values" => {
|
|
127
|
-
"type" => "array",
|
|
128
|
-
"minItems" => 2,
|
|
129
|
-
"maxItems" => 5,
|
|
130
|
-
"items" => {
|
|
131
|
-
"type" => "number",
|
|
132
|
-
"minimum" => 0,
|
|
133
|
-
"maximum" => 100
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
begin
|
|
140
|
-
prompt_text = "Generate a valid object with id (1-1000), " \
|
|
141
|
-
"name (3-20 alphanumeric chars), " \
|
|
142
|
-
"and values (2-5 numbers 0-100)"
|
|
143
|
-
result = @client.generate(
|
|
144
|
-
prompt: prompt_text,
|
|
145
|
-
schema: strict_schema
|
|
146
|
-
)
|
|
147
|
-
puts " ✅ Handled strict schema"
|
|
148
|
-
puts " ID: #{result['id']}, Name: #{result['name']}, Values: #{result['values']}"
|
|
149
|
-
rescue Ollama::Error => e
|
|
150
|
-
puts " ❌ Error: #{e.class} - #{e.message}"
|
|
151
|
-
end
|
|
152
|
-
puts
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def test_nested_arrays
|
|
156
|
-
puts "Test 7: Deeply nested arrays"
|
|
157
|
-
nested_schema = {
|
|
158
|
-
"type" => "object",
|
|
159
|
-
"properties" => {
|
|
160
|
-
"matrix" => {
|
|
161
|
-
"type" => "array",
|
|
162
|
-
"items" => {
|
|
163
|
-
"type" => "array",
|
|
164
|
-
"items" => {
|
|
165
|
-
"type" => "array",
|
|
166
|
-
"items" => { "type" => "integer" }
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
begin
|
|
174
|
-
@client.generate(
|
|
175
|
-
prompt: "Generate a 2x2x2 matrix of integers",
|
|
176
|
-
schema: nested_schema
|
|
177
|
-
)
|
|
178
|
-
puts " ✅ Handled nested arrays"
|
|
179
|
-
rescue Ollama::Error => e
|
|
180
|
-
puts " ❌ Error: #{e.class} - #{e.message}"
|
|
181
|
-
end
|
|
182
|
-
puts
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def test_enum_constraints
|
|
186
|
-
puts "Test 8: Strict enum constraints"
|
|
187
|
-
enum_schema = {
|
|
188
|
-
"type" => "object",
|
|
189
|
-
"required" => ["status", "priority"],
|
|
190
|
-
"properties" => {
|
|
191
|
-
"status" => {
|
|
192
|
-
"type" => "string",
|
|
193
|
-
"enum" => ["pending", "in_progress", "completed", "failed"]
|
|
194
|
-
},
|
|
195
|
-
"priority" => {
|
|
196
|
-
"type" => "string",
|
|
197
|
-
"enum" => ["low", "medium", "high", "urgent"]
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
begin
|
|
203
|
-
result = @client.generate(
|
|
204
|
-
prompt: "Choose a status and priority from the allowed values",
|
|
205
|
-
schema: enum_schema
|
|
206
|
-
)
|
|
207
|
-
puts " ✅ Handled enum constraints: status=#{result['status']}, priority=#{result['priority']}"
|
|
208
|
-
rescue Ollama::Error => e
|
|
209
|
-
puts " ❌ Error: #{e.class} - #{e.message}"
|
|
210
|
-
end
|
|
211
|
-
puts
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def run_all_tests
|
|
215
|
-
puts "=" * 60
|
|
216
|
-
puts "Edge Case Testing Suite"
|
|
217
|
-
puts "=" * 60
|
|
218
|
-
puts
|
|
219
|
-
|
|
220
|
-
test_empty_prompt
|
|
221
|
-
test_very_long_prompt
|
|
222
|
-
test_special_characters
|
|
223
|
-
test_unicode_characters
|
|
224
|
-
test_minimal_schema
|
|
225
|
-
test_strict_schema
|
|
226
|
-
test_nested_arrays
|
|
227
|
-
test_enum_constraints
|
|
228
|
-
|
|
229
|
-
puts "=" * 60
|
|
230
|
-
puts "Edge case testing complete!"
|
|
231
|
-
puts "=" * 60
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
# Run tests
|
|
236
|
-
if __FILE__ == $PROGRAM_NAME
|
|
237
|
-
client = Ollama::Client.new
|
|
238
|
-
tester = EdgeCaseTester.new(client: client)
|
|
239
|
-
tester.run_all_tests
|
|
240
|
-
end
|
|
241
|
-
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Advanced Example: Comprehensive Error Handling and Recovery Patterns
|
|
5
|
-
# Demonstrates: All error types, retry strategies, fallback mechanisms, observability
|
|
6
|
-
|
|
7
|
-
require "json"
|
|
8
|
-
require_relative "../lib/ollama_client"
|
|
9
|
-
|
|
10
|
-
class ResilientAgent
|
|
11
|
-
def initialize(client:)
|
|
12
|
-
@client = client
|
|
13
|
-
@stats = {
|
|
14
|
-
total_calls: 0,
|
|
15
|
-
successes: 0,
|
|
16
|
-
retries: 0,
|
|
17
|
-
failures: 0,
|
|
18
|
-
errors_by_type: {}
|
|
19
|
-
}
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
23
|
-
def execute_with_resilience(prompt:, schema:, max_attempts: 3)
|
|
24
|
-
@stats[:total_calls] += 1
|
|
25
|
-
attempt = 0
|
|
26
|
-
|
|
27
|
-
loop do
|
|
28
|
-
attempt += 1
|
|
29
|
-
puts "\n📞 Attempt #{attempt}/#{max_attempts}"
|
|
30
|
-
|
|
31
|
-
begin
|
|
32
|
-
result = @client.generate(prompt: prompt, schema: schema)
|
|
33
|
-
@stats[:successes] += 1
|
|
34
|
-
puts "✅ Success on attempt #{attempt}"
|
|
35
|
-
return { success: true, result: result, attempts: attempt }
|
|
36
|
-
rescue Ollama::NotFoundError => e
|
|
37
|
-
@stats[:failures] += 1
|
|
38
|
-
@stats[:errors_by_type]["NotFoundError"] ||= 0
|
|
39
|
-
@stats[:errors_by_type]["NotFoundError"] += 1
|
|
40
|
-
|
|
41
|
-
puts "❌ Model not found: #{e.message}"
|
|
42
|
-
puts " Suggestions: #{e.suggestions.join(', ')}" if e.suggestions && !e.suggestions.empty?
|
|
43
|
-
# Don't retry 404s
|
|
44
|
-
return { success: false, error: e, error_type: "NotFoundError", attempts: attempt }
|
|
45
|
-
rescue Ollama::HTTPError => e
|
|
46
|
-
@stats[:failures] += 1
|
|
47
|
-
@stats[:errors_by_type]["HTTPError"] ||= 0
|
|
48
|
-
@stats[:errors_by_type]["HTTPError"] += 1
|
|
49
|
-
|
|
50
|
-
puts "❌ HTTP Error (#{e.status_code}): #{e.message}"
|
|
51
|
-
if e.retryable?
|
|
52
|
-
@stats[:retries] += 1
|
|
53
|
-
puts " → Retryable, will retry..."
|
|
54
|
-
if attempt > max_attempts
|
|
55
|
-
return { success: false, error: e, error_type: "HTTPError", retryable: true,
|
|
56
|
-
attempts: attempt }
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
sleep(2**attempt) # Exponential backoff
|
|
60
|
-
next
|
|
61
|
-
else
|
|
62
|
-
puts " → Non-retryable, aborting"
|
|
63
|
-
return { success: false, error: e, error_type: "HTTPError", retryable: false, attempts: attempt }
|
|
64
|
-
end
|
|
65
|
-
rescue Ollama::TimeoutError => e
|
|
66
|
-
@stats[:failures] += 1
|
|
67
|
-
@stats[:errors_by_type]["TimeoutError"] ||= 0
|
|
68
|
-
@stats[:errors_by_type]["TimeoutError"] += 1
|
|
69
|
-
|
|
70
|
-
puts "⏱️ Timeout: #{e.message}"
|
|
71
|
-
@stats[:retries] += 1
|
|
72
|
-
return { success: false, error: e, error_type: "TimeoutError", attempts: attempt } unless attempt < max_attempts
|
|
73
|
-
|
|
74
|
-
puts " → Retrying with exponential backoff..."
|
|
75
|
-
sleep(2**attempt)
|
|
76
|
-
next
|
|
77
|
-
rescue Ollama::SchemaViolationError => e
|
|
78
|
-
@stats[:failures] += 1
|
|
79
|
-
@stats[:errors_by_type]["SchemaViolationError"] ||= 0
|
|
80
|
-
@stats[:errors_by_type]["SchemaViolationError"] += 1
|
|
81
|
-
|
|
82
|
-
puts "🔴 Schema violation: #{e.message}"
|
|
83
|
-
# Schema violations are usually not worth retrying (model issue)
|
|
84
|
-
# But we could try with a simpler schema as fallback
|
|
85
|
-
unless attempt < max_attempts
|
|
86
|
-
return { success: false, error: e, error_type: "SchemaViolationError", attempts: attempt }
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
puts " → Attempting with simplified schema..."
|
|
90
|
-
simplified_schema = create_fallback_schema(schema)
|
|
91
|
-
return execute_with_resilience(
|
|
92
|
-
prompt: prompt,
|
|
93
|
-
schema: simplified_schema,
|
|
94
|
-
max_attempts: 1
|
|
95
|
-
)
|
|
96
|
-
rescue Ollama::InvalidJSONError => e
|
|
97
|
-
@stats[:failures] += 1
|
|
98
|
-
@stats[:errors_by_type]["InvalidJSONError"] ||= 0
|
|
99
|
-
@stats[:errors_by_type]["InvalidJSONError"] += 1
|
|
100
|
-
|
|
101
|
-
puts "📄 Invalid JSON: #{e.message}"
|
|
102
|
-
@stats[:retries] += 1
|
|
103
|
-
unless attempt < max_attempts
|
|
104
|
-
return { success: false, error: e, error_type: "InvalidJSONError", attempts: attempt }
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
puts " → Retrying..."
|
|
108
|
-
sleep(1)
|
|
109
|
-
next
|
|
110
|
-
rescue Ollama::RetryExhaustedError => e
|
|
111
|
-
@stats[:failures] += 1
|
|
112
|
-
@stats[:errors_by_type]["RetryExhaustedError"] ||= 0
|
|
113
|
-
@stats[:errors_by_type]["RetryExhaustedError"] += 1
|
|
114
|
-
|
|
115
|
-
puts "🔄 Retries exhausted: #{e.message}"
|
|
116
|
-
return { success: false, error: e, error_type: "RetryExhaustedError", attempts: attempt }
|
|
117
|
-
rescue Ollama::Error => e
|
|
118
|
-
@stats[:failures] += 1
|
|
119
|
-
@stats[:errors_by_type]["Error"] ||= 0
|
|
120
|
-
@stats[:errors_by_type]["Error"] += 1
|
|
121
|
-
|
|
122
|
-
puts "❌ General error: #{e.message}"
|
|
123
|
-
return { success: false, error: e, error_type: "Error", attempts: attempt }
|
|
124
|
-
rescue StandardError => e
|
|
125
|
-
@stats[:failures] += 1
|
|
126
|
-
@stats[:errors_by_type]["StandardError"] ||= 0
|
|
127
|
-
@stats[:errors_by_type]["StandardError"] += 1
|
|
128
|
-
|
|
129
|
-
puts "💥 Unexpected error: #{e.class}: #{e.message}"
|
|
130
|
-
return { success: false, error: e, error_type: "StandardError", attempts: attempt }
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
135
|
-
|
|
136
|
-
def create_fallback_schema(_original_schema)
|
|
137
|
-
# Create a minimal fallback schema
|
|
138
|
-
{
|
|
139
|
-
"type" => "object",
|
|
140
|
-
"additionalProperties" => true
|
|
141
|
-
}
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def display_stats
|
|
145
|
-
puts "\n" + "=" * 60
|
|
146
|
-
puts "Execution Statistics"
|
|
147
|
-
puts "=" * 60
|
|
148
|
-
puts "Total calls: #{@stats[:total_calls]}"
|
|
149
|
-
puts "Successes: #{@stats[:successes]}"
|
|
150
|
-
puts "Failures: #{@stats[:failures]}"
|
|
151
|
-
puts "Retries: #{@stats[:retries]}"
|
|
152
|
-
success_rate = @stats[:total_calls].positive? ? (@stats[:successes].to_f / @stats[:total_calls] * 100).round(2) : 0
|
|
153
|
-
puts "Success rate: #{success_rate}%"
|
|
154
|
-
puts "\nErrors by type:"
|
|
155
|
-
@stats[:errors_by_type].each do |type, count|
|
|
156
|
-
puts " #{type}: #{count}"
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
# Test scenarios
|
|
162
|
-
if __FILE__ == $PROGRAM_NAME
|
|
163
|
-
client = Ollama::Client.new
|
|
164
|
-
agent = ResilientAgent.new(client: client)
|
|
165
|
-
|
|
166
|
-
schema = {
|
|
167
|
-
"type" => "object",
|
|
168
|
-
"required" => ["status", "message"],
|
|
169
|
-
"properties" => {
|
|
170
|
-
"status" => { "type" => "string" },
|
|
171
|
-
"message" => { "type" => "string" }
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
puts "=" * 60
|
|
176
|
-
puts "Test 1: Normal execution"
|
|
177
|
-
puts "=" * 60
|
|
178
|
-
result1 = agent.execute_with_resilience(
|
|
179
|
-
prompt: "Respond with status 'ok' and a greeting message",
|
|
180
|
-
schema: schema
|
|
181
|
-
)
|
|
182
|
-
puts "Result: #{result1[:success] ? 'SUCCESS' : 'FAILED'}"
|
|
183
|
-
|
|
184
|
-
puts "\n" + "=" * 60
|
|
185
|
-
puts "Test 2: Invalid model (should trigger NotFoundError)"
|
|
186
|
-
puts "=" * 60
|
|
187
|
-
# Temporarily use invalid model
|
|
188
|
-
invalid_client = Ollama::Client.new(
|
|
189
|
-
config: Ollama::Config.new.tap { |c| c.model = "nonexistent-model:999" }
|
|
190
|
-
)
|
|
191
|
-
invalid_agent = ResilientAgent.new(client: invalid_client)
|
|
192
|
-
result2 = invalid_agent.execute_with_resilience(
|
|
193
|
-
prompt: "Test",
|
|
194
|
-
schema: schema
|
|
195
|
-
)
|
|
196
|
-
puts "Result: #{result2[:success] ? 'SUCCESS' : 'FAILED'}"
|
|
197
|
-
|
|
198
|
-
agent.display_stats
|
|
199
|
-
end
|
|
200
|
-
|