Engine Application

Interaction Pipeline

A conversation is executed as a reactive pipeline: a Flux<Element> coming from the client is transformed into a Flux<OutputElement> going back to it. The abstractions themselves — Pipeline, Context, Input, PipelineComponent — live in the common library; this page describes how the engine puts them together.

Pipeline Setups

The setupName part of a pipeline key selects a setup: a pair of a context service and an interaction manager, configured under promethist.pipeline.setup.{name}.

Setup Context service Interaction manager

agent

AgentContextService

RelationalAgentInteractionManager, BasicAgentInteractionManager or TestAgentInteractionManager — the setup used for regular agents. All three are registered for the agent setup, and the one matching the agent’s type is used.

realtime

BasicContextService

BasicInteractionManager — a minimal setup without an agent, used for realtime experiments.

realtime-preview

BasicContextService

PreviewInteractionManager — one-shot voice preview: the agent speaks a sample sentence in the requested locale and the session ends.

promethist.pipeline.allowedSetupNames can restrict which setups a deployment accepts; a key naming an unconfigured setup fails the connection.

PipelineService

PipelineService is the single entry point for every transport — the WebSocket handler, the Socket.IO service, the Twilio handler and the HTTP pipeline controller all go through it.

Building the Configuration

createConfiguration(key, headers, parameters, sessionId) normalizes query parameters and X- headers into a PipelineConfiguration, with the query parameter taking precedence over the header. The resulting object carries everything the conversation needs: session ID, device ref, locales and time zone, audio encoding and sample rates, wire formats, feature flags and the optional realtime configuration. The full parameter list is documented in Pipeline Configuration.

Creating the Pipeline

createPipeline(configuration, authentication) returns an anonymous Pipeline implementation over the full set of injected PipelineComponent beans. The base class sorts those components into typed collections (extractors, element filters, action mappers, speech synthesizers, interaction managers), so adding a component to the engine is a matter of declaring a bean — no registration step.

The instance also resolves the conversation’s user from the authentication: a JWT token yields the platform user (and copies the name and email claims onto the session), Basic and API key identities resolve by name, and without an identity the user is derived from the speaker or the device.

Session Windowing

process(configuration, authentication, elements) implements the multi-session state machine over one connection:

  1. If the configuration already carries a key, a synthetic #ready:key=…&sessionId=… token is prepended, which starts the first session immediately. Otherwise the pipeline waits for the client to send that token.

  2. The element stream is split on every #ready:key= token, so one physical connection can carry several consecutive sessions.

  3. Within a session, elements are taken until an #exit token.

  4. Each session window re-reads its key and session ID from the token, so a subsequent session on the same connection can address a different agent.

Three control tokens are intercepted mid-stream rather than passed on:

Token Effect

#authorization:<jwt>

Decodes the token and replaces the pipeline’s authentication for the remainder of the session.

#locale:<tags>

Replaces the accepted locales of the configuration.

#end

Handled by the transport layer: it completes the input stream, which ends the session gracefully.

Session Lifecycle

For each session window the service resolves the device (creating a Device record for an unknown deviceRef) and then the Session — either the existing document for a reused sessionId or a new one in state OPEN.

A new document is written before any agent has been resolved, so it carries no user, agent or project association yet. Those are filled in and saved by the context service once the agent’s project has passed the permission and subscription check — see Session Start. The rest of the session’s state (turn count, emotional sets, summary, evaluation fields) accumulates only in memory and reaches MongoDB on the next save, which is normally the one at session end; a #rating action is the exception, saving the session mid-conversation so a disconnect cannot lose the rating.

Input then flows through ProcessorManager (audio and token normalization, see Processors) into the pipeline manager chosen for the model (see Pipeline Managers), and the output flows back to the transport.

How the session ends determines the cleanup:

Outcome Session state Cleanup

Input stream completed (client sent #end)

ENDED

End-of-conversation evaluation runs, post-session webhooks execute, then the session is saved. The evaluation output is appended to the output stream, so a still-connected client can receive its results as an evaluation-status element.

Error

DISCONNECTED

The session is saved in the disconnected state.

Cancelled (client vanished)

DISCONNECTED

Same as above. This is why closing a socket without sending #end delays the post-session processing — the engine has to notice the disconnect first.

A watchdog guards against a pipeline that never completes: once the input stream has completed, the output is force-closed after promethist.pipeline.sessionEndTimeoutMs.

Each turn is persisted through the pipeline’s saveContext, which stores the Turn with its timing log and records the latency metrics described in Observability.

Pipeline Managers

PipelineService prepares a conversation before any pipeline manager is involved. It builds the context, resolves the interaction manager for it and opens the model session through RealtimeSessionFactory. The interaction manager is the one registered for the setup (a @PipelineSetup annotation) whose content classes contain the class of the context’s content — the agent; failing that, the one that claims no particular content. Only then is the pipeline manager chosen, from the model’s properties:

Pipeline manager Used when Drives

TurnPipelineManager

isTurnless is false — every model except OpenAI GPT-Live

A conversation delimited into turns. It windows the element stream into turns, drives the interaction and planning managers, and records usage when the conversation ends. Needs a TurnInteractionManager.

TurnlessPipelineManager

isTurnless is true — OpenAI GPT-Live

A conversation that is not delimited: the model speaks continuously and decides for itself when to talk, so there are no turns, no planning and no response end. Needs a TurnlessInteractionManager.

An interaction manager that does not implement the contract of the chosen pipeline manager is rejected with an error.

The turn-based manager is the most intricate part of the engine, so it has its own pages:

Contexts

The context is the per-turn state handed to every component. The engine provides two context services:

Service Context

AgentContextService

Builds an AgentContext — session, user, memory plus the agent, its project, the active skills, shared agents and the evaluation state. Used by the agent setup.

BasicContextService

Builds a BasicContext for setups that run without an agent.

Both extend ContextBase, which creates the Turn document, increments the session’s turn count and records transcripts.

In this section