codeep 1.0.28 → 1.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -343,7 +343,7 @@ async function agentChatFallback(messages, systemPrompt, onChunk, abortSignal, d
343
343
  ],
344
344
  stream: Boolean(onChunk),
345
345
  temperature: config.get('temperature'),
346
- max_tokens: config.get('maxTokens'),
346
+ max_tokens: Math.max(config.get('maxTokens'), 16384), // Ensure enough tokens for large file generation
347
347
  };
348
348
  }
349
349
  else {
@@ -357,7 +357,7 @@ async function agentChatFallback(messages, systemPrompt, onChunk, abortSignal, d
357
357
  ],
358
358
  stream: Boolean(onChunk),
359
359
  temperature: config.get('temperature'),
360
- max_tokens: config.get('maxTokens'),
360
+ max_tokens: Math.max(config.get('maxTokens'), 16384), // Ensure enough tokens for large file generation
361
361
  };
362
362
  }
363
363
  const response = await fetch(endpoint, {
@@ -226,7 +226,12 @@ export function parseOpenAIToolCalls(toolCalls) {
226
226
  }
227
227
  }
228
228
  // Validate required parameters for specific tools
229
- if (toolName === 'write_file' && (!parameters.path || parameters.content === undefined)) {
229
+ // For write_file, we need at least a path (content can be empty string or placeholder)
230
+ if (toolName === 'write_file' && !parameters.path) {
231
+ // Log for debugging write_file issues
232
+ if (process.env.CODEEP_DEBUG) {
233
+ console.error(`[WARN] write_file missing path, raw args: ${rawArgs.substring(0, 200)}`);
234
+ }
230
235
  continue;
231
236
  }
232
237
  if (toolName === 'read_file' && !parameters.path) {
@@ -252,21 +257,29 @@ function extractPartialToolParams(toolName, rawArgs) {
252
257
  // For write_file, try to extract path and content
253
258
  if (toolName === 'write_file') {
254
259
  const pathMatch = rawArgs.match(/"path"\s*:\s*"([^"]+)"/);
255
- const contentMatch = rawArgs.match(/"content"\s*:\s*"([\s\S]*?)(?:"|$)/);
256
- if (pathMatch && contentMatch) {
257
- // Unescape the content
258
- let content = contentMatch[1];
259
- content = content
260
- .replace(/\\n/g, '\n')
261
- .replace(/\\t/g, '\t')
262
- .replace(/\\r/g, '\r')
263
- .replace(/\\"/g, '"')
264
- .replace(/\\\\/g, '\\');
265
- // If content appears truncated (doesn't end properly), add a comment
266
- if (!content.endsWith('\n') && !content.endsWith('}') && !content.endsWith(';') && !content.endsWith('>')) {
267
- content += '\n<!-- Content may be truncated -->\n';
268
- }
269
- return { path: pathMatch[1], content };
260
+ if (pathMatch) {
261
+ // Try to extract content - it may be truncated
262
+ const contentMatch = rawArgs.match(/"content"\s*:\s*"([\s\S]*?)(?:"|$)/);
263
+ if (contentMatch) {
264
+ // Unescape the content
265
+ let content = contentMatch[1];
266
+ content = content
267
+ .replace(/\\n/g, '\n')
268
+ .replace(/\\t/g, '\t')
269
+ .replace(/\\r/g, '\r')
270
+ .replace(/\\"/g, '"')
271
+ .replace(/\\\\/g, '\\');
272
+ // If content appears truncated (doesn't end properly), add a comment
273
+ if (!content.endsWith('\n') && !content.endsWith('}') && !content.endsWith(';') && !content.endsWith('>')) {
274
+ content += '\n<!-- Content may be truncated -->\n';
275
+ }
276
+ return { path: pathMatch[1], content };
277
+ }
278
+ else {
279
+ // Path found but content completely missing or malformed
280
+ // Return with empty content placeholder so the file is at least created
281
+ return { path: pathMatch[1], content: '<!-- Content was truncated by API -->\n' };
282
+ }
270
283
  }
271
284
  }
272
285
  // For read_file, just need path
@@ -553,7 +566,16 @@ function tryParseToolCall(str) {
553
566
  * Validate path is within project
554
567
  */
555
568
  function validatePath(path, projectRoot) {
556
- const absolutePath = isAbsolute(path) ? path : resolve(projectRoot, path);
569
+ // If path is absolute but starts with projectRoot, convert to relative
570
+ let normalizedPath = path;
571
+ if (isAbsolute(path) && path.startsWith(projectRoot)) {
572
+ normalizedPath = relative(projectRoot, path);
573
+ }
574
+ // If still absolute and doesn't match projectRoot, reject it
575
+ if (isAbsolute(normalizedPath)) {
576
+ return { valid: false, absolutePath: normalizedPath, error: `Absolute path '${path}' not allowed. Use relative paths.` };
577
+ }
578
+ const absolutePath = resolve(projectRoot, normalizedPath);
557
579
  const relativePath = relative(projectRoot, absolutePath);
558
580
  if (relativePath.startsWith('..')) {
559
581
  return { valid: false, absolutePath, error: `Path '${path}' is outside project directory` };
@@ -594,12 +616,13 @@ export function executeTool(toolCall, projectRoot) {
594
616
  }
595
617
  case 'write_file': {
596
618
  const path = parameters.path;
597
- const content = parameters.content;
619
+ let content = parameters.content;
598
620
  if (!path) {
599
621
  return { success: false, output: '', error: 'Missing required parameter: path', tool, parameters };
600
622
  }
601
- if (content === undefined) {
602
- return { success: false, output: '', error: 'Missing required parameter: content', tool, parameters };
623
+ // Allow empty content or provide placeholder for truncated responses
624
+ if (content === undefined || content === null) {
625
+ content = '<!-- Content was not provided -->\n';
603
626
  }
604
627
  const validation = validatePath(path, projectRoot);
605
628
  if (!validation.valid) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.0.28",
3
+ "version": "1.0.29",
4
4
  "description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",