/*
RFC-0287: the static Agent Surface knowledge tier. Defines the closed domain
list, the per-domain envelope shape, and the pure envelope formatter. Callers
(kernel commands) load and project business content through the existing
RFC-0148 projectors and pass the already-resolved per-language payload here —
this module never reads files or invents fact shapes.
- Do not read content or call projectors — the kernel command does that.
- Do not define new fact shapes — extend business-projection.ts/models.ts first.
- RFC-0287: initial knowledge tier — domain list, envelope, formatter.
- RFC-0602: allow null lastVerified in AgentKnowledgeFreshness for derived-source fallback.
*/
import { computeAgentManifestContentHash } from "./manifest.ts";
import type { AgentSurfaceProof } from "./proof.ts";
/** Exactly the `public`-visibility keys of BUSINESS_DOMAIN_VISIBILITY (RFC-0148). */
export const AGENT_KNOWLEDGE_DOMAINS = [
"company",
"legal",
"contact",
"offer",
"service",
"location",
"web",
"people",
"trust",
"faq",
] as const;
export type AgentKnowledgeDomain = (typeof AGENT_KNOWLEDGE_DOMAINS)[number];
export function isAgentKnowledgeDomain(value: string): value is AgentKnowledgeDomain {
return (AGENT_KNOWLEDGE_DOMAINS as readonly string[]).includes(value);
}
export interface AgentKnowledgeFreshness {
lastVerified: string | null;
source: "ckl-claim-ledger" | "authored-verification" | "derived-source";
coverage: "domain";
}
export interface AgentKnowledgeEnvelope {
/** e.g. "gogol.agent.knowledge/offer@1" or @2 for RFC-0319 shape changes. */
schema: string;
site: string;
baseUrl: string;
languages: { default: string; supported: string[] };
/** sha256 hex over sorted-key JSON of this document minus contentHash. */
contentHash: string;
/** RFC-0319: required freshness for every emitted envelope. */
freshness?: AgentKnowledgeFreshness;
/** Per-language payload; non-default languages carry only overlay fields (RFC-0008). */
data: Record;
/** RFC-0308: detached Ed25519 proof, null/absent when unsigned. */
proof?: AgentSurfaceProof | null;
}
export interface AgentKnowledgeBuildInput {
domain: AgentKnowledgeDomain;
site: string;
baseUrl: string;
languages: { default: string; supported: string[] };
/** Already-projected per-language payload — never raw content. */
data: Record;
freshness?: AgentKnowledgeFreshness;
/** RFC-0319: schema version. Defaults to 1. Bump to 2 for breaking shape changes. */
schemaVersion?: number;
}
/** Pure: assemble + hash one domain's knowledge envelope. Deterministic. */
export function formatAgentKnowledge(
input: AgentKnowledgeBuildInput,
): AgentKnowledgeEnvelope {
const version = input.schemaVersion ?? 1;
const base: Omit, "contentHash"> = {
schema: `gogol.agent.knowledge/${input.domain}@${version}`,
site: input.site,
baseUrl: input.baseUrl.replace(/\/+$/, ""),
languages: {
default: input.languages.default,
supported: [...input.languages.supported].sort(),
},
...(input.freshness ? { freshness: input.freshness } : {}),
data: input.data,
};
const contentHash = computeAgentManifestContentHash(base as unknown as Record);
return { ...base, contentHash };
}