// Package persona owns the bot's identity and the system prompt the LLM // sees. The full prompt text lives in the YAML's `system_prompt` field // (long, freeform, hand-tuned for the deployment). This package only // adds the RAG context after it. package persona import ( "github.com/VictorVargas/rony-llm-agent/pkg/persona" "github.com/VictorVargas/rony-chat-bot/internal/config" ) // FromConfig returns a minimal persona used only for the UI greeting and // the SSE event metadata. The system prompt itself comes from // config.SystemPrompt, not from this struct — see BuildSystemPrompt. func FromConfig(c *config.Config) (persona.Persona, error) { lang := c.Persona.Language if lang == "" { lang = "the user's language" } return persona.Persona{ ID: "rony", Name: c.Persona.Name, Tone: c.Persona.Tone, Language: lang, }, nil } // BuildSystemPrompt returns the full prompt for one chat turn: // 1. The hand-written system prompt from the YAML (who Rony is, how to speak) // 2. The RAG block (omitted when the index returns no hits) // // The RAG block is appended, not prepended, so the persona instructions // always come first and the LLM never gets the chance to "forget" them. func BuildSystemPrompt(systemPrompt, ragContext string) string { out := systemPrompt if ragContext != "" { out += "\n\n## Relevant context from the portfolio\n\n" + "Use these excerpts to answer. Cite the project filename when you reference a detail. " + "If the excerpts don't contain the answer, say you don't have that information — do not invent.\n\n" + ragContext } return out }