Skill: ewankeynes/response-tone-polisher (version 0.1.0)

--- name: response-tone-polisher description: Polishes response letters by transforming defensive or harsh language into professional, courteous academic prose. Converts phrases like "I will not correct this" into "We respectfully believe the original data sufficiently supports..." to avoid reviewer conflict. version: 1.0.0 category: Writing tags: - peer-review - response-letter - tone-polish - academic-writing - reviewer-communication author: AIPOCH license: MIT status: Draft risk_level: Medium skill_type: Tool/Script owner: AIPOCH reviewer: '' last_updated: '2026-02-06' --- # Response Tone Polisher Polishes response letters to peer reviewers by softening harsh or defensive language while preserving the author's position and scientific integrity. ## Overview This skill analyzes author draft responses to reviewer comments and transforms confrontational or defensive phrasing into professional, diplomatic academic language. It helps researchers maintain positive relationships with reviewers while standing firm on scientifically justified positions. ## Key Features - **Tone Analysis**: Identifies defensive, confrontational, or overly direct language - **Polite Transformation**: Converts harsh statements into courteous academic prose - **Position Preservation**: Maintains the author's scientific stance while improving delivery - **Context Awareness**: Adapts based on response type (acceptance, partial acceptance, respectful decline) - **Academic Expression Library**: Built-in collection of polished academic phrasings ## When to Use - Before submitting response letters to journal editors - When reviewer feedback triggers emotional or defensive reactions - For authors whose first language is not English - When revising rejected manuscripts for resubmission - To ensure diplomatic handling of disagreements with reviewers ## Usage Examples ### Basic Usage ``` Input: Reviewer: The sample size is too small for meaningful conclusions. Draft Response: I disagree. Our sample size is standard in this field. Output: We appreciate the reviewer's concern regarding sample size. While we acknowledge that larger samples provide greater statistical power, our sample size is consistent with established conventions in this field and meets the requirements for adequate power analysis (as detailed in the Methods section). ``` ### Defensive Language Transformation | Original (Defensive) | Polished (Professional) | |---------------------|------------------------| | "I will not change this." | "We have carefully considered this suggestion and respectfully maintain our original approach because..." | | "The reviewer is wrong." | "We respectfully offer a different interpretation..." | | "This is unnecessary." | "We appreciate this suggestion; however, we believe the current presentation adequately addresses this point." | | "We already explained this." | "We have expanded our explanation to enhance clarity (Page X, Lines Y-Z)." | | "That's not our fault." | "We acknowledge this limitation and have added appropriate caveats to the Discussion." | ## Input Parameters | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `reviewer_comment` | str | Yes | The reviewer's original comment or criticism | | `draft_response` | str | Yes | Author's initial draft response (may contain harsh/defensive language) | | `response_type` | str | No | One of: `accept`, `partial`, `decline` (default: auto-detect) | | `polish_level` | str | No | `light`, `moderate`, `heavy` (default: moderate) | | `preserve_meaning` | bool | No | Ensure scientific position is preserved (default: true) | ## Output Format ```json { "polished_response": "string", "original_tone_score": "float (0-1, higher = more defensive)", "improvements": [ { "original_phrase": "string", "polished_phrase": "string", "issue_type": "string" } ], "suggestions": ["string"], "politeness_score": "float (0-1)" } ``` ## Tone Patterns Detected The skill identifies and transforms: ### 1. Direct Refusals - "No" / "We won't" → "We respectfully decline to..." - "We can't" → "We are unable to..." ### 2. Defensive Statements - "But we already..." → "We have now clarified..." - "This is not correct" → "We respectfully note that..." ### 3. Blame Shifting - "The reviewer misunderstood" → "We apologize for the lack of clarity; we have revised..." - "This is standard" → "This approach aligns with established conventions..." ### 4. Emotional Language - "Unfortunately" (overused) → [removed or softened] - "Obviously" → [removed] - "Clearly" → [removed or context-dependent] ## Polite Academic Expressions ### Acknowledging Reviewers - "We thank the reviewer for this insightful observation." - "We appreciate the reviewer's careful attention to this detail." - "We are grateful for this constructive feedback." - "This is an excellent point." ### Expressing Disagreement Diplomatically - "We respectfully offer an alternative interpretation..." - "Upon careful reconsideration, we believe..." - "While we appreciate this perspective, we note that..." - "We respectfully maintain our position that..." ### Explaining Limitations - "We acknowledge this limitation and have addressed it by..." - "This constraint reflects the trade-off between..." - "We have added appropriate caveats regarding this limitation." ### Describing Changes - "We have revised the manuscript to clarify..." - "We have expanded the relevant section to include..." - "We have incorporated this suggestion by..." ## Workflow 1. **Input Analysis**: Parse reviewer comment and draft response 2. **Tone Assessment**: Score defensiveness and identify problematic phrases 3. **Pattern Matching**: Find harsh expressions in the transformation library 4. **Reconstruction**: Rewrite maintaining scientific accuracy 5. **Quality Check**: Verify politeness and clarity ## Command Line Usage ```bash # Interactive mode python scripts/main.py --interactive # File-based python scripts/main.py \ --reviewer-comment "comment.txt" \ --draft-response "draft.txt" \ --output "polished.txt" # Direct input python scripts/main.py \ --reviewer "The data is insufficient." \ --draft "You are wrong. We have enough data." \ --polish-level heavy ``` ## Python API ```python from scripts.main import TonePolisher polisher = TonePolisher() result = polisher.polish( reviewer_comment="The methodology is flawed.", draft_response="No it's not. We did it right.", response_type="decline", polish_level="moderate" ) print(result["polished_response"]) ``` ## References - `references/polite_expressions.json` - Curated library of academic polite expressions - `references/tone_patterns.md` - Common defensive patterns and their transformations - `references/examples/` - Before/after polishing examples ## Limitations - Does not verify scientific accuracy of responses - Requires human review for complex nuanced disagreements - May over-soften; authors should verify position is still clear - Best for English-language responses ## Quality Checklist After polishing, verify: - [ ] Original scientific position is preserved - [ ] No confrontational language remains - [ ] Professional tone throughout - [ ] Clear acknowledgment of reviewer's effort - [ ] Specific changes are still referenced - [ ] Response directly addresses the comment ## Risk Assessment | Risk Indicator | Assessment | Level | |----------------|------------|-------| | Code Execution | Python/R scripts executed locally | Medium | | Network Access | No external API calls | Low | | File System Access | Read input files, write output files | Medium | | Instruction Tampering | Standard prompt guidelines | Low | | Data Exposure | Output files saved to workspace | Low | ## Security Checklist - [ ] No hardcoded credentials or API keys - [ ] No unauthorized file system access (../) - [ ] Output does not expose sensitive information - [ ] Prompt injection protections in place - [ ] Input file paths validated (no ../ traversal) - [ ] Output directory restricted to workspace - [ ] Script execution in sandboxed environment - [ ] Error messages sanitized (no stack traces exposed) - [ ] Dependencies audited ## Prerequisites ```bash # Python dependencies pip install -r requirements.txt ``` ## Evaluation Criteria ### Success Metrics - [ ] Successfully executes main functionality - [ ] Output meets quality standards - [ ] Handles edge cases gracefully - [ ] Performance is acceptable ### Test Cases 1. **Basic Functionality**: Standard input → Expected output 2. **Edge Case**: Invalid input → Graceful error handling 3. **Performance**: Large dataset → Acceptable processing time ## Lifecycle Status - **Current Stage**: Draft - **Next Review Date**: 2026-03-06 - **Known Issues**: None - **Planned Improvements**: - Performance optimization - Additional feature support

path: references/polite_expressions.json
content: {
  "defensive_patterns": {
    "direct_refusal": {
      "patterns": [
        "I will not change this",
        "We will not modify",
        "We cannot do this",
        "No, we won't",
        "This is not possible"
      ],
      "replacements": [
        "We have carefully considered this suggestion and respectfully maintain our original approach",
        "Upon thorough evaluation, we believe our current approach is appropriate",
        "We respectfully decline to make this change because"
      ]
    },
    "confrontational": {
      "patterns": [
        "I disagree",
        "We disagree",
        "This is wrong",
        "You are incorrect",
        "The reviewer is mistaken"
      ],
      "replacements": [
        "We respectfully offer a different interpretation",
        "We note that an alternative view may be warranted",
        "Upon careful reconsideration, we maintain that"
      ]
    },
    "defensive": {
      "patterns": [
        "But we already explained",
        "We already stated this",
        "This was mentioned before",
        "We previously noted"
      ],
      "replacements": [
        "We have now expanded our explanation to enhance clarity",
        "We have revised this section to provide additional detail",
        "To improve clarity, we have added"
      ]
    },
    "blame_shifting": {
      "patterns": [
        "The reviewer misunderstood",
        "This was misinterpreted",
        "You didn't understand",
        "This is not our fault"
      ],
      "replacements": [
        "We apologize for the lack of clarity; we have revised",
        "We recognize that our explanation was insufficient; we have clarified",
        "We acknowledge this limitation and have addressed it"
      ]
    },
    "dismissive": {
      "patterns": [
        "This is unnecessary",
        "This is not needed",
        "Obviously",
        "Clearly",
        "It is evident that"
      ],
      "replacements": [
        "While we appreciate this suggestion, we believe the current presentation is appropriate",
        "We have considered this and maintain that",
        "We note that"
      ]
    }
  },
  "polite_acknowledgments": {
    "standard": [
      "We thank the reviewer for this insightful observation.",
      "We appreciate the reviewer's careful attention to this detail.",
      "We are grateful for this constructive feedback.",
      "We value this thoughtful comment.",
      "Thank you for raising this important point."
    ],
    "major_comment": [
      "We are grateful for this significant observation.",
      "This is an excellent and important point.",
      "We deeply appreciate this critical feedback."
    ],
    "minor_comment": [
      "Thank you for this helpful suggestion.",
      "We appreciate this refinement.",
      "This is a valuable correction."
    ]
  },
  "respectful_disagreement": {
    "opening": [
      "We respectfully offer an alternative interpretation.",
      "Upon careful reconsideration, we believe that",
      "While we appreciate this perspective, we respectfully note that",
      "We respectfully maintain our position that",
      "We believe an alternative approach may be warranted because"
    ],
    "rationale": [
      "our data strongly support the current interpretation",
      "the established methodology in this field supports our approach",
      "the specific constraints of our study necessitate this approach",
      "additional analysis (described below) confirms our original conclusion"
    ],
    "closing": [
      "We hope this explanation adequately addresses the reviewer's concern.",
      "We have added further discussion of this point to the manuscript.",
      "We believe this approach best serves the scientific integrity of the study."
    ]
  },
  "accepting_changes": {
    "simple": [
      "We have revised the manuscript accordingly.",
      "This has been addressed in the revised version.",
      "We have incorporated this suggestion."
    ],
    "detailed": [
      "We have expanded the {section} section to include {detail} (Page {page}, Lines {lines}).",
      "We have added {content} as suggested (Page {page}).",
      "The {section} has been revised to clarify {point} (Lines {lines})."
    ]
  },
  "explaining_limitations": {
    "sample_size": [
      "We acknowledge that our sample size is limited; however, it is consistent with similar studies in this field.",
      "While we recognize the constraint of our sample size, our power analysis indicates adequate statistical power.",
      "We have added a discussion of this limitation to the manuscript."
    ],
    "methodological": [
      "This methodological choice reflects the trade-off between {factor1} and {factor2}.",
      "We selected this approach because {rationale}, while acknowledging that {alternative} is also valid.",
      "We have added appropriate caveats regarding this methodological choice."
    ],
    "general": [
      "We acknowledge this limitation and have addressed it by {action}.",
      "We recognize this constraint and have noted it in the Discussion section.",
      "This limitation is now explicitly discussed in the revised manuscript."
    ]
  },
  "clarification_phrases": [
    "To enhance clarity, we have",
    "We have revised this section to more clearly state that",
    "The text now explicitly states",
    "We have clarified this point by",
    "For improved clarity, we have added"
  ],
  "location_indicators": [
    "(Page {page}, Lines {start}-{end})",
    "(Page {page})",
    "(Lines {start}-{end})",
    "(Figure {number})",
    "(Table {number}, Page {page})"
  ]
}


path: references/tone_patterns.md
content: # Tone Transformation Patterns

This document catalogs common defensive or harsh language patterns in peer review responses and their polished academic alternatives.

## Pattern Categories

### 1. Direct Refusals

When you must decline a reviewer's suggestion, avoid blunt refusals.

| ❌ Defensive | ✅ Polished |
|-------------|------------|
| "I will not change this." | "We have carefully considered this suggestion and respectfully maintain our original approach because..." |
| "We can't do this." | "We are unable to make this change due to [reason]. However, we have..." |
| "This is not possible." | "Unfortunately, this modification is not feasible within the scope of our study because..." |
| "No, we won't do that." | "We respectfully decline to make this change because [rationale]. Instead, we have..." |
| "I refuse to change this." | "Upon careful evaluation, we believe the current formulation best serves the manuscript because..." |

### 2. Expressing Disagreement

Disagreement is acceptable; rudeness is not.

| ❌ Defensive | ✅ Polished |
|-------------|------------|
| "You're wrong." | "We respectfully offer a different interpretation..." |
| "The reviewer is incorrect." | "We note that an alternative view may be warranted..." |
| "This is not true." | "We respectfully suggest that the evidence may support an alternative conclusion..." |
| "I disagree completely." | "Upon careful reconsideration, we maintain that..." |
| "That's not right." | "We believe the data are best interpreted as..." |
| "The reviewer misunderstood." | "We apologize for the lack of clarity; we have revised the text to clarify that..." |

### 3. Defensive Responses

Don't defend by pointing out what you already did.

| ❌ Defensive | ✅ Polished |
|-------------|------------|
| "But we already explained this." | "We have now expanded our explanation in Section X to provide additional detail..." |
| "We stated this clearly in the original." | "We have revised this section to enhance clarity regarding..." |
| "This was mentioned on page X." | "To make this more prominent, we have added additional emphasis to the discussion on page X..." |
| "We already discussed this limitation." | "We have expanded our discussion of this limitation to better address the reviewer's concern..." |
| "This point was already made." | "We have strengthened the presentation of this point by..." |

### 4. Dismissive Language

Never dismiss a reviewer's comment, even if it seems trivial.

| ❌ Defensive | ✅ Polished |
|-------------|------------|
| "This is unnecessary." | "While we appreciate this suggestion, we believe the current presentation adequately addresses this point because..." |
| "This doesn't matter." | "We have considered this point and believe the current approach is appropriate because..." |
| "This is obvious." | "We have ensured this point is clearly stated in the revised manuscript..." |
| "This is standard practice." | "This approach aligns with established conventions in the field..." |
| "Everyone knows this." | "We have added a brief explanation of this concept for clarity..." |

### 5. Blame Shifting

Take responsibility for any misunderstanding.

| ❌ Defensive | ✅ Polished |
|-------------|------------|
| "The reviewer didn't understand." | "We recognize that our explanation was insufficient; we have revised the text to clarify..." |
| "This was clear in the original." | "We have enhanced the clarity of this section by..." |
| "The figure caption was clear." | "We have revised the figure caption to provide additional clarity..." |
| "This is not our fault." | "We acknowledge this limitation and have added appropriate caveats to the Discussion..." |
| "The reviewer missed this." | "We have made this point more prominent in the revised manuscript..." |

### 6. Emotional Language

Keep emotions out of academic writing.

| ❌ Defensive | ✅ Polished |
|-------------|------------|
| "Unfortunately, we cannot..." | "We are unable to..." |
| "We are disappointed that..." | [Remove entirely] |
| "This is frustrating because..." | "This presents a challenge because..." |
| "We strongly believe..." | "We maintain that..." |
| "We feel that..." | "We believe that..." |

### 7. Hedges and Qualifiers

Academic writing uses measured, precise language.

| ❌ Too Strong | ✅ Measured |
|--------------|------------|
| "This proves that..." | "These results suggest that..." |
| "This clearly shows..." | "These findings indicate that..." |
| "Obviously..." | [Remove or provide evidence] |
| "Undoubtedly..." | "The evidence suggests..." |
| "It is certain that..." | "It is likely that..." |

## Response Templates by Scenario

### Accepting a Suggestion

**Structure:**
1. Acknowledge the value of the suggestion
2. Describe the specific change made
3. Provide location reference

**Template:**
```
We thank the reviewer for this valuable suggestion. We have revised the 
[section] to [describe change]. Specifically, we have [specific action] 
(Page X, Lines Y-Z).
```

### Partial Acceptance

**Structure:**
1. Acknowledge the suggestion
2. Explain what was implemented
3. Explain what was not and why
4. Provide rationale

**Template:**
```
We appreciate the reviewer's suggestion regarding [topic]. We have adopted 
part of this recommendation by [action taken]. However, we have maintained 
our original approach to [aspect] because [brief rationale]. We have added 
a discussion of this rationale to the manuscript (Page X).
```

### Respectful Decline

**Structure:**
1. Thank the reviewer
2. State your position respectfully
3. Provide clear rationale
4. Offer a compromise if possible

**Template:**
```
We thank the reviewer for this suggestion. Upon careful consideration, we 
respectfully maintain our original [approach/formulation/interpretation] 
because [clear rationale supported by evidence]. We hope this explanation 
adequately addresses the reviewer's concern. To enhance clarity, we have 
added additional discussion of this point (Page X, Lines Y-Z).
```

## Key Phrases Library

### Opening Acknowledgments
- "We thank the reviewer for this insightful observation."
- "We appreciate the reviewer's careful attention to this detail."
- "We are grateful for this constructive feedback."
- "This is an excellent point."
- "We value this thoughtful comment."

### Expressing Alternative Views
- "We respectfully offer an alternative interpretation..."
- "Upon careful reconsideration, we believe..."
- "While we appreciate this perspective, we respectfully note that..."
- "We respectfully maintain our position that..."
- "An alternative view might be that..."

### Describing Limitations
- "We acknowledge this limitation and have addressed it by..."
- "This constraint reflects the trade-off between..."
- "We have added appropriate caveats regarding this limitation..."
- "We recognize this constraint and have noted it in the Discussion..."

### Describing Changes
- "We have revised the manuscript to clarify..."
- "We have expanded the relevant section to include..."
- "We have incorporated this suggestion by..."
- "The text has been updated to reflect..."
- "We have added the following clarification..."

### Closing Statements
- "We hope this explanation adequately addresses the reviewer's concern."
- "We believe these revisions have substantially improved the manuscript."
- "We are grateful for the opportunity to strengthen our work."

## Common Pitfalls

### 1. Over-Apologizing
Avoid excessive apologies. One "thank you" is sufficient.

❌ "We sincerely apologize for this error and are deeply sorry..."
✅ "We thank the reviewer for identifying this error. We have corrected..."

### 2. Over-Explaining
Keep rationales concise. Reviewers don't need your entire thought process.

❌ "We spent many weeks considering this and consulted with several colleagues and reviewed the literature extensively and..."
✅ "Based on [specific reference/standard practice], we maintain that..."

### 3. Being Too Vague
Be specific about what you changed.

❌ "We have addressed this concern."
✅ "We have added a paragraph discussing [specific topic] (Page X, Lines Y-Z)."

### 4. Promising Too Much
Don't promise changes you won't make.

❌ "We will conduct additional experiments..." (if you won't)
✅ "We respectfully note that additional experiments are beyond the scope..."

## Quick Reference: Severity Levels

### Light Polish (Defensiveness 0.3-0.5)
- Remove obvious emotional language
- Add basic acknowledgments
- Fix direct refusals

### Moderate Polish (Defensiveness 0.5-0.7)
- Transform confrontational language
- Add rationale for disagreements
- Improve overall flow

### Heavy Polish (Defensiveness 0.7+)
- Complete restructuring of response
- Add comprehensive acknowledgments
- Multiple revision passes
- Suggest alternative compromises


path: requirements.txt
content: dataclasses
enum


path: scripts/main.py
content: #!/usr/bin/env python3
"""
Response Tone Polisher

Polishes response letters to peer reviewers by transforming defensive or harsh 
language into professional, courteous academic prose.

Usage:
    python main.py --interactive
    python main.py --reviewer-comment "comment.txt" --draft-response "draft.txt"
    python main.py --reviewer "The data is insufficient" --draft "We disagree"

Author: AI Assistant
Version: 1.0.0
"""

import argparse
import json
import re
import sys
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Optional, Dict, Tuple
import os


class ResponseType(Enum):
    """Types of response to reviewer comments."""
    ACCEPT = "accept"
    PARTIAL = "partial"
    DECLINE = "decline"


class PolishLevel(Enum):
    """Levels of tone polishing."""
    LIGHT = "light"
    MODERATE = "moderate"
    HEAVY = "heavy"


@dataclass
class ToneIssue:
    """Represents a tone issue found in text."""
    original_phrase: str
    issue_type: str
    severity: float  # 0-1, higher = more problematic
    position: Tuple[int, int]  # start, end positions


@dataclass
class PolishResult:
    """Result of tone polishing."""
    polished_response: str
    original_tone_score: float
    politeness_score: float
    improvements: List[Dict]
    suggestions: List[str]


class TonePolisher:
    """
    Main class for polishing response letter tone.
    
    Transforms defensive or harsh language into professional, 
    courteous academic prose while preserving scientific positions.
    """
    
    # Defensive/harsh patterns and their polished alternatives
    TONE_PATTERNS = {
        # Direct refusals
        r"\b[Ii] will not (?:change|modify|correct|revise|update)\b": {
            "replacement": "We have carefully considered this suggestion and respectfully maintain our original {noun}",
            "issue_type": "direct_refusal",
            "severity": 0.9
        },
        r"\b[Ww]e will not (?:change|modify|correct|revise|update)\b": {
            "replacement": "We have carefully considered this suggestion and respectfully maintain our original {noun}",
            "issue_type": "direct_refusal",
            "severity": 0.9
        },
        r"\b[Nn]o,? (?:we )?(?:will not|won't|cannot|can't)\b": {
            "replacement": "We respectfully decline to {verb} because",
            "issue_type": "direct_refusal",
            "severity": 0.85
        },
        r"\b[Ii] (?:disagree|don't agree)\b": {
            "replacement": "We respectfully offer a different interpretation",
            "issue_type": "confrontational",
            "severity": 0.7
        },
        r"\b[Ww]e (?:disagree|don't agree)\b": {
            "replacement": "We respectfully offer a different interpretation",
            "issue_type": "confrontational",
            "severity": 0.7
        },
        
        # Defensive statements
        r"\b[Tt]he reviewer is (?:wrong|incorrect|mistaken)\b": {
            "replacement": "We respectfully note that",
            "issue_type": "defensive",
            "severity": 0.95
        },
        r"\b[Tt]his is (?:wrong|incorrect|not correct)\b": {
            "replacement": "We respectfully suggest an alternative view",
            "issue_type": "defensive",
            "severity": 0.8
        },
        r"\b[Ww]e (?:already|previously) (?:stated|mentioned|explained|noted)\b": {
            "replacement": "We have now expanded our explanation to enhance clarity",
            "issue_type": "defensive",
            "severity": 0.75
        },
        r"\b[Bb]ut we (?:already|did)\b": {
            "replacement": "We have now clarified",
            "issue_type": "defensive",
            "severity": 0.7
        },
        
        # Blame shifting
        r"\b[Tt]he reviewer (?:misunderstood|misinterpreted|did not understand)\b": {
            "replacement": "We apologize for the lack of clarity; we have revised",
            "issue_type": "blame_shifting",
            "severity": 0.9
        },
        r"\b[Tt]his was not our (?:fault|responsibility|error)\b": {
            "replacement": "We acknowledge this limitation and have added appropriate caveats",
            "issue_type": "blame_shifting",
            "severity": 0.85
        },
        
        # Dismissive language
        r"\b[Tt]his is (?:unnecessary|not needed|redundant)\b": {
            "replacement": "While we appreciate this suggestion, we believe the current presentation adequately addresses this point",
            "issue_type": "dismissive",
            "severity": 0.75
        },
        r"\b[Tt]his is (?:obvious|clear|evident)\b": {
            "replacement": "This point is addressed",
            "issue_type": "dismissive",
            "severity": 0.6
        },
        r"\b[Ii]t is (?:obvious|clear|evident) that\b": {
            "replacement": "We note that",
            "issue_type": "dismissive",
            "severity": 0.65
        },
        
        # Overly casual/direct
        r"\b[Ii]t's not our (?:fault|problem)\b": {
            "replacement": "This reflects an inherent limitation that we have now addressed",
            "issue_type": "unprofessional",
            "severity": 0.9
        },
        r"\b[Nn]ot our (?:fault|responsibility)\b": {
            "replacement": "We acknowledge this constraint",
            "issue_type": "unprofessional",
            "severity": 0.85
        },
        
        # Emotional/overly apologetic
        r"\b[Uu]nfortunately,? we (?:cannot|can't|are unable to)\b": {
            "replacement": "We are unable to",
            "issue_type": "emotional",
            "severity": 0.4
        },
        r"\b[Ww]e (?:cannot|can't) (?:possibly|really)\b": {
            "replacement": "We are unable to",
            "issue_type": "emotional",
            "severity": 0.5
        },
    }
    
    # Polite academic expression library
    POLITE_EXPRESSIONS = {
        "acknowledgments": [
            "We thank the reviewer for this insightful observation.",
            "We appreciate the reviewer's careful attention to this detail.",
            "We are grateful for this constructive feedback.",
            "This is an excellent point.",
            "We value this thoughtful comment.",
        ],
        "partial_agreement": [
            "We thank the reviewer for this suggestion. While we appreciate this perspective, we note that",
            "We appreciate this recommendation. Upon careful consideration, we believe",
            "We have carefully evaluated this suggestion. However,",
        ],
        "respectful_disagreement": [
            "We respectfully offer an alternative interpretation",
            "Upon careful reconsideration, we maintain that",
            "While we appreciate this perspective, we respectfully note that",
            "We respectfully maintain our position that",
            "We believe an alternative approach may be warranted",
        ],
        "limitations": [
            "We acknowledge this limitation and have addressed it by",
            "This constraint reflects the trade-off between",
            "We have added appropriate caveats regarding this limitation",
            "We recognize this constraint and have noted it in",
        ],
        "changes_made": [
            "We have revised the manuscript to clarify",
            "We have expanded the relevant section to include",
            "We have incorporated this suggestion by",
            "We have updated the text to reflect",
            "We have added the following clarification",
        ],
        "clarification": [
            "To enhance clarity, we have",
            "We have revised this section to more clearly state",
            "The text now explicitly states",
            "We have clarified this point by",
        ]
    }
    
    def __init__(self, polish_level: PolishLevel = PolishLevel.MODERATE):
        self.polish_level = polish_level
        self.context_noun = "approach"  # Default noun for replacements
        
    def analyze_tone(self, text: str) -> Tuple[float, List[ToneIssue]]:
        """
        Analyze the tone of a draft response.
        
        Returns:
            Tuple of (defensiveness_score, list_of_issues)
        """
        issues = []
        total_severity = 0
        
        for pattern, info in self.TONE_PATTERNS.items():
            matches = list(re.finditer(pattern, text, re.IGNORECASE))
            for match in matches:
                issue = ToneIssue(
                    original_phrase=match.group(),
                    issue_type=info["issue_type"],
                    severity=info["severity"],
                    position=(match.start(), match.end())
                )
                issues.append(issue)
                total_severity += info["severity"]
        
        # Calculate overall defensiveness score (0-1)
        word_count = len(text.split())
        if word_count > 0:
            defensiveness_score = min(1.0, total_severity / (word_count / 20 + 1))
        else:
            defensiveness_score = 0.0
            
        return defensiveness_score, issues
    
    def polish(
        self,
        reviewer_comment: str,
        draft_response: str,
        response_type: Optional[ResponseType] = None,
        polish_level: Optional[PolishLevel] = None
    ) -> PolishResult:
        """
        Polish a draft response to make it more professional and courteous.
        
        Args:
            reviewer_comment: The original reviewer comment
            draft_response: The author's draft response
            response_type: Type of response (accept/partial/decline)
            polish_level: Level of polishing to apply
            
        Returns:
            PolishResult containing polished response and metadata
        """
        if polish_level:
            self.polish_level = polish_level
            
        # Auto-detect response type if not provided
        if not response_type:
            response_type = self._detect_response_type(draft_response)
        
        # Analyze original tone
        original_tone_score, issues = self.analyze_tone(draft_response)
        
        # Generate polished response
        polished = self._generate_polished_response(
            reviewer_comment, draft_response, response_type, issues
        )
        
        # Calculate politeness score
        politeness_score = self._calculate_politeness(polished)
        
        # Generate improvements list
        improvements = self._generate_improvements_list(issues, polished)
        
        # Generate additional suggestions
        suggestions = self._generate_suggestions(reviewer_comment, polished)
        
        return PolishResult(
            polished_response=polished,
            original_tone_score=original_tone_score,
            politeness_score=politeness_score,
            improvements=improvements,
            suggestions=suggestions
        )
    
    def _detect_response_type(self, draft_response: str) -> ResponseType:
        """Auto-detect the type of response based on content."""
        decline_indicators = [
            r"\bnot change\b", r"\bnot modify\b", r"\bnot revise\b",
            r"\bdisagree\b", r"\bwon't\b", r"\bcannot\b",
            r"\bmaintain\b", r"\boriginal\b"
        ]
        accept_indicators = [
            r"\bhave revised\b", r"\bhave changed\b", r"\bhave updated\b",
            r"\bthank you\b", r"\bagree\b", r"\bmodified\b"
        ]
        
        decline_count = sum(1 for p in decline_indicators if re.search(p, draft_response, re.I))
        accept_count = sum(1 for p in accept_indicators if re.search(p, draft_response, re.I))
        
        if decline_count > accept_count:
            return ResponseType.DECLINE
        elif accept_count > 0:
            return ResponseType.ACCEPT
        else:
            return ResponseType.PARTIAL
    
    def _generate_polished_response(
        self,
        reviewer_comment: str,
        draft_response: str,
        response_type: ResponseType,
        issues: List[ToneIssue]
    ) -> str:
        """Generate the polished response text."""
        
        # Start with acknowledgment
        result_parts = []
        
        # Add appropriate opening based on response type
        if response_type == ResponseType.ACCEPT:
            opener = self._select_expression("acknowledgments")
            result_parts.append(opener)
            result_parts.append(self._transform_to_acceptance(draft_response))
        elif response_type == ResponseType.PARTIAL:
            opener = self._select_expression("partial_agreement")
            result_parts.append(opener)
            result_parts.append(self._transform_to_partial(draft_response))
        else:  # DECLINE
            opener = self._select_expression("acknowledgments")
            result_parts.append(opener)
            result_parts.append(self._transform_to_decline(draft_response))
        
        # Apply pattern-based replacements
        polished = " ".join(result_parts)
        
        # Apply specific pattern replacements
        for pattern, info in self.TONE_PATTERNS.items():
            replacement = info["replacement"]
            if "{noun}" in replacement:
                replacement = replacement.format(noun=self.context_noun)
            if "{verb}" in replacement:
                # Extract verb from context - simplified
                replacement = replacement.format(verb="make this change")
            
            polished = re.sub(pattern, replacement, polished, flags=re.IGNORECASE)
        
        # Clean up and format
        polished = self._clean_text(polished)
        
        return polished
    
    def _select_expression(self, category: str) -> str:
        """Select a polite expression from the library."""
        import random
        expressions = self.POLITE_EXPRESSIONS.get(category, ["Thank you for this comment."])
        return random.choice(expressions)
    
    def _transform_to_acceptance(self, draft: str) -> str:
        """Transform draft into acceptance language."""
        # Remove defensive prefixes
        cleaned = re.sub(r"^\s*(?:[Bb]ut|[Hh]owever)\s*,?\s*", "", draft)
        
        # Add change language if not present
        if not re.search(r"\b(?:have revised|have changed|have updated|have modified)\b", cleaned, re.I):
            return f"We have revised the manuscript as suggested. {cleaned}"
        return cleaned
    
    def _transform_to_partial(self, draft: str) -> str:
        """Transform draft into partial acceptance language."""
        # Start with partial acceptance framing
        return draft
    
    def _transform_to_decline(self, draft: str) -> str:
        """Transform draft into respectful decline language."""
        # Replace harsh refusals with polite alternatives
        return draft
    
    def _clean_text(self, text: str) -> str:
        """Clean up and format the text."""
        # Fix spacing
        text = re.sub(r"\s+", " ", text)
        # Fix punctuation spacing
        text = re.sub(r"\s+([.,;:!?])", r"\1", text)
        # Capitalize first letter
        text = text.strip()
        if text:
            text = text[0].upper() + text[1:]
        # Ensure period at end
        if text and not text.endswith((".", "!", "?")):
            text += "."
        return text
    
    def _calculate_politeness(self, text: str) -> float:
        """Calculate a politeness score for the text."""
        polite_indicators = [
            r"\bthank\b", r"\bappreciate\b", r"\bgrateful\b",
            r"\brespectfully\b", r"\bcarefully considered\b",
            r"\bvaluable\b", r"\binsightful\b", r"\bconstructive\b"
        ]
        
        rude_indicators = [
            r"\bwrong\b", r"\bincorrect\b", r"\bdisagree\b(?!\s+with)",
            r"\bnot\s+(?:correct|true|accurate)\b", r"\byou\s+(?:are|have)\s+(?:wrong|mistaken)"
        ]
        
        polite_count = sum(1 for p in polite_indicators if re.search(p, text, re.I))
        rude_count = sum(1 for p in rude_indicators if re.search(p, text, re.I))
        
        score = 0.5 + (polite_count * 0.1) - (rude_count * 0.2)
        return max(0.0, min(1.0, score))
    
    def _generate_improvements_list(
        self,
        issues: List[ToneIssue],
        polished: str
    ) -> List[Dict]:
        """Generate a list of improvements made."""
        improvements = []
        for issue in issues:
            # Find what this issue was transformed to (simplified)
            improvements.append({
                "original_phrase": issue.original_phrase,
                "polished_phrase": f"[Transformed {issue.issue_type}]",
                "issue_type": issue.issue_type,
                "severity": issue.severity
            })
        return improvements
    
    def _generate_suggestions(self, reviewer_comment: str, polished: str) -> List[str]:
        """Generate additional suggestions for improvement."""
        suggestions = []
        
        # Check for missing location references
        if not re.search(r"\b(?:[Pp]age|[Ll]ine|[Ff]igure|[Tt]able)\b", polished):
            suggestions.append("Consider adding page/line references to help reviewers locate changes.")
        
        # Check for rationale in decline situations
        if "respectfully" in polished.lower() and "because" not in polished.lower():
            suggestions.append("When declining suggestions, provide a brief rationale.")
        
        # Check length
        word_count = len(polished.split())
        if word_count < 20:
            suggestions.append("The response is quite brief; consider adding more detail about the changes made.")
        
        return suggestions


def interactive_mode():
    """Run in interactive mode to collect input from user."""
    print("=" * 70)
    print("Response Tone Polisher - Interactive Mode")
    print("=" * 70)
    print()
    print("This tool helps polish your responses to peer reviewers.")
    print("It transforms defensive or harsh language into professional, courteous prose.")
    print()
    
    # Get polish level
    print("Select polish level:")
    print("  1. Light (minimal changes)")
    print("  2. Moderate (recommended)")
    print("  3. Heavy (aggressive polishing)")
    level_choice = input("Choice (1-3): ").strip() or "2"
    
    level_map = {
        "1": PolishLevel.LIGHT,
        "2": PolishLevel.MODERATE,
        "3": PolishLevel.HEAVY
    }
    polish_level = level_map.get(level_choice, PolishLevel.MODERATE)
    
    # Get reviewer comment
    print("\n" + "-" * 70)
    print("Paste the REVIEWER COMMENT below (type 'END' on new line when done):")
    print("-" * 70)
    lines = []
    while True:
        line = input()
        if line.strip() == "END":
            break
        lines.append(line)
    reviewer_comment = "\n".join(lines)
    
    # Get draft response
    print("\n" + "-" * 70)
    print("Paste your DRAFT RESPONSE below (type 'END' on new line when done):")
    print("-" * 70)
    lines = []
    while True:
        line = input()
        if line.strip() == "END":
            break
        lines.append(line)
    draft_response = "\n".join(lines)
    
    # Process
    print("\n" + "=" * 70)
    print("Polishing your response...")
    print("=" * 70)
    
    polisher = TonePolisher(polish_level=polish_level)
    result = polisher.polish(reviewer_comment, draft_response)
    
    # Display results
    print("\n📊 TONE ANALYSIS:")
    print(f"   Original defensiveness score: {result.original_tone_score:.2f}/1.0")
    print(f"   Politeness score: {result.politeness_score:.2f}/1.0")
    
    if result.improvements:
        print(f"\n🔧 IMPROVEMENTS MADE ({len(result.improvements)}):")
        for i, imp in enumerate(result.improvements[:5], 1):
            print(f"   {i}. [{imp['issue_type'].replace('_', ' ').title()}]")
            print(f"      Original: \"{imp['original_phrase'][:50]}...\" " if len(imp['original_phrase']) > 50 else f"      Original: \"{imp['original_phrase']}\"")
    
    if result.suggestions:
        print(f"\n💡 SUGGESTIONS:")
        for i, sug in enumerate(result.suggestions, 1):
            print(f"   {i}. {sug}")
    
    print("\n" + "=" * 70)
    print("✨ POLISHED RESPONSE:")
    print("=" * 70)
    print(result.polished_response)
    
    # Save option
    save = input("\n\nSave to file? (filename or 'n'): ").strip()
    if save and save.lower() != 'n':
        output = {
            "polished_response": result.polished_response,
            "original_tone_score": result.original_tone_score,
            "politeness_score": result.politeness_score,
            "improvements": result.improvements,
            "suggestions": result.suggestions
        }
        with open(save, 'w') as f:
            json.dump(output, f, indent=2)
        print(f"✅ Saved to {save}")


def main():
    parser = argparse.ArgumentParser(
        description="Polish response letters by transforming defensive language into professional prose"
    )
    parser.add_argument(
        "--reviewer-comment", "-r",
        help="File containing reviewer comment, or the comment text directly"
    )
    parser.add_argument(
        "--draft-response", "-d",
        help="File containing draft response, or the text directly"
    )
    parser.add_argument(
        "--output", "-o",
        help="Output file for the polished response"
    )
    parser.add_argument(
        "--response-type", "-t",
        choices=["accept", "partial", "decline"],
        help="Type of response (default: auto-detect)"
    )
    parser.add_argument(
        "--polish-level", "-p",
        choices=["light", "moderate", "heavy"],
        default="moderate",
        help="Level of polishing (default: moderate)"
    )
    parser.add_argument(
        "--interactive", "-i",
        action="store_true",
        help="Run in interactive mode"
    )
    parser.add_argument(
        "--json", "-j",
        action="store_true",
        help="Output as JSON"
    )
    
    args = parser.parse_args()
    
    if args.interactive or (not args.reviewer_comment and not args.draft_response):
        interactive_mode()
        return
    
    # Read inputs
    reviewer_comment = args.reviewer_comment
    draft_response = args.draft_response
    
    # Check if inputs are files
    if reviewer_comment and os.path.isfile(reviewer_comment):
        with open(reviewer_comment, 'r') as f:
            reviewer_comment = f.read()
    
    if draft_response and os.path.isfile(draft_response):
        with open(draft_response, 'r') as f:
            draft_response = f.read()
    
    if not reviewer_comment or not draft_response:
        print("Error: Both --reviewer-comment and --draft-response are required.")
        sys.exit(1)
    
    # Map response type
    response_type = None
    if args.response_type:
        response_type = ResponseType(args.response_type)
    
    # Map polish level
    polish_level = PolishLevel(args.polish_level)
    
    # Process
    polisher = TonePolisher(polish_level=polish_level)
    result = polisher.polish(reviewer_comment, draft_response, response_type, polish_level)
    
    # Output
    if args.json:
        output = {
            "polished_response": result.polished_response,
            "original_tone_score": result.original_tone_score,
            "politeness_score": result.politeness_score,
            "improvements": result.improvements,
            "suggestions": result.suggestions
        }
        output_text = json.dumps(output, indent=2)
    else:
        output_text = result.polished_response
    
    if args.output:
        with open(args.output, 'w') as f:
            f.write(output_text)
        print(f"Polished response saved to {args.output}")
    else:
        print(output_text)


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)