Skip to content

AI Assistant: fix Save to Macros in worker mode, propose macros without running them - #77

Merged
PierreRaybaut merged 1 commit into
developfrom
fix/ai-assistant-save-macro
Oct 28, 2026
Merged

PierreRaybaut merged 1 commit into
developfrom
fix/ai-assistant-save-macro

Conversation

@PierreRaybaut

Copy link
Copy Markdown
Contributor

Summary

Found during a demo: in a conversation reopened from the history, 💾 Save to Macros turned into Saved ✓, but no macro appeared in the Macros panel; asking the same question again, the assistant answered with plain code and no Save to Macros button.

Closes #76 — companion desktop fix: DataLab-Platform/DataLab#448 (DataLab-Platform/DataLab#447).

Root causes and fixes

  • Save to Macros (worker mode): DataLabRuntime.saveMacro created the macro, then notified the Macros panel through a dlw:macros-changed event on window. Since 0.10.0 the runtime runs by default in a Dedicated Web Worker, where window does not exist: the event was never dispatched (and each click added another hidden macro). The AI Assistant panel now saves through the Macros panel (onSaveMacro → MacroPanel.importMacro), which works in both runtime modes and brings the Macros tab to the front (a floating Macros panel is left as is). saveMacro and the event are removed.
  • get_macro_console_output: read the public lastMacroOutput field, which the worker façade turns into a forwarding function: the model received an empty result. Now read through getLastMacroOutput().
  • Plain-code answers: the system prompt sent super-Gaussian, Lorentzian and polynomial curves to create_synthetic_signal (which only supports sine, cosine, gauss and noise) while forbidding macros. The prompt now follows the kinds the creation tools actually support, and routes "write a macro" requests to create_and_run_macro with the new autorun: false parameter (as in DataLab desktop): the macro is only linted and offered for saving. The approval dialog states that it will not be executed, and remembering such an approval never auto-approves a macro that runs (separate approval key).
  • Fallback: a Save to Macros button is offered under each Python code block of the replies (extractMacroCodeBlocks, via marked.lexer), named after the user request. The sanitized Markdown HTML is untouched.

Tests

  • Unit: tools.test.ts (autorun, getLastMacroOutput, approval key), macroCodeBlocks.test.ts, systemPrompt.test.ts, panel.test.tsx (save through onSaveMacro, conversation restored from IndexedDB, retry after a failed save, code-block buttons, approval scoping). The panel tests now reset the conversation store between tests.
  • Audit: workerBoundaryAudit.test.ts — public DataLabRuntime members must be methods, and the runtime must not dispatch DOM events. Both checks fail on the previous runtime.ts.
  • E2E: ai_assistant_macro.spec.ts, in worker mode with the mock provider: save a proposed macro, save it again after a reload from the restored conversation (the demo scenario), save a code block.
  • format:check, lint, tsc -b, vitest run (969 passed), Playwright ai_assistant_macro, worker_mode and macro specs.

Not covered: the actual choice of a real LLM (the prompt makes plain-code answers less likely; the code-block button covers the remaining cases).

"Save to Macros" showed "Saved ✓" but the macro never appeared in the
Macros panel. DataLabRuntime.saveMacro created the macro, then notified the
panel through a "dlw:macros-changed" event on `window`, guarded by
`typeof window !== "undefined"`. Since 0.10.0 the runtime runs by default in
a Dedicated Web Worker, where there is no `window`: the event was never
dispatched, and each click added another hidden macro to the workspace.
The AI Assistant panel now saves through the Macros panel
(`onSaveMacro` -> `MacroPanel.importMacro`), which works in both runtime
modes and brings the Macros tab to the front; saveMacro and the event are
removed.

Same boundary: get_macro_console_output read the public `lastMacroOutput`
field, which the worker façade turns into a forwarding function (the model
received an empty result). It is now read through getLastMacroOutput().

The model could also answer "write a macro" requests with plain code that
cannot be saved: the system prompt sent super-Gaussian, Lorentzian and
polynomial curves to create_synthetic_signal, which cannot produce them,
while forbidding macros. The prompt now follows the kinds the creation
tools support, and create_and_run_macro gets an `autorun` parameter (as in
DataLab desktop): with `autorun: false`, the macro is only linted and
offered for saving. The approval dialog states it, and remembering such an
approval never auto-approves a macro that runs. As a fallback, a "Save to
Macros" button is offered under each Python code block of the replies.

Tests: unit tests (tools, prompt, code blocks, panel incl. a conversation
restored from IndexedDB), an audit of the worker boundary (public runtime
members must be methods; no `window` events from the runtime), which fails
on the previous runtime, and an E2E test in worker mode with the mock
provider.

Closes #76

Assisted-by: Claude Opus 5.5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AI Assistant: "Save to Macros" does nothing in worker mode, and the model writes macro code instead of calling the tool

1 participant