fix(brain): Timer in 2min funktioniert wieder — Zeit im Prompt + in_seconds-Param
ARIA wusste nicht wieviel Uhr es ist (kein Bash, kein Time-Tool, kein
Timestamp im System-Prompt) und konnte fires_at als ISO-UTC schlicht
nicht ausrechnen. Zwei Fixes:
1. prompts.py: build_time_section() injiziert UTC + lokale Zeit
(Europa/Berlin Sommer/Winter-Heuristik) als '## Aktuelle Zeit'-Block
oben in den System-Prompt. Hilft auch beim Einordnen von
Watcher-Conditions wie hour_of_day == 8.
2. agent.py trigger_timer-Tool: neuer Parameter `in_seconds` als
Alternative zu fires_at. Bei relativen Angaben ('in 2 Minuten')
rechnet jetzt der Server den absoluten Timestamp aus — keine
Rechnerei in der LLM noetig. fires_at bleibt fuer feste Termine.
required nur noch name + message.
Diagnostic-API (/triggers/timer) bleibt absolute-only, da der Browser
selbst datetime hat.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+31
-9
@@ -97,26 +97,35 @@ META_TOOLS = [
|
|||||||
"function": {
|
"function": {
|
||||||
"name": "trigger_timer",
|
"name": "trigger_timer",
|
||||||
"description": (
|
"description": (
|
||||||
"Lege einen Timer-Trigger an — feuert EINMALIG zum angegebenen Zeitpunkt "
|
"Lege einen Timer-Trigger an — feuert EINMALIG und ruft dich dann selbst auf "
|
||||||
"und ruft dich selbst auf (Push-Nachricht an Stefan). "
|
"(Push-Nachricht an Stefan). Use-Case: 'erinnere mich in 10min', "
|
||||||
"Use-Case: 'erinnere mich in 10min', 'sag mir um 14:30 Bescheid'."
|
"'sag mir um 14:30 Bescheid'. Genau EINES von `in_seconds` ODER `fires_at` "
|
||||||
|
"muss gesetzt sein."
|
||||||
),
|
),
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {"type": "string", "description": "kurzer kebab-case-Name, a-z 0-9 - _"},
|
"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": {
|
"fires_at": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": (
|
"description": (
|
||||||
"Absoluter ISO-Timestamp UTC, z.B. '2026-05-12T14:30:00Z'. "
|
"Absoluter ISO-Timestamp UTC fuer feste Termine, z.B. "
|
||||||
"Berechne aus relativer Angabe ('in 10min') selbst — die "
|
"'2026-05-12T14:30:00Z'. Die aktuelle Zeit findest du im "
|
||||||
"aktuelle Zeit findest du im System-Prompt nicht, also nutze "
|
"System-Prompt unter '## Aktuelle Zeit'. Fuer relative Angaben "
|
||||||
"Bash: `date -u -d '+10 minutes' --iso-8601=seconds`."
|
"lieber `in_seconds` nutzen."
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
"message": {"type": "string", "description": "Was soll bei der Erinnerung gesagt werden"},
|
"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}"
|
out += f"\nstderr:\n{err}"
|
||||||
return out
|
return out
|
||||||
if name == "trigger_timer":
|
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(
|
t = triggers_mod.create_timer(
|
||||||
name=arguments["name"],
|
name=arguments["name"],
|
||||||
fires_at_iso=arguments["fires_at"],
|
fires_at_iso=fires_at_iso,
|
||||||
message=arguments["message"],
|
message=arguments["message"],
|
||||||
author="aria",
|
author="aria",
|
||||||
)
|
)
|
||||||
|
|||||||
+25
-1
@@ -15,10 +15,34 @@ mit dem Conversation-Loop in spaeteren Phasen.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from memory import MemoryPoint
|
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 = {
|
TYPE_HEADINGS = {
|
||||||
"identity": "## Wer du bist",
|
"identity": "## Wer du bist",
|
||||||
"rule": "## Sicherheitsregeln & Prinzipien",
|
"rule": "## Sicherheitsregeln & Prinzipien",
|
||||||
@@ -177,7 +201,7 @@ def build_system_prompt(
|
|||||||
condition_funcs: List[dict] | None = None,
|
condition_funcs: List[dict] | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Kompletter System-Prompt: Hot + Cold + Skills + Triggers."""
|
"""Kompletter System-Prompt: Hot + Cold + Skills + Triggers."""
|
||||||
parts = [build_hot_memory_section(pinned)]
|
parts = [build_hot_memory_section(pinned), "", build_time_section()]
|
||||||
if skills:
|
if skills:
|
||||||
parts.append("")
|
parts.append("")
|
||||||
parts.append(build_skills_section(skills))
|
parts.append(build_skills_section(skills))
|
||||||
|
|||||||
Reference in New Issue
Block a user