diff --git a/CHANGELOG.md b/CHANGELOG.md index 61f1b9e08f8..7fd57cdec5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Docs: https://docs.openclaw.ai - Media understanding: convert HEIC and HEIF images to JPEG before image description providers run so iPhone photos work in direct and configured image-description flows. (#86037) - Agents: release embedded-attempt session locks from outer teardown so post-prompt exceptions cannot wedge later requests behind `SessionWriteLockTimeoutError`. Fixes #86014. Thanks @openperf. - Discord/OpenAI voice: rotate Realtime sessions at provider max duration without logging the expected session-expiry event as an error. +- Sessions: skip metadata-only entries during QMD-slugified session lookup so one incomplete row does not block transcript hit resolution. (#86327) Thanks @abnershang. - Agents/media: derive bundled plugin local-media trust from plugin tool metadata instead of importing the full plugin registry on subscription paths. (#84409) Thanks @samzong. - Image tool: keep config-backed custom-provider API keys usable for auto-discovered vision models, including deferred image-tool execution without env keys or auth profiles. (#85733) - Memory/local embeddings: run local GGUF embeddings in an isolated worker sidecar and degrade to configured fallback or keyword search on worker failure so native embedding crashes do not take down the Gateway. (#85348) Thanks @osolmaz. diff --git a/src/plugin-sdk/session-transcript-hit.test.ts b/src/plugin-sdk/session-transcript-hit.test.ts index 6522bf0b499..3e575950dfa 100644 --- a/src/plugin-sdk/session-transcript-hit.test.ts +++ b/src/plugin-sdk/session-transcript-hit.test.ts @@ -217,6 +217,23 @@ describe("resolveTranscriptStemToSessionKeys", () => { ).toEqual(["agent:main:s1"]); }); + it("ignores store entries without session ids during QMD-slugified fallback", () => { + const store: Record = { + "agent:main:non-session": { + updatedAt: 1, + } as SessionEntry, + "agent:main:s1": baseEntry({ sessionId: "foo_bar.v1" }), + }; + + expect( + resolveTranscriptStemToSessionKeys({ + store, + stem: "foo-bar-v1", + allowQmdSlugFallback: true, + }), + ).toEqual(["agent:main:s1"]); + }); + it("does not use QMD-slugified fallback unless requested", () => { const store: Record = { "agent:main:s1": baseEntry({ sessionId: "foo_bar.v1" }), diff --git a/src/plugin-sdk/session-transcript-hit.ts b/src/plugin-sdk/session-transcript-hit.ts index 26f0ca06540..45e6165ce26 100644 --- a/src/plugin-sdk/session-transcript-hit.ts +++ b/src/plugin-sdk/session-transcript-hit.ts @@ -151,7 +151,8 @@ export function resolveTranscriptStemToSessionKeys(params: { continue; } } - if (normalizeQmdSessionStem(entry.sessionId) === normalizedStem) { + const entrySessionId = normalizeOptionalString(entry.sessionId); + if (entrySessionId && normalizeQmdSessionStem(entrySessionId) === normalizedStem) { matches.push(sessionKey); } }