// Thin Harn wrappers over host session-state primitives. These are CRUD only;
// no decision logic lives here. The agent loop holds the session dict locally
// and passes session_id into the host for any mutation.
/**
* agent_session_init.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_init(message, system_prompt, opts)
*/
pub fn agent_session_init(message, system_prompt, opts) {
return __host_agent_session_init(message, system_prompt, opts)
}
/**
* agent_session_finalize.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_finalize(session_id, status)
*/
pub fn agent_session_finalize(session_id, status) {
return __host_agent_session_finalize(session_id, status)
}
/**
* agent_session_messages.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_messages(session_id)
*/
pub fn agent_session_messages(session_id) {
return __host_agent_session_messages(session_id)
}
/**
* agent_session_record_assistant.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_record_assistant(session_id, llm_result)
*/
pub fn agent_session_record_assistant(session_id, llm_result) {
return __host_agent_session_record_assistant(session_id, llm_result)
}
/**
* agent_session_record_tool_results.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_record_tool_results(session_id, dispatch)
*/
pub fn agent_session_record_tool_results(session_id, dispatch) {
return __host_agent_session_record_tool_results(session_id, dispatch)
}
fn __agent_usage_int(value) {
if type_of(value) == "int" {
return value
}
if type_of(value) == "float" {
return to_int(value)
}
return 0
}
/**
* agent_reminder_providers_fire.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_reminder_providers_fire(session_id, "post_compact", payload, opts)
*/
pub fn agent_reminder_providers_fire(session_id, event, payload = nil, opts = nil) {
return __host_agent_reminder_providers_fire(session_id, event, payload ?? {}, opts ?? {})
}
/**
* agent_session_record_usage.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_record_usage(session_id, llm_result, opts, iteration)
*/
pub fn agent_session_record_usage(session_id, llm_result, opts = nil, iteration = 0) {
let totals = __host_agent_session_record_usage(session_id, llm_result)
let llm = llm_result?.llm ?? {}
let input_tokens = __agent_usage_int(llm?.input_tokens ?? llm_result?.input_tokens)
let output_tokens = __agent_usage_int(llm?.output_tokens ?? llm_result?.output_tokens)
agent_reminder_providers_fire(
session_id,
"on_budget_threshold",
{
session: {id: session_id},
iteration: iteration,
input_tokens: input_tokens,
output_tokens: output_tokens,
tokens_used: totals?.tokens_used ?? 0,
cost_usd: totals?.cost_usd ?? 0.0,
provider: llm_result?.provider ?? opts?.provider ?? "",
model: llm_result?.model ?? opts?.model ?? "",
},
opts ?? {},
)
return totals
}
/**
* agent_session_drain_feedback.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_drain_feedback(session_id)
*/
pub fn agent_session_drain_feedback(session_id) {
return __host_agent_session_drain_feedback(session_id)
}
/**
* agent_session_drain_bridge_injections.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_drain_bridge_injections(session_id, "finish_step")
*/
pub fn agent_session_drain_bridge_injections(session_id, checkpoint) {
return __host_agent_session_drain_bridge_injections(session_id, checkpoint)
}
/**
* agent_session_push_bridge_injection.
*
* Push a system-reminder onto the session's host bridge queue. The
* reminder is held until the agent loop's next eligible checkpoint
* drains it (gated by `options.mode`). Returns the reminder id.
*
* `options` mirrors the ACP `session/remind` JSON-RPC params:
* `{body, mode?, tags?, dedupe_key?, ttl_turns?, role_hint?,
* propagate?, preserve_on_compact?}`.
*
* `mode` defaults to `"audit_only"`:
*
* - `"interrupt_immediate"` — skip the next pending tool batch at the
* `pre_tool_dispatch` checkpoint.
* - `"finish_step"` — drained at every iteration boundary; the
* reminder renders into the model's next prompt.
* - `"audit_only"` — drained only at `loop_exit`. The reminder lands
* in the transcript audit but is NEVER rendered into a model
* prompt (no further LLM call runs after `loop_exit`). Use this
* for record-keeping; use `finish_step` if the model must see it
* before the loop terminates (harn#2212).
*
* @effects: [host]
* @allocation: heap
* @errors: [HARN-RMD-002]
* @api_stability: experimental
* @example: agent_session_push_bridge_injection(session_id, {body: "stop", mode: "interrupt_immediate"})
*/
pub fn agent_session_push_bridge_injection(session_id, options) {
return __host_agent_session_push_bridge_injection(session_id, options)
}
/**
* agent_session_pending_injections.
*
* Return a FIFO snapshot of queued bridge injections for `session_id`.
* The result shape is `{pendingCount, injections}` where each row has
* `kind: "user"` or `kind: "reminder"`, stable `id`, `mode`, and
* kind-specific fields such as `messageId`, `reminderId`, or `body`.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_pending_injections(session_id)
*/
pub fn agent_session_pending_injections(session_id) {
return __host_agent_session_pending_injections(session_id)
}
/**
* agent_session_revoke_reminder.
*
* Revoke a pending bridge reminder before it is drained by an agent
* checkpoint. Returns `{status, reminderId}` where `status` is one of
* `"revoked"`, `"already_revoked"`, `"already_delivered"`, or
* `"unknown_reminder_id"`.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_revoke_reminder(session_id, reminder_id)
*/
pub fn agent_session_revoke_reminder(session_id, reminder_id) {
return __host_agent_session_revoke_reminder(session_id, reminder_id)
}
/**
* agent_session_totals.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_totals(session_id)
*/
pub fn agent_session_totals(session_id) {
return __host_agent_session_totals(session_id)
}
/**
* agent_session_inject_feedback.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_inject_feedback(session_id, kind, content)
*/
pub fn agent_session_inject_feedback(session_id, kind, content) {
return __host_agent_session_inject_feedback(session_id, kind, content)
}
/**
* agent_session_pop_last_assistant. Discard the trailing assistant
* turn from a session transcript. Used by `agent_step_judge` in
* `replace` (pop-and-regen) mode to remove a vetoed assistant
* response before the next iteration regenerates. Returns true if a
* turn was popped, false if the transcript was empty. Errors if the
* trailing message is not an assistant turn — signals a call-site
* discipline bug, not a runtime condition.
*
* @effects: [host]
* @allocation: heap
* @errors: [runtime]
* @api_stability: experimental
* @example: agent_session_pop_last_assistant(session_id)
*/
pub fn agent_session_pop_last_assistant(session_id) {
return __host_agent_session_pop_last_assistant(session_id)
}
/**
* agent_session_post_event. Post an event into a running session's
* inbox from outside the loop (triggers, connectors, host
* integrations). The next turn boundary — including the post-
* compaction drain — surfaces the entry as feedback.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_post_event(session_id, kind, content, source)
*/
pub fn agent_session_post_event(session_id, kind, content, source = nil) {
return __host_agent_session_post_event(session_id, kind, content, source)
}
/**
* agent_session_apply_reminder_post_turn.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_apply_reminder_post_turn(session_id, turn)
*/
pub fn agent_session_apply_reminder_post_turn(session_id, turn = 0) {
return __host_agent_session_apply_reminder_post_turn(session_id, turn)
}
/**
* agent_session_set_active_skills.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_set_active_skills(session_id, skills)
*/
pub fn agent_session_set_active_skills(session_id, skills) {
return __host_agent_session_set_active_skills(session_id, skills)
}
/**
* agent_session_active_skills.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_active_skills(session_id)
*/
pub fn agent_session_active_skills(session_id) {
return __host_agent_session_active_skills(session_id)
}
/**
* agent_session_record_skill_event.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_record_skill_event(session_id, kind, metadata)
*/
pub fn agent_session_record_skill_event(session_id, kind, metadata) {
return __host_agent_session_record_skill_event(session_id, kind, metadata)
}
/**
* agent_session_claim_tool_format_internal.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_claim_tool_format_internal(session_id, tool_format)
*/
pub fn agent_session_claim_tool_format_internal(session_id, tool_format) {
return __host_agent_session_claim_tool_format(session_id, tool_format)
}
/**
* agent_emit_event.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_emit_event(session_id, event_type, payload)
*/
pub fn agent_emit_event(session_id, event_type, payload) {
return __host_agent_emit_event(session_id, event_type, payload)
}
/**
* agent_record_native_tool_fallback.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_record_native_tool_fallback(session_id, payload)
*/
pub fn agent_record_native_tool_fallback(session_id, payload) {
return __host_agent_record_native_tool_fallback(session_id, payload)
}
/**
* agent_record_compaction.
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_record_compaction(session_id, payload)
*/
pub fn agent_record_compaction(session_id, payload) {
return __host_agent_record_compaction(session_id, payload)
}
/**
* agent_session_project_turn projects the session transcript through a
* policy, appends a `transcript.projection` event into the raw
* transcript, emits a typed `TranscriptProjected` agent event, and
* returns the projected messages with metadata.
*
* The persisted message list is never mutated — projection only
* controls what the next provider request will see. Supported policies:
* "raw", "clean_tool_repair", "squash_failed_calls", "summary_prefix",
* and "custom" (with a `projector` closure).
*
* @effects: [host]
* @allocation: heap
* @errors: []
* @api_stability: experimental
* @example: agent_session_project_turn(session_id, {policy: "clean_tool_repair"})
*/
pub fn agent_session_project_turn(session_id, options = nil) {
return __host_agent_session_project_turn(session_id, options ?? {})
}