Seed 20 Odoo+AI prospects and enforce model-only chat responses

This commit is contained in:
Ruslan Bakiev
2026-02-18 21:50:41 +07:00
parent fdc85d5c42
commit 693faa8621
3 changed files with 293 additions and 157 deletions

View File

@@ -856,30 +856,64 @@ export async function runLangGraphCrmAgentFor(input: {
{ recursionLimit: 30 },
);
const extractText = (value: unknown, depth = 0): string => {
if (depth > 5 || value == null) return "";
if (typeof value === "string") return value.trim();
if (Array.isArray(value)) {
const parts = value
.map((item) => extractText(item, depth + 1))
.filter(Boolean);
return parts.join("\n").trim();
}
if (typeof value !== "object") return "";
const obj = value as Record<string, unknown>;
for (const key of ["text", "content", "answer", "output_text", "final_text"]) {
const text = extractText(obj[key], depth + 1);
if (text) return text;
}
if (Array.isArray(obj.parts)) {
const text = extractText(obj.parts, depth + 1);
if (text) return text;
}
return "";
};
const messageType = (msg: any): string => {
if (typeof msg?._getType === "function") {
try {
return String(msg._getType() ?? "");
} catch {
// ignore
}
}
return String(msg?.type ?? msg?.role ?? msg?.constructor?.name ?? "");
};
const structured = res?.structuredResponse as { answer?: string; plan?: string[] } | undefined;
const fallbackText = (() => {
const messages = Array.isArray(res?.messages) ? res.messages : [];
for (let i = messages.length - 1; i >= 0; i -= 1) {
const msg = messages[i];
const type = String(msg?.type ?? "").toLowerCase();
if (type !== "ai") continue;
const content = msg?.content;
if (typeof content === "string" && content.trim()) return content.trim();
if (Array.isArray(content)) {
const text = content
.map((part: any) => (typeof part?.text === "string" ? part.text : ""))
.filter(Boolean)
.join("\n")
.trim();
if (text) return text;
}
const type = messageType(msg).toLowerCase();
if (!type.includes("ai") && !type.includes("assistant")) continue;
const text = extractText(msg?.content) || extractText(msg);
if (text) return text;
}
return "";
return (
extractText(res?.output) ||
extractText(res?.response) ||
extractText(res?.finalResponse) ||
""
);
})();
const text = structured?.answer?.trim() || fallbackText || "Готово.";
const plan = Array.isArray(structured?.plan) && structured.plan.length
? structured.plan
: ["Собрать данные", "Сформировать ответ"];
const text = structured?.answer?.trim() || fallbackText;
if (!text) {
throw new Error("Model returned empty response");
}
const plan = Array.isArray(structured?.plan) ? structured.plan : [];
return {
text,