Skip to content

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 27 Jul 19:00
· 437 commits to main since this release

Changed

  • README repositioned and restructured. sage-wiki's README now leads
    with what it has become — a graph memory and knowledge base for AI
    agents and humans, scaling personal → team → company — and shrinks from
    1058 to ~335 lines by linking into the guides instead of inlining them.
    Two new guides absorb the extracted depth:
    docs/guides/configuration.md (the full annotated config, multi-provider
    recipes, the serve-mode compile worker, price-table override) and
    docs/guides/customizing-prompts.md (prompt scaffolding — all EIGHT
    template files, not the five previously listed — and custom frontmatter
    fields). Guide merges preserve README-only content: the block-level
    co-occurrence rule for relation extraction (configurable-relations), the
    in-memory vector-cache restart caveat and opt-in ANN section
    (search-quality), external-parser hardening details (CONTRIBUTING +
    team-setup), and webui dist regeneration (CONTRIBUTING).
    User-visible corrections riding along: summary_max_tokens default is
    4000 (was misdocumented as 2000) and init writes max_parallel: 4;
    batch API availability includes Gemini; the deprecated
    ontology.relations key reference now reads relation_types; benchmark
    numbers refreshed to eval/REPORT.md's current results (85.9–86.7%
    overall, 97.5–99.7% recall@1) with fixed eval/ paths; the command table
    gains ontology resolve, hub init|compile, compile --fresh,
    source, coverage, and version; .bmp added to supported image
    formats; the stale "durable workers — do not assume" note in
    storage-backends.md now points at the shipped serve.worker. Translated
    READMEs carry a parity banner and the corrected 18-tool count (7 read);
    full translation parity follows in dedicated commits.

Added

  • Claude-driven entity resolution (P3-3), opt-in. With
    ontology.resolve.enabled: true, a new compile pass proposes links between
    surface-form variants of one entity — "NASA" and "National Aeronautics and
    Space Administration" — so that once applied, the canonical carries the union
    of the cluster's edges. Proposals are queued, not applied: see the default
    below.
    It links; it does not collapse: both entity rows survive and the canonical
    gains the alias's edges, so nothing is ever deleted. It is also reversible
    sage-wiki ontology resolve --unlink <alias> removes exactly the edges that
    link caused and rejects the pair so a later compile cannot re-apply it.
    Defaults to off; and when
    enabled, auto_apply_threshold defaults to 0.85 — a proposal at or above
    it that passes every guard is applied automatically, and --unlink makes a
    mistaken link cost one command, which is what justifies the default. Set an
    explicit 1.0 for review-only and it is a hard guarantee: 1.0 means never
    auto-apply, exactly, so even a model reporting confidence 1.0 cannot clear
    it. The pass warns at the default log level whenever proposals are waiting,
    and when an out-of-range threshold falls back to the 0.85 default.
    Auto-apply additionally requires a description on at least one side,
    and triple extraction is the only compile-path writer of those — though
    sage-wiki scribe writes them too, so resolve on with triples off is not
    by itself a guarantee. A proposal goes to review when the threshold forbids
    auto-apply (an explicit 1.0), when confidence is below it, when the model flags a
    member as strictly "broader", or when neither side has a description; decide
    them with sage-wiki ontology resolve --review|--apply|--reject|--unlink. Rejection is symmetric,
    so re-rolling the direction cannot bypass it. Candidate blocking is seeded only
    by entities the compile touched (a new unmatched entity costs zero LLM calls)
    and discards name tokens shared by more than 5% of a type, with an absolute
    floor so a rare name in a small vault survives. use_embeddings optionally
    widens candidates to names sharing no tokens, in memory and globally capped.
    sage-wiki ontology resolve --sweep re-applies approved links with no LLM
    calls — the remedy for edges added outside a compile. SQLite migration V11 and
    Postgres migration v4 add the entity_aliases table on both backends. See
    docs/guides/graph-memory.md, including the cost section and the notes on
    derived-edge provenance and the partial prune contract.
  • Multi-hop graph query with per-fact provenance (P3-4). New MCP tool
    wiki_graph_query ({question, hops?, max_edges?}) answers relational
    questions by traversal: seed entities are resolved from the question via
    hybrid search (an alias seed lands on its canonical entity), a bounded
    subgraph is serialized as numbered triples, and the model must answer ONLY
    from those edges — every citation returns with source_doc and
    confidence (plus the evidence span when present). Zero matched entities
    and zero edges each short-circuit with a distinct answer and no LLM call.
    Bounds come from ontology.graph_query (max_hops default 2, max_edges
    default 60; out-of-range values fall back rather than clamping),
    overridable per call, and truncation is reported in the response. The
    serialized subgraph is framed as untrusted content with delimiter-spoof
    neutralization (the P1-6 frame). Strictly additive — all 18 tool schemas
    are now pinned by a per-name golden. The regular Q&A context also gains
    edge provenance: each related-article fallback block names its connecting
    edge (via: (a) --[rel]--> (b) {source, confidence}); graph-EXPANDED
    articles are deliberately not annotated, because expansion aggregates many
    signals and naming one edge would be false provenance.
  • Alias-aware retrieval surfaces. Once entity resolution links an alias,
    every user-facing graph surface starts from its canonical entity:
    graph-expansion seeds in query/search, the query context's fallback
    traversal, the web graph (?center= resolves, and the response gains an
    additive center field naming the node actually centered on), and
    sage-wiki ontology query --entity (which prints a note on stderr; stdout
    stays one valid JSON document). MCP behaviour change: wiki_ontology_query
    now resolves an alias entity argument to its canonical before traversing —
    previously it traversed the alias's own stored view. The payload shape is
    unchanged (a bare entity array, no extra fields). Store-level reads are
    deliberately untouched — Traverse/GetRelations on an alias still return
    only its own stored edges, pinned by a conformance test on both backends —
    as are wiki_list (browsing, not seeding) and
    --unlink/--apply/--reject, which take the alias by definition.
  • LLM structured-output triple extraction (P3-2), opt-in. With
    ontology.triples.enabled: true, each Tier-3 document gets one additional
    Pass-2 LLM call that extracts typed entities (each with a one-sentence
    grounded description) and evidenced (subject, predicate, object) triples,
    persisted as P3-1 evidenced relations. Defaults to off: the pass costs one
    call per document, and an upgrade should not change anyone's bill. Model
    resolution follows ontology.triples.modelmodels.extract
    models.summarize. Keyword extraction (Pass 3) is unchanged and still runs.
    See docs/guides/graph-memory.md, including the cost section — --re-extract
    is O(all summaries), and the --batch compile path does not run the pass.
    Evidence spans are quoted from a document's compiled summary, not its raw
    source; source_doc names the origin document.
  • Evidenced, provenance-bearing relations (P3-1). Ontology edges now carry
    evidence (the source span supporting the edge), confidence (0–1), and
    source_doc (the originating document), plus valid_from, valid_to and
    invalidated_by reserved for temporal validity. Schema addition only —
    backward compatible: existing rows read back with zero values, and every
    caller that does not set the new fields behaves exactly as before. SQLite
    migration V10 and Postgres migration v3 are both plain ADD COLUMN, with
    upgrade tests from the prior schema on each backend. Re-asserting an edge now
    updates its evidence only when the incoming confidence is strictly higher;
    created_at always keeps the earliest assertion's value. Evidence spans are
    quoted from a document's compiled summary, not its raw source — Pass 2 sees
    summaries — so a citation names source_doc as the origin while the summary
    is what the span is verifiable against.

Changed

  • AddEntity no longer erases a stored value with an empty one. An empty
    (or, on Postgres, NULL) incoming name, definition or article_path now
    leaves the stored value alone; non-empty values still overwrite. Previously a
    re-assert that omitted a field wiped it — most visibly, re-indexing an article
    erased its entity definition.
  • An entity's type is now correctable on SQLite. The SQLite upsert
    previously ignored type entirely, so a wrong type was permanent; it is now
    written on every upsert, matching Postgres. Consequently sage-wiki scribe
    can retype an existing entity where it previously could not.
  • sage-wiki pack apply no longer resets ontology.triples. The ontology
    merge rebuilt the ontology: node from a literal carrying only relation and
    entity types, so any other key under it was erased. A pack cannot set
    triples itself; the user's value is now preserved.
  • Keyword-extracted edges can appear where they previously did not (only
    with ontology.triples.enabled: true). Keyword extraction gates each pattern
    on the stored entity types and skips a pattern whose target entity does not
    exist yet. Once triple extraction populates typed entities in Pass 2, some
    previously-skipped keyword edges start being created. No code in the keyword
    pass changed.
  • Article re-indexing reads the article's declared type and display name.
    reconcile, sage-wiki write and the MCP write_article tool previously
    hard-coded type: concept and the raw slug when indexing an already-written
    article. With type now writable, that would have demoted a technique on
    every run. All three read entity_type: from the article's frontmatter
    (falling back to concept, including when the declared type is no longer
    configured) and write the formatted display name. Frontmatter is parsed on CRLF
    checkouts as well as LF.

Fixed

  • Postgres could write a NULL updated_at over a stored timestamp.
    AddEntity defaulted UpdatedAt only when CreatedAt was empty, so a caller
    supplying one but not the other bound NULL — and the upsert wrote it. The two
    now default independently, matching SQLite.
  • GetRelations with Both and a relation filter returned the wrong edges on
    SQLite.
    The query built WHERE source_id=? OR target_id=? and appended
    AND relation=?, which parses as source_id=? OR (target_id=? AND relation=?) — so outbound edges of every type were returned regardless of the
    filter. Reachable through wiki_ontology_query and sage-wiki ontology.
    Postgres was already correct; both backends are now covered by the shared
    conformance suite.