# Understanding the System Prompt Utility and Bot Customization in y-gui

> Learn how the y-gui system prompt utility centralizes LLM instructions and enables per-bot customization. Discover how to tailor system prompts for your AI bots.

- Repository: [luohy15/y-gui](https://github.com/luohy15/y-gui)
- Tags: deep-dive
- Published: 2026-03-06

---

**The system prompt utility in y-gui centralizes default LLM instructions in [`backend/src/utils/system-prompt.ts`](https://github.com/luohy15/y-gui/blob/main/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`](https://github.com/luohy15/y-gui/blob/main/backend/src/utils/system-prompt.ts). It exports two primary pieces:

1. **`DEFAULT_PROMPTS`** – a `Record<string, string>` that maps bot identifiers to their default system instructions.
2. **`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).

```typescript
// 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`](https://github.com/luohy15/y-gui/blob/main/backend/src/api/chat.ts). This route handler validates the request, extracts the `botId`, and delegates to the chat service.

```typescript
// 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`](https://github.com/luohy15/y-gui/blob/main/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.

```typescript
// 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`](https://github.com/luohy15/y-gui/blob/main/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.

```typescript
// 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`](https://github.com/luohy15/y-gui/blob/main/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"`.

```typescript
// 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`](https://github.com/luohy15/y-gui/blob/main/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.

```typescript
// 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.

```typescript
// 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

```typescript
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

```typescript
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

```typescript
// 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.ts`](https://github.com/luohy15/y-gui/blob/main/backend/src/utils/system-prompt.ts) and exports a `DEFAULT_PROMPTS` map plus the `getSystemPrompt(botId)` helper.
- Every chat request flows through [`backend/src/api/chat.ts`](https://github.com/luohy15/y-gui/blob/main/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:
  1. **Global defaults** – edit `DEFAULT_PROMPTS` in the utility file to affect all bots that lack an override.
  2. **Per‑bot overrides** – add a `systemPrompt` field to a bot record in [`backend/src/repository/d1/bot-d1-repository.ts`](https://github.com/luohy15/y-gui/blob/main/backend/src/repository/d1/bot-d1-repository.ts) (or similar) to tailor behavior for that specific bot.
- The [`openai-format-provider.ts`](https://github.com/luohy15/y-gui/blob/main/openai-format-provider.ts) (and analogous providers) injects the resolved prompt as the first `role: "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`](https://github.com/luohy15/y-gui/blob/main/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`](https://github.com/luohy15/y-gui/blob/main/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`](https://github.com/luohy15/y-gui/blob/main/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`](https://github.com/luohy15/y-gui/blob/main/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.