Toolnexus.Agents.Handle (toolnexus v0.12.0)

Copy Markdown View Source

A live agent — one GenServer per handle (SPEC §7D).

The agent's INBOX is GenServer STATE (bounded, loud-reject, transactionally drained, checkpointable) — never the BEAM mailbox; the BEAM mailbox carries only the verbs. The Run (one client-loop invocation) is a separate monitored process: its crash or kill crosses this boundary as an is_error RESULT, never as a GenServer exit — only the root may throw to the host.

Rootward-call discipline (the deadlock invariant)

Handle→handle blocking calls flow strictly ROOTWARD (child→ancestor: admit_wake, child_started, rollup, get_tokens, snapshot reads on the parent). The only parent→child interaction is a cast (wake_now — the slot transfer on dequeue). Downward traversal — close cascade, list, resume — runs from OUTSIDE the tree (the Runtime API in the caller's process), and external processes (hosts, tests, the Run's tool workers) may call any handle they hold. Violating any leg of this (an ancestor blocking on a descendant while the descendant blocks rootward) deadlocks the tree; every truly-concurrent port rediscovered this rule in the spike.

Handles are capabilities: post/wake what you hold; wait on what you spawned (the host, from outside the tree, may wait on anything it holds — a sibling handle may not).

The handle owns ONE client struct, built at init on the runtime's shared ConversationStore and MetricsRegistry — no per-turn client processes, and the transcript (conversation id = the handle's deterministic id) genuinely survives turns; durable resume reads real history.

Summary

Functions

Returns a specification to start this module under a supervisor.

Verb: abort the in-flight Run → idle, drained inbox restored. Never a kill.

Verb: append an item to the inbox (no transition; bounded; loud reject).

Read-only view of the handle's state.

Verb: resolve with the next result or the last result (a settled handle answers immediately). as: :host (default) is the host capability from outside the tree; a handle-scoped caller passes its own handle id and may wait only on its spawn.

Verb: idle → running; the turn input is the drained inbox (+ optional prompt).

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

interrupt(pid)

Verb: abort the in-flight Run → idle, drained inbox restored. Never a kill.

post(pid, item)

Verb: append an item to the inbox (no transition; bounded; loud reject).

snapshot(pid)

Read-only view of the handle's state.

wait(pid, timeout_ms \\ nil, opts \\ [])

Verb: resolve with the next result or the last result (a settled handle answers immediately). as: :host (default) is the host capability from outside the tree; a handle-scoped caller passes its own handle id and may wait only on its spawn.

wake(pid, prompt \\ nil)

Verb: idle → running; the turn input is the drained inbox (+ optional prompt).