Skip to content

Commit 22b85dd

Browse files
committed
clawdbot-d02.1.9.1.18.1: migrate bundled transcript target lookups
1 parent aaf6a2c commit 22b85dd

8 files changed

Lines changed: 369 additions & 236 deletions

extensions/discord/src/monitor/message-handler.process.test.ts

Lines changed: 24 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -198,31 +198,16 @@ const recordInboundSession = vi.hoisted(() =>
198198
vi.fn<(params?: unknown) => Promise<void>>(async () => {}),
199199
);
200200
const configSessionsMocks = vi.hoisted(() => ({
201-
loadSessionStore: vi.fn<(storePath: string, opts?: unknown) => Record<string, unknown>>(
202-
() => ({}),
203-
),
201+
getSessionEntry: vi.fn<(params?: unknown) => unknown>(() => undefined),
202+
readSessionTranscriptEvents: vi.fn<(params?: unknown) => Promise<unknown[]>>(async () => []),
204203
readSessionUpdatedAt: vi.fn<(params?: unknown) => number | undefined>(() => undefined),
205-
readLatestAssistantTextFromSessionTranscript: vi.fn<
206-
(sessionFile: string) => Promise<{ text: string; timestamp?: number } | undefined>
207-
>(async () => undefined),
208-
resolveAndPersistSessionFile: vi.fn<(params?: unknown) => Promise<{ sessionFile: string }>>(
209-
async () => ({ sessionFile: "/tmp/openclaw-discord-process-test-session.jsonl" }),
210-
),
211-
resolveSessionStoreEntry: vi.fn<
212-
(params: { store: Record<string, unknown>; sessionKey?: string }) => { existing?: unknown }
213-
>((params) => ({
214-
existing: params.sessionKey ? params.store[params.sessionKey] : undefined,
215-
})),
216204
resolveStorePath: vi.fn<(path?: unknown, opts?: unknown) => string>(
217205
() => "/tmp/openclaw-discord-process-test-sessions.json",
218206
),
219207
}));
220-
const loadSessionStore = configSessionsMocks.loadSessionStore;
208+
const getSessionEntry = configSessionsMocks.getSessionEntry;
209+
const readSessionTranscriptEvents = configSessionsMocks.readSessionTranscriptEvents;
221210
const readSessionUpdatedAt = configSessionsMocks.readSessionUpdatedAt;
222-
const readLatestAssistantTextFromSessionTranscript =
223-
configSessionsMocks.readLatestAssistantTextFromSessionTranscript;
224-
const resolveAndPersistSessionFile = configSessionsMocks.resolveAndPersistSessionFile;
225-
const resolveSessionStoreEntry = configSessionsMocks.resolveSessionStoreEntry;
226211
const resolveStorePath = configSessionsMocks.resolveStorePath;
227212
const createDiscordRestClientSpy = vi.hoisted(() =>
228213
vi.fn<
@@ -394,19 +379,17 @@ vi.mock("openclaw/plugin-sdk/conversation-runtime", () => ({
394379
}));
395380

396381
vi.mock("openclaw/plugin-sdk/session-store-runtime", () => ({
397-
loadSessionStore: (storePath: string, opts?: unknown) =>
398-
configSessionsMocks.loadSessionStore(storePath, opts),
382+
getSessionEntry: (params?: unknown) => configSessionsMocks.getSessionEntry(params),
399383
readSessionUpdatedAt: (params?: unknown) => configSessionsMocks.readSessionUpdatedAt(params),
400-
readLatestAssistantTextFromSessionTranscript: (sessionFile: string) =>
401-
configSessionsMocks.readLatestAssistantTextFromSessionTranscript(sessionFile),
402-
resolveAndPersistSessionFile: (params?: unknown) =>
403-
configSessionsMocks.resolveAndPersistSessionFile(params),
404-
resolveSessionStoreEntry: (params: { store: Record<string, unknown>; sessionKey?: string }) =>
405-
configSessionsMocks.resolveSessionStoreEntry(params),
406384
resolveStorePath: (path?: unknown, opts?: unknown) =>
407385
configSessionsMocks.resolveStorePath(path, opts),
408386
}));
409387

388+
vi.mock("openclaw/plugin-sdk/session-transcript-runtime", () => ({
389+
readSessionTranscriptEvents: (params?: unknown) =>
390+
configSessionsMocks.readSessionTranscriptEvents(params),
391+
}));
392+
410393
vi.mock("../client.js", () => ({
411394
createDiscordRuntimeAccountContext: (params: { cfg: unknown; accountId: string }) => ({
412395
cfg: params.cfg,
@@ -499,24 +482,16 @@ beforeEach(() => {
499482
createDiscordDraftStream.mockClear();
500483
dispatchInboundMessage.mockClear();
501484
recordInboundSession.mockClear();
502-
loadSessionStore.mockClear();
503485
readSessionUpdatedAt.mockClear();
504-
readLatestAssistantTextFromSessionTranscript.mockClear();
505-
resolveAndPersistSessionFile.mockClear();
506-
resolveSessionStoreEntry.mockClear();
486+
getSessionEntry.mockClear();
487+
readSessionTranscriptEvents.mockClear();
507488
resolveStorePath.mockClear();
508489
createDiscordRestClientSpy.mockClear();
509490
dispatchInboundMessage.mockResolvedValue(createNoQueuedDispatchResult());
510491
recordInboundSession.mockResolvedValue(undefined);
511-
loadSessionStore.mockReturnValue({});
512492
readSessionUpdatedAt.mockReturnValue(undefined);
513-
readLatestAssistantTextFromSessionTranscript.mockResolvedValue(undefined);
514-
resolveAndPersistSessionFile.mockResolvedValue({
515-
sessionFile: "/tmp/openclaw-discord-process-test-session.jsonl",
516-
});
517-
resolveSessionStoreEntry.mockImplementation((params) => ({
518-
existing: params.sessionKey ? params.store[params.sessionKey] : undefined,
519-
}));
493+
getSessionEntry.mockReturnValue(undefined);
494+
readSessionTranscriptEvents.mockResolvedValue([]);
520495
resolveStorePath.mockReturnValue("/tmp/openclaw-discord-process-test-sessions.json");
521496
threadBindingTesting.resetThreadBindingsForTests();
522497
});
@@ -2202,13 +2177,16 @@ describe("processDiscordMessage draft streaming", () => {
22022177
(_value, index) => `continuation${index}`,
22032178
).join(" ")}`;
22042179

2205-
loadSessionStore.mockReturnValue({
2206-
"agent:main:discord:channel:c1": { sessionId: "session-1" },
2207-
});
2208-
readLatestAssistantTextFromSessionTranscript.mockResolvedValue({
2209-
text: fullAnswer,
2210-
timestamp: Date.now() + 60_000,
2211-
});
2180+
getSessionEntry.mockReturnValue({ sessionId: "session-1" });
2181+
readSessionTranscriptEvents.mockResolvedValue([
2182+
{
2183+
message: {
2184+
role: "assistant",
2185+
content: [{ type: "text", text: fullAnswer }],
2186+
timestamp: Date.now() + 60_000,
2187+
},
2188+
},
2189+
]);
22122190
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
22132191
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
22142192
await params?.replyOptions?.onItemEvent?.({ progressText: "exec done" });

extensions/discord/src/monitor/message-handler.process.ts

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import path from "node:path";
21
import { MessageFlags } from "discord-api-types/v10";
32
import {
43
formatReasoningMessage,
@@ -41,13 +40,9 @@ import {
4140
} from "openclaw/plugin-sdk/reply-payload";
4241
import type { ReplyDispatchKind, ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
4342
import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
44-
import {
45-
loadSessionStore,
46-
readLatestAssistantTextFromSessionTranscript,
47-
resolveAndPersistSessionFile,
48-
resolveSessionStoreEntry,
49-
resolveStorePath,
50-
} from "openclaw/plugin-sdk/session-store-runtime";
43+
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
44+
import { readSessionTranscriptEvents } from "openclaw/plugin-sdk/session-transcript-runtime";
45+
import { extractAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
5146
import { resolveDiscordAccount, resolveDiscordMaxLinesPerMessage } from "../accounts.js";
5247
import { createDiscordRestClient } from "../client.js";
5348
import { beginDiscordInboundEventDeliveryCorrelation } from "../inbound-event-delivery.js";
@@ -145,6 +140,58 @@ type ToolStartPayload = {
145140
detailMode?: "explain" | "raw";
146141
};
147142

143+
type AssistantTranscriptText = {
144+
text: string;
145+
timestamp?: number;
146+
};
147+
148+
function resolveAssistantTranscriptText(event: unknown): AssistantTranscriptText | undefined {
149+
if (!event || typeof event !== "object") {
150+
return undefined;
151+
}
152+
const message = (event as { message?: unknown }).message;
153+
if (!message || typeof message !== "object") {
154+
return undefined;
155+
}
156+
const record = message as {
157+
model?: unknown;
158+
provider?: unknown;
159+
role?: unknown;
160+
timestamp?: unknown;
161+
};
162+
if (record.role !== "assistant") {
163+
return undefined;
164+
}
165+
if (
166+
record.provider === "openclaw" &&
167+
(record.model === "delivery-mirror" || record.model === "gateway-injected")
168+
) {
169+
return undefined;
170+
}
171+
const text = extractAssistantVisibleText(record)?.trim();
172+
if (!text) {
173+
return undefined;
174+
}
175+
return {
176+
text,
177+
...(typeof record.timestamp === "number" && Number.isFinite(record.timestamp)
178+
? { timestamp: record.timestamp }
179+
: {}),
180+
};
181+
}
182+
183+
function resolveLatestAssistantTranscriptText(
184+
events: unknown[],
185+
): AssistantTranscriptText | undefined {
186+
for (let index = events.length - 1; index >= 0; index -= 1) {
187+
const text = resolveAssistantTranscriptText(events[index]);
188+
if (text) {
189+
return text;
190+
}
191+
}
192+
return undefined;
193+
}
194+
148195
function readToolStringArg(args: Record<string, unknown>, key: string): string | undefined {
149196
const value = args[key];
150197
return typeof value === "string" && value.trim() ? value.trim() : undefined;
@@ -514,21 +561,21 @@ async function processDiscordMessageInner(
514561
}
515562
try {
516563
const storePath = resolveStorePath(cfg.session?.store, { agentId: route.agentId });
517-
const store = loadSessionStore(storePath, { clone: false });
518-
const sessionEntry = resolveSessionStoreEntry({ store, sessionKey }).existing;
564+
const sessionEntry = getSessionEntry({
565+
agentId: route.agentId,
566+
sessionKey,
567+
storePath,
568+
});
519569
if (!sessionEntry?.sessionId) {
520570
return undefined;
521571
}
522-
const { sessionFile } = await resolveAndPersistSessionFile({
572+
const events = await readSessionTranscriptEvents({
573+
agentId: route.agentId,
523574
sessionId: sessionEntry.sessionId,
524575
sessionKey,
525-
sessionStore: store,
526576
storePath,
527-
sessionEntry,
528-
agentId: route.agentId,
529-
sessionsDir: path.dirname(storePath),
530577
});
531-
const latest = await readLatestAssistantTextFromSessionTranscript(sessionFile);
578+
const latest = resolveLatestAssistantTranscriptText(events);
532579
if (!latest?.timestamp || latest.timestamp < dispatchStartedAt) {
533580
return undefined;
534581
}

extensions/telegram/src/bot-message-dispatch.runtime.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
export {
2+
getSessionEntry,
23
loadSessionStore,
3-
readLatestAssistantTextFromSessionTranscript,
4-
resolveAndPersistSessionFile,
54
resolveSessionStoreEntry,
5+
resolveStorePath,
66
} from "openclaw/plugin-sdk/session-store-runtime";
77
export { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
88
export { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";

0 commit comments

Comments
 (0)