Files
Josh Lehman 65ad180052 feat(knowledge): bundle the Knowledge memory plugin (#180139)
* feat(knowledge): import Knowledge plugin sources

Imported from openclaw/knowledge at 7847e55. Uses the public SDK root()
and the host's typed projectKey.

* style(knowledge): apply repository formatting and lint autofixes

* test(knowledge): port the Knowledge suite to vitest

* docs(knowledge): document the bundled Knowledge plugin

* refactor(knowledge): conform to bundled-plugin lint, types and file-size rules

* fix(knowledge): locate workers and packaged data from the runtime entry

Built output moves shared modules into host chunks, so module-relative
URLs no longer reach the storage and registry workers, the default
ontology or the sample vault. Resolve them from api.runtimeSource, ship
the data as static assets, and read files through @openclaw/fs-safe.

* chore(knowledge): register plugin inventory, config baseline and labels

* refactor(knowledge): drop standalone-host leftovers

Metadata-only registration has no runtime entry; locate packaged files
only when the host supplies one. Remove the older-host panel guard and
references to docs that did not move with the plugin.

* refactor(knowledge): remove unused exports and dead search helpers

* openclaw-ef3.7.3: open Knowledge databases through SDK helpers and stamp schema versions

Replace raw DatabaseSync construction and PRAGMA-based header versioning in the
operational (state.sqlite) and registry databases with openNodeSqliteDatabase,
runSqliteImmediateTransactionSync and a knowledge_schema version table. Stores
written before stamping are dated by their tables and migrated additively;
their native header is left untouched. Identity and registry upserts use Kysely.

* openclaw-ef3.7.2: port Knowledge transactions and conflict inserts to SDK patterns

BEGIN IMMEDIATE blocks become runSqliteImmediateTransactionSync, INSERT OR
IGNORE/REPLACE become Kysely onConflict inserts, and sqlite_master probes use
tableExists. Register Knowledge's worker-only SQL modules in workerModules.

* openclaw-ef3.7.4: move Knowledge JSON projections out of raw SQL

Publication source and receipt lookups use jsonPathValue with Kysely. The recent
projection parses each published plan once in TypeScript instead of json_each/
json_extract, and applies record eligibility and source grouping while streaming
newest-first events. Storage base transactions and upserts use SDK helpers.

* openclaw-ef3.7.6: document type assertion invariants in Knowledge storage modules

Every type assertion in the storage, registry, recent, retrieval, lifecycle,
session-activity and attachment modules now states its invariant, satisfying
the assertion SAFETY ratchet against main.

* openclaw-ef3.7.6: keep the Knowledge schema step type module-private

* openclaw-ef3.7.2: resolve Knowledge worker SQLite SDK modules through the host resolver

* openclaw-ef3.7.4: keep Knowledge SQL out of the control UI bundle

Recent activity SQL moves to recent-activity.ts so recent.ts only carries the
schemas the control UI imports, and session activity records retried calls with
a portable ON CONFLICT DO NOTHING prepared statement instead of the SQLite SDK.

* refactor(knowledge): move scan primitives to a leaf module

Breaks the evidence-files -> publication-files -> vault import cycle.

* openclaw-ef3.7: import digest from scan-primitives to break the lifecycle -> vault -> retrieval cycle

* openclaw-ef3.7.5: classify Knowledge keyword-index FTS5 as engine-private

Knowledge's keyword index is a rebuildable cache in each store's own
state.sqlite, opened by SqliteIdentityStore and never through the selected
Gateway engine. Classify its fts5, temp-schema and rowid constructs in
retrieval.ts as owned engine maintenance; other constructs there stay counted.

* chore(knowledge): justify or remove type assertions

Adds SAFETY invariants for the assertion ratchet and removes casts that
real types or narrowing make unnecessary.

* refactor(knowledge): drop the Publisher alias and unused MAX_ENTRIES re-exports

* fix(knowledge): bound Markdown block runs before link lexing

JavaScriptCore reports regexp matches that exceed its backtracking memory
cap as no match. marked's paragraph rule hits that cap after ~49K lines in
one block, then lexes the rest line by line, so scanning a near-limit
record took hours under Bun. Split runs over 10K non-blank lines before
lexing; links are unchanged.

* fix(knowledge): transfer workspace attachments without model byte copying

knowledge-live-728: reuse durable chunk uploads behind a scoped workspace-file tool and document programmatic source retention.
(cherry picked from commit d196fdc0b1c30c4850a1f97d94a512ae2b27aa74)

* fix(knowledge): declare knowledge_attach_file in the plugin manifest

* feat(knowledge): add knowledge-unlinked-claims skill for post-relink review

* fix(knowledge): resume interrupted store setup and admit state once

- Resume a store whose setup was interrupted: an empty state.sqlite is a new
  database, and writeOnce completes an empty vault.json or registry sentinel.
- Admit each physical state database once per thread: the schema check,
  history indexes and additive operational tables move out of every
  connection and every operation.
- Keep maintenance schedule bookkeeping in registry meta instead of
  maintenance.json.

* feat(knowledge): steer the memory prompt toward entity pages and recall before planning

Describe Knowledge as world knowledge about ontology entities, search named
entities once before planning, keep pages for sustained work through
knowledge-entities and knowledge-capture, record agent findings on pages
instead of skipping them, word remembered claims no more broadly than their
excerpt, and record supersession with knowledge-correct.

* fix(knowledge): keep knowledge_remember a search-free fast path for one-off claims

* fix(knowledge): complete an empty registry sentinel before checking it

A crash after the registry sentinel is created but before its ID is written
left an empty registry.id. The constructor compared it with the registry ID
before writeOnce could complete it, so every registry operation failed until
manual recovery. writeOnce now runs first and reports whether it wrote; the
comparison still refuses a sentinel that names another registry.

* feat(knowledge): append a generated Knowledge index to owner-private sessions

* fix(knowledge): honor operator roles and name the real memory audience denial

Operator browsing of an agent's private knowledge now stays within the caller's role agents and requires operator.admin on a shared Gateway. A missing memory audience no longer blames a parent reset; the error points to the memory_audience_denied Gateway log entry without naming other sessions.

(cherry picked from commit 2745ceeed4)

* test(knowledge): keep the flush-plan test to tool policy and read-only behavior

Prompt phrasing is not a contract; the persistence tool set, NO_REPLY, determinism, and read-only null plan stay asserted.

* chore(knowledge): regenerate config baseline and worker inventory on current main

* test(knowledge): match the missing-audience denial by its new diagnostic

* fix(knowledge): re-admit a state database whose inode was recycled

Admission was cached per device:inode, so a deleted and recreated or restored database on a recycled inode skipped schema creation and failed with missing tables. An admitted inode must now also carry the current schema stamp; otherwise it is admitted again.

* fix(knowledge): check operator role and shared-Gateway policy live before each read

Operator browsing now calls the host's allowsAgent() and isSharedGateway() each time the principal is re-resolved, so a role or roster change during an awaited read refuses it before disclosure instead of trusting dispatch-time values.

* fix(knowledge): pin the rendered memory index for a session until its cutoff moves

Each turn re-rendered current records, and edits keep recorded_at, so a rename between turns changed the system prompt. The rendered text is now pinned per agent, session incarnation, store binding and cutoff, and authority is still checked live before reuse.

* feat(knowledge): subject hint on remember and agent review after maintenance relink

knowledge_remember accepts an optional per-item about hint, stored as
subject_hint; remember and relink resolve it before the claim text. A
configured maintenance.reviewJobId automation is queued after a pass that
leaves private remembered claims unlinked; its agent turn follows the
knowledge-unlinked-claims skill.

* feat(knowledge): count every pageless claim for the maintenance review

Maintenance queued the review only for unlinked knowledge_remember claims,
so claims saved unlinked through knowledge_create_claim were never reviewed.
The pending count and the skill's enumeration now cover every current claim
with no linked page and no source page, via knowledge_relink include: all
(dry run only; relink still links only remembered claims).

* feat(knowledge): list the busiest pages' newest decisions and commitments in the index

* fix(knowledge): recheck operator authority when saving store assignments

A store-assignment change checks operator.admin at admission, then waits for
the registry, store lanes and the config lock before writing. An operator who
disconnected or lost access meanwhile could still persist new membership.

plugins.sessionAction now gives handlers a live client.assertCurrent backed by
the Gateway's request authority. Knowledge passes it to the config writer as
writeOptions.assertCurrent, so publication is refused once the caller's
authority has ended, and accepts assignment changes only from hosts that
provide it.

* fix(knowledge): satisfy the type-assertion and forced-exit boundary guards

- History reads use a typed Kysely query against a declared history table
  instead of casting raw rows.
- The download picker uses an optional Window.showSaveFilePicker declaration
  and the DOM FileSystemWritableFileStream type instead of a window cast.
- The source-ingest scripts run from an async entry function and return from
  the help branch instead of calling process.exit.

* test(knowledge): narrow possibly-missing records in maintenance and index tests

* openclaw-87bf: split shared Knowledge skill guidance into topic references

* openclaw-395: rewrite meeting ingestion skill as a short routed procedure

* openclaw-395: speaker mapping, page-creation rules, writing style and new-store setup for meeting ingestion

* openclaw-14d: slim knowledge-entities onto shared topic references with gbrain parity

* openclaw-14d: carry gbrain meeting-ingestion rules into knowledge-meeting-ingest

* openclaw-c0f openclaw-b6d openclaw-5f3: no reference rereads on handoff, ingestion-scoped web lookups, ontology-led typing

* openclaw-b6d openclaw-5f3 openclaw-395: participant identity lookups, project typing, single-pass transcript digest

* openclaw-395: verify from drafts; no full published-page readback

* openclaw-951: lookup-first identity resolution with a reusable identity map

* openclaw-b22: compact knowledge_grep/lookup hits and a 10-hit default for agent calls

* feat(knowledge): search every named entity, page significant ones now, and state the remember call shape

* fix(knowledge): apply live operator policy to store record counts

stores_snapshot counted every running store's private records with an access
that checked only static operator scopes, so an operator whose role excludes
an agent, or a non-admin on a shared Gateway, could read that agent's private
record count. Counts now resolve through featurePrincipal, pinned for each
storage check, through a member the operator may browse; forbidden counts stay
null.

* fix(knowledge): type withSearchDetail through Type.Object instead of a chained assertion

* test(knowledge): remove unchecked any casts from the Knowledge suite

The repository keeps unchecked `as any` casts at zero; the imported Knowledge
tests had 602. Most were redundant (casting values already typed any). The
rest now use real types: typed fixture returns, contract and record types,
literal tuples, non-null assertions where tests already rely on presence,
small subclasses for storage and Git fakes, and single-step assertions to real
types for deliberately partial inputs. No assertion changed.

The five ingestion-contract @ts-expect-error checks are deliberate negative
type tests and join the inventory's explicit allow-list.

* feat(knowledge): route /learn into knowledge-ingest with source-faithful supersession

* chore(knowledge): align fs-safe with main at 0.26.11

* chore(knowledge): regenerate config baseline and worker inventory on current main

* fix(knowledge): state the invariant behind the search-detail input cast

* docs(learn): describe /learn as saving to skills or memory

* fix(knowledge): break storage and retrieval import cycles and clear lint errors

* chore(knowledge): regenerate config baseline on current main

* chore(knowledge): regenerate plugin inventory on current main

* fix(knowledge): key the pinned memory index by physical store

A binding can move to a different physical store (share the store, then use
own), so a pin keyed by binding, session and cutoff could serve the previous
store's index. The pin key now includes the store's vault ID.

* test(knowledge): walk test trees with listDirectoryTreeStrict

* test(knowledge): consolidate duplicated and low-value tests

* test(knowledge): drop low-stakes single-purpose tests

* ci: raise test-lines ceiling to 6,363,000 for bundled Knowledge

* ci: keep main's test-lines ceiling; regenerate worker inventory after main merge
2026-10-25 10:30:07 -07:00
..
…