From b01e1d5c43ea61f00105efc44e8583789bc65958 Mon Sep 17 00:00:00 2001 From: sanil-23 Date: Tue, 9 Jun 2026 18:31:08 +0530 Subject: [PATCH] feat(chat): make reasoning-v1 vision-capable; remove pro-reasoning tier (#3545) --- app/src/lib/i18n/ar.ts | 3 +- app/src/lib/i18n/bn.ts | 3 +- app/src/lib/i18n/de.ts | 3 +- app/src/lib/i18n/en.ts | 3 +- app/src/lib/i18n/es.ts | 3 +- app/src/lib/i18n/fr.ts | 3 +- app/src/lib/i18n/hi.ts | 3 +- app/src/lib/i18n/id.ts | 3 +- app/src/lib/i18n/it.ts | 3 +- app/src/lib/i18n/ko.ts | 3 +- app/src/lib/i18n/pl.ts | 3 +- app/src/lib/i18n/pt.ts | 3 +- app/src/lib/i18n/ru.ts | 3 +- app/src/lib/i18n/zh-CN.ts | 4 +- app/src/pages/Conversations.tsx | 13 ----- .../Conversations.attachments.test.tsx | 14 ++--- src/openhuman/agent/cost.rs | 7 --- .../agent/harness/session/builder/factory.rs | 3 -- src/openhuman/agent/profiles.rs | 19 ------- .../channels/providers/web/session.rs | 3 -- src/openhuman/channels/providers/web_tests.rs | 8 --- src/openhuman/config/mod.rs | 5 +- src/openhuman/config/schema/identity_cost.rs | 12 +---- src/openhuman/config/schema/types.rs | 4 -- src/openhuman/inference/model_context.rs | 15 +++--- src/openhuman/inference/provider/factory.rs | 37 +++----------- .../inference/provider/factory_tests.rs | 51 +++---------------- 27 files changed, 46 insertions(+), 188 deletions(-) diff --git a/app/src/lib/i18n/ar.ts b/app/src/lib/i18n/ar.ts index 0b2d18f23..cf4a75337 100644 --- a/app/src/lib/i18n/ar.ts +++ b/app/src/lib/i18n/ar.ts @@ -1828,7 +1828,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'نوع ملف غير مدعوم. استخدم صورة (PNG أو JPEG أو WebP أو GIF أو BMP) أو ملف PDF أو TXT أو Markdown.', 'chat.attachment.imageNotSupported': - 'لا يمكن لهذا النموذج قراءة الصور. بدّل إلى تفكير احترافي لإرفاق صورتك.', + 'لا يمكن لهذا النموذج قراءة الصور. يمكنك استخدام مستوى التفكير من OpenHuman لإرفاق صورتك.', 'chat.attachment.readFailed': 'تعذر قراءة الملف', 'memory.searchAria': 'البحث في الذاكرة', 'memory.searchPlaceholder': 'البحث في إدخالات الذاكرة...', @@ -4362,7 +4362,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'ملف تعريف الوكيل', 'chat.agentProfile.quick': 'سريع', 'chat.agentProfile.reasoning': 'تفكير', - 'chat.agentProfile.proReasoning': 'تفكير احترافي', 'chat.agentProfile.namePlaceholder': 'اسم ملف التعريف', 'chat.agentProfile.promptStylePlaceholder': 'نمط المطالبة', 'chat.agentProfile.allowedToolsPlaceholder': 'الأدوات المسموح بها', diff --git a/app/src/lib/i18n/bn.ts b/app/src/lib/i18n/bn.ts index 6abe9a022..b4ca3fa77 100644 --- a/app/src/lib/i18n/bn.ts +++ b/app/src/lib/i18n/bn.ts @@ -1870,7 +1870,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'অসমর্থিত ফাইল প্রকার। একটি ছবি (PNG, JPEG, WebP, GIF, BMP) অথবা একটি PDF, TXT, বা Markdown ফাইল ব্যবহার করুন।', 'chat.attachment.imageNotSupported': - 'এই মডেলটি ছবি পড়তে পারে না। আপনার ছবি সংযুক্ত করতে প্রো যুক্তিতে স্যুইচ করুন।', + 'এই মডেলটি ছবি পড়তে পারে না। আপনার ছবি সংযুক্ত করতে আপনি OpenHuman যুক্তি স্তর ব্যবহার করতে পারেন।', 'chat.attachment.readFailed': 'ফাইল পড়া যায়নি', 'memory.searchAria': 'মেমোরি খুঁজুন', 'memory.searchPlaceholder': 'মেমোরি এন্ট্রি খুঁজুন...', @@ -4446,7 +4446,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'এজেন্ট প্রোফাইল', 'chat.agentProfile.quick': 'দ্রুত', 'chat.agentProfile.reasoning': 'যুক্তি', - 'chat.agentProfile.proReasoning': 'প্রো যুক্তি', 'chat.agentProfile.namePlaceholder': 'প্রোফাইল নাম', 'chat.agentProfile.promptStylePlaceholder': 'প্রম্পট স্টাইল', 'chat.agentProfile.allowedToolsPlaceholder': 'অনুমোদিত টুল', diff --git a/app/src/lib/i18n/de.ts b/app/src/lib/i18n/de.ts index c2c53944d..4e0b03a33 100644 --- a/app/src/lib/i18n/de.ts +++ b/app/src/lib/i18n/de.ts @@ -1917,7 +1917,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'Nicht unterstützter Dateityp. Verwenden Sie ein Bild (PNG, JPEG, WebP, GIF, BMP) oder eine PDF-, TXT- oder Markdown-Datei.', 'chat.attachment.imageNotSupported': - 'Dieses Modell kann keine Bilder lesen. Wechsle zu Pro-Denkmodus, um dein Bild anzuhängen.', + 'Dieses Modell kann keine Bilder lesen. Du kannst die OpenHuman-Stufe „Denkmodus“ verwenden, um dein Bild anzuhängen.', 'chat.attachment.readFailed': 'Datei konnte nicht gelesen werden', 'memory.searchAria': 'Speicher durchsuchen', 'memory.searchPlaceholder': 'Speichereinträge durchsuchen...', @@ -4563,7 +4563,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'Agentenprofil', 'chat.agentProfile.quick': 'Schnell', 'chat.agentProfile.reasoning': 'Denkmodus', - 'chat.agentProfile.proReasoning': 'Pro-Denkmodus', 'chat.agentProfile.namePlaceholder': 'Profilname', 'chat.agentProfile.promptStylePlaceholder': 'Eingabeaufforderungsstil', 'chat.agentProfile.allowedToolsPlaceholder': 'Zulässige Tools', diff --git a/app/src/lib/i18n/en.ts b/app/src/lib/i18n/en.ts index 05f6c18fc..5f8cb3971 100644 --- a/app/src/lib/i18n/en.ts +++ b/app/src/lib/i18n/en.ts @@ -2244,7 +2244,7 @@ const en: TranslationMap = { 'chat.attachment.unsupportedType': 'Unsupported file type. Use an image (PNG, JPEG, WebP, GIF, BMP) or a PDF, TXT, or Markdown file.', 'chat.attachment.imageNotSupported': - 'This model can’t read images. Switch to Pro-reasoning to attach your image.', + 'This model can’t read images. You can use the OpenHuman Reasoning tier to attach your image.', 'chat.attachment.readFailed': 'Could not read file', // Memory (additional) @@ -4980,7 +4980,6 @@ const en: TranslationMap = { 'chat.agentProfile.label': 'Agent profile', 'chat.agentProfile.quick': 'Quick', 'chat.agentProfile.reasoning': 'Reasoning', - 'chat.agentProfile.proReasoning': 'Pro-reasoning', 'chat.agentProfile.namePlaceholder': 'Profile name', 'chat.agentProfile.promptStylePlaceholder': 'Prompt style', 'chat.agentProfile.allowedToolsPlaceholder': 'Allowed tools', diff --git a/app/src/lib/i18n/es.ts b/app/src/lib/i18n/es.ts index a4f8ffc26..c47536843 100644 --- a/app/src/lib/i18n/es.ts +++ b/app/src/lib/i18n/es.ts @@ -1909,7 +1909,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'Tipo de archivo no compatible. Use una imagen (PNG, JPEG, WebP, GIF, BMP) o un archivo PDF, TXT o Markdown.', 'chat.attachment.imageNotSupported': - 'Este modelo no puede leer imágenes. Cambia a Pro-razonamiento para adjuntar tu imagen.', + 'Este modelo no puede leer imágenes. Puedes usar el nivel Razonamiento de OpenHuman para adjuntar tu imagen.', 'chat.attachment.readFailed': 'No se pudo leer el archivo', 'memory.searchAria': 'Buscar en memoria', 'memory.searchPlaceholder': 'Buscar entradas de memoria...', @@ -4532,7 +4532,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'Perfil del agente', 'chat.agentProfile.quick': 'Rápido', 'chat.agentProfile.reasoning': 'Razonamiento', - 'chat.agentProfile.proReasoning': 'Pro-razonamiento', 'chat.agentProfile.namePlaceholder': 'Nombre del perfil', 'chat.agentProfile.promptStylePlaceholder': 'estilo rápido', 'chat.agentProfile.allowedToolsPlaceholder': 'Herramientas permitidas', diff --git a/app/src/lib/i18n/fr.ts b/app/src/lib/i18n/fr.ts index 292b077e9..c7a060617 100644 --- a/app/src/lib/i18n/fr.ts +++ b/app/src/lib/i18n/fr.ts @@ -1917,7 +1917,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'Type de fichier non pris en charge. Utilise une image (PNG, JPEG, WebP, GIF, BMP) ou un fichier PDF, TXT ou Markdown.', 'chat.attachment.imageNotSupported': - 'Ce modèle ne peut pas lire les images. Passe en Pro-raisonnement pour joindre ton image.', + 'Ce modèle ne peut pas lire les images. Tu peux utiliser le niveau Raisonnement d’OpenHuman pour joindre ton image.', 'chat.attachment.readFailed': 'Impossible de lire le fichier', 'memory.searchAria': 'Rechercher dans la mémoire', 'memory.searchPlaceholder': 'Rechercher des entrées de mémoire…', @@ -4549,7 +4549,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': "Profil d'agent", 'chat.agentProfile.quick': 'Rapide', 'chat.agentProfile.reasoning': 'Raisonnement', - 'chat.agentProfile.proReasoning': 'Pro-raisonnement', 'chat.agentProfile.namePlaceholder': 'Nom du profil', 'chat.agentProfile.promptStylePlaceholder': 'Style de prompt', 'chat.agentProfile.allowedToolsPlaceholder': 'Outils autorisés', diff --git a/app/src/lib/i18n/hi.ts b/app/src/lib/i18n/hi.ts index 7832cb5c5..2a4a38f71 100644 --- a/app/src/lib/i18n/hi.ts +++ b/app/src/lib/i18n/hi.ts @@ -1869,7 +1869,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'असमर्थित फ़ाइल प्रकार। कोई छवि (PNG, JPEG, WebP, GIF, BMP) या PDF, TXT, या Markdown फ़ाइल का उपयोग करें।', 'chat.attachment.imageNotSupported': - 'यह मॉडल छवियाँ नहीं पढ़ सकता। अपनी छवि संलग्न करने के लिए प्रो तर्क पर स्विच करें।', + 'यह मॉडल छवियाँ नहीं पढ़ सकता। अपनी छवि संलग्न करने के लिए आप OpenHuman तर्क टियर का उपयोग कर सकते हैं।', 'chat.attachment.readFailed': 'फ़ाइल पढ़ नहीं सकी', 'memory.searchAria': 'मेमोरी सर्च करें', 'memory.searchPlaceholder': 'मेमोरी एंट्रीज़ सर्च करें...', @@ -4455,7 +4455,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'एजेंट प्रोफ़ाइल', 'chat.agentProfile.quick': 'त्वरित', 'chat.agentProfile.reasoning': 'तर्क', - 'chat.agentProfile.proReasoning': 'प्रो तर्क', 'chat.agentProfile.namePlaceholder': 'प्रोफ़ाइल नाम', 'chat.agentProfile.promptStylePlaceholder': 'शीघ्र शैली', 'chat.agentProfile.allowedToolsPlaceholder': 'अनुमत उपकरण', diff --git a/app/src/lib/i18n/id.ts b/app/src/lib/i18n/id.ts index 73978f481..f1f5f4be1 100644 --- a/app/src/lib/i18n/id.ts +++ b/app/src/lib/i18n/id.ts @@ -1872,7 +1872,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'Jenis file tidak didukung. Gunakan gambar (PNG, JPEG, WebP, GIF, BMP) atau file PDF, TXT, atau Markdown.', 'chat.attachment.imageNotSupported': - 'Model ini tidak dapat membaca gambar. Beralih ke Penalaran Pro untuk melampirkan gambar Anda.', + 'Model ini tidak dapat membaca gambar. Anda dapat menggunakan tingkat Penalaran OpenHuman untuk melampirkan gambar Anda.', 'chat.attachment.readFailed': 'Tidak dapat membaca file', 'memory.searchAria': 'Cari memori', 'memory.searchPlaceholder': 'Cari entri memori...', @@ -4466,7 +4466,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'Profil agen', 'chat.agentProfile.quick': 'Cepat', 'chat.agentProfile.reasoning': 'Penalaran', - 'chat.agentProfile.proReasoning': 'Penalaran Pro', 'chat.agentProfile.namePlaceholder': 'Nama profil', 'chat.agentProfile.promptStylePlaceholder': 'Gaya perintah', 'chat.agentProfile.allowedToolsPlaceholder': 'Alat yang diizinkan', diff --git a/app/src/lib/i18n/it.ts b/app/src/lib/i18n/it.ts index c2cc4d9f1..fdb392273 100644 --- a/app/src/lib/i18n/it.ts +++ b/app/src/lib/i18n/it.ts @@ -1901,7 +1901,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'Tipo di file non supportato. Usa un file immagine (PNG, JPEG, WebP, GIF, BMP) oppure PDF, TXT o Markdown.', 'chat.attachment.imageNotSupported': - 'Questo modello non può leggere le immagini. Passa a Pro-ragionamento per allegare la tua immagine.', + 'Questo modello non può leggere le immagini. Puoi usare il livello Ragionamento di OpenHuman per allegare la tua immagine.', 'chat.attachment.readFailed': 'Impossibile leggere il file', 'memory.searchAria': 'Cerca memoria', 'memory.searchPlaceholder': 'Cerca voci di memoria...', @@ -4525,7 +4525,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'Profilo agente', 'chat.agentProfile.quick': 'Veloce', 'chat.agentProfile.reasoning': 'Ragionamento', - 'chat.agentProfile.proReasoning': 'Pro-ragionamento', 'chat.agentProfile.namePlaceholder': 'Nome profilo', 'chat.agentProfile.promptStylePlaceholder': 'Stile prompt', 'chat.agentProfile.allowedToolsPlaceholder': 'Strumenti consentiti', diff --git a/app/src/lib/i18n/ko.ts b/app/src/lib/i18n/ko.ts index 954a28865..045bfd29d 100644 --- a/app/src/lib/i18n/ko.ts +++ b/app/src/lib/i18n/ko.ts @@ -1849,7 +1849,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': '지원되지 않는 파일 형식입니다. 이미지(PNG, JPEG, WebP, GIF, BMP) 또는 PDF, TXT, Markdown 파일을 사용하세요.', 'chat.attachment.imageNotSupported': - '이 모델은 이미지를 읽을 수 없습니다. 이미지를 첨부하려면 프로 추론으로 전환하세요.', + '이 모델은 이미지를 읽을 수 없습니다. 이미지를 첨부하려면 OpenHuman 추론 등급을 사용할 수 있습니다.', 'chat.attachment.readFailed': '파일을 읽을 수 없습니다', 'memory.searchAria': '메모리 검색', 'memory.searchPlaceholder': '메모리 항목 검색...', @@ -4407,7 +4407,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': '에이전트 프로필', 'chat.agentProfile.quick': '빠름', 'chat.agentProfile.reasoning': '추론', - 'chat.agentProfile.proReasoning': '프로 추론', 'chat.agentProfile.namePlaceholder': '프로필 이름', 'chat.agentProfile.promptStylePlaceholder': '프롬프트 스타일', 'chat.agentProfile.allowedToolsPlaceholder': '허용된 도구', diff --git a/app/src/lib/i18n/pl.ts b/app/src/lib/i18n/pl.ts index dd4920a34..ab913958d 100644 --- a/app/src/lib/i18n/pl.ts +++ b/app/src/lib/i18n/pl.ts @@ -1890,7 +1890,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'Nieobsługiwany typ pliku. Użyj obrazu (PNG, JPEG, WebP, GIF, BMP) lub pliku PDF, TXT albo Markdown.', 'chat.attachment.imageNotSupported': - 'Ten model nie może odczytywać obrazów. Przełącz na Pro-rozumowanie, aby dołączyć obraz.', + 'Ten model nie może odczytywać obrazów. Możesz użyć poziomu Rozumowanie OpenHuman, aby dołączyć obraz.', 'chat.attachment.readFailed': 'Nie można odczytać pliku', 'memory.searchAria': 'Szukaj w pamięci', 'memory.searchPlaceholder': 'Szukaj wpisów pamięci...', @@ -4523,7 +4523,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'Profil agenta', 'chat.agentProfile.quick': 'Szybki', 'chat.agentProfile.reasoning': 'Rozumowanie', - 'chat.agentProfile.proReasoning': 'Pro-rozumowanie', 'chat.agentProfile.namePlaceholder': 'Nazwa profilu', 'chat.agentProfile.promptStylePlaceholder': 'Styl promptu', 'chat.agentProfile.allowedToolsPlaceholder': 'Dozwolone narzędzia', diff --git a/app/src/lib/i18n/pt.ts b/app/src/lib/i18n/pt.ts index edf59a7b3..7c879cc66 100644 --- a/app/src/lib/i18n/pt.ts +++ b/app/src/lib/i18n/pt.ts @@ -1908,7 +1908,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'Tipo de arquivo não suportado. Use uma imagem (PNG, JPEG, WebP, GIF, BMP) ou um arquivo PDF, TXT ou Markdown.', 'chat.attachment.imageNotSupported': - 'Este modelo não consegue ler imagens. Mude para Pro-raciocínio para anexar sua imagem.', + 'Este modelo não consegue ler imagens. Você pode usar o nível Raciocínio do OpenHuman para anexar sua imagem.', 'chat.attachment.readFailed': 'Não foi possível ler o arquivo', 'memory.searchAria': 'Pesquisar memória', 'memory.searchPlaceholder': 'Pesquisar entradas de memória...', @@ -4522,7 +4522,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'Perfil do agente', 'chat.agentProfile.quick': 'Rápido', 'chat.agentProfile.reasoning': 'Raciocínio', - 'chat.agentProfile.proReasoning': 'Pro-raciocínio', 'chat.agentProfile.namePlaceholder': 'Nome do perfil', 'chat.agentProfile.promptStylePlaceholder': 'Estilo de prompt', 'chat.agentProfile.allowedToolsPlaceholder': 'Ferramentas permitidas', diff --git a/app/src/lib/i18n/ru.ts b/app/src/lib/i18n/ru.ts index a2d9aa4d2..50b536c97 100644 --- a/app/src/lib/i18n/ru.ts +++ b/app/src/lib/i18n/ru.ts @@ -1884,7 +1884,7 @@ const messages: TranslationMap = { 'chat.attachment.unsupportedType': 'Неподдерживаемый тип файла. Используйте изображение (PNG, JPEG, WebP, GIF, BMP) или файл PDF, TXT либо Markdown.', 'chat.attachment.imageNotSupported': - 'Эта модель не может читать изображения. Переключитесь на Про-рассуждение, чтобы прикрепить изображение.', + 'Эта модель не может читать изображения. Вы можете использовать уровень «Рассуждение» от OpenHuman, чтобы прикрепить изображение.', 'chat.attachment.readFailed': 'Не удалось прочитать файл', 'memory.searchAria': 'Поиск в памяти', 'memory.searchPlaceholder': 'Поиск записей памяти...', @@ -4485,7 +4485,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': 'Профиль агента', 'chat.agentProfile.quick': 'Быстрый', 'chat.agentProfile.reasoning': 'Рассуждение', - 'chat.agentProfile.proReasoning': 'Про-рассуждение', 'chat.agentProfile.namePlaceholder': 'Имя профиля', 'chat.agentProfile.promptStylePlaceholder': 'Стиль подсказки', 'chat.agentProfile.allowedToolsPlaceholder': 'Разрешенные инструменты', diff --git a/app/src/lib/i18n/zh-CN.ts b/app/src/lib/i18n/zh-CN.ts index 4be456726..434678f94 100644 --- a/app/src/lib/i18n/zh-CN.ts +++ b/app/src/lib/i18n/zh-CN.ts @@ -1765,7 +1765,8 @@ const messages: TranslationMap = { 'chat.attachment.tooLarge': '图片超过 {max} 大小限制', 'chat.attachment.unsupportedType': '不支持的文件类型。请使用图片(PNG、JPEG、WebP、GIF、BMP)或 PDF、TXT、Markdown 文件。', - 'chat.attachment.imageNotSupported': '此模型无法读取图像。请切换到专业推理以附加您的图像。', + 'chat.attachment.imageNotSupported': + '此模型无法读取图像。您可以使用 OpenHuman 推理层级来附加您的图像。', 'chat.attachment.readFailed': '无法读取文件', 'memory.searchAria': '搜索记忆', 'memory.searchPlaceholder': '搜索记忆条目...', @@ -4231,7 +4232,6 @@ const messages: TranslationMap = { 'chat.agentProfile.label': '代理简介', 'chat.agentProfile.quick': '快速', 'chat.agentProfile.reasoning': '推理', - 'chat.agentProfile.proReasoning': '专业推理', 'chat.agentProfile.namePlaceholder': '个人资料名称', 'chat.agentProfile.promptStylePlaceholder': '提示风格', 'chat.agentProfile.allowedToolsPlaceholder': '允许使用的工具', diff --git a/app/src/pages/Conversations.tsx b/app/src/pages/Conversations.tsx index bf5510c1c..bf4d351f1 100644 --- a/app/src/pages/Conversations.tsx +++ b/app/src/pages/Conversations.tsx @@ -1574,19 +1574,6 @@ const Conversations = ({ }`}> {t('chat.agentProfile.reasoning')} - {(selectedThreadId ?? activeThreadId) && ( diff --git a/app/src/pages/__tests__/Conversations.attachments.test.tsx b/app/src/pages/__tests__/Conversations.attachments.test.tsx index fcc96ce46..f95264de1 100644 --- a/app/src/pages/__tests__/Conversations.attachments.test.tsx +++ b/app/src/pages/__tests__/Conversations.attachments.test.tsx @@ -417,20 +417,20 @@ describe('Conversations — attachment feature', () => { expect(mockSelectAgentProfile).not.toHaveBeenCalled(); }); - it('selects the Pro-reasoning tier from the chat-header toggle', async () => { + it('selects the Reasoning tier from the chat-header toggle', async () => { await renderWithSelectedThread(); - const proButton = await screen.findByRole('radio', { name: 'Pro-reasoning' }); - expect(proButton).toHaveAttribute('aria-checked', 'false'); + const reasoningButton = await screen.findByRole('radio', { name: 'Reasoning' }); + expect(reasoningButton).toHaveAttribute('aria-checked', 'false'); await act(async () => { - fireEvent.click(proButton); + fireEvent.click(reasoningButton); }); await waitFor(() => { - expect(mockSelectAgentProfile).toHaveBeenCalledWith('pro-reasoning'); + expect(mockSelectAgentProfile).toHaveBeenCalledWith('reasoning'); // Store updates to the new active profile → toggle reflects the selection. - expect(screen.getByRole('radio', { name: 'Pro-reasoning' })).toHaveAttribute( + expect(screen.getByRole('radio', { name: 'Reasoning' })).toHaveAttribute( 'aria-checked', 'true' ); @@ -450,7 +450,7 @@ describe('Conversations — attachment feature', () => { // Advisory points users at the vision-capable managed tier. await waitFor(() => { - expect(screen.getByText(/Switch to Pro-reasoning/i)).toBeInTheDocument(); + expect(screen.getByText(/OpenHuman Reasoning tier/i)).toBeInTheDocument(); }); // The image is not attached, and the profile is left untouched. expect(screen.queryByText('no-vision.png')).not.toBeInTheDocument(); diff --git a/src/openhuman/agent/cost.rs b/src/openhuman/agent/cost.rs index 4fc5c3a91..c66ba4ecb 100644 --- a/src/openhuman/agent/cost.rs +++ b/src/openhuman/agent/cost.rs @@ -69,13 +69,6 @@ pub const PRICING_TABLE: &[ModelPricing] = &[ cached_input_per_mtok_usd: 1.50, output_per_mtok_usd: 75.00, }, - // Pro-reasoning chat tier — pricing copied from reasoning-v1. - ModelPricing { - model: "pro-reasoning-v1", - input_per_mtok_usd: 15.00, - cached_input_per_mtok_usd: 1.50, - output_per_mtok_usd: 75.00, - }, // Chat tier — Kimi K2.6 Turbo on Fireworks (backend PR #760). // Low TTFT, 128k context, `supportsThinking: false`. Rates track // Fireworks' published Kimi turbo pricing at time of writing. diff --git a/src/openhuman/agent/harness/session/builder/factory.rs b/src/openhuman/agent/harness/session/builder/factory.rs index b388b503a..622f5f144 100644 --- a/src/openhuman/agent/harness/session/builder/factory.rs +++ b/src/openhuman/agent/harness/session/builder/factory.rs @@ -413,9 +413,6 @@ impl Agent { Some("hint:coding") => "coding", Some("hint:summarization") => "summarization", Some("hint:reasoning") => "reasoning", - // Always-managed chat tier — keep in sync with - // `factory::provider_for_role` and `web::session::provider_role_for_model_override`. - Some("hint:pro-reasoning") => "pro-reasoning", _ => "chat", }; let (provider, mut model_name): (Box, String) = diff --git a/src/openhuman/agent/profiles.rs b/src/openhuman/agent/profiles.rs index abb301aaf..b5faa5f03 100644 --- a/src/openhuman/agent/profiles.rs +++ b/src/openhuman/agent/profiles.rs @@ -382,25 +382,6 @@ pub fn built_in_profiles() -> Vec { is_master: false, sort_order: None, }, - AgentProfile { - id: "pro-reasoning".to_string(), - name: "Pro-reasoning".to_string(), - description: "Premium reasoning tier (always managed).".to_string(), - agent_id: "orchestrator".to_string(), - model_override: Some("hint:pro-reasoning".to_string()), - temperature: None, - system_prompt_suffix: None, - allowed_tools: None, - built_in: true, - avatar_url: None, - voice_id: None, - soul_md: None, - soul_md_path: None, - composio_integrations: None, - memory_dir_suffix: None, - is_master: false, - sort_order: None, - }, AgentProfile { id: "research".to_string(), name: "Research".to_string(), diff --git a/src/openhuman/channels/providers/web/session.rs b/src/openhuman/channels/providers/web/session.rs index c5899b316..919506d8d 100644 --- a/src/openhuman/channels/providers/web/session.rs +++ b/src/openhuman/channels/providers/web/session.rs @@ -39,9 +39,6 @@ pub(crate) fn provider_role_for_model_override(model_override: Option<&str>) -> Some("hint:coding") | Some("coding-v1") => "coding", Some("hint:summarization") | Some("summarization-v1") => "summarization", Some("hint:reasoning") => "reasoning", - // pro-reasoning routes to its own always-managed role (never the BYOK - // chat provider) — keep in sync with `factory::provider_for_role`. - Some("hint:pro-reasoning") | Some("pro-reasoning-v1") => "pro-reasoning", _ => "chat", } } diff --git a/src/openhuman/channels/providers/web_tests.rs b/src/openhuman/channels/providers/web_tests.rs index 3c6d24c8a..879129a59 100644 --- a/src/openhuman/channels/providers/web_tests.rs +++ b/src/openhuman/channels/providers/web_tests.rs @@ -1533,14 +1533,6 @@ fn provider_role_override_routes_hint_workloads() { provider_role_for_model_override(Some("hint:reasoning")), "reasoning" ); - assert_eq!( - provider_role_for_model_override(Some("hint:pro-reasoning")), - "pro-reasoning" - ); - assert_eq!( - provider_role_for_model_override(Some("pro-reasoning-v1")), - "pro-reasoning" - ); assert_eq!( provider_role_for_model_override(Some("gpt-4.1-mini")), "chat" diff --git a/src/openhuman/config/mod.rs b/src/openhuman/config/mod.rs index 80294d9be..f5eceb998 100644 --- a/src/openhuman/config/mod.rs +++ b/src/openhuman/config/mod.rs @@ -49,9 +49,8 @@ pub use schema::{ VoiceActivationMode, VoiceServerConfig, WebSearchConfig, WebhookConfig, DEFAULT_CLOUD_LLM_MODEL, DEFAULT_MEMORY_SYNC_INTERVAL_SECS, DEFAULT_MODEL, MEMORY_SYNC_INTERVAL_PRESETS_SECS, MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, - MODEL_PRO_REASONING_V1, MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1, MODEL_SUMMARIZATION_V1, - SEARCH_ENGINE_BRAVE, SEARCH_ENGINE_DISABLED, SEARCH_ENGINE_MANAGED, SEARCH_ENGINE_PARALLEL, - SEARCH_ENGINE_QUERIT, + MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1, MODEL_SUMMARIZATION_V1, SEARCH_ENGINE_BRAVE, + SEARCH_ENGINE_DISABLED, SEARCH_ENGINE_MANAGED, SEARCH_ENGINE_PARALLEL, SEARCH_ENGINE_QUERIT, }; pub use schemas::{ all_controller_schemas as all_config_controller_schemas, diff --git a/src/openhuman/config/schema/identity_cost.rs b/src/openhuman/config/schema/identity_cost.rs index f6d23c3e3..2f99a239d 100644 --- a/src/openhuman/config/schema/identity_cost.rs +++ b/src/openhuman/config/schema/identity_cost.rs @@ -150,8 +150,8 @@ impl Default for CostConfig { /// Default pricing for popular models (USD per 1M tokens) fn get_default_pricing() -> HashMap { use super::types::{ - MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_PRO_REASONING_V1, - MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1, + MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_REASONING_QUICK_V1, + MODEL_REASONING_V1, }; let mut prices = HashMap::new(); @@ -163,14 +163,6 @@ fn get_default_pricing() -> HashMap { output: 2.52, }, ); - // Pro-reasoning chat tier — pricing copied from reasoning-v1. - prices.insert( - MODEL_PRO_REASONING_V1.into(), - ModelPricing { - input: 0.84, - output: 2.52, - }, - ); // Kimi K2.6 Turbo on Fireworks — see backend PR #760. prices.insert( MODEL_CHAT_V1.into(), diff --git a/src/openhuman/config/schema/types.rs b/src/openhuman/config/schema/types.rs index 0918c8e0f..87e2a4c11 100644 --- a/src/openhuman/config/schema/types.rs +++ b/src/openhuman/config/schema/types.rs @@ -9,10 +9,6 @@ use std::path::PathBuf; /// Standard model identifiers matching the backend model registry. pub const MODEL_AGENTIC_V1: &str = "agentic-v1"; pub const MODEL_REASONING_V1: &str = "reasoning-v1"; -/// Premium reasoning tier for chat. Always managed (OpenHuman backend) — never -/// BYOK/cloud-overridable — and selected only via the chat-header toggle, so it -/// is intentionally not a configurable Advanced-LLM workload. -pub const MODEL_PRO_REASONING_V1: &str = "pro-reasoning-v1"; /// Low-latency conversational tier. pub const MODEL_CHAT_V1: &str = "chat-v1"; /// Legacy low-latency chat tier slug retained for older persisted configs. diff --git a/src/openhuman/inference/model_context.rs b/src/openhuman/inference/model_context.rs index 214382f81..e09c8912a 100644 --- a/src/openhuman/inference/model_context.rs +++ b/src/openhuman/inference/model_context.rs @@ -6,8 +6,7 @@ //! metadata is not yet available. use crate::openhuman::config::{ - MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_PRO_REASONING_V1, - MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1, + MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1, }; /// Conservative default for OpenHuman abstract tier models (tokens). @@ -98,9 +97,7 @@ pub fn context_window_for_model(model: &str) -> Option { fn tier_context_window(model: &str) -> Option { match model { - MODEL_REASONING_V1 | MODEL_PRO_REASONING_V1 | MODEL_AGENTIC_V1 | MODEL_CODING_V1 => { - Some(TIER_LARGE_CONTEXT) - } + MODEL_REASONING_V1 | MODEL_AGENTIC_V1 | MODEL_CODING_V1 => Some(TIER_LARGE_CONTEXT), "summarization-v1" => Some(TIER_SUMMARIZATION_CONTEXT), MODEL_CHAT_V1 | MODEL_REASONING_QUICK_V1 | "chat" => Some(TIER_STANDARD_CONTEXT), m if m.starts_with("gemma") || m.contains(":1b") || m.contains("270m") => { @@ -172,7 +169,7 @@ pub fn model_vision_enabled(model: &str, config: &crate::openhuman::config::Conf /// - **Managed OpenHuman tiers** consult the hardcoded per-tier map /// ([`crate::openhuman::inference::provider::factory::oh_tier_supports_vision`]) — /// the remote backend does not advertise per-tier capability, so the core owns -/// it. Currently every managed tier is `false`. +/// it. Currently only `reasoning-v1` is vision-capable. /// - **Custom/BYOK models** consult the user-set `model_registry.vision` flag /// ([`model_vision_enabled`]). pub fn model_supports_vision(model: &str, config: &crate::openhuman::config::Config) -> bool { @@ -221,7 +218,6 @@ mod tests { #[test] fn tier_aliases_resolve() { assert_eq!(context_window_for_model("reasoning-v1"), Some(200_000)); - assert_eq!(context_window_for_model("pro-reasoning-v1"), Some(200_000)); assert_eq!(context_window_for_model("agentic-v1"), Some(200_000)); assert_eq!(context_window_for_model("chat-v1"), Some(128_000)); assert_eq!( @@ -288,9 +284,10 @@ mod tests { cost_per_1m_output: 0.0, vision: true, }]; - // Managed tiers are non-vision (the per-tier map is all `false` today). + // `reasoning-v1` is the one vision-capable managed tier; the rest are not. + assert!(model_supports_vision("reasoning-v1", &config)); + assert!(model_supports_vision("hint:reasoning", &config)); assert!(!model_supports_vision("chat-v1", &config)); - assert!(!model_supports_vision("reasoning-v1", &config)); assert!(!model_supports_vision("hint:chat", &config)); // BYOK model flagged in the registry is vision-capable. assert!(model_supports_vision("my-llava", &config)); diff --git a/src/openhuman/inference/provider/factory.rs b/src/openhuman/inference/provider/factory.rs index 55dbd8b7f..1915da3b4 100644 --- a/src/openhuman/inference/provider/factory.rs +++ b/src/openhuman/inference/provider/factory.rs @@ -62,15 +62,14 @@ pub const BYOK_INCOMPLETE_SENTINEL: &str = "__byok_incomplete__"; fn is_abstract_tier_model(model: &str) -> bool { use crate::openhuman::config::{ - MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_PRO_REASONING_V1, - MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1, + MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_REASONING_QUICK_V1, + MODEL_REASONING_V1, }; // No dedicated constant for the summarization tier yet; keep the literal // in sync with the tier name used by the summarizer sub-agent. const MODEL_SUMMARIZATION_V1: &str = "summarization-v1"; let trimmed = model.trim(); trimmed == MODEL_REASONING_V1 - || trimmed == MODEL_PRO_REASONING_V1 || trimmed == MODEL_REASONING_QUICK_V1 || trimmed == MODEL_CHAT_V1 || trimmed == MODEL_AGENTIC_V1 @@ -94,10 +93,6 @@ pub fn auth_key_for_slug(slug: &str) -> String { pub fn resolve_model_for_hint(hint_or_tier: &str, config: &Config) -> String { let hint_to_tier: &[(&str, &str)] = &[ ("reasoning", crate::openhuman::config::MODEL_REASONING_V1), - ( - "pro-reasoning", - crate::openhuman::config::MODEL_PRO_REASONING_V1, - ), ("chat", crate::openhuman::config::MODEL_CHAT_V1), ("agentic", crate::openhuman::config::MODEL_AGENTIC_V1), ("coding", crate::openhuman::config::MODEL_CODING_V1), @@ -105,12 +100,6 @@ pub fn resolve_model_for_hint(hint_or_tier: &str, config: &Config) -> String { ]; let tier_to_role: &[(&str, &str)] = &[ (crate::openhuman::config::MODEL_REASONING_V1, "reasoning"), - // Dedicated role so `provider_for_role` can force the managed backend — - // pro-reasoning must never inherit a BYOK/cloud chat provider. - ( - crate::openhuman::config::MODEL_PRO_REASONING_V1, - "pro-reasoning", - ), (crate::openhuman::config::MODEL_CHAT_V1, "chat"), (crate::openhuman::config::MODEL_REASONING_QUICK_V1, "chat"), (crate::openhuman::config::MODEL_AGENTIC_V1, "agentic"), @@ -164,20 +153,18 @@ pub fn resolve_model_for_hint(hint_or_tier: &str, config: &Config) -> String { /// to the backend. pub(crate) fn is_known_openhuman_tier(model: &str) -> bool { use crate::openhuman::config::{ - MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_PRO_REASONING_V1, - MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1, MODEL_SUMMARIZATION_V1, + MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_REASONING_QUICK_V1, + MODEL_REASONING_V1, MODEL_SUMMARIZATION_V1, }; matches!( model, MODEL_REASONING_V1 - | MODEL_PRO_REASONING_V1 | MODEL_CHAT_V1 | MODEL_AGENTIC_V1 | MODEL_CODING_V1 | MODEL_REASONING_QUICK_V1 | MODEL_SUMMARIZATION_V1 | "hint:reasoning" - | "hint:pro-reasoning" | "hint:chat" | "hint:agentic" | "hint:coding" @@ -192,20 +179,19 @@ pub(crate) fn is_known_openhuman_tier(model: &str) -> bool { /// constants and their `hint:*` forms (callers may pass either pre- or /// post-resolution). /// -/// `pro-reasoning-v1` is multimodal; the rest return `false` — flip an individual +/// `reasoning-v1` is multimodal; the rest return `false` — flip an individual /// arm to `true` once that tier is confirmed multimodal on the backend. This is /// the **only** place to change managed-model vision; BYOK/custom models are /// handled separately by the user-set `model_registry.vision` flag /// ([`crate::openhuman::inference::model_context::model_vision_enabled`]). pub(crate) fn oh_tier_supports_vision(model: &str) -> bool { use crate::openhuman::config::{ - MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_PRO_REASONING_V1, - MODEL_REASONING_QUICK_V1, MODEL_REASONING_V1, MODEL_SUMMARIZATION_V1, + MODEL_AGENTIC_V1, MODEL_CHAT_V1, MODEL_CODING_V1, MODEL_REASONING_QUICK_V1, + MODEL_REASONING_V1, MODEL_SUMMARIZATION_V1, }; match model { - MODEL_PRO_REASONING_V1 | "hint:pro-reasoning" => true, + MODEL_REASONING_V1 | "hint:reasoning" => true, MODEL_CHAT_V1 | "hint:chat" => false, - MODEL_REASONING_V1 | "hint:reasoning" => false, MODEL_REASONING_QUICK_V1 => false, MODEL_AGENTIC_V1 | "hint:agentic" => false, MODEL_CODING_V1 | "hint:coding" => false, @@ -232,12 +218,6 @@ pub(crate) fn oh_tier_supports_vision(model: &str) -> bool { /// migration 1→2 preserved the URL as a custom provider entry but older /// configs did not explicitly set per-workload routes. pub fn provider_for_role(role: &str, config: &Config) -> String { - // `pro-reasoning` is always managed: it has no per-workload config knob and - // must never inherit a BYOK/cloud provider (or `primary_cloud`). Force the - // OpenHuman backend before any inheritance/fallback logic runs. - if role == "pro-reasoning" { - return PROVIDER_OPENHUMAN.to_string(); - } let opt = match role { "chat" => config.chat_provider.as_deref(), "reasoning" => config.reasoning_provider.as_deref(), @@ -750,7 +730,6 @@ fn make_openhuman_backend(config: &Config) -> anyhow::Result<(Box, // "deepseek-v4-pro", "claude-opus-4-7") fall back to the platform default. let model = match model.strip_prefix("hint:") { Some("reasoning") => crate::openhuman::config::MODEL_REASONING_V1.to_string(), - Some("pro-reasoning") => crate::openhuman::config::MODEL_PRO_REASONING_V1.to_string(), Some("chat") => crate::openhuman::config::MODEL_CHAT_V1.to_string(), Some("agentic") => crate::openhuman::config::MODEL_AGENTIC_V1.to_string(), Some("coding") => crate::openhuman::config::MODEL_CODING_V1.to_string(), diff --git a/src/openhuman/inference/provider/factory_tests.rs b/src/openhuman/inference/provider/factory_tests.rs index abb4bd3fa..59af93d57 100644 --- a/src/openhuman/inference/provider/factory_tests.rs +++ b/src/openhuman/inference/provider/factory_tests.rs @@ -830,7 +830,6 @@ fn lookup_key_for_slug_routes_openai_oauth_lookup_path() { fn known_tiers_pass() { for tier in [ "reasoning-v1", - "pro-reasoning-v1", "chat-v1", "agentic-v1", "coding-v1", @@ -847,7 +846,6 @@ fn known_tiers_pass() { #[test] fn known_hints_pass() { assert!(is_known_openhuman_tier("hint:reasoning")); - assert!(is_known_openhuman_tier("hint:pro-reasoning")); assert!(is_known_openhuman_tier("hint:chat")); assert!(is_known_openhuman_tier("hint:agentic")); assert!(is_known_openhuman_tier("hint:coding")); @@ -872,18 +870,20 @@ fn invalid_models_fail() { // ── oh_tier_supports_vision ────────────────────────────────────────────────────── #[test] -fn no_managed_tier_is_vision_capable_yet() { - // Every managed tier (and its hint form) is non-vision until confirmed +fn reasoning_is_the_vision_capable_managed_tier() { + // `reasoning-v1` (and its hint form) is the one vision-capable managed tier. + assert!(oh_tier_supports_vision("reasoning-v1")); + assert!(oh_tier_supports_vision("hint:reasoning")); + + // Every other managed tier (and its hint form) is non-vision until confirmed // multimodal on the backend. Flip the corresponding arm in // `oh_tier_supports_vision` to enable one. for model in [ - "reasoning-v1", "chat-v1", "agentic-v1", "coding-v1", "reasoning-quick-v1", "summarization-v1", - "hint:reasoning", "hint:chat", "hint:agentic", "hint:coding", @@ -903,45 +903,6 @@ fn unknown_models_are_not_vision_capable() { assert!(!oh_tier_supports_vision("")); } -#[test] -fn pro_reasoning_is_vision_capable() { - assert!(oh_tier_supports_vision("pro-reasoning-v1")); - assert!(oh_tier_supports_vision("hint:pro-reasoning")); -} - -#[test] -fn pro_reasoning_is_classified_as_abstract_tier() { - // Must be detected as an abstract managed tier alongside the others so - // custom/BYOK routes remap/reject it instead of forwarding it as a - // provider-native model id. - assert!(is_abstract_tier_model("pro-reasoning-v1")); - assert!(is_abstract_tier_model(" pro-reasoning-v1 ")); -} - -// ── pro-reasoning is always managed ────────────────────────────────────────── - -#[test] -fn pro_reasoning_role_forces_openhuman_even_with_byok_chat() { - // pro-reasoning has no per-workload knob and must never inherit the user's - // BYOK chat provider — `provider_for_role` forces the managed backend. - let mut config = Config::default(); - config.chat_provider = Some("openai:gpt-5".to_string()); - config.reasoning_provider = Some("openai:gpt-5".to_string()); - assert_eq!(provider_for_role("pro-reasoning", &config), "openhuman"); -} - -#[test] -fn pro_reasoning_hint_resolves_to_managed_tier_despite_byok() { - // Even with a BYOK chat provider configured, resolving the pro-reasoning - // hint yields the managed tier id (not the BYOK model). - let mut config = Config::default(); - config.chat_provider = Some("openai:gpt-5".to_string()); - assert_eq!( - resolve_model_for_hint("hint:pro-reasoning", &config), - "pro-reasoning-v1" - ); -} - #[test] fn make_openhuman_backend_forwards_unknown_hint_verbatim() { // Unrecognised hint:* strings (e.g. hint:reaction for lightweight models)