feat: local LLM multi-model, session search, cron proactive types, notifications, docs overhaul
Local LLM:
- user_settings.py: per-user hosts/models config (local_llm.json)
- routers/local_llm.py + static/local_llm.html: dedicated settings page
- llm_client.py: local OpenAI-compatible backend via httpx
- config.py: LOCAL_API_URL/KEY/MODEL + per-backend timeouts
- Active model shown near backend toggle (amber hint text)
Memory distillation:
- memory_distiller.py: DISTILL_BACKEND_MID/LONG .env overrides
- scheduler.py + notification.py: notify NC Talk after mid/long distill
- notification.py: outbound channel abstraction (NC Talk, extensible)
Session search:
- routers/files.py: GET /sessions/search?q= with excerpts grouped by date
- static/index.html + app.js: search UI in file sidebar with highlight
- _esc() helper to prevent XSS in search results
Proactive cron:
- cron_runner.py: new job types — message (send directly) and brief (LLM + send)
- Both support optional per-job channel override
Channels:
- routers/nextcloud_talk.py: consolidated using notification._send_nct_message()
- routers/auth.py: local backend status in /auth/status
- routers/chat.py: /backend returns {primary, fallback, local_model} object
UI / UX:
- Copy button for user messages (matching assistant)
- Autocomplete disabled on sensitive form fields
- settings.html: local model section replaced with link to /settings/local
Docs overhaul:
- MASTER.md hub + ARCH__SYSTEM/BACKENDS/PERSONA/CHANNELS/FUTURE.md
- ARCH__Intelligence_Layer.md replaced with redirect table
- CORTEX.md trimmed to vision only; README updated
- OPEN_WEBUI_API.md added to docs/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,16 +10,20 @@ Job schema:
|
||||
"id": "c_abc123",
|
||||
"label": "Human-readable name",
|
||||
"schedule": "daily:09:00", # see parse_schedule() for all formats
|
||||
"type": "remind" | "note",
|
||||
"payload": "Text to write when the job fires",
|
||||
"type": "remind" | "note" | "message" | "brief",
|
||||
"payload": "Text or prompt when the job fires",
|
||||
"channel": null | "nextcloud" | "google_chat", # for message/brief types
|
||||
"enabled": true,
|
||||
"created_at": "ISO 8601",
|
||||
"last_run": null | "ISO 8601"
|
||||
}
|
||||
|
||||
Job types:
|
||||
remind → appends to inara/REMINDERS.md (auto-loaded into Inara's context)
|
||||
note → appends to inara/SCRATCH.md (read on demand via scratch_read)
|
||||
remind → appends to REMINDERS.md (auto-loaded into context at tier 2+)
|
||||
note → appends to SCRATCH.md (read on demand via scratch_read)
|
||||
message → sends payload as-is to NC Talk notification_room
|
||||
brief → runs LLM with payload as the prompt, sends response to NC Talk
|
||||
(good for morning briefings, summaries, proactive check-ins)
|
||||
"""
|
||||
|
||||
import logging
|
||||
@@ -150,6 +154,39 @@ async def run_job(job: dict) -> None:
|
||||
p.write_text(existing.rstrip() + "\n" + section)
|
||||
logger.info("cron [note] fired: %s", label)
|
||||
|
||||
elif job_type == "message":
|
||||
# Send payload text directly to the user's notification channel
|
||||
from notification import notify
|
||||
username = job.get("user") or "scott"
|
||||
channel = job.get("channel") or None
|
||||
await notify(username, payload, channel=channel)
|
||||
logger.info("cron [message] sent: %s", label)
|
||||
|
||||
elif job_type == "brief":
|
||||
# Run LLM with payload as the prompt, send response to notification channel.
|
||||
# Great for morning briefings, reminders, proactive check-ins.
|
||||
from context_loader import load_context
|
||||
from llm_client import complete
|
||||
from notification import notify
|
||||
from persona import set_context
|
||||
from config import settings as _s
|
||||
|
||||
username = job.get("user") or _s.user_name.lower()
|
||||
persona_nm = job.get("persona") or _s.agent_name.lower()
|
||||
channel = job.get("channel") or None
|
||||
set_context(username, persona_nm)
|
||||
|
||||
system_prompt = load_context(2) # tier 2: identity + memory + user profile
|
||||
try:
|
||||
response_text, backend = await complete(
|
||||
system_prompt=system_prompt,
|
||||
messages=[{"role": "user", "content": payload}],
|
||||
)
|
||||
await notify(username, response_text, channel=channel)
|
||||
logger.info("cron [brief] sent via %s: %s", backend, label)
|
||||
except Exception as e:
|
||||
logger.error("cron [brief] LLM error for %s: %s", label, e)
|
||||
|
||||
else:
|
||||
logger.warning("cron: unknown type %r (job %s)", job_type, job.get("id"))
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user