parrot on Dear ImGui: a shared module's function addresses in the standalone exe, parked browser workers, cached model sets - #3995
Conversation
…n the author's own notes, and the folder's checklist names the module ledger as its planned-work home Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…Pocket clone, now with panels that show what the engine does while it does it. The status chip and line across the top say ready, recording with the seconds, cloning, generating, speaking or read out; the voice panel is the record disc with the silence countdown drawn around it, the level, a gain slider that scales the frames before the detector and the clone (the physical input gain is the browser's), the take's waveform with its kept window shaded, and a picker of the clone plus the file's nineteen voices; the text panel is an editor, say, and the say's chunks in the colour of their state - pending, generating, generated, speaking, spoken - so the phrase being read is the one lit; the output is the say's waveform growing chunk by chunk with a tick at each chunk's start and a playhead on the mixer's own clock, and a table of each chunk's prompt, backbone, head and codec time; the lab panel is the model's facts, the job queue's knobs (a jobs slider up to the engine's cap, team dispatch, the workers' spin) reaching the queue the speech thread dispatches on, and a measure button that says the text three times without playing it and reports each run's real-time factor. The speech thread announces each chunk's text before it synthesizes it and returns the clip with its stage times; each clip gets its own status box, since a box shared across clips reads the last clip's stop as the next one's and cut the say short (a rule in the folder's checklist now). take.das keeps the resampler, the take rules and the clip window and gains the countdown, the ten-millisecond waveform columns grown per drain, and the chunk ledger; the text-box helpers go with the text layer. dasGlfw's browser glue measures the canvas's parent box instead of the document viewport (the document when the parent is the body or in fullscreen), so a page whose stage sits under a nav gets a window the size of the stage instead of a viewport-sized picture squeezed into it. test_parrot holds the countdown, the columns (fed in drains of every size, the open column redone) and the ledger model-free, and the smoke rail reads the same witness lines; the desktop run and the browser page (the wasm64 release, dasImgui's archives built on demand) both read the poem in a cloned voice. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…instead of cores minus one: a browser build caps the pool at four, and the slider narrows dispatch below the pool, never above it Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ight and a size up; the state chip pulses with a spinner beside it while anything is going on; the output waveform keeps a fixed time scale so the playhead moves at one speed instead of jumping back as chunks land; say names the voice it will use; every figure prints to a tenth (speeds as times real time - seconds of audio per second of generation - the inverse of the engine's real-time factor); and the wasm job pool cap rises from four workers to eight (platform.h, emscripten only), inside the sixteen-worker pthread pool the wasm64 builds link Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rrot across the top, voice, text over output, lab) the user splits and tabs; say and stop are the play and stop icon buttons beside the voice's name; the status row reserves its own height so the separator no longer cuts the chip and the spinner; a measure names its number so a second press reads as a second run; the shell keeps the space bar's keydown for the editor (a prevented keydown swallowed the keypress); and the three browser shells put a fetched model file in the origin's Cache Storage under its sha256 and read it from there on the next visit, so a set downloads once per browser Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…hes the standalone exe: the exe emitter's startup walk over global initializers (collect_external_functions) left out every module flagged builtIn, and a promoted das module - `module X shared`, imgui_icons and most of daslib - is flagged builtIn too, so a `@@fn` in such a module's global never had its address global stored, LLVM dropped the private function, and the first invoke threw "invoke null function" (the parrot page's WebAssembly.Exception on its first frame, at the first icon button). The walk now skips only the C++ modules (builtIn and not promoted); llvm_exe_shared_addr.das holds the shape against the interpreted run (red before the change), ARCHITECTURE.md sec.12 states the walk, and the checklist bans a module walk keyed on builtIn alone. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…moved focus out of the text one types into was the second key that did nothing in the editor, after the space bar the shell now leaves to it; the panels doc says so. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…30 ms spin-before-park window was unconditional, and in Chrome the eight spinning web workers cost the caller its core - Pocket TTS on the parrot page generated at 1.1x real time with the renderer at 800% CPU, 1.4x with the workers parked at 112% (one worker reads 0.7x, so the pool pays once nothing spins; team dispatch keeps its edge). dasllama_jobque_spin_default sets the window to 0 when the RUNNING platform is emscripten - get_platform_name folds at cross-compile time to the host's name, which is why a first form of the init never fired in the browser - and a box profile's jobque_spin_us and the setter still override it. The facade exposes get/set_jobque_spin_us over the engine's underscore spellings (the four engine-side callers renamed), ARCHITECTURE_RUNTIME.md 2.18a states the mechanism and PERF_LEDGER.md carries the numbers. The parrot lab reads the spin default from the engine, and its jobs slider goes through set_dispatch_worker_limit as the engine's contract says - a raw worker limit was overridden by the hybrid pool's per-phase parking on the desktop, which is why the measure's number did not follow the slider there; the panels doc says so. The page now measures 1.4x with its defaults. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…model file against the manifest's sha256 before they cache it - a wrong body under an HTTP 200 (a proxy's error page) is refused by name and never cached, where the store would have served it on every later visit - and sweep the page's keys a new manifest no longer names, so a re-mint does not wait on the browser's quota eviction (the three pages share one store, so each sweeps only its own models path); the parrot smoke gains an instrument for the per-clip status box rule - the read-out line reports the say's speech seconds and its playback wall, and the test holds the wall to the speech, so a clip read as stopped before its end (the shape the rule bans) fails it, where the witness lines alone stayed green; the facade's spin knob gets its cells (the desktop default read before any set, the setter landing on the engine); the standalone exe's architecture moves to its own companion, ARCHITECTURE_EXE.md (the require-resolver rows beside the startup address walk, stubs left in the main doc, which sat at the line cap) and the checklist rule that binds the walk is scoped to this module's daslib; the facade knobs are taught in the performance tutorial and its page, as the facade gate demands; a stale default in the tutorial, tune_for_this_box.md and two build comments reads the browser's 0 beside the desktop's 30 ms; the ledger entry carries its provenance; and the examples' checklist reads an input rule the imgui harness can meet. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…cap: get_jobque_spin_us and set_jobque_spin_us join the operations group, so the generated page carries no uncategorized entry. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The parrot smoke tests dropped --null-audio (risking headless/CI failures) and the performance tutorial leaks a global spin-window value instead of restoring the prior/default value.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR upgrades the dasLLAMA browser “parrot” experience into an ImGui-based lab UI, fixes standalone-exe address resolution for @@fn taken in shared-module global initializers, and improves browser runtime behavior (parked workers by default, higher wasm worker cap, and cached model downloads).
Changes:
- Fix
-exestartup global-initializer walking to include promoted (shared) das modules so@@fnglobals are populated before init runs; add a dedicated regression test and architecture doc. - Change dasLLAMA browser defaults/perf: job-queue spin window defaults to 0 on emscripten, wasm worker cap increases to 8, and document the runtime/platform gating nuance.
- Rework the parrot example into a multi-panel ImGui lab; update browser shells to cache model-set files in Cache Storage keyed by URL+sha256 and sweep stale entries.
File summaries
| File | Description |
|---|---|
| utils/dasllama-server/REVIEW.md | Updates checklist to point planned work at the new follow-up doc location. |
| utils/dasllama-server/CONTROL_PAGE_PLAN.md | Removes the in-folder control page plan document. |
| tutorials/dasLLAMA/05_performance.das | Documents and demonstrates the job-queue spin window knob. |
| src/misc/job_que.cpp | Comment update reflecting the wasm job cap change. |
| skills/daspkg.md | Documents runtime vs compile-time platform name APIs for wasm gating. |
| modules/dasLLVM/tests/llvm_exe_shared_addr.das | Adds regression test for shared-module @@fn addresses in standalone exes. |
| modules/dasLLVM/tests/llvm_exe_shared_addr_lib.das | Shared-module fixture exercising global initializer function-address capture. |
| modules/dasLLVM/tests/_exe_shared_addr_root.das | Minimal exported program used by the regression test. |
| modules/dasLLVM/REVIEW.md | Adds checklist guidance about promoted modules being builtIn and requiring special-casing. |
| modules/dasLLVM/daslib/llvm_exe.das | Includes promoted modules in the global-initializer walk; updates doc references. |
| modules/dasLLVM/ARCHITECTURE.md | Routes standalone-exe details into a new dedicated architecture document. |
| modules/dasLLVM/ARCHITECTURE_EXE.md | New doc describing exe link decisions and startup initializer/address behavior. |
| modules/dasLLAMA/tune_for_this_box.md | Updates tuning doc to note browser default spin window is 0. |
| modules/dasLLAMA/tests/test_parrot.das | Updates parrot tests for new pure functions and smoke witness; adjusts smoke argv. |
| modules/dasLLAMA/tests/test_facade.das | Adds a facade-level test for the jobque spin getter/setter. |
| modules/dasLLAMA/tests/test_box_profile.das | Switches profile application to the internal underscore spin getter/setter. |
| modules/dasLLAMA/PERF_LEDGER.md | Records the browser parked-workers perf win as a landed ledger entry. |
| modules/dasLLAMA/dasllama/dasllama.das | Exposes get_jobque_spin_us / set_jobque_spin_us via the facade. |
| modules/dasLLAMA/dasllama/dasllama_math.das | Adds emscripten [init] defaulting spin to 0; renames internal spin accessors. |
| modules/dasLLAMA/dasllama/dasllama_fat_start.das | Updates runtime snapshot to use underscore spin getter. |
| modules/dasLLAMA/dasllama/dasllama_common.das | Applies box-profile jobque_spin_us via underscore spin setter. |
| modules/dasLLAMA/ARCHITECTURE_RUNTIME.md | Documents the browser parked-workers default and rationale. |
| modules/dasGlfw/src/dasGLFW.main.cpp | Improves emscripten canvas sizing logic to prefer parent box when appropriate. |
| include/daScript/misc/platform.h | Raises wasm DAS_MAX_HW_JOBS default cap from 4 to 8 (with updated rationale). |
| examples/dasLLAMA/storywish/web_shell.html | Adds Cache Storage model caching with sha256 verification and stale-key sweep. |
| examples/dasLLAMA/storyteller/web_shell.html | Same caching/sweep logic as storywish shell. |
| examples/dasLLAMA/REVIEW.md | Clarifies browser input rules for ImGui-harness vs manual GLFW polling; adds audio-status-box rule. |
| examples/dasLLAMA/parrot/web_shell.html | Fixes keydown prevention (don’t swallow space) and adds model caching + sweep. |
| examples/dasLLAMA/parrot/take.das | Replaces textbox/button logic with waveform peak aggregation + chunk ledger utilities. |
| examples/dasLLAMA/parrot/main.das | Rebuilds parrot into an ImGui multi-panel lab, adds jobque controls and chunk timing display. |
| examples/dasLLAMA/parrot/.das_package | Updates package description to reflect ImGui-based UI. |
| examples/dasLLAMA/ARCHITECTURE.md | Updates example architecture docs for ImGui harness usage and model caching behavior. |
| doc/source/reference/tutorials/dasLLAMA_05_performance.rst | Documents spin window semantics, defaults, and latching behavior. |
| doc/reflections/das2rst.das | Updates doc grouping regex to include new facade spin APIs. |
| CMakeLists.txt | Updates cached description of wasm DAS_MAX_HW_JOBS default to 8. |
Review details
- Files reviewed: 35/35 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…mple never declared (the run plays through the mixer and a box without a window server skips it), and the performance tutorial's spin section restores the window it found rather than a fixed desktop value, on the page as in the source. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
There are a few correctness/documentation issues in the changed code (notably a non-portable facade test expectation and some misleading checklist wording) that should be fixed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 35/35 changed files
- Comments generated: 3
- Review effort level: Lite
… ready - a box profile's own value, or the desktop's 30 ms where the engine's default is 0 - instead of a fixed 30 ms that replaced a tuned window after a toggle off and on. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
There is at least one confirmed correctness hazard (int64→int narrowing without clamping for the spin window in examples/dasLLAMA/parrot/main.das) that should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 35/35 changed files
- Comments generated: 1
- Review effort level: Lite
… DLL imports dasModuleClipboard.shared_module, and a recording start that saw nothing require the clipboard module wrote it as deferred beside an eager imgui, so the next start's eager load of the three imgui DLLs failed on the import ("the specified module could not be found") and stayed pending, out of the deferred fallback's reach - the Windows lane's deferred-modules test, red or green by whichever manifests earlier children left. With the requirement declared the recording start pulls the clipboard module in, and the rows agree. modules/REVIEW.md, new, carries the duty for every module: a shared module linked against another module's target requires that module in its initDependencies in the same change.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
It modifies a generated binder output file (modules/dasImgui/src/dasIMGUI.cpp) in a way that is likely to be lost on regeneration, risking a silent dependency regression.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 37/37 changed files
- Comments generated: 2
- Review effort level: Lite
… gains require_load_modules, the modules a binding's library imports and must initialize first but whose types stay out of its type library (require_modules adds the module to the library, and imgui's ImVector fields then resolve to clipboard_core's copies of the same annotations - the OpenGL driver stops compiling), bind_imgui.das pushes clipboard_core into it, and the generated dasIMGUI.cpp carries the binder's exact emission (the require and its initDependencies), so the self-binder's freshness gate reproduces the file rather than reverting a hand edit. modules/REVIEW.md states the link-implies-require duty and the binder duty as two rules with one WHY each, cites no other folder's architecture doc, and routes the shader-emitter checklist by kind alone (the dasMetal and dasSpirv checklists already route by location). The lab's hint names Ctrl or Cmd, the chord the handler accepts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
It spans cross-cutting runtime behavior changes (wasm threading defaults), exe emission logic, binding generation, and multiple UI/browser-shell paths, making it higher risk than can be safely auto-approved here.
Review details
- Files reviewed: 39/39 changed files
- Comments generated: 0 new
- Review effort level: Lite
Behavior change: a dasLLAMA program running in a browser now starts with the job queue's worker spin window at 0 - a page that wants the 30 ms window sets it with
set_jobque_spin_us.Why. The parrot page was a text overlay on a GL canvas with no way to see what the take, the synthesis or the job queue were doing, and its browser build could not use Dear ImGui at all: a
@@fntaken in a shared module's global initializer came out null in a standalone exe, so the first icon button threw on the first frame. On the same page the eight spinning web workers held the caller's core: the poem generated at 1.1x real time with the renderer at 800% CPU, against 1.4x parked at 112%.What changes.
imgui_harness: dock windows for the status strip, the voice (record disc with the silence countdown, level, gain, the take's waveform, the roster picker), the text (editor, play and stop, the say's chunks in their state's colour), the output (the growing waveform with the mixer-clock playhead, the per-chunk stage times) and the lab (model facts, the job queue's jobs slider and team and spin toggles, a measure button reporting times real time).shared) das module's@@fnis stored before the init script runs.[init]sets the worker spin window to 0 when the running platform is emscripten; the facade exposesget_jobque_spin_usandset_jobque_spin_usover the engine's underscore spellings.Observable behavior.
WebAssembly.Exceptionon its first frame with an icon button -> the page runs;llvm_exe_shared_addr.dasholds the shape.set_dispatch_worker_limit, which stands the parking down.Where to look.
collect_external_functionsinmodules/dasLLVM/daslib/llvm_exe.das(one condition),dasllama_jobque_spin_defaultinmodules/dasLLAMA/dasllama/dasllama_math.das, andexamples/dasLLAMA/parrot/main.dasfor the lab; the measured figures are the PERF_LEDGER.md entry.Validation, claims, ledger
Validation
llvm_exe_shared_addr.daswas red before the change (EXCEPTION: invoke null function) and green after.run.das -- --changed, every area) passed 120 of 122 files; the two reds,test_vulkan_dec_tail.dasandtest_vulkan_tier.das, are this Mac's Vulkan device declining a 33 KB row tile over its 32 KB shared-memory cap, and fail the same way in runs from before this branch.clipboard_corein itsinitDependencies, through the binder's newrequire_load_moduleslist, the module its DLL imports;modules/REVIEW.md(new) carries the duty. It does not change the Windows lane's primary sweep: the arm "a module whose C++ dependencies are deferred too" oftests/module_cache/test_deferred_modules.dasfails there on master and on this branch alike (the OS resolves the DLL's import at load time, before any module code runs, and the deferred fallback loads imgui before clipboard), and the isolated retry passes, so the job reads green on both. A retry-until-no-progress pass in that fallback is a candidate for its own PR.Claims - stated, not tested
llvm_exe_shared_addr.das's Windows arm (theset PATH=...&&spelling of the run command, the.exesuffix) has not executed; the Windows nightly's dasLLVM lane is its first run, as for the two sibling exe tests. A break would read as that one file red on Windows only.The spin default fires only when
get_running_platform_name()answersemscripten; no desktop test reaches that arm. It was verified on the page: the lab's spin toggle reads the engine's value and starts unticked, and the measure reads 1.4x. A break would show the toggle ticked and the poem back at 1.1x.The GLFW glue's parent-box sizing and the shells' Cache Storage are browser-only JavaScript; verified by the page's canvas rect and by a reload fetching only
manifest.jsonand the wasm (304s). A break would show a vertically squeezed picture, or the model files fetched on every visit.The parrot smoke proves the program runs to read-out and, through the read-out line's figures, that the say played to its end (a clip read as stopped on its first frame fails it - checked by mutation); the lab's measure path, the take's microphone wiring and the drawing layer run inside it without an assertion of their own. A break in one of them reads as a panic in the smoke or a wrong panel on the page.
The two per-PR dasLLAMA suites were not run as such; the changed-file run over every area (122 files) stands in for them, per the owner's ruling.
Not done