Skip to content

NativeLabPro_Major_featureUpdate_v4

Latest

Choose a tag to compare

@7ZoneSystems 7ZoneSystems released this 06 Mar 23:14
· 111 commits to main since this release
0796de1

NativeLab Pro — Release Notes

Version 2.5 · Development Session Changelog


Overview

This document covers every feature, improvement, and bug fix applied to nativelab.py during this development session. Changes are grouped by area. Each section describes what was added, how it works, and what files / classes were touched.


1. GPU Acceleration Support

Area: Server Tab · ServerConfig dataclass · ServerTab class

What was added

The Server tab now contains a dedicated GPU Acceleration card that auto-detects available graphics hardware on startup and exposes all GPU launch flags visually — no more hand-editing the Extra Launch Flags box.

How it works

A new utility function _detect_gpus() is called once when the Server tab builds. It probes three backends in order: nvidia-smi for NVIDIA CUDA cards, system_profiler on macOS for Apple Metal GPUs, and vulkaninfo as a Vulkan fallback. Each probe runs in a subprocess with a short timeout so the UI never freezes. The result is a list of dicts carrying device index, name, VRAM in MB, and backend type.

The GPU card renders a backend badge (🟢 CUDA / Metal, 🟡 Vulkan, ⚪ None) followed by a list of all detected GPUs with their VRAM. Four controls appear:

  • Enable GPU offloading checkbox — disabled automatically if no GPU was detected.
  • GPU layers spin box (-1 to 999) — special display text "All (−1)" when set to −1 means offload every layer.
  • Primary GPU combo box — populated from the detected device list.
  • Tensor split line edit — for multi-GPU ratio strings like 0.6,0.4.

On save (_save()), the GPU flags are serialised into ServerConfig and also injected into extra_server_args as --ngl N [--main-gpu N] [--tensor-split X,Y] using a regex strip-then-prepend so existing manually typed flags are preserved. The existing launch code picks them up with zero changes.

New fields in ServerConfig

enable_gpu    bool   = False
ngl           int    = -1
main_gpu      int    = 0
tensor_split  str    = ""

2. HuggingFace GGUF Model Download Tab

Area: New tab · ModelDownloadTab widget · HfSearchWorker / HfDownloadWorker QThreads

What was added

A new ⬇️ Download tab that lets users search HuggingFace for GGUF model files and download them directly into any local folder, with live progress and cancellation — no browser needed.

How it works

Search flow: The user types a repo ID (e.g. TheBloke/Mistral-7B-GGUF) and clicks Search. A HfSearchWorker QThread calls https://huggingface.co/api/models/{repo}, filters the siblings list to .gguf files only, and emits results_ready(list). Results appear in a QListWidget with colour-coded quantisation badges (Q2 = red through Q8 = green) and a human-readable file size.

Download flow: The user selects a file, picks a destination folder, and clicks Download. A HfDownloadWorker QThread fetches https://huggingface.co/{repo}/resolve/main/{filename} in 256 KB chunks, emitting progress(int) on each chunk. If the user cancels or the download errors, the partial file is deleted. On successful completion MODEL_REGISTRY.add(path) is called so the model appears immediately in all model lists, and a success dialog offers to open the folder.

Only Python standard library (urllib) is used — no new pip dependencies.


3. MCP Server Management Tab

Area: New tab · McpTab widget · MCP_CONFIG_FILE constant

What was added

A new 🔌 MCP tab for managing Model Context Protocol servers. Users can add, start, stop, and remove MCP servers (stdio or SSE transport) and see live log output from each.

How it works

Configuration is stored in ./localllm/mcp_config.json as {"servers": [...]}. Each server entry holds name, transport type (stdio / sse), command or URL, and description.

The tab has three panels: a server list with 🟢/⚪ running indicators, a control row (Start / Stop / Remove), and a log pane with timestamps. Clicking Start on a stdio server launches it via subprocess.Popen(shell=True) and stores the handle in a _procs dict keyed by server name. SSE servers just log their URL since they run externally. Log lines are appended from stdout polling. Stop terminates the process and removes it from _procs.


4. Pipeline Builder — Full Logic Block System

Area: PipelineBlockType · PipelineCanvas · PipelineExecutionWorker · PipelineBuilderTab sidebar

What was added

Seven new Python-evaluated logic blocks that let users build conditional, branching, and transforming pipelines without writing any model calls.

Block types

⑂ IF / ELSE evaluates a Python boolean expression (len(text) > 200, 'error' in text.lower()) against the incoming context. TRUE routes to the E port, FALSE to the W port. Users draw two labelled arrows to set up the branches.

⑃ SWITCH evaluates a Python expression that returns a string key ('long' if len(text) > 300 else 'short'). Each outgoing arrow carries a user-supplied label. Only the arm whose label matches the returned key is followed. A default labelled arm catches unmatched keys.

⊘ FILTER acts as a gate. If the condition is True the text continues unchanged. If False the pipeline terminates cleanly with a [FILTER DROPPED] message in the Output tab — no crash, no silent drop.

⟲ TRANSFORM performs instant deterministic text operations with no model: prefix, suffix, find-and-replace, upper, lower, strip whitespace, or truncate to N characters.

⊕ MERGE collects every context queued for it in the current execution pass (from multiple incoming arrows) and joins them. Modes: concat with separator, prepend, append, or JSON array.

⑁ SPLIT broadcasts the exact same text to every outgoing arrow simultaneously. No configuration needed — just draw multiple outgoing arrows.

⌥ Custom Code opens a full code editor dialog (described below) where the user writes arbitrary Python.

Multi-output fan-out

Before this change every source port was limited to one outgoing arrow (the old code deleted the previous connection on each new draw). Logic blocks are now added to a _LOGIC_BTYPES set that skips that deletion, allowing any number of arrows to fan out from the same port. Duplicate connections (same from_bid + from_port + to_bid) are silently ignored. Normal flow blocks (Input, Model, Output, Intermediate) still enforce single-output-per-port.

Branch label badges on arrows

When an arrow leaves an IF/ELSE or SWITCH block, a branch label is stored as a dynamic attribute conn.branch_label on the PipelineConnection object. The _draw_arrow method reads this attribute and renders a small rounded badge at 35% along the Bezier curve — green for TRUE, red for FALSE, pipeline-colour for other labels.

Custom Code Editor Dialog (_CodeEditorDialog)

A QDialog with a QTextEdit code editor (Consolas 11pt, 28-unit tab stops), a live syntax-check label that updates on every keystroke using compile(), an available-variables reference table, and a 🧪 Test button that runs the code in a sandboxed exec() with sample text and shows the result and log output in a QMessageBox. Saving validates syntax first and refuses to close if there is a syntax error. The block label is automatically set to the first non-comment code line.

The sandbox exposes only safe builtins: len str int float bool list dict tuple range enumerate zip map filter sorted min max sum abs round isinstance hasattr getattr repr type print — no open, os, subprocess, or __import__.


5. Pipeline Builder — LLM Logic Block System

Area: PipelineBlockType · PipelineCanvas · PipelineExecutionWorker · PipelineBuilderTab sidebar · _LlmLogicEditorDialog

What was added

Five new LLM-evaluated logic blocks that are functionally identical to the Python logic blocks above except every condition or instruction is written in plain English and evaluated at runtime by an attached GGUF model over the llama-server HTTP API.

Block types

🧠 LLM IF / ELSE sends the incoming text plus a plain-English condition to the model with a tight system prompt demanding a single word: YES or NO. The parser accepts YES Y TRUE 1 PASS POSITIVE as truthy. Routes to E (YES) or W (NO).

🧠 LLM SWITCH presents the model with the incoming text and the classification task. The valid category names are automatically extracted from the branch labels on the outgoing arrows and included in the prompt. Case-insensitive matching with a substring fallback ensures robustness. A default labelled arm catches unmatched classifications.

🧠 LLM FILTER demands PASS or STOP. On STOP the pipeline ends with a structured message showing the filter name, condition, model decision, and original text — so the user can inspect exactly what was blocked and why.

🧠 LLM TRANSFORM uses a higher default token budget (512), provides a system prompt that demands output-only with no preamble, and automatically strips common model preamble phrases (Here is, Result:, Output:, Transformed:) before the result flows downstream.

🧠 LLM SCORE extracts the first integer 1–10 from the model response using regex (handles prose like "I'd give it a 7"), maps to LOW (1–3) / MID (4–7) / HIGH (8–10) bands routed to E / S / W ports. A score-labelled outgoing arrow receives the raw numeric string instead of the original context.

LLM Logic Editor Dialog (_LlmLogicEditorDialog)

A QDialog tailored per block type. It shows: a colour-coded about-panel describing exactly what the model will receive and return, a branch-routing hint (e.g. "E port = YES / W port = NO"), a model selector combo box populated from MODEL_REGISTRY with a Browse button, and a multi-line instruction editor with a placeholder showing practical examples for that block type.

Advanced settings (collapsed by default): max response tokens, temperature (0–100 mapped to 0.00–1.00), show-model-reasoning-in-log toggle, and a passthrough-on-error safety switch that continues the pipeline unchanged if the model call fails rather than halting.

Shared _llm_query_sync helper

A new method on PipelineExecutionWorker wraps the llama-server HTTP call for all five LLM logic blocks. It calls _ensure_server() to guarantee server mode, builds the prompt using the model family template, POSTs to /completion synchronously (stream=False), and returns the raw content string. All error states (file not found, server fail, HTTP error) go through _llm_block_call() which handles the passthrough-on-error flag and emits appropriate log messages before returning.


6. Pipeline Builder — Canvas UX Improvements

Area: PipelineCanvas · PipelineBuilderTab

Drag and drop from model list

The sidebar model list (QListWidget) now has DragEnabled = True and DragDropMode = DragOnly. The canvas (PipelineCanvas) sets setAcceptDrops(True) and implements dragEnterEvent, dragMoveEvent, dragLeaveEvent, and dropEvent. The dropEvent decodes the Qt MIME format application/x-qabstractitemmodeldatalist using QDataStream to extract the model path (UserRole) and role (UserRole+1), then calls add_block() at the snapped drop position.

Ghost block preview while dragging

During a drag-over, dragMoveEvent stores the snapped cursor position in self._drop_preview. paintEvent calls a new _draw_drop_ghost() method which renders a 140×48 translucent dashed rectangle with a ⚡ Drop here label at that position. The ghost is painted before the blocks layer so it appears underneath existing blocks. On dragLeaveEvent or after dropEvent, _drop_preview is cleared and the canvas repaints.

Horizontal model pill scroll bar

A 36px fixed-height strip is inserted between the canvas toolbar and the canvas scroll area. It contains a QScrollArea (horizontal-only) holding a QHBoxLayout of QPushButton pills, one per MODEL / logic / LLM-logic block on the canvas. Each pill is colour-coded to match the block's border colour and labelled with the block's current label. Clicking a pill sets canvas._selected to that block and triggers a repaint — effectively a jump-to-block shortcut when the canvas is large. The pill bar rebuilds every time blocks_changed fires via the existing _on_blocks_changed handler. When the canvas has no relevant blocks a "No model or logic blocks yet" placeholder label is shown instead.


7. Pipeline Builder Manual

Area: PipelineBuilderTab · _make_manual_html() function

What was added

A 📖 Manual button added to the right execution panel header opens a themed HTML manual in a scrollable QDialog.

Contents

The manual covers every single block type with port tables, configuration steps, practical examples in highlighted code boxes, tips, and warnings. Sections include: Quick Start, Canvas Controls, Port Dots, all Flow Blocks, Model Block, all Context Blocks, all seven Python Logic Blocks, all five LLM Logic Blocks, Loops, Save/Load, Debugging, and Performance Tips.

It is generated at import time by _make_manual_html() which reads the live C colour dict so the manual renders in the user's current light or dark theme. Helper functions (h2, h3, p, note, tip, code, badge, kbd, port_table, example_box) produce consistent HTML throughout.


8. Bug Fixes

cursor:pointer invalid QSS warning (× 10 instances)

Qt's QSS engine does not support the CSS cursor property — it prints Unknown property cursor to stdout for every widget that has it in a stylesheet. All cursor:pointer strings were removed from setStyleSheet() calls. Where pointer-hand behaviour was needed, widget.setCursor(Qt.CursorShape.PointingHandCursor) was used instead (this was already in place on most buttons; the stylesheet form was left over from copy-paste).

Affected dialogs: _LlmLogicEditorDialog advanced settings header.

QFont::setPointSize: Point size <= 0 (-1) crash

The _CodeEditorDialog code editor was calling QFont("Consolas", 11) and then setTabStopDistance(28.0). On some Windows font configurations the resolved point size comes back as −1 before the font is attached to a widget, triggering the Qt warning and occasionally a crash. Fixed by clamping: _code_font.setPointSize(max(1, _code_font.pointSize())) before setting the font. setTabStopDistance is wrapped in a try/except as a secondary guard.

QSpinBox missing from PyQt6 imports

QSpinBox was used in the GPU card and LLM logic dialog but was not present in the from PyQt6.QtWidgets import block, causing a NameError on startup. Added to the import.

QDataStream, QIODevice, QVariant missing from QtCore imports

Required by the canvas dropEvent MIME decoder. Added to from PyQt6.QtCore import.

QAbstractItemView missing from QtWidgets imports

Required to set DragDropMode.DragOnly on the model list. Added to from PyQt6.QtWidgets import.

exec_hdr_row undefined at runtime

The find-and-replace for the Manual button change partially applied — the old exec_hdr = QLabel(...) line duplicated and the new exec_hdr_row = QHBoxLayout() creation line was never inserted. The duplicate label line was removed and the layout creation line was added as the first statement of the block.

'PipelineBuilderTab' object has no attribute '_show_manual'

The _show_manual method body was never inserted into the class — the _PIPELINE_MANUAL_HTML constant was placed correctly but the method was missing. Added _show_manual() directly before _refresh_models().


9. Serialisation

branch_label on PipelineConnection

Branch labels for IF/ELSE and SWITCH arms are stored as a dynamic attribute conn.branch_label set at connection-creation time. This attribute is not currently persisted to the pipeline JSON (the serialiser only writes the fixed dataclass fields). Loaded pipelines therefore lose branch labels on reload — a known limitation to be addressed in a future session by adding branch_label to _pipeline_to_dict and _pipeline_from_dict.


Files Changed

Only nativelab.py was modified. All changes were applied as surgical find-and-replace edits — no full rewrites. Approximate line count grew from 11,571 to approximately 12,800 lines after all additions.


Summary Table

# Feature Type Lines affected
1 GPU acceleration (CUDA / Metal / Vulkan) New feature ServerTab, ServerConfig
2 HuggingFace GGUF download tab New feature New HfSearchWorker, HfDownloadWorker, ModelDownloadTab classes
3 MCP server management tab New feature New McpTab class
4 Python logic blocks (IF/ELSE, SWITCH, FILTER, TRANSFORM, MERGE, SPLIT, CODE) New feature PipelineBlockType, PipelineCanvas, PipelineExecutionWorker, sidebar
5 LLM logic blocks (LLM-IF/SW/FL/TX/SC) New feature Same + new _LlmLogicEditorDialog, _llm_query_sync
6 Multi-output fan-out for logic ports Enhancement PipelineCanvas._try_connect
7 Branch label badges on arrows Enhancement PipelineCanvas._draw_arrow
8 Drag-and-drop model onto canvas Enhancement PipelineCanvas dragEnter/Move/Leave/Drop, model_list
9 Ghost block drop preview Enhancement PipelineCanvas._draw_drop_ghost, paintEvent
10 Horizontal model pill scroll bar Enhancement PipelineBuilderTab._build, _on_blocks_changed
11 Pipeline Builder full manual New feature _make_manual_html, _show_manual, Manual button
12 cursor:pointer QSS warnings removed Bug fix _LlmLogicEditorDialog stylesheet
13 QFont point size ≤ 0 crash fixed Bug fix _CodeEditorDialog
14 Missing Qt imports (QSpinBox, QDataStream, QIODevice, QVariant, QAbstractItemView) Bug fix Top-level imports
15 exec_hdr_row undefined Bug fix PipelineBuilderTab._build
16 _show_manual AttributeError Bug fix PipelineBuilderTab