fix: fixing the prompt in one

This commit is contained in:
Carlos
2025-05-24 15:34:21 -04:00
parent c1bfbf2eef
commit 34b5a54daf

View File

@ -6,10 +6,9 @@ const { savePrompt, saveError } = require("../controller/generate");
/** /**
* Injects file contents into message content when file tags are present * Injects file contents into message content when file tags are present
* @param {string} content - The message content to process * @param {string} content - The message content to process
* @returns {string} The processed content with file contents injected * @returns {Promise<string>} The processed content with file contents injected
*/ */
async function injectFileContent(content) {
function injectFileContent(content) {
let processedContent = content; let processedContent = content;
// First, handle <selected_files> block // First, handle <selected_files> block
@ -19,7 +18,7 @@ function injectFileContent(content) {
if (selectedFilesMatch) { if (selectedFilesMatch) {
const fileListBlock = selectedFilesMatch[1]; const fileListBlock = selectedFilesMatch[1];
// Skip injection if it already contains <file> blocks // Skip injection if it already contains <file> tags
const containsFileTags = fileListBlock.includes("<file path="); const containsFileTags = fileListBlock.includes("<file path=");
if (!containsFileTags) { if (!containsFileTags) {
const filePaths = fileListBlock const filePaths = fileListBlock
@ -28,8 +27,8 @@ function injectFileContent(content) {
.filter((line) => line && line.startsWith("- ")) .filter((line) => line && line.startsWith("- "))
.map((line) => line.replace(/^- /, "")); .map((line) => line.replace(/^- /, ""));
const fileBlocks = filePaths const fileBlocks = await Promise.all(
.map(async (filePath) => { filePaths.map(async (filePath) => {
try { try {
const resolvedPath = path.resolve(process.cwd(), filePath); const resolvedPath = path.resolve(process.cwd(), filePath);
const fileContent = fs.readFileSync(resolvedPath, "utf-8"); const fileContent = fs.readFileSync(resolvedPath, "utf-8");
@ -39,26 +38,24 @@ function injectFileContent(content) {
console.warn( console.warn(
`⚠️ Failed to read file: ${filePath}${error.message}`, `⚠️ Failed to read file: ${filePath}${error.message}`,
); );
const errorDetails = {
message: error.message,
request: null,
response: error.response?.data,
stack: error.stack,
};
await saveError({ await saveError({
error_message: error.message, error_message: error.message,
details: errorDetails, details: {
message: error.message,
request: null,
response: error.response?.data,
stack: error.stack,
},
}); });
return `<file path="${filePath}" language="text">\n[Error: File not found or unreadable]\n</file>`; return `<file path="${filePath}" language="text">\n[Error: File not found or unreadable]\n</file>`;
} }
}) }),
.join("\n\n"); );
// Replace the original <selected_files> block with injected file tags // Replace the <selected_files> block with the injected file tags
processedContent = processedContent.replace( processedContent = processedContent.replace(
selectedFilesMatch[0], selectedFilesMatch[0],
fileBlocks, fileBlocks.join("\n\n"),
); );
} else { } else {
console.log( console.log(
@ -67,34 +64,34 @@ function injectFileContent(content) {
} }
} }
// Then, safely resolve and inject content into any <file path="..."> tags (without inner content) // Inject content into empty <file> tags
const fileTagRegex = /<file path="(.+?)"(?: language="(.+?)")?>\s*<\/file>/g; const fileTagRegex = /<file path="(.+?)"(?: language="(.+?)")?>\s*<\/file>/g;
processedContent = processedContent.replace( const matches = [...processedContent.matchAll(fileTagRegex)];
fileTagRegex,
async (_, filePath, lang) => { for (const match of matches) {
try { const [fullTag, filePath, lang] = match;
const resolvedPath = path.resolve(process.cwd(), filePath); try {
const fileContent = fs.readFileSync(resolvedPath, "utf-8"); const resolvedPath = path.resolve(process.cwd(), filePath);
return `<file path="${filePath}" language="${lang || "text"}">\n${fileContent}\n</file>`; const fileContent = fs.readFileSync(resolvedPath, "utf-8");
} catch (error) { const replacement = `<file path="${filePath}" language="${lang || "text"}">\n${fileContent}\n</file>`;
console.warn( processedContent = processedContent.replace(fullTag, replacement);
`⚠️ Failed to inject <file> tag for ${filePath}: ${error.message}`, } catch (error) {
); console.warn(
const errorDetails = { `⚠️ Failed to inject <file> tag for ${filePath}: ${error.message}`,
);
await saveError({
error_message: error.message,
details: {
message: error.message, message: error.message,
request: null, request: null,
response: error.response?.data, response: error.response?.data,
stack: error.stack, stack: error.stack,
}; },
});
await saveError({ const replacement = `<file path="${filePath}" language="${lang || "text"}">\n[Error: File not found or unreadable]\n</file>`;
error_message: error.message, processedContent = processedContent.replace(fullTag, replacement);
details: errorDetails, }
}); }
return `<file path="${filePath}" language="${lang || "text"}">\n[Error: File not found or unreadable]\n</file>`;
}
},
);
return processedContent; return processedContent;
} }
@ -104,7 +101,6 @@ function injectFileContent(content) {
* Handles both chat-style and prompt-style requests to Ollama * Handles both chat-style and prompt-style requests to Ollama
*/ */
async function handleGenerate(req, res) { async function handleGenerate(req, res) {
// Log the complete request for debugging
try { try {
const requestData = { const requestData = {
method: req.method, method: req.method,
@ -119,9 +115,7 @@ async function handleGenerate(req, res) {
}, },
}; };
// Validate request body
if (!requestData.body) { if (!requestData.body) {
// Save request data even if body is empty
await savePrompt({ await savePrompt({
model: requestData.body?.model || "codellama:7b", model: requestData.body?.model || "codellama:7b",
prompt: null, prompt: null,
@ -131,9 +125,9 @@ async function handleGenerate(req, res) {
throw new Error("Request body is required"); throw new Error("Request body is required");
} }
// Determine request type and validate required fields
const isChatRequest = const isChatRequest =
requestData.body.messages && Array.isArray(requestData.body.messages); requestData.body.messages && Array.isArray(requestData.body.messages);
if ( if (
isChatRequest && isChatRequest &&
(!requestData.body.messages.length || (!requestData.body.messages.length ||
@ -147,45 +141,42 @@ async function handleGenerate(req, res) {
throw new Error("Prompt request must include a prompt field"); throw new Error("Prompt request must include a prompt field");
} }
// Set defaults and validate model
const model = requestData.body.model || "codellama:7b"; const model = requestData.body.model || "codellama:7b";
const stream = const stream =
requestData.body.stream !== undefined ? requestData.body.stream : true; requestData.body.stream !== undefined ? requestData.body.stream : true;
// Clean and prepare the prompt/messages
const cleanedRequest = { const cleanedRequest = {
model, model,
stream, stream,
...(isChatRequest ...(isChatRequest
? { ? {
messages: requestData.body.messages.map((msg) => ({ messages: await Promise.all(
role: msg.role || "user", requestData.body.messages.map(async (msg) => ({
content: role: msg.role || "user",
msg.role === "user" && typeof msg.content === "string" content:
? injectFileContent(msg.content.trim()) msg.role === "user" && typeof msg.content === "string"
: msg.content.trim(), ? await injectFileContent(msg.content.trim())
})), : msg.content.trim(),
})),
),
} }
: { : {
prompt: injectFileContent(requestData.body.prompt.trim()), prompt: await injectFileContent(requestData.body.prompt.trim()),
}), }),
}; };
// Save the complete request data to database
await savePrompt({ await savePrompt({
model, model,
prompt: isChatRequest ? null : cleanedRequest.prompt, prompt: isChatRequest ? null : cleanedRequest.prompt,
messages: isChatRequest ? cleanedRequest.messages : null, messages: isChatRequest ? cleanedRequest.messages : null,
request_data: requestData, // Save all request data for debugging/tracking request_data: requestData,
}); });
// Prepare Ollama endpoint and payload
const ollamaUrl = isChatRequest const ollamaUrl = isChatRequest
? "http://localhost:11434/api/chat" ? "http://localhost:11434/api/chat"
: "http://localhost:11434/api/generate"; : "http://localhost:11434/api/generate";
if (stream) { if (stream) {
// Handle streaming response
const ollamaResponse = await axios.post(ollamaUrl, cleanedRequest, { const ollamaResponse = await axios.post(ollamaUrl, cleanedRequest, {
responseType: "stream", responseType: "stream",
headers: { headers: {
@ -197,11 +188,9 @@ async function handleGenerate(req, res) {
res.setHeader("Content-Type", "application/x-ndjson"); res.setHeader("Content-Type", "application/x-ndjson");
res.setHeader("Transfer-Encoding", "chunked"); res.setHeader("Transfer-Encoding", "chunked");
let responseContent = "";
ollamaResponse.data.on("data", (chunk) => { ollamaResponse.data.on("data", (chunk) => {
try { try {
const data = JSON.parse(chunk.toString()); const data = JSON.parse(chunk.toString());
responseContent += data.response || "";
res.write(JSON.stringify(data) + "\n"); res.write(JSON.stringify(data) + "\n");
} catch (err) { } catch (err) {
console.error("Error parsing chunk:", err); console.error("Error parsing chunk:", err);
@ -233,12 +222,10 @@ async function handleGenerate(req, res) {
} }
}); });
} else { } else {
// Handle non-streaming response
const ollamaResponse = await axios.post(ollamaUrl, cleanedRequest); const ollamaResponse = await axios.post(ollamaUrl, cleanedRequest);
res.status(ollamaResponse.status).json(ollamaResponse.data); res.status(ollamaResponse.status).json(ollamaResponse.data);
} }
} catch (error) { } catch (error) {
// Enhanced error handling
const errorDetails = { const errorDetails = {
message: error.message, message: error.message,
request: requestData, request: requestData,