import { parseAiJson } from "./parse-json"; export function safeParseAiJson(raw: string): unknown | null { try { return parseAiJson(raw); } catch { return null; } } export function normalizeTeacherPayload(data: unknown): unknown { if (!data || typeof data !== "object") return data; const o = data as Record; const flashcards = Array.isArray(o.flashcards) ? o.flashcards .map((c) => { if (!c || typeof c !== "object") return null; const card = c as Record; const front = String(card.front ?? "").trim(); const back = String(card.back ?? "").trim(); if (!front && !back) return null; return { front, back }; }) .filter(Boolean) : []; const quiz = Array.isArray(o.quiz) ? o.quiz .map((q) => { if (!q || typeof q !== "object") return null; const item = q as Record; const options = Array.isArray(item.options) ? item.options.map((opt) => String(opt)) : []; if (options.length === 0) return null; let answer = Number(item.answer ?? 0); if (!Number.isFinite(answer)) answer = 0; if (answer < 0 || answer >= options.length) answer = 0; return { question: String(item.question ?? "Question"), options, answer, }; }) .filter(Boolean) : []; return { title: o.title != null ? String(o.title) : undefined, introduction: o.introduction != null ? String(o.introduction) : undefined, objectives: Array.isArray(o.objectives) ? o.objectives.map(String).filter(Boolean) : undefined, readingSteps: Array.isArray(o.readingSteps) ? o.readingSteps.map(String).filter(Boolean) : undefined, reflectionPrompt: o.reflectionPrompt != null ? String(o.reflectionPrompt) : undefined, flashcards, quiz, assignment: String(o.assignment ?? o.homework ?? "").trim(), }; } export function normalizeExplorationPayload(data: unknown): unknown { if (!data || typeof data !== "object") return data; const o = data as Record; const items = Array.isArray(o.explorations) ? o.explorations : Array.isArray(o.quests) ? o.quests : []; return { explorations: items .map((item) => { if (!item || typeof item !== "object") return null; const e = item as Record; const title = String(e.title ?? "").trim(); if (!title) return null; const minutes = Number(e.minutes ?? e.duration ?? 20); return { title, hook: String(e.hook ?? e.description ?? e.reason ?? title).trim(), category: String(e.category ?? "general").trim(), minutes: Number.isFinite(minutes) && minutes > 0 ? minutes : 20, }; }) .filter(Boolean), }; } export function debugAiLog( location: string, message: string, data: Record ) { console.error(`[adventureos-ai] ${location}: ${message}`, JSON.stringify(data)); // #region agent log fetch("http://127.0.0.1:7257/ingest/abfa22e4-3d86-4176-9679-7c59b1f0489f", { method: "POST", headers: { "Content-Type": "application/json", "X-Debug-Session-Id": "04e12c", }, body: JSON.stringify({ sessionId: "04e12c", location, message, data, timestamp: Date.now(), }), }).catch(() => {}); // #endregion } export function isAiTimeoutError(error: unknown): boolean { if (!(error instanceof Error)) return false; if (error.name === "TimeoutError") return true; if (error.message.toLowerCase().includes("timeout")) return true; return (error as Error & { code?: number }).code === 23; }