# `Cyclium.Strategy.Template.Agentic.Loop`
[🔗](https://github.com/Cyclium/cyclium_ex/blob/main/lib/cyclium/strategy/template/agentic/loop.ex#L1)

The shared agentic loop that powers the interactive and autonomous strategy
templates. It owns the middle of the state machine — the phases neither
template needs to customize:

    interpret → validate → [preview] → execute → summarize → (loop | done)

A template supplies the ends: `init/2` (how intent is seeded), the
`:context_assembly` phase (what data the synthesizer sees), and `converge/2`
(what the episode produces). Everything between is delegated here so the
`Interactive` and `AgenticTask` templates stay thin and share one tested loop.

## The `finish_agentic_task` tool

A reserved tool named `"finish_agentic_task"` lets an autonomous run signal
completion explicitly (rather than relying on a plain-text `explain_only`,
which invites a model to stop early). When a parsed plan calls it, the loop
routes straight to `:done` and stashes the tool's args as `state.conclusion` —
the plan never reaches `PlanGate` or `ToolExec`, so there is no real capability
to register. `Interactive` never puts `"finish_agentic_task"` in its tool menu,
so the interception is inert there.

All functions operate on the shared strategy-state map. A template's `next_step`
and `handle_result` handle their custom `:context_assembly` phase and delegate
every other phase to `next_step/2` and `handle_result/3` here.

# `budget_exhausted_summary`

User-facing summary when a run stops on budget exhaustion.

# `build_execution_summary`

Technical summary of what an executed plan did (converge fallback).

# `build_findings_list`

Normalize a list of finding maps (from plan meta or a finish tool's args) into
the `{:raise, ...}` / `{:clear, key, reason}` tuples `ConvergeResult` expects.

# `build_interpret_prompt`

# `build_outputs_list`

Normalize a list of output-proposal maps into `%OutputProposal{}` structs.

# `build_summarize_prompt`

# `coerce_explanation`

# `finish_signature`

A tool-menu signature for the reserved `finish_agentic_task` tool. Templates
that want the explicit terminal action append this to `allowed_tool_signatures`
so the synthesizer offers it to the model. It is never validated by `PlanGate`
— the loop intercepts a `finish_agentic_task` call before the `:validate` phase.

# `finish_tool_name`

The reserved tool name that terminates an agentic run.

# `handle_budget_exhausted`

Graceful budget-exhaustion convergence. A template's `handle_budget_exhausted/2`
can delegate here to end with an "out of budget" summary instead of failing.
`Map.put` keeps this safe for states resumed from a pre-`:budget_exhausted`
checkpoint.

# `handle_result`

# `load_strategy_config`

Resolve an actor's `strategy_config`, checking persistent_term first (set by
the Actor DSL `strategy_config` option) and falling back to the
`cyclium_agent_definitions` table for dynamic actors.

Prefer `load_strategy_config/2` when the expectation id is known — this
actor-only lookup is first-match-by-actor and non-deterministic for a
multi-expectation actor.

# `load_strategy_config`

Resolve `strategy_config` for a specific `{actor_id, expectation_id}` pair.

Prefer this over `load_strategy_config/1`: an actor with more than one
expectation (e.g. an interactive chat *and* an agentic appraisal) registers a
distinct config under each `{:cyclium_strategy_config, actor, exp}` key. The
actor-only lookup scans persistent_term for the *first* matching actor entry
in unspecified order, so it can hand an agentic run the chat's config — wrong
role/guidelines, missing `objective`, and the wrong `allowed_tool_signatures`
(so the run's own finding-recording tool may never be in the menu). Resolving
by the exact expectation key is deterministic; it falls back to the actor-only
path (then the DB) when no per-expectation config is registered.

# `next_step`

# `parse_action_plan`

# `resume_from_block`

Resume after a human resolved an approval. Rebuilds the approved plan from the
journal (no state checkpoint) and jumps to `:execute`/`:denied` so we run
exactly what was approved — no extra LLM round-trip or re-prompt.

# `tool_menu_from_config`

# `with_finish_tool`

Append the `finish_agentic_task` signature to a strategy_config's tool list,
unless the app already declared a tool by that name.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
