import type { StudioAssistantMessage, StudioFileAttachment, StudioSessionEventStore, StudioTaskStore, StudioWork, StudioWorkContext, StudioWorkResultStore, StudioWorkStore } from '../domain/types' import { listPendingSessionEvents } from './session-event-inbox' interface BuildStudioWorkContextInput { sessionId: string agent: string assistantMessage: StudioAssistantMessage workStore?: StudioWorkStore workResultStore?: StudioWorkResultStore taskStore?: StudioTaskStore sessionEventStore?: StudioSessionEventStore } export async function buildStudioWorkContext(input: BuildStudioWorkContextInput): Promise { const context: StudioWorkContext = { sessionId: input.sessionId, agent: input.agent } if (input.workStore) { const works = await input.workStore.listBySessionId(input.sessionId) if (works.length) { const currentWork = selectCurrentWork(works) const lastRenderWork = [...works] .filter((work) => work.type === 'video' || work.type === 'plot' || work.type === 'render-fix') .sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt))[0] context.currentWork = currentWork ? { id: currentWork.id, type: currentWork.type, status: mapWorkStatus(currentWork.status), title: currentWork.title } : undefined if (lastRenderWork && input.workResultStore) { const results = await input.workResultStore.listByWorkId(lastRenderWork.id) const lastResult = [...results].sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt))[0] if (lastResult) { context.lastRender = { status: lastResult.kind === 'failure-report' ? 'failed' : 'success', timestamp: Date.parse(lastResult.createdAt), workId: lastRenderWork.id, output: lastResult.kind === 'render-output' ? { videoPath: findAttachment(lastResult.attachments, 'video/'), imagePaths: listAttachments(lastResult.attachments, 'image/') } : undefined, error: lastResult.kind === 'failure-report' ? typeof lastResult.metadata?.error === 'string' ? lastResult.metadata.error : lastResult.summary : undefined } } } } } if (input.sessionEventStore) { const pendingEvents = await listPendingSessionEvents(input.sessionEventStore, input.sessionId) if (pendingEvents.length) { context.pendingEvents = pendingEvents.map((event) => ({ id: event.id, kind: event.kind, title: event.title, summary: event.summary, createdAt: event.createdAt })) } } return context } function selectCurrentWork(works: StudioWork[]): StudioWork | undefined { return [...works] .sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt)) .find((work) => work.status === 'running' || work.status === 'queued' || work.status === 'proposed') ?? [...works].sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt))[0] } function mapWorkStatus(status: StudioWork['status']): 'pending' | 'running' | 'completed' | 'failed' { if (status === 'proposed' || status === 'queued') { return 'pending' } if (status === 'cancelled') { return 'failed' } return status } function findAttachment(attachments: StudioFileAttachment[] | undefined, prefix: string): string | undefined { return attachments?.find((attachment) => attachment.mimeType?.startsWith(prefix))?.path } function listAttachments(attachments: StudioFileAttachment[] | undefined, prefix: string): string[] | undefined { const paths = attachments?.filter((attachment) => attachment.mimeType?.startsWith(prefix)).map((attachment) => attachment.path) ?? [] return paths.length ? paths : undefined }