选读、预算和快照标识
策略的具体实现如下。
ts
export function defineKnowledgeCatalog(
documents: readonly KnowledgeDocument[],
options: KnowledgeCatalogOptions = {},
): KnowledgeCatalog {
const { maxChars } = options,
observe = options.observe?.bind(options);
const catalog = new Map<string, ReturnType<typeof compileKnowledgeDocument>>();
if (maxChars !== undefined && (!Number.isSafeInteger(maxChars) || maxChars < 1))
throw new TypeError('Invalid knowledge budget');
for (const document of documents) {
if (catalog.has(document.id))
throw new TypeError(`Duplicate knowledge document: ${document.id}`);
catalog.set(document.id, compileKnowledgeDocument(document));
}
const resolve = (input: KnowledgeRead) => {
if (!input || typeof input !== 'object') throw new TypeError('Invalid knowledge request');
const read = { documentId: input.documentId, selection: input.selection },
entry = catalog.get(read.documentId);
if (!entry) throw new TypeError(`Unknown knowledge document: ${read.documentId}`);
if (!read.selection || !['document', 'self', 'subtree'].includes(read.selection.mode))
throw new TypeError('Invalid knowledge selection');
if (read.selection.mode !== 'document') {
if (
!Array.isArray(read.selection.sectionIds) ||
!read.selection.sectionIds.length ||
new Set(read.selection.sectionIds).size !== read.selection.sectionIds.length
)
throw new TypeError('Invalid knowledge section selection');
for (const id of read.selection.sectionIds)
if (!entry.sections.has(id))
throw new TypeError(`Unknown knowledge section: ${read.documentId}/${id}`);
}
return { read, entry };
};
const sectionIds = (id: string) => {
const entry = catalog.get(id);
if (!entry) throw new TypeError(`Unknown knowledge document: ${id}`);
return Object.freeze([...entry.sections.keys()]);
};
const assertSelection = (read: KnowledgeRead) => {
resolve(read);
};
return Object.freeze({
...readonlyCatalog(
[...catalog.values()].map((entry) => entry.document),
(id) => new TypeError(`Unknown knowledge document: ${id}`),
),
sectionIds,
assertSelection,
read(
input: KnowledgeRead,
context: Partial<
Pick<import('../../structs/common.js').ExecutionContext, 'logger' | 'signal'>
> = {},
): KnowledgeSnapshot {
return nativeSubFlowSync(context, 'knowledge', input.documentId, () => {
const { read, entry } = resolve(input),
raw = read.selection;
const selection =
raw.mode === 'document'
? Object.freeze({ mode: 'document' as const })
: Object.freeze({ mode: raw.mode, sectionIds: Object.freeze([...raw.sectionIds]) });
const content = (
selection.mode === 'document'
? knowledgeText(entry.document.parts)
: selection.sectionIds
.map((id) =>
knowledgeText(entry.sections.get(id)!.parts, selection.mode === 'subtree'),
)
.join('\n\n')
).trim();
if (maxChars !== undefined && content.length > maxChars)
throw new RangeError('Knowledge selection exceeds its budget');
// Preserve the existing opaque snapshot identity format.
const identitySelection =
selection.mode === 'document'
? selection
: { mode: selection.mode, sections: selection.sectionIds };
const snapshot = Object.freeze({
documentId: read.documentId,
selection,
revision: entry.document.revision,
locale: entry.document.locale,
content,
id: JSON.stringify([
read.documentId,
entry.document.revision,
entry.document.locale,
identitySelection,
]),
});
observeSafely(observe, snapshot);
return snapshot;
});
},
});
}