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_agent_start", async (event, ctx) => { if (ctx?.trigger && ctx.trigger !== "user") return; const config = api.getConfig?.() || {}; const minPromptLength = Number(config.minPromptLength || DEFAULT_MIN_PROMPT_LENGTH); const prompt = trimText(event?.prompt || ""); if (!shouldCapturePrompt(prompt, minPromptLength)) { pendingBySession.delete(ctx.sessionId); return; } pendingBySession.set(ctx.sessionId, { prompt, sessionId: ctx.sessionId, sessionKey: ctx.sessionKey || "", project: "" }); }); api.on("llm_output", async (event, ctx) => { if (ctx?.trigger && ctx.trigger !== "user") return; const pending = pendingBySession.get(ctx.sessionId); 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(ctx.sessionId); }); api.on("session_end", async (event) => { if (event?.sessionId) pendingBySession.delete(event.sessionId); }); } });