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
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
# Test Checklist: `ollama-client` Client-Only Testing
|
|
2
|
+
|
|
3
|
+
This checklist ensures comprehensive testing of the `ollama-client` transport layer without leaking agent concerns.
|
|
4
|
+
|
|
5
|
+
## Category A: `/generate` Mode Tests (Stateless, Deterministic)
|
|
6
|
+
|
|
7
|
+
### ✅ G1 — Basic Generate
|
|
8
|
+
- [ ] Response is a Hash
|
|
9
|
+
- [ ] JSON is parsed correctly
|
|
10
|
+
- [ ] No `tool_calls` present
|
|
11
|
+
- [ ] No streaming artifacts
|
|
12
|
+
- [ ] Schema validation passes (if schema provided)
|
|
13
|
+
|
|
14
|
+
**Test File:** `spec/ollama/client_generate_spec.rb`
|
|
15
|
+
|
|
16
|
+
**Example Test:**
|
|
17
|
+
```ruby
|
|
18
|
+
it "parses JSON response from generate endpoint" do
|
|
19
|
+
stub_request(:post, "http://localhost:11434/api/generate")
|
|
20
|
+
.to_return(
|
|
21
|
+
status: 200,
|
|
22
|
+
body: { response: '{"status":"ok"}' }.to_json
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
result = client.generate(
|
|
26
|
+
prompt: "Output a JSON object with a single key 'status' and value 'ok'.",
|
|
27
|
+
schema: { "type" => "object", "required" => ["status"] }
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
expect(result).to be_a(Hash)
|
|
31
|
+
expect(result["status"]).to eq("ok")
|
|
32
|
+
expect(result).not_to have_key("tool_calls")
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
### ✅ G2 — Strict Schema Enforcement
|
|
39
|
+
- [ ] Raises error if schema violated
|
|
40
|
+
- [ ] Rejects extra fields (if strict mode enabled)
|
|
41
|
+
- [ ] Validates required fields
|
|
42
|
+
- [ ] Validates type constraints
|
|
43
|
+
- [ ] Validates enum constraints
|
|
44
|
+
- [ ] Validates number min/max
|
|
45
|
+
- [ ] Validates string minLength/maxLength
|
|
46
|
+
|
|
47
|
+
**Test File:** `spec/ollama/client_generate_spec.rb` or `spec/ollama/schema_validator_spec.rb`
|
|
48
|
+
|
|
49
|
+
**Example Test:**
|
|
50
|
+
```ruby
|
|
51
|
+
it "rejects responses that violate schema" do
|
|
52
|
+
stub_request(:post, "http://localhost:11434/api/generate")
|
|
53
|
+
.to_return(
|
|
54
|
+
status: 200,
|
|
55
|
+
body: { response: '{"count":"not-a-number"}' }.to_json
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
schema = {
|
|
59
|
+
"type" => "object",
|
|
60
|
+
"required" => ["count"],
|
|
61
|
+
"properties" => {
|
|
62
|
+
"count" => { "type" => "number" }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
expect do
|
|
67
|
+
client.generate(prompt: "Output JSON with key 'count' as a number.", schema: schema)
|
|
68
|
+
end.to raise_error(Ollama::SchemaViolationError)
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### ❌ G3 — Tool Attempt in Generate (Must Fail)
|
|
75
|
+
- [ ] No `tool_calls` parsed
|
|
76
|
+
- [ ] No silent acceptance of tool intent
|
|
77
|
+
- [ ] Either ignored or explicit error
|
|
78
|
+
- [ ] `/generate` remains non-agentic
|
|
79
|
+
|
|
80
|
+
**Test File:** `spec/ollama/client_generate_spec.rb`
|
|
81
|
+
|
|
82
|
+
**Example Test:**
|
|
83
|
+
```ruby
|
|
84
|
+
it "ignores tool calls in generate mode" do
|
|
85
|
+
stub_request(:post, "http://localhost:11434/api/generate")
|
|
86
|
+
.to_return(
|
|
87
|
+
status: 200,
|
|
88
|
+
body: { response: '{"action":"call read_file tool on foo.rb"}' }.to_json
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
result = client.generate(
|
|
92
|
+
prompt: "Call the read_file tool on foo.rb",
|
|
93
|
+
schema: { "type" => "object" }
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
expect(result).not_to have_key("tool_calls")
|
|
97
|
+
expect(result).not_to have_key("tool_use")
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Category B: `/chat` Mode Tests (Stateful, Tool-Aware)
|
|
104
|
+
|
|
105
|
+
### ✅ C1 — Simple Chat
|
|
106
|
+
- [ ] Response contains assistant message
|
|
107
|
+
- [ ] Message history preserved in request
|
|
108
|
+
- [ ] Role is correct
|
|
109
|
+
- [ ] Content is parsed correctly
|
|
110
|
+
|
|
111
|
+
**Test File:** `spec/ollama/client_chat_spec.rb` or `spec/ollama/client_chat_raw_spec.rb`
|
|
112
|
+
|
|
113
|
+
**Example Test:**
|
|
114
|
+
```ruby
|
|
115
|
+
it "handles simple chat messages" do
|
|
116
|
+
stub_request(:post, "http://localhost:11434/api/chat")
|
|
117
|
+
.to_return(
|
|
118
|
+
status: 200,
|
|
119
|
+
body: {
|
|
120
|
+
message: { role: "assistant", content: "Hello!" }
|
|
121
|
+
}.to_json
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
response = client.chat_raw(
|
|
125
|
+
messages: [{ role: "user", content: "Say hello." }],
|
|
126
|
+
allow_chat: true
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
expect(response.message.content).to eq("Hello!")
|
|
130
|
+
expect(response.message.role).to eq("assistant")
|
|
131
|
+
end
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### ✅ C2 — Tool-Call Parsing (Critical)
|
|
137
|
+
- [ ] `tool_calls` extracted correctly
|
|
138
|
+
- [ ] Tool name parsed
|
|
139
|
+
- [ ] Arguments parsed as hash
|
|
140
|
+
- [ ] **No execution happens** (client must not execute tools)
|
|
141
|
+
- [ ] Multiple tool calls handled
|
|
142
|
+
- [ ] Tool call ID preserved (if present)
|
|
143
|
+
|
|
144
|
+
**Test File:** `spec/ollama/client_chat_raw_spec.rb`
|
|
145
|
+
|
|
146
|
+
**Example Test:**
|
|
147
|
+
```ruby
|
|
148
|
+
it "extracts tool calls from chat response" do
|
|
149
|
+
stub_request(:post, "http://localhost:11434/api/chat")
|
|
150
|
+
.to_return(
|
|
151
|
+
status: 200,
|
|
152
|
+
body: {
|
|
153
|
+
message: {
|
|
154
|
+
role: "assistant",
|
|
155
|
+
content: "I'll call the ping tool.",
|
|
156
|
+
tool_calls: [
|
|
157
|
+
{
|
|
158
|
+
type: "function",
|
|
159
|
+
function: {
|
|
160
|
+
name: "ping",
|
|
161
|
+
arguments: { "x" => 1 }.to_json
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
}.to_json
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
response = client.chat_raw(
|
|
170
|
+
messages: [{ role: "user", content: "If a tool named 'ping' exists, call it with { 'x': 1 }." }],
|
|
171
|
+
tools: [tool_definition],
|
|
172
|
+
allow_chat: true
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
tool_calls = response.message.tool_calls
|
|
176
|
+
expect(tool_calls).not_to be_empty
|
|
177
|
+
expect(tool_calls.first["function"]["name"]).to eq("ping")
|
|
178
|
+
expect(JSON.parse(tool_calls.first["function"]["arguments"])).to eq("x" => 1)
|
|
179
|
+
end
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
### ✅ C3 — Tool Result Round-Trip Formatting
|
|
185
|
+
- [ ] Client serializes tool message correctly
|
|
186
|
+
- [ ] Ollama accepts tool result message
|
|
187
|
+
- [ ] Response parsed cleanly after tool result
|
|
188
|
+
- [ ] Tool name preserved
|
|
189
|
+
- [ ] Tool content serialized as JSON string
|
|
190
|
+
|
|
191
|
+
**Test File:** `spec/ollama/client_chat_raw_spec.rb`
|
|
192
|
+
|
|
193
|
+
**Example Test:**
|
|
194
|
+
```ruby
|
|
195
|
+
it "serializes tool result messages correctly" do
|
|
196
|
+
messages = [
|
|
197
|
+
{ role: "user", content: "Call ping tool" },
|
|
198
|
+
{ role: "assistant", content: "", tool_calls: [...] },
|
|
199
|
+
{ role: "tool", name: "ping", content: { ok: true }.to_json }
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
stub_request(:post, "http://localhost:11434/api/chat")
|
|
203
|
+
.with(body: hash_including(messages: messages))
|
|
204
|
+
.to_return(
|
|
205
|
+
status: 200,
|
|
206
|
+
body: { message: { role: "assistant", content: "Done!" } }.to_json
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
response = client.chat_raw(messages: messages, allow_chat: true)
|
|
210
|
+
expect(response.message.content).to eq("Done!")
|
|
211
|
+
end
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Category C: Protocol Adapters (Anthropic / Native)
|
|
217
|
+
|
|
218
|
+
### ✅ A1 — Anthropic Message Shape
|
|
219
|
+
- [ ] Messages serialized as content blocks
|
|
220
|
+
- [ ] Tool calls emitted as `tool_use` (if Anthropic mode)
|
|
221
|
+
- [ ] Tool results serialized as `tool_result`
|
|
222
|
+
- [ ] Request payload matches Anthropic format
|
|
223
|
+
|
|
224
|
+
**Test File:** `spec/ollama/client_chat_raw_spec.rb` or new `spec/ollama/protocol_adapter_spec.rb`
|
|
225
|
+
|
|
226
|
+
**Example Test:**
|
|
227
|
+
```ruby
|
|
228
|
+
it "serializes messages in Anthropic format" do
|
|
229
|
+
stub_request(:post, "http://localhost:11434/api/chat")
|
|
230
|
+
.with do |req|
|
|
231
|
+
body = JSON.parse(req.body)
|
|
232
|
+
expect(body["messages"]).to be_an(Array)
|
|
233
|
+
expect(body["messages"].first).to include("role", "content")
|
|
234
|
+
end
|
|
235
|
+
.to_return(status: 200, body: { message: {} }.to_json)
|
|
236
|
+
|
|
237
|
+
client.chat_raw(
|
|
238
|
+
messages: [{ role: "user", content: "Test" }],
|
|
239
|
+
allow_chat: true
|
|
240
|
+
)
|
|
241
|
+
end
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### ✅ A2 — Anthropic Response Parsing
|
|
247
|
+
- [ ] Client normalizes Anthropic format into internal `tool_calls`
|
|
248
|
+
- [ ] Protocol adapter correctness
|
|
249
|
+
- [ ] Tool use ID preserved
|
|
250
|
+
- [ ] Tool input parsed correctly
|
|
251
|
+
|
|
252
|
+
**Test File:** `spec/ollama/client_chat_raw_spec.rb` or new `spec/ollama/protocol_adapter_spec.rb`
|
|
253
|
+
|
|
254
|
+
**Example Test:**
|
|
255
|
+
```ruby
|
|
256
|
+
it "normalizes Anthropic-style responses into internal format" do
|
|
257
|
+
anthropic_response = {
|
|
258
|
+
content: [
|
|
259
|
+
{
|
|
260
|
+
type: "tool_use",
|
|
261
|
+
id: "call_123",
|
|
262
|
+
name: "search",
|
|
263
|
+
input: { q: "foo" }
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
stub_request(:post, "http://localhost:11434/api/chat")
|
|
269
|
+
.to_return(status: 200, body: anthropic_response.to_json)
|
|
270
|
+
|
|
271
|
+
response = client.chat_raw(
|
|
272
|
+
messages: [{ role: "user", content: "Search for foo" }],
|
|
273
|
+
allow_chat: true
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
tool_calls = response.message.tool_calls
|
|
277
|
+
expect(tool_calls).not_to be_empty
|
|
278
|
+
expect(tool_calls.first["function"]["name"]).to eq("search")
|
|
279
|
+
end
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Category D: Failure Modes (Non-Negotiable)
|
|
285
|
+
|
|
286
|
+
### ✅ F1 — Ollama Down
|
|
287
|
+
- [ ] Connection refused raises correct exception
|
|
288
|
+
- [ ] No hangs
|
|
289
|
+
- [ ] Retries handled correctly (if retryable)
|
|
290
|
+
- [ ] Error message is clear
|
|
291
|
+
|
|
292
|
+
**Test File:** `spec/ollama/errors_spec.rb` or `spec/ollama/client_spec.rb`
|
|
293
|
+
|
|
294
|
+
**Example Test:**
|
|
295
|
+
```ruby
|
|
296
|
+
it "handles connection refused gracefully" do
|
|
297
|
+
stub_request(:post, "http://localhost:11434/api/generate")
|
|
298
|
+
.to_raise(Errno::ECONNREFUSED)
|
|
299
|
+
|
|
300
|
+
start_time = Time.now
|
|
301
|
+
expect do
|
|
302
|
+
client.generate(prompt: "test", schema: schema)
|
|
303
|
+
end.to raise_error(Ollama::Error)
|
|
304
|
+
|
|
305
|
+
# Verify no hangs
|
|
306
|
+
expect(Time.now - start_time).to be < 5
|
|
307
|
+
end
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
### ✅ F2 — Invalid JSON from Model
|
|
313
|
+
- [ ] Client raises parse error
|
|
314
|
+
- [ ] Does not silently continue
|
|
315
|
+
- [ ] Retries handled (if retryable)
|
|
316
|
+
- [ ] Error message includes context
|
|
317
|
+
|
|
318
|
+
**Test File:** `spec/ollama/errors_spec.rb`
|
|
319
|
+
|
|
320
|
+
**Example Test:**
|
|
321
|
+
```ruby
|
|
322
|
+
it "raises error on invalid JSON response" do
|
|
323
|
+
stub_request(:post, "http://localhost:11434/api/generate")
|
|
324
|
+
.to_return(status: 200, body: { response: "not json at all" }.to_json)
|
|
325
|
+
|
|
326
|
+
expect do
|
|
327
|
+
client.generate(prompt: "test", schema: schema)
|
|
328
|
+
end.to raise_error(Ollama::InvalidJSONError)
|
|
329
|
+
end
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
### ✅ F3 — Streaming Interruption
|
|
335
|
+
- [ ] Partial stream handled
|
|
336
|
+
- [ ] Client terminates cleanly
|
|
337
|
+
- [ ] No corrupted state
|
|
338
|
+
- [ ] Error raised appropriately
|
|
339
|
+
|
|
340
|
+
**Test File:** `spec/ollama/client_chat_raw_spec.rb` (if streaming tests exist)
|
|
341
|
+
|
|
342
|
+
**Example Test:**
|
|
343
|
+
```ruby
|
|
344
|
+
it "handles partial stream gracefully" do
|
|
345
|
+
stub_request(:post, "http://localhost:11434/api/chat")
|
|
346
|
+
.to_return(
|
|
347
|
+
status: 200,
|
|
348
|
+
body: "data: {\"message\":{\"content\":\"partial\"}}\n",
|
|
349
|
+
headers: { "Content-Type" => "text/event-stream" }
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
# Simulate stream interruption
|
|
353
|
+
expect do
|
|
354
|
+
client.chat_raw(messages: [{ role: "user", content: "test" }], allow_chat: true)
|
|
355
|
+
end.to raise_error(Ollama::Error)
|
|
356
|
+
end
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Additional Test Areas
|
|
362
|
+
|
|
363
|
+
### Retry Logic
|
|
364
|
+
- [ ] Retries up to `config.retries` times
|
|
365
|
+
- [ ] Only retries retryable errors (5xx, 408, 429)
|
|
366
|
+
- [ ] Raises `RetryExhaustedError` after max retries
|
|
367
|
+
- [ ] Succeeds if retry succeeds
|
|
368
|
+
- [ ] Non-retryable errors (400, 404) fail immediately
|
|
369
|
+
|
|
370
|
+
### Error Handling
|
|
371
|
+
- [ ] **404 (NotFoundError)**: Model not found, no retries, includes suggestions
|
|
372
|
+
- [ ] **500 (HTTPError)**: Retryable, retries up to config limit
|
|
373
|
+
- [ ] **400 (HTTPError)**: Non-retryable, fails immediately
|
|
374
|
+
- [ ] **TimeoutError**: Retries on timeout
|
|
375
|
+
- [ ] **InvalidJSONError**: Retries on JSON parse errors
|
|
376
|
+
- [ ] **SchemaViolationError**: Retries on schema validation failures
|
|
377
|
+
- [ ] **Connection Errors**: Retries on network failures
|
|
378
|
+
|
|
379
|
+
### Edge Cases
|
|
380
|
+
- [ ] JSON wrapped in markdown code blocks
|
|
381
|
+
- [ ] Plain JSON responses
|
|
382
|
+
- [ ] Empty model lists
|
|
383
|
+
- [ ] Missing response fields
|
|
384
|
+
- [ ] Malformed JSON
|
|
385
|
+
- [ ] Empty prompts
|
|
386
|
+
- [ ] Very long prompts
|
|
387
|
+
- [ ] Special characters in prompts
|
|
388
|
+
|
|
389
|
+
### Model Suggestions
|
|
390
|
+
- [ ] Suggests similar models on 404
|
|
391
|
+
- [ ] Fuzzy matching on model names
|
|
392
|
+
- [ ] Limits suggestions to 5 models
|
|
393
|
+
- [ ] Handles model listing failures gracefully
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## What NOT to Test (Agent Concerns)
|
|
398
|
+
|
|
399
|
+
❌ **Do not test:**
|
|
400
|
+
- Infinite loops
|
|
401
|
+
- Retries based on content
|
|
402
|
+
- Agent stopping behavior
|
|
403
|
+
- Tool side effects
|
|
404
|
+
- Correctness of answers
|
|
405
|
+
- Agent convergence logic
|
|
406
|
+
- Policy decisions
|
|
407
|
+
- Tool execution
|
|
408
|
+
- Agent state management
|
|
409
|
+
|
|
410
|
+
**Those belong to `agent-runtime` and app repos.**
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Test Coverage Goals
|
|
415
|
+
|
|
416
|
+
- **Transport layer**: 100% coverage
|
|
417
|
+
- **Protocol parsing**: 100% coverage
|
|
418
|
+
- **Error handling**: 100% coverage
|
|
419
|
+
- **Schema validation**: 100% coverage
|
|
420
|
+
- **Tool-call parsing**: 100% coverage
|
|
421
|
+
|
|
422
|
+
**Note:** We don't aim for 100% line coverage of agent logic because agent logic doesn't belong in this gem.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Running the Checklist
|
|
427
|
+
|
|
428
|
+
1. Review each category
|
|
429
|
+
2. Mark tests as complete when implemented
|
|
430
|
+
3. Add test file references
|
|
431
|
+
4. Update this checklist as new test categories are identified
|
|
432
|
+
5. Remove tests that leak agent concerns
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Test File Organization
|
|
437
|
+
|
|
438
|
+
```
|
|
439
|
+
spec/
|
|
440
|
+
├── ollama/
|
|
441
|
+
│ ├── client_spec.rb # Basic initialization, config
|
|
442
|
+
│ ├── client_generate_spec.rb # Category A (G1-G3)
|
|
443
|
+
│ ├── client_chat_spec.rb # Category B (C1-C3) - basic chat
|
|
444
|
+
│ ├── client_chat_raw_spec.rb # Category B (C1-C3) - tool calls
|
|
445
|
+
│ ├── protocol_adapter_spec.rb # Category C (A1-A2) - if needed
|
|
446
|
+
│ ├── errors_spec.rb # Category D (F1-F3)
|
|
447
|
+
│ ├── schema_validator_spec.rb # Category A (G2)
|
|
448
|
+
│ ├── client_list_models_spec.rb # Model listing
|
|
449
|
+
│ └── client_model_suggestions_spec.rb # Model suggestions
|
|
450
|
+
```
|