Hausmeister: Inline-Buttons fuer Memory-Kandidaten + /memory Befehl

This commit is contained in:
root 2026-03-15 12:55:04 +07:00
parent 1fc197dd13
commit f9ea49013a
2 changed files with 85 additions and 3 deletions

View file

@ -155,6 +155,32 @@ def log_message(session_id: str, role: str, content: str, source: str = None, me
_post(f"/sessions/{session_id}/messages", data)
def get_candidates() -> list[dict]:
"""Holt alle offenen Memory-Kandidaten."""
result = _get("/memory", {"status": "candidate", "limit": 20})
if result and "items" in result:
return result["items"]
return []
def activate_candidate(item_id: int) -> bool:
"""Setzt einen Kandidaten auf aktiv."""
result = _patch(f"/memory/{item_id}", {"status": "active"})
return bool(result and result.get("ok"))
def delete_candidate(item_id: int) -> bool:
"""Loescht einen Kandidaten."""
_ensure_config()
if not _base_url:
return False
try:
r = requests.delete(f"{_base_url}/memory/{item_id}", headers=_headers(), timeout=5)
return r.ok
except Exception:
return False
def get_active_memory() -> list[dict]:
"""Holt alle aktiven Memory-Items fuer den System-Prompt."""
result = _get("/memory", {"status": "active", "limit": 100})

View file

@ -37,9 +37,9 @@ def _release_lock():
except OSError:
pass
from telegram import BotCommand, Update, ReplyKeyboardMarkup, KeyboardButton
from telegram import BotCommand, Update, ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import (
Application, CommandHandler, MessageHandler, filters, ContextTypes,
Application, CommandHandler, MessageHandler, CallbackQueryHandler, filters, ContextTypes,
)
BOT_COMMANDS = [
@ -52,6 +52,7 @@ BOT_COMMANDS = [
BotCommand("report", "Tagesbericht"),
BotCommand("check", "Monitoring-Check"),
BotCommand("feeds", "Feed-Status & Artikel heute"),
BotCommand("memory", "Offene Memory-Kandidaten"),
BotCommand("start", "Hilfe anzeigen"),
]
@ -284,6 +285,47 @@ async def cmd_feeds(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
except Exception as e:
await update.message.reply_text(f"Fehler: {e}")
def _memory_buttons(item_id: int) -> InlineKeyboardMarkup:
return InlineKeyboardMarkup([[
InlineKeyboardButton("✅ Merken", callback_data=f"mem_activate:{item_id}"),
InlineKeyboardButton("❌ Verwerfen", callback_data=f"mem_delete:{item_id}"),
]])
async def cmd_memory(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
if not _authorized(update):
return
candidates = memory_client.get_candidates()
if not candidates:
await update.message.reply_text("Keine offenen Kandidaten.")
return
for item in candidates:
text = f"📝 [{item['scope']}/{item['kind']}]\n{item['content']}"
await update.message.reply_text(text, reply_markup=_memory_buttons(item["id"]))
async def handle_memory_callback(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
data = query.data or ""
if data.startswith("mem_activate:"):
item_id = int(data.split(":")[1])
ok = memory_client.activate_candidate(item_id)
if ok:
await query.edit_message_text("✅ Aktiviert: " + query.message.text.split("\n", 1)[-1])
else:
await query.edit_message_text("Fehler beim Aktivieren.")
elif data.startswith("mem_delete:"):
item_id = int(data.split(":")[1])
ok = memory_client.delete_candidate(item_id)
if ok:
await query.edit_message_text("🗑 Verworfen.")
else:
await query.edit_message_text("Fehler beim Loeschen.")
async def handle_message(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
"""Button-Presses und Freitext-Fragen verarbeiten."""
if not _authorized(update):
@ -311,12 +353,24 @@ async def handle_message(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("🤔 Denke nach...")
try:
candidates_before = {c["id"] for c in memory_client.get_candidates()}
handlers = context.get_tool_handlers(session_id=session_id)
answer = llm.ask_with_tools(text, handlers, session_id=session_id)
if session_id:
memory_client.log_message(session_id, "user", text)
memory_client.log_message(session_id, "assistant", answer)
await update.message.reply_text(answer[:4000], reply_markup=KEYBOARD)
candidates_after = memory_client.get_candidates()
new_candidates = [c for c in candidates_after if c["id"] not in candidates_before]
if new_candidates:
c = new_candidates[0]
await update.message.reply_text(
answer[:4000] + "\n\n📝 " + c["content"],
reply_markup=_memory_buttons(c["id"]),
)
else:
await update.message.reply_text(answer[:4000], reply_markup=KEYBOARD)
except Exception as e:
log.exception("Fehler bei Freitext")
await update.message.reply_text(f"Fehler: {e}")
@ -345,6 +399,8 @@ def main():
app.add_handler(CommandHandler("report", cmd_report))
app.add_handler(CommandHandler("check", cmd_check))
app.add_handler(CommandHandler("feeds", cmd_feeds))
app.add_handler(CommandHandler("memory", cmd_memory))
app.add_handler(CallbackQueryHandler(handle_memory_callback, pattern=r"^mem_"))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
async def post_init(application):