| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import { applyLearnedAdjustments } from './autotune-feedback' |
| | import type { LearnedProfile } from './autotune-feedback' |
| |
|
| | |
| |
|
| | export type AutoTuneStrategy = 'precise' | 'balanced' | 'creative' | 'chaotic' | 'adaptive' |
| |
|
| | export interface AutoTuneParams { |
| | temperature: number |
| | top_p: number |
| | top_k: number |
| | frequency_penalty: number |
| | presence_penalty: number |
| | repetition_penalty: number |
| | } |
| |
|
| | export interface ContextScore { |
| | type: ContextType |
| | score: number |
| | percentage: number |
| | } |
| |
|
| | export interface PatternMatch { |
| | pattern: string |
| | source: 'current' | 'history' |
| | } |
| |
|
| | export interface ParamDelta { |
| | param: keyof AutoTuneParams |
| | before: number |
| | after: number |
| | delta: number |
| | reason: string |
| | } |
| |
|
| | export interface AutoTuneResult { |
| | params: AutoTuneParams |
| | detectedContext: ContextType |
| | confidence: number |
| | reasoning: string |
| | |
| | contextScores: ContextScore[] |
| | patternMatches: PatternMatch[] |
| | paramDeltas: ParamDelta[] |
| | baselineParams: AutoTuneParams |
| | } |
| |
|
| | export type ContextType = 'code' | 'creative' | 'analytical' | 'conversational' | 'chaotic' |
| |
|
| | |
| |
|
| | export const STRATEGY_PROFILES: Record<Exclude<AutoTuneStrategy, 'adaptive'>, AutoTuneParams> = { |
| | precise: { |
| | temperature: 0.2, |
| | top_p: 0.85, |
| | top_k: 30, |
| | frequency_penalty: 0.3, |
| | presence_penalty: 0.1, |
| | repetition_penalty: 1.1 |
| | }, |
| | balanced: { |
| | temperature: 0.7, |
| | top_p: 0.9, |
| | top_k: 50, |
| | frequency_penalty: 0.1, |
| | presence_penalty: 0.1, |
| | repetition_penalty: 1.0 |
| | }, |
| | creative: { |
| | temperature: 1.1, |
| | top_p: 0.95, |
| | top_k: 80, |
| | frequency_penalty: 0.4, |
| | presence_penalty: 0.6, |
| | repetition_penalty: 1.15 |
| | }, |
| | chaotic: { |
| | temperature: 1.6, |
| | top_p: 0.98, |
| | top_k: 100, |
| | frequency_penalty: 0.7, |
| | presence_penalty: 0.8, |
| | repetition_penalty: 1.25 |
| | } |
| | } |
| |
|
| | |
| |
|
| | const CONTEXT_PATTERNS: Record<ContextType, RegExp[]> = { |
| | code: [ |
| | /\b(code|function|class|variable|bug|error|debug|compile|syntax|api|endpoint|regex|algorithm|refactor|typescript|javascript|python|rust|html|css|sql|json|xml|import|export|return|async|await|promise|interface|type|const|let|var)\b/i, |
| | /```[\s\S]*```/, |
| | /\b(fix|implement|write|create|build|deploy|test|unit test|lint|npm|pip|cargo|git)\b.*\b(code|function|app|service|component|module)\b/i, |
| | /[{}();=><]/, |
| | /\b(stack overflow|github|repo|pull request|commit|merge)\b/i |
| | ], |
| | creative: [ |
| | /\b(write|story|poem|creative|imagine|fiction|narrative|character|plot|scene|dialogue|metaphor|lyrics|song|artistic|fantasy|dream|inspire|muse|prose|verse|haiku)\b/i, |
| | /\b(describe|paint|envision|portray|illustrate|craft)\b.*\b(world|scene|character|feeling|emotion|atmosphere)\b/i, |
| | /\b(roleplay|role-play|pretend|act as|you are a)\b/i, |
| | /\b(brainstorm|ideate|come up with|think of|generate ideas)\b/i |
| | ], |
| | analytical: [ |
| | /\b(analyze|analysis|compare|contrast|evaluate|assess|examine|investigate|research|study|review|critique|breakdown|data|statistics|metrics|benchmark|measure)\b/i, |
| | /\b(pros and cons|advantages|disadvantages|trade-?offs|implications|consequences)\b/i, |
| | /\b(why|how does|what causes|explain|elaborate|clarify|define|summarize|overview)\b/i, |
| | /\b(report|document|technical|specification|architecture|diagram|whitepaper)\b/i |
| | ], |
| | conversational: [ |
| | /\b(hey|hi|hello|sup|what's up|how are you|thanks|thank you|cool|nice|awesome|great|lol|haha)\b/i, |
| | /\b(chat|talk|tell me about|what do you think|opinion|feel|believe)\b/i, |
| | /^.{0,30}$/ |
| | ], |
| | chaotic: [ |
| | /\b(chaos|random|wild|crazy|absurd|surreal|glitch|corrupt|break|destroy|unleash|madness|void|entropy)\b/i, |
| | /[zΜ·aΜΈlΜ΅gΜΆoΜ·]/, |
| | /\b(gl1tch|h4ck|pwn|1337|l33t)\b/i, |
| | /(!{3,}|\?{3,}|\.{4,})/ |
| | ] |
| | } |
| |
|
| | |
| |
|
| | const CONTEXT_PROFILE_MAP: Record<ContextType, AutoTuneParams> = { |
| | code: { |
| | temperature: 0.15, |
| | top_p: 0.8, |
| | top_k: 25, |
| | frequency_penalty: 0.2, |
| | presence_penalty: 0.0, |
| | repetition_penalty: 1.05 |
| | }, |
| | creative: { |
| | temperature: 1.15, |
| | top_p: 0.95, |
| | top_k: 85, |
| | frequency_penalty: 0.5, |
| | presence_penalty: 0.7, |
| | repetition_penalty: 1.2 |
| | }, |
| | analytical: { |
| | temperature: 0.4, |
| | top_p: 0.88, |
| | top_k: 40, |
| | frequency_penalty: 0.2, |
| | presence_penalty: 0.15, |
| | repetition_penalty: 1.08 |
| | }, |
| | conversational: { |
| | temperature: 0.75, |
| | top_p: 0.9, |
| | top_k: 50, |
| | frequency_penalty: 0.1, |
| | presence_penalty: 0.1, |
| | repetition_penalty: 1.0 |
| | }, |
| | chaotic: { |
| | temperature: 1.7, |
| | top_p: 0.99, |
| | top_k: 100, |
| | frequency_penalty: 0.8, |
| | presence_penalty: 0.9, |
| | repetition_penalty: 1.3 |
| | } |
| | } |
| |
|
| |
|
| | |
| |
|
| | interface DetectionResult { |
| | type: ContextType |
| | confidence: number |
| | allScores: ContextScore[] |
| | patternMatches: PatternMatch[] |
| | } |
| |
|
| | |
| | |
| | |
| | function describePattern(pattern: RegExp): string { |
| | const source = pattern.source |
| | |
| | const wordMatch = source.match(/\\b\(([^)]+)\)\\b/i) |
| | if (wordMatch) { |
| | const words = wordMatch[1].split('|').slice(0, 3) |
| | return words.join(', ') + (wordMatch[1].split('|').length > 3 ? '...' : '') |
| | } |
| | if (source.includes('```')) return 'code blocks' |
| | if (source.includes('[{}();=><]')) return 'code syntax' |
| | if (source.includes('^.{0,30}$')) return 'short message' |
| | if (source.includes('!{3,}')) return 'excessive punctuation' |
| | return pattern.source.slice(0, 20) + '...' |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | function detectContext( |
| | message: string, |
| | conversationHistory: { role: string; content: string }[] |
| | ): DetectionResult { |
| | const scores: Record<ContextType, number> = { |
| | code: 0, |
| | creative: 0, |
| | analytical: 0, |
| | conversational: 0, |
| | chaotic: 0 |
| | } |
| |
|
| | const patternMatches: PatternMatch[] = [] |
| |
|
| | |
| | for (const [context, patterns] of Object.entries(CONTEXT_PATTERNS)) { |
| | for (const pattern of patterns) { |
| | if (pattern.test(message)) { |
| | scores[context as ContextType] += 3 |
| | patternMatches.push({ |
| | pattern: `${context.toUpperCase()}: ${describePattern(pattern)}`, |
| | source: 'current' |
| | }) |
| | } |
| | } |
| | } |
| |
|
| | |
| | const recentMessages = conversationHistory.slice(-4) |
| | for (const msg of recentMessages) { |
| | for (const [context, patterns] of Object.entries(CONTEXT_PATTERNS)) { |
| | for (const pattern of patterns) { |
| | if (pattern.test(msg.content)) { |
| | scores[context as ContextType] += 1 |
| | |
| | if (patternMatches.filter(p => p.source === 'history').length < 3) { |
| | patternMatches.push({ |
| | pattern: `${context.toUpperCase()}: ${describePattern(pattern)}`, |
| | source: 'history' |
| | }) |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | const entries = Object.entries(scores) as [ContextType, number][] |
| | const total = entries.reduce((sum, [, score]) => sum + score, 0) |
| |
|
| | |
| | const allScores: ContextScore[] = entries |
| | .map(([type, score]) => ({ |
| | type, |
| | score, |
| | percentage: total > 0 ? Math.round((score / total) * 100) : 0 |
| | })) |
| | .sort((a, b) => b.score - a.score) |
| |
|
| | const bestType = allScores[0].type |
| | const confidence = total > 0 ? allScores[0].score / total : 0 |
| |
|
| | |
| | if (total === 0) { |
| | return { |
| | type: 'conversational', |
| | confidence: 0.5, |
| | allScores: [ |
| | { type: 'conversational', score: 1, percentage: 100 }, |
| | { type: 'code', score: 0, percentage: 0 }, |
| | { type: 'creative', score: 0, percentage: 0 }, |
| | { type: 'analytical', score: 0, percentage: 0 }, |
| | { type: 'chaotic', score: 0, percentage: 0 } |
| | ], |
| | patternMatches: [{ pattern: 'DEFAULT: no patterns matched', source: 'current' }] |
| | } |
| | } |
| |
|
| | return { |
| | type: bestType, |
| | confidence: Math.min(confidence, 1.0), |
| | allScores, |
| | patternMatches |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | function generateReasoning( |
| | strategy: AutoTuneStrategy, |
| | context: ContextType, |
| | confidence: number, |
| | conversationLength: number |
| | ): string { |
| | const contextLabels: Record<ContextType, string> = { |
| | code: 'programming/technical', |
| | creative: 'creative/generative', |
| | analytical: 'analytical/research', |
| | conversational: 'casual conversation', |
| | chaotic: 'chaotic/experimental' |
| | } |
| |
|
| | if (strategy !== 'adaptive') { |
| | return `Strategy: ${strategy.toUpperCase()} | Fixed profile applied` |
| | } |
| |
|
| | const parts = [ |
| | `Detected: ${contextLabels[context]} (${Math.round(confidence * 100)}% confidence)`, |
| | ] |
| |
|
| | if (conversationLength > 10) { |
| | parts.push('Long conversation: +repetition penalty') |
| | } |
| |
|
| | return parts.join(' | ') |
| | } |
| |
|
| | |
| | |
| | |
| | function clamp(value: number, min: number, max: number): number { |
| | return Math.min(Math.max(value, min), max) |
| | } |
| |
|
| | |
| | |
| | |
| | function applyBounds(params: AutoTuneParams): AutoTuneParams { |
| | return { |
| | temperature: clamp(params.temperature, 0.0, 2.0), |
| | top_p: clamp(params.top_p, 0.0, 1.0), |
| | top_k: clamp(Math.round(params.top_k), 1, 100), |
| | frequency_penalty: clamp(params.frequency_penalty, -2.0, 2.0), |
| | presence_penalty: clamp(params.presence_penalty, -2.0, 2.0), |
| | repetition_penalty: clamp(params.repetition_penalty, 0.0, 2.0) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | function blendParams(a: AutoTuneParams, b: AutoTuneParams, weight: number): AutoTuneParams { |
| | const w = clamp(weight, 0, 1) |
| | const iw = 1 - w |
| | return { |
| | temperature: a.temperature * iw + b.temperature * w, |
| | top_p: a.top_p * iw + b.top_p * w, |
| | top_k: Math.round(a.top_k * iw + b.top_k * w), |
| | frequency_penalty: a.frequency_penalty * iw + b.frequency_penalty * w, |
| | presence_penalty: a.presence_penalty * iw + b.presence_penalty * w, |
| | repetition_penalty: a.repetition_penalty * iw + b.repetition_penalty * w |
| | } |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | export function computeAutoTuneParams(options: { |
| | strategy: AutoTuneStrategy |
| | message: string |
| | conversationHistory: { role: string; content: string }[] |
| | overrides?: Partial<AutoTuneParams> |
| | learnedProfiles?: Record<ContextType, LearnedProfile> |
| | }): AutoTuneResult { |
| | const { strategy, message, conversationHistory, overrides, learnedProfiles } = options |
| |
|
| | let baseParams: AutoTuneParams |
| | let detectedContext: ContextType = 'conversational' |
| | let confidence = 1.0 |
| | let contextScores: ContextScore[] = [] |
| | let patternMatches: PatternMatch[] = [] |
| |
|
| | |
| | const strategyBaseline = strategy === 'adaptive' |
| | ? STRATEGY_PROFILES.balanced |
| | : STRATEGY_PROFILES[strategy] |
| | const baselineParams: AutoTuneParams = { ...strategyBaseline } |
| |
|
| | |
| | const paramDeltas: ParamDelta[] = [] |
| |
|
| | if (strategy === 'adaptive') { |
| | |
| | const detection = detectContext(message, conversationHistory) |
| | detectedContext = detection.type |
| | confidence = detection.confidence |
| | contextScores = detection.allScores |
| | patternMatches = detection.patternMatches |
| |
|
| | |
| | if (confidence < 0.6) { |
| | baseParams = blendParams( |
| | CONTEXT_PROFILE_MAP[detectedContext], |
| | STRATEGY_PROFILES.balanced, |
| | 1 - confidence |
| | ) |
| | } else { |
| | baseParams = { ...CONTEXT_PROFILE_MAP[detectedContext] } |
| | } |
| |
|
| | |
| | for (const key of Object.keys(baselineParams) as (keyof AutoTuneParams)[]) { |
| | const before = baselineParams[key] |
| | const after = baseParams[key] |
| | if (Math.abs(after - before) > 0.001) { |
| | paramDeltas.push({ |
| | param: key, |
| | before, |
| | after, |
| | delta: after - before, |
| | reason: `${getContextLabel(detectedContext)} context` |
| | }) |
| | } |
| | } |
| | } else { |
| | baseParams = { ...STRATEGY_PROFILES[strategy] } |
| | |
| | contextScores = [{ type: detectedContext, score: 1, percentage: 100 }] |
| | patternMatches = [{ pattern: `FIXED: ${strategy.toUpperCase()} strategy`, source: 'current' }] |
| | } |
| |
|
| | |
| | const convLength = conversationHistory.length |
| | if (convLength > 10) { |
| | const boost = Math.min((convLength - 10) * 0.01, 0.15) |
| | const repBefore = baseParams.repetition_penalty |
| | const freqBefore = baseParams.frequency_penalty |
| |
|
| | baseParams.repetition_penalty += boost |
| | baseParams.frequency_penalty += boost * 0.5 |
| |
|
| | paramDeltas.push({ |
| | param: 'repetition_penalty', |
| | before: repBefore, |
| | after: baseParams.repetition_penalty, |
| | delta: boost, |
| | reason: `long conversation (${convLength} msgs)` |
| | }) |
| | paramDeltas.push({ |
| | param: 'frequency_penalty', |
| | before: freqBefore, |
| | after: baseParams.frequency_penalty, |
| | delta: boost * 0.5, |
| | reason: `long conversation (${convLength} msgs)` |
| | }) |
| | } |
| |
|
| | |
| | let learnedNote = '' |
| | if (learnedProfiles) { |
| | const beforeLearned = { ...baseParams } |
| | const learnedResult = applyLearnedAdjustments(baseParams, detectedContext, learnedProfiles) |
| | if (learnedResult.applied) { |
| | baseParams = learnedResult.params |
| | learnedNote = learnedResult.note |
| |
|
| | |
| | for (const key of Object.keys(beforeLearned) as (keyof AutoTuneParams)[]) { |
| | const before = beforeLearned[key] |
| | const after = baseParams[key] |
| | if (Math.abs(after - before) > 0.001) { |
| | paramDeltas.push({ |
| | param: key, |
| | before, |
| | after, |
| | delta: after - before, |
| | reason: 'learned from feedback' |
| | }) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | if (overrides) { |
| | for (const [key, value] of Object.entries(overrides)) { |
| | if (value !== undefined && value !== null) { |
| | const k = key as keyof AutoTuneParams |
| | const before = baseParams[k] |
| | ;(baseParams as any)[key] = value |
| |
|
| | paramDeltas.push({ |
| | param: k, |
| | before, |
| | after: value as number, |
| | delta: (value as number) - before, |
| | reason: 'manual override' |
| | }) |
| | } |
| | } |
| | } |
| |
|
| | |
| | const finalParams = applyBounds(baseParams) |
| |
|
| | let reasoning = generateReasoning( |
| | strategy, |
| | detectedContext, |
| | confidence, |
| | convLength |
| | ) |
| |
|
| | if (learnedNote) { |
| | reasoning += ` | ${learnedNote}` |
| | } |
| |
|
| | return { |
| | params: finalParams, |
| | detectedContext, |
| | confidence, |
| | reasoning, |
| | |
| | contextScores, |
| | patternMatches, |
| | paramDeltas, |
| | baselineParams |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | export function getContextLabel(context: ContextType): string { |
| | const labels: Record<ContextType, string> = { |
| | code: 'CODE', |
| | creative: 'CREATIVE', |
| | analytical: 'ANALYTICAL', |
| | conversational: 'CHAT', |
| | chaotic: 'CHAOS' |
| | } |
| | return labels[context] |
| | } |
| |
|
| | |
| | |
| | |
| | export function getStrategyLabel(strategy: AutoTuneStrategy): string { |
| | const labels: Record<AutoTuneStrategy, string> = { |
| | precise: 'PRECISE', |
| | balanced: 'BALANCED', |
| | creative: 'CREATIVE', |
| | chaotic: 'CHAOTIC', |
| | adaptive: 'ADAPTIVE' |
| | } |
| | return labels[strategy] |
| | } |
| |
|
| | |
| | |
| | |
| | export function getStrategyDescription(strategy: AutoTuneStrategy): string { |
| | const descriptions: Record<AutoTuneStrategy, string> = { |
| | precise: 'Low temperature, tight sampling. Optimal for code, math, and factual queries.', |
| | balanced: 'Well-rounded defaults. Good for general use.', |
| | creative: 'High temperature, diverse sampling. Ideal for writing, brainstorming, roleplay.', |
| | chaotic: 'Maximum entropy. Unpredictable, wild outputs. Use at your own risk.', |
| | adaptive: 'Analyzes your message context and automatically morphs between profiles.' |
| | } |
| | return descriptions[strategy] |
| | } |
| |
|
| | |
| | |
| | |
| | export const PARAM_META: Record<keyof AutoTuneParams, { |
| | label: string |
| | short: string |
| | min: number |
| | max: number |
| | step: number |
| | description: string |
| | }> = { |
| | temperature: { |
| | label: 'Temperature', |
| | short: 'TEMP', |
| | min: 0.0, |
| | max: 2.0, |
| | step: 0.05, |
| | description: 'Controls randomness. Lower = more deterministic, higher = more creative.' |
| | }, |
| | top_p: { |
| | label: 'Top P', |
| | short: 'TOP-P', |
| | min: 0.0, |
| | max: 1.0, |
| | step: 0.05, |
| | description: 'Nucleus sampling. Considers tokens within this cumulative probability.' |
| | }, |
| | top_k: { |
| | label: 'Top K', |
| | short: 'TOP-K', |
| | min: 1, |
| | max: 100, |
| | step: 1, |
| | description: 'Limits token selection to the top K most likely tokens.' |
| | }, |
| | frequency_penalty: { |
| | label: 'Frequency Penalty', |
| | short: 'FREQ', |
| | min: -2.0, |
| | max: 2.0, |
| | step: 0.05, |
| | description: 'Penalizes tokens based on how often they appear. Reduces repetition.' |
| | }, |
| | presence_penalty: { |
| | label: 'Presence Penalty', |
| | short: 'PRES', |
| | min: -2.0, |
| | max: 2.0, |
| | step: 0.05, |
| | description: 'Penalizes tokens that have already appeared. Encourages new topics.' |
| | }, |
| | repetition_penalty: { |
| | label: 'Repetition Penalty', |
| | short: 'REP', |
| | min: 0.0, |
| | max: 2.0, |
| | step: 0.05, |
| | description: 'Multiplicative penalty on repeated tokens. 1.0 = no penalty.' |
| | } |
| | } |
| |
|