From c4b14e2a3aa47808ea34d3b3daa4002370cded79 Mon Sep 17 00:00:00 2001 From: Tom Rochette Date: Thu, 13 Aug 2026 04:06:09 +0000 Subject: [PATCH] Remove the 5-model limit on multi-run groups The per-group cap of 5 models was enforced in three client-side locations with no server-side constraint and no technical justification; the store iterates models in a plain loop and dispatches each run via Promise.allSettled. Remove the cap entirely from MultiRunLauncher, useMultiRunStore, and AgentManagerEmptyState, and drop the {max} ceiling from the launcher info copy across all locales. Closes #2847 --- .../src/components/multirun/MultiRunLauncher.tsx | 5 +---- .../agent-manager/AgentManagerEmptyState.tsx | 8 +------- packages/ui/src/lib/i18n/messages/en.ts | 2 +- packages/ui/src/lib/i18n/messages/es.ts | 2 +- packages/ui/src/lib/i18n/messages/fr.ts | 2 +- packages/ui/src/lib/i18n/messages/ko.ts | 2 +- packages/ui/src/lib/i18n/messages/pl.ts | 2 +- packages/ui/src/lib/i18n/messages/pt-BR.ts | 2 +- packages/ui/src/lib/i18n/messages/uk.ts | 2 +- packages/ui/src/lib/i18n/messages/zh-CN.ts | 2 +- packages/ui/src/lib/i18n/messages/zh-TW.ts | 2 +- packages/ui/src/stores/useMultiRunStore.test.ts | 16 ++++++++++++++++ packages/ui/src/stores/useMultiRunStore.ts | 4 ---- 13 files changed, 27 insertions(+), 24 deletions(-) diff --git a/packages/ui/src/components/multirun/MultiRunLauncher.tsx b/packages/ui/src/components/multirun/MultiRunLauncher.tsx index 54716085..aff0ff7d 100644 --- a/packages/ui/src/components/multirun/MultiRunLauncher.tsx +++ b/packages/ui/src/components/multirun/MultiRunLauncher.tsx @@ -32,7 +32,6 @@ import { startDesktopWindowDrag } from '@/lib/desktopNative'; import { useI18n } from '@/lib/i18n'; const MAX_FILE_SIZE = 10 * 1024 * 1024; -const MAX_MODELS_PER_GROUP = 5; interface MultiRunAttachedFile { id: string; @@ -727,7 +726,6 @@ const RunGroupCard: React.FC = ({ const snippetRef = React.useRef(null); const handleAddModel = React.useCallback((model: ModelSelectionWithId) => { - if (group.models.length >= MAX_MODELS_PER_GROUP) return; onUpdate(group.id, { models: [...group.models, model] }); }, [group.id, group.models, onUpdate]); @@ -987,7 +985,7 @@ const RunGroupCard: React.FC = ({
{t('multirun.launcher.models.info', { max: MAX_MODELS_PER_GROUP })}} + info={{t('multirun.launcher.models.info')}} > {t('multirun.launcher.models.label')} @@ -997,7 +995,6 @@ const RunGroupCard: React.FC = ({ onRemove={handleRemoveModel} onUpdate={handleUpdateModel} minModels={1} - maxModels={MAX_MODELS_PER_GROUP} />
diff --git a/packages/ui/src/components/views/agent-manager/AgentManagerEmptyState.tsx b/packages/ui/src/components/views/agent-manager/AgentManagerEmptyState.tsx index 61ad0d09..1f8df59a 100644 --- a/packages/ui/src/components/views/agent-manager/AgentManagerEmptyState.tsx +++ b/packages/ui/src/components/views/agent-manager/AgentManagerEmptyState.tsx @@ -22,8 +22,6 @@ import { useI18n } from '@/lib/i18n'; /** Max file size in bytes (10MB) */ const MAX_FILE_SIZE = 10 * 1024 * 1024; -/** Max number of concurrent runs */ -const MAX_MODELS = 5; /** Attached file for agent manager */ interface AttachedFile { @@ -132,11 +130,8 @@ export const AgentManagerEmptyState: React.FC = ({ }, [projectRef]); const handleAddModel = React.useCallback((model: ModelSelectionWithId) => { - if (selectedModels.length >= MAX_MODELS) { - return; - } setSelectedModels((prev) => [...prev, model]); - }, [selectedModels.length]); + }, []); const handleRemoveModel = React.useCallback((index: number) => { setSelectedModels((prev) => prev.filter((_, i) => i !== index)); @@ -529,7 +524,6 @@ export const AgentManagerEmptyState: React.FC = ({ onUpdate={handleUpdateModel} minModels={1} addButtonLabel={t('agentManager.empty.models.addModel')} - maxModels={5} /> diff --git a/packages/ui/src/lib/i18n/messages/en.ts b/packages/ui/src/lib/i18n/messages/en.ts index cd1d0e9f..e3344b55 100644 --- a/packages/ui/src/lib/i18n/messages/en.ts +++ b/packages/ui/src/lib/i18n/messages/en.ts @@ -369,7 +369,7 @@ export const dict = { 'multirun.launcher.attachments.attach': 'Attach', 'multirun.launcher.attachments.tooltip': 'Same files sent to all runs', 'multirun.launcher.models.label': 'Models', - 'multirun.launcher.models.info': 'Select 2-{max} models. Same model can be added multiple times.', + 'multirun.launcher.models.info': 'Select 2 or more models. Same model can be added multiple times.', 'multirun.launcher.toast.fileTooLarge': 'File "{fileName}" is too large (max 10MB)', 'multirun.launcher.toast.attachFailed': 'Failed to attach "{fileName}"', 'multirun.launcher.toast.attachedSingle': 'Attached {count} file', diff --git a/packages/ui/src/lib/i18n/messages/es.ts b/packages/ui/src/lib/i18n/messages/es.ts index 50778a36..f2e618af 100644 --- a/packages/ui/src/lib/i18n/messages/es.ts +++ b/packages/ui/src/lib/i18n/messages/es.ts @@ -370,7 +370,7 @@ export const dict: Record = { "multirun.launcher.attachments.attach": "Adjuntar", "multirun.launcher.attachments.tooltip": "Archivos idénticos enviados a todas las ejecuciones", "multirun.launcher.models.label": "Modelos", - "multirun.launcher.models.info": "Selecciona 2-{max} modelos. El mismo modelo puede añadirse varias veces.", + "multirun.launcher.models.info": "Selecciona 2 o más modelos. El mismo modelo puede añadirse varias veces.", "multirun.launcher.toast.fileTooLarge": "El archivo \"{fileName}\" es demasiado grande (máximo 10MB)", "multirun.launcher.toast.attachFailed": "No se pudo adjuntar \"{fileName}\"", "multirun.launcher.toast.attachedSingle": "Archivo adjuntado ({count})", diff --git a/packages/ui/src/lib/i18n/messages/fr.ts b/packages/ui/src/lib/i18n/messages/fr.ts index d7f5dabb..6a664abb 100644 --- a/packages/ui/src/lib/i18n/messages/fr.ts +++ b/packages/ui/src/lib/i18n/messages/fr.ts @@ -201,7 +201,7 @@ export const dict = { 'multirun.launcher.attachments.attach': 'Attacher', 'multirun.launcher.attachments.tooltip': 'Mêmes fichiers envoyés à toutes les exécutions', 'multirun.launcher.models.label': 'Modèles', - 'multirun.launcher.models.info': 'Sélectionnez les modèles 2-{max}. Le même modèle peut être ajouté plusieurs fois.', + 'multirun.launcher.models.info': 'Sélectionnez 2 modèles ou plus. Le même modèle peut être ajouté plusieurs fois.', 'multirun.launcher.toast.fileTooLarge': 'Le fichier "{fileName}" est trop volumineux (max 10 Mo)', 'multirun.launcher.toast.attachFailed': 'Échec de la connexion de "{fileName}"', 'multirun.launcher.toast.attachedSingle': 'Fichier {count} joint', diff --git a/packages/ui/src/lib/i18n/messages/ko.ts b/packages/ui/src/lib/i18n/messages/ko.ts index e92a1b52..05ed304f 100644 --- a/packages/ui/src/lib/i18n/messages/ko.ts +++ b/packages/ui/src/lib/i18n/messages/ko.ts @@ -370,7 +370,7 @@ export const dict: Record = { 'multirun.launcher.attachments.attach': '첨부', 'multirun.launcher.attachments.tooltip': '같은 파일을 모든 실행에 보냅니다', 'multirun.launcher.models.label': '모델', - 'multirun.launcher.models.info': '모델을 2~{max}개 선택하세요. 같은 모델을 여러 번 추가할 수 있습니다.', + 'multirun.launcher.models.info': '모델을 2개 이상 선택하세요. 같은 모델을 여러 번 추가할 수 있습니다.', 'multirun.launcher.toast.fileTooLarge': '파일 "{fileName}"이 너무 큽니다(최대 10MB)', 'multirun.launcher.toast.attachFailed': '"{fileName}" 첨부 실패', 'multirun.launcher.toast.attachedSingle': '파일 {count}개 첨부됨', diff --git a/packages/ui/src/lib/i18n/messages/pl.ts b/packages/ui/src/lib/i18n/messages/pl.ts index 3548e484..92b17881 100644 --- a/packages/ui/src/lib/i18n/messages/pl.ts +++ b/packages/ui/src/lib/i18n/messages/pl.ts @@ -497,7 +497,7 @@ export const dict: Record = { 'multirun.launcher.attachments.attach': 'Dołącz', 'multirun.launcher.attachments.tooltip': 'Te same pliki wysłane do wszystkich uruchomień', 'multirun.launcher.models.label': 'Modele', - 'multirun.launcher.models.info': 'Wybierz od 2 do {max} modeli. Ten sam model może być dodany wielokrotnie.', + 'multirun.launcher.models.info': 'Wybierz 2 lub więcej modeli. Ten sam model może być dodany wielokrotnie.', 'multirun.launcher.toast.fileTooLarge': 'Plik "{fileName}" jest zbyt duży (max 10MB)', 'multirun.launcher.toast.attachFailed': 'Nie udało się dołączyć "{fileName}"', 'multirun.launcher.toast.attachedSingle': 'Dołączono {count} plik', diff --git a/packages/ui/src/lib/i18n/messages/pt-BR.ts b/packages/ui/src/lib/i18n/messages/pt-BR.ts index 144d79d1..bad161a7 100644 --- a/packages/ui/src/lib/i18n/messages/pt-BR.ts +++ b/packages/ui/src/lib/i18n/messages/pt-BR.ts @@ -370,7 +370,7 @@ export const dict: Record = { "multirun.launcher.attachments.attach": "Anexar", "multirun.launcher.attachments.tooltip": "Arquivos idênticos enviados a todas as execuções", "multirun.launcher.models.label": "Modelos", - "multirun.launcher.models.info": "Selecione 2-{max} modelos. O mesmo modelo pode ser adicionado várias vezes.", + "multirun.launcher.models.info": "Selecione 2 ou mais modelos. O mesmo modelo pode ser adicionado várias vezes.", "multirun.launcher.toast.fileTooLarge": "O arquivo \"{fileName}\" é grande demais (máximo 10MB)", "multirun.launcher.toast.attachFailed": "Não foi possível anexar \"{fileName}\"", "multirun.launcher.toast.attachedSingle": "Arquivo anexado ({count})", diff --git a/packages/ui/src/lib/i18n/messages/uk.ts b/packages/ui/src/lib/i18n/messages/uk.ts index 1fee6316..b1656963 100644 --- a/packages/ui/src/lib/i18n/messages/uk.ts +++ b/packages/ui/src/lib/i18n/messages/uk.ts @@ -370,7 +370,7 @@ export const dict: Record = { "multirun.launcher.attachments.attach": "Прикріпити", "multirun.launcher.attachments.tooltip": "Ті самі файли буде надіслано в усі запуски", "multirun.launcher.models.label": "Моделі", - "multirun.launcher.models.info": "Вибрати моделі 2-{max}. Ту саму модель можна додавати кілька разів.", + "multirun.launcher.models.info": "Вибрати 2 або більше моделей. Ту саму модель можна додавати кілька разів.", "multirun.launcher.toast.fileTooLarge": "Файл \"{fileName}\" завеликий (макс. 10 МБ)", "multirun.launcher.toast.attachFailed": "Не вдалося вкласти \"{fileName}\"", "multirun.launcher.toast.attachedSingle": "Прикріплено файл: {count}", diff --git a/packages/ui/src/lib/i18n/messages/zh-CN.ts b/packages/ui/src/lib/i18n/messages/zh-CN.ts index 977665c4..3d3a98f3 100644 --- a/packages/ui/src/lib/i18n/messages/zh-CN.ts +++ b/packages/ui/src/lib/i18n/messages/zh-CN.ts @@ -370,7 +370,7 @@ export const dict: Record = { 'multirun.launcher.attachments.attach': '附加', 'multirun.launcher.attachments.tooltip': '相同文件会发送到所有运行', 'multirun.launcher.models.label': '模型', - 'multirun.launcher.models.info': '选择 2-{max} 个模型。同一模型可重复添加。', + 'multirun.launcher.models.info': '选择 2 个或更多模型。同一模型可重复添加。', 'multirun.launcher.toast.fileTooLarge': '文件“{fileName}”过大(最大 10MB)', 'multirun.launcher.toast.attachFailed': '附加“{fileName}”失败', 'multirun.launcher.toast.attachedSingle': '已附加 {count} 个文件', diff --git a/packages/ui/src/lib/i18n/messages/zh-TW.ts b/packages/ui/src/lib/i18n/messages/zh-TW.ts index 9e0982f0..f45f7443 100644 --- a/packages/ui/src/lib/i18n/messages/zh-TW.ts +++ b/packages/ui/src/lib/i18n/messages/zh-TW.ts @@ -383,7 +383,7 @@ export const dict: Record = { 'multirun.launcher.attachments.attach': '附加', 'multirun.launcher.attachments.tooltip': '相同檔案會傳送到所有執行', 'multirun.launcher.models.label': '模型', - 'multirun.launcher.models.info': '選擇 2-{max} 個模型。同一模型可重複加入。', + 'multirun.launcher.models.info': '選擇 2 個或更多模型。同一模型可重複加入。', 'multirun.launcher.toast.fileTooLarge': '檔案「{fileName}」過大(最大 10MB)', 'multirun.launcher.toast.attachFailed': '附加「{fileName}」失敗', 'multirun.launcher.toast.attachedSingle': '已附加 {count} 個檔案', diff --git a/packages/ui/src/stores/useMultiRunStore.test.ts b/packages/ui/src/stores/useMultiRunStore.test.ts index c01295f1..dddb10c9 100644 --- a/packages/ui/src/stores/useMultiRunStore.test.ts +++ b/packages/ui/src/stores/useMultiRunStore.test.ts @@ -226,4 +226,20 @@ describe('useMultiRunStore', () => { 'createSession:/repo-worktrees/fix-thing', ]); }); + + test('accepts more than 5 models per group without a "maximum 5 models" error', async () => { + const models = Array.from({ length: 6 }, (_, i) => ({ + providerID: 'anthropic', + modelID: `claude-sonnet-4-5-${i}`, + })); + + const result = await useMultiRunStore.getState().createMultiRun({ + name: 'Many models', + isolateRuns: false, + groups: [{ prompt: 'Fix it', models }], + }); + + expect(useMultiRunStore.getState().error).toBeNull(); + expect(result?.sessionIds).toHaveLength(6); + }); }); diff --git a/packages/ui/src/stores/useMultiRunStore.ts b/packages/ui/src/stores/useMultiRunStore.ts index c06d9605..324b9caa 100644 --- a/packages/ui/src/stores/useMultiRunStore.ts +++ b/packages/ui/src/stores/useMultiRunStore.ts @@ -138,10 +138,6 @@ export const useMultiRunStore = create()( set({ error: `Group ${gi + 1}: select at least 1 model` }); return null; } - if (groups[gi].models.length > 5) { - set({ error: `Group ${gi + 1}: maximum 5 models allowed` }); - return null; - } } set({ isLoading: true, error: null });