feat(ai): add code interpreter for AI data analysis (#16559)

## Summary

- Add code interpreter tool that enables AI to execute Python code for
data analysis, CSV processing, and chart generation
- Support for both local (development) and E2B (sandboxed production)
execution drivers
- Real-time streaming of stdout/stderr and generated files
- Frontend components for displaying code execution results with
expandable sections

## Code Quality Improvements

- Extract `getMimeType` to shared utility to reduce code duplication
between drivers
- Fix security issue: escape single quotes/backslashes in E2B driver env
variable injection
- Add `buildExecutionState` helper to reduce duplicated state object
construction
- Add `DEFAULT_CODE_INTERPRETER_TIMEOUT_MS` constant for consistency
- Fix lingui linting warning and TypeScript theme errors in frontend

## Test Plan

- [ ] Test code interpreter with local driver in development
- [ ] Test code interpreter with E2B driver in production environment
- [ ] Verify streaming output displays correctly in chat UI
- [ ] Verify generated files (charts, CSVs) are uploaded and
downloadable
- [ ] Test file upload flow (CSV, Excel) triggers code interpreter

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Updates generated i18n catalogs for Polish and pseudo-English, adding
strings for code execution/output (code interpreter) and various UI
messages, with minor text adjustments.
> 
> - **Localization**:
> - **Generated catalogs**: Refresh `locales/generated/pl-PL.ts` and
`locales/generated/pseudo-en.ts`.
> - Add strings for code execution/output (e.g., code, copy code/output,
running/waiting states, download files, generated files, Python code
execution).
> - Include new UI texts (errors, prompts, menus) and minor text
corrections.
>   - No changes to `pt-BR`; other files unchanged functionally.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
befc13d02c21e5a6647bc1aa6daa2a89f60b7ef8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This commit is contained in:
Félix Malfait
2025-12-15 16:11:24 +01:00
committed by GitHub
parent 4281a71f40
commit 2e104c8e76
151 changed files with 10361 additions and 449 deletions
@@ -4,7 +4,8 @@ import { useFileCategoryColors } from '@/file/hooks/useFileCategoryColors';
import { IconMapping } from '@/file/utils/fileIconMappings';
import { useTheme } from '@emotion/react';
import { type FileUIPart } from 'ai';
import { AvatarChip, Chip, ChipVariant } from 'twenty-ui/components';
import { isDefined } from 'twenty-shared/utils';
import { AvatarChip, Chip, ChipVariant, LinkChip } from 'twenty-ui/components';
import { type IconComponent, IconX } from 'twenty-ui/display';
import { Loader } from 'twenty-ui/feedback';
@@ -24,35 +25,51 @@ export const AgentChatFilePreview = ({
const fileName =
file instanceof File ? file.name : (file.filename ?? 'Unknown file');
const fileUrl = file instanceof File ? undefined : file.url;
const fileCategory: AttachmentFileCategory = getFileType(fileName);
const FileCategoryIcon: IconComponent = IconMapping[fileCategory];
const iconBackgroundColor: string = iconColors[fileCategory];
const leftComponent = isUploading ? (
<Loader color="yellow" />
) : (
<AvatarChip
Icon={FileCategoryIcon}
IconBackgroundColor={iconBackgroundColor}
/>
);
const rightComponent = onRemove ? (
<AvatarChip
Icon={IconX}
IconColor={theme.font.color.secondary}
onClick={onRemove}
divider="left"
/>
) : undefined;
if (isDefined(fileUrl)) {
return (
<LinkChip
label={fileName}
variant={ChipVariant.Static}
to={fileUrl}
target="_blank"
leftComponent={leftComponent}
rightComponent={rightComponent}
/>
);
}
return (
<Chip
label={fileName}
variant={ChipVariant.Static}
leftComponent={
isUploading ? (
<Loader color="yellow" />
) : (
<AvatarChip
Icon={FileCategoryIcon}
IconBackgroundColor={iconBackgroundColor}
/>
)
}
rightComponent={
onRemove ? (
<AvatarChip
Icon={IconX}
IconColor={theme.font.color.secondary}
onClick={onRemove}
divider="left"
/>
) : undefined
}
clickable={false}
leftComponent={leftComponent}
rightComponent={rightComponent}
/>
);
};