ollama-client 0.2.4 → 0.2.6
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 +21 -1
- data/README.md +560 -106
- data/docs/EXAMPLE_REORGANIZATION.md +412 -0
- 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/README.md +2 -3
- data/docs/RELEASE_GUIDE.md +376 -0
- data/docs/TESTING.md +392 -170
- data/docs/TEST_CHECKLIST.md +450 -0
- data/docs/ruby_guide.md +6232 -0
- data/examples/README.md +51 -66
- data/examples/basic_chat.rb +33 -0
- data/examples/basic_generate.rb +29 -0
- data/examples/tool_calling_parsing.rb +59 -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 +43 -21
- data/lib/ollama/config.rb +4 -1
- data/lib/ollama/document_loader.rb +163 -0
- data/lib/ollama/embeddings.rb +42 -13
- data/lib/ollama/errors.rb +1 -0
- data/lib/ollama/personas.rb +287 -0
- data/lib/ollama/version.rb +1 -1
- data/lib/ollama_client.rb +8 -0
- metadata +31 -53
- data/docs/GEM_RELEASE_GUIDE.md +0 -794
- data/docs/GET_RUBYGEMS_SECRET.md +0 -151
- data/docs/QUICK_OTP_SETUP.md +0 -80
- data/docs/QUICK_RELEASE.md +0 -106
- data/docs/RUBYGEMS_OTP_SETUP.md +0 -199
- 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,366 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Advanced Example: Complex Nested Schemas and Validation
|
|
5
|
-
# Demonstrates: Deep nesting, arrays of objects, conditional validation, real-world data structures
|
|
6
|
-
|
|
7
|
-
require "json"
|
|
8
|
-
require_relative "../lib/ollama_client"
|
|
9
|
-
|
|
10
|
-
# Example 1: Financial Analysis Schema
|
|
11
|
-
class FinancialAnalyzer
|
|
12
|
-
def initialize(client:)
|
|
13
|
-
@client = client
|
|
14
|
-
@schema = {
|
|
15
|
-
"type" => "object",
|
|
16
|
-
"required" => ["analysis_date", "summary", "metrics", "recommendations"],
|
|
17
|
-
"properties" => {
|
|
18
|
-
"analysis_date" => {
|
|
19
|
-
"type" => "string",
|
|
20
|
-
"format" => "date-time"
|
|
21
|
-
},
|
|
22
|
-
"summary" => {
|
|
23
|
-
"type" => "string",
|
|
24
|
-
"minLength" => 50,
|
|
25
|
-
"maxLength" => 500
|
|
26
|
-
},
|
|
27
|
-
"metrics" => {
|
|
28
|
-
"type" => "object",
|
|
29
|
-
"required" => ["revenue", "profit_margin", "growth_rate"],
|
|
30
|
-
"properties" => {
|
|
31
|
-
"revenue" => {
|
|
32
|
-
"type" => "number",
|
|
33
|
-
"minimum" => 0
|
|
34
|
-
},
|
|
35
|
-
"profit_margin" => {
|
|
36
|
-
"type" => "number",
|
|
37
|
-
"minimum" => 0,
|
|
38
|
-
"maximum" => 100,
|
|
39
|
-
"description" => "Profit margin as percentage (0 to 100)"
|
|
40
|
-
},
|
|
41
|
-
"growth_rate" => {
|
|
42
|
-
"type" => "number"
|
|
43
|
-
},
|
|
44
|
-
"trend" => {
|
|
45
|
-
"type" => "string",
|
|
46
|
-
"enum" => ["increasing", "stable", "decreasing"]
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
"recommendations" => {
|
|
51
|
-
"type" => "array",
|
|
52
|
-
"minItems" => 1,
|
|
53
|
-
"maxItems" => 10,
|
|
54
|
-
"items" => {
|
|
55
|
-
"type" => "object",
|
|
56
|
-
"required" => ["action", "priority", "rationale"],
|
|
57
|
-
"properties" => {
|
|
58
|
-
"action" => {
|
|
59
|
-
"type" => "string"
|
|
60
|
-
},
|
|
61
|
-
"priority" => {
|
|
62
|
-
"type" => "string",
|
|
63
|
-
"enum" => ["low", "medium", "high", "critical"]
|
|
64
|
-
},
|
|
65
|
-
"rationale" => {
|
|
66
|
-
"type" => "string"
|
|
67
|
-
},
|
|
68
|
-
"estimated_impact" => {
|
|
69
|
-
"type" => "object",
|
|
70
|
-
"properties" => {
|
|
71
|
-
"revenue_impact" => {
|
|
72
|
-
"type" => "number"
|
|
73
|
-
},
|
|
74
|
-
"risk_level" => {
|
|
75
|
-
"type" => "string",
|
|
76
|
-
"enum" => ["low", "medium", "high"]
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
"risk_factors" => {
|
|
84
|
-
"type" => "array",
|
|
85
|
-
"items" => {
|
|
86
|
-
"type" => "object",
|
|
87
|
-
"required" => ["factor", "severity"],
|
|
88
|
-
"properties" => {
|
|
89
|
-
"factor" => { "type" => "string" },
|
|
90
|
-
"severity" => {
|
|
91
|
-
"type" => "string",
|
|
92
|
-
"enum" => ["low", "medium", "high", "critical"]
|
|
93
|
-
},
|
|
94
|
-
"mitigation" => { "type" => "string" }
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def analyze(data:)
|
|
103
|
-
prompt = <<~PROMPT
|
|
104
|
-
Analyze this financial data: #{data}
|
|
105
|
-
|
|
106
|
-
Return JSON with: summary (50-500 chars), metrics (revenue, profit_margin, growth_rate, trend),
|
|
107
|
-
recommendations array (action, priority, rationale), and optional risk_factors array.
|
|
108
|
-
PROMPT
|
|
109
|
-
|
|
110
|
-
@client.generate(prompt: prompt, schema: @schema)
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# Example 2: Code Review Schema
|
|
115
|
-
class CodeReviewer
|
|
116
|
-
def initialize(client:)
|
|
117
|
-
@client = client
|
|
118
|
-
@schema = {
|
|
119
|
-
"type" => "object",
|
|
120
|
-
"required" => ["overall_score", "issues", "suggestions"],
|
|
121
|
-
"properties" => {
|
|
122
|
-
"overall_score" => {
|
|
123
|
-
"type" => "integer",
|
|
124
|
-
"minimum" => 0,
|
|
125
|
-
"maximum" => 100,
|
|
126
|
-
"description" => "Overall quality score (0 to 100)"
|
|
127
|
-
},
|
|
128
|
-
"issues" => {
|
|
129
|
-
"type" => "array",
|
|
130
|
-
"items" => {
|
|
131
|
-
"type" => "object",
|
|
132
|
-
"required" => ["type", "severity", "location", "description"],
|
|
133
|
-
"properties" => {
|
|
134
|
-
"type" => {
|
|
135
|
-
"type" => "string",
|
|
136
|
-
"enum" => ["bug", "security", "performance", "style", "maintainability"]
|
|
137
|
-
},
|
|
138
|
-
"severity" => {
|
|
139
|
-
"type" => "string",
|
|
140
|
-
"enum" => ["low", "medium", "high", "critical"]
|
|
141
|
-
},
|
|
142
|
-
"location" => {
|
|
143
|
-
"type" => "object",
|
|
144
|
-
"properties" => {
|
|
145
|
-
"file" => { "type" => "string" },
|
|
146
|
-
"line" => { "type" => "integer" },
|
|
147
|
-
"column" => { "type" => "integer" }
|
|
148
|
-
}
|
|
149
|
-
},
|
|
150
|
-
"description" => { "type" => "string" },
|
|
151
|
-
"suggestion" => { "type" => "string" }
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
"suggestions" => {
|
|
156
|
-
"type" => "array",
|
|
157
|
-
"items" => {
|
|
158
|
-
"type" => "object",
|
|
159
|
-
"required" => ["category", "description"],
|
|
160
|
-
"properties" => {
|
|
161
|
-
"category" => {
|
|
162
|
-
"type" => "string",
|
|
163
|
-
"enum" => ["refactoring", "optimization", "documentation", "testing"]
|
|
164
|
-
},
|
|
165
|
-
"description" => { "type" => "string" },
|
|
166
|
-
"priority" => {
|
|
167
|
-
"type" => "string",
|
|
168
|
-
"enum" => ["low", "medium", "high"]
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
"strengths" => {
|
|
174
|
-
"type" => "array",
|
|
175
|
-
"items" => { "type" => "string" }
|
|
176
|
-
},
|
|
177
|
-
"estimated_effort" => {
|
|
178
|
-
"type" => "object",
|
|
179
|
-
"properties" => {
|
|
180
|
-
"hours" => { "type" => "number", "minimum" => 0 },
|
|
181
|
-
"complexity" => {
|
|
182
|
-
"type" => "string",
|
|
183
|
-
"enum" => ["simple", "moderate", "complex"]
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def review(code:)
|
|
192
|
-
prompt = <<~PROMPT
|
|
193
|
-
Review this Ruby code: #{code}
|
|
194
|
-
|
|
195
|
-
Return JSON with: overall_score (0-100), issues array (type, severity, location, description),
|
|
196
|
-
suggestions array (category, description, priority), optional strengths array, optional estimated_effort.
|
|
197
|
-
PROMPT
|
|
198
|
-
|
|
199
|
-
@client.generate(prompt: prompt, schema: @schema)
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
# Example 3: Research Paper Analysis Schema
|
|
204
|
-
class ResearchAnalyzer
|
|
205
|
-
def initialize(client:)
|
|
206
|
-
@client = client
|
|
207
|
-
@schema = {
|
|
208
|
-
"type" => "object",
|
|
209
|
-
"required" => ["title", "key_findings", "methodology", "citations"],
|
|
210
|
-
"properties" => {
|
|
211
|
-
"title" => { "type" => "string" },
|
|
212
|
-
"key_findings" => {
|
|
213
|
-
"type" => "array",
|
|
214
|
-
"minItems" => 3,
|
|
215
|
-
"maxItems" => 10,
|
|
216
|
-
"items" => {
|
|
217
|
-
"type" => "object",
|
|
218
|
-
"required" => ["finding", "significance"],
|
|
219
|
-
"properties" => {
|
|
220
|
-
"finding" => { "type" => "string" },
|
|
221
|
-
"significance" => {
|
|
222
|
-
"type" => "string",
|
|
223
|
-
"enum" => ["low", "medium", "high", "breakthrough"]
|
|
224
|
-
},
|
|
225
|
-
"evidence" => { "type" => "string" }
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
"methodology" => {
|
|
230
|
-
"type" => "object",
|
|
231
|
-
"required" => ["type", "description"],
|
|
232
|
-
"properties" => {
|
|
233
|
-
"type" => {
|
|
234
|
-
"type" => "string",
|
|
235
|
-
"enum" => ["experimental", "observational", "theoretical", "computational", "mixed"]
|
|
236
|
-
},
|
|
237
|
-
"description" => { "type" => "string" },
|
|
238
|
-
"limitations" => {
|
|
239
|
-
"type" => "array",
|
|
240
|
-
"items" => { "type" => "string" }
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
},
|
|
244
|
-
"citations" => {
|
|
245
|
-
"type" => "array",
|
|
246
|
-
"items" => {
|
|
247
|
-
"type" => "object",
|
|
248
|
-
"required" => ["author", "title", "year"],
|
|
249
|
-
"properties" => {
|
|
250
|
-
"author" => { "type" => "string" },
|
|
251
|
-
"title" => { "type" => "string" },
|
|
252
|
-
"year" => {
|
|
253
|
-
"type" => "integer",
|
|
254
|
-
"minimum" => 1900,
|
|
255
|
-
"maximum" => 2100
|
|
256
|
-
},
|
|
257
|
-
"relevance" => {
|
|
258
|
-
"type" => "string",
|
|
259
|
-
"enum" => ["low", "medium", "high"]
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
},
|
|
264
|
-
"reproducibility_score" => {
|
|
265
|
-
"type" => "number",
|
|
266
|
-
"minimum" => 0,
|
|
267
|
-
"maximum" => 1,
|
|
268
|
-
"description" => "Reproducibility score (0.0 to 1.0, where 1.0 means fully reproducible)"
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
def analyze(paper_text:)
|
|
275
|
-
prompt = <<~PROMPT
|
|
276
|
-
Analyze this research paper: #{paper_text}
|
|
277
|
-
|
|
278
|
-
Return JSON with: title, key_findings array (3-10 items: finding, significance, evidence),
|
|
279
|
-
methodology (type, description, limitations), citations array (author, title, year, relevance),
|
|
280
|
-
optional reproducibility_score (0-1).
|
|
281
|
-
PROMPT
|
|
282
|
-
|
|
283
|
-
@client.generate(prompt: prompt, schema: @schema)
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
# Run examples
|
|
288
|
-
if __FILE__ == $PROGRAM_NAME
|
|
289
|
-
# Use longer timeout for complex schemas
|
|
290
|
-
config = Ollama::Config.new
|
|
291
|
-
config.timeout = 60 # 60 seconds for complex operations
|
|
292
|
-
client = Ollama::Client.new(config: config)
|
|
293
|
-
|
|
294
|
-
puts "=" * 60
|
|
295
|
-
puts "Example 1: Financial Analysis"
|
|
296
|
-
puts "=" * 60
|
|
297
|
-
financial_data = <<~DATA
|
|
298
|
-
Q4 2024 Financial Report:
|
|
299
|
-
- Revenue: $2.5M (up 15% from Q3)
|
|
300
|
-
- Operating expenses: $1.8M
|
|
301
|
-
- Net profit: $700K
|
|
302
|
-
- Customer base: 5,000 (up 20%)
|
|
303
|
-
- Churn rate: 2% (down from 3%)
|
|
304
|
-
DATA
|
|
305
|
-
|
|
306
|
-
analyzer = FinancialAnalyzer.new(client: client)
|
|
307
|
-
begin
|
|
308
|
-
puts "⏳ Analyzing financial data (this may take 30-60 seconds)..."
|
|
309
|
-
result = analyzer.analyze(data: financial_data)
|
|
310
|
-
puts JSON.pretty_generate(result)
|
|
311
|
-
rescue Ollama::TimeoutError => e
|
|
312
|
-
puts "⏱️ Timeout: #{e.message}"
|
|
313
|
-
puts " Try increasing timeout or using a faster model"
|
|
314
|
-
rescue Ollama::Error => e
|
|
315
|
-
puts "❌ Error: #{e.message}"
|
|
316
|
-
end
|
|
317
|
-
|
|
318
|
-
puts "\n" + "=" * 60
|
|
319
|
-
puts "Example 2: Code Review"
|
|
320
|
-
puts "=" * 60
|
|
321
|
-
code_sample = <<~RUBY
|
|
322
|
-
def calculate_total(items)
|
|
323
|
-
total = 0
|
|
324
|
-
items.each do |item|
|
|
325
|
-
total += item.price
|
|
326
|
-
end
|
|
327
|
-
total
|
|
328
|
-
end
|
|
329
|
-
RUBY
|
|
330
|
-
|
|
331
|
-
reviewer = CodeReviewer.new(client: client)
|
|
332
|
-
begin
|
|
333
|
-
puts "⏳ Reviewing code (this may take 30-60 seconds)..."
|
|
334
|
-
result = reviewer.review(code: code_sample)
|
|
335
|
-
puts JSON.pretty_generate(result)
|
|
336
|
-
rescue Ollama::TimeoutError => e
|
|
337
|
-
puts "⏱️ Timeout: #{e.message}"
|
|
338
|
-
puts " Try increasing timeout or using a faster model"
|
|
339
|
-
rescue Ollama::Error => e
|
|
340
|
-
puts "❌ Error: #{e.message}"
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
puts "\n" + "=" * 60
|
|
344
|
-
puts "Example 3: Research Paper Analysis"
|
|
345
|
-
puts "=" * 60
|
|
346
|
-
paper_abstract = <<~TEXT
|
|
347
|
-
This study investigates the impact of machine learning on financial forecasting.
|
|
348
|
-
We analyzed 10 years of market data using neural networks and found a 23% improvement
|
|
349
|
-
in prediction accuracy. The methodology involved training on historical data and
|
|
350
|
-
validating on out-of-sample periods. Key limitations include data quality and
|
|
351
|
-
model interpretability challenges.
|
|
352
|
-
TEXT
|
|
353
|
-
|
|
354
|
-
research_analyzer = ResearchAnalyzer.new(client: client)
|
|
355
|
-
begin
|
|
356
|
-
puts "⏳ Analyzing research paper (this may take 30-60 seconds)..."
|
|
357
|
-
result = research_analyzer.analyze(paper_text: paper_abstract)
|
|
358
|
-
puts JSON.pretty_generate(result)
|
|
359
|
-
rescue Ollama::TimeoutError => e
|
|
360
|
-
puts "⏱️ Timeout: #{e.message}"
|
|
361
|
-
puts " Try increasing timeout or using a faster model"
|
|
362
|
-
rescue Ollama::Error => e
|
|
363
|
-
puts "❌ Error: #{e.message}"
|
|
364
|
-
end
|
|
365
|
-
end
|
|
366
|
-
|
|
@@ -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
|
-
|