(
messages: ChatMessage[],
modelConfig: ModelConfig
)
| 130 | } |
| 131 | |
| 132 | private async prepareApiMessages( |
| 133 | messages: ChatMessage[], |
| 134 | modelConfig: ModelConfig |
| 135 | ): Promise<ChatMessage[]> { |
| 136 | const apiMessages = await Promise.all( |
| 137 | messages.map(async (message) => { |
| 138 | if (!message.attachments || message.attachments.length === 0) { |
| 139 | return { |
| 140 | role: message.role, |
| 141 | content: message.content |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | const contentParts: AIContentPart[] = [] |
| 146 | |
| 147 | if (typeof message.content === 'string' && message.content.trim()) { |
| 148 | contentParts.push({ |
| 149 | type: 'text', |
| 150 | text: message.content |
| 151 | }) |
| 152 | } |
| 153 | |
| 154 | for (const attachment of message.attachments) { |
| 155 | if (!attachment.type.startsWith('image/')) { |
| 156 | continue |
| 157 | } |
| 158 | |
| 159 | try { |
| 160 | const filePath = await resolveAttachmentPathForAI(attachment.localPath) |
| 161 | const buffer = await readFile(filePath) |
| 162 | contentParts.push({ |
| 163 | type: 'image_url', |
| 164 | image_url: { |
| 165 | url: `data:${attachment.type};base64,${buffer.toString('base64')}` |
| 166 | } |
| 167 | }) |
| 168 | } catch (error) { |
| 169 | console.error('Failed to read attachment for AI request:', attachment.localPath, error) |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | return { |
| 174 | role: message.role, |
| 175 | content: contentParts |
| 176 | } |
| 177 | }) |
| 178 | ) |
| 179 | |
| 180 | if ( |
| 181 | modelConfig.systemPrompt && |
| 182 | (apiMessages.length === 0 || apiMessages[0].role !== 'system') |
| 183 | ) { |
| 184 | apiMessages.unshift({ |
| 185 | role: 'system', |
| 186 | content: modelConfig.systemPrompt |
| 187 | }) |
| 188 | } |
| 189 |
no test coverage detected