Skip to content

Visual Console GUI Extensibility & Micro-Frontends

AgentV v1.7.3 features Dynamic Navigation Manifest Ingestion and Runtime Module Federation for the native Visual Console (/v2).

This architecture allows Python plugins, third-party libraries, and enterprise extensions to inject custom tabs, sidebar entries, and interactive React micro-frontend views directly into the console with zero build-time recompilation of the Open Core.


β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Python Backend (Plugin Layer) β”‚
β”‚ β”‚
β”‚ 1. Plugin defines on_register_console_routes(app, nav_registry) β”‚
β”‚ 2. Registers custom Flask API blueprints β”‚
β”‚ 3. Appends NavItem metadata to app.config["NAV_REGISTRY"] β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”‚ GET /api/nav (JSON Manifest)
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Visual Console (Open Core React Frontend) β”‚
β”‚ β”‚
β”‚ 1. Ingests Manifest on mount via TanStack Query (60s staleTime) β”‚
β”‚ 2. Merges dynamic items with fallback built-in groups β”‚
β”‚ 3. Renders Badges ("LIVE", "APM", "CUSTOM"), Tiers, & Icons β”‚
β”‚ 4. Mounts remote ESM bundles on demand via React.lazy & import()β”‚
β”‚ 5. Fault-isolated inside RemoteErrorBoundary β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

When your plugin appends navigation metadata to nav_registry, it conforms to the following schema:

export interface NavItem {
id?: string; // Unique identifier (e.g. "fleet_monitor")
name: string; // Display label in the sidebar
path: string; // Route path (e.g. "/fleet") or external URL ("https://...")
icon?: string; // Lucide icon name (e.g. "Cpu", "Layers", "Radio", "Terminal")
group?: string; // Target nav group (e.g. "Operations", "Audit & Compliance", "Build")
badge?: string; // Optional badge chip (e.g. "LIVE", "HOT-RELOAD", "FLEET", "CUSTOM")
tier?: 'core' | 'enterprise'; // Visual tier accent (amber accent for 'enterprise')
remoteEntry?: string; // ESM bundle URL for dynamic micro-frontend mounting
required_role?: string[]; // Optional RBAC restrictions (e.g. ["System Admin"])
}

The console’s dynamic icon resolver automatically maps standard icon string keys to Lucide icons:

  • home, filetext, play, activity, barchart, shield, shieldcheck, settings, bookopen, server, bell, heartpulse, layers, cpu, radio, terminal, zap, compass, sparkles
  • Any unknown or unspecified icon gracefully defaults to chevronright.

πŸ› οΈ Step-by-Step Guide: Building a GUI Extension

Section titled β€œπŸ› οΈ Step-by-Step Guide: Building a GUI Extension”

In your Python plugin class (inheriting from BaseEvalPlugin), implement on_register_console_routes:

from eval_runner.plugins import BaseEvalPlugin
from flask import Blueprint, jsonify, send_from_directory
from pathlib import Path
plugin_bp = Blueprint("my_plugin", __name__)
@plugin_bp.route("/api/my-plugin/status")
def plugin_status():
return jsonify({"status": "healthy", "nodes": 42})
@plugin_bp.route("/static/my-plugin/<path:filename>")
def serve_mfe_bundle(filename):
static_dir = Path(__file__).parent / "dist"
return send_from_directory(static_dir, filename)
class MyFleetExtensionPlugin(BaseEvalPlugin):
def on_register_console_routes(self, app, nav_registry):
# 1. Register backend API blueprint
app.register_blueprint(plugin_bp)
# 2. Inject navigation item into sidebar
nav_registry.append(
{
"id": "fleet_management",
"name": "Fleet APM",
"path": "/fleet",
"icon": "Cpu",
"group": "Analyze",
"badge": "LIVE",
"tier": "enterprise",
"remoteEntry": "/static/my-plugin/fleet-bundle.js",
"required_role": ["System Admin", "MultiAgentOps Eng."],
}
)

Create a standalone Vite/Rollup project for your custom tab.

import React, { useState, useEffect } from 'react';
export default function FleetView() {
const [data, setData] = useState<{ status: string; nodes: number } | null>(null);
useEffect(() => {
fetch('/api/my-plugin/status')
.then(res => res.json())
.then(setData)
.catch(console.error);
}, []);
return (
<div className="p-8 space-y-6">
<div className="flex items-center justify-between pb-4 border-b border-slate-800">
<div>
<h1 className="text-xl font-bold text-white tracking-tight">Agent Fleet Telemetry</h1>
<p className="text-xs text-slate-400">Real-time distributed agent cluster telemetry.</p>
</div>
<span className="px-2.5 py-1 text-xs font-bold rounded-lg bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
● {data?.status || 'Connecting...'}
</span>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="p-5 rounded-xl bg-slate-900/60 border border-slate-800 space-y-1">
<span className="text-[10px] font-bold text-slate-400 uppercase tracking-wider">Active Nodes</span>
<p className="text-2xl font-mono font-bold text-indigo-400">{data?.nodes ?? '-'}</p>
</div>
</div>
</div>
);
}

Configure Vite to bundle as a standalone standard ESM module:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: {
lib: {
entry: './src/FleetView.tsx',
formats: ['es'],
fileName: () => 'fleet-bundle.js',
},
rollupOptions: {
// Externalize react/react-dom to share single runtime instance
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
},
},
},
});

  1. Error Boundary Containment: Remote components are automatically wrapped inside RemoteErrorBoundary. If a plugin throws a rendering or network error, only that tab displays a diagnostic cardβ€”the host console and sidebar remain completely operational.
  2. Standard Browser Security: Remote ESM bundles imported via standard import() adhere to strict browser CORS policies and CSP headers.
  3. Graceful Offline Fallback: If /api/nav is unreachable or the backend is offline, the Visual Console falls back cleanly to the built-in core navigation structure.