# Message Loop Result Extensions DOX ## Purpose - Own normalization and policy handling after a model turn completes, before default assistant-history and tool-dispatch processing. ## Ownership - `_05_leaked_tool_call.py` optionally converts complete alternate-format text through `helpers.extract_tools` before Context Doctor. It maps aliases and normalizes actions against the Responses turn map or lazily resolved Chat Completions prompt/MCP surface. Failed conversion or unavailable tools leave the result untouched for normal repair and dispatch; this hook never inserts history, warns, or forces a retry. Native calls remain authoritative. - Extensions receive mutable `result_data` with `llm_result` and may set `skip_default_processing` after fully handling the turn. - Text converters preserve the first input in turn-local `result_data.raw_response` before rewriting it, so Context Doctor can keep original View Details content when `update_log` is off. Recovery retains the outer call's string headline for display and emits a `util` diagnostic, following the WebUI's utility visibility preference. - `_05_truncated_response.py` retries turns the provider cut off at the output token limit (`LLMResult.truncated`) that carry no complete tool request: add an agent-facing `fw.msg_output_limit.md` history warning with a separate `fw.msg_output_limit_response.md` user notice naming the finish reason, instead of the generic misformat warning, and count them through the stop-unusable-response-loop extension. Reasoning-only output defers to silent thought-preserving recovery below. Native calls are complete only when every raw argument value is a JSON object; a synthesized envelope around malformed arguments does not qualify. - `_20_empty_response.py` retries fully empty turns (no response and no reasoning): count them toward the unusable-response limit without adding a warning to model history, and use `fw.msg_empty_response.md` for the UI warning text only. - `_20_empty_response.py` also catches non-action prose in either transport when Context Doctor is disabled: retain assistant text in history, show it as thoughts on the generating log, and append an internal `fw.msg_misformat.md` reminder without a UI warning. Actual tool requests and unrepaired tool intent retain their dispatch/repair paths. - `_20_empty_response.py` retries reasoning-only turns silently: append emitted reasoning as compact assistant thoughts through `hist_add_ai_response`, preserve the original `LLMResult` metadata and Responses state, and display thoughts on the existing generation log. Append only the internal `fw.msg_reasoning_only.md` reminder; it still advances the stop-unusable-response counter. Native function/built-in actions bypass this handler. - `_30_repeat_response.py` compares `LLMResult.repeat_response_text()` for native calls (public text plus all calls), otherwise full response text. It retries content that exactly matches `loop_data.last_response`, regardless of separate reasoning or provider IDs, using `fw.msg_repeat.md` for history and `fw.msg_repeat_response.md` for the UI warning text. State advancement is owned by `hist_add_ai_response`; do not call `_remember_llm_result_state` manually. - `_40_native_thoughts.py` folds public commentary accompanying native function calls into the existing completed-generation log `thoughts` array. It preserves provider output items, canonical history, repeat comparison and dispatch. It respects handled results and excludes reasoning/encrypted items and explicit final-answer messages. Normal log masking applies. ## Local Contracts - Files run in deterministic filename order. - A handler that sets `skip_default_processing` owns needed history and UI side effects for that turn. - Handlers that should not add side effects after an earlier extension has handled the result must return when `skip_default_processing` is set. - Do not use this point to mutate streamed partial content. ## Work Guidance - Normalize a completed result before policy extensions compare or persist it. - Keep loop-control policy independent from optional plugins. ## Verification - Run message-loop and unusable-response regression tests. ## Child DOX Index No child DOX files.