Complete

Complete#

Complete tool - signals that the autonomous session is finished.

exception gptme.tools.complete.SessionCompleteException

Exception raised to signal that the session should end.

__init__(message: str = '', *, outcome: str | None = None) → None
exception gptme.tools.complete.StaleManifestError

Raised when a live-manifest runner changed after approval and cannot be snapshotted.

gptme.tools.complete.auto_reply_hook(manager: LogManager, interactive: bool, prompt_queue: Any, no_confirm: bool = False) → Generator[Message | StopPropagation, None, None]

Hook that implements auto-reply mechanism for autonomous operation.

If in non-interactive mode and last assistant message had no tools, inject an auto-reply to ensure the assistant does work.

In interactive + no_confirm mode (gptme -y), inject a quiet nudge once to avoid piling on, then let the loop continue naturally.

This is called via LOOP_CONTINUE hook, which receives interactive, prompt_queue, and no_confirm.

Parameters:
  • manager – Conversation manager with log and workspace

  • interactive – Whether in interactive mode

  • prompt_queue – Queue of pending prompts

  • no_confirm – Whether tool confirmations are skipped (–no-confirm / -y mode)

gptme.tools.complete.block_budget_hook(manager: LogManager) → Generator[Message | StopPropagation, None, None]

End a non-interactive session after 2x the policy-block budget.

A retry-after-block loop is a series of tool calls inside one turn, so LOOP_CONTINUE (which fires after a tool-less turn) never sees it. This STEP_PRE hook runs before every step and is the only place to stop it. Interactive sessions (including -y) are left alone: a human is present.

gptme.tools.complete.complete_hook(messages: list[Message], workspace: Path | None = None, **kwargs) → Generator[Message | StopPropagation, None, None]

Persist an accepted stop, never the complete tool’s pre-verification ack.

gptme.tools.complete.count_policy_blocks(messages: list[Message]) → int

Count policy blocks ([policy-block] system messages) in the current episode.

gptme.tools.complete.current_episode(messages: list[Message]) → list[Message]

Return the messages after the last real (human) user message.

Auto-reply nudges and autocompaction checkpoint requests are harness-generated and stay inside the episode. A real user message is new authority and starts a fresh episode — even when it quotes the auto-reply marker text.

gptme.tools.complete.execute_complete(code: str | None, args: list[str] | None, kwargs: dict[str, str] | None) → Message

Signal that the autonomous session is complete and ready to exit.

gptme.tools.complete.session_end_metadata_hook(manager: LogManager, **kwargs: Any) → Generator[Message | StopPropagation, None, None]

Emit one <!-- gptme:session-end {...} --> block when a session ends.

Registered on SESSION_END, which fires exactly once per session: on the CLI completion path (after SessionCompleteException), on normal loop exit, in the TUI, and on last-session server teardown. TURN_POST was the idea’s first suggestion, but it fires on every turn and cannot see the completion signal, so it would need a separate flag to know the run is over.

gptme.tools.complete.stuck_detect_hook(manager: LogManager, interactive: bool, prompt_queue: Any, no_confirm: bool = False) → Generator[Message | StopPropagation, None, None]

Detect a stuck agent that keeps issuing the same tool call(s).

Unlike auto_reply_hook (which only acts when the last assistant message has no tool uses), this hook fires when the agent does emit tool uses but keeps repeating an identical action without progress — a silent failing loop that would otherwise run until the budget or session timeout is hit.

Registered as a separate LOOP_CONTINUE hook at higher priority than auto_reply_hook so it can observe the yes-tool-but-repeating case the latter early-returns on. Yields a system nudge when stuck; in non-interactive mode, raises SessionCompleteException after repeated escalations.

In interactive mode (e.g. gptme.ai web sessions) the nudge fires normally but the session is never force-exited — the human can break the loop.

See gptme/gptme#2725, gptme/gptme#3459, and the design note in Bob’s workspace.