ollama-client 1.3.0 → 1.4.0

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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +11 -0
  3. data/API_CONTRACT.md +79 -8
  4. data/CHANGELOG.md +45 -0
  5. data/CONTRIBUTING.md +8 -0
  6. data/README.md +205 -273
  7. data/ROADMAP.md +23 -0
  8. data/docs/API_GAPS.md +18 -141
  9. data/docs/ARCHITECTURE.md +141 -0
  10. data/docs/AREAS_FOR_CONSIDERATION.md +13 -1
  11. data/docs/CLOUD.md +19 -0
  12. data/docs/CONSOLE_IMPROVEMENTS.md +20 -1
  13. data/docs/ECOSYSTEM_GEMS.md +41 -0
  14. data/docs/ECOSYSTEM_STRATEGY.md +151 -0
  15. data/docs/GETTING_STARTED.md +16 -8
  16. data/docs/INTEGRATION_TESTING.md +23 -5
  17. data/docs/PRODUCTION_FIXES.md +15 -3
  18. data/docs/QUICK_START.md +1 -1
  19. data/docs/README.md +1 -0
  20. data/docs/RUBYLLM_ADOPTION_MATRIX.md +273 -0
  21. data/docs/adr/001-openai-boundary.md +12 -0
  22. data/docs/adr/002-transport-abstraction.md +12 -0
  23. data/docs/adr/003-response-normalization.md +12 -0
  24. data/docs/adr/004-mock-transport.md +16 -0
  25. data/docs/adr/005-error-taxonomy.md +16 -0
  26. data/docs/adr/006-stream-runtime.md +16 -0
  27. data/docs/ecosystem/BOUNDARIES.md +19 -0
  28. data/docs/ecosystem/DEPENDENCY_GRAPH.md +14 -0
  29. data/docs/ecosystem/DESIGN_PRINCIPLES.md +9 -0
  30. data/docs/ecosystem/EXISTING_REPOS.md +31 -0
  31. data/docs/ecosystem/EXPERIMENTAL_LABS.md +24 -0
  32. data/docs/ecosystem/OVERVIEW.md +28 -0
  33. data/docs/ecosystem/RELEASE_ORDER.md +17 -0
  34. data/docs/observability/README.md +8 -0
  35. data/docs/rails/README.md +7 -0
  36. data/docs/rfcs/0001-stream-runtime.md +6 -0
  37. data/docs/rfcs/0002-schema-system.md +6 -0
  38. data/docs/rfcs/0003-observability-hooks.md +6 -0
  39. data/docs/rfcs/0004-async-runtime.md +6 -0
  40. data/docs/rfcs/README.md +16 -0
  41. data/docs/runtime/ERROR_CONTRACT.md +14 -0
  42. data/docs/runtime/SCHEMA_CONTRACT.md +28 -0
  43. data/docs/runtime/STREAM_CONTRACT.md +17 -0
  44. data/docs/runtime/STREAM_RUNTIME.md +20 -0
  45. data/docs/runtime/TRANSPORT_CONTRACT.md +26 -0
  46. data/docs/schema/README.md +8 -0
  47. data/docs/schema/STRUCTURED_OUTPUTS.md +22 -0
  48. data/docs/streaming/README.md +8 -0
  49. data/docs/testing/README.md +7 -0
  50. data/docs/testing/REPLAY_SYSTEM.md +17 -0
  51. data/docs/transport/README.md +7 -0
  52. data/examples/README.md +44 -0
  53. data/examples/basic_chat.rb +9 -0
  54. data/examples/cloud_models.rb +162 -0
  55. data/examples/embeddings.rb +10 -0
  56. data/examples/free_catalog.json +290 -0
  57. data/examples/generate.rb +9 -0
  58. data/examples/streaming.rb +12 -0
  59. data/examples/structured_tools.rb +90 -0
  60. data/examples/tool_calling_direct.rb +101 -0
  61. data/examples/tool_dto_example.rb +94 -0
  62. data/exe/ollama-client +5 -1
  63. data/lib/ollama/agent/executor.rb +243 -0
  64. data/lib/ollama/agent/messages.rb +31 -0
  65. data/lib/ollama/agent/planner.rb +45 -0
  66. data/lib/ollama/api_key_pool.rb +61 -0
  67. data/lib/ollama/attachment.rb +74 -0
  68. data/lib/ollama/capabilities.rb +1 -1
  69. data/lib/ollama/chat_response.rb +33 -0
  70. data/lib/ollama/client/chat/request_preparer.rb +82 -0
  71. data/lib/ollama/client/chat.rb +58 -68
  72. data/lib/ollama/client/chat_stream_processor.rb +85 -25
  73. data/lib/ollama/client/generate/request_preparer.rb +118 -0
  74. data/lib/ollama/client/generate/response_formatter.rb +95 -0
  75. data/lib/ollama/client/generate.rb +83 -165
  76. data/lib/ollama/client/model_management.rb +182 -84
  77. data/lib/ollama/client/openai_compat.rb +185 -0
  78. data/lib/ollama/client/raw.rb +66 -0
  79. data/lib/ollama/client/tool_intent.rb +38 -0
  80. data/lib/ollama/client/web_search.rb +39 -0
  81. data/lib/ollama/client.rb +83 -35
  82. data/lib/ollama/config.rb +122 -17
  83. data/lib/ollama/embeddings.rb +67 -29
  84. data/lib/ollama/errors.rb +55 -1
  85. data/lib/ollama/events.rb +55 -0
  86. data/lib/ollama/generate_stream_handler.rb +23 -4
  87. data/lib/ollama/http_error_handler.rb +42 -0
  88. data/lib/ollama/messages.rb +109 -0
  89. data/lib/ollama/middleware/cache.rb +73 -0
  90. data/lib/ollama/middleware/logger.rb +74 -0
  91. data/lib/ollama/middleware/metrics.rb +84 -0
  92. data/lib/ollama/middleware/tracing.rb +101 -0
  93. data/lib/ollama/middleware.rb +39 -0
  94. data/lib/ollama/model_profile.rb +1 -1
  95. data/lib/ollama/openai.rb +16 -0
  96. data/lib/ollama/options.rb +63 -1
  97. data/lib/ollama/params.rb +139 -0
  98. data/lib/ollama/parsers/base.rb +24 -0
  99. data/lib/ollama/parsers/chat.rb +22 -0
  100. data/lib/ollama/parsers/embeddings.rb +23 -0
  101. data/lib/ollama/parsers/generate.rb +38 -0
  102. data/lib/ollama/parsers/list_running.rb +15 -0
  103. data/lib/ollama/parsers/show_model.rb +14 -0
  104. data/lib/ollama/parsers/version.rb +15 -0
  105. data/lib/ollama/pipeline.rb +169 -0
  106. data/lib/ollama/plugins.rb +83 -0
  107. data/lib/ollama/policies/auto_pull.rb +69 -0
  108. data/lib/ollama/policies/base.rb +70 -0
  109. data/lib/ollama/policies/capability_validation.rb +88 -0
  110. data/lib/ollama/policies/fallback.rb +57 -0
  111. data/lib/ollama/policies/rate_limit.rb +115 -0
  112. data/lib/ollama/policies/repair_json.rb +137 -0
  113. data/lib/ollama/policies/retry/strategies/exponential.rb +27 -0
  114. data/lib/ollama/policies/retry/strategies/fixed.rb +27 -0
  115. data/lib/ollama/policies/retry/strategies/jitter.rb +30 -0
  116. data/lib/ollama/policies/retry/strategies/linear.rb +27 -0
  117. data/lib/ollama/policies/retry.rb +152 -0
  118. data/lib/ollama/policies/schema_repair.rb +180 -0
  119. data/lib/ollama/policies/timeout.rb +43 -0
  120. data/lib/ollama/policies.rb +24 -0
  121. data/lib/ollama/prompt.rb +86 -0
  122. data/lib/ollama/prompt_adapters/base.rb +3 -2
  123. data/lib/ollama/prompt_adapters/gemma4.rb +22 -14
  124. data/lib/ollama/prompts/tool_planner.rb +35 -0
  125. data/lib/ollama/providers/base.rb +70 -0
  126. data/lib/ollama/providers/llama_cpp.rb +131 -0
  127. data/lib/ollama/providers/ollama.rb +54 -0
  128. data/lib/ollama/providers/openai.rb +134 -0
  129. data/lib/ollama/providers.rb +28 -0
  130. data/lib/ollama/rate_limit_handler.rb +48 -0
  131. data/lib/ollama/request.rb +169 -0
  132. data/lib/ollama/response.rb +3 -2
  133. data/lib/ollama/responses/base.rb +11 -0
  134. data/lib/ollama/responses/chat.rb +11 -0
  135. data/lib/ollama/responses/embeddings.rb +14 -0
  136. data/lib/ollama/responses/generate.rb +22 -0
  137. data/lib/ollama/schema_dsl.rb +97 -0
  138. data/lib/ollama/schema_validator.rb +90 -53
  139. data/lib/ollama/schemas/tool_intent.json +15 -0
  140. data/lib/ollama/schemas/tool_intent.rb +16 -0
  141. data/lib/ollama/serializers/base.rb +44 -0
  142. data/lib/ollama/serializers/chat.rb +42 -0
  143. data/lib/ollama/serializers/embeddings.rb +36 -0
  144. data/lib/ollama/serializers/generate.rb +47 -0
  145. data/lib/ollama/streaming_observer.rb +22 -0
  146. data/lib/ollama/testing.rb +103 -0
  147. data/lib/ollama/tool/function/parameters/property.rb +72 -0
  148. data/lib/ollama/tool/function/parameters.rb +101 -0
  149. data/lib/ollama/tool/function.rb +78 -0
  150. data/lib/ollama/tool.rb +60 -0
  151. data/lib/ollama/tool_dsl.rb +93 -0
  152. data/lib/ollama/tool_intent.rb +19 -0
  153. data/lib/ollama/transport/base.rb +42 -0
  154. data/lib/ollama/transport/mock.rb +48 -0
  155. data/lib/ollama/transport/net_http.rb +76 -0
  156. data/lib/ollama/transport/request.rb +20 -0
  157. data/lib/ollama/transport/response.rb +41 -0
  158. data/lib/ollama/transport.rb +26 -0
  159. data/lib/ollama/version.rb +1 -1
  160. data/lib/ollama_client.rb +35 -0
  161. data/script/live_branch_smoke/chat_exercises.rb +232 -0
  162. data/script/live_branch_smoke/generation_exercises.rb +128 -0
  163. data/script/live_branch_smoke/model_exercises.rb +105 -0
  164. data/script/live_branch_smoke/utility_exercises.rb +375 -0
  165. data/script/live_branch_smoke.rb +159 -174
  166. data/test_all_features.rb +315 -0
  167. metadata +158 -24
  168. data/.cursor/.gitignore +0 -1
  169. data/RELEASE_NOTES_v0.2.6.md +0 -41
  170. data/devagent_proper.rb +0 -430
  171. data/docs/TESTING.md +0 -508
  172. data/examples/agent_loop.rb +0 -120
  173. data/examples/failure_modes/invalid_json_repair.rb +0 -42
  174. data/examples/production/rails_agent.rb +0 -62
  175. data/market.jpg +0 -0
  176. data/print_capabilities.rb +0 -20
  177. data/schema.json +0 -1
  178. data/test_tool.rb +0 -26
@@ -0,0 +1,17 @@
1
+ # Stream Contract (Draft)
2
+
3
+ `ollama-client` is the canonical owner of stream semantics.
4
+
5
+ ## Required runtime semantics
6
+
7
+ - Explicit lifecycle states
8
+ - Cancellation semantics (graceful vs immediate)
9
+ - UTF-8 safe chunk assembly
10
+ - SSE boundary correctness
11
+ - Backpressure and bounded buffering
12
+ - Error channel for malformed/incomplete events
13
+
14
+ ## Contract direction
15
+
16
+ Higher-level gems (`ollama-stream`, `ollama-rails`, `ollama-agent`) compose on top of
17
+ core stream semantics and must not fork or redefine lifecycle guarantees.
@@ -0,0 +1,20 @@
1
+ # Stream Runtime Design (Draft)
2
+
3
+ Target object:
4
+
5
+ ```ruby
6
+ stream = client.chat.stream(...)
7
+ stream.each_token { |t| ... }
8
+ stream.each_chunk { |c| ... }
9
+ stream.cancel
10
+ stream.close
11
+ ```
12
+
13
+ ## Required semantics
14
+
15
+ - Explicit lifecycle: open -> active -> closing -> closed
16
+ - Cancellation modes: graceful vs immediate
17
+ - Backpressure: bounded buffering
18
+ - UTF-8 safe chunk assembly
19
+ - SSE event boundary correctness
20
+ - Error channel for malformed/incomplete events
@@ -0,0 +1,26 @@
1
+ # Transport Contract
2
+
3
+ `ollama-client` owns transport/runtime semantics.
4
+
5
+ ## Adapter interface (current baseline)
6
+
7
+ - `request(uri:, request:, read_timeout:)`
8
+ - `stream(uri:, request:, &block)` (defined contract; implementation may be pending)
9
+ - `capabilities`
10
+
11
+ ## Response contract
12
+
13
+ Adapters must return normalized transport responses with:
14
+
15
+ - `status`
16
+ - `headers`
17
+ - `body`
18
+ - `raw`
19
+ - `duration_ms`
20
+
21
+ Compatibility behavior for migration is allowed (e.g. status helper methods),
22
+ but response normalization remains mandatory.
23
+
24
+ ## Ownership rule
25
+
26
+ No orchestration repo may redefine transport contracts. They consume this contract.
@@ -0,0 +1,8 @@
1
+ # Schema Docs
2
+
3
+ Canonical schema semantics live in:
4
+
5
+ - `docs/runtime/SCHEMA_CONTRACT.md`
6
+ - `docs/schema/STRUCTURED_OUTPUTS.md`
7
+
8
+ Typed schema and repair RFCs should be linked from `docs/rfcs/`.
@@ -0,0 +1,22 @@
1
+ # Structured Outputs (Draft)
2
+
3
+ ## Goals
4
+
5
+ - typed schema declarations
6
+ - coercion + validation
7
+ - repair strategies
8
+ - deterministic parse contracts
9
+
10
+ ## Target APIs
11
+
12
+ ```ruby
13
+ client.chat.parse(schema: TradeSignal)
14
+ client.chat.stream_parse(schema: TradeSignal)
15
+ ```
16
+
17
+ ## Streaming requirements
18
+
19
+ - incremental parse
20
+ - partial AST assembly
21
+ - stream-time validation
22
+ - repair during stream
@@ -0,0 +1,8 @@
1
+ # Streaming Docs
2
+
3
+ Canonical streaming contracts live in:
4
+
5
+ - `docs/runtime/STREAM_CONTRACT.md`
6
+ - `docs/runtime/STREAM_RUNTIME.md`
7
+
8
+ Use this folder for parser/backpressure/cancellation implementation notes.
@@ -0,0 +1,7 @@
1
+ # Testing Docs
2
+
3
+ Testing and replay architecture references:
4
+
5
+ - `docs/testing/REPLAY_SYSTEM.md`
6
+
7
+ This folder covers deterministic replay, stream simulation, and failure injection design.
@@ -0,0 +1,17 @@
1
+ # Replay System (Draft)
2
+
3
+ ## Purpose
4
+
5
+ Deterministic CI and incident reproduction for AI runtime behavior.
6
+
7
+ ## Capabilities
8
+
9
+ - recorded fixtures
10
+ - response replay
11
+ - stream replay
12
+ - latency injection
13
+ - failure injection
14
+
15
+ ## Integration point
16
+
17
+ Built on top of transport adapters (`:mock` first).
@@ -0,0 +1,7 @@
1
+ # Transport Docs
2
+
3
+ Canonical transport semantics live in:
4
+
5
+ - `docs/runtime/TRANSPORT_CONTRACT.md`
6
+
7
+ This folder is reserved for adapter-specific design notes and future transport RFC mappings.
@@ -0,0 +1,44 @@
1
+ # Examples
2
+
3
+ This directory contains working example scripts demonstrating various capabilities of `ollama-client`.
4
+
5
+ ## Running Examples
6
+
7
+ Most examples assume you are in the project root and use `require_relative` to load the local gem:
8
+
9
+ ```bash
10
+ bundle exec ruby examples/<script>.rb
11
+ ```
12
+
13
+ ## Overview
14
+
15
+ | Script | What it demonstrates |
16
+ |---|---|
17
+ | [`agent_loop.rb`](agent_loop.rb) | Agentic loop with tool calling and stateful memory |
18
+ | [`cloud_models.rb`](cloud_models.rb) | List Ollama Cloud models and probe which ones your account can access |
19
+ | [`llama_cpp_gpu_test.rb`](llama_cpp_gpu_test.rb) | Connect to a llama.cpp GPU server via the OpenAI provider |
20
+ | [`timeout_retry.rb`](timeout_retry.rb) | How timeout and exponential backoff work in production |
21
+ | [`failure_modes/invalid_json_repair.rb`](failure_modes/invalid_json_repair.rb) | Automatic JSON repair when the model returns markdown-wrapped JSON |
22
+ | [`production/rails_agent.rb`](production/rails_agent.rb) | Resilient background job pattern for Rails (e.g. Sidekiq) |
23
+ | [`dhanhq_agent.rb`](dhanhq_agent.rb) | DhanHQ trading agent runner |
24
+ | [`dhanhq/`](dhanhq/) | Modular DhanHQ technical analysis and trading agent system |
25
+
26
+ ## Cloud Model Accessibility Probe
27
+
28
+ [`cloud_models.rb`](cloud_models.rb) is useful if you use Ollama Cloud and want to know which models are available under your current plan:
29
+
30
+ ```bash
31
+ export OLLAMA_API_KEY="your-ollama-cloud-api-key"
32
+ bundle exec ruby examples/cloud_models.rb
33
+ ```
34
+
35
+ Output is JSON printed to stdout:
36
+
37
+ ```json
38
+ [
39
+ { "name": "gpt-oss:20b", "accessible": true, "reason": null },
40
+ { "name": "deepseek-v4-pro", "accessible": false, "reason": "plan_restricted" }
41
+ ]
42
+ ```
43
+
44
+ See the script's header comments for the full list of `reason` codes.
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Basic chat completion with Ollama
5
+ require "ollama_client"
6
+
7
+ client = Ollama::Client.new
8
+ response = client.chat(model: "llama3.1:8b", messages: [{ role: "user", content: "Hello, how are you?" }])
9
+ puts response
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../lib/ollama_client"
4
+ require "json"
5
+
6
+ begin
7
+ require "concurrent"
8
+ rescue LoadError
9
+ warn "Error: concurrent-ruby is required. Add it to your Gemfile."
10
+ exit 1
11
+ end
12
+
13
+ # ---------------------------------------------------------------------------
14
+ # Cloud Model Accessibility Probe
15
+ #
16
+ # Lists all models available on Ollama Cloud and probes each one to determine
17
+ # whether the current authenticated account can run inference against it.
18
+ # Results are printed as JSON to stdout and saved to examples/free_catalog.json.
19
+ # ---------------------------------------------------------------------------
20
+
21
+ OUTPUT_FILE = File.join(__dir__, "free_catalog.json").freeze
22
+ ONLY_ACCESSIBLE = ARGV.include?("--accessible")
23
+ NAMES_ONLY = ARGV.include?("--names-only")
24
+
25
+ api_key = ENV.fetch("OLLAMA_API_KEY", nil)
26
+ if api_key.nil? || api_key.empty?
27
+ warn <<~USAGE
28
+ Usage: OLLAMA_API_KEY=<your-key> bundle exec ruby examples/cloud_models.rb
29
+
30
+ Please set the OLLAMA_API_KEY environment variable to your Ollama Cloud API key.
31
+ USAGE
32
+ exit 1
33
+ end
34
+
35
+ config = Ollama::Config.new
36
+ config.base_url = "https://ollama.com"
37
+ config.api_key = api_key
38
+ config.timeout = 30
39
+ config.retries = 0
40
+
41
+ client = Ollama::Client.new(config: config)
42
+
43
+ # Fetch the public model catalog from Ollama Cloud.
44
+ begin
45
+ catalog = client.raw.get("/api/tags")
46
+ rescue Ollama::Error => e
47
+ warn "Failed to fetch model catalog: #{e.message}"
48
+ exit 1
49
+ end
50
+
51
+ models = catalog["models"] || []
52
+ names = models.map { |m| m["name"] }.compact.sort
53
+
54
+ catalog_capabilities = {}
55
+ models.each do |m|
56
+ name = m["name"]
57
+ next unless name
58
+
59
+ catalog_capabilities[name] = Ollama::Capabilities.for(m)
60
+ end
61
+
62
+ # Also try the OpenAI-compatible endpoint for a broader model list.
63
+ begin
64
+ openai_models = client.raw.get("/v1/models")
65
+ openai_names = (openai_models["data"] || []).map { |m| m["id"] }.compact
66
+ added = openai_names - names
67
+ names = (names + openai_names).uniq.sort
68
+ warn "/v1/models returned #{openai_names.length} model(s), #{added.length} new"
69
+ rescue Ollama::Error => e
70
+ warn "Warning: could not fetch /v1/models (#{e.message}), using /api/tags only"
71
+ end
72
+
73
+ # Known Ollama Cloud models not always surfaced by /api/tags.
74
+ EXTRA_MODELS = %w[
75
+ gemma4:12b
76
+ gemma4:26b
77
+ gemma4:31b
78
+ qwen3.5:0.8b
79
+ qwen3.5:2b
80
+ qwen3.5:4b
81
+ qwen3.5:9b
82
+ qwen3.5:27b
83
+ qwen3.5:35b
84
+ qwen3.5:122b
85
+ mistral-large-3:123b
86
+ mistral-large-3:400b
87
+ nemotron-3-nano:4b
88
+ gemini-3-flash-preview
89
+ glm-5
90
+ kimi-k2.5
91
+ ].freeze
92
+
93
+ extra = EXTRA_MODELS - names
94
+ names = (names + extra).uniq.sort
95
+ warn "Added #{extra.length} extra known cloud model(s) to probe"
96
+
97
+ if names.empty?
98
+ puts "[]"
99
+ exit 0
100
+ end
101
+
102
+ warn "Probing #{names.length} cloud model(s) with 10 concurrent threads..."
103
+
104
+ results = Concurrent::Array.new
105
+ pool = Concurrent::FixedThreadPool.new(10)
106
+
107
+ names.each do |name|
108
+ pool.post do
109
+ sleep(rand * 0.2)
110
+
111
+ result = { name: name, accessible: false, reason: nil, capabilities: catalog_capabilities[name] || {} }
112
+
113
+ begin
114
+ client.chat(
115
+ model: name,
116
+ messages: [{ role: "user", content: "ping" }],
117
+ options: { num_predict: 1 }
118
+ )
119
+
120
+ result[:accessible] = true
121
+ rescue Ollama::UnauthorizedError
122
+ result[:reason] = "unauthorized"
123
+ rescue Ollama::ModelUnavailableError
124
+ result[:reason] = "unavailable"
125
+ rescue Ollama::NotFoundError
126
+ result[:reason] = "not_found"
127
+ rescue Ollama::HTTPError => e
128
+ reason = case e.status_code
129
+ when 402 then "usage_limit"
130
+ when 403 then "plan_restricted"
131
+ when 429 then "rate_limited"
132
+ else "http_error"
133
+ end
134
+ result[:reason] = reason
135
+ rescue Ollama::TimeoutError
136
+ result[:reason] = "timeout"
137
+ rescue StandardError => e
138
+ result[:reason] = "error: #{e.class}: #{e.message}"
139
+ end
140
+
141
+ results << result
142
+ end
143
+ end
144
+
145
+ pool.shutdown
146
+ pool.wait_for_termination
147
+
148
+ sorted = results.sort_by { |r| r[:name] }
149
+
150
+ if ONLY_ACCESSIBLE
151
+ sorted = sorted.select { |r| r[:accessible] }
152
+ warn "Filtering to #{sorted.length} accessible model(s) (--accessible)"
153
+ end
154
+
155
+ if NAMES_ONLY
156
+ sorted.each { |r| puts r[:name] }
157
+ else
158
+ json = JSON.pretty_generate(sorted)
159
+ puts json
160
+ File.write(OUTPUT_FILE, json + "\n")
161
+ warn "Saved free catalog to #{OUTPUT_FILE}"
162
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Generate embeddings
5
+ require "ollama_client"
6
+
7
+ client = Ollama::Client.new
8
+ response = client.embeddings.embed(model: "nomic-embed-text", input: "Hello, world!")
9
+ puts "Embedding dimension: #{response.length}"
10
+ puts "First 5 values: #{response.first(5)}"
@@ -0,0 +1,290 @@
1
+ [
2
+ {
3
+ "name": "deepseek-v4-flash",
4
+ "accessible": false,
5
+ "reason": "plan_restricted",
6
+ "capabilities": {
7
+ "tools": false,
8
+ "thinking": false,
9
+ "vision": false,
10
+ "embeddings": false
11
+ }
12
+ },
13
+ {
14
+ "name": "deepseek-v4-flash:0731",
15
+ "accessible": false,
16
+ "reason": "plan_restricted",
17
+ "capabilities": {
18
+ "tools": false,
19
+ "thinking": false,
20
+ "vision": false,
21
+ "embeddings": false
22
+ }
23
+ },
24
+ {
25
+ "name": "deepseek-v4-pro",
26
+ "accessible": false,
27
+ "reason": "plan_restricted",
28
+ "capabilities": {
29
+ "tools": false,
30
+ "thinking": false,
31
+ "vision": false,
32
+ "embeddings": false
33
+ }
34
+ },
35
+ {
36
+ "name": "gemini-3-flash-preview",
37
+ "accessible": false,
38
+ "reason": "http_error",
39
+ "capabilities": {}
40
+ },
41
+ {
42
+ "name": "gemma4:12b",
43
+ "accessible": false,
44
+ "reason": "not_found",
45
+ "capabilities": {}
46
+ },
47
+ {
48
+ "name": "gemma4:26b",
49
+ "accessible": false,
50
+ "reason": "not_found",
51
+ "capabilities": {}
52
+ },
53
+ {
54
+ "name": "gemma4:31b",
55
+ "accessible": true,
56
+ "reason": null,
57
+ "capabilities": {
58
+ "tools": false,
59
+ "thinking": true,
60
+ "vision": false,
61
+ "embeddings": false
62
+ }
63
+ },
64
+ {
65
+ "name": "glm-5",
66
+ "accessible": false,
67
+ "reason": "http_error",
68
+ "capabilities": {}
69
+ },
70
+ {
71
+ "name": "glm-5.1",
72
+ "accessible": false,
73
+ "reason": "plan_restricted",
74
+ "capabilities": {
75
+ "tools": false,
76
+ "thinking": false,
77
+ "vision": false,
78
+ "embeddings": false
79
+ }
80
+ },
81
+ {
82
+ "name": "glm-5.2",
83
+ "accessible": false,
84
+ "reason": "plan_restricted",
85
+ "capabilities": {
86
+ "tools": false,
87
+ "thinking": false,
88
+ "vision": false,
89
+ "embeddings": false
90
+ }
91
+ },
92
+ {
93
+ "name": "gpt-oss:120b",
94
+ "accessible": true,
95
+ "reason": null,
96
+ "capabilities": {
97
+ "tools": false,
98
+ "thinking": false,
99
+ "vision": false,
100
+ "embeddings": false
101
+ }
102
+ },
103
+ {
104
+ "name": "gpt-oss:20b",
105
+ "accessible": true,
106
+ "reason": null,
107
+ "capabilities": {
108
+ "tools": false,
109
+ "thinking": false,
110
+ "vision": false,
111
+ "embeddings": false
112
+ }
113
+ },
114
+ {
115
+ "name": "kimi-k2.5",
116
+ "accessible": false,
117
+ "reason": "http_error",
118
+ "capabilities": {}
119
+ },
120
+ {
121
+ "name": "kimi-k2.6",
122
+ "accessible": false,
123
+ "reason": "plan_restricted",
124
+ "capabilities": {
125
+ "tools": false,
126
+ "thinking": false,
127
+ "vision": false,
128
+ "embeddings": false
129
+ }
130
+ },
131
+ {
132
+ "name": "kimi-k2.7-code",
133
+ "accessible": false,
134
+ "reason": "plan_restricted",
135
+ "capabilities": {
136
+ "tools": false,
137
+ "thinking": false,
138
+ "vision": false,
139
+ "embeddings": false
140
+ }
141
+ },
142
+ {
143
+ "name": "kimi-k3",
144
+ "accessible": false,
145
+ "reason": "plan_restricted",
146
+ "capabilities": {
147
+ "tools": false,
148
+ "thinking": false,
149
+ "vision": false,
150
+ "embeddings": false
151
+ }
152
+ },
153
+ {
154
+ "name": "minimax-m2.7",
155
+ "accessible": false,
156
+ "reason": "plan_restricted",
157
+ "capabilities": {
158
+ "tools": false,
159
+ "thinking": false,
160
+ "vision": false,
161
+ "embeddings": false
162
+ }
163
+ },
164
+ {
165
+ "name": "minimax-m3",
166
+ "accessible": true,
167
+ "reason": null,
168
+ "capabilities": {
169
+ "tools": false,
170
+ "thinking": false,
171
+ "vision": false,
172
+ "embeddings": false
173
+ }
174
+ },
175
+ {
176
+ "name": "mistral-large-3:123b",
177
+ "accessible": false,
178
+ "reason": "not_found",
179
+ "capabilities": {}
180
+ },
181
+ {
182
+ "name": "mistral-large-3:400b",
183
+ "accessible": false,
184
+ "reason": "not_found",
185
+ "capabilities": {}
186
+ },
187
+ {
188
+ "name": "mistral-large-3:675b",
189
+ "accessible": false,
190
+ "reason": "plan_restricted",
191
+ "capabilities": {
192
+ "tools": false,
193
+ "thinking": false,
194
+ "vision": false,
195
+ "embeddings": false
196
+ }
197
+ },
198
+ {
199
+ "name": "nemotron-3-nano:30b",
200
+ "accessible": true,
201
+ "reason": null,
202
+ "capabilities": {
203
+ "tools": false,
204
+ "thinking": false,
205
+ "vision": false,
206
+ "embeddings": false
207
+ }
208
+ },
209
+ {
210
+ "name": "nemotron-3-nano:4b",
211
+ "accessible": false,
212
+ "reason": "not_found",
213
+ "capabilities": {}
214
+ },
215
+ {
216
+ "name": "nemotron-3-super",
217
+ "accessible": true,
218
+ "reason": null,
219
+ "capabilities": {
220
+ "tools": false,
221
+ "thinking": false,
222
+ "vision": false,
223
+ "embeddings": false
224
+ }
225
+ },
226
+ {
227
+ "name": "nemotron-3-ultra",
228
+ "accessible": true,
229
+ "reason": null,
230
+ "capabilities": {
231
+ "tools": false,
232
+ "thinking": false,
233
+ "vision": false,
234
+ "embeddings": false
235
+ }
236
+ },
237
+ {
238
+ "name": "qwen3.5:0.8b",
239
+ "accessible": false,
240
+ "reason": "not_found",
241
+ "capabilities": {}
242
+ },
243
+ {
244
+ "name": "qwen3.5:122b",
245
+ "accessible": false,
246
+ "reason": "rate_limited",
247
+ "capabilities": {}
248
+ },
249
+ {
250
+ "name": "qwen3.5:27b",
251
+ "accessible": false,
252
+ "reason": "rate_limited",
253
+ "capabilities": {}
254
+ },
255
+ {
256
+ "name": "qwen3.5:2b",
257
+ "accessible": false,
258
+ "reason": "rate_limited",
259
+ "capabilities": {}
260
+ },
261
+ {
262
+ "name": "qwen3.5:35b",
263
+ "accessible": false,
264
+ "reason": "not_found",
265
+ "capabilities": {}
266
+ },
267
+ {
268
+ "name": "qwen3.5:397b",
269
+ "accessible": false,
270
+ "reason": "plan_restricted",
271
+ "capabilities": {
272
+ "tools": false,
273
+ "thinking": false,
274
+ "vision": false,
275
+ "embeddings": false
276
+ }
277
+ },
278
+ {
279
+ "name": "qwen3.5:4b",
280
+ "accessible": false,
281
+ "reason": "not_found",
282
+ "capabilities": {}
283
+ },
284
+ {
285
+ "name": "qwen3.5:9b",
286
+ "accessible": false,
287
+ "reason": "rate_limited",
288
+ "capabilities": {}
289
+ }
290
+ ]
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Single completion (generate endpoint)
5
+ require "ollama_client"
6
+
7
+ client = Ollama::Client.new
8
+ response = client.generate(prompt: "Explain quantum computing in one sentence", model: "llama3.1:8b")
9
+ puts response
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Streaming chat completion
5
+ require "ollama_client"
6
+
7
+ client = Ollama::Client.new
8
+ client.chat(model: "llama3.1:8b", messages: [{ role: "user", content: "Count from 1 to 5" }], stream: true) do |chunk|
9
+ print chunk.dig("message", "content")
10
+ $stdout.flush
11
+ end
12
+ puts