File size: 3,966 Bytes
5433b53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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<StudioWorkContext | undefined> {
  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
}