whoosh 1.9.0 → 1.10.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/lib/whoosh/ai/llm.rb +48 -17
- data/lib/whoosh/ai.rb +2 -1
- data/lib/whoosh/streaming/llm_stream.rb +17 -1
- data/lib/whoosh/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0c8ecbe08e5ecf50f7f1233da3767074a79d9e4164a719e9397be1ac9637efb3
|
|
4
|
+
data.tar.gz: 622f3f889c550ecdff4cfab4f38120f2ce3f14b7f2021be99dae9790c3cfc5f7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70add9595209f2ff3a1c5c4a52e25a4428149694f4df9debc7cc58dace2d15b77d46dcf1591cb9cd78e7d02654f0402326c58c9e060f1c94897e0011fc2cfab2
|
|
7
|
+
data.tar.gz: 83fb93d35d3b1d446bc99d1f8ee0a21b16f062af81da4f4e737b98cd85acced622fe332ccefb785c5f114fa78131131bdea9f008e109c49291c793c117cea843
|
data/lib/whoosh/ai/llm.rb
CHANGED
|
@@ -2,15 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
module Whoosh
|
|
4
4
|
module AI
|
|
5
|
+
# Bounded LRU cache. Ruby's Hash preserves insertion order, so we reorder
|
|
6
|
+
# on read (delete+reinsert) and evict the oldest entry when over capacity.
|
|
7
|
+
class LRUCache
|
|
8
|
+
def initialize(max_size)
|
|
9
|
+
@max_size = max_size
|
|
10
|
+
@store = {}
|
|
11
|
+
@mutex = Mutex.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def [](key)
|
|
15
|
+
@mutex.synchronize do
|
|
16
|
+
return nil unless @store.key?(key)
|
|
17
|
+
value = @store.delete(key)
|
|
18
|
+
@store[key] = value
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def []=(key, value)
|
|
23
|
+
@mutex.synchronize do
|
|
24
|
+
@store.delete(key) if @store.key?(key)
|
|
25
|
+
@store[key] = value
|
|
26
|
+
@store.shift while @store.size > @max_size
|
|
27
|
+
value
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def size
|
|
32
|
+
@store.size
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
DEFAULT_MODEL = "claude-sonnet-4-6"
|
|
37
|
+
DEFAULT_CACHE_MAX = 1000
|
|
38
|
+
|
|
5
39
|
class LLM
|
|
6
40
|
attr_reader :provider, :model
|
|
7
41
|
|
|
8
|
-
def initialize(provider: "auto", model: nil, cache_enabled: true)
|
|
42
|
+
def initialize(provider: "auto", model: nil, cache_enabled: true, cache_size: DEFAULT_CACHE_MAX)
|
|
9
43
|
@provider = provider
|
|
10
44
|
@model = model
|
|
11
45
|
@cache_enabled = cache_enabled
|
|
12
|
-
@cache = cache_enabled ?
|
|
13
|
-
@mutex = Mutex.new
|
|
46
|
+
@cache = cache_enabled ? LRUCache.new(cache_size) : nil
|
|
14
47
|
@ruby_llm = nil
|
|
15
48
|
end
|
|
16
49
|
|
|
@@ -32,10 +65,7 @@ module Whoosh
|
|
|
32
65
|
temperature: temperature
|
|
33
66
|
)
|
|
34
67
|
|
|
35
|
-
|
|
36
|
-
if use_cache && @cache
|
|
37
|
-
@mutex.synchronize { @cache[cache_key] = result }
|
|
38
|
-
end
|
|
68
|
+
@cache[cache_key] = result if use_cache && @cache
|
|
39
69
|
|
|
40
70
|
result
|
|
41
71
|
end
|
|
@@ -60,18 +90,19 @@ module Whoosh
|
|
|
60
90
|
end
|
|
61
91
|
end
|
|
62
92
|
|
|
63
|
-
# Stream LLM response — yields
|
|
93
|
+
# Stream an LLM response — yields each chunk as ruby_llm produces it.
|
|
94
|
+
# The block receives a RubyLLM::Chunk (a Message subclass with #content).
|
|
95
|
+
# Returns the final response message after the stream completes.
|
|
64
96
|
def stream(message, model: nil, system: nil, &block)
|
|
65
97
|
ensure_ruby_llm!
|
|
98
|
+
unless @ruby_llm
|
|
99
|
+
raise Errors::DependencyError, "No LLM provider available. Add 'ruby_llm' to your Gemfile."
|
|
100
|
+
end
|
|
66
101
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# For now, fall back to non-streaming
|
|
72
|
-
result = chat(message, model: model, system: system, cache: false)
|
|
73
|
-
yield result if block_given?
|
|
74
|
-
result
|
|
102
|
+
chat = RubyLLM.chat(model: model || @model || DEFAULT_MODEL)
|
|
103
|
+
chat.with_instructions(system) if system
|
|
104
|
+
chat.ask(message) do |chunk|
|
|
105
|
+
block.call(chunk) if block
|
|
75
106
|
end
|
|
76
107
|
end
|
|
77
108
|
|
|
@@ -87,7 +118,7 @@ module Whoosh
|
|
|
87
118
|
|
|
88
119
|
if @ruby_llm
|
|
89
120
|
# Use ruby_llm gem
|
|
90
|
-
chat = RubyLLM.chat(model: model ||
|
|
121
|
+
chat = RubyLLM.chat(model: model || DEFAULT_MODEL)
|
|
91
122
|
chat.with_instructions(system) if system
|
|
92
123
|
response = chat.ask(messages.last[:content])
|
|
93
124
|
response.content
|
data/lib/whoosh/ai.rb
CHANGED
|
@@ -11,7 +11,8 @@ module Whoosh
|
|
|
11
11
|
LLM.new(
|
|
12
12
|
provider: ai_config["provider"] || "auto",
|
|
13
13
|
model: ai_config["model"],
|
|
14
|
-
cache_enabled: ai_config["cache"] != false
|
|
14
|
+
cache_enabled: ai_config["cache"] != false,
|
|
15
|
+
cache_size: ai_config["cache_size"] || DEFAULT_CACHE_MAX
|
|
15
16
|
)
|
|
16
17
|
end
|
|
17
18
|
end
|
|
@@ -17,7 +17,8 @@ module Whoosh
|
|
|
17
17
|
|
|
18
18
|
def <<(chunk)
|
|
19
19
|
return if @closed
|
|
20
|
-
text = chunk
|
|
20
|
+
text = extract_text(chunk)
|
|
21
|
+
return self if text.nil? || text.empty?
|
|
21
22
|
payload = { choices: [{ delta: { content: text } }] }
|
|
22
23
|
write("data: #{JSON.generate(payload)}\n\n")
|
|
23
24
|
self
|
|
@@ -40,6 +41,21 @@ module Whoosh
|
|
|
40
41
|
|
|
41
42
|
private
|
|
42
43
|
|
|
44
|
+
# ruby_llm chunks expose #content (Message subclass). Older code paths
|
|
45
|
+
# and plain-string yields are also supported.
|
|
46
|
+
def extract_text(chunk)
|
|
47
|
+
return chunk if chunk.is_a?(String)
|
|
48
|
+
if chunk.respond_to?(:content)
|
|
49
|
+
c = chunk.content
|
|
50
|
+
return "" if c.nil?
|
|
51
|
+
return c if c.is_a?(String)
|
|
52
|
+
return c.text if c.respond_to?(:text)
|
|
53
|
+
return c.to_s
|
|
54
|
+
end
|
|
55
|
+
return chunk.text if chunk.respond_to?(:text)
|
|
56
|
+
chunk.to_s
|
|
57
|
+
end
|
|
58
|
+
|
|
43
59
|
def write(data)
|
|
44
60
|
@io.write(data)
|
|
45
61
|
@io.flush if @io.respond_to?(:flush)
|
data/lib/whoosh/version.rb
CHANGED