import { definePluginEntry } from "openclaw/plugin-sdk/core"; const DEFAULT_BASE_URL = process.env.ATOCORE_BASE_URL || "http://dalidou:8100"; const DEFAULT_MIN_PROMPT_LENGTH = 15; const DEFAULT_MAX_RESPONSE_LENGTH = 50_000; function trimText(value) { return typeof value === "string" ? value.trim() : ""; } function truncateResponse(text, maxLength) { if (!text || text.length <= maxLength) return text; return `${text.slice(0, maxLength)}\n\n[truncated]`; } function shouldCapturePrompt(prompt, minLength) { const text = trimText(prompt); if (!text) return false; if (text.startsWith("<")) return false; return text.length >= minLength; } async function postInteraction(baseUrl, payload, logger) { try { const res = await fetch(`${baseUrl.replace(/\/$/, "")}/interactions`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), signal: AbortSignal.timeout(10_000) }); if (!res.ok) { logger?.debug?.("atocore_capture_post_failed", { status: res.status }); return false; } return true; } catch (error) { logger?.debug?.("atocore_capture_post_error", { error: error instanceof Error ? error.message : String(error) }); return false; } } export default definePluginEntry({ register(api) { const logger = api.logger; const pendingBySession = new Map(); api.on("before_dispatch", async (event, ctx) => { const config = api.getConfig?.() || {}; const minPromptLength = Number(config.minPromptLength || DEFAULT_MIN_PROMPT_LENGTH); const prompt = trimText(event?.body || event?.content || ""); const key = ctx?.sessionKey || event?.sessionKey; if (!key) return; if (!shouldCapturePrompt(prompt, minPromptLength)) { pendingBySession.delete(key); return; } pendingBySession.set(key, { prompt, sessionId: key, sessionKey: key, project: "" }); }); api.on("llm_output", async (event, ctx) => { if (ctx?.trigger && ctx.trigger !== "user") return; const key = ctx.sessionKey || ctx.sessionId; const pending = pendingBySession.get(key); if (!pending) return; const assistantTexts = Array.isArray(event?.assistantTexts) ? event.assistantTexts : []; const response = truncateResponse( trimText(assistantTexts.join("\n\n")), Number((api.getConfig?.() || {}).maxResponseLength || DEFAULT_MAX_RESPONSE_LENGTH) ); if (!response) return; const config = api.getConfig?.() || {}; const baseUrl = trimText(config.baseUrl) || DEFAULT_BASE_URL; const payload = { prompt: pending.prompt, response, client: "openclaw", session_id: pending.sessionKey || pending.sessionId, project: pending.project || "", reinforce: true }; await postInteraction(baseUrl, payload, logger); pendingBySession.delete(key); }); api.on("agent_end", async (event) => { const key = event?.sessionKey || event?.sessionId; if (key) pendingBySession.delete(key); }); api.on("session_end", async (event) => { const key = event?.sessionKey || event?.sessionId; if (key) pendingBySession.delete(key); }); } });