From 355166c194a163687eb5bc99f41874380d9bfb88 Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Thu, 7 May 2026 04:15:31 +0200 Subject: [PATCH] =?UTF-8?q?feat(sos):=20tier-based=20LLM-Default=20?= =?UTF-8?q?=E2=80=94=20Free/Pro=3DGroq,=20Legend=3DHaiku?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend (sos-stream.get.ts): wenn sessionData.llmProvider === 'auto' oder undefined, resolved zu plan-based default via profile.plan: - legend → openrouter-haiku (Anthropic warm + sort:latency) - pro/free → groq-llama (sachlich + schnell, ~157ms TTFB) Frontend (llmProvider.ts): DEFAULT_PROVIDER = 'auto', neue Pill 'Auto' in LlmProviderToggle. Explicit-Toggles (Sonnet/Haiku/Groq) sind debug-overrides die plan-logic bypassen. --- .../components/urge/LlmProviderToggle.tsx | 2 +- apps/rebreak-native/lib/llmProvider.ts | 11 ++++++++--- backend/server/api/coach/sos-stream.get.ts | 12 +++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/rebreak-native/components/urge/LlmProviderToggle.tsx b/apps/rebreak-native/components/urge/LlmProviderToggle.tsx index d921a6a..ff7f968 100644 --- a/apps/rebreak-native/components/urge/LlmProviderToggle.tsx +++ b/apps/rebreak-native/components/urge/LlmProviderToggle.tsx @@ -1,7 +1,7 @@ import { Pressable, Text, View } from 'react-native'; import { LLM_PROVIDER_LABEL, type LlmProvider, useLlmProvider } from '../../lib/llmProvider'; -const PROVIDERS: LlmProvider[] = ['openrouter-sonnet', 'openrouter-haiku', 'groq-llama']; +const PROVIDERS: LlmProvider[] = ['auto', 'openrouter-sonnet', 'openrouter-haiku', 'groq-llama']; export function LlmProviderToggle() { const [current, set] = useLlmProvider(); diff --git a/apps/rebreak-native/lib/llmProvider.ts b/apps/rebreak-native/lib/llmProvider.ts index 8ad44b8..3fb32ba 100644 --- a/apps/rebreak-native/lib/llmProvider.ts +++ b/apps/rebreak-native/lib/llmProvider.ts @@ -6,12 +6,15 @@ import AsyncStorage from '@react-native-async-storage/async-storage'; import { useEffect, useState } from 'react'; -export type LlmProvider = 'openrouter-sonnet' | 'openrouter-haiku' | 'groq-llama'; +export type LlmProvider = 'auto' | 'openrouter-sonnet' | 'openrouter-haiku' | 'groq-llama'; const STORAGE_KEY = 'rebreak-sos-llm-provider'; -const DEFAULT_PROVIDER: LlmProvider = 'openrouter-sonnet'; +// Default 'auto' → backend wählt nach plan: Pro=Groq, Legend=Haiku, Free=Groq. +// Explicit-Toggles (Sonnet/Haiku/Groq) sind debug-overrides und bypassen plan-logic. +const DEFAULT_PROVIDER: LlmProvider = 'auto'; export const LLM_PROVIDER_LABEL: Record = { + auto: 'Auto', 'openrouter-sonnet': 'Sonnet', 'openrouter-haiku': 'Haiku', 'groq-llama': 'Groq', @@ -24,7 +27,9 @@ export async function loadLlmProvider(): Promise { if (cached) return cached; const raw = await AsyncStorage.getItem(STORAGE_KEY).catch(() => null); cached = - raw === 'openrouter-haiku' || raw === 'groq-llama' ? raw : DEFAULT_PROVIDER; + raw === 'auto' || raw === 'openrouter-sonnet' || raw === 'openrouter-haiku' || raw === 'groq-llama' + ? raw + : DEFAULT_PROVIDER; return cached; } diff --git a/backend/server/api/coach/sos-stream.get.ts b/backend/server/api/coach/sos-stream.get.ts index 8dad30f..94f94ef 100644 --- a/backend/server/api/coach/sos-stream.get.ts +++ b/backend/server/api/coach/sos-stream.get.ts @@ -152,7 +152,17 @@ export default defineEventHandler(async (event) => { // LLM-Routing: client schickt llmProvider via /sos-session-Body (Toggle). // Default openrouter-sonnet. sort:latency bei Anthropic über OR spart 30-58% TTFB // (server-curl-bench gemessen). Groq bypasst OpenRouter-Hop für ~157ms TTFB. - const llmProvider = sessionData.llmProvider ?? "openrouter-sonnet"; + // Tier-based LLM: Pro=Groq (sachlich+schnell), Legend=Haiku 4.5 (warm+fast), + // Free=Groq (kostenkontrolle). User kann via Toggle override (debug); + // 'auto' (oder undefined) → plan-based default. + const userToggle = sessionData.llmProvider; + let llmProvider: string; + if (userToggle && userToggle !== "auto") { + llmProvider = userToggle; + } else { + const plan = ((profile as any)?.plan ?? "free").toLowerCase(); + llmProvider = plan === "legend" ? "openrouter-haiku" : "groq-llama"; + } let upstreamUrl: string; let upstreamKey: string | undefined; let upstreamModel: string;