@thanh01.pmt/curriculum-kit 1.4.31 → 1.4.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/index.cjs +126 -1
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +10 -46
- package/dist/ai/index.d.ts +10 -46
- package/dist/ai/index.mjs +126 -1
- package/dist/ai/index.mjs.map +1 -1
- package/dist/index.cjs +128 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +128 -1
- package/dist/index.mjs.map +1 -1
- package/dist/media/index.cjs.map +1 -1
- package/dist/media/index.d.cts +1 -1
- package/dist/media/index.d.ts +1 -1
- package/dist/media/index.mjs.map +1 -1
- package/dist/pipeline/index.cjs +48 -1
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.mjs +48 -1
- package/dist/pipeline/index.mjs.map +1 -1
- package/dist/{streamRunner-DYHFhNUr.d.cts → streamRunner-B0Z1nAG5.d.cts} +76 -1
- package/dist/{streamRunner-DYHFhNUr.d.ts → streamRunner-B0Z1nAG5.d.ts} +76 -1
- package/dist/workflow/index.cjs +48 -1
- package/dist/workflow/index.cjs.map +1 -1
- package/dist/workflow/index.mjs +48 -1
- package/dist/workflow/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/media/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/media/types.ts","../../src/media/imageProviders.ts","../../src/media/stockSearch.ts","../../src/media/ledger.ts","../../src/errors/index.ts","../../src/ai/streamRunner.ts","../../src/media/curator.ts","../../src/media/orchestrate.ts"],"names":["path","fs","resolveApiKey"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Media Types — image generation, image search, video search cho học liệu.\n * Mục tiêu: mọi artifact instruction step-by-step / slide đều có minh họa phù hợp,\n * sinh bằng AI (Gemini/GPT image) HOẶC tìm kiếm ảnh/video thật có license phù hợp.\n */\n\nexport type MediaProvider = 'openai' | 'gemini';\n/** Default = 'openai' (gpt-image-1): infographic quality preferred. */\n\nexport interface GeneratedImage {\n /** Base64-encoded image data (không kèm prefix data:) */\n base64: string;\n mimeType: string;\n /** Provider dùng để sinh (audit/debug) */\n provider: string;\n /** Prompt đã được dùng (sau khi enrich theo ngữ cảnh) */\n prompt: string;\n revisedPrompt?: string;\n}\n\nexport interface StockImage {\n url: string;\n thumbnailUrl?: string;\n width?: number;\n height?: number;\n photographer?: string;\n source: string;\n license: string;\n pageUrl?: string;\n altText?: string;\n}\n\nexport interface StockVideo {\n url: string;\n thumbnailUrl?: string;\n durationSeconds?: number;\n width?: number;\n height?: number;\n source: string;\n license: string;\n pageUrl?: string;\n}\n\nexport interface GenerateImageOptions {\n /** Mô tả minh họa cần sinh */\n prompt: string;\n /** Ngữ cảnh bài học để enrich prompt (concept, grade band, style guide excerpt) */\n context?: {\n lessonTitle?: string;\n concept?: string;\n gradeBand?: [number, number] | number;\n pedagogy?: string;\n styleGuideExcerpt?: string;\n language?: string;\n };\n /** Tỷ lệ khung: 16:9 cho slide, 4:3/1:1 cho worksheet */\n aspectRatio?: '1:1' | '16:9' | '4:3' | '3:4';\n /** Phong cách hình: phù hợp giáo dục, rõ ràng, an toàn cho học sinh */\n style?: 'educational-diagram' | 'realistic-photo' | 'flat-illustration' | 'technical-schematic';\n provider?: MediaProvider;\n /** API key override (nếu không dùng env) */\n apiKey?: string;\n /** Timeout tổng cho request sinh ảnh (mặc định 420_000ms = 7 phút) */\n timeoutMs?: number;\n}\n\nexport interface SearchImageOptions {\n query: string;\n perPage?: number;\n orientation?: 'landscape' | 'portrait' | 'square';\n apiKey?: string;\n}\n\nexport interface SearchVideoOptions {\n query: string;\n perPage?: number;\n apiKey?: string;\n}\n\nexport class MediaError extends Error {\n constructor(message: string, public readonly provider?: string, public readonly status?: number) {\n super(message);\n this.name = 'MediaError';\n }\n}\n\n/** Enrich prompt gốc với ngữ cảnh sư phạm → prompt sinh ảnh chất lượng, nhất quán phong cách */\nexport function buildImagePrompt(options: GenerateImageOptions): string {\n const { prompt, context, style = 'educational-diagram' } = options;\n const parts: string[] = [];\n const styleMap: Record<string, string> = {\n 'educational-diagram': 'clean educational diagram, labeled parts, high contrast, suitable for K-12 textbook',\n 'realistic-photo': 'realistic photograph, natural lighting, educational context',\n 'flat-illustration': 'flat vector illustration, friendly shapes, modern educational style',\n 'technical-schematic': 'precise technical schematic, wiring-style clarity, engineering drawing conventions',\n };\n parts.push(prompt);\n if (context?.concept) parts.push(`Subject concept: ${context.concept}`);\n if (context?.lessonTitle) parts.push(`From lesson: ${context.lessonTitle}`);\n if (context?.gradeBand) {\n const band = Array.isArray(context.gradeBand) ? context.gradeBand : [context.gradeBand, context.gradeBand];\n parts.push(`Audience: grade ${band[0]}-${band[1]} students, age-appropriate, no scary or unsafe imagery`);\n }\n if (context?.styleGuideExcerpt) parts.push(`Visual style guide: ${context.styleGuideExcerpt.slice(0, 200)}`);\n parts.push(styleMap[style] || styleMap['educational-diagram']);\n if (options.aspectRatio === '16:9') parts.push('wide 16:9 composition');\n return parts.join('. ');\n}","import { GeneratedImage, MediaError, GenerateImageOptions, buildImagePrompt } from './types';\n\n/**\n * Image Generation Providers\n * — gemini: Gemini 2.x image generation (generateContent với responseModalities IMAGE)\n * — openai: gpt-image-1 (images/generations endpoint, b64_json)\n * Cả hai trả về GeneratedImage chuẩn — caller không cần biết provider nào.\n */\n\nfunction resolveApiKey(options: GenerateImageOptions): { provider: string; key: string } {\n const provider = options.provider || 'openai';\n const key = options.apiKey\n || (provider === 'openai' ? process.env.OPENAI_API_KEY : undefined)\n || (provider === 'gemini' ? (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY) : undefined)\n || '';\n if (!key) {\n throw new MediaError(`API key missing for image provider '${provider}'. Set GEMINI_API_KEY or OPENAI_API_KEY.`, provider);\n }\n return { provider, key };\n}\n\nfunction resolveImageTimeout(options: GenerateImageOptions): number {\n const envTimeout = Number(process.env.IMAGE_GEN_TIMEOUT_MS || process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS);\n return Number.isFinite(options.timeoutMs) && options.timeoutMs! > 0\n ? options.timeoutMs!\n : (Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : 420_000);\n}\n\nasync function generateWithGemini(options: GenerateImageOptions, key: string): Promise<GeneratedImage> {\n const finalPrompt = buildImagePrompt(options);\n const model = 'gemini-2.0-flash-exp'; // image generation capable\n const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${key}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n contents: [{ parts: [{ text: finalPrompt }] }],\n generationConfig: { responseModalities: ['TEXT', 'IMAGE'] },\n }),\n signal: AbortSignal.timeout(resolveImageTimeout(options)),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new MediaError(`Gemini image API ${res.status}: ${body.slice(0, 300)}`, 'gemini', res.status);\n }\n const data: any = await res.json();\n const parts = data?.candidates?.[0]?.content?.parts || [];\n const imagePart = parts.find((p: any) => p.inlineData?.data);\n if (!imagePart) {\n throw new MediaError('Gemini returned no image part (may have refused prompt).', 'gemini');\n }\n const textPart = parts.find((p: any) => p.text);\n return {\n base64: imagePart.inlineData.data,\n mimeType: imagePart.inlineData.mimeType || 'image/png',\n provider: 'gemini',\n prompt: finalPrompt,\n revisedPrompt: textPart?.text,\n };\n}\n\nasync function generateWithOpenAI(options: GenerateImageOptions, key: string): Promise<GeneratedImage> {\n const finalPrompt = buildImagePrompt(options);\n const sizeMap: Record<string, string> = { '1:1': '1024x1024', '16:9': '1536x1024', '4:3': '1024x1024', '3:4': '1024x1536' };\n const res = await fetch('https://api.openai.com/v1/images/generations', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },\n body: JSON.stringify({\n model: 'gpt-image-1',\n prompt: finalPrompt,\n size: sizeMap[options.aspectRatio || '1:1'] || '1024x1024',\n n: 1,\n }),\n signal: AbortSignal.timeout(resolveImageTimeout(options)),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new MediaError(`OpenAI image API ${res.status}: ${body.slice(0, 300)}`, 'openai', res.status);\n }\n const data: any = await res.json();\n const item = data?.data?.[0];\n if (!item?.b64_json) {\n throw new MediaError('OpenAI returned no image data.', 'openai');\n }\n return {\n base64: item.b64_json,\n mimeType: 'image/png',\n provider: 'openai',\n prompt: finalPrompt,\n revisedPrompt: item.revised_prompt,\n };\n}\n\n/**\n * Sinh ảnh minh họa cho học liệu. Provider mặc định: gemini.\n * Prompt tự động enrich với ngữ cảnh sư phạm (grade band, style guide, khái niệm bài học).\n */\nexport async function generateEducationalImage(options: GenerateImageOptions): Promise<GeneratedImage> {\n const { provider, key } = resolveApiKey(options);\n if (provider === 'openai') return generateWithOpenAI(options, key);\n return generateWithGemini(options, key);\n}","import { MediaError, SearchImageOptions, SearchVideoOptions, StockImage, StockVideo } from './types';\n\n/**\n * Stock Media Search — tìm ảnh/video minh họa THẬT có license mở (Pexels).\n * Dùng khi: không cần sinh AI, muốn ảnh thật của phần cứng (ESP32, breadboard…),\n * hoặc muốn video demo quá trình thực tế cho step-by-step instructions.\n * API key: PEXELS_API_KEY (miễn phí tại pexels.com/api).\n */\n\nexport async function searchEducationalImages(options: SearchImageOptions): Promise<StockImage[]> {\n const key = options.apiKey || process.env.PEXELS_API_KEY || '';\n if (!key) throw new MediaError('Pexels API key missing. Set PEXELS_API_KEY.', 'pexels');\n const params = new URLSearchParams({\n query: options.query,\n per_page: String(options.perPage ?? 6),\n orientation: options.orientation || 'landscape',\n });\n const res = await fetch(`https://api.pexels.com/v1/search?${params}`, {\n headers: { Authorization: key },\n signal: AbortSignal.timeout(30_000),\n });\n if (!res.ok) {\n throw new MediaError(`Pexels image search ${res.status}`, 'pexels', res.status);\n }\n const data: any = await res.json();\n return (data?.photos || []).map((p: any) => ({\n url: p.src?.large2x || p.src?.large || p.src?.original,\n thumbnailUrl: p.src?.medium,\n width: p.width,\n height: p.height,\n photographer: p.photographer,\n source: 'pexels',\n license: 'Pexels License (free to use, attribution appreciated)',\n pageUrl: p.url,\n altText: p.alt,\n }));\n}\n\nexport async function searchEducationalVideos(options: SearchVideoOptions): Promise<StockVideo[]> {\n const key = options.apiKey || process.env.PEXELS_API_KEY || '';\n if (!key) throw new MediaError('Pexels API key missing. Set PEXELS_API_KEY.', 'pexels');\n const params = new URLSearchParams({\n query: options.query,\n per_page: String(options.perPage ?? 4),\n orientation: 'landscape',\n });\n const res = await fetch(`https://api.pexels.com/videos/search?${params}`, {\n headers: { Authorization: key },\n signal: AbortSignal.timeout(30_000),\n });\n if (!res.ok) {\n throw new MediaError(`Pexels video search ${res.status}`, 'pexels', res.status);\n }\n const data: any = await res.json();\n return (data?.videos || []).map((v: any) => {\n const files = v.video_files || [];\n const best = files.filter((f: any) => f.quality === 'hd').sort((a: any, b: any) => (a.width || 0) - (b.width || 0))[0] || files[0];\n return {\n url: best?.link,\n thumbnailUrl: v.image,\n durationSeconds: v.duration,\n width: best?.width,\n height: best?.height,\n source: 'pexels',\n license: 'Pexels License (free to use, attribution appreciated)',\n pageUrl: v.url,\n };\n });\n}","import fs from 'fs';\nimport path from 'path';\n\n/**\n * Media Ledger — sổ cái ảnh per-lesson (JSONL), nguồn chân lý cho quy hoạch ảnh.\n * Vòng đời entry: pending → approved (Curator chốt) → done | failed (kèm lastError)\n * Agent tạo artifact chỉ APPEND (pending). Curator quyết định. Orchestrator thực thi.\n * Idempotent: 1 slug chỉ có 1 entry active; append cùng slug → cập nhật, không trùng.\n */\n\nexport type MediaLedgerMode = 'generate' | 'search';\nexport type MediaLedgerStatus = 'pending' | 'approved' | 'rejected' | 'done' | 'failed';\n\nexport interface MediaLedgerEntry {\n /** Định danh ảnh trong bài, vd 'img-loop-diagram' — unique per lesson */\n slug: string;\n /** Artifact chứa slot, vd 'LESSON_U01_M01_L01' */\n artifactId: string;\n /** Tên ảnh (human-readable) */\n name: string;\n /** Mô tả chi tiết nội dung ảnh — input chính cho Curator enrich + agent con */\n description: string;\n /** 'generate' (AI) hoặc 'search' (ảnh/video thật) */\n mode: MediaLedgerMode;\n /** Vị trí chèn: markdown heading/anchor gần nhất trong artifact */\n anchor?: string;\n status: MediaLedgerStatus;\n /** Provider đã dùng (set khi done) */\n provider?: string;\n /** Inline Markdown credit (tác giả + nguồn + license) — từ multimedia-kit AttributionBuilder */\n attribution?: string;\n /** Path tương đối trong project sau khi done: _media/xxx.png */\n relPath?: string;\n /** Prompt cuối (đã enrich) — audit/debug */\n finalPrompt?: string;\n lastError?: string;\n retryCount?: number;\n /** Quyết định của Curator: mã lý do (duplicate/content_mismatch/...) — audit + user override */\n decisionReasonCode?: string;\n decisionReason?: string;\n updatedAt: string;\n}\n\nexport class MediaLedger {\n readonly filePath: string;\n private entries: Map<string, MediaLedgerEntry> = new Map();\n\n constructor(projectDir: string, lessonId: string) {\n this.filePath = path.join(projectDir, '_media', `ledger-${lessonId.toUpperCase()}.jsonl`);\n this.load();\n }\n\n private load(): void {\n this.entries.clear();\n if (!fs.existsSync(this.filePath)) return;\n const lines = fs.readFileSync(this.filePath, 'utf-8').split('\\n');\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const e = JSON.parse(trimmed) as MediaLedgerEntry;\n this.entries.set(e.slug, e); // last-wins\n } catch { /* dòng hỏng — bỏ qua nhưng không giấu: giữ file nguyên */ }\n }\n }\n\n private persist(): void {\n fs.mkdirSync(path.dirname(this.filePath), { recursive: true });\n fs.writeFileSync(this.filePath, Array.from(this.entries.values()).map(e => JSON.stringify(e)).join('\\n') + '\\n', 'utf-8');\n }\n\n /** Agent tạo artifact ghi entry mới (hoặc cập nhật nếu slug đã có và chưa done) */\n upsert(input: Omit<MediaLedgerEntry, 'status' | 'updatedAt'> & { status?: MediaLedgerStatus }): MediaLedgerEntry {\n const existing = this.entries.get(input.slug);\n if (existing && (existing.status === 'done')) return existing; // done là bất biến\n const entry: MediaLedgerEntry = { ...input, status: input.status ?? 'pending', updatedAt: new Date().toISOString() };\n this.entries.set(input.slug, entry);\n this.persist();\n return entry;\n }\n\n get(slug: string): MediaLedgerEntry | undefined { return this.entries.get(slug); }\n list(): MediaLedgerEntry[] { return Array.from(this.entries.values()); }\n listByStatus(status: MediaLedgerStatus): MediaLedgerEntry[] { return this.list().filter(e => e.status === status); }\n pending(): MediaLedgerEntry[] { return this.listByStatus('pending'); }\n\n setStatus(slug: string, status: MediaLedgerStatus, patch: Partial<MediaLedgerEntry> = {}): MediaLedgerEntry | undefined {\n const e = this.entries.get(slug);\n if (!e) return undefined;\n Object.assign(e, patch, { status, updatedAt: new Date().toISOString() });\n if (status === 'failed') e.retryCount = (e.retryCount ?? 0) + 1;\n this.entries.set(slug, e);\n this.persist();\n return e;\n }\n\n /** Đếm ảnh đã done trong lesson — để Curator tôn trọng maxImages */\n doneCount(): number { return this.listByStatus('done').length; }\n\n /**\n * Scan artifact content và seed pending entries cho mọi placeholder [IMAGE: slug].\n * Được gọi sau khi agent sinh artifact (trước khi Curator duyệt) — đây là cầu nối\n * duy nhất giữa \"agent chèn placeholder\" và \"sổ cái có entry để Curator/Fulfiller xử\".\n * Idempotent: slug đã có entry active (pending/approved/done) → giữ nguyên;\n * chỉ re-describe khi entry trước bị rejected/failed.\n */\n seedFromArtifact(artifactId: string, content: string): MediaLedgerEntry[] {\n const seeded: MediaLedgerEntry[] = [];\n const re = /\\[IMAGE\\s*:\\s*([a-z0-9][a-z0-9-]*)\\s*\\]/gi;\n const seen = new Set<string>();\n let m: RegExpExecArray | null;\n while ((m = re.exec(content)) !== null) {\n const slug = m[1].toLowerCase();\n if (seen.has(slug)) continue;\n seen.add(slug);\n const existing = this.entries.get(slug);\n const isActive = existing && (existing.status === 'pending' || existing.status === 'approved' || existing.status === 'done');\n if (isActive) continue;\n seeded.push(this.upsert({\n slug,\n artifactId,\n name: slug.replace(/^(img-|image-)/, '').replace(/-/g, ' '),\n description: `Placeholder chèn bởi agent trong artifact ${artifactId} — chờ Curator enrich (mô tả gốc chưa có).`,\n mode: 'generate',\n status: 'pending',\n }));\n }\n return seeded;\n }\n}","/**\n * Curriculum OS - Standardized Error Taxonomy & Traceability System\n *\n * Provides typed, structured, and traceable error codes for all pipeline failures,\n * API exceptions, safeguard blocks, and contract violations.\n */\n\nexport type CurriculumErrorCode =\n | 'ERR_AI_NO_API_KEY'\n | 'ERR_AI_RATE_LIMIT'\n | 'ERR_AI_AUTH_FAILED'\n | 'ERR_AI_NETWORK_TIMEOUT'\n | 'ERR_AI_RESPONSE_MALFORMED'\n | 'ERR_AI_ALL_PROVIDERS_FAILED'\n | 'ERR_CUSTOM_INFERENCE_REQUIRED'\n | 'ERR_SOT_MISSING'\n | 'ERR_SOT_INVALID_SCHEMA'\n | 'ERR_TASK_GATE_BLOCKED'\n | 'ERR_METERED_LIMIT_EXCEEDED'\n | 'ERR_SCHEMA_CONTRACT_VIOLATION'\n | 'ERR_STORAGE_IO_FAILED'\n | 'ERR_LESSON_NOT_IN_SOT'\n | 'ERR_CONTEXT_MISSING';\n\nexport interface CurriculumErrorDetail {\n errorCode: CurriculumErrorCode;\n agent?: string;\n artifactType?: string;\n lessonId?: string;\n provider?: string;\n statusCode?: number;\n message: string;\n suggestedAction: string;\n retryable: boolean;\n timestamp: string;\n rawError?: string;\n}\n\nexport class CurriculumError extends Error {\n public readonly detail: CurriculumErrorDetail;\n\n constructor(detail: Omit<CurriculumErrorDetail, 'timestamp'>) {\n super(`[${detail.errorCode}] ${detail.message}`);\n this.name = 'CurriculumError';\n this.detail = {\n ...detail,\n timestamp: new Date().toISOString()\n };\n Object.setPrototypeOf(this, CurriculumError.prototype);\n }\n\n get errorCode(): CurriculumErrorCode {\n return this.detail.errorCode;\n }\n\n get retryable(): boolean {\n return this.detail.retryable;\n }\n\n get suggestedAction(): string {\n return this.detail.suggestedAction;\n }\n\n toJSON(): CurriculumErrorDetail {\n return this.detail;\n }\n}\n\n/**\n * Helper to build standardized AI inference errors\n */\nexport function createAiInferenceError(params: {\n errorCode: CurriculumErrorCode;\n message: string;\n provider?: string;\n statusCode?: number;\n agent?: string;\n artifactType?: string;\n lessonId?: string;\n rawError?: any;\n suggestedAction?: string;\n retryable?: boolean;\n}): CurriculumError {\n const {\n errorCode,\n message,\n provider,\n statusCode,\n agent,\n artifactType,\n lessonId,\n rawError,\n suggestedAction = getSuggestedActionForCode(errorCode),\n retryable = isCodeRetryable(errorCode)\n } = params;\n\n return new CurriculumError({\n errorCode,\n message,\n provider,\n statusCode,\n agent,\n artifactType,\n lessonId,\n suggestedAction,\n retryable,\n rawError: typeof rawError === 'string' ? rawError : rawError?.message || JSON.stringify(rawError)\n });\n}\n\nfunction getSuggestedActionForCode(code: CurriculumErrorCode): string {\n switch (code) {\n case 'ERR_AI_NO_API_KEY':\n return 'Vào Settings > API Keys để cấu hình ít nhất một khóa API (Gemini, DeepSeek, OpenRouter, Alibaba hoặc NVIDIA).';\n case 'ERR_AI_RATE_LIMIT':\n return 'API đã vượt quá giới hạn lượt gọi (Rate Limit HTTP 429). Hãy chờ 30-60 giây rồi bấm Rerun hoặc chuyển sang Provider dự phòng.';\n case 'ERR_AI_AUTH_FAILED':\n return 'API Key không hợp lệ hoặc đã hết hạn (HTTP 401/403). Vui lòng kiểm tra lại Key trong mục Cài đặt.';\n case 'ERR_AI_NETWORK_TIMEOUT':\n return 'Kết nối mạng tới máy chủ AI bị quá thời gian chờ (Timeout). Vui lòng kiểm tra đường truyền và bấm Rerun.';\n case 'ERR_AI_RESPONSE_MALFORMED':\n return 'Mô hình AI trả về kết quả rỗng hoặc không đúng định dạng markdown. Bấm Rerun để yêu cầu AI sinh lại.';\n case 'ERR_AI_ALL_PROVIDERS_FAILED':\n return 'Toàn bộ các nhà cung cấp trong chuỗi Fallback đều thất bại. Vui lòng kiểm tra kết nối Internet và hạn mức Token.';\n case 'ERR_SOT_MISSING':\n return 'Thiếu tài liệu nền tảng SOT (CURRICULUM_FRAMEWORK.md hoặc LEARNER_PROFILE.md). Hãy chạy workflow Khởi tạo dự án trước.';\n case 'ERR_TASK_GATE_BLOCKED':\n return 'Học liệu phía sau bị chặn do Giáo án (LESSON) phía trước chưa được Phê duyệt (Approval Gate). Hãy bấm Phê duyệt Giáo án để mở khóa.';\n case 'ERR_METERED_LIMIT_EXCEEDED':\n return 'Chính sách Metered Execution giới hạn tối đa 2 bài học mỗi đợt. Vui lòng phê duyệt các bài hiện tại trước khi tạo thêm.';\n case 'ERR_SCHEMA_CONTRACT_VIOLATION':\n return 'Nội dung sinh ra thiếu các phần bắt buộc [REQUIRED]. Hãy kích hoạt kiểm thử hoặc bấm Rerun.';\n case 'ERR_STORAGE_IO_FAILED':\n return 'Lỗi đọc/ghi tệp tin trên hệ thống lưu trữ. Kiểm tra quyền ghi thư mục output/projects.';\n case 'ERR_CONTEXT_MISSING':\n return 'Thiếu nguồn tri thức bắt buộc (KNOWLEDGE_EXPOSITION hoặc CANONICAL LESSON) theo Dependency Routing Matrix. Vui lòng tạo hoặc đồng bộ tài liệu nguồn trước.';\n default:\n return 'Bấm Rerun để thử lại hoặc kiểm tra nhật ký hệ thống.';\n }\n}\n\nfunction isCodeRetryable(code: CurriculumErrorCode): boolean {\n switch (code) {\n case 'ERR_AI_RATE_LIMIT':\n case 'ERR_AI_NETWORK_TIMEOUT':\n case 'ERR_AI_RESPONSE_MALFORMED':\n case 'ERR_STORAGE_IO_FAILED':\n return true;\n case 'ERR_AI_NO_API_KEY':\n case 'ERR_AI_AUTH_FAILED':\n case 'ERR_SOT_MISSING':\n case 'ERR_TASK_GATE_BLOCKED':\n case 'ERR_METERED_LIMIT_EXCEEDED':\n case 'ERR_SCHEMA_CONTRACT_VIOLATION':\n case 'ERR_CONTEXT_MISSING':\n return false;\n default:\n return true;\n }\n}\n\nexport function createContextMissingError(params: {\n artifactType: string;\n missingSource: string;\n lessonId?: string;\n agent?: string;\n}): CurriculumError {\n return new CurriculumError({\n errorCode: 'ERR_CONTEXT_MISSING',\n artifactType: params.artifactType,\n lessonId: params.lessonId,\n agent: params.agent,\n message: `Required context source \"${params.missingSource}\" is missing for artifact \"${params.artifactType}\"`,\n suggestedAction: `Generate or provide the authoritative \"${params.missingSource}\" source before producing \"${params.artifactType}\".`,\n retryable: false\n });\n}\n\n","import { createAiInferenceError } from '../errors';\nimport fs from 'fs';\nimport path from 'path';\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system' | 'model';\n content: string;\n}\n\nexport interface StreamRunnerOptions {\n openrouterKey?: string;\n deepseekKey?: string;\n alibabaKey?: string;\n geminiKey?: string;\n nvidiaKey?: string;\n openaiKey?: string;\n anthropicKey?: string;\n model?: string;\n systemPersona?: string;\n maxTokens?: number;\n temperature?: number;\n reasoningEffort?: 'off' | 'low' | 'medium' | 'high' | 'max';\n /** Thời gian tối đa cho phép không nhận thêm token mới trước khi abort (mặc định 90_000ms = 90s; env ARTIFACT_STREAM_IDLE_TIMEOUT_MS override) */\n idleTimeoutMs?: number;\n /** Thời gian hard cap tối đa cho toàn bộ lượt stream trước khi abort (mặc định 420_000ms = 7 phút) */\n timeoutMs?: number;\n /**\n * Host-provided inference override (Vercel AI SDK gateway, test stubs, …).\n * When set, ALL built-in provider routes (raw-fetch NVIDIA/OpenRouter/\n * DeepSeek/DashScope/Gemini + designated fallback chain) are bypassed and\n * every inference call goes through this function instead. It receives the\n * fully-formed system instruction (persona + project context + guidelines)\n * and the user prompt, plus the same onChunk contract as the built-in\n * routes: stream text deltas via ('content'|'thought'), and report token\n * spend via onChunk(JSON.stringify({ promptTokens, completionTokens,\n * totalTokens, reasoningTokens }), 'usage'). Return the full completion text.\n */\n customInference?: (request: {\n systemInstruction: string;\n userPrompt: string;\n messages: ChatMessage[];\n temperature: number;\n maxTokens: number;\n onChunk: (token: string, type: ChunkType) => void;\n }) => Promise<string>;\n}\n\nexport function resolveApiKey(keyName: string, explicitKey?: string): string {\n if (explicitKey && explicitKey.trim()) return explicitKey.trim();\n if (typeof process !== 'undefined' && process.env && process.env[keyName]) {\n return process.env[keyName]!;\n }\n\n try {\n const currentDir = process.cwd();\n const envPaths = [\n path.resolve(currentDir, '.env.local'),\n path.resolve(currentDir, '.env'),\n path.resolve(currentDir, 'apps/web/.env.local'),\n path.resolve(currentDir, 'packages/learnwell-platform/.env'),\n path.resolve(currentDir, '..', '.env.local'),\n path.resolve(currentDir, '..', '.env'),\n path.resolve(currentDir, '../..', '.env.local'),\n path.resolve(currentDir, '../..', '.env'),\n ];\n for (const envPath of envPaths) {\n if (fs.existsSync(envPath)) {\n const content = fs.readFileSync(envPath, 'utf-8');\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith('#') && trimmed.startsWith(keyName + '=')) {\n return trimmed.substring(keyName.length + 1).trim().replace(/^[\"']|[\"']$/g, '');\n }\n }\n }\n }\n } catch {}\n return '';\n}\n\n/**\n * Checks if a specific AI provider is enabled via environment variables.\n * Supported env controls:\n * 1. ENABLE_<PROVIDER>=true|false (e.g. ENABLE_ALIBABA=false, ENABLE_OPENROUTER=true)\n * 2. ALLOWED_AI_PROVIDERS=openrouter,nvidia\n * 3. DISABLED_AI_PROVIDERS=alibaba,deepseek,gemini\n */\nexport function isProviderEnabled(provider: string): boolean {\n const p = provider.toLowerCase();\n\n // 1. Explicit ENABLE_<PROVIDER>=true/false\n const explicitVal = resolveApiKey(`ENABLE_${p.toUpperCase()}`);\n if (explicitVal !== '') {\n return explicitVal === 'true' || explicitVal === '1';\n }\n\n // 2. ALLOWED_AI_PROVIDERS (whitelist)\n const allowedList = resolveApiKey('ALLOWED_AI_PROVIDERS');\n if (allowedList && allowedList.trim()) {\n const allowed = allowedList.split(',').map(s => s.trim().toLowerCase());\n return allowed.includes(p);\n }\n\n // 3. DISABLED_AI_PROVIDERS (blacklist)\n const disabledList = resolveApiKey('DISABLED_AI_PROVIDERS');\n if (disabledList && disabledList.trim()) {\n const disabled = disabledList.split(',').map(s => s.trim().toLowerCase());\n if (disabled.includes(p)) return false;\n }\n\n return true;\n}\n\n/**\n * Checks if a model is permitted by ALLOWED_AI_MODELS filter (supports wildcards e.g. nvidia/*, *:free)\n */\nexport function isModelAllowed(model: string): boolean {\n const allowedList = resolveApiKey('ALLOWED_AI_MODELS');\n if (!allowedList || !allowedList.trim()) return true;\n\n const patterns = allowedList.split(',').map(s => s.trim());\n return patterns.some(pattern => {\n if (pattern === '*' || pattern === model) return true;\n if (pattern.endsWith('*') && model.startsWith(pattern.slice(0, -1))) return true;\n if (pattern.startsWith('*') && model.endsWith(pattern.slice(1))) return true;\n return false;\n });\n}\n\nexport interface FallbackTarget {\n provider: string;\n model: string;\n}\n\n/**\n * Resolves the designated last-resort fallback chain from environment variables.\n * Comma-separated lists are parsed in left-to-right priority order:\n * - FALLBACK_AI_PROVIDER=nvidia,openrouter (Must be enabled / in ALLOWED_AI_PROVIDERS)\n * - FALLBACK_AI_MODEL=nvidia/nemotron-3-ultra-550b-a55b:free,@preset/coding-free,deepseek/deepseek-chat:free\n */\nexport function getDesignatedFallbackChain(): FallbackTarget[] {\n const rawProviders =\n resolveApiKey('FALLBACK_AI_PROVIDER') ||\n resolveApiKey('FALLBACK_AI_PROVIDERS') ||\n resolveApiKey('DEFAULT_AI_PROVIDER') ||\n '9router,nvidia,openrouter';\n\n const rawModels =\n resolveApiKey('FALLBACK_AI_MODEL') ||\n resolveApiKey('FALLBACK_AI_MODELS') ||\n resolveApiKey('DEFAULT_AI_MODEL') ||\n 'fast-reasoning,deep-reasoning,mid-range,free-tier';\n\n // Providers in priority order (MUST be enabled / allowed in ALLOWED_AI_PROVIDERS)\n const providerList = rawProviders\n .split(',')\n .map((p) => p.trim().toLowerCase())\n .filter((p) => p.length > 0 && isProviderEnabled(p));\n\n const modelList = rawModels\n .split(',')\n .map((m) => m.trim())\n .filter((m) => m.length > 0 && isModelAllowed(m));\n\n const chain: FallbackTarget[] = [];\n\n for (const provider of providerList) {\n let providerModels: string[] = [];\n\n if (provider === '9router' || provider === 'ninerouter') {\n providerModels = modelList.filter((m) => ['fast-reasoning', 'deep-reasoning', 'mid-range', 'free-tier'].includes(m));\n if (providerModels.length === 0) {\n providerModels = ['fast-reasoning', 'mid-range', 'free-tier'];\n }\n } else if (provider === 'nvidia') {\n providerModels = modelList.filter((m) => m.startsWith('nvidia/') || m.startsWith('meta/') || m.startsWith('mistralai/'));\n if (providerModels.length === 0) {\n providerModels = ['nvidia/nemotron-3-ultra-550b-a55b:free', 'nvidia/nemotron-3.5-lightning-30b-a3b'];\n }\n } else if (provider === 'openrouter') {\n providerModels = modelList.filter((m) => m.startsWith('@') || m.includes('/') || m.includes(':'));\n if (providerModels.length === 0) {\n providerModels = ['@preset/coding-free', 'deepseek/deepseek-chat:free', 'meta-llama/llama-3.3-70b-instruct:free'];\n }\n } else if (provider === 'alibaba' || provider === 'dashscope') {\n providerModels = modelList.filter((m) => m.startsWith('qwen') || m.includes('deepseek'));\n if (providerModels.length === 0) {\n providerModels = ['deepseek-v4-flash-0731', 'qwen-plus', 'qwen3.7-plus'];\n }\n } else if (provider === 'google' || provider === 'gemini') {\n providerModels = modelList.filter((m) => m.startsWith('gemini'));\n if (providerModels.length === 0) {\n providerModels = ['gemini-2.0-flash', 'gemini-1.5-flash'];\n }\n } else if (provider === 'deepseek') {\n providerModels = modelList.filter((m) => m.startsWith('deepseek'));\n if (providerModels.length === 0) {\n providerModels = ['deepseek-chat', 'deepseek-reasoner'];\n }\n } else {\n providerModels = modelList.length > 0 ? modelList : ['default'];\n }\n\n for (const model of providerModels) {\n if (!chain.some((c) => c.provider === provider && c.model === model)) {\n chain.push({ provider, model });\n }\n }\n }\n\n return chain;\n}\n\nexport function getDesignatedFallbackConfig(): FallbackTarget {\n const chain = getDesignatedFallbackChain();\n if (chain.length > 0) return chain[0];\n return { provider: '9router', model: 'fast-reasoning' };\n}\n\nexport type ChunkType = 'content' | 'thought' | 'tool_call' | 'usage';\n\n/**\n * Separate thinking process from main content safely\n */\nexport function extractThoughtAndContent(rawText: string): { thought: string; content: string } {\n let text = rawText || '';\n let thought = '';\n\n // 1. Explicit <think>...</think> tags\n const thinkMatch = text.match(/<think>([\\s\\S]*?)<\\/think>/i);\n if (thinkMatch) {\n thought = thinkMatch[1].trim();\n text = text.replace(/<think>[\\s\\S]*?<\\/think>/gi, '').trim();\n } else if (text.includes('<think>')) {\n // Unclosed <think> tag\n const parts = text.split('<think>');\n text = parts[0].trim();\n thought = parts[1].trim();\n }\n\n // 2. Patterns like \"Here's a thinking process: ... \\n\\n# Main Title\"\n if (!thought && (text.startsWith(\"Here's a thinking process:\") || text.startsWith(\"Thinking Process:\"))) {\n // Look for markdown heading (# or ## or 🎯 or 1. or ---) as transition to main answer\n const splitRegex = /\\n(?=(?:#|##|###|🎯|🧭|📋|🚀|1\\.\\s+[A-Z\\u00C0-\\u1EF9]|---))/m;\n const match = text.search(splitRegex);\n if (match > 0) {\n thought = text.slice(0, match).trim();\n text = text.slice(match).trim();\n }\n }\n\n // 3. Strip outer markdown codeblock fence if AI wrapped the entire document\n let content = text.trim();\n if (content.startsWith('```markdown')) {\n content = content.replace(/^```markdown\\s*\\n/i, '').replace(/\\n```\\s*$/i, '');\n } else if (content.startsWith('```md')) {\n content = content.replace(/^```md\\s*\\n/i, '').replace(/\\n```\\s*$/i, '');\n } else if (content.startsWith('```') && content.endsWith('```') && !content.includes('---')) {\n content = content.replace(/^```\\w*\\s*\\n/i, '').replace(/\\n```\\s*$/i, '');\n }\n\n return {\n thought: thought.trim(),\n content: content.trim()\n };\n}\n\nexport const DEFAULT_ARTIFACT_STREAM_IDLE_MS = 90_000;\nexport const DEFAULT_ARTIFACT_STREAM_TOTAL_MS = 480_000;\n\nexport interface StreamAbortController {\n signal: AbortSignal;\n /** Reset the idle window (call on every received chunk). */\n kick: () => void;\n /** Clear all pending timers once the request lifecycle is over. */\n dispose: () => void;\n}\n\n/**\n * Budget-aware stream abort controller. Combines an idle window (kicked on\n * every received chunk — covers slow TTFT and hung connections) with a generous\n * total hard cap (defaults to 420s / 7 minutes).\n *\n * Configurable via options or process.env:\n * - ARTIFACT_STREAM_IDLE_TIMEOUT_MS / STREAM_IDLE_TIMEOUT_MS\n * - ARTIFACT_STREAM_TOTAL_TIMEOUT_MS / STREAM_TOTAL_TIMEOUT_MS\n */\nexport function createStreamAbortController(options?: { idleMs?: number; totalMs?: number }): StreamAbortController {\n const envIdle = Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS);\n const envTotal = Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS);\n\n const idleMs = Number.isFinite(options?.idleMs) && (options!.idleMs! > 0)\n ? options!.idleMs!\n : (Number.isFinite(envIdle) && envIdle > 0 ? envIdle : DEFAULT_ARTIFACT_STREAM_IDLE_MS);\n\n const totalMs = Number.isFinite(options?.totalMs) && (options!.totalMs! > 0)\n ? options!.totalMs!\n : (Number.isFinite(envTotal) && envTotal > 0 ? envTotal : DEFAULT_ARTIFACT_STREAM_TOTAL_MS);\n\n const controller = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let totalTimer: ReturnType<typeof setTimeout> | null = null;\n\n const armIdle = () => {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(\n () => controller.abort(new Error(`Idle timeout: no data for ${Math.round(idleMs / 1000)}s`)),\n idleMs\n );\n (idleTimer as any)?.unref?.();\n };\n armIdle();\n\n if (totalMs > 0) {\n totalTimer = setTimeout(\n () => controller.abort(new Error(`Total stream timeout after ${Math.round(totalMs / 1000)}s`)),\n totalMs\n );\n (totalTimer as any)?.unref?.();\n }\n\n return {\n signal: controller.signal,\n kick: armIdle,\n dispose: () => {\n if (idleTimer) clearTimeout(idleTimer);\n if (totalTimer) clearTimeout(totalTimer);\n idleTimer = null;\n totalTimer = null;\n }\n };\n}\n\n/** Backward-compatible alias */\nexport function createIdleAbortController(idleMs?: number, totalMs?: number): StreamAbortController {\n return createStreamAbortController({ idleMs, totalMs });\n}\nexport type IdleAbort = StreamAbortController;\n\n/**\n * Helper to process an OpenAI-compatible SSE response stream with Thinking & Tool Call streaming\n */\nasync function processOpenAISSEStream(\n response: Response,\n onChunk?: (token: string, type: ChunkType) => void,\n idle?: IdleAbort,\n toolCallCollector?: Map<string, { id: string; name: string; argsBuffer: string }>\n): Promise<string> {\n if (!response.body) return '';\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let fullRaw = '';\n let buffer = '';\n let insideThinkTag = false;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n idle?.kick();\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(':')) continue;\n if (trimmed === 'data: [DONE]') continue;\n if (trimmed.startsWith('data: ')) {\n try {\n const json = JSON.parse(trimmed.substring(6));\n\n // 0. Capture exact provider token usage if available in the SSE stream\n if (json.usage) {\n const promptTokens = json.usage.prompt_tokens || json.usage.input_tokens || 0;\n const completionTokens = json.usage.completion_tokens || json.usage.output_tokens || 0;\n const totalTokens = json.usage.total_tokens || (promptTokens + completionTokens);\n const reasoningTokens = json.usage.completion_tokens_details?.reasoning_tokens || 0;\n if (onChunk) {\n onChunk(JSON.stringify({ promptTokens, completionTokens, totalTokens, reasoningTokens }), 'usage');\n }\n }\n\n const delta = json.choices?.[0]?.delta;\n if (!delta) continue;\n\n // 1. Explicit reasoning_content (DeepSeek / Qwen / Claude / Gemini on OpenRouter)\n const reasoning = delta.reasoning_content || delta.thought || delta.reasoning || delta.thought_process || '';\n if (reasoning) {\n if (onChunk) onChunk(reasoning, 'thought');\n }\n\n // 2. Tool Calls — stream ra UI + aggregate thành call hoàn chỉnh khi có collector\n if (delta.tool_calls) {\n const toolStr = JSON.stringify(delta.tool_calls);\n if (onChunk) onChunk(toolStr, 'tool_call');\n if (toolCallCollector) {\n for (const tc of delta.tool_calls) {\n const idx = String(tc.index ?? tc.id ?? '0');\n const existing = toolCallCollector.get(idx) || { id: tc.id || `call_${idx}`, name: '', argsBuffer: '' };\n if (tc.id) existing.id = tc.id;\n if (tc.function?.name) existing.name += tc.function.name;\n if (tc.function?.arguments) existing.argsBuffer += tc.function.arguments;\n toolCallCollector.set(idx, existing);\n }\n }\n }\n\n // 3. Content tokens (handle inline <think> tags dynamically)\n let content = delta.content || '';\n if (content) {\n fullRaw += content;\n\n if (content.includes('<think>')) {\n insideThinkTag = true;\n const parts = content.split('<think>');\n if (parts[0] && onChunk) onChunk(parts[0], 'content');\n content = parts[1] || '';\n }\n if (content.includes('</think>')) {\n insideThinkTag = false;\n const parts = content.split('</think>');\n if (parts[0] && onChunk) onChunk(parts[0], 'thought');\n content = parts[1] || '';\n }\n\n if (insideThinkTag) {\n if (onChunk && content) onChunk(content, 'thought');\n } else if (content) {\n if (onChunk) onChunk(content, 'content');\n }\n }\n } catch {\n // Incomplete JSON chunk, skip\n }\n }\n }\n }\n\n idle?.dispose();\n\n // Final sanity cleanup so raw output has thinking separated\n const extracted = extractThoughtAndContent(fullRaw);\n return extracted.content || fullRaw;\n}\n\n/**\n * Helper to process a Google Gemini SSE stream with Thought streaming\n */\nasync function processGeminiSSEStream(\n response: Response,\n onChunk?: (token: string, type: ChunkType) => void,\n idle?: IdleAbort\n): Promise<string> {\n if (!response.body) return '';\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let fullText = '';\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n idle?.kick();\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(':')) continue;\n if (trimmed.startsWith('data: ')) {\n try {\n const json = JSON.parse(trimmed.substring(6));\n\n if (json.usageMetadata) {\n const promptTokens = json.usageMetadata.promptTokenCount || 0;\n const completionTokens = json.usageMetadata.candidatesTokenCount || 0;\n const totalTokens = json.usageMetadata.totalTokenCount || (promptTokens + completionTokens);\n if (onChunk) {\n onChunk(JSON.stringify({ promptTokens, completionTokens, totalTokens }), 'usage');\n }\n }\n\n const parts = json.candidates?.[0]?.content?.parts || [];\n for (const part of parts) {\n if (part.thought) {\n if (onChunk) onChunk(part.text || '', 'thought');\n } else if (part.text) {\n fullText += part.text;\n if (onChunk) onChunk(part.text, 'content');\n }\n }\n } catch {\n // Incomplete JSON chunk, skip\n }\n }\n }\n }\n idle?.dispose();\n return fullText;\n}\n\n/**\n * Real-time Streaming Multi-Provider Inference Runner with Thinking & Tool Streaming\n */\nexport async function streamCurriculumAIInference(\n messages: ChatMessage[],\n projectContext: string,\n options: StreamRunnerOptions = {},\n onChunk?: (token: string, type: ChunkType) => void\n): Promise<string> {\n const openrouterKey = resolveApiKey('OPENROUTER_API_KEY', options.openrouterKey);\n const deepseekKey = resolveApiKey('DEEPSEEK_API_KEY', options.deepseekKey);\n const alibabaKey = resolveApiKey('ALIBABA_API_KEY', options.alibabaKey) || resolveApiKey('DASHSCOPE_API_KEY');\n const geminiKey = resolveApiKey('GEMINI_API_KEY', options.geminiKey) || resolveApiKey('NEXT_PUBLIC_GEMINI_API_KEY');\n const nvidiaKey = resolveApiKey('NVIDIA_API_KEY', options.nvidiaKey);\n\n const temperature = options.temperature ?? 0.3;\n // Default to 32768 tokens (32k) so long reasoning, deep curriculum artifacts, code labs, and quizzes are never truncated\n const maxTokens = options.maxTokens ?? 32768;\n\n const basePersona = options.systemPersona || 'You are Curriculum OS Assistant — Senior AI Technical Curriculum Architect & Educational Content Specialist.';\n\n const systemInstruction = `${basePersona}\n\nProject Context:\n${projectContext}\n\nGuidelines:\n1. You have full context of the project hierarchy, syllabus, lessons, and learning objectives. Answer precisely, deeply, and directly.\n2. Complete responses fully without truncation. When generating tables or roadmaps, include all sections/milestones.\n3. Keep technical terminology and official API symbols intact.\n4. Format output using clean Markdown, clear sections, bullet points, and code blocks where required.\n5. Do NOT use emojis in headings, tab titles, or UI navigation labels.`;\n\n // ── Route 0: Host-provided inference override (Vercel AI SDK gateway, …) ──\n // When the embedding app supplies customInference, it is the SOLE inference\n // path: the raw-fetch provider routes below never run, so host apps that\n // mandate a gateway (e.g. Vercel AI SDK) get exactly one auditable engine.\n if (options.customInference) {\n try {\n const text = await options.customInference({\n systemInstruction,\n userPrompt: messages.map(m => m.content).join('\\n\\n'),\n messages,\n temperature,\n maxTokens,\n onChunk: onChunk ?? (() => {}),\n });\n if (text && text.trim()) return text;\n throw createAiInferenceError({\n errorCode: 'ERR_AI_ALL_PROVIDERS_FAILED',\n message: 'customInference returned empty output',\n rawError: { customInference: 'empty response' }\n });\n } catch (e: any) {\n if (e?.errorCode || e?.name === 'AiInferenceError') throw e;\n throw createAiInferenceError({\n errorCode: 'ERR_AI_ALL_PROVIDERS_FAILED',\n message: `customInference failed: ${e?.message || e}`,\n rawError: { customInference: String(e?.message || e) }\n });\n }\n }\n\n // ── Unified-tracing mandate (2026-09-14): fail LOUD on silent bypass ──\n // The embedding app routes every LLM call through its own gateway\n // (customInference → Vercel AI SDK → OpenTelemetry → Langfuse). The raw-fetch\n // routes below are OUTSIDE that telemetry boundary: a call site that forgets\n // to pass customInference used to fall through here silently, producing\n // untraceable generations. When the host mandates gateway-only inference\n // (CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE=1), refuse to run raw instead of\n // silently bypassing the unified tracing mechanism.\n if (!options.customInference && resolveApiKey('CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE') === '1') {\n throw createAiInferenceError({\n errorCode: 'ERR_CUSTOM_INFERENCE_REQUIRED',\n message:\n 'customInference is REQUIRED (CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE=1): pass buildKitCustomInference(...) ' +\n 'so every LLM call flows through the host AI SDK gateway and its unified Langfuse tracing. ' +\n 'Raw-fetch provider routes are disabled by mandate.',\n rawError: { mandate: 'CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE', hasCustomInference: false },\n });\n }\n\n const formattedMessages = [\n { role: 'system', content: systemInstruction },\n ...messages.map(m => ({\n role: m.role === 'assistant' || m.role === 'model' ? 'assistant' : 'user',\n content: m.content\n }))\n ];\n\n // Collect failure errors for full traceability\n const providerErrors: Record<string, string> = {};\n\n const requestedModel = options.model || 'fast-reasoning';\n const isNvidiaPreferred = requestedModel.startsWith('nvidia/') || (Boolean(nvidiaKey && !openrouterKey) && isProviderEnabled('nvidia'));\n\n // ── Route 0: 9Router Gateway ──\n const ninerouterKey = resolveApiKey('NINEROUTER_API_KEY') || resolveApiKey('NINE_ROUTER_API_KEY');\n if (ninerouterKey && isProviderEnabled('9router')) {\n const rawUrl = resolveApiKey('NINEROUTER_BASE_URL') || resolveApiKey('NINE_ROUTER_BASE_URL') || 'https://ai-router.orchable.app/v1';\n const ninerouterBaseUrl = rawUrl.replace(/^[\"']|[\"']$/g, '').replace(/\\/$/, '');\n const candidateModels = [\n options.model || 'fast-reasoning',\n 'fast-reasoning',\n 'mid-range',\n 'free-tier',\n ].filter(m => isModelAllowed(m));\n const unique9RouterModels = Array.from(new Set(candidateModels));\n\n for (const model of unique9RouterModels) {\n try {\n // 2026-09-14 (SLIDE idle audit): 45s was tuned for chat-sized prompts.\n // SLIDE cluster prompts run 30k+ chars and the gateway can think for\n // >45s BEFORE the first token, so the budget aborted healthy streams\n // (\"Idle timeout: no data for 45s\"). Honor options.idleTimeoutMs /\n // env like every other route, falling back to the same 90s default.\n const r9Idle = options.idleTimeoutMs\n ?? (Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS) || 0)\n ?? 0;\n const r9Total = options.timeoutMs\n ?? (Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS) || 0)\n ?? 0;\n const idle = createStreamAbortController({\n idleMs: r9Idle > 0 ? r9Idle : 90_000,\n totalMs: r9Total > 0 ? r9Total : 300_000,\n });\n const res = await fetch(`${ninerouterBaseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${ninerouterKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true },\n }),\n signal: idle.signal,\n });\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`9router_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`9router_${model}`] = e?.message || 'Network error';\n console.warn(`[9Router Stream] Failover for ${model}:`, e?.message || e);\n }\n }\n }\n\n // ── Route 1: NVIDIA NIM (Nemotron Suite) ──\n if (nvidiaKey && isProviderEnabled('nvidia')) {\n const candidateNemotronModels = [\n requestedModel.startsWith('nvidia/') ? requestedModel : 'nvidia/nemotron-3-ultra-550b-a55b:free',\n 'nvidia/nemotron-3-ultra-550b-a55b:free',\n 'nvidia/nemotron-3.5-lightning-30b-a3b',\n 'nvidia/nemotron-3-super-120b-a12b',\n 'nvidia/llama-3.1-nemotron-70b-instruct'\n ].filter(m => isModelAllowed(m));\n const uniqueNvidiaModels = Array.from(new Set(candidateNemotronModels));\n\n if (isNvidiaPreferred || uniqueNvidiaModels.length > 0) {\n for (const model of uniqueNvidiaModels) {\n try {\n const nvdIdle = options.idleTimeoutMs ?? 180_000;\n const nvdTotal = options.timeoutMs ?? 600_000;\n const idle = createStreamAbortController({ idleMs: nvdIdle, totalMs: nvdTotal });\n const res = await fetch('https://integrate.api.nvidia.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${nvidiaKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`nvidia_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`nvidia_${model}`] = e?.message || 'Network error';\n console.warn(`[NVIDIA Stream] Failover for ${model}:`, e?.message || e);\n }\n }\n }\n }\n\n // ── Route 2: OpenRouter (Primary Free Presets & Models) ──\n if (openrouterKey && isProviderEnabled('openrouter')) {\n const openrouterModels = [\n requestedModel,\n 'openrouter/free',\n 'nvidia/nemotron-3-super-120b-a12b:free',\n 'nvidia/nemotron-3-ultra-550b-a55b:free',\n 'nvidia/nemotron-3.5-lightning:free',\n 'minimax/minimax-m3:free',\n 'cohere/north-mini-code:free',\n ].filter(m => isModelAllowed(m));\n const uniqueOrModels = Array.from(new Set(openrouterModels));\n\n for (const model of uniqueOrModels) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch('https://openrouter.ai/api/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${openrouterKey}`,\n 'Content-Type': 'application/json',\n 'HTTP-Referer': 'https://orchable.composer',\n 'X-Title': 'Curriculum OS Studio'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`openrouter_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n if (res.status === 429) {\n console.warn(`[OpenRouter] Rate limited (429) for ${model}, trying fallback...`);\n }\n }\n } catch (e: any) {\n providerErrors[`openrouter_${model}`] = e?.message || 'Network error';\n console.warn(`[OpenRouter Stream] Failover for ${model}:`, e?.message || e);\n }\n }\n }\n\n // ── Route 3: DeepSeek Official API (Configurable via ENABLE_DEEPSEEK=true) ──\n if (deepseekKey && isProviderEnabled('deepseek')) {\n const dsModel = options.model?.includes('deepseek-reasoner') ? 'deepseek-reasoner' : 'deepseek-chat';\n if (isModelAllowed(dsModel)) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch('https://api.deepseek.com/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${deepseekKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n model: dsModel,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors['deepseek'] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors['deepseek'] = e?.message || 'Network error';\n console.warn(`[DeepSeek Stream] Failover:`, e?.message || e);\n }\n }\n }\n\n // ── Route 4: Alibaba DashScope / Qwen Cloud (Configurable via ENABLE_ALIBABA=true) ──\n if (alibabaKey && isProviderEnabled('alibaba')) {\n const qwenModels = (options.model?.startsWith('qwen')\n ? [options.model, 'qwen3.7-plus', 'qwen3.6-flash']\n : ['qwen3.7-plus', 'qwen3.6-flash']).filter(m => isModelAllowed(m));\n\n const baseUrl = alibabaKey.startsWith('sk-sp-')\n ? 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions'\n : 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions';\n\n for (const qwenModel of qwenModels) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const payload: any = {\n model: qwenModel,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n };\n\n const res = await fetch(baseUrl, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${alibabaKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`alibaba_${qwenModel}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`alibaba_${qwenModel}`] = e?.message || 'Network error';\n console.warn(`[Alibaba Stream] Failover for ${qwenModel}:`, e?.message || e);\n }\n }\n }\n\n // ── Route 5: Google Gemini Direct (Configurable via ENABLE_GEMINI=true) ──\n if (geminiKey && (isProviderEnabled('gemini') || isProviderEnabled('google'))) {\n const geminiModels = (options.model?.startsWith('gemini')\n ? [options.model, 'gemini-1.5-flash', 'gemini-2.0-flash']\n : ['gemini-1.5-flash', 'gemini-2.0-flash']).filter(m => isModelAllowed(m));\n\n const geminiContents = [\n { role: 'user', parts: [{ text: systemInstruction }] },\n { role: 'model', parts: [{ text: 'Tôi đã hiểu rõ toàn bộ bối cảnh dự án và sẵn sàng hỗ trợ bạn một cách chuyên sâu, chính xác nhất.' }] },\n ...messages.map(m => ({\n role: m.role === 'assistant' || m.role === 'model' ? 'model' : 'user',\n parts: [{ text: m.content }]\n }))\n ];\n\n for (const gModel of geminiModels) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${gModel}:streamGenerateContent?alt=sse&key=${geminiKey}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n contents: geminiContents,\n generationConfig: {\n temperature,\n maxOutputTokens: maxTokens,\n }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processGeminiSSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`gemini_${gModel}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`gemini_${gModel}`] = e?.message || 'Network error';\n console.warn(`[Gemini Stream] Failover for ${gModel}:`, e?.message || e);\n }\n }\n }\n\n // ── Route 6: Ultimate Designated Fallback Chain (Configurable via FALLBACK_AI_PROVIDER / FALLBACK_AI_MODEL) ──\n const fallbackChain = getDesignatedFallbackChain();\n if (fallbackChain.length > 0) {\n console.log(\n `[streamRunner] 🛡️ Primary routes failed/exhausted. Invoking designated last-resort fallback chain:`,\n fallbackChain.map((c) => `${c.provider}(${c.model})`).join(' -> ')\n );\n\n for (const target of fallbackChain) {\n const { provider, model } = target;\n\n // ── 9Router designated fallback ──\n // 2026-09-14 (9Router-only mandate): the loop previously had NO branch\n // for provider '9router', so a 9router-only chain iterated without ever\n // attempting a call and providerErrors stayed {} — masking the real\n // failure as \"Chi tiết: {}\". This branch makes the designated fallback\n // actually call the gateway (OpenAI-compatible SSE, same as Route 0).\n if ((provider === '9router' || provider === 'ninerouter') && ninerouterKey && isProviderEnabled('9router')) {\n try {\n const rawUrl = resolveApiKey('NINEROUTER_BASE_URL') || resolveApiKey('NINE_ROUTER_BASE_URL') || 'https://ai-router.orchable.app/v1';\n const fbBaseUrl = rawUrl.replace(/[\"']/g, '').replace(/\\/$/, '');\n // Same SLIDE idle-audit fix as Route 0: honor options/env instead of\n // a hardcoded 45s that aborted healthy long-prompt streams.\n const fbIdle = options.idleTimeoutMs\n ?? (Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS) || 0)\n ?? 0;\n const fbTotal = options.timeoutMs\n ?? (Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS) || 0)\n ?? 0;\n const idle = createStreamAbortController({\n idleMs: fbIdle > 0 ? fbIdle : 90_000,\n totalMs: fbTotal > 0 ? fbTotal : 300_000,\n });\n const res = await fetch(`${fbBaseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${ninerouterKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true },\n }),\n signal: idle.signal,\n });\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback 9Router (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_9router_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_9router_${model}`] = e?.message || 'Network error';\n }\n } else if (provider === 'nvidia' && nvidiaKey && isProviderEnabled('nvidia')) {\n try {\n const nvdIdle = options.idleTimeoutMs ?? 180_000;\n const nvdTotal = options.timeoutMs ?? 600_000;\n const idle = createStreamAbortController({ idleMs: nvdIdle, totalMs: nvdTotal });\n const res = await fetch('https://integrate.api.nvidia.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${nvidiaKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback NVIDIA (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_nvidia_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_nvidia_${model}`] = e?.message || 'Network error';\n }\n } else if (provider === 'openrouter' && openrouterKey && isProviderEnabled('openrouter')) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch('https://openrouter.ai/api/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${openrouterKey}`,\n 'Content-Type': 'application/json',\n 'HTTP-Referer': 'https://orchable.composer',\n 'X-Title': 'Curriculum OS Studio'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback OpenRouter (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_openrouter_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_openrouter_${model}`] = e?.message || 'Network error';\n }\n } else if ((provider === 'alibaba' || provider === 'dashscope') && alibabaKey && isProviderEnabled('alibaba')) {\n const baseUrl = alibabaKey.startsWith('sk-sp-')\n ? 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions'\n : 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions';\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch(baseUrl, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${alibabaKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback Alibaba (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_alibaba_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_alibaba_${model}`] = e?.message || 'Network error';\n }\n } else if ((provider === 'google' || provider === 'gemini') && geminiKey && (isProviderEnabled('gemini') || isProviderEnabled('google'))) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs }); const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${geminiKey}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n contents: [\n { role: 'user', parts: [{ text: systemInstruction }] },\n { role: 'model', parts: [{ text: 'Understood. I will follow the project context and guidelines.' }] },\n ...messages.map((m) => ({\n role: m.role === 'assistant' || m.role === 'model' ? 'model' : 'user',\n parts: [{ text: m.content }]\n }))\n ],\n generationConfig: {\n temperature,\n maxOutputTokens: maxTokens\n }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processGeminiSSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback Gemini (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_gemini_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_gemini_${model}`] = e?.message || 'Network error';\n }\n }\n }\n }\n\n const isRateLimited = Object.values(providerErrors).some(msg => msg.includes('429'));\n const isAuthFailed = Object.values(providerErrors).some(msg => msg.includes('401') || msg.includes('403'));\n\n const errorCode = isRateLimited\n ? 'ERR_AI_RATE_LIMIT'\n : isAuthFailed\n ? 'ERR_AI_AUTH_FAILED'\n : 'ERR_AI_ALL_PROVIDERS_FAILED';\n\n throw createAiInferenceError({\n errorCode,\n message: `Không thể kết nối tới các nhà cung cấp AI trong chuỗi Fallback. Chi tiết: ${JSON.stringify(providerErrors)}`,\n rawError: providerErrors\n });\n}\n\n/**\n * Synchronous Multi-Model Inference Wrapper with strict error propagation\n */\nexport async function runCurriculumAIInference(\n messages: ChatMessage[],\n projectContext: string,\n options: StreamRunnerOptions = {},\n onChunk?: (token: string, type: ChunkType) => void\n): Promise<string> {\n return await streamCurriculumAIInference(messages, projectContext, options, onChunk);\n}\n","import { runCurriculumAIInference, type StreamRunnerOptions } from '../ai/streamRunner';\nimport type { MediaLedger, MediaLedgerEntry } from './ledger';\nimport { MediaError } from './types';\n\nexport type MediaPolicyMode = 'search_only' | 'gen_only' | 'auto';\n\nexport interface MediaPolicy {\n /** Giới hạn số ảnh ĐƯỢC GEN (AI) tối đa per artifact — search kho ảnh KHÔNG tốn quota */\n maxGenImagesPerArtifact: number;\n /** Ưu tiên provider khi mode=generate */\n preferredProvider?: 'openai' | 'gemini';\n /**\n * Chiến lược nguồn ảnh:\n * — search_only: chỉ tìm kho ảnh (Pexels), không sinh AI\n * — gen_only: chỉ sinh AI, bỏ qua kho ảnh\n * — auto: LUÔN search trước, không có kết quả mới generate (mặc định)\n */\n mode?: MediaPolicyMode;\n}\n\nexport interface CurationDecision {\n slug: string;\n action: 'approve' | 'drop' | 're-describe';\n /** Mã lý do máy-đọc-được — bắt buộc khi drop, để audit + user có thể override */\n reasonCode?: 'duplicate' | 'content_mismatch' | 'low_quality_description' | 'over_quota' | 'none_needed';\n /** Mô tả đã enrich (grade band, style, pedagogy) — chỉ khi approve/re-describe */\n enrichedPrompt?: string;\n reason: string;\n}\n\nexport interface CurateOptions {\n ledger: MediaLedger;\n /** Nội dung artifact ĐÃ PASS judge (markdown, strip YAML) */\n artifactContent: string;\n policy: MediaPolicy;\n /** Ngữ cảnh dự án: grade band, style guide, tiêu đề bài */\n context: {\n lessonTitle?: string;\n gradeBand?: [number, number];\n styleGuideExcerpt?: string;\n language?: string;\n };\n llm?: StreamRunnerOptions;\n}\n\n/**\n * Curator: phân tích toàn bộ sổ cái + nội dung đã chốt → quyết định ảnh nào tạo.\n * Tôn trọng maxImagesPerArtifact (count cả ảnh done + pending được approve).\n * LLM trả JSON: [{slug, action, enrichedPrompt, reason}]. Parse lỗi → MediaError rõ ràng.\n */\nexport async function curateMediaLedger(options: CurateOptions): Promise<CurationDecision[]> {\n const { ledger, artifactContent, policy, context } = options;\n const pendingEntries = ledger.pending();\n if (pendingEntries.length === 0) return [];\n\n const genQuota = Math.max(0, (policy.maxGenImagesPerArtifact ?? 3) - ledger.doneCount());\n const entriesBrief = pendingEntries.map(e => `- slug=${e.slug} | mode=${e.mode} | name=${e.name} | desc=${e.description.slice(0, 300)}`).join('\\n');\n\n const prompt = `Bạn là Media Curator cho học liệu giáo dục. Sổ cái có ${pendingEntries.length} ảnh đề xuất (pending), đã có ${ledger.doneCount()} ảnh hoàn tất, quota GEN tối đa ${policy.maxGenImagesPerArtifact} ảnh/bài (search kho ảnh KHÔNG tốn quota — xử ở tầng thực thi).\n${context.lessonTitle ? `Bài học: ${context.lessonTitle}` : ''}\n${context.gradeBand ? `Grade band: ${context.gradeBand[0]}-${context.gradeBand[1]}` : ''}\n\nCác ảnh đề xuất (sổ cái):\n${entriesBrief}\n\nNội dung bài (đã duyệt):\n${artifactContent.slice(0, 12000)}\n\nQUY TẮC PHÂN BỔ THEO 2 TRƯỜNG HỢP:\nA) Nếu ${pendingEntries.length} <= ${genQuota}: APPROVE TẤT CẢ — trừ khi có lý do CỨNG:\n - duplicate: 2+ ảnh cùng chủ đề (chỉ giữ 1, cái còn lại action=drop reasonCode=duplicate)\n - content_mismatch: mô tả không liên quan gì đến nội dung bài\n - low_quality_description: mô tả mơ hồ đến mức không thể tạo ảnh dùng được (vd \"ảnh minh họa chung\")\n KHÔNG được drop vì \"cảm thấy không cần\" — agent tạo đã lọc từ đầu.\nB) Về quota GEN (tối đa ${policy.maxGenImagesPerArtifact} ảnh AI/bài): KHÔNG drop ở bước này vì quota —\n tầng thực thi sẽ search kho ảnh trước cho mọi slot, chỉ những slot search-miss mới được xếp hạng để gen.\n Việc của bạn ở đây: approve/re-describe/drop theo 3 lý do CỨNG ở trên.\n\nVới mỗi ảnh approve/re-describe: viết enrichedPrompt TIẾNG ANH chi tiết (subject, layout, labeled parts, educational-diagram style, age-appropriate).\nKHÔNG BAO GIỜ approve vượt ${genQuota}.\n\nTrả về CHÍNH XÁC JSON (không markdown fence) cho TẤT CẢ các slug:\n[{\"slug\":\"...\",\"action\":\"approve|drop|re-describe\",\"reasonCode\":\"duplicate|content_mismatch|low_quality_description|over_quota\",\"enrichedPrompt\":\"...\",\"reason\":\"...\"}]`;\n\n const raw = await runCurriculumAIInference(\n [{ role: 'user', content: prompt }],\n '',\n options.llm || {}\n );\n\n const jsonMatch = raw.match(/\\[[\\s\\S]*\\]/);\n if (!jsonMatch) throw new MediaError(`Curator LLM trả về không parse được JSON: ${raw.slice(0, 200)}`, 'curator');\n let decisions: CurationDecision[];\n try {\n decisions = JSON.parse(jsonMatch[0]);\n } catch (e: any) {\n throw new MediaError(`Curator JSON invalid: ${e?.message}`, 'curator');\n }\n\n // Validate + enforce maxImages server-side (LLM không được vượt quota) + kiểm định danh\n const validSlugs = new Set(pendingEntries.map(e => e.slug));\n decisions = decisions.filter(d => validSlugs.has(d.slug)); // bỏ slug bịa\n\n const approved = decisions.filter(d => d.action === 'approve' || d.action === 're-describe');\n const overflow = approved.slice(genQuota);\n for (const d of overflow) {\n d.action = 'drop';\n d.reasonCode = 'over_quota';\n d.reason = 'Vượt maxImagesPerArtifact sau kiểm tra server-side';\n }\n\n // Bắt buộc reasonCode khi drop — fallback 'none_needed' nếu LLM quên\n for (const d of decisions) {\n if (d.action === 'drop' && !d.reasonCode) d.reasonCode = 'none_needed';\n }\n\n // Persist quyết định vào sổ cái (kèm reasonCode để audit + user override)\n for (const d of decisions) {\n if (d.action === 'drop') {\n ledger.setStatus(d.slug, 'rejected', { decisionReasonCode: d.reasonCode, decisionReason: d.reason, lastError: d.reason });\n } else {\n ledger.setStatus(d.slug, 'approved', { decisionReasonCode: undefined, decisionReason: d.reason, finalPrompt: d.enrichedPrompt });\n }\n }\n return decisions;\n \n\n}\n/** Input ranking cho 1 gen candidate */\nexport interface GenCandidate {\n slug: string;\n name: string;\n description: string;\n}\n\nexport interface GenRanking {\n /** Slugs được quyền gen (≤ quota) theo thứ tự ưu tiên */\n selected: string[];\n /** Slots không được gen kèm lý do */\n dropped: Array<{ slug: string; rank: number }>;\n}\n\n/**\n * Xếp hạng gen candidates khi số slot search-miss (hoặc gen_only tổng slot) VƯỢT quota gen.\n * Chỉ xếp hạng theo mức cần thiết của minh họa cho hiểu bài — KHÔNG đụng ledger (orchestrate lo persist).\n * LLM fail → fallback first-come theo thứ tự sổ cái + log warning rõ (degradation có chủ đích, không im lặng).\n */\nexport async function rankGenCandidates(\n candidates: GenCandidate[],\n quota: number,\n context: { lessonTitle?: string; gradeBand?: [number, number] },\n llm?: StreamRunnerOptions\n): Promise<GenRanking> {\n if (candidates.length <= quota) {\n return { selected: candidates.map(c => c.slug), dropped: [] };\n }\n\n const brief = candidates.map((c, i) => `${i + 1}. slug=${c.slug} | name=${c.name} | desc=${c.description.slice(0, 250)}`).join('\\n');\n const prompt = `Xếp hạng ${candidates.length} ảnh minh họa giáo dục, chọn ĐÚNG ${quota} ảnh ưu tiên gen (ảnh AI tốn kém).\n${context.lessonTitle ? `Bài học: ${context.lessonTitle}` : ''}\n${context.gradeBand ? `Grade band: ${context.gradeBand[0]}-${context.gradeBand[1]}` : ''}\n\nCandidates:\n${brief}\n\nThứ tự ưu tiên:\n1. Diagram/sơ đồ giải thích khái niệm trừu tượng hoặc quy trình nhiều bước (thiếu là khó hiểu nhất)\n2. Minh họa step-by-step thực hành (wiring, thao tác, UI)\n3. Ảnh bối cảnh/động lực (ít cần nhất)\n\nTrả CHÍNH XÁC JSON (không fence): {\"selected\":[\"slug1\",\"slug2\",...]} — đúng ${quota} slugs, theo thứ tự ưu tiên.`;\n\n try {\n const raw = await runCurriculumAIInference([{ role: 'user', content: prompt }], '', llm || {});\n const m = raw.match(/\\{[\\s\\S]*\\}/);\n if (!m) throw new Error('no JSON in response');\n const parsed = JSON.parse(m[0]) as { selected?: string[] };\n const valid = (parsed.selected || []).filter(s => candidates.some(c => c.slug === s)).slice(0, quota);\n if (valid.length === 0) throw new Error('empty selection');\n const selectedSet = new Set(valid);\n // Fill nếu LLM chọn thiếu quota: lấy theo thứ tự gốc\n for (const c of candidates) {\n if (valid.length >= quota) break;\n if (!selectedSet.has(c.slug)) { valid.push(c.slug); selectedSet.add(c.slug); }\n }\n const dropped = candidates.filter(c => !selectedSet.has(c.slug)).map((c, i) => ({ slug: c.slug, rank: i + 1 }));\n return { selected: valid, dropped };\n } catch (err: any) {\n // KHÔNG giấu lỗi — warn rõ rồi fallback first-come (ổn định, không chặn pipeline)\n console.warn('[curator] rankGenCandidates LLM failed — fallback first-come order:', err?.message || err);\n const selected = candidates.slice(0, quota).map(c => c.slug);\n const dropped = candidates.slice(quota).map((c, i) => ({ slug: c.slug, rank: i + 1 }));\n return { selected, dropped };\n }\n}","import fs from 'fs';\nimport path from 'path';\nimport { generateEducationalImage } from './imageProviders';\nimport { searchEducationalImages, searchEducationalVideos } from './stockSearch';\nimport type { MediaProvider } from './types';\nimport { MediaLedger, type MediaLedgerEntry } from './ledger';\nimport { rankGenCandidates } from './curator';\nimport type { MediaPolicy } from './curator';\nimport type { StreamRunnerOptions } from '../ai/streamRunner';\n\nexport interface FulfillOptions {\n ledger: MediaLedger;\n projectDir: string;\n policy: MediaPolicy;\n /** Tỷ lệ khung mặc định cho artifact type (SLIDE → 16:9) */\n defaultAspect?: '1:1' | '16:9' | '4:3' | '3:4';\n apiKeyOverrides?: { openai?: string; gemini?: string; pexels?: string };\n /** Số lần retry tối đa trước khi đánh dấu failed vĩnh viễn */\n maxRetries?: number;\n /** Ngữ cảnh cho gen-ranking (khi search-miss vượt quota gen) */\n rankingContext?: { lessonTitle?: string; gradeBand?: [number, number] };\n llm?: StreamRunnerOptions;\n onProgress?: (slug: string, status: string, detail?: string) => void;\n}\n\nexport interface FulfillResult {\n done: string[];\n failed: string[];\n skipped: string[];\n}\n\n/**\n * Thực thi các entry approved trong sổ cái (từng ảnh độc lập — lỗi 1 ảnh không chặn ảnh khác).\n * generate → base64 → save file _media/; search → lưu URL đầu tiên (metadata vào ledger).\n * Quá maxRetries → status 'failed', slot giữ placeholder trong markdown (client render).\n */\nexport async function fulfillMediaLedger(options: FulfillOptions): Promise<FulfillResult> {\n const { ledger, projectDir, policy } = options;\n const maxRetries = options.maxRetries ?? 2;\n const approved = ledger.listByStatus('approved');\n const result: FulfillResult = { done: [], failed: [], skipped: [] };\n\n const mediaDir = path.join(projectDir, '_media');\n fs.mkdirSync(mediaDir, { recursive: true });\n\n const mode = policy.mode ?? 'auto';\n const canSearch = mode === 'search_only' || mode === 'auto';\n const canGen = mode === 'gen_only' || mode === 'auto';\n\n // ── PHA 1: SEARCH kho ảnh cho TẤT CẢ slots (search không tốn quota gen) ──\n const searchMisses: typeof approved = [];\n if (canSearch) {\n for (const entry of approved) {\n if ((entry.retryCount ?? 0) >= maxRetries) { result.skipped.push(entry.slug); continue; }\n options.onProgress?.(entry.slug, 'searching');\n try {\n const images = await searchEducationalImages({\n query: entry.finalPrompt || entry.description,\n perPage: 1,\n apiKey: options.apiKeyOverrides?.pexels,\n });\n const target = images[0];\n if (target) {\n ledger.setStatus(entry.slug, 'done', { relPath: target.url, provider: 'pexels' });\n result.done.push(entry.slug);\n options.onProgress?.(entry.slug, 'done', 'source: pexels');\n } else {\n searchMisses.push(entry);\n }\n } catch (err: any) {\n if (mode === 'search_only') {\n // search_only: lỗi search = thất bại slot (đúng nghĩa chế độ)\n const msg = err?.message || String(err);\n ledger.setStatus(entry.slug, 'failed', { lastError: msg });\n options.onProgress?.(entry.slug, 'failed', msg);\n result.failed.push(entry.slug);\n } else {\n searchMisses.push(entry); // auto: search lỗi → coi như miss, thử gen\n }\n }\n }\n } else {\n // gen_only: mọi slot là \"miss\" đối với search\n for (const entry of approved) {\n if ((entry.retryCount ?? 0) >= maxRetries) { result.skipped.push(entry.slug); continue; }\n searchMisses.push(entry);\n }\n }\n\n // ── PHA 2: GEN cho search-miss — nếu vượt genQuota → rankGenCandidates xếp hạng ──\n if (canGen && searchMisses.length > 0) {\n const genQuota = Math.max(0, (policy.maxGenImagesPerArtifact ?? 3) - ledger.doneCount());\n let toGen: typeof approved = [];\n if (searchMisses.length > genQuota) {\n const ranking = await rankGenCandidates(\n searchMisses.map(e => ({ slug: e.slug, name: e.name, description: e.finalPrompt || e.description })),\n genQuota,\n options.rankingContext || {},\n options.llm\n );\n const allowed = new Set(ranking.selected);\n toGen = searchMisses.filter(e => allowed.has(e.slug));\n for (const dropped of ranking.dropped) {\n const entry = searchMisses.find(e => e.slug === dropped.slug);\n if (!entry) continue;\n // Quá quota gen → failed với lý do RÕ (user có thể 'Tạo ảnh bù' sau, hoặc tăng quota)\n ledger.setStatus(entry.slug, 'failed', {\n lastError: `Vượt quota gen (${policy.maxGenImagesPerArtifact}/bài) — hạng ${dropped.rank} khi xếp hạng theo mức cần thiết cho việc hiểu bài`,\n });\n result.failed.push(entry.slug);\n options.onProgress?.(entry.slug, 'failed', 'over gen quota');\n }\n } else {\n toGen = searchMisses;\n }\n\n for (const entry of toGen) {\n options.onProgress?.(entry.slug, 'generating');\n try {\n const provider: MediaProvider = policy.preferredProvider || 'openai';\n const image = await generateEducationalImage({\n prompt: entry.finalPrompt || entry.description,\n aspectRatio: options.defaultAspect || '4:3',\n provider,\n apiKey: provider === 'openai' ? options.apiKeyOverrides?.openai : options.apiKeyOverrides?.gemini,\n });\n const ext = image.mimeType === 'image/jpeg' ? 'jpg' : 'png';\n const filename = `${entry.slug}-${Date.now()}.${ext}`;\n fs.writeFileSync(path.join(mediaDir, filename), Buffer.from(image.base64, 'base64'));\n ledger.setStatus(entry.slug, 'done', { relPath: `_media/${filename}`, provider: image.provider });\n result.done.push(entry.slug);\n options.onProgress?.(entry.slug, 'done', `source: ${image.provider}`);\n } catch (err: any) {\n const msg = err?.message || String(err);\n ledger.setStatus(entry.slug, 'failed', { lastError: msg });\n options.onProgress?.(entry.slug, 'failed', msg);\n result.failed.push(entry.slug);\n }\n }\n }\n\n // search_only slots mà search trống nhưng KHÔNG fail ở pha 1 (đã xử) — không gen\n return result;\n}\n\n/** Sau khi done: thay placeholder [IMAGE: slug] trong markdown bằng  */\nexport function injectMediaIntoMarkdown(markdown: string, ledger: MediaLedger | MediaLedgerEntry[]): string {\n let out = markdown;\n const entries = Array.isArray(ledger) ? ledger : ledger.list();\n for (const entry of entries) {\n if (entry.status !== 'done' || !entry.relPath) continue;\n const placeholder = new RegExp(`\\\\[IMAGE\\\\s*:\\\\s*${entry.slug}\\\\]`, 'g');\n out = out.replace(placeholder, ``);\n }\n return out;\n}\n\n/** Tạo placeholder hiển thị khi failed/pending — client render rõ trạng thái, không im lặng */\nexport function renderMediaPlaceholder(entry: MediaLedgerEntry): string {\n if (entry.status === 'failed') {\n return `> ⚠️ [Ảnh ${entry.name} chưa tạo được (${entry.lastError || 'lỗi không rõ'}) — bấm \"Tạo ảnh bù\" để thử lại]`;\n }\n return `> 🖼️ [Ảnh đang chờ: ${entry.name} — sẽ được tạo sau khi duyệt media]`;\n}"]}
|
|
1
|
+
{"version":3,"sources":["../../src/media/types.ts","../../src/media/imageProviders.ts","../../src/media/stockSearch.ts","../../src/media/ledger.ts","../../src/errors/index.ts","../../src/ai/streamRunner.ts","../../src/media/curator.ts","../../src/media/orchestrate.ts"],"names":["path","fs","resolveApiKey"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Media Types — image generation, image search, video search cho học liệu.\n * Mục tiêu: mọi artifact instruction step-by-step / slide đều có minh họa phù hợp,\n * sinh bằng AI (Gemini/GPT image) HOẶC tìm kiếm ảnh/video thật có license phù hợp.\n */\n\nexport type MediaProvider = 'openai' | 'gemini';\n/** Default = 'openai' (gpt-image-1): infographic quality preferred. */\n\nexport interface GeneratedImage {\n /** Base64-encoded image data (không kèm prefix data:) */\n base64: string;\n mimeType: string;\n /** Provider dùng để sinh (audit/debug) */\n provider: string;\n /** Prompt đã được dùng (sau khi enrich theo ngữ cảnh) */\n prompt: string;\n revisedPrompt?: string;\n}\n\nexport interface StockImage {\n url: string;\n thumbnailUrl?: string;\n width?: number;\n height?: number;\n photographer?: string;\n source: string;\n license: string;\n pageUrl?: string;\n altText?: string;\n}\n\nexport interface StockVideo {\n url: string;\n thumbnailUrl?: string;\n durationSeconds?: number;\n width?: number;\n height?: number;\n source: string;\n license: string;\n pageUrl?: string;\n}\n\nexport interface GenerateImageOptions {\n /** Mô tả minh họa cần sinh */\n prompt: string;\n /** Ngữ cảnh bài học để enrich prompt (concept, grade band, style guide excerpt) */\n context?: {\n lessonTitle?: string;\n concept?: string;\n gradeBand?: [number, number] | number;\n pedagogy?: string;\n styleGuideExcerpt?: string;\n language?: string;\n };\n /** Tỷ lệ khung: 16:9 cho slide, 4:3/1:1 cho worksheet */\n aspectRatio?: '1:1' | '16:9' | '4:3' | '3:4';\n /** Phong cách hình: phù hợp giáo dục, rõ ràng, an toàn cho học sinh */\n style?: 'educational-diagram' | 'realistic-photo' | 'flat-illustration' | 'technical-schematic';\n provider?: MediaProvider;\n /** API key override (nếu không dùng env) */\n apiKey?: string;\n /** Timeout tổng cho request sinh ảnh (mặc định 420_000ms = 7 phút) */\n timeoutMs?: number;\n}\n\nexport interface SearchImageOptions {\n query: string;\n perPage?: number;\n orientation?: 'landscape' | 'portrait' | 'square';\n apiKey?: string;\n}\n\nexport interface SearchVideoOptions {\n query: string;\n perPage?: number;\n apiKey?: string;\n}\n\nexport class MediaError extends Error {\n constructor(message: string, public readonly provider?: string, public readonly status?: number) {\n super(message);\n this.name = 'MediaError';\n }\n}\n\n/** Enrich prompt gốc với ngữ cảnh sư phạm → prompt sinh ảnh chất lượng, nhất quán phong cách */\nexport function buildImagePrompt(options: GenerateImageOptions): string {\n const { prompt, context, style = 'educational-diagram' } = options;\n const parts: string[] = [];\n const styleMap: Record<string, string> = {\n 'educational-diagram': 'clean educational diagram, labeled parts, high contrast, suitable for K-12 textbook',\n 'realistic-photo': 'realistic photograph, natural lighting, educational context',\n 'flat-illustration': 'flat vector illustration, friendly shapes, modern educational style',\n 'technical-schematic': 'precise technical schematic, wiring-style clarity, engineering drawing conventions',\n };\n parts.push(prompt);\n if (context?.concept) parts.push(`Subject concept: ${context.concept}`);\n if (context?.lessonTitle) parts.push(`From lesson: ${context.lessonTitle}`);\n if (context?.gradeBand) {\n const band = Array.isArray(context.gradeBand) ? context.gradeBand : [context.gradeBand, context.gradeBand];\n parts.push(`Audience: grade ${band[0]}-${band[1]} students, age-appropriate, no scary or unsafe imagery`);\n }\n if (context?.styleGuideExcerpt) parts.push(`Visual style guide: ${context.styleGuideExcerpt.slice(0, 200)}`);\n parts.push(styleMap[style] || styleMap['educational-diagram']);\n if (options.aspectRatio === '16:9') parts.push('wide 16:9 composition');\n return parts.join('. ');\n}","import { GeneratedImage, MediaError, GenerateImageOptions, buildImagePrompt } from './types';\n\n/**\n * Image Generation Providers\n * — gemini: Gemini 2.x image generation (generateContent với responseModalities IMAGE)\n * — openai: gpt-image-1 (images/generations endpoint, b64_json)\n * Cả hai trả về GeneratedImage chuẩn — caller không cần biết provider nào.\n */\n\nfunction resolveApiKey(options: GenerateImageOptions): { provider: string; key: string } {\n const provider = options.provider || 'openai';\n const key = options.apiKey\n || (provider === 'openai' ? process.env.OPENAI_API_KEY : undefined)\n || (provider === 'gemini' ? (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY) : undefined)\n || '';\n if (!key) {\n throw new MediaError(`API key missing for image provider '${provider}'. Set GEMINI_API_KEY or OPENAI_API_KEY.`, provider);\n }\n return { provider, key };\n}\n\nfunction resolveImageTimeout(options: GenerateImageOptions): number {\n const envTimeout = Number(process.env.IMAGE_GEN_TIMEOUT_MS || process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS);\n return Number.isFinite(options.timeoutMs) && options.timeoutMs! > 0\n ? options.timeoutMs!\n : (Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : 420_000);\n}\n\nasync function generateWithGemini(options: GenerateImageOptions, key: string): Promise<GeneratedImage> {\n const finalPrompt = buildImagePrompt(options);\n const model = 'gemini-2.0-flash-exp'; // image generation capable\n const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${key}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n contents: [{ parts: [{ text: finalPrompt }] }],\n generationConfig: { responseModalities: ['TEXT', 'IMAGE'] },\n }),\n signal: AbortSignal.timeout(resolveImageTimeout(options)),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new MediaError(`Gemini image API ${res.status}: ${body.slice(0, 300)}`, 'gemini', res.status);\n }\n const data: any = await res.json();\n const parts = data?.candidates?.[0]?.content?.parts || [];\n const imagePart = parts.find((p: any) => p.inlineData?.data);\n if (!imagePart) {\n throw new MediaError('Gemini returned no image part (may have refused prompt).', 'gemini');\n }\n const textPart = parts.find((p: any) => p.text);\n return {\n base64: imagePart.inlineData.data,\n mimeType: imagePart.inlineData.mimeType || 'image/png',\n provider: 'gemini',\n prompt: finalPrompt,\n revisedPrompt: textPart?.text,\n };\n}\n\nasync function generateWithOpenAI(options: GenerateImageOptions, key: string): Promise<GeneratedImage> {\n const finalPrompt = buildImagePrompt(options);\n const sizeMap: Record<string, string> = { '1:1': '1024x1024', '16:9': '1536x1024', '4:3': '1024x1024', '3:4': '1024x1536' };\n const res = await fetch('https://api.openai.com/v1/images/generations', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${key}` },\n body: JSON.stringify({\n model: 'gpt-image-1',\n prompt: finalPrompt,\n size: sizeMap[options.aspectRatio || '1:1'] || '1024x1024',\n n: 1,\n }),\n signal: AbortSignal.timeout(resolveImageTimeout(options)),\n });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new MediaError(`OpenAI image API ${res.status}: ${body.slice(0, 300)}`, 'openai', res.status);\n }\n const data: any = await res.json();\n const item = data?.data?.[0];\n if (!item?.b64_json) {\n throw new MediaError('OpenAI returned no image data.', 'openai');\n }\n return {\n base64: item.b64_json,\n mimeType: 'image/png',\n provider: 'openai',\n prompt: finalPrompt,\n revisedPrompt: item.revised_prompt,\n };\n}\n\n/**\n * Sinh ảnh minh họa cho học liệu. Provider mặc định: gemini.\n * Prompt tự động enrich với ngữ cảnh sư phạm (grade band, style guide, khái niệm bài học).\n */\nexport async function generateEducationalImage(options: GenerateImageOptions): Promise<GeneratedImage> {\n const { provider, key } = resolveApiKey(options);\n if (provider === 'openai') return generateWithOpenAI(options, key);\n return generateWithGemini(options, key);\n}","import { MediaError, SearchImageOptions, SearchVideoOptions, StockImage, StockVideo } from './types';\n\n/**\n * Stock Media Search — tìm ảnh/video minh họa THẬT có license mở (Pexels).\n * Dùng khi: không cần sinh AI, muốn ảnh thật của phần cứng (ESP32, breadboard…),\n * hoặc muốn video demo quá trình thực tế cho step-by-step instructions.\n * API key: PEXELS_API_KEY (miễn phí tại pexels.com/api).\n */\n\nexport async function searchEducationalImages(options: SearchImageOptions): Promise<StockImage[]> {\n const key = options.apiKey || process.env.PEXELS_API_KEY || '';\n if (!key) throw new MediaError('Pexels API key missing. Set PEXELS_API_KEY.', 'pexels');\n const params = new URLSearchParams({\n query: options.query,\n per_page: String(options.perPage ?? 6),\n orientation: options.orientation || 'landscape',\n });\n const res = await fetch(`https://api.pexels.com/v1/search?${params}`, {\n headers: { Authorization: key },\n signal: AbortSignal.timeout(30_000),\n });\n if (!res.ok) {\n throw new MediaError(`Pexels image search ${res.status}`, 'pexels', res.status);\n }\n const data: any = await res.json();\n return (data?.photos || []).map((p: any) => ({\n url: p.src?.large2x || p.src?.large || p.src?.original,\n thumbnailUrl: p.src?.medium,\n width: p.width,\n height: p.height,\n photographer: p.photographer,\n source: 'pexels',\n license: 'Pexels License (free to use, attribution appreciated)',\n pageUrl: p.url,\n altText: p.alt,\n }));\n}\n\nexport async function searchEducationalVideos(options: SearchVideoOptions): Promise<StockVideo[]> {\n const key = options.apiKey || process.env.PEXELS_API_KEY || '';\n if (!key) throw new MediaError('Pexels API key missing. Set PEXELS_API_KEY.', 'pexels');\n const params = new URLSearchParams({\n query: options.query,\n per_page: String(options.perPage ?? 4),\n orientation: 'landscape',\n });\n const res = await fetch(`https://api.pexels.com/videos/search?${params}`, {\n headers: { Authorization: key },\n signal: AbortSignal.timeout(30_000),\n });\n if (!res.ok) {\n throw new MediaError(`Pexels video search ${res.status}`, 'pexels', res.status);\n }\n const data: any = await res.json();\n return (data?.videos || []).map((v: any) => {\n const files = v.video_files || [];\n const best = files.filter((f: any) => f.quality === 'hd').sort((a: any, b: any) => (a.width || 0) - (b.width || 0))[0] || files[0];\n return {\n url: best?.link,\n thumbnailUrl: v.image,\n durationSeconds: v.duration,\n width: best?.width,\n height: best?.height,\n source: 'pexels',\n license: 'Pexels License (free to use, attribution appreciated)',\n pageUrl: v.url,\n };\n });\n}","import fs from 'fs';\nimport path from 'path';\n\n/**\n * Media Ledger — sổ cái ảnh per-lesson (JSONL), nguồn chân lý cho quy hoạch ảnh.\n * Vòng đời entry: pending → approved (Curator chốt) → done | failed (kèm lastError)\n * Agent tạo artifact chỉ APPEND (pending). Curator quyết định. Orchestrator thực thi.\n * Idempotent: 1 slug chỉ có 1 entry active; append cùng slug → cập nhật, không trùng.\n */\n\nexport type MediaLedgerMode = 'generate' | 'search';\nexport type MediaLedgerStatus = 'pending' | 'approved' | 'rejected' | 'done' | 'failed';\n\nexport interface MediaLedgerEntry {\n /** Định danh ảnh trong bài, vd 'img-loop-diagram' — unique per lesson */\n slug: string;\n /** Artifact chứa slot, vd 'LESSON_U01_M01_L01' */\n artifactId: string;\n /** Tên ảnh (human-readable) */\n name: string;\n /** Mô tả chi tiết nội dung ảnh — input chính cho Curator enrich + agent con */\n description: string;\n /** 'generate' (AI) hoặc 'search' (ảnh/video thật) */\n mode: MediaLedgerMode;\n /** Vị trí chèn: markdown heading/anchor gần nhất trong artifact */\n anchor?: string;\n status: MediaLedgerStatus;\n /** Provider đã dùng (set khi done) */\n provider?: string;\n /** Inline Markdown credit (tác giả + nguồn + license) — từ multimedia-kit AttributionBuilder */\n attribution?: string;\n /** Path tương đối trong project sau khi done: _media/xxx.png */\n relPath?: string;\n /** Prompt cuối (đã enrich) — audit/debug */\n finalPrompt?: string;\n lastError?: string;\n retryCount?: number;\n /** Quyết định của Curator: mã lý do (duplicate/content_mismatch/...) — audit + user override */\n decisionReasonCode?: string;\n decisionReason?: string;\n updatedAt: string;\n}\n\nexport class MediaLedger {\n readonly filePath: string;\n private entries: Map<string, MediaLedgerEntry> = new Map();\n\n constructor(projectDir: string, lessonId: string) {\n this.filePath = path.join(projectDir, '_media', `ledger-${lessonId.toUpperCase()}.jsonl`);\n this.load();\n }\n\n private load(): void {\n this.entries.clear();\n if (!fs.existsSync(this.filePath)) return;\n const lines = fs.readFileSync(this.filePath, 'utf-8').split('\\n');\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const e = JSON.parse(trimmed) as MediaLedgerEntry;\n this.entries.set(e.slug, e); // last-wins\n } catch { /* dòng hỏng — bỏ qua nhưng không giấu: giữ file nguyên */ }\n }\n }\n\n private persist(): void {\n fs.mkdirSync(path.dirname(this.filePath), { recursive: true });\n fs.writeFileSync(this.filePath, Array.from(this.entries.values()).map(e => JSON.stringify(e)).join('\\n') + '\\n', 'utf-8');\n }\n\n /** Agent tạo artifact ghi entry mới (hoặc cập nhật nếu slug đã có và chưa done) */\n upsert(input: Omit<MediaLedgerEntry, 'status' | 'updatedAt'> & { status?: MediaLedgerStatus }): MediaLedgerEntry {\n const existing = this.entries.get(input.slug);\n if (existing && (existing.status === 'done')) return existing; // done là bất biến\n const entry: MediaLedgerEntry = { ...input, status: input.status ?? 'pending', updatedAt: new Date().toISOString() };\n this.entries.set(input.slug, entry);\n this.persist();\n return entry;\n }\n\n get(slug: string): MediaLedgerEntry | undefined { return this.entries.get(slug); }\n list(): MediaLedgerEntry[] { return Array.from(this.entries.values()); }\n listByStatus(status: MediaLedgerStatus): MediaLedgerEntry[] { return this.list().filter(e => e.status === status); }\n pending(): MediaLedgerEntry[] { return this.listByStatus('pending'); }\n\n setStatus(slug: string, status: MediaLedgerStatus, patch: Partial<MediaLedgerEntry> = {}): MediaLedgerEntry | undefined {\n const e = this.entries.get(slug);\n if (!e) return undefined;\n Object.assign(e, patch, { status, updatedAt: new Date().toISOString() });\n if (status === 'failed') e.retryCount = (e.retryCount ?? 0) + 1;\n this.entries.set(slug, e);\n this.persist();\n return e;\n }\n\n /** Đếm ảnh đã done trong lesson — để Curator tôn trọng maxImages */\n doneCount(): number { return this.listByStatus('done').length; }\n\n /**\n * Scan artifact content và seed pending entries cho mọi placeholder [IMAGE: slug].\n * Được gọi sau khi agent sinh artifact (trước khi Curator duyệt) — đây là cầu nối\n * duy nhất giữa \"agent chèn placeholder\" và \"sổ cái có entry để Curator/Fulfiller xử\".\n * Idempotent: slug đã có entry active (pending/approved/done) → giữ nguyên;\n * chỉ re-describe khi entry trước bị rejected/failed.\n */\n seedFromArtifact(artifactId: string, content: string): MediaLedgerEntry[] {\n const seeded: MediaLedgerEntry[] = [];\n const re = /\\[IMAGE\\s*:\\s*([a-z0-9][a-z0-9-]*)\\s*\\]/gi;\n const seen = new Set<string>();\n let m: RegExpExecArray | null;\n while ((m = re.exec(content)) !== null) {\n const slug = m[1].toLowerCase();\n if (seen.has(slug)) continue;\n seen.add(slug);\n const existing = this.entries.get(slug);\n const isActive = existing && (existing.status === 'pending' || existing.status === 'approved' || existing.status === 'done');\n if (isActive) continue;\n seeded.push(this.upsert({\n slug,\n artifactId,\n name: slug.replace(/^(img-|image-)/, '').replace(/-/g, ' '),\n description: `Placeholder chèn bởi agent trong artifact ${artifactId} — chờ Curator enrich (mô tả gốc chưa có).`,\n mode: 'generate',\n status: 'pending',\n }));\n }\n return seeded;\n }\n}","/**\n * Curriculum OS - Standardized Error Taxonomy & Traceability System\n *\n * Provides typed, structured, and traceable error codes for all pipeline failures,\n * API exceptions, safeguard blocks, and contract violations.\n */\n\nexport type CurriculumErrorCode =\n | 'ERR_AI_NO_API_KEY'\n | 'ERR_AI_RATE_LIMIT'\n | 'ERR_AI_AUTH_FAILED'\n | 'ERR_AI_NETWORK_TIMEOUT'\n | 'ERR_AI_RESPONSE_MALFORMED'\n | 'ERR_AI_ALL_PROVIDERS_FAILED'\n | 'ERR_CUSTOM_INFERENCE_REQUIRED'\n | 'ERR_SOT_MISSING'\n | 'ERR_SOT_INVALID_SCHEMA'\n | 'ERR_TASK_GATE_BLOCKED'\n | 'ERR_METERED_LIMIT_EXCEEDED'\n | 'ERR_SCHEMA_CONTRACT_VIOLATION'\n | 'ERR_STORAGE_IO_FAILED'\n | 'ERR_LESSON_NOT_IN_SOT'\n | 'ERR_CONTEXT_MISSING';\n\nexport interface CurriculumErrorDetail {\n errorCode: CurriculumErrorCode;\n agent?: string;\n artifactType?: string;\n lessonId?: string;\n provider?: string;\n statusCode?: number;\n message: string;\n suggestedAction: string;\n retryable: boolean;\n timestamp: string;\n rawError?: string;\n}\n\nexport class CurriculumError extends Error {\n public readonly detail: CurriculumErrorDetail;\n\n constructor(detail: Omit<CurriculumErrorDetail, 'timestamp'>) {\n super(`[${detail.errorCode}] ${detail.message}`);\n this.name = 'CurriculumError';\n this.detail = {\n ...detail,\n timestamp: new Date().toISOString()\n };\n Object.setPrototypeOf(this, CurriculumError.prototype);\n }\n\n get errorCode(): CurriculumErrorCode {\n return this.detail.errorCode;\n }\n\n get retryable(): boolean {\n return this.detail.retryable;\n }\n\n get suggestedAction(): string {\n return this.detail.suggestedAction;\n }\n\n toJSON(): CurriculumErrorDetail {\n return this.detail;\n }\n}\n\n/**\n * Helper to build standardized AI inference errors\n */\nexport function createAiInferenceError(params: {\n errorCode: CurriculumErrorCode;\n message: string;\n provider?: string;\n statusCode?: number;\n agent?: string;\n artifactType?: string;\n lessonId?: string;\n rawError?: any;\n suggestedAction?: string;\n retryable?: boolean;\n}): CurriculumError {\n const {\n errorCode,\n message,\n provider,\n statusCode,\n agent,\n artifactType,\n lessonId,\n rawError,\n suggestedAction = getSuggestedActionForCode(errorCode),\n retryable = isCodeRetryable(errorCode)\n } = params;\n\n return new CurriculumError({\n errorCode,\n message,\n provider,\n statusCode,\n agent,\n artifactType,\n lessonId,\n suggestedAction,\n retryable,\n rawError: typeof rawError === 'string' ? rawError : rawError?.message || JSON.stringify(rawError)\n });\n}\n\nfunction getSuggestedActionForCode(code: CurriculumErrorCode): string {\n switch (code) {\n case 'ERR_AI_NO_API_KEY':\n return 'Vào Settings > API Keys để cấu hình ít nhất một khóa API (Gemini, DeepSeek, OpenRouter, Alibaba hoặc NVIDIA).';\n case 'ERR_AI_RATE_LIMIT':\n return 'API đã vượt quá giới hạn lượt gọi (Rate Limit HTTP 429). Hãy chờ 30-60 giây rồi bấm Rerun hoặc chuyển sang Provider dự phòng.';\n case 'ERR_AI_AUTH_FAILED':\n return 'API Key không hợp lệ hoặc đã hết hạn (HTTP 401/403). Vui lòng kiểm tra lại Key trong mục Cài đặt.';\n case 'ERR_AI_NETWORK_TIMEOUT':\n return 'Kết nối mạng tới máy chủ AI bị quá thời gian chờ (Timeout). Vui lòng kiểm tra đường truyền và bấm Rerun.';\n case 'ERR_AI_RESPONSE_MALFORMED':\n return 'Mô hình AI trả về kết quả rỗng hoặc không đúng định dạng markdown. Bấm Rerun để yêu cầu AI sinh lại.';\n case 'ERR_AI_ALL_PROVIDERS_FAILED':\n return 'Toàn bộ các nhà cung cấp trong chuỗi Fallback đều thất bại. Vui lòng kiểm tra kết nối Internet và hạn mức Token.';\n case 'ERR_SOT_MISSING':\n return 'Thiếu tài liệu nền tảng SOT (CURRICULUM_FRAMEWORK.md hoặc LEARNER_PROFILE.md). Hãy chạy workflow Khởi tạo dự án trước.';\n case 'ERR_TASK_GATE_BLOCKED':\n return 'Học liệu phía sau bị chặn do Giáo án (LESSON) phía trước chưa được Phê duyệt (Approval Gate). Hãy bấm Phê duyệt Giáo án để mở khóa.';\n case 'ERR_METERED_LIMIT_EXCEEDED':\n return 'Chính sách Metered Execution giới hạn tối đa 2 bài học mỗi đợt. Vui lòng phê duyệt các bài hiện tại trước khi tạo thêm.';\n case 'ERR_SCHEMA_CONTRACT_VIOLATION':\n return 'Nội dung sinh ra thiếu các phần bắt buộc [REQUIRED]. Hãy kích hoạt kiểm thử hoặc bấm Rerun.';\n case 'ERR_STORAGE_IO_FAILED':\n return 'Lỗi đọc/ghi tệp tin trên hệ thống lưu trữ. Kiểm tra quyền ghi thư mục output/projects.';\n case 'ERR_CONTEXT_MISSING':\n return 'Thiếu nguồn tri thức bắt buộc (KNOWLEDGE_EXPOSITION hoặc CANONICAL LESSON) theo Dependency Routing Matrix. Vui lòng tạo hoặc đồng bộ tài liệu nguồn trước.';\n default:\n return 'Bấm Rerun để thử lại hoặc kiểm tra nhật ký hệ thống.';\n }\n}\n\nfunction isCodeRetryable(code: CurriculumErrorCode): boolean {\n switch (code) {\n case 'ERR_AI_RATE_LIMIT':\n case 'ERR_AI_NETWORK_TIMEOUT':\n case 'ERR_AI_RESPONSE_MALFORMED':\n case 'ERR_STORAGE_IO_FAILED':\n return true;\n case 'ERR_AI_NO_API_KEY':\n case 'ERR_AI_AUTH_FAILED':\n case 'ERR_SOT_MISSING':\n case 'ERR_TASK_GATE_BLOCKED':\n case 'ERR_METERED_LIMIT_EXCEEDED':\n case 'ERR_SCHEMA_CONTRACT_VIOLATION':\n case 'ERR_CONTEXT_MISSING':\n return false;\n default:\n return true;\n }\n}\n\nexport function createContextMissingError(params: {\n artifactType: string;\n missingSource: string;\n lessonId?: string;\n agent?: string;\n}): CurriculumError {\n return new CurriculumError({\n errorCode: 'ERR_CONTEXT_MISSING',\n artifactType: params.artifactType,\n lessonId: params.lessonId,\n agent: params.agent,\n message: `Required context source \"${params.missingSource}\" is missing for artifact \"${params.artifactType}\"`,\n suggestedAction: `Generate or provide the authoritative \"${params.missingSource}\" source before producing \"${params.artifactType}\".`,\n retryable: false\n });\n}\n\n","import { createAiInferenceError } from '../errors';\nimport type { ToolDefinition, AggregatedToolCall } from './toolLoopTypes';\nimport fs from 'fs';\nimport path from 'path';\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system' | 'model';\n content: string;\n}\n\nexport interface StreamRunnerOptions {\n openrouterKey?: string;\n deepseekKey?: string;\n alibabaKey?: string;\n geminiKey?: string;\n nvidiaKey?: string;\n openaiKey?: string;\n anthropicKey?: string;\n model?: string;\n systemPersona?: string;\n maxTokens?: number;\n temperature?: number;\n reasoningEffort?: 'off' | 'low' | 'medium' | 'high' | 'max';\n /** Thời gian tối đa cho phép không nhận thêm token mới trước khi abort (mặc định 90_000ms = 90s; env ARTIFACT_STREAM_IDLE_TIMEOUT_MS override) */\n idleTimeoutMs?: number;\n /** Thời gian hard cap tối đa cho toàn bộ lượt stream trước khi abort (mặc định 420_000ms = 7 phút) */\n timeoutMs?: number;\n /**\n * Host-provided inference override (Vercel AI SDK gateway, test stubs, …).\n * When set, ALL built-in provider routes (raw-fetch NVIDIA/OpenRouter/\n * DeepSeek/DashScope/Gemini + designated fallback chain) are bypassed and\n * every inference call goes through this function instead. It receives the\n * fully-formed system instruction (persona + project context + guidelines)\n * and the user prompt, plus the same onChunk contract as the built-in\n * routes: stream text deltas via ('content'|'thought'), and report token\n * spend via onChunk(JSON.stringify({ promptTokens, completionTokens,\n * totalTokens, reasoningTokens }), 'usage'). Return the full completion text.\n */\n customInference?: (request: {\n systemInstruction: string;\n userPrompt: string;\n messages: ChatMessage[];\n temperature: number;\n maxTokens: number;\n onChunk: (token: string, type: ChunkType) => void;\n }) => Promise<string>;\n /**\n * Host-provided TOOL-CALLING inference override (unified-tracing mandate,\n * gap #8 audit 2026-09-14). When present, `streamCurriculumAIInferenceWithTools`\n * routes every turn through this gateway instead of its built-in raw-fetch\n * provider routes, so tool-loop calls emit the host's OpenTelemetry spans\n * (unified Langfuse trace). The request carries the FULL conversation\n * (including prior assistant tool_calls and tool results) and the OpenAI-\n * compatible tool definitions; the implementation returns the turn result.\n * Stream text deltas via ('content'|'thought') chunks and report token spend\n * via onChunk(JSON.stringify({ promptTokens, completionTokens, totalTokens,\n * reasoningTokens }), 'usage') — same contract as customInference.\n */\n customToolInference?: (request: {\n messages: Array<{\n role: string;\n content: string | null;\n tool_calls?: Array<{ id: string; type: 'function'; function: { name: string; arguments: string } }>;\n tool_call_id?: string;\n }>;\n tools: ToolDefinition[];\n temperature: number;\n maxTokens: number;\n onChunk: (token: string, type: ChunkType) => void;\n }) => Promise<{ content: string; toolCalls: AggregatedToolCall[] }>;\n}\n\nexport function resolveApiKey(keyName: string, explicitKey?: string): string {\n if (explicitKey && explicitKey.trim()) return explicitKey.trim();\n if (typeof process !== 'undefined' && process.env && process.env[keyName]) {\n return process.env[keyName]!;\n }\n\n try {\n const currentDir = process.cwd();\n const envPaths = [\n path.resolve(currentDir, '.env.local'),\n path.resolve(currentDir, '.env'),\n path.resolve(currentDir, 'apps/web/.env.local'),\n path.resolve(currentDir, 'packages/learnwell-platform/.env'),\n path.resolve(currentDir, '..', '.env.local'),\n path.resolve(currentDir, '..', '.env'),\n path.resolve(currentDir, '../..', '.env.local'),\n path.resolve(currentDir, '../..', '.env'),\n ];\n for (const envPath of envPaths) {\n if (fs.existsSync(envPath)) {\n const content = fs.readFileSync(envPath, 'utf-8');\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith('#') && trimmed.startsWith(keyName + '=')) {\n return trimmed.substring(keyName.length + 1).trim().replace(/^[\"']|[\"']$/g, '');\n }\n }\n }\n }\n } catch {}\n return '';\n}\n\n/**\n * Checks if a specific AI provider is enabled via environment variables.\n * Supported env controls:\n * 1. ENABLE_<PROVIDER>=true|false (e.g. ENABLE_ALIBABA=false, ENABLE_OPENROUTER=true)\n * 2. ALLOWED_AI_PROVIDERS=openrouter,nvidia\n * 3. DISABLED_AI_PROVIDERS=alibaba,deepseek,gemini\n */\nexport function isProviderEnabled(provider: string): boolean {\n const p = provider.toLowerCase();\n\n // 1. Explicit ENABLE_<PROVIDER>=true/false\n const explicitVal = resolveApiKey(`ENABLE_${p.toUpperCase()}`);\n if (explicitVal !== '') {\n return explicitVal === 'true' || explicitVal === '1';\n }\n\n // 2. ALLOWED_AI_PROVIDERS (whitelist)\n const allowedList = resolveApiKey('ALLOWED_AI_PROVIDERS');\n if (allowedList && allowedList.trim()) {\n const allowed = allowedList.split(',').map(s => s.trim().toLowerCase());\n return allowed.includes(p);\n }\n\n // 3. DISABLED_AI_PROVIDERS (blacklist)\n const disabledList = resolveApiKey('DISABLED_AI_PROVIDERS');\n if (disabledList && disabledList.trim()) {\n const disabled = disabledList.split(',').map(s => s.trim().toLowerCase());\n if (disabled.includes(p)) return false;\n }\n\n return true;\n}\n\n/**\n * Checks if a model is permitted by ALLOWED_AI_MODELS filter (supports wildcards e.g. nvidia/*, *:free)\n */\nexport function isModelAllowed(model: string): boolean {\n const allowedList = resolveApiKey('ALLOWED_AI_MODELS');\n if (!allowedList || !allowedList.trim()) return true;\n\n const patterns = allowedList.split(',').map(s => s.trim());\n return patterns.some(pattern => {\n if (pattern === '*' || pattern === model) return true;\n if (pattern.endsWith('*') && model.startsWith(pattern.slice(0, -1))) return true;\n if (pattern.startsWith('*') && model.endsWith(pattern.slice(1))) return true;\n return false;\n });\n}\n\nexport interface FallbackTarget {\n provider: string;\n model: string;\n}\n\n/**\n * Resolves the designated last-resort fallback chain from environment variables.\n * Comma-separated lists are parsed in left-to-right priority order:\n * - FALLBACK_AI_PROVIDER=nvidia,openrouter (Must be enabled / in ALLOWED_AI_PROVIDERS)\n * - FALLBACK_AI_MODEL=nvidia/nemotron-3-ultra-550b-a55b:free,@preset/coding-free,deepseek/deepseek-chat:free\n */\nexport function getDesignatedFallbackChain(): FallbackTarget[] {\n const rawProviders =\n resolveApiKey('FALLBACK_AI_PROVIDER') ||\n resolveApiKey('FALLBACK_AI_PROVIDERS') ||\n resolveApiKey('DEFAULT_AI_PROVIDER') ||\n '9router,nvidia,openrouter';\n\n const rawModels =\n resolveApiKey('FALLBACK_AI_MODEL') ||\n resolveApiKey('FALLBACK_AI_MODELS') ||\n resolveApiKey('DEFAULT_AI_MODEL') ||\n 'fast-reasoning,deep-reasoning,mid-range,free-tier';\n\n // Providers in priority order (MUST be enabled / allowed in ALLOWED_AI_PROVIDERS)\n const providerList = rawProviders\n .split(',')\n .map((p) => p.trim().toLowerCase())\n .filter((p) => p.length > 0 && isProviderEnabled(p));\n\n const modelList = rawModels\n .split(',')\n .map((m) => m.trim())\n .filter((m) => m.length > 0 && isModelAllowed(m));\n\n const chain: FallbackTarget[] = [];\n\n for (const provider of providerList) {\n let providerModels: string[] = [];\n\n if (provider === '9router' || provider === 'ninerouter') {\n providerModels = modelList.filter((m) => ['fast-reasoning', 'deep-reasoning', 'mid-range', 'free-tier'].includes(m));\n if (providerModels.length === 0) {\n providerModels = ['fast-reasoning', 'mid-range', 'free-tier'];\n }\n } else if (provider === 'nvidia') {\n providerModels = modelList.filter((m) => m.startsWith('nvidia/') || m.startsWith('meta/') || m.startsWith('mistralai/'));\n if (providerModels.length === 0) {\n providerModels = ['nvidia/nemotron-3-ultra-550b-a55b:free', 'nvidia/nemotron-3.5-lightning-30b-a3b'];\n }\n } else if (provider === 'openrouter') {\n providerModels = modelList.filter((m) => m.startsWith('@') || m.includes('/') || m.includes(':'));\n if (providerModels.length === 0) {\n providerModels = ['@preset/coding-free', 'deepseek/deepseek-chat:free', 'meta-llama/llama-3.3-70b-instruct:free'];\n }\n } else if (provider === 'alibaba' || provider === 'dashscope') {\n providerModels = modelList.filter((m) => m.startsWith('qwen') || m.includes('deepseek'));\n if (providerModels.length === 0) {\n providerModels = ['deepseek-v4-flash-0731', 'qwen-plus', 'qwen3.7-plus'];\n }\n } else if (provider === 'google' || provider === 'gemini') {\n providerModels = modelList.filter((m) => m.startsWith('gemini'));\n if (providerModels.length === 0) {\n providerModels = ['gemini-2.0-flash', 'gemini-1.5-flash'];\n }\n } else if (provider === 'deepseek') {\n providerModels = modelList.filter((m) => m.startsWith('deepseek'));\n if (providerModels.length === 0) {\n providerModels = ['deepseek-chat', 'deepseek-reasoner'];\n }\n } else {\n providerModels = modelList.length > 0 ? modelList : ['default'];\n }\n\n for (const model of providerModels) {\n if (!chain.some((c) => c.provider === provider && c.model === model)) {\n chain.push({ provider, model });\n }\n }\n }\n\n return chain;\n}\n\nexport function getDesignatedFallbackConfig(): FallbackTarget {\n const chain = getDesignatedFallbackChain();\n if (chain.length > 0) return chain[0];\n return { provider: '9router', model: 'fast-reasoning' };\n}\n\nexport type ChunkType = 'content' | 'thought' | 'tool_call' | 'usage';\n\n/**\n * Separate thinking process from main content safely\n */\nexport function extractThoughtAndContent(rawText: string): { thought: string; content: string } {\n let text = rawText || '';\n let thought = '';\n\n // 1. Explicit <think>...</think> tags\n const thinkMatch = text.match(/<think>([\\s\\S]*?)<\\/think>/i);\n if (thinkMatch) {\n thought = thinkMatch[1].trim();\n text = text.replace(/<think>[\\s\\S]*?<\\/think>/gi, '').trim();\n } else if (text.includes('<think>')) {\n // Unclosed <think> tag\n const parts = text.split('<think>');\n text = parts[0].trim();\n thought = parts[1].trim();\n }\n\n // 2. Patterns like \"Here's a thinking process: ... \\n\\n# Main Title\"\n if (!thought && (text.startsWith(\"Here's a thinking process:\") || text.startsWith(\"Thinking Process:\"))) {\n // Look for markdown heading (# or ## or 🎯 or 1. or ---) as transition to main answer\n const splitRegex = /\\n(?=(?:#|##|###|🎯|🧭|📋|🚀|1\\.\\s+[A-Z\\u00C0-\\u1EF9]|---))/m;\n const match = text.search(splitRegex);\n if (match > 0) {\n thought = text.slice(0, match).trim();\n text = text.slice(match).trim();\n }\n }\n\n // 3. Strip outer markdown codeblock fence if AI wrapped the entire document\n let content = text.trim();\n if (content.startsWith('```markdown')) {\n content = content.replace(/^```markdown\\s*\\n/i, '').replace(/\\n```\\s*$/i, '');\n } else if (content.startsWith('```md')) {\n content = content.replace(/^```md\\s*\\n/i, '').replace(/\\n```\\s*$/i, '');\n } else if (content.startsWith('```') && content.endsWith('```') && !content.includes('---')) {\n content = content.replace(/^```\\w*\\s*\\n/i, '').replace(/\\n```\\s*$/i, '');\n }\n\n return {\n thought: thought.trim(),\n content: content.trim()\n };\n}\n\nexport const DEFAULT_ARTIFACT_STREAM_IDLE_MS = 90_000;\nexport const DEFAULT_ARTIFACT_STREAM_TOTAL_MS = 480_000;\n\nexport interface StreamAbortController {\n signal: AbortSignal;\n /** Reset the idle window (call on every received chunk). */\n kick: () => void;\n /** Clear all pending timers once the request lifecycle is over. */\n dispose: () => void;\n}\n\n/**\n * Budget-aware stream abort controller. Combines an idle window (kicked on\n * every received chunk — covers slow TTFT and hung connections) with a generous\n * total hard cap (defaults to 420s / 7 minutes).\n *\n * Configurable via options or process.env:\n * - ARTIFACT_STREAM_IDLE_TIMEOUT_MS / STREAM_IDLE_TIMEOUT_MS\n * - ARTIFACT_STREAM_TOTAL_TIMEOUT_MS / STREAM_TOTAL_TIMEOUT_MS\n */\nexport function createStreamAbortController(options?: { idleMs?: number; totalMs?: number }): StreamAbortController {\n const envIdle = Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS);\n const envTotal = Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS);\n\n const idleMs = Number.isFinite(options?.idleMs) && (options!.idleMs! > 0)\n ? options!.idleMs!\n : (Number.isFinite(envIdle) && envIdle > 0 ? envIdle : DEFAULT_ARTIFACT_STREAM_IDLE_MS);\n\n const totalMs = Number.isFinite(options?.totalMs) && (options!.totalMs! > 0)\n ? options!.totalMs!\n : (Number.isFinite(envTotal) && envTotal > 0 ? envTotal : DEFAULT_ARTIFACT_STREAM_TOTAL_MS);\n\n const controller = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let totalTimer: ReturnType<typeof setTimeout> | null = null;\n\n const armIdle = () => {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(\n () => controller.abort(new Error(`Idle timeout: no data for ${Math.round(idleMs / 1000)}s`)),\n idleMs\n );\n (idleTimer as any)?.unref?.();\n };\n armIdle();\n\n if (totalMs > 0) {\n totalTimer = setTimeout(\n () => controller.abort(new Error(`Total stream timeout after ${Math.round(totalMs / 1000)}s`)),\n totalMs\n );\n (totalTimer as any)?.unref?.();\n }\n\n return {\n signal: controller.signal,\n kick: armIdle,\n dispose: () => {\n if (idleTimer) clearTimeout(idleTimer);\n if (totalTimer) clearTimeout(totalTimer);\n idleTimer = null;\n totalTimer = null;\n }\n };\n}\n\n/** Backward-compatible alias */\nexport function createIdleAbortController(idleMs?: number, totalMs?: number): StreamAbortController {\n return createStreamAbortController({ idleMs, totalMs });\n}\nexport type IdleAbort = StreamAbortController;\n\n/**\n * Helper to process an OpenAI-compatible SSE response stream with Thinking & Tool Call streaming\n */\nasync function processOpenAISSEStream(\n response: Response,\n onChunk?: (token: string, type: ChunkType) => void,\n idle?: IdleAbort,\n toolCallCollector?: Map<string, { id: string; name: string; argsBuffer: string }>\n): Promise<string> {\n if (!response.body) return '';\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let fullRaw = '';\n let buffer = '';\n let insideThinkTag = false;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n idle?.kick();\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(':')) continue;\n if (trimmed === 'data: [DONE]') continue;\n if (trimmed.startsWith('data: ')) {\n try {\n const json = JSON.parse(trimmed.substring(6));\n\n // 0. Capture exact provider token usage if available in the SSE stream\n if (json.usage) {\n const promptTokens = json.usage.prompt_tokens || json.usage.input_tokens || 0;\n const completionTokens = json.usage.completion_tokens || json.usage.output_tokens || 0;\n const totalTokens = json.usage.total_tokens || (promptTokens + completionTokens);\n const reasoningTokens = json.usage.completion_tokens_details?.reasoning_tokens || 0;\n if (onChunk) {\n onChunk(JSON.stringify({ promptTokens, completionTokens, totalTokens, reasoningTokens }), 'usage');\n }\n }\n\n const delta = json.choices?.[0]?.delta;\n if (!delta) continue;\n\n // 1. Explicit reasoning_content (DeepSeek / Qwen / Claude / Gemini on OpenRouter)\n const reasoning = delta.reasoning_content || delta.thought || delta.reasoning || delta.thought_process || '';\n if (reasoning) {\n if (onChunk) onChunk(reasoning, 'thought');\n }\n\n // 2. Tool Calls — stream ra UI + aggregate thành call hoàn chỉnh khi có collector\n if (delta.tool_calls) {\n const toolStr = JSON.stringify(delta.tool_calls);\n if (onChunk) onChunk(toolStr, 'tool_call');\n if (toolCallCollector) {\n for (const tc of delta.tool_calls) {\n const idx = String(tc.index ?? tc.id ?? '0');\n const existing = toolCallCollector.get(idx) || { id: tc.id || `call_${idx}`, name: '', argsBuffer: '' };\n if (tc.id) existing.id = tc.id;\n if (tc.function?.name) existing.name += tc.function.name;\n if (tc.function?.arguments) existing.argsBuffer += tc.function.arguments;\n toolCallCollector.set(idx, existing);\n }\n }\n }\n\n // 3. Content tokens (handle inline <think> tags dynamically)\n let content = delta.content || '';\n if (content) {\n fullRaw += content;\n\n if (content.includes('<think>')) {\n insideThinkTag = true;\n const parts = content.split('<think>');\n if (parts[0] && onChunk) onChunk(parts[0], 'content');\n content = parts[1] || '';\n }\n if (content.includes('</think>')) {\n insideThinkTag = false;\n const parts = content.split('</think>');\n if (parts[0] && onChunk) onChunk(parts[0], 'thought');\n content = parts[1] || '';\n }\n\n if (insideThinkTag) {\n if (onChunk && content) onChunk(content, 'thought');\n } else if (content) {\n if (onChunk) onChunk(content, 'content');\n }\n }\n } catch {\n // Incomplete JSON chunk, skip\n }\n }\n }\n }\n\n idle?.dispose();\n\n // Final sanity cleanup so raw output has thinking separated\n const extracted = extractThoughtAndContent(fullRaw);\n return extracted.content || fullRaw;\n}\n\n/**\n * Helper to process a Google Gemini SSE stream with Thought streaming\n */\nasync function processGeminiSSEStream(\n response: Response,\n onChunk?: (token: string, type: ChunkType) => void,\n idle?: IdleAbort\n): Promise<string> {\n if (!response.body) return '';\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let fullText = '';\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n idle?.kick();\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(':')) continue;\n if (trimmed.startsWith('data: ')) {\n try {\n const json = JSON.parse(trimmed.substring(6));\n\n if (json.usageMetadata) {\n const promptTokens = json.usageMetadata.promptTokenCount || 0;\n const completionTokens = json.usageMetadata.candidatesTokenCount || 0;\n const totalTokens = json.usageMetadata.totalTokenCount || (promptTokens + completionTokens);\n if (onChunk) {\n onChunk(JSON.stringify({ promptTokens, completionTokens, totalTokens }), 'usage');\n }\n }\n\n const parts = json.candidates?.[0]?.content?.parts || [];\n for (const part of parts) {\n if (part.thought) {\n if (onChunk) onChunk(part.text || '', 'thought');\n } else if (part.text) {\n fullText += part.text;\n if (onChunk) onChunk(part.text, 'content');\n }\n }\n } catch {\n // Incomplete JSON chunk, skip\n }\n }\n }\n }\n idle?.dispose();\n return fullText;\n}\n\n/**\n * Real-time Streaming Multi-Provider Inference Runner with Thinking & Tool Streaming\n */\nexport async function streamCurriculumAIInference(\n messages: ChatMessage[],\n projectContext: string,\n options: StreamRunnerOptions = {},\n onChunk?: (token: string, type: ChunkType) => void\n): Promise<string> {\n const openrouterKey = resolveApiKey('OPENROUTER_API_KEY', options.openrouterKey);\n const deepseekKey = resolveApiKey('DEEPSEEK_API_KEY', options.deepseekKey);\n const alibabaKey = resolveApiKey('ALIBABA_API_KEY', options.alibabaKey) || resolveApiKey('DASHSCOPE_API_KEY');\n const geminiKey = resolveApiKey('GEMINI_API_KEY', options.geminiKey) || resolveApiKey('NEXT_PUBLIC_GEMINI_API_KEY');\n const nvidiaKey = resolveApiKey('NVIDIA_API_KEY', options.nvidiaKey);\n\n const temperature = options.temperature ?? 0.3;\n // Default to 32768 tokens (32k) so long reasoning, deep curriculum artifacts, code labs, and quizzes are never truncated\n const maxTokens = options.maxTokens ?? 32768;\n\n const basePersona = options.systemPersona || 'You are Curriculum OS Assistant — Senior AI Technical Curriculum Architect & Educational Content Specialist.';\n\n const systemInstruction = `${basePersona}\n\nProject Context:\n${projectContext}\n\nGuidelines:\n1. You have full context of the project hierarchy, syllabus, lessons, and learning objectives. Answer precisely, deeply, and directly.\n2. Complete responses fully without truncation. When generating tables or roadmaps, include all sections/milestones.\n3. Keep technical terminology and official API symbols intact.\n4. Format output using clean Markdown, clear sections, bullet points, and code blocks where required.\n5. Do NOT use emojis in headings, tab titles, or UI navigation labels.`;\n\n // ── Route 0: Host-provided inference override (Vercel AI SDK gateway, …) ──\n // When the embedding app supplies customInference, it is the SOLE inference\n // path: the raw-fetch provider routes below never run, so host apps that\n // mandate a gateway (e.g. Vercel AI SDK) get exactly one auditable engine.\n if (options.customInference) {\n try {\n const text = await options.customInference({\n systemInstruction,\n userPrompt: messages.map(m => m.content).join('\\n\\n'),\n messages,\n temperature,\n maxTokens,\n onChunk: onChunk ?? (() => {}),\n });\n if (text && text.trim()) return text;\n throw createAiInferenceError({\n errorCode: 'ERR_AI_ALL_PROVIDERS_FAILED',\n message: 'customInference returned empty output',\n rawError: { customInference: 'empty response' }\n });\n } catch (e: any) {\n if (e?.errorCode || e?.name === 'AiInferenceError') throw e;\n throw createAiInferenceError({\n errorCode: 'ERR_AI_ALL_PROVIDERS_FAILED',\n message: `customInference failed: ${e?.message || e}`,\n rawError: { customInference: String(e?.message || e) }\n });\n }\n }\n\n // ── Unified-tracing mandate (2026-09-14): fail LOUD on silent bypass ──\n // The embedding app routes every LLM call through its own gateway\n // (customInference → Vercel AI SDK → OpenTelemetry → Langfuse). The raw-fetch\n // routes below are OUTSIDE that telemetry boundary: a call site that forgets\n // to pass customInference used to fall through here silently, producing\n // untraceable generations. When the host mandates gateway-only inference\n // (CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE=1), refuse to run raw instead of\n // silently bypassing the unified tracing mechanism.\n if (!options.customInference && resolveApiKey('CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE') === '1') {\n throw createAiInferenceError({\n errorCode: 'ERR_CUSTOM_INFERENCE_REQUIRED',\n message:\n 'customInference is REQUIRED (CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE=1): pass buildKitCustomInference(...) ' +\n 'so every LLM call flows through the host AI SDK gateway and its unified Langfuse tracing. ' +\n 'Raw-fetch provider routes are disabled by mandate.',\n rawError: { mandate: 'CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE', hasCustomInference: false },\n });\n }\n\n const formattedMessages = [\n { role: 'system', content: systemInstruction },\n ...messages.map(m => ({\n role: m.role === 'assistant' || m.role === 'model' ? 'assistant' : 'user',\n content: m.content\n }))\n ];\n\n // Collect failure errors for full traceability\n const providerErrors: Record<string, string> = {};\n\n const requestedModel = options.model || 'fast-reasoning';\n const isNvidiaPreferred = requestedModel.startsWith('nvidia/') || (Boolean(nvidiaKey && !openrouterKey) && isProviderEnabled('nvidia'));\n\n // ── Route 0: 9Router Gateway ──\n const ninerouterKey = resolveApiKey('NINEROUTER_API_KEY') || resolveApiKey('NINE_ROUTER_API_KEY');\n if (ninerouterKey && isProviderEnabled('9router')) {\n const rawUrl = resolveApiKey('NINEROUTER_BASE_URL') || resolveApiKey('NINE_ROUTER_BASE_URL') || 'https://ai-router.orchable.app/v1';\n const ninerouterBaseUrl = rawUrl.replace(/^[\"']|[\"']$/g, '').replace(/\\/$/, '');\n const candidateModels = [\n options.model || 'fast-reasoning',\n 'fast-reasoning',\n 'mid-range',\n 'free-tier',\n ].filter(m => isModelAllowed(m));\n const unique9RouterModels = Array.from(new Set(candidateModels));\n\n for (const model of unique9RouterModels) {\n try {\n // 2026-09-14 (SLIDE idle audit): 45s was tuned for chat-sized prompts.\n // SLIDE cluster prompts run 30k+ chars and the gateway can think for\n // >45s BEFORE the first token, so the budget aborted healthy streams\n // (\"Idle timeout: no data for 45s\"). Honor options.idleTimeoutMs /\n // env like every other route, falling back to the same 90s default.\n const r9Idle = options.idleTimeoutMs\n ?? (Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS) || 0)\n ?? 0;\n const r9Total = options.timeoutMs\n ?? (Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS) || 0)\n ?? 0;\n const idle = createStreamAbortController({\n idleMs: r9Idle > 0 ? r9Idle : 90_000,\n totalMs: r9Total > 0 ? r9Total : 300_000,\n });\n const res = await fetch(`${ninerouterBaseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${ninerouterKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true },\n }),\n signal: idle.signal,\n });\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`9router_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`9router_${model}`] = e?.message || 'Network error';\n console.warn(`[9Router Stream] Failover for ${model}:`, e?.message || e);\n }\n }\n }\n\n // ── Route 1: NVIDIA NIM (Nemotron Suite) ──\n if (nvidiaKey && isProviderEnabled('nvidia')) {\n const candidateNemotronModels = [\n requestedModel.startsWith('nvidia/') ? requestedModel : 'nvidia/nemotron-3-ultra-550b-a55b:free',\n 'nvidia/nemotron-3-ultra-550b-a55b:free',\n 'nvidia/nemotron-3.5-lightning-30b-a3b',\n 'nvidia/nemotron-3-super-120b-a12b',\n 'nvidia/llama-3.1-nemotron-70b-instruct'\n ].filter(m => isModelAllowed(m));\n const uniqueNvidiaModels = Array.from(new Set(candidateNemotronModels));\n\n if (isNvidiaPreferred || uniqueNvidiaModels.length > 0) {\n for (const model of uniqueNvidiaModels) {\n try {\n const nvdIdle = options.idleTimeoutMs ?? 180_000;\n const nvdTotal = options.timeoutMs ?? 600_000;\n const idle = createStreamAbortController({ idleMs: nvdIdle, totalMs: nvdTotal });\n const res = await fetch('https://integrate.api.nvidia.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${nvidiaKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`nvidia_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`nvidia_${model}`] = e?.message || 'Network error';\n console.warn(`[NVIDIA Stream] Failover for ${model}:`, e?.message || e);\n }\n }\n }\n }\n\n // ── Route 2: OpenRouter (Primary Free Presets & Models) ──\n if (openrouterKey && isProviderEnabled('openrouter')) {\n const openrouterModels = [\n requestedModel,\n 'openrouter/free',\n 'nvidia/nemotron-3-super-120b-a12b:free',\n 'nvidia/nemotron-3-ultra-550b-a55b:free',\n 'nvidia/nemotron-3.5-lightning:free',\n 'minimax/minimax-m3:free',\n 'cohere/north-mini-code:free',\n ].filter(m => isModelAllowed(m));\n const uniqueOrModels = Array.from(new Set(openrouterModels));\n\n for (const model of uniqueOrModels) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch('https://openrouter.ai/api/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${openrouterKey}`,\n 'Content-Type': 'application/json',\n 'HTTP-Referer': 'https://orchable.composer',\n 'X-Title': 'Curriculum OS Studio'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`openrouter_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n if (res.status === 429) {\n console.warn(`[OpenRouter] Rate limited (429) for ${model}, trying fallback...`);\n }\n }\n } catch (e: any) {\n providerErrors[`openrouter_${model}`] = e?.message || 'Network error';\n console.warn(`[OpenRouter Stream] Failover for ${model}:`, e?.message || e);\n }\n }\n }\n\n // ── Route 3: DeepSeek Official API (Configurable via ENABLE_DEEPSEEK=true) ──\n if (deepseekKey && isProviderEnabled('deepseek')) {\n const dsModel = options.model?.includes('deepseek-reasoner') ? 'deepseek-reasoner' : 'deepseek-chat';\n if (isModelAllowed(dsModel)) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch('https://api.deepseek.com/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${deepseekKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n model: dsModel,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors['deepseek'] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors['deepseek'] = e?.message || 'Network error';\n console.warn(`[DeepSeek Stream] Failover:`, e?.message || e);\n }\n }\n }\n\n // ── Route 4: Alibaba DashScope / Qwen Cloud (Configurable via ENABLE_ALIBABA=true) ──\n if (alibabaKey && isProviderEnabled('alibaba')) {\n const qwenModels = (options.model?.startsWith('qwen')\n ? [options.model, 'qwen3.7-plus', 'qwen3.6-flash']\n : ['qwen3.7-plus', 'qwen3.6-flash']).filter(m => isModelAllowed(m));\n\n const baseUrl = alibabaKey.startsWith('sk-sp-')\n ? 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions'\n : 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions';\n\n for (const qwenModel of qwenModels) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const payload: any = {\n model: qwenModel,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n };\n\n const res = await fetch(baseUrl, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${alibabaKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`alibaba_${qwenModel}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`alibaba_${qwenModel}`] = e?.message || 'Network error';\n console.warn(`[Alibaba Stream] Failover for ${qwenModel}:`, e?.message || e);\n }\n }\n }\n\n // ── Route 5: Google Gemini Direct (Configurable via ENABLE_GEMINI=true) ──\n if (geminiKey && (isProviderEnabled('gemini') || isProviderEnabled('google'))) {\n const geminiModels = (options.model?.startsWith('gemini')\n ? [options.model, 'gemini-1.5-flash', 'gemini-2.0-flash']\n : ['gemini-1.5-flash', 'gemini-2.0-flash']).filter(m => isModelAllowed(m));\n\n const geminiContents = [\n { role: 'user', parts: [{ text: systemInstruction }] },\n { role: 'model', parts: [{ text: 'Tôi đã hiểu rõ toàn bộ bối cảnh dự án và sẵn sàng hỗ trợ bạn một cách chuyên sâu, chính xác nhất.' }] },\n ...messages.map(m => ({\n role: m.role === 'assistant' || m.role === 'model' ? 'model' : 'user',\n parts: [{ text: m.content }]\n }))\n ];\n\n for (const gModel of geminiModels) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${gModel}:streamGenerateContent?alt=sse&key=${geminiKey}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n contents: geminiContents,\n generationConfig: {\n temperature,\n maxOutputTokens: maxTokens,\n }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processGeminiSSEStream(res, onChunk, idle);\n if (text && text.trim()) return text;\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`gemini_${gModel}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`gemini_${gModel}`] = e?.message || 'Network error';\n console.warn(`[Gemini Stream] Failover for ${gModel}:`, e?.message || e);\n }\n }\n }\n\n // ── Route 6: Ultimate Designated Fallback Chain (Configurable via FALLBACK_AI_PROVIDER / FALLBACK_AI_MODEL) ──\n const fallbackChain = getDesignatedFallbackChain();\n if (fallbackChain.length > 0) {\n console.log(\n `[streamRunner] 🛡️ Primary routes failed/exhausted. Invoking designated last-resort fallback chain:`,\n fallbackChain.map((c) => `${c.provider}(${c.model})`).join(' -> ')\n );\n\n for (const target of fallbackChain) {\n const { provider, model } = target;\n\n // ── 9Router designated fallback ──\n // 2026-09-14 (9Router-only mandate): the loop previously had NO branch\n // for provider '9router', so a 9router-only chain iterated without ever\n // attempting a call and providerErrors stayed {} — masking the real\n // failure as \"Chi tiết: {}\". This branch makes the designated fallback\n // actually call the gateway (OpenAI-compatible SSE, same as Route 0).\n if ((provider === '9router' || provider === 'ninerouter') && ninerouterKey && isProviderEnabled('9router')) {\n try {\n const rawUrl = resolveApiKey('NINEROUTER_BASE_URL') || resolveApiKey('NINE_ROUTER_BASE_URL') || 'https://ai-router.orchable.app/v1';\n const fbBaseUrl = rawUrl.replace(/[\"']/g, '').replace(/\\/$/, '');\n // Same SLIDE idle-audit fix as Route 0: honor options/env instead of\n // a hardcoded 45s that aborted healthy long-prompt streams.\n const fbIdle = options.idleTimeoutMs\n ?? (Number(process.env.ARTIFACT_STREAM_IDLE_TIMEOUT_MS || process.env.STREAM_IDLE_TIMEOUT_MS) || 0)\n ?? 0;\n const fbTotal = options.timeoutMs\n ?? (Number(process.env.ARTIFACT_STREAM_TOTAL_TIMEOUT_MS || process.env.STREAM_TOTAL_TIMEOUT_MS) || 0)\n ?? 0;\n const idle = createStreamAbortController({\n idleMs: fbIdle > 0 ? fbIdle : 90_000,\n totalMs: fbTotal > 0 ? fbTotal : 300_000,\n });\n const res = await fetch(`${fbBaseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${ninerouterKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true },\n }),\n signal: idle.signal,\n });\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback 9Router (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_9router_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_9router_${model}`] = e?.message || 'Network error';\n }\n } else if (provider === 'nvidia' && nvidiaKey && isProviderEnabled('nvidia')) {\n try {\n const nvdIdle = options.idleTimeoutMs ?? 180_000;\n const nvdTotal = options.timeoutMs ?? 600_000;\n const idle = createStreamAbortController({ idleMs: nvdIdle, totalMs: nvdTotal });\n const res = await fetch('https://integrate.api.nvidia.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${nvidiaKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback NVIDIA (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_nvidia_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_nvidia_${model}`] = e?.message || 'Network error';\n }\n } else if (provider === 'openrouter' && openrouterKey && isProviderEnabled('openrouter')) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch('https://openrouter.ai/api/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${openrouterKey}`,\n 'Content-Type': 'application/json',\n 'HTTP-Referer': 'https://orchable.composer',\n 'X-Title': 'Curriculum OS Studio'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback OpenRouter (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_openrouter_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_openrouter_${model}`] = e?.message || 'Network error';\n }\n } else if ((provider === 'alibaba' || provider === 'dashscope') && alibabaKey && isProviderEnabled('alibaba')) {\n const baseUrl = alibabaKey.startsWith('sk-sp-')\n ? 'https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1/chat/completions'\n : 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions';\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs });\n const res = await fetch(baseUrl, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${alibabaKey}`,\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n model,\n messages: formattedMessages,\n max_tokens: maxTokens,\n temperature,\n stream: true,\n stream_options: { include_usage: true }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processOpenAISSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback Alibaba (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_alibaba_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_alibaba_${model}`] = e?.message || 'Network error';\n }\n } else if ((provider === 'google' || provider === 'gemini') && geminiKey && (isProviderEnabled('gemini') || isProviderEnabled('google'))) {\n try {\n const idle = createStreamAbortController({ idleMs: options.idleTimeoutMs, totalMs: options.timeoutMs }); const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${geminiKey}`,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n contents: [\n { role: 'user', parts: [{ text: systemInstruction }] },\n { role: 'model', parts: [{ text: 'Understood. I will follow the project context and guidelines.' }] },\n ...messages.map((m) => ({\n role: m.role === 'assistant' || m.role === 'model' ? 'model' : 'user',\n parts: [{ text: m.content }]\n }))\n ],\n generationConfig: {\n temperature,\n maxOutputTokens: maxTokens\n }\n }),\n signal: idle.signal\n });\n\n if (res.ok) {\n const text = await processGeminiSSEStream(res, onChunk, idle);\n if (text && text.trim()) {\n console.log(`[streamRunner] ✅ Designated fallback Gemini (${model}) succeeded!`);\n return text;\n }\n } else {\n const errText = await res.text().catch(() => '');\n providerErrors[`designated_fallback_gemini_${model}`] = `HTTP ${res.status}: ${errText.slice(0, 120)}`;\n }\n } catch (e: any) {\n providerErrors[`designated_fallback_gemini_${model}`] = e?.message || 'Network error';\n }\n }\n }\n }\n\n const isRateLimited = Object.values(providerErrors).some(msg => msg.includes('429'));\n const isAuthFailed = Object.values(providerErrors).some(msg => msg.includes('401') || msg.includes('403'));\n\n const errorCode = isRateLimited\n ? 'ERR_AI_RATE_LIMIT'\n : isAuthFailed\n ? 'ERR_AI_AUTH_FAILED'\n : 'ERR_AI_ALL_PROVIDERS_FAILED';\n\n throw createAiInferenceError({\n errorCode,\n message: `Không thể kết nối tới các nhà cung cấp AI trong chuỗi Fallback. Chi tiết: ${JSON.stringify(providerErrors)}`,\n rawError: providerErrors\n });\n}\n\n/**\n * Synchronous Multi-Model Inference Wrapper with strict error propagation\n */\nexport async function runCurriculumAIInference(\n messages: ChatMessage[],\n projectContext: string,\n options: StreamRunnerOptions = {},\n onChunk?: (token: string, type: ChunkType) => void\n): Promise<string> {\n return await streamCurriculumAIInference(messages, projectContext, options, onChunk);\n}\n","import { runCurriculumAIInference, type StreamRunnerOptions } from '../ai/streamRunner';\nimport type { MediaLedger, MediaLedgerEntry } from './ledger';\nimport { MediaError } from './types';\n\nexport type MediaPolicyMode = 'search_only' | 'gen_only' | 'auto';\n\nexport interface MediaPolicy {\n /** Giới hạn số ảnh ĐƯỢC GEN (AI) tối đa per artifact — search kho ảnh KHÔNG tốn quota */\n maxGenImagesPerArtifact: number;\n /** Ưu tiên provider khi mode=generate */\n preferredProvider?: 'openai' | 'gemini';\n /**\n * Chiến lược nguồn ảnh:\n * — search_only: chỉ tìm kho ảnh (Pexels), không sinh AI\n * — gen_only: chỉ sinh AI, bỏ qua kho ảnh\n * — auto: LUÔN search trước, không có kết quả mới generate (mặc định)\n */\n mode?: MediaPolicyMode;\n}\n\nexport interface CurationDecision {\n slug: string;\n action: 'approve' | 'drop' | 're-describe';\n /** Mã lý do máy-đọc-được — bắt buộc khi drop, để audit + user có thể override */\n reasonCode?: 'duplicate' | 'content_mismatch' | 'low_quality_description' | 'over_quota' | 'none_needed';\n /** Mô tả đã enrich (grade band, style, pedagogy) — chỉ khi approve/re-describe */\n enrichedPrompt?: string;\n reason: string;\n}\n\nexport interface CurateOptions {\n ledger: MediaLedger;\n /** Nội dung artifact ĐÃ PASS judge (markdown, strip YAML) */\n artifactContent: string;\n policy: MediaPolicy;\n /** Ngữ cảnh dự án: grade band, style guide, tiêu đề bài */\n context: {\n lessonTitle?: string;\n gradeBand?: [number, number];\n styleGuideExcerpt?: string;\n language?: string;\n };\n llm?: StreamRunnerOptions;\n}\n\n/**\n * Curator: phân tích toàn bộ sổ cái + nội dung đã chốt → quyết định ảnh nào tạo.\n * Tôn trọng maxImagesPerArtifact (count cả ảnh done + pending được approve).\n * LLM trả JSON: [{slug, action, enrichedPrompt, reason}]. Parse lỗi → MediaError rõ ràng.\n */\nexport async function curateMediaLedger(options: CurateOptions): Promise<CurationDecision[]> {\n const { ledger, artifactContent, policy, context } = options;\n const pendingEntries = ledger.pending();\n if (pendingEntries.length === 0) return [];\n\n const genQuota = Math.max(0, (policy.maxGenImagesPerArtifact ?? 3) - ledger.doneCount());\n const entriesBrief = pendingEntries.map(e => `- slug=${e.slug} | mode=${e.mode} | name=${e.name} | desc=${e.description.slice(0, 300)}`).join('\\n');\n\n const prompt = `Bạn là Media Curator cho học liệu giáo dục. Sổ cái có ${pendingEntries.length} ảnh đề xuất (pending), đã có ${ledger.doneCount()} ảnh hoàn tất, quota GEN tối đa ${policy.maxGenImagesPerArtifact} ảnh/bài (search kho ảnh KHÔNG tốn quota — xử ở tầng thực thi).\n${context.lessonTitle ? `Bài học: ${context.lessonTitle}` : ''}\n${context.gradeBand ? `Grade band: ${context.gradeBand[0]}-${context.gradeBand[1]}` : ''}\n\nCác ảnh đề xuất (sổ cái):\n${entriesBrief}\n\nNội dung bài (đã duyệt):\n${artifactContent.slice(0, 12000)}\n\nQUY TẮC PHÂN BỔ THEO 2 TRƯỜNG HỢP:\nA) Nếu ${pendingEntries.length} <= ${genQuota}: APPROVE TẤT CẢ — trừ khi có lý do CỨNG:\n - duplicate: 2+ ảnh cùng chủ đề (chỉ giữ 1, cái còn lại action=drop reasonCode=duplicate)\n - content_mismatch: mô tả không liên quan gì đến nội dung bài\n - low_quality_description: mô tả mơ hồ đến mức không thể tạo ảnh dùng được (vd \"ảnh minh họa chung\")\n KHÔNG được drop vì \"cảm thấy không cần\" — agent tạo đã lọc từ đầu.\nB) Về quota GEN (tối đa ${policy.maxGenImagesPerArtifact} ảnh AI/bài): KHÔNG drop ở bước này vì quota —\n tầng thực thi sẽ search kho ảnh trước cho mọi slot, chỉ những slot search-miss mới được xếp hạng để gen.\n Việc của bạn ở đây: approve/re-describe/drop theo 3 lý do CỨNG ở trên.\n\nVới mỗi ảnh approve/re-describe: viết enrichedPrompt TIẾNG ANH chi tiết (subject, layout, labeled parts, educational-diagram style, age-appropriate).\nKHÔNG BAO GIỜ approve vượt ${genQuota}.\n\nTrả về CHÍNH XÁC JSON (không markdown fence) cho TẤT CẢ các slug:\n[{\"slug\":\"...\",\"action\":\"approve|drop|re-describe\",\"reasonCode\":\"duplicate|content_mismatch|low_quality_description|over_quota\",\"enrichedPrompt\":\"...\",\"reason\":\"...\"}]`;\n\n const raw = await runCurriculumAIInference(\n [{ role: 'user', content: prompt }],\n '',\n options.llm || {}\n );\n\n const jsonMatch = raw.match(/\\[[\\s\\S]*\\]/);\n if (!jsonMatch) throw new MediaError(`Curator LLM trả về không parse được JSON: ${raw.slice(0, 200)}`, 'curator');\n let decisions: CurationDecision[];\n try {\n decisions = JSON.parse(jsonMatch[0]);\n } catch (e: any) {\n throw new MediaError(`Curator JSON invalid: ${e?.message}`, 'curator');\n }\n\n // Validate + enforce maxImages server-side (LLM không được vượt quota) + kiểm định danh\n const validSlugs = new Set(pendingEntries.map(e => e.slug));\n decisions = decisions.filter(d => validSlugs.has(d.slug)); // bỏ slug bịa\n\n const approved = decisions.filter(d => d.action === 'approve' || d.action === 're-describe');\n const overflow = approved.slice(genQuota);\n for (const d of overflow) {\n d.action = 'drop';\n d.reasonCode = 'over_quota';\n d.reason = 'Vượt maxImagesPerArtifact sau kiểm tra server-side';\n }\n\n // Bắt buộc reasonCode khi drop — fallback 'none_needed' nếu LLM quên\n for (const d of decisions) {\n if (d.action === 'drop' && !d.reasonCode) d.reasonCode = 'none_needed';\n }\n\n // Persist quyết định vào sổ cái (kèm reasonCode để audit + user override)\n for (const d of decisions) {\n if (d.action === 'drop') {\n ledger.setStatus(d.slug, 'rejected', { decisionReasonCode: d.reasonCode, decisionReason: d.reason, lastError: d.reason });\n } else {\n ledger.setStatus(d.slug, 'approved', { decisionReasonCode: undefined, decisionReason: d.reason, finalPrompt: d.enrichedPrompt });\n }\n }\n return decisions;\n \n\n}\n/** Input ranking cho 1 gen candidate */\nexport interface GenCandidate {\n slug: string;\n name: string;\n description: string;\n}\n\nexport interface GenRanking {\n /** Slugs được quyền gen (≤ quota) theo thứ tự ưu tiên */\n selected: string[];\n /** Slots không được gen kèm lý do */\n dropped: Array<{ slug: string; rank: number }>;\n}\n\n/**\n * Xếp hạng gen candidates khi số slot search-miss (hoặc gen_only tổng slot) VƯỢT quota gen.\n * Chỉ xếp hạng theo mức cần thiết của minh họa cho hiểu bài — KHÔNG đụng ledger (orchestrate lo persist).\n * LLM fail → fallback first-come theo thứ tự sổ cái + log warning rõ (degradation có chủ đích, không im lặng).\n */\nexport async function rankGenCandidates(\n candidates: GenCandidate[],\n quota: number,\n context: { lessonTitle?: string; gradeBand?: [number, number] },\n llm?: StreamRunnerOptions\n): Promise<GenRanking> {\n if (candidates.length <= quota) {\n return { selected: candidates.map(c => c.slug), dropped: [] };\n }\n\n const brief = candidates.map((c, i) => `${i + 1}. slug=${c.slug} | name=${c.name} | desc=${c.description.slice(0, 250)}`).join('\\n');\n const prompt = `Xếp hạng ${candidates.length} ảnh minh họa giáo dục, chọn ĐÚNG ${quota} ảnh ưu tiên gen (ảnh AI tốn kém).\n${context.lessonTitle ? `Bài học: ${context.lessonTitle}` : ''}\n${context.gradeBand ? `Grade band: ${context.gradeBand[0]}-${context.gradeBand[1]}` : ''}\n\nCandidates:\n${brief}\n\nThứ tự ưu tiên:\n1. Diagram/sơ đồ giải thích khái niệm trừu tượng hoặc quy trình nhiều bước (thiếu là khó hiểu nhất)\n2. Minh họa step-by-step thực hành (wiring, thao tác, UI)\n3. Ảnh bối cảnh/động lực (ít cần nhất)\n\nTrả CHÍNH XÁC JSON (không fence): {\"selected\":[\"slug1\",\"slug2\",...]} — đúng ${quota} slugs, theo thứ tự ưu tiên.`;\n\n try {\n const raw = await runCurriculumAIInference([{ role: 'user', content: prompt }], '', llm || {});\n const m = raw.match(/\\{[\\s\\S]*\\}/);\n if (!m) throw new Error('no JSON in response');\n const parsed = JSON.parse(m[0]) as { selected?: string[] };\n const valid = (parsed.selected || []).filter(s => candidates.some(c => c.slug === s)).slice(0, quota);\n if (valid.length === 0) throw new Error('empty selection');\n const selectedSet = new Set(valid);\n // Fill nếu LLM chọn thiếu quota: lấy theo thứ tự gốc\n for (const c of candidates) {\n if (valid.length >= quota) break;\n if (!selectedSet.has(c.slug)) { valid.push(c.slug); selectedSet.add(c.slug); }\n }\n const dropped = candidates.filter(c => !selectedSet.has(c.slug)).map((c, i) => ({ slug: c.slug, rank: i + 1 }));\n return { selected: valid, dropped };\n } catch (err: any) {\n // KHÔNG giấu lỗi — warn rõ rồi fallback first-come (ổn định, không chặn pipeline)\n console.warn('[curator] rankGenCandidates LLM failed — fallback first-come order:', err?.message || err);\n const selected = candidates.slice(0, quota).map(c => c.slug);\n const dropped = candidates.slice(quota).map((c, i) => ({ slug: c.slug, rank: i + 1 }));\n return { selected, dropped };\n }\n}","import fs from 'fs';\nimport path from 'path';\nimport { generateEducationalImage } from './imageProviders';\nimport { searchEducationalImages, searchEducationalVideos } from './stockSearch';\nimport type { MediaProvider } from './types';\nimport { MediaLedger, type MediaLedgerEntry } from './ledger';\nimport { rankGenCandidates } from './curator';\nimport type { MediaPolicy } from './curator';\nimport type { StreamRunnerOptions } from '../ai/streamRunner';\n\nexport interface FulfillOptions {\n ledger: MediaLedger;\n projectDir: string;\n policy: MediaPolicy;\n /** Tỷ lệ khung mặc định cho artifact type (SLIDE → 16:9) */\n defaultAspect?: '1:1' | '16:9' | '4:3' | '3:4';\n apiKeyOverrides?: { openai?: string; gemini?: string; pexels?: string };\n /** Số lần retry tối đa trước khi đánh dấu failed vĩnh viễn */\n maxRetries?: number;\n /** Ngữ cảnh cho gen-ranking (khi search-miss vượt quota gen) */\n rankingContext?: { lessonTitle?: string; gradeBand?: [number, number] };\n llm?: StreamRunnerOptions;\n onProgress?: (slug: string, status: string, detail?: string) => void;\n}\n\nexport interface FulfillResult {\n done: string[];\n failed: string[];\n skipped: string[];\n}\n\n/**\n * Thực thi các entry approved trong sổ cái (từng ảnh độc lập — lỗi 1 ảnh không chặn ảnh khác).\n * generate → base64 → save file _media/; search → lưu URL đầu tiên (metadata vào ledger).\n * Quá maxRetries → status 'failed', slot giữ placeholder trong markdown (client render).\n */\nexport async function fulfillMediaLedger(options: FulfillOptions): Promise<FulfillResult> {\n const { ledger, projectDir, policy } = options;\n const maxRetries = options.maxRetries ?? 2;\n const approved = ledger.listByStatus('approved');\n const result: FulfillResult = { done: [], failed: [], skipped: [] };\n\n const mediaDir = path.join(projectDir, '_media');\n fs.mkdirSync(mediaDir, { recursive: true });\n\n const mode = policy.mode ?? 'auto';\n const canSearch = mode === 'search_only' || mode === 'auto';\n const canGen = mode === 'gen_only' || mode === 'auto';\n\n // ── PHA 1: SEARCH kho ảnh cho TẤT CẢ slots (search không tốn quota gen) ──\n const searchMisses: typeof approved = [];\n if (canSearch) {\n for (const entry of approved) {\n if ((entry.retryCount ?? 0) >= maxRetries) { result.skipped.push(entry.slug); continue; }\n options.onProgress?.(entry.slug, 'searching');\n try {\n const images = await searchEducationalImages({\n query: entry.finalPrompt || entry.description,\n perPage: 1,\n apiKey: options.apiKeyOverrides?.pexels,\n });\n const target = images[0];\n if (target) {\n ledger.setStatus(entry.slug, 'done', { relPath: target.url, provider: 'pexels' });\n result.done.push(entry.slug);\n options.onProgress?.(entry.slug, 'done', 'source: pexels');\n } else {\n searchMisses.push(entry);\n }\n } catch (err: any) {\n if (mode === 'search_only') {\n // search_only: lỗi search = thất bại slot (đúng nghĩa chế độ)\n const msg = err?.message || String(err);\n ledger.setStatus(entry.slug, 'failed', { lastError: msg });\n options.onProgress?.(entry.slug, 'failed', msg);\n result.failed.push(entry.slug);\n } else {\n searchMisses.push(entry); // auto: search lỗi → coi như miss, thử gen\n }\n }\n }\n } else {\n // gen_only: mọi slot là \"miss\" đối với search\n for (const entry of approved) {\n if ((entry.retryCount ?? 0) >= maxRetries) { result.skipped.push(entry.slug); continue; }\n searchMisses.push(entry);\n }\n }\n\n // ── PHA 2: GEN cho search-miss — nếu vượt genQuota → rankGenCandidates xếp hạng ──\n if (canGen && searchMisses.length > 0) {\n const genQuota = Math.max(0, (policy.maxGenImagesPerArtifact ?? 3) - ledger.doneCount());\n let toGen: typeof approved = [];\n if (searchMisses.length > genQuota) {\n const ranking = await rankGenCandidates(\n searchMisses.map(e => ({ slug: e.slug, name: e.name, description: e.finalPrompt || e.description })),\n genQuota,\n options.rankingContext || {},\n options.llm\n );\n const allowed = new Set(ranking.selected);\n toGen = searchMisses.filter(e => allowed.has(e.slug));\n for (const dropped of ranking.dropped) {\n const entry = searchMisses.find(e => e.slug === dropped.slug);\n if (!entry) continue;\n // Quá quota gen → failed với lý do RÕ (user có thể 'Tạo ảnh bù' sau, hoặc tăng quota)\n ledger.setStatus(entry.slug, 'failed', {\n lastError: `Vượt quota gen (${policy.maxGenImagesPerArtifact}/bài) — hạng ${dropped.rank} khi xếp hạng theo mức cần thiết cho việc hiểu bài`,\n });\n result.failed.push(entry.slug);\n options.onProgress?.(entry.slug, 'failed', 'over gen quota');\n }\n } else {\n toGen = searchMisses;\n }\n\n for (const entry of toGen) {\n options.onProgress?.(entry.slug, 'generating');\n try {\n const provider: MediaProvider = policy.preferredProvider || 'openai';\n const image = await generateEducationalImage({\n prompt: entry.finalPrompt || entry.description,\n aspectRatio: options.defaultAspect || '4:3',\n provider,\n apiKey: provider === 'openai' ? options.apiKeyOverrides?.openai : options.apiKeyOverrides?.gemini,\n });\n const ext = image.mimeType === 'image/jpeg' ? 'jpg' : 'png';\n const filename = `${entry.slug}-${Date.now()}.${ext}`;\n fs.writeFileSync(path.join(mediaDir, filename), Buffer.from(image.base64, 'base64'));\n ledger.setStatus(entry.slug, 'done', { relPath: `_media/${filename}`, provider: image.provider });\n result.done.push(entry.slug);\n options.onProgress?.(entry.slug, 'done', `source: ${image.provider}`);\n } catch (err: any) {\n const msg = err?.message || String(err);\n ledger.setStatus(entry.slug, 'failed', { lastError: msg });\n options.onProgress?.(entry.slug, 'failed', msg);\n result.failed.push(entry.slug);\n }\n }\n }\n\n // search_only slots mà search trống nhưng KHÔNG fail ở pha 1 (đã xử) — không gen\n return result;\n}\n\n/** Sau khi done: thay placeholder [IMAGE: slug] trong markdown bằng  */\nexport function injectMediaIntoMarkdown(markdown: string, ledger: MediaLedger | MediaLedgerEntry[]): string {\n let out = markdown;\n const entries = Array.isArray(ledger) ? ledger : ledger.list();\n for (const entry of entries) {\n if (entry.status !== 'done' || !entry.relPath) continue;\n const placeholder = new RegExp(`\\\\[IMAGE\\\\s*:\\\\s*${entry.slug}\\\\]`, 'g');\n out = out.replace(placeholder, ``);\n }\n return out;\n}\n\n/** Tạo placeholder hiển thị khi failed/pending — client render rõ trạng thái, không im lặng */\nexport function renderMediaPlaceholder(entry: MediaLedgerEntry): string {\n if (entry.status === 'failed') {\n return `> ⚠️ [Ảnh ${entry.name} chưa tạo được (${entry.lastError || 'lỗi không rõ'}) — bấm \"Tạo ảnh bù\" để thử lại]`;\n }\n return `> 🖼️ [Ảnh đang chờ: ${entry.name} — sẽ được tạo sau khi duyệt media]`;\n}"]}
|