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
data/docs/PERSONAS.md
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# Personas: Explicit Personalization for Ollama
|
|
2
|
+
|
|
3
|
+
## Core Principle
|
|
4
|
+
|
|
5
|
+
**You cannot "install" ChatGPT-style personalization into Ollama globally.** You **inject it explicitly** at the **system / prompt layer**, and you do it **deliberately**, depending on whether you are:
|
|
6
|
+
|
|
7
|
+
- doing **schema-based agent work**, or
|
|
8
|
+
- doing **chat / streaming UI work**.
|
|
9
|
+
|
|
10
|
+
This is by design — and it's actually a *good thing*.
|
|
11
|
+
|
|
12
|
+
## Mental Model
|
|
13
|
+
|
|
14
|
+
### ChatGPT Personalization
|
|
15
|
+
- Stored server-side
|
|
16
|
+
- Implicit
|
|
17
|
+
- Always applied
|
|
18
|
+
- You don't control when it's used
|
|
19
|
+
|
|
20
|
+
### Ollama (local / Docker)
|
|
21
|
+
- **No implicit memory**
|
|
22
|
+
- **No global personality**
|
|
23
|
+
- Everything must be **explicitly provided**
|
|
24
|
+
- You decide *when* it applies
|
|
25
|
+
|
|
26
|
+
So your customization becomes a **tool**, not a background bias. That's architecturally superior.
|
|
27
|
+
|
|
28
|
+
## Where Personalization Lives
|
|
29
|
+
|
|
30
|
+
There are **exactly three valid places** to apply your personalization:
|
|
31
|
+
|
|
32
|
+
| Context | How | When |
|
|
33
|
+
| ----------------------- | ---------------- | -------------------- |
|
|
34
|
+
| **Planner / generate** | Prompt prefix | Deterministic agents |
|
|
35
|
+
| **Chat / UI assistant** | `system` message | Human-facing chat |
|
|
36
|
+
| **Executor tool loop** | System guard | Controlled reasoning |
|
|
37
|
+
|
|
38
|
+
You do **NOT** bake it into:
|
|
39
|
+
- the model
|
|
40
|
+
- Docker image
|
|
41
|
+
- Ollama server config
|
|
42
|
+
|
|
43
|
+
## Using Personas
|
|
44
|
+
|
|
45
|
+
### 1. Planner (Schema-Based Agent Work)
|
|
46
|
+
|
|
47
|
+
Use **compressed agent-safe personas** for deterministic structured outputs:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
require "ollama_client"
|
|
51
|
+
|
|
52
|
+
client = Ollama::Client.new
|
|
53
|
+
|
|
54
|
+
planner = Ollama::Agent::Planner.new(
|
|
55
|
+
client,
|
|
56
|
+
system_prompt: Ollama::Personas.get(:architect, variant: :agent)
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
plan = planner.run(
|
|
60
|
+
prompt: "Design a caching layer for a high-traffic API.",
|
|
61
|
+
schema: DECISION_SCHEMA
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
✅ This preserves determinism
|
|
66
|
+
✅ No chatty behavior
|
|
67
|
+
✅ No markdown drift
|
|
68
|
+
|
|
69
|
+
### 2. Executor (Tool-Calling Agents)
|
|
70
|
+
|
|
71
|
+
Use **compressed agent-safe personas** for tool-calling agents:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
executor = Ollama::Agent::Executor.new(client, tools: tools)
|
|
75
|
+
|
|
76
|
+
answer = executor.run(
|
|
77
|
+
system: Ollama::Personas.get(:trading, variant: :agent),
|
|
78
|
+
user: "Analyze AAPL. Get current price and technical indicators."
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 3. ChatSession (Human-Facing Chat)
|
|
83
|
+
|
|
84
|
+
Use **minimal chat-safe personas** for human-facing chat interfaces:
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
config = Ollama::Config.new
|
|
88
|
+
config.allow_chat = true
|
|
89
|
+
config.streaming_enabled = true
|
|
90
|
+
|
|
91
|
+
client = Ollama::Client.new(config: config)
|
|
92
|
+
|
|
93
|
+
observer = Ollama::StreamingObserver.new do |event|
|
|
94
|
+
print event.text if event.type == :token
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
chat = Ollama::ChatSession.new(
|
|
98
|
+
client,
|
|
99
|
+
system: Ollama::Personas.get(:architect, variant: :chat),
|
|
100
|
+
stream: observer
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
chat.say("How should I structure a multi-agent system?")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Chat-safe personas:
|
|
107
|
+
- Allow explanations and examples (chat needs)
|
|
108
|
+
- Allow streaming (presentation needs)
|
|
109
|
+
- Still prevent hallucination (safety)
|
|
110
|
+
- Explicitly disclaim authority (boundaries)
|
|
111
|
+
- Never imply side effects (safety)
|
|
112
|
+
|
|
113
|
+
Now:
|
|
114
|
+
- Streaming works
|
|
115
|
+
- Tone matches your architect persona
|
|
116
|
+
- UI feels consistent
|
|
117
|
+
- Agents are unaffected
|
|
118
|
+
|
|
119
|
+
## Available Personas
|
|
120
|
+
|
|
121
|
+
### Architect
|
|
122
|
+
- **Agent variant**: Minimal, focused on correctness and invariants
|
|
123
|
+
- **Chat variant**: Minimal chat-safe, allows explanations while preventing hallucination
|
|
124
|
+
- **Use case**: System design, architecture decisions, planning
|
|
125
|
+
|
|
126
|
+
### Trading
|
|
127
|
+
- **Agent variant**: Minimal, data-driven analysis
|
|
128
|
+
- **Chat variant**: Minimal chat-safe, allows explanations while preventing hallucination
|
|
129
|
+
- **Use case**: Market analysis, trading decisions, risk management
|
|
130
|
+
|
|
131
|
+
### Reviewer
|
|
132
|
+
- **Agent variant**: Minimal, focused on maintainability
|
|
133
|
+
- **Chat variant**: Minimal chat-safe, allows explanations while preventing hallucination
|
|
134
|
+
- **Use case**: Code review, refactoring, quality assurance
|
|
135
|
+
|
|
136
|
+
## Agent-Safe vs Chat-Safe Personas
|
|
137
|
+
|
|
138
|
+
### Agent-Safe Personas (`:agent` variant)
|
|
139
|
+
|
|
140
|
+
Designed for `/api/generate` with JSON schemas:
|
|
141
|
+
|
|
142
|
+
- **Minimal and directive** - reduces token noise and drift
|
|
143
|
+
- **Non-chatty** - avoids markdown and verbosity
|
|
144
|
+
- **Schema-first** - protects deterministic parsing
|
|
145
|
+
- **No persona fluff** - no tone bleed into output
|
|
146
|
+
- **Preserves determinism** - for planners, routers, decision engines
|
|
147
|
+
|
|
148
|
+
**Use with:**
|
|
149
|
+
- `Planner` for structured outputs
|
|
150
|
+
- `generate()` with schemas
|
|
151
|
+
- Tool routing and decision making
|
|
152
|
+
|
|
153
|
+
**Will NOT fight:**
|
|
154
|
+
- Schema enforcement
|
|
155
|
+
- Retries
|
|
156
|
+
- Validation
|
|
157
|
+
- Tool routing
|
|
158
|
+
- Policy gates
|
|
159
|
+
|
|
160
|
+
### Chat-Safe Personas (`:chat` variant)
|
|
161
|
+
|
|
162
|
+
Designed for `/api/chat` with ChatSession:
|
|
163
|
+
|
|
164
|
+
- **Allows explanations** - chat needs context
|
|
165
|
+
- **Allows streaming** - presentation needs
|
|
166
|
+
- **Still prevents hallucination** - safety first
|
|
167
|
+
- **Explicitly disclaims authority** - clear boundaries
|
|
168
|
+
- **Never implies side effects** - safety boundaries
|
|
169
|
+
|
|
170
|
+
**Use with:**
|
|
171
|
+
- `ChatSession` for human-facing interfaces
|
|
172
|
+
- Streaming conversations
|
|
173
|
+
- Explanatory interactions
|
|
174
|
+
|
|
175
|
+
**Must NEVER be used for:**
|
|
176
|
+
- Schema-based agent work
|
|
177
|
+
- `/api/generate` calls
|
|
178
|
+
- Deterministic structured outputs
|
|
179
|
+
|
|
180
|
+
## Critical Separation
|
|
181
|
+
|
|
182
|
+
**Agent personas** (`:agent`):
|
|
183
|
+
- `/api/generate` + schemas = deterministic reasoning
|
|
184
|
+
- Use for planners, routers, decision engines
|
|
185
|
+
- Preserves determinism and schema enforcement
|
|
186
|
+
|
|
187
|
+
**Chat personas** (`:chat`):
|
|
188
|
+
- `/api/chat` + humans = explanatory conversation
|
|
189
|
+
- Use for ChatSession, streaming, UI interactions
|
|
190
|
+
- Allows explanations while maintaining safety
|
|
191
|
+
|
|
192
|
+
**NEVER mix them:**
|
|
193
|
+
- Using chat personas in agents breaks determinism
|
|
194
|
+
- Using agent personas in chat suppresses explanations
|
|
195
|
+
- They serve different purposes with different contracts
|
|
196
|
+
|
|
197
|
+
## Persona Registry
|
|
198
|
+
|
|
199
|
+
```ruby
|
|
200
|
+
# List all available personas
|
|
201
|
+
Ollama::Personas.available
|
|
202
|
+
# => [:architect, :trading, :reviewer]
|
|
203
|
+
|
|
204
|
+
# Check if persona exists
|
|
205
|
+
Ollama::Personas.exists?(:architect)
|
|
206
|
+
# => true
|
|
207
|
+
|
|
208
|
+
# Get persona (defaults to :agent variant)
|
|
209
|
+
Ollama::Personas.get(:architect)
|
|
210
|
+
Ollama::Personas.get(:architect, variant: :agent)
|
|
211
|
+
Ollama::Personas.get(:architect, variant: :chat)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Dynamic Persona Selection
|
|
215
|
+
|
|
216
|
+
```ruby
|
|
217
|
+
def select_persona_for_task(task_type)
|
|
218
|
+
case task_type
|
|
219
|
+
when :planning, :architecture
|
|
220
|
+
Ollama::Personas.get(:architect, variant: :agent)
|
|
221
|
+
when :trading, :analysis
|
|
222
|
+
Ollama::Personas.get(:trading, variant: :agent)
|
|
223
|
+
when :review, :refactor
|
|
224
|
+
Ollama::Personas.get(:reviewer, variant: :agent)
|
|
225
|
+
else
|
|
226
|
+
nil
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
planner = Ollama::Agent::Planner.new(
|
|
231
|
+
client,
|
|
232
|
+
system_prompt: select_persona_for_task(:planning)
|
|
233
|
+
)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Per-Call Persona Override
|
|
237
|
+
|
|
238
|
+
```ruby
|
|
239
|
+
planner = Ollama::Agent::Planner.new(
|
|
240
|
+
client,
|
|
241
|
+
system_prompt: Ollama::Personas.get(:architect, variant: :agent)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Override for specific call
|
|
245
|
+
plan = planner.run(
|
|
246
|
+
prompt: "Review this code for maintainability issues.",
|
|
247
|
+
schema: REVIEW_SCHEMA,
|
|
248
|
+
system_prompt: Ollama::Personas.get(:reviewer, variant: :agent)
|
|
249
|
+
)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Why NOT Bake Into Docker / Model
|
|
253
|
+
|
|
254
|
+
You might be tempted to:
|
|
255
|
+
- create a custom Modelfile
|
|
256
|
+
- bake instructions into the model
|
|
257
|
+
- hardcode personality in the server
|
|
258
|
+
|
|
259
|
+
**Don't.** Here's why:
|
|
260
|
+
|
|
261
|
+
❌ All agents inherit it (bad)
|
|
262
|
+
❌ Hard to change per task
|
|
263
|
+
❌ Breaks determinism
|
|
264
|
+
❌ Makes debugging impossible
|
|
265
|
+
❌ Pollutes structured outputs
|
|
266
|
+
|
|
267
|
+
Your personalization is **contextual**, not universal.
|
|
268
|
+
|
|
269
|
+
## Multiple Personas (This is Powerful)
|
|
270
|
+
|
|
271
|
+
Once explicit, you can do this:
|
|
272
|
+
|
|
273
|
+
```ruby
|
|
274
|
+
PERSONAS = {
|
|
275
|
+
architect: Ollama::Personas.get(:architect, variant: :agent),
|
|
276
|
+
trading: Ollama::Personas.get(:trading, variant: :agent),
|
|
277
|
+
reviewer: Ollama::Personas.get(:reviewer, variant: :agent)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
# Choose per call
|
|
281
|
+
prompt = PERSONAS[:architect] + task_prompt
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
This is **far more powerful** than ChatGPT's single global personality.
|
|
285
|
+
|
|
286
|
+
## Philosophy Alignment
|
|
287
|
+
|
|
288
|
+
Your instruction says:
|
|
289
|
+
|
|
290
|
+
> "Treat LLMs as components, not oracles"
|
|
291
|
+
|
|
292
|
+
That **forces** explicit prompting. Implicit personalization would actually violate your own design principles.
|
|
293
|
+
|
|
294
|
+
## Validation Checklist
|
|
295
|
+
|
|
296
|
+
### For Agent Personas
|
|
297
|
+
|
|
298
|
+
If the model:
|
|
299
|
+
- ✅ Emits pure JSON matching schema exactly → correct usage
|
|
300
|
+
- ✅ No markdown or explanations → correct usage
|
|
301
|
+
- ✅ Deterministic outputs → correct usage
|
|
302
|
+
- ❌ Emits markdown → prompt is being misused
|
|
303
|
+
- ❌ Adds extra fields → schema too loose or prompt issue
|
|
304
|
+
- ❌ Explains decisions → prompt leaked into chat mode
|
|
305
|
+
- ❌ Hallucinates APIs → tool boundaries not enforced
|
|
306
|
+
|
|
307
|
+
### For Chat Personas
|
|
308
|
+
|
|
309
|
+
If the model:
|
|
310
|
+
- ✅ Explains reasoning when helpful → correct usage
|
|
311
|
+
- ✅ Uses markdown for readability → correct usage
|
|
312
|
+
- ✅ Disclaims authority explicitly → correct usage
|
|
313
|
+
- ✅ No side effects implied → correct usage
|
|
314
|
+
- ❌ Executes actions → boundaries not clear
|
|
315
|
+
- ❌ Invents data/APIs → hallucination prevention failed
|
|
316
|
+
- ❌ Makes guarantees → safety boundaries not enforced
|
|
317
|
+
|
|
318
|
+
## What NOT to Do
|
|
319
|
+
|
|
320
|
+
### ❌ Don't Use Chat Personas for Agent Work
|
|
321
|
+
|
|
322
|
+
```ruby
|
|
323
|
+
# WRONG - breaks determinism
|
|
324
|
+
planner = Ollama::Agent::Planner.new(
|
|
325
|
+
client,
|
|
326
|
+
system_prompt: Ollama::Personas.get(:architect, variant: :chat) # ❌
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
plan = planner.run(prompt: "...", schema: SCHEMA)
|
|
330
|
+
# This will fight schema enforcement and break determinism
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### ❌ Don't Use Agent Personas for Chat
|
|
334
|
+
|
|
335
|
+
```ruby
|
|
336
|
+
# WRONG - suppresses explanations
|
|
337
|
+
chat = Ollama::ChatSession.new(
|
|
338
|
+
client,
|
|
339
|
+
system: Ollama::Personas.get(:architect, variant: :agent) # ❌
|
|
340
|
+
)
|
|
341
|
+
# This makes chat feel robotic and suppresses helpful explanations
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### ❌ Don't Mix Personas
|
|
345
|
+
|
|
346
|
+
```ruby
|
|
347
|
+
# WRONG - creates confusion
|
|
348
|
+
prompt = Ollama::Personas.get(:architect, variant: :agent) +
|
|
349
|
+
Ollama::Personas.get(:architect, variant: :chat)
|
|
350
|
+
# This creates conflicting instructions
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### ✅ Do Keep Them Separate
|
|
354
|
+
|
|
355
|
+
```ruby
|
|
356
|
+
# CORRECT - explicit separation
|
|
357
|
+
agent_persona = Ollama::Personas.get(:architect, variant: :agent)
|
|
358
|
+
chat_persona = Ollama::Personas.get(:architect, variant: :chat)
|
|
359
|
+
|
|
360
|
+
# Use agent persona for planning
|
|
361
|
+
planner = Ollama::Agent::Planner.new(client, system_prompt: agent_persona)
|
|
362
|
+
|
|
363
|
+
# Use chat persona for UI
|
|
364
|
+
chat = Ollama::ChatSession.new(client, system: chat_persona)
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## Summary
|
|
368
|
+
|
|
369
|
+
**Q:** How do I use this customization with Ollama / Docker / ollama-client?
|
|
370
|
+
**A:**
|
|
371
|
+
|
|
372
|
+
- You **do NOT install it into Ollama**
|
|
373
|
+
- You **inject it as a system prompt**
|
|
374
|
+
- You **use minimal agent-safe version for agents** (`/api/generate` + schemas)
|
|
375
|
+
- You **use minimal chat-safe version for chat UIs** (`/api/chat` + ChatSession)
|
|
376
|
+
- You **never make it implicit**
|
|
377
|
+
- You **never mix agent and chat personas**
|
|
378
|
+
|
|
379
|
+
That's not a limitation. That's **correct system design**.
|
|
380
|
+
|
|
381
|
+
## Examples
|
|
382
|
+
|
|
383
|
+
See `examples/personas_example.rb` for complete working examples.
|
data/docs/QUICK_START.md
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Quick Start: Copy-Paste Examples
|
|
2
|
+
|
|
3
|
+
All examples below are **complete and copy-pasteable** - no missing constants or undefined variables.
|
|
4
|
+
|
|
5
|
+
## Basic Client Setup
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
require "ollama_client"
|
|
9
|
+
|
|
10
|
+
# Simplest client (uses defaults)
|
|
11
|
+
client = Ollama::Client.new
|
|
12
|
+
|
|
13
|
+
# Or with custom config
|
|
14
|
+
config = Ollama::Config.new
|
|
15
|
+
config.model = ENV["OLLAMA_MODEL"] || "llama3.1:8b"
|
|
16
|
+
config.base_url = ENV["OLLAMA_BASE_URL"] || "http://localhost:11434"
|
|
17
|
+
client = Ollama::Client.new(config: config)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Generate with Schema (Structured Output)
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
require "ollama_client"
|
|
24
|
+
|
|
25
|
+
client = Ollama::Client.new
|
|
26
|
+
|
|
27
|
+
DECISION_SCHEMA = {
|
|
28
|
+
"type" => "object",
|
|
29
|
+
"required" => ["action", "reasoning"],
|
|
30
|
+
"properties" => {
|
|
31
|
+
"action" => {
|
|
32
|
+
"type" => "string",
|
|
33
|
+
"enum" => ["search", "calculate", "finish"]
|
|
34
|
+
},
|
|
35
|
+
"reasoning" => {
|
|
36
|
+
"type" => "string"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
result = client.generate(
|
|
42
|
+
prompt: "Analyze the situation and decide next action.",
|
|
43
|
+
schema: DECISION_SCHEMA
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
puts result["action"] # => "search"
|
|
47
|
+
puts result["reasoning"] # => "User needs data..."
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Generate Plain Text
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
require "ollama_client"
|
|
54
|
+
|
|
55
|
+
client = Ollama::Client.new
|
|
56
|
+
|
|
57
|
+
response = client.generate(
|
|
58
|
+
prompt: "Explain Ruby blocks in one sentence.",
|
|
59
|
+
allow_plain_text: true
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
puts response # => Plain text/markdown String
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Planner with Persona
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
require "ollama_client"
|
|
69
|
+
|
|
70
|
+
client = Ollama::Client.new
|
|
71
|
+
|
|
72
|
+
planner = Ollama::Agent::Planner.new(
|
|
73
|
+
client,
|
|
74
|
+
system_prompt: Ollama::Personas.get(:architect, variant: :agent)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
DECISION_SCHEMA = {
|
|
78
|
+
"type" => "object",
|
|
79
|
+
"required" => ["action", "reasoning"],
|
|
80
|
+
"properties" => {
|
|
81
|
+
"action" => {
|
|
82
|
+
"type" => "string",
|
|
83
|
+
"enum" => ["refactor", "test", "document", "defer"]
|
|
84
|
+
},
|
|
85
|
+
"reasoning" => {
|
|
86
|
+
"type" => "string"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
plan = planner.run(
|
|
92
|
+
prompt: "Design a caching layer for a high-traffic API.",
|
|
93
|
+
schema: DECISION_SCHEMA
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
puts plan["action"] # => "refactor" (or one of the enum values)
|
|
97
|
+
puts plan["reasoning"] # => Explanation string
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Executor with Tools
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
require "ollama_client"
|
|
104
|
+
|
|
105
|
+
client = Ollama::Client.new
|
|
106
|
+
|
|
107
|
+
# Define tools (copy-paste ready)
|
|
108
|
+
tools = {
|
|
109
|
+
"get_price" => ->(symbol:) { { symbol: symbol, price: 24500.50, volume: 1_000_000 } },
|
|
110
|
+
"get_indicators" => ->(symbol:) { { symbol: symbol, rsi: 65.5, macd: 1.2 } }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
executor = Ollama::Agent::Executor.new(client, tools: tools)
|
|
114
|
+
|
|
115
|
+
answer = executor.run(
|
|
116
|
+
system: Ollama::Personas.get(:trading, variant: :agent),
|
|
117
|
+
user: "Analyze NIFTY. Get current price and technical indicators."
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
puts answer
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## ChatSession (Human-Facing Chat)
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
require "ollama_client"
|
|
127
|
+
|
|
128
|
+
config = Ollama::Config.new
|
|
129
|
+
config.allow_chat = true
|
|
130
|
+
config.streaming_enabled = true
|
|
131
|
+
|
|
132
|
+
client = Ollama::Client.new(config: config)
|
|
133
|
+
|
|
134
|
+
observer = Ollama::StreamingObserver.new do |event|
|
|
135
|
+
print event.text if event.type == :token
|
|
136
|
+
puts "\n" if event.type == :final
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
chat = Ollama::ChatSession.new(
|
|
140
|
+
client,
|
|
141
|
+
system: Ollama::Personas.get(:architect, variant: :chat),
|
|
142
|
+
stream: observer
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
chat.say("How should I structure a multi-agent system?")
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Complete Working Example
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
#!/usr/bin/env ruby
|
|
152
|
+
# frozen_string_literal: true
|
|
153
|
+
|
|
154
|
+
require "ollama_client"
|
|
155
|
+
|
|
156
|
+
# Step 1: Create client
|
|
157
|
+
client = Ollama::Client.new
|
|
158
|
+
|
|
159
|
+
# Step 2: Define schema
|
|
160
|
+
DECISION_SCHEMA = {
|
|
161
|
+
"type" => "object",
|
|
162
|
+
"required" => ["action", "reasoning"],
|
|
163
|
+
"properties" => {
|
|
164
|
+
"action" => {
|
|
165
|
+
"type" => "string",
|
|
166
|
+
"enum" => ["refactor", "test", "document", "defer"]
|
|
167
|
+
},
|
|
168
|
+
"reasoning" => {
|
|
169
|
+
"type" => "string"
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Step 3: Create planner with persona
|
|
175
|
+
planner = Ollama::Agent::Planner.new(
|
|
176
|
+
client,
|
|
177
|
+
system_prompt: Ollama::Personas.get(:architect, variant: :agent)
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Step 4: Use planner
|
|
181
|
+
begin
|
|
182
|
+
plan = planner.run(
|
|
183
|
+
prompt: "Design a caching layer for a high-traffic API.",
|
|
184
|
+
schema: DECISION_SCHEMA
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
puts "✅ Success!"
|
|
188
|
+
puts "Action: #{plan['action']}"
|
|
189
|
+
puts "Reasoning: #{plan['reasoning']}"
|
|
190
|
+
rescue Ollama::Error => e
|
|
191
|
+
puts "❌ Error: #{e.message}"
|
|
192
|
+
end
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
All examples above are **complete and ready to copy-paste**!
|
data/docs/README.md
CHANGED
|
@@ -4,8 +4,7 @@ This directory contains internal development documentation for the ollama-client
|
|
|
4
4
|
|
|
5
5
|
## Quick Links
|
|
6
6
|
|
|
7
|
-
- 🚀 **[
|
|
8
|
-
- 📘 **[Complete Release Guide](GEM_RELEASE_GUIDE.md)** - Full automation setup (794 lines)
|
|
7
|
+
- 🚀 **[Release Guide](RELEASE_GUIDE.md)** - Complete guide for automated gem releases with MFA
|
|
9
8
|
|
|
10
9
|
## Contents
|
|
11
10
|
|
|
@@ -22,7 +21,7 @@ This directory contains internal development documentation for the ollama-client
|
|
|
22
21
|
|
|
23
22
|
### CI/Automation
|
|
24
23
|
- **[CLOUD.md](CLOUD.md)** - Cloud agent guide for automated testing and fixes
|
|
25
|
-
- **[
|
|
24
|
+
- **[RELEASE_GUIDE.md](RELEASE_GUIDE.md)** - Complete guide for automated gem releases via GitHub Actions with OTP/MFA
|
|
26
25
|
|
|
27
26
|
## For Users
|
|
28
27
|
|