Skip to content
This repository was archived by the owner on Apr 12, 2026. It is now read-only.

feat: add configurable thought visibility with slash and text commands#95

Open
aadaam wants to merge 8 commits into
tuannvm:mainfrom
aadaam:feat/thought-visibility
Open

feat: add configurable thought visibility with slash and text commands#95
aadaam wants to merge 8 commits into
tuannvm:mainfrom
aadaam:feat/thought-visibility

Conversation

@aadaam
Copy link
Copy Markdown

@aadaam aadaam commented Jul 29, 2025

Summary

  • Added configurable thought visibility feature for LLM reasoning process
  • Implemented both slash commands and text commands for better flexibility
  • Thoughts are always stored in conversation history for LLM context

Changes

  • Added showThoughts configuration option in config.go and schema (defaults to true)
  • Implemented slash commands /think_aloud and /think_silent for main channels
  • Added text command variants for thread support: think silent, \!think_aloud, etc.
  • Modified agentCallbackHandler to conditionally format output based on visibility setting
  • Added per-channel/thread preference tracking

Benefits

  • Users can control whether they see the LLM's reasoning process
  • Works in both main channels (slash commands) and threads (text commands)
  • LLM maintains full context even when thoughts are hidden
  • Improves user experience by reducing noise when desired

Test Plan

  • Test /think_silent slash command in main channel
  • Test \!think_aloud text command in thread
  • Verify thoughts are hidden but still in LLM context
  • Verify settings persist per channel/thread

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for toggling the visibility of the agent’s internal reasoning ("thoughts") in Slack, controllable per thread via slash commands or text commands.
    • Introduced Slack message formatting enhancements, including structured display of agent responses and optional metadata.
    • Added support for rendering markdown images in Slack messages.
    • Emoji reactions now indicate when the bot is processing a message.
  • Bug Fixes

    • Improved thread-aware message handling, allowing the bot to maintain context and preferences per Slack thread.
  • Chores

    • Updated configuration and schema to support the new "showThoughts" option.
    • Extended ignore rules for build artifacts and Python files.

aadaam and others added 3 commits July 28, 2025 00:27
This commit improves the Slack bot's agent mode interface with better visual formatting and user experience enhancements:

**Configuration Changes (internal/config/config.go):**
- Updated default thinking message from "Thinking..." to ":thinking_face: _Thinking..._" with emoji and italic formatting

**LLM Agent Prompt Improvements (internal/llm/langchain.go):**
- Enhanced agent prompt formatting with visual hierarchy using ">" prefixes for thoughts
- Clarified tool invocation instructions with better structure and clearer field descriptions
- Improved thought/action formatting to be more readable in Slack

**Slack Agent Output Formatting (internal/slack/agentCallbackHandler.go):**
- Added comprehensive agent output formatting system with two approaches:
  - Block Kit formatting for rich Slack messages with proper sections, context blocks, and code formatting
  - Plain text fallback with emojis, visual separators, and structured metadata display
- Implemented intelligent parsing of agent responses to extract:
  - Thoughts with :brain: emoji and italic formatting
  - Justifications with :scales: emoji
  - Actions with :right-facing_fist: emoji
  - Action inputs formatted as code blocks
  - Observations with :mag: emoji
- Added visual separators (───────────) between metadata and AI responses
- Proper handling of markdown headers, code blocks, and structured content
- Fallback mechanisms to ensure messages always display properly

These changes make the agent's reasoning process more transparent and visually appealing in Slack, helping users better understand what the AI is thinking and doing.

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Exclude bin/ directory containing build artifacts
- Ignore Python files and requirements.txt
- Ignore system.prompt file

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

Co-Authored-By: Claude <noreply@anthropic.com>
- Add AddReaction and RemoveReaction methods to UserFrontend interface
- Implement reaction methods in SlackClient using Slack API
- Add stub implementations for StdioClient
- Remove code that deleted thinking messages from SendMessage

This enables the bot to use emoji reactions for status indicators
instead of sending temporary messages.

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

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

coderabbitai Bot commented Jul 29, 2025

Warning

Rate limit exceeded

@aadaam has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 15 minutes and 1 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 72c7053 and f6f89e2.

📒 Files selected for processing (7)
  • internal/config/config.go (2 hunks)
  • internal/slack/agentCallbackHandler.go (2 hunks)
  • internal/slack/client.go (14 hunks)
  • internal/slack/formatter/detector.go (1 hunks)
  • internal/slack/formatter/formatter.go (1 hunks)
  • internal/slack/userFrontend.go (3 hunks)
  • schema/config-schema.json (1 hunks)

Walkthrough

This change introduces per-thread "thinking aloud" mode in Slack, allowing users to toggle agent reasoning visibility via slash or text commands. It adds structured Slack message formatting, supports markdown images, manages thread participation, and updates configuration with a new showThoughts option. Several new formatting and reaction-handling methods are implemented.

Changes

Cohort / File(s) Change Summary
Slack Client: Thread Awareness, Thinking Mode, Reactions
internal/slack/client.go
Adds per-thread participation tracking, per-thread "showThoughts" state, slash and text command handling for toggling thinking mode, thread-aware message history, and emoji reaction management. Updates message and LLM response handling accordingly.
Agent Output Formatting and Visibility
internal/slack/agentCallbackHandler.go
Adds showThoughts and storeFullMessage fields, new output formatting functions for Slack (including visibility control), and updates message handling to support storing and displaying agent thoughts based on settings.
Slack Message Formatting: Markdown Images
internal/slack/formatter/detector.go, internal/slack/formatter/formatter.go
Adds detection and extraction of markdown images, conversion to Slack Block Kit image blocks, and support for image blocks in the formatter.
Slack User Frontend: Reactions, Image Handling
internal/slack/userFrontend.go
Extends interface and implementation with AddReaction and RemoveReaction methods. Enhances message sending to handle markdown images and removes typing indicator deletion.
Stdio Client: Reactions
internal/slack/stdioClient.go
Adds AddReaction and RemoveReaction methods for standard output, printing simulated reaction actions.
Configuration: Show Thoughts Option
internal/config/config.go, schema/config-schema.json
Adds ShowThoughts boolean to LLM config and schema, with default true. Updates Slack thinking message default.
LangChain Prompt Formatting
internal/llm/langchain.go
Updates agent prompt instructions to prefix "Thought:" lines with "> " for improved formatting.
.gitignore Updates
.gitignore
Adds ignore rules for bin/, *.py, requirements.txt, and system.prompt.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Slack
    participant SlackClient
    participant Agent
    participant Config

    User->>Slack: Sends message (/think_aloud, /think_silent, or normal)
    Slack->>SlackClient: Event (message or slash command)
    SlackClient->>Config: Get showThoughts setting (per-thread)
    alt Slash command
        SlackClient->>SlackClient: Update showThoughts state
        SlackClient->>Slack: Send confirmation message
    else Normal message
        SlackClient->>Slack: Add :thinking_face: reaction
        SlackClient->>Agent: Send prompt (with context)
        Agent->>SlackClient: Return response (with thoughts/metadata)
        SlackClient->>SlackClient: Format response (show/hide thoughts)
        SlackClient->>Slack: Send formatted message
        SlackClient->>Slack: Remove :thinking_face: reaction
        SlackClient->>SlackClient: Track thread participation
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

released

Suggested reviewers

  • tuannvm

Poem

A rabbit in Slack, with thoughts to show or hide,
Now listens in threads, with users as their guide.
Images hop in, markdown in tow,
Reactions and whispers, all in the flow.
Toggle your thinking, aloud or in mind—
This bunny’s new features are thoughtfully designed! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 0

🧹 Nitpick comments (6)
internal/slack/formatter/detector.go (3)

264-264: Consider improving regex robustness for complex URLs.

The current regex pattern may not handle URLs with parentheses correctly, which are common in some URLs (e.g., Wikipedia links). Consider using a more robust pattern or additional URL validation.

-	imagePattern := regexp.MustCompile(`!\[([^\]]*)\]\((https?://[^\s]+)\)`)
+	imagePattern := regexp.MustCompile(`!\[([^\]]*)\]\((https?://[^\s)]+(?:\([^\s)]*\))*[^\s)]*)\)`)

275-277: URL cleanup logic could be more robust.

The parentheses balancing check is a good approach, but it only handles the simple case where there's one extra closing parenthesis. Consider handling more complex scenarios or documenting the limitations.

You could improve the URL cleanup to handle multiple unbalanced parentheses:

-		// If URL ends with a parenthesis that's likely part of the markdown, remove it
-		if strings.HasSuffix(url, ")") && strings.Count(url, "(") < strings.Count(url, ")") {
-			url = url[:len(url)-1]
-		}
+		// Remove trailing unbalanced closing parentheses
+		for strings.HasSuffix(url, ")") && strings.Count(url, "(") < strings.Count(url, ")") {
+			url = url[:len(url)-1]
+		}

348-351: Consider the fallback condition logic.

The condition len(blocks) == 0 || (len(blocks) == 1 && blocks[0]["type"] == "section") might be overly restrictive. If there's only a text section without images, it might still be valuable to format it as a block rather than falling back to plain text.

Consider adjusting the fallback logic:

-	// If we have no valid image blocks after validation, return original text
-	if len(blocks) == 0 || (len(blocks) == 1 && blocks[0]["type"] == "section") {
+	// If we have no image blocks after validation, return original text
+	hasImageBlocks := false
+	for _, block := range blocks {
+		if block["type"] == "image" {
+			hasImageBlocks = true
+			break
+		}
+	}
+	if !hasImageBlocks {
 		return text
 	}
internal/config/config.go (1)

46-46: Consider adding default value handling for ShowThoughts.

The ShowThoughts field doesn't have default value handling in applyLLMDefaults(). Consider adding explicit default handling for consistency with other configuration fields.

Add default handling in the applyLLMDefaults() method:

 func (c *Config) applyLLMDefaults() {
 	if c.LLM.Provider == "" {
 		c.LLM.Provider = ProviderOpenAI
 	}
 
+	// Set default for ShowThoughts if not explicitly configured
+	if c.LLM.ShowThoughts == nil {
+		showThoughts := true
+		c.LLM.ShowThoughts = &showThoughts
+	}
+
 	if c.LLM.MaxAgentIterations <= 0 || c.LLM.MaxAgentIterations > 100 {
internal/slack/agentCallbackHandler.go (1)

34-226: Consider simplifying the complex formatting logic

The formatAgentOutput function is quite complex with nested conditions and multiple responsibilities. Consider extracting helper functions for better maintainability:

+// Helper function to process metadata line
+func processMetadataLine(line string, contextElements *[]slack.MixedElement) bool {
+	trimmedLine := strings.TrimSpace(line)
+	
+	if strings.HasPrefix(trimmedLine, "> Thought:") || strings.HasPrefix(trimmedLine, "Thought:") {
+		thoughtContent := strings.TrimPrefix(trimmedLine, "> ")
+		thoughtContent = strings.TrimPrefix(thoughtContent, "Thought:")
+		*contextElements = append(*contextElements, 
+			slack.NewTextBlockObject("mrkdwn", "_Thought:_ "+strings.TrimSpace(thoughtContent), false, false))
+		return true
+	}
+	// ... similar patterns for other metadata types
+	return false
+}

 func formatAgentOutput(text string) string {
 	// ... existing setup code ...
 	
 	for _, line := range lines {
-		// ... existing code block handling ...
-		
-		// Process thoughts and metadata as context blocks
-		if strings.HasPrefix(trimmedLine, "> Thought:") || strings.HasPrefix(trimmedLine, "Thought:") {
-			addSectionBlock() // Add any pending section
-			thoughtContent := strings.TrimPrefix(trimmedLine, "> ")
-			thoughtContent = strings.TrimPrefix(thoughtContent, "Thought:")
-			contextElements = append(contextElements, 
-				slack.NewTextBlockObject("mrkdwn", "_Thought:_ "+strings.TrimSpace(thoughtContent), false, false))
+		if processMetadataLine(line, &contextElements) {
+			addSectionBlock() // Add any pending section
+			continue
+		}
internal/slack/client.go (1)

402-419: Consider extracting command patterns to constants

The command detection logic handles multiple variants well, but the hardcoded strings could be maintained better:

+var (
+	silentCommands = []string{
+		"think silent", "think quietly",
+		"/think_silent", "/think_quietly", 
+		"!think_silent", "!think_quietly",
+	}
+	aloudCommands = []string{
+		"think aloud", "think loud",
+		"/think_aloud", "/think_loud",
+		"!think_aloud", "!think_loud", 
+	}
+)
+
+func isCommand(prompt string, commands []string) bool {
+	lower := strings.ToLower(strings.TrimSpace(prompt))
+	for _, cmd := range commands {
+		if lower == cmd {
+			return true
+		}
+	}
+	return false
+}

 // Check for thinking mode commands (text or slash style)
-if lowerPrompt == "think silent" || lowerPrompt == "think quietly" || 
-   lowerPrompt == "/think_silent" || lowerPrompt == "/think_quietly" ||
-   lowerPrompt == "!think_silent" || lowerPrompt == "!think_quietly" {
+if isCommand(trimmedPrompt, silentCommands) {
 	c.setThinkingMode(false, channelID, threadTS)
 	return
 }

-if lowerPrompt == "think aloud" || lowerPrompt == "think loud" ||
-   lowerPrompt == "/think_aloud" || lowerPrompt == "/think_loud" ||
-   lowerPrompt == "!think_aloud" || lowerPrompt == "!think_loud" {
+if isCommand(trimmedPrompt, aloudCommands) {
 	c.setThinkingMode(true, channelID, threadTS)
 	return
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d511b2 and 72c7053.

📒 Files selected for processing (10)
  • .gitignore (1 hunks)
  • internal/config/config.go (2 hunks)
  • internal/llm/langchain.go (1 hunks)
  • internal/slack/agentCallbackHandler.go (2 hunks)
  • internal/slack/client.go (14 hunks)
  • internal/slack/formatter/detector.go (1 hunks)
  • internal/slack/formatter/formatter.go (1 hunks)
  • internal/slack/stdioClient.go (1 hunks)
  • internal/slack/userFrontend.go (3 hunks)
  • schema/config-schema.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
internal/llm/**/*.go

📄 CodeRabbit Inference Engine (CLAUDE.md)

internal/llm/**/*.go: LLM provider factories and LangChain integration should be implemented in internal/llm/
Factory pattern should be used in internal/llm/ for provider creation
LangChain gateway should provide a unified interface for LLM providers
Environment variables should override config file settings in LLM provider code
Support both native tools and system prompt-based tools in LLM provider code
Adding a new LLM provider requires creating a factory in internal/llm/
Implement LangChain integration when adding a new LLM provider
Update provider constants when adding a new LLM provider

Files:

  • internal/llm/langchain.go
internal/slack/**/*.go

📄 CodeRabbit Inference Engine (CLAUDE.md)

Slack client implementation and message formatting should be in internal/slack/

Files:

  • internal/slack/formatter/formatter.go
  • internal/slack/stdioClient.go
  • internal/slack/userFrontend.go
  • internal/slack/client.go
  • internal/slack/agentCallbackHandler.go
  • internal/slack/formatter/detector.go
internal/config/**/*.go

📄 CodeRabbit Inference Engine (CLAUDE.md)

Configuration management should be handled in internal/config/, supporting environment variable overrides

Files:

  • internal/config/config.go
internal/config/config.go

📄 CodeRabbit Inference Engine (CLAUDE.md)

Add environment variable handling in config.go when adding a new LLM provider

Files:

  • internal/config/config.go
🧠 Learnings (10)
.gitignore (3)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to mcp-servers.json : Adding a new MCP server requires updating mcp-servers.json

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to mcp-servers.json : MCP servers must be configured in mcp-servers.json with command/args or URL

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to mcp-servers.json : Configuration files must support both legacy format and new mcpServers format

schema/config-schema.json (1)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to .env : Environment variables required: SLACK_BOT_TOKEN, SLACK_APP_TOKEN, OPENAI_API_KEY, LLM_PROVIDER

internal/llm/langchain.go (5)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Support both native tools and system prompt-based tools in LLM provider code

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Implement LangChain integration when adding a new LLM provider

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Agent mode should use multi-turn conversational interactions via LangChain agents and context-aware tool usage decisions

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : LangChain gateway should provide a unified interface for LLM providers

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Standard mode should use single-prompt interactions with tool descriptions in system prompt and direct JSON tool call parsing and execution

internal/slack/formatter/formatter.go (1)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/slack/**/*.go : Slack client implementation and message formatting should be in internal/slack/

internal/slack/stdioClient.go (2)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/slack/**/*.go : Slack client implementation and message formatting should be in internal/slack/

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/mcp/**/*.go : Clients should support stdio, HTTP, and SSE transport modes

internal/config/config.go (8)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/config/config.go : Add environment variable handling in config.go when adding a new LLM provider

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Update provider constants when adding a new LLM provider

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Environment variables should override config file settings in LLM provider code

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Implement LangChain integration when adding a new LLM provider

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Adding a new LLM provider requires creating a factory in internal/llm/

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/slack/**/*.go : Slack client implementation and message formatting should be in internal/slack/

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : LLM provider factories and LangChain integration should be implemented in internal/llm/

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Support both native tools and system prompt-based tools in LLM provider code

internal/slack/userFrontend.go (1)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/slack/**/*.go : Slack client implementation and message formatting should be in internal/slack/

internal/slack/client.go (15)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/slack/**/*.go : Slack client implementation and message formatting should be in internal/slack/

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/mcp/**/*.go : Clients should support stdio, HTTP, and SSE transport modes

Learnt from: AdamShannag
PR: #63
File: internal/mcp/sseClient.go:66-68
Timestamp: 2025-07-08T15:34:53.015Z
Learning: The upstream mcp-go library does not provide typed transport errors and only uses string prefixes like "transport error: " via fmt.Errorf. This requires string matching as a fallback approach for error detection in the SSEMCPClientWithRetry implementation.

Learnt from: AdamShannag
PR: #63
File: internal/mcp/sseClient.go:66-68
Timestamp: 2025-07-08T15:34:53.015Z
Learning: The upstream mcp-go library does not provide typed transport errors and only uses string prefixes like "transport error: " via fmt.Errorf. This requires string matching as a fallback approach for error detection in the SSEMCPClientWithRetry implementation until the library supports typed error wrapping.

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/mcp/**/*.go : Test stdio vs HTTP transport modes when debugging MCP issues

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/mcp/**/*.go : Component-specific loggers should be used for MCP servers

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/mcp/**/*.go : Enable --mcpdebug for MCP client logs when debugging MCP issues

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Support both native tools and system prompt-based tools in LLM provider code

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : LangChain gateway should provide a unified interface for LLM providers

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Implement LangChain integration when adding a new LLM provider

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : LLM provider factories and LangChain integration should be implemented in internal/llm/

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/handlers/**/*.go : Tool handlers and LLM-MCP bridge should be implemented in internal/handlers/

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Update provider constants when adding a new LLM provider

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Adding a new LLM provider requires creating a factory in internal/llm/

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/llm/**/*.go : Factory pattern should be used in internal/llm/ for provider creation

internal/slack/agentCallbackHandler.go (1)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/slack/**/*.go : Slack client implementation and message formatting should be in internal/slack/

internal/slack/formatter/detector.go (1)

Learnt from: CR
PR: tuannvm/slack-mcp-client#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T02:54:03.119Z
Learning: Applies to internal/slack/**/*.go : Slack client implementation and message formatting should be in internal/slack/

🧬 Code Graph Analysis (3)
internal/llm/langchain.go (1)
internal/handlers/llm_mcp_bridge.go (1)
  • generateToolPrompt (41-113)
internal/slack/formatter/formatter.go (1)
internal/slack/formatter/formatter_test.go (2)
  • TestCreateBlockMessage (75-134)
  • TestFormatStructuredData (231-277)
internal/slack/userFrontend.go (2)
internal/slack/formatter/detector.go (2)
  • HasMarkdownImages (289-292)
  • ConvertMarkdownWithImages (295-366)
internal/slack/formatter/formatter.go (4)
  • DefaultOptions (32-38)
  • BlockFormat (21-21)
  • FormatMessage (60-158)
  • FormatMarkdown (279-292)
🔇 Additional comments (22)
.gitignore (3)

36-38: 👍 Good call on excluding build output

Tracking the bin/ directory would only add noise to the history, so this ignore pattern is spot-on.


39-42: *.py + requirements.txt look overly broad—verify intent

Ignoring every Python source file and the lockfile means:

  1. Any helper scripts, prototypes, or infra tooling written in Python can no longer be committed.
  2. If requirements.txt is the canonical dependency manifest for those scripts, it will also be lost to VCS.

Unless the repo has a hard rule of “zero Python code checked in,” consider narrowing the patterns to the usual artifacts instead:

-# Python files
-*.py
-requirements.txt
+# Python artifacts
+__pycache__/
+*.py[cod]

This still keeps byte-code and caches out of the repo while retaining real source and its dependency list.


43-44: Fine to ignore generated system.prompt

If this file is produced locally and never edited by hand, excluding it avoids accidental commits.

internal/slack/formatter/detector.go (1)

325-329: Good security practice with URL validation.

The URL validation that restricts to http:// and https:// protocols is a good security measure to prevent potentially malicious protocols.

internal/config/config.go (2)

46-46: Good use of pointer type for optional boolean configuration.

Using *bool allows distinguishing between an explicitly set false value and an unset configuration, which is the correct approach for optional boolean settings.


245-245: Enhanced thinking message improves user experience.

The updated thinking message with emoji and markdown formatting (:thinking_face: _Thinking..._) provides better visual feedback in Slack.

internal/slack/formatter/formatter.go (1)

120-125: LGTM! Consistent implementation following established patterns.

The image block parsing follows the same pattern as other block types with proper error handling and use of the appropriate slack.ImageBlock type from the Slack SDK.

internal/llm/langchain.go (1)

212-212: Good formatting enhancement for thought visibility.

Adding the "> " prefix to "Thought:" lines formats them as block quotes in Slack, which improves visual distinction when thoughts are displayed. This aligns well with the configurable thought visibility feature.

Also applies to: 222-222

schema/config-schema.json (1)

63-67: Well-structured schema addition with clear documentation.

The showThoughts property is properly defined with:

  • Appropriate boolean type
  • Sensible default value (true)
  • Clear description explaining the feature and its relationship to LLM history
  • Consistent placement within the LLM configuration section
internal/slack/stdioClient.go (1)

128-136: LGTM!

The AddReaction and RemoveReaction methods correctly implement the UserFrontend interface for the stdio client, following the established pattern of printing actions to standard output.

internal/slack/userFrontend.go (3)

27-28: Interface extension looks good!

The addition of AddReaction and RemoveReaction methods to the UserFrontend interface properly supports the new reaction-based feedback mechanism.


126-146: Well-implemented reaction methods!

Both methods properly handle Slack API calls with appropriate error logging and debug messages. The use of slack.NewRefToMessage is the correct way to create message references.


179-194: Good enhancement for markdown image support!

The logic correctly detects markdown images and converts them to Slack Block Kit format for better rendering. The fallback to regular markdown formatting when no images are present maintains backward compatibility.

internal/slack/agentCallbackHandler.go (4)

16-17: Good design for thought visibility control!

The addition of showThoughts flag and storeFullMessage callback properly supports the configurable visibility feature while preserving full message history.


24-29: Proper implementation of visibility control!

The logic correctly stores the full message for history while formatting the display based on the showThoughts setting.


228-330: Well-structured plain text formatting!

The formatPlainAgentOutput function provides good readability with emojis and visual separators. The handling of code blocks within Action Input is particularly well done.


332-396: Correct implementation of visibility filtering!

The formatPlainAgentOutputWithVisibility function properly filters out thoughts when showThoughts is false, while preserving the actual AI response. The default message "(Response processed)" is a good fallback.

internal/slack/client.go (5)

38-39: Good design for thread-aware state management!

The use of maps with "channel:threadTS" keys for tracking thread participation and per-thread thought visibility preferences is a clean approach.


308-336: Thread-aware history management looks good!

The implementation correctly uses composite keys for thread-specific history while maintaining backward compatibility for non-threaded messages.


427-430: Good UX with thinking emoji reactions!

The implementation of adding/removing "thinking_face" reactions provides clear visual feedback during processing. Error handling is appropriate - failures are logged but don't block the main flow.

Also applies to: 450-451, 477-478, 488-489, 590-591


662-680: Well-designed preference cascade!

The getShowThoughts method implements a proper hierarchy: thread preference -> config default -> true. This provides flexibility while maintaining sensible defaults.


267-298: Verify thread participation logic manually

Automated inspection didn’t locate unit tests covering hasParticipatedInThread or trackThreadParticipation, nor could we extract their implementations via scripts—please confirm the following edge cases are handled:

  • Empty or malformed threadTS values (e.g. "", non‐numeric, missing decimal)
  • Race conditions when marking or checking participation concurrently
  • Initialization of the participation cache/map before first use
  • Expiration or cleanup of old thread entries, if applicable

Additionally, consider adding unit tests in *_test.go that:

  • Call trackThreadParticipation then assert hasParticipatedInThread returns true
  • Pass empty or invalid threadTS values to both methods
  • Simulate concurrent calls to ensure thread‐safe behavior

aadaam and others added 5 commits July 29, 2025 21:47
- Replace SendMessage thinking indicator with AddReaction emoji
- Add thinking_face emoji when processing begins
- Remove thinking_face emoji when processing completes or errors
- Pass message timestamp through to enable reactions on correct message
- Update handleUserPrompt and processLLMResponseAndReply signatures

This provides a cleaner UX with emoji reactions instead of temporary
messages that need to be deleted.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Adam Nemeth <aadaam@gmail.com>
- Add participatedThreads map to track threads where bot has responded
- Enable bot to respond to messages in threads it has participated in
- Make message history thread-aware using "channel:threadTS" keys
- Update addToHistory and getContextFromHistory to handle thread context
- Track thread participation when bot sends messages

This allows the bot to maintain separate conversation contexts for each
thread and respond to follow-up messages without requiring @mentions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Adam Nemeth <aadaam@gmail.com>
- Detect markdown image syntax (\![alt](url)) in messages
- Convert markdown images to Slack Block Kit image blocks
- Add support for image blocks in FormatMessage function
- Enable rich chart visualization from MCP servers (e.g., QuickChart)

This enhancement allows MCP servers that generate chart URLs (like
https://github.com/GongRzhe/Quickchart-MCP-Server) to display their
visualizations directly in Slack as embedded images instead of just URLs.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Adam Nemeth <aadaam@gmail.com>
- Add showThoughts config option (defaults to true)
- Implement /think_aloud and /think_silent slash commands for main channels
- Add text command variants for thread support (think silent, \!think_aloud, etc)
- Store full thoughts in conversation history while hiding from Slack display
- Maintain per-channel/thread preferences for thought visibility

This allows users to control whether the LLM's reasoning process is visible
while maintaining full context for the LLM to provide better responses.

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

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Adam Nemeth <aadaam@gmail.com>
- Return empty string instead of default message when no AI response content
- Only send non-empty messages to Slack in HandleChainEnd
- Prevents unnecessary messages appearing during agent thinking

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

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Adam Nemeth <aadaam@gmail.com>
@aadaam aadaam force-pushed the feat/thought-visibility branch from f5f52e2 to f6f89e2 Compare July 29, 2025 19:48
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant