(part: OcPart, data: Pick<OpenCodeAssistantData, 'toolsUsed' | 'editedFiles' | 'referencedFiles'>, textParts: string[])
| 136 | } |
| 137 | |
| 138 | function applyOpenCodePart(part: OcPart, data: Pick<OpenCodeAssistantData, 'toolsUsed' | 'editedFiles' | 'referencedFiles'>, textParts: string[]): void { |
| 139 | if (part.type === 'text' && part.text) { |
| 140 | textParts.push(part.text); |
| 141 | return; |
| 142 | } |
| 143 | |
| 144 | if (part.type !== 'tool' || !part.tool) return; |
| 145 | |
| 146 | data.toolsUsed.push(part.tool); |
| 147 | const input = part.state?.input || {}; |
| 148 | const filePath = typeof input.filePath === 'string' |
| 149 | ? input.filePath |
| 150 | : typeof input.file_path === 'string' |
| 151 | ? input.file_path |
| 152 | : typeof input.path === 'string' |
| 153 | ? input.path |
| 154 | : null; |
| 155 | if (!filePath) return; |
| 156 | |
| 157 | const toolLower = part.tool.toLowerCase(); |
| 158 | if (WRITE_TOOLS.has(toolLower)) { |
| 159 | data.editedFiles.push(filePath); |
| 160 | // Include generated code content so extractCodeBlocks() can detect AI-produced code. |
| 161 | // Write tools store the code in various input fields; also check state.output. |
| 162 | const content = typeof input.content === 'string' ? input.content |
| 163 | : typeof input.code === 'string' ? input.code |
| 164 | : typeof input.new_string === 'string' ? input.new_string |
| 165 | : typeof part.state?.output === 'string' ? part.state.output |
| 166 | : null; |
| 167 | if (content) { |
| 168 | const ext = filePath.split('.').pop() || 'unknown'; |
| 169 | textParts.push(`\n\`\`\`${ext}\n${content}\n\`\`\`\n`); |
| 170 | } |
| 171 | } else if (READ_TOOLS.has(toolLower)) { |
| 172 | data.referencedFiles.push(filePath); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | function collectAssistantData( |
| 177 | assistantMsg: OcMessage | null, |
no outgoing calls
no test coverage detected