Architecture
Layers
API + Transport Layer
- ConversationController
- request ingress + validation + correlation ids
- SSE / STOMP event transport for audit streams
Runtime Pipeline Layer
- DefaultConversationalEngine
- EnginePipelineFactory (DAG sort + wrappers + timing + step hooks)
- EngineSession (per-turn mutable state)
Decision + Control Layer
- dialogue act: DialogueActStep
- policy: InteractionPolicyStep
- correction routing: CorrectionStep
- pending action lifecycle: ActionLifecycleStep, DisambiguationStep, PendingActionStep
- guard + transition validation: GuardrailStep, StateGraphStep
- core intent/schema/rules/response path
Tooling Layer
- ToolOrchestrationStep (unified tool request/execute/result contract)
- McpToolStep (planner loop +
CALL_TOOL/ANSWER)
Persistence + Audit Layer
- JPA repositories on ce_*
- ce_conversation, ce_audit, ce_memory write path
Request Path (high-level)
Controller receives request
Builds EngineContext from conversationId, message, inputParams, optional reset flag.
Engine opens session
EngineSessionFactory creates session and history provider injects last turns.
Control steps run
Dialogue act + interaction policy + correction routing + pending-action lifecycle decide whether to execute task, clarify, confirm, patch, or continue standard intent flow.
Core flow resolves output
Intent/schema/rules/response steps produce deterministic state transition + assistant payload.
Persist + return result
Final payload is persisted and returned as TEXT/JSON response, with full audit trail.
Code references
@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);
}
for (EngineStep step : steps) {
StepResult r = step.execute(session);
if (r instanceof StepResult.Stop(EngineResult result)) {
return result;
}
}
You can intercept any step via EngineStepHook (beforeStep, afterStep, onStepError) without forking the engine.
Rules execute by phase: PRE_RESPONSE_RESOLUTION, POST_AGENT_INTENT, POST_SCHEMA_EXTRACTION, PRE_AGENT_MCP, POST_AGENT_MCP, and POST_TOOL_EXECUTION.
Keep business transitions in ce_rule and state graph config, not hardcoded in steps, so behavior remains data-driven and auditable.