ollama-ruby 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,121 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Documents::RedisCache do
4
- let :prefix do
5
- 'test-'
6
- end
7
-
8
- let :cache do
9
- described_class.new prefix:, url: 'something'
10
- end
11
-
12
- it 'can be instantiated' do
13
- expect(cache).to be_a described_class
14
- end
15
-
16
- it 'defaults to nil object_class' do
17
- expect(cache.object_class).to be_nil
18
- end
19
-
20
- it 'can be configured with object_class' do
21
- object_class = Class.new(JSON::GenericObject)
22
- cache = described_class.new(prefix:, url: 'something', object_class:)
23
- expect(cache.object_class).to eq object_class
24
- end
25
-
26
- it 'raises ArgumentError if url is missing' do
27
- expect {
28
- described_class.new prefix:, url: nil
29
- }.to raise_error ArgumentError
30
- end
31
-
32
- context 'test redis interactions' do
33
- let :redis do
34
- double('Redis')
35
- end
36
-
37
- before do
38
- allow_any_instance_of(described_class).to receive(:redis).and_return(redis)
39
- end
40
-
41
- it 'has Redis client' do
42
- expect(cache.redis).to eq redis
43
- end
44
-
45
- it 'can get a key' do
46
- key = 'foo'
47
- expect(redis).to receive(:get).with(prefix + key).and_return '"some_json"'
48
- expect(cache[key]).to eq 'some_json'
49
- end
50
-
51
- it 'can set a value for a key' do
52
- key, value = 'foo', { test: true }
53
- expect(redis).to receive(:set).with(prefix + key, JSON(value), ex: nil)
54
- cache[key] = value
55
- end
56
-
57
- it 'can set a value for a key with ttl' do
58
- cache = described_class.new prefix:, url: 'something', ex: 3_600
59
- key, value = 'foo', { test: true }
60
- expect(redis).to receive(:set).with(prefix + key, JSON(value), ex: 3_600)
61
- cache[key] = value
62
- expect(redis).to receive(:ttl).with(prefix + key).and_return 3_600
63
- expect(cache.ttl(key)).to eq 3_600
64
- end
65
-
66
- it 'can determine if key exists' do
67
- key = 'foo'
68
- expect(redis).to receive(:exists?).with(prefix + key).and_return(false, true)
69
- expect(cache.key?('foo')).to eq false
70
- expect(cache.key?('foo')).to eq true
71
- end
72
-
73
- it 'can delete' do
74
- key = 'foo'
75
- expect(redis).to receive(:del).with(prefix + key)
76
- cache.delete(key)
77
- end
78
-
79
- it 'can iterate over keys, values' do
80
- key, value = 'foo', { 'test' => true }
81
- expect(redis).to receive(:set).with(prefix + key, JSON(value), ex: nil)
82
- cache[key] = value
83
- expect(redis).to receive(:scan_each).with(match: "#{prefix}*").
84
- and_yield("#{prefix}foo")
85
- expect(redis).to receive(:get).with(prefix + key).and_return(JSON(test: true))
86
- cache.each do |k, v|
87
- expect(k).to eq prefix + key
88
- expect(v).to eq value
89
- end
90
- end
91
-
92
- it 'returns size' do
93
- expect(redis).to receive(:scan_each).with(match: "#{prefix}*").
94
- and_yield("#{prefix}foo").
95
- and_yield("#{prefix}bar").
96
- and_yield("#{prefix}baz")
97
- expect(cache.size).to eq 3
98
- end
99
-
100
- it 'can clear' do
101
- expect(redis).to receive(:scan_each).with(match: 'test-*').and_yield(
102
- 'test-foo'
103
- )
104
- expect(redis).to receive(:del).with('test-foo')
105
- expect(cache.clear).to eq cache
106
- end
107
-
108
- it 'can iterate over keys under a prefix' do
109
- expect(redis).to receive(:scan_each).with(match: 'test-*')
110
- cache.to_a
111
- end
112
-
113
- it 'can compute prefix with pre' do
114
- expect(cache.pre('foo')).to eq 'test-foo'
115
- end
116
-
117
- it 'can remove prefix with unpre' do
118
- expect(cache.unpre('test-foo')).to eq 'foo'
119
- end
120
- end
121
- end
@@ -1,141 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Documents::SQLiteCache do
4
- let :prefix do
5
- 'test-'
6
- end
7
-
8
- let :test_value do
9
- {
10
- key: 'test',
11
- text: 'test text',
12
- norm: 0.5,
13
- source: 'for-test.txt',
14
- tags: %w[ test ],
15
- embedding: [ 0.5 ] * 1_024,
16
- }
17
- end
18
-
19
- let :cache do
20
- described_class.new prefix:
21
- end
22
-
23
- it 'can be instantiated' do
24
- expect(cache).to be_a described_class
25
- end
26
-
27
- it 'defaults to :memory: mode' do
28
- expect(cache.filename).to eq ':memory:'
29
- end
30
-
31
- it 'can be switchted to file mode' do
32
- expect(SQLite3::Database).to receive(:new).with('foo.sqlite').
33
- and_return(double.as_null_object)
34
- cache = described_class.new prefix:, filename: 'foo.sqlite'
35
- expect(cache.filename).to eq 'foo.sqlite'
36
- end
37
-
38
- it 'can get/set a key' do
39
- key, value = 'foo', test_value
40
- queried_value = nil
41
- expect {
42
- cache[key] = value
43
- }.to change {
44
- queried_value = cache[key]
45
- }.from(nil).to(Ollama::Documents::Record[value])
46
- expect(queried_value.embedding).to eq [ 0.5 ] * 1_024
47
- end
48
-
49
- it 'can determine if key exists' do
50
- key, value = 'foo', test_value
51
- expect {
52
- cache[key] = value
53
- }.to change {
54
- cache.key?(key)
55
- }.from(false).to(true)
56
- end
57
-
58
- it 'can set key with different prefixes' do
59
- key, value = 'foo', test_value
60
- expect {
61
- cache[key] = value
62
- }.to change {
63
- cache.size
64
- }.from(0).to(1)
65
- cache2 = cache.dup
66
- cache2.prefix = 'test2-'
67
- expect {
68
- cache2[key] = value
69
- }.to change {
70
- cache2.size
71
- }.from(0).to(1)
72
- expect(cache.size).to eq 1
73
- s = 0
74
- cache.full_each { s += 1 }
75
- expect(s).to eq 2
76
- end
77
-
78
- it 'can delete' do
79
- key, value = 'foo', test_value
80
- expect(cache.delete(key)).to be_falsy
81
- cache[key] = value
82
- expect {
83
- expect(cache.delete(key)).to be_truthy
84
- }.to change {
85
- cache.key?(key)
86
- }.from(true).to(false)
87
- end
88
-
89
- it 'returns size' do
90
- key, value = 'foo', test_value
91
- expect {
92
- cache[key] = value
93
- }.to change {
94
- cache.size
95
- }.from(0).to(1)
96
- end
97
-
98
- it 'can convert_to_vector' do
99
- vector = [ 23.0, 666.0 ]
100
- expect(cache.convert_to_vector(vector)).to eq vector
101
- end
102
-
103
- it 'can clear' do
104
- key, value = 'foo', { embedding: [ 0.5 ] * 1_024 }
105
- cache[key] = value
106
- expect {
107
- expect(cache.clear).to eq cache
108
- }.to change {
109
- cache.size
110
- }.from(1).to(0)
111
- end
112
-
113
- it 'can clear for tags' do
114
- key, value = 'foo', { tags: %w[ foo ], embedding: [ 0.5 ] * 1_024 }
115
- cache[key] = value
116
- key, value = 'bar', { embedding: [ 0.5 ] * 1_024 }
117
- cache[key] = value
118
- expect {
119
- expect(cache.clear_for_tags(%w[ #foo ])).to eq cache
120
- }.to change {
121
- cache.size
122
- }.from(2).to(1)
123
- expect(cache).not_to be_key 'foo'
124
- expect(cache).to be_key 'bar'
125
- end
126
-
127
- it 'can return tags' do
128
- key, value = 'foo', { tags: %w[ foo ], embedding: [ 0.5 ] * 1_024 }
129
- cache[key] = value
130
- key, value = 'bar', { tags: %w[ bar baz ], embedding: [ 0.5 ] * 1_024 }
131
- cache[key] = value
132
- tags = cache.tags
133
- expect(tags).to be_a Ollama::Utils::Tags
134
- expect(tags.to_a).to eq %w[ bar baz foo ]
135
- end
136
-
137
- it 'can iterate over keys under a prefix' do
138
- cache['foo'] = test_value
139
- expect(cache.to_a).to eq [ [ 'test-foo', Ollama::Documents::Record[test_value] ] ]
140
- end
141
- end
@@ -1,110 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Documents::Splitters::Character do
4
- let :splitter do
5
- described_class.new chunk_size: 23, combining_string: ''
6
- end
7
-
8
- it 'can be instantiated' do
9
- expect(splitter).to be_a described_class
10
- end
11
-
12
- it 'can split' do
13
- text = [ ?A * 10 ] * 10 * "\n\n"
14
- result = splitter.split(text)
15
- expect(result.count).to eq 5
16
- expect(result.to_a.join('')).to eq ?A * 100
17
- end
18
-
19
- it 'can split combining with separation' do
20
- splitter = described_class.new chunk_size: 25, include_separator: false,
21
- combining_string: ?X
22
- text = [ ?A * 10 ] * 10 * "\n\n"
23
- result = splitter.split(text)
24
- expect(result.count).to eq 5
25
- expect(result.to_a.join(?B)).to eq\
26
- "AAAAAAAAAAXAAAAAAAAAAXBAAAAAAAAAAAAAAAAAAAAXBAAAAAAAAAAAAAAAAAAAAXB"\
27
- "AAAAAAAAAAAAAAAAAAAAXBAAAAAAAAAAAAAAAAAAAAX"
28
- end
29
-
30
- it 'can split including separator' do
31
- splitter = described_class.new chunk_size: 25, include_separator: true,
32
- combining_string: ''
33
- text = [ ?A * 10 ] * 10 * "\n\n"
34
- result = splitter.split(text)
35
- expect(result.count).to eq 5
36
- expect(result.to_a.join('')).to eq text
37
- end
38
-
39
- it 'cannot split' do
40
- text = [ ?A * 10 ] * 10 * "\n"
41
- result = splitter.split(text)
42
- expect(result.count).to eq 1
43
- expect(result.to_a.join('').count(?A)).to eq text.count(?A)
44
- end
45
-
46
- it 'cannot split2' do
47
- text = ?A * 25
48
- result = splitter.split(text)
49
- expect(result.count).to eq 1
50
- expect(result.to_a.join('')).to eq ?A * 25
51
- end
52
-
53
- it 'can split sentences' do
54
- text = "foo.foo. bar!bar! baz?baz? quux.\nquux."
55
- splitter = described_class.new(separator: /[.!?]\s*(?:\b|\z)/, chunk_size: 2)
56
- result = splitter.split(text)
57
- expect(result.to_a).to eq %w[ foo foo bar bar baz baz quux quux ]
58
- end
59
- end
60
-
61
- RSpec.describe Ollama::Documents::Splitters::RecursiveCharacter do
62
- let :splitter do
63
- described_class.new chunk_size: 23, combining_string: ''
64
- end
65
-
66
- it 'can be instantiated' do
67
- expect(splitter).to be_a described_class
68
- end
69
-
70
- it 'can split' do
71
- text = [ ?A * 10 ] * 10 * "\n\n"
72
- result = splitter.split(text)
73
- expect(result.count).to eq 5
74
- expect(result.to_a.join('')).to eq ?A * 100
75
- end
76
-
77
- it 'cannot split' do
78
- splitter = described_class.new chunk_size: 23, include_separator: true,
79
- separators: described_class::DEFAULT_SEPARATORS[0..-2]
80
- text = ?A * 25
81
- result = splitter.split(text)
82
- expect(result.count).to eq 1
83
- expect(result.to_a.join('')).to eq ?A * 25
84
- end
85
-
86
- it 'can split including separator' do
87
- splitter = described_class.new chunk_size: 25, include_separator: true,
88
- combining_string: ''
89
- text = [ ?A * 10 ] * 10 * "\n\n"
90
- result = splitter.split(text)
91
- expect(result.count).to eq 5
92
- expect(result.to_a.join('')).to eq text
93
- end
94
-
95
- it 'can split single newline as well' do
96
- text = [ ?A * 10 ] * 10 * "\n"
97
- result = splitter.split(text)
98
- expect(result.count).to eq 5
99
- expect(result.to_a.join('')).to eq ?A * 100
100
- end
101
-
102
- it 'can split single newline as well including separator' do
103
- splitter = described_class.new chunk_size: 25, include_separator: true,
104
- combining_string: ''
105
- text = [ ?A * 10 ] * 10 * "\n"
106
- result = splitter.split(text)
107
- expect(result.count).to eq 5
108
- expect(result.to_a.join('')).to eq text
109
- end
110
- end
@@ -1,56 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Documents::Splitters::Semantic do
4
- let :ollama do
5
- double('Ollama::Client')
6
- end
7
-
8
- let :splitter do
9
- described_class.new ollama:, model: 'mxbai-embed-large'
10
- end
11
-
12
- let :embeddings do
13
- JSON(File.read(asset('embeddings.json')))
14
- end
15
-
16
- it 'can be instantiated' do
17
- expect(splitter).to be_a described_class
18
- end
19
-
20
- before do
21
- allow(ollama).to receive(:embed).and_return(double(embeddings:))
22
- end
23
-
24
- it 'can split with breakpoint :percentile' do
25
- text = ([ "A" * 10 ] * 3 + [ "B" * 10 ] * 3 + [ "A" * 10 ] * 3) * ". "
26
- result = splitter.split(text, breakpoint: :percentile, percentile: 75)
27
- expect(result.count).to eq 3
28
- expect(result.to_a.join('').count(?A)).to eq text.count(?A)
29
- expect(result.to_a.join('').count(?B)).to eq text.count(?B)
30
- end
31
-
32
- it 'can split with breakpoint :percentile' do
33
- described_class.new ollama:, model: 'mxbai-embed-large', chunk_size: 50
34
- text = ([ "A" * 10 ] * 6 + [ "B" * 10 ] * 3 + [ "A" * 10 ] * 3) * ". "
35
- result = splitter.split(text, breakpoint: :percentile, percentile: 75)
36
- expect(result.count).to eq 4
37
- expect(result.to_a.join('').count(?A)).to eq text.count(?A)
38
- expect(result.to_a.join('').count(?B)).to eq text.count(?B)
39
- end
40
-
41
- it 'can split with breakpoint :standard_deviation' do
42
- text = ([ "A" * 10 ] * 3 + [ "B" * 10 ] * 3 + [ "A" * 10 ] * 3) * ". "
43
- result = splitter.split(text, breakpoint: :standard_deviation, percentage: 100)
44
- expect(result.count).to eq 3
45
- expect(result.to_a.join('').count(?A)).to eq text.count(?A)
46
- expect(result.to_a.join('').count(?B)).to eq text.count(?B)
47
- end
48
-
49
- it 'can split with breakpoint :interquartile' do
50
- text = ([ "A" * 10 ] * 3 + [ "B" * 10 ] * 3 + [ "A" * 10 ] * 3) * ". "
51
- result = splitter.split(text, breakpoint: :interquartile, percentage: 75)
52
- expect(result.count).to eq 3
53
- expect(result.to_a.join('').count(?A)).to eq text.count(?A)
54
- expect(result.to_a.join('').count(?B)).to eq text.count(?B)
55
- end
56
- end
@@ -1,162 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Documents do
4
- let :ollama do
5
- double('Ollama::Client')
6
- end
7
-
8
- let :model do
9
- 'mxbai-embed-large'
10
- end
11
-
12
- let :documents do
13
- described_class.new ollama:, model:
14
- end
15
-
16
- it 'can be instantiated' do
17
- expect(documents).to be_a described_class
18
- end
19
-
20
- it 'no texts can be added to it' do
21
- expect(documents.add([])).to eq documents
22
- end
23
-
24
- it 'texts can be added to it' do
25
- expect(ollama).to receive(:embed).
26
- with(model:, input: %w[ foo bar ], options: nil).
27
- and_return(double(embeddings: [ [ 0.1 ], [ 0.2 ] ]))
28
- expect(documents.add(%w[ foo bar ])).to eq documents
29
- expect(documents.exist?('foo')).to eq true
30
- expect(documents.exist?('bar')).to eq true
31
- expect(documents['foo']).to be_a Ollama::Documents::Record
32
- end
33
-
34
- it 'a text can be added to it' do
35
- expect(ollama).to receive(:embed).
36
- with(model:, input: %w[ foo ], options: nil).
37
- and_return(double(embeddings: [ [ 0.1 ] ]))
38
- expect(documents << 'foo').to eq documents
39
- expect(documents.exist?('foo')).to eq true
40
- expect(documents.exist?('bar')).to eq false
41
- expect(documents['foo']).to be_a Ollama::Documents::Record
42
- end
43
-
44
- it 'can find strings' do
45
- expect(ollama).to receive(:embed).
46
- with(model:, input: [ 'foo' ], options: nil).
47
- and_return(double(embeddings: [ [ 0.1 ] ]))
48
- expect(documents << 'foo').to eq documents
49
- expect(ollama).to receive(:embed).
50
- with(model:, input: 'foo', options: nil).
51
- and_return(double(embeddings: [ [ 0.1 ] ]))
52
- records = documents.find('foo')
53
- expect(records).to eq [
54
- Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ]
55
- ]
56
- expect(records[0].to_s).to eq '#<Ollama::Documents::Record "foo" 1.0>'
57
- end
58
-
59
- it 'can find only tagged strings' do
60
- expect(ollama).to receive(:embed).
61
- with(model:, input: [ 'foo' ], options: nil).
62
- and_return(double(embeddings: [ [ 0.1 ] ]))
63
- expect(documents.add('foo', tags: %w[ test ])).to eq documents
64
- expect(ollama).to receive(:embed).
65
- with(model:, input: 'foo', options: nil).
66
- and_return(double(embeddings: [ [ 0.1 ] ]))
67
- records = documents.find('foo', tags: %w[ nix ])
68
- expect(records).to eq []
69
- expect(ollama).to receive(:embed).
70
- with(model:, input: 'foo', options: nil).
71
- and_return(double(embeddings: [ [ 0.1 ] ]))
72
- records = documents.find('foo', tags: %w[ test ])
73
- expect(records).to eq [
74
- Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ]
75
- ]
76
- expect(records[0].to_s).to eq '#<Ollama::Documents::Record "foo" #test 1.0>'
77
- end
78
-
79
- it 'can find strings conditionally' do
80
- expect(ollama).to receive(:embed).
81
- with(model:, input: [ 'foobar' ], options: nil).
82
- and_return(double(embeddings: [ [ 0.01 ] ]))
83
- expect(ollama).to receive(:embed).
84
- with(model:, input: [ 'foo' ], options: nil).
85
- and_return(double(embeddings: [ [ 0.1 ] ]))
86
- expect(documents << 'foobar').to eq documents
87
- expect(documents << 'foo').to eq documents
88
- expect(ollama).to receive(:embed).at_least(:once).
89
- with(model:, input: 'foo', options: nil).
90
- and_return(double(embeddings: [ [ 0.1 ] ]))
91
- records = documents.find_where('foo', text_count: 1)
92
- expect(records).to eq [
93
- Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ],
94
- ]
95
- records = documents.find_where('foo', text_size: 3)
96
- expect(records).to eq [
97
- Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ],
98
- ]
99
- records = documents.find_where('foo')
100
- expect(records).to eq [
101
- Ollama::Documents::Record[text: 'foo', embedding: [ 0.1 ], similarity: 1.0 ],
102
- Ollama::Documents::Record[text: 'foobar', embedding: [ 0.1 ], similarity: 1.0 ],
103
- ]
104
- end
105
-
106
-
107
- context 'it uses cache' do
108
- before do
109
- allow(ollama).to receive(:embed).
110
- with(model:, input: %w[ foo ], options: nil).
111
- and_return(double(embeddings: [ [ 0.1 ] ]))
112
- end
113
-
114
- it 'can delete texts' do
115
- expect(documents << 'foo').to eq documents
116
- expect {
117
- documents.delete('foo')
118
- }.to change { documents.exist?('foo') }.from(true).to(false)
119
- end
120
-
121
- it 'tracks size' do
122
- expect {
123
- expect(documents << 'foo').to eq documents
124
- }.to change { documents.size }.from(0).to(1)
125
- end
126
-
127
- it 'can clear texts' do
128
- expect(documents << 'foo').to eq documents
129
- expect {
130
- documents.clear
131
- }.to change { documents.size }.from(1).to(0)
132
- end
133
-
134
- it 'can clear texts with tags' do
135
- expect(ollama).to receive(:embed).
136
- with(model:, input: %w[ bar ], options: nil).
137
- and_return(double(embeddings: [ [ 0.1 ] ]))
138
- expect(documents.add('foo', tags: %w[ test ])).to eq documents
139
- expect(documents.add('bar', tags: %w[ test2 ])).to eq documents
140
- expect(documents.tags.to_a).to eq %w[ test test2 ]
141
- expect {
142
- documents.clear tags: 'test'
143
- }.to change { documents.size }.from(2).to(1)
144
- expect {
145
- documents.clear tags: :test2
146
- }.to change { documents.size }.from(1).to(0)
147
- end
148
-
149
- it 'returns collections' do
150
- expect(documents.collections).to eq [ :default ]
151
- end
152
-
153
- it 'can change collection' do
154
- expect(documents.instance_eval { @cache }).to receive(:prefix=).
155
- with(/#@collection/).and_call_original
156
- expect { documents.collection = :new_collection }.
157
- to change { documents.collection }.
158
- from(:default).
159
- to(:new_collection)
160
- end
161
- end
162
- end
@@ -1,13 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Utils::ColorizeTexts do
4
- it 'colorizes texts' do
5
- ct = described_class.new(%w[ foo bar ])
6
- colored = ct.to_s
7
- uncolored = Term::ANSIColor.uncolor(ct.to_s)
8
- expect(colored.size).to be > uncolored.size
9
- expect(uncolored).to eq(
10
- "foo\n#3 \n\nbar\n#3 \n\n"
11
- )
12
- end
13
- end
@@ -1,53 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe Ollama::Utils::Tags do
4
- it 'can be instantiated' do
5
- expect(described_class.new).to be_a described_class
6
- end
7
-
8
- it 'can contain unique tags and is sorted' do
9
- tags = described_class.new(%w[ bar foo ])
10
- expect(tags.to_a).to eq %w[ bar foo ]
11
- end
12
-
13
- it 'can contain unique tags with leading # characters and is sorted' do
14
- tags = described_class.new(%w[ #bar ##foo ])
15
- expect(tags.to_a).to eq %w[ bar foo ]
16
- end
17
-
18
- it 'tags can be added to it' do
19
- tags = described_class.new([ 'foo' ])
20
- tags.add 'bar'
21
- expect(tags.to_a).to eq %w[ bar foo ]
22
- end
23
-
24
- it 'can increase in size' do
25
- tags = described_class.new
26
- expect { tags.add 'foo' }.to change { tags.size }.from(0).to(1)
27
- expect { tags.add 'bar' }.to change { tags.size }.from(1).to(2)
28
- end
29
-
30
- it 'can be cleared' do
31
- tags = described_class.new([ 'foo', 'bar' ])
32
- expect { tags.clear }.to change { tags.size }.from(2).to(0)
33
- end
34
-
35
- it 'tags can be empty' do
36
- tags = described_class.new([ 'foo' ])
37
- expect { tags.clear }.to change { tags.empty? }.from(false).to(true)
38
- end
39
-
40
- it 'can be output nicely' do
41
- expect(described_class.new(%w[ #foo bar ]).to_s).to eq '#bar #foo'
42
- end
43
-
44
- it 'can be output nicely with links to source' do
45
- tags = described_class.new([ 'foo' ], source: 'https://foo.example.com')
46
- tags.add 'bar', source: '/path/to/bar.html'
47
- expect(tags.to_a).to eq %w[ bar foo ]
48
- tags.all? { expect(_1).to be_a(Ollama::Utils::Tags::Tag) }
49
- expect(tags.to_s).to eq(
50
- "\e]8;;file:///path/to/bar.html\e\\#bar\e]8;;\e\\ \e]8;;https://foo.example.com\e\\#foo\e]8;;\e\\"
51
- )
52
- end
53
- end