/*
RFC-0319: omit-empty serialization for agent knowledge JSON envelopes.
Prunes empty strings, empty objects, and empty arrays from public knowledge
payloads before hashing and serialization. Never omits false, 0, or null
when schema explicitly allows them.
- Do not omit false, 0, or null when schema allows them.
- Do not invent values to fill empty fields.
- RFC-0319: initial implementation.
*/
export interface OmitEmptyOptions {
/** JSON pointer paths where empty arrays are meaningful and should be preserved. */
preserveEmptyArraysFor?: readonly string[];
/** JSON pointer paths where empty objects are meaningful and should be preserved. */
preserveEmptyObjectsFor?: readonly string[];
}
/**
* RFC-0319: Recursively prune empty strings, empty objects, and empty arrays.
* Returns `undefined` if the entire value becomes empty after pruning.
*/
export function omitEmptyKnowledgeValues(
value: T,
opts: OmitEmptyOptions = {},
path = "",
): T | undefined {
if (value === null || value === undefined) return undefined;
if (typeof value === "string") {
const trimmed = value.trim();
return trimmed === "" ? undefined : (value as T);
}
if (typeof value === "boolean" || typeof value === "number") {
return value;
}
if (Array.isArray(value)) {
const pruned = value
.map((item, i) => omitEmptyKnowledgeValues(item, opts, `${path}/${i}`))
.filter((item) => item !== undefined);
if (pruned.length === 0) {
const preserve = opts.preserveEmptyArraysFor?.includes(path);
return preserve ? ([] as unknown as T) : undefined;
}
return pruned as unknown as T;
}
if (typeof value === "object") {
const result: Record = {};
for (const [key, val] of Object.entries(value as Record)) {
const childPath = `${path}/${key}`;
const pruned = omitEmptyKnowledgeValues(val, opts, childPath);
if (pruned !== undefined) {
result[key] = pruned;
}
}
const keys = Object.keys(result);
if (keys.length === 0) {
const preserve = opts.preserveEmptyObjectsFor?.includes(path);
return preserve ? ({} as unknown as T) : undefined;
}
return result as unknown as T;
}
return value;
}