harn-stdlib 0.10.128

Embedded Harn standard library source catalog
Documentation
import {
  __agent_await_resumption_args,
  __agent_loop_await_resumption,
  __agent_loop_invalid_await_resumption_feedback,
  __agent_loop_record_await_tool_results,
  __inject_feedback_with_tool_repair,
} from "std/agent/loop_tool_calls"
import {
  __agent_loop_budget_exhaustion,
  __agent_loop_emit_budget_exhausted,
  __agent_loop_iteration_info,
  __agent_loop_record_budget_stop,
} from "std/agent/loop_turn_options"
import {
  agent_emit_event,
  agent_session_record_undispatched_tool_results,
  agent_session_record_usage,
} from "std/agent/state"

/** Whether the turn loop breaks out or starts its next iteration. */
pub type AgentLoopAwaitAction = "break" | "continue"

/** Everything the await turn reads from the loop that owns it. */
pub type AgentLoopAwaitContext = {
  await_call: any,
  budget: any,
  budget_decisions: any,
  budget_exhausted_emitted: bool,
  current_max: int,
  final_status: string,
  iteration: int,
  iteration_index: int,
  llm_result: any,
  loop_start_ms: int | float,
  opts: any,
  stop_reason: any,
  suspend_result: any,
  tool_calls: any,
  turn_llm_opts: any,
  visible_text: string,
}

/** The loop state this turn hands back, plus what the loop should do next. */
pub type AgentLoopAwaitOutcome = {
  action: AgentLoopAwaitAction,
  final_status: string,
  stop_reason: any,
  suspend_result: any,
  budget_exhausted_emitted: bool,
  budget_decisions: any,
}

/**
 * Run the turn in which the model called `agent_await_resumption`.
 *
 * Moved out of the run loop unchanged. It is expressed as an outcome rather
 * than as inline control flow for one reason only: a function cannot `break`
 * its caller's loop, so the two breaks and the one continue become an `action`
 * the caller re-dispatches. Every other line is the code that was inline.
 *
 * This turn never falls through. It either suspends the session, or it repairs
 * an invalid call and asks for another iteration, or it stops on an exhausted
 * budget.
 *
 * @effects: [event, agent]
 * @errors: []
 * @api_stability: internal
 * @example: __agent_loop_await_turn(harness, session, ctx)
 */
pub fn __agent_loop_await_turn(
  harness: Harness,
  session: any,
  ctx: AgentLoopAwaitContext,
) -> AgentLoopAwaitOutcome {
  const await_call = ctx.await_call
  const budget = ctx.budget
  const current_max = ctx.current_max
  const iteration = ctx.iteration
  const iteration_index = ctx.iteration_index
  const llm_result = ctx.llm_result
  const loop_start_ms = ctx.loop_start_ms
  const opts = ctx.opts
  const tool_calls = ctx.tool_calls
  const turn_llm_opts = ctx.turn_llm_opts
  const visible_text = ctx.visible_text
  let budget_decisions = ctx.budget_decisions
  let budget_exhausted_emitted = ctx.budget_exhausted_emitted
  let final_status = ctx.final_status
  let stop_reason = ctx.stop_reason
  let suspend_result = ctx.suspend_result
  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
      return {
        action: "break",
        final_status: final_status,
        stop_reason: stop_reason,
        suspend_result: suspend_result,
        budget_exhausted_emitted: budget_exhausted_emitted,
        budget_decisions: budget_decisions,
      }
    }
    return {
      action: "continue",
      final_status: final_status,
      stop_reason: stop_reason,
      suspend_result: suspend_result,
      budget_exhausted_emitted: budget_exhausted_emitted,
      budget_decisions: budget_decisions,
    }
  }
  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"
  return {
    action: "break",
    final_status: final_status,
    stop_reason: stop_reason,
    suspend_result: suspend_result,
    budget_exhausted_emitted: budget_exhausted_emitted,
    budget_decisions: budget_decisions,
  }
}