Files
ATOCore/openclaw-plugins/atocore-capture/index.js

106 lines
3.2 KiB
JavaScript

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);
});
}
});