Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions lib/legion/extensions/apollo/runners/knowledge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ def deprecate_entry(entry_id:, reason:, **)
def handle_ingest(content: nil, content_type: nil, tags: [], source_agent: 'unknown', # rubocop:disable Metrics/ParameterLists
source_provider: nil, source_channel: nil, knowledge_domain: nil,
submitted_by: nil, submitted_from: nil, content_hash: nil, context: {},
skip: false, access_scope: 'global', identity_principal_id: nil,
identity_id: nil, identity_canonical_name: nil, **)
skip: false, access_scope: 'global', **)
return { status: :skipped } if skip

identity = resolve_process_identity
content = normalize_text_input(content)
content_type = normalize_content_type(content_type.nil? ? :observation : content_type)
log.debug("Apollo Knowledge.handle_ingest content_length=#{content.length} content_type=#{content_type} tags=#{Array(tags).size} source_agent=#{source_agent} source_channel=#{source_channel || 'nil'}") # rubocop:disable Layout/LineLength
Expand All @@ -97,7 +97,7 @@ def handle_ingest(content: nil, content_type: nil, tags: [], source_agent: 'unkn

hash = content_hash || (defined?(Helpers::Writeback) ? Helpers::Writeback.content_hash(content) : nil)
existing = active_duplicate_for_hash(hash, access_scope: access_scope,
identity_principal_id: identity_principal_id)
identity_principal_id: identity[:principal_id])
if existing
log.info("Apollo Knowledge.handle_ingest deduped entry_id=#{existing.id} source_agent=#{source_agent}")
return { success: true, entry_id: existing.id, deduped: true }
Expand All @@ -109,9 +109,9 @@ def handle_ingest(content: nil, content_type: nil, tags: [], source_agent: 'unkn
source_provider: source_provider, source_channel: source_channel,
submitted_by: submitted_by, submitted_from: submitted_from,
access_scope: access_scope,
identity_principal_id: identity_principal_id,
identity_id: identity_id,
identity_canonical_name: identity_canonical_name)
identity_principal_id: identity[:principal_id],
identity_id: identity[:identity_id],
identity_canonical_name: identity[:canonical_name])

corroborated, existing_id = find_corroboration(
embedding, content_type_sym, metadata[:source_agent], metadata[:source_channel]
Expand Down Expand Up @@ -148,6 +148,7 @@ def handle_query(query:, limit: Helpers::GraphQuery.default_query_limit, # ruboc
requesting_principal_id: nil, **)
return { success: false, error: 'apollo_data_not_available' } unless Helpers::DataModels.apollo_entry_available?

requesting_principal_id = resolve_requesting_principal_id(requesting_principal_id)
entry_model = Helpers::DataModels.apollo_entry
query = normalize_text_input(query)
status_defaulted = status.equal?(UNSET)
Expand Down Expand Up @@ -273,6 +274,7 @@ def retrieve_relevant(query: nil, limit: Helpers::Confidence.apollo_setting(:que

return { success: false, error: 'apollo_data_not_available' } unless Helpers::DataModels.apollo_entry_available?

requesting_principal_id = resolve_requesting_principal_id(requesting_principal_id)
query = normalize_text_input(query)
log.debug("Apollo Knowledge.retrieve_relevant query_length=#{query.length} limit=#{limit} min_confidence=#{min_confidence} tags=#{Array(tags).size} domain=#{domain || 'nil'}") # rubocop:disable Layout/LineLength
return { success: true, entries: [], count: 0 } if query.nil? || query.to_s.strip.empty?
Expand Down Expand Up @@ -720,6 +722,29 @@ def upsert_expertise(source_agent:, domain:)
end
end

def resolve_process_identity
return { principal_id: nil, identity_id: nil, canonical_name: nil } unless defined?(Legion::Identity::Process)

{
principal_id: Legion::Identity::Process.db_principal_id,
identity_id: Legion::Identity::Process.db_identity_id,
canonical_name: Legion::Identity::Process.canonical_name
}
rescue StandardError => e
handle_exception(e, level: :warn, operation: 'apollo.knowledge.resolve_process_identity')
{ principal_id: nil, identity_id: nil, canonical_name: nil }
end

def resolve_requesting_principal_id(explicit_value)
return explicit_value if explicit_value
return nil unless defined?(Legion::Identity::Process)

Legion::Identity::Process.db_principal_id
rescue StandardError => e
handle_exception(e, level: :warn, operation: 'apollo.knowledge.resolve_requesting_principal_id')
nil
end

include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
include Legion::JSON::Helper
include Legion::Settings::Helper
Expand Down
2 changes: 1 addition & 1 deletion lib/legion/extensions/apollo/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Legion
module Extensions
module Apollo
VERSION = '0.4.27'
VERSION = '0.4.28'
end
end
end
24 changes: 13 additions & 11 deletions spec/legion/extensions/apollo/runners/knowledge_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def self.generate(*, **)
end
end

context 'identity kwargs persistence' do
context 'identity from Legion::Identity::Process' do
let(:mock_entry_class2) { double('ApolloEntry2') }
let(:mock_expertise_class2) { double('ApolloExpertise2') }
let(:mock_access_log_class2) { double('ApolloAccessLog2') }
Expand All @@ -390,18 +390,20 @@ def self.generate(*, **)
allow(host).to receive(:embed_text).and_return(nil)
allow(host).to receive(:find_corroboration).and_return([false, nil])
allow(host).to receive(:detect_contradictions).and_return([])
stub_const('Legion::Identity::Process', double(
db_principal_id: 42,
db_identity_id: 7,
canonical_name: 'alice'
))
end

it 'passes identity_principal_id and access_scope through to create_candidate_entry' do
it 'derives identity from Legion::Identity::Process and persists it' do
expect(mock_entry_class2).to receive(:create).with(
hash_including(identity_principal_id: 42, access_scope: 'private')
hash_including(identity_principal_id: 42, identity_id: 7, identity_canonical_name: 'alice',
access_scope: 'private')
).and_return(mock_entry2)

host.handle_ingest(
content: 'test fact', tags: [],
identity_principal_id: 42, identity_id: 7, identity_canonical_name: 'alice',
access_scope: 'private'
)
host.handle_ingest(content: 'test fact', tags: [], access_scope: 'private')
end

it 'defaults access_scope to global when not provided' do
Expand All @@ -412,14 +414,14 @@ def self.generate(*, **)
host.handle_ingest(content: 'test fact', tags: [])
end

it 'persists identity_id and identity_canonical_name' do
it 'ignores identity kwargs passed by callers' do
expect(mock_entry_class2).to receive(:create).with(
hash_including(identity_id: 7, identity_canonical_name: 'alice')
hash_including(identity_principal_id: 42, identity_id: 7, identity_canonical_name: 'alice')
).and_return(mock_entry2)

host.handle_ingest(
content: 'test fact', tags: [],
identity_principal_id: 42, identity_id: 7, identity_canonical_name: 'alice',
identity_principal_id: 999, identity_id: 888, identity_canonical_name: 'mallory',
access_scope: 'private'
)
end
Expand Down
Loading