Files
Nicolò Boschi 4d22a882f5 docs(knowledge-pages): document Knowledge Pages and Mental Models, and manage them from the CLI (#3151)
* docs(knowledge-pages): document Knowledge Pages and Mental Models

Knowledge Pages shipped in #2455 with no documentation at all — no
architecture page, no API page, no mention in the sidebar. Mental models
had an API page but nothing explaining what they are or why they are
fast. Add both, as top-level entries under Architecture and API.

- Architecture: how pages are mental models with a simplified,
  document-shaped configuration; the folder hierarchy; the `hindsight fs`
  filesystem projection; page-level search; and why a projected view over
  reconciled memory is not the same thing as a folder of raw files.
- Architecture: mental models as standing answers built in the background,
  so an application reads the current version instead of paying for
  synthesis on the request path.
- API: the full knowledge-base endpoint surface, the page defaults and
  what each one buys, staleness gating, what a refresh reads, and how
  delta mode edits a structured document instead of regenerating prose.
  The mental-model trigger table gains the seven settings it was missing.
- FAQ: mental model vs knowledge page. Also corrects the neighbouring
  answer, which described mental models as built automatically during
  retain — that is observations.

The API examples use the maintained clients like every other API page, so
this adds the knowledge-base surface to the Python and TypeScript wrappers
(kept at parity, with request-mapping tests on both sides) and runnable
Python/Node/Go examples.

* feat(cli): manage knowledge pages from the CLI

The knowledge base was reachable from every client except the CLI, where
the eight endpoints were listed as deliberate coverage skips ("managed in
the control plane UI"). That left `hindsight fs` able to mirror pages
read-only but nothing able to create, edit, search, or delete them — and
it meant the API docs could not show a CLI tab alongside Python/Node/Go.

Adds `hindsight knowledge-base` with tree, create-folder, create-page,
get-page, search, update, delete, and export, removing the skips so
cli-coverage-check enforces the surface from here on.

`create-page` sends no trigger unless --mode or --fact-types is passed, so
the server's page defaults stand; when either is given the whole trigger
has to be restated, because a supplied trigger replaces the defaults
rather than merging with them.

Also adds the CLI tab to the Knowledge Pages API page and a Knowledge Base
section to the CLI reference.
2026-08-03 14:53:57 +02:00

107 lines
3.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Knowledge Pages API examples for Hindsight (Node.js)
* Run: node examples/api/knowledge-pages.mjs
*/
import { HindsightClient } from '@vectorize-io/hindsight-client';
const HINDSIGHT_URL = process.env.HINDSIGHT_API_URL || 'http://localhost:8888';
const BANK_ID = 'knowledge-pages-demo-bank-node';
// =============================================================================
// Setup (not shown in docs)
// =============================================================================
const client = new HindsightClient({ baseUrl: HINDSIGHT_URL });
await client.createBank(BANK_ID, { name: 'Knowledge Pages Demo' });
await client.retain(BANK_ID, 'The API is deployed to Kubernetes with a rolling update');
await client.retain(BANK_ID, 'Deploys run from the main branch after CI passes');
await client.retain(BANK_ID, 'A failed deploy is rolled back by redeploying the previous tag');
await new Promise(r => setTimeout(r, 2000));
// =============================================================================
// Doc Examples
// =============================================================================
// [docs:create-folder]
// Create a folder (omit parentId, or pass null, to create it at the root)
const folder = await client.createKnowledgeFolder(BANK_ID, 'Operations');
console.log(`Folder ID: ${folder.id}`);
// [/docs:create-folder]
// [docs:create-page]
// Create a page — content is generated in the background
const page = await client.createKnowledgePage(
BANK_ID,
'Deploying the API',
'How is the API deployed?',
{ parentId: folder.id, tags: ['ops', 'type:runbook'] },
);
// Poll the operation to know when the first build has finished
console.log(`Page ID: ${page.page_id}, operation: ${page.operation_id}`);
// [/docs:create-page]
// Wait for the page's first build
await new Promise(r => setTimeout(r, 20000));
// [docs:get-tree]
// Fetch the whole knowledge base as a nested folder/page tree (no page bodies)
const tree = await client.getKnowledgeBaseTree(BANK_ID);
for (const root of tree.roots) {
console.log(`${root.kind}: ${root.name}`);
for (const child of root.children ?? []) {
console.log(` ${child.kind}: ${child.name} (stale: ${child.is_stale})`);
}
}
// [/docs:get-tree]
// [docs:get-page]
// Read a page as a markdown document
const document = await client.getKnowledgePage(BANK_ID, page.page_id);
console.log(document.type); // "runbook" — from the type:runbook tag
console.log(document.body); // the synthesized markdown body
console.log(document.markdown); // YAML frontmatter + body
// [/docs:get-page]
// [docs:search-pages]
// Hybrid search (full-text + vector) over whole pages
const results = await client.searchKnowledgeBase(BANK_ID, 'how do we deploy', { limit: 5 });
for (const hit of results.results) {
console.log(`${hit.score.toFixed(3)} ${hit.name}: ${hit.snippet}`);
}
// [/docs:search-pages]
// [docs:update-node]
// Rename a node, move it, and/or update a page's options.
// Changing sourceQuery rebuilds the page against the new question.
await client.updateKnowledgeNode(BANK_ID, page.page_id, {
name: 'Deploying the API (v2)',
tags: ['ops', 'type:runbook', 'reviewed'],
});
// [/docs:update-node]
// [docs:export]
// Export the knowledge base as a portable markdown bundle
const bundle = await client.exportKnowledgeBase(BANK_ID);
for (const file of bundle.files) {
console.log(file.path); // index.md, <page-id>.md, <page-id>.log.md
}
// [/docs:export]
// [docs:delete-node]
// Delete a folder or page — deleting a folder removes its whole subtree
await client.deleteKnowledgeNode(BANK_ID, folder.id);
// [/docs:delete-node]
// =============================================================================
// Cleanup (not shown in docs)
// =============================================================================
await client.deleteBank(BANK_ID);
console.log('knowledge-pages.mjs: All examples passed');