Standardise Issue/Recommendation formatting across all agents
Replace single-line bullet format with a structured two-part format (**Issue:** / **Recommendation:**) in all specialist and lead agent prompts. Update Gemini response schema description to match. Update frontend formatFeedbackText and formatFeedbackTextForPDF to parse **bold** markdown and preserve line breaks within multi-line bullets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f1183e1bff
commit
3207ec301c
8 changed files with 129 additions and 47 deletions
|
|
@ -143,9 +143,14 @@ If the proof is nonsensical, not a marketing material, or cannot be analyzed, se
|
|||
**Response Format:**
|
||||
- Keep feedback brief and scannable
|
||||
- Use bullet points for each finding
|
||||
- Each bullet should be one actionable sentence
|
||||
- Start with the issue, then the recommendation
|
||||
- Example: "Logo placement incorrect (bottom-left) - move to top-right corner per guidelines"
|
||||
- Structure each feedback bullet as two clearly labelled parts separated by a line break:
|
||||
**Issue:** [Clear description of what's wrong]
|
||||
**Recommendation:** [Actionable fix — what to do and how]
|
||||
- Always capitalise "Issue:" and "Recommendation:" and bold them with double asterisks (**)
|
||||
- Always place the Recommendation on a new line after the Issue (not on the same line)
|
||||
- Example:
|
||||
"• **Issue:** The logo is placed in the bottom-left corner, which doesn't align with brand guidelines.
|
||||
**Recommendation:** Move the logo to the top-right corner as specified in the brand guidelines."
|
||||
- IMPORTANT: Use British English spelling throughout all output (e.g. "authorised" not "authorized", "colour" not "color", "capitalise" not "capitalize", "organised" not "organized", "centre" not "center", "analysed" not "analyzed").
|
||||
- IMPORTANT: Never use the words "violation", "violates", or "violated" in your output. Use constructive alternatives such as "issue", "doesn't align with", "doesn't meet", or "conflicts with".
|
||||
- IMPORTANT: Use Plain English throughout. Choose simple, clear words over complex vocabulary. Prefer: "add" over "incorporate/integrate", "about" over "regarding", "qualifies as" over "constitutes", "use" over "utilise", "before" over "prior to", "to" over "in order to", "try" over "endeavour", "then" over "subsequently", "put in place" over "implement", "keep/contain" over "constrain", "standard interest rate" over "reversion rate". Avoid unnecessary jargon (e.g. use "exaggerated claim" instead of "puffery"). Feedback should be easy to understand for all users.
|
||||
|
|
|
|||
|
|
@ -136,9 +136,14 @@ If the proof is nonsensical, not a marketing material, or cannot be analyzed, se
|
|||
**Response Format:**
|
||||
- Keep feedback brief and scannable
|
||||
- Use bullet points for each finding
|
||||
- Each bullet should be one actionable sentence
|
||||
- Start with the issue, then the recommendation
|
||||
- Example: "CTA placement below fold - move above fold for better visibility"
|
||||
- Structure each feedback bullet as two clearly labelled parts separated by a line break:
|
||||
**Issue:** [Clear description of what's wrong]
|
||||
**Recommendation:** [Actionable fix — what to do and how]
|
||||
- Always capitalise "Issue:" and "Recommendation:" and bold them with double asterisks (**)
|
||||
- Always place the Recommendation on a new line after the Issue (not on the same line)
|
||||
- Example:
|
||||
"• **Issue:** The Call-to-Action (CTA) is placed below the fold, reducing visibility.
|
||||
**Recommendation:** Move the CTA above the fold so users see it without scrolling."
|
||||
- IMPORTANT: Use British English spelling throughout all output (e.g. "authorised" not "authorized", "colour" not "color", "capitalise" not "capitalize", "organised" not "organized", "centre" not "center", "analysed" not "analyzed").
|
||||
- IMPORTANT: Never use the words "violation", "violates", or "violated" in your output. Use constructive alternatives such as "issue", "doesn't align with", "doesn't meet", or "conflicts with".
|
||||
- IMPORTANT: Use Plain English throughout. Choose simple, clear words over complex vocabulary. Prefer: "add" over "incorporate/integrate", "about" over "regarding", "qualifies as" over "constitutes", "use" over "utilise", "before" over "prior to", "to" over "in order to", "try" over "endeavour", "then" over "subsequently", "put in place" over "implement", "keep/contain" over "constrain", "standard interest rate" over "reversion rate". Avoid unnecessary jargon (e.g. use "exaggerated claim" instead of "puffery"). Feedback should be easy to understand for all users.
|
||||
|
|
|
|||
|
|
@ -144,9 +144,14 @@ If the proof is nonsensical, not a marketing material, or cannot be analyzed, se
|
|||
- Then provide your analysis findings below
|
||||
- Keep feedback brief and scannable
|
||||
- Use bullet points for each finding
|
||||
- Each bullet should be one actionable sentence
|
||||
- Start with the issue, then the specification requirement
|
||||
- Example: "Image resolution 72dpi - increase to minimum 150dpi for print quality"
|
||||
- Structure each feedback bullet as two clearly labelled parts separated by a line break:
|
||||
**Issue:** [Clear description of what's wrong]
|
||||
**Recommendation:** [Actionable fix — what to do and how]
|
||||
- Always capitalise "Issue:" and "Recommendation:" and bold them with double asterisks (**)
|
||||
- Always place the Recommendation on a new line after the Issue (not on the same line)
|
||||
- Example:
|
||||
"• **Issue:** The image resolution is 72 DPI (dots per inch), which is below the minimum for this format.
|
||||
**Recommendation:** Increase the resolution to at least 150 DPI to meet the platform's quality requirements."
|
||||
- IMPORTANT: Use British English spelling throughout all output (e.g. "authorised" not "authorized", "colour" not "color", "capitalise" not "capitalize", "organised" not "organized", "centre" not "center", "analysed" not "analyzed").
|
||||
- IMPORTANT: Never use the words "violation", "violates", or "violated" in your output. Use constructive alternatives such as "issue", "doesn't align with", "doesn't meet", or "conflicts with".
|
||||
- IMPORTANT: Use Plain English throughout. Choose simple, clear words over complex vocabulary. Prefer: "add" over "incorporate/integrate", "about" over "regarding", "qualifies as" over "constitutes", "use" over "utilise", "before" over "prior to", "to" over "in order to", "try" over "endeavour", "then" over "subsequently", "put in place" over "implement", "keep/contain" over "constrain", "standard interest rate" over "reversion rate". Avoid unnecessary jargon (e.g. use "exaggerated claim" instead of "puffery"). Feedback should be easy to understand for all users.
|
||||
|
|
|
|||
|
|
@ -149,8 +149,14 @@ Your summary should:
|
|||
- For 'Analysis Error': "This proof could not be reliably processed."
|
||||
- For 'Requires Manual Legal Review': "This proof requires manual legal review."
|
||||
- Do NOT prefix the opening line with "Verdict:", "Summary:", "Result:", or any other label.
|
||||
- Follow the opening line with bullet points listing the key actions (max 3-5 bullets)
|
||||
- Each bullet: one sentence, actionable
|
||||
- Follow the opening line with bullet points (max 3-5 bullets)
|
||||
- Structure each bullet as two clearly labelled parts separated by a line break:
|
||||
**Issue:** [Clear description of what's wrong]
|
||||
**Recommendation:** [Actionable fix]
|
||||
- Always capitalise "Issue:" and "Recommendation:" and bold them with double asterisks (**)
|
||||
- Example:
|
||||
"• **Issue:** The logo is positioned in the top-left corner, which doesn't align with brand guidelines.
|
||||
**Recommendation:** Move the logo to the bottom-right corner."
|
||||
- Do NOT include page numbers, document names, or source citations. Keep all feedback self-contained and actionable.
|
||||
- For 'Passed': briefly note any amber items in 1-2 bullets
|
||||
- IMPORTANT: Use British English spelling throughout all output (e.g. "authorised" not "authorized", "colour" not "color", "capitalise" not "capitalize", "organised" not "organized", "centre" not "center", "analysed" not "analyzed").
|
||||
|
|
|
|||
|
|
@ -145,10 +145,15 @@ If the proof is nonsensical, not a marketing material, or cannot be analyzed, se
|
|||
**Response Format:**
|
||||
- Keep feedback brief and scannable
|
||||
- Use bullet points for each finding
|
||||
- Each bullet should be one actionable sentence
|
||||
- Structure each feedback bullet as two clearly labelled parts separated by a line break:
|
||||
**Issue:** [Clear description of what's wrong]
|
||||
**Recommendation:** [Actionable fix — what to do and how]
|
||||
- Always capitalise "Issue:" and "Recommendation:" and bold them with double asterisks (**)
|
||||
- Always place the Recommendation on a new line after the Issue (not on the same line)
|
||||
- Example:
|
||||
"• **Issue:** The 'save more' claim is a comparative claim without a defined baseline.
|
||||
**Recommendation:** Clarify what the customer is saving against (e.g. standard interest rates)."
|
||||
- Do NOT include page numbers, document names, or source citations (e.g., no "Page 10", "per the Legal Guidelines"). Feedback must be self-contained and actionable.
|
||||
- Start with the issue, then the requirement
|
||||
- Example: "Missing APR disclaimer - add representative APR per FCA requirements"
|
||||
- IMPORTANT: Use British English spelling throughout all output (e.g. "authorised" not "authorized", "colour" not "color", "capitalise" not "capitalize", "organised" not "organized", "centre" not "center", "analysed" not "analyzed").
|
||||
- IMPORTANT: Never use the words "violation", "violates", or "violated" in your output. Use constructive alternatives such as "issue", "doesn't align with", "doesn't meet", or "conflicts with".
|
||||
- IMPORTANT: Use Plain English throughout. Choose simple, clear words over complex vocabulary. Prefer: "add" over "incorporate/integrate", "about" over "regarding", "qualifies as" over "constitutes", "use" over "utilise", "before" over "prior to", "to" over "in order to", "try" over "endeavour", "then" over "subsequently", "put in place" over "implement", "keep/contain" over "constrain", "standard interest rate" over "reversion rate". Avoid unnecessary jargon (e.g. use "exaggerated claim" instead of "puffery"). Feedback should be easy to understand for all users.
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class GeminiService:
|
|||
},
|
||||
"feedback": {
|
||||
"type": "string",
|
||||
"description": "Brief bullet-point feedback. Each bullet: one actionable sentence. Format: '• Issue: recommendation'. Max 5 bullets."
|
||||
"description": "Brief bullet-point feedback. Each bullet has two parts: '**Issue:** [problem]' on one line, then '**Recommendation:** [fix]' on the next line. Use • for bullets. Max 5 bullets."
|
||||
},
|
||||
"issues": {
|
||||
"type": "array",
|
||||
|
|
@ -201,7 +201,7 @@ class GeminiService:
|
|||
},
|
||||
"feedback": {
|
||||
"type": "string",
|
||||
"description": "Brief bullet-point feedback. Each bullet: one actionable sentence. Format: '• Issue: recommendation'. Max 5 bullets."
|
||||
"description": "Brief bullet-point feedback. Each bullet has two parts: '**Issue:** [problem]' on one line, then '**Recommendation:** [fix]' on the next line. Use • for bullets. Max 5 bullets."
|
||||
},
|
||||
"issues": {
|
||||
"type": "array",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,31 @@ import { LegalIcon } from './icons/LegalIcon';
|
|||
* Formats feedback text from Gemini API into properly structured React elements.
|
||||
* Handles HTML tags, bullet characters, and newline-separated text.
|
||||
*/
|
||||
/**
|
||||
* Renders inline markdown bold (**text**) as <strong> elements.
|
||||
* Returns an array of React nodes with bold segments wrapped in <strong>.
|
||||
*/
|
||||
const renderBoldMarkdown = (text: string): React.ReactNode[] => {
|
||||
const parts: React.ReactNode[] = [];
|
||||
const regex = /\*\*(.+?)\*\*/g;
|
||||
let lastIndex = 0;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = regex.exec(text)) !== null) {
|
||||
if (match.index > lastIndex) {
|
||||
parts.push(text.slice(lastIndex, match.index));
|
||||
}
|
||||
parts.push(<strong key={match.index}>{match[1]}</strong>);
|
||||
lastIndex = regex.lastIndex;
|
||||
}
|
||||
|
||||
if (lastIndex < text.length) {
|
||||
parts.push(text.slice(lastIndex));
|
||||
}
|
||||
|
||||
return parts;
|
||||
};
|
||||
|
||||
const formatFeedbackText = (text: string): React.ReactNode => {
|
||||
if (!text) return null;
|
||||
|
||||
|
|
@ -22,7 +47,7 @@ const formatFeedbackText = (text: string): React.ReactNode => {
|
|||
// Remove opening tags
|
||||
.replace(/<ul[^>]*>/gi, '')
|
||||
.replace(/<li[^>]*>/gi, '• ')
|
||||
// Remove any other HTML tags
|
||||
// Remove any other HTML tags (but preserve ** markdown bold)
|
||||
.replace(/<[^>]+>/g, '')
|
||||
// Normalize whitespace around bullets
|
||||
.replace(/\s*•\s*/g, '\n• ')
|
||||
|
|
@ -34,26 +59,22 @@ const formatFeedbackText = (text: string): React.ReactNode => {
|
|||
const lines = normalizedText.split('\n').filter(line => line.trim());
|
||||
|
||||
// Separate intro text from bullet points
|
||||
const bulletLines: string[] = [];
|
||||
// Each bullet is an array of lines (to support multi-line Issue/Recommendation)
|
||||
const bulletGroups: string[][] = [];
|
||||
const introLines: string[] = [];
|
||||
|
||||
lines.forEach(line => {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith('•')) {
|
||||
// Remove the bullet character, we'll add it via CSS
|
||||
bulletLines.push(trimmed.replace(/^•\s*/, '').trim());
|
||||
// Start a new bullet group
|
||||
bulletGroups.push([trimmed.replace(/^•\s*/, '').trim()]);
|
||||
} else if (trimmed) {
|
||||
// If we haven't started collecting bullets yet, it's intro text
|
||||
if (bulletLines.length === 0) {
|
||||
if (bulletGroups.length === 0) {
|
||||
// Haven't started bullets yet — it's intro text
|
||||
introLines.push(trimmed);
|
||||
} else {
|
||||
// Text after bullets - treat as continuation of last bullet
|
||||
const lastBullet = bulletLines.pop();
|
||||
if (lastBullet) {
|
||||
bulletLines.push(`${lastBullet} ${trimmed}`);
|
||||
} else {
|
||||
bulletLines.push(trimmed);
|
||||
}
|
||||
// Continuation line within the current bullet
|
||||
bulletGroups[bulletGroups.length - 1].push(trimmed);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -61,12 +82,19 @@ const formatFeedbackText = (text: string): React.ReactNode => {
|
|||
return (
|
||||
<>
|
||||
{introLines.length > 0 && (
|
||||
<p className="mb-3">{introLines.join(' ')}</p>
|
||||
<p className="mb-3">{renderBoldMarkdown(introLines.join(' '))}</p>
|
||||
)}
|
||||
{bulletLines.length > 0 && (
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
{bulletLines.map((item, index) => (
|
||||
<li key={index}>{item}</li>
|
||||
{bulletGroups.length > 0 && (
|
||||
<ul className="list-disc list-inside space-y-3">
|
||||
{bulletGroups.map((group, index) => (
|
||||
<li key={index}>
|
||||
{group.map((line, lineIdx) => (
|
||||
<React.Fragment key={lineIdx}>
|
||||
{lineIdx > 0 && <br />}
|
||||
{renderBoldMarkdown(line)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,30 @@ interface PDFReportProps {
|
|||
proofs: any[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders inline markdown bold (**text**) as <strong> elements for PDF output.
|
||||
*/
|
||||
const renderBoldMarkdownForPDF = (text: string): React.ReactNode[] => {
|
||||
const parts: React.ReactNode[] = [];
|
||||
const regex = /\*\*(.+?)\*\*/g;
|
||||
let lastIndex = 0;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = regex.exec(text)) !== null) {
|
||||
if (match.index > lastIndex) {
|
||||
parts.push(text.slice(lastIndex, match.index));
|
||||
}
|
||||
parts.push(<strong key={match.index}>{match[1]}</strong>);
|
||||
lastIndex = regex.lastIndex;
|
||||
}
|
||||
|
||||
if (lastIndex < text.length) {
|
||||
parts.push(text.slice(lastIndex));
|
||||
}
|
||||
|
||||
return parts;
|
||||
};
|
||||
|
||||
const formatFeedbackTextForPDF = (text: string): React.ReactNode => {
|
||||
if (!text) return null;
|
||||
|
||||
|
|
@ -27,23 +51,20 @@ const formatFeedbackTextForPDF = (text: string): React.ReactNode => {
|
|||
|
||||
const lines = normalizedText.split('\n').filter(line => line.trim());
|
||||
|
||||
const bulletLines: string[] = [];
|
||||
// Each bullet is an array of lines (to support multi-line Issue/Recommendation)
|
||||
const bulletGroups: string[][] = [];
|
||||
const introLines: string[] = [];
|
||||
|
||||
lines.forEach(line => {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith('•')) {
|
||||
bulletLines.push(trimmed.replace(/^•\s*/, '').trim());
|
||||
bulletGroups.push([trimmed.replace(/^•\s*/, '').trim()]);
|
||||
} else if (trimmed) {
|
||||
if (bulletLines.length === 0) {
|
||||
if (bulletGroups.length === 0) {
|
||||
introLines.push(trimmed);
|
||||
} else {
|
||||
const lastBullet = bulletLines.pop();
|
||||
if (lastBullet) {
|
||||
bulletLines.push(`${lastBullet} ${trimmed}`);
|
||||
} else {
|
||||
bulletLines.push(trimmed);
|
||||
}
|
||||
// Continuation line within the current bullet
|
||||
bulletGroups[bulletGroups.length - 1].push(trimmed);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -51,12 +72,19 @@ const formatFeedbackTextForPDF = (text: string): React.ReactNode => {
|
|||
return (
|
||||
<>
|
||||
{introLines.length > 0 && (
|
||||
<p style={{ margin: '0 0 8px 0' }}>{introLines.join(' ')}</p>
|
||||
<p style={{ margin: '0 0 8px 0' }}>{renderBoldMarkdownForPDF(introLines.join(' '))}</p>
|
||||
)}
|
||||
{bulletLines.length > 0 && (
|
||||
{bulletGroups.length > 0 && (
|
||||
<ul style={{ margin: 0, paddingLeft: '18px', listStyleType: 'disc' }}>
|
||||
{bulletLines.map((item, index) => (
|
||||
<li key={index} style={{ marginBottom: '4px' }}>{item}</li>
|
||||
{bulletGroups.map((group, index) => (
|
||||
<li key={index} style={{ marginBottom: '8px' }}>
|
||||
{group.map((line, lineIdx) => (
|
||||
<React.Fragment key={lineIdx}>
|
||||
{lineIdx > 0 && <br />}
|
||||
{renderBoldMarkdownForPDF(line)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue