FastTBHandler¶
Also see: FastTB — user-facing API (decorators, path params, WebSocket handlers, integration modes).
Dispatch engine for FastTB routes — resolves incoming HTTP requests to registered handlers, injects parameters via signature inspection, and converts return values into WSGI-compatible (status, headers, body) tuples. Also manages static file serving, SSE streaming, WebSocket infrastructure, and development-mode hot reload.
Why This Matters¶
When building a web application with FastTB's decorator-based routing, you need a layer that bridges those registered routes to a real WSGI server. FastTBHandler is that bridge. It handles the full request lifecycle — route matching, parameter injection (path, query, body, session), response formatting, and static files — so your handler functions stay focused on business logic. For development, it also provides hot-module-reload via filesystem watching.
Quick Start¶
from toolboxv2.utils.workers.fast_tb_handler import FastTBHandler
# handler is typically created internally by FastTB
handler = FastTBHandler(fast_tb_app=my_app)
# Get a full WSGI app with HTTPWorker infrastructure baked in
wsgi_app = handler.as_wsgi_app()
# Serve with any WSGI server (e.g. waitress)
from waitress import serve
serve(wsgi_app, host="0.0.0.0", port=8080)
Usage Guide¶
Basic Usage — Standalone WSGI Server¶
The as_wsgi_app() method produces a complete WSGI callable that reuses HTTPWorker's infrastructure (sessions, auth, CORS, built-in endpoints) while adding FastTB's route resolution:
handler = FastTBHandler(my_fast_tb_app)
app = handler.as_wsgi_app()
# app is a standard WSGI callable: (environ, start_response) -> [bytes]
Advanced Usage — WebSocket Support + Hot Reload¶
When WebSocket routes are registered (or enable_ws=True is passed), as_wsgi_app automatically starts the full WS stack:
app = handler.as_wsgi_app(enable_ws=True)
# Internally starts:
# 1. ZMQ broker (inter-thread messaging)
# 2. WS worker (persistent WebSocket connections)
# 3. Event bridge (wires WS connect/message/disconnect to handlers)
Hot reload monitors registered directories for file changes and broadcasts reload events to connected WS clients:
handler._start_hot_reload(app, config, get_loop_fn)
# Watches .py, .js, .css, .html, .jsx, .ts, .tsx, .vue, .svelte files
# Reloads Python modules in-place, preserving ReactiveState values
How It Works¶
FastTBHandler operates as a three-layer dispatch pipeline. First, handle_request resolves the incoming path+method to a registered Route object (or a static file). Second, _build_kwargs inspects the handler's function signature using inspect.signature and injects parameters from the request — path params, query params, JSON body fields, the ParsedRequest itself, or session data — with automatic type coercion for int, float, and bool. Third, _format_result normalizes whatever the handler returns (dict, list, str, bytes, tuple, async generator, ToolBoxV2 Result object) into a standard (status, headers, body) triple.
For streaming, _async_gen_to_sync bridges async generators to WSGI's synchronous iteration model by running coroutines on a background event loop via run_coroutine_threadsafe, with 30-second chunk timeouts that emit SSE keepalive comments. The as_wsgi_app method wraps everything in a patched WSGI callable that tries FastTB routes first, then falls through to HTTPWorker's built-in endpoints.
flowchart TD
A[Incoming HTTP Request] --> B[patched_wsgi]
B --> C{FastTB has route?}
C -->|Yes| D[FastTBHandler.handle_request]
C -->|No| E[HTTPWorker fallback]
D --> F{Static file?}
F -->|Yes| G[_serve_static_file]
F -->|No| H[resolve_route]
H --> I[_build_kwargs]
I --> J[_execute_and_format]
J --> K[_format_result / _format_tb_result]
K --> L["(status, headers, body)"]
G --> L
API Reference¶
Classes¶
FastTBHandler¶
Dispatch engine for FastTB routes. Matches incoming path+method to a registered Route, inspects handler signature and injects the right parameters, and converts return values to WSGI-compatible (status, headers, body) tuples.
| Method | Signature | Description |
|---|---|---|
__init__ |
def __init__(self, fast_tb_app: "FastTB", session_manager=None) |
Initialize with a FastTB instance and optional SessionManager for standalone mode. |
has_route |
def has_route(self, path: str, method: str) -> bool |
Check if FastTB can handle this path+method. |
handle_request |
async def handle_request(self, request: ParsedRequest) -> Tuple[int, Dict[str, str], bytes] |
Resolve route, inject params, execute handler, format response. Also serves static files from mounted directories. |
as_wsgi_app |
def as_wsgi_app(self, config=None, app=None, enable_ws: bool \| None = None) -> Callable |
Return a WSGI app that wraps HTTPWorker with FastTB routes. Reuses HTTPWorker's full infrastructure. Starts WS infrastructure automatically when websocket routes exist. |
_build_kwargs |
def _build_kwargs(self, handler: Callable, request: ParsedRequest, path_params: Dict[str, str]) -> Dict[str, Any] |
Inspect handler signature and build kwargs. Resolution order: request injection → session injection → path params → query params → body fields. |
_coerce |
def _coerce(value: str, annotation) -> Any |
Coerce string value to annotated type (int, float, bool). |
_missing_param_error |
def _missing_param_error(param_name: str) |
Return error dict that _execute_and_format will detect. Raises ValueError. |
_execute_and_format |
async def _execute_and_format(self, handler: Callable, kwargs: Dict[str, Any]) -> Tuple[int, Dict[str, str], bytes] |
Execute handler (async or sync) and convert return value to response tuple. |
_format_result |
def _format_result(result) -> Tuple[int, Dict[str, str], bytes] |
Convert handler return value to (status, headers, body). Supports: tuple passthrough, Result objects, dict/list → JSON, str → HTML or JSON, bytes → raw, generators → streaming. |
_format_tb_result |
def _format_tb_result(result) -> Tuple[int, Dict[str, str], Any] |
Convert a ToolBoxV2 Result object to response tuple. Handles: stream, html, special_html, redirect, file_path, file, binary, json. |
_serve_static_file |
def _serve_static_file(file_path: str) -> Tuple[int, Dict[str, str], bytes] |
Serve a static file with correct content-type and cache headers (immutable for hashed filenames, 1h otherwise). |
_start_ws_infrastructure |
def _start_ws_infrastructure(self, config, app, worker, get_loop_fn) |
Start ZMQ broker, WS worker, and event bridge in background threads. Called by as_wsgi_app() when WebSocket routes are registered. |
_start_hot_reload |
def _start_hot_reload(self, app, config, get_loop_fn) |
Start file watcher for hot-reload in development mode. Uses watchdog; falls back to no-op if not installed. |
ReloadHandler(FileSystemEventHandler)¶
Inner class (defined inside _start_hot_reload) that handles filesystem change events for hot-module-reload. Debounces changes (0.5s), filters by extension, skips cache/git directories, reloads Python modules via AST-based safe extraction, and broadcasts reload events to WS clients.
| Method | Signature | Description |
|---|---|---|
on_modified |
def on_modified(self, event) |
Delegate to _handle. |
on_created |
def on_created(self, event) |
Delegate to _handle. |
_handle |
def _handle(self, event) |
Debounced file change handler. Filters by extension and path, reloads .py modules, broadcasts reload to WS clients. |
_exec_reload |
def _exec_reload(self, filepath) |
Reload a Python file by extracting only function/class definitions via AST parsing. Skips module-level side effects. |
_reload_python_module |
def _reload_python_module(self, filepath) |
Reload a Python module and update MinuBridge view classes. Preserves existing ReactiveState values while swapping in new class definitions (render, handlers). |
Functions¶
_file_iter(file_obj, chunk_size: int = 65536)¶
Generator for streaming a file object as WSGI response body. Reads in chunks until exhausted, then closes the file object in a finally block.
Parameters:
- file_obj — open file object to read from
- chunk_size — bytes per read iteration (default 65536)
Returns: Generator yielding bytes chunks.
_async_gen_to_sync(async_gen, loop)¶
Convert async generator to sync iterator for WSGI streaming. Each __next__ blocks the Waitress thread until the next chunk arrives. Timeout per chunk: 30s. Sends SSE keepalive comment (": keepalive\n\n") on timeout to prevent proxy/browser disconnect.
Parameters:
- async_gen — async generator to bridge
- loop — event loop to run coroutines on
Returns: Synchronous iterator yielding bytes.
_maybe_inject_style(html_str: str) -> str¶
Inject Paper CSS into HTML responses that lack TBJS web_context. Skips injection if the string is empty, inject_style is globally disabled, the HTML already contains TBJS markers (tbjs-main, TB.init, web_context), or already has substantial user CSS (>200 chars in a <style> block not from _SHARED_CSS/ftb-wrap). Injects fonts + main.css + paper.css and adds data-style="paper" to the <html> tag.
Parameters:
- html_str — HTML string to potentially inject styles into
Returns: Modified or unmodified HTML string.
_is_hashed_filename(path: str) -> bool¶
Check if filename contains a content hash (e.g. main-5d3f7ed2.js). Hashed files are treated as immutable for caching purposes.
Parameters:
- path — file path string to check
Returns: True if the basename matches the pattern [-_.][0-9a-f]{6,}..
Dependencies¶
- ZMQEventManager from
toolboxv2/utils/workers/event_manager.py— pub/sub messaging and WS event dispatch - WSWorker from
toolboxv2/utils/workers/ws_worker.py— persistent WebSocket connection handling - install_ws_bridge from
toolboxv2/utils/workers/ws_bridge.py— bridges WS send/broadcast onto the app - HTTPWorker from
toolboxv2/utils/workers/server_worker.py— WSGI infrastructure, sessions, auth, CORS - load_config from
toolboxv2/utils/workers/config.py— worker configuration loading - FastTB from
toolboxv2/utils/workers/fast_tb.py— route registration and resolution - fast_tb_defaults from
toolboxv2/utils/workers/fast_tb_defaults.py—_MAIN_CSS,_PAPER_CSS,_FONTSconstants
Used By¶
- Referenced by
enhanced_on_messagein WhatsAppTb/server - Referenced by
_coercein manifest_cli - Referenced by
_coercein toolbox_admin - Referenced by
_run_ws_worker_processin cli_worker_manager - Referenced by
_render_quick_mode,_render_discovery_mode,_render_profiles_mode,_render_successin adaptive_prompt_system - Referenced by
_handle_macro_commandin minicli - Referenced by
_format_results_as_strin ai_semantic_memory