import "server-only"; import type { AgentThreadState } from "@/lib/ai/runtime/agent-thread-state"; export interface StoryboardPreferenceMemory { preferredGridType?: "grid_2x2" | "grid_3x2" | "grid_3x3"; preferredShotCount?: number; prefersConfirmation?: boolean; lastUsedGridType?: "grid_2x2" | "grid_3x2" | "grid_3x3"; lastUsedShotCount?: number; } function normalizeGridType(value: unknown) { const normalized = String(value || "").trim(); if (normalized === "grid_2x2" || normalized === "grid_3x2" || normalized === "grid_3x3") { return normalized; } return undefined; } function normalizeShotCount(value: unknown) { const parsed = Number(value); if (!Number.isFinite(parsed)) return undefined; const rounded = Math.round(parsed); if (rounded === 4 || rounded === 6 || rounded === 9) return rounded; return undefined; } export function extractStoryboardPreferenceMemory( workingState?: { lastTurnSummary?: unknown; } | null, ): StoryboardPreferenceMemory | null { const summary = workingState?.lastTurnSummary; if (!summary || typeof summary !== "object") return null; const summaryRecord = summary as Record; const memory = summaryRecord.storyboardMemory; if (!memory || typeof memory !== "object") return null; const memoryRecord = memory as Record; const normalized: StoryboardPreferenceMemory = { preferredGridType: normalizeGridType(memoryRecord.preferredGridType), preferredShotCount: normalizeShotCount(memoryRecord.preferredShotCount), prefersConfirmation: typeof memoryRecord.prefersConfirmation === "boolean" ? memoryRecord.prefersConfirmation : undefined, lastUsedGridType: normalizeGridType(memoryRecord.lastUsedGridType), lastUsedShotCount: normalizeShotCount(memoryRecord.lastUsedShotCount), }; if ( !normalized.preferredGridType && !normalized.preferredShotCount && normalized.prefersConfirmation === undefined && !normalized.lastUsedGridType && !normalized.lastUsedShotCount ) { return null; } return normalized; } export function buildStoryboardPreferenceMemoryUpdate(params: { existing?: StoryboardPreferenceMemory | null; preferredGridType?: "grid_2x2" | "grid_3x2" | "grid_3x3"; preferredShotCount?: number; prefersConfirmation?: boolean; lastUsedGridType?: "grid_2x2" | "grid_3x2" | "grid_3x3"; lastUsedShotCount?: number; }) { const next: StoryboardPreferenceMemory = { preferredGridType: params.preferredGridType ?? params.existing?.preferredGridType, preferredShotCount: params.preferredShotCount ?? params.existing?.preferredShotCount, prefersConfirmation: params.prefersConfirmation ?? params.existing?.prefersConfirmation, lastUsedGridType: params.lastUsedGridType ?? params.existing?.lastUsedGridType, lastUsedShotCount: params.lastUsedShotCount ?? params.existing?.lastUsedShotCount, }; return next; } export function getStoryboardPreferencePlanningHints( threadState?: AgentThreadState | null, ): string[] { const metadata = threadState?.metadata; const memory = metadata && typeof metadata === "object" && !Array.isArray(metadata) ? ((metadata.storyboardPreferenceMemory as StoryboardPreferenceMemory | undefined) || undefined) : undefined; if (!memory) return []; const hints: string[] = []; if (memory.preferredGridType) { hints.push(`用户最近偏好宫格版式:${memory.preferredGridType}。`); } if (memory.preferredShotCount) { hints.push(`用户最近常用镜头数:${memory.preferredShotCount} 段。`); } if (memory.prefersConfirmation === true) { hints.push("用户偏好先确认分镜草案,再开始执行。"); } if (memory.lastUsedGridType && memory.lastUsedShotCount) { hints.push( `用户最近一次分镜任务使用的是 ${memory.lastUsedGridType}(${memory.lastUsedShotCount} 段)。` ); } return hints; }