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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -1
  3. data/README.md +560 -106
  4. data/docs/EXAMPLE_REORGANIZATION.md +412 -0
  5. data/docs/GETTING_STARTED.md +361 -0
  6. data/docs/INTEGRATION_TESTING.md +170 -0
  7. data/docs/NEXT_STEPS_SUMMARY.md +114 -0
  8. data/docs/PERSONAS.md +383 -0
  9. data/docs/QUICK_START.md +195 -0
  10. data/docs/README.md +2 -3
  11. data/docs/RELEASE_GUIDE.md +376 -0
  12. data/docs/TESTING.md +392 -170
  13. data/docs/TEST_CHECKLIST.md +450 -0
  14. data/docs/ruby_guide.md +6232 -0
  15. data/examples/README.md +51 -66
  16. data/examples/basic_chat.rb +33 -0
  17. data/examples/basic_generate.rb +29 -0
  18. data/examples/tool_calling_parsing.rb +59 -0
  19. data/exe/ollama-client +128 -1
  20. data/lib/ollama/agent/planner.rb +7 -2
  21. data/lib/ollama/chat_session.rb +101 -0
  22. data/lib/ollama/client.rb +43 -21
  23. data/lib/ollama/config.rb +4 -1
  24. data/lib/ollama/document_loader.rb +163 -0
  25. data/lib/ollama/embeddings.rb +42 -13
  26. data/lib/ollama/errors.rb +1 -0
  27. data/lib/ollama/personas.rb +287 -0
  28. data/lib/ollama/version.rb +1 -1
  29. data/lib/ollama_client.rb +8 -0
  30. metadata +31 -53
  31. data/docs/GEM_RELEASE_GUIDE.md +0 -794
  32. data/docs/GET_RUBYGEMS_SECRET.md +0 -151
  33. data/docs/QUICK_OTP_SETUP.md +0 -80
  34. data/docs/QUICK_RELEASE.md +0 -106
  35. data/docs/RUBYGEMS_OTP_SETUP.md +0 -199
  36. data/examples/advanced_complex_schemas.rb +0 -366
  37. data/examples/advanced_edge_cases.rb +0 -241
  38. data/examples/advanced_error_handling.rb +0 -200
  39. data/examples/advanced_multi_step_agent.rb +0 -341
  40. data/examples/advanced_performance_testing.rb +0 -186
  41. data/examples/chat_console.rb +0 -143
  42. data/examples/complete_workflow.rb +0 -245
  43. data/examples/dhan_console.rb +0 -843
  44. data/examples/dhanhq/README.md +0 -236
  45. data/examples/dhanhq/agents/base_agent.rb +0 -74
  46. data/examples/dhanhq/agents/data_agent.rb +0 -66
  47. data/examples/dhanhq/agents/orchestrator_agent.rb +0 -120
  48. data/examples/dhanhq/agents/technical_analysis_agent.rb +0 -252
  49. data/examples/dhanhq/agents/trading_agent.rb +0 -81
  50. data/examples/dhanhq/analysis/market_structure.rb +0 -138
  51. data/examples/dhanhq/analysis/pattern_recognizer.rb +0 -192
  52. data/examples/dhanhq/analysis/trend_analyzer.rb +0 -88
  53. data/examples/dhanhq/builders/market_context_builder.rb +0 -67
  54. data/examples/dhanhq/dhanhq_agent.rb +0 -829
  55. data/examples/dhanhq/indicators/technical_indicators.rb +0 -158
  56. data/examples/dhanhq/scanners/intraday_options_scanner.rb +0 -492
  57. data/examples/dhanhq/scanners/swing_scanner.rb +0 -247
  58. data/examples/dhanhq/schemas/agent_schemas.rb +0 -61
  59. data/examples/dhanhq/services/base_service.rb +0 -46
  60. data/examples/dhanhq/services/data_service.rb +0 -118
  61. data/examples/dhanhq/services/trading_service.rb +0 -59
  62. data/examples/dhanhq/technical_analysis_agentic_runner.rb +0 -411
  63. data/examples/dhanhq/technical_analysis_runner.rb +0 -420
  64. data/examples/dhanhq/test_tool_calling.rb +0 -538
  65. data/examples/dhanhq/test_tool_calling_verbose.rb +0 -251
  66. data/examples/dhanhq/utils/instrument_helper.rb +0 -32
  67. data/examples/dhanhq/utils/parameter_cleaner.rb +0 -28
  68. data/examples/dhanhq/utils/parameter_normalizer.rb +0 -45
  69. data/examples/dhanhq/utils/rate_limiter.rb +0 -23
  70. data/examples/dhanhq/utils/trading_parameter_normalizer.rb +0 -72
  71. data/examples/dhanhq_agent.rb +0 -964
  72. data/examples/dhanhq_tools.rb +0 -1663
  73. data/examples/multi_step_agent_with_external_data.rb +0 -368
  74. data/examples/structured_outputs_chat.rb +0 -72
  75. data/examples/structured_tools.rb +0 -89
  76. data/examples/test_dhanhq_tool_calling.rb +0 -375
  77. data/examples/test_tool_calling.rb +0 -160
  78. data/examples/tool_calling_direct.rb +0 -124
  79. data/examples/tool_calling_pattern.rb +0 -269
  80. data/exe/dhan_console +0 -4
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+ require "json"
5
+
6
+ module Ollama
7
+ # Document loader for RAG (Retrieval-Augmented Generation)
8
+ #
9
+ # Loads files from a directory and provides them as context for LLM queries.
10
+ # Supports: .txt, .md, .csv, .json files
11
+ #
12
+ # Example:
13
+ # loader = Ollama::DocumentLoader.new("docs/")
14
+ # context = loader.load_all
15
+ # result = client.generate(
16
+ # prompt: "Context: #{context}\n\nQuestion: What is Ruby?",
17
+ # schema: {...}
18
+ # )
19
+ class DocumentLoader
20
+ SUPPORTED_EXTENSIONS = %w[.txt .md .markdown .csv .json].freeze
21
+
22
+ def initialize(directory, extensions: SUPPORTED_EXTENSIONS)
23
+ @directory = File.expand_path(directory)
24
+ @extensions = extensions
25
+ @documents = {}
26
+ end
27
+
28
+ # Load all supported files from the directory
29
+ #
30
+ # @param recursive [Boolean] Load files from subdirectories
31
+ # @return [Hash] Hash of filename => content
32
+ def load_all(recursive: false)
33
+ raise Error, "Directory not found: #{@directory}" unless Dir.exist?(@directory)
34
+
35
+ pattern = recursive ? "**/*" : "*"
36
+ files = Dir.glob(File.join(@directory, pattern)).select { |f| File.file?(f) }
37
+
38
+ loaded_count = 0
39
+ files.each do |file|
40
+ next unless supported_file?(file)
41
+
42
+ filename = File.basename(file)
43
+ content = load_file(file)
44
+ next if content.nil?
45
+
46
+ @documents[filename] = content
47
+ loaded_count += 1
48
+ end
49
+
50
+ @documents
51
+ end
52
+
53
+ # Load a specific file
54
+ #
55
+ # @param filename [String] Name of the file to load (can be relative or absolute)
56
+ # @return [String] File content as text, or nil if file not found
57
+ def load_file(filename)
58
+ # Handle both relative and absolute paths
59
+ full_path = if File.absolute_path?(filename)
60
+ filename
61
+ else
62
+ File.join(@directory, filename)
63
+ end
64
+
65
+ return nil unless File.exist?(full_path)
66
+
67
+ # Store with basename for consistency
68
+ basename = File.basename(filename)
69
+
70
+ ext = File.extname(filename).downcase
71
+ content = File.read(full_path)
72
+
73
+ parsed_content = case ext
74
+ when ".csv"
75
+ parse_csv(content)
76
+ when ".json"
77
+ parse_json(content)
78
+ else
79
+ # .txt, .md, .markdown, or any other text file
80
+ content
81
+ end
82
+
83
+ # Store in documents hash
84
+ @documents[basename] = parsed_content
85
+ parsed_content
86
+ end
87
+
88
+ # Get all loaded documents as a single context string
89
+ #
90
+ # @param separator [String] Separator between documents
91
+ # @return [String] Combined context from all documents
92
+ def to_context(separator: "\n\n---\n\n")
93
+ @documents.map do |filename, content|
94
+ "File: #{filename}\n#{content}"
95
+ end.join(separator)
96
+ end
97
+
98
+ # Get documents matching a pattern
99
+ #
100
+ # @param pattern [String, Regexp] Pattern to match filenames
101
+ # @return [Hash] Matching documents
102
+ def select(pattern)
103
+ if pattern.is_a?(Regexp)
104
+ @documents.select { |filename, _| filename.match?(pattern) }
105
+ else
106
+ @documents.select { |filename, _| filename.include?(pattern.to_s) }
107
+ end
108
+ end
109
+
110
+ # Get a specific document by filename
111
+ #
112
+ # @param filename [String] Name of the document
113
+ # @return [String, nil] Document content or nil if not found
114
+ def [](filename)
115
+ @documents[filename]
116
+ end
117
+
118
+ # List all loaded document names
119
+ #
120
+ # @return [Array<String>] Array of filenames
121
+ def files
122
+ @documents.keys
123
+ end
124
+
125
+ # Check if any documents are loaded
126
+ #
127
+ # @return [Boolean] True if documents are loaded
128
+ def empty?
129
+ @documents.empty?
130
+ end
131
+
132
+ private
133
+
134
+ def supported_file?(file)
135
+ ext = File.extname(file).downcase
136
+ @extensions.include?(ext)
137
+ end
138
+
139
+ def parse_csv(content)
140
+ rows = CSV.parse(content, headers: true)
141
+ return content if rows.empty?
142
+
143
+ # Convert CSV to readable text format
144
+ headers = rows.headers || []
145
+ text_rows = rows.map do |row|
146
+ if headers.any?
147
+ headers.map { |h| "#{h}: #{row[h]}" }.join(", ")
148
+ else
149
+ row.fields.join(", ")
150
+ end
151
+ end
152
+
153
+ "CSV Data:\n#{text_rows.join("\n")}"
154
+ end
155
+
156
+ def parse_json(content)
157
+ parsed = JSON.parse(content)
158
+ JSON.pretty_generate(parsed)
159
+ rescue JSON::ParserError
160
+ content
161
+ end
162
+ end
163
+ end
@@ -44,19 +44,9 @@ module Ollama
44
44
  response_body = JSON.parse(res.body)
45
45
  embedding = response_body["embedding"]
46
46
 
47
- # Return single array for single input, or array of arrays for multiple inputs
48
- if input.is_a?(Array)
49
- # Ollama returns single embedding array even for multiple inputs
50
- # We need to check the response structure
51
- if embedding.is_a?(Array) && embedding.first.is_a?(Array)
52
- embedding
53
- else
54
- # Single embedding returned, wrap it
55
- [embedding]
56
- end
57
- else
58
- embedding
59
- end
47
+ validate_embedding_response!(embedding, response_body, model)
48
+
49
+ format_embedding_result(embedding, input)
60
50
  rescue JSON::ParserError => e
61
51
  raise InvalidJSONError, "Failed to parse embeddings response: #{e.message}"
62
52
  rescue Net::ReadTimeout, Net::OpenTimeout
@@ -67,6 +57,45 @@ module Ollama
67
57
 
68
58
  private
69
59
 
60
+ def validate_embedding_response!(embedding, response_body, model)
61
+ if embedding.nil?
62
+ keys = response_body.keys.join(", ")
63
+ response_preview = response_body.inspect[0..200]
64
+ raise Error, "Embedding not found in response. Response keys: #{keys}. " \
65
+ "Full response: #{response_preview}"
66
+ end
67
+
68
+ return unless embedding.is_a?(Array) && embedding.empty?
69
+
70
+ error_msg = build_empty_embedding_error_message(model, response_body)
71
+ raise Error, error_msg
72
+ end
73
+
74
+ def build_empty_embedding_error_message(model, response_body)
75
+ curl_command = "curl http://localhost:11434/api/embeddings " \
76
+ "-d '{\"model\":\"#{model}\",\"input\":\"test\"}'"
77
+ response_preview = response_body.inspect[0..300]
78
+
79
+ "Empty embedding returned. This usually means:\n " \
80
+ "1. The model may not be properly loaded - try: ollama pull #{model}\n " \
81
+ "2. The model may not support embeddings - verify it's an embedding model\n " \
82
+ "3. Check if the model is working: #{curl_command}\n" \
83
+ "Response: #{response_preview}"
84
+ end
85
+
86
+ def format_embedding_result(embedding, input)
87
+ return embedding unless input.is_a?(Array)
88
+
89
+ # Ollama returns single embedding array even for multiple inputs
90
+ # We need to check the response structure
91
+ if embedding.is_a?(Array) && embedding.first.is_a?(Array)
92
+ embedding
93
+ else
94
+ # Single embedding returned, wrap it
95
+ [embedding]
96
+ end
97
+ end
98
+
70
99
  def handle_http_error(res, requested_model: nil)
71
100
  status_code = res.code.to_i
72
101
  raise NotFoundError.new(res.message, requested_model: requested_model) if status_code == 404
data/lib/ollama/errors.rb CHANGED
@@ -6,6 +6,7 @@ module Ollama
6
6
  class InvalidJSONError < Error; end
7
7
  class SchemaViolationError < Error; end
8
8
  class RetryExhaustedError < Error; end
9
+ class ChatNotAllowedError < Error; end
9
10
 
10
11
  # HTTP error with retry logic
11
12
  class HTTPError < Error
@@ -0,0 +1,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ollama
4
+ # Persona system for explicit, contextual personalization.
5
+ #
6
+ # Personas are NOT baked into models or server config. They are injected
7
+ # explicitly at the system/prompt layer, allowing you to:
8
+ #
9
+ # - Use compressed versions for schema-based agent work (deterministic)
10
+ # - Use minimal chat-safe versions for chat/streaming UI work (human-facing)
11
+ # - Switch personas per task without model changes
12
+ # - Maintain multiple personas for different contexts
13
+ #
14
+ # This is architecturally superior to ChatGPT's implicit global personalization.
15
+ #
16
+ # ## Persona Variants
17
+ #
18
+ # Each persona has two variants:
19
+ #
20
+ # ### Agent Variants (`:agent`)
21
+ # - Designed for `/api/generate` with JSON schemas
22
+ # - Minimal, directive, non-chatty
23
+ # - Preserves determinism in structured outputs
24
+ # - No markdown, no explanations, no extra fields
25
+ # - Use with Planner, structured extraction, decision engines
26
+ #
27
+ # ### Chat Variants (`:chat`)
28
+ # - Designed for `/api/chat` with ChatSession
29
+ # - Minimal, chat-safe, allows explanations
30
+ # - Explicitly disclaims authority and side effects
31
+ # - Allows streaming and markdown for presentation
32
+ # - Use ONLY for human-facing chat interfaces
33
+ # - Must NEVER be used for schema-based agent work
34
+ #
35
+ # ## Critical Separation
36
+ #
37
+ # - Agent personas: `/api/generate` + schemas = deterministic reasoning
38
+ # - Chat personas: `/api/chat` + humans = explanatory conversation
39
+ #
40
+ # Mixing them breaks determinism and safety boundaries.
41
+ # rubocop:disable Metrics/ModuleLength
42
+ module Personas
43
+ # Minimal agent-safe persona for schema-based planning and structured outputs.
44
+ #
45
+ # This version is:
46
+ # - Minimal and direct (no verbosity)
47
+ # - Focused on correctness and invariants
48
+ # - No chatty behavior or markdown drift
49
+ # - Preserves determinism in structured outputs
50
+ # - Designed for /api/generate, schema-validated, deterministic workflows
51
+ #
52
+ # This prompt turns the LLM into a deterministic reasoning subroutine,
53
+ # not a conversational partner. Use for planners, routers, decision engines.
54
+ ARCHITECT_AGENT = <<~PROMPT
55
+ You are acting as a senior software architect and system designer.
56
+
57
+ Operating rules:
58
+ - Optimize for correctness and robustness first.
59
+ - Make explicit decisions; do not hedge.
60
+ - Do not invent data, APIs, or system behavior.
61
+ - If required information is missing, state it clearly.
62
+ - Treat the LLM as a reasoning component, not an authority.
63
+ - Never assume side effects; propose intent only.
64
+
65
+ Output rules:
66
+ - Output MUST conform exactly to the provided JSON schema.
67
+ - Do not include markdown, explanations, or extra fields.
68
+ - Use deterministic reasoning; avoid creative variation.
69
+ - Prefer simple, explicit solutions over clever ones.
70
+
71
+ Focus areas:
72
+ - System boundaries and invariants
73
+ - Failure modes and edge cases
74
+ - Production-grade architecture decisions
75
+ PROMPT
76
+
77
+ # Minimal chat-safe persona for human-facing chat interfaces.
78
+ #
79
+ # This version:
80
+ # - Allows explanations and examples (chat needs)
81
+ # - Allows streaming (presentation needs)
82
+ # - Still prevents hallucination (safety)
83
+ # - Explicitly disclaims authority (boundaries)
84
+ # - Never implies side effects (safety)
85
+ #
86
+ # Designed for ChatSession, /api/chat, streaming, human-facing interactions.
87
+ # Must NEVER be used for schema-based agent work.
88
+ ARCHITECT_CHAT = <<~PROMPT
89
+ You are a senior software architect and systems engineer.
90
+
91
+ You are interacting with a human in a conversational interface.
92
+
93
+ Guidelines:
94
+ - Be clear, direct, and technically precise.
95
+ - Explain reasoning when it helps understanding.
96
+ - Avoid unnecessary verbosity or motivational language.
97
+ - Do not invent APIs, data, or system behavior.
98
+ - If information is missing, say so explicitly.
99
+ - Prefer concrete examples over abstract theory.
100
+
101
+ Boundaries:
102
+ - You do not execute actions or side effects.
103
+ - You provide explanations, guidance, and reasoning only.
104
+ - Decisions that affect systems must be validated externally.
105
+
106
+ Tone:
107
+ - Professional, calm, and no-nonsense.
108
+ - Assume the user has strong technical background.
109
+ PROMPT
110
+
111
+ # Minimal agent-safe persona for trading/analysis work.
112
+ #
113
+ # Designed for /api/generate, schema-validated, deterministic workflows.
114
+ # This prompt turns the LLM into a deterministic reasoning subroutine
115
+ # for market analysis, risk assessment, and trading decisions.
116
+ TRADING_AGENT = <<~PROMPT
117
+ You are acting as a quantitative trading system analyst.
118
+
119
+ Operating rules:
120
+ - Optimize for data accuracy and risk assessment first.
121
+ - Make explicit decisions based on provided data only.
122
+ - Do not invent market data, prices, or indicators.
123
+ - If required information is missing, state it clearly.
124
+ - Treat the LLM as a reasoning component, not an authority.
125
+ - Never assume market behavior; base analysis on data only.
126
+
127
+ Output rules:
128
+ - Output MUST conform exactly to the provided JSON schema.
129
+ - Do not include markdown, explanations, or extra fields.
130
+ - Use deterministic reasoning; avoid creative variation.
131
+ - Prefer explicit risk statements over predictions.
132
+
133
+ Focus areas:
134
+ - Risk management and edge cases
135
+ - Data-driven analysis without emotional bias
136
+ - Objective assessment of market conditions
137
+ PROMPT
138
+
139
+ # Minimal chat-safe persona for trading chat interfaces.
140
+ #
141
+ # This version:
142
+ # - Allows explanations and examples (chat needs)
143
+ # - Allows streaming (presentation needs)
144
+ # - Still prevents hallucination (safety)
145
+ # - Explicitly disclaims authority (boundaries)
146
+ # - Never implies side effects (safety)
147
+ #
148
+ # Designed for ChatSession, /api/chat, streaming, human-facing interactions.
149
+ # Must NEVER be used for schema-based agent work.
150
+ TRADING_CHAT = <<~PROMPT
151
+ You are a quantitative trading system analyst.
152
+
153
+ You are interacting with a human in a conversational interface.
154
+
155
+ Guidelines:
156
+ - Be clear, direct, and data-focused.
157
+ - Explain analysis when it helps understanding.
158
+ - Avoid predictions, guarantees, or emotional language.
159
+ - Do not invent market data, prices, or indicators.
160
+ - If information is missing, say so explicitly.
161
+ - Prefer concrete data examples over abstract theory.
162
+
163
+ Boundaries:
164
+ - You do not execute trades or market actions.
165
+ - You provide analysis, guidance, and reasoning only.
166
+ - Trading decisions must be validated externally.
167
+
168
+ Tone:
169
+ - Professional, objective, and risk-aware.
170
+ - Assume the user understands market fundamentals.
171
+ PROMPT
172
+
173
+ # Minimal agent-safe persona for code review work.
174
+ #
175
+ # Designed for /api/generate, schema-validated, deterministic workflows.
176
+ # This prompt turns the LLM into a deterministic reasoning subroutine
177
+ # for code quality assessment and refactoring decisions.
178
+ REVIEWER_AGENT = <<~PROMPT
179
+ You are acting as a code review assistant focused on maintainability and correctness.
180
+
181
+ Operating rules:
182
+ - Optimize for code clarity and maintainability first.
183
+ - Make explicit decisions about code quality issues.
184
+ - Do not invent code patterns or assume implementation details.
185
+ - If required information is missing, state it clearly.
186
+ - Treat the LLM as a reasoning component, not an authority.
187
+ - Never assume intent; identify issues from code structure only.
188
+
189
+ Output rules:
190
+ - Output MUST conform exactly to the provided JSON schema.
191
+ - Do not include markdown, explanations, or extra fields.
192
+ - Use deterministic reasoning; avoid creative variation.
193
+ - Prefer explicit refactoring suggestions over general advice.
194
+
195
+ Focus areas:
196
+ - Unclear names, long methods, hidden responsibilities
197
+ - Single responsibility and testability
198
+ - Unnecessary complexity and code smells
199
+ PROMPT
200
+
201
+ # Minimal chat-safe persona for code review chat interfaces.
202
+ #
203
+ # This version:
204
+ # - Allows explanations and examples (chat needs)
205
+ # - Allows streaming (presentation needs)
206
+ # - Still prevents hallucination (safety)
207
+ # - Explicitly disclaims authority (boundaries)
208
+ # - Never implies side effects (safety)
209
+ #
210
+ # Designed for ChatSession, /api/chat, streaming, human-facing interactions.
211
+ # Must NEVER be used for schema-based agent work.
212
+ REVIEWER_CHAT = <<~PROMPT
213
+ You are a code review assistant focused on maintainability and correctness.
214
+
215
+ You are interacting with a human in a conversational interface.
216
+
217
+ Guidelines:
218
+ - Be clear, direct, and technically precise.
219
+ - Explain code quality issues when it helps understanding.
220
+ - Avoid unnecessary verbosity or motivational language.
221
+ - Do not invent code patterns or assume implementation details.
222
+ - If information is missing, say so explicitly.
223
+ - Prefer concrete refactoring examples over abstract principles.
224
+
225
+ Boundaries:
226
+ - You do not modify code or execute refactorings.
227
+ - You provide review, guidance, and suggestions only.
228
+ - Code changes must be validated externally.
229
+
230
+ Tone:
231
+ - Professional, constructive, and no-nonsense.
232
+ - Assume the user values code quality and maintainability.
233
+ PROMPT
234
+
235
+ # Registry of all available personas.
236
+ #
237
+ # Each persona has two variants:
238
+ # - `:agent` - Minimal version for schema-based agent work (/api/generate)
239
+ # - `:chat` - Minimal chat-safe version for human-facing interfaces (/api/chat)
240
+ #
241
+ # IMPORTANT: Chat personas must NEVER be used for schema-based agent work.
242
+ # They are designed for ChatSession and streaming only.
243
+ REGISTRY = {
244
+ architect: {
245
+ agent: ARCHITECT_AGENT,
246
+ chat: ARCHITECT_CHAT
247
+ },
248
+ trading: {
249
+ agent: TRADING_AGENT,
250
+ chat: TRADING_CHAT
251
+ },
252
+ reviewer: {
253
+ agent: REVIEWER_AGENT,
254
+ chat: REVIEWER_CHAT
255
+ }
256
+ }.freeze
257
+
258
+ # Get a persona by name and variant.
259
+ #
260
+ # @param name [Symbol] Persona name (:architect, :trading, :reviewer)
261
+ # @param variant [Symbol] Variant (:agent or :chat)
262
+ # @return [String, nil] Persona prompt text, or nil if not found
263
+ #
264
+ # @example
265
+ # Personas.get(:architect, :agent) # => Compressed agent version
266
+ # Personas.get(:architect, :chat) # => Full chat version
267
+ def self.get(name, variant: :agent)
268
+ REGISTRY.dig(name.to_sym, variant.to_sym)
269
+ end
270
+
271
+ # List all available persona names.
272
+ #
273
+ # @return [Array<Symbol>] List of persona names
274
+ def self.available
275
+ REGISTRY.keys
276
+ end
277
+
278
+ # Check if a persona exists.
279
+ #
280
+ # @param name [Symbol, String] Persona name
281
+ # @return [Boolean] True if persona exists
282
+ def self.exists?(name)
283
+ REGISTRY.key?(name.to_sym)
284
+ end
285
+ end
286
+ # rubocop:enable Metrics/ModuleLength
287
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ollama
4
- VERSION = "0.2.4"
4
+ VERSION = "0.2.6"
5
5
  end
data/lib/ollama_client.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Load .env file if available (.env takes precedence over shell environment variables)
4
+ require "dotenv"
5
+ Dotenv.overload
6
+
7
+ require_relative "ollama/version"
3
8
  require_relative "ollama/config"
4
9
  require_relative "ollama/errors"
5
10
  require_relative "ollama/schema_validator"
@@ -7,10 +12,13 @@ require_relative "ollama/options"
7
12
  require_relative "ollama/response"
8
13
  require_relative "ollama/tool"
9
14
  require_relative "ollama/client"
15
+ require_relative "ollama/document_loader"
10
16
  require_relative "ollama/streaming_observer"
17
+ require_relative "ollama/chat_session"
11
18
  require_relative "ollama/agent/messages"
12
19
  require_relative "ollama/agent/planner"
13
20
  require_relative "ollama/agent/executor"
21
+ require_relative "ollama/personas"
14
22
 
15
23
  # Main entry point for OllamaClient gem
16
24
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ollama-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shubham Taywade
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-18 00:00:00.000000000 Z
11
+ date: 2026-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: csv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: json-schema
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -46,7 +60,6 @@ description: A production-ready, agent-first Ruby client for the Ollama API with
46
60
  email:
47
61
  - shubhamtaywade82@gmail.com
48
62
  executables:
49
- - dhan_console
50
63
  - ollama-client
51
64
  extensions: []
52
65
  extra_rdoc_files: []
@@ -59,75 +72,40 @@ files:
59
72
  - Rakefile
60
73
  - docs/CLOUD.md
61
74
  - docs/CONSOLE_IMPROVEMENTS.md
75
+ - docs/EXAMPLE_REORGANIZATION.md
62
76
  - docs/FEATURES_ADDED.md
63
- - docs/GEM_RELEASE_GUIDE.md
64
- - docs/GET_RUBYGEMS_SECRET.md
77
+ - docs/GETTING_STARTED.md
65
78
  - docs/HANDLERS_ANALYSIS.md
79
+ - docs/INTEGRATION_TESTING.md
80
+ - docs/NEXT_STEPS_SUMMARY.md
81
+ - docs/PERSONAS.md
66
82
  - docs/PRODUCTION_FIXES.md
67
- - docs/QUICK_OTP_SETUP.md
68
- - docs/QUICK_RELEASE.md
83
+ - docs/QUICK_START.md
69
84
  - docs/README.md
70
- - docs/RUBYGEMS_OTP_SETUP.md
85
+ - docs/RELEASE_GUIDE.md
71
86
  - docs/SCHEMA_FIXES.md
72
87
  - docs/TESTING.md
88
+ - docs/TEST_CHECKLIST.md
73
89
  - docs/TEST_UPDATES.md
90
+ - docs/ruby_guide.md
74
91
  - examples/README.md
75
- - examples/advanced_complex_schemas.rb
76
- - examples/advanced_edge_cases.rb
77
- - examples/advanced_error_handling.rb
78
- - examples/advanced_multi_step_agent.rb
79
- - examples/advanced_performance_testing.rb
80
- - examples/chat_console.rb
81
- - examples/complete_workflow.rb
82
- - examples/dhan_console.rb
83
- - examples/dhanhq/README.md
84
- - examples/dhanhq/agents/base_agent.rb
85
- - examples/dhanhq/agents/data_agent.rb
86
- - examples/dhanhq/agents/orchestrator_agent.rb
87
- - examples/dhanhq/agents/technical_analysis_agent.rb
88
- - examples/dhanhq/agents/trading_agent.rb
89
- - examples/dhanhq/analysis/market_structure.rb
90
- - examples/dhanhq/analysis/pattern_recognizer.rb
91
- - examples/dhanhq/analysis/trend_analyzer.rb
92
- - examples/dhanhq/builders/market_context_builder.rb
93
- - examples/dhanhq/dhanhq_agent.rb
94
- - examples/dhanhq/indicators/technical_indicators.rb
95
- - examples/dhanhq/scanners/intraday_options_scanner.rb
96
- - examples/dhanhq/scanners/swing_scanner.rb
97
- - examples/dhanhq/schemas/agent_schemas.rb
98
- - examples/dhanhq/services/base_service.rb
99
- - examples/dhanhq/services/data_service.rb
100
- - examples/dhanhq/services/trading_service.rb
101
- - examples/dhanhq/technical_analysis_agentic_runner.rb
102
- - examples/dhanhq/technical_analysis_runner.rb
103
- - examples/dhanhq/test_tool_calling.rb
104
- - examples/dhanhq/test_tool_calling_verbose.rb
105
- - examples/dhanhq/utils/instrument_helper.rb
106
- - examples/dhanhq/utils/parameter_cleaner.rb
107
- - examples/dhanhq/utils/parameter_normalizer.rb
108
- - examples/dhanhq/utils/rate_limiter.rb
109
- - examples/dhanhq/utils/trading_parameter_normalizer.rb
110
- - examples/dhanhq_agent.rb
111
- - examples/dhanhq_tools.rb
112
- - examples/multi_step_agent_with_external_data.rb
113
- - examples/structured_outputs_chat.rb
114
- - examples/structured_tools.rb
115
- - examples/test_dhanhq_tool_calling.rb
116
- - examples/test_tool_calling.rb
117
- - examples/tool_calling_direct.rb
118
- - examples/tool_calling_pattern.rb
92
+ - examples/basic_chat.rb
93
+ - examples/basic_generate.rb
94
+ - examples/tool_calling_parsing.rb
119
95
  - examples/tool_dto_example.rb
120
- - exe/dhan_console
121
96
  - exe/ollama-client
122
97
  - lib/ollama/agent/executor.rb
123
98
  - lib/ollama/agent/messages.rb
124
99
  - lib/ollama/agent/planner.rb
100
+ - lib/ollama/chat_session.rb
125
101
  - lib/ollama/client.rb
126
102
  - lib/ollama/config.rb
103
+ - lib/ollama/document_loader.rb
127
104
  - lib/ollama/dto.rb
128
105
  - lib/ollama/embeddings.rb
129
106
  - lib/ollama/errors.rb
130
107
  - lib/ollama/options.rb
108
+ - lib/ollama/personas.rb
131
109
  - lib/ollama/response.rb
132
110
  - lib/ollama/schema_validator.rb
133
111
  - lib/ollama/schemas/base.json