harn-stdlib 0.8.26

Embedded Harn standard library source catalog
Documentation
// @harn-entrypoint-category agent.stdlib
import { daemon_timer_feedback_prompt, daemon_watch_feedback_prompt } from "std/agent/prompts"
import {
  agent_emit_event,
  agent_reminder_providers_fire,
  agent_session_inject_feedback,
} from "std/agent/state"
import { agent_await_resumption } from "std/agent/workers"

fn __daemon_compaction_summary(opts) {
  if !(opts?.consolidate_on_idle ?? false) {
    return nil
  }
  if !(opts?.auto_compact ?? false) {
    return nil
  }
  let callback = opts?.compact_callback
  if callback == nil {
    return nil
  }
  let compacted = callback([])
  if type_of(compacted) == "dict" {
    return compacted?.summary
  }
  if type_of(compacted) == "string" {
    return compacted
  }
  return nil
}

fn __agent_daemon_feedback(wake, opts) {
  if wake?.reason == "timer" {
    return {kind: wake?.feedback_kind ?? "timer", text: daemon_timer_feedback_prompt(opts)}
  }
  if wake?.reason == "watch" || wake?.changed_paths != nil {
    let changed_paths = wake?.changed_paths ?? []
    let changed_paths_text = if type_of(changed_paths) == "list" {
      join(changed_paths, ", ")
    } else {
      to_string(changed_paths)
    }
    return {
      kind: wake?.feedback_kind ?? wake?.reason ?? "daemon",
      text: daemon_watch_feedback_prompt({changed_paths: changed_paths_text}, opts),
    }
  }
  if wake?.feedback != nil {
    return {kind: wake?.feedback_kind ?? wake?.reason ?? "daemon", text: wake.feedback}
  }
  return nil
}

fn __agent_daemon_timeout_condition(timeout_ms) {
  if timeout_ms <= 0 {
    return nil
  }
  return {
    duration_minutes: to_int(max(1, ceil(timeout_ms * 1.0 / 60000.0))),
    on_timeout: "resume_with_input",
  }
}

fn __agent_daemon_raw_resume_conditions(opts, timeout_ms) {
  var conditions = {}
  let timeout = __agent_daemon_timeout_condition(timeout_ms)
  if timeout != nil {
    conditions = conditions + {timeout: timeout}
  }
  let event_topic = opts?.resume_event_topic ?? opts?.daemon_event_topic ?? nil
  if event_topic != nil {
    conditions = conditions + {on_event: event_topic}
  }
  if len(conditions.keys()) == 0 {
    return nil
  }
  return conditions
}

fn __agent_daemon_await_resumption(session, opts, iteration, timeout_ms) {
  let request = agent_await_resumption("daemon idle", __agent_daemon_raw_resume_conditions(opts, timeout_ms))
  agent_emit_event(
    session.session_id,
    "tool_call_audit",
    {
      tool_call_id: "daemon_idle:" + to_string(iteration),
      tool_name: "agent_await_resumption",
      audit: {
        layer: "agent_lifecycle",
        status: "daemon_idle",
        initiator: "self",
        reason: request.reason,
        conditions: request.conditions,
      },
    },
  )
  return request
}

/**
 * agent_daemon_snapshot.
 *
 * @effects: [host]
 * @allocation: heap
 * @errors: []
 * @api_stability: experimental
 * @example: agent_daemon_snapshot(session, opts, daemon_state, iteration)
 */
pub fn agent_daemon_snapshot(session, opts, daemon_state = "idle", iteration = 0) {
  let summary = __daemon_compaction_summary(opts)
  var snapshot_opts = opts + {daemon_state: daemon_state, total_iterations: iteration}
  if summary != nil {
    snapshot_opts = snapshot_opts + {transcript_summary: summary}
  }
  return __host_agent_daemon_snapshot(session.session_id, snapshot_opts)
}

/**
 * agent_daemon_step.
 *
 * @effects: [host, agent]
 * @allocation: heap
 * @errors: []
 * @api_stability: experimental
 * @example: agent_daemon_step(session, opts, iteration)
 */
pub fn agent_daemon_step(session, opts, iteration) {
  let snapshot = agent_daemon_snapshot(session, opts, "idle", iteration)
  let timeout = opts?.wake_interval_ms ?? 0
  __agent_daemon_await_resumption(session, opts, iteration, timeout)
  let idle_payload = {
    session: {id: session.session_id},
    iteration: iteration,
    wake_interval_ms: timeout,
    consolidate_on_idle: opts?.consolidate_on_idle ?? false,
  }
  __host_fire_session_hook("session_idle", idle_payload)
  agent_reminder_providers_fire(session.session_id, "session_idle", idle_payload, opts)
  var wake = __host_agent_daemon_wait(session.session_id, timeout)
  while wake?.reason == nil && timeout > 0 {
    wake = __host_agent_daemon_wait(session.session_id, timeout)
  }
  let feedback = __agent_daemon_feedback(wake, opts)
  if feedback != nil {
    agent_session_inject_feedback(session.session_id, feedback.kind, feedback.text)
  }
  return {snapshot: snapshot, wake: wake}
}