Class: Insika::Knowledge::Consolidator

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/knowledge.rb

Overview

The "second LLM call" §3.5 describes — spent ONLY when a concept name already exists AND the new sighting's body differs from the stored one (the cheap same-claim check in Knowledge.write_concept already handled the identical-reworded case without a call). ONE call decides AND merges together: Workflow::Schema cannot express "merged_body required only if verdict==related", so the schema only requires verdict and a Ruby check afterward treats a missing/oversized merged_body on a "related" answer as unusable.

resolve never raises: any parse/schema failure — or simply not being configured — resolves to {verdict: :contradicting}, the safe default when the engine cannot tell. A guess that risks merging two genuinely different claims into one confident-sounding lie is the worse failure mode; a conflict a human has to look at is not.

Defined Under Namespace

Classes: Unusable

Constant Summary collapse

DEFAULT_PROMPT =
<<~PROMPT.freeze
  You are comparing two claims about the SAME concept in a store's
  knowledge base — an existing one already on record, and a new one
  just observed in a conversation.

  Answer with a single JSON object and NOTHING else. No prose, no fences.

  - If the two claims are COMPATIBLE — they can be combined into one
    coherent statement without losing or inventing anything either one
    said — answer {"verdict": "related", "merged_body": "<the merged
    claim, in your own words, max 2000 chars>"}.
  - If they state genuinely DIFFERENT things and merging would hide a
    real change or disagreement, answer {"verdict": "contradicting"}.

  When unsure, prefer "contradicting" — a human resolves it; a wrong
  merge would state something nobody actually confirmed.
PROMPT
VERDICT_SCHEMA =
Insika::Workflow::Schema.coerce({
  "type" => "object",
  "properties" => {
    "verdict" => { "type" => "string" },
    "merged_body" => { "type" => "string" }
  },
  "required" => ["verdict"]
})
MAX_MERGED_BODY =
2000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ask:, model: "utility_model") ⇒ Consolidator

Returns a new instance of Consolidator.



429
430
431
432
# File 'lib/insika/knowledge.rb', line 429

def initialize(ask:, model: "utility_model")
  @ask = ask
  @model = model.to_s
end

Instance Attribute Details

#modelObject (readonly)

Returns the value of attribute model.



427
428
429
# File 'lib/insika/knowledge.rb', line 427

def model
  @model
end

Instance Method Details

#resolve(existing_body:, new_body:) ⇒ Object

-> { verdict: :related, merged_body: String } | { verdict: :contradicting }



435
436
437
438
439
440
441
442
443
# File 'lib/insika/knowledge.rb', line 435

def resolve(existing_body:, new_body:)
  answer = @ask.call(prompt_for(existing_body, new_body))
  parsed = parse(text_of(answer))
  raise Unusable, "not a JSON object" unless VERDICT_SCHEMA.call(parsed).success?

  classify(parsed)
rescue Unusable
  { verdict: :contradicting }
end