Multi-step task planner for agentic goal execution.
Purpose
-------
Process-singleton plan state that the model uses to break a complex
goal into discrete steps and track progress across ReAct iterations.
The model calls :func:`create_plan` to set up a plan, :func:`mark_step`
as each step completes, :func:`get_status` for progress, and
:func:`stop_plan` to halt execution.
Responsibilities
----------------
- :class:`Step` / :class:`Plan` — dataclasses describing a single
step (description, status, result) and the active plan (goal,
steps, completion check).
- :func:`create_plan` — start a new plan; replaces any existing one.
- :func:`mark_step` — transition a step to ``done`` / ``failed`` with
an optional result string.
- :func:`get_status` — return the current plan as a dict.
- :func:`stop_plan` — clear active plan state and set the stop flag.
Diagnostics
-----------
Domain: OC_CHAT.TOOLS
Levels:
L2 — lifecycle events
L3 — semantic details
L4 — deep tracing
Contracts
---------
- Module-level ``_active_plan`` and ``_stopped`` are process-singleton
state — only one plan is active at a time per REPL.
- ``create_plan`` overwrites any existing plan without warning.
- ``mark_step`` validates the step index; out-of-range indices return
an error dict rather than raising.
- ``stop_plan`` is idempotent — calling it twice has no extra effect.
Dependencies
------------
- oc_diagnostics (structured debug logging via _dbg)
See Also
--------
oc_chat/docs/conventions/CONTRACTS.md §8 Plan / Step — owner of the planner
dataclasses; §3 Tool registry contract; §4 Tool return-value conventions.
| "tuple[list[str] | None, str | None]" oc_chat.tools.planner._coerce_steps |
( |
object | steps | ) |
|
|
protected |
Coerce a model-supplied *steps* value into a ``list[str]``, or return an error.
F28: ``create_plan`` used to ``len(steps)`` / iterate ``steps`` blindly, so a
``None`` raised ``TypeError`` (invisible crash) and a bare STRING was silently
char-split into one step per character. This tolerates the shapes the model
actually sends — a list of dicts (``{'description'|'step'|'title'|...: ...}``),
non-string scalars (stringified) — and hard-rejects only the crash/corruption
shapes (``None`` and a bare string). An empty list is allowed (an empty plan is
a valid, supported state).
Returns ``(steps_list, None)`` on success or ``(None, error_message)``.
Definition at line 97 of file planner.py.