Runtime

Turn Finalizer

The post-loop layer that persists output, syncs memory, and shapes completion results.

Turn Finalizer

What it is

The post-loop layer that persists output, syncs memory, and shapes completion results.

In plain terms

Picture an airline crew’s post-landing checklist: once passengers have deplaned, someone still has to log the flight time, radio in anything that went wrong mechanically, and flag it for the next crew before the plane is cleared for the night. Hermes’s turn finalizer runs that same checklist. It executes the moment the back-and-forth with tools and the model has stopped, before anything is handed back to whoever asked.

Why it matters

After a turn’s model call and tool calls are done, finalize_turn writes the output to session history, syncs anything memory-worthy into the memory manager, and shapes what actually gets returned to whoever asked. Skip a reliable finalize step and a cron job could technically complete its work while leaving nothing behind Hermes could recall later. Retention and privacy rules typically get applied right here, before a turn’s output becomes part of durable session state.

How it works

finalize_turn (agent/turn_finalizer.py) runs once the tool-calling loop exits, whatever the reason. It first checks whether the iteration budget ran out; when it has, the turn either keeps an answer a verification step had already composed and was withholding, or — the more common case — asks the model for one extra toolless summary rather than leaving the reply empty. Trajectory save, task-resource cleanup, and session persistence each run inside their own try/except block so one failure — a bad write, a stuck browser teardown — can’t erase a response the other two already secured; problems are collected into a cleanup_errors list instead. It can append a footer flagging file edits that silently failed, or replace a suspiciously short or empty reply with a plain-language explanation of why the turn stopped. Plugin hooks transform_llm_output and post_llm_call each get a turn before background memory or skill review is queued to run after the user already has their answer; the on_session_end hook fires last of all, once that queueing has already happened.

A concrete example

Say a nightly cron job asks Hermes to tidy a shared inbox. It runs several tool calls, then the model produces a closing summary. Turn finalizer steps in: it saves the run’s trajectory, closes any spawned browser session, writes the exchange into session history, and checks whether any file edit silently failed mid-run. If one did, it tacks on a short footer naming exactly which file wasn’t actually saved, rather than letting the model’s confident-sounding summary stand uncorrected. The finished result — reply text, token counts, cost estimate — then heads back to whichever channel triggered the job, while a background pass decides if anything from the conversation is worth saving to long-term memory.

How it connects

This note belongs to the Runtime family. Its closest neighboring concepts are: Tool Executor, Model Call, Personal OS.

Source evidence

  • vendor/hermes-agent/agent/turn_finalizer.py#<file> — Structural Source Map fallback for agent/turn_finalizer.py. A core source file in the Conversation Turn Loop structure within Agent Runtime.

Workflows

  • No first-pass workflow mapping yet; this concept still appears in the vault graph through articles and source evidence.
  • Inside Hermes: How the Agent Loop, Context, Memory, Gateways, and Cron Jobs Work Together