fix(captain-memory): strengthen RecallService logging context and document timeout tradeoff
This commit is contained in:
parent
502c3d1698
commit
0fee1b3c2f
@ -12,21 +12,41 @@ class Captain::ContactMemories::RecallService
|
||||
def call
|
||||
return [] if @contact.blank? || @query_text.blank?
|
||||
|
||||
# NOTE: Timeout.timeout is used here as a hard cap on both embedding API + DB query.
|
||||
# It has known hazards (async exception, can't cleanly interrupt C-level I/O, can
|
||||
# corrupt connection state) — tradeoff accepted because this service is non-critical:
|
||||
# any failure returns [] and the agent degrades gracefully without memory. Phase 6
|
||||
# will consider refactoring the DB portion to Postgres statement_timeout for safer
|
||||
# cancellation.
|
||||
Timeout.timeout(TIMEOUT_SECONDS) do
|
||||
query_embedding = Captain::Llm::EmbeddingService.new(account_id: @contact.account_id).get_embedding(@query_text)
|
||||
return [] if query_embedding.blank?
|
||||
|
||||
Captain::ContactMemory
|
||||
.active
|
||||
.for_contact(@contact.id)
|
||||
.scope_compatible(@unit_id)
|
||||
.where.not(embedding: nil)
|
||||
.nearest_neighbors(:embedding, query_embedding, distance: 'cosine')
|
||||
.limit(@top_k)
|
||||
.to_a
|
||||
nearest_memories(query_embedding)
|
||||
end
|
||||
rescue StandardError => e
|
||||
Rails.logger.warn("[ContactMemory::RecallService] #{e.class}: #{e.message}")
|
||||
log_failure(e)
|
||||
[]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def nearest_memories(query_embedding)
|
||||
Captain::ContactMemory
|
||||
.active
|
||||
.for_contact(@contact.id)
|
||||
.scope_compatible(@unit_id)
|
||||
.where.not(embedding: nil)
|
||||
.nearest_neighbors(:embedding, query_embedding, distance: 'cosine')
|
||||
.limit(@top_k)
|
||||
.to_a
|
||||
end
|
||||
|
||||
def log_failure(error)
|
||||
Rails.logger.warn(
|
||||
"[ContactMemory::RecallService] #{error.class}: #{error.message} " \
|
||||
"(contact_id=#{@contact&.id} account_id=#{@contact&.account_id})"
|
||||
)
|
||||
Rails.logger.warn(error.backtrace.first(5).join("\n")) unless error.is_a?(Timeout::Error)
|
||||
end
|
||||
end
|
||||
|
||||
@ -62,8 +62,9 @@ RSpec.describe Captain::ContactMemories::RecallService do
|
||||
|
||||
it 'skips memories with NULL embedding' do
|
||||
create(:captain_contact_memory, contact: contact, account: account, embedding: nil)
|
||||
valid = create(:captain_contact_memory, contact: contact, account: account, embedding: Array.new(1536, 0.1))
|
||||
result = described_class.new(contact: contact, query_text: 'x').call
|
||||
expect(result).to eq([])
|
||||
expect(result).to eq([valid])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user