harn-stdlib 0.10.118

Embedded Harn standard library source catalog
Documentation
import "std/agent/loop_tool_calls"
import "std/agent/loop_turn_options"
import "std/agent/state"

pub type AgentLoopAwaitState = {
  budget: dict,
  iteration: int,
  iteration_index: int,
  opts: dict,
  visible_text: string,
  loop_start_ms: int,
  current_max: int,
  budget_exhausted_emitted: bool,
  budget_decisions: list,
}

pub type AgentLoopAwaitOutcome = {
  action: "continue" | "break",
  suspend_result: any,
  final_status: string,
  stop_reason: string,
  budget_exhausted_emitted: bool,
  budget_decisions: list,
}

pub type AgentLoopAwaitTurn = {
  session: dict,
  call: dict,
  tool_calls: list,
  llm_result: dict,
  llm_options: dict,
}

/**
 * Resolve an `agent_await_resumption` call and record its complete turn evidence.
 *
 * @effects: [agent]
 * @errors: [runtime]
 */
pub fn agent_loop_await(
  agent: HarnessAgent,
  runtime: HarnessRuntime,
  clock: HarnessClock,
  turn: AgentLoopAwaitTurn,
  state: AgentLoopAwaitState,
) -> AgentLoopAwaitOutcome {
  const session = turn.session
  const await_call = turn.call
  const tool_calls = turn.tool_calls
  const llm_result = turn.llm_result
  const turn_llm_opts = turn.llm_options
  const await_parsed = try {
    __agent_await_resumption_args(agent, await_call)
  }
  if !is_err(await_parsed) {
    __agent_loop_record_await_tool_results(
      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(
    agent,
    session.session_id,
    llm_result,
    turn_llm_opts,
    state.iteration_index + 1,
  )
  const await_result = if is_err(await_parsed) {
    await_parsed
  } else {
    try {
      __agent_loop_await_resumption(
        agent,
        runtime,
        session,
        state.iteration,
        await_call,
        unwrap(await_parsed),
        state.opts,
      )
    }
  }
  if is_err(await_result) {
    const await_error = unwrap_err(await_result)
    if is_err(await_parsed) {
      agent_session_record_undispatched_tool_results(
        agent,
        session.session_id,
        tool_calls,
        "skipped",
        "not dispatched: the agent_await_resumption call in this turn was invalid",
      )
    }
    __inject_feedback_with_tool_repair(
      agent,
      session.session_id,
      "agent_await_resumption",
      __agent_loop_invalid_await_resumption_feedback(await_error),
    )
    agent_emit_event(
      agent,
      session.session_id,
      "iteration_end",
      {
        iteration: state.iteration_index + 1,
        iteration_info: __agent_loop_iteration_info(
          agent,
          clock,
          session.session_id,
          llm_result,
          len(tool_calls),
          state.visible_text,
          await_totals,
          state.loop_start_ms,
        )
          + {dispatch_skipped: true, skip_reason: "invalid_agent_await_resumption"},
      },
    )
    const await_exhaustion = __agent_loop_budget_exhaustion(
      agent,
      clock,
      session.session_id,
      state.budget,
      state.iteration,
      await_totals,
      state.loop_start_ms,
      state.current_max,
    )
    if await_exhaustion.exhausted {
      __agent_loop_emit_budget_exhausted(agent, session.session_id, await_exhaustion)
      return {
        action: "break",
        suspend_result: nil,
        final_status: "budget_exhausted",
        stop_reason: await_exhaustion.kind,
        budget_exhausted_emitted: true,
        budget_decisions: __agent_loop_record_budget_stop(
          state.budget_decisions,
          state.iteration,
          state.current_max,
          await_exhaustion.kind,
        ),
      }
    }
    return {
      action: "continue",
      suspend_result: nil,
      final_status: "",
      stop_reason: "",
      budget_exhausted_emitted: state.budget_exhausted_emitted,
      budget_decisions: state.budget_decisions,
    }
  }
  const suspend_result = unwrap(await_result)
  agent_emit_event(
    agent,
    session.session_id,
    "iteration_end",
    {
      iteration: state.iteration_index + 1,
      iteration_info: __agent_loop_iteration_info(
        agent,
        clock,
        session.session_id,
        llm_result,
        len(tool_calls),
        state.visible_text,
        await_totals,
        state.loop_start_ms,
      ),
    },
  )
  return {
    action: "break",
    suspend_result: suspend_result,
    final_status: "suspended",
    stop_reason: "suspended",
    budget_exhausted_emitted: state.budget_exhausted_emitted,
    budget_decisions: state.budget_decisions,
  }
}