Module: Legion::LLM::ResponseCache
- Extended by:
- Legion::Logging::Helper
- Defined in:
- lib/legion/llm/response_cache.rb
Constant Summary collapse
- DEFAULT_TTL =
300- SPOOL_THRESHOLD =
8 MB
8 * 1024 * 1024
- SPOOL_DIR =
File.('~/.legionio/data/spool/llm_responses').freeze
Class Method Summary collapse
-
.cleanup(request_id) ⇒ Object
Removes all cache keys for a request (and any spool file).
-
.complete(request_id, response:, meta:, ttl: DEFAULT_TTL) ⇒ Object
Writes response, meta, and marks status as :done.
-
.error(request_id) ⇒ Object
Returns { code:, message: } hash, or nil.
-
.fail_request(request_id, code:, message:, ttl: DEFAULT_TTL) ⇒ Object
Writes error details and marks status as :error.
-
.init_request(request_id, ttl: DEFAULT_TTL) ⇒ Object
Sets status to :pending for a new request.
-
.meta(request_id) ⇒ Object
Returns meta hash with symbolized keys, or nil.
-
.poll(request_id, timeout: DEFAULT_TTL, interval: 0.1) ⇒ Object
Blocking poll.
-
.response(request_id) ⇒ Object
Returns the response string (handles spool overflow transparently).
-
.status(request_id) ⇒ Object
Returns :pending, :done, :error, or nil.
Class Method Details
.cleanup(request_id) ⇒ Object
Removes all cache keys for a request (and any spool file).
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/legion/llm/response_cache.rb', line 92 def cleanup(request_id) raw = Legion::Cache.get(response_key(request_id)) if raw&.start_with?('spool:') path = raw.delete_prefix('spool:') FileUtils.rm_f(path) end Legion::Cache.delete(status_key(request_id)) Legion::Cache.delete(response_key(request_id)) Legion::Cache.delete((request_id)) Legion::Cache.delete(error_key(request_id)) end |
.complete(request_id, response:, meta:, ttl: DEFAULT_TTL) ⇒ Object
Writes response, meta, and marks status as :done.
24 25 26 27 28 |
# File 'lib/legion/llm/response_cache.rb', line 24 def complete(request_id, response:, meta:, ttl: DEFAULT_TTL) write_response(request_id, response, ttl) cache_set((request_id), ::JSON.dump(), ttl) cache_set(status_key(request_id), 'done', ttl) end |
.error(request_id) ⇒ Object
Returns { code:, message: } hash, or nil.
62 63 64 65 66 67 |
# File 'lib/legion/llm/response_cache.rb', line 62 def error(request_id) raw = Legion::Cache.get(error_key(request_id)) return nil if raw.nil? ::JSON.parse(raw, symbolize_names: true) end |
.fail_request(request_id, code:, message:, ttl: DEFAULT_TTL) ⇒ Object
Writes error details and marks status as :error.
31 32 33 34 35 36 |
# File 'lib/legion/llm/response_cache.rb', line 31 def fail_request(request_id, code:, message:, ttl: DEFAULT_TTL) log.warn("ResponseCache fail_request request_id=#{request_id} code=#{code} message=#{}") payload = ::JSON.dump({ code: code, message: }) cache_set(error_key(request_id), payload, ttl) cache_set(status_key(request_id), 'error', ttl) end |
.init_request(request_id, ttl: DEFAULT_TTL) ⇒ Object
Sets status to :pending for a new request.
19 20 21 |
# File 'lib/legion/llm/response_cache.rb', line 19 def init_request(request_id, ttl: DEFAULT_TTL) cache_set(status_key(request_id), 'pending', ttl) end |
.meta(request_id) ⇒ Object
Returns meta hash with symbolized keys, or nil.
54 55 56 57 58 59 |
# File 'lib/legion/llm/response_cache.rb', line 54 def (request_id) raw = Legion::Cache.get((request_id)) return nil if raw.nil? ::JSON.parse(raw, symbolize_names: true) end |
.poll(request_id, timeout: DEFAULT_TTL, interval: 0.1) ⇒ Object
Blocking poll. Returns { status: :done, response:, meta: }, { status: :error, error: }, or { status: :timeout }.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/legion/llm/response_cache.rb', line 71 def poll(request_id, timeout: DEFAULT_TTL, interval: 0.1) deadline = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + timeout loop do current = status(request_id) log.debug("ResponseCache poll request_id=#{request_id} status=#{current}") case current when :done return { status: :done, response: response(request_id), meta: (request_id) } when :error return { status: :error, error: error(request_id) } end return { status: :timeout } if ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) >= deadline sleep interval end end |
.response(request_id) ⇒ Object
Returns the response string (handles spool overflow transparently).
45 46 47 48 49 50 51 |
# File 'lib/legion/llm/response_cache.rb', line 45 def response(request_id) raw = Legion::Cache.get(response_key(request_id)) return nil if raw.nil? return File.read(raw.delete_prefix('spool:')) if raw.start_with?('spool:') raw end |
.status(request_id) ⇒ Object
Returns :pending, :done, :error, or nil.
39 40 41 42 |
# File 'lib/legion/llm/response_cache.rb', line 39 def status(request_id) raw = Legion::Cache.get(status_key(request_id)) raw&.to_sym end |