Examples (ReactFlow + DML + Audit)
This page is the practical E2E companion to deep dive. Each example shows:
- conversation UX
- runtime flow graph
- DML seed rows
- expected audit stages
Canonical Runtime Step Set
Step loop behavior
Step loop invokes each execute(session). If a step returns Stop, response returns immediately; otherwise loop continues.
1LoadOrCreateConversationStep
2ResetConversationStep
3PersistConversationBootstrapStep
4AuditUserInputStep
5PolicyEnforcementStep
6IntentResolutionStep
7ResetResolvedIntentStep
8FallbackIntentStateStep
9AddContainerDataStep
10McpToolStep
11SchemaExtractionStep
12AutoAdvanceStep
13RulesStep
14ResponseResolutionStep
15PersistConversationStep
16PipelineEndGuardStep
Open full step traversal with snippets
ConversationController.message
file: src/main/java/com/github/salilvnair/convengine/api/controller/ConversationController.java
JAVA
@PostMapping("/message")
public ConversationResponse message(@RequestBody ConversationRequest request) {
UUID conversationId = request.getConversationId() != null
? request.getConversationId() : UUID.randomUUID();
Map<String, Object> inputParams = new LinkedHashMap<>();
if (request.getInputParams() != null) {
inputParams.putAll(request.getInputParams());
}
EngineContext engineContext = EngineContext.builder()
.conversationId(conversationId.toString())
.userText(request.getMessage())
.inputParams(inputParams)
.build();
EngineResult result = engine.process(engineContext);
return mapToResponse(result);
}
DefaultConversationalEngine.process
file: src/main/java/com/github/salilvnair/convengine/engine/provider/DefaultConversationalEngine.java
JAVA
@Override
public EngineResult process(EngineContext engineContext) {
EngineSession session = sessionFactory.open(engineContext);
session.setConversationHistory(historyProvider.lastTurns(session.getConversationId(), 10));
EnginePipeline pipeline = pipelineFactory.create();
return pipeline.execute(session);
}
EnginePipeline.execute
file: src/main/java/com/github/salilvnair/convengine/engine/pipeline/EnginePipeline.java
JAVA
public EngineResult execute(EngineSession session) {
for (EngineStep step : steps) {
StepResult result = step.execute(session);
if (result instanceof StepResult.Stop(EngineResult finalResult)) {
return finalResult;
}
}
if (session.getFinalResult() == null) {
throw new ConversationEngineException(ConversationEngineErrorCode.PIPELINE_NO_FINAL_RESULT);
}
return session.getFinalResult();
}
LoadOrCreateConversationStep.execute
file: src/main/java/com/github/salilvnair/convengine/engine/steps/LoadOrCreateConversationStep.java
JAVA
public StepResult execute(EngineSession session) {
CeConversation persisted = conversationRepo.findByConversationId(session.getConversationId())
.orElseGet(() -> conversationRepo.save(createConversation(session.getConversationId())));
session.setConversation(persisted);
session.setIntent(persisted.getIntentCode());
session.setState(persisted.getStateCode());
session.mergeContextJson(persisted.getContextJson());
return new StepResult.Continue();
}
IntentResolutionStep.execute
file: src/main/java/com/github/salilvnair/convengine/engine/steps/IntentResolutionStep.java
JAVA
public StepResult execute(EngineSession session) {
if (session.isSchemaLocked() && session.hasIntent()) {
audit.audit("INTENT_SKIP_LOCKED", session.getConversationId(), Map.of("intent", session.getIntent()));
return new StepResult.Continue();
}
IntentResolutionTrace trace = resolver.resolveWithTrace(session.getUserText(), session.contextDict());
session.setIntent(trace.getIntent());
session.setState(trace.getState());
audit.audit("INTENT_RESOLVED", session.getConversationId(), Map.of(
"intent", trace.getIntent(),
"confidence", trace.getConfidence(),
"source", trace.getSource()
));
return new StepResult.Continue();
}
SchemaExtractionStep.execute
file: src/main/java/com/github/salilvnair/convengine/engine/steps/SchemaExtractionStep.java
JAVA
public StepResult execute(EngineSession session) {
Optional<CeOutputSchema> schemaOpt = outputSchemaRepo.findEnabled(session.getIntent(), session.getState());
if (schemaOpt.isEmpty()) {
return new StepResult.Continue();
}
CeOutputSchema schema = schemaOpt.get();
String prompt = promptRenderer.renderSchemaPrompt(session, schema);
String extractedJson = llmClient.generateJson(prompt, schema.getSchemaJson(), session.getContextJsonOrEmpty());
session.mergeContextJson(extractedJson);
MissingFieldResult missing = missingFieldEvaluator.evaluate(schema.getSchemaJson(), session.contextDict());
session.setMissingFields(missing.names());
session.setSchemaLocked(!missing.isComplete());
audit.audit("SCHEMA_EVALUATED", session.getConversationId(), Map.of("missing", missing.names()));
return new StepResult.Continue();
}
RulesStep.execute
file: src/main/java/com/github/salilvnair/convengine/engine/steps/RulesStep.java
JAVA
public StepResult execute(EngineSession session) {
int pass = 0;
boolean changed;
do {
changed = false;
pass++;
for (CeRule rule : ruleRepo.findEnabled(session.getIntent(), session.getState())) {
if (!ruleMatcher.matches(rule, session)) {
continue;
}
RuleOutcome outcome = actionExecutor.apply(rule, session);
changed = changed || outcome.mutatedIntentOrState();
audit.audit("RULE_MATCH", session.getConversationId(), Map.of("ruleId", rule.getId(), "action", rule.getAction()));
}
} while (changed && pass < 4);
return new StepResult.Continue();
}
ResponseResolutionStep.execute
file: src/main/java/com/github/salilvnair/convengine/engine/steps/ResponseResolutionStep.java
JAVA
public StepResult execute(EngineSession session) {
CeResponse row = responseRepo.resolve(session.getIntent(), session.getState())
.orElseThrow(() -> new ConversationEngineException(RESPONSE_NOT_FOUND));
EngineResult result = "EXACT".equalsIgnoreCase(row.getResponseType())
? exactResolver.resolve(row, session)
: derivedResolver.resolve(row, session);
session.setFinalResult(result);
audit.audit("ASSISTANT_OUTPUT", session.getConversationId(), Map.of(
"responseType", row.getResponseType(),
"outputFormat", row.getOutputFormat()
));
return new StepResult.Continue();
}
PersistConversationStep.execute
file: src/main/java/com/github/salilvnair/convengine/engine/steps/PersistConversationStep.java
JAVA
public StepResult execute(EngineSession session) {
CeConversation c = session.getConversation();
c.setIntentCode(session.getIntent());
c.setStateCode(session.getState());
c.setContextJson(session.getContextJsonOrEmpty());
c.setLastAssistantJson(session.getFinalResultJson());
conversationRepo.save(c);
return new StepResult.Continue();
}
FAQ
- Conversation + Flow
- DML Entries
- Audit Trail
FAQ
FAQ runtime flow
Classifier-first deterministic path
FAQ seed SQL
SQL
insert into ce_intent(intent_code, state_code, enabled) values ('FAQ', null, true);
insert into ce_intent_classifier(intent_code, match_pattern, priority, enabled)
values ('FAQ', '(?i).*(office|location|address).*', 10, true);
insert into ce_response(intent_code, state_code, response_type, output_format, exact_text, enabled)
values ('FAQ', null, 'EXACT', 'TEXT', 'Yes. You can request relocation from the support portal.', true);
insert into ce_config(component, config_key, config_value, enabled)
values ('ResetConversationStep', 'RESET_COMMAND', 'RESET_SESSION', true);
FAQ seed preview
| Table | Key values |
|---|---|
| ce_intent | intent_code=FAQ |
| ce_intent_classifier | pattern=(?i).*(office|location|address).* |
| ce_response | response_type=EXACT, output_format=TEXT |
| ce_config | RESET_COMMAND=RESET_SESSION |
FAQ expected ce_audit trail
| Stage | Meaning |
|---|---|
| USER_INPUT | Incoming user message captured |
| INTENT_RESOLVED | FAQ selected |
| RULE_NO_MATCH | No transition rule needed |
| ASSISTANT_OUTPUT | EXACT response emitted |
| CONVERSATION_PERSIST | Session snapshot saved |
DISCONNECT_ELECTRICITY
- Conversation + Flow
- DML Entries
- Audit Trail
DISCONNECT_ELECTRICITY
Disconnect flow
Incomplete schema -> follow-up -> complete -> finalize
DISCONNECT_ELECTRICITY seed SQL
SQL
insert into ce_intent(intent_code, enabled) values ('DISCONNECT_ELECTRICITY', true);
insert into ce_output_schema(intent_code, schema_json, enabled)
values ('DISCONNECT_ELECTRICITY',
'{"type":"object","properties":{"accountId":{"type":"string"},"disconnectDate":{"type":"string"},"reason":{"type":"string"}},"required":["accountId","disconnectDate","reason"]}',
true);
insert into ce_prompt_template(intent_code, state_code, response_type, system_prompt, user_prompt, enabled)
values ('DISCONNECT_ELECTRICITY', 'COLLECT_REQUIRED', 'TEXT', 'Collect missing disconnect fields.', 'Ask only for missing disconnect fields from: {{user_input}}', true);
insert into ce_response(intent_code, state_code, response_type, output_format, enabled)
values ('DISCONNECT_ELECTRICITY', 'COLLECT_REQUIRED', 'DERIVED', 'TEXT', true);
DISCONNECT_ELECTRICITY expected ce_audit trail
| Stage | Meaning |
|---|---|
| INTENT_RESOLVED | Intent selected |
| SCHEMA_INCOMPLETE | Missing fields detected |
| ASSISTANT_OUTPUT | Follow-up asked |
| SCHEMA_COMPLETE | All required fields present |
| RULE_MATCH | State transition executed |
| CONVERSATION_PERSIST | Final state stored |
LOG_ANALYSIS
- Conversation + Flow
- DML Entries
- Audit Trail
LOG_ANALYSIS
Log analysis flow
GET_SCHEMA_JSON rule and DERIVED output
LOG_ANALYSIS seed preview
| Table | Key values |
|---|---|
| ce_intent | intent_code=LOG_ANALYSIS |
| ce_output_schema | fields=errorCode,component,severity |
| ce_rule | action=GET_SCHEMA_JSON |
| ce_response | response_type=DERIVED |
LOG_ANALYSIS expected ce_audit trail
| Stage | Meaning |
|---|---|
| INTENT_RESOLVED | LOG_ANALYSIS selected |
| SCHEMA_EVALUATED | Structured facts extracted |
| RULE_MATCH | GET_SCHEMA_JSON evaluated |
| ASSISTANT_OUTPUT | Derived explanation produced |
REQUEST_TRACKER
- Conversation + Flow
- DML Entries
- Audit Trail
REQUEST_TRACKER
Tracker flow
SET_TASK driven state path
REQUEST_TRACKER seed preview
| Table | Key values |
|---|---|
| ce_intent | intent_code=REQUEST_TRACKER |
| ce_output_schema | field=requestId |
| ce_rule | action=SET_TASK |
| ce_response | response_type=DERIVED |
REQUEST_TRACKER expected ce_audit trail
| Stage | Meaning |
|---|---|
| INTENT_RESOLVED | REQUEST_TRACKER selected |
| RULE_MATCH | SET_TASK applied |
| ASSISTANT_OUTPUT | Status response emitted |
| CONVERSATION_PERSIST | Turn persisted |
Fast validation
For each example run, inspect both /api/v1/conversation/audit/{conversationId} and /api/v1/conversation/audit/{conversationId}/trace.