Class: AssistantBrainEntry
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- AssistantBrainEntry
- Includes:
- Models::Embeddable
- Defined in:
- app/models/assistant_brain_entry.rb
Overview
== Schema Information
Table name: assistant_brain_entries
Database name: primary
id :bigint not null, primary key
applies_to_services :string default([]), not null, is an Array
category :string not null
priority :enum default("normal"), not null
rule :text not null
scope :string default("global"), not null
source :string default("manual"), not null
status :string default("active"), not null
title :string not null
created_at :datetime not null
updated_at :datetime not null
approved_by_id :bigint
assistant_conversation_id :bigint
suggested_by_id :bigint
user_id :bigint
Indexes
index_assistant_brain_entries_on_category (category)
index_assistant_brain_entries_on_scope (scope)
index_assistant_brain_entries_on_status_and_category (status,category)
index_assistant_brain_entries_on_status_and_priority (status,priority)
index_assistant_brain_entries_on_user_id (user_id)
Constant Summary collapse
- CATEGORIES =
Categories.
%w[url_rules product_data content_rules seo_rules general].freeze
- STATUSES =
Statuses.
%w[active pending inactive].freeze
- SOURCES =
Sources.
%w[manual auto_learned].freeze
- SCOPES =
Scopes.
%w[global user].freeze
- CATEGORY_LABELS =
Category labels.
{ 'url_rules' => 'URL Rules', 'product_data' => 'Product Data', 'content_rules' => 'Content Rules', 'seo_rules' => 'SEO Rules', 'general' => 'General' }.freeze
Constants included from Models::Embeddable
Models::Embeddable::MAX_CONTENT_LENGTH
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #category ⇒ Object readonly
- #rule ⇒ Object readonly
- #scope ⇒ Object readonly
- #source ⇒ Object readonly
- #status ⇒ Object readonly
- #title ⇒ Object readonly
- #user_id ⇒ Object readonly
Belongs to collapse
Class Method Summary collapse
-
.active ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are active.
-
.auto_learned ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are auto learned.
-
.by_category ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are by category.
-
.for_context(user_id:, active_services: []) ⇒ ActiveRecord::Relation
Fetch all entries applicable to a given user and set of active tool services.
-
.for_user ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are for user.
-
.global_scope ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are global scope.
-
.inactive ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are inactive.
-
.manual ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are manual.
-
.pending ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are pending.
- .ransackable_attributes(_auth_object = nil) ⇒ Object
-
.semantic_search_for(query, within_ids:, limit: 20) ⇒ Array<AssistantBrainEntry>
Find the most semantically relevant active brain entries for a user query.
-
.user_scope ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are user scope.
Instance Method Summary collapse
- #active? ⇒ Boolean
- #applies_everywhere? ⇒ Boolean
- #approve!(approver) ⇒ Object
- #auto_learned? ⇒ Boolean
- #category_label ⇒ Object
-
#content_for_embedding(_content_type = :primary) ⇒ Object
Embed the full title + rule text so retrieval matches on both what the rule is about (title) and what it says (rule body).
- #global? ⇒ Boolean
- #inactive? ⇒ Boolean
- #pending? ⇒ Boolean
- #personal? ⇒ Boolean
- #reject! ⇒ Object
Methods included from Models::Embeddable
#content_embeddings, embeddable_content_types, #embeddable_locales, #embedding_content_hash, embedding_partition_class, #embedding_stale?, #embedding_type_name, #embedding_vector, #find_content_embedding, #find_similar, #generate_all_embeddings!, #generate_chunked_embeddings!, #generate_embedding!, #has_embedding?, #locale_for_embedding, #needs_chunking?, regenerate_all_embeddings, semantic_search
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#category ⇒ Object (readonly)
62 |
# File 'app/models/assistant_brain_entry.rb', line 62 validates :category, presence: true, inclusion: { in: CATEGORIES } |
#rule ⇒ Object (readonly)
64 |
# File 'app/models/assistant_brain_entry.rb', line 64 validates :rule, presence: true |
#scope ⇒ Object (readonly)
67 |
# File 'app/models/assistant_brain_entry.rb', line 67 validates :scope, presence: true, inclusion: { in: SCOPES } |
#source ⇒ Object (readonly)
66 |
# File 'app/models/assistant_brain_entry.rb', line 66 validates :source, presence: true, inclusion: { in: SOURCES } |
#status ⇒ Object (readonly)
65 |
# File 'app/models/assistant_brain_entry.rb', line 65 validates :status, presence: true, inclusion: { in: STATUSES } |
#title ⇒ Object (readonly)
63 |
# File 'app/models/assistant_brain_entry.rb', line 63 validates :title, presence: true |
#user_id ⇒ Object (readonly)
68 |
# File 'app/models/assistant_brain_entry.rb', line 68 validates :user_id, presence: true, if: -> { scope == 'user' } |
Class Method Details
.active ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are active. Active Record Scope
70 |
# File 'app/models/assistant_brain_entry.rb', line 70 scope :active, -> { where(status: 'active') } |
.auto_learned ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are auto learned. Active Record Scope
78 |
# File 'app/models/assistant_brain_entry.rb', line 78 scope :auto_learned, -> { where(source: 'auto_learned') } |
.by_category ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are by category. Active Record Scope
73 |
# File 'app/models/assistant_brain_entry.rb', line 73 scope :by_category, -> { order(:category, :title) } |
.for_context(user_id:, active_services: []) ⇒ ActiveRecord::Relation
Fetch all entries applicable to a given user and set of active tool services.
Returns global entries + the user's personal entries, filtered by service applicability.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'app/models/assistant_brain_entry.rb', line 86 def self.for_context(user_id:, active_services: []) base = active.where('scope = ? OR (scope = ? AND user_id = ?)', 'global', 'user', user_id) if active_services.present? # Inject if: applies_to_services is empty (universal) OR overlaps with active services. # Cast both sides to varchar[] so PostgreSQL can use the && (overlap) operator. base.where( 'cardinality(applies_to_services) = 0 OR applies_to_services && ARRAY[?]::varchar[]', active_services ) else # No tools active — only inject universal entries (no service filter) base.where('cardinality(applies_to_services) = 0') end end |
.for_user ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are for user. Active Record Scope
76 |
# File 'app/models/assistant_brain_entry.rb', line 76 scope :for_user, ->(user_id) { where(scope: 'user', user_id: user_id) } |
.global_scope ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are global scope. Active Record Scope
74 |
# File 'app/models/assistant_brain_entry.rb', line 74 scope :global_scope, -> { where(scope: 'global') } |
.inactive ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are inactive. Active Record Scope
72 |
# File 'app/models/assistant_brain_entry.rb', line 72 scope :inactive, -> { where(status: 'inactive') } |
.manual ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are manual. Active Record Scope
77 |
# File 'app/models/assistant_brain_entry.rb', line 77 scope :manual, -> { where(source: 'manual') } |
.pending ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are pending. Active Record Scope
71 |
# File 'app/models/assistant_brain_entry.rb', line 71 scope :pending, -> { where(status: 'pending') } |
.ransackable_attributes(_auth_object = nil) ⇒ Object
158 159 160 |
# File 'app/models/assistant_brain_entry.rb', line 158 def self.ransackable_attributes(_auth_object = nil) %w[title rule category status source scope priority created_at updated_at] end |
.semantic_search_for(query, within_ids:, limit: 20) ⇒ Array<AssistantBrainEntry>
Find the most semantically relevant active brain entries for a user query.
Used by ChatService when the total entry count exceeds the injection threshold
and full verbatim injection would bloat the system prompt.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'app/models/assistant_brain_entry.rb', line 126 def self.semantic_search_for(query, within_ids:, limit: 20) return [] if query.blank? || within_ids.empty? query_vector = ContentEmbedding.(query) return [] unless query_vector ContentEmbedding .where(embeddable_type: 'AssistantBrainEntry', embeddable_id: within_ids) .by_model(ContentEmbedding::UNIFIED_MODELS) . .nearest_neighbors(:unified_embedding, query_vector, distance: :cosine) .limit(limit) .includes(:embeddable) .filter_map(&:embeddable) end |
.user_scope ⇒ ActiveRecord::Relation<AssistantBrainEntry>
A relation of AssistantBrainEntries that are user scope. Active Record Scope
75 |
# File 'app/models/assistant_brain_entry.rb', line 75 scope :user_scope, -> { where(scope: 'user') } |
Instance Method Details
#active? ⇒ Boolean
106 |
# File 'app/models/assistant_brain_entry.rb', line 106 def active? = status == 'active' |
#applies_everywhere? ⇒ Boolean
113 114 115 |
# File 'app/models/assistant_brain_entry.rb', line 113 def applies_everywhere? applies_to_services.blank? end |
#approve!(approver) ⇒ Object
150 151 152 |
# File 'app/models/assistant_brain_entry.rb', line 150 def approve!(approver) update!(status: 'active', approved_by: approver) end |
#approved_by ⇒ Party
59 |
# File 'app/models/assistant_brain_entry.rb', line 59 belongs_to :approved_by, class_name: 'Party', optional: true |
#assistant_conversation ⇒ AssistantConversation
60 |
# File 'app/models/assistant_brain_entry.rb', line 60 belongs_to :assistant_conversation, class_name: 'AssistantConversation', optional: true |
#auto_learned? ⇒ Boolean
109 |
# File 'app/models/assistant_brain_entry.rb', line 109 def auto_learned? = source == 'auto_learned' |
#category_label ⇒ Object
102 103 104 |
# File 'app/models/assistant_brain_entry.rb', line 102 def category_label CATEGORY_LABELS.fetch(category, category.humanize) end |
#content_for_embedding(_content_type = :primary) ⇒ Object
Embed the full title + rule text so retrieval matches on both what the rule
is about (title) and what it says (rule body).
146 147 148 |
# File 'app/models/assistant_brain_entry.rb', line 146 def (_content_type = :primary) "#{title}\n\n#{rule}" end |
#global? ⇒ Boolean
110 |
# File 'app/models/assistant_brain_entry.rb', line 110 def global? = scope == 'global' |
#inactive? ⇒ Boolean
108 |
# File 'app/models/assistant_brain_entry.rb', line 108 def inactive? = status == 'inactive' |
#pending? ⇒ Boolean
107 |
# File 'app/models/assistant_brain_entry.rb', line 107 def pending? = status == 'pending' |
#personal? ⇒ Boolean
111 |
# File 'app/models/assistant_brain_entry.rb', line 111 def personal? = scope == 'user' |
#reject! ⇒ Object
154 155 156 |
# File 'app/models/assistant_brain_entry.rb', line 154 def reject! update!(status: 'inactive') end |
#suggested_by ⇒ Party
58 |
# File 'app/models/assistant_brain_entry.rb', line 58 belongs_to :suggested_by, class_name: 'Party', optional: true |