Module: Insika::Distill

Defined in:
lib/insika/distill.rb

Overview

the one place distillation asks a model for anything.

The engine's generic prompt (what a durable customer fact is, the shape of the answer, and the "never invent, never guess a scope" rules). A pack distill.prompt REPLACES this wholesale (the forge's half) — the engine never writes store vocabulary.

Defined Under Namespace

Modules: DistillerFactory Classes: Distiller

Constant Summary collapse

DEFAULT_PROMPT =
<<~PROMPT.freeze
  You are distilling durable facts about ONE customer from a finished
  conversation, for a shop assistant's memory. A fact is something that
  stays true across conversations: a size, a preference, a situation, an
  address. It is NOT the conversation itself, not a summary, and not a
  question.

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

  Rules:
  - Each element is an object with "name" (the fact's key, short, lowercase,
    underscore-separated), "value" (the fact's content, plain text), an
    optional "confidence" (a number between 0 and 1) and an optional "turns"
    (the message indexes in the transcript that support the fact).
  - Never invent: only facts the conversation actually supports.
  - Never guess a scope: you are not told any customer id or tenant — do not
    include one, the engine stamps it.
  - Fewer, better facts beat filling a quota.
PROMPT
PROPOSAL_SCHEMA =

The SAFE-subset JSON Schema (object/array/string/number/integer + required

  • items — workflow.rb:77's subset). The validator is permissive on unknown keys, so the Distiller itself rejects a proposal carrying any key OUTSIDE this set (D1 — a model-authored scope is a cross-tenant escape) and counts the drop.
Insika::Workflow::Schema.coerce({
  "type" => "array",
  "items" => {
    "type" => "object",
    "properties" => {
      "name" => { "type" => "string" },
      "value" => { "type" => "string" },
      "confidence" => { "type" => "number" },
      "turns" => { "type" => "array", "items" => { "type" => "integer" } }
    },
    "required" => ["name", "value"]
  }
})
ITEM_SCHEMA =

The per-PROPOSAL half (an item of PROPOSAL_SCHEMA) — the Distiller validates each element against THIS, not the whole-answer schema.

Insika::Workflow::Schema.coerce(PROPOSAL_SCHEMA.json_schema["items"])