Last active
May 11, 2025 23:33
-
-
Save mohsen1/c867d038fc4f46494af4c4024cfc7939 to your computer and use it in GitHub Desktop.
Revisions
-
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 5 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -75,7 +75,11 @@ function debug(message) { * @param {string} str * @returns {number} */ function reallyDumbTokenCounter(str) { if (typeof str !== "string") { console.trace("str is not a string", typeof str, str); } str = typeof str === "string" ? str : ""; return ( str // Split on whitespace, newlines, and parentheses, brackets, and braces -
mohsen1 revised this gist
Jan 21, 2025 . 2 changed files with 48 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,6 +4,8 @@ CLI tool that uses DeepSeek AI to debug Rust projects by analyzing test failures > This is highly personalized to my own use case. But you can customize it for yourself. This will collect all of test failues, filter out passing test, serialize the repo and git changes into one request to ask deepseek for help ## Setup 1. Install [yek](https://github.com/bodo-run/yek) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -62,10 +62,36 @@ const systemPrompt = [ function debug(message) { if (debugEnabled) { console.log(`[ask.js] ${message}`); } } /** * Really dumb token counter. It assumes that each word is a token. * It's a bit smarter than that though, it splits camelCase, * snake_case, PascalCase, and kebab-case multi-word strings into tokens. * It also assumes ()[]{} are token separators. * Dumb but works for most cases and is fast. * @param {string} str * @returns {number} */ function reallyDumbTokenCounter(str = "") { return ( str // Split on whitespace, newlines, and parentheses, brackets, and braces .split(/[\s\n()[\]{}]+/) .flatMap((word) => // Split camelCase/PascalCase into separate words word .split(/(?=[A-Z][a-z])|(?<=[a-z])(?=[A-Z])/) // Split snake_case and kebab-case .flatMap((part) => part.split(/[_\-]/)) // Filter out empty strings .filter(Boolean) ).length ); } if (!token) { console.error("DEEPSEEK_API_KEY is not set"); process.exit(1); @@ -76,7 +102,7 @@ const maxTokens = 128000; // 10000 tokens for test failures // Alternatively we can use the word count of trimmedTestOutput but that means running test and serializing // can not happen in parallel. 10k characters is good enough for most cases. const maxSize = maxTokens - 10000 - reallyDumbTokenCounter(systemPrompt); // Convert execSync to Promise-based execution async function execCommand(program, args = [], options = {}) { @@ -178,10 +204,10 @@ const findTestFiles = async (tests) => { return Array.from(results); }; // Truncate and escape content if too large (from bottom up) const truncateAndEscape = (str) => { if (reallyDumbTokenCounter(str) > maxTokens) { str = "... (truncated) ...\n" + str.slice(-maxTokens); } return JSON.stringify(str); }; @@ -194,8 +220,9 @@ Promise.all([ returnError: true, printToConsole: true, }), execCommand("git", ["diff", "|", "cat"]), ]) .then(async ([serialized, testOutput, gitDiff]) => { debug("Serializing and test run complete"); // Check if any test failed by looking for "test result: FAILED" in the output @@ -244,7 +271,9 @@ Promise.all([ process.exit(1); } const timer = setInterval(() => { process.stdout.write("."); }, 1000); // Any lines before "failures:" is not needed. Those are tests that passed. const trimmedTestOutput = testOutput.split("failures:").slice(1).join("\n"); @@ -253,13 +282,20 @@ Promise.all([ [ `# Repo:`, serialized, `# Git diff:`, gitDiff, `# Test contents:`, testContents.join("\n\n"), `# Test failures:`, trimmedTestOutput, ].join("\n\n") ); debug(`Content length: ${reallyDumbTokenCounter(content)} tokens`); console.log( `Asking DeepSeek R1 a ${reallyDumbTokenCounter( content )} token question. This will take a while...` ); const data = JSON.stringify({ model: "deepseek-reasoner", @@ -294,6 +330,7 @@ Promise.all([ }); res.on("end", () => { clearInterval(timer); debug("Response completed"); try { const jsonResponse = JSON.parse(responseData); @@ -314,6 +351,7 @@ Promise.all([ }); req.on("error", (error) => { clearInterval(timer); console.error("Error:", error); debug(`Request error: ${error.message}`); process.exit(1); -
mohsen1 revised this gist
Jan 21, 2025 . 2 changed files with 57 additions and 50 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,6 +2,8 @@ CLI tool that uses DeepSeek AI to debug Rust projects by analyzing test failures. > This is highly personalized to my own use case. But you can customize it for yourself. ## Setup 1. Install [yek](https://github.com/bodo-run/yek) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -73,7 +73,10 @@ if (!token) { const maxTokens = 128000; // DeepSeek maximum context length is 128K tokens. we leave some room for the test failures. // 10000 tokens for test failures // Alternatively we can use the word count of trimmedTestOutput but that means running test and serializing // can not happen in parallel. 10k characters is good enough for most cases. const maxSize = maxTokens - 10000 - systemPrompt.split(/\s/).length; // Convert execSync to Promise-based execution async function execCommand(program, args = [], options = {}) { @@ -134,6 +137,54 @@ async function execCommand(program, args = [], options = {}) { } }); } const findTestFiles = async (tests) => { const results = new Set(); for (const test of tests) { try { // Search in tests directory first const testsResult = execSync( `find ./tests -type f -name "*.rs" -exec grep -l "${test}" {} \\;`, { stdio: ["pipe", "pipe", "pipe"], } ) .toString() .trim(); if (testsResult) { testsResult.split("\n").forEach((file) => results.add(file)); continue; } // If not found in tests, search in src const srcResult = execSync( `find ./src -type f -name "*.rs" -exec grep -l "${test}" {} \\;`, { stdio: ["pipe", "pipe", "pipe"], } ) .toString() .trim(); if (srcResult) { srcResult.split("\n").forEach((file) => results.add(file)); } } catch (error) { debug(`Error finding test file for ${test}: ${error.message}`); } } return Array.from(results); }; // Truncate and escape content if too large const truncateAndEscape = (str) => { if (str.length > maxTokens) { str = str.slice(0, maxTokens) + "... (truncated)"; } return JSON.stringify(str); }; // Run serialization and testing in parallel debug("Starting serialization and testing in parallel..."); @@ -168,47 +219,6 @@ Promise.all([ debug(`Failed tests: ${failedTests.join(", ")}`); const testFiles = await findTestFiles(failedTests); if (testFiles.length === 0) { @@ -236,13 +246,8 @@ Promise.all([ console.log("Asking DeepSeek R1. This will take a while..."); // Any lines before "failures:" is not needed. Those are tests that passed. const trimmedTestOutput = testOutput.split("failures:").slice(1).join("\n"); const content = truncateAndEscape( [ @@ -251,7 +256,7 @@ Promise.all([ `# Test contents:`, testContents.join("\n\n"), `# Test failures:`, trimmedTestOutput, ].join("\n\n") ); debug(`Content length: ${content.length} characters`); -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,7 +4,7 @@ CLI tool that uses DeepSeek AI to debug Rust projects by analyzing test failures ## Setup 1. Install [yek](https://github.com/bodo-run/yek) 2. Set API key: `export DEEPSEEK_API_KEY=your_key` ## Usage -
mohsen1 renamed this gist
Jan 21, 2025 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 26 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,26 @@ # ask.js CLI tool that uses DeepSeek AI to debug Rust projects by analyzing test failures. ## Setup 1. Install [yek](https://github.com/bodo-run/yek): `npm install -g yek` 2. Set API key: `export DEEPSEEK_API_KEY=your_key` ## Usage Run in your Rust project: `./ask.js` Options: - `--debug`: Enable debug logging The script runs tests, analyzes failures, and returns AI-powered debugging recommendations. ## Cursor AI Editor I have this in Cursor AI Editor settings: ``` IMPORTANT: to run the tests execute `./ask.js`. this will take up to 5 minutes. wait long enough IMPORTANT: DO NOT KILL ask.js too quickly while asking DeepSeek ``` -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 39 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,7 +14,6 @@ const { spawn, execSync } = require("child_process"); const https = require("https"); const fs = require("fs"); const token = process.env.DEEPSEEK_API_KEY; @@ -23,6 +22,44 @@ const testCommand = "cargo test"; // TODO: make this configurable const testProgram = testCommand.split(" ")[0]; const testArgs = testCommand.split(" ").slice(1); const systemPrompt = [ "You are a senior Rust engineer with 10+ years of experience in systems programming.", "Your expertise includes:", "- Deep knowledge of Rust's ownership system, lifetimes, and concurrency model", "- Mastery of cargo, clippy, and modern Rust toolchain features", "- Experience debugging complex memory issues and performance bottlenecks", "- Familiarity with common Rust crates and idiomatic patterns", "When analyzing test failures:", "1. First clearly identify the failure type (compiler error, runtime panic, logical error, performance issue)", "2. Analyze backtraces and error messages with attention to ownership boundaries", "3. Consider common Rust pitfalls:", " - Lifetime mismatches", " - Unsafe code violations", " - Trait bound errors", " - Concurrency race conditions", " - Iterator invalidation", "4. Cross-reference with cargo test output and clippy warnings", "For proposed fixes:", "- Always prioritize type safety and borrow checker rules", "- Prefer idiomatic solutions over clever hacks", "- Include exact code diffs using markdown format with file names", "- Explain the root cause before presenting fixes", "- Suggest relevant clippy lints or cargo checks to prevent regressions", "Response guidelines:", "- Structure analysis using bullet points for clarity", "- Use code fences for error snippets and diffs", "- Highlight connections between test failures and system architecture", "- When uncertain, propose multiple hypothesis with verification strategies", "Special capabilities:", "- Leverage knowledge of Rust internals (MIR, drop order, etc.)", "- Reference similar issues in popular Rust OSS projects", "- Suggest property-based testing strategies for edge cases", ].join("\n"); function debug(message) { if (debugEnabled) { console.log(`[DEBUG] ${message}`); @@ -34,10 +71,9 @@ if (!token) { process.exit(1); } const maxTokens = 128000; // DeepSeek maximum context length is 128K tokens. we leave some room for the test failures. const maxSize = maxTokens - 10000 - systemPrompt.split(/\s/).length; // 10000 tokens for test failures // Convert execSync to Promise-based execution async function execCommand(program, args = [], options = {}) { @@ -220,15 +256,6 @@ Promise.all([ ); debug(`Content length: ${content.length} characters`); const data = JSON.stringify({ model: "deepseek-reasoner", messages: [ -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 5 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,13 +1,14 @@ #!/usr/bin/env node // @ts-check /** * @fileoverview * This script asks DeepSeek to help with debugging a Rust project. * It serializes the project, gets test failures, and sends the content to DeepSeek. * The response is then printed to the console. * * YOU WILL NEED `yek` to be installed * @see https://github.com/bodo-run/yek */ const { spawn, execSync } = require("child_process"); @@ -197,7 +198,7 @@ Promise.all([ process.exit(1); } console.log("Asking DeepSeek R1. This will take a while..."); // Truncate and escape content if too large const truncateAndEscape = (str) => { @@ -229,7 +230,7 @@ Promise.all([ `; const data = JSON.stringify({ model: "deepseek-reasoner", messages: [ { role: "system", content: systemPrompt }, { role: "user", content }, -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,8 @@ #!/usr/bin/env node // @ts-check /** @see https://github.com/bodo-run/yek */ /** * @fileoverview * This script asks DeepSeek to help with debugging a Rust project. -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 17 additions and 17 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -51,15 +51,15 @@ async function execCommand(program, args = [], options = {}) { process.stdout.on("data", (data) => { const str = data.toString(); outputs.push(str); if (options.printToConsole) { console.log(str); } }); process.stderr.on("data", (data) => { const str = data.toString(); outputs.push(str); if (options.printToConsole) { console.error(str); } }); @@ -99,31 +99,31 @@ async function execCommand(program, args = [], options = {}) { // Run serialization and testing in parallel debug("Starting serialization and testing in parallel..."); Promise.all([ execCommand("yek", [`--max-size`, maxSize.toString(), `--tokens`], {}), execCommand(testProgram, testArgs, { returnError: true, printToConsole: true, }), ]) .then(async ([serialized, testOutput]) => { debug("Serializing and test run complete"); // Check if any test failed by looking for "test result: FAILED" in the output const hasFailures = testOutput.includes("test result: FAILED"); if (!hasFailures) { console.log("All tests passed!"); process.exit(0); } // Extract failed test names const failedTests = testOutput .split("\n") .map((line) => line.trim()) .filter((line) => line.toLowerCase().endsWith("failed")) .map((line) => line.split(" ")?.[1]); if (failedTests.length === 0) { console.log("All tests passed!"); process.exit(0); } -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 99 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,13 +8,15 @@ * The response is then printed to the console. */ const { spawn, execSync } = require("child_process"); const https = require("https"); const fs = require("fs"); const path = require("path"); const token = process.env.DEEPSEEK_API_KEY; const debugEnabled = process.argv.includes("--debug"); const testCommand = "cargo test"; // TODO: make this configurable const testProgram = testCommand.split(" ")[0]; const testArgs = testCommand.split(" ").slice(1); @@ -102,14 +104,96 @@ Promise.all([ }), execCommand(testProgram, testArgs, { returnError: true, stdio: "inherit", }), ]) .then(async ([serialized, testOutput]) => { const failedTests = testOutput .split("\n") .map((line) => line.trim()) .filter( (line) => line.toLowerCase().includes("test") && line.toLowerCase().endsWith("failed") ) .map((line) => { const parts = line.split(" "); return parts.find((part) => part.includes("::")) || parts[1]; }) .filter(Boolean); if (failedTests.length === 0) { console.error("No test failures found in the output"); process.exit(0); } debug(`Failed tests: ${failedTests.join(", ")}`); const findTestFiles = async (tests) => { const results = new Set(); for (const test of tests) { try { // Search in tests directory first const testsResult = execSync( `find ./tests -type f -name "*.rs" -exec grep -l "${test}" {} \\;`, { stdio: ["pipe", "pipe", "pipe"], } ) .toString() .trim(); if (testsResult) { testsResult.split("\n").forEach((file) => results.add(file)); continue; } // If not found in tests, search in src const srcResult = execSync( `find ./src -type f -name "*.rs" -exec grep -l "${test}" {} \\;`, { stdio: ["pipe", "pipe", "pipe"], } ) .toString() .trim(); if (srcResult) { srcResult.split("\n").forEach((file) => results.add(file)); } } catch (error) { debug(`Error finding test file for ${test}: ${error.message}`); } } return Array.from(results); }; const testFiles = await findTestFiles(failedTests); if (testFiles.length === 0) { console.error("Could not find any test files"); process.exit(1); } debug(`Test files: ${testFiles.join(", ")}`); const testContents = testFiles .map((filename) => { try { return fs.readFileSync(filename, "utf8"); } catch (error) { debug(`Error reading file ${filename}: ${error.message}`); return ""; } }) .filter(Boolean); if (testContents.length === 0) { console.error("Could not read any test files"); process.exit(1); } debug("Asking deepseek..."); @@ -122,7 +206,14 @@ Promise.all([ }; const content = truncateAndEscape( [ `# Repo:`, serialized, `# Test contents:`, testContents.join("\n\n"), `# Test failures:`, testOutput, ].join("\n\n") ); debug(`Content length: ${content.length} characters`); -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 15 additions and 11 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -42,21 +42,25 @@ async function execCommand(program, args = [], options = {}) { debug(`Running: ${program} ${args.join(" ")}`); const process = spawn(program, args, { shell: true, stdio: ["pipe", "pipe", "pipe"], // Always pipe to capture output ...options, }); process.stdout.on("data", (data) => { const str = data.toString(); outputs.push(str); if (options.stdio === "inherit") { console.log(str); } }); process.stderr.on("data", (data) => { const str = data.toString(); outputs.push(str); if (options.stdio === "inherit") { console.error(str); } }); process.on("error", (error) => { if (options.returnError) { -
mohsen1 revised this gist
Jan 21, 2025 . 1 changed file with 144 additions and 81 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,5 @@ #!/usr/bin/env node // @ts-check /** * @fileoverview @@ -7,71 +8,121 @@ * The response is then printed to the console. */ const { spawn } = require("child_process"); const https = require("https"); const token = process.env.DEEPSEEK_API_KEY; const debugEnabled = process.argv.includes("--debug"); const testCommand = process.argv[2] || "cargo test"; const testProgram = testCommand.split(" ")[0]; const testArgs = testCommand.split(" ").slice(1); function debug(message) { if (debugEnabled) { console.log(`[DEBUG] ${message}`); } } if (!token) { console.error("DEEPSEEK_API_KEY is not set"); process.exit(1); } debug("Serializing..."); const maxTokens = 128000; // DeepSeek maximum context length is 128K tokens. we leave some room for the test failures. const maxSize = maxTokens - 10000; // 10000 tokens for test failures // Convert execSync to Promise-based execution async function execCommand(program, args = [], options = {}) { const outputs = []; return new Promise((resolve, reject) => { try { debug(`Running: ${program} ${args.join(" ")}`); const process = spawn(program, args, { shell: true, stdio: options.stdio || "inherit", ...options, }); if (process.stdout) { process.stdout.on("data", (data) => { outputs.push(data); }); } if (process.stderr) { process.stderr.on("data", (data) => { outputs.push(data); }); } process.on("error", (error) => { if (options.returnError) { resolve(outputs.join("")); } else { reject(error); } }); process.on("close", (code) => { const output = outputs.join(""); if (code !== 0) { if (options.returnError) { resolve(output); } else { reject( new Error(`Command failed with code ${code}\nOutput: ${output}`) ); } } else { resolve(output); } }); } catch (error) { if (options.returnError) { resolve(outputs.join("")); } else { reject(error); } } }); } // Run serialization and testing in parallel debug("Starting serialization and testing in parallel..."); Promise.all([ execCommand("yek", [`--max-size`, maxSize.toString(), `--tokens`], { stdio: ["pipe", "pipe", "pipe"], }), execCommand(testProgram, testArgs, { returnError: true, }), ]) .then(([serialized, testOutput]) => { const testFailures = testOutput .split("\n") .filter((line) => line.match(/test .* failed/)) .join("\n") .trim(); debug("Asking deepseek..."); // Truncate and escape content if too large const truncateAndEscape = (str) => { if (str.length > maxTokens) { str = str.slice(0, maxTokens) + "... (truncated)"; } return JSON.stringify(str); }; const content = truncateAndEscape( `# Repo:\n\n${serialized}\n\n# Test failures:\n\n${testFailures}` ); debug(`Content length: ${content.length} characters`); const systemPrompt = `You are a an expert Rust developer. You are familiar with the Rust language and its ecosystem. You use modern Rust and the latest Rust features. You are given a Rust project and some test failures. Your task is to help the user debug the test failures. @@ -81,57 +132,69 @@ Promise.all([ `; const data = JSON.stringify({ model: "deepseek-chat", messages: [ { role: "system", content: systemPrompt }, { role: "user", content }, ], stream: false, }); debug(`Request payload size: ${Buffer.byteLength(data)} bytes`); const options = { hostname: "api.deepseek.com", path: "/chat/completions", method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, "Content-Length": Buffer.byteLength(data), }, }; debug("Sending request to DeepSeek API..."); const req = https.request(options, (res) => { debug(`Response status: ${res.statusCode} ${res.statusMessage}`); let responseData = ""; res.on("data", (chunk) => { responseData += chunk; debug(`Received chunk of ${chunk.length} bytes`); }); res.on("end", () => { debug("Response completed"); try { const jsonResponse = JSON.parse(responseData); debug(`Parsed response successfully`); const content = jsonResponse?.choices?.[0]?.message?.content; if (content) { console.log(content); } else { console.error("No content found in the response"); debug(`Full response: ${JSON.stringify(jsonResponse, null, 2)}`); } } catch (error) { console.error("Failed to parse response:", responseData); debug(`Parse error: ${error.message}`); process.exit(1); } }); }); req.on("error", (error) => { console.error("Error:", error); debug(`Request error: ${error.message}`); process.exit(1); }); debug("Writing request payload..."); req.write(data); debug("Ending request"); req.end(); }) .catch((error) => { console.error("Error:", error); process.exit(1); }); -
mohsen1 created this gist
Jan 20, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,137 @@ #!/usr/bin/env node /** * @fileoverview * This script asks DeepSeek to help with debugging a Rust project. * It serializes the project, gets test failures, and sends the content to DeepSeek. * The response is then printed to the console. */ const { execSync } = require('child_process'); const https = require('https'); const token = process.env.DEEPSEEK_API_KEY; const testCommand = process.argv[2] || 'cargo test'; const debugEnabled = process.argv.includes('--debug'); function debug(message) { if (debugEnabled) { console.log(`[DEBUG] ${message}`); } } if (!token) { console.error('DEEPSEEK_API_KEY is not set'); process.exit(1); } debug('Serializing...'); // DeepSeek maximum context length is 128K tokens. we leave some room for the test failures. const maxSize = 128000 - 10000; // 10000 tokens for test failures // Convert execSync to Promise-based execution function execCommand(command, options = {}) { return new Promise((resolve, reject) => { try { const result = execSync(command, { ...options, encoding: 'utf8' }); resolve(result); } catch (error) { if (options.returnError) { resolve(error.stdout + error.stderr); } else { reject(error); } } }); } // Run serialization and testing in parallel debug('Starting serialization and testing in parallel...'); Promise.all([ execCommand(`yek --max-size ${maxSize} --tokens`), execCommand(testCommand, { stdio: ['pipe', 'pipe', 'pipe'], returnError: true }) ]) .then(([serialized, testOutput]) => { const testFailures = testOutput.split('\n') .filter(line => line.match(/test .* failed/)) .join('\n') .trim(); debug('Asking deepseek...'); // Truncate and escape content if too large const maxContentLength = 30000; // Adjust this value as needed const truncateAndEscape = (str) => { if (str.length > maxContentLength) { str = str.slice(0, maxContentLength) + '... (truncated)'; } return JSON.stringify(str); }; const content = truncateAndEscape(`Repo:\n\n${serialized}\n\nTest failures:\n\n${testFailures}`); const systemPrompt = `You are a an expert Rust developer. You are familiar with the Rust language and its ecosystem. You use modern Rust and the latest Rust features. You are given a Rust project and some test failures. Your task is to help the user debug the test failures. You should provide a detailed explanation of the test failures and how to fix them. Keep your response concise and to the point. Write **high-quality** and **clean** code. `; const data = JSON.stringify({ model: 'deepseek-chat', messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content } ], stream: false }); const options = { hostname: 'api.deepseek.com', path: '/chat/completions', method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, 'Content-Length': Buffer.byteLength(data) } }; const req = https.request(options, (res) => { let responseData = ''; res.on('data', (chunk) => { responseData += chunk; }); res.on('end', () => { try { const jsonResponse = JSON.parse(responseData); const content = jsonResponse?.choices?.[0]?.message?.content; if (content) { console.log(content); } else { console.error('No content found in the response'); } } catch (error) { console.error('Failed to parse response:', responseData); process.exit(1); } }); }); req.on('error', (error) => { console.error('Error:', error); process.exit(1); }); req.write(data); req.end(); }) .catch(error => { console.error('Error:', error); process.exit(1); });