Skip to content

feat: add polling fallback for stale asset downloads#7926

Merged
DrJKL merged 12 commits intomainfrom
feat/stale-download-polling
Jan 10, 2026
Merged

feat: add polling fallback for stale asset downloads#7926
DrJKL merged 12 commits intomainfrom
feat/stale-download-polling

Conversation

@DrJKL
Copy link
Contributor

@DrJKL DrJKL commented Jan 9, 2026

Summary

Adds a polling fallback mechanism to recover from dropped WebSocket messages during model downloads.

Problem

When downloading models via the asset download service, status updates are received over WebSocket. Sometimes these messages are dropped (network issues, reconnection, etc.), causing downloads to appear "stuck" even when they've completed on the backend.

Solution

Periodically poll for stale downloads using the existing REST API:

  • Track lastUpdate timestamp on each download
  • Downloads without updates for 10s are considered "stale"
  • Poll stale downloads every 10s via GET /tasks/{task_id} to check if the asset exists
  • If the asset exists with size > 0, mark the download as completed

Implementation

  • Added lastUpdate field to AssetDownload interface
  • Use VueUse's useIntervalFn with a watch to auto start/stop polling based on active downloads
  • Reuse existing handleAssetDownload for completion (synthetic event)
  • Added 9 unit tests covering the polling behavior

Testing

  • All existing tests pass
  • New tests cover:
    • Basic download tracking
    • Completion/failure handling
    • Duplicate message prevention
    • Stale download polling
    • Polling error handling

┆Issue is synchronized with this Notion page by Unito

@DrJKL DrJKL requested a review from a team as a code owner January 9, 2026 10:01
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jan 9, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Adds timestamp tracking to AssetDownload, makes assetId optional, introduces polling reconciliation using a new taskService to finalize stale downloads, updates stories and schemas, and adds comprehensive store tests plus testing docs and AGENTS references.

Changes

Cohort / File(s) Change summary / attention points
Store + Polling
src/stores/assetDownloadStore.ts
Add lastUpdate: number, make assetId optional, introduce STALE/POLL constants, start/stop polling via useIntervalFn/watch, remove processedTask cleanup, synthesize terminal events from taskService. Review polling lifecycle, deduplication, and race conditions.
Task service
src/platform/tasks/services/taskService.ts
New singleton taskService.getTask(taskId) with Zod validation and exported TaskResponse type. Verify HTTP error handling and schema mapping for download_file payloads.
API schema
src/schemas/apiSchema.ts
zAssetDownloadWsMessage.asset_id made optional. Consumers must handle missing asset_id.
Stories
src/components/honeyToast/HoneyToast.stories.ts, src/components/toast/ProgressToastItem.stories.ts
Story mocks now include lastUpdate: Date.now(). Update assertions or shape expectations if present.
Tests
src/stores/assetDownloadStore.test.ts
New comprehensive tests covering WS handling, polling reconciliation, staleness thresholds, deduplication, and clearing finished downloads. Note use of fake timers and module resets.
Docs / Meta
AGENTS.md, docs/testing/vitest-patterns.md
Added testing guidance and AGENTS references; editorial only.

Sequence Diagram(s)

sequenceDiagram
  participant WS as WebSocket / API events
  participant Store as assetDownloadStore
  participant Task as taskService (HTTP)

  Note over WS,Store: Runtime asset_download WebSocket events
  WS->>Store: asset_download (may omit asset_id)
  Store->>Store: create/update AssetDownload (set lastUpdate)
  alt event is terminal (completed/failed)
    Store->>Store: move entry to finishedDownloads (record timestamp)
  else non-terminal
    Store->>Store: keep/update in activeDownloads
  end

  Note over Store,Task: Polling reconciles stale active downloads
  Store->>Task: getTask(taskId) [pollStaleDownloads]
  Task-->>Store: TaskResponse (status/payload)
  alt TaskResponse indicates terminal and Store lacks terminal event
    Store->>Store: synthesize terminal asset_download event -> move to finished
  end
Loading

Possibly related PRs

  • Comfy-Org/ComfyUI_frontend PR 7746 — Modifies AssetDownload shape and assetDownload store behavior; likely overlaps on schema and store logic.
  • Comfy-Org/ComfyUI_frontend PR 7897 — Also adjusts assetDownload store and finishedDownloads handling; related to deduplication/cleanup changes.
✨ Finishing touches
  • 📝 Generate docstrings

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Jan 9, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/10/2026, 12:17:18 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Jan 9, 2026

🎭 Playwright Test Results

All tests passed!

⏰ Completed at: 01/10/2026, 12:22:36 AM UTC

📈 Summary

  • Total Tests: 514
  • Passed: 506 ✅
  • Failed: 0
  • Flaky: 0
  • Skipped: 8 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 494 / ❌ 0 / ⚠️ 0 / ⏭️ 8
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 9 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Jan 9, 2026

Bundle Size Report

Summary

  • Raw size: 18.7 MB baseline 18.7 MB — 🔴 +2.87 kB
  • Gzip: 3.83 MB baseline 3.83 MB — 🔴 +700 B
  • Brotli: 2.92 MB baseline 2.92 MB — 🔴 +223 B
  • Bundles: 94 current • 94 baseline • 51 added / 51 removed

Category Glance
App Entry Points 🔴 +2.87 kB (3.24 MB) · Vendor & Third-Party ⚪ 0 B (9.19 MB) · Other ⚪ 0 B (4.68 MB) · Graph Workspace ⚪ 0 B (1.05 MB) · Panels & Settings ⚪ 0 B (337 kB) · UI Components ⚪ 0 B (198 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.24 MB (baseline 3.24 MB) • 🔴 +2.87 kB

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BrAqc48W.js (new) 3.05 MB 🔴 +3.05 MB 🔴 +640 kB 🔴 +486 kB
assets/index-CfIrGs2y.js (removed) 3.05 MB 🟢 -3.05 MB 🟢 -640 kB 🟢 -486 kB
assets/index-BZen8dn6.js (removed) 194 kB 🟢 -194 kB 🟢 -42.3 kB 🟢 -35.1 kB
assets/index-Dk2zQiNG.js (new) 194 kB 🔴 +194 kB 🔴 +42.3 kB 🔴 +35.1 kB
assets/index-BN4ljhjY.js (new) 345 B 🔴 +345 B 🔴 +245 B 🔴 +201 B
assets/index-DrLqTWe7.js (removed) 345 B 🟢 -345 B 🟢 -245 B 🟢 -234 B

Status: 3 added / 3 removed

Graph Workspace — 1.05 MB (baseline 1.05 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-B1E4EC_a.js (new) 1.05 MB 🔴 +1.05 MB 🔴 +203 kB 🔴 +154 kB
assets/GraphView-CEjWxJJN.js (removed) 1.05 MB 🟢 -1.05 MB 🟢 -203 kB 🟢 -154 kB

Status: 1 added / 1 removed

Views & Navigation — 6.63 kB (baseline 6.63 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-4y0XDHil.js (new) 6.63 kB 🔴 +6.63 kB 🔴 +2.14 kB 🔴 +1.89 kB
assets/UserSelectView-BNQJ_uNv.js (removed) 6.63 kB 🟢 -6.63 kB 🟢 -2.14 kB 🟢 -1.89 kB

Status: 1 added / 1 removed

Panels & Settings — 337 kB (baseline 337 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LegacyCreditsPanel-Bgt2kH_1.js (removed) 25.1 kB 🟢 -25.1 kB 🟢 -5.74 kB 🟢 -5 kB
assets/LegacyCreditsPanel-Dhfg4AI1.js (new) 25.1 kB 🔴 +25.1 kB 🔴 +5.74 kB 🔴 +5.01 kB
assets/KeybindingPanel-C3IjcjWy.js (removed) 14.8 kB 🟢 -14.8 kB 🟢 -3.57 kB 🟢 -3.12 kB
assets/KeybindingPanel-DkdwSlJg.js (new) 14.8 kB 🔴 +14.8 kB 🔴 +3.58 kB 🔴 +3.12 kB
assets/ExtensionPanel-BYlF7M4V.js (removed) 11.1 kB 🟢 -11.1 kB 🟢 -2.62 kB 🟢 -2.3 kB
assets/ExtensionPanel-Drv6QU7l.js (new) 11.1 kB 🔴 +11.1 kB 🔴 +2.62 kB 🔴 +2.29 kB
assets/AboutPanel-5XPzproC.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/AboutPanel-QIUdkBTA.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/ServerConfigPanel-B1iZiNEF.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -2.04 kB 🟢 -1.81 kB
assets/ServerConfigPanel-ljMwgVoO.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +2.04 kB 🔴 +1.81 kB
assets/UserPanel-Ch3M1IxT.js (removed) 6.88 kB 🟢 -6.88 kB 🟢 -1.79 kB 🟢 -1.56 kB
assets/UserPanel-Cr0RHbzh.js (new) 6.88 kB 🔴 +6.88 kB 🔴 +1.79 kB 🔴 +1.57 kB
assets/settings-BbW1wrcp.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CtIClcWI.js 26 kB 26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D_f3uAqO.js 22.4 kB 22.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DiVjuKQX.js 34.4 kB 34.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DJiF1Y59.js 25.8 kB 25.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DKkx6nFR.js 28.2 kB 28.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DX5qVgIQ.js 24.9 kB 24.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-MzsBgiwB.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-pR7Ue3ei.js 26.7 kB 26.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-y_-zNlA6.js 27.5 kB 27.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 198 kB (baseline 198 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LazyImage.vue_vue_type_script_setup_true_lang-DXIeKBDS.js (removed) 63 kB 🟢 -63 kB 🟢 -12.9 kB 🟢 -11.2 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-uj0WlXay.js (new) 63 kB 🔴 +63 kB 🔴 +12.9 kB 🔴 +11.2 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-BJZdsmHj.js (removed) 56.4 kB 🟢 -56.4 kB 🟢 -8.78 kB 🟢 -7.53 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-C1PmFdBg.js (new) 56.4 kB 🔴 +56.4 kB 🔴 +8.78 kB 🔴 +7.54 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-CjtKHvtr.js (new) 49 kB 🔴 +49 kB 🔴 +10.6 kB 🔴 +9.14 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-CxdwNn9k.js (removed) 49 kB 🟢 -49 kB 🟢 -10.5 kB 🟢 -9.14 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-BdNSbJt-.js (new) 10.9 kB 🔴 +10.9 kB 🔴 +2.89 kB 🔴 +2.57 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-pIdkoAiI.js (removed) 10.9 kB 🟢 -10.9 kB 🟢 -2.89 kB 🟢 -2.55 kB
assets/ComfyQueueButton-CH4a87Wp.js (removed) 8.83 kB 🟢 -8.83 kB 🟢 -2.58 kB 🟢 -2.3 kB
assets/ComfyQueueButton-MNRoPI14.js (new) 8.83 kB 🔴 +8.83 kB 🔴 +2.58 kB 🔴 +2.3 kB
assets/WidgetWithControl.vue_vue_type_script_setup_true_lang-7A9CtilT.js (removed) 3.72 kB 🟢 -3.72 kB 🟢 -1.45 kB 🟢 -1.32 kB
assets/WidgetWithControl.vue_vue_type_script_setup_true_lang-B779uCMj.js (new) 3.72 kB 🔴 +3.72 kB 🔴 +1.45 kB 🔴 +1.32 kB
assets/WidgetButton-Bt40D8Ze.js (removed) 2.21 kB 🟢 -2.21 kB 🟢 -994 B 🟢 -896 B
assets/WidgetButton-DOhXngOW.js (new) 2.21 kB 🔴 +2.21 kB 🔴 +995 B 🔴 +887 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-CGRC2FfQ.js (new) 2.14 kB 🔴 +2.14 kB 🔴 +891 B 🔴 +770 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-Diyrcm5a.js (removed) 2.14 kB 🟢 -2.14 kB 🟢 -889 B 🟢 -773 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-CLNGxUXy.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -688 B 🟢 -597 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-DIK87nsO.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +687 B 🔴 +593 B

Status: 9 added / 9 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-CBwSeLD1.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/keybindingService-CCQUvJom.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.83 kB 🟢 -1.57 kB
assets/serverConfigStore-B2t_j388.js (new) 2.83 kB 🔴 +2.83 kB 🔴 +908 B 🔴 +789 B
assets/serverConfigStore-WBPbcz9c.js (removed) 2.83 kB 🟢 -2.83 kB 🟢 -908 B 🟢 -791 B
assets/audioService-BddXi7HG.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +962 B 🔴 +824 B
assets/audioService-Be4scINa.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -961 B 🟢 -822 B

Status: 3 added / 3 removed

Utilities & Hooks — 1.41 kB (baseline 1.41 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-C4eQjPqq.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +652 B 🔴 +542 B
assets/audioUtils-DVexhS3J.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -651 B 🟢 -544 B

Status: 1 added / 1 removed

Vendor & Third-Party — 9.19 MB (baseline 9.19 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-other-BKaihHB6.js (removed) 3.9 MB 🟢 -3.9 MB 🟢 -848 kB 🟢 -678 kB
assets/vendor-other-CTAuztsb.js (new) 3.9 MB 🔴 +3.9 MB 🔴 +848 kB 🔴 +678 kB
assets/vendor-three-B_f9r0GW.js (new) 2.08 MB 🔴 +2.08 MB 🔴 +430 kB 🔴 +308 kB
assets/vendor-three-dmBDP-PR.js (removed) 2.08 MB 🟢 -2.08 MB 🟢 -430 kB 🟢 -308 kB
assets/vendor-primevue-Sy8DeJCi.js (removed) 1.95 MB 🟢 -1.95 MB 🟢 -333 kB 🟢 -201 kB
assets/vendor-primevue-VcXE4r8X.js (new) 1.95 MB 🔴 +1.95 MB 🔴 +333 kB 🔴 +201 kB
assets/vendor-chart-DDj4RAFz.js (removed) 452 kB 🟢 -452 kB 🟢 -99 kB 🟢 -81 kB
assets/vendor-chart-DUP4WQ_9.js (new) 452 kB 🔴 +452 kB 🔴 +99 kB 🔴 +81 kB
assets/vendor-tiptap-B8b7Kqfl.js (new) 232 kB 🔴 +232 kB 🔴 +45.7 kB 🔴 +37.7 kB
assets/vendor-tiptap-Dbtt2BZO.js (removed) 232 kB 🟢 -232 kB 🟢 -45.7 kB 🟢 -37.7 kB
assets/vendor-vue-BfO51q9u.js (removed) 160 kB 🟢 -160 kB 🟢 -37 kB 🟢 -31.3 kB
assets/vendor-vue-BggM5WRa.js (new) 160 kB 🔴 +160 kB 🔴 +37 kB 🔴 +31.3 kB
assets/vendor-xterm-BF8peZ5_.js 420 kB 420 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

Other — 4.68 MB (baseline 4.68 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SubscriptionRequiredDialogContent-BkzQEJdj.js (removed) 29.3 kB 🟢 -29.3 kB 🟢 -6.51 kB 🟢 -5.66 kB
assets/SubscriptionRequiredDialogContent-CnTRzUcZ.js (new) 29.3 kB 🔴 +29.3 kB 🔴 +6.51 kB 🔴 +5.66 kB
assets/WidgetRecordAudio-BF9bPOmS.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.23 kB 🟢 -4.63 kB
assets/WidgetRecordAudio-tB9rDtkn.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.23 kB 🔴 +4.64 kB
assets/AudioPreviewPlayer-DaLxYPiG.js (new) 13.3 kB 🔴 +13.3 kB 🔴 +3.35 kB 🔴 +2.99 kB
assets/AudioPreviewPlayer-pEgmEKgD.js (removed) 13.3 kB 🟢 -13.3 kB 🟢 -3.35 kB 🟢 -3 kB
assets/ValueControlPopover-3Qr0zOYo.js (removed) 5.49 kB 🟢 -5.49 kB 🟢 -1.71 kB 🟢 -1.51 kB
assets/ValueControlPopover-D2GdGRh7.js (new) 5.49 kB 🔴 +5.49 kB 🔴 +1.71 kB 🔴 +1.52 kB
assets/WidgetGalleria-ik45NFXc.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.45 kB 🔴 +1.31 kB
assets/WidgetGalleria-seMP1NBV.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.45 kB 🟢 -1.31 kB
assets/WidgetColorPicker-CADTw-St.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-vt00ew7v.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.24 kB
assets/WidgetImageCompare-BpH9qHbL.js (new) 3.21 kB 🔴 +3.21 kB 🔴 +1.1 kB 🔴 +979 B
assets/WidgetImageCompare-CUzpNdr6.js (removed) 3.21 kB 🟢 -3.21 kB 🟢 -1.1 kB 🟢 -952 B
assets/WidgetTextarea-BeTY1Bj3.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.21 kB 🔴 +1.08 kB
assets/WidgetTextarea-CD5_G9jk.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.21 kB 🟢 -1.08 kB
assets/WidgetMarkdown-Bj_pwWLp.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetMarkdown-DKuvZKO_.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetAudioUI-9GIk0Psl.js (new) 2.89 kB 🔴 +2.89 kB 🔴 +1.17 kB 🔴 +1.06 kB
assets/WidgetAudioUI-BCuYVpAW.js (removed) 2.89 kB 🟢 -2.89 kB 🟢 -1.17 kB 🟢 -1.06 kB
assets/WidgetToggleSwitch-4lxTvqQY.js (new) 2.66 kB 🔴 +2.66 kB 🔴 +1.13 kB 🔴 +1.02 kB
assets/WidgetToggleSwitch-D_C-k4dx.js (removed) 2.66 kB 🟢 -2.66 kB 🟢 -1.13 kB 🟢 -1.03 kB
assets/MediaVideoTop-9cP_AzIo.js (new) 2.65 kB 🔴 +2.65 kB 🔴 +1.01 kB 🔴 +867 B
assets/MediaVideoTop-BTtflGg_.js (removed) 2.65 kB 🟢 -2.65 kB 🟢 -1.01 kB 🟢 -867 B
assets/WidgetChart-BMxZsP1p.js (removed) 2.48 kB 🟢 -2.48 kB 🟢 -932 B 🟢 -820 B
assets/WidgetChart-CZhjICiW.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +932 B 🔴 +816 B
assets/WidgetInputText-BG8bKeqt.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +921 B 🔴 +847 B
assets/WidgetInputText-C8T2LvHI.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -919 B 🟢 -829 B
assets/MediaImageTop-B_idcQw8.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +840 B 🔴 +713 B
assets/MediaImageTop-BLi3FV8T.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -842 B 🟢 -722 B
assets/Media3DTop-CwYoBige.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +767 B 🔴 +653 B
assets/Media3DTop-D7Q9LqZG.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -768 B 🟢 -653 B
assets/MediaAudioTop-D4etXAkS.js (removed) 1.46 kB 🟢 -1.46 kB 🟢 -740 B 🟢 -619 B
assets/MediaAudioTop-Dc3cUA9O.js (new) 1.46 kB 🔴 +1.46 kB 🔴 +739 B 🔴 +619 B
assets/WidgetSelect-BiJctx5H.js (new) 733 B 🔴 +733 B 🔴 +360 B 🔴 +303 B
assets/WidgetSelect-C3uY_YvR.js (removed) 733 B 🟢 -733 B 🟢 -359 B 🟢 -304 B
assets/WidgetInputNumber-DGwhRadm.js (new) 673 B 🔴 +673 B 🔴 +348 B 🔴 +286 B
assets/WidgetInputNumber-x60fXuS-.js (removed) 673 B 🟢 -673 B 🟢 -345 B 🟢 -290 B
assets/Load3D-CO6d3Z4U.js (removed) 424 B 🟢 -424 B 🟢 -266 B 🟢 -223 B
assets/Load3D-DAi88yzm.js (new) 424 B 🔴 +424 B 🔴 +267 B 🔴 +224 B
assets/WidgetLegacy-CCFONKbP.js (removed) 364 B 🟢 -364 B 🟢 -238 B 🟢 -194 B
assets/WidgetLegacy-DgLk5sh6.js (new) 364 B 🔴 +364 B 🔴 +237 B 🔴 +195 B
assets/commands-BtYX0Lg9.js 17.7 kB 17.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BwenEAzL.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CXF6rcF5.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CyGop0zh.js 15.1 kB 15.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DDahbUT-.js 15.7 kB 15.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DlbDMAz3.js 15.2 kB 15.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DLFlLaoZ.js 16.4 kB 16.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-edqUNgZp.js 16 kB 16 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-SQ5j-1oJ.js 14.3 kB 14.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-zgiVm_G2.js 15.1 kB 15.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B16jKkB3.js 107 kB 107 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B2TMohNC.js 93.7 kB 93.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B9-NG52U.js 147 kB 147 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-bQPsWuI2.js 105 kB 105 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Bx9Pzrg9.js 121 kB 121 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cb3hBPIf.js 111 kB 111 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CeXo1Tna.js 127 kB 127 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-gLRt05og.js 93 kB 93 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-GZ4VEqlX.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-NJcwE12r.js 105 kB 105 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-0_kHljWg.js 353 kB 353 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bjeo0cw0.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BLhGKWur.js 325 kB 325 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BUu8SapY.js 316 kB 316 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BWAWxLy2.js 385 kB 385 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BxejeXt1.js 309 kB 309 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CkOvKQSg.js 312 kB 312 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DL1JIqUG.js 313 kB 313 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DLvvFZfB.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-otaRtSJI.js 288 kB 288 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 21 added / 21 removed

Copy link
Contributor

@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: 1

🤖 Fix all issues with AI agents
In @src/stores/assetDownloadStore.test.ts:
- Around line 6-7: The module-level mutable variable eventHandler should be
hoisted for per-test control; replace the top-level declaration with
vi.hoisted(() => null) and add a getEventHandler helper to read/write it, update
dispatchDownloadEvent to use getEventHandler() instead of the bare eventHandler,
and call eventHandler.set(null) (or reset via the hoisted handle) in beforeEach
to ensure each test starts with a clean mock state.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 43c162a and 14f0695.

📒 Files selected for processing (4)
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Leverage VueUse functions for performance-enhancing utilities

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements; do not mix inline type imports in the same statement
Sort and group imports by plugin; run pnpm format before committing
Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Code should be well-designed with clear names for everything; write code that is expressive and self-documenting
Avoid redundant comments and clean up code as you go; comments should explain why, not what
Ask if there is a simpler way to implement functionality; refactor complex code to simplify it
Minimize nesting depth (e.g., if () { ... } or for () { ... }); watch for arrow anti-pattern
Watch out for code smells and refactor to avoid them
Never use any type; use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Indent with 2 spaces; use single quotes; no trailing semicolons; max line width 80 (per .prettierrc)
Complex type definitions used in multiple related places should be extracted and named for reuse
Implement proper error handling

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional; use function declarations instead of function expressions when possible
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
src/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.test.ts: Write unit tests in src/**/*.test.ts; use Vitest with happy-dom
Do not write tests that only test the mocks; ensure tests fail when code behaves unexpectedly
Use Vitest's utilities for mocking where possible; keep module mocks contained and avoid global mutable state
Use Vue Test Utils for component testing; follow advice about making components easy to test
Use vi.hoisted() in tests to allow per-test Arrange phase manipulation of mock state
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/stores/assetDownloadStore.test.ts
**/*.{test,spec}.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.ts: Do not write change detector tests that only assert default values
Do not write tests dependent on non-behavioral features like utility classes or styles
Write tests for all changes, especially bug fixes to catch future regressions
Be parsimonious in testing; do not write redundant tests (see Composable Tests pattern)
Do not mock what you don't own; avoid mocking external dependencies

Files:

  • src/stores/assetDownloadStore.test.ts
src/stores/**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia store files with the *Store.ts suffix

Files:

  • src/stores/assetDownloadStore.ts
🧠 Learnings (16)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2026-01-08T21:43:58.213Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7897
File: src/stores/assetDownloadStore.ts:117-117
Timestamp: 2026-01-08T21:43:58.213Z
Learning: In src/stores/assetDownloadStore.ts, the api.addEventListener('asset_download', handleAssetDownload) call at module level is intentional and should persist for the application lifetime since it's a singleton Pinia store managing global WebSocket events.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Check assets/ directory for test data when writing tests

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to **/*.{test,spec}.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Use Vitest's utilities for mocking where possible; keep module mocks contained and avoid global mutable state

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Use `vi.hoisted()` in tests to allow per-test Arrange phase manipulation of mock state

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift. This improves maintainability and consistency across tests.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T02:07:54.558Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:54.558Z
Learning: In test files (e.g., any .test.ts or .test.tsx under src/...), when you create mock objects that partially implement an interface (such as LGraphNode), prefer casting with as Partial<InterfaceType> as InterfaceType rather than as any or as unknown as InterfaceType. This makes the incomplete implementation explicit while preserving type safety, improving readability and maintainability of tests.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-06T19:17:12.355Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:12.355Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.

Applied to files:

  • src/stores/assetDownloadStore.ts
🧬 Code graph analysis (2)
src/stores/assetDownloadStore.test.ts (2)
src/schemas/apiSchema.ts (1)
  • AssetDownloadWsMessage (168-168)
src/stores/assetDownloadStore.ts (1)
  • useAssetDownloadStore (31-153)
src/stores/assetDownloadStore.ts (1)
src/platform/assets/services/assetService.ts (1)
  • assetService (533-533)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: setup
  • GitHub Check: collect
🔇 Additional comments (13)
src/components/toast/ProgressToastItem.stories.ts (1)

32-32: LGTM!

The addition of lastUpdate: Date.now() correctly aligns the mock data with the updated AssetDownload interface.

src/components/honeyToast/HoneyToast.stories.ts (1)

20-20: LGTM!

The addition of lastUpdate: Date.now() correctly updates the mock data to match the new AssetDownload interface.

src/stores/assetDownloadStore.test.ts (2)

147-170: LGTM! Polling test correctly validates stale download recovery.

The test properly verifies the polling behavior:

  • Uses vi.advanceTimersByTimeAsync(45000) which correctly accounts for the 30s stale threshold + 15s poll interval
  • Verifies that assetService.getAssetDetails is called for stale downloads
  • Confirms the download transitions from active to finished with completed status

68-219: Excellent test coverage for the polling feature.

The test suite comprehensively covers:

  • Basic download tracking and status transitions
  • Deduplication of terminal states
  • Model type association for completion tracking
  • Stale download polling with threshold enforcement
  • Polling error handling
  • Finished download cleanup

The tests follow behavioral testing principles and validate the critical paths of the new polling mechanism.

src/stores/assetDownloadStore.ts (9)

1-1: LGTM! Appropriate VueUse and service imports.

The additions correctly import:

  • useIntervalFn for interval-based polling
  • watch for reactive polling control
  • assetService for REST API asset fetching

Also applies to: 3-3, 5-5


18-18: LGTM! lastUpdate field added to track stale downloads.

The lastUpdate: number field is essential for the polling mechanism to determine when downloads have gone stale.


28-29: LGTM! Well-chosen polling constants.

The 30-second stale threshold and 15-second poll interval provide a good balance:

  • Allows for transient network issues without immediate polling
  • Frequent enough to recover dropped messages reasonably quickly
  • Polls twice within the stale window for reliability

56-61: Excellent defensive check to prevent duplicate processing.

The terminal state check ensures that completed or failed downloads are not re-processed if additional WebSocket messages arrive. This is critical for the polling fallback which synthesizes completion events.


72-72: LGTM! Timestamp updated on every download event.

Setting lastUpdate: Date.now() on each event ensures the polling logic can accurately determine staleness.


80-84: LGTM! Completion tracking updated with timestamp.

The immutable update pattern correctly adds new completed downloads with timestamps while maintaining the MAX_COMPLETED_DOWNLOADS limit.


93-122: Solid polling implementation with appropriate error handling.

The pollStaleDownloads function correctly:

  • Filters active downloads by staleness threshold
  • Skips downloads without asset IDs
  • Fetches asset details from the REST API
  • Synthesizes completion events via the existing handleAssetDownload flow
  • Silently handles errors (asset not ready yet)

The silent error handling on line 118-120 is appropriate here since the asset may legitimately not be ready, and the next poll will retry.

Verify that the silent error handling aligns with expected backend behavior when assets are still processing.


124-128: LGTM! Proper use of VueUse's useIntervalFn.

The configuration is correct:

  • Uses void operator for the async function (fire-and-forget is appropriate for polling)
  • Sets immediate: false to defer polling until explicitly started
  • Destructures pause and resume for lifecycle control

130-133: Excellent reactive polling control.

The watch properly starts polling when downloads become active and stops when all downloads finish, ensuring efficient resource usage.

@DrJKL DrJKL force-pushed the feat/stale-download-polling branch 2 times, most recently from 5c6452d to f5fc449 Compare January 9, 2026 10:08
@DrJKL DrJKL force-pushed the feat/stale-download-polling branch from f5fc449 to 020f880 Compare January 9, 2026 10:09
@DrJKL DrJKL force-pushed the feat/stale-download-polling branch from e0d3333 to 39d664a Compare January 9, 2026 10:15
@DrJKL DrJKL marked this pull request as draft January 9, 2026 19:58
@DrJKL DrJKL marked this pull request as ready for review January 9, 2026 21:12
@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jan 9, 2026
Copy link
Contributor

@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: 2

🤖 Fix all issues with AI agents
In @src/platform/tasks/services/taskService.ts:
- Around line 56-61: The task response validation currently throws a generic
Error with result.error.message after zTaskResponse.safeParse; instead import
and use fromZodError to format the Zod error and include it in the thrown Error
to provide clearer, user-friendly messages without leaking schema internals (add
import of fromZodError and replace the throw new Error(...) in the safeParse
failure branch to throw a new Error(fromZodError(result.error))).

In @src/stores/assetDownloadStore.ts:
- Around line 93-124: pollStaleDownloads currently iterates activeDownloads
sequentially and awaits each taskService.getTask call one-by-one, which can
stall recovery when many items are stale; change it to collect stale entries
(using activeDownloads.value and STALE_THRESHOLD_MS), then perform the
taskService.getTask calls in parallel with bounded concurrency (e.g., batch them
or use a concurrency limiter) and for each resolved task invoke
handleAssetDownload with the same event construction and error handling; keep
the existing task.status checks and catch block but replace the for...of await
sequence with Promise.all over the batched/limited async map to improve
scalability.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14f0695 and 8807e14.

📒 Files selected for processing (7)
  • AGENTS.md
  • docs/testing/vitest-patterns.md
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
🧰 Additional context used
📓 Path-based instructions (13)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Leverage VueUse functions for performance-enhancing utilities

Files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements; do not mix inline type imports in the same statement
Sort and group imports by plugin; run pnpm format before committing
Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Code should be well-designed with clear names for everything; write code that is expressive and self-documenting
Avoid redundant comments and clean up code as you go; comments should explain why, not what
Ask if there is a simpler way to implement functionality; refactor complex code to simplify it
Minimize nesting depth (e.g., if () { ... } or for () { ... }); watch for arrow anti-pattern
Watch out for code smells and refactor to avoid them
Never use any type; use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Indent with 2 spaces; use single quotes; no trailing semicolons; max line width 80 (per .prettierrc)
Complex type definitions used in multiple related places should be extracted and named for reuse
Implement proper error handling

Files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.test.ts: Write unit tests in src/**/*.test.ts; use Vitest with happy-dom
Do not write tests that only test the mocks; ensure tests fail when code behaves unexpectedly
Use Vitest's utilities for mocking where possible; keep module mocks contained and avoid global mutable state
Use Vue Test Utils for component testing; follow advice about making components easy to test
Use vi.hoisted() in tests to allow per-test Arrange phase manipulation of mock state
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • src/stores/assetDownloadStore.test.ts
**/*.{test,spec}.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.ts: Do not write change detector tests that only assert default values
Do not write tests dependent on non-behavioral features like utility classes or styles
Write tests for all changes, especially bug fixes to catch future regressions
Be parsimonious in testing; do not write redundant tests (see Composable Tests pattern)
Do not mock what you don't own; avoid mocking external dependencies

Files:

  • src/stores/assetDownloadStore.test.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional; use function declarations instead of function expressions when possible
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/stores/**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia store files with the *Store.ts suffix

Files:

  • src/stores/assetDownloadStore.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/platform/tasks/services/taskService.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
🧠 Learnings (32)
📚 Learning: 2026-01-08T21:43:58.213Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7897
File: src/stores/assetDownloadStore.ts:117-117
Timestamp: 2026-01-08T21:43:58.213Z
Learning: In src/stores/assetDownloadStore.ts, the api.addEventListener('asset_download', handleAssetDownload) call at module level is intentional and should persist for the application lifetime since it's a singleton Pinia store managing global WebSocket events.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Check assets/ directory for test data when writing tests

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to **/*.{test,spec}.ts : Write tests for all changes, especially bug fixes to catch future regressions

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • docs/testing/vitest-patterns.md
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Use `vi.hoisted()` in tests to allow per-test Arrange phase manipulation of mock state

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • docs/testing/vitest-patterns.md
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Use Vitest's utilities for mocking where possible; keep module mocks contained and avoid global mutable state

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • docs/testing/vitest-patterns.md
  • AGENTS.md
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to browser_tests/**/*.spec.ts : Follow Playwright best practices as described in the official documentation

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • docs/testing/vitest-patterns.md
  • AGENTS.md
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Do not write tests that only test the mocks; ensure tests fail when code behaves unexpectedly

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In TypeScript test files (e.g., any test under src), avoid duplicating interface/type definitions. Import real type definitions from the component modules under test and reference them directly, so there is a single source of truth and to prevent type drift. This improves maintainability and consistency across tests.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2026-01-09T02:07:54.558Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7898
File: src/composables/usePaste.test.ts:248-248
Timestamp: 2026-01-09T02:07:54.558Z
Learning: In test files (e.g., any .test.ts or .test.tsx under src/...), when you create mock objects that partially implement an interface (such as LGraphNode), prefer casting with as Partial<InterfaceType> as InterfaceType rather than as any or as unknown as InterfaceType. This makes the incomplete implementation explicit while preserving type safety, improving readability and maintainability of tests.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/stores/assetDownloadStore.test.ts
  • src/stores/assetDownloadStore.ts
  • src/platform/tasks/services/taskService.ts
  • src/components/honeyToast/HoneyToast.stories.ts
  • src/components/toast/ProgressToastItem.stories.ts
📚 Learning: 2026-01-06T19:17:12.355Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:12.355Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:20:56.167Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:56.167Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.

Applied to files:

  • src/platform/tasks/services/taskService.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • docs/testing/vitest-patterns.md
  • AGENTS.md
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Write unit tests in `src/**/*.test.ts`; use Vitest with happy-dom

Applied to files:

  • docs/testing/vitest-patterns.md
  • AGENTS.md
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • docs/testing/vitest-patterns.md
  • AGENTS.md
📚 Learning: 2025-12-30T01:31:11.188Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:11.188Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (with `new` keyword), the mock implementation must use `function()` or `class` syntax instead of arrow functions. Arrow functions will cause `<anonymous> is not a constructor` errors. This is a breaking change from Vitest v3 where mocks used `mock.apply`.

Applied to files:

  • docs/testing/vitest-patterns.md
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • docs/testing/vitest-patterns.md
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.test.ts : Use Vue Test Utils for component testing; follow advice about making components easy to test

Applied to files:

  • docs/testing/vitest-patterns.md
  • AGENTS.md
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor

Applied to files:

  • docs/testing/vitest-patterns.md
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to **/*.{test,spec}.ts : Be parsimonious in testing; do not write redundant tests (see Composable Tests pattern)

Applied to files:

  • docs/testing/vitest-patterns.md
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to browser_tests/**/*.spec.ts : Write E2E tests in `browser_tests/**/*.spec.ts`; use Playwright

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Test user workflows in browser tests

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Use Playwright fixtures for browser tests

Applied to files:

  • AGENTS.md
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • AGENTS.md
🧬 Code graph analysis (3)
src/stores/assetDownloadStore.test.ts (3)
src/schemas/apiSchema.ts (1)
  • AssetDownloadWsMessage (168-168)
src/stores/assetDownloadStore.ts (1)
  • useAssetDownloadStore (31-155)
src/platform/tasks/services/taskService.ts (2)
  • TaskResponse (43-43)
  • taskService (69-69)
src/stores/assetDownloadStore.ts (1)
src/platform/tasks/services/taskService.ts (1)
  • taskService (69-69)
src/platform/tasks/services/taskService.ts (1)
src/scripts/api.ts (1)
  • api (1309-1309)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: playwright-tests-chromium-sharded (3, 8)
  • GitHub Check: playwright-tests-chromium-sharded (2, 8)
  • GitHub Check: playwright-tests-chromium-sharded (5, 8)
  • GitHub Check: playwright-tests-chromium-sharded (4, 8)
  • GitHub Check: playwright-tests-chromium-sharded (6, 8)
  • GitHub Check: playwright-tests-chromium-sharded (1, 8)
  • GitHub Check: playwright-tests-chromium-sharded (8, 8)
  • GitHub Check: playwright-tests-chromium-sharded (7, 8)
  • GitHub Check: playwright-tests (chromium-0.5x)
  • GitHub Check: playwright-tests (chromium-2x)
  • GitHub Check: playwright-tests (mobile-chrome)
  • GitHub Check: test
🔇 Additional comments (20)
AGENTS.md (1)

164-165: LGTM! Documentation reference is helpful.

The cross-reference to the new testing patterns documentation is appropriate and aligns with the new docs/testing/vitest-patterns.md file added in this PR.

docs/testing/vitest-patterns.md (1)

1-138: LGTM! Excellent testing documentation.

This documentation provides clear, practical patterns that align with the project's testing conventions and Vitest best practices. The examples are well-chosen and directly applicable to the codebase.

src/platform/tasks/services/taskService.ts (1)

1-9: Good caveat documentation.

The comment clearly documents the limitation that these schemas are specific to task:download_file tasks. This is appropriate for the initial implementation.

src/components/toast/ProgressToastItem.stories.ts (1)

23-35: LGTM! Mock data updated correctly.

The addition of lastUpdate to the mock aligns with the updated AssetDownload interface. This ensures Storybook stories remain functional with the new polling feature.

src/components/honeyToast/HoneyToast.stories.ts (1)

11-23: LGTM! Mock data updated correctly.

The addition of lastUpdate to the mock keeps this story file consistent with the updated AssetDownload interface, matching the identical change in ProgressToastItem.stories.ts.

src/stores/assetDownloadStore.test.ts (8)

1-8: LGTM! Imports are properly organized.

Type imports are correctly separated from value imports per the repository's lint rules. The use of vi.hoisted() for the event handler state follows the coding guidelines for per-test mock state manipulation.


17-30: LGTM! Mocks are cleanly scoped.

The mocks for api and taskService are self-contained and capture the event handler for test manipulation. This avoids global mutable state per the testing guidelines.


32-54: LGTM! Well-designed test helpers.

createDownloadMessage and dispatch are reusable helpers that keep tests concise. The error guard in dispatch provides helpful debugging feedback if the store isn't initialized.


56-66: LGTM! Proper test isolation setup.

Using createTestingPinia({ stubActions: false }) ensures real action execution while still providing test isolation. Fake timers and mock resets ensure clean state between tests.


68-114: LGTM! Good behavioral coverage for handleAssetDownload.

Tests verify:

  • Running downloads are tracked
  • Completed downloads move to finished state
  • Failed downloads move to finished state with error
  • Duplicate terminal state messages are ignored

These tests validate actual store behavior rather than implementation details.


131-166: LGTM! Polling success path is well tested.

The 45s advance correctly triggers the stale threshold (30s) and allows the poll interval (15s) to fire. The test verifies the integration with taskService.getTask and confirms the download transitions to completed state.


168-210: LGTM! Comprehensive polling edge case coverage.

Tests cover:

  • Failed task status propagation with error message
  • No state change when backend task is still running
  • Graceful handling of polling errors (download remains active)

This ensures the polling fallback is resilient to various backend states.


213-224: LGTM! clearFinishedDownloads test is straightforward.

Simple behavioral test that verifies finished downloads are removed from the store.

src/stores/assetDownloadStore.ts (7)

1-7: LGTM! Imports follow repository conventions.

Type imports are properly separated from value imports. Using useIntervalFn from VueUse for polling aligns with the coding guidelines to leverage VueUse for utility functions.


18-18: LGTM! lastUpdate field enables staleness detection.

Adding lastUpdate: number to the interface provides the timestamp needed to determine when a download should be polled.


28-29: LGTM! Reasonable polling constants.

30-second stale threshold balances responsiveness with avoiding premature polling. 15-second interval provides recovery without overwhelming the backend.


56-61: LGTM! Terminal state guard prevents duplicate processing.

The early return for completed/failed downloads ensures idempotency when WebSocket messages arrive after polling has already reconciled the state.


120-122: Empty catch block is appropriate here.

The silent catch aligns with the polling fallback design—errors are expected (task not found, network hiccups) and the next poll interval will retry. No action needed.


126-135: LGTM! Clean interval lifecycle management.

Using useIntervalFn with { immediate: false } and a watch to start/stop based on hasActiveDownloads ensures polling only runs when needed, avoiding unnecessary network requests when idle.


145-154: LGTM! Store exposes a clean public interface.

The return object maintains a minimal surface area with only the necessary computed properties and methods, keeping internal implementation (polling, event handling) private.

@DrJKL DrJKL force-pushed the feat/stale-download-polling branch from 4e64de5 to 6c180e0 Compare January 9, 2026 22:15
Copy link
Contributor

@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: 1

🤖 Fix all issues with AI agents
In @src/stores/assetDownloadStore.ts:
- Around line 93-129: The catch in pollSingleDownload inside pollStaleDownloads
swallows all errors, hiding network/parse/unexpected failures—update
pollSingleDownload to catch and handle only known "task not ready/not found"
cases (e.g., inspect error.status or error.code) and for other errors log them
with details (using the existing logger or console.error) and either rethrow or
mark the download as failed; specifically, adjust the try/catch around
taskService.getTask and include the error object in the log, referencing
pollStaleDownloads, pollSingleDownload, taskService.getTask, and
handleAssetDownload so you only suppress genuine "not found/not ready" errors
while surface unexpected ones for debugging.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8807e14 and 464e66c.

📒 Files selected for processing (2)
  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
🧰 Additional context used
📓 Path-based instructions (8)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Leverage VueUse functions for performance-enhancing utilities

Files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/platform/tasks/services/taskService.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements; do not mix inline type imports in the same statement
Sort and group imports by plugin; run pnpm format before committing
Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Code should be well-designed with clear names for everything; write code that is expressive and self-documenting
Avoid redundant comments and clean up code as you go; comments should explain why, not what
Ask if there is a simpler way to implement functionality; refactor complex code to simplify it
Minimize nesting depth (e.g., if () { ... } or for () { ... }); watch for arrow anti-pattern
Watch out for code smells and refactor to avoid them
Never use any type; use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Indent with 2 spaces; use single quotes; no trailing semicolons; max line width 80 (per .prettierrc)
Complex type definitions used in multiple related places should be extracted and named for reuse
Implement proper error handling

Files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional; use function declarations instead of function expressions when possible
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/assetDownloadStore.ts
src/stores/**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia store files with the *Store.ts suffix

Files:

  • src/stores/assetDownloadStore.ts
🧠 Learnings (8)
📚 Learning: 2026-01-06T19:20:56.167Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:56.167Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.

Applied to files:

  • src/platform/tasks/services/taskService.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/platform/tasks/services/taskService.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-08T21:43:58.213Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7897
File: src/stores/assetDownloadStore.ts:117-117
Timestamp: 2026-01-08T21:43:58.213Z
Learning: In src/stores/assetDownloadStore.ts, the api.addEventListener('asset_download', handleAssetDownload) call at module level is intentional and should persist for the application lifetime since it's a singleton Pinia store managing global WebSocket events.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:17:12.355Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:12.355Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.

Applied to files:

  • src/stores/assetDownloadStore.ts
🧬 Code graph analysis (2)
src/platform/tasks/services/taskService.ts (1)
src/scripts/api.ts (1)
  • api (1309-1309)
src/stores/assetDownloadStore.ts (1)
src/platform/tasks/services/taskService.ts (1)
  • taskService (70-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: playwright-tests-chromium-sharded (2, 8)
  • GitHub Check: playwright-tests-chromium-sharded (7, 8)
  • GitHub Check: playwright-tests-chromium-sharded (8, 8)
  • GitHub Check: playwright-tests-chromium-sharded (6, 8)
  • GitHub Check: playwright-tests-chromium-sharded (5, 8)
  • GitHub Check: playwright-tests-chromium-sharded (4, 8)
  • GitHub Check: playwright-tests-chromium-sharded (3, 8)
  • GitHub Check: playwright-tests-chromium-sharded (1, 8)
  • GitHub Check: playwright-tests (chromium-2x)
  • GitHub Check: playwright-tests (mobile-chrome)
  • GitHub Check: playwright-tests (chromium-0.5x)
  • GitHub Check: test
🔇 Additional comments (5)
src/platform/tasks/services/taskService.ts (2)

46-65: LGTM: Well-structured task fetching with proper error handling.

The getTask function correctly follows the established pattern:

  • Uses safeParse() instead of parse() to avoid exposing internal Zod schema details
  • Applies fromZodError() for user-friendly error messages
  • Handles 404 and other HTTP errors appropriately

Based on learnings from PR #7746.


30-42: Critical: Replace Zod v4 features with v3-compatible patterns.

Lines 31, 38, 40, and 41 use Zod v4-only validators (z.string().uuid() and z.string().datetime()), but this project uses Zod v3.x. These will cause runtime errors.

Based on learnings, in Zod v3:

  • Use z.string() with .refine() or .regex() for UUID validation
  • Use z.string() with ISO date/time string validation for datetime fields
🔧 Proposed fix for Zod v3 compatibility
+// UUID regex pattern for Zod v3
+const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
+
+// ISO 8601 datetime regex for Zod v3
+const ISO_DATETIME_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/
+
 const zTaskResponse = z.object({
-  id: z.string().uuid(),
+  id: z.string().regex(UUID_REGEX, 'Invalid UUID format'),
   idempotency_key: z.string(),
   task_name: z.string(),
   payload: z.record(z.unknown()),
   status: zTaskStatus,
   result: zDownloadFileResult.optional(),
   error_message: z.string().optional(),
-  create_time: z.string().datetime(),
-  update_time: z.string().datetime(),
-  started_at: z.string().datetime().optional(),
-  completed_at: z.string().datetime().optional()
+  create_time: z.string().regex(ISO_DATETIME_REGEX, 'Invalid ISO datetime'),
+  update_time: z.string().regex(ISO_DATETIME_REGEX, 'Invalid ISO datetime'),
+  started_at: z.string().regex(ISO_DATETIME_REGEX, 'Invalid ISO datetime').optional(),
+  completed_at: z.string().regex(ISO_DATETIME_REGEX, 'Invalid ISO datetime').optional()
 })

Based on learnings from PR #7169.

⛔ Skipped due to learnings
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:56.167Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.
src/stores/assetDownloadStore.ts (3)

56-61: LGTM: Prevents duplicate processing of completed downloads.

The terminal state check correctly guards against re-processing downloads that have already reached a final state, preventing unnecessary updates and potential race conditions.


131-140: LGTM: Efficient polling control with automatic start/stop.

The use of useIntervalFn with watch provides clean automatic lifecycle management:

  • Polling starts only when active downloads exist
  • Polling stops when all downloads complete
  • Avoids unnecessary polling cycles

This follows VueUse best practices for performance-enhancing utilities per coding guidelines.


71-72: LGTM: Consistent state tracking with lastUpdate.

The lastUpdate timestamp is correctly maintained on every event, enabling accurate stale detection. The error field is properly preserved from the WebSocket message.

task_name: z.string(),
payload: z.record(z.unknown()),
status: zTaskStatus,
result: zDownloadFileResult.optional(),
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: you could make the a generic and inject the zDownloadFileResult in the getTask function to future proof this a bit

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's what the caveat at the top is for.
I don't like to make single use things generic. Reusable things, those should be generic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

YAGNI

@DrJKL DrJKL requested a review from christian-byrne January 9, 2026 22:28

const PROCESSED_TASK_CLEANUP_MS = 60000
const MAX_COMPLETED_DOWNLOADS = 10
const STALE_THRESHOLD_MS = 30_000
Copy link
Contributor

Choose a reason for hiding this comment

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

we can maybe make this a little shorter? but probably okay. this is a fallback

Copy link
Contributor Author

Choose a reason for hiding this comment

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

30 seconds does feel like an eternity sometimes. 10 seconds seem better?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@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: 1

🤖 Fix all issues with AI agents
In @src/stores/assetDownloadStore.ts:
- Around line 123-125: The empty catch in src/stores/assetDownloadStore.ts
should capture the error and log it instead of silently swallowing it; change
the block to catch (err) and call the module's logger (or console.error if no
logger exists) with a descriptive message including context (e.g.,
"pollDownloadTask failed" or the method name) and the error object so
network/malformed-response issues are visible; optionally distinguish expected
"task not ready/not found" cases from unexpected errors before deciding whether
to swallow or rethrow.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 464e66c and 72c9196.

📒 Files selected for processing (1)
  • src/stores/assetDownloadStore.ts
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Leverage VueUse functions for performance-enhancing utilities

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements; do not mix inline type imports in the same statement
Sort and group imports by plugin; run pnpm format before committing
Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Code should be well-designed with clear names for everything; write code that is expressive and self-documenting
Avoid redundant comments and clean up code as you go; comments should explain why, not what
Ask if there is a simpler way to implement functionality; refactor complex code to simplify it
Minimize nesting depth (e.g., if () { ... } or for () { ... }); watch for arrow anti-pattern
Watch out for code smells and refactor to avoid them
Never use any type; use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Indent with 2 spaces; use single quotes; no trailing semicolons; max line width 80 (per .prettierrc)
Complex type definitions used in multiple related places should be extracted and named for reuse
Implement proper error handling

Files:

  • src/stores/assetDownloadStore.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/stores/assetDownloadStore.ts
src/stores/**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia store files with the *Store.ts suffix

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional; use function declarations instead of function expressions when possible
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/stores/assetDownloadStore.ts
🧠 Learnings (10)
📚 Learning: 2026-01-08T21:43:58.213Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7897
File: src/stores/assetDownloadStore.ts:117-117
Timestamp: 2026-01-08T21:43:58.213Z
Learning: In src/stores/assetDownloadStore.ts, the api.addEventListener('asset_download', handleAssetDownload) call at module level is intentional and should persist for the application lifetime since it's a singleton Pinia store managing global WebSocket events.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:20:56.167Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:56.167Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Implement proper error handling

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Implement proper error handling

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:17:12.355Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:12.355Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/stores/assetDownloadStore.ts
🧬 Code graph analysis (1)
src/stores/assetDownloadStore.ts (1)
src/platform/tasks/services/taskService.ts (1)
  • taskService (70-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test
  • GitHub Check: setup
  • GitHub Check: lint-and-format
  • GitHub Check: collect
🔇 Additional comments (7)
src/stores/assetDownloadStore.ts (7)

1-7: LGTM!

Imports are properly organized with import type separated as required. Good use of VueUse's useIntervalFn for the polling mechanism.


18-18: LGTM!

The lastUpdate timestamp addition enables staleness detection for the polling fallback.


28-29: LGTM!

Constants are appropriately defined using numeric separators for readability.


54-91: LGTM!

Good improvements to handleAssetDownload:

  • Terminal state guard prevents re-processing of completed/failed downloads
  • lastUpdate timestamp enables staleness tracking
  • Completed downloads array properly capped at MAX_COMPLETED_DOWNLOADS

131-140: LGTM!

Clean polling lifecycle management using VueUse's useIntervalFn with reactive start/stop based on active downloads. The immediate: false ensures polling only starts when needed. Based on learnings, the singleton store pattern means cleanup isn't required.


150-159: LGTM!

Good encapsulation: polling mechanism kept internal while maintaining a clean, minimal public API.


103-121: No action needed—all accessed properties are properly defined in the TaskResponse type.

The TaskResponse type includes status, result, and error_message as verified in the taskService definition. All properties accessed in the code snippet (asset_id, filename, bytes_downloaded, error) are correctly defined in the zDownloadFileResult schema. Optional chaining is appropriately used for the optional result object.

Copy link
Contributor

@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: 2

🤖 Fix all issues with AI agents
In @src/stores/assetDownloadStore.ts:
- Around line 123-125: In assetDownloadStore.ts replace the empty catch block
that currently swallows errors (the catch following the try that comments "Task
not ready or not found") with a catch (err) { ... } that logs the error at debug
level (e.g., using your store/logger instance or console.debug) including a
short contextual message and the error object, then continue (do not rethrow) so
polling proceeds but real failures are visible for troubleshooting.
- Around line 113-115: The code assigns bytes_total and bytes_downloaded from
the same value; change the assignments so bytes_total uses result?.bytes_total
?? download.bytesTotal and bytes_downloaded uses result?.bytes_downloaded ??
download.bytesDownloaded (update the field names to the correct result/download
properties) so total and downloaded are sourced from their respective fields
instead of both using the downloaded/bytesTotal value.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72c9196 and 06b3ebb.

📒 Files selected for processing (2)
  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Leverage VueUse functions for performance-enhancing utilities

Files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements; do not mix inline type imports in the same statement
Sort and group imports by plugin; run pnpm format before committing
Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Code should be well-designed with clear names for everything; write code that is expressive and self-documenting
Avoid redundant comments and clean up code as you go; comments should explain why, not what
Ask if there is a simpler way to implement functionality; refactor complex code to simplify it
Minimize nesting depth (e.g., if () { ... } or for () { ... }); watch for arrow anti-pattern
Watch out for code smells and refactor to avoid them
Never use any type; use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Indent with 2 spaces; use single quotes; no trailing semicolons; max line width 80 (per .prettierrc)
Complex type definitions used in multiple related places should be extracted and named for reuse
Implement proper error handling

Files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional; use function declarations instead of function expressions when possible
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/assetDownloadStore.ts
src/stores/**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia store files with the *Store.ts suffix

Files:

  • src/stores/assetDownloadStore.ts
🧠 Learnings (20)
📚 Learning: 2026-01-06T19:20:56.167Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:56.167Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.

Applied to files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/schemas/apiSchema.ts
  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-08T21:43:58.213Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7897
File: src/stores/assetDownloadStore.ts:117-117
Timestamp: 2026-01-08T21:43:58.213Z
Learning: In src/stores/assetDownloadStore.ts, the api.addEventListener('asset_download', handleAssetDownload) call at module level is intentional and should persist for the application lifetime since it's a singleton Pinia store managing global WebSocket events.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Implement proper error handling

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Implement proper error handling

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-22T21:36:46.909Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts:189-194
Timestamp: 2025-12-22T21:36:46.909Z
Learning: In the Comfy-Org/ComfyUI_frontend repository test files: Do not stub primitive UI components or customized primitive components (e.g., Button). Instead, import and register the real components in test setup. This ensures tests accurately reflect production behavior and component API usage.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T03:50:03.127Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:50:03.127Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, when avoiding PrimeVue components, prefer using the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) rather than plain HTML buttons. These components wrap PrimeVue with custom design system styling.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-16T22:22:06.840Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: pnpm-workspace.yaml:50-50
Timestamp: 2025-12-16T22:22:06.840Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, the project uses cva1.0.0-beta.4 (beta version) by deliberate choice. Do not suggest replacing it with class-variance-authority or flagging it as a beta dependency concern.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In the Comfy-Org/ComfyUI_frontend repository test files: When testing components, import the real type definitions from the component files instead of duplicating interface definitions in the test files. This prevents type drift and maintains consistency.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-05T06:11:09.383Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7177
File: src/platform/assets/components/UploadModelFooter.vue:72-78
Timestamp: 2025-12-05T06:11:09.383Z
Learning: For the ComfyUI_frontend repository, avoid suggesting comments that would be redundant when the code is already self-explanatory through descriptive naming (e.g., filenames, prop names, aria-labels). The project prefers clean code without unnecessary documentation comments.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-22T21:36:16.031Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:16.031Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, avoid creating single-use variants for the Button component (and other UI components). Variants should be reusable across multiple use cases. It's acceptable to use a mix of variant props and manual Tailwind classes temporarily when a specific styling need exists in only one place, with consolidation deferred to a later phase when patterns emerge.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T21:40:19.792Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:19.792Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, inline Tailwind CSS class strings, even when long, are acceptable and preferred over extracting them to computed properties when the classes are static. This is a common Tailwind pattern and doesn't need to be flagged as a readability issue.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-10T03:09:19.636Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:19.636Z
Learning: For test files in the Comfy-Org/ComfyUI_frontend repository: When writing tests, prefer selecting elements by accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests verify actual user-facing behavior and accessibility compliance.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Implement proper error handling in stores

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:17:12.355Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:12.355Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.

Applied to files:

  • src/stores/assetDownloadStore.ts
🧬 Code graph analysis (1)
src/stores/assetDownloadStore.ts (1)
src/platform/tasks/services/taskService.ts (1)
  • taskService (70-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: deploy-and-comment
  • GitHub Check: setup
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (7)
src/schemas/apiSchema.ts (1)

138-147: LGTM - Schema change aligns with store interface.

The asset_id field is now optional, which correctly matches the assetId?: string field in the AssetDownload interface. This supports the polling fallback mechanism where the asset_id may not be present in all WebSocket messages.

src/stores/assetDownloadStore.ts (6)

28-29: Verify intended threshold and interval values.

The PR description states a 30-second stale threshold and 15-second polling interval, but the code uses 10 seconds for both. Please confirm which values are intended.


54-61: LGTM - Terminal state guard prevents redundant processing.

The early return for downloads already in terminal state (completed/failed) correctly prevents duplicate event processing, which is especially important when the polling fallback synthesizes events for stale downloads.


63-75: LGTM - Download tracking with lastUpdate timestamp.

The lastUpdate field is correctly set on every WebSocket event, enabling the staleness detection in the polling mechanism.


77-91: LGTM - Completed downloads tracking with bounded history.

The immutable array pattern ensures proper Vue reactivity, and the shift() call correctly maintains a bounded history of the most recent completed downloads.


131-142: LGTM - Polling lifecycle management.

Good use of VueUse's useIntervalFn with immediate: false to defer polling until needed. The watch correctly starts/stops polling based on active downloads, avoiding unnecessary polling when idle. Based on learnings, the module-level addEventListener is intentional for this singleton store.


150-159: LGTM - Clean public interface.

The store correctly exposes only the necessary reactive state and actions, keeping internal implementation details (handleAssetDownload, pollStaleDownloads) private.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@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: 3

🤖 Fix all issues with AI agents
In @src/stores/assetDownloadStore.ts:
- Around line 137-140: The watcher on hasActiveDownloads currently only responds
to changes and will miss handling downloads already active at initialization;
modify the watch call for hasActiveDownloads to pass the options object with
immediate: true so the callback runs once immediately and invokes resume() or
pause() based on the current value, ensuring existing active downloads are
polled on startup (target the watch(hasActiveDownloads, ...) invocation and
adjust its call signature to include { immediate: true }).
- Around line 28-29: The constants STALE_THRESHOLD_MS and POLL_INTERVAL_MS are
set to 10_000 but the PR summary specifies a 30s stale threshold and 15s poll
interval; update STALE_THRESHOLD_MS to 30_000 and POLL_INTERVAL_MS to 15_000
(replace the numeric values where those constants are declared) so the code
matches the documented behavior.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 06b3ebb and 1061f78.

📒 Files selected for processing (1)
  • src/stores/assetDownloadStore.ts
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Leverage VueUse functions for performance-enhancing utilities

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements; do not mix inline type imports in the same statement
Sort and group imports by plugin; run pnpm format before committing
Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Code should be well-designed with clear names for everything; write code that is expressive and self-documenting
Avoid redundant comments and clean up code as you go; comments should explain why, not what
Ask if there is a simpler way to implement functionality; refactor complex code to simplify it
Minimize nesting depth (e.g., if () { ... } or for () { ... }); watch for arrow anti-pattern
Watch out for code smells and refactor to avoid them
Never use any type; use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Indent with 2 spaces; use single quotes; no trailing semicolons; max line width 80 (per .prettierrc)
Complex type definitions used in multiple related places should be extracted and named for reuse
Implement proper error handling

Files:

  • src/stores/assetDownloadStore.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/stores/assetDownloadStore.ts
src/stores/**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia store files with the *Store.ts suffix

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional; use function declarations instead of function expressions when possible
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/stores/assetDownloadStore.ts
🧠 Learnings (19)
📚 Learning: 2026-01-08T21:43:58.213Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7897
File: src/stores/assetDownloadStore.ts:117-117
Timestamp: 2026-01-08T21:43:58.213Z
Learning: In src/stores/assetDownloadStore.ts, the api.addEventListener('asset_download', handleAssetDownload) call at module level is intentional and should persist for the application lifetime since it's a singleton Pinia store managing global WebSocket events.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:20:56.167Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:56.167Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Implement proper error handling

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Implement proper error handling

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-22T21:36:46.909Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts:189-194
Timestamp: 2025-12-22T21:36:46.909Z
Learning: In the Comfy-Org/ComfyUI_frontend repository test files: Do not stub primitive UI components or customized primitive components (e.g., Button). Instead, import and register the real components in test setup. This ensures tests accurately reflect production behavior and component API usage.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T03:50:03.127Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:50:03.127Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, when avoiding PrimeVue components, prefer using the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) rather than plain HTML buttons. These components wrap PrimeVue with custom design system styling.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-16T22:22:06.840Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: pnpm-workspace.yaml:50-50
Timestamp: 2025-12-16T22:22:06.840Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, the project uses cva1.0.0-beta.4 (beta version) by deliberate choice. Do not suggest replacing it with class-variance-authority or flagging it as a beta dependency concern.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In the Comfy-Org/ComfyUI_frontend repository test files: When testing components, import the real type definitions from the component files instead of duplicating interface definitions in the test files. This prevents type drift and maintains consistency.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-05T06:11:09.383Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7177
File: src/platform/assets/components/UploadModelFooter.vue:72-78
Timestamp: 2025-12-05T06:11:09.383Z
Learning: For the ComfyUI_frontend repository, avoid suggesting comments that would be redundant when the code is already self-explanatory through descriptive naming (e.g., filenames, prop names, aria-labels). The project prefers clean code without unnecessary documentation comments.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-22T21:36:16.031Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:16.031Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, avoid creating single-use variants for the Button component (and other UI components). Variants should be reusable across multiple use cases. It's acceptable to use a mix of variant props and manual Tailwind classes temporarily when a specific styling need exists in only one place, with consolidation deferred to a later phase when patterns emerge.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T21:40:19.792Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:19.792Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, inline Tailwind CSS class strings, even when long, are acceptable and preferred over extracting them to computed properties when the classes are static. This is a common Tailwind pattern and doesn't need to be flagged as a readability issue.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-10T03:09:19.636Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:19.636Z
Learning: For test files in the Comfy-Org/ComfyUI_frontend repository: When writing tests, prefer selecting elements by accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests verify actual user-facing behavior and accessibility compliance.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:17:12.355Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:12.355Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/stores/assetDownloadStore.ts
🧬 Code graph analysis (1)
src/stores/assetDownloadStore.ts (1)
src/platform/tasks/services/taskService.ts (1)
  • taskService (70-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test
  • GitHub Check: lint-and-format
  • GitHub Check: setup
  • GitHub Check: collect
🔇 Additional comments (2)
src/stores/assetDownloadStore.ts (2)

56-61: LGTM! Prevents duplicate processing.

The terminal state guard correctly prevents reprocessing downloads that have already reached a completed or failed state, which is essential for the polling reconciliation mechanism.


72-72: LGTM! Clean timestamp tracking and sliding window cleanup.

The lastUpdate timestamp enables stale download detection, and the refactored sliding window approach for completedDownloads is cleaner than the previous bookkeeping mechanism.

Also applies to: 80-86

@DrJKL DrJKL assigned AustinMroz and unassigned christian-byrne Jan 10, 2026
Copy link
Contributor

@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: 1

🤖 Fix all issues with AI agents
In @src/stores/assetDownloadStore.ts:
- Around line 80-85: Replace the mutation-with-shift pattern on
completedDownloads.value with a pure slice-based truncation: after building the
new array (currently assigned to updated), set completedDownloads.value to the
last MAX_COMPLETED_DOWNLOADS items by using Array.prototype.slice with a
negative start index so no in-place mutation (shift) happens; keep the same
object shape ({ taskId: data.task_id, modelType, timestamp: Date.now() }) and
the same symbols (completedDownloads.value, MAX_COMPLETED_DOWNLOADS, updated) to
locate and apply the change.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1061f78 and e3bb74b.

📒 Files selected for processing (1)
  • src/stores/assetDownloadStore.ts
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Leverage VueUse functions for performance-enhancing utilities

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements; do not mix inline type imports in the same statement
Sort and group imports by plugin; run pnpm format before committing
Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Code should be well-designed with clear names for everything; write code that is expressive and self-documenting
Avoid redundant comments and clean up code as you go; comments should explain why, not what
Ask if there is a simpler way to implement functionality; refactor complex code to simplify it
Minimize nesting depth (e.g., if () { ... } or for () { ... }); watch for arrow anti-pattern
Watch out for code smells and refactor to avoid them
Never use any type; use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Indent with 2 spaces; use single quotes; no trailing semicolons; max line width 80 (per .prettierrc)
Complex type definitions used in multiple related places should be extracted and named for reuse
Implement proper error handling

Files:

  • src/stores/assetDownloadStore.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/stores/assetDownloadStore.ts
src/stores/**/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia store files with the *Store.ts suffix

Files:

  • src/stores/assetDownloadStore.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional; use function declarations instead of function expressions when possible
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/stores/assetDownloadStore.ts
🧠 Learnings (22)
📓 Common learnings
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7926
File: src/stores/assetDownloadStore.ts:101-126
Timestamp: 2026-01-09T23:59:04.777Z
Learning: In src/stores/assetDownloadStore.ts, the empty catch block in pollSingleDownload within pollStaleDownloads is intentional. Do not suggest adding error logging or handling for polling failures in this function.
📚 Learning: 2026-01-09T23:59:04.777Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7926
File: src/stores/assetDownloadStore.ts:101-126
Timestamp: 2026-01-09T23:59:04.777Z
Learning: In src/stores/assetDownloadStore.ts, the empty catch block in pollSingleDownload within pollStaleDownloads is intentional. Do not suggest adding error logging or error handling for polling failures in this function; treat it as a deliberate swallow of errors to avoid affecting poll logic or user-visible behavior. Reviewers should refrain from proposing fixes to this catch block for this function.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-08T21:43:58.213Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7897
File: src/stores/assetDownloadStore.ts:117-117
Timestamp: 2026-01-08T21:43:58.213Z
Learning: In src/stores/assetDownloadStore.ts, the api.addEventListener('asset_download', handleAssetDownload) call at module level is intentional and should persist for the application lifetime since it's a singleton Pinia store managing global WebSocket events.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:20:56.167Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/services/assetService.ts:484-491
Timestamp: 2026-01-06T19:20:56.167Z
Learning: In `src/platform/assets/services/assetService.ts`, prefer using `schema.safeParse()` over `schema.parse()` for validating API responses to avoid throwing ZodError with internal schema details; follow the existing pattern: call `safeParse()`, check `result.success`, and use `fromZodError(result.error)` to format error messages for logging while throwing user-friendly errors.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Implement proper error handling

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Implement proper error handling

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-22T21:36:46.909Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts:189-194
Timestamp: 2025-12-22T21:36:46.909Z
Learning: In the Comfy-Org/ComfyUI_frontend repository test files: Do not stub primitive UI components or customized primitive components (e.g., Button). Instead, import and register the real components in test setup. This ensures tests accurately reflect production behavior and component API usage.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T03:50:03.127Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:50:03.127Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, when avoiding PrimeVue components, prefer using the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) rather than plain HTML buttons. These components wrap PrimeVue with custom design system styling.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-16T22:22:06.840Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: pnpm-workspace.yaml:50-50
Timestamp: 2025-12-16T22:22:06.840Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, the project uses cva1.0.0-beta.4 (beta version) by deliberate choice. Do not suggest replacing it with class-variance-authority or flagging it as a beta dependency concern.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-08T02:40:15.482Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7894
File: src/renderer/extensions/vueNodes/widgets/components/WidgetToggleSwitch.test.ts:11-14
Timestamp: 2026-01-08T02:40:15.482Z
Learning: In the Comfy-Org/ComfyUI_frontend repository test files: When testing components, import the real type definitions from the component files instead of duplicating interface definitions in the test files. This prevents type drift and maintains consistency.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-05T06:11:09.383Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7177
File: src/platform/assets/components/UploadModelFooter.vue:72-78
Timestamp: 2025-12-05T06:11:09.383Z
Learning: For the ComfyUI_frontend repository, avoid suggesting comments that would be redundant when the code is already self-explanatory through descriptive naming (e.g., filenames, prop names, aria-labels). The project prefers clean code without unnecessary documentation comments.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-22T21:36:16.031Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:16.031Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, avoid creating single-use variants for the Button component (and other UI components). Variants should be reusable across multiple use cases. It's acceptable to use a mix of variant props and manual Tailwind classes temporarily when a specific styling need exists in only one place, with consolidation deferred to a later phase when patterns emerge.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T21:40:19.792Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:19.792Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, inline Tailwind CSS class strings, even when long, are acceptable and preferred over extracting them to computed properties when the classes are static. This is a common Tailwind pattern and doesn't need to be flagged as a readability issue.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-10T03:09:19.636Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:19.636Z
Learning: For test files in the Comfy-Org/ComfyUI_frontend repository: When writing tests, prefer selecting elements by accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests verify actual user-facing behavior and accessibility compliance.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Implement proper error handling in stores

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2026-01-06T19:17:12.355Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7746
File: src/platform/assets/composables/useUploadModelWizard.ts:207-219
Timestamp: 2026-01-06T19:17:12.355Z
Learning: In `src/platform/assets/composables/useUploadModelWizard.ts`, the `uploadModel()` function should have a concurrency guard at the beginning that checks if `isUploading.value` is already true and returns false early to prevent race conditions from multiple rapid invocations.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/stores/assetDownloadStore.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/stores/assetDownloadStore.ts
🧬 Code graph analysis (1)
src/stores/assetDownloadStore.ts (1)
src/platform/tasks/services/taskService.ts (1)
  • taskService (70-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: setup
  • GitHub Check: lint-and-format
  • GitHub Check: collect
  • GitHub Check: test
🔇 Additional comments (7)
src/stores/assetDownloadStore.ts (7)

1-7: LGTM!

Imports correctly leverage VueUse for the polling utility and follow the guideline of using separate import type statements.


9-19: LGTM!

Interface changes correctly add lastUpdate for staleness tracking and make assetId optional to align with the updated schema.


28-29: LGTM!

Constants are well-named and use numeric separators for readability. The 10-second thresholds align with the PR objectives.


58-61: LGTM!

The terminal state guard is essential for preventing duplicate processing when both WebSocket messages and polling may report the same completion. Good defensive programming.


93-129: LGTM!

The polling logic correctly identifies stale downloads, queries the task service, and synthesizes completion events. The reuse of handleAssetDownload ensures consistent state transitions, and the terminal state guard in that function makes concurrent polling safe.


131-144: LGTM!

The combination of useIntervalFn with immediate: false and watch with immediate: true correctly ensures polling starts immediately when there are already-active downloads on initialization, and properly pauses when no active downloads remain. Good use of VueUse per guidelines.


146-163: LGTM!

The event listener registration at module level is appropriate for a singleton Pinia store (per learnings), and the public interface is minimal, keeping the polling implementation internal.

Comment on lines +80 to 85
const updated = [
...completedDownloads.value,
{ taskId: data.task_id, modelType, timestamp: Date.now() }
]
if (updated.length > MAX_COMPLETED_DOWNLOADS) updated.shift()
completedDownloads.value = updated
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider a more functional approach for array truncation.

The current pattern creates a new array then mutates it with shift(). Per guidelines preferring immutability, a slice-based approach is cleaner.

♻️ Suggested refactor
-        const updated = [
-          ...completedDownloads.value,
-          { taskId: data.task_id, modelType, timestamp: Date.now() }
-        ]
-        if (updated.length > MAX_COMPLETED_DOWNLOADS) updated.shift()
-        completedDownloads.value = updated
+        const newEntry = { taskId: data.task_id, modelType, timestamp: Date.now() }
+        const all = [...completedDownloads.value, newEntry]
+        completedDownloads.value = all.slice(-MAX_COMPLETED_DOWNLOADS)
🤖 Prompt for AI Agents
In @src/stores/assetDownloadStore.ts around lines 80 - 85, Replace the
mutation-with-shift pattern on completedDownloads.value with a pure slice-based
truncation: after building the new array (currently assigned to updated), set
completedDownloads.value to the last MAX_COMPLETED_DOWNLOADS items by using
Array.prototype.slice with a negative start index so no in-place mutation
(shift) happens; keep the same object shape ({ taskId: data.task_id, modelType,
timestamp: Date.now() }) and the same symbols (completedDownloads.value,
MAX_COMPLETED_DOWNLOADS, updated) to locate and apply the change.

@DrJKL DrJKL merged commit 41ffb7c into main Jan 10, 2026
32 checks passed
@DrJKL DrJKL deleted the feat/stale-download-polling branch January 10, 2026 00:23
@luke-mino-altherr luke-mino-altherr added needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch cloud/1.36 Backport PRs for cloud 1.36 labels Jan 10, 2026
@github-actions
Copy link

⚠️ Backport to cloud/1.36 failed

Reason: Merge conflicts detected during cherry-pick of 41ffb7c

📄 Conflicting files
tests-ui/vitest-patterns.md
🤖 Prompt for AI Agents
Backport PR #7926 (https://github.com/Comfy-Org/ComfyUI_frontend/pull/7926) to cloud/1.36.
Cherry-pick merge commit 41ffb7c627630fa402011a8ba7b3379442a6c67a onto new branch
backport-7926-to-cloud-1.36 from origin/cloud/1.36.
Resolve conflicts in: tests-ui/vitest-patterns.md .
For test snapshots (browser_tests/**/*-snapshots/), accept PR version if
changed in original PR, else keep target. For package.json versions, keep
target branch. For pnpm-lock.yaml, regenerate with pnpm install.
Ask user for non-obvious conflicts.
Create PR titled "[backport cloud/1.36] <original title>" with label "backport".
See .github/workflows/pr-backport.yaml for workflow details.

cc @DrJKL

DrJKL added a commit that referenced this pull request Jan 13, 2026
Adds a polling fallback mechanism to recover from dropped WebSocket
messages during model downloads.

When downloading models via the asset download service, status updates
are received over WebSocket. Sometimes these messages are dropped
(network issues, reconnection, etc.), causing downloads to appear
"stuck" even when they've completed on the backend.

Periodically poll for stale downloads using the existing REST API:

- Track `lastUpdate` timestamp on each download
- Downloads without updates for 10s are considered "stale"
- Poll stale downloads every 10s via `GET /tasks/{task_id}` to check if
the asset exists
- If the asset exists with size > 0, mark the download as completed

- Added `lastUpdate` field to `AssetDownload` interface
- Use VueUse's `useIntervalFn` with a `watch` to auto start/stop polling
based on active downloads
- Reuse existing `handleAssetDownload` for completion (synthetic event)
- Added 9 unit tests covering the polling behavior

- All existing tests pass
- New tests cover:
  - Basic download tracking
  - Completion/failure handling
  - Duplicate message prevention
  - Stale download polling
  - Polling error handling

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7926-feat-add-polling-fallback-for-stale-asset-downloads-2e36d73d3650810ea966f5480f08b60c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
DrJKL added a commit that referenced this pull request Jan 13, 2026
Adds a polling fallback mechanism to recover from dropped WebSocket
messages during model downloads.

When downloading models via the asset download service, status updates
are received over WebSocket. Sometimes these messages are dropped
(network issues, reconnection, etc.), causing downloads to appear
"stuck" even when they've completed on the backend.

Periodically poll for stale downloads using the existing REST API:

- Track `lastUpdate` timestamp on each download
- Downloads without updates for 10s are considered "stale"
- Poll stale downloads every 10s via `GET /tasks/{task_id}` to check if
the asset exists
- If the asset exists with size > 0, mark the download as completed

- Added `lastUpdate` field to `AssetDownload` interface
- Use VueUse's `useIntervalFn` with a `watch` to auto start/stop polling
based on active downloads
- Reuse existing `handleAssetDownload` for completion (synthetic event)
- Added 9 unit tests covering the polling behavior

- All existing tests pass
- New tests cover:
  - Basic download tracking
  - Completion/failure handling
  - Duplicate message prevention
  - Stale download polling
  - Polling error handling

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7926-feat-add-polling-fallback-for-stale-asset-downloads-2e36d73d3650810ea966f5480f08b60c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
DrJKL added a commit that referenced this pull request Jan 13, 2026
…loads (#7981)

Backport of #7926 to cloud/1.36

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7981-backport-cloud-1-36-feat-add-polling-fallback-for-stale-asset-downloads-2e76d73d365081a983a4e5a8683ae2c9)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cloud/1.36 Backport PRs for cloud 1.36 High-Priority needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants