Module: Insika::MessageOrigin
- Defined in:
- lib/insika/message_origin.rb
Overview
WHO PRODUCED A TRANSCRIPT MESSAGE — the field a role cannot carry.
role says where a message sits in the conversation, not who wrote it, and the
two come apart constantly:
· The engine delivers an async subagent's result to the parent as a NEW turn
(RFC-0010) — a user message the engine wrote.
· A guardrail short-circuits with a safe reply — an assistant message produced
with zero LLM calls.
· A consumer composes context blocks into the input it sends (<memoria> …,
<cacau_cep_obrigatorio> …) — a user message the customer never typed.
· In an imported transcript, a human operator types after a handoff — an
assistant message no model produced.
Reading a transcript without that distinction is not a rounding error. The first
refinement run over real traffic reported repetition ×219 on one agent: every
one of them the engine reading its own injected fragment back and calling it a
customer repeating themselves (PR #133). That was filtered by a REGEX on the
leading tag, labelled in the code as a heuristic standing in for this field.
ABSENT is the common case and stays valid forever: a message with no origin is
read as the natural producer for its role (user → the customer, assistant →
the agent). Nothing in the existing corpus, the stores or the pilot's database
has to be migrated, and a reader that ignores the field is exactly as correct as
it was before.
Constant Summary collapse
- KEY =
"origin"- CUSTOMER =
a person on the user side (the default for
user) "customer"- AGENT =
the model (the default for
assistant) "agent"- ENGINE =
Insika itself, or the consumer composing on its behalf
"engine"- OPERATOR =
a HUMAN on the assistant side (a handoff; set by importers)
"operator"- ALL =
[CUSTOMER, AGENT, ENGINE, OPERATOR].freeze
Class Method Summary collapse
-
.agent?(message) ⇒ Boolean
Did the MODEL write this? Absent origin = yes, same reasoning.
-
.customer?(message) ⇒ Boolean
Did a PERSON on the user side write this? Absent origin = yes, because that is what a
usermessage meant before this field existed. - .origin_of(message) ⇒ Object
-
.parse!(value) ⇒ Object
A declared origin, or nil.
-
.stamp(message, origin) ⇒ Object
Stamps a message hash, leaving it untouched when there is nothing to declare — so the common turn keeps producing exactly the two-key shape it always did.
Class Method Details
.agent?(message) ⇒ Boolean
Did the MODEL write this? Absent origin = yes, same reasoning.
61 62 63 |
# File 'lib/insika/message_origin.rb', line 61 def agent?() ["role"].to_s == "assistant" && [nil, AGENT].include?(origin_of()) end |
.customer?(message) ⇒ Boolean
Did a PERSON on the user side write this? Absent origin = yes, because that is
what a user message meant before this field existed.
56 57 58 |
# File 'lib/insika/message_origin.rb', line 56 def customer?() ["role"].to_s == "user" && [nil, CUSTOMER].include?(origin_of()) end |
.origin_of(message) ⇒ Object
65 66 67 68 |
# File 'lib/insika/message_origin.rb', line 65 def origin_of() v = [KEY] || [KEY.to_sym] Coercion.presence(v)&.downcase end |
.parse!(value) ⇒ Object
A declared origin, or nil. Anything outside the closed set is REFUSED rather than stored: an unknown value would silently read as "absent" downstream, and a typo'd marker is worse than none — it looks like the filtering is on.
44 45 46 47 48 49 50 51 52 |
# File 'lib/insika/message_origin.rb', line 44 def parse!(value) return nil if Coercion.blank?(value) name = value.to_s.strip.downcase return name if ALL.include?(name) raise Insika::ValidationError, "unknown message origin: #{value.inspect} (expected #{ALL.join(', ')})" end |
.stamp(message, origin) ⇒ Object
Stamps a message hash, leaving it untouched when there is nothing to declare — so the common turn keeps producing exactly the two-key shape it always did.
72 73 74 |
# File 'lib/insika/message_origin.rb', line 72 def stamp(, origin) origin.nil? ? : .merge(KEY => origin) end |