Skip to content

refactor: Use strategy pattern instead of case in webviewMessageHandler #7254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

NaccOll
Copy link

@NaccOll NaccOll commented Aug 20, 2025

This is a refactor proposal for webviewMessageHandler. Using the strategy pattern to separate the webviewMessageHandler without affecting functionality, it is recommended.

If this pattern is approved, please review it and merge it into the main branch. I will gradually migrate each event to a separate handler.


Important

Refactor webviewMessageHandler to use a strategy pattern with WebviewMessageHandlerRegistry, replacing switch-case with handler classes for improved scalability.

  • Refactor:
    • Introduce WebviewMessageHandlerRegistry in WebviewMessageHandlerRegistry.ts to manage message handlers using a strategy pattern.
    • Replace switch-case in webviewMessageHandler.ts with handler registry lookup for message processing.
  • Handlers:
    • Implement individual handler classes (e.g., AllowedMaxCostHandler, SoundEnabledHandler) for specific message types in auto-approval and notification directories.
    • Register handlers in registerAutoApprovalHandler and registerNotificationHandler functions.
  • Misc:
    • Add types.ts to define interfaces for handlers and registry.
    • Update imports and exports in index.ts files to include new handlers and registry.

This description was created by Ellipsis for ebf30df. You can customize this summary. It will automatically update as commits are pushed.

@NaccOll NaccOll requested review from mrubens, cte and jr as code owners August 20, 2025 15:12
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Aug 20, 2025
Copy link

@roomote roomote bot left a comment

Choose a reason for hiding this comment

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

Thank you for this refactoring proposal! I appreciate the effort to improve code organization using the strategy pattern. The implementation shows good separation of concerns and a clean file structure.

Review Findings

Critical Issues (Must Fix):

  1. Missing await in handler calls - In webviewMessageHandler.ts line 216, the handler is called without await: handler.handle(provider, message, { marketplaceManager }). This could lead to unhandled promise rejections and race conditions. It should be await handler.handle(...).

Important Suggestions (Should Consider):

  1. Incomplete migration - The refactoring only migrates 22 handlers out of ~100+ message types. The remaining handlers are still in the switch statement (starting at line 220), creating a hybrid approach that's harder to maintain. Consider either migrating all handlers at once or adding clear documentation about the migration strategy.

  2. Missing error handling - The handler classes don't have try-catch blocks, and there's no error handling in the registry's handler invocation. If provider.contextProxy.setValue() fails, it could crash the message handling system.

  3. Circular dependency risk - The registry imports from handler directories which import the registry type, creating potential circular dependencies.

Minor Improvements (Nice to Have):

  1. Missing tests - No unit tests are included for the new registry or handler classes.

  2. Type safety - Consider using a discriminated union type for message types to ensure compile-time safety when registering handlers.

  3. Testing utilities - The singleton pattern in WebviewMessageHandlerRegistry could benefit from a reset method for testing purposes.

Positive Aspects:

  • Clean separation of concerns with individual handler classes
  • Good use of the singleton pattern for the registry
  • Consistent handler interface implementation
  • Well-organized file structure

Overall, this is a good start to the refactoring, but the critical issue with the missing await needs to be fixed before merging. The gradual migration approach is fine, but please add documentation explaining the strategy and timeline.

@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Aug 20, 2025
@NaccOll NaccOll force-pushed the refactor-webviewMessageHandler branch from ebf30df to a64cef7 Compare August 20, 2025 15:41
@NaccOll
Copy link
Author

NaccOll commented Aug 20, 2025

@roomote-agent

Review the pull request again, following the following guidelines:

  1. Ignore new code without tests; regression testing of the new code will be handled by the existing test code.
  2. Ignore the lack of migration of all types. This is a proposal that is implemented incrementally, and modifying too many files in a single pull request is unacceptable.

Copy link

roomote bot commented Aug 20, 2025

Hi @NaccOll, I see your request. I will review the pull request following your guidelines:

  1. Ignoring new code without tests (regression testing handled by existing tests)
  2. Ignoring the lack of migration of all types (incremental implementation is acceptable)

Let me analyze the strategy pattern implementation now.

Copy link

roomote bot commented Aug 20, 2025

Hi @NaccOll,

I have completed my review of the pull request following your guidelines. Here is my detailed feedback:

✅ Overall Assessment

The strategy pattern implementation is well-designed and properly executed. This refactoring successfully replaces the switch-case pattern with a more scalable and maintainable architecture.

🎯 Key Strengths

  1. Clean Separation of Concerns: Each handler is isolated in its own class with a single responsibility, making the code more maintainable and testable.

  2. Proper Use of Strategy Pattern:

    • The WebviewMessageHandlerRegistry acts as a singleton registry managing handler instances
    • Each handler implements the IWebviewMessageHandler interface consistently
    • The registry provides useful utility methods (hasHandler, getStats, etc.)
  3. Backward Compatibility: The implementation maintains backward compatibility by:

    • Checking the registry first for migrated handlers
    • Falling back to the original switch statement for unmigrated message types
    • This allows for incremental migration as stated in your requirements
  4. Type Safety: The implementation leverages TypeScript types effectively with WebviewMessage["type"] ensuring type safety across the registry.

📋 Implementation Details

The refactoring introduces:

  • 1 Registry class (WebviewMessageHandlerRegistry) with singleton pattern
  • 2 Registration functions for auto-approval and notification handlers
  • 21 Individual handler classes for different message types
  • Clean interfaces (IWebviewMessageHandler, IWebviewMessageHandlerRegistry)

🔄 Migration Path

The current implementation successfully demonstrates the pattern with:

  • 15 auto-approval related handlers
  • 6 notification related handlers

The remaining message types in the switch statement can be migrated incrementally in future PRs, which aligns perfectly with your stated approach.

✅ Compliance with Guidelines

Per your requirements:

  1. Tests: Not required for new code (regression testing handled by existing tests)
  2. Incremental migration: The implementation supports gradual migration of message types

🚀 Recommendation

This PR is ready to merge. The strategy pattern implementation is solid, maintains backward compatibility, and provides a clear path for future migrations. The code quality is high and the architecture is scalable.

Great work on this refactoring! 👍

@daniel-lxs
Copy link
Collaborator

Thank you @NaccOll for your contribution. I am curious, does it make sense to create so many files with basically the same code, or should we create just a single helper function that can adapt to the use case?

Let me know what you think!

@daniel-lxs daniel-lxs moved this from Triage to PR [Draft / In Progress] in Roo Code Roadmap Aug 20, 2025
@daniel-lxs daniel-lxs marked this pull request as draft August 20, 2025 16:53
@hannesrudolph hannesrudolph added PR - Draft / In Progress and removed Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. labels Aug 20, 2025
@NaccOll
Copy link
Author

NaccOll commented Aug 20, 2025

Thank you @NaccOll for your contribution. I am curious, does it make sense to create so many files with basically the same code, or should we create just a single helper function that can adapt to the use case?

Let me know what you think!

I believe the current implementation follows best practices.

Although it may seem a bit verbose, it offers several advantages:

  1. The logic fully inherits the original case-by-case approach while simply decoupling the code, which facilitates review and validation.
  2. It makes it easier to modify corresponding strategies in the future.

While we could encapsulate some common functions to generate handler instances and avoid class template code, that might be an illusion caused by the fact that the auto-approval case is overly simple.

Moreover, general encapsulation would introduce two issues:

  1. During future maintenance, developers might repeatedly implement case-by-case operations for the webviewMessageHandler within common functions, which would defeat the purpose of using the strategy pattern.
  2. The current value assignments are based on strict type validation, which would be lost with generic encapsulation.

If you dislike the class-based strategy pattern, I can change the implementation by turning the IWebviewMessageHandler interface into a single handle method. Each case would correspond to a function, eliminating the need to create new class instances.

As for whether to split each handler into separate files—this is more of a personal preference. Doing so encourages future developers to follow the same structure. Although the auto-approval logic is simple and may not require so many files, we’re dealing with over 100 different types here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR - Draft / In Progress size:L This PR changes 100-499 lines, ignoring generated files.
Projects
Status: PR [Draft / In Progress]
Development

Successfully merging this pull request may close these issues.

3 participants