harn-stdlib 0.10.129

Embedded Harn standard library source catalog
Documentation
// @harn-entrypoint-category agent.stdlib
import { AgentLoopTerminalError, AgentResult } from "std/agent/contracts"
import { __agent_loop_run } from "std/agent/loop_run"
import "std/agent/loop_support"
import {
  __agent_loop_fire_resume_continuity,
  __loop_progress_nudge_text,
} from "std/agent/loop_turn_options"
import { agent_tool_format_override_warning_text } from "std/agent/options"
import {
  agent_purpose_label_config,
  agent_purpose_label_prompt_fragment,
} from "std/agent/purpose_labels"

pub fn __progress_nudge_text(
  depth: int,
  has_tools: any,
  paradigm: dict,
  made_tool_calls: bool = false,
) {
  return __loop_progress_nudge_text(depth, has_tools, paradigm, made_tool_calls)
}

/**
 * agent_loop.
 *
 * @effects: [host, agent]
 * Throws `AgentLoopTerminalError` for every exceptional terminal. Its
 * `provider_call_count` is an integer when measured and nil only when the
 * session ledger itself is unavailable.
 *
 * @errors: [runtime]
 * @api_stability: experimental
 */
pub fn agent_loop(
  harness: Harness,
  message: any,
  system_prompt: any = nil,
  options: any = nil,
) -> AgentResult {
  let session: dict? = nil
  let session_finalized = false
  // Private lexical provenance distinguishes an inner normalized terminal
  // from a caller-supplied dictionary with the same public shape.
  let inner_terminal: AgentLoopTerminalError? = nil
  try {
    let opts = agent_loop_options(harness, agent_progress_apply_options(harness.agent, options))
    // Lifecycle composition owns the agent projection so direct callers and
    // this default path share one validated, closure-preserving boundary.
    opts = opts + {tools: agent_lifecycle_tools(harness.agent, opts?.tools, opts)}
    // Teaching the declaration grammar is part of the mechanism, so it lives
    // with the mechanism rather than in each host's prompt prose. The fragment
    // is empty unless the caller turned purpose labels on.
    const purpose_fragment = agent_purpose_label_prompt_fragment(
      agent_purpose_label_config(opts?.purpose_labels),
    )
    const effective_system = if purpose_fragment == "" {
      system_prompt
    } else if system_prompt == nil || system_prompt == "" {
      purpose_fragment
    } else {
      to_string(system_prompt) + "\n\n" + purpose_fragment
    }
    if effective_system != nil && effective_system != "" {
      opts = opts + {_primary_system: effective_system}
    }
    const initialized_session = agent_session_init(harness.agent, message, effective_system, opts)
    session = initialized_session
    if initialized_session.done {
      session_finalized = true
      const completed_result = initialized_session.result
      if !schema_is(completed_result, schema_of(AgentResult)) {
        throw "agent_loop: completed session result violated AgentResult"
      }
      return completed_result
    }
    agent_scratchpad_init(harness.agent, initialized_session, opts)
    if opts?._tool_format_override != nil {
      agent_emit_event(
        harness.agent,
        initialized_session.session_id,
        "tool_format_override",
        opts._tool_format_override,
      )
      const warning = agent_tool_format_override_warning_text(opts._tool_format_override)
      if warning != nil {
        harness.stdio.eprintln(warning)
      }
    }
    if opts?._tool_format_capability_gap != nil {
      agent_emit_event(
        harness.agent,
        initialized_session.session_id,
        "capability_gap",
        opts._tool_format_capability_gap,
      )
    }
    defer {
      try {
        __host_mcp_disconnect(initialized_session.session_id)
      } catch (e) {
      }
    }
    opts = __agent_loop_fire_resume_continuity(harness.agent, initialized_session, opts)
    opts = agent_stance_prepare(harness, initialized_session, message, opts)
    const outcome = __agent_loop_run(harness, message, initialized_session, opts)
    if outcome.kind == "completed" {
      session_finalized = true
      return outcome.result
    }
    inner_terminal = outcome.error
    throw outcome.error
  } catch (error) {
    if inner_terminal != nil {
      throw inner_terminal
    }
    const terminal: AgentLoopTerminalError = __agent_loop_normalize_boundary_error(
      harness.agent,
      session,
      error,
      session_finalized,
    )
    throw terminal
  }
}