diff --git a/aria-brain/agent.py b/aria-brain/agent.py index 0fbbb42..45f3232 100644 --- a/aria-brain/agent.py +++ b/aria-brain/agent.py @@ -97,26 +97,35 @@ META_TOOLS = [ "function": { "name": "trigger_timer", "description": ( - "Lege einen Timer-Trigger an — feuert EINMALIG zum angegebenen Zeitpunkt " - "und ruft dich selbst auf (Push-Nachricht an Stefan). " - "Use-Case: 'erinnere mich in 10min', 'sag mir um 14:30 Bescheid'." + "Lege einen Timer-Trigger an — feuert EINMALIG und ruft dich dann selbst auf " + "(Push-Nachricht an Stefan). Use-Case: 'erinnere mich in 10min', " + "'sag mir um 14:30 Bescheid'. Genau EINES von `in_seconds` ODER `fires_at` " + "muss gesetzt sein." ), "parameters": { "type": "object", "properties": { "name": {"type": "string", "description": "kurzer kebab-case-Name, a-z 0-9 - _"}, + "in_seconds": { + "type": "integer", + "description": ( + "Relativ ab jetzt in Sekunden. Bevorzugt bei Angaben wie " + "'in 2 Minuten' (=120), 'in 1 Stunde' (=3600). " + "Server berechnet daraus den absoluten Feuer-Zeitpunkt." + ), + }, "fires_at": { "type": "string", "description": ( - "Absoluter ISO-Timestamp UTC, z.B. '2026-05-12T14:30:00Z'. " - "Berechne aus relativer Angabe ('in 10min') selbst — die " - "aktuelle Zeit findest du im System-Prompt nicht, also nutze " - "Bash: `date -u -d '+10 minutes' --iso-8601=seconds`." + "Absoluter ISO-Timestamp UTC fuer feste Termine, z.B. " + "'2026-05-12T14:30:00Z'. Die aktuelle Zeit findest du im " + "System-Prompt unter '## Aktuelle Zeit'. Fuer relative Angaben " + "lieber `in_seconds` nutzen." ), }, "message": {"type": "string", "description": "Was soll bei der Erinnerung gesagt werden"}, }, - "required": ["name", "fires_at", "message"], + "required": ["name", "message"], }, }, }, @@ -389,9 +398,22 @@ class Agent: out += f"\nstderr:\n{err}" return out if name == "trigger_timer": + fires_at_iso = arguments.get("fires_at") + in_seconds = arguments.get("in_seconds") + if not fires_at_iso and in_seconds is not None: + from datetime import datetime as _dt, timezone as _tz, timedelta as _td + try: + secs = int(in_seconds) + except (TypeError, ValueError): + return "FEHLER: in_seconds muss eine ganze Zahl sein." + if secs < 1: + return "FEHLER: in_seconds muss >= 1 sein." + fires_at_iso = (_dt.now(_tz.utc) + _td(seconds=secs)).isoformat(timespec="seconds") + if not fires_at_iso: + return "FEHLER: entweder `in_seconds` ODER `fires_at` muss gesetzt sein." t = triggers_mod.create_timer( name=arguments["name"], - fires_at_iso=arguments["fires_at"], + fires_at_iso=fires_at_iso, message=arguments["message"], author="aria", ) diff --git a/aria-brain/prompts.py b/aria-brain/prompts.py index 2cba2b2..161708f 100644 --- a/aria-brain/prompts.py +++ b/aria-brain/prompts.py @@ -15,10 +15,34 @@ mit dem Conversation-Loop in spaeteren Phasen. from __future__ import annotations +from datetime import datetime, timezone, timedelta from typing import List from memory import MemoryPoint + +def build_time_section() -> str: + """Aktueller Zeitstempel — damit ARIA Timer korrekt anlegen kann + und Watcher-Conditions mit hour_of_day etc. einordenbar bleiben.""" + now_utc = datetime.now(timezone.utc) + # Europa/Berlin: Sommerzeit CEST = UTC+2, Winterzeit CET = UTC+1. + # Wir nehmen den simplen Fall (kein zoneinfo-Import noetig im Brain-Image): + # Stefans VM laeuft auf UTC, die Bridge in der Wohnung — Anzeige reicht. + local_offset_h = 2 if 3 <= now_utc.month <= 10 else 1 + local = now_utc + timedelta(hours=local_offset_h) + lines = [ + "## Aktuelle Zeit", + f"- UTC: {now_utc.isoformat(timespec='seconds')}", + f"- Lokal (Europa/Berlin, UTC+{local_offset_h}): " + f"{local.strftime('%Y-%m-%d %H:%M:%S')} ({local.strftime('%A')})", + "", + "Nutze das fuer Trigger-Timestamps und um Watcher-Conditions wie " + "`hour_of_day == 8` einzuordnen. Fuer relative Angaben " + "('in 10min', 'in 2 Stunden') nutze beim `trigger_timer` den " + "`in_seconds`-Parameter — Server rechnet dann selbst.", + ] + return "\n".join(lines) + TYPE_HEADINGS = { "identity": "## Wer du bist", "rule": "## Sicherheitsregeln & Prinzipien", @@ -177,7 +201,7 @@ def build_system_prompt( condition_funcs: List[dict] | None = None, ) -> str: """Kompletter System-Prompt: Hot + Cold + Skills + Triggers.""" - parts = [build_hot_memory_section(pinned)] + parts = [build_hot_memory_section(pinned), "", build_time_section()] if skills: parts.append("") parts.append(build_skills_section(skills))