Architecture Overview
Version: 6.0.0
This document provides a comprehensive overview of EDDI's architecture, design principles, and internal workflow.
Table of Contents
Overview
E.D.D.I. (Enhanced Dialog Driven Interface) is a multi-agent orchestration middleware for conversational AI systems, not a standalone agent or language model. It sits between user-facing applications and multiple AI agents (LLMs like OpenAI, Claude, Gemini, or traditional REST APIs), intelligently routing requests, coordinating responses, and maintaining conversation state across agent interactions.
Core Purpose: Orchestrate multiple AI agents and business systems in complex conversational workflows without writing code.
What EDDI Is (and Isn't)
A Multi-Agent Orchestration Middleware: Coordinates multiple AI agents (LLMs, APIs) in complex workflows
An Intelligent Router: Directs requests to appropriate agents based on patterns, rules, and context
A Conversation Coordinator: Maintains stateful conversations across multiple agent interactions
A Configuration Engine: Agent orchestration defined through JSON configurations, not code
A Middleware Service: Acts as an intermediary that adds intelligence and control to conversation flows
Business System Integrator: Connects AI agents with your existing APIs, databases, and services
Cloud-Native: Built with Quarkus for fast startup, low memory footprint, and containerized deployment
Stateful: Maintains complete conversation history and context throughout interactions
EDDI Is Not:
Not a standalone LLM: It doesn't train or run machine learning models
Not a chatbot platform: It's the infrastructure that powers conversational agents
Not just a proxy: It provides orchestration, state management, and complex behavior rules beyond simple API forwarding
Core Architecture
Architectural Principles
EDDI's architecture is built on several key principles:
Modularity: Every component is pluggable and replaceable
Composability: Agents are assembled from reusable packages and extensions
Asynchronous Processing: Non-blocking I/O for handling concurrent conversations
State-Driven: All operations transform or query the conversation state
Cloud-Native: Designed for containerized, distributed deployments
High-Level Architecture Diagram
The Lifecycle Pipeline
The Lifecycle is EDDI's most distinctive architectural feature. Instead of hard-coded agent logic, EDDI processes every user interaction through a configurable, sequential pipeline of tasks called the Lifecycle.
How the Lifecycle Works
Pipeline Composition: Each agent defines a sequence of
ILifecycleTaskcomponentsSequential Execution: Tasks execute one after another, each transforming the
IConversationMemoryStateless Tasks: Each task is stateless; all state resides in the memory object passed through
Interruptible: The pipeline can be stopped early based on conditions (e.g.,
STOP_CONVERSATION)
Standard Lifecycle Tasks
A typical agent lifecycle includes these task types:
Input Parsing
Normalizes and understands user input
Extracting entities, intents from text
Semantic Parsing
Uses dictionaries to parse expressions
Matching "hello" → greeting(hello)
Behavior Rules
Evaluates IF-THEN rules to decide actions
"If greeting(*) then action(welcome)"
Property Extraction
Extracts and stores data in conversation memory
Saving user name, preferences
HTTP Calls
Calls external REST APIs
Weather API, CRM systems
LangChain Task
Invokes LLM APIs (OpenAI, Claude, etc.)
Conversational AI responses
Output Generation
Formats final response using templates
Qute templating with conversation data
Lifecycle Task Interface
Every task receives:
IConversationMemory: Complete conversation state
component: Task-specific configuration/resources
Conversation Flow
Step-by-Step: User Interaction Flow
Here's what happens when a user sends a message to an EDDI agent:
1. API Request
2. RestAgentEngine Receives Request
Validates agent ID and environment
Wraps response in
AsyncResponsefor non-blocking processingIncrements metrics counters
3. ConversationCoordinator Queues Message
Ensures messages for the same conversation are processed sequentially
Allows different conversations to process concurrently
Prevents race conditions in conversation state
4. IConversationMemory Loaded/Created
If existing conversation: Loads from MongoDB
If new conversation: Creates fresh memory object
Includes all previous steps, user data, context
5. LifecycleManager Executes Pipeline
Each task in sequence:
Reads current conversation state
Performs its operation (parsing, rule evaluation, API call, etc.)
Writes results back to conversation memory
Passes control to next task
6. State Persistence
Updated
IConversationMemorysaved to MongoDBCache updated with latest conversation state
Metrics recorded (duration, success/failure)
7. Response Returned
Agent Composition Model
EDDI agents are not monolithic. They are composite objects assembled from version-controlled, reusable components.
Hierarchy: Agent → Workflow → Extensions
1. Agent Level
File: {agentId}.agent.json
A agent is simply a list of package references:
2. Workflow Level
File: {workflowId}.package.json
A package is a container of functionality with a list of extensions:
3. Extension Level
Files: {extensionId}.{type}.json
Extensions are the actual agent logic:
Behavior Rules Extension
HTTP Calls Extension
LangChain Extension
What Lives Where: A Decision Guide
When adding a new feature, use this guide to decide where configuration belongs:
Does it affect the entire agent across all conversations?
Agent level (AgentConfiguration)
enableMemoryTools, enableStreaming
Does it control how a pipeline step behaves?
Extension level (e.g., langchain.json, property.json)
LLM parameters, property instructions
Does it define which extensions run and in what order?
Workflow level (package.json)
Extension types and URIs
Is it a user-facing runtime setting?
Agent level
User memory config, audit settings
Is it a tool/capability the LLM can use?
Extension level (in langchain.json)
builtInToolsWhitelist
Rule of thumb: If a feature is a cross-conversation concern (e.g., persistent memory, user preferences, GDPR compliance), it belongs at the agent level. If it's a per-turn processing concern (e.g., LLM parameters, HTTP call config), it belongs at the extension level.
Key Components
RestAgentEngine
Location: ai.labs.eddi.engine.internal.RestAgentEngine
Purpose: Main entry point for all agent interactions
Responsibilities:
Receives HTTP requests via JAX-RS
Validates agent and conversation IDs
Handles async responses
Records metrics
Coordinates with
IConversationCoordinator
ConversationCoordinator
Location: ai.labs.eddi.engine.runtime.internal.ConversationCoordinator
Purpose: Ensures proper message ordering and concurrency control
Key Feature: Uses a queue system to guarantee that:
Messages within the same conversation are processed sequentially
Different conversations can be processed in parallel
No race conditions occur in conversation state updates
IConversationMemory
Location: ai.labs.eddi.engine.memory.IConversationMemory
Purpose: The stateful object representing a complete conversation
Contains:
Conversation ID, agent ID, user ID
All previous conversation steps (history)
Current step being processed
User properties (name, preferences, etc.)
Context data (passed with each request)
Actions and outputs generated
Key Methods:
LifecycleManager
Location: ai.labs.eddi.engine.lifecycle.internal.LifecycleManager
Purpose: Executes the lifecycle pipeline
Key Method:
How It Works:
Iterates through registered
ILifecycleTaskinstancesFor each task, calls
task.execute(conversationMemory, component)Checks for interruption or stop conditions
Continues until all tasks complete or stop condition is met
WorkflowConfiguration
Location: ai.labs.eddi.configs.packages.model.WorkflowConfiguration
Purpose: Defines the structure of an agent package
Model:
ToolExecutionService
Location: ai.labs.eddi.modules.langchain.tools.ToolExecutionService
Purpose: Unified execution pipeline for all AI agent tool invocations
Pipeline:
Features:
Token-bucket rate limiting per tool (configurable per-tool or global default)
Smart caching — deduplicates calls with identical arguments
Cost tracking with per-conversation budgets and automatic eviction
Security: tools that accept URLs are validated against private/internal addresses (SSRF protection via
UrlValidationUtils)Security: math expressions are evaluated in a sandboxed parser (
SafeMathParser)
See the Security documentation for details.
Technology Stack
Core Framework
Quarkus: Supersonic, subatomic Java framework
Fast startup times (~0.05s)
Low memory footprint
Native compilation support
Built-in observability (metrics, health checks)
Language & Runtime
Java 25: Latest LTS with modern language features
GraalVM: Optional native compilation for even faster startup
Dependency Injection
CDI (Contexts and Dependency Injection): Jakarta EE standard
@ApplicationScoped, @Inject: Clean, testable component wiring
REST Framework
JAX-RS: Jakarta REST API standard
AsyncResponse: Non-blocking, scalable request handling
JSON-B: JSON binding for serialization/deserialization
Database (DB-Agnostic)
MongoDB 6.0+ (default): Document store for agent configurations and conversation logs
PostgreSQL (alternative): JDBC + JSONB storage, switchable via
eddi.datastore.type=postgresBoth backends support:
Agent, workflow, and extension configuration storage
Conversation history persistence
Version control of agent components
Automatic schema migration on startup
Caching
Caffeine: High-performance in-memory cache (replaced Infinispan in v6)
Caches conversation state and agent configurations
Configurable size limits per cache type
Zero external dependencies — provided transitively by
quarkus-cache
LLM Integration
LangChain4j: Java library for LLM orchestration
Unified interface to multiple LLM providers
Supports OpenAI, Claude, Gemini, Ollama, Hugging Face, etc.
Handles chat message formatting, streaming, tool calling
Observability
Micrometer: Metrics collection
Prometheus: Metrics exposition
Kubernetes Probes: Liveness and readiness endpoints
Security
OAuth 2.0: Authentication and authorization
Keycloak: Identity and access management
Templating
Qute: Output templating engine
Dynamic output generation
Access to conversation memory in templates
Expression language support
Design Patterns Used
1. Strategy Pattern
Where: Lifecycle tasks
Why: Different behaviors (parsing, rules, API calls) implement the same
ILifecycleTaskinterface
2. Chain of Responsibility
Where: Lifecycle pipeline
Why: Each task processes the memory object and passes it to the next task
3. Composite Pattern
Where: Agent composition (Agent → Workflows → Extensions)
Why: Agents are built from hierarchical, reusable components
4. Repository Pattern
Where: Data access (stores: agentstore, packagestore, etc.)
Why: Abstracts data persistence from business logic
5. Factory Pattern
Where:
IAgentFactoryWhy: Complex agent instantiation from multiple packages and configurations
6. Coordinator Pattern
Where:
ConversationCoordinatorWhy: Manages concurrent access to shared conversation state
Performance Characteristics
Startup Time
JVM mode: < 2 seconds
Native mode: < 50ms (with GraalVM)
Memory Footprint
JVM mode: ~200MB baseline
Native mode: ~50MB baseline
Request Latency
Without LLM: 10-50ms (parsing, rules, simple API calls)
With LLM: 500-5000ms (depends on LLM provider)
Scalability
Vertical: Handles thousands of concurrent conversations per instance
Horizontal: Stateless design allows infinite horizontal scaling
Agenttleneck: MongoDB becomes agenttleneck; use replica sets and sharding
Cloud-Native Features
Containerization
Official Docker images:
labsai/eddiCertified by IBM/Red Hat
Multi-stage builds for minimal image size
Orchestration
Kubernetes-ready
OpenShift certified
Health checks built-in
Configuration
Externalized configuration via environment variables
ConfigMaps and Secrets support
No rebuild needed for configuration changes
Observability
Prometheus metrics endpoint:
/q/metricsHealth checks:
/q/health/live,/q/health/readyStructured logging with correlation IDs
Case Study: The "Agent Father"
The Agent Father is a meta-agent that demonstrates EDDI's architecture in action. It's an agent that creates other agents.
For a comprehensive, step-by-step walkthrough of Agent Father, see Agent Father: A Deep Dive
How It Works
Conversation Start: User starts chat with Agent Father
Information Gathering: Agent Father asks questions:
"What do you want to call your agent?"
"What should it do?"
"Which LLM API should it use?"
Memory Storage: Property setters save answers to conversation memory:
context.agentNamecontext.agentDescriptioncontext.llmType
Condition Triggers: Behavior rule monitors memory:
API Call Execution: HTTP Calls extension triggers:
Self-Modification: Agent Father calls EDDI's own API to create a new agent configuration
Key Insight
Agent Father isn't special code—it's a regular EDDI agent that uses:
Behavior rules to control conversation flow
Property extraction to gather data
HTTP Calls to invoke EDDI's REST API
Output templates to guide the user
This demonstrates EDDI's power: the same architecture that powers conversational agents can orchestrate complex, multi-step workflows, even self-modifying the system itself.
See the Agent Father Deep Dive for complete implementation details, code examples, and real-world applications.
Summary
EDDI's architecture is built on principles of modularity, composability, and orchestration. It's not a chatbot—it's the infrastructure for building sophisticated conversational AI systems that can:
Orchestrate multiple APIs and LLMs
Apply complex business logic through configurable rules
Maintain stateful, context-aware conversations
Scale horizontally in cloud environments
Be assembled from reusable, version-controlled components
The Lifecycle Pipeline is the heart of this architecture, providing a flexible, pluggable system where agent behavior is configuration, not code.
Configuration Model Deep Dive
EDDI's configuration model is a 4-level tree:
Agent → Workflows → Extensions
Agent
List of workflow URIs + channels. The top-level container.
Workflow
Ordered list of workflow extensions — each extension = one lifecycle task type. Order matters: tasks execute sequentially.
Extension
The actual configuration that drives each ILifecycleTask. Referenced by URI from the workflow.
Descriptor
Metadata (name, description, timestamps) for any resource. Not functional, purely for UI/management.
URI-Based References
Every resource references its dependencies by eddi:// URI:
Extension Types & Their Pipeline Role
Each workflow runs its extensions in order: Parser → Behavior → Property → HttpCalls → LLM → Output (typical order).
Parser
Raw user text
Expressions (semantic representation)
expressionsAsActions: true — parser expressions become actions
Behavior Rules
Actions and expressions
New actions that drive subsequent tasks
IF-THEN condition engine — the routing logic
Property Setter
Current memory data
Stored properties (conversation-scoped or long-term)
Slot-filling using {memory.current.input} templates
HTTP Calls
Actions, template variables
Response data stored in memory
Pre/post request property instructions, retry support
LLM
Conversation memory, system prompt, tools
LLM response text
Legacy chat (simple) or Agent mode (tool-calling loop)
Output Templates
Actions from current step
Text responses + quickReplies
Template variables, response variation via valueAlternatives
Parser & Expression System
The parser uses a recursive expression model with Prolog heritage:
QuickReply → Expression → Action flow: When a user clicks a quickReply, the parser matches the text against the previous step's quickReply value fields, extracts the corresponding expressions, and (if expressionsAsActions is enabled) converts them to actions that drive behavior rules.
Available NLP Extensions
Dictionaries (7)
RegularDictionary, IntegerDictionary, DecimalDictionary, EmailDictionary, TimeExpressionDictionary, OrdinalNumbersDictionary, PunctuationDictionary
Normalizers (4)
ContractedWordNormalizer, ConvertSpecialCharacterNormalizer, PunctuationNormalizer, RemoveUndefinedCharacterNormalizer
Corrections (3)
DamerauLevenshteinCorrection, MergedTermsCorrection, PhoneticCorrection
Database Architecture
EDDI's data layer is fully DB-agnostic via the IResourceStorageFactory SPI:
Switching databases requires only a config change:
Related Documentation
Getting Started - Setup and installation
Conversation Memory & State Management - Deep dive into conversation state
Agent Father: A Deep Dive - Complete walkthrough of a real-world example
Behavior Rules - Configure decision logic
HTTP Calls - External API integration
LLM Integration - Connect to LLM APIs
Extensions - Available agent components
Security - Authentication, authorization, and tool security
Secrets Vault - Encrypted secret management
Audit Ledger - EU AI Act compliance
MCP Server - Model Context Protocol integration
Last updated
Was this helpful?