Compare commits

...

2 Commits

Author SHA1 Message Date
teknium1
5301c01776 fix(cron): make naive ISO timestamps timezone-aware at parse time
User-provided ISO timestamps like '2026-02-03T14:00' (no timezone)
were stored naive. The _ensure_aware() helper at check time interprets
naive datetimes using the current system timezone, but if the system
timezone changes between job creation and checking, the job fires at
the wrong time.

Fix: call dt.astimezone() at parse time to immediately stamp the
datetime with the local timezone. The stored value is now always
timezone-aware, so it's stable regardless of later timezone changes.
2026-03-17 04:20:24 -07:00
Teknium
1314b4b541 feat(hooks): emit session:end lifecycle event (#1725)
Based on PR #1432 by @bayrakdarerdem. session:start was already on main; this adds the session:end event.

Co-authored-by: bayrakdarerdem <bayrakdarerdem@users.noreply.github.com>
2026-03-17 04:17:44 -07:00
3 changed files with 15 additions and 3 deletions

View File

@@ -168,6 +168,10 @@ def parse_schedule(schedule: str) -> Dict[str, Any]:
try:
# Parse and validate
dt = datetime.fromisoformat(schedule.replace('Z', '+00:00'))
# Make naive timestamps timezone-aware at parse time so the stored
# value doesn't depend on the system timezone matching at check time.
if dt.tzinfo is None:
dt = dt.astimezone() # Interpret as local timezone
return {
"kind": "once",
"run_at": dt.isoformat(),

View File

@@ -8,8 +8,9 @@ Hooks are discovered from ~/.hermes/hooks/ directories, each containing:
Events:
- gateway:startup -- Gateway process starts
- session:start -- New session created
- session:reset -- User ran /new or /reset
- session:start -- New session created (first message of a new session)
- session:end -- Session ends (user ran /new or /reset)
- session:reset -- Session reset completed (new session entry created)
- agent:start -- Agent begins processing a message
- agent:step -- Each turn in the tool-calling loop
- agent:end -- Agent finishes processing

View File

@@ -2178,7 +2178,14 @@ class GatewayRunner:
# Reset the session
new_entry = self.session_store.reset_session(session_key)
# Emit session:end hook (session is ending)
await self.hooks.emit("session:end", {
"platform": source.platform.value if source.platform else "",
"user_id": source.user_id,
"session_key": session_key,
})
# Emit session:reset hook
await self.hooks.emit("session:reset", {
"platform": source.platform.value if source.platform else "",