harn-stdlib 0.10.129

Embedded Harn standard library source catalog
Documentation
import "std/agent/loop_resource_dispatch"
import "std/agent/loop_result_status"
import "std/agent/loop_support"
import "std/agent/loop_tool_calls"
import "std/agent/loop_turn_options"
import "std/agent/loop_turn_scope"

/*
 * The typed cause of a suspension, for the host that has to tell a person why
 * the run stopped and what would let it continue.
 *
 * `agent_await_resumption` validates the reason and the resume conditions at
 * the call that produces them, and the suspend record keeps both. This hands
 * that record to the finalize seam unchanged rather than re-deriving a summary
 * the loop already has. A run that did not park contributes nothing, and so
 * does a park with no declared reason, so an absent record always means there
 * was no cause to carry and never that one was dropped.
 */
fn __agent_loop_suspension_record(suspend_result: any) -> dict? {
  if suspend_result == nil {
    return nil
  }
  const reason = trim(to_string(suspend_result?.reason ?? ""))
  if reason == "" {
    return nil
  }
  return {
    reason: reason,
    initiator: to_string(suspend_result?.initiator ?? ""),
    conditions: suspend_result?.conditions,
  }
}

/*
 * Terminal bookkeeping lives outside the turn engine so the engine can stay
 * focused on one iteration's control flow. The state record is deliberately
 * assembled by loop_run: it keeps this boundary explicit without making the
 * Harn module depend on a second, parallel result schema.
 */
pub fn __agent_loop_finalize(harness: Harness, message: any, session: dict, state: dict) -> dict {
  let final_status = state.final_status
  let stop_reason = state.stop_reason
  let budget_exhausted_emitted = state.budget_exhausted_emitted
  let budget_decisions = state.budget_decisions
  if final_status == "budget_exhausted" && !budget_exhausted_emitted {
    const projection = __agent_loop_budget_error_projection(state.terminal_error)
    const terminal_exhaustion = __agent_loop_budget_aggregates(
      harness.agent,
      harness.clock,
      session.session_id,
      nil,
      state.loop_start_ms,
    )
      + {
        exhausted: true,
        // Naming a default ceiling here would invent a cause: a break that left
        // `stop_reason` unset reached this seam without one, and guessing
        // "max_iterations" reads as a spent iteration budget even at iteration 1
        // of 8. Say the reason is missing and let the reader go look.
        kind: stop_reason ?? "unattributed",
        iteration: state.iteration,
        max_iterations: state.current_max,
      }
    __agent_loop_emit_budget_exhausted(
      harness.agent,
      session.session_id,
      terminal_exhaustion,
      projection,
    )
    budget_exhausted_emitted = true
    budget_decisions = __agent_loop_record_budget_stop(
      budget_decisions,
      state.iteration,
      state.current_max,
      terminal_exhaustion.kind,
    )
  }
  const opts = state.opts
  const suspend_result = state.suspend_result
  const terminal_error = state.terminal_error
  const wrapup_enabled = opts?.final_wrapup ?? true
  // A no-tool terminal normally skips wrap-up (nothing to summarize), but a
  // host that supplied its own directive is explicitly asking for sad-path
  // coverage — including the zero-write terminals where the user is most owed
  // a truthful closing message — so honor it even at last_tool_count == 0.
  const wrapup_tools_ok = state.last_tool_count > 0
    || __agent_loop_has_host_wrapup_directive(opts)
  if wrapup_enabled
    && suspend_result == nil
    && terminal_error == nil
    && wrapup_tools_ok
    && __agent_loop_wrapup_eligible_status(final_status) {
    let _ = try {
      __agent_loop_final_wrapup(
        harness,
        message,
        session,
        opts,
        final_status,
        stop_reason,
        state.iteration,
      )
    }
  }
  const output_contract = if terminal_error == nil
    && suspend_result == nil
    && (final_status == "" || final_status == "done")
    && __agent_loop_has_terminal_output_contract(opts) {
    __agent_loop_prepare_output_contract(harness, opts, session, state.iteration)
  } else {
    nil
  }
  if opts?.daemon && final_status != "" {
    agent_daemon_snapshot(harness.agent, session, opts, final_status, state.iteration)
  }
  try {
    __host_drain_file_edits(session.session_id)
  } catch (e) {
    nil
  }
  agent_stage(harness.agent, session.session_id, "loop_exit", {iteration: state.iteration})
  __drain_audit_flushes(state.audit_background_tasks)
  const result = agent_session_finalize(
    harness.agent,
    session.session_id,
    {
      final_status: final_status,
      stop_reason: __agent_loop_sealed_stop_reason(stop_reason, final_status),
      iterations: state.iteration,
      error: terminal_error,
      suspension: __agent_loop_suspension_record(suspend_result),
    },
  )
  return {result: result, budget_decisions: budget_decisions, output_contract: output_contract}
}

pub fn __agent_loop_project_terminal_result(
  harness: Harness,
  result: any,
  message: any,
  session: dict,
  state: dict,
) -> dict {
  const opts = state.opts
  const final_status = state.final_status
  const stop_reason = state.stop_reason
  const suspend_result = state.suspend_result
  const terminal_error = state.terminal_error
  const terminated_ok = terminal_error == nil
    && suspend_result == nil
    && (final_status == "" || final_status == "done")
  const final_stall_state = if terminated_ok {
    agent_stall_clear_current_failure(state.stall_state)
  } else {
    state.stall_state
  }
  const result_with_stalls = agent_stall_apply_result(
    result,
    state.stall_enabled_seen,
    final_stall_state,
  )
  const enforced = if suspend_result != nil {
    result_with_stalls
  } else {
    agent_required_tools_enforce(harness.agent, harness.obs, result_with_stalls, opts)
  }
  let final_result = enforced
  if opts?.verify_completion_judge != nil {
    final_result = final_result
      + {
        completion_judge: {
          invocations: state.verify_completion_judge_invocations,
          vetoes: state.verify_completion_judge_vetoes,
          max_invocations: agent_verify_completion_judge_cap(
            opts?.verify_completion_judge,
            agent_completion_review(harness.llm, opts),
          ),
          cap_reached: final_status == "completion_unverified"
            && stop_reason
              == "completion_judge_cap_reached",
        },
      }
  }
  if agent_has_turn_end_condition(opts?.turn_end_condition) {
    final_result = final_result
      + {
        turn_end_condition: {
          invocations: state.turn_end_judge_invocations,
          vetoes: state.turn_end_judge_vetoes,
          max_invocations: agent_turn_end_judge_cap(opts?.turn_end_condition),
          cap_reached: final_status == "completion_unverified"
            && stop_reason == "turn_end_judge_cap_reached",
        },
      }
  }
  const budget = state.budget
  if budget.expose_decisions {
    final_result = final_result
      + {
        adaptive_budget: {
          mode: budget.mode,
          initial: budget.initial,
          max: budget.max,
          final_limit: state.current_max,
          extensions_used: state.extensions_used,
          decisions: state.budget_decisions,
        },
      }
  }
  // harn#7915: the abandonment evidence rides BESIDE the terminal, on the same
  // result the host already reads, so the typed kind says the run failed and
  // this says what the loop saw. Absent whenever the run was not convicted, so
  // a present record always means the rule fired and never that a default was
  // stamped.
  const abandonment = state?.abandonment
  if abandonment != nil {
    final_result = final_result + {abandonment: abandonment}
  }
  // harn#7915 cause 3: the declared-artifact audit is reported on every run
  // that declared a contract, PASSING RUNS INCLUDED. A verdict published only
  // on conviction would be indistinguishable from a contract that was never
  // checked, and a caller could not tell a satisfied declaration from a
  // skipped one.
  const declared_artifacts = state?.declared_artifacts
  if declared_artifacts != nil {
    final_result = final_result + {declared_artifacts: declared_artifacts}
  }
  if suspend_result != nil {
    final_result = final_result + suspend_result
  }
  if terminated_ok && state.output_contract != nil {
    final_result = final_result + state.output_contract
  }
  return final_result
}