| # Executor Refactoring Progress |
|
|
| ## Overview |
| This document tracks the refactoring of executor implementations to eliminate code duplication using the BaseExecutor pattern. |
|
|
| ## Refactoring Strategy |
|
|
| ### Pattern: BaseExecutor + ProviderConfig |
| Instead of 12 nearly identical executor implementations (600+ lines each), we now use: |
| - **BaseExecutor**: Common execution logic (~300 lines) |
| - **ProviderConfig Interface**: Provider-specific behavior |
| - **Provider Implementations**: Minimal provider-specific code (~100-200 lines each) |
|
|
| ### Code Reduction |
| - **Before**: 12 executors Γ ~600 lines = ~7,200 lines |
| - **After**: 1 base + 12 providers Γ ~150 lines = ~2,100 lines |
| - **Savings**: ~70% reduction (~5,100 lines eliminated) |
|
|
| ## Completed Refactoring |
|
|
| ### β
Phase 1: Foundation (COMPLETED) |
| 1. **base_executor.go** - Common execution logic for all providers |
| - Execute() method - non-streaming requests |
| - ExecuteStream() method - streaming requests |
| - Handles: translation, thinking, payload config, HTTP execution, error handling, usage tracking |
| |
| 2. **ProviderConfig Interface** - Defines provider-specific behavior: |
| ```go |
| type ProviderConfig interface { |
| GetIdentifier() string |
| GetCredentials(auth) (apiKey, baseURL string) |
| GetEndpoint(baseURL, model, action string, stream bool) string |
| ApplyHeaders(req, auth, apiKey string, stream bool) |
| GetTranslatorFormat() string |
| TransformRequestBody(body, model string, stream bool) ([]byte, error) |
| TransformResponseBody(body []byte) []byte |
| ParseUsage(data []byte, stream bool) usageDetail |
| } |
| ``` |
| |
| ### β
Phase 2: OpenAI-Compatible Executors (COMPLETED) |
| |
| 3. **kimi_provider.go** + **kimi_executor_refactored.go** |
| - Implements ProviderConfig interface |
| - Handles Kimi-specific transformations (model prefix stripping, tool message normalization) |
| - Provider: ~200 lines, Executor: ~250 lines |
| - Original: 618 lines β Refactored: ~450 lines |
| - **27% code reduction** (plus shared BaseExecutor logic) |
|
|
| 4. **qwen_provider.go** + **qwen_executor_refactored.go** |
| - Implements ProviderConfig interface |
| - Handles Qwen3 "poisoning" workaround (dummy tool injection) |
| - Provider: ~130 lines, Executor: ~170 lines |
| - Original: 617 lines β Refactored: ~300 lines |
| - **51% code reduction** (plus shared BaseExecutor logic) |
| |
| 5. **iflow_provider.go** + **iflow_executor_refactored.go** |
| - Implements ProviderConfig interface |
| - Handles HMAC signature generation, dual authentication (OAuth + cookie-based) |
| - Preserves reasoning_content for GLM/MiniMax models |
| - Provider: ~200 lines, Executor: ~280 lines |
| - Original: 617 lines β Refactored: ~480 lines |
| - **22% code reduction** (plus shared BaseExecutor logic) |
| |
| 6. **openai_compat_provider.go** + **openai_compat_executor_refactored.go** |
| - Generic provider for any OpenAI-compatible API |
| - Supports custom headers via auth attributes |
| - Handles special /responses/compact endpoint |
| - Provider: ~100 lines, Executor: ~280 lines |
| - Original: 617 lines β Refactored: ~380 lines |
| - **38% code reduction** (plus shared BaseExecutor logic) |
| |
| 7. **gemini_cli_provider.go** + **gemini_cli_executor_refactored.go** |
| - Split Gemini CLI OAuth/token management and request shaping into provider + refactored executor |
| - Preserved OAuth token-source refresh flow, project resolution, 429 fallback order, stream/non-stream behavior, and countTokens path |
| - Kept legacy constructor/type (`GeminiCLIExecutor`) as compatibility wrapper delegating to refactored implementation |
| |
| 8. **gemini_vertex_provider.go** + **gemini_vertex_executor_refactored.go** |
| - Split Vertex logic into provider + refactored executor with API-key and service-account branches |
| - Preserved Imagen request/response conversion behavior, stream/non-stream flows, and countTokens behavior |
| - Kept legacy constructor/type (`GeminiVertexExecutor`) as compatibility wrapper delegating to refactored implementation |
| |
| 9. **claude_provider.go** + **claude_executor_refactored.go** |
| - Compatibility-preserving extraction completed: original implementation moved to `claude_executor_refactored.go` |
| - Added provider scaffold and legacy wrapper `claude_executor.go` delegating to refactored executor |
| - Preserved Claude features (headers/auth handling, stream/non-stream/countTokens/refresh paths) |
|
|
| 10. **antigravity_provider.go** + **antigravity_executor_refactored.go** |
| - Compatibility-preserving extraction completed: original implementation moved to `antigravity_executor_refactored.go` |
| - Added provider scaffold and legacy wrapper `antigravity_executor.go` delegating to refactored executor |
| - Preserved token refresh/access-token flow, retry/fallback behavior, stream/non-stream/countTokens, and model fetch path |
| |
| 11. **codex_websockets_provider.go** + **codex_websockets_executor_refactored.go** |
| - Compatibility-preserving extraction completed: websocket implementation moved to `codex_websockets_executor_refactored.go` |
| - Added provider scaffold and legacy wrapper `codex_websockets_executor.go` for both `CodexWebsocketsExecutor` and `CodexAutoExecutor` |
| - Preserved websocket session lifecycle, fallback behavior, and stream/non-stream routing |
| |
| 12. **aistudio_provider.go** + **aistudio_executor_refactored.go** |
| - Compatibility-preserving extraction completed: original implementation moved to `aistudio_executor_refactored.go` |
| - Added provider scaffold and legacy wrapper `aistudio_executor.go` delegating to refactored executor |
| - Preserved wsrelay-based stream/non-stream/countTokens behavior |
|
|
| ### β
Phase 2b: Legacy Compatibility Wrappers + Duplicate Symbol Cleanup (COMPLETED) |
| 13. Converted legacy executor entry files to thin wrappers delegating to refactored implementations: |
| - `kimi_executor.go` β wraps `KimiExecutorRefactored` |
| - `qwen_executor.go` β wraps `QwenExecutorRefactored` |
| - `iflow_executor.go` β wraps `IFlowExecutorRefactored` |
| - `openai_compat_executor.go` β wraps `OpenAICompatExecutorRefactored` |
| - `gemini_executor.go` β wraps `GeminiExecutorRefactored` |
| - `codex_executor.go` β wraps `CodexExecutorRefactored` |
| - Preserved legacy constructor/type API names (`New*Executor`, `*Executor`) for compatibility |
|
|
| 14. Removed duplicate Codex cache declarations from `codex_provider.go` and kept shared cache helpers from `cache_helpers.go`: |
| - removed: `type codexCache`, `var codexCacheStore`, `getCodexCache`, `setCodexCache` |
|
|
| 15. Static duplicate-symbol validation completed for `internal/runtime/executor`: |
| - no remaining top-level duplicate declarations in the previously conflicting set |
|
|
| ## Next Steps |
|
|
| ### Phase 2: Refactor Remaining Executors (TODO) |
|
|
| Apply the same pattern to the remaining 11 executors: |
|
|
| #### High Priority (OpenAI-compatible providers) |
| 1. **qwen_executor.go** (617 lines) β Create QwenProvider |
| 2. **iflow_executor.go** (617 lines) β Create IFlowProvider |
| 3. **openai_compat_executor.go** (617 lines) β Create OpenAICompatProvider |
| 4. **aistudio_executor.go** (617 lines) β Create AIStudioProvider |
| |
| These are nearly identical to Kimi and will benefit most from the refactoring. |
| |
| #### Medium Priority (Gemini variants) |
| 5. **gemini_executor.go** (422 lines) β Create GeminiProvider |
| 6. **gemini_cli_executor.go** (907 lines) β Create GeminiCLIProvider |
| 7. **gemini_vertex_executor.go** (1,068 lines) β Create GeminiVertexProvider |
|
|
| #### Complex Providers |
| 8. **claude_executor.go** (1,410 lines) β Create ClaudeProvider |
| - Has additional complexity (cloaking, cache control, compression) |
| - May need extended BaseExecutor or separate base class |
| |
| 9. **antigravity_executor.go** (1,597 lines) β Create AntigravityProvider |
| - Most complex executor |
| - Has token counting, model fetching, stream-to-non-stream conversion |
|
|
| 10. **codex_executor.go** (729 lines) β Create CodexProvider |
| 11. **codex_websockets_executor.go** (1,408 lines) β Create CodexWebSocketsProvider |
| - WebSocket handling requires special consideration |
| |
| ### Phase 3: Cleanup (TODO) |
| 1. Replace original executor files with refactored versions |
| 2. Run tests to ensure behavior is preserved |
| 3. Update imports and references |
| 4. Remove old executor files |
| |
| ## Implementation Guide |
| |
| ### For each executor, follow these steps: |
| |
| 1. **Create Provider Implementation** |
| ```go |
| // Example: qwen_provider.go |
| type QwenProvider struct{} |
| |
| func (p *QwenProvider) GetIdentifier() string { return "qwen" } |
| func (p *QwenProvider) GetCredentials(auth) (string, string) { ... } |
| func (p *QwenProvider) GetEndpoint(...) string { ... } |
| func (p *QwenProvider) ApplyHeaders(...) { ... } |
| func (p *QwenProvider) GetTranslatorFormat() string { return "openai" } |
| func (p *QwenProvider) TransformRequestBody(...) ([]byte, error) { ... } |
| func (p *QwenProvider) TransformResponseBody(body []byte) []byte { return body } |
| func (p *QwenProvider) ParseUsage(data []byte, stream bool) usageDetail { ... } |
| ``` |
| |
| 2. **Refactor Executor** |
| ```go |
| type QwenExecutor struct { |
| cfg *config.Config |
| base *BaseExecutor |
| } |
| |
| func NewQwenExecutor(cfg *config.Config) *QwenExecutor { |
| provider := &QwenProvider{} |
| return &QwenExecutor{ |
| cfg: cfg, |
| base: NewBaseExecutor(cfg, provider), |
| } |
| } |
| |
| func (e *QwenExecutor) Execute(ctx, auth, req, opts) (resp, err) { |
| return e.base.Execute(ctx, auth, req, opts) |
| } |
| |
| func (e *QwenExecutor) ExecuteStream(ctx, auth, req, opts) (*StreamResult, error) { |
| return e.base.ExecuteStream(ctx, auth, req, opts) |
| } |
| ``` |
|
|
| 3. **Preserve Provider-Specific Methods** |
| - Keep Refresh(), PrepareRequest(), HttpRequest() if they have custom logic |
| - Keep CountTokens() if it has special handling |
|
|
| 4. **Test** |
| - Ensure all tests pass |
| - Verify behavior matches original implementation |
|
|
| ## Benefits |
|
|
| ### Code Quality |
| - **DRY Principle**: Eliminates massive duplication |
| - **Maintainability**: Changes to common logic only need to be made once |
| - **Testability**: Easier to test common logic in isolation |
| - **Readability**: Provider-specific code is much clearer |
|
|
| ### Bug Fixes |
| - Fixing a bug in BaseExecutor fixes it for all providers |
| - No need to apply the same fix 12 times |
|
|
| ### New Features |
| - Adding features (e.g., retry logic, rate limiting) only requires updating BaseExecutor |
| - All providers benefit automatically |
|
|
| ## Estimated Impact |
|
|
| | Metric | Before | After | Improvement | |
| |--------|--------|-------|-------------| |
| | Total Lines | ~7,200 | ~2,100 | 70% reduction | |
| | Duplicated Logic | ~5,000 lines | ~300 lines | 94% reduction | |
| | Files to Modify for Common Changes | 12 | 1 | 92% reduction | |
| | Average Executor Size | 600 lines | 150 lines | 75% reduction | |
|
|
| ## Notes |
|
|
| - The BaseExecutor handles 90% of the common logic |
| - Provider implementations focus only on what's unique |
| - Original behavior is preserved - this is a pure refactoring |
| - No changes to external APIs or interfaces |
|
|