spacr.qt.widgets.ai_chat_panel

AIChatPanel — reusable chat widget hosting the spacr AI Console.

Meant to be embedded next to the pipeline Console (via a QDockWidget on the main window) so users never leave the app they’re running. Exposes open_error_flow(traceback, active_app) for AppScreen’s “Explain error” button.

Design notes

  • One instance is shared across the whole main window; the user’s chat context persists as they switch between Mask/Measure/etc.

  • Streaming is done in a QThread via spacr.qt.ai.worker.StreamWorker. The worker reference is stored on self — if we let Python drop it, Qt may never deliver the finished signal.

  • There is NO “already streaming” guard. If a stream is in flight, the Send button turns into Cancel so the user can always recover.

Classes

AIChatPanel

Full chat panel — embed inside a QDockWidget or any container.

Module Contents

class spacr.qt.widgets.ai_chat_panel.AIChatPanel(parent: PySide6.QtWidgets.QWidget | None = None)[source]

Bases: PySide6.QtWidgets.QWidget

Full chat panel — embed inside a QDockWidget or any container.

Parameters:

parent – parent widget.

Build the chat panel.

Parameters:

parent – parent widget.

clear_chat() → None[source]

Discard chat history and remove every bubble from the scroll area.

closeEvent(event) → None[source]

Drain the streaming thread before Qt destroys the panel.

Parameters:

event – the close event; it is not inspected, only passed on to the base class after shutdown().

is_streaming() → bool[source]

Return True while a response is being streamed.

open_error_flow(traceback_text: str, active_app: str = '') → None[source]

Send a traceback to the AI explainer and stream the reply.

Parameters:
  • traceback_text – raw traceback captured from the pipeline.

  • active_app – optional app label used in the framing prompt.

refresh_provider_combo() → None[source]

Rebuild the provider dropdown from the currently configured CLIs.

shutdown() → None[source]

Cancel any active stream and block until its QThread exits.

Must run before the panel is destroyed — otherwise Python drops the last reference to a running QThread and Qt aborts with QThread: Destroyed while thread '' is still running.

Never terminates a thread: see spacr.qt.bridge.drain_thread() and the note in spacr.qt.widgets.console_panel.ConsolePanel.shutdown() for why QThread.terminate() on a Python thread trades one crash for a worse, unattributable one.