Summary
cli/commands/ui.py defines a reusable _launch_aiui_app() helper, but the default ui() callback re-implements the same install-check, app-file resolution and subprocess-launch logic inline instead of calling it. The two copies are textually near-identical, so a fix to one (e.g. the install hint or the aiui→python -m praisonaiui.cli fallback) silently misses the other.
Current behaviour
Code citations from src/praisonai/praisonai/cli/commands/ui.py:
cli/commands/ui.py:45-108 — _launch_aiui_app(...): checks importlib.util.find_spec("praisonaiui"), resolves the app file, runs ["aiui", "run", ...], and falls back to [sys.executable, "-m", "praisonaiui.cli", ...].
cli/commands/ui.py:~138-181 — the default ui() callback (when ctx.invoked_subcommand is None) repeats the identical install check, app-file resolution and the same subprocess launch + fallback block.
Why it matters
Maintenance / duplication. The default praisonai ui path and the helper used by the sub-commands (ui agents, ui bot, ui realtime) can drift apart; a bug fixed in one launch path remains in the other.
Category
Duplicate
Capability preserved
praisonai ui and all ui sub-commands continue to work exactly as today, including the praisonaiui install check, custom --app handling, default-app bootstrap, --port/--host/--reload, and the aiui→python -m praisonaiui.cli fallback.
Proposed approach
Merge. Replace the inline block in the ui() callback with a single call to the existing _launch_aiui_app(...), passing the chat defaults. Behaviour is identical; the callback already holds every argument the helper needs.
Resolution sketch
# Before — inline duplicate inside ui() callback
if ctx.invoked_subcommand is not None:
return
# ...install check... resolve app file... subprocess.run(["aiui","run",...]) + fallback...
# After — delegate to the existing helper
if ctx.invoked_subcommand is not None:
return
_launch_aiui_app("ui_chat", "ui_chat", port, host, app_file, reload, "Chat")
(If the callback's bespoke _ensure_default_app() resolution must be retained, fold that one difference into _launch_aiui_app behind a parameter so a single function owns the launch path.)
Layer placement
- Primary layer: wrapper
- Touches core/tools/plugins (optional): none
- 3-way surface (CLI + YAML + Python): CLI only (UI launch command); preserved yes
Severity
Low — small, contained duplication; no runtime cost, purely maintenance.
Validation
Traced: both blocks read in full; install check, command vector and fallback are identical bar minor formatting and the _ensure_default_app() vs bundled-copy detail. Not intentional robustness. No user-facing change.
Keep unchanged
Keep the praisonaiui install check and its pip install "praisonai[ui]" hint, the aiui→module fallback, the per-UI sub-commands (agents, bot, chat, realtime, dashboard), and the bundled default_app.py bootstrap behaviour.
Summary
cli/commands/ui.pydefines a reusable_launch_aiui_app()helper, but the defaultui()callback re-implements the same install-check, app-file resolution and subprocess-launch logic inline instead of calling it. The two copies are textually near-identical, so a fix to one (e.g. the install hint or theaiui→python -m praisonaiui.clifallback) silently misses the other.Current behaviour
Code citations from
src/praisonai/praisonai/cli/commands/ui.py:cli/commands/ui.py:45-108—_launch_aiui_app(...): checksimportlib.util.find_spec("praisonaiui"), resolves the app file, runs["aiui", "run", ...], and falls back to[sys.executable, "-m", "praisonaiui.cli", ...].cli/commands/ui.py:~138-181— the defaultui()callback (whenctx.invoked_subcommand is None) repeats the identical install check, app-file resolution and the same subprocess launch + fallback block.Why it matters
Maintenance / duplication. The default
praisonai uipath and the helper used by the sub-commands (ui agents,ui bot,ui realtime) can drift apart; a bug fixed in one launch path remains in the other.Category
Duplicate
Capability preserved
praisonai uiand alluisub-commands continue to work exactly as today, including the praisonaiui install check, custom--apphandling, default-app bootstrap,--port/--host/--reload, and theaiui→python -m praisonaiui.clifallback.Proposed approach
Merge. Replace the inline block in the
ui()callback with a single call to the existing_launch_aiui_app(...), passing the chat defaults. Behaviour is identical; the callback already holds every argument the helper needs.Resolution sketch
(If the callback's bespoke
_ensure_default_app()resolution must be retained, fold that one difference into_launch_aiui_appbehind a parameter so a single function owns the launch path.)Layer placement
Severity
Low — small, contained duplication; no runtime cost, purely maintenance.
Validation
Traced: both blocks read in full; install check, command vector and fallback are identical bar minor formatting and the
_ensure_default_app()vs bundled-copy detail. Not intentional robustness. No user-facing change.Keep unchanged
Keep the praisonaiui install check and its
pip install "praisonai[ui]"hint, theaiui→module fallback, the per-UI sub-commands (agents,bot,chat,realtime,dashboard), and the bundleddefault_app.pybootstrap behaviour.