Compare commits
2 Commits
136f15d35f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 18eb68f03d | |||
| e518c21166 |
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) [year] [fullname]
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -3,7 +3,26 @@
|
|||||||
Bridges a [MeshCore](https://meshcore.io) companion radio to any OpenAI-compatible LLM endpoint
|
Bridges a [MeshCore](https://meshcore.io) companion radio to any OpenAI-compatible LLM endpoint
|
||||||
(e.g. `llama-server`, vLLM, Ollama). Listens for direct messages on the device, runs each
|
(e.g. `llama-server`, vLLM, Ollama). Listens for direct messages on the device, runs each
|
||||||
conversation through the LLM with full per-sender history stored in SQLite, and replies back
|
conversation through the LLM with full per-sender history stored in SQLite, and replies back
|
||||||
over the mesh — trimmed to the MeshCore packet payload limit.
|
over the mesh — split into UTF-8-safe chunks within the MeshCore packet payload limit.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **LLM-backed DMs** with persistent per-sender chat history; replies are split across multiple
|
||||||
|
packets when needed.
|
||||||
|
- **Reliable chunked delivery** via meshcore's `send_msg_with_retry`: each chunk waits for the
|
||||||
|
recipient ACK (correlated by `expected_ack` code) before the next chunk goes out, with a
|
||||||
|
configurable retry budget.
|
||||||
|
- **Contact persistence**: contacts are mirrored from the device into SQLite at connect and
|
||||||
|
kept in sync via `NEW_CONTACT` events, so resolution is local and survives a flaky or
|
||||||
|
cleared device contact list.
|
||||||
|
- **Inbound deduplication**: consecutive identical DMs from the same sender within a short
|
||||||
|
window are dropped (handles radio retransmits and impatient peers).
|
||||||
|
- **Slash commands**: `/help`, `/clear` (reset LLM context), `/thinking` (toggle thinking-mode
|
||||||
|
prompts).
|
||||||
|
- **LLM tool calling** (when the model supports it): a built-in weather tool (Open-Meteo, no
|
||||||
|
key); web search and URL fetch via [Tavily](https://tavily.com) when an API key is set.
|
||||||
|
- **Web UI** (read-only by default): live status, conversations, contact list, manual advert
|
||||||
|
button. Listens on `127.0.0.1:8080` by default.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
@@ -20,13 +39,27 @@ python -m lorabot
|
|||||||
Config file path defaults to `./config.toml` and can be overridden with `LORABOT_CONFIG`.
|
Config file path defaults to `./config.toml` and can be overridden with `LORABOT_CONFIG`.
|
||||||
Any field can be overridden via env vars, e.g. `LORABOT_LLM__API_KEY=sk-...`.
|
Any field can be overridden via env vars, e.g. `LORABOT_LLM__API_KEY=sk-...`.
|
||||||
|
|
||||||
|
The web UI is at <http://localhost:8080> while the bot is running.
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
- `src/lorabot/bot.py` — connect, subscribe to `CONTACT_MSG_RECV`, dispatch each DM.
|
- [src/lorabot/bot.py](src/lorabot/bot.py) — connect, wire collaborators, subscribe to
|
||||||
- `src/lorabot/db.py` — SQLite schema and per-conversation repo functions.
|
`CONTACT_MSG_RECV` and `NEW_CONTACT`.
|
||||||
- `src/lorabot/llm.py` — `AsyncOpenAI` wrapper.
|
- [src/lorabot/transport.py](src/lorabot/transport.py) — `MeshTransport`: contact resolution
|
||||||
- `src/lorabot/messages.py` — UTF-8-safe byte-length trimming.
|
(DB-backed) and reliable chunked sending with per-contact serialization.
|
||||||
- `src/lorabot/config.py` — TOML + env-var settings (pydantic-settings).
|
- [src/lorabot/handler.py](src/lorabot/handler.py) — DM pipeline: dedup → command dispatch
|
||||||
|
or LLM call → send → persist.
|
||||||
|
- [src/lorabot/commands.py](src/lorabot/commands.py) — slash-command parser and registry.
|
||||||
|
- [src/lorabot/llm.py](src/lorabot/llm.py) — `AsyncOpenAI` wrapper with tool-call loop.
|
||||||
|
- [src/lorabot/tools/](src/lorabot/tools/) — pluggable LLM tools (weather, web search,
|
||||||
|
fetch URL).
|
||||||
|
- [src/lorabot/db.py](src/lorabot/db.py) — SQLite schema and repo functions for
|
||||||
|
conversations, messages, contacts.
|
||||||
|
- [src/lorabot/messages.py](src/lorabot/messages.py) — UTF-8-safe byte-length splitting.
|
||||||
|
- [src/lorabot/web.py](src/lorabot/web.py) — aiohttp web UI (status, conversations,
|
||||||
|
contacts, SSE).
|
||||||
|
- [src/lorabot/config.py](src/lorabot/config.py) — TOML + env-var settings
|
||||||
|
(pydantic-settings).
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -18,7 +18,7 @@ base_url = "http://localhost:8080/v1"
|
|||||||
api_key = "not-needed"
|
api_key = "not-needed"
|
||||||
model = "gemma-4-E4B"
|
model = "gemma-4-E4B"
|
||||||
system_prompt = "You are a concise assistant on a low-bandwidth mesh radio. Replies must be brief — under 180 bytes."
|
system_prompt = "You are a concise assistant on a low-bandwidth mesh radio. Replies must be brief — under 180 bytes."
|
||||||
temperature = 0.7
|
temperature = 1.0
|
||||||
request_timeout_seconds = 60
|
request_timeout_seconds = 60
|
||||||
|
|
||||||
[storage]
|
[storage]
|
||||||
@@ -39,7 +39,7 @@ send_retries = 1
|
|||||||
[web]
|
[web]
|
||||||
# Built-in read-only web UI: stored conversations + live status.
|
# Built-in read-only web UI: stored conversations + live status.
|
||||||
enabled = true
|
enabled = true
|
||||||
host = "0.0.0.0"
|
host = "127.0.0.1"
|
||||||
port = 8080
|
port = 8080
|
||||||
|
|
||||||
[advertise]
|
[advertise]
|
||||||
|
|||||||
Reference in New Issue
Block a user