Skip to content
English

development/skills/agent-core-app/scripts/lib/knowledge.mjs ​

js
/**
 * App-owned knowledge loading for the `agent-core-app` Skill.
 *
 * Reads the App's `knowledge.config.json` allowlist, verifies each referenced document against the
 * configured byte limit, and compiles the documents into a Knowledge Kit catalog. This is App
 * configuration code, not a Core file-store API: no model or request may supply a filesystem path.
 *
 * Exports: `compileApplicationKnowledge`, `readApplicationKnowledge`, `loadApplicationKnowledge`.
 */
import { readFile } from 'node:fs/promises';
import { createHash } from 'node:crypto';
import { Knowledge } from '@jangts/agent-core/kits/knowledge';

/**
 * Compile parsed documents into a Knowledge catalog.
 *
 * @param documents Documents produced by `Knowledge.parseKnowledgeDocument`.
 * @param policy Validated `knowledge.config.json` content (`schemaVersion`, `maxReadChars`,
 *   `requiredReads`).
 * @returns The compiled catalog; required reads are resolved so a missing read fails here.
 * @throws {TypeError} When the policy shape or a required read is invalid.
 */
export function compileApplicationKnowledge(documents, policy) {
  if (
    !policy ||
    policy.schemaVersion !== 1 ||
    !Number.isSafeInteger(policy.maxReadChars) ||
    policy.maxReadChars < 1 ||
    !Array.isArray(policy.requiredReads)
  )
    throw new TypeError('Invalid application knowledge policy');
  const catalog = Knowledge.defineKnowledgeCatalog(documents, { maxChars: policy.maxReadChars });
  // Required task reads must fit their runtime content budget as well as resolve.
  for (const read of policy.requiredReads) catalog.read(read);
  return catalog;
}

/**
 * Read the knowledge config and its allowed documents from one directory.
 *
 * The config hash is computed over the exact bytes parsed below, so a proposal identity cannot
 * drift from the document catalog it was derived from.
 *
 * @param directory Directory holding `knowledge.config.json` and the listed documents.
 * @returns Parsed `documents`, the raw `policy` and the `baseConfigSha256` of the config file.
 * @throws {TypeError} When the config or a document entry fails validation.
 * @throws {RangeError} When a source document exceeds `maxDocumentBytes`.
 */
export async function readApplicationKnowledge(directory = new URL('./', import.meta.url)) {
  // Bind validation and proposal identity to the exact bytes parsed below.
  const configBytes = await readFile(new URL('knowledge.config.json', directory));
  const baseConfigSha256 = createHash('sha256').update(configBytes).digest('hex');
  const policy = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(configBytes));
  if (
    !Array.isArray(policy.documents) ||
    !Number.isSafeInteger(policy.maxDocumentBytes) ||
    policy.maxDocumentBytes < 1
  )
    throw new TypeError('Invalid application document catalog');
  const documents = await Promise.all(
    policy.documents.map(async (entry) => {
      // The allowlist is App-maintained. Neither a model nor a request supplies this filesystem path.
      if (
        !entry ||
        typeof entry.id !== 'string' ||
        typeof entry.file !== 'string' ||
        !/^[a-z0-9][a-z0-9.-]*\.knowledge\.md$/.test(entry.file) ||
        (entry.locale !== undefined && typeof entry.locale !== 'string')
      )
        throw new TypeError('Invalid application document entry');
      const bytes = await readFile(new URL(entry.file, directory));
      if (bytes.length > policy.maxDocumentBytes)
        throw new RangeError('Source document exceeds the App limit');
      const text = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
      const revision = createHash('sha256')
        .update(JSON.stringify([entry.id, entry.locale, text]))
        .digest('hex');
      return Knowledge.parseKnowledgeDocument({
        id: entry.id,
        revision,
        locale: entry.locale,
        text,
      });
    }),
  );
  return { documents, policy, baseConfigSha256 };
}

/**
 * Read and compile the App knowledge catalog in one step.
 *
 * @param directory Directory holding `knowledge.config.json` and the listed documents.
 * @returns The compiled Knowledge catalog.
 * @throws {TypeError | RangeError} Same validation failures as `readApplicationKnowledge` and
 *   `compileApplicationKnowledge`.
 */
export async function loadApplicationKnowledge(directory = new URL('./', import.meta.url)) {
  const { documents, policy } = await readApplicationKnowledge(directory);
  return compileApplicationKnowledge(documents, policy);
}

接口参考、使用示例与开发指南。