fix(desktop): accept both action_items and items keys in ActionItemsListResponse#6414
Conversation
…istResponse
/v1/action-items returns {"action_items": ...} while /v1/staged-tasks
returns {"items": ...}. After PR #6380 changed the CodingKey to expect
action_items, getStagedTasks() broke with a decode error.
Custom init(from:) tries action_items first, falls back to items.
Fixes #6387
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR fixes a decode failure in Confidence Score: 5/5Safe to merge — the fix is minimal, correct, and directly addresses the root cause with no P0/P1 issues. All observations are P2 style suggestions (e.g., defensive decoding of has_more). The decode logic correctly uses decodeIfPresent for the optional action_items key with a required decode fallback for items, ensuring a clear DecodingError.keyNotFound if both keys are absent. The Codable→Decodable narrowing is appropriate since this type is never encoded. No files require special attention.
|
| Filename | Overview |
|---|---|
| desktop/Desktop/Sources/APIClient.swift | Adds custom init(from:) decoder that tries 'action_items' first then falls back to 'items'; narrows conformance from Codable to Decodable — correct and minimal fix for the staged-tasks decode failure. |
Sequence Diagram
sequenceDiagram
participant Caller as Caller (TasksStore / TaskDeduplicationService)
participant APIClient as APIClient
participant Backend as Backend (api.omi.me)
participant Decoder as Custom init(from:)
Caller->>APIClient: getActionItems(...)
APIClient->>Backend: GET /v1/action-items
Backend-->>APIClient: {"action_items": [...], "has_more": true}
APIClient->>Decoder: decode ActionItemsListResponse
Note right of Decoder: decodeIfPresent(.actionItems) succeeds<br/>self.items = actionItems
Decoder-->>Caller: ActionItemsListResponse(items: [...])
Caller->>APIClient: getStagedTasks(...)
APIClient->>Backend: GET /v1/staged-tasks
Backend-->>APIClient: {"items": [...], "has_more": false}
APIClient->>Decoder: decode ActionItemsListResponse
Note right of Decoder: decodeIfPresent(.actionItems) → nil<br/>fallback: decode(.items)<br/>self.items = items
Decoder-->>Caller: ActionItemsListResponse(items: [...])
Reviews (1): Last reviewed commit: "fix(desktop): accept both action_items a..." | Re-trigger Greptile
Cover both action_items and items key variants, precedence when both present, missing key errors, and empty arrays. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All checkpoints passed — ready for merge
Changes:
Awaiting human merge approval. by AI for @beastoin |
E2E Test Results — Mac Mini (pr6414 named bundle)Build & Launch
Test Results1. TaskDedup / Staged Tasks decode (the fix) ✅
2. Tasks page ✅ 3. Goals ✅ 4. Decode errors ✅ None ScreenshotsDashboard (Tasks + Goals loaded) Unit Tests7/7 pass: by AI for @beastoin |
|
lgtm |
Desktop App Walkthrough — Omi Beta v0.11.251 (Mac Mini)Pages Tested
Errors Found in Logs (v0.11.251)1. TaskDedup decode error (fixed by this PR) 🔧 This is the exact bug #6387 fixes. Will be resolved in the next release. 2. Backend settings decode error Backend settings response missing 3. SQLite disk I/O errors (widespread) Multiple subsystems hit SQLite I/O errors — RewindIndexer, TasksStore, Focus, Memory, TranscriptionRetry. The database eventually recovers but this causes data loss for Rewind frames captured during the error window. 4. TranscriptionRetryService: Crashed sessions ℹ️ 15 out of 71 transcription sessions failed (21% failure rate). 5. AppleNotesReaderService: Authorization denied ℹ️ Missing Full Disk Access permission for reading Apple Notes. 6. WebSocket disconnect ℹ️ Single WS disconnect event. ScreenshotsRecommendations
by AI for @beastoin |


Summary
ActionItemsListResponsecustomDecodableinit(from:)now triesaction_itemsfirst, falls back toitems— fixinggetStagedTasks()which hits/v1/staged-tasksreturning{"items": [...]}.CodabletoDecodable(type is never encoded).Tests
7 unit tests in
ActionItemsListResponseTests.swift:action_itemskey (/v1/action-items shape)itemskey (/v1/staged-tasks shape)action_itemstakes precedencehas_more→ decode throwsaction_itemsarrayitemsarrayAll 7 tests pass locally via
xcrun swift test --filter ActionItemsListResponse.Risks / Edge Cases
action_itemsanditemswith different values,action_itemswins.Decodableonly. If encoding is ever needed, addEncodableconformance separately.Review Cycle Changes
Fixes #6387
🤖 Generated with Claude Code