diff --git a/agent/turn_finalizer.py b/agent/turn_finalizer.py index 5c0973973d..9fd951f17b 100644 --- a/agent/turn_finalizer.py +++ b/agent/turn_finalizer.py @@ -24,6 +24,13 @@ _VERIFICATION_CONTINUATION_FLAGS = ("_verification_stop_synthetic", "_pre_verify _SENTENCE_END = {".", "!", "?", "。", "!", "?", "`", ")"} +# ``result[key] = agent.session_`` for the per-session usage/cost counters. +_SESSION_TOKEN_KEYS = ( + "input_tokens", "output_tokens", "cache_read_tokens", "cache_write_tokens", + "reasoning_tokens", "prompt_tokens", "completion_tokens", "total_tokens", +) +_SESSION_COST_KEYS = ("estimated_cost_usd", "cost_status", "cost_source") + def _assistant_row_missing_visible_text(msg: dict) -> bool: """True when an assistant row has no visible text (blank final or tool-only).""" @@ -485,18 +492,9 @@ def finalize_turn( "model": agent.model, "provider": agent.provider, "base_url": agent.base_url, - "input_tokens": agent.session_input_tokens, - "output_tokens": agent.session_output_tokens, - "cache_read_tokens": agent.session_cache_read_tokens, - "cache_write_tokens": agent.session_cache_write_tokens, - "reasoning_tokens": agent.session_reasoning_tokens, - "prompt_tokens": agent.session_prompt_tokens, - "completion_tokens": agent.session_completion_tokens, - "total_tokens": agent.session_total_tokens, + **{key: getattr(agent, f"session_{key}") for key in _SESSION_TOKEN_KEYS}, "last_prompt_tokens": getattr(agent.context_compressor, "last_prompt_tokens", 0) or 0, - "estimated_cost_usd": agent.session_estimated_cost_usd, - "cost_status": agent.session_cost_status, - "cost_source": agent.session_cost_source, + **{key: getattr(agent, f"session_{key}") for key in _SESSION_COST_KEYS}, # Requested service tier, for billing audits (`hermes -z --usage-file`). "service_tier": ( (getattr(agent, "request_overrides", {}) or {}).get("extra_body") or {} diff --git a/agent/turn_stop_gates.py b/agent/turn_stop_gates.py index 2d92693905..35aefe5334 100644 --- a/agent/turn_stop_gates.py +++ b/agent/turn_stop_gates.py @@ -112,6 +112,7 @@ def apply_stop_gates( there).""" def _continue(nudge: str, flag: str) -> StopGateVerdict: + """Append the synthetic nudge row and hand the turn back to the loop.""" append_message(messages, {"role": "user", "content": nudge, flag: True}) agent._session_messages = messages # Keep the answer only as a budget-exhaustion fallback; clear ``final_response`` so @@ -127,17 +128,14 @@ def apply_stop_gates( _verify_nudge = _verify_on_stop_nudge(agent) if _verify_nudge: - agent._verification_stop_nudges = ( - getattr(agent, "_verification_stop_nudges", 0) + 1 - ) + agent._verification_stop_nudges = getattr(agent, "_verification_stop_nudges", 0) + 1 final_msg["finish_reason"] = "verification_required" _append_interim_answer( agent, final_msg, messages, conversation_history, "verify-on-stop interim flush failed" ) verdict = _continue(_verify_nudge, "_verification_stop_synthetic") # Internal nudge: stay silent on the terminal, debug-log only. - logger.debug("verification stop-loop nudge issued (attempt %d)", - agent._verification_stop_nudges) + logger.debug("verification stop-loop nudge issued (attempt %d)", agent._verification_stop_nudges) return verdict _attempt = getattr(agent, "_pre_verify_nudges", 0) @@ -149,15 +147,12 @@ def apply_stop_gates( agent, final_msg, messages, conversation_history, "pre_verify interim flush failed" ) verdict = _continue(_verify_nudge2, "_pre_verify_synthetic") - logger.debug("pre_verify nudge issued (attempt %d)", - agent._pre_verify_nudges) + logger.debug("pre_verify nudge issued (attempt %d)", agent._pre_verify_nudges) return verdict _kanban_nudge = _kanban_stop_nudge(agent, messages) if _kanban_nudge: - agent._kanban_stop_nudges = ( - getattr(agent, "_kanban_stop_nudges", 0) + 1 - ) + agent._kanban_stop_nudges = getattr(agent, "_kanban_stop_nudges", 0) + 1 final_msg["finish_reason"] = "kanban_terminal_required" final_msg["_kanban_stop_synthetic"] = True append_message(messages, final_msg) diff --git a/agent/turn_tool_round.py b/agent/turn_tool_round.py index f2c7a65fb5..16f7c04e87 100644 --- a/agent/turn_tool_round.py +++ b/agent/turn_tool_round.py @@ -82,7 +82,7 @@ def run_tool_round( if _tvv.action == "continue": return _verdict("continue") - # ── Post-call guardrails ────────────────────────── + # Post-call guardrails. assistant_message.tool_calls = agent._deduplicate_tool_calls( agent._cap_delegate_task_calls(assistant_message.tool_calls) )