symfonic.core.learning.procedural_extractor¶
procedural_extractor ¶
ProceduralExtractor protocol + ProceduralDraft dataclass.
v7.6 (Jarvio Ask 9) — opt-in surface for the LLM-backed Phase 12 extractor. Mirrors the v7.2 EntityExtractor pluggability shape:
- the regex-based extractor in
:mod:
symfonic.core.learning.phases_procedural_promotionis the default (configured at v6.1) and produces flat verb-object skills; - the LLM-backed extractor in
:mod:
symfonic.core.learning.procedural_extractor_llmis opt-in viaFrameworkConfig.phase_12_use_llm_extractor=Trueand produces structured :class:ProceduralDraftrecords that distinguish action / preflight / recovery / guardrail rules.
The protocol is intentionally minimal -- the dispatch site in
:func:promote_episodic_to_procedural only needs to call extract
and turn the returned drafts into :class:~symfonic.memory.models.entry.MemoryEntry
records via the shared :func:_build_skill_entry_from_draft helper.
Design reference:
.claude/docs/2026-05-28-jarvio-llm-procedural-extractor-eval.md §8.
ProceduralKind
module-attribute
¶
Allowed values for ProceduralDraft.kind.
The four-way split tracks the failure modes Jarvio identified in their
deep-dive (symfonic-core-ask-llm-procedural-extractor.md):
action— repeated tool usage that should become a learned habit.preflight— pre-flight check that prevents downstream failure ("before X, call Y"). The most load-bearing kind for v7.6 since the regex extractor structurally cannot represent it.recovery— error-recovery rule ("after E, call R").guardrail— negative rule ("never X — use Y instead").
VALID_PROCEDURAL_KINDS
module-attribute
¶
VALID_PROCEDURAL_KINDS: frozenset[str] = frozenset(
{"action", "preflight", "recovery", "guardrail"}
)
Runtime mirror of :data:ProceduralKind for response-shape validation.
The Literal type is gone at runtime so the LLM-response parser uses this
frozenset to clamp unknown kinds back to "action" (the most benign
default — a noisy action draft surfaces to human review, a fabricated
preflight rule could hide a real precondition gap).
ProceduralDraft
dataclass
¶
ProceduralDraft(
kind: ProceduralKind,
trigger: str,
action: str,
rationale: str,
confidence: float = 0.0,
precondition: str | list[str] | None = None,
source_episode_ids: list[str] = list(),
)
Structured draft produced by a :class:ProceduralExtractor.
Frozen so the dispatch site can pass instances around without
worrying about downstream mutation. Defaults match the LLM prompt's
nullable / optional fields so a minimal response can still
construct a valid draft (only kind, trigger, action,
and rationale are strictly required).
precondition shape (v7.6.3 -- Jarvio multi-precondition ask):
None-- no pre-flight gate.str-- single pre-flight rule (v7.6.0 byte-identical shape; preserved so consumers thatisinstance(p, str)still match the common case).list[str]-- ordered multi-pre-flight rule. Mirrors the v7.6.2 storage widening on :meth:~symfonic.memory.layers.procedural.layer.ProceduralLayer.seed_authored_skill, so LLM-extracted drafts and hand-authored skills share one storage shape. The v7.5.1 :class:~symfonic.memory.layers.procedural.router.CapabilityRouterrenders one indentedPRE-FLIGHT:line per entry in supplied order.
ProceduralExtractor ¶
Bases: Protocol
Pluggable Phase 12 extractor interface.
Implementations MUST be best-effort: a malformed response, a missing
field, or an exception during model invocation must yield []
rather than raise. The dispatch site logs the empty result via the
standard Phase 12 telemetry line so consumers can tell "extractor
found nothing" from "extractor crashed" via the cost_usd /
llm_calls fields.