feat: add custom system prompt support to LLM utility

- Allow passing full system prompts (>100 chars) or personality IDs
- Auto-detect prompt type based on length
- Pass custom prompts through provider chain with retry logic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2025-12-04 03:16:13 -08:00
parent ee0e34c5bf
commit 53a7e11e4c
1 changed files with 37 additions and 17 deletions

View File

@ -6,7 +6,7 @@ import { getRunPodConfig, getRunPodTextConfig, getOllamaConfig } from "@/lib/cli
export async function llm( export async function llm(
userPrompt: string, userPrompt: string,
onToken: (partialResponse: string, done?: boolean) => void, onToken: (partialResponse: string, done?: boolean) => void,
customPersonality?: string, customSystemPromptOrPersonality?: string,
) { ) {
// Validate the callback function // Validate the callback function
if (typeof onToken !== 'function') { if (typeof onToken !== 'function') {
@ -46,9 +46,19 @@ export async function llm(
}; };
} }
// Override personality if custom personality is provided // Check if custom system prompt or personality is provided
if (customPersonality) { // If it looks like a full system prompt (long text), store it for direct use
settings.personality = customPersonality; // If it looks like a personality ID (short), look it up from AI_PERSONALITIES
let customSystemPrompt: string | null = null;
if (customSystemPromptOrPersonality) {
// If it's longer than 100 chars, treat it as a full system prompt
// Personality IDs are short like "web-developer", "creative-writer", etc.
if (customSystemPromptOrPersonality.length > 100) {
customSystemPrompt = customSystemPromptOrPersonality;
} else {
// It's a personality ID - look it up
settings.personality = customSystemPromptOrPersonality;
}
} }
const availableKeys = settings.keys || {} const availableKeys = settings.keys || {}
@ -89,7 +99,7 @@ export async function llm(
attemptedProviders.push(`${provider} (${model})`); attemptedProviders.push(`${provider} (${model})`);
// Add retry logic for temporary failures // Add retry logic for temporary failures
await callProviderAPIWithRetry(provider, apiKey, model, userPrompt, onToken, settings, endpointId); await callProviderAPIWithRetry(provider, apiKey, model, userPrompt, onToken, settings, endpointId, customSystemPrompt);
console.log(`✅ Successfully used ${provider} API (${model})`); console.log(`✅ Successfully used ${provider} API (${model})`);
return; // Success, exit the function return; // Success, exit the function
} catch (error) { } catch (error) {
@ -109,7 +119,7 @@ export async function llm(
attemptedProviders.push(`${provider} (${fallbackModel})`); attemptedProviders.push(`${provider} (${fallbackModel})`);
const providerInfo = availableProviders.find(p => p.provider === provider); const providerInfo = availableProviders.find(p => p.provider === provider);
const endpointId = (providerInfo as any)?.endpointId; const endpointId = (providerInfo as any)?.endpointId;
await callProviderAPIWithRetry(provider, apiKey, fallbackModel, userPrompt, onToken, settings, endpointId); await callProviderAPIWithRetry(provider, apiKey, fallbackModel, userPrompt, onToken, settings, endpointId, customSystemPrompt);
console.log(`✅ Successfully used ${provider} API with fallback model ${fallbackModel}`); console.log(`✅ Successfully used ${provider} API with fallback model ${fallbackModel}`);
fallbackSucceeded = true; fallbackSucceeded = true;
return; // Success, exit the function return; // Success, exit the function
@ -424,20 +434,21 @@ function isValidApiKey(provider: string, apiKey: string): boolean {
// Helper function to call API with retry logic // Helper function to call API with retry logic
async function callProviderAPIWithRetry( async function callProviderAPIWithRetry(
provider: string, provider: string,
apiKey: string, apiKey: string,
model: string, model: string,
userPrompt: string, userPrompt: string,
onToken: (partialResponse: string, done?: boolean) => void, onToken: (partialResponse: string, done?: boolean) => void,
settings?: any, settings?: any,
endpointId?: string, endpointId?: string,
customSystemPrompt?: string | null,
maxRetries: number = 2 maxRetries: number = 2
) { ) {
let lastError: Error | null = null; let lastError: Error | null = null;
for (let attempt = 1; attempt <= maxRetries; attempt++) { for (let attempt = 1; attempt <= maxRetries; attempt++) {
try { try {
await callProviderAPI(provider, apiKey, model, userPrompt, onToken, settings, endpointId); await callProviderAPI(provider, apiKey, model, userPrompt, onToken, settings, endpointId, customSystemPrompt);
return; // Success return; // Success
} catch (error) { } catch (error) {
lastError = error as Error; lastError = error as Error;
@ -525,16 +536,25 @@ function getSystemPrompt(settings: any): string {
// Helper function to call the appropriate provider API // Helper function to call the appropriate provider API
async function callProviderAPI( async function callProviderAPI(
provider: string, provider: string,
apiKey: string, apiKey: string,
model: string, model: string,
userPrompt: string, userPrompt: string,
onToken: (partialResponse: string, done?: boolean) => void, onToken: (partialResponse: string, done?: boolean) => void,
settings?: any, settings?: any,
endpointId?: string endpointId?: string,
customSystemPrompt?: string | null
) { ) {
let partial = ""; let partial = "";
const systemPrompt = settings ? getSystemPrompt(settings) : 'You are a helpful assistant.'; // Use custom system prompt if provided, otherwise fall back to personality-based prompt
const systemPrompt = customSystemPrompt || (settings ? getSystemPrompt(settings) : 'You are a helpful assistant.');
// Debug: log which system prompt is being used
if (customSystemPrompt) {
console.log(`🧠 Using custom system prompt (${customSystemPrompt.length} chars)`);
} else {
console.log(`🧠 Using personality-based system prompt: ${settings?.personality || 'default'}`);
}
if (provider === 'ollama') { if (provider === 'ollama') {
// Ollama API integration via AI Orchestrator // Ollama API integration via AI Orchestrator