Faithful port of DSPy 3.2.1 TwoStepAdapter (dspy/adapters/two_step_adapter.py).
Two stages:
- The MAIN LM receives a simple natural-language prompt: a persona/task
system message built from the signature's field descriptions (no
[[ ## field ## ]]markers), demos rendered as plainname: valueuser/assistant turns, and a plainname: valueuser message. - Parsing runs a SECOND extraction LM through the ChatAdapter path over a
synthesized
text -> {original output fields}signature, extracting the structured fields from the main LM's free-form completion. A failed chat extraction falls back to a JSONAdapter-formatted retry, exactly like DSPy'sChatAdapter.__call__fallback.
Extraction LM threading (mapping to DSPy's constructor argument)
DSPy carries the extraction LM on the adapter instance:
dspy.TwoStepAdapter(extraction_model=lm). Imp adapters are stateless
modules, so the instance slot maps onto Imp's settings surface — the same
place dspy.configure(adapter=...) state already lives:
Imp.configure(adapter: Imp.Adapter.TwoStep, two_step_extraction_lm: small_lm)
# or scoped:
Imp.Settings.context([two_step_extraction_lm: small_lm], fn -> ... end)A direct parse/3 call may instead pass extraction_lm: in opts. A missing
extraction LM is a loud error: parse returns
{:error, {:two_step_extraction_lm_not_configured, ...}} rather than
silently degrading to single-step parsing.
The former plan-prepend extension that wore this name is now
Imp.Adapter.PlanFirst.
Summary
Functions
Formats the MAIN-LM messages: persona system message, name: value demos,
and a name: value user message (DSPy TwoStepAdapter.format).
Parses the main LM's free-form completion by calling the extraction LM with
a ChatAdapter-formatted text -> outputs signature (DSPy
TwoStepAdapter.parse). Any extraction failure (after DSPy's JSONAdapter
fallback) is a loud error carrying the original completion.
Functions
Formats the MAIN-LM messages: persona system message, name: value demos,
and a name: value user message (DSPy TwoStepAdapter.format).
Parses the main LM's free-form completion by calling the extraction LM with
a ChatAdapter-formatted text -> outputs signature (DSPy
TwoStepAdapter.parse). Any extraction failure (after DSPy's JSONAdapter
fallback) is a loud error carrying the original completion.