"""Builds the system prompt that is sent to the AI at the start of each chat session."""
# Prevents very large files from flooding the context window with tokens.
MAX_FILE_CHARS = 4000
class SystemPrompter:
"""Generates system prompts for the chat assistant.
When a file is open in the editor it can be embedded in the prompt so the
AI has direct context of the code the user is currently working on.
"""
@staticmethod
def generate_prompt(
file_context: dict | None = None,
search_context: list[dict] | None = None,
) -> str:
"""Build a system prompt, optionally embedding a file and/or web search results.
Args:
file_context: dict with keys 'name' (filename) and 'content' (raw text),
or None if no file should be included.
search_context: list of {"title", "url", "snippet"} dicts from SearchManager,
or None if no search results should be included.
Returns:
A ready-to-use system prompt string.
"""
base = (
"You are an expert code assistant integrated into a lightweight code editor. "
"Help the user with code suggestions, debugging, explanations, and improvements. "
"Be concise and precise. Use markdown and fenced code blocks where appropriate."
)
prompt = base
if file_context:
name = file_context.get("name", "unknown")
content = file_context.get("content", "")
# Truncate large files to avoid exceeding the model's token limit
if len(content) > MAX_FILE_CHARS:
content = content[:MAX_FILE_CHARS] + "\n... [truncated]"
prompt += (
f"\n\nThe user currently has the following file open in the editor:\n"
f"\n"
f"\n{content}\n\n"
f"\n"
f"Refer to this file when answering questions about the code."
)
if search_context:
search_section = "\n\nThe user has performed a web search. Use the results below as additional context if relevant:\n\n"
for i, r in enumerate(search_context, 1):
search_section += (
f"[{i}] {r.get('title', '')}\n"
f"URL: {r.get('url', '')}\n"
f"{r.get('snippet', '')}\n\n"
)
search_section += ""
prompt += search_section
return prompt