mihailik commited on
Commit
99fd943
Β·
1 Parent(s): f62c223

UI integration plan.

Browse files
plans/2025-08-01-model-filtering/5-ui-worker-model-integration.md ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Worker Model Listing β€” UI Integration Plan
2
+
3
+ Purpose: document a complete, actionable plan to replace UI-side HF model fetching and caching with the worker-based `listChatModels` flow, remove UI caching, and defer slash-command creation until the worker returns the final model list.
4
+
5
+ Requirements checklist
6
+ - Use the `listChatModels` action name everywhere (do not introduce `loadChatModels`).
7
+ - Remove UI-side HF network logic and localStorage caching.
8
+ - Defer Crepe/Milkdown BlockEdit population until the worker returns the final models list.
9
+ - Keep the implementation simple, minimal, and easy to iterate on.
10
+ - Expose cancellation for the listing operation.
11
+ - Provide a small hard-coded fallback list if the worker fails.
12
+ - Make changes recoverable (do not permanently obliterate legacy code without a backup or relying on git).
13
+
14
+ ## One-line summary
15
+ Replace `fetchBrowserModels()` in the UI with a thin worker-backed proxy that calls `listChatModels`, expose a cancellable wrapper in `src/app/worker-connection.js`, and update `src/app/init-milkdown.js` to wait for the final list before adding the BlockEdit `models` group.
16
+
17
+ ## Deliverables (files to change)
18
+ - Edit: `src/app/worker-connection.js` β€” add a small wrapper that returns `{ id, promise, cancel }` for `listChatModels` requests.
19
+ - Edit: `src/app/model-list.js` β€” replace the heavy `fetchBrowserModels()` implementation with a worker-proxy (no caching/localStorage).
20
+ - Edit: `src/app/init-milkdown.js` β€” defer BlockEdit creation until the worker returns the final list; show a simple placeholder while waiting.
21
+ - Add (optional): `src/app/_legacy/fetchBrowserModels.removed.js` β€” move old implementation here for safe disposal (or rely on git history).
22
+ - Add (optional): `test/app/model-list.integration.test.js` β€” a fast smoke test that mocks `listChatModels` and verifies BlockEdit population.
23
+
24
+ ## API contract (UI-side wrapper)
25
+ - Function: `listChatModels(params = {}, onProgress?)` β€” keep this name and behavior.
26
+ - Wrapper return: `{ id, promise, cancel }` where:
27
+ - `id` (string) is the request id posted to the worker;
28
+ - `promise` resolves to the final `ModelEntry[]` (use the shape from the plan) or rejects on fatal error;
29
+ - `cancel()` posts `{ type: 'cancelListChatModels', id }` and cleans up local pending state.
30
+ - `onProgress(delta)` will be called with small delta objects emitted by the worker. Keep deltas as-is (no heavy transformation).
31
+
32
+ Keep the `fetchBrowserModels()` export stable: it should return a Promise resolving to the model array so existing callers need no changes.
33
+
34
+ ## Implementation steps (detailed, exact)
35
+
36
+ 1) Worker client wrapper (`src/app/worker-connection.js`)
37
+
38
+ - Replace the current `listChatModels` helper with a thin wrapper that returns `{ id, promise, cancel }`:
39
+ - Generate an `id` (e.g., `String(Math.random()).slice(2)`).
40
+ - Create a pending entry in the connection's `pending` map containing `resolve`, `reject`, and `onProgress`.
41
+ - `worker.postMessage({ type: 'listChatModels', id, params })`.
42
+ - `promise` is a new Promise that resolves/rejects via the pending entry.
43
+ - `cancel()` posts `{ type: 'cancelListChatModels', id }` and removes the pending entry.
44
+
45
+ - Keep naming strictly `listChatModels` (do not introduce `loadChatModels`).
46
+
47
+ 2) UI proxy in `src/app/model-list.js`
48
+
49
+ - Replace the heavy implementation of `fetchBrowserModels()` with a worker-proxy implementation. Keep the same exported function name/signature to preserve callers.
50
+
51
+ - Minimal behavior for `fetchBrowserModels()`:
52
+ - Call `const { id, promise, cancel } = workerConnection().listChatModels(params, onProgress)`.
53
+ - Optionally handle simple timeout (e.g., `Promise.race([promise, timeout(30_000)])`). If timed out, call `cancel()` and fall back.
54
+ - Map the `ModelEntry[]` returned by the worker to the previous UI shape expected by callers (keep only the fields UI needs: `id`, `name`, `size`, `slashCommand`, `pipeline_tag`, etc.). Use concise mapping.
55
+ - No localStorage, no caching, no persisted TTL logic.
56
+ - Maintain an in-memory transient map for in-progress deltas if you want to display progress β€” but keep it small; for this iteration final result suffices.
57
+
58
+ - Provide a small hard-coded fallback array of 3–5 known models to return on worker failure.
59
+
60
+ 3) Defer BlockEdit creation (`src/app/init-milkdown.js`)
61
+
62
+ - Start Crepe without the BlockEdit `models` group (as the code already does in the repository).
63
+ - After mounting creat the Crepe editor, call `fetchBrowserModels()` (the new worker-backed function) and await the final array.
64
+ - Once the worker returns the final models list, call `crepeInput.addFeature(blockEdit, { buildMenu })` and populate the `models` group there.
65
+ - buildMenu: loop final models and call `group.addItem(model.slashCommand, { label, icon, onRun })`.
66
+ - While waiting, show a simple spinner or placeholder. Keep the UX minimal: BlockEdit appears only after the final list resolves.
67
+
68
+ 4) Remove caching + cleanup
69
+
70
+ - Remove any `localStorage` persistence logic and in-memory long-lived caches from `src/app/model-list.js`.
71
+ - Do not delete the legacy implementation irreversibly in the first pass. Move the old code into `src/app/_legacy/fetchBrowserModels.removed.js` or rely on git to recover it. Add a short header comment in `src/app/model-list.js` explaining the replacement.
72
+
73
+ 5) Add fallback & feature flag
74
+
75
+ - Add a small `FALLBACK_MODELS` constant inside `src/app/model-list.js` or a small `fallback-models.js` file. Return this when the worker fails.
76
+ - Add `const FEATURE_LIST_CHAT_MODELS_WORKER = true` (or read from an ENV/config object) near top of `init-milkdown.js` so you can toggle behavior quickly.
77
+
78
+ 6) Tests & smoke
79
+
80
+ - Integration test: `test/app/model-list.integration.test.js` β€” mock `workerConnection().listChatModels` to return a resolved promise; assert that `init-milkdown()` ends up adding BlockEdit items.
81
+ - Unit test: small test for `worker-connection` wrapper to assert returned `{ id, promise, cancel }` shape and that cancel posts a cancel message (stub worker).
82
+
83
+ ## Mapping worker ModelEntry -> UI model shape
84
+
85
+ Worker returns ModelEntry with these fields (plan):
86
+
87
+ ```
88
+ {
89
+ id,
90
+ name?,
91
+ pipeline_tag?,
92
+ siblings?,
93
+ tags?,
94
+ model_type?,
95
+ architectures?,
96
+ classification: 'gen'|'encoder'|'unknown'|'auth-protected',
97
+ confidence: 'high'|'medium'|'low',
98
+ fetchStatus: 'ok'|'404'|'401'|'403'|'429'|'error',
99
+ fetchError?
100
+ }
101
+ ```
102
+
103
+ Map into the minimal UI `ModelInfo` shape used by `init-milkdown` (example):
104
+
105
+ - `id`: same
106
+ - `name`: entry.name || humanized(id)
107
+ - `vendor`: extract from id (reuse `extractVendor` helper)
108
+ - `size`: keep conservative default or empty
109
+ - `slashCommand`: keep `generateSlashCommand(id)` helper usage
110
+ - `pipeline_tag`: pass through
111
+ - `requiresAuth`: classification === 'auth-protected'
112
+
113
+ Keep the mapping concise with a single `map()` call.
114
+
115
+ ## Edge cases & caveats
116
+
117
+ - Cold start (no caching): expect slower initial load; mitigate by returning `FALLBACK_MODELS` on error.
118
+ - Many progress events: the worker may stream many small deltas; for the first iteration, only use the final `done` response to build BlockEdit. Optionally show a spinner while progress is in-flight.
119
+ - Rate limiting and auth-protected repos: worker classifies these; UI should honor `classification` and `confidence` but can ignore nuance for this initial pass.
120
+ - Cancellation: callers must keep the `id` or `cancel` handle and call it when unmounting.
121
+ - API name strictness: keep `listChatModels` everywhere; do not create `loadChatModels`.
122
+
123
+ ## Rollout and rollback
124
+
125
+ - Implement in a feature branch and commit in small steps: 1) worker wrapper, 2) `fetchBrowserModels` replacement, 3) `init-milkdown` change, 4) tests + fallback.
126
+ - Test locally: open the editor, confirm the BlockEdit `models` group appears after the worker finishes and slash commands work.
127
+ - If anything breaks, toggle `FEATURE_LIST_CHAT_MODELS_WORKER` to `false` or revert via git.
128
+
129
+ ## Time estimates
130
+ - `worker-connection` wrapper: 15–30 minutes
131
+ - `model-list` replacement: 30–60 minutes
132
+ - `init-milkdown` deferment: 30–60 minutes
133
+ - Tests & verification: 30–90 minutes
134
+ Total: ~1.5–3.5 hours.
135
+
136
+ ## Minimal code style guidance (brevity & elegance)
137
+ - Use concise arrow functions and destructuring.
138
+ - Favor `map()`/`filter()` over manual loops.
139
+ - Keep try/catch blocks narrowly scoped.
140
+ - One-liner helpers for timeouts and small utilities: `const wait = ms => new Promise(r => setTimeout(r, ms));`
141
+ - Keep file-level exports small and stable; prefer preserving function names to avoid cascade edits.
142
+
143
+ ## Next step (recommended)
144
+ - Implement the `listChatModels` wrapper in `src/app/worker-connection.js` and replace `fetchBrowserModels()` body in `src/app/model-list.js` with the worker-backed proxy. Then update `src/app/init-milkdown.js` to await the final list before adding BlockEdit. Add `FALLBACK_MODELS` for safety.
145
+
146
+ ---
147
+
148
+ This document is intentionally prescriptive and conservative: small, reversible edits; stable export names; and minimal UI changes for the first iteration. Once this is merged and verified, we can iterate to add caching, incremental UI updates, and telemetry.