elelem-ollama 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed18986dc0288ed968cbfacfec76a970d8ff096df3ebc3ca8e7f0d72c9128c5e
4
- data.tar.gz: ba32c8f12ae8c4bda87cab6de6c7aa09d390ac38608d1e45a4c5624ddf18bca9
3
+ metadata.gz: 103d5e51990858afaab14fe8042a85b0a05517e2896535677b29adbd60e861d7
4
+ data.tar.gz: c45b6f097c19dfb9515c80a4ff742a190b8d950ca414ae6d3be071171f6ffd99
5
5
  SHA512:
6
- metadata.gz: 7ebb2bdd4cd7cc9eb396f60007400c976976e8b0622f053395e852c25023906003ae6d815678998d7d994b59daea68653aa75fed47784b2b1b13aeaf372a48c7
7
- data.tar.gz: f9e679d352b8bc01268e7cee6c09af48b6974db4781b650ba369467a4a974b1903081273730551658fb697157d70c873b223140e10edd696ea9a7cd64ece0e5a
6
+ metadata.gz: bc6342db3a78a8cc206f2547b88b9af13eeb0ee146ba8d7dd1698695839559cdba5292e45894ceb916fc6978cc19735535078713bcd2032b0d9b2f16e602a31e
7
+ data.tar.gz: 61560a4fd4857899427828c20b9121ff7f0237b98f652d1b32b3612056f7b8451282251051a0d75794bb3b268d22bb9a3f92c8287f5147fba4b829e3611ff064
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/Rakefile CHANGED
@@ -1,4 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- task default: %i[]
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: %i[spec]
@@ -6,12 +6,13 @@ module Elelem
6
6
  def initialize(
7
7
  model:,
8
8
  host: "localhost:11434",
9
- think: false,
10
- keep_alive: "5m",
9
+ think: nil,
10
+ keep_alive: nil,
11
11
  options: {},
12
12
  params: {},
13
13
  read_timeout: 3600,
14
- open_timeout: 10
14
+ open_timeout: 10,
15
+ http: nil
15
16
  )
16
17
  @uri = normalize_uri(host)
17
18
  @model = model
@@ -21,6 +22,7 @@ module Elelem
21
22
  @params = params
22
23
  @read_timeout = read_timeout
23
24
  @open_timeout = open_timeout
25
+ @http = http
24
26
  end
25
27
 
26
28
  def fetch(messages, tools = [], &block)
@@ -103,24 +105,17 @@ module Elelem
103
105
  end
104
106
 
105
107
  def stream(body)
106
- request = Net::HTTP::Post.new(@uri)
107
- request["content-type"] = "application/json"
108
- request.body = JSON.generate(body)
108
+ http.post(@uri, body: body) do |response|
109
+ raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
109
110
 
110
- http = Net::HTTP.new(@uri.host, @uri.port)
111
- http.use_ssl = @uri.scheme == "https"
112
- http.read_timeout = @read_timeout
113
- http.open_timeout = @open_timeout
114
-
115
- http.start do |conn|
116
- conn.request(request) do |response|
117
- raise "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
118
-
119
- read_ndjson_stream(response) { |event| yield event }
120
- end
111
+ read_ndjson_stream(response) { |event| yield event }
121
112
  end
122
113
  end
123
114
 
115
+ def http
116
+ @http ||= HttpAdapter.new(read_timeout: @read_timeout, open_timeout: @open_timeout)
117
+ end
118
+
124
119
  def read_ndjson_stream(response)
125
120
  buffer = String.new
126
121
 
@@ -145,6 +140,28 @@ module Elelem
145
140
  }
146
141
  end
147
142
  end
143
+
144
+ class HttpAdapter
145
+ def initialize(read_timeout:, open_timeout:)
146
+ @read_timeout = read_timeout
147
+ @open_timeout = open_timeout
148
+ end
149
+
150
+ def post(uri, body:)
151
+ request = Net::HTTP::Post.new(uri)
152
+ request["content-type"] = "application/json"
153
+ request.body = JSON.generate(body)
154
+
155
+ http = Net::HTTP.new(uri.host, uri.port)
156
+ http.use_ssl = uri.scheme == "https"
157
+ http.read_timeout = @read_timeout
158
+ http.open_timeout = @open_timeout
159
+
160
+ http.start do |conn|
161
+ conn.request(request) { |response| yield response }
162
+ end
163
+ end
164
+ end
148
165
  end
149
166
  end
150
167
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Elelem
4
4
  module Ollama
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
data/lib/elelem/ollama.rb CHANGED
@@ -8,9 +8,13 @@ require "uri"
8
8
  require_relative "ollama/version"
9
9
  require_relative "ollama/client"
10
10
 
11
- Elelem::Providers.register(:ollama) do
12
- Elelem::Ollama::Client.new(
13
- model: ENV.fetch("OLLAMA_MODEL", "gpt-oss:latest"),
14
- host: ENV.fetch("OLLAMA_HOST", "localhost:11434")
15
- )
11
+ Elelem.configure do |config|
12
+ config.provider(:ollama) do
13
+ Elelem::Ollama::Client.new(
14
+ model: ENV.fetch("OLLAMA_MODEL", "gpt-oss:latest"),
15
+ host: ENV.fetch("OLLAMA_HOST", "localhost:11434"),
16
+ think: ENV["OLLAMA_THINK"],
17
+ keep_alive: ENV["OLLAMA_KEEP_ALIVE"]
18
+ )
19
+ end
16
20
  end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Elelem::Ollama::Client do
4
+ subject(:client) { described_class.new(model: "gpt-oss:latest", http:, **params) }
5
+
6
+ let(:params) { {} }
7
+ let(:messages) { [{ role: "user", content: "hi" }] }
8
+ let(:body) { http.body }
9
+
10
+ let(:response) do
11
+ ::Net::HTTPOK.new("1.1", "200", "OK").tap do |it|
12
+ allow(it).to receive(:read_body).and_yield(%({"done":true,"message":{}}\n))
13
+ end
14
+ end
15
+
16
+ let(:http) do
17
+ Class.new do
18
+ attr_reader :body
19
+
20
+ def initialize(response)
21
+ @response = response
22
+ end
23
+
24
+ def post(_url, body:)
25
+ @body = body
26
+ yield @response
27
+ end
28
+ end.new(response)
29
+ end
30
+
31
+ describe "#fetch" do
32
+ it "sends only model, messages and stream by default" do
33
+ client.fetch(messages) { }
34
+
35
+ expect(body).to eq(model: "gpt-oss:latest", messages:, stream: true)
36
+ end
37
+
38
+ it "sends tools when present" do
39
+ tools = [{ type: "function", function: { name: "read" } }]
40
+
41
+ client.fetch(messages, tools) { }
42
+
43
+ expect(body[:tools]).to eq(tools)
44
+ end
45
+
46
+ context "with tuning keywords" do
47
+ let(:params) { { think: "high", keep_alive: "30m", options: { num_ctx: 32_768 } } }
48
+
49
+ it "sends them in the request body" do
50
+ client.fetch(messages) { }
51
+
52
+ expect(body).to include(think: "high", keep_alive: "30m", options: { num_ctx: 32_768 })
53
+ end
54
+ end
55
+
56
+ context "with an empty options hash" do
57
+ let(:params) { { options: {} } }
58
+
59
+ it "omits options" do
60
+ client.fetch(messages) { }
61
+
62
+ expect(body).not_to have_key(:options)
63
+ end
64
+ end
65
+
66
+ context "with passthrough params" do
67
+ let(:params) { { params: { format: "json", truncate: false, top_logprobs: 3 } } }
68
+
69
+ it "merges them into the request body" do
70
+ client.fetch(messages) { }
71
+
72
+ expect(body).to include(format: "json", truncate: false, top_logprobs: 3)
73
+ end
74
+ end
75
+
76
+ context "with a passthrough param that collides with a keyword" do
77
+ let(:params) { { think: "low", params: { think: "high" } } }
78
+
79
+ it "prefers the passthrough value" do
80
+ client.fetch(messages) { }
81
+
82
+ expect(body[:think]).to eq("high")
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../lib/elelem/ollama"
4
+
5
+ RSpec.configure do |config|
6
+ config.disable_monkey_patching!
7
+
8
+ config.expect_with :rspec do |c|
9
+ c.syntax = :expect
10
+ end
11
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elelem-ollama
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - mo khan
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '0.10'
18
+ version: '0.11'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '0.10'
25
+ version: '0.11'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: json
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '2.21'
32
+ version: '3.0'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '2.21'
39
+ version: '3.0'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: net-http
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -73,12 +73,15 @@ executables:
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
+ - ".rspec"
76
77
  - LICENSE.txt
77
78
  - Rakefile
78
79
  - exe/elelem-ollama
79
80
  - lib/elelem/ollama.rb
80
81
  - lib/elelem/ollama/client.rb
81
82
  - lib/elelem/ollama/version.rb
83
+ - spec/elelem/ollama/client_spec.rb
84
+ - spec/spec_helper.rb
82
85
  homepage: https://src.mokhan.ca/elelem/ollama
83
86
  licenses:
84
87
  - MIT