diff --git a/src/plugin-sdk/config-runtime.ts b/src/plugin-sdk/config-runtime.ts index abc13e0da0fb..c8a2bb675d5d 100644 --- a/src/plugin-sdk/config-runtime.ts +++ b/src/plugin-sdk/config-runtime.ts @@ -8,6 +8,7 @@ import { loadSessionStore as loadSessionStoreImpl } from "../config/sessions/sto export { getSessionEntry, listSessionEntries, + patchSessionEntry, updateSessionStoreEntry, upsertSessionEntry, } from "./session-store-runtime.js"; @@ -147,7 +148,6 @@ export type { } from "../config/types.js"; export { clearSessionStoreCacheForTest, - patchSessionEntry, readSessionUpdatedAt, recordSessionMetaFromInbound, saveSessionStore, diff --git a/src/plugin-sdk/session-store-runtime.test.ts b/src/plugin-sdk/session-store-runtime.test.ts index fc3b670bf5af..12c62a012708 100644 --- a/src/plugin-sdk/session-store-runtime.test.ts +++ b/src/plugin-sdk/session-store-runtime.test.ts @@ -5,6 +5,7 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { getSessionEntry, listSessionEntries, + patchSessionEntry, updateSessionStoreEntry, upsertSessionEntry, } from "./session-store-runtime.js"; @@ -80,6 +81,19 @@ describe("session-store-runtime compatibility surface", () => { updatedAt: 10, }, }); + const beforePatch = getSessionEntry({ sessionKey, storePath }); + await expect( + patchSessionEntry({ + sessionKey, + storePath, + preserveActivity: true, + update: () => ({ providerOverride: "openai", updatedAt: 20 }), + }), + ).resolves.toMatchObject({ + providerOverride: "openai", + sessionId: "session-1", + updatedAt: beforePatch?.updatedAt, + }); await expect( updateSessionStoreEntry({ sessionKey, diff --git a/src/plugin-sdk/session-store-runtime.ts b/src/plugin-sdk/session-store-runtime.ts index f225557a4da9..505ecfe0e4b9 100644 --- a/src/plugin-sdk/session-store-runtime.ts +++ b/src/plugin-sdk/session-store-runtime.ts @@ -3,6 +3,7 @@ import { listSessionEntries as listAccessorSessionEntries, loadSessionEntry, + patchSessionEntry as patchAccessorSessionEntry, replaceSessionEntry, updateSessionEntry, } from "../config/sessions/session-accessor.js"; @@ -28,6 +29,18 @@ type SessionStoreEntryUpdate = ( entry: SessionEntry, ) => Promise | null> | Partial | null; +type SessionStoreEntryPatch = ( + entry: SessionEntry, + context: { existingEntry?: SessionEntry }, +) => Promise | null> | Partial | null; + +type PatchSessionEntryParams = SessionStoreReadParams & { + fallbackEntry?: SessionEntry; + preserveActivity?: boolean; + replaceEntry?: boolean; + update: SessionStoreEntryPatch; +}; + type UpdateSessionStoreEntryParams = { storePath: string; sessionKey: string; @@ -70,6 +83,27 @@ export function listSessionEntries( }); } +/** Patches one session entry through the accessor seam. */ +export async function patchSessionEntry( + params: PatchSessionEntryParams, +): Promise { + return await patchAccessorSessionEntry( + { + agentId: params.agentId, + env: params.env, + hydrateSkillPromptRefs: params.hydrateSkillPromptRefs, + sessionKey: params.sessionKey, + storePath: params.storePath, + }, + params.update, + { + fallbackEntry: params.fallbackEntry, + preserveActivity: params.preserveActivity, + replaceEntry: params.replaceEntry, + }, + ); +} + /** Updates an existing session entry through the accessor seam. */ export async function updateSessionStoreEntry( params: UpdateSessionStoreEntryParams, @@ -114,7 +148,6 @@ export { resolveGroupSessionKey } from "../config/sessions/group.js"; export { canonicalizeMainSessionAlias } from "../config/sessions/main-session.js"; export { clearSessionStoreCacheForTest, - patchSessionEntry, readSessionUpdatedAt, recordSessionMetaFromInbound, saveSessionStore, diff --git a/src/plugins/runtime/runtime-agent.ts b/src/plugins/runtime/runtime-agent.ts index 8777eba0bc6b..0462e128b390 100644 --- a/src/plugins/runtime/runtime-agent.ts +++ b/src/plugins/runtime/runtime-agent.ts @@ -13,12 +13,12 @@ import { resolveSessionFilePath, resolveStorePath } from "../../config/sessions/ import { listSessionEntries as listAccessorSessionEntries, loadSessionEntry, + patchSessionEntry as patchAccessorSessionEntry, replaceSessionEntry, updateSessionEntry, } from "../../config/sessions/session-accessor.js"; import { loadSessionStore, - patchSessionEntry, saveSessionStore, updateSessionStore, } from "../../config/sessions/store.js"; @@ -52,6 +52,16 @@ type RuntimeSessionStoreEntryUpdateParams = { takeCacheOwnership?: boolean; }; +type RuntimeSessionStoreEntryPatchParams = RuntimeSessionStoreReadParams & { + fallbackEntry?: SessionEntry; + preserveActivity?: boolean; + replaceEntry?: boolean; + update: ( + entry: SessionEntry, + context: { existingEntry?: SessionEntry }, + ) => Promise | null> | Partial | null; +}; + type RuntimeUpsertSessionEntryParams = RuntimeSessionStoreReadParams & { entry: SessionEntry; }; @@ -91,6 +101,26 @@ function listSessionEntries( }); } +async function patchSessionEntry( + params: RuntimeSessionStoreEntryPatchParams, +): Promise { + return await patchAccessorSessionEntry( + { + agentId: params.agentId, + env: params.env, + hydrateSkillPromptRefs: params.hydrateSkillPromptRefs, + sessionKey: params.sessionKey, + storePath: params.storePath, + }, + params.update, + { + fallbackEntry: params.fallbackEntry, + preserveActivity: params.preserveActivity, + replaceEntry: params.replaceEntry, + }, + ); +} + async function updateSessionStoreEntry( params: RuntimeSessionStoreEntryUpdateParams, ): Promise { diff --git a/src/plugins/runtime/types-core.ts b/src/plugins/runtime/types-core.ts index cfa4cd152d3f..aa9307c2c83e 100644 --- a/src/plugins/runtime/types-core.ts +++ b/src/plugins/runtime/types-core.ts @@ -222,7 +222,23 @@ export type PluginRuntimeCore = { sessionKey: string; entry: import("../../config/sessions/types.js").SessionEntry; }>; - patchSessionEntry: typeof import("../../config/sessions/store.js").patchSessionEntry; + patchSessionEntry: (params: { + agentId?: string; + env?: NodeJS.ProcessEnv; + fallbackEntry?: import("../../config/sessions/types.js").SessionEntry; + hydrateSkillPromptRefs?: boolean; + preserveActivity?: boolean; + replaceEntry?: boolean; + sessionKey: string; + storePath?: string; + update: ( + entry: import("../../config/sessions/types.js").SessionEntry, + context: { existingEntry?: import("../../config/sessions/types.js").SessionEntry }, + ) => + | Promise | null> + | Partial + | null; + }) => Promise; upsertSessionEntry: (params: { agentId?: string; env?: NodeJS.ProcessEnv;