codecritique 1.1.0 → 1.2.0
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.
- package/README.md +53 -579
- package/package.json +1 -1
- package/src/index.js +2 -0
- package/src/llm.js +59 -40
- package/src/llm.test.js +14 -2
- package/src/project-analyzer.js +13 -50
- package/src/prompt-cache.js +627 -0
- package/src/rag-analyzer.js +112 -455
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -54,6 +54,7 @@ program
|
|
|
54
54
|
.option('--model <model>', 'LLM model to use (e.g., claude-sonnet-4-5)')
|
|
55
55
|
.option('--temperature <number>', 'LLM temperature', parseFloat, 0.2)
|
|
56
56
|
.option('--max-tokens <number>', 'LLM max tokens', parseInt, 8192)
|
|
57
|
+
.option('--cache-ttl <ttl>', 'Cache TTL for LLM prompts: "5m" (default, no extra cost) or "1h" (extended, extra cost for writes)', '5m')
|
|
57
58
|
.option('--similarity-threshold <number>', 'Threshold for finding similar code examples', parseFloat, 0.6)
|
|
58
59
|
.option('--max-examples <number>', 'Max similar code examples to use', parseInt, 5)
|
|
59
60
|
.option('--concurrency <number>', 'Concurrency for processing multiple files', parseInt, 3)
|
|
@@ -329,6 +330,7 @@ async function runCodeReview(options) {
|
|
|
329
330
|
model: options.model,
|
|
330
331
|
temperature: options.temperature,
|
|
331
332
|
maxTokens: options.maxTokens,
|
|
333
|
+
cacheTtl: options.cacheTtl,
|
|
332
334
|
similarityThreshold: options.similarityThreshold,
|
|
333
335
|
maxExamples: options.maxExamples,
|
|
334
336
|
concurrency: options.concurrency,
|
package/src/llm.js
CHANGED
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* for code analysis and review. Enhanced to leverage project-specific patterns and
|
|
6
6
|
* feedback from PR reviews for more context-aware recommendations.
|
|
7
7
|
* Currently supports Anthropic's Claude Sonnet 4.
|
|
8
|
+
*
|
|
9
|
+
* Prompt Caching:
|
|
10
|
+
* This module uses Anthropic's prompt caching feature for cost optimization.
|
|
11
|
+
* Static content in the system message is cached and reused across multiple
|
|
12
|
+
* requests, reducing input token costs by 75%.
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
import { Anthropic } from '@anthropic-ai/sdk';
|
|
@@ -15,6 +20,7 @@ import dotenv from 'dotenv';
|
|
|
15
20
|
dotenv.config();
|
|
16
21
|
|
|
17
22
|
let anthropic = null;
|
|
23
|
+
|
|
18
24
|
/**
|
|
19
25
|
* Get the Anthropic client
|
|
20
26
|
* @returns {Anthropic} The Anthropic client
|
|
@@ -36,80 +42,93 @@ const DEFAULT_MODEL = 'claude-sonnet-4-5';
|
|
|
36
42
|
const MAX_TOKENS = 4096;
|
|
37
43
|
|
|
38
44
|
/**
|
|
39
|
-
* Send a prompt to Claude and get a structured JSON response using tool calling
|
|
45
|
+
* Send a prompt to Claude and get a structured JSON response using tool calling.
|
|
46
|
+
* Uses prompt caching for system prompts to reduce token costs.
|
|
40
47
|
*
|
|
41
48
|
* @param {string} prompt - The prompt to send to Claude
|
|
42
49
|
* @param {Object} options - Options for the request
|
|
50
|
+
* @param {string} options.system - System prompt (will be cached for cost optimization)
|
|
43
51
|
* @param {Object} options.jsonSchema - JSON schema for structured output
|
|
52
|
+
* @param {string} options.cacheTtl - Cache TTL: '5m' (default, no extra cost) or '1h' (extended, extra cost for writes)
|
|
44
53
|
* @returns {Promise<Object>} The response from Claude with structured data
|
|
45
54
|
*/
|
|
46
55
|
async function sendPromptToClaude(prompt, options = {}) {
|
|
47
|
-
const { model = DEFAULT_MODEL, maxTokens = MAX_TOKENS, temperature = 0.7, system = '', jsonSchema = null } = options;
|
|
56
|
+
const { model = DEFAULT_MODEL, maxTokens = MAX_TOKENS, temperature = 0.7, system = '', jsonSchema = null, cacheTtl = '5m' } = options;
|
|
48
57
|
|
|
49
58
|
try {
|
|
50
59
|
console.log(chalk.cyan('Sending prompt to Claude...'));
|
|
51
60
|
|
|
52
61
|
const client = getAnthropicClient();
|
|
53
62
|
|
|
54
|
-
//
|
|
63
|
+
// Build system content with cache_control for cost optimization
|
|
64
|
+
// The system is passed as an array of blocks with cache_control on the static portion
|
|
65
|
+
// TTL options: '5m' (default, no extra cost) or '1h' (extended, extra cost for cache writes)
|
|
66
|
+
const cacheControl = cacheTtl === '1h' ? { type: 'ephemeral', ttl: '1h' } : { type: 'ephemeral' };
|
|
67
|
+
|
|
68
|
+
const systemContent = system
|
|
69
|
+
? [
|
|
70
|
+
{
|
|
71
|
+
type: 'text',
|
|
72
|
+
text: system,
|
|
73
|
+
cache_control: cacheControl,
|
|
74
|
+
},
|
|
75
|
+
]
|
|
76
|
+
: 'You are an expert code reviewer with deep knowledge of software engineering principles, design patterns, and best practices.';
|
|
77
|
+
|
|
78
|
+
// Build base request parameters
|
|
79
|
+
const requestParams = {
|
|
80
|
+
model,
|
|
81
|
+
max_tokens: maxTokens,
|
|
82
|
+
temperature,
|
|
83
|
+
system: systemContent,
|
|
84
|
+
messages: [
|
|
85
|
+
{
|
|
86
|
+
role: 'user',
|
|
87
|
+
content: prompt,
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Add tool calling if JSON schema is provided
|
|
55
93
|
if (jsonSchema) {
|
|
56
|
-
|
|
94
|
+
requestParams.tools = [
|
|
57
95
|
{
|
|
58
96
|
name: 'return_json',
|
|
59
97
|
description: 'Return the final answer strictly as JSON matching the schema.',
|
|
60
98
|
input_schema: jsonSchema,
|
|
61
99
|
},
|
|
62
100
|
];
|
|
101
|
+
requestParams.tool_choice = { type: 'tool', name: 'return_json' };
|
|
102
|
+
}
|
|
63
103
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
tool_choice: { type: 'tool', name: 'return_json' },
|
|
70
|
-
system:
|
|
71
|
-
system ||
|
|
72
|
-
'You are an expert code reviewer with deep knowledge of software engineering principles, design patterns, and best practices.',
|
|
73
|
-
messages: [
|
|
74
|
-
{
|
|
75
|
-
role: 'user',
|
|
76
|
-
content: prompt,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
});
|
|
104
|
+
const response = await client.messages.create(requestParams);
|
|
105
|
+
|
|
106
|
+
// Log response structure for debugging
|
|
107
|
+
console.log(chalk.gray(` Response stop_reason: ${response.stop_reason}`));
|
|
108
|
+
console.log(chalk.gray(` Response content blocks: ${response.content?.length || 0}`));
|
|
80
109
|
|
|
81
|
-
|
|
110
|
+
// Process response based on whether we used tool calling
|
|
111
|
+
if (jsonSchema) {
|
|
82
112
|
const toolUse = response.content.find((block) => block.type === 'tool_use' && block.name === 'return_json');
|
|
83
113
|
|
|
84
114
|
if (!toolUse) {
|
|
115
|
+
// Log actual content for debugging
|
|
116
|
+
console.error(chalk.red('No tool_use block found. Response content:'));
|
|
117
|
+
response.content?.forEach((block, i) => {
|
|
118
|
+
console.error(chalk.gray(` Block ${i}: type=${block.type}, name=${block.name || 'N/A'}`));
|
|
119
|
+
});
|
|
85
120
|
throw new Error('No structured output received from Claude');
|
|
86
121
|
}
|
|
87
122
|
|
|
88
123
|
return {
|
|
89
|
-
content: JSON.stringify(toolUse.input, null, 2),
|
|
124
|
+
content: JSON.stringify(toolUse.input, null, 2),
|
|
90
125
|
model: response.model,
|
|
91
126
|
usage: response.usage,
|
|
92
|
-
json: toolUse.input,
|
|
127
|
+
json: toolUse.input,
|
|
93
128
|
};
|
|
94
129
|
} else {
|
|
95
|
-
// Fallback to regular text response
|
|
96
|
-
const response = await client.messages.create({
|
|
97
|
-
model,
|
|
98
|
-
max_tokens: maxTokens,
|
|
99
|
-
temperature,
|
|
100
|
-
system:
|
|
101
|
-
system ||
|
|
102
|
-
'You are an expert code reviewer with deep knowledge of software engineering principles, design patterns, and best practices.',
|
|
103
|
-
messages: [
|
|
104
|
-
{
|
|
105
|
-
role: 'user',
|
|
106
|
-
content: prompt,
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
});
|
|
110
|
-
|
|
111
130
|
return {
|
|
112
|
-
content: response.content[0]
|
|
131
|
+
content: response.content[0]?.text || '',
|
|
113
132
|
model: response.model,
|
|
114
133
|
usage: response.usage,
|
|
115
134
|
};
|
package/src/llm.test.js
CHANGED
|
@@ -75,7 +75,13 @@ describe('sendPromptToClaude', () => {
|
|
|
75
75
|
model: 'claude-3-opus',
|
|
76
76
|
max_tokens: 8192,
|
|
77
77
|
temperature: 0.5,
|
|
78
|
-
system:
|
|
78
|
+
system: [
|
|
79
|
+
{
|
|
80
|
+
type: 'text',
|
|
81
|
+
text: 'Custom system prompt',
|
|
82
|
+
cache_control: { type: 'ephemeral' },
|
|
83
|
+
},
|
|
84
|
+
],
|
|
79
85
|
})
|
|
80
86
|
);
|
|
81
87
|
});
|
|
@@ -225,7 +231,13 @@ describe('sendPromptToClaude', () => {
|
|
|
225
231
|
|
|
226
232
|
expect(mockMessagesCreate).toHaveBeenCalledWith(
|
|
227
233
|
expect.objectContaining({
|
|
228
|
-
system:
|
|
234
|
+
system: [
|
|
235
|
+
{
|
|
236
|
+
type: 'text',
|
|
237
|
+
text: customSystem,
|
|
238
|
+
cache_control: { type: 'ephemeral' },
|
|
239
|
+
},
|
|
240
|
+
],
|
|
229
241
|
})
|
|
230
242
|
);
|
|
231
243
|
});
|
package/src/project-analyzer.js
CHANGED
|
@@ -11,6 +11,7 @@ import path from 'path';
|
|
|
11
11
|
import chalk from 'chalk';
|
|
12
12
|
import { getDefaultEmbeddingsSystem } from './embeddings/factory.js';
|
|
13
13
|
import * as llm from './llm.js';
|
|
14
|
+
import { FILE_SELECTION_SYSTEM_PROMPT, PROJECT_SUMMARY_SYSTEM_PROMPT } from './prompt-cache.js';
|
|
14
15
|
import { isDocumentationFile, isTestFile } from './utils/file-validation.js';
|
|
15
16
|
|
|
16
17
|
// Consolidated file classification configuration
|
|
@@ -494,18 +495,7 @@ Project: ${path.basename(projectPath)}
|
|
|
494
495
|
Files found by embeddings search:
|
|
495
496
|
${candidatesSummary}
|
|
496
497
|
|
|
497
|
-
Select files
|
|
498
|
-
- Framework setup & key configurations
|
|
499
|
-
- Custom utilities, hooks, and wrappers
|
|
500
|
-
- API/data layer patterns and GraphQL setup
|
|
501
|
-
- Type definitions & core interfaces
|
|
502
|
-
- Entry points, routing, and main structure
|
|
503
|
-
- State management and data flow patterns
|
|
504
|
-
|
|
505
|
-
IMPORTANT: Return ONLY a JSON array of file paths, nothing else:
|
|
506
|
-
["path1", "path2", "path3"]
|
|
507
|
-
|
|
508
|
-
Select files that define HOW this project works, especially custom implementations.`;
|
|
498
|
+
Select files following the criteria in the system instructions.`;
|
|
509
499
|
|
|
510
500
|
try {
|
|
511
501
|
const fileSelectionSchema = {
|
|
@@ -524,6 +514,7 @@ Select files that define HOW this project works, especially custom implementatio
|
|
|
524
514
|
};
|
|
525
515
|
|
|
526
516
|
const response = await this.llm.sendPromptToClaude(prompt, {
|
|
517
|
+
system: FILE_SELECTION_SYSTEM_PROMPT,
|
|
527
518
|
temperature: 0.1,
|
|
528
519
|
maxTokens: 1000,
|
|
529
520
|
jsonSchema: fileSelectionSchema,
|
|
@@ -636,11 +627,15 @@ Select files that define HOW this project works, especially custom implementatio
|
|
|
636
627
|
async generateProjectSummary(keyFiles, projectPath) {
|
|
637
628
|
const fileContents = await this.extractFileContents(keyFiles);
|
|
638
629
|
|
|
639
|
-
const prompt = `Analyze this project's architecture and provide a comprehensive summary.
|
|
630
|
+
const prompt = `Analyze this project's architecture and provide a comprehensive summary.
|
|
631
|
+
|
|
632
|
+
## KEY FILES
|
|
640
633
|
|
|
641
634
|
${fileContents}
|
|
642
635
|
|
|
643
|
-
|
|
636
|
+
## OUTPUT FORMAT
|
|
637
|
+
|
|
638
|
+
Provide a JSON response with this structure:
|
|
644
639
|
|
|
645
640
|
{
|
|
646
641
|
"projectName": "Project name from package.json or inferred",
|
|
@@ -661,7 +656,7 @@ Please analyze this project and provide a JSON response with:
|
|
|
661
656
|
"name": "Custom feature/hook/utility name",
|
|
662
657
|
"description": "What it does and HOW it modifies standard library behavior",
|
|
663
658
|
"files": ["Files where it's defined"],
|
|
664
|
-
"properties": ["Key properties/methods it exposes
|
|
659
|
+
"properties": ["Key properties/methods it exposes"],
|
|
665
660
|
"usage": "How it should be used",
|
|
666
661
|
"extendsStandard": "Which standard library/framework objects or APIs this modifies"
|
|
667
662
|
}
|
|
@@ -697,44 +692,11 @@ Please analyze this project and provide a JSON response with:
|
|
|
697
692
|
"reviewGuidelines": [
|
|
698
693
|
"Specific guidelines for code review based on this project's patterns",
|
|
699
694
|
"What to look for in PRs",
|
|
700
|
-
"Common patterns that should be maintained"
|
|
701
|
-
"Potential issues specific to this architecture"
|
|
695
|
+
"Common patterns that should be maintained"
|
|
702
696
|
]
|
|
703
697
|
}
|
|
704
698
|
|
|
705
|
-
|
|
706
|
-
- Custom utilities or modules that extend standard frameworks and libraries
|
|
707
|
-
- **CRITICAL: Custom properties or methods added to standard library objects** (e.g., custom properties on database query results, API responses, or framework objects)
|
|
708
|
-
- **Extensions to library APIs** - any way this project modifies or enhances standard library behavior
|
|
709
|
-
- Specific ways APIs are called and results are handled (look for non-standard patterns)
|
|
710
|
-
- Data flow and processing patterns
|
|
711
|
-
- Module organization and code structure patterns
|
|
712
|
-
- Type definitions and interfaces that define contracts, especially those that extend standard types
|
|
713
|
-
- Configuration patterns and environment handling
|
|
714
|
-
- **Custom wrappers** around standard libraries that add functionality
|
|
715
|
-
|
|
716
|
-
**CRITICAL ANALYSIS REQUIRED**: Look specifically for code that:
|
|
717
|
-
1. **Takes standard library return values and adds custom properties** - For example:
|
|
718
|
-
- Functions that take query results and add success/loading/error properties
|
|
719
|
-
- Wrappers that enhance API responses with additional metadata
|
|
720
|
-
- Custom hooks that extend standard framework hooks with extra functionality
|
|
721
|
-
2. **Modifies or extends standard library interfaces** - Look for:
|
|
722
|
-
- TypeScript interfaces that extend standard types with additional fields
|
|
723
|
-
- Custom implementations that add methods to standard objects
|
|
724
|
-
- Wrapper classes that enhance standard library functionality
|
|
725
|
-
3. **Creates custom versions of standard patterns** - Such as:
|
|
726
|
-
- Custom error handling that adds properties to standard error objects
|
|
727
|
-
- Middleware that modifies standard request/response patterns
|
|
728
|
-
- Custom state management that extends standard patterns
|
|
729
|
-
|
|
730
|
-
**EXAMPLES TO RECOGNIZE**:
|
|
731
|
-
- If you see a function that takes a standard query result and returns an object with added success/error properties, identify this as a custom implementation
|
|
732
|
-
- If you see custom hooks that wrap standard library hooks and add properties, document these
|
|
733
|
-
- If you see type definitions that extend standard interfaces, note what properties they add
|
|
734
|
-
|
|
735
|
-
**OUTPUT REQUIREMENT**: For each custom implementation found, specifically identify what standard library object or pattern it extends in the "extendsStandard" field.
|
|
736
|
-
|
|
737
|
-
Be thorough but concise. This summary will be used to provide context during automated code reviews to prevent false positives about "non-standard" properties that are actually valid custom implementations in this project.`;
|
|
699
|
+
Follow the analysis guidelines from the system instructions to identify custom implementations and patterns.`;
|
|
738
700
|
|
|
739
701
|
try {
|
|
740
702
|
const projectSummarySchema = {
|
|
@@ -807,6 +769,7 @@ Be thorough but concise. This summary will be used to provide context during aut
|
|
|
807
769
|
};
|
|
808
770
|
|
|
809
771
|
const response = await this.llm.sendPromptToClaude(prompt, {
|
|
772
|
+
system: PROJECT_SUMMARY_SYSTEM_PROMPT,
|
|
810
773
|
temperature: 0.1,
|
|
811
774
|
maxTokens: 4000,
|
|
812
775
|
jsonSchema: projectSummarySchema,
|