feat: Phase 3 - LLM mesh health integration, recommendations, and health commands

New files:
- mesh_reporter.py: MeshReporter class for prompt injection
  - build_tier1_summary(): ~500-800 token mesh health summary
  - build_region_detail(): Detailed region breakdown
  - build_node_detail(): Single node info with recommendations
  - build_recommendations(): Optimization suggestions
  - build_lora_compact(): Short format for LoRa messages
  - list_regions_compact(): Region list with scores

- commands/health.py: !health and !region commands
  - !health: Quick mesh summary (no LLM)
  - !region [name]: Region info or list all regions

Modified files:
- router.py: Mesh question detection and prompt injection
  - _is_mesh_question(): Keyword/phrase matching
  - _detect_mesh_scope(): Node/region/mesh scope detection
  - Inject Tier 1/2 data for mesh questions
  - Add mesh awareness instructions to LLM

- main.py: Create MeshReporter, pass to dispatcher/router

- commands/dispatcher.py: Register health/region commands

- mesh_health.py: Fix role type (int -> str)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
K7ZVX 2026-05-04 19:19:42 +00:00
commit 44c74ccfd4
6 changed files with 1546 additions and 784 deletions

View file

@ -157,6 +157,7 @@ def create_dispatcher(
prefix: str = "!",
disabled_commands: Optional[list[str]] = None,
custom_commands: Optional[dict] = None,
mesh_reporter=None,
) -> CommandDispatcher:
"""Create and populate command dispatcher with default commands.
@ -164,6 +165,7 @@ def create_dispatcher(
prefix: Command prefix (default: "!")
disabled_commands: List of command names to disable
custom_commands: Dict of name -> response for custom commands
mesh_reporter: MeshReporter instance for health commands
Returns:
Configured CommandDispatcher
@ -174,6 +176,7 @@ def create_dispatcher(
from .reset import ResetCommand
from .status import StatusCommand
from .weather import WeatherCommand
from .health import HealthCommand, RegionCommand
dispatcher = CommandDispatcher(prefix=prefix, disabled_commands=disabled_commands)
@ -185,6 +188,23 @@ def create_dispatcher(
dispatcher.register(StatusCommand())
dispatcher.register(WeatherCommand())
# Register mesh health commands
health_cmd = HealthCommand(mesh_reporter)
dispatcher.register(health_cmd)
# Register aliases for health command
for alias in getattr(health_cmd, 'aliases', []):
alias_handler = HealthCommand(mesh_reporter)
alias_handler.name = alias
dispatcher.register(alias_handler)
region_cmd = RegionCommand(mesh_reporter)
dispatcher.register(region_cmd)
# Register aliases for region command
for alias in getattr(region_cmd, 'aliases', []):
alias_handler = RegionCommand(mesh_reporter)
alias_handler.name = alias
dispatcher.register(alias_handler)
# Register custom commands
if custom_commands:
for name, response in custom_commands.items():

58
meshai/commands/health.py Normal file
View file

@ -0,0 +1,58 @@
"""Health and region commands for mesh status."""
from .base import CommandContext, CommandHandler
class HealthCommand(CommandHandler):
"""Quick mesh health summary."""
name = "health"
description = "Show mesh health summary"
usage = "!health"
aliases = ["mesh", "status"]
def __init__(self, mesh_reporter=None):
"""Initialize with optional mesh reporter.
Args:
mesh_reporter: MeshReporter instance for health data
"""
self._mesh_reporter = mesh_reporter
async def execute(self, args: str, context: CommandContext) -> str:
"""Return compact mesh health summary."""
if not self._mesh_reporter:
return "Mesh health not available."
return self._mesh_reporter.build_lora_compact("mesh")
class RegionCommand(CommandHandler):
"""Region health information."""
name = "region"
description = "Show region health info"
usage = "!region [name]"
aliases = ["reg"]
def __init__(self, mesh_reporter=None):
"""Initialize with optional mesh reporter.
Args:
mesh_reporter: MeshReporter instance for health data
"""
self._mesh_reporter = mesh_reporter
async def execute(self, args: str, context: CommandContext) -> str:
"""Return region health info."""
if not self._mesh_reporter:
return "Mesh health not available."
args = args.strip()
if not args:
# List all regions
return self._mesh_reporter.list_regions_compact()
# Get specific region detail (compact for LoRa)
return self._mesh_reporter.build_lora_compact("region", args)