





















@@ -10,6 +10,7 @@ const PROMPT_BLOB_VERSION: SessionSkillPromptRef["version"] = 1;
1010const MIN_PROMPT_BLOB_CHARS = 512;
1111const MAX_PROMPT_BLOB_BYTES = 512 * 1024;
1212const PROMPT_REF_CACHE_MAX_ENTRIES = 256;
13+const VALID_PROMPT_BLOB_CACHE_MAX_ENTRIES = 256;
13141415type PersistedSessionStore = {
1516store: Record<string, SessionEntry>;
@@ -27,13 +28,15 @@ export type SessionStorePersistenceProjection = PersistedSessionStore & {
2728};
28292930const promptRefCache = new Map<string, SessionSkillPromptRef>();
31+const validPromptBlobCache = new Map<string, { mtimeMs: number; size: number; prompt: string }>();
30323133function hashPrompt(prompt: string): string {
3234return crypto.createHash(PROMPT_BLOB_ALGORITHM).update(prompt).digest("hex");
3335}
34363537export function clearSessionSkillPromptRefCache(): void {
3638promptRefCache.clear();
39+validPromptBlobCache.clear();
3740}
38413942export function getSessionSkillPromptRefCacheStatsForTest(): {
@@ -46,6 +49,16 @@ export function getSessionSkillPromptRefCacheStatsForTest(): {
4649};
4750}
485152+export function getValidSessionSkillPromptBlobCacheStatsForTest(): {
53+entries: number;
54+maxEntries: number;
55+} {
56+return {
57+entries: validPromptBlobCache.size,
58+maxEntries: VALID_PROMPT_BLOB_CACHE_MAX_ENTRIES,
59+};
60+}
61+4962function isSha256Hex(value: string): boolean {
5063return /^[a-f0-9]{64}$/u.test(value);
5164}
@@ -90,6 +103,17 @@ function shouldStorePromptAsBlob(prompt: string): boolean {
90103return prompt.length >= MIN_PROMPT_BLOB_CHARS && bytes <= MAX_PROMPT_BLOB_BYTES;
91104}
92105106+function rememberValidPromptBlob(blobPath: string, stat: fs.Stats, prompt: string): void {
107+validPromptBlobCache.set(blobPath, { mtimeMs: stat.mtimeMs, size: stat.size, prompt });
108+while (validPromptBlobCache.size > VALID_PROMPT_BLOB_CACHE_MAX_ENTRIES) {
109+const oldest = validPromptBlobCache.keys().next().value;
110+if (typeof oldest !== "string") {
111+break;
112+}
113+validPromptBlobCache.delete(oldest);
114+}
115+}
116+93117function readValidPromptBlob(storePath: string, ref: SessionSkillPromptRef): string | null {
94118if (
95119ref.version !== PROMPT_BLOB_VERSION ||
@@ -109,13 +133,22 @@ function readValidPromptBlob(storePath: string, ref: SessionSkillPromptRef): str
109133try {
110134const stat = fs.statSync(blobPath);
111135if (!stat.isFile() || stat.size !== ref.bytes) {
136+validPromptBlobCache.delete(blobPath);
112137return null;
113138}
139+const cached = validPromptBlobCache.get(blobPath);
140+if (cached && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) {
141+return cached.prompt;
142+}
114143const prompt = fs.readFileSync(blobPath, "utf8");
115-return hashPrompt(prompt) === ref.hash && Buffer.byteLength(prompt, "utf8") === ref.bytes
116- ? prompt
117- : null;
144+if (hashPrompt(prompt) !== ref.hash || Buffer.byteLength(prompt, "utf8") !== ref.bytes) {
145+validPromptBlobCache.delete(blobPath);
146+return null;
147+}
148+rememberValidPromptBlob(blobPath, stat, prompt);
149+return prompt;
118150} catch {
151+validPromptBlobCache.delete(blobPath);
119152return null;
120153}
121154}
@@ -140,6 +173,7 @@ async function ensurePromptBlob(storePath: string, prompt: string): Promise<Sess
140173// sessions.json is replaced. Refresh its mtime so orphan cleanup does not
141174// reclaim the blob while the store write is still in flight.
142175await fs.promises.utimes(blobPath, now, now);
176+rememberValidPromptBlob(blobPath, await fs.promises.stat(blobPath), prompt);
143177return ref;
144178} catch {
145179// A concurrent cleanup may have removed it; rewrite below.
@@ -151,6 +185,7 @@ async function ensurePromptBlob(storePath: string, prompt: string): Promise<Sess
151185mode: 0o600,
152186tempPrefix: path.basename(blobPath),
153187});
188+rememberValidPromptBlob(blobPath, await fs.promises.stat(blobPath), prompt);
154189return ref;
155190}
156191此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。