mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
feat(chat): make reasoning-v1 vision-capable; remove pro-reasoning tier (#3545)
This commit is contained in:
@@ -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': 'الأدوات المسموح بها',
|
||||
|
||||
@@ -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': 'অনুমোদিত টুল',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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': 'अनुमत उपकरण',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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': '허용된 도구',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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': 'Разрешенные инструменты',
|
||||
|
||||
@@ -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': '允许使用的工具',
|
||||
|
||||
@@ -1574,19 +1574,6 @@ const Conversations = ({
|
||||
}`}>
|
||||
{t('chat.agentProfile.reasoning')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
role="radio"
|
||||
aria-checked={selectedAgentProfileId === 'pro-reasoning'}
|
||||
data-analytics-id="chat-header-mode-pro-reasoning"
|
||||
onClick={() => void handleSelectAgentProfile('pro-reasoning')}
|
||||
className={`px-2.5 py-0.5 rounded-full text-xs font-medium transition-all ${
|
||||
selectedAgentProfileId === 'pro-reasoning'
|
||||
? 'bg-white dark:bg-neutral-600 text-stone-800 dark:text-neutral-100 shadow-sm'
|
||||
: 'text-stone-500 dark:text-neutral-400 hover:text-stone-700 dark:hover:text-neutral-200'
|
||||
}`}>
|
||||
{t('chat.agentProfile.proReasoning')}
|
||||
</button>
|
||||
</div>
|
||||
{(selectedThreadId ?? activeThreadId) && (
|
||||
<ChatFilesChip threadId={(selectedThreadId ?? activeThreadId) as string} />
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<dyn Provider>, String) =
|
||||
|
||||
@@ -382,25 +382,6 @@ pub fn built_in_profiles() -> Vec<AgentProfile> {
|
||||
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(),
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -150,8 +150,8 @@ impl Default for CostConfig {
|
||||
/// Default pricing for popular models (USD per 1M tokens)
|
||||
fn get_default_pricing() -> HashMap<String, ModelPricing> {
|
||||
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<String, ModelPricing> {
|
||||
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(),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<u64> {
|
||||
|
||||
fn tier_context_window(model: &str) -> Option<u64> {
|
||||
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));
|
||||
|
||||
@@ -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<dyn Provider>,
|
||||
// "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(),
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user