Understanding the System Prompt Utility and Bot Customization in y-gui
The system prompt utility in y-gui centralizes default LLM instructions in backend/src/utils/system-prompt.ts and allows per-bot customization through the getSystemPrompt(botId) function, which injects the appropriate system message as the first entry in every chat completion request.
The y-gui repository (luohy15/y-gui) is a TypeScript-based chat interface that orchestrates multiple LLM providers. A core part of its architecture is the system prompt utility, which ensures every bot behaves according to a predefined personality or instruction set while still allowing individual overrides.
What Is the System Prompt Utility?
The utility is implemented in backend/src/utils/system-prompt.ts. It exports two primary pieces:
DEFAULT_PROMPTS– aRecord<string, string>that maps bot identifiers to their default system instructions.getSystemPrompt(botId: string)– a helper that looks up the bot ID in the map and returns the corresponding prompt string. If no entry exists, it returns a safe fallback (often an empty string or a generic assistant prompt).
// backend/src/utils/system-prompt.ts
export const DEFAULT_PROMPTS: Record<string, string> = {
generic: "You are a helpful assistant.",
codeAssistant: "You are an expert programmer. Answer with concise, runnable code.",
translator: "You are a translation expert. Translate between English and Chinese.",
};
export function getSystemPrompt(botId: string): string {
return DEFAULT_PROMPTS[botId] ?? DEFAULT_PROMPTS.generic;
}
How the System Prompt Flows Through the Architecture
The prompt travels through several layers before reaching the LLM. Below is the path from the HTTP request to the final API call.
Entry Point: Chat API
User messages hit backend/src/api/chat.ts. This route handler validates the request, extracts the botId, and delegates to the chat service.
// backend/src/api/chat.ts (simplified)
import { getSystemPrompt } from '@/backend/src/utils/system-prompt';
export async function POST(req: Request) {
const { botId, message } = await req.json();
const systemPrompt = getSystemPrompt(botId); // ← utility invoked here
// ... pass to chat service
}
Bot Resolution
Bot metadata (including optional overrides) lives in the repository layer, e.g., backend/src/repository/d1/bot-d1-repository.ts. Each bot record may contain a systemPrompt field. When the chat service loads a bot, it checks for this override.
// backend/src/repository/d1/bot-d1-repository.ts
export const CODE_BOT = {
id: "code-bot",
name: "Code Assistant",
model: "gpt-4o-mini",
systemPrompt: "You are a senior developer. Explain concepts clearly.",
// …other fields
};
Provider Factory Integration
backend/src/providers/provider-factory.ts instantiates the correct LLM client (OpenAI, Azure, etc.). During instantiation it receives the resolved system prompt and passes it down to the format provider.
// backend/src/providers/provider-factory.ts
import { getSystemPrompt } from '@/backend/src/utils/system-prompt';
export function createProvider(bot: BotConfig) {
const systemPrompt = bot.systemPrompt ?? getSystemPrompt(bot.id);
return new OpenAIFormatProvider({ ...bot, systemPrompt });
}
OpenAI Format Provider
backend/src/providers/openai-format-provider.ts assembles the final JSON payload. It inserts the system prompt as the first element of the messages array with role: "system".
// backend/src/providers/openai-format-provider.ts
export class OpenAIFormatProvider {
buildPayload(userMessage: string) {
return {
model: this.config.model,
messages: [
{ role: "system", content: this.config.systemPrompt },
{ role: "user", content: userMessage },
],
};
}
}
Customizing System Prompts for Different Bots
Default Prompts Map
Edit backend/src/utils/system-prompt.ts to change the global defaults. Adding a new key here makes that prompt available to any bot that does not define its own override.
// Add to DEFAULT_PROMPTS
const DEFAULT_PROMPTS: Record<string, string> = {
generic: "You are a helpful assistant.",
codeAssistant: "You are an expert programmer...",
translator: "You are a translation expert...",
// New entry
creativeWriter: "You are a creative writing coach. Be encouraging and detailed.",
};
Per-Bot Overrides
For one-off personalities, modify the bot record in the repository layer instead of the utility.
// backend/src/repository/d1/bot-d1-repository.ts
export const CREATIVE_BOT = {
id: "creative-bot",
name: "Creative Coach",
model: "gpt-4o",
systemPrompt: "You are a creative writing coach. Be encouraging and detailed.",
};
When creative-bot is requested, getSystemPrompt detects the override and returns the custom string, leaving the default map untouched.
Practical Implementation Examples
Example 1 – Using the default generic prompt
import { getSystemPrompt } from '@/backend/src/utils/system-prompt';
const botId = "generic-bot"; // no override defined
const systemMsg = getSystemPrompt(botId);
// Returns: "You are a helpful assistant."
Example 2 – Using a bot with a custom override
const botId = "code-bot"; // defined with systemPrompt override
const systemMsg = getSystemPrompt(botId);
// Returns: "You are a senior developer. Explain concepts clearly."
Example 3 – Adding a new default prompt without touching bot definitions
// In backend/src/utils/system-prompt.ts
DEFAULT_PROMPTS["dataAnalyst"] = "You are a data analyst. Provide insights in bullet points.";
// Usage anywhere in the app
const systemMsg = getSystemPrompt("dataAnalyst");
Summary
- The system prompt utility lives in
backend/src/utils/system-prompt.tsand exports aDEFAULT_PROMPTSmap plus thegetSystemPrompt(botId)helper. - Every chat request flows through
backend/src/api/chat.ts→ chat service → provider factory →getSystemPrompt, ensuring the correct system message is retrieved before the LLM call. - Customization happens at two levels:
- Global defaults – edit
DEFAULT_PROMPTSin the utility file to affect all bots that lack an override. - Per‑bot overrides – add a
systemPromptfield to a bot record inbackend/src/repository/d1/bot-d1-repository.ts(or similar) to tailor behavior for that specific bot.
- Global defaults – edit
- The
openai-format-provider.ts(and analogous providers) injects the resolved prompt as the firstrole: "system"message in the JSON payload sent to the LLM.
Frequently Asked Questions
Where is the system prompt utility defined in y-gui?
The utility is defined in backend/src/utils/system-prompt.ts. It exports the DEFAULT_PROMPTS record and the getSystemPrompt(botId: string) function that the rest of the application uses to retrieve the correct system message for any given bot.
How do I add a custom system prompt for a specific bot?
Open the relevant bot repository file (e.g., backend/src/repository/d1/bot-d1-repository.ts), locate the bot’s configuration object, and add a systemPrompt property with your desired text. When that bot is invoked, getSystemPrompt detects the override and returns your custom string instead of the default.
Can I override the default prompt without modifying the utility file?
Yes. You can create a new entry in the DEFAULT_PROMPTS map inside system-prompt.ts for a new bot ID, or you can supply a systemPrompt field directly in the bot’s definition. The latter approach keeps the utility file untouched and is the recommended way for one‑off customisations.
Which provider handles the injection of the system message?
The OpenAIFormatProvider (located in backend/src/providers/openai-format-provider.ts) is responsible for assembling the final API payload. It receives the system prompt from the provider factory and inserts it as the first element of the messages array with role: "system" before sending the request to the LLM.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →