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.
- checksums.yaml +4 -4
- data/.env.example +11 -0
- data/API_CONTRACT.md +79 -8
- data/CHANGELOG.md +45 -0
- data/CONTRIBUTING.md +8 -0
- data/README.md +205 -273
- data/ROADMAP.md +23 -0
- data/docs/API_GAPS.md +18 -141
- data/docs/ARCHITECTURE.md +141 -0
- data/docs/AREAS_FOR_CONSIDERATION.md +13 -1
- data/docs/CLOUD.md +19 -0
- data/docs/CONSOLE_IMPROVEMENTS.md +20 -1
- data/docs/ECOSYSTEM_GEMS.md +41 -0
- data/docs/ECOSYSTEM_STRATEGY.md +151 -0
- data/docs/GETTING_STARTED.md +16 -8
- data/docs/INTEGRATION_TESTING.md +23 -5
- data/docs/PRODUCTION_FIXES.md +15 -3
- data/docs/QUICK_START.md +1 -1
- data/docs/README.md +1 -0
- data/docs/RUBYLLM_ADOPTION_MATRIX.md +273 -0
- data/docs/adr/001-openai-boundary.md +12 -0
- data/docs/adr/002-transport-abstraction.md +12 -0
- data/docs/adr/003-response-normalization.md +12 -0
- data/docs/adr/004-mock-transport.md +16 -0
- data/docs/adr/005-error-taxonomy.md +16 -0
- data/docs/adr/006-stream-runtime.md +16 -0
- data/docs/ecosystem/BOUNDARIES.md +19 -0
- data/docs/ecosystem/DEPENDENCY_GRAPH.md +14 -0
- data/docs/ecosystem/DESIGN_PRINCIPLES.md +9 -0
- data/docs/ecosystem/EXISTING_REPOS.md +31 -0
- data/docs/ecosystem/EXPERIMENTAL_LABS.md +24 -0
- data/docs/ecosystem/OVERVIEW.md +28 -0
- data/docs/ecosystem/RELEASE_ORDER.md +17 -0
- data/docs/observability/README.md +8 -0
- data/docs/rails/README.md +7 -0
- data/docs/rfcs/0001-stream-runtime.md +6 -0
- data/docs/rfcs/0002-schema-system.md +6 -0
- data/docs/rfcs/0003-observability-hooks.md +6 -0
- data/docs/rfcs/0004-async-runtime.md +6 -0
- data/docs/rfcs/README.md +16 -0
- data/docs/runtime/ERROR_CONTRACT.md +14 -0
- data/docs/runtime/SCHEMA_CONTRACT.md +28 -0
- data/docs/runtime/STREAM_CONTRACT.md +17 -0
- data/docs/runtime/STREAM_RUNTIME.md +20 -0
- data/docs/runtime/TRANSPORT_CONTRACT.md +26 -0
- data/docs/schema/README.md +8 -0
- data/docs/schema/STRUCTURED_OUTPUTS.md +22 -0
- data/docs/streaming/README.md +8 -0
- data/docs/testing/README.md +7 -0
- data/docs/testing/REPLAY_SYSTEM.md +17 -0
- data/docs/transport/README.md +7 -0
- data/examples/README.md +44 -0
- data/examples/basic_chat.rb +9 -0
- data/examples/cloud_models.rb +162 -0
- data/examples/embeddings.rb +10 -0
- data/examples/free_catalog.json +290 -0
- data/examples/generate.rb +9 -0
- data/examples/streaming.rb +12 -0
- data/examples/structured_tools.rb +90 -0
- data/examples/tool_calling_direct.rb +101 -0
- data/examples/tool_dto_example.rb +94 -0
- data/exe/ollama-client +5 -1
- data/lib/ollama/agent/executor.rb +243 -0
- data/lib/ollama/agent/messages.rb +31 -0
- data/lib/ollama/agent/planner.rb +45 -0
- data/lib/ollama/api_key_pool.rb +61 -0
- data/lib/ollama/attachment.rb +74 -0
- data/lib/ollama/capabilities.rb +1 -1
- data/lib/ollama/chat_response.rb +33 -0
- data/lib/ollama/client/chat/request_preparer.rb +82 -0
- data/lib/ollama/client/chat.rb +58 -68
- data/lib/ollama/client/chat_stream_processor.rb +85 -25
- data/lib/ollama/client/generate/request_preparer.rb +118 -0
- data/lib/ollama/client/generate/response_formatter.rb +95 -0
- data/lib/ollama/client/generate.rb +83 -165
- data/lib/ollama/client/model_management.rb +182 -84
- data/lib/ollama/client/openai_compat.rb +185 -0
- data/lib/ollama/client/raw.rb +66 -0
- data/lib/ollama/client/tool_intent.rb +38 -0
- data/lib/ollama/client/web_search.rb +39 -0
- data/lib/ollama/client.rb +83 -35
- data/lib/ollama/config.rb +122 -17
- data/lib/ollama/embeddings.rb +67 -29
- data/lib/ollama/errors.rb +55 -1
- data/lib/ollama/events.rb +55 -0
- data/lib/ollama/generate_stream_handler.rb +23 -4
- data/lib/ollama/http_error_handler.rb +42 -0
- data/lib/ollama/messages.rb +109 -0
- data/lib/ollama/middleware/cache.rb +73 -0
- data/lib/ollama/middleware/logger.rb +74 -0
- data/lib/ollama/middleware/metrics.rb +84 -0
- data/lib/ollama/middleware/tracing.rb +101 -0
- data/lib/ollama/middleware.rb +39 -0
- data/lib/ollama/model_profile.rb +1 -1
- data/lib/ollama/openai.rb +16 -0
- data/lib/ollama/options.rb +63 -1
- data/lib/ollama/params.rb +139 -0
- data/lib/ollama/parsers/base.rb +24 -0
- data/lib/ollama/parsers/chat.rb +22 -0
- data/lib/ollama/parsers/embeddings.rb +23 -0
- data/lib/ollama/parsers/generate.rb +38 -0
- data/lib/ollama/parsers/list_running.rb +15 -0
- data/lib/ollama/parsers/show_model.rb +14 -0
- data/lib/ollama/parsers/version.rb +15 -0
- data/lib/ollama/pipeline.rb +169 -0
- data/lib/ollama/plugins.rb +83 -0
- data/lib/ollama/policies/auto_pull.rb +69 -0
- data/lib/ollama/policies/base.rb +70 -0
- data/lib/ollama/policies/capability_validation.rb +88 -0
- data/lib/ollama/policies/fallback.rb +57 -0
- data/lib/ollama/policies/rate_limit.rb +115 -0
- data/lib/ollama/policies/repair_json.rb +137 -0
- data/lib/ollama/policies/retry/strategies/exponential.rb +27 -0
- data/lib/ollama/policies/retry/strategies/fixed.rb +27 -0
- data/lib/ollama/policies/retry/strategies/jitter.rb +30 -0
- data/lib/ollama/policies/retry/strategies/linear.rb +27 -0
- data/lib/ollama/policies/retry.rb +152 -0
- data/lib/ollama/policies/schema_repair.rb +180 -0
- data/lib/ollama/policies/timeout.rb +43 -0
- data/lib/ollama/policies.rb +24 -0
- data/lib/ollama/prompt.rb +86 -0
- data/lib/ollama/prompt_adapters/base.rb +3 -2
- data/lib/ollama/prompt_adapters/gemma4.rb +22 -14
- data/lib/ollama/prompts/tool_planner.rb +35 -0
- data/lib/ollama/providers/base.rb +70 -0
- data/lib/ollama/providers/llama_cpp.rb +131 -0
- data/lib/ollama/providers/ollama.rb +54 -0
- data/lib/ollama/providers/openai.rb +134 -0
- data/lib/ollama/providers.rb +28 -0
- data/lib/ollama/rate_limit_handler.rb +48 -0
- data/lib/ollama/request.rb +169 -0
- data/lib/ollama/response.rb +3 -2
- data/lib/ollama/responses/base.rb +11 -0
- data/lib/ollama/responses/chat.rb +11 -0
- data/lib/ollama/responses/embeddings.rb +14 -0
- data/lib/ollama/responses/generate.rb +22 -0
- data/lib/ollama/schema_dsl.rb +97 -0
- data/lib/ollama/schema_validator.rb +90 -53
- data/lib/ollama/schemas/tool_intent.json +15 -0
- data/lib/ollama/schemas/tool_intent.rb +16 -0
- data/lib/ollama/serializers/base.rb +44 -0
- data/lib/ollama/serializers/chat.rb +42 -0
- data/lib/ollama/serializers/embeddings.rb +36 -0
- data/lib/ollama/serializers/generate.rb +47 -0
- data/lib/ollama/streaming_observer.rb +22 -0
- data/lib/ollama/testing.rb +103 -0
- data/lib/ollama/tool/function/parameters/property.rb +72 -0
- data/lib/ollama/tool/function/parameters.rb +101 -0
- data/lib/ollama/tool/function.rb +78 -0
- data/lib/ollama/tool.rb +60 -0
- data/lib/ollama/tool_dsl.rb +93 -0
- data/lib/ollama/tool_intent.rb +19 -0
- data/lib/ollama/transport/base.rb +42 -0
- data/lib/ollama/transport/mock.rb +48 -0
- data/lib/ollama/transport/net_http.rb +76 -0
- data/lib/ollama/transport/request.rb +20 -0
- data/lib/ollama/transport/response.rb +41 -0
- data/lib/ollama/transport.rb +26 -0
- data/lib/ollama/version.rb +1 -1
- data/lib/ollama_client.rb +35 -0
- data/script/live_branch_smoke/chat_exercises.rb +232 -0
- data/script/live_branch_smoke/generation_exercises.rb +128 -0
- data/script/live_branch_smoke/model_exercises.rb +105 -0
- data/script/live_branch_smoke/utility_exercises.rb +375 -0
- data/script/live_branch_smoke.rb +159 -174
- data/test_all_features.rb +315 -0
- metadata +158 -24
- data/.cursor/.gitignore +0 -1
- data/RELEASE_NOTES_v0.2.6.md +0 -41
- data/devagent_proper.rb +0 -430
- data/docs/TESTING.md +0 -508
- data/examples/agent_loop.rb +0 -120
- data/examples/failure_modes/invalid_json_repair.rb +0 -42
- data/examples/production/rails_agent.rb +0 -62
- data/market.jpg +0 -0
- data/print_capabilities.rb +0 -20
- data/schema.json +0 -1
- data/test_tool.rb +0 -26
data/docs/API_GAPS.md
CHANGED
|
@@ -1,143 +1,20 @@
|
|
|
1
1
|
# Gaps: Ollama REST API vs ollama-client Gem
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
|
12
|
-
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
**API parameters:** `model`, `modelfile` (optional), `path` (optional), `stream`, `quantize`.
|
|
23
|
-
|
|
24
|
-
**Gem:** `create_model(model:, from:, system:, template:, license:, parameters:, messages:, quantize:, stream:)` and sends `from` (+ system, template, etc.) in the JSON body.
|
|
25
|
-
|
|
26
|
-
- The reference docs do not list `from`, `system`, or `template` as top-level create parameters; they describe passing **modelfile content** or a **path** to a Modelfile.
|
|
27
|
-
- If the Ollama server accepts `from` as a shorthand for a minimal modelfile, the gem may work but is undocumented in the official API.
|
|
28
|
-
- **Gaps:**
|
|
29
|
-
- No way to pass raw **modelfile** string (full Modelfile content).
|
|
30
|
-
- No way to pass **path** (path to a Modelfile on the server).
|
|
31
|
-
|
|
32
|
-
**Recommendation:** Add optional `modelfile:` and `path:` to `create_model`. If `modelfile` or `path` is present, use that; otherwise keep building from `from` + system/template for backward compatibility (and document that behavior).
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## 3. Pull β **Missing parameters**
|
|
37
|
-
|
|
38
|
-
**API parameters:** `model`, `stream` (optional), `insecure` (optional).
|
|
39
|
-
|
|
40
|
-
**Gem:** `pull(model_name)` β always sends `stream: false` and does not accept `insecure` or `stream`.
|
|
41
|
-
|
|
42
|
-
**Gaps:**
|
|
43
|
-
- No `insecure:` option (e.g. for pulling from a custom/self-hosted registry).
|
|
44
|
-
- No choice of streaming vs non-streaming; callers cannot get progress via stream.
|
|
45
|
-
|
|
46
|
-
**Recommendation:** Add `pull(model_name, stream: false, insecure: false)` and pass them through.
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## 4. Generate β **Context (conversational memory)**
|
|
51
|
-
|
|
52
|
-
**API:** `/api/generate` accepts optional `context` (from a previous response) and returns `context` in the response for use in the next request.
|
|
53
|
-
|
|
54
|
-
**Gem:** `generate` does not accept or return `context`. Multi-turn βmemoryβ is only via chat, not via generate.
|
|
55
|
-
|
|
56
|
-
**Gap:** No support for generate-side context for short conversational memory when using the generate endpoint.
|
|
57
|
-
|
|
58
|
-
**Recommendation:** Optional `context:` argument and returning `context` in metadata when `return_meta: true` (or a dedicated accessor) would align with the API.
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## 5. Generate / Chat β **Options coverage**
|
|
63
|
-
|
|
64
|
-
**API (Modelfile/options):** The docs list many options, including at least:
|
|
65
|
-
|
|
66
|
-
- `min_p`
|
|
67
|
-
- `penalize_newline`
|
|
68
|
-
- `repeat_last_n`
|
|
69
|
-
- `numa`
|
|
70
|
-
- `num_batch`
|
|
71
|
-
- `main_gpu`
|
|
72
|
-
- `low_vram`
|
|
73
|
-
- `vocab_only`
|
|
74
|
-
- `use_mmap`
|
|
75
|
-
- `use_mlock`
|
|
76
|
-
|
|
77
|
-
**Gem:** `Ollama::Options` supports: `temperature`, `top_p`, `top_k`, `num_ctx`, `repeat_penalty`, `seed`, `num_predict`, `stop`, `tfs_z`, `mirostat`, `mirostat_tau`, `mirostat_eta`, `num_gpu`, `num_thread`, `num_keep`, `typical_p`, `presence_penalty`, `frequency_penalty`.
|
|
78
|
-
|
|
79
|
-
**Gap:** Options such as `min_p`, `penalize_newline`, `repeat_last_n`, `numa`, `num_batch`, `main_gpu`, `low_vram`, `vocab_only`, `use_mmap`, `use_mlock` are not in the type-safe Options class. They can still be passed as a raw hash via `options:`, so behavior is only a **documentation/consistency** gap.
|
|
80
|
-
|
|
81
|
-
**Recommendation:** Either extend `Ollama::Options` with these keys (and document which are server-dependent) or explicitly document that arbitrary option hashes are allowed and list the known API options in the yardocs.
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## 6. Push β **Streaming behavior**
|
|
86
|
-
|
|
87
|
-
**API:** Supports `stream: true` (default) or `stream: false` with a single final JSON object.
|
|
88
|
-
|
|
89
|
-
**Gem:** `push_model(model:, insecure: false, stream: false)` β implements both parameters. When `stream: true`, the current implementation uses a single `http_request` and `JSON.parse(res.body)`, which is wrong for streaming NDJSON.
|
|
90
|
-
|
|
91
|
-
**Gap:** For `stream: true`, the gem would need to read the response body as a stream (NDJSON) and yield or return status updates, similar to pull/generate streaming. Currently only non-streaming push is correct.
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## 7. Pull β **Streaming behavior**
|
|
96
|
-
|
|
97
|
-
**API:** Pull can stream progress (default) or return a single object when `stream: false`.
|
|
98
|
-
|
|
99
|
-
**Gem:** Always sends `stream: false` and parses a single JSON object. No streaming pull.
|
|
100
|
-
|
|
101
|
-
**Gap:** No API to get pull progress (e.g. status, digest, total, completed) via streaming. This is a **feature** gap, not a wrong-call gap.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## 8. Chat β **Tool message role**
|
|
106
|
-
|
|
107
|
-
**API:** Message object may have `role`: `system` | `user` | `assistant` | `tool`. Tool results are sent as messages with `role: "tool"`.
|
|
108
|
-
|
|
109
|
-
**Gem:** Response wrapper and tool_calls handling are in place; no gap identified for normal tool use. If the client ever needs to **send** tool results back (e.g. in a follow-up request), the message format with `role: "tool"` should be documented or helpers provided. Not a missing endpoint, but worth documenting for agent loops.
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## 9. Embeddings β **Legacy endpoint**
|
|
114
|
-
|
|
115
|
-
**API:** Documents both `/api/embed` (current) and `/api/embeddings` (superseded).
|
|
116
|
-
|
|
117
|
-
**Gem:** Uses `/api/embed` only. No gap.
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## 10. Load / Unload model (explicit)
|
|
122
|
-
|
|
123
|
-
**API:** Describes loading by calling generate/chat with empty prompt (and optional `keep_alive`), and unload with empty prompt + `keep_alive: 0`.
|
|
124
|
-
|
|
125
|
-
**Gem:** No dedicated `load_model` or `unload_model` helpers. Callers can do the same by calling `generate(prompt: "", ...)` or `chat(messages: [], ...)` with `keep_alive`.
|
|
126
|
-
|
|
127
|
-
**Gap:** Convenience only β optional helpers could reduce confusion and document the pattern.
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## Summary table
|
|
132
|
-
|
|
133
|
-
| Area | Severity | Gap |
|
|
134
|
-
|-------------------|------------|-----|
|
|
135
|
-
| Blob API | High | HEAD/POST blobs not implemented |
|
|
136
|
-
| Create model | Medium | No raw `modelfile` or `path`; uses `from` only |
|
|
137
|
-
| Pull | Medium | No `insecure` or `stream`; no streaming progress |
|
|
138
|
-
| Push | Low | `stream: true` not implemented as real streaming |
|
|
139
|
-
| Generate context | Low | No `context` in/out for conversational memory |
|
|
140
|
-
| Options | Low | Several Modelfile options not in `Ollama::Options` |
|
|
141
|
-
| Load/Unload | Optional | No convenience methods for load/unload |
|
|
142
|
-
|
|
143
|
-
Implementing **Blob API** and **Create model (modelfile/path)** would fully align the gem with the documented API for model creation. **Pull (insecure + stream)** and **Generate context** are the next most useful for parity and agent use cases.
|
|
3
|
+
Original comparison against the [Ollama API Reference](https://ollama.readthedocs.io/en/api/). All 10
|
|
4
|
+
items identified below have since been closed. This file is kept for history; the actively maintained
|
|
5
|
+
gap tracker is [`docs/RUBYLLM_ADOPTION_MATRIX.md`](RUBYLLM_ADOPTION_MATRIX.md) section K.
|
|
6
|
+
|
|
7
|
+
| # | Area | Original gap | Status |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| 1 | Blob API | No `blob_exists?`/`create_blob` | **Resolved** β `Client::ModelManagement#blob_exists?(digest:)`, `#create_blob(digest:, content:)` |
|
|
10
|
+
| 2 | Create model | No raw `modelfile`/`path` | **Resolved** β `create_model(model:, from:, modelfile:, path:, ...)` |
|
|
11
|
+
| 3 | Pull | No `insecure`/`stream` | **Resolved** β `pull(model_name, insecure:, stream:, hooks:)` |
|
|
12
|
+
| 4 | Generate context | No `context` in/out | **Resolved** β `generate(prompt:, context:, ...)`, context returned via `return_meta:` |
|
|
13
|
+
| 5 | Options coverage | Missing `min_p`, `penalize_newline`, `repeat_last_n`, `numa`, `num_batch`, `main_gpu`, `low_vram`, `vocab_only`, `use_mmap`, `use_mlock` | **Resolved** β all present on `Ollama::Options` |
|
|
14
|
+
| 6 | Push streaming | `stream: true` not real NDJSON streaming | **Resolved** β `push_model` streams via `handle_ndjson_stream` + `hooks[:on_progress]` |
|
|
15
|
+
| 7 | Pull streaming | No streaming progress | **Resolved** β same mechanism as push |
|
|
16
|
+
| 8 | Tool message role | No `role: "tool"` helper for follow-up requests | **Resolved** β `Ollama::Agent::Messages#tool_result` (`lib/ollama/agent/messages.rb`) |
|
|
17
|
+
| 9 | Embeddings legacy endpoint | n/a | No gap β `/api/embed` is the current documented endpoint; `/api/embeddings` is Ollama's deprecated alias |
|
|
18
|
+
| 10 | Load/unload convenience | No dedicated helpers | **Resolved** β `load_model(model:, keep_alive:)`, `unload_model(model:)` |
|
|
19
|
+
|
|
20
|
+
See `API_CONTRACT.md` for the current signatures of all methods above.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# ollama-client Architecture
|
|
2
|
+
|
|
3
|
+
This document specifies the frozen v1 architecture design of `ollama-client`.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
ollama-client
|
|
7
|
+
β
|
|
8
|
+
βββ Config
|
|
9
|
+
βββ Request
|
|
10
|
+
βββ Response
|
|
11
|
+
βββ Errors
|
|
12
|
+
β
|
|
13
|
+
βββ Transport
|
|
14
|
+
β βββ HTTP
|
|
15
|
+
β βββ Mock
|
|
16
|
+
β βββ Streaming
|
|
17
|
+
β
|
|
18
|
+
βββ Middleware
|
|
19
|
+
β βββ Logger
|
|
20
|
+
β βββ Metrics
|
|
21
|
+
β βββ Cache
|
|
22
|
+
β βββ Tracing
|
|
23
|
+
β βββ Base
|
|
24
|
+
β
|
|
25
|
+
βββ Policies
|
|
26
|
+
β βββ Retry
|
|
27
|
+
β βββ AutoPull
|
|
28
|
+
β βββ RepairJson
|
|
29
|
+
β βββ SchemaRepair
|
|
30
|
+
β βββ CapabilityValidation
|
|
31
|
+
β βββ RateLimit
|
|
32
|
+
β
|
|
33
|
+
βββ Core
|
|
34
|
+
β βββ Chat
|
|
35
|
+
β βββ Generate
|
|
36
|
+
β βββ Embeddings
|
|
37
|
+
β βββ Models
|
|
38
|
+
β βββ Version
|
|
39
|
+
β
|
|
40
|
+
βββ Ruby
|
|
41
|
+
β βββ Messages
|
|
42
|
+
β βββ Tool
|
|
43
|
+
β βββ Schema
|
|
44
|
+
β βββ TypedResponses
|
|
45
|
+
β βββ Streaming
|
|
46
|
+
β βββ Testing
|
|
47
|
+
β
|
|
48
|
+
βββ Plugins
|
|
49
|
+
β
|
|
50
|
+
βββ Rails (optional)
|
|
51
|
+
β
|
|
52
|
+
βββ Compliance Tests
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 1. Request/Response Pipeline Design
|
|
58
|
+
|
|
59
|
+
All lifecycle hooks, logging, retries, and errors run inside a single composable pipeline of middleware:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
Request
|
|
63
|
+
β
|
|
64
|
+
βΌ
|
|
65
|
+
Middleware (Logger / Caching)
|
|
66
|
+
β
|
|
67
|
+
βΌ
|
|
68
|
+
Policies (Retry / AutoPull / JsonRepair)
|
|
69
|
+
β
|
|
70
|
+
βΌ
|
|
71
|
+
Transport Terminal (HTTP / Mock)
|
|
72
|
+
β
|
|
73
|
+
βΌ
|
|
74
|
+
Response
|
|
75
|
+
β
|
|
76
|
+
βΌ
|
|
77
|
+
Typed Objects
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Composable Middleware Stack
|
|
81
|
+
|
|
82
|
+
Every middleware implements the following Rack/Faraday-style interface:
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
class Base
|
|
86
|
+
def initialize(app, **options)
|
|
87
|
+
@app = app
|
|
88
|
+
@options = options
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def call(request)
|
|
92
|
+
@app.call(request)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 2. Core Abstractions
|
|
100
|
+
|
|
101
|
+
### Request Object
|
|
102
|
+
|
|
103
|
+
An immutable container for all request parameters, keeping core logic completely decoupled from HTTP adapters or JSON payloads.
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
class Request
|
|
107
|
+
attr_reader :endpoint, :model, :messages, :prompt, :images, :tools, :schema, :options, :stream
|
|
108
|
+
|
|
109
|
+
def initialize(endpoint:, **args)
|
|
110
|
+
@endpoint = endpoint
|
|
111
|
+
@model = args[:model]
|
|
112
|
+
@messages = args[:messages]
|
|
113
|
+
@prompt = args[:prompt]
|
|
114
|
+
@images = args[:images]
|
|
115
|
+
@tools = args[:tools]
|
|
116
|
+
@schema = args[:schema]
|
|
117
|
+
@options = args[:options] || {}
|
|
118
|
+
@stream = args[:stream]
|
|
119
|
+
freeze
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def streaming?
|
|
123
|
+
hooks = @options[:hooks]
|
|
124
|
+
(hooks && !hooks.empty?) || @stream == true
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Response Object
|
|
130
|
+
|
|
131
|
+
Typed accessors wrapping LLM returns instead of raw HTTP hashes:
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
response.message.content
|
|
135
|
+
response.done?
|
|
136
|
+
response.total_duration
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Policies Namespace
|
|
140
|
+
|
|
141
|
+
All recovery policies (AutoPull, Retry, RepairJson) live in the `Ollama::Policies` plural namespace for consistency.
|
|
@@ -20,6 +20,7 @@ This document addresses three key areas that warrant attention in the `ollama-cl
|
|
|
20
20
|
### Responsibilities
|
|
21
21
|
|
|
22
22
|
The `Client` class currently handles:
|
|
23
|
+
|
|
23
24
|
1. HTTP communication with Ollama API
|
|
24
25
|
2. JSON parsing and validation
|
|
25
26
|
3. Schema validation
|
|
@@ -65,12 +66,14 @@ end
|
|
|
65
66
|
```
|
|
66
67
|
|
|
67
68
|
**Benefits:**
|
|
69
|
+
|
|
68
70
|
- Single Responsibility Principle
|
|
69
71
|
- Easier to test
|
|
70
72
|
- Easier to maintain
|
|
71
73
|
- Can enable RuboCop metrics
|
|
72
74
|
|
|
73
75
|
**Trade-offs:**
|
|
76
|
+
|
|
74
77
|
- More files to navigate
|
|
75
78
|
- Slightly more complex initialization
|
|
76
79
|
|
|
@@ -88,23 +91,27 @@ end
|
|
|
88
91
|
```
|
|
89
92
|
|
|
90
93
|
**Benefits:**
|
|
94
|
+
|
|
91
95
|
- Still one file
|
|
92
96
|
- Better organization
|
|
93
97
|
- Can test modules independently
|
|
94
98
|
|
|
95
99
|
**Trade-offs:**
|
|
100
|
+
|
|
96
101
|
- Still a large file
|
|
97
102
|
- RuboCop metrics still problematic
|
|
98
103
|
|
|
99
104
|
#### Option C: Accept Complexity (Current State)
|
|
100
105
|
|
|
101
106
|
**Rationale:**
|
|
107
|
+
|
|
102
108
|
- Client is the core API surface
|
|
103
109
|
- All methods are public API
|
|
104
110
|
- Breaking it up might make usage more complex
|
|
105
111
|
- Current structure is functional
|
|
106
112
|
|
|
107
113
|
**Action Items:**
|
|
114
|
+
|
|
108
115
|
- Document why metrics are disabled
|
|
109
116
|
- Add architectural decision record (ADR)
|
|
110
117
|
- Consider refactoring in future major version
|
|
@@ -122,6 +129,7 @@ end
|
|
|
122
129
|
### Current State
|
|
123
130
|
|
|
124
131
|
**Global Configuration:**
|
|
132
|
+
|
|
125
133
|
```ruby
|
|
126
134
|
module OllamaClient
|
|
127
135
|
@config_mutex = Mutex.new
|
|
@@ -136,6 +144,7 @@ end
|
|
|
136
144
|
```
|
|
137
145
|
|
|
138
146
|
**Issues:**
|
|
147
|
+
|
|
139
148
|
1. Mutex protects global config access, but warning says "not thread-safe"
|
|
140
149
|
2. Confusing messaging - mutex IS present but warning suggests it's not safe
|
|
141
150
|
3. Per-client config is recommended but not enforced
|
|
@@ -143,11 +152,13 @@ end
|
|
|
143
152
|
### Analysis
|
|
144
153
|
|
|
145
154
|
**What's Actually Thread-Safe:**
|
|
155
|
+
|
|
146
156
|
- β
Global config access (protected by mutex)
|
|
147
157
|
- β
Per-client instances (each has own config)
|
|
148
158
|
- β
Client methods (stateless, use instance config)
|
|
149
159
|
|
|
150
160
|
**What's NOT Thread-Safe:**
|
|
161
|
+
|
|
151
162
|
- β οΈ Modifying global config while clients are using it
|
|
152
163
|
- β οΈ Shared config objects between threads (if mutated)
|
|
153
164
|
|
|
@@ -270,7 +281,7 @@ Need structured output?
|
|
|
270
281
|
```ruby
|
|
271
282
|
# High-level API for beginners
|
|
272
283
|
class SimpleAgent
|
|
273
|
-
def initialize(model: "
|
|
284
|
+
def initialize(model: "qwen3.5:4b")
|
|
274
285
|
@client = Ollama::Client.new
|
|
275
286
|
@model = model
|
|
276
287
|
end
|
|
@@ -294,6 +305,7 @@ end
|
|
|
294
305
|
### Recommended Approach
|
|
295
306
|
|
|
296
307
|
**Immediate:**
|
|
308
|
+
|
|
297
309
|
1. Add "Quick Start" section to README (Option A)
|
|
298
310
|
2. Add decision tree diagram (Option B)
|
|
299
311
|
|
data/docs/CLOUD.md
CHANGED
|
@@ -27,3 +27,22 @@ Rules:
|
|
|
27
27
|
## Guardrails
|
|
28
28
|
- Keep API surface stable and backward compatible.
|
|
29
29
|
- Update specs when behavior changes.
|
|
30
|
+
|
|
31
|
+
## Ollama Cloud Model Accessibility
|
|
32
|
+
|
|
33
|
+
Ollama Cloud does not expose a `free` flag per model. The only reliable way to determine whether a model is accessible to your account is to attempt a tiny inference and observe the HTTP response.
|
|
34
|
+
|
|
35
|
+
The project includes a standalone example script that automates this:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
export OLLAMA_API_KEY="your-ollama-cloud-api-key"
|
|
39
|
+
bundle exec ruby examples/cloud_models.rb
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The script:
|
|
43
|
+
1. Fetches the public cloud model catalog from `https://ollama.com/api/tags`
|
|
44
|
+
2. Probes each model concurrently (10 threads) with a minimal chat request
|
|
45
|
+
3. Classifies the response into accessibility statuses (`accessible`, `unauthorized`, `plan_restricted`, `usage_limit`, `unavailable`, `rate_limited`, `timeout`, etc.)
|
|
46
|
+
4. Prints sorted JSON to stdout
|
|
47
|
+
|
|
48
|
+
See [`examples/cloud_models.rb`](../examples/cloud_models.rb) for the full implementation and [`examples/README.md`](../examples/README.md) for usage details.
|
|
@@ -15,6 +15,7 @@ When the LLM was processing a response, the `llm>` prompt appeared immediately,
|
|
|
15
15
|
Added a **thinking indicator** that shows while waiting for the API response:
|
|
16
16
|
|
|
17
17
|
**Before:**
|
|
18
|
+
|
|
18
19
|
```
|
|
19
20
|
you> Hi
|
|
20
21
|
llm> [cursor blinks here - looks like a prompt!]
|
|
@@ -23,6 +24,7 @@ llm> [cursor blinks here - looks like a prompt!]
|
|
|
23
24
|
```
|
|
24
25
|
|
|
25
26
|
**After:**
|
|
27
|
+
|
|
26
28
|
```
|
|
27
29
|
you> Hi
|
|
28
30
|
... [thinking indicator in cyan]
|
|
@@ -62,6 +64,7 @@ end
|
|
|
62
64
|
```
|
|
63
65
|
|
|
64
66
|
**Key Changes:**
|
|
67
|
+
|
|
65
68
|
- `\r` (carriage return) replaces `...` with `llm>` when first token arrives
|
|
66
69
|
- `$stdout.flush` ensures immediate visual feedback
|
|
67
70
|
- Clear visual state: thinking β responding β ready for input
|
|
@@ -71,11 +74,13 @@ end
|
|
|
71
74
|
### Problem
|
|
72
75
|
|
|
73
76
|
Tool results were displayed as raw JSON dumps, making it hard to quickly understand:
|
|
77
|
+
|
|
74
78
|
- **Which tool** was called
|
|
75
79
|
- **What data** was retrieved
|
|
76
80
|
- **Key information** from the response
|
|
77
81
|
|
|
78
82
|
**Before:**
|
|
83
|
+
|
|
79
84
|
```
|
|
80
85
|
Tool Results:
|
|
81
86
|
- get_live_ltp
|
|
@@ -103,6 +108,7 @@ Tool Results:
|
|
|
103
108
|
Implemented **formatted, human-readable tool results** that extract and display key information:
|
|
104
109
|
|
|
105
110
|
**After:**
|
|
111
|
+
|
|
106
112
|
```
|
|
107
113
|
π§ Tool Called: get_live_ltp
|
|
108
114
|
β NIFTY (IDX_I)
|
|
@@ -114,6 +120,7 @@ llm> The current price of NIFTY is 25694.35.
|
|
|
114
120
|
### Formatted Output by Tool
|
|
115
121
|
|
|
116
122
|
#### 1. Live LTP (`get_live_ltp`)
|
|
123
|
+
|
|
117
124
|
```
|
|
118
125
|
π§ Tool Called: get_live_ltp
|
|
119
126
|
β NIFTY (IDX_I)
|
|
@@ -121,6 +128,7 @@ llm> The current price of NIFTY is 25694.35.
|
|
|
121
128
|
```
|
|
122
129
|
|
|
123
130
|
#### 2. Market Quote (`get_market_quote`)
|
|
131
|
+
|
|
124
132
|
```
|
|
125
133
|
π§ Tool Called: get_market_quote
|
|
126
134
|
β RELIANCE
|
|
@@ -132,6 +140,7 @@ llm> The current price of NIFTY is 25694.35.
|
|
|
132
140
|
#### 3. Historical Data (`get_historical_data`)
|
|
133
141
|
|
|
134
142
|
**Regular data:**
|
|
143
|
+
|
|
135
144
|
```
|
|
136
145
|
π§ Tool Called: get_historical_data
|
|
137
146
|
β Historical data: 30 records
|
|
@@ -139,6 +148,7 @@ llm> The current price of NIFTY is 25694.35.
|
|
|
139
148
|
```
|
|
140
149
|
|
|
141
150
|
**With indicators:**
|
|
151
|
+
|
|
142
152
|
```
|
|
143
153
|
π§ Tool Called: get_historical_data
|
|
144
154
|
β Technical Indicators:
|
|
@@ -150,6 +160,7 @@ llm> The current price of NIFTY is 25694.35.
|
|
|
150
160
|
```
|
|
151
161
|
|
|
152
162
|
#### 4. Option Chain (`get_option_chain`)
|
|
163
|
+
|
|
153
164
|
```
|
|
154
165
|
π§ Tool Called: get_option_chain
|
|
155
166
|
β Spot: βΉ25694.35
|
|
@@ -158,6 +169,7 @@ llm> The current price of NIFTY is 25694.35.
|
|
|
158
169
|
```
|
|
159
170
|
|
|
160
171
|
#### 5. Expiry List (`get_expiry_list`)
|
|
172
|
+
|
|
161
173
|
```
|
|
162
174
|
π§ Tool Called: get_expiry_list
|
|
163
175
|
β Available expiries: 12
|
|
@@ -166,6 +178,7 @@ llm> The current price of NIFTY is 25694.35.
|
|
|
166
178
|
```
|
|
167
179
|
|
|
168
180
|
#### 6. Find Instrument (`find_instrument`)
|
|
181
|
+
|
|
169
182
|
```
|
|
170
183
|
π§ Tool Called: find_instrument
|
|
171
184
|
β Found: NIFTY
|
|
@@ -192,6 +205,7 @@ end
|
|
|
192
205
|
```
|
|
193
206
|
|
|
194
207
|
Each tool has a dedicated formatter that:
|
|
208
|
+
|
|
195
209
|
1. Extracts key information from the result
|
|
196
210
|
2. Formats it in a human-readable way
|
|
197
211
|
3. Uses color coding for better readability
|
|
@@ -200,11 +214,13 @@ Each tool has a dedicated formatter that:
|
|
|
200
214
|
## Benefits
|
|
201
215
|
|
|
202
216
|
### Chat Console
|
|
217
|
+
|
|
203
218
|
β
**Clear visual feedback** - Users know when the LLM is thinking vs responding
|
|
204
219
|
β
**No confusion** - Thinking indicator prevents accidental typing
|
|
205
220
|
β
**Better UX** - Immediate response to user input
|
|
206
221
|
|
|
207
222
|
### DhanHQ Console
|
|
223
|
+
|
|
208
224
|
β
**Instant comprehension** - See what tool was called at a glance
|
|
209
225
|
β
**Key data highlighted** - Important values (price, volume) are prominent
|
|
210
226
|
β
**Less noise** - No JSON clutter, just the facts
|
|
@@ -216,14 +232,16 @@ Each tool has a dedicated formatter that:
|
|
|
216
232
|
Both consoles support environment variables:
|
|
217
233
|
|
|
218
234
|
**Chat Console:**
|
|
235
|
+
|
|
219
236
|
```bash
|
|
220
237
|
OLLAMA_BASE_URL=http://localhost:11434
|
|
221
|
-
OLLAMA_MODEL=
|
|
238
|
+
OLLAMA_MODEL=qwen3.5:4b
|
|
222
239
|
OLLAMA_TEMPERATURE=0.7
|
|
223
240
|
OLLAMA_SYSTEM="You are a helpful assistant"
|
|
224
241
|
```
|
|
225
242
|
|
|
226
243
|
**DhanHQ Console:**
|
|
244
|
+
|
|
227
245
|
```bash
|
|
228
246
|
# All chat console vars, plus:
|
|
229
247
|
DHANHQ_CLIENT_ID=your_client_id
|
|
@@ -243,6 +261,7 @@ ruby examples/dhan_console.rb
|
|
|
243
261
|
```
|
|
244
262
|
|
|
245
263
|
Try queries like:
|
|
264
|
+
|
|
246
265
|
- "What is NIFTY price?" β See formatted LTP
|
|
247
266
|
- "Get RELIANCE quote" β See formatted quote with OHLC
|
|
248
267
|
- "Show me historical data for NIFTY" β See record count
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Ollama Ruby Ecosystem Blueprint
|
|
2
|
+
|
|
3
|
+
This repository remains the deterministic core runtime (`ollama-client`).
|
|
4
|
+
|
|
5
|
+
## Proposed Gem Split
|
|
6
|
+
|
|
7
|
+
- `ollama-client` (core): transport, retries, schema enforcement, model lifecycle, raw endpoint access, OpenAI facade.
|
|
8
|
+
- `ollama-openai`: standalone OpenAI protocol adapter for external OpenAI SDK consumers (currently provided as an optional extension via `require "ollama/openai"` as an interim step).
|
|
9
|
+
- `ollama-stream`: advanced streaming runtime (SSE object model, resumable streams, WS relay, backpressure primitives).
|
|
10
|
+
- `ollama-observability`: OpenTelemetry spans, metrics, token accounting, structured log emitters.
|
|
11
|
+
- `ollama-agent`: optional orchestration layer (tool runtime, memory, planners) kept separate from core transport.
|
|
12
|
+
|
|
13
|
+
## Gem Scaffolding Checklist
|
|
14
|
+
|
|
15
|
+
For each new gem:
|
|
16
|
+
|
|
17
|
+
1. `bundle gem <name> --mit --test=rspec --ci=github`
|
|
18
|
+
2. Add `README.md` with:
|
|
19
|
+
- scope boundaries
|
|
20
|
+
- compatibility matrix
|
|
21
|
+
- migration guide
|
|
22
|
+
3. Add `sig/` RBS contracts for public APIs.
|
|
23
|
+
4. Add integration tests against local Ollama.
|
|
24
|
+
5. Publish with independent semver and changelog.
|
|
25
|
+
|
|
26
|
+
## Suggested Release Order
|
|
27
|
+
|
|
28
|
+
1. `ollama-openai` (highest interoperability impact)
|
|
29
|
+
2. `ollama-observability`
|
|
30
|
+
3. `ollama-stream`
|
|
31
|
+
4. `ollama-agent`
|
|
32
|
+
|
|
33
|
+
## Non-Goals for Core
|
|
34
|
+
|
|
35
|
+
Core should not include:
|
|
36
|
+
|
|
37
|
+
- vector DB abstractions
|
|
38
|
+
- prompt-chain DSLs
|
|
39
|
+
- opaque βmagicβ agent workflows
|
|
40
|
+
|
|
41
|
+
Keep core deterministic and infra-grade.
|