mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-05-21 23:24:44 +02:00
fix: remove hardcoded timezone and region names for portability
- Timezone now configurable (default America/Boise) - Router prompt generates region name instructions from config - Any operator can run MeshAI for their region without code changes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2255ca5803
commit
c5f4dac8b6
4 changed files with 25 additions and 6 deletions
|
|
@ -68,6 +68,7 @@ class AlertEngine:
|
||||||
subscription_manager: "SubscriptionManager",
|
subscription_manager: "SubscriptionManager",
|
||||||
config: "MeshIntelligenceConfig",
|
config: "MeshIntelligenceConfig",
|
||||||
db_path: str = "",
|
db_path: str = "",
|
||||||
|
timezone: str = "America/Boise",
|
||||||
):
|
):
|
||||||
self._health = health_engine
|
self._health = health_engine
|
||||||
self._reporter = reporter
|
self._reporter = reporter
|
||||||
|
|
@ -75,6 +76,7 @@ class AlertEngine:
|
||||||
self._rules = config.alert_rules
|
self._rules = config.alert_rules
|
||||||
self._critical_nodes = set(n.upper() for n in (config.critical_nodes or []))
|
self._critical_nodes = set(n.upper() for n in (config.critical_nodes or []))
|
||||||
self._db_path = db_path
|
self._db_path = db_path
|
||||||
|
self._timezone = timezone
|
||||||
|
|
||||||
self._states: dict[str, AlertState] = {}
|
self._states: dict[str, AlertState] = {}
|
||||||
self._prev_infra_online: dict[int, bool] = {}
|
self._prev_infra_online: dict[int, bool] = {}
|
||||||
|
|
@ -266,7 +268,7 @@ class AlertEngine:
|
||||||
if self._rules.solar_not_charging and getattr(node, "has_solar", False) and 0 < bat <= 100:
|
if self._rules.solar_not_charging and getattr(node, "has_solar", False) and 0 < bat <= 100:
|
||||||
try:
|
try:
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
tz = ZoneInfo("America/Boise")
|
tz = ZoneInfo(self._timezone)
|
||||||
hour = datetime.now(tz).hour
|
hour = datetime.now(tz).hour
|
||||||
if 8 <= hour <= 18:
|
if 8 <= hour <= 18:
|
||||||
prev_bat = self._prev_battery.get(node_num)
|
prev_bat = self._prev_battery.get(node_num)
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,9 @@ class DashboardConfig:
|
||||||
class Config:
|
class Config:
|
||||||
"""Main configuration container."""
|
"""Main configuration container."""
|
||||||
|
|
||||||
|
# Global settings
|
||||||
|
timezone: str = "America/Boise" # IANA timezone for local time display
|
||||||
|
|
||||||
bot: BotConfig = field(default_factory=BotConfig)
|
bot: BotConfig = field(default_factory=BotConfig)
|
||||||
connection: ConnectionConfig = field(default_factory=ConnectionConfig)
|
connection: ConnectionConfig = field(default_factory=ConnectionConfig)
|
||||||
response: ResponseConfig = field(default_factory=ResponseConfig)
|
response: ResponseConfig = field(default_factory=ResponseConfig)
|
||||||
|
|
|
||||||
|
|
@ -330,6 +330,7 @@ class MeshAI:
|
||||||
subscription_manager=self.subscription_manager,
|
subscription_manager=self.subscription_manager,
|
||||||
config=mi,
|
config=mi,
|
||||||
db_path="/data/mesh_history.db",
|
db_path="/data/mesh_history.db",
|
||||||
|
timezone=self.config.timezone,
|
||||||
)
|
)
|
||||||
logger.info(f"Alert engine initialized (critical: {mi.critical_nodes}, channel: {mi.alert_channel})")
|
logger.info(f"Alert engine initialized (critical: {mi.critical_nodes}, channel: {mi.alert_channel})")
|
||||||
|
|
||||||
|
|
@ -574,7 +575,7 @@ class MeshAI:
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
tz = ZoneInfo("America/Boise")
|
tz = ZoneInfo(self.config.timezone)
|
||||||
now = datetime.now(tz)
|
now = datetime.now(tz)
|
||||||
current_hhmm = now.strftime("%H%M")
|
current_hhmm = now.strftime("%H%M")
|
||||||
current_day = now.strftime("%a").lower()
|
current_day = now.strftime("%a").lower()
|
||||||
|
|
|
||||||
|
|
@ -110,8 +110,8 @@ coverage gap, and problem node on the mesh. USE THIS DATA in your response.
|
||||||
|
|
||||||
RESPONSE STYLE:
|
RESPONSE STYLE:
|
||||||
- DETAILED, data-driven responses. Reference specific node names, scores, gateway counts.
|
- DETAILED, data-driven responses. Reference specific node names, scores, gateway counts.
|
||||||
- Use LOCAL NAMES from the region descriptions (Magic Valley, Treasure Valley, etc.)
|
- Use LOCAL NAMES from the region descriptions when available.
|
||||||
- ALWAYS use local region names: say "Treasure Valley" not "South Western ID", say "Magic Valley" not "South Central ID". The code names mean nothing to users.
|
{region_name_instructions}
|
||||||
- When listing nodes, be concise: "BT Base c8d5 — via AIDA" not "BT Base c8d5 (c8d5) is connected via AIDA-MeshMonitor in the South Western ID region."
|
- When listing nodes, be concise: "BT Base c8d5 — via AIDA" not "BT Base c8d5 (c8d5) is connected via AIDA-MeshMonitor in the South Western ID region."
|
||||||
- Don't repeat the region on every line when listing multiple nodes in the same region. Say the region once at the top, then just list the nodes.
|
- Don't repeat the region on every line when listing multiple nodes in the same region. Say the region once at the top, then just list the nodes.
|
||||||
- Don't include shortnames in parentheses when you're already giving the full name — it's noise.
|
- Don't include shortnames in parentheses when you're already giving the full name — it's noise.
|
||||||
|
|
@ -721,8 +721,21 @@ class MessageRouter:
|
||||||
if recommendations:
|
if recommendations:
|
||||||
system_prompt += "\n\n" + recommendations
|
system_prompt += "\n\n" + recommendations
|
||||||
|
|
||||||
# Add mesh awareness instructions
|
# Add mesh awareness instructions with dynamic region name mappings
|
||||||
system_prompt += _MESH_AWARENESS_PROMPT
|
region_name_instructions = ""
|
||||||
|
if self.config.mesh_intelligence and self.config.mesh_intelligence.regions:
|
||||||
|
# Build region name mappings for the prompt
|
||||||
|
mappings = []
|
||||||
|
for region in self.config.mesh_intelligence.regions:
|
||||||
|
local = getattr(region, "local_name", "") or ""
|
||||||
|
if local and local != region.name:
|
||||||
|
mappings.append(f'say "{local}" not "{region.name}"')
|
||||||
|
if mappings:
|
||||||
|
region_name_instructions = f"- ALWAYS use local region names: {', '.join(mappings)}. The code names mean nothing to users."
|
||||||
|
|
||||||
|
system_prompt += _MESH_AWARENESS_PROMPT.format(
|
||||||
|
region_name_instructions=region_name_instructions
|
||||||
|
)
|
||||||
|
|
||||||
# Build region geography from config dynamically
|
# Build region geography from config dynamically
|
||||||
if self.config.mesh_intelligence and self.config.mesh_intelligence.regions:
|
if self.config.mesh_intelligence and self.config.mesh_intelligence.regions:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue