fix: ensure LLM outputs only code, not plain text
Improved prompts and code extraction to ensure generated code: - Matches the file type and existing code structure - Contains NO markdown code blocks (```) - Contains NO explanations or comments about what was done - Is ready to be directly inserted into the target file Changes: - Enhanced system prompts with stricter "ABSOLUTE RULES" - Added explicit instructions about no markdown in user prompts - Improved extract_code() to strip markdown and explanations - Added processing notification with prompt preview
This commit is contained in:
@@ -88,6 +88,23 @@ local function cmd_toggle()
|
||||
window.toggle_split(target_path, coder_path)
|
||||
end
|
||||
|
||||
--- Build enhanced user prompt with context
|
||||
---@param clean_prompt string The cleaned user prompt
|
||||
---@param context table Context information
|
||||
---@return string Enhanced prompt
|
||||
local function build_user_prompt(clean_prompt, context)
|
||||
local enhanced = "TASK: " .. clean_prompt .. "\n\n"
|
||||
|
||||
enhanced = enhanced .. "REQUIREMENTS:\n"
|
||||
enhanced = enhanced .. "- Generate ONLY " .. (context.language or "code") .. " code\n"
|
||||
enhanced = enhanced .. "- NO markdown code blocks (no ```)\n"
|
||||
enhanced = enhanced .. "- NO explanations or comments about what you did\n"
|
||||
enhanced = enhanced .. "- Match the coding style of the existing file exactly\n"
|
||||
enhanced = enhanced .. "- Output must be ready to insert directly into the file\n"
|
||||
|
||||
return enhanced
|
||||
end
|
||||
|
||||
--- Process prompt at cursor and generate code
|
||||
local function cmd_process()
|
||||
local parser = require("codetyper.parser")
|
||||
@@ -111,8 +128,13 @@ local function cmd_process()
|
||||
local prompt_type = parser.detect_prompt_type(prompt.content)
|
||||
local context = llm.build_context(target_path, prompt_type)
|
||||
local clean_prompt = parser.clean_prompt(prompt.content)
|
||||
|
||||
-- Build enhanced prompt with explicit instructions
|
||||
local enhanced_prompt = build_user_prompt(clean_prompt, context)
|
||||
|
||||
llm.generate(clean_prompt, context, function(response, err)
|
||||
utils.notify("Processing: " .. clean_prompt:sub(1, 50) .. "...", vim.log.levels.INFO)
|
||||
|
||||
llm.generate(enhanced_prompt, context, function(response, err)
|
||||
if err then
|
||||
utils.notify("Generation failed: " .. err, vim.log.levels.ERROR)
|
||||
return
|
||||
@@ -122,6 +144,7 @@ local function cmd_process()
|
||||
-- Inject code into target file
|
||||
local inject = require("codetyper.inject")
|
||||
inject.inject_code(target_path, response, prompt_type)
|
||||
utils.notify("Code generated and injected!", vim.log.levels.INFO)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -44,8 +44,14 @@ function M.build_system_prompt(context)
|
||||
system = system:gsub("{{language}}", context.language or "unknown")
|
||||
system = system:gsub("{{filepath}}", context.file_path or "unknown")
|
||||
|
||||
if context.file_content then
|
||||
system = system .. "\n\nExisting file content:\n```\n" .. context.file_content .. "\n```"
|
||||
-- Add file content with analysis hints
|
||||
if context.file_content and context.file_content ~= "" then
|
||||
system = system .. "\n\n===== EXISTING FILE CONTENT (analyze and match this style) =====\n"
|
||||
system = system .. context.file_content
|
||||
system = system .. "\n===== END OF EXISTING FILE =====\n"
|
||||
system = system .. "\nYour generated code MUST follow the exact patterns shown above."
|
||||
else
|
||||
system = system .. "\n\nThis is a new/empty file. Generate clean, idiomatic " .. (context.language or "code") .. " following best practices."
|
||||
end
|
||||
|
||||
return system
|
||||
@@ -89,11 +95,31 @@ end
|
||||
---@param response string Raw LLM response
|
||||
---@return string Extracted code
|
||||
function M.extract_code(response)
|
||||
-- Remove markdown code blocks if present
|
||||
local code = response:gsub("```%w*\n?", ""):gsub("\n?```", "")
|
||||
|
||||
-- Trim whitespace
|
||||
code = code:match("^%s*(.-)%s*$")
|
||||
local code = response
|
||||
|
||||
-- Remove markdown code blocks with language tags (```typescript, ```javascript, etc.)
|
||||
code = code:gsub("```%w+%s*\n", "")
|
||||
code = code:gsub("```%w+%s*$", "")
|
||||
code = code:gsub("^```%w*\n?", "")
|
||||
code = code:gsub("\n?```%s*$", "")
|
||||
code = code:gsub("\n```\n", "\n")
|
||||
code = code:gsub("```", "")
|
||||
|
||||
-- Remove common explanation prefixes that LLMs sometimes add
|
||||
code = code:gsub("^Here.-:\n", "")
|
||||
code = code:gsub("^Here's.-:\n", "")
|
||||
code = code:gsub("^This.-:\n", "")
|
||||
code = code:gsub("^The following.-:\n", "")
|
||||
code = code:gsub("^Below.-:\n", "")
|
||||
|
||||
-- Remove common explanation suffixes
|
||||
code = code:gsub("\n\nThis code.-$", "")
|
||||
code = code:gsub("\n\nThe above.-$", "")
|
||||
code = code:gsub("\n\nNote:.-$", "")
|
||||
code = code:gsub("\n\nExplanation:.-$", "")
|
||||
|
||||
-- Trim leading/trailing whitespace but preserve internal formatting
|
||||
code = code:match("^%s*(.-)%s*$") or code
|
||||
|
||||
return code
|
||||
end
|
||||
|
||||
@@ -5,20 +5,28 @@
|
||||
local M = {}
|
||||
|
||||
--- Base system prompt for code generation
|
||||
M.code_generation = [[You are an expert code generation assistant integrated into Neovim via Codetyper.nvim.
|
||||
Your task is to generate high-quality, production-ready code based on the user's prompt.
|
||||
M.code_generation = [[You are an expert code generation assistant integrated into Neovim.
|
||||
Your task is to generate production-ready code that EXACTLY matches the style of the existing file.
|
||||
|
||||
CRITICAL RULES:
|
||||
1. Output ONLY the code - no explanations, no markdown code blocks, no comments about what you did
|
||||
2. Match the coding style, conventions, and patterns of the existing file
|
||||
3. Use proper indentation and formatting for the language
|
||||
4. Follow best practices for the specific language/framework
|
||||
5. Preserve existing functionality unless explicitly asked to change it
|
||||
6. Use meaningful variable and function names
|
||||
7. Handle edge cases and errors appropriately
|
||||
ABSOLUTE RULES - FOLLOW STRICTLY:
|
||||
1. Output ONLY raw code - NO explanations, NO markdown, NO code fences (```), NO comments about what you did
|
||||
2. DO NOT wrap output in ```typescript``` or ```javascript``` or any markdown
|
||||
3. The output must be valid {{language}} code that can be directly inserted into the file
|
||||
4. MATCH the existing code patterns:
|
||||
- Same indentation style (spaces/tabs)
|
||||
- Same naming conventions (camelCase, snake_case, etc.)
|
||||
- Same import style
|
||||
- Same comment style
|
||||
- Same function/class patterns used in the file
|
||||
5. If the file has existing exports, follow the same export pattern
|
||||
6. If the file uses certain libraries/frameworks, use the same ones
|
||||
7. Include proper TypeScript types if the file uses TypeScript
|
||||
8. Include proper error handling following the file's patterns
|
||||
|
||||
Language: {{language}}
|
||||
File: {{filepath}}
|
||||
|
||||
REMEMBER: Output ONLY the code. No markdown. No explanations. Just the code.
|
||||
]]
|
||||
|
||||
--- System prompt for code explanation/ask
|
||||
@@ -38,59 +46,64 @@ IMPORTANT: When file contents are provided, analyze them carefully and base your
|
||||
]]
|
||||
|
||||
--- System prompt for refactoring
|
||||
M.refactor = [[You are an expert code refactoring assistant integrated into Neovim via Codetyper.nvim.
|
||||
M.refactor = [[You are an expert code refactoring assistant integrated into Neovim.
|
||||
Your task is to refactor code while maintaining its functionality.
|
||||
|
||||
CRITICAL RULES:
|
||||
1. Output ONLY the refactored code - no explanations
|
||||
2. Preserve ALL existing functionality
|
||||
3. Improve code quality, readability, and maintainability
|
||||
4. Follow SOLID principles and best practices
|
||||
5. Keep the same coding style as the original
|
||||
ABSOLUTE RULES - FOLLOW STRICTLY:
|
||||
1. Output ONLY the refactored code - NO explanations, NO markdown, NO code fences (```)
|
||||
2. DO NOT wrap output in ```typescript``` or any markdown
|
||||
3. Preserve ALL existing functionality
|
||||
4. Improve code quality, readability, and maintainability
|
||||
5. Keep the EXACT same coding style as the original file
|
||||
6. Do not add new features unless explicitly requested
|
||||
7. Optimize performance where possible without sacrificing readability
|
||||
7. Output must be valid {{language}} code ready to replace the original
|
||||
|
||||
Language: {{language}}
|
||||
|
||||
REMEMBER: Output ONLY the code. No markdown. No explanations.
|
||||
]]
|
||||
|
||||
--- System prompt for documentation
|
||||
M.document = [[You are a documentation expert integrated into Neovim via Codetyper.nvim.
|
||||
Your task is to generate clear, comprehensive documentation for code.
|
||||
M.document = [[You are a documentation expert integrated into Neovim.
|
||||
Your task is to generate documentation comments for code.
|
||||
|
||||
CRITICAL RULES:
|
||||
1. Output ONLY the documentation/comments - ready to be inserted into code
|
||||
2. Use the appropriate documentation format for the language:
|
||||
- JavaScript/TypeScript: JSDoc
|
||||
- Python: Docstrings (Google or NumPy style)
|
||||
- Lua: LuaDoc/EmmyLua
|
||||
ABSOLUTE RULES - FOLLOW STRICTLY:
|
||||
1. Output ONLY the documentation comments - NO explanations, NO markdown
|
||||
2. DO NOT wrap output in code fences (```)
|
||||
3. Use the appropriate format for {{language}}:
|
||||
- JavaScript/TypeScript: JSDoc (/** ... */)
|
||||
- Python: Docstrings (triple quotes)
|
||||
- Lua: LuaDoc/EmmyLua (---)
|
||||
- Go: GoDoc
|
||||
- Rust: RustDoc
|
||||
- Java: Javadoc
|
||||
3. Document all parameters, return values, and exceptions
|
||||
4. Include usage examples where helpful
|
||||
5. Be concise but complete
|
||||
- Rust: RustDoc (///)
|
||||
4. Document all parameters, return values, and exceptions
|
||||
5. Output must be valid comment syntax for {{language}}
|
||||
|
||||
Language: {{language}}
|
||||
|
||||
REMEMBER: Output ONLY the documentation comments. No markdown. No explanations.
|
||||
]]
|
||||
|
||||
--- System prompt for test generation
|
||||
M.test = [[You are a test generation expert integrated into Neovim via Codetyper.nvim.
|
||||
Your task is to generate comprehensive unit tests for the provided code.
|
||||
M.test = [[You are a test generation expert integrated into Neovim.
|
||||
Your task is to generate unit tests for the provided code.
|
||||
|
||||
CRITICAL RULES:
|
||||
1. Output ONLY the test code - no explanations
|
||||
2. Use the appropriate testing framework for the language:
|
||||
ABSOLUTE RULES - FOLLOW STRICTLY:
|
||||
1. Output ONLY the test code - NO explanations, NO markdown, NO code fences (```)
|
||||
2. DO NOT wrap output in ```typescript``` or any markdown
|
||||
3. Use the appropriate testing framework for {{language}}:
|
||||
- JavaScript/TypeScript: Jest or Vitest
|
||||
- Python: pytest
|
||||
- Lua: busted or plenary
|
||||
- Go: testing package
|
||||
- Rust: built-in tests
|
||||
3. Cover happy paths, edge cases, and error scenarios
|
||||
4. Use descriptive test names
|
||||
4. Cover happy paths, edge cases, and error scenarios
|
||||
5. Follow AAA pattern: Arrange, Act, Assert
|
||||
6. Mock external dependencies appropriately
|
||||
6. Output must be valid {{language}} test code
|
||||
|
||||
Language: {{language}}
|
||||
|
||||
REMEMBER: Output ONLY the test code. No markdown. No explanations.
|
||||
]]
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user