Download src/logging/diagnostic-session-context.test.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 9.02 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/logging/diagnostic-session-context.test.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/logging/diagnostic-session-context.test.ts
-
curl -L -o diagnostic-session-context.test.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/logging/diagnostic-session-context.test.ts
9.02 kB
| // Diagnostic session context tests cover session context capture for diagnostics. | |
| import fs from "node:fs"; | |
| import path from "node:path"; | |
| import { afterEach, beforeEach, describe, expect, it } from "vitest"; | |
| import { | |
| appendTranscriptMessageSync, | |
| readLatestTranscriptAssistantText, | |
| replaceSessionEntry, | |
| } from "../config/sessions/session-accessor.js"; | |
| import { saveCronStore } from "../cron/store.js"; | |
| import { | |
| createOpenClawTestState, | |
| type OpenClawTestState, | |
| } from "../test-utils/openclaw-test-state.js"; | |
| import { | |
| formatCronSessionDiagnosticFields, | |
| formatStoppedCronSessionDiagnosticFields, | |
| resolveCronSessionDiagnosticContext, | |
| } from "./diagnostic-session-context.js"; | |
| let tempDir: string | undefined; | |
| let testState: OpenClawTestState | undefined; | |
| async function seedSessionTranscript(params: { | |
| agentId: string; | |
| sessionId: string; | |
| sessionKey: string; | |
| messages: unknown[]; | |
| incognito?: boolean; | |
| }) { | |
| const { agentId, sessionId, sessionKey, messages, incognito } = params; | |
| await replaceSessionEntry( | |
| { agentId, sessionKey }, | |
| { sessionId, updatedAt: 1, ...(incognito ? { incognito: true } : {}) }, | |
| ); | |
| for (const message of messages) { | |
| appendTranscriptMessageSync({ agentId, sessionId, sessionKey }, { message }); | |
| } | |
| } | |
| describe("diagnostic session context", () => { | |
| beforeEach(async () => { | |
| testState = await createOpenClawTestState({ | |
| layout: "state-only", | |
| prefix: "openclaw-diagnostic-session-", | |
| }); | |
| tempDir = testState.stateDir; | |
| }); | |
| afterEach(async () => { | |
| await testState?.cleanup(); | |
| testState = undefined; | |
| tempDir = undefined; | |
| }); | |
| it("parses cron run session keys", () => { | |
| expect( | |
| resolveCronSessionDiagnosticContext({ | |
| sessionKey: "agent:clawblocker:cron:job-123:run:run-456", | |
| }), | |
| ).toMatchObject({ agentId: "clawblocker", cronJobId: "job-123", cronRunId: "run-456" }); | |
| }); | |
| it("formats cron job and last assistant context for stalled session logs", async () => { | |
| const stateDir = tempDir!; | |
| await saveCronStore(path.join(stateDir, "cron", "jobs.json"), { | |
| version: 1, | |
| jobs: [ | |
| { | |
| id: "job-123", | |
| name: "Twitter Mention Moderation Agent", | |
| enabled: true, | |
| createdAtMs: 1_700_000_000_000, | |
| updatedAtMs: 1_700_000_000_000, | |
| schedule: { kind: "every", everyMs: 60_000 }, | |
| sessionTarget: "main", | |
| wakeMode: "next-heartbeat", | |
| payload: { kind: "systemEvent", text: "tick" }, | |
| state: {}, | |
| }, | |
| ], | |
| }); | |
| const sessionKey = "agent:clawblocker:cron:job-123:run:run-456"; | |
| await seedSessionTranscript({ | |
| agentId: "clawblocker", | |
| sessionId: "run-456", | |
| sessionKey, | |
| messages: [ | |
| { role: "user", content: "run" }, | |
| { | |
| role: "assistant", | |
| content: [{ type: "text", text: "There are 40\ncached mentions ready." }], | |
| }, | |
| ], | |
| }); | |
| const context = resolveCronSessionDiagnosticContext({ | |
| sessionKey, | |
| activeSessionId: "run-456", | |
| }); | |
| expect(formatCronSessionDiagnosticFields(context)).toContain("cronJobId=job-123"); | |
| expect(formatCronSessionDiagnosticFields(context)).toContain("cronRunId=run-456"); | |
| expect(formatCronSessionDiagnosticFields(context)).toContain( | |
| 'cronJob="Twitter Mention Moderation Agent"', | |
| ); | |
| expect(formatCronSessionDiagnosticFields(context)).toContain( | |
| 'lastAssistant="There are 40 cached mentions ready."', | |
| ); | |
| expect(formatStoppedCronSessionDiagnosticFields(context)).toContain( | |
| 'stopped="Twitter Mention Moderation Agent"', | |
| ); | |
| }); | |
| it("reads the latest visible app-agent assistant text from its SQLite transcript", async () => { | |
| const sessionKey = "agent:oauth-agent:main"; | |
| await seedSessionTranscript({ | |
| agentId: "oauth-agent", | |
| sessionId: "oauth-session", | |
| sessionKey, | |
| messages: [ | |
| { role: "assistant", content: "older reply" }, | |
| { role: "user", content: "later user" }, | |
| { | |
| role: "assistant", | |
| content: [ | |
| { | |
| type: "text", | |
| text: "internal reasoning", | |
| textSignature: JSON.stringify({ v: 1, id: "reasoning", phase: "commentary" }), | |
| }, | |
| { | |
| type: "text", | |
| text: "latest visible reply", | |
| textSignature: JSON.stringify({ v: 1, id: "reply", phase: "final_answer" }), | |
| }, | |
| ], | |
| }, | |
| ], | |
| }); | |
| const context = resolveCronSessionDiagnosticContext({ | |
| sessionKey, | |
| activeSessionId: "oauth-session", | |
| }); | |
| expect(context.lastAssistant).toBe("latest visible reply"); | |
| expect(formatCronSessionDiagnosticFields(context)).toBe('lastAssistant="latest visible reply"'); | |
| }); | |
| it.each(["dashboard", "subagent", "internal-session-effects"])( | |
| "never exposes a %s incognito assistant reply to durable diagnostics", | |
| async (sessionSurface) => { | |
| const sessionKey = `agent:main:${sessionSurface}:incognito-private`; | |
| const sessionId = `incognito-${sessionSurface}`; | |
| const privateReply = `memory-only ${sessionSurface} reply`; | |
| await seedSessionTranscript({ | |
| agentId: "main", | |
| incognito: true, | |
| sessionId, | |
| sessionKey, | |
| messages: [{ role: "assistant", content: privateReply }], | |
| }); | |
| expect( | |
| readLatestTranscriptAssistantText({ agentId: "main", sessionId, sessionKey })?.text, | |
| ).toBe(privateReply); | |
| expect( | |
| resolveCronSessionDiagnosticContext({ sessionKey, activeSessionId: sessionId }), | |
| ).toEqual({}); | |
| expect( | |
| fs.existsSync(path.join(tempDir!, "agents", "main", "agent", "openclaw-agent.sqlite")), | |
| ).toBe(false); | |
| }, | |
| ); | |
| it("requires the authoritative current session id before reading transcript text", async () => { | |
| const sessionKey = "agent:oauth-agent:main"; | |
| await seedSessionTranscript({ | |
| agentId: "oauth-agent", | |
| sessionId: "current-session", | |
| sessionKey, | |
| messages: [{ role: "assistant", content: "current private reply" }], | |
| }); | |
| expect( | |
| resolveCronSessionDiagnosticContext({ | |
| sessionKey, | |
| activeSessionId: "rotated-session", | |
| }).lastAssistant, | |
| ).toBeUndefined(); | |
| expect(resolveCronSessionDiagnosticContext({ sessionKey }).lastAssistant).toBeUndefined(); | |
| }); | |
| it("keeps identical session ids isolated to their owning agents", async () => { | |
| await seedSessionTranscript({ | |
| agentId: "main", | |
| sessionId: "shared-session-id", | |
| sessionKey: "agent:main:main", | |
| messages: [{ role: "assistant", content: "main private reply" }], | |
| }); | |
| await seedSessionTranscript({ | |
| agentId: "oauth-agent", | |
| sessionId: "shared-session-id", | |
| sessionKey: "agent:oauth-agent:main", | |
| messages: [{ role: "assistant", content: "oauth private reply" }], | |
| }); | |
| expect( | |
| resolveCronSessionDiagnosticContext({ | |
| sessionKey: "agent:oauth-agent:main", | |
| activeSessionId: "shared-session-id", | |
| }).lastAssistant, | |
| ).toBe("oauth private reply"); | |
| }); | |
| it("rejects malformed agent ids before resolving a default agent transcript", async () => { | |
| await seedSessionTranscript({ | |
| agentId: "main", | |
| sessionId: "main-session", | |
| sessionKey: "agent:main:main", | |
| messages: [{ role: "assistant", content: "main private reply" }], | |
| }); | |
| expect( | |
| resolveCronSessionDiagnosticContext({ | |
| sessionKey: "agent:../main:main", | |
| activeSessionId: "main-session", | |
| }), | |
| ).toEqual({}); | |
| }); | |
| it("does not treat channel-owned cron segments as cron metadata", async () => { | |
| const sessionKey = "agent:oauth-agent:slack:cron:job-123:run:run-456"; | |
| await seedSessionTranscript({ | |
| agentId: "oauth-agent", | |
| sessionId: "slack-session", | |
| sessionKey, | |
| messages: [{ role: "assistant", content: "channel reply" }], | |
| }); | |
| const context = resolveCronSessionDiagnosticContext({ | |
| sessionKey, | |
| activeSessionId: "slack-session", | |
| }); | |
| expect(context.lastAssistant).toBe("channel reply"); | |
| expect(context.cronJobId).toBeUndefined(); | |
| expect(context.cronRunId).toBeUndefined(); | |
| }); | |
| it("keeps bounded quoted fields UTF-16 safe", () => { | |
| const prefix = "a".repeat(136); | |
| expect( | |
| formatCronSessionDiagnosticFields({ cronJobName: `${prefix}😀${"b".repeat(140)}` }), | |
| ).toBe(`cronJob="${prefix}..."`); | |
| }); | |
| it("does not create an agent database when its session store is missing", () => { | |
| const databasePath = path.join( | |
| tempDir!, | |
| "agents", | |
| "missing-agent", | |
| "agent", | |
| "openclaw-agent.sqlite", | |
| ); | |
| expect(fs.existsSync(databasePath)).toBe(false); | |
| expect( | |
| resolveCronSessionDiagnosticContext({ | |
| sessionKey: "agent:missing-agent:main", | |
| activeSessionId: "missing", | |
| }).lastAssistant, | |
| ).toBeUndefined(); | |
| expect(fs.existsSync(databasePath)).toBe(false); | |
| }); | |
| }); | |