Files
package-language-reader-run…/src/cache.ts
T

68 lines
2.2 KiB
TypeScript

/** Cache only semantic inputs. Scope/context stay in the source-range identity; generation is scheduling.
* This pure wire-format helper is shared by the runtime and presentation.
*/
export function cacheConfiguration(
identity: string,
scope: string,
_generation: string,
options: Record<string, unknown>,
inputs: readonly string[],
) {
return JSON.stringify({
processor: identity,
scope,
options: Object.fromEntries([...inputs].sort().map((key) => [key, options[key]])),
});
}
/** Keep transaction reads bounded, without one serial RPC per historical job.
* Relationship order still decides which reusable result wins. */
export async function findCachedJob<T>(
history: readonly T[],
read: (reference: T) => Promise<{ key: string; status: string }>,
key: string,
retry: boolean,
) {
let retries = 0;
for (let offset = 0; offset < history.length; offset += 32) {
const batch = history.slice(offset, offset + 32);
const records = await Promise.all(batch.map(read));
for (let index = 0; index < batch.length; index++) {
const data = records[index];
if (data.key !== key) continue;
retries++;
if (data.status === "queued" || (!retry && data.status === "ready")) return { reference: batch[index], retries };
}
}
return { reference: undefined, retries };
}
/** Compare persisted semantic configurations without scheduling choices. The
* original wire format retained generation; removing it preserves old results
* when an author switches between preparation and intent-driven generation. */
export function sameCacheConfiguration(a: string, b: string) {
if (a === b) return true;
try {
const semantic = (raw: string) => {
const { processor, scope, options } = JSON.parse(raw);
if (
typeof processor !== "string" ||
typeof scope !== "string" ||
!options ||
typeof options !== "object" ||
Array.isArray(options)
)
return null;
return JSON.stringify({
processor,
scope,
options: Object.fromEntries(Object.entries(options).sort(([a], [b]) => a.localeCompare(b))),
});
};
const left = semantic(a);
return left !== null && left === semantic(b);
} catch {
return false;
}
}