mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-10 12:32:27 +00:00
test: use sqlite transcript locators in fixtures
This commit is contained in:
@@ -147,7 +147,7 @@ describe("active-memory plugin", () => {
|
||||
| undefined;
|
||||
return entries?.find((entry) => entry.pluginId === "active-memory")?.lines ?? [];
|
||||
};
|
||||
const writeTranscriptJsonl = async (sessionFile: string, records: unknown[]) => {
|
||||
const writeSqliteTranscriptEvents = async (sessionFile: string, records: unknown[]) => {
|
||||
const sessionId = path.basename(sessionFile, ".jsonl");
|
||||
for (const record of records) {
|
||||
appendSqliteSessionTranscriptEvent({
|
||||
@@ -1617,7 +1617,7 @@ describe("active-memory plugin", () => {
|
||||
},
|
||||
}),
|
||||
];
|
||||
await writeTranscriptJsonl(
|
||||
await writeSqliteTranscriptEvents(
|
||||
params.sessionFile,
|
||||
lines.map((line) => JSON.parse(line) as unknown),
|
||||
);
|
||||
@@ -1852,7 +1852,7 @@ describe("active-memory plugin", () => {
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{ type: "message", message: { role: "user", content: "ignore this user text" } },
|
||||
{
|
||||
type: "message",
|
||||
@@ -1914,7 +1914,7 @@ describe("active-memory plugin", () => {
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
tempSessionFile = params.sessionFile;
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{
|
||||
type: "message",
|
||||
message: { role: "assistant", content: "temporary partial recall summary" },
|
||||
@@ -1962,7 +1962,7 @@ describe("active-memory plugin", () => {
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, []);
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, []);
|
||||
return await waitForAbort(params.abortSignal);
|
||||
},
|
||||
);
|
||||
@@ -2024,7 +2024,7 @@ describe("active-memory plugin", () => {
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{
|
||||
type: "message",
|
||||
message: {
|
||||
@@ -2070,7 +2070,7 @@ describe("active-memory plugin", () => {
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{
|
||||
type: "message",
|
||||
message: { role: "assistant", content: "partial abort summary" },
|
||||
@@ -2118,7 +2118,7 @@ describe("active-memory plugin", () => {
|
||||
updatedAt: 0,
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{
|
||||
type: "message",
|
||||
message: { role: "assistant", content: "must not be surfaced from generic errors" },
|
||||
@@ -2143,7 +2143,7 @@ describe("active-memory plugin", () => {
|
||||
|
||||
it("bounds partial assistant transcript reads by character cap for large JSONL files", async () => {
|
||||
const sessionFile = path.join(stateDir, "large-timeout-transcript.jsonl");
|
||||
await writeTranscriptJsonl(
|
||||
await writeSqliteTranscriptEvents(
|
||||
sessionFile,
|
||||
Array.from({ length: 50 }, () => ({
|
||||
type: "message",
|
||||
@@ -2169,7 +2169,7 @@ describe("active-memory plugin", () => {
|
||||
|
||||
it("skips malformed JSONL lines when reading partial assistant transcripts", async () => {
|
||||
const sessionFile = path.join(stateDir, "malformed-timeout-transcript.jsonl");
|
||||
await writeTranscriptJsonl(sessionFile, [
|
||||
await writeSqliteTranscriptEvents(sessionFile, [
|
||||
{ type: "message", message: { role: "assistant", content: "valid partial summary" } },
|
||||
]);
|
||||
|
||||
@@ -2183,7 +2183,7 @@ describe("active-memory plugin", () => {
|
||||
|
||||
it("honors transcript maxLines caps for partial text and search debug reads", async () => {
|
||||
const sessionFile = path.join(stateDir, "max-lines-transcript.jsonl");
|
||||
await writeTranscriptJsonl(sessionFile, [
|
||||
await writeSqliteTranscriptEvents(sessionFile, [
|
||||
{
|
||||
type: "message",
|
||||
message: { role: "user", content: "line one" },
|
||||
@@ -2529,7 +2529,7 @@ describe("active-memory plugin", () => {
|
||||
hoisted.sessionStore[sessionKey] = { sessionId: "s-terminal-zero-hit", updatedAt: 0 };
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{
|
||||
message: {
|
||||
role: "toolResult",
|
||||
@@ -2574,7 +2574,7 @@ describe("active-memory plugin", () => {
|
||||
updatedAt: 0,
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{
|
||||
message: {
|
||||
role: "toolResult",
|
||||
@@ -2616,7 +2616,7 @@ describe("active-memory plugin", () => {
|
||||
hoisted.sessionStore[sessionKey] = { sessionId: "s-terminal-unavailable", updatedAt: 0 };
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{
|
||||
message: {
|
||||
role: "toolResult",
|
||||
@@ -2662,7 +2662,7 @@ describe("active-memory plugin", () => {
|
||||
};
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
await writeSqliteTranscriptEvents(params.sessionFile, [
|
||||
{
|
||||
message: {
|
||||
role: "toolResult",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { createSqliteSessionTranscriptLocator } from "../../src/config/sessions/paths.ts";
|
||||
import { upsertSessionEntry } from "../../src/config/sessions/store.ts";
|
||||
import { replaceSqliteSessionTranscriptEvents } from "../../src/config/sessions/transcript-store.sqlite.ts";
|
||||
import { resolveOpenClawAgentSqlitePath } from "../../src/state/openclaw-agent-db.ts";
|
||||
@@ -10,7 +11,10 @@ async function main() {
|
||||
const stateDir = process.env.OPENCLAW_STATE_DIR?.trim() || path.join(os.homedir(), ".openclaw");
|
||||
const configPath =
|
||||
process.env.OPENCLAW_CONFIG_PATH?.trim() || path.join(stateDir, "openclaw.json");
|
||||
const transcriptPath = path.join(stateDir, "agents", "main", "sessions", "sess-main.jsonl");
|
||||
const transcriptPath = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId: "sess-main",
|
||||
});
|
||||
const now = Date.now();
|
||||
|
||||
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
||||
|
||||
@@ -5,7 +5,6 @@ import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
import {
|
||||
queueRuntimeContextForNextTurn,
|
||||
resolveRuntimeContextPromptParts,
|
||||
@@ -28,14 +27,6 @@ function assert(condition: unknown, message: string): asserts condition {
|
||||
}
|
||||
}
|
||||
|
||||
async function readJsonl(filePath: string): Promise<TranscriptEntry[]> {
|
||||
const raw = await fs.readFile(filePath, "utf-8");
|
||||
return raw
|
||||
.split(/\r?\n/)
|
||||
.filter(Boolean)
|
||||
.map((line) => JSON.parse(line) as TranscriptEntry);
|
||||
}
|
||||
|
||||
function messageText(content: unknown): string {
|
||||
if (typeof content === "string") {
|
||||
return content;
|
||||
@@ -52,10 +43,8 @@ function messageText(content: unknown): string {
|
||||
.join("");
|
||||
}
|
||||
|
||||
async function verifyRuntimeContextTranscriptShape(root: string) {
|
||||
const sessionFile = path.join(root, ".openclaw", "agents", "main", "sessions", "runtime.jsonl");
|
||||
await fs.mkdir(path.dirname(sessionFile), { recursive: true });
|
||||
const sessionManager = SessionManager.open(sessionFile);
|
||||
async function verifyRuntimeContextTranscriptShape() {
|
||||
const entries: TranscriptEntry[] = [];
|
||||
const effectivePrompt = [
|
||||
"visible ask",
|
||||
"",
|
||||
@@ -79,27 +68,29 @@ async function verifyRuntimeContextTranscriptShape(root: string) {
|
||||
session: {
|
||||
sendCustomMessage: async (message, options) => {
|
||||
assert(options?.deliverAs === "nextTurn", "runtime context was not queued for next turn");
|
||||
sessionManager.appendCustomMessageEntry(
|
||||
message.customType,
|
||||
message.content,
|
||||
message.display,
|
||||
message.details,
|
||||
);
|
||||
entries.push({
|
||||
type: "custom_message",
|
||||
customType: message.customType,
|
||||
content: message.content,
|
||||
display: message.display,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
sessionManager.appendMessage({
|
||||
role: "user",
|
||||
content: promptSubmission.prompt,
|
||||
timestamp: Date.now(),
|
||||
entries.push({
|
||||
type: "message",
|
||||
message: {
|
||||
role: "user",
|
||||
content: promptSubmission.prompt,
|
||||
},
|
||||
});
|
||||
sessionManager.appendMessage({
|
||||
role: "assistant",
|
||||
content: "done",
|
||||
timestamp: Date.now() + 1,
|
||||
entries.push({
|
||||
type: "message",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: "done",
|
||||
},
|
||||
});
|
||||
|
||||
const entries = await readJsonl(sessionFile);
|
||||
const customEntry = entries.find((entry) => entry.type === "custom_message");
|
||||
assert(customEntry, "hidden runtime custom message was not persisted");
|
||||
assert(customEntry.customType === "openclaw.runtime-context", "unexpected custom message type");
|
||||
@@ -257,7 +248,7 @@ async function main() {
|
||||
process.env.OPENCLAW_STATE_DIR = path.join(root, ".openclaw");
|
||||
process.env.OPENCLAW_CONFIG_PATH = path.join(process.env.OPENCLAW_STATE_DIR, "openclaw.json");
|
||||
try {
|
||||
await verifyRuntimeContextTranscriptShape(root);
|
||||
await verifyRuntimeContextTranscriptShape();
|
||||
await verifyDoctorRepair(root);
|
||||
console.log("session runtime context Docker E2E passed");
|
||||
} finally {
|
||||
|
||||
@@ -3,6 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { SessionEntry } from "../../config/sessions.js";
|
||||
import { createSqliteSessionTranscriptLocator } from "../../config/sessions/paths.js";
|
||||
import { listSessionEntries, upsertSessionEntry } from "../../config/sessions/store.js";
|
||||
import { appendSessionTranscriptMessage } from "../../config/sessions/transcript-append.js";
|
||||
import { loadSqliteSessionTranscriptEvents } from "../../config/sessions/transcript-store.sqlite.js";
|
||||
@@ -64,6 +65,10 @@ function makeCliResult(text: string): EmbeddedPiRunResult {
|
||||
};
|
||||
}
|
||||
|
||||
function sessionTranscriptLocator(sessionId: string): string {
|
||||
return createSqliteSessionTranscriptLocator({ agentId: "main", sessionId });
|
||||
}
|
||||
|
||||
async function readSessionMessages(sessionFile: string) {
|
||||
return (await readSessionFileEntries(sessionFile))
|
||||
.filter((entry) => entry.type === "message")
|
||||
@@ -139,7 +144,7 @@ describe("CLI attempt execution", () => {
|
||||
sessionId: params.sessionEntry.sessionId,
|
||||
sessionKey: params.sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(params.sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: params.body,
|
||||
isFallbackRetry: false,
|
||||
@@ -203,7 +208,7 @@ describe("CLI attempt execution", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "retry this",
|
||||
isFallbackRetry: false,
|
||||
@@ -348,7 +353,7 @@ describe("CLI attempt execution", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "continue",
|
||||
isFallbackRetry: false,
|
||||
@@ -596,7 +601,7 @@ describe("CLI attempt execution", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "route this",
|
||||
isFallbackRetry: false,
|
||||
@@ -654,7 +659,7 @@ describe("CLI attempt execution", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "route this",
|
||||
isFallbackRetry: false,
|
||||
@@ -708,7 +713,7 @@ describe("CLI attempt execution", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "route this",
|
||||
isFallbackRetry: false,
|
||||
@@ -764,7 +769,7 @@ describe("CLI attempt execution", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "raw prompt",
|
||||
isFallbackRetry: false,
|
||||
@@ -832,7 +837,7 @@ describe("CLI attempt execution", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey,
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "cleanup",
|
||||
isFallbackRetry: false,
|
||||
@@ -897,7 +902,7 @@ describe("embedded attempt harness pinning", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey: "agent:main:main",
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "continue",
|
||||
isFallbackRetry: false,
|
||||
@@ -947,7 +952,7 @@ describe("embedded attempt harness pinning", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey: "agent:main:main",
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "continue",
|
||||
isFallbackRetry: false,
|
||||
@@ -1006,7 +1011,7 @@ describe("embedded attempt harness pinning", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey: "agent:main:main",
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "continue",
|
||||
isFallbackRetry: false,
|
||||
@@ -1052,7 +1057,7 @@ describe("embedded attempt harness pinning", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey: "agent:main:main",
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "start",
|
||||
isFallbackRetry: false,
|
||||
@@ -1097,7 +1102,7 @@ describe("embedded attempt harness pinning", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey: "agent:main:main",
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "continue",
|
||||
isFallbackRetry: false,
|
||||
@@ -1150,7 +1155,7 @@ describe("embedded attempt harness pinning", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey: "agent:main:main",
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "continue",
|
||||
isFallbackRetry: false,
|
||||
@@ -1204,7 +1209,7 @@ describe("embedded attempt harness pinning", () => {
|
||||
sessionId: sessionEntry.sessionId,
|
||||
sessionKey: "agent:main:main",
|
||||
sessionAgentId: "main",
|
||||
sessionFile: path.join(tmpDir, "session.jsonl"),
|
||||
sessionFile: sessionTranscriptLocator(sessionEntry.sessionId),
|
||||
workspaceDir: tmpDir,
|
||||
body: "fallback",
|
||||
isFallbackRetry: true,
|
||||
|
||||
Reference in New Issue
Block a user