Skip to content

feat: redesign message templates with professional branding#33

Merged
Kavirubc merged 7 commits intomainfrom
update/design-new-chat-message-templates
Feb 5, 2026
Merged

feat: redesign message templates with professional branding#33
Kavirubc merged 7 commits intomainfrom
update/design-new-chat-message-templates

Conversation

@Kavirubc
Copy link
Copy Markdown
Contributor

@Kavirubc Kavirubc commented Feb 5, 2026

Summary

Redesigns the bot's message templates to be more professional, cleaner, and brand-consistent.

Changes

  • Triage Report: Updated to use GitHub Flavored Markdown (Alerts, Tables, Collapsible sections).
  • Branding: Added Shields.io badges for labels and confidence scores using brand colors (Orange #ff7300/Black #000000).
  • Undo Command: Updated response to use professional alerts.
  • Fix: Resolved lint error in .
  • Tests: Added unit tests for response builder templates.

Summary by CodeRabbit

  • New Features

    • Restructured triage response layout with a new Classification section displayed as a formatted table.
    • Added Quality Improvements section as a collapsible block.
    • Converted Similar Issues and Duplicate sections to collapsible blocks for improved readability.
    • Replaced emoji-based styling with GitHub Alerts formatting for quality assessments.
  • Tests

    • Added unit tests for response builder functionality.

@Kavirubc Kavirubc requested a review from Copilot February 5, 2026 09:24
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 5, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

The changes update the triage response formatting to use markdown tables and collapsible blocks for better organization, add comprehensive unit tests for response building logic, modify the undo message styling, and remove initialization of the currentRepo variable in the LLM router.

Changes

Cohort / File(s) Summary
Response Builder Restructuring
internal/steps/response_builder.go
Refactored triage output rendering: replaced emoji headers with plain text, introduced Classification table with category/value rows, added Quality Improvements as collapsible block, converted Similar Issues and Duplicate sections to collapsible details blocks with GitHub Alerts styling for quality assessment. Added internal helpers (buildLabelsRow, buildTransferRow, buildQualityImprovements). Updated Transfer logic to render conditionally with confidence badges. No public API changes.
Response Builder Tests
internal/steps/response_builder_test.go
New unit test file with tests for buildTriageSummary and buildTransferRow_CurrentRepo. Tests verify presence of key sections (classification table, labels, quality score, transfer suggestions) and proper markdown formatting. Uses mocks for gemini.QualityResult and gemini.RouterResult.
Command Handler Message Update
internal/steps/command_handler.go
Changed undo reply message from inline emoji-based confirmation to "Professional Alert" styled blockquote in metadata comment. Content and formatting only; control flow unchanged.
LLM Router Initialization
internal/steps/llm_router.go
Removed initialization of currentRepo variable. The variable is subsequently used in RouteIssue input and comparison against targetRepo, which may create undefined reference or compile error.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Response pages now shine so bright,
With tables and blocks, a structured delight,
Tests guard the builders with watchful care,
Though one little router removal... beware!
Our code hops forward with style and grace,
Organization now has its place.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: redesign message templates with professional branding' accurately describes the main changes across multiple files, including redesigned response templates, professional formatting, and branding updates.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch update/design-new-chat-message-templates

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/steps/command_handler.go (1)

43-45: ⚠️ Potential issue | 🔴 Critical

Marker mismatch will break self-detection and loop prevention.

The code checks for "🤖 Simili Triage Report" (with emoji) at lines 43, 100, and 134, but response_builder.go line 55 now generates "### Simili Triage Report" (no emoji). This will cause:

  1. Bot may process its own triage reports (line 43 check fails)
  2. Loop prevention won't detect previous transfers (lines 100, 134)
🐛 Proposed fix - update markers to match new format
 // Self-prevention: Ignore bot's own reports even if using PAT
-if strings.Contains(body, "🤖 Simili Triage Report") {
+if strings.Contains(body, "### Simili Triage Report") {
 	return pipeline.ErrSkipPipeline
 }
 // Check for previous transfers (hot-potato loop prevention)
-if strings.Contains(body, "🤖 Simili Triage Report") && strings.Contains(body, "Transferred from") {
+if strings.Contains(body, "### Simili Triage Report") && strings.Contains(body, "Transferred from") {
-if strings.Contains(body, "🤖 Simili Triage Report") && strings.Contains(body, "Transferred from") {
+if strings.Contains(body, "### Simili Triage Report") && strings.Contains(body, "Transferred from") {

Alternatively, use a more robust marker like "Simili Triage Report" without the prefix to handle both old and new formats during transition.

Also applies to: 100-100, 134-134

🤖 Fix all issues with AI agents
In `@internal/steps/response_builder.go`:
- Around line 236-241: The initial assignment to status is ineffectual because
you immediately overwrite it; remove "status := similar.State" and instead
initialize status only within the conditional (e.g., declare "var status string"
then set status = "Closed" if similar.State == "closed" else status = "Open"),
or simply assign directly with the conditional so the variable is only set once;
update the code that uses status accordingly (referencing the "status" variable
and "similar.State").
- Around line 144-147: The badge label encoding currently only replaces spaces
and dashes (see encodedLabel handling) but misses escaping underscores and other
reserved URL characters; update the encoding for encodedLabel (used before
appending to badges in the badges construction) to: first escape literal
underscores by replacing "_" with "__" per Shields.io rules, then percent-encode
remaining reserved characters (use net/url.QueryEscape or equivalent) so
characters like %, #, ?, &, /, + are encoded; ensure the final string is what
you insert into fmt.Sprintf("![](https://img.shields.io/badge/%s-%s)",
encodedLabel, color).
🧹 Nitpick comments (2)
.claude/sessions/2026-02-05-1853.md (1)

5-5: Branch name inconsistency.

The session document references branch feature/hybrid-index-learn, but this PR is for update/design-new-chat-message-templates. Consider updating the session document to reflect the correct branch context, or verify this file was intended for this PR.

internal/steps/response_builder_test.go (1)

107-108: Error message doesn't match assertion.

The error message says "Expected 'Issue belongs in this repository' message" but the actual check is for "✅ To check". Update the error message for clarity when debugging failures.

🔧 Proposed fix
 if !strings.Contains(row, "✅ To check **similigh/simili-bot**") {
-	t.Errorf("Expected 'Issue belongs in this repository' message, got: %s", row)
+	t.Errorf("Expected '✅ To check **similigh/simili-bot**' message, got: %s", row)
 }

Comment thread internal/steps/response_builder.go Outdated
Comment on lines +144 to +147
// URL encode label
encodedLabel := strings.ReplaceAll(label, " ", "%20")
encodedLabel = strings.ReplaceAll(encodedLabel, "-", "--") // Shields.io escaping
badges = append(badges, fmt.Sprintf("![](https://img.shields.io/badge/%s-%s)", encodedLabel, color))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Shields.io badge URL encoding requirements special characters

💡 Result:

For Shields.io badge text (label/message) you generally need normal URL encoding (percent-encoding) for anything that isn’t URL-safe—especially in path-based badges like https://img.shields.io/badge/<label>-<message>-<color>. [1]

1) Use standard URL percent-encoding for reserved/special characters

Encode characters like: space, %, #, ?, &, /, +, etc. (e.g., %%25, +%2B). Shields explicitly notes that “URL-Encoding [is] needed for spaces or special characters” in text overrides like ?label=.... [2]

2) Shields “static badge” path segment rules (very important)

Because the dash - is the field separator in /badge/..., Shields defines extra escaping rules for common characters in the badgeContent path: [1]

  • _ or %20 in the URL → space in the rendered badge
  • __ in the URL → literal underscore _ in the rendered badge
  • -- in the URL → literal dash - in the rendered badge

So if your label/message must contain a literal -, write it as -- in the /badge/... path. If you need a literal _, write __.

Examples

  • Space in message: .../badge/just%20the%20message-8A2BE2 [1]
  • Literal dash in text: use -- (e.g., hello--world renders as hello-world) [1]
  • Percent sign in text: encode as %25 (example shown in Shields docs: 95%25) [1]

Sources: Shields.io “Static Badge” docs for the path escaping table and examples [1], and Shields.io badge docs noting URL-encoding for spaces/special characters in label overrides [2].

[1] https://shields.io/badges/static-badge
[2] https://shields.io/badges/git-hub-labels


🏁 Script executed:

# First, let's examine the actual code at the specified lines
cat -n internal/steps/response_builder.go | sed -n '140,150p'

Repository: similigh/simili-bot

Length of output: 702


Incomplete URL encoding for Shields.io badges—underscores not escaped.

Labels containing underscores will render incorrectly. Per Shields.io escaping rules, literal underscores must be escaped as __ in the badge URL. The current code handles spaces and dashes correctly but misses underscore escaping. Additionally, if labels contain reserved characters (%, #, ?, &, /, +), they should be percent-encoded.

🔧 Proposed fix
 	// URL encode label
 	encodedLabel := strings.ReplaceAll(label, " ", "%20")
+	encodedLabel = strings.ReplaceAll(encodedLabel, "_", "__")
 	encodedLabel = strings.ReplaceAll(encodedLabel, "-", "--") // Shields.io escaping
 	badges = append(badges, fmt.Sprintf("![](https://img.shields.io/badge/%s-%s)", encodedLabel, color))

For more comprehensive escaping of reserved characters like %, #, ?, consider using net/url.QueryEscape or a similar approach.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// URL encode label
encodedLabel := strings.ReplaceAll(label, " ", "%20")
encodedLabel = strings.ReplaceAll(encodedLabel, "-", "--") // Shields.io escaping
badges = append(badges, fmt.Sprintf("![](https://img.shields.io/badge/%s-%s)", encodedLabel, color))
// URL encode label
encodedLabel := strings.ReplaceAll(label, " ", "%20")
encodedLabel = strings.ReplaceAll(encodedLabel, "_", "__")
encodedLabel = strings.ReplaceAll(encodedLabel, "-", "--") // Shields.io escaping
badges = append(badges, fmt.Sprintf("![](https://img.shields.io/badge/%s-%s)", encodedLabel, color))
🤖 Prompt for AI Agents
In `@internal/steps/response_builder.go` around lines 144 - 147, The badge label
encoding currently only replaces spaces and dashes (see encodedLabel handling)
but misses escaping underscores and other reserved URL characters; update the
encoding for encodedLabel (used before appending to badges in the badges
construction) to: first escape literal underscores by replacing "_" with "__"
per Shields.io rules, then percent-encode remaining reserved characters (use
net/url.QueryEscape or equivalent) so characters like %, #, ?, &, /, + are
encoded; ensure the final string is what you insert into
fmt.Sprintf("![](https://img.shields.io/badge/%s-%s)", encodedLabel, color).

Comment thread internal/steps/response_builder.go Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request redesigns the bot's message templates to adopt a more professional appearance using GitHub Flavored Markdown features. The changes modernize the triage report output with alerts, badges, and collapsible sections, replacing the previous emoji-heavy format with a cleaner, more structured presentation.

Changes:

  • Updated triage report to use GFM alerts (NOTE, WARNING, TIP) instead of text-based indicators
  • Converted labels and transfer information from standalone sections to a structured classification table with Shields.io badges
  • Made quality improvements and similar issues sections collapsible using HTML <details> elements
  • Updated undo command response to use professional alert formatting

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
internal/steps/response_builder.go Core redesign of all message templates including header change, GFM alerts, classification table with badges, and collapsible sections
internal/steps/response_builder_test.go New unit tests validating the updated template formats and output structure
internal/steps/command_handler.go Updated undo command response to use GFM alert style
.claude/sessions/2026-02-05-1853.md Development session log (unrelated to PR purpose, appears accidentally included)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .claude/sessions/2026-02-05-1853.md Outdated
Comment on lines +1 to +18
# Development Session - 2026-02-05 18:53

## Session Overview
- **Start Time:** 2026-02-05 18:53
- **Branch:** feature/hybrid-index-learn
- **Status:** Active

## Goals
_Awaiting user input..._

## Progress

### Session Started
- Initialized new development session
- Current branch: `feature/hybrid-index-learn`

---
_Session updates will be logged below_
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This session file appears to be unrelated to the current PR's purpose. The session references branch "feature/hybrid-index-learn" but this PR is about message template redesign. This file seems to have been accidentally included in this pull request and should be removed or committed separately in the appropriate branch/PR.

Copilot uses AI. Check for mistakes.
Comment thread internal/steps/response_builder.go Outdated
Comment on lines +145 to +146
encodedLabel := strings.ReplaceAll(label, " ", "%20")
encodedLabel = strings.ReplaceAll(encodedLabel, "-", "--") // Shields.io escaping
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label encoding logic only handles spaces and hyphens, but labels can contain other special characters that need URL encoding (e.g., slashes, underscores, parentheses). Additionally, the current logic first replaces spaces with %20, then replaces hyphens with --. However, if a label already contains "%20" from a previous step or other URL-encoded characters, the hyphen replacement could affect those. Consider using a more comprehensive URL encoding function like url.QueryEscape() from the net/url package, or apply the Shields.io escaping rules more carefully (hyphens should be escaped to -- before other encoding).

Copilot uses AI. Check for mistakes.
Comment thread internal/steps/response_builder.go Outdated
Comment on lines +245 to +246
if len(title) > 50 {
title = title[:47] + "..."
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The title truncation logic has a potential issue with multibyte UTF-8 characters. Using title[:47] could slice in the middle of a multibyte character, resulting in invalid UTF-8 and potential display issues. Consider using the utf8 package or []rune conversion to safely truncate at character boundaries: runes := []rune(title); if len(runes) > 50 { title = string(runes[:47]) + "..." }.

Suggested change
if len(title) > 50 {
title = title[:47] + "..."
runes := []rune(title)
if len(runes) > 50 {
title = string(runes[:47]) + "..."

Copilot uses AI. Check for mistakes.
Comment on lines +139 to +142
// Heuristic: 'urgent' or 'bug' gets orange, others get black
color := "000000" // Black
if strings.Contains(strings.ToLower(label), "urgent") || strings.Contains(strings.ToLower(label), "high") || strings.Contains(strings.ToLower(label), "bug") {
color = "ff7300" // Orange
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The color assignment heuristic using string matching (lines 141-142) is fragile and may not work well with all label types. Consider making the color mapping configurable or using label metadata if available. For example, labels might have a color property from GitHub that could be used, or the configuration could include a mapping of label patterns to badge colors. This would make the system more flexible and maintainable.

Copilot uses AI. Check for mistakes.
Comment thread internal/steps/response_builder.go Outdated
value = fmt.Sprintf("🔄 Transferred from **%s** %s", sourceRepo, confBadge)
} else if targetRepo == currentRepo {
// Best match is current repo
value = fmt.Sprintf("✅ To check **%s** %s", targetRepo, confBadge)
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message "To check" appears to be grammatically incorrect or unclear. When the issue belongs in the current repository, the message should probably say "Belongs in" or "Correctly placed in" instead of "To check". The phrase "To check" suggests an action that needs to be taken, which doesn't match the semantic meaning of confirming the issue is in the right place.

Suggested change
value = fmt.Sprintf("✅ To check **%s** %s", targetRepo, confBadge)
value = fmt.Sprintf("✅ Belongs in **%s** %s", targetRepo, confBadge)

Copilot uses AI. Check for mistakes.
Comment thread internal/steps/response_builder_test.go Outdated

row := builder.buildTransferRow(ctx)

if !strings.Contains(row, "✅ To check **similigh/simili-bot**") {
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test expectation doesn't match the implementation. The test expects "To check" but this wording is unclear. The test should verify the actual message that will be displayed, which should clearly indicate the issue belongs in the current repository (e.g., "Belongs in" or "Correctly placed in").

Suggested change
if !strings.Contains(row, "✅ To check **similigh/simili-bot**") {
if !strings.Contains(row, "✅ Belongs in **similigh/simili-bot**") {

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@internal/steps/response_builder.go`:
- Around line 243-250: The similar issue title isn't escaped before embedding in
the Markdown table, so sanitize similar.Title by first replacing
newlines/carriage returns with spaces and then escaping table-sensitive
characters (|, [, ]) using strings.NewReplacer, assign the escaped value to
title (or titleEscaped) and perform truncation on the escaped string (or ensure
truncation preserves escapes), then use that escaped/truncated title in the
fmt.Sprintf that appends to parts (referencing the variables similar.Title,
title, parts and the fmt.Sprintf call).

Comment thread internal/steps/response_builder.go Outdated
Comment on lines +243 to +250
// Truncate title if too long
title := similar.Title
if len(title) > 50 {
title = title[:47] + "..."
}

parts = append(parts, fmt.Sprintf("| %.0f%% | [#%d %s](%s) | %s |",
similar.Similarity*100, similar.Number, title, similar.URL, status))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

head -n 260 internal/steps/response_builder.go | tail -n 30

Repository: similigh/simili-bot

Length of output: 965


🏁 Script executed:

cat -n internal/steps/response_builder.go | sed -n '240,255p'

Repository: similigh/simili-bot

Length of output: 600


🏁 Script executed:

cat -n internal/steps/response_builder.go | sed -n '200,280p'

Repository: similigh/simili-bot

Length of output: 2978


🏁 Script executed:

head -n 30 internal/steps/response_builder.go

Repository: similigh/simili-bot

Length of output: 748


🏁 Script executed:

rg -n "append.*parts.*fmt\.Sprintf" internal/

Repository: similigh/simili-bot

Length of output: 913


🏁 Script executed:

rg -n "Markdown|markdown|table|Table" internal/steps/response_builder.go

Repository: similigh/simili-bot

Length of output: 250


🌐 Web query:

Markdown table pipe character escaping |

💡 Result:

In Markdown tables, | is the column separator. To include a literal pipe inside a cell:

Method What to write in the cell Notes
Backslash escape a | b Works in CommonMark/GitHub Flavored Markdown because `
HTML entity a &#124; b or a &vert; b Useful if a renderer mishandles | in tables (some do). (designcise.com)

Example:

| Expr | Meaning |
|---|---|
| a \| b | OR |
| a &#124; b | OR |

Citations:


🏁 Script executed:

# Check if there are other places in the file building tables or formatted Markdown with user data
rg -n "similar\.|Reasoning|Title|State" internal/steps/response_builder.go | head -20

Repository: similigh/simili-bot

Length of output: 332


Escape table-sensitive characters in similar issue titles.

The title is embedded in both a Markdown table cell and link text. Raw titles containing |, [, ], or newlines will break table parsing. For example, a title like "foo | bar" renders as | ... | [#123 foo | bar](...) | ..., breaking the column structure.

Sanitize by replacing newlines/carriage returns with spaces, then escaping |, [, and ] with backslashes using strings.NewReplacer().

🔧 Proposed fix
-		title := similar.Title
+		title := strings.ReplaceAll(similar.Title, "\n", " ")
+		title = strings.ReplaceAll(title, "\r", " ")
 		if len(title) > 50 {
 			title = title[:47] + "..."
 		}
+		title = strings.NewReplacer("|", "\\|", "[", "\\[", "]", "\\]").Replace(title)

 		parts = append(parts, fmt.Sprintf("| %.0f%% | [#%d %s](%s) | %s |",
 			similar.Similarity*100, similar.Number, title, similar.URL, status))
🤖 Prompt for AI Agents
In `@internal/steps/response_builder.go` around lines 243 - 250, The similar issue
title isn't escaped before embedding in the Markdown table, so sanitize
similar.Title by first replacing newlines/carriage returns with spaces and then
escaping table-sensitive characters (|, [, ]) using strings.NewReplacer, assign
the escaped value to title (or titleEscaped) and perform truncation on the
escaped string (or ensure truncation preserves escapes), then use that
escaped/truncated title in the fmt.Sprintf that appends to parts (referencing
the variables similar.Title, title, parts and the fmt.Sprintf call).

- Remove accidentally committed .claude session file
- Improve label encoding to handle underscores and special chars
- Fix UTF-8 safe title truncation for similar issues
- Update 'To check' to 'Belongs in' for clarity
- Update test expectations to match
@Kavirubc Kavirubc merged commit 7705cfb into main Feb 5, 2026
3 of 4 checks passed
@Kavirubc Kavirubc deleted the update/design-new-chat-message-templates branch February 5, 2026 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants