rony-chat-bot/internal/persona/persona.go

44 lines
1.6 KiB
Go
Raw Normal View History

// 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
}