mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
clawdbot-4a6: defer transcript identity api to contract
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
612a1bd7e585b9f2ab3661137e9cf335598d4cd13e6863be88a4c29fe17a3173 plugin-sdk-api-baseline.json
|
||||
50172cdfae7d3fb6b5d060be0899ca2afdc3b2adc8629e3b65a03d55755065a0 plugin-sdk-api-baseline.jsonl
|
||||
5db28bde1ec593bd1aaa08d1b95b466ac79e422d7677d1ce8c64e75eb4b06eee plugin-sdk-api-baseline.json
|
||||
4f308dd4bb49e9775a0499228e55103ecd7a687d382f2116b7e8ec16927bb2a3 plugin-sdk-api-baseline.jsonl
|
||||
|
||||
@@ -148,16 +148,11 @@ export { resolveGroupSessionKey } from "../config/sessions/group.js";
|
||||
export { canonicalizeMainSessionAlias } from "../config/sessions/main-session.js";
|
||||
export {
|
||||
clearSessionStoreCacheForTest,
|
||||
cleanupSessionLifecycleArtifacts,
|
||||
recordSessionMetaFromInbound,
|
||||
saveSessionStore,
|
||||
updateLastRoute,
|
||||
updateSessionStore,
|
||||
} from "../config/sessions/store.js";
|
||||
export type {
|
||||
SessionLifecycleArtifactCleanupParams,
|
||||
SessionLifecycleArtifactCleanupResult,
|
||||
} from "../config/sessions/store.js";
|
||||
export {
|
||||
evaluateSessionFreshness,
|
||||
resolveChannelResetConfig,
|
||||
|
||||
@@ -11,10 +11,6 @@ describe("extractTranscriptStemFromSessionsMemoryHit", () => {
|
||||
expect(extractTranscriptStemFromSessionsMemoryHit("sessions/abc-uuid.jsonl")).toBe("abc-uuid");
|
||||
});
|
||||
|
||||
it("reads storage-neutral transcript keys without basename parsing", () => {
|
||||
expect(extractTranscriptStemFromSessionsMemoryHit("transcript:main:abc-uuid")).toBe("abc-uuid");
|
||||
});
|
||||
|
||||
it("handles plain basename jsonl", () => {
|
||||
expect(extractTranscriptStemFromSessionsMemoryHit("def-topic-thread.jsonl")).toBe(
|
||||
"def-topic-thread",
|
||||
@@ -145,16 +141,6 @@ describe("extractTranscriptStemFromSessionsMemoryHit", () => {
|
||||
});
|
||||
|
||||
describe("extractTranscriptIdentityFromSessionsMemoryHit", () => {
|
||||
it("extracts owner metadata from storage-neutral transcript keys", () => {
|
||||
expect(
|
||||
extractTranscriptIdentityFromSessionsMemoryHit("transcript:agent-a:session:with:colon"),
|
||||
).toEqual({
|
||||
stem: "session:with:colon",
|
||||
ownerAgentId: "agent-a",
|
||||
archived: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("extracts owner metadata from agent-scoped session archive paths", () => {
|
||||
expect(
|
||||
extractTranscriptIdentityFromSessionsMemoryHit(
|
||||
@@ -207,16 +193,6 @@ describe("resolveTranscriptStemToSessionKeys", () => {
|
||||
expect(keys).toEqual(["agent:main:s1", "agent:peer:s2"]);
|
||||
});
|
||||
|
||||
it("accepts storage-neutral entries while preserving the legacy store parameter", () => {
|
||||
const entries: Record<string, SessionEntry> = {
|
||||
"agent:main:s1": baseEntry({ sessionId: "sqlite-session" }),
|
||||
};
|
||||
|
||||
expect(resolveTranscriptStemToSessionKeys({ entries, stem: "sqlite-session" })).toEqual([
|
||||
"agent:main:s1",
|
||||
]);
|
||||
});
|
||||
|
||||
it("falls back to archived owner metadata when deleted archives are gone from the live store", () => {
|
||||
const keys = resolveTranscriptStemToSessionKeys({
|
||||
store: {},
|
||||
|
||||
@@ -7,7 +7,6 @@ import { normalizeAgentId } from "../routing/session-key.js";
|
||||
|
||||
export { loadCombinedSessionStoreForGateway } from "../config/sessions/combined-store-gateway.js";
|
||||
|
||||
const TRANSCRIPT_KEY_PREFIX = "transcript:";
|
||||
const QMD_ARCHIVE_STEM_RE = /^(.+)-jsonl-(reset|deleted)-(.+)$/;
|
||||
const QMD_ARCHIVE_TIMESTAMP_RE =
|
||||
/^(\d{4}-\d{2}-\d{2})[tT](\d{2}-\d{2}-\d{2})(?:(?:\.|-)(\d{3}))?[zZ]$/;
|
||||
@@ -47,24 +46,7 @@ export type SessionTranscriptHitIdentity = {
|
||||
archived: boolean;
|
||||
};
|
||||
|
||||
function parseTranscriptKey(hitPath: string): { base: string; ownerAgentId?: string } | null {
|
||||
if (!hitPath.startsWith(TRANSCRIPT_KEY_PREFIX)) {
|
||||
return null;
|
||||
}
|
||||
const parts = hitPath.slice(TRANSCRIPT_KEY_PREFIX.length).split(":");
|
||||
const agentId = parts.shift()?.trim();
|
||||
const sessionId = parts.join(":").trim();
|
||||
if (!agentId || !sessionId) {
|
||||
return null;
|
||||
}
|
||||
return { base: sessionId, ownerAgentId: normalizeAgentId(agentId) };
|
||||
}
|
||||
|
||||
function parseSessionsPath(hitPath: string): { base: string; ownerAgentId?: string } | null {
|
||||
const transcriptKey = parseTranscriptKey(hitPath);
|
||||
if (transcriptKey) {
|
||||
return transcriptKey;
|
||||
}
|
||||
function parseSessionsPath(hitPath: string): { base: string; ownerAgentId?: string } {
|
||||
const normalized = hitPath.replace(/\\/g, "/");
|
||||
const fromSessionsRoot = normalized.startsWith("sessions/")
|
||||
? normalized.slice("sessions/".length)
|
||||
@@ -79,9 +61,10 @@ function parseSessionsPath(hitPath: string): { base: string; ownerAgentId?: stri
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive transcript stem `S` from a memory search hit key for `source === "sessions"`.
|
||||
* Storage-neutral hits use `transcript:<agent>:<session>`. Legacy file/QMD
|
||||
* paths remain accepted so older session collections stay visibility-gated.
|
||||
* Derive transcript stem `S` from a memory search hit path for `source === "sessions"`.
|
||||
* Builtin index uses `sessions/<basename>.jsonl`; QMD exports use `<stem>.md`.
|
||||
* Archived transcripts (`.jsonl.reset.<iso>` / `.jsonl.deleted.<iso>`) resolve
|
||||
* to the same stem as the live `.jsonl` they were rotated from.
|
||||
*/
|
||||
export function extractTranscriptStemFromSessionsMemoryHit(hitPath: string): string | null {
|
||||
return extractTranscriptIdentityFromSessionsMemoryHit(hitPath)?.stem ?? null;
|
||||
@@ -91,14 +74,7 @@ export function extractTranscriptIdentityFromSessionsMemoryHit(
|
||||
hitPath: string,
|
||||
): SessionTranscriptHitIdentity | null {
|
||||
const isQmdPath = hitPath.replace(/\\/g, "/").startsWith("qmd/");
|
||||
const parsed = parseSessionsPath(hitPath);
|
||||
if (!parsed) {
|
||||
return null;
|
||||
}
|
||||
const { base, ownerAgentId } = parsed;
|
||||
if (hitPath.startsWith(TRANSCRIPT_KEY_PREFIX)) {
|
||||
return { stem: base, ownerAgentId, archived: false };
|
||||
}
|
||||
const { base, ownerAgentId } = parseSessionsPath(hitPath);
|
||||
const archivedStem = parseUsageCountedSessionIdFromFileName(base);
|
||||
if (archivedStem && base !== `${archivedStem}.jsonl`) {
|
||||
return { stem: archivedStem, ownerAgentId, archived: true };
|
||||
@@ -136,13 +112,12 @@ export function extractTranscriptIdentityFromSessionsMemoryHit(
|
||||
* `createSessionVisibilityGuard`), including cross-agent cases.
|
||||
*/
|
||||
export function resolveTranscriptStemToSessionKeys(params: {
|
||||
store?: Record<string, SessionEntry>;
|
||||
entries?: Record<string, SessionEntry>;
|
||||
store: Record<string, SessionEntry>;
|
||||
stem: string;
|
||||
archivedOwnerAgentId?: string;
|
||||
allowQmdSlugFallback?: boolean;
|
||||
}): string[] {
|
||||
const store = params.entries ?? params.store ?? {};
|
||||
const { store } = params;
|
||||
const matches: string[] = [];
|
||||
const stemAsFile = params.stem.endsWith(".jsonl") ? params.stem : `${params.stem}.jsonl`;
|
||||
const parsedStemId = parseUsageCountedSessionIdFromFileName(stemAsFile);
|
||||
|
||||
Reference in New Issue
Block a user