Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/utils/clean-context-runner.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { CleanContextRunner } from "./clean-context-runner.js";

describe("CleanContextRunner", () => {
it("seeds default clean workspace with task brief files and passes explicit prompts", async () => {
const calls: Array<Record<string, unknown>> = [];
const runner = new CleanContextRunner({
config: {
agents: {
defaults: {
systemPromptOverride: "existing host prompt",
},
},
},
agentRuntime: {
runEmbeddedPiAgent: (async (args: Record<string, unknown>) => {
calls.push(args);
return {
payloads: [
{
text: "[]",
},
],
};
}) as never,
},
});

const result = await runner.run({
taskId: "l1-extraction",
systemPrompt: "extract memories as JSON",
prompt: "conversation payload",
timeoutMs: 1000,
});

expect(result).toBe("[]");
expect(calls).toHaveLength(1);
const call = calls[0];
expect(call.prompt).toBe("conversation payload");
expect(call.extraSystemPrompt).toBe("extract memories as JSON");
expect(call.disableTools).toBe(true);
expect((call.config as {
agents: { defaults: { systemPromptOverride: string } };
}).agents.defaults.systemPromptOverride).toBe("extract memories as JSON");

const workspaceDir = call.workspaceDir;
expect(typeof workspaceDir).toBe("string");
const agents = await fs.readFile(path.join(workspaceDir as string, "AGENTS.md"), "utf8");
const soul = await fs.readFile(path.join(workspaceDir as string, "SOUL.md"), "utf8");

expect(agents.length).toBeGreaterThan(76);
expect(agents).toContain("TencentDB Agent Memory");
expect(agents).toContain("Follow the explicit system prompt and user prompt");
expect(soul.length).toBeGreaterThan(76);
expect(soul).toContain("system and user prompts");
});
});
30 changes: 27 additions & 3 deletions src/utils/clean-context-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,38 @@ export interface CleanContextRunnerOptions {
logger?: RunnerLogger;
}

// Stable empty directory used as default workspaceDir so that:
// 1. Bootstrap/skills scans find nothing → clean LLM context
const CLEAN_WORKSPACE_AGENTS = `# TencentDB Agent Memory Background Task

This is an isolated workspace for TencentDB Agent Memory background LLM tasks.
Do not infer task requirements from repository files in this directory.
Follow the explicit system prompt and user prompt passed with the current run.
Return only the output format requested by that prompt.
`;

const CLEAN_WORKSPACE_SOUL = `You are running an isolated TencentDB Agent Memory background task.
The real task instructions are supplied directly in the current system and user prompts.
Ignore the absence of project files here and answer according to those prompts only.
`;

async function ensureCleanWorkspaceBrief(dir: string): Promise<void> {
await Promise.all([
fs.writeFile(path.join(dir, "AGENTS.md"), CLEAN_WORKSPACE_AGENTS, "utf8"),
fs.writeFile(path.join(dir, "SOUL.md"), CLEAN_WORKSPACE_SOUL, "utf8"),
]);
}

// Stable low-context directory used as default workspaceDir so that:
// 1. Bootstrap/skills scans see only a tiny task brief → clean LLM context
// 2. The path is constant → plugin cacheKey stays stable (no re-registration)
let _cleanWorkspaceDir: string | undefined;
async function getCleanWorkspaceDir(): Promise<string> {
if (_cleanWorkspaceDir) return _cleanWorkspaceDir;
if (_cleanWorkspaceDir) {
await ensureCleanWorkspaceBrief(_cleanWorkspaceDir);
return _cleanWorkspaceDir;
}
const dir = path.join(resolveOpenClawTmpDir(), "memory-tdai-clean-workspace");
await fs.mkdir(dir, { recursive: true });
await ensureCleanWorkspaceBrief(dir);
_cleanWorkspaceDir = dir;
return dir;
}
Expand Down