Skip to main content
v1

Architecture

Layers

API Layer

  • ConversationController
  • request DTO: ConversationRequest
  • response DTO: ConversationResponse

Engine Layer

  • DefaultConversationalEngine
  • EnginePipelineFactory (DAG sort + wrappers + timing + step hooks)
  • EngineSession (per-turn mutable state)

Resolver Layer

  • intent: classifier + agent + collision resolver
  • rules: type/action factories
  • response: response type + output format factories
  • MCP: planner + registry + DB executor

Persistence Layer

  • JPA repositories on ce_*
  • ce_conversation and ce_audit write path

Transport Layer (configurable)

  • SSE stream endpoint
  • STOMP/WebSocket publisher

Request Path (high-level)

1

Controller receives request

Builds EngineContext from conversationId, message, inputParams, optional reset flag.

2

Engine opens session

EngineSessionFactory creates session and history provider injects last turns.

3

Pipeline runs ordered steps

Each step receives same session instance and may mutate intent/state/context/payload.

4

Persist + return result

Final payload is persisted and returned as TEXT/JSON response.

Code references

Engine entrypoint
package: com.github.salilvnair.convengine.engine.providerfile: 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);
}
Pipeline execution loop
package: com.github.salilvnair.convengine.engine.pipelinefile: src/main/java/com/github/salilvnair/convengine/engine/pipeline/EnginePipeline.java
JAVA
for (EngineStep step : steps) {
StepResult r = step.execute(session);
if (r instanceof StepResult.Stop(EngineResult result)) {
return result;
}
}
Intervention point

You can intercept any step via EngineStepHook (beforeStep, afterStep, onStepError) without forking the engine.

DAG-ordering model

Step order is never hardcoded as a list. It is computed from annotations and validated for cycles/missing dependencies.