Files
openclaw/src/hooks/llm-slug-generator.ts
2026-02-17 13:36:48 +09:00

86 lines
2.5 KiB
TypeScript

/**
* LLM-based slug generator for session memory filenames
*/
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import {
resolveDefaultAgentId,
resolveAgentWorkspaceDir,
resolveAgentDir,
} from "../agents/agent-scope.js";
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
import type { OpenClawConfig } from "../config/config.js";
/**
* Generate a short 1-2 word filename slug from session content using LLM
*/
export async function generateSlugViaLLM(params: {
sessionContent: string;
cfg: OpenClawConfig;
}): Promise<string | null> {
let tempSessionFile: string | null = null;
try {
const agentId = resolveDefaultAgentId(params.cfg);
const workspaceDir = resolveAgentWorkspaceDir(params.cfg, agentId);
const agentDir = resolveAgentDir(params.cfg, agentId);
// Create a temporary session file for this one-off LLM call
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-slug-"));
tempSessionFile = path.join(tempDir, "session.jsonl");
const prompt = `Based on this conversation, generate a short 1-2 word filename slug (lowercase, hyphen-separated, no file extension).
Conversation summary:
${params.sessionContent.slice(0, 2000)}
Reply with ONLY the slug, nothing else. Examples: "vendor-pitch", "api-design", "bug-fix"`;
const result = await runEmbeddedPiAgent({
sessionId: `slug-generator-${Date.now()}`,
sessionKey: "temp:slug-generator",
agentId,
sessionFile: tempSessionFile,
workspaceDir,
agentDir,
config: params.cfg,
prompt,
timeoutMs: 15_000, // 15 second timeout
runId: `slug-gen-${Date.now()}`,
});
// Extract text from payloads
if (result.payloads && result.payloads.length > 0) {
const text = result.payloads[0]?.text;
if (text) {
// Clean up the response - extract just the slug
const slug = text
.trim()
.toLowerCase()
.replace(/[^a-z0-9-]/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "")
.slice(0, 30); // Max 30 chars
return slug || null;
}
}
return null;
} catch (err) {
console.error("[llm-slug-generator] Failed to generate slug:", err);
return null;
} finally {
// Clean up temporary session file
if (tempSessionFile) {
try {
await fs.rm(path.dirname(tempSessionFile), { recursive: true, force: true });
} catch {
// Ignore cleanup errors
}
}
}
}