harn-stdlib 0.10.44

Embedded Harn standard library source catalog
Documentation
pub import { agent_unheeded_recurring_diagnostic } from "std/agent/recurring_diagnostic"
pub import { agent_stall_initial_state } from "std/agent/stall_config"
pub import {
  detector_action_of,
  detector_spec_to_stall,
  detector_spec_token_runaway,
  token_runaway_decision,
  token_runaway_made_progress,
  token_runaway_post_turn,
  token_runaway_resolve_cap,
  unified_detectors_post_turn,
} from "std/agent/stall_detectors"
pub import {
  agent_stall_inject_feedback,
  agent_stall_observe_tool_calls,
} from "std/agent/stall_observation"
pub import {
  AgentStallConfig,
  AgentStallObservation,
  AgentStallState,
  AgentStallWarning,
} from "std/agent/stall_types"
pub import {
  agent_stall_apply_result,
  agent_stall_clear_current_failure,
  agent_stall_current_failure,
  agent_stall_done_judge_due,
  agent_stall_no_net_progress,
  agent_stall_repair_config,
  agent_stall_repeated_verified_pass,
  agent_stall_verified_write_satisfied,
} from "std/agent/stall_verification"

// Keep this public alias on the facade: runtime `pub import` re-exports carry
// type schemas, but the type checker currently resolves consumer annotations
// only from aliases declared directly in the imported module.
pub type DetectorSpec = {
  enabled?: bool,
  hard_stop_after_trips?: int,
  loop?: {ping_pong_cycles?: int, repeat?: int},
  no_progress?: {messages?: int},
  stuck?: {same_diagnostic?: int, same_error?: int},
  token_runaway?: {
    fallback?: float,
    hard_multiple?: float,
    median?: float,
    sigma?: float,
    stddev?: float,
  },
}

pub type RecurringDiagnosticCategory = "syntax" | "resolution" | "type" | "semantic" | "unknown"

pub type DiagnosticCategoryPattern = {pattern: string, category: RecurringDiagnosticCategory}

pub type DiagnosticCategories = {
  codes?: dict<string, RecurringDiagnosticCategory>,
  patterns?: list<DiagnosticCategoryPattern>,
}

pub type UnheededRecurringDiagnostic = {
  signature: string,
  category: RecurringDiagnosticCategory,
  streak: int,
  first_attempt: int,
  last_attempt: int,
  location: string?,
  message: string,
}

pub type RecurringDiagnosticState = {
  signatures: list<string>,
  diagnostic_count: int,
  signature: string,
  category: RecurringDiagnosticCategory,
  streak: int,
  first_attempt: int,
  last_attempt: int,
  location: string?,
  message: string,
}

pub type RecurringDiagnosticObservation = {
  state: RecurringDiagnosticState?,
  signal: UnheededRecurringDiagnostic?,
}

/** One caller-declared environment surface used to judge action futility. */
pub type AgentObservationSurface = {
  name: string,
  value?: any,
  fingerprint?: string,
  observable?: bool,
  evidence?: string,
}

/** Canonical fingerprint of the observable subset of an environment. */
pub type AgentObservationFingerprint = {
  fingerprint: string?,
  surfaces: list<{name: string, fingerprint: string, evidence?: string}>,
}

/** Stable identity for deciding whether an agent repeated the same action. */
pub type AgentActionIdentity = {name: string, arguments_fingerprint: string, identity: string}

/** Structural verdict for an action's before/after environment observations. */
pub type AgentFutilityVerdict = {
  kind: "changed" | "unchanged" | "unobservable",
  action: AgentActionIdentity,
  repeated_action: bool,
  before_fingerprint: string?,
  after_fingerprint: string?,
  compared_surfaces: list<string>,
  evidence: list<{
    surface: string,
    before_fingerprint: string,
    after_fingerprint: string,
    changed: bool,
    before_evidence?: string,
    after_evidence?: string,
  }>,
}

pub type AgentFutilityPolicyAction = "retry" | "reformulate" | "escalate" | "stop"

/** Policy decision layered over a structural futility verdict. */
pub type AgentFutilityDecision = {
  verdict: AgentFutilityVerdict,
  action: AgentFutilityPolicyAction,
  repeat_count: int,
  threshold: int,
  retry_allowed: bool,
  blocked: bool,
}

/**
 * Fingerprint named observable surfaces once at the caller-owned observation
 * boundary. `observable: false`, a missing value, or an empty explicit
 * fingerprint excludes that surface; an empty result is deliberately
 * unobservable rather than equal to another empty result.
 *
 * @effects: []
 * @errors: [validation]
 */
pub fn agent_observation_fingerprint(
  surfaces: list<AgentObservationSurface>,
) -> AgentObservationFingerprint {
  let normalized = []
  let names = []
  for surface in surfaces {
    const name = trim(surface.name)
    if name == "" {
      throw "agent_observation_fingerprint: surface name must not be empty"
    }
    if names.contains(name) {
      throw "agent_observation_fingerprint: duplicate surface name: " + name
    }
    names = names + [name]
    const explicit = trim(to_string(surface?.fingerprint ?? ""))
    const observable = (surface?.observable ?? true)
      && (explicit != "" || surface?.value != nil)
    if observable {
      const fingerprint = if explicit != "" {
        explicit
      } else {
        sha256(json_stringify(surface.value))
      }
      normalized = normalized
        + [{name: name, fingerprint: fingerprint, evidence: surface?.evidence}]
    }
  }
  if len(normalized) == 0 {
    return {fingerprint: nil, surfaces: []}
  }
  const stable = normalized.sort_by({ surface -> surface.name })
  let fingerprint_rows = []
  for surface in stable {
    fingerprint_rows = fingerprint_rows
      + [{name: surface.name, fingerprint: surface.fingerprint}]
  }
  return {fingerprint: sha256(json_stringify(fingerprint_rows)), surfaces: stable}
}

/**
 * Build the stable repeated-action identity from a name and typed arguments.
 *
 * @effects: []
 * @errors: []
 */
pub fn agent_action_identity(name: string, arguments: any) -> AgentActionIdentity {
  const arguments_fingerprint = sha256(json_stringify(arguments))
  return {
    name: name,
    arguments_fingerprint: arguments_fingerprint,
    identity: sha256(name + "\n" + arguments_fingerprint),
  }
}

fn __agent_observation_surface(observation: AgentObservationFingerprint, name: string) {
  for surface in observation.surfaces {
    if surface.name == name {
      return surface
    }
  }
  return nil
}

/**
 * Compare the intersection of named before/after surfaces. At least one
 * comparable surface is required for `unchanged`; missing observations never
 * become evidence that the environment stayed the same.
 *
 * @effects: []
 * @errors: []
 */
pub fn agent_futility_verdict(
  before: AgentObservationFingerprint,
  after: AgentObservationFingerprint,
  action: AgentActionIdentity,
  previous_action: AgentActionIdentity? = nil,
) -> AgentFutilityVerdict {
  let evidence = []
  let compared = []
  let changed = false
  for before_surface in before.surfaces {
    const after_surface = __agent_observation_surface(after, before_surface.name)
    if after_surface != nil {
      const surface_changed = before_surface.fingerprint != after_surface.fingerprint
      changed = changed || surface_changed
      compared = compared + [before_surface.name]
      evidence = evidence
        + [
        {
          surface: before_surface.name,
          before_fingerprint: before_surface.fingerprint,
          after_fingerprint: after_surface.fingerprint,
          changed: surface_changed,
          before_evidence: before_surface?.evidence,
          after_evidence: after_surface?.evidence,
        },
      ]
    }
  }
  const kind = if changed {
    "changed"
  } else if len(compared) == 0
    || len(compared) != len(before.surfaces)
    || len(compared) != len(after.surfaces) {
    "unobservable"
  } else {
    "unchanged"
  }
  return {
    kind: kind,
    action: action,
    repeated_action: previous_action != nil && previous_action.identity == action.identity,
    before_fingerprint: before.fingerprint,
    after_fingerprint: after.fingerprint,
    compared_surfaces: compared,
    evidence: evidence,
  }
}

fn __agent_futility_default_policy(verdict, repeat_count, threshold) {
  if verdict.kind == "unobservable" {
    return "escalate"
  }
  if verdict.kind == "unchanged"
    && verdict.repeated_action
    && repeat_count >= threshold {
    return "reformulate"
  }
  return "retry"
}

/**
 * Apply caller policy after the stdlib-owned verdict. The optional hook
 * receives `{verdict, repeat_count, threshold}` and must return one of retry,
 * reformulate, escalate, or stop. Non-retry actions block the identical retry;
 * callers retain ownership of wording and the concrete recovery mechanism.
 *
 * @effects: []
 * @errors: [validation]
 */
pub fn agent_futility_decide(
  verdict: AgentFutilityVerdict,
  repeat_count: int = 1,
  threshold: int = 1,
  policy = nil,
) -> AgentFutilityDecision {
  if threshold <= 0 {
    throw "agent_futility_decide: threshold must be a positive int"
  }
  if repeat_count <= 0 {
    throw "agent_futility_decide: repeat_count must be a positive int"
  }
  const selected = if policy == nil {
    __agent_futility_default_policy(verdict, repeat_count, threshold)
  } else {
    policy({verdict: verdict, repeat_count: repeat_count, threshold: threshold})
  }
  if !["retry", "reformulate", "escalate", "stop"].contains(selected) {
    throw "agent_futility_decide: policy must return retry, reformulate, escalate, or stop"
  }
  return {
    verdict: verdict,
    action: selected,
    repeat_count: repeat_count,
    threshold: threshold,
    retry_allowed: selected == "retry",
    blocked: selected != "retry",
  }
}