Problem
ClarificationMiddleware currently writes pending clarification data into checkpointed thread_data. A host product then reinterprets final graph state as a durable interaction. This creates two state authorities and lets checkpoint history be confused with the current Run.
Decision
Keep clarification product-neutral in North, but make it transient and per-Run:
ask_clarification produces a versioned ToolMessage artifact with question, response kind, and bounded options.
- The middleware must not read or write
thread_data and must not clear state on a later HumanMessage.
RunExecutor collects clarification artifacts observed during its current astream() invocation and passes a structured RunExecutionResult / ClarificationRequest tuple to its completion hook before the end sentinel.
- A clarification call should terminate the current Run. Do not use LangGraph
interrupt(), which changes the contract to checkpoint-resume.
Acceptance criteria
- A checkpoint containing an old clarification artifact or old
thread_data cannot cause a later Run to report a clarification.
- Current-Run clarification is available to the host through a public, versioned North API.
- The model does not continue to another model turn or execute sibling write tools after clarification is requested.
- Multiple clarification calls are exposed explicitly; hosts do not silently receive only the last one.
- Artifact remains model-hidden while available to host streaming/audit.
- Runtime terminal callback receives the outcome before
publish_end.
- Public API and focused middleware/runtime tests cover the behavior.
Out of scope
North must not persist product interaction state, expiry, CAS, UI choices, or resume semantics. Hosts remain responsible for durable interaction lifecycle.
Problem
ClarificationMiddlewarecurrently writes pending clarification data into checkpointedthread_data. A host product then reinterprets final graph state as a durable interaction. This creates two state authorities and lets checkpoint history be confused with the current Run.Decision
Keep clarification product-neutral in North, but make it transient and per-Run:
ask_clarificationproduces a versioned ToolMessage artifact with question, response kind, and bounded options.thread_dataand must not clear state on a later HumanMessage.RunExecutorcollects clarification artifacts observed during its currentastream()invocation and passes a structuredRunExecutionResult/ClarificationRequesttuple to its completion hook before the end sentinel.interrupt(), which changes the contract to checkpoint-resume.Acceptance criteria
thread_datacannot cause a later Run to report a clarification.publish_end.Out of scope
North must not persist product interaction state, expiry, CAS, UI choices, or resume semantics. Hosts remain responsible for durable interaction lifecycle.