Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions apps/web/src/components/code-reviews/ReviewConfigForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ export function ReviewConfigForm({
platform,
reviewStyle,
focusAreas,
customInstructions: customInstructions.trim() || undefined,
customInstructions: customInstructions || undefined,
modelSlug: selectedModel,
thinkingEffort,
gateThreshold,
Expand All @@ -470,7 +470,7 @@ export function ReviewConfigForm({
platform,
reviewStyle,
focusAreas,
customInstructions: customInstructions.trim() || undefined,
customInstructions: customInstructions || undefined,
modelSlug: selectedModel,
thinkingEffort,
gateThreshold,
Expand Down Expand Up @@ -1047,18 +1047,30 @@ export function ReviewConfigForm({

{/* Custom Instructions */}
<div className="space-y-3">
<Label htmlFor="custom-instructions">Custom Instructions (Optional)</Label>
<Label htmlFor="custom-instructions">Custom Instructions (Deprecated)</Label>
<Textarea
id="custom-instructions"
placeholder="e.g., 'Always check for TypeScript strict mode compliance' or 'Focus on React best practices'"
value={customInstructions}
onChange={e => setCustomInstructions(e.target.value)}
rows={4}
className="resize-none"
disabled
aria-describedby="custom-instructions-deprecation"
/>
<p className="text-muted-foreground text-sm">
Add specific guidelines for your team's code review standards
</p>
<Alert id="custom-instructions-deprecation" variant="warning">
<AlertCircle className="size-4" />
<AlertTitle>Custom instructions are no longer applied</AlertTitle>
<AlertDescription>
This value remains visible to help you migrate it, but Code Reviewer no longer
uses it. Move any guidance you still need to a REVIEW.md file in the repository
root.{' '}
<Link
href={reviewMdGuideHref}
className="text-blue-400 underline-offset-4 hover:text-blue-300 hover:underline"
>
Learn about REVIEW.md
</Link>
</AlertDescription>
</Alert>
</div>

{/* Save Button */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const guidanceItems = [

const limits = [
'Hard safety, tooling, platform, and read-only constraints still apply.',
'Custom instructions and focus areas are still applied around repository guidance.',
'Focus areas are still applied around repository guidance.',
'@ imports are not expanded. Keep the guidance directly in REVIEW.md.',
'Content is truncated after 10,000 characters.',
'Do not include secrets, credentials, tokens, or private operational data.',
Expand Down
14 changes: 7 additions & 7 deletions apps/web/src/lib/code-reviews/prompts/generate-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,12 @@ describe('resolveTemplate', () => {

// --- generateReviewPrompt (integration) ---

const legacyCustomInstructions = 'Also consider account-level policy.';

const baseConfig = {
review_style: 'balanced' as const,
focus_areas: [],
custom_instructions: '',
custom_instructions: legacyCustomInstructions,
model_slug: 'test-model',
} satisfies CodeReviewAgentConfig;

Expand All @@ -152,6 +154,8 @@ describe('generateReviewPrompt', () => {
expect(prompt).toContain('# WHAT TO REVIEW');
expect(prompt).toContain('Security vulnerabilities (injection, XSS, auth bypass)');
expect(prompt).not.toContain(`# ${REVIEW_INSTRUCTIONS_FILE} code review instructions`);
expect(prompt).not.toContain('# CUSTOM INSTRUCTIONS');
expect(prompt).not.toContain(legacyCustomInstructions);
});

it('replaces built-in review guidance with REVIEW.md instructions at the same prompt point', async () => {
Expand All @@ -164,16 +168,15 @@ describe('generateReviewPrompt', () => {
].join('\n');
const customConfig = {
...baseConfig,
custom_instructions: 'Also consider account-level policy.',
focus_areas: ['security'],
} satisfies CodeReviewAgentConfig;

const { prompt } = await generateReviewPrompt(customConfig, 'owner/repo', 1, {
repositoryReviewInstructions,
});

expect(prompt).toContain('# CUSTOM INSTRUCTIONS');
expect(prompt).toContain('Also consider account-level policy.');
expect(prompt).not.toContain('# CUSTOM INSTRUCTIONS');
expect(prompt).not.toContain(legacyCustomInstructions);
expect(prompt).toContain(`# ${REVIEW_INSTRUCTIONS_FILE} code review instructions`);
expect(prompt).toContain('Only flag regressions with direct evidence.');
expect(prompt).toContain('```ts\nconst markdown = true;\n```');
Expand All @@ -185,9 +188,6 @@ describe('generateReviewPrompt', () => {
expect(prompt).toContain('# COMMENT FORMAT');
expect(prompt).toContain('## Inline Comments API Call');

expect(prompt.indexOf('# CUSTOM INSTRUCTIONS')).toBeLessThan(
prompt.indexOf(`# ${REVIEW_INSTRUCTIONS_FILE} code review instructions`)
);
expect(prompt.indexOf(`# ${REVIEW_INSTRUCTIONS_FILE} code review instructions`)).toBeLessThan(
prompt.indexOf('# FOCUS AREAS')
);
Expand Down
20 changes: 7 additions & 13 deletions apps/web/src/lib/code-reviews/prompts/generate-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* 4. Adding dynamic context (existing comments table)
* 5. Selecting CREATE vs UPDATE summary command
* 6. Platform-specific template selection (GitHub vs GitLab)
* 7. Injecting style guidance, custom instructions, and focus areas from config
* 7. Injecting style guidance and focus areas from config
* 8. Applying per-style comment format and summary format overrides
*/

Expand All @@ -22,7 +22,6 @@ import { logExceptInTest } from '@/lib/utils.server';
import type { CodeReviewPlatform } from '@/lib/code-reviews/core/schemas';
import { getPromptTemplateFeatureFlag, getPlatformConfig } from './platform-helpers';
import { PLATFORM } from '@/lib/integrations/core/constants';
import { sanitizeUserInput } from './prompt-utils';
import { formatRepositoryReviewInstructions } from './repository-review-instructions';
import { getCurrentReviewSummaryForContext } from '../summary/history';

Expand Down Expand Up @@ -263,15 +262,10 @@ export async function generateReviewPrompt(
prompt += styleGuide + '\n\n';
}

// 3. Custom instructions (user-provided, sanitized to prevent injection)
if (config.custom_instructions) {
prompt += '# CUSTOM INSTRUCTIONS\n\n' + sanitizeUserInput(config.custom_instructions) + '\n\n';
}

// 4. Hard constraints (MOST IMPORTANT - always included)
// 3. Hard constraints (MOST IMPORTANT - always included)
prompt += template.hardConstraints + '\n\n';

// 5. Workflow with placeholders replaced
// 4. Workflow with placeholders replaced
// Use incremental workflow when we have a previous completed review SHA and a summary comment
if (
previousHeadSha &&
Expand Down Expand Up @@ -305,27 +299,27 @@ export async function generateReviewPrompt(
}
}

// 6. What to review
// 5. What to review
prompt +=
(repositoryReviewInstructions
? formatRepositoryReviewInstructions(repositoryReviewInstructions)
: template.whatToReview) + '\n\n';

// 7. Focus areas (if any selected)
// 6. Focus areas (if any selected)
if (config.focus_areas.length > 0) {
prompt +=
'# FOCUS AREAS\n\nPay special attention to: ' + config.focus_areas.join(', ') + '\n\n';
}

// 8. Comment format (use style override if available, otherwise default)
// 7. Comment format (use style override if available, otherwise default)
const commentFormat = template.commentFormatOverrides?.[reviewStyle] ?? template.commentFormat;
prompt += commentFormat + '\n\n';

if (platform === 'github' && template.inlineCommentFooter) {
prompt += template.inlineCommentFooter + '\n\n';
}

// 9. Dynamic context section (separator)
// 8. Dynamic context section (separator)
prompt += '---\n\n# CONTEXT FOR THIS ' + platformConfig.prTerm + '\n\n';
prompt += `**${platform === PLATFORM.GITLAB ? 'Project' : 'Repository'}:** ${repository}\n`;
prompt += `**${platformConfig.prTerm} Number:** ${pr}\n\n`;
Expand Down