Commit graph

42 commits

Author SHA1 Message Date
f69a05dd6d feat(v0.7-fire-tracker-4): fix LLM DM path + daily fire digest + ?status queries
Phase 4 of FIRMS+WFIGS fusion. Foundation: every direct LLM DM
mentioning a fire/weather/quake/avalanche/flood/etc. keyword was
failing silently in prod with UnboundLocalError because router.py
referenced scope_type before assigning it. With that path restored,
two new features land: a twice-daily fire-digest scheduled broadcast
(LLM-rendered) and a ?status <fire_name> on-demand mesh-DM intent.

BUG-FIX ROOT CAUSE (Job Zero):
  router.py:745 ("if should_inject_mesh and scope_type == 'env'") read
  `scope_type` -- a local variable bound only at line 761 inside an
  unrelated `if self.source_manager and self.mesh_reporter` block.
  Python's lexical scoping made scope_type a local of the whole
  generate_llm_response function, so reading it before the assignment
  raised UnboundLocalError on every env-keyword DM. The exception
  propagated to main.py's outer except, no response went out, bot
  appeared dead on fire/weather/quake/avalanche/flood queries.

  Evidence (synthetic in-process trace against the live container's
  config + GoogleBackend):
    "are there any fires near me?" -> UnboundLocalError (pre-fix)
                                  -> real LLM answer (post-fix)
                                     "Yes, there are a few active
                                      fires reported in the region.
                                      Salmon River: 4,200 acres, 78%
                                      contained. Cache Peak: 1,847
                                      acres, 23% contained. ..."
    "what's the weather?"          -> UnboundLocalError (pre-fix)
                                  -> "I do not have current weather
                                      information. I can tell you
                                      about active fires, stream gauge
                                      levels, space weather, or band
                                      conditions if you'd like." (post-fix)
    "hi there"                     -> normal LLM answer in both cases

  Fix: hoist `scope_type, scope_value = self._detect_mesh_scope(query)`
  to right after `should_inject_mesh` is computed; remove the
  now-duplicate detection inside the source_manager block.

  Secondary mitigation: tightened the "do not invent commands" prompt
  with an explicit "if no list appears above, you have NO commands"
  clause. The prior prompt told the LLM "answer based on the command
  list provided below" without always providing one, so the LLM
  hallucinated plausible-sounding !commands (the "use ! commands"
  canned-looking response Matt was seeing on non-env queries).

PHASE 4 FEATURES:

1. Fire-digest scheduler (meshai/notifications/scheduled/fire_digest.py).
   Modeled after BandConditionsScheduler. Runs in the pipeline's
   start_pipeline coroutine alongside band_conditions + reminders.
   On each slot (default 06:00 + 18:00 America/Boise):
     - Queries active fires (tombstoned_at IS NULL) + last 24h passes.
     - Builds a prompt asking for a single mesh-wire summary <= 200
       chars.
     - Calls the LLM (Google/Anthropic/OpenAI per config).
     - Falls back to a terse "Fires today (N): Cache Peak 1847 ac;
       Twin Peaks 320 ac; +N more" line when the LLM is unavailable.
     - Dispatches via dispatcher.dispatch_scheduled_broadcast (same
       path band_conditions uses).
   Idempotency: v16.sql adds fire_digest_broadcasts(slot_epoch PK,
   sent_at, summary, source). INSERT OR IGNORE pattern blocks the same
   slot firing twice (matters when container restarts mid-day).

2. ?status <fire_name> on-demand intent (router.py).
   Before falling through to the LLM, route() now checks for a leading
   "?status" / "status:" sigil or natural-language triggers like
   "how is X fire?". On match:
     - _lookup_fire_fuzzy walks fires by exact -> startswith ->
       contains -> word-overlap (skipping a trailing " fire" word so
       "cache peak fire" matches "Cache Peak"). Active fires rank
       above tombstoned ones.
     - _build_fire_status_context composes a small context block
       (name, acres, containment, county/state, last 3 passes with
       drift).
     - The query is REWRITTEN into an LLM prompt with that context
       inlined; the rest of the normal LLM path (chunking, history,
       summary persistence) runs unchanged.
   Live verification: "?status Cache Peak" -> "The Cache Peak fire is
   1,847 acres and 23% contained. It's located in Probe / ID.";
   "?status Salmon" -> word-overlap matches "Salmon River" ->
   "The Salmon River fire is 4,200 acres and 78% contained, located
   in Probe / ID."

3. adapter_config rows (GUI-editable per CONFIG-vs-CODE rule):
     fires.digest_enabled         = true   (master toggle)
     fires.digest_schedule        = ["06:00", "18:00"]
     fires.digest_timezone        = "America/Boise"
     fires.digest_max_chars       = 200

Schema (v16.sql):
- fire_digest_broadcasts(slot_epoch INTEGER PK, sent_at, summary,
  source) with source in {'llm', 'fallback_terse', 'skipped_no_fires'}.
- Index on sent_at for ops queries.

Tests (tests/test_fire_tracker_phase4.py, 10 cases all green):
- Regression guard: scope_type appears as an assignment BEFORE the
  env_reporter check (prevents the UnboundLocalError from coming back).
- adapter_config seeds all 4 digest keys with expected defaults.
- render_digest returns ('', 'no_fires') when no active fires.
- render_digest falls back to terse line when LLM is None; wire fits cap.
- render_digest with a stub LLM returns ('<llm text>', 'llm').
- _lookup_fire_fuzzy: exact, "X fire" trim, word-overlap, no-match.
- _maybe_rewrite_status_query: builds context-bearing prompt; returns
  None on non-status queries.

Combined suite: 60 passed in 3.81s across phase1+phase2+phase3+phase4
+or-arch+include-roundtrip.

Live verification on CT108 after rebuild:
- v16 migration applied (schema_meta=16, no Traceback in 3 min).
- FireDigestScheduler started: enabled=True schedule=['06:00','18:00']
  tz=America/Boise.
- LLM DM probe (real Gemini) returns real answers on env queries
  (Bug A fixed end-to-end).
- ?status Cache Peak + ?status Salmon return fire-specific summaries.
- render_digest with real LLM returns source=llm + non-empty wire.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-06 07:13:17 +00:00
eb84f27941 feat(v0.6-5): env_reporter + router wiring + include_in_llm_context per-adapter toggle -- LLM gains read access to every adapter table via the existing mesh_reporter pre-rendered prompt-injection pattern
Closes audit doc Section C. The LLM can now answer "any fires near me?",
"how are band conditions?", "why didnt I hear about that quake?"
without any tool-use / MCP / SQL pass-through -- via the same prompt-
injection contract mesh_reporter uses.

env_reporter (meshai/notifications/env_reporter.py):
  - EnvReporter class with build_env_summary / build_fires_detail /
    build_alerts_detail / build_quakes_detail / build_traffic_detail /
    build_gauges_detail / build_swpc_detail / build_drop_audit / build_all
  - Reads from fires + firms_pixels + nws_alerts + quake_events +
    traffic_events + gauge_readings + swpc_events +
    band_conditions_broadcasts + event_log + dispatcher_state
  - Each build_*_detail() checks adapter_meta.include_in_llm_context for
    the relevant adapter(s) before reading; turning the meta off via
    /api/adapter-meta drops that adapters block out of the LLM prompt
  - Defensive: missing meta row defaults to True (include); DB-unavailable
    returns empty string; per-block 3000-char cap
  - Module-level env_reporter singleton for the router

Router wiring (meshai/router.py):
  - Extended _MESH_KEYWORDS dispatcher with _ENV_KEYWORDS_TO_SUBTYPE
    mapping (fire/quake/flood/warning/storm/road/swpc/etc -> coarse
    subtype). "flood" intentionally precedes "warning" so
    "river flood warning" routes to gauges, not alerts
  - _detect_env_subtype helper at module level (also test-importable)
  - _is_mesh_question now also fires for env keywords -- single detector
    per Matt s spec
  - _detect_mesh_scope returns ("env", subtype) when an env keyword
    matches, taking precedence over the node/region branches
  - generate_llm_response: when scope_type == "env", appends
    env_reporter.build_all() + env_reporter.build_drop_audit(hours=1)
    to the system prompt. Wrapped in try/except so a reporter fault
    never blocks the LLM call

Tests:
  - tests/test_env_reporter.py (18 cases): meta gate, every build_*
    method shape, build_all combines blocks, all-off produces empty
  - tests/test_router_env_scope.py (18 cases): parametrized subtype
    detection across fires/quakes/alerts/gauges/traffic/swpc, word-
    boundary check (firearm != fire), synthetic-probe end-to-end
    (seed fires table -> env_reporter emits a fires block with the
    seeded row)

Test count: 761 -> 797 (+36 new, 0 regressions).
2026-06-05 20:11:40 +00:00
d6bc6b2b89 build: normalize all line endings to LF
One-time renormalization pass under the .gitattributes added in the
previous commit. Every tracked text file now uses LF. No semantic
changes — verified via git diff --cached --ignore-all-space showing
zero real differences. Future diffs will only show real content
changes.

This commit will appear huge in git log --stat but represents zero
behavior change. Use git log --follow --ignore-all-space or
git blame -w when archaeologically tracing through this commit.
2026-05-14 22:43:06 +00:00
f8bf7e5057 feat(env): USGS stream gauges, TomTom traffic, 511 road conditions 2026-05-12 22:22:57 +00:00
c5f4dac8b6 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>
2026-05-12 15:39:54 -06:00
2255ca5803 feat(env): NIFC fire perimeters + avalanche advisories
- WFIGS ArcGIS fire perimeter polling with proximity alerts
- Avalanche.org advisory polling (seasonal, SNFAC)
- !fire and !avy commands
- Distance-based severity for fires near mesh infrastructure
- Dashboard environment page integration
- Alert engine fires on fires within 50km of mesh area

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-12 15:22:07 -06:00
549ae4bdfb feat(env): NWS weather alerts, NOAA space weather, tropospheric ducting
- Environmental feed system with tick-based adapters
- NWS Active Alerts: polls api.weather.gov, zone-based filtering
- NOAA SWPC: Kp, SFI, R/S/G scales, band assessment, alert detection
- Tropospheric ducting: Open-Meteo GFS refractivity profile, duct classification
- !alerts command for active weather warnings
- !solar / !hf commands for RF propagation (HF + UHF ducting)
- Alert engine integration: severe weather, R3+ blackout, ducting events
- LLM context injection for weather/propagation queries
- Dashboard RF Propagation card with HF + UHF ducting display
- EnvironmentalConfig with per-feed toggles in config.yaml
2026-05-12 17:21:43 +00:00
a80ed6cc7c fix: Dedup packets across sources, translate numeric port numbers to names
Packet dedup: track seen packet IDs across all sources. Same packet from
Meshview + MeshMonitor counted once, not twice. Fixes inflated counts.
Portnum: numeric values (3, 4, 71) mapped to names (Position, NodeInfo, Neighbors).
LLM prompt: guidance on normal vs abnormal packet rates per type.
2026-05-07 03:08:08 +00:00
b7237469e4 feat: ACK-based message delivery, markdown stripping, prompt fixes
- Connector: send_and_wait_ack() waits for ACK before returning
- Responder: ACK waiting for DMs with retry, delay-based for broadcasts
- Chunker: strip_markdown() removes bold/italic/headers/lists from LLM output
- Router: applies strip_markdown before chunking
- Prompt: stronger no-markdown rules, no manual continuation prompt, gateway explanation
- Config: delays 3-5s (was 2.2-3), max_length 200 (was 150), max_messages 3 (was 2)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-06 04:17:44 +00:00
7670b7c0b9 feat: !health returns list for separate LoRa messages, partial name distance matching
- build_lora_compact returns list[str] instead of str
- Each line is a separate LoRa message (no chunking needed)
- main.py handles list responses from commands
- _try_compute_distance supports partial names (TVM Pearl → TVM Pearl Relay)
- Ambiguous names detected (TVM → asks which node)
- Max message size: 54 bytes (well under 228 byte limit)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-06 00:11:57 +00:00
5839fdeb18 feat: !health colored dots no numbers, distance from AIDA, router distance detection
!health: 🔵 perfect, 🟢 healthy, 🟠 warning, 🔴 critical — no /100 scores.
Each line ends with period for separate LoRa messages.
Uses long_name to avoid emoji shortnames (📡 → TVM Tablerock Relay).
Distance from AIDA shown on every infra node in Tier 1.
Router detects how far questions and injects computed distance.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 23:47:48 +00:00
1662d80f02 feat: !health personality with emojis, skip empty regions, AIDA physical node identity
- Replace build_lora_compact with personality version using emojis
- Add _region_lora_compact helper for region-specific display
- Skip empty regions in 3 loops (build_tier1_summary, utilization, list_regions_compact)
- Update AIDA identity: she IS a physical node (!27780c47 AIDA-N2)
- AIDA now knows she has real GPS coordinates and radio connections

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 22:35:00 +00:00
79ff756a38 fix: Remove hard-coded token limits on LLM responses
- Add max_response_tokens config (8192) to LLMConfig
- Use config value in router.py instead of hardcoded 500
- Update base.py default from 300 to 8192
- Lets LLM generate full responses; chunker handles size limits

Fixes truncated responses like Here are three nodes in the freq

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 22:06:50 +00:00
6ac21d5f0e fix: LLM prompt — use local names, concise node listings, no redundant regions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 21:09:21 +00:00
aef78996a9 feat: Named single-gw nodes, infra-only monitoring, commands overhaul
Coverage:
- Single-gateway infra nodes named as critical risks per region
- Client single-gw nodes counted but not individually named
- Mesh-wide single-gw infra summary

Monitoring rules by node type:
- Infrastructure: full detail - battery, offline, coverage, neighbors, hardware
- Clients causing problems: named - high util, top senders
- Clients otherwise: counted per region, not individually tracked
- POWER breakdown now infra-only

Commands:
- Removed hardcoded command list from config.py system_prompt
- Dynamic command list in router.py from dispatcher (only enabled commands)
- MeshMonitor commands no longer listed as MeshAI commands
- !help overhaul: grouped by category, per-command detailed help
- LLM explicitly told to only mention listed commands

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 15:33:14 +00:00
56536f55c8 feat: Rich Tier 1 data - named infra per region, problem nodes, expanded recommendations
Tier 1 now includes:
- Every infrastructure node BY NAME per region with status/battery/util/gateways
- Problem nodes section: offline infra, critical battery, high util, coverage risks
- Per-region coverage with gateway counts and single-gw counts
- Environmental data per region
- All 5 pillars with weights
- Expanded recommendations with specifics (10 max, up from 5)
- LLM prompt simplified: data speaks for itself

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 14:32:43 +00:00
8d1a48ea08 fix: Short sentence instruction + chunker splits instead of truncating
- Added CRITICAL instruction to keep sentences under 150 chars
- Chunker now splits long sentences at word boundaries instead of truncating
- No words lost when splitting

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 07:22:52 +00:00
51969050da fix: Replace deleted REGION_CONTEXT with config method, replace hardcoded city map with config aliases
- Line 763: REGION_CONTEXT.get() → self._region_context() (same method used elsewhere)
- Deleted _CITY_TO_REGION hardcoded dict
- Scope detection now uses config aliases/cities from RegionAnchor
- Fixed Sun Valley/Ketchum geography (was Central ID, should be South Central ID)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 07:11:08 +00:00
de400068dd feat(mesh): config-driven regions with stale purge and coverage fix
- Extended RegionAnchor with local_name, description, aliases, cities
- Moved region geographic context from hardcoded Python to config.yaml
- Added 7-day stale node purge in _do_refresh (556 → 267 nodes)
- Fixed coverage lookup: str(node_num) → node_num (int key)
- Added bidirectional neighbor lookup for better region assignment
- Dynamic geography building in router from config
- Reporter reads region context from config instead of hardcoded dict

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 06:33:38 +00:00
abcf2d88e2 feat: Geographic context — local names, accurate Idaho/Utah geography, no Unknown gaps
- Magic Valley, Treasure Valley, Panhandle, Dixie — local names in all output
- Southern Idaho correctly maps to Magic Valley, not lumped with Boise/IF
- Unlocated nodes excluded from coverage gap recommendations
- LLM response rules override brevity for mesh questions
- Node detail shows region with local context

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 06:08:58 +00:00
45630f2cc6 fix: Override LLM brevity for mesh questions — give detailed data responses
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-05 05:29:09 +00:00
df197cc395 fix: Scope detection, follow-up context, utilization calculation, duplicate disambiguation
- router.py: Fixed region scope detection to match longest region name first
- router.py: Added region abbreviations (SCID, SWID, etc.) for quick matching
- router.py: Added city name mapping (Boise -> South Western ID, etc.)
- router.py: Fixed node longname matching (case-insensitive substring)
- router.py: Added follow-up message context tracking (_user_mesh_context)
- router.py: Added more mesh keywords (noisy, traffic, packets, etc.)
- mesh_reporter.py: Added disambiguation for duplicate shortnames in region detail
- mesh_health.py: Added util_data_available flag to track packet data presence
- mesh_health.py: Passes has_packet_data through score computation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-04 20:56:54 +00:00
44c74ccfd4 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>
2026-05-04 19:19:42 +00:00
a7c409e406 feat: Add Phase 2 - Geographic Hierarchy and Health Scoring
Implements mesh intelligence with geo clustering, four-pillar health scoring,
and auto-naming regions from GPS data.

New: geo.py, mesh_health.py
Modified: config.py, main.py, router.py, configurator.py, config.example.yaml

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-04 16:43:12 +00:00
b945558ba3 feat: Phase 1 — multi-source data aggregation from Meshview and MeshMonitor APIs
- Add MeshviewSource class for fetching nodes, edges, stats from Meshview API
- Add MeshMonitorDataSource class for fetching nodes, channels, telemetry,
  traceroutes, network stats, topology, packets, solar from MeshMonitor API
- Add MeshSourceManager for managing multiple sources with aggregation
- Add MeshSourceConfig dataclass and mesh_sources list to config
- Integrate source_manager into main.py with periodic refresh
- Add source_manager parameter to MessageRouter (for future Phase 3)
- Add Mesh Sources TUI menu with add/edit/remove/test functionality
- Update config.example.yaml with mesh_sources section

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-04 16:26:58 +00:00
root
0e36869a5f feat: Hybrid RAG knowledge base, sentence-aware chunking, MeshMonitor HTTP sync
Knowledge Base:
- Hybrid FTS5 + vector search using sqlite-vec and bge-small-en-v1.5
- Reciprocal Rank Fusion for result merging
- Domain-aware query construction handles typos
- Configurable weights for keyword vs semantic matching

Message Chunking:
- Sentence-aware splitting respects message boundaries
- Continuation prompts for long responses
- Natural follow-up detection (yes, ok, continue, more, etc.)
- Per-user continuation state management

MeshMonitor Integration:
- HTTP API trigger sync (replaces file-based triggers.json)
- Dynamic refresh interval
- Trigger injection into LLM prompt

Other:
- Updated system prompt for better response length control
- Simplified responder to handle message lists
- Updated README with new features and architecture diagram
- Cleaned up config.example.yaml

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-04 07:44:12 +00:00
root
5f66b69c9c feat: Dynamic identity system prompt from bot config
- Build system prompt dynamically using bot.name and bot.owner from config
- Reorder prompt: identity -> static prompt -> MeshMonitor (conditional) -> mesh context
- MeshMonitor description only injected when meshmonitor.enabled is true
- Update default system_prompt to static parts only (commands, architecture, rules)
- Fix meshmonitor.py to handle trigger arrays (not just strings)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-03 05:45:58 +00:00
root
f6540e893d feat: Dynamic MeshMonitor trigger sync — auto-ignore MeshMonitor commands
Add MeshMonitorSync class that reads trigger patterns from a JSON file
and compiles them to regex. The router checks incoming messages against
these patterns and ignores messages that MeshMonitor will handle.

- New meshai/meshmonitor.py: Pattern compilation and file watching
- MeshMonitorConfig dataclass with enabled, triggers_file, inject_into_prompt
- Router integration: ignore matching messages, inject commands into prompt
- Main loop refresh: watch triggers file for changes without restart

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-03 03:20:23 +00:00
Ubuntu
1172b9b67f Add API timeout to all backends + mesh-aware system prompt
All three LLM backends (Google, OpenAI, Anthropic) now wrap API calls
in asyncio.wait_for() using config.timeout (default 30s). Previously
Gemini could hang indefinitely with grounding+AFC enabled.

Router catches TimeoutError with user-friendly "request timed out" message.
Empty context buffer now injects "[No recent mesh traffic observed yet.]"
so the LLM knows the capability exists even when buffer is empty.
Default system prompt updated to mention mesh awareness.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 07:27:39 +00:00
Ubuntu
63a2caad37 Add passive mesh context awareness — observe channel traffic, inject into LLM prompts
New context.py module: ring buffer (50K hard cap, ~25MB ceiling) passively
records all channel broadcasts. Observations are formatted with relative
timestamps and injected into the system prompt when generating LLM responses.
Only public channel traffic is observed; DMs to the bot are excluded (already
in per-user history). Bot's own node ID is auto-added to ignore list.

Config: context.enabled, observe_channels, ignore_nodes, max_age, max_context_items
TUI: new Context settings submenu (menu item 7)
Hourly prune removes expired observations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 22:02:42 +00:00
Ubuntu
1e033316fb Remove dead channel/mention code — DM-only bot cleanup
MeshAI is now DM-only. Removed all unreachable channel response
paths, @mention detection, ChannelsConfig, and channel TUI menu.
Fixed restart mechanism with integrated watcher and SIGKILL fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 08:43:25 +00:00
Ubuntu
6a67fe1940 Disable rolling summary — send full conversation history to Gemini
Mesh messages are short enough that summarization is unnecessary
with Gemini Flash's 1M token context window.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 07:11:24 +00:00
Ubuntu
69b749930c Revert date injection from system prompt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 06:46:42 +00:00
Ubuntu
825d93e52d Inject current date into system prompt so LLM knows today's date
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 06:28:24 +00:00
Ubuntu
10bc94b273 Remove dead modules: safety, rate_limiter, personality, webhook, web_status, announcements, log_setup
These modules were wired up but never actually functional in the
running bot. Strips all imports and usage from main.py and router.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 00:23:46 +00:00
Ubuntu
247074afd1 Add advBBS protocol message filter to router
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:28:20 +00:00
Ubuntu
ab7e52b9fb Fix healthcheck to verify PID and add DM-only conversational mode
- 6a: Change healthcheck in Dockerfile and docker-compose.yml to verify
  the PID file exists and the process is alive (kill -0) instead of
  testing SQLite connectivity, which only proves the DB file exists
- 6b: In DMs, skip !commands so MeshMonitor or other bots handle them.
  MeshAI only responds conversationally in DMs (no bang commands)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:18:27 +00:00
Ubuntu
32cd2b3427 Add HTML escaping to status page and prompt injection guard to router
- 5a: Import html.escape and apply to all values rendered into the
  HTML template in _serve_status_page() — uptime, counts, status text,
  node counts, errors. Prevents XSS via crafted node names or errors.
- 5b: Add basic prompt injection detection to _clean_query() with
  configurable safety.prompt_injection_guard (default: on). Detects
  patterns like "ignore all previous", "you are now", "system prompt:",
  etc. Truncates query before the injection phrase and logs a warning.
  Not foolproof but better than nothing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:17:46 +00:00
Ubuntu
a71f92a77a Wire up all unused modules into main application lifecycle
- 2a: SafetyFilter + UserFilter — check user access before processing,
  filter LLM responses through SafetyFilter before sending
- 2b: RateLimiter — check rate limits before processing, record
  messages after successful response delivery
- 2c: PersonalityManager — pass to MessageRouter, used for system
  prompt generation instead of raw config.llm.system_prompt
- 2d: WebhookClient — start/stop in lifecycle, fire events on
  message_received, response_sent, error, startup, shutdown
- 2e: WebStatusServer — start/stop in lifecycle, record messages,
  responses, and errors in StatusData
- 2f: AnnouncementScheduler — start/stop in lifecycle, uses
  connector.send_message as callback
- 2g: FallbackBackend — wrap primary backend when config.llm.fallback
  is configured, otherwise use primary directly
- 2h: CommandDispatcher — pass prefix, disabled_commands, and
  custom_commands from config to create_dispatcher()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:16:25 +00:00
173af91d45 Increase max_tokens to 500 for web search/RAG responses 2025-12-15 14:34:21 -07:00
152f46282f Add toggle to enable/disable system prompt 2025-12-15 13:56:10 -07:00
fd3f995ebb Initial commit: MeshAI - LLM-powered Meshtastic assistant
Features:
- Multi-backend LLM support (OpenAI, Anthropic, Google)
- Rolling summary memory for token optimization (~70-80% reduction)
- Per-user conversation history with SQLite persistence
- Bang commands (!help, !ping, !reset, !status, !weather)
- Meshtastic integration via serial or TCP
- Message chunking for mesh network constraints (150 char limit)
- Rate limiting to prevent network congestion
- Rich TUI configurator
- Docker support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 11:53:46 -07:00