@@ -39,9 +39,9 @@ This document outlines a prioritized refactoring plan for the 51 issues identifi
3939| 2.6 | Simplify use-activity-query.ts | ✅ Complete | Codebuff |
4040| 2.7 | Consolidate XML parsing | ✅ Complete | Codebuff |
4141| 2.8 | Consolidate analytics | ✅ Complete | Codebuff |
42- | 2.9 | Refactor doStream | ⬜ Not Started | - |
43- | 2.10 | DRY up OpenRouter stream handling | ⬜ Not Started | - |
44- | 2.11 | Consolidate image handling | ⬜ Not Started | - |
42+ | 2.9 | Refactor doStream | ✅ Complete | Codebuff |
43+ | 2.10 | DRY up OpenRouter stream handling | ⏭️ Skipped | - |
44+ | 2.11 | Consolidate image handling | ✅ Not Needed | - |
4545| 2.12 | Refactor suggestion-engine | ⬜ Not Started | - |
4646| 2.13 | Fix browser actions + string utils | ⬜ Not Started | - |
4747| 2.14 | Refactor agent-builder.ts | ⬜ Not Started | - |
@@ -780,59 +780,160 @@ common/src/analytics/
780780
781781---
782782
783- ### Commit 2.9: Refactor ` doStream ` in OpenAI Compatible Model
784- ** Files:** ` packages/internal/src/ai-sdk /openai-compatible-chat-language-model.ts `
783+ ### Commit 2.9: Refactor ` doStream ` in OpenAI Compatible Model ✅ COMPLETE
784+ ** Files:** ` packages/internal/src/openai-compatible/chat /openai-compatible-chat-language-model.ts `
785785** Est. Time:** 3-4 hours
786- ** Est. LOC Changed:** ~ 350-400
786+ ** Actual Time:** ~ 2 hours
787+ ** Est. LOC Changed:** ~ 350-400
788+ ** Actual LOC Changed:** ~ 290 lines (3 new files) + ~ 180 lines reduced from main file
787789
788- | Task | Description |
789- | ------| -------------|
790- | Extract ` StreamParser ` class | Parsing logic |
791- | Extract ` ChunkProcessor ` | Chunk handling |
792- | Extract ` StreamErrorHandler ` | Error handling |
793- | Simplify ` doStream ` | Orchestration only |
790+ | Task | Description | Status |
791+ | ------| -------------| --------|
792+ | Create ` stream-usage-tracker.ts ` | Usage accumulation with factory pattern | ✅ |
793+ | Create ` stream-content-tracker.ts ` | Text/reasoning delta handling | ✅ |
794+ | Create ` stream-tool-call-handler.ts ` | Tool call state management | ✅ |
795+ | Simplify ` doStream ` | Orchestration with extracted helpers | ✅ |
796+ | Multi-agent review | Codex CLI + Codebuff reviewed, fixes applied | ✅ |
797+
798+ ** New Files Created:**
799+ - ` packages/internal/src/openai-compatible/chat/stream-usage-tracker.ts ` (~ 60 lines):
800+ - ` createStreamUsageTracker() ` - factory for usage accumulation
801+ - ` update() ` - process chunk usage data
802+ - ` getUsage() ` - get LanguageModelV2Usage
803+ - ` getCompletionTokensDetails() ` - get detailed token breakdown
804+ - ` packages/internal/src/openai-compatible/chat/stream-content-tracker.ts ` (~ 45 lines):
805+ - ` createStreamContentTracker() ` - factory for content state
806+ - ` processReasoningDelta() ` - emit reasoning-start/delta events
807+ - ` processTextDelta() ` - emit text-start/delta events
808+ - ` flush() ` - emit reasoning-end/text-end events
809+ - Constants: ` REASONING_ID ` , ` TEXT_ID `
810+ - ` packages/internal/src/openai-compatible/chat/stream-tool-call-handler.ts ` (~ 120 lines):
811+ - ` createStreamToolCallHandler() ` - factory for tool call state
812+ - ` processToolCallDelta() ` - handle streaming tool call chunks
813+ - ` flushUnfinishedToolCalls() ` - emit incomplete tool calls at end
814+ - ` emitToolCallCompletion() ` - extracted helper for DRY completion logic
815+
816+ ** doStream Reduction:**
817+ - ` openai-compatible-chat-language-model.ts ` : ~ 300 → ~ 120 lines in doStream (-60%)
818+ - TransformStream now delegates to helpers instead of inline logic
819+
820+ ** Multi-Agent Review (Codex CLI, Codebuff):**
821+
822+ | Finding | Agent | Severity | Resolution |
823+ | ---------| -------| ----------| ------------|
824+ | ** Magic string IDs** | Codebuff | Info | Added ` REASONING_ID ` , ` TEXT_ID ` constants |
825+ | ** Unused getters** | Codebuff | Info | Removed ` isReasoningActive() ` , ` isTextActive() ` , ` getToolCalls() ` |
826+ | ** Duplicated completion logic** | Codebuff | Warning | Extracted ` emitToolCallCompletion() ` helper |
827+ | ** Non-null assertion** | Codex | Info | Removed unnecessary ` ! ` assertion |
828+ | ** Redundant nullish coalescing** | Both | Suggestion | Simplified ` ?? undefined ` to just return value |
829+ | ** Unused type exports** | Codebuff | Info | Made ` ToolCallState ` internal (not exported) |
830+
831+ ** Multi-Agent Review (All 4 CLI Agents: Codex, Codebuff, Claude Code, Gemini):**
832+
833+ | Finding | Agents | Severity | Resolution |
834+ | ---------| --------| ----------| ------------|
835+ | ** Empty delta emission** | Codebuff, Claude | Warning | Fixed: Only emit delta if arguments truthy |
836+ | ** Invalid JSON in flush** | Codex, Codebuff | Warning | Fixed: Use ` isParsableJson ` with ` '{}' ` fallback |
837+ | ** Dead generateId() fallback** | Codebuff, Claude | Info | Fixed: Removed dead ` ?? generateId() ` |
838+ | ** Magic string IDs** | Codex, Claude, Gemini | Suggestion | Fixed: Added ` REASONING_ID ` , ` TEXT_ID ` constants |
839+ | ** Side-effect mutation** | Codebuff, Claude, Gemini | Suggestion | Accepted: Keep for simplicity within limited scope |
840+ | ** Hardcoded IDs** | Codex, Claude, Gemini | Suggestion | Documented: Single block assumption |
841+ | ** No unit tests** | Codex | Warning | Deferred: Integration tests sufficient for now |
842+ | ** Premature tool finalization** | Gemini | Critical | Rejected: Matches original behavior, intentional for providers sending complete tool calls |
843+
844+ ** Architecture Decisions Validated (All 4 agents agree):**
845+ - ✅ Factory pattern is correct (vs classes or standalone functions)
846+ - ✅ Event arrays are cleaner than passing controller (testability)
847+ - ✅ Helpers are ready for OpenRouter reuse in Commit 2.10
848+
849+ ** Review Fixes Applied:**
850+ | Fix | Description |
851+ | -----| -------------|
852+ | Add constants | ` REASONING_ID = 'reasoning-0' ` , ` TEXT_ID = 'txt-0' ` |
853+ | Remove unused getters | Deleted ` isReasoningActive() ` , ` isTextActive() ` , ` getToolCalls() ` |
854+ | Extract completion helper | ` emitToolCallCompletion() ` reduces duplication by ~ 30 lines |
855+ | Simplify usage tracker | Flattened state to simple variables instead of nested object |
856+ | Remove redundant code | Cleaned up ` ?? undefined ` patterns |
857+ | ** Empty delta fix** | Moved delta emission inside ` if (arguments != null) ` block |
858+ | ** Invalid JSON fix** | Added ` isParsableJson ` check with ` '{}' ` fallback in flush |
859+ | ** Dead fallback fix** | Removed ` ?? generateId() ` since id is validated earlier |
860+
861+ ** Test Results:**
862+ - 191 internal package tests pass
863+ - All 13 package typechecks pass
864+ - Streaming behavior unchanged
794865
795866** Dependencies:** None
796867** Risk:** Medium - Core streaming
797- ** Feature Flag :** ` REFACTOR_STREAM=true `
798- ** Rollback :** Revert and flag off
868+ ** Rollback :** Revert single commit
869+ ** Commit :** ` 559857bc2 `
799870
800871---
801872
802- ### Commit 2.10: DRY Up OpenRouter Stream Handling
803- ** Files:** ` packages/internal/src/ai-sdk/ openrouter-ai-sdk/chat/index.ts `
873+ ### Commit 2.10: DRY Up OpenRouter Stream Handling ⏭️ SKIPPED
874+ ** Files:** ` packages/internal/src/openrouter-ai-sdk/chat/index.ts `
804875** Est. Time:** 2-3 hours
805876** Est. LOC Changed:** ~ 300-400
806877
807- | Task | Description |
808- | ------| -------------|
809- | Create shared ` stream-utils.ts ` | Common streaming utilities |
810- | Extract shared chunk processing | Reuse across providers |
811- | Update OpenRouter implementation | Use shared code |
812- | Update OpenAI compatible | Use shared code |
878+ > ** Decision:** Skipped after multi-agent review of Commit 2.9. All 4 CLI agents reviewed and Codebuff's recommendation was adopted.
879+
880+ ** Reason for Skipping:**
881+ OpenRouter streaming has materially different requirements from OpenAI-compatible streaming:
882+ - ` reasoning_details ` array with types (Text, Summary, Encrypted) vs simple ` reasoning_content `
883+ - ` annotations ` / web search citations support
884+ - ` openrouterUsage ` with ` cost ` , ` cost_details ` , ` upstreamInferenceCost `
885+ - Different tool call tracking (` inputStarted ` flag vs ` hasFinished ` )
886+ - Provider routing info
887+
888+ Premature abstraction would add complexity without clear benefit. The helpers are small (45-120 lines each) and the "duplication" cost is low compared to the complexity cost of a forced abstraction.
889+
890+ ** Revisit When:** We find ourselves fixing the same streaming bug in both implementations, or the APIs converge.
813891
814892** Dependencies:** Commit 2.9
815- ** Risk:** Medium
816- ** Rollback:** Revert single commit
893+ ** Risk:** N/A - Skipped
894+ ** Rollback:** N/A
817895
818896---
819897
820- ### Commit 2.11: Consolidate Image Handling
898+ ### Commit 2.11: Consolidate Image Handling ✅ NOT NEEDED
821899** Files:** Clipboard/image related files in CLI
822- ** Est. Time:** 2-3 hours
823- ** Est. LOC Changed:** ~ 300-400
900+ ** Est. Time:** 0 hours (skipped)
901+ ** Est. LOC Changed:** 0
902+
903+ > ** Decision:** Skipped after codebase analysis. The image handling architecture is already well-organized.
904+
905+ ** Reason for Skipping:**
906+ The refactoring plan's description was based on outdated analysis. The current architecture is clean:
907+
908+ | File | Purpose | Lines |
909+ | ------| ---------| -------|
910+ | ` common/src/constants/images.ts ` | Shared constants, MIME types, size limits | ~ 50 |
911+ | ` cli/src/utils/image-handler.ts ` | Core processing, compression, validation | ~ 290 |
912+ | ` cli/src/utils/clipboard-image.ts ` | Cross-platform clipboard operations | ~ 370 |
913+ | ` cli/src/utils/image-processor.ts ` | SDK message content integration | ~ 70 |
914+ | ` cli/src/utils/pending-attachments.ts ` | State management for pending images | ~ 190 |
915+ | ` cli/src/utils/image-thumbnail.ts ` | Pixel extraction for thumbnails | ~ 75 |
916+ | ` cli/src/utils/terminal-images.ts ` | iTerm2/Kitty protocol rendering | ~ 190 |
917+ | ` cli/src/utils/image-display.ts ` | Terminal dimension calculations | ~ 60 |
918+
919+ ** Clean Dependency Chain:**
920+ ```
921+ common/constants/images.ts (constants)
922+ ↓
923+ cli/utils/image-handler.ts (core processing)
924+ ↓
925+ ├── cli/utils/clipboard-image.ts (clipboard operations)
926+ ├── cli/utils/image-processor.ts (SDK integration)
927+ └── cli/utils/pending-attachments.ts (state management)
928+ ```
824929
825- | Task | Description |
826- | ------| -------------|
827- | Create ` utils/image-handler.ts ` | Unified image handling |
828- | Extract ` processImageFromClipboard() ` | Clipboard images |
829- | Extract ` processImageFromFile() ` | File images |
830- | Extract ` validateImage() ` | Image validation |
831- | Update all usages | Replace duplicates |
930+ No duplication found. Architecture follows single responsibility principle.
832931
833- ** Dependencies:** None (can run in parallel with 2.10)
834- ** Risk:** Low
835- ** Rollback:** Revert single commit
932+ ** Revisit When:** If new image handling code introduces duplication.
933+
934+ ** Dependencies:** N/A
935+ ** Risk:** N/A
936+ ** Rollback:** N/A
836937
837938---
838939
0 commit comments