import {
CommandHoldState,
command_ledger_ingest,
command_ledger_new,
command_wait_normalize,
} from "std/agent/command_ledger"
import "std/agent/loop_call_resolution"
import "std/agent/loop_denial_cutoff"
import "std/agent/loop_finalize"
import "std/agent/loop_foundation"
import {
agent_loop_command_hold_transition,
agent_loop_post_turn_transition,
} from "std/agent/loop_post_turn"
import { agent_loop_provider_failure } from "std/agent/loop_provider_failure"
import "std/agent/loop_resource_dispatch"
import "std/agent/loop_result_status"
import "std/agent/loop_support"
import "std/agent/loop_terminal"
import "std/agent/loop_tool_calls"
import "std/agent/loop_turn_options"
import "std/agent/loop_turn_scope"
@complexity(allow)
pub fn __agent_loop_run(harness: Harness, message: any, session: dict, initial_opts: any) {
let opts = initial_opts
let iteration = 0
let session_finalized = false
let audit_background_tasks = []
const run = try {
opts = agent_mcp_bootstrap_if_needed(harness.tools, session, opts)
const primary_llm_opts = __agent_loop_effective_llm_options(harness.llm, opts)
const primary_provider = to_string(primary_llm_opts?.provider ?? "")
const primary_model = to_string(primary_llm_opts?.model ?? "")
const primary_tool_format = to_string(primary_llm_opts?.tool_format ?? "")
let escalation_retry_pending = false
let stop_reason = nil
let final_status = ""
let terminal_error = nil
let verify_attempts = 0
let done_judge_invocations = 0
let done_judge_vetoes = 0
let verify_completion_judge_invocations = 0
let verify_completion_judge_vetoes = 0
let feedback_history = {}
let step_judge_attempts = 0
let structural_validator_attempts = 0
let last_turn_parse_dropped = false
let consecutive_text_only = 0
let turns_since_progress = 0
let fallback_index = 0
let successful_tools_seen = []
let rejected_tools_seen = []
let suspend_result = nil
let stall_state = agent_stall_initial_state()
let stall_enabled_seen = false
let stall_prev_dispatch = nil
let stall_hard_stop_rescues = 0
const max_verify_attempts = opts?.max_verify_attempts ?? 20
const budget = opts.iteration_budget
let current_max = budget.initial
let extensions_used = 0
let budget_decisions = []
let consecutive_failure_count = 0
let budget_exhausted_emitted = false
let last_tool_count = 0
const loop_start_ms = __agent_loop_clock_now_ms(harness.clock)
opts = __agent_loop_apply_deadline(opts, budget, loop_start_ms)
const __reserve_cfg = agent_stall_repair_config(opts?.stall_diagnostics)
let terminal_write_unverified = false
let made_source_write = false
let terminal_verify_reserve_remaining = if __reserve_cfg.reserved_terminal_verify
|| __reserve_cfg.zero_write_terminal_verify {
__reserve_cfg.reserved_terminal_verify_iterations
} else {
0
}
let terminal_callback_continues = 0
// Session-scoped ownership of long-running handles keeps polling out of the
// model loop. Normalize thresholds and wording once here (harn#4456);
// linked hosts predating `command_wait` receive the defaults.
const command_wait = command_wait_normalize(opts?.command_wait)
let command_ledger = command_ledger_new()
let command_hold_state: CommandHoldState = {reentries: 0}
// One-shot output cap after a progress-only hold: deciding "keep waiting"
// needs no reasoning budget. Nil for normal/result turns and cleared after
// exactly one application.
let command_hold_cap_tokens = nil
while true {
while iteration < current_max {
const boundary_exhaustion = __agent_loop_budget_exhaustion(
harness.agent,
harness.clock,
session.session_id,
budget,
iteration,
nil,
loop_start_ms,
current_max,
)
if boundary_exhaustion.exhausted {
__agent_loop_emit_budget_exhausted(harness.agent, session.session_id, boundary_exhaustion)
budget_exhausted_emitted = true
budget_decisions = __agent_loop_record_budget_stop(
budget_decisions,
iteration,
current_max,
boundary_exhaustion.kind,
)
final_status = "budget_exhausted"
stop_reason = boundary_exhaustion.kind
break
}
let checkpoint = __agent_loop_suspend_checkpoint(
harness.agent,
harness.runtime,
session,
iteration,
)
if checkpoint != nil {
__drain_audit_flushes(audit_background_tasks)
audit_background_tasks = []
suspend_result = checkpoint
final_status = "suspended"
stop_reason = "suspended"
break
}
if agent_budget_pre_call_blocked(harness.agent, session, opts) {
final_status = "budget_exhausted"
break
}
const iteration_index = iteration
const monologue_actuation_prior_read_streak = stall_state.monologue_actuation
.read_only_streak
stall_state = stall_state
+ {monologue_actuation: stall_state.monologue_actuation + {read_only_streak: 0}}
const pending_prefill = agent_take_one_shot_prefill(opts)
opts = pending_prefill.options
const iteration_opts = __agent_loop_effective_llm_options(harness.llm, opts)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_start",
{
iteration: iteration_index + 1,
provider: iteration_opts?.provider ?? "",
model: iteration_opts?.model ?? "",
},
)
try {
__host_drain_file_edits(session.session_id)
} catch (e) {
nil
}
agent_stage(
harness.agent,
session.session_id,
"iteration_start",
{iteration: iteration_index + 1},
)
let turn_opts = agent_skills_match(harness.agent, session, iteration_opts, iteration_index)
if turn_opts?._skill_activated_this_turn ?? false {
opts = agent_reset_tool_surface_narrowing(opts)
turn_opts = agent_reset_tool_surface_narrowing(turn_opts)
}
if opts?.mid_conversation_mcp_mount ?? false {
const skill_mcp_specs = __agent_loop_active_skill_mcp_specs(turn_opts?.active_skills)
if len(skill_mcp_specs) > 0 {
opts = agent_mcp_mount_additional(harness.tools, session, opts, skill_mcp_specs)
const mcp_delta = opts?._mcp_delta_bootstrap
if mcp_delta != nil {
turn_opts = agent_mcp_admit_bootstrap(turn_opts, mcp_delta)
}
}
}
turn_opts = agent_tool_search_inject_if_needed(harness.llm, turn_opts)
turn_opts = agent_apply_tool_surface_narrowing(turn_opts)
turn_opts = agent_stance_apply(turn_opts)
if command_hold_cap_tokens != nil {
turn_opts = turn_opts + {max_tokens: command_hold_cap_tokens}
command_hold_cap_tokens = nil
}
const turn_llm_opts = __turn_llm_opts(harness, session, turn_opts, iteration_index)
agent_stage(
harness.agent,
session.session_id,
"pre_compact",
{iteration: iteration_index + 1},
)
agent_autocompact_if_needed(harness.agent, session, turn_llm_opts)
agent_stage(
harness.agent,
session.session_id,
"post_compact",
{iteration: iteration_index + 1},
)
const input_guardrail_verdict = __run_input_guardrail(
harness.agent,
turn_llm_opts?._input_guardrail ?? opts?._input_guardrail,
session,
message,
turn_llm_opts,
iteration_index,
)
if input_guardrail_verdict != nil && (input_guardrail_verdict.tripwire ?? false) {
__input_guardrail_record_skip_turn(
harness.agent,
harness.llm,
session,
input_guardrail_verdict,
iteration_index,
)
iteration = iteration + 1
final_status = "input_guardrail"
stop_reason = "input_guardrail_tripwire"
break
}
const scope_verdict = __run_pre_turn_scope_classifier(
harness.agent,
turn_llm_opts?._pre_turn_scope_classifier ?? opts?._pre_turn_scope_classifier,
session,
message,
turn_llm_opts,
iteration_index,
)
if __scope_classifier_skip_main(scope_verdict) {
__scope_classifier_record_skip_turn(
harness.agent,
harness.llm,
session,
scope_verdict,
iteration_index,
)
iteration = iteration + 1
final_status = "scope_alert"
stop_reason = "out_of_scope"
break
}
const turn_prompt = __agent_loop_build_turn_prompt(
harness,
session,
turn_llm_opts,
iteration_index,
)
const direct_llm_opts = agent_direct_llm_options(
turn_llm_opts,
turn_prompt,
session.session_id,
iteration_index + 1,
)
const monologue_actuation = agent_monologue_actuation_take_for_turn(
harness.agent,
harness.llm,
session.session_id,
iteration_index + 1,
stall_state.monologue_actuation,
turn_opts,
turn_llm_opts,
pending_prefill.prefill == "",
agent_tool_call_paradigm(harness.llm, turn_llm_opts),
)
stall_state = stall_state + {monologue_actuation: monologue_actuation.state}
const one_shot_prefill = if monologue_actuation.applied {
monologue_actuation.prefill
} else {
pending_prefill.prefill
}
const base_llm_opts = if monologue_actuation.applied {
direct_llm_opts
} else {
__agent_loop_enable_equivalent_failover(
direct_llm_opts,
primary_provider,
primary_model,
opts,
)
}
const llm_opts = if one_shot_prefill != "" {
llm_arm_one_shot_prefill(one_shot_prefill, base_llm_opts)
} else {
base_llm_opts
}
let call = __agent_loop_invoke_main_request(
harness,
message,
turn_prompt.system,
llm_opts,
turn_opts,
session.session_id,
iteration_index,
)
if !call.ok && __agent_loop_is_context_overflow(call?.error) {
call = __agent_loop_recover_context_overflow(
harness,
call,
message,
turn_prompt.system,
llm_opts,
turn_opts,
session,
iteration_index,
)
}
if !call.ok {
const provider_failure = agent_loop_provider_failure(
harness.agent,
harness.clock,
session.session_id,
call,
turn_llm_opts,
{
primary_provider: primary_provider,
primary_model: primary_model,
primary_tool_format: primary_tool_format,
opts: opts,
budget: budget,
iteration: iteration,
iteration_index: iteration_index,
consecutive_failure_count: consecutive_failure_count,
loop_start_ms: loop_start_ms,
current_max: current_max,
escalation_retry_pending: escalation_retry_pending,
budget_exhausted_emitted: budget_exhausted_emitted,
budget_decisions: budget_decisions,
},
)
opts = provider_failure.opts
iteration = provider_failure.iteration
consecutive_failure_count = provider_failure.consecutive_failure_count
escalation_retry_pending = provider_failure.escalation_retry_pending
budget_exhausted_emitted = provider_failure.budget_exhausted_emitted
budget_decisions = provider_failure.budget_decisions
if provider_failure.action == "continue" {
continue
}
final_status = provider_failure.final_status
stop_reason = provider_failure.stop_reason
terminal_error = provider_failure.terminal_error
break
}
escalation_retry_pending = false
const llm_result = call.value
consecutive_failure_count = 0
iteration = iteration + 1
const projection_context = {llm_options: turn_llm_opts, turn_options: turn_opts}
const projected = __agent_loop_project_result(harness.agent, llm_result, projection_context)
const raw_text = projected.raw_text
const parsed = projected.parsed
const visible_text = projected.visible_text
const normalized = projected.normalized
const fallback_outcome = __detect_native_fallback(
harness.agent,
harness.fs,
llm_result,
parsed,
projected.tool_options,
fallback_index,
session.session_id,
iteration_index,
)
fallback_index = fallback_outcome.fallback_index
let tool_calls = if fallback_outcome.triggered {
fallback_outcome.calls ?? []
} else {
__resolve_tool_calls(llm_result, parsed)
}
const recovered_batch_drop = __drop_unsafe_recovered_text_batch(
harness.llm,
parsed,
tool_calls,
projected.tool_options,
)
tool_calls = agent_collapse_duplicate_read_calls(
recovered_batch_drop.tool_calls,
turn_opts?.tools,
turn_opts,
)
const parse_feedback = __agent_loop_record_parse_feedback(
harness,
session.session_id,
normalized,
fallback_outcome,
tool_calls,
parsed,
recovered_batch_drop.feedback,
llm_result,
projected.tool_options,
)
last_turn_parse_dropped = parse_feedback.parse_dropped
const had_parse_errors = parse_feedback.had_parse_errors
const had_full_parse_rejection = parse_feedback.had_full_parse_rejection
const await_call = __agent_await_resumption_call(tool_calls)
if await_call != nil {
const await_parsed = try {
__agent_await_resumption_args(harness.agent, await_call)
}
if !is_err(await_parsed) {
__agent_loop_record_await_tool_results(
harness.agent,
session,
await_call,
tool_calls,
unwrap(await_parsed).reason,
)
}
// The await helper snapshots the session before it returns a
// suspended result. Record the provider turn first so the portable
// checkpoint carries its usage and outcome facts with the messages.
const await_totals = agent_session_record_usage(
harness.agent,
session.session_id,
llm_result,
turn_llm_opts,
iteration_index + 1,
)
const await_result = if is_err(await_parsed) {
await_parsed
} else {
try {
__agent_loop_await_resumption(
harness.agent,
harness.runtime,
session,
iteration,
await_call,
unwrap(await_parsed),
opts,
)
}
}
if is_err(await_result) {
const await_error = unwrap_err(await_result)
if is_err(await_parsed) {
agent_session_record_undispatched_tool_results(
harness.agent,
session.session_id,
tool_calls,
"skipped",
"not dispatched: the agent_await_resumption call in this turn was invalid",
)
}
__inject_feedback_with_tool_repair(
harness.agent,
session.session_id,
"agent_await_resumption",
__agent_loop_invalid_await_resumption_feedback(await_error),
)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_end",
{
iteration: iteration_index + 1,
iteration_info: __agent_loop_iteration_info(
harness.agent,
harness.clock,
session.session_id,
llm_result,
len(tool_calls),
visible_text,
await_totals,
loop_start_ms,
)
+ {dispatch_skipped: true, skip_reason: "invalid_agent_await_resumption"},
},
)
const await_exhaustion = __agent_loop_budget_exhaustion(
harness.agent,
harness.clock,
session.session_id,
budget,
iteration,
await_totals,
loop_start_ms,
current_max,
)
if await_exhaustion.exhausted {
__agent_loop_emit_budget_exhausted(
harness.agent,
session.session_id,
await_exhaustion,
)
budget_exhausted_emitted = true
budget_decisions = __agent_loop_record_budget_stop(
budget_decisions,
iteration,
current_max,
await_exhaustion.kind,
)
final_status = "budget_exhausted"
stop_reason = await_exhaustion.kind
break
}
continue
}
suspend_result = unwrap(await_result)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_end",
{
iteration: iteration_index + 1,
iteration_info: __agent_loop_iteration_info(
harness.agent,
harness.clock,
session.session_id,
llm_result,
len(tool_calls),
visible_text,
await_totals,
loop_start_ms,
),
},
)
final_status = "suspended"
stop_reason = "suspended"
break
}
const stall_judge_due = agent_stall_done_judge_due(
turn_opts,
done_judge_invocations,
iteration_index + 1,
)
const stall_prev_turn_made_edit = __turn_made_edit(stall_prev_dispatch, opts?.tools)
const stall_observation = agent_stall_observe_tool_calls(
harness.agent,
session.session_id,
tool_calls,
iteration_index + 1,
turn_opts?.stall_diagnostics,
stall_state,
stall_judge_due,
stall_prev_dispatch,
visible_text,
had_full_parse_rejection,
stall_prev_turn_made_edit,
llm_result?.stop_reason ?? "",
{
dispatch: stall_prev_dispatch,
iteration: iteration_index + 1,
session_id: session.session_id,
},
)
stall_state = stall_observation.state
stall_enabled_seen = stall_enabled_seen || stall_observation.enabled
if agent_stall_verified_write_satisfied(turn_opts?.stall_diagnostics, stall_state) {
terminal_write_unverified = false
}
const stall_warning = stall_observation.warning
const structural_verdict = __run_structural_validator(
opts?._structural_validator,
session.session_id,
normalized + {raw_text: raw_text},
tool_calls,
parsed,
llm_opts,
turn_opts,
successful_tools_seen,
rejected_tools_seen,
structural_validator_attempts,
)
if structural_verdict.vetoed {
const on_failure = structural_verdict?.on_failure ?? "regenerate_with_feedback"
if on_failure == "raise" {
throw structural_verdict?.diagnostic
?? "structural validator rejected assistant turn"
}
structural_validator_attempts = structural_validator_attempts + 1
__agent_loop_pop_structural_veto_turn(harness.agent, session.session_id)
const feedback = to_string(structural_verdict?.feedback ?? "")
if feedback != "" {
agent_session_inject_feedback(
harness.agent,
session.session_id,
"structural_validator",
feedback,
1,
)
}
const structural_totals = agent_session_record_usage(
harness.agent,
session.session_id,
llm_result,
turn_llm_opts,
iteration_index + 1,
)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_end",
{
iteration: iteration_index + 1,
iteration_info: __agent_loop_iteration_info(
harness.agent,
harness.clock,
session.session_id,
llm_result,
0,
visible_text,
structural_totals,
loop_start_ms,
)
+ {
dispatch_skipped: true,
skip_reason: "structural_validator_revise",
structural_validator_attempts: structural_validator_attempts,
structural_validator_rule: structural_verdict?.rule ?? "",
},
},
)
const structural_exhaustion = __agent_loop_budget_exhaustion(
harness.agent,
harness.clock,
session.session_id,
budget,
iteration,
structural_totals,
loop_start_ms,
current_max,
)
if structural_exhaustion.exhausted {
__agent_loop_emit_budget_exhausted(
harness.agent,
session.session_id,
structural_exhaustion,
)
budget_exhausted_emitted = true
budget_decisions = __agent_loop_record_budget_stop(
budget_decisions,
iteration,
current_max,
structural_exhaustion.kind,
)
final_status = "budget_exhausted"
stop_reason = structural_exhaustion.kind
break
}
continue
} else if !(structural_verdict?.skipped ?? false) {
structural_validator_attempts = 0
}
if stall_judge_due && stall_warning != nil {
const stall_verify_opts = __stall_judge_opts(
turn_opts,
verify_completion_judge_invocations,
done_judge_invocations,
)
+ {_feedback_history: feedback_history}
const stall_verdict = agent_evaluate_completion(
harness,
session,
stall_verify_opts,
"stalled",
visible_text,
iteration_index + 1,
raw_text,
)
done_judge_invocations += __done_judge_hit(stall_verdict)
verify_completion_judge_invocations += __completion_judge_hit(stall_verdict)
feedback_history = stall_verdict?.feedback_history ?? feedback_history
if stall_verdict.action == "stop_unverified" {
__close_stall_calls(
harness.agent,
session.session_id,
tool_calls,
"stopped without verified completion",
)
final_status = "completion_unverified"
stop_reason = __completion_stop_reason(stall_verdict)
break
} else if stall_verdict.action == "continue" {
done_judge_vetoes += __done_judge_hit(stall_verdict)
verify_completion_judge_vetoes += __completion_judge_hit(stall_verdict)
stall_state = __agent_loop_apply_stall_judge_veto(
harness.agent,
harness.clock,
session.session_id,
tool_calls,
stall_verdict,
stall_observation,
stall_warning,
stall_state,
llm_result,
visible_text,
turn_llm_opts,
iteration_index + 1,
loop_start_ms,
)
continue
} else {
__close_stall_calls(
harness.agent,
session.session_id,
tool_calls,
"accepted completion",
)
const stall_totals = agent_session_record_usage(
harness.agent,
session.session_id,
llm_result,
turn_llm_opts,
iteration_index + 1,
)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_end",
{
iteration: iteration_index + 1,
iteration_info: __agent_loop_iteration_info(
harness.agent,
harness.clock,
session.session_id,
llm_result,
len(tool_calls),
visible_text,
stall_totals,
loop_start_ms,
),
},
)
const stall_exhaustion = __agent_loop_budget_exhaustion(
harness.agent,
harness.clock,
session.session_id,
budget,
iteration,
stall_totals,
loop_start_ms,
current_max,
)
if stall_exhaustion.exhausted {
__agent_loop_emit_budget_exhausted(
harness.agent,
session.session_id,
stall_exhaustion,
)
budget_exhausted_emitted = true
budget_decisions = __agent_loop_record_budget_stop(
budget_decisions,
iteration,
current_max,
stall_exhaustion.kind,
)
final_status = "budget_exhausted"
stop_reason = stall_exhaustion.kind
break
}
const stalled_done_checkpoint = agent_stage(
harness.agent,
session.session_id,
"iteration_end",
{iteration: iteration_index + 1, mock_queue: harness.llm.mock_snapshot()},
)
if stalled_done_checkpoint.delivered > 0 {
continue
}
final_status = "done"
stop_reason = "stalled_done_judge"
break
}
}
if stall_observation.hard_stop {
if stall_hard_stop_rescues == 0
&& __agent_loop_thrash_recovery_allowed(stall_warning, tool_calls) {
stall_hard_stop_rescues = stall_hard_stop_rescues + 1
const old_limit = current_max
current_max = max(current_max, iteration + 1)
if len(tool_calls) > 0 {
agent_session_record_undispatched_tool_results(
harness.agent,
session.session_id,
tool_calls,
"skipped",
"not dispatched: repeated identical tool call entered bounded thrash recovery",
)
}
__inject_feedback_with_tool_repair(
harness.agent,
session.session_id,
__agent_loop_thrash_recovery_key(stall_warning),
__agent_loop_thrash_recovery_feedback(stall_warning, visible_text),
)
const thrash_totals = agent_session_record_usage(
harness.agent,
session.session_id,
llm_result,
turn_llm_opts,
iteration_index + 1,
)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_end",
{
iteration: iteration_index + 1,
iteration_info: __agent_loop_iteration_info(
harness.agent,
harness.clock,
session.session_id,
llm_result,
len(tool_calls),
visible_text,
thrash_totals,
loop_start_ms,
)
+ {
dispatch_skipped: true,
skip_reason: __agent_loop_thrash_recovery_skip_reason(stall_warning),
},
},
)
const recovery_reason = __agent_loop_thrash_recovery_reason(stall_warning)
agent_emit_event(
harness.agent,
session.session_id,
"loop_control_decision",
{
iteration: iteration_index + 1,
action: "thrash_rescue",
old_limit: old_limit,
new_limit: current_max,
reason: recovery_reason,
status: "recovering",
},
)
__agent_loop_emit_thrash_recovery_checkpoint(
harness.agent,
session.session_id,
iteration_index + 1,
tool_calls,
stall_warning,
old_limit,
current_max,
"fired",
"thrash_rescue",
recovery_reason,
)
continue
}
// The governor is about to seal a terminal. `postturn.harn` declares
// `__arbitrate_stalled_toolless_turn` THE arbitration point for a turn
// carrying prose and no tool call — but this branch leaves the loop
// before `agent_compute_post_turn` ever runs, so for exactly that turn
// shape the contract was owed an arbitration it never got. A read-only
// task answers in prose; composing the answer is indistinguishable
// from a monologue stall by signature alone, so the run that is
// finishing and the run that is looping both end here.
//
// Arbitrate once, at the moment of the stop. This can only convert a
// terminal, never extend the run: a decline leaves the hard stop
// exactly as it was, so a genuinely looping run still terminates. The
// cadence-driven arbitration above cannot collide with this one —
// every path out of it continues or breaks, so a turn that reaches
// here was never arbitrated. A cadence rations how often a judge runs
// during a run; this is the end of the run, so it asks anyway. The
// invocation caps still apply, and they are the budget that matters.
//
// Only a turn that actually said something is worth arbitrating, and
// only when this run declared someone to arbitrate it. Silence has no
// answer to adjudicate, and an undeclared adjudicator would answer
// `accept` out of an empty plan — silence read as approval.
const stall_arbitration_opts = __stall_judge_opts(
turn_opts,
verify_completion_judge_invocations,
done_judge_invocations,
)
+ {_feedback_history: feedback_history}
if trim(visible_text) != ""
&& agent_completion_adjudicator_declared(stall_arbitration_opts, "stalled") {
const governor_verdict = agent_evaluate_completion(
harness,
session,
stall_arbitration_opts,
"stalled",
visible_text,
iteration_index + 1,
)
done_judge_invocations += __done_judge_hit(governor_verdict)
verify_completion_judge_invocations += __completion_judge_hit(governor_verdict)
feedback_history = governor_verdict?.feedback_history ?? feedback_history
// A judge that hit its invocation cap is marked capped without ever
// being asked, so a plan alone is not proof that anyone answered.
// Only an adjudicator that actually ran may convert a stop into a
// completion; a cap instead reports the completion as unverified,
// which is what it is.
if governor_verdict.action == "accept"
&& __completion_directive_adjudicated(governor_verdict) {
__close_stall_calls(
harness.agent,
session.session_id,
tool_calls,
"accepted completion",
)
const arbitrated_totals = agent_session_record_usage(
harness.agent,
session.session_id,
llm_result,
turn_llm_opts,
iteration_index + 1,
)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_end",
{
iteration: iteration_index + 1,
iteration_info: __agent_loop_iteration_info(
harness.agent,
harness.clock,
session.session_id,
llm_result,
len(tool_calls),
visible_text,
arbitrated_totals,
loop_start_ms,
),
},
)
final_status = "done"
stop_reason = "stalled_done_judge"
break
} else if governor_verdict.action == "stop_unverified" {
__close_stall_calls(
harness.agent,
session.session_id,
tool_calls,
"stopped without verified completion",
)
final_status = "completion_unverified"
stop_reason = __completion_stop_reason(governor_verdict)
break
}
}
const recovery_skip_outcome = __agent_loop_thrash_recovery_skip_outcome(
stall_warning,
tool_calls,
stall_hard_stop_rescues,
)
__agent_loop_emit_thrash_recovery_checkpoint(
harness.agent,
session.session_id,
iteration_index + 1,
tool_calls,
stall_warning,
current_max,
current_max,
"skipped",
"stop",
recovery_skip_outcome,
recovery_skip_outcome,
)
agent_emit_event(
harness.agent,
session.session_id,
"loop_control_decision",
{
iteration: iteration_index + 1,
action: "stop",
old_limit: current_max,
new_limit: current_max,
reason: "thrash_hard_stop",
status: "stuck",
},
)
final_status = "stuck"
stop_reason = "thrash_hard_stop"
break
}
if turn_opts?.step_judge != nil {
const remaining_iterations = current_max - iteration_index
const step_verdict = agent_step_judge(
harness,
session,
llm_result,
turn_opts,
iteration_index + 1,
stall_warning,
step_judge_attempts,
remaining_iterations,
)
if step_verdict.vetoed {
step_judge_attempts = step_judge_attempts + 1
const on_veto = step_verdict?.on_veto ?? "replace"
if on_veto == "replace" {
agent_session_pop_last_assistant(harness.agent, session.session_id)
}
const critique = step_verdict?.feedback ?? step_verdict?.critique ?? ""
if critique != "" {
if on_veto == "replace" {
agent_session_inject_feedback(
harness.agent,
session.session_id,
"step_judge",
critique,
1,
)
} else {
__inject_feedback_with_tool_repair(
harness.agent,
session.session_id,
"step_judge",
critique,
)
}
}
const step_totals = agent_session_record_usage(
harness.agent,
session.session_id,
llm_result,
turn_llm_opts,
iteration_index + 1,
)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_end",
{
iteration: iteration_index + 1,
iteration_info: __agent_loop_iteration_info(
harness.agent,
harness.clock,
session.session_id,
llm_result,
0,
visible_text,
step_totals,
loop_start_ms,
)
+ {
dispatch_skipped: true,
skip_reason: "step_judge_revise",
on_veto: on_veto,
step_judge_attempts: step_judge_attempts,
},
},
)
const step_exhaustion = __agent_loop_budget_exhaustion(
harness.agent,
harness.clock,
session.session_id,
budget,
iteration,
step_totals,
loop_start_ms,
current_max,
)
if step_exhaustion.exhausted {
__agent_loop_emit_budget_exhausted(harness.agent, session.session_id, step_exhaustion)
budget_exhausted_emitted = true
budget_decisions = __agent_loop_record_budget_stop(
budget_decisions,
iteration,
current_max,
step_exhaustion.kind,
)
final_status = "budget_exhausted"
stop_reason = step_exhaustion.kind
break
}
continue
} else if !(step_verdict?.skipped ?? false) {
step_judge_attempts = 0
}
}
const pre_dispatch_checkpoint = agent_stage(
harness.agent,
session.session_id,
"pre_tool_dispatch",
{iteration: iteration_index + 1},
)
if pre_dispatch_checkpoint.dispatch_skipped {
agent_session_record_undispatched_tool_results(
harness.agent,
session.session_id,
tool_calls,
"interrupted",
"a user interrupt arrived before this tool call was dispatched",
)
const tool_count_skipped = len(tool_calls)
const totals_skipped = agent_session_record_usage(
harness.agent,
session.session_id,
llm_result,
turn_llm_opts,
iteration_index + 1,
)
agent_emit_event(
harness.agent,
session.session_id,
"iteration_end",
{
iteration: iteration_index + 1,
iteration_info: __agent_loop_iteration_info(
harness.agent,
harness.clock,
session.session_id,
llm_result,
tool_count_skipped,
visible_text,
totals_skipped,
loop_start_ms,
)
+ {dispatch_skipped: true, skip_reason: "interrupt_immediate"},
},
)
const skipped_exhaustion = __agent_loop_budget_exhaustion(
harness.agent,
harness.clock,
session.session_id,
budget,
iteration,
totals_skipped,
loop_start_ms,
current_max,
)
if skipped_exhaustion.exhausted {
__agent_loop_emit_budget_exhausted(
harness.agent,
session.session_id,
skipped_exhaustion,
)
budget_exhausted_emitted = true
budget_decisions = __agent_loop_record_budget_stop(
budget_decisions,
iteration,
current_max,
skipped_exhaustion.kind,
)
final_status = "budget_exhausted"
stop_reason = skipped_exhaustion.kind
break
}
const skipped_budget_stop = agent_budget_post_call_stop_reason(totals_skipped, turn_opts)
if skipped_budget_stop != "" {
final_status = "budget_exhausted"
stop_reason = skipped_budget_stop
break
}
consecutive_text_only = __next_text_only_count(0, consecutive_text_only)
turns_since_progress = __next_progress_count(false, turns_since_progress)
last_tool_count = 0
continue
}
const dispatched = __dispatch_tool_calls(
harness,
session.session_id,
tool_calls,
turn_opts
+ {
_iteration: iteration_index + 1,
_tool_caller: opts?._tool_caller,
_stop_reason: llm_result?.stop_reason ?? "",
},
)
const dispatch = dispatched.dispatch
const actuation_dispatch_results = __dispatch_results_list(dispatch)
const completed_observation = __agent_loop_completed_dispatch_stall(
{
harness: harness,
session_id: session.session_id,
tool_calls: tool_calls,
dispatch: dispatch,
iteration: iteration_index + 1,
stall_config: stall_observation.config,
stall_state: stall_state,
turn_opts: turn_opts,
prior_read_streak: monologue_actuation_prior_read_streak,
},
)
stall_state = completed_observation.state
// Register long-running handles (`status=="running"` with a `handle_id`).
// Awaited rows gate the next no-tool-call boundary into a hold; the
// loop owns the decision cadence, so the model never polls.
command_ledger = command_ledger_ingest(
command_ledger,
actuation_dispatch_results,
__agent_loop_clock_now_ms(harness.clock),
command_wait,
)
audit_background_tasks = __spawn_audit_flushes(
audit_background_tasks,
dispatched.audit_flushes,
)
opts = __sync_tool_search_state(opts, dispatched.turn_opts)
successful_tools_seen = __merge_tool_names(
successful_tools_seen,
__tool_names_by_status(dispatch, true),
)
rejected_tools_seen = __merge_tool_names(
rejected_tools_seen,
__tool_names_by_status(dispatch, false),
)
const post_dispatch = __agent_loop_post_dispatch(
harness,
session.session_id,
llm_result,
turn_llm_opts,
iteration_index,
tool_calls,
visible_text,
loop_start_ms,
current_max,
dispatch,
stall_prev_dispatch,
)
const totals = post_dispatch.totals
const tool_count = len(tool_calls)
const bridge_step_delivered = post_dispatch.bridge_step_delivered
if post_dispatch.terminal != nil {
final_status = "error"
stop_reason = post_dispatch.terminal.reason
terminal_error = post_dispatch.terminal.error
break
}
stall_prev_dispatch = dispatch
const exhaustion = __agent_loop_budget_exhaustion(
harness.agent,
harness.clock,
session.session_id,
budget,
iteration,
totals,
loop_start_ms,
current_max,
)
if exhaustion.exhausted {
__agent_loop_emit_budget_exhausted(harness.agent, session.session_id, exhaustion)
budget_exhausted_emitted = true
budget_decisions = __agent_loop_record_budget_stop(
budget_decisions,
iteration,
current_max,
exhaustion.kind,
)
final_status = "budget_exhausted"
stop_reason = exhaustion.kind
break
}
const budget_stop = agent_budget_post_call_stop_reason(totals, turn_opts)
if budget_stop != "" {
final_status = "budget_exhausted"
stop_reason = budget_stop
break
}
const hold_transition = agent_loop_command_hold_transition(
harness,
session.session_id,
{
ledger: command_ledger,
command_wait: command_wait,
hold_state: command_hold_state,
reentry_cap: command_hold_cap_tokens,
iteration: iteration_index + 1,
tool_count: tool_count,
},
)
command_ledger = hold_transition.ledger
command_hold_state = hold_transition.hold_state
command_hold_cap_tokens = hold_transition.reentry_cap
if hold_transition.action == "continue" {
if hold_transition.reset_progress {
consecutive_text_only = 0
turns_since_progress = 0
}
continue
}
const post_turn_transition = agent_loop_post_turn_transition(
harness,
session,
{
budget: budget,
bridge_step_delivered: bridge_step_delivered,
completed_no_information_gain: completed_observation.no_information_gain,
consecutive_failure_count: consecutive_failure_count,
dispatch: dispatch,
dispatched_turn_opts: dispatched.turn_opts,
fallback_accepted: fallback_outcome.accepted,
fallback_triggered: fallback_outcome.triggered,
had_parse_errors: had_parse_errors,
iteration: iteration,
iteration_index: iteration_index,
llm_result: llm_result,
loop_start_ms: loop_start_ms,
normalized: normalized,
parsed_done_marker: parsed?.done_marker ?? "",
raw_text: raw_text,
rejected_tools_seen: rejected_tools_seen,
successful_tools_seen: successful_tools_seen,
tool_calls: tool_calls,
totals: totals,
turn_llm_opts: turn_llm_opts,
turn_opts: turn_opts,
visible_text: visible_text,
},
{
budget_decisions: budget_decisions,
consecutive_text_only: consecutive_text_only,
current_max: current_max,
done_judge_invocations: done_judge_invocations,
done_judge_vetoes: done_judge_vetoes,
extensions_used: extensions_used,
feedback_history: feedback_history,
final_status: final_status,
last_tool_count: last_tool_count,
made_source_write: made_source_write,
opts: opts,
stall_state: stall_state,
stop_reason: stop_reason,
terminal_write_unverified: terminal_write_unverified,
turns_since_progress: turns_since_progress,
verify_attempts: verify_attempts,
verify_completion_judge_invocations: verify_completion_judge_invocations,
verify_completion_judge_vetoes: verify_completion_judge_vetoes,
},
max_verify_attempts,
)
const post_turn_state = post_turn_transition.state
budget_decisions = post_turn_state.budget_decisions
consecutive_text_only = post_turn_state.consecutive_text_only
current_max = post_turn_state.current_max
done_judge_invocations = post_turn_state.done_judge_invocations
done_judge_vetoes = post_turn_state.done_judge_vetoes
extensions_used = post_turn_state.extensions_used
feedback_history = post_turn_state.feedback_history
final_status = post_turn_state.final_status
last_tool_count = post_turn_state.last_tool_count
made_source_write = post_turn_state.made_source_write
opts = post_turn_state.opts
stall_state = post_turn_state.stall_state
stop_reason = post_turn_state.stop_reason
terminal_write_unverified = post_turn_state.terminal_write_unverified
turns_since_progress = post_turn_state.turns_since_progress
verify_attempts = post_turn_state.verify_attempts
verify_completion_judge_invocations = post_turn_state.verify_completion_judge_invocations
verify_completion_judge_vetoes = post_turn_state.verify_completion_judge_vetoes
if post_turn_transition.action == "break" {
break
}
continue
}
const terminal_boundary = __agent_loop_terminal_boundary(
harness,
session,
{
opts: opts,
final_status: final_status,
stop_reason: stop_reason,
reserve_cfg: __reserve_cfg,
terminal_write_unverified: terminal_write_unverified,
made_source_write: made_source_write,
terminal_verify_reserve_remaining: terminal_verify_reserve_remaining,
verify_attempts: verify_attempts,
max_verify_attempts: max_verify_attempts,
verify_completion_judge_invocations: verify_completion_judge_invocations,
verify_completion_judge_vetoes: verify_completion_judge_vetoes,
done_judge_invocations: done_judge_invocations,
iteration: iteration,
current_max: current_max,
budget: budget,
budget_exhausted_emitted: budget_exhausted_emitted,
budget_decisions: budget_decisions,
terminal_callback_continues: terminal_callback_continues,
suspend_result: suspend_result,
terminal_error: terminal_error,
last_turn_parse_dropped: last_turn_parse_dropped,
stall_state: stall_state,
successful_tools_seen: successful_tools_seen,
rejected_tools_seen: rejected_tools_seen,
feedback_history: feedback_history,
},
)
opts = terminal_boundary.opts
final_status = terminal_boundary.final_status
stop_reason = terminal_boundary.stop_reason
terminal_write_unverified = terminal_boundary.terminal_write_unverified
stall_state = terminal_boundary.stall_state
terminal_verify_reserve_remaining = terminal_boundary.terminal_verify_reserve_remaining
verify_attempts = terminal_boundary.verify_attempts
verify_completion_judge_invocations = terminal_boundary.verify_completion_judge_invocations
verify_completion_judge_vetoes = terminal_boundary.verify_completion_judge_vetoes
current_max = terminal_boundary.current_max
budget_exhausted_emitted = terminal_boundary.budget_exhausted_emitted
budget_decisions = terminal_boundary.budget_decisions
terminal_callback_continues = terminal_boundary.terminal_callback_continues
terminal_error = terminal_boundary.terminal_error
feedback_history = terminal_boundary.feedback_history ?? feedback_history
if terminal_boundary.action == "continue" {
continue
}
break
}
const finalized = __agent_loop_finalize_session(
harness,
message,
session,
{
opts: opts,
final_status: final_status,
stop_reason: stop_reason,
iteration: iteration,
loop_start_ms: loop_start_ms,
suspend_result: suspend_result,
terminal_error: terminal_error,
audit_background_tasks: audit_background_tasks,
budget: budget,
budget_exhausted_emitted: budget_exhausted_emitted,
budget_decisions: budget_decisions,
current_max: current_max,
extensions_used: extensions_used,
last_tool_count: last_tool_count,
stall_state: stall_state,
stall_enabled_seen: stall_enabled_seen,
verify_completion_judge_invocations: verify_completion_judge_invocations,
verify_completion_judge_vetoes: verify_completion_judge_vetoes,
done_judge_invocations: done_judge_invocations,
done_judge_vetoes: done_judge_vetoes,
},
)
session_finalized = true
const final_result = __agent_loop_project_final_result(
harness,
finalized.result,
message,
session,
{
opts: opts,
final_status: final_status,
stop_reason: stop_reason,
iteration: iteration,
suspend_result: suspend_result,
terminal_error: terminal_error,
budget: budget,
budget_decisions: finalized.budget_decisions,
current_max: current_max,
extensions_used: extensions_used,
stall_state: stall_state,
stall_enabled_seen: stall_enabled_seen,
verify_completion_judge_invocations: verify_completion_judge_invocations,
verify_completion_judge_vetoes: verify_completion_judge_vetoes,
done_judge_invocations: done_judge_invocations,
done_judge_vetoes: done_judge_vetoes,
},
)
final_result
}
if is_err(run) {
__drain_audit_flushes(audit_background_tasks)
if !session_finalized {
__agent_loop_finalize_failed(harness.agent, session, iteration)
}
throw unwrap_err(run)
}
return unwrap(run)
}