Skip to content

Conversation

@shuhuiluo
Copy link
Collaborator

@shuhuiluo shuhuiluo commented Dec 4, 2025

Thread replies now use a condensed format since context (repo, PR/issue number, title) is already visible in the anchor message.

Format: emoji + content preview + user + link

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Thread-aware formatting: thread replies show a condensed preview (user + link) while standalone messages retain full formatting.
    • Concise preview extraction for message bodies, stripping markup/comments and truncating for cleaner thread lines.
  • Chores

    • Updated message flow to pass a thread flag so replies attach reliably; missing user info now falls back to a consistent "unknown" default.

✏️ Tip: You can customize this high-level summary in your review settings.

Thread replies now use a condensed format since context (repo, PR/issue
number, title) is already visible in the anchor message.

Format: emoji + content preview + user + link

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Dec 4, 2025

Walkthrough

This PR adds an extractPreview utility and updates webhook formatters (issue comment, pull request review, review comment) to accept an optional isThreadReply flag. When isThreadReply is true the formatters emit a condensed single-line thread reply (preview, user, URL); otherwise they preserve the full message while reusing the new preview and unified user extraction. The event processor computes isThreadReply from threadingContext (true when threadingContext exists and isAnchor is false), passes it to formatters, and derives threadId/send-path based on that flag.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect extractPreview for edge cases (HTML comments, line joins, truncation).
  • Verify thread vs non-thread outputs for formatIssueComment, formatPullRequestReview, formatPullRequestReviewComment.
  • Confirm event-processor correctly computes isThreadReply and uses it for threadId lookup and send-path.
  • Check consistent defaulting of user to "unknown" and handling of missing body/content.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: compact message format for thread replies' directly and clearly describes the main change: implementing a compact message format specifically for thread replies, which is the central objective of this PR.
✨ 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 feat/compact-thread-replies

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5f2b697 and 247d042.

📒 Files selected for processing (1)
  • src/formatters/webhook-events.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/formatters/webhook-events.ts

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

Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 276332a and 7d57fad.

📒 Files selected for processing (2)
  • src/formatters/webhook-events.ts (4 hunks)
  • src/github-app/event-processor.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: Store context externally - maintain stateless bot architecture with no message history, thread context, or conversation memory
Use <@{userId}> for mentions in messages AND add mentions in sendMessage options - do not use @username format
Implement event handlers for onMessage, onSlashCommand, onReaction, onTip, and onInteractionResponse to respond to Towns Protocol events
Define slash commands in src/commands.ts as a const array with name and description properties, then register handlers using bot.onSlashCommand()
Set ID in interaction requests and match ID in responses to correlate form submissions, button clicks, and transaction/signature responses
Use readContract for reading smart contract state, writeContract for SimpleAccount operations, and execute() for external contract interactions
Fund bot.appAddress (Smart Account) for on-chain operations, not bot.botId (Gas Wallet/EOA)
Use bot.* handler methods directly (outside event handlers) for unprompted messages via webhooks, timers, or tasks - requires channelId, spaceId, or other context stored externally
Always check permissions using handler.hasAdminPermission() before performing admin operations like ban, redact, or pin
User IDs are hex addresses in format 0x..., not usernames - use them consistently throughout event handling and message sending
Slash commands do not trigger onMessage - register slash command handlers using bot.onSlashCommand() instead
Use getSmartAccountFromUserId() to retrieve a user's wallet address from their userId
Include required environment variables: APP_PRIVATE_DATA (bot credentials) and JWT_SECRET (webhook security token)

Files:

  • src/github-app/event-processor.ts
  • src/formatters/webhook-events.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Provide alt text for image attachments and use appropriate MIME types for chunked attachments (videos, screenshots)

Files:

  • src/github-app/event-processor.ts
  • src/formatters/webhook-events.ts
🧠 Learnings (2)
📚 Learning: 2025-11-25T03:24:12.463Z
Learnt from: CR
Repo: HereNotThere/bot-github PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T03:24:12.463Z
Learning: All event handlers receive a base payload including userId, spaceId, channelId, eventId, and createdAt - use eventId as threadId/replyId when responding to maintain event threading

Applied to files:

  • src/github-app/event-processor.ts
📚 Learning: 2025-11-25T03:24:12.463Z
Learnt from: CR
Repo: HereNotThere/bot-github PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T03:24:12.463Z
Learning: Applies to **/*.ts : Use bot.* handler methods directly (outside event handlers) for unprompted messages via webhooks, timers, or tasks - requires channelId, spaceId, or other context stored externally

Applied to files:

  • src/github-app/event-processor.ts
🧬 Code graph analysis (1)
src/formatters/webhook-events.ts (1)
src/types/webhooks.ts (3)
  • IssueCommentPayload (19-19)
  • PullRequestReviewPayload (20-20)
  • PullRequestReviewCommentPayload (21-22)
🔇 Additional comments (4)
src/github-app/event-processor.ts (1)

85-85: Formatter signature extension is compatible with existing call sites

The new (event: T, isThreadReply?: boolean) => string signature is fine, and existing formatters that ignore the second argument (e.g., branch create/delete wrapper) remain type-safe since extra arguments are ignored at runtime.

src/formatters/webhook-events.ts (3)

143-168: Thread reply format for issue comments looks correct and consistent

The new formatIssueComment(payload, isThreadReply?):

  • Uses a shared preview and user for both paths, avoiding duplication.
  • Returns 💬 ${preview} 👤 ${user} 🔗 ${comment.html_url} when isThreadReply is true, which matches the desired compact pattern (emoji + preview + user + link).
  • Preserves the previous rich, multi-line message when isThreadReply is falsy.

Logic and truncation behavior are sound.


170-195: PR review compact formatting and state normalization are reasonable

The updated formatPullRequestReview(payload, isThreadReply?):

  • Normalizes review.state via review.state.replace("_", " "), improving readability for "changes_requested" while leaving other states unchanged.
  • Introduces a compact reply format ${emoji} ${state} 👤 ${user} 🔗 ${review.html_url} when isThreadReply is true.
  • Reuses the same state and user in the full message path, keeping behavior consistent.

This cleanly supports thread replies without regressing the full PR review message.


200-225: Review comment thread reply format matches the compact spec

In formatPullRequestReviewComment(payload, isThreadReply?):

  • preview and user are shared between thread and non-thread paths.
  • The thread reply variant 💬 ${preview} 👤 ${user} 🔗 ${comment.html_url} aligns with the compact format requirement.
  • The existing multi-line message (with repo, PR number, preview, user, link) is preserved for non-threaded usage.

No functional issues spotted; this is a straightforward extension.

shuhuiluo and others added 2 commits December 4, 2025 00:59
TypeScript's control flow analysis already narrows threadingContext
in the ternary, so only the explicit boolean coercion was needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add extractPreview helper to strip HTML comments and markdown formatting
- Apply to formatIssueComment, formatPullRequestReview, formatPullRequestReviewComment
- PR reviews now show body preview when available

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link

@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

🧹 Nitpick comments (1)
src/formatters/webhook-events.ts (1)

197-205: Good null check pattern; consider global replace for robustness.

The review.body ? extractPreview(...) : "" pattern on line 201 correctly guards against null bodies—this is the pattern that should also be applied in formatIssueComment and formatPullRequestReviewComment.

Minor: replace("_", " ") only replaces the first underscore. While current states like changes_requested only have one underscore, using replaceAll would be more future-proof.

-    const state = review.state.replace("_", " ");
+    const state = review.state.replaceAll("_", " ");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3935a4d and 5f2b697.

📒 Files selected for processing (1)
  • src/formatters/webhook-events.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: Store context externally - maintain stateless bot architecture with no message history, thread context, or conversation memory
Use <@{userId}> for mentions in messages AND add mentions in sendMessage options - do not use @username format
Implement event handlers for onMessage, onSlashCommand, onReaction, onTip, and onInteractionResponse to respond to Towns Protocol events
Define slash commands in src/commands.ts as a const array with name and description properties, then register handlers using bot.onSlashCommand()
Set ID in interaction requests and match ID in responses to correlate form submissions, button clicks, and transaction/signature responses
Use readContract for reading smart contract state, writeContract for SimpleAccount operations, and execute() for external contract interactions
Fund bot.appAddress (Smart Account) for on-chain operations, not bot.botId (Gas Wallet/EOA)
Use bot.* handler methods directly (outside event handlers) for unprompted messages via webhooks, timers, or tasks - requires channelId, spaceId, or other context stored externally
Always check permissions using handler.hasAdminPermission() before performing admin operations like ban, redact, or pin
User IDs are hex addresses in format 0x..., not usernames - use them consistently throughout event handling and message sending
Slash commands do not trigger onMessage - register slash command handlers using bot.onSlashCommand() instead
Use getSmartAccountFromUserId() to retrieve a user's wallet address from their userId
Include required environment variables: APP_PRIVATE_DATA (bot credentials) and JWT_SECRET (webhook security token)

Files:

  • src/formatters/webhook-events.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Provide alt text for image attachments and use appropriate MIME types for chunked attachments (videos, screenshots)

Files:

  • src/formatters/webhook-events.ts
🧬 Code graph analysis (1)
src/formatters/webhook-events.ts (1)
src/types/webhooks.ts (3)
  • IssueCommentPayload (19-19)
  • PullRequestReviewPayload (20-20)
  • PullRequestReviewCommentPayload (21-22)
🔇 Additional comments (2)
src/formatters/webhook-events.ts (2)

160-184: Clean implementation of thread reply format.

The condensed format 💬 "${preview}" 👤 ${user} 🔗 ${url} aligns well with the PR objective. The logic correctly gates on isThreadReply and preserves backward compatibility when the flag is not provided.


219-243: Consistent implementation with other formatters.

The thread reply format and logic mirror formatIssueComment, maintaining good consistency. Once the null guard is added to extractPreview, this function will also be protected.

- Add null/undefined guard for body parameter
- Join all lines for more context
- Keep markdown formatting since Towns renders it

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@shuhuiluo shuhuiluo merged commit bdbcadf into main Dec 4, 2025
2 checks passed
@shuhuiluo shuhuiluo deleted the feat/compact-thread-replies branch December 4, 2025 06:51
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