Mimir: Web Search feature & impoving the CPU budget usage (#202)
* game-launcher: add launcher toggles, keyboard nav, auto-refresh * game-launcher: update README with runner toggle settings * fix: remove duplicate translation keys after upstream merge * fix(game-launcher): add ~/.local/share/Steam to steam roots for NixOS support * chore(game-launcher): bump version to 1.1.1 * feat(mimir): AI companion plugin with LLM chat panel Mimir is an AI companion for Noctalia — an LLM-powered chat interface with model selection, conversation history, and a bar widget. - Service-based architecture: service (brain) handles HTTP API calls, panel (chat) renders the UI, widget (status) shows bar indicator - OpenAI-compatible chat completions with dynamic model discovery - Floating side panel (center_right) with message history and simple markdown rendering (code blocks) - Model selection dropdown populated from API /models endpoint - Bar widget with brain icon to toggle chat panel - i18n via translations/en.json - Auto-detection of OpenCode Go API key from auth.json - Full-height floating panel layout matching oficial notes plugin .gitignore: add editor files, OS junk, auth secrets, compiled binary * mimir: rename author leo->Alexander, strip scrollBottom, update README with plans - plugin.toml: author leo -> Alexander, widget panel-toggle id -> alexander/mimir - widget.luau: togglePanel id -> alexander/mimir:chat - panel.luau: remove scrollBottom/dynamic key (unstable), remove setUpdateInterval - README.md: add future plans (commands, file search, etc.) - thumbnail.webp: removed (replaced by mimir-thumbnail.webp) * added thumbnail * added thumbnail.webp * mimir: bump 0.1.0 → 0.3.0, update README with tools + copy + editable approval * mimir: copy-to-clipboard toggle, editable command approval, unicode bold rendering * mimir: fix review findings — conditional auth, dedupe user msg, apply max_history * mimir: fix manifest validation — use select setting type, add README Plugin section * mimir: multi-tool queue support, plain approve/deny, better tool-use prompt * mimir: add full markdown rendering — headings, lists, quotes, hr, bold/italic * mimir: bump 0.3.2 — fix Lua pattern quantifiers, multi-tool queue, markdown rendering * mimir: fix security review findings * mimir: clarify selectable message text * mimir: add command history display * mimir: add web search * mimir: align README with template * mimir: fix CPU budget error with many messages --------- Co-authored-by: Ahmed5Emad <ahmed5emad@users.noreply.github.com>
This commit is contained in:
+23
-50
@@ -11,65 +11,29 @@ An AI companion for Noctalia that brings LLM-powered chat and terminal command e
|
||||
|
||||
## Requirements
|
||||
|
||||
- A [Noctalia](https://noctalia.app) build supporting `plugin_api >= 16`.
|
||||
- An **OpenAI-compatible API endpoint** with `/chat/completions` and `/models` endpoints.
|
||||
- An API key (for hosted providers) or leave empty for local servers (e.g. Ollama).
|
||||
- A [Noctalia](https://noctalia.app) build supporting `plugin_api >= 16`.
|
||||
- `curl` and `python3` on `PATH` for the web search and page-fetch features.
|
||||
- An internet connection for the no-setup web search feature.
|
||||
|
||||
If you use [OpenCode Go](https://opencode.ai/go) with the default OpenCode endpoint, Mimir auto-detects your API key from `~/.local/share/opencode/auth.json` — no manual setup needed.
|
||||
|
||||
## Features
|
||||
|
||||
- **Chat** — Conversational AI with formatted responses, markdown rendering (code blocks in shaded boxes), and selectable text for every message.
|
||||
- **Command History** — Optionally shows executed commands in the chat, including commands run automatically in `allow` mode.
|
||||
- **Model Browser** — Fetches available models from your API endpoint. Switch models on the fly from the panel header.
|
||||
- **Command Execution** — Mimir can run terminal commands through the AI. In `ask` mode, each command must be approved before it runs; `allow` mode runs non-blocked commands automatically.
|
||||
- **Permission Modes** — `ask` (prompt before every command), `allow` (run automatically), `off` (no tools). Automatic mode still rejects blocked commands and shell composition.
|
||||
- **Command Blocklist** — Dangerous commands and shell composition are rejected before execution. This is an extra safeguard, not a replacement for reviewing commands.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌──────────┐ state ┌──────────┐ HTTP ┌─────────────┐
|
||||
│ panel │◄───────────►│ service │◄──────────►│ API Server │
|
||||
│ (chat) │ mimir.* │ (brain) │ chat/* │ (OpenCode) │
|
||||
│ │ │ │ models │ │
|
||||
└────┬─────┘ └──────────┘ └─────────────┘
|
||||
│
|
||||
│ click
|
||||
┌────▼─────┐
|
||||
│ widget │
|
||||
│ (status) │
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
**Widget** (`widget.luau`) — Bar indicator. Click to toggle the chat panel.
|
||||
|
||||
**Panel** (`panel.luau`) — Chat interface with model selector, command approval, command history, message history with markdown rendering, and per-message selectable text views.
|
||||
|
||||
**Service** (`service.luau`) — HTTP communication with the API, conversation management, command execution, model discovery, and deferred state propagation.
|
||||
|
||||
## Usage
|
||||
|
||||
### Install
|
||||
|
||||
1. Add the plugin directory as a path source in Noctalia settings.
|
||||
2. Enable `alexander/mimir` in **Settings → Plugins**.
|
||||
3. Add the bar widget `alexander/mimir:status` to your bar.
|
||||
|
||||
### Chat
|
||||
Click the brain icon in your bar or toggle the panel from a terminal:
|
||||
|
||||
Click the brain icon in your bar or run:
|
||||
```sh
|
||||
noctalia msg panel-toggle alexander/mimir:chat
|
||||
```
|
||||
|
||||
Type a message and press Enter. Mimir responds with formatted text — code blocks render in shaded boxes. Click the copy icon on any message to open its content in a selectable field, then copy the text manually.
|
||||
|
||||
### Command Approval
|
||||
|
||||
When Mimir wants to run a terminal command (in `ask` permission mode), the panel shows an approval dialog:
|
||||
1. Review the command shown in the dialog.
|
||||
2. Click **Approve** to run it or **Deny** to cancel.
|
||||
When Mimir wants to run a terminal command in `ask` permission mode, the panel shows the command with **Approve** / **Deny** buttons.
|
||||
|
||||
## Settings
|
||||
|
||||
@@ -79,23 +43,32 @@ When Mimir wants to run a terminal command (in `ask` permission mode), the panel
|
||||
| `api_key` | `string` | (auto-detect) | API key. If empty and using the trusted OpenCode endpoint, reads from `~/.local/share/opencode/auth.json`. |
|
||||
| `tool_permission` | `enum` | `ask` | `ask` — prompt before commands; `allow` — run automatically; `off` — disable tools. |
|
||||
| `tool_blocklist` | `string` | `sudo,su,passwd,rm,...` | Comma-separated commands rejected before execution. |
|
||||
| `web_search_enabled` | `bool` | `true` | Enable or disable web search and public-page fetching. |
|
||||
| `show_commands` | `bool` | `true` | Show executed commands in the chat. |
|
||||
| `max_history` | `int` | `50` | Max messages kept in context. |
|
||||
| `glyph` | `glyph` | `brain` | Bar icon (per-widget setting). |
|
||||
|
||||
## How It Works
|
||||
## IPC
|
||||
|
||||
### API Compatibility
|
||||
Compatible with any OpenAI-compatible chat completion API. Defaults to OpenCode Go.
|
||||
Send a message to Mimir without opening the panel:
|
||||
|
||||
### Tool Calling
|
||||
When the model returns `tool_calls`, the service routes them to `run_command`. The permission mode determines whether to run immediately, prompt the user, or skip. Blocklisted commands and shell composition are rejected before execution.
|
||||
|
||||
### State Flow
|
||||
Entries are isolated VMs — they communicate through Noctalia's shared state (`noctalia.state.*`). HTTP callbacks queue responses to avoid cross-context state corruption. A timer-driven `update()` processes the queue and propagates results.
|
||||
```sh
|
||||
noctalia msg plugin alexander/mimir:brain all input "your message"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Conversation is ephemeral (in-memory only). Restarting clears it.
|
||||
- API key auto-detection reads OpenCode Go's auth file at runtime only — never stored.
|
||||
- API key auto-detection reads OpenCode Go's auth file at runtime only — never stored or logged.
|
||||
- Web search uses DuckDuckGo's public HTML endpoint (no key or account). Search queries are sent to DuckDuckGo; results are cached in memory for five minutes and requests time out after 15 seconds. The model treats search results and fetched pages as untrusted data, not instructions.
|
||||
- Web requests run through a `curl | python3` subprocess (with the bundled `webparse.py`) rather than inside the Luau VM, because Noctalia enforces small per-callback CPU budgets.
|
||||
- For best results, use a model with tool-calling support.
|
||||
|
||||
### Security
|
||||
|
||||
Mimir is a trusted desktop plugin that runs the model's shell commands and makes outbound web requests. This is the security model:
|
||||
|
||||
- **API key handling** — the key is read at runtime only and never written to disk, state, or logs. Auto-detection from `~/.local/share/opencode/auth.json` happens only when the endpoint is exactly `https://opencode.ai` on port 443/absent. The API key is never sent to DuckDuckGo or fetched pages — web requests carry only a browser User-Agent and an Accept-Language header.
|
||||
- **Command execution** — `ask` mode shows every command for approval; `allow` runs non-blocked commands automatically; `off` disables tools. The blocklist rejects destructive, interpreter, and network tools (`sudo`, `rm`, `sh`, `python`, `curl`, `ssh`, `git`, cloud CLIs, and more) as well as shell composition (`; | & > < \` $ \` and newlines). The blocklist is a safety guardrail, not a security boundary — raw shell execution in `allow` mode carries inherent risk.
|
||||
- **Web fetch** — only accepts `https://` URLs, rejects credentials, private/loopback/link-local IPv4 and IPv6 addresses, `localhost`, `.local` hosts, and numeric/IP obfuscations. Requests verify TLS, follow no redirects, and are restricted to HTTPS. Parser input and output are size- and length-limited and control characters are stripped.
|
||||
- **Residual risks** — DNS rebinding cannot be fully prevented (Noctalia exposes no DNS resolution API), so `web_fetch` is only for well-known public URLs. Plugins run as trusted code, so a malicious model output combined with `allow` mode can still run commands the blocklist does not cover — review commands in `ask` mode for sensitive work.
|
||||
|
||||
Reference in New Issue
Block a user