02 - Architecture
Module Structure
Section titled “Module Structure”agentensemble/ # Root project agentensemble-core/ # Core library (the framework) agentensemble-examples/ # Example applicationsDependency Graph
Section titled “Dependency Graph”agentensemble-core +-- langchain4j-core (LLM abstractions, tool specs, message types) +-- lombok (compile-only: builders, value objects) +-- jackson-databind (JSON serialization for tool I/O) +-- slf4j-api (logging facade)
agentensemble-examples +-- agentensemble-core +-- langchain4j-open-ai (OpenAI model provider -- example only) +-- logback-classic (SLF4J implementation for examples)Users add their own LangChain4j model provider as a runtime dependency (e.g., langchain4j-open-ai, langchain4j-ollama, langchain4j-anthropic).
Package Structure
Section titled “Package Structure”net.agentensemble Agent.java # Top-level user-facing domain objects Task.java Ensemble.java
net.agentensemble.agent AgentExecutor.java # Runs one agent on one task AgentPromptBuilder.java # Constructs system/user prompts
net.agentensemble.task TaskOutput.java # Task result value object
net.agentensemble.ensemble EnsembleOutput.java # Ensemble result value object
net.agentensemble.workflow Workflow.java # Enum: SEQUENTIAL, HIERARCHICAL WorkflowExecutor.java # Strategy interface SequentialWorkflowExecutor.java # Runs tasks one-by-one HierarchicalConstraints.java # Constraints for hierarchical workflow HierarchicalConstraintEnforcer.java # Enforces hierarchical constraints (package-private)
net.agentensemble.tool AgentTool.java # Framework tool interface ToolResult.java # Tool execution result LangChain4jToolAdapter.java # Adapts AgentTool to LC4j
net.agentensemble.config TemplateResolver.java # {variable} substitution
net.agentensemble.exception AgentEnsembleException.java # Base exception ValidationException.java # Invalid configuration TaskExecutionException.java # Task-level failure AgentExecutionException.java # Agent-level failure ToolExecutionException.java # Tool execution failure MaxIterationsExceededException.java # Agent hit iteration limit PromptTemplateException.java # Template variable error ConstraintViolationException.java # Hierarchical constraint violated
net.agentensemble.metrics # Execution metrics (issue #42) TaskMetrics.java # Per-task token counts, timing, costs ExecutionMetrics.java # Aggregated per-run metrics CostConfiguration.java # Per-token cost rates for estimation CostEstimate.java # Monetary cost estimate value object MemoryOperationCounts.java # STM/LTM/entity operation counters
net.agentensemble.trace # Execution trace (issues #42, #89) ExecutionTrace.java # Top-level immutable run trace TaskTrace.java # Per-task trace LlmInteraction.java # Single LLM chat() call record ToolCallTrace.java # Single tool invocation record DelegationTrace.java # Peer delegation record TaskPrompts.java # System/user prompt snapshot AgentSummary.java # Agent configuration snapshot ErrorTrace.java # Error record LlmResponseType.java # FINAL_ANSWER / TOOL_CALLS enum ToolCallOutcome.java # SUCCESS / FAILURE / ERROR / SKIPPED enum CaptureMode.java # OFF / STANDARD / FULL capture depth (issue #89) CapturedMessage.java # Serializable LLM message snapshot (issue #89)
net.agentensemble.trace.export # Trace export (issue #42) ExecutionTraceExporter.java # Strategy interface for exporting traces JsonTraceExporter.java # File-based JSON exporter
net.agentensemble.trace.internal # Internal accumulator (package-private API) TaskTraceAccumulator.java # Mutable collector, frozen at task end
net.agentensemble.memory # Memory subsystem MemoryContext.java # Runtime memory state for one run MemoryOperationListener.java # Callback interface for memory events (issue #89) EnsembleMemory.java # Memory configuration ShortTermMemory.java # In-run task output accumulator LongTermMemory.java # Pluggable persistent store interface EntityMemory.java # Key-value fact store interface MemoryEntry.java # Memory entry value objectDesign Principles
Section titled “Design Principles”-
Immutability:
Agent,Task,TaskOutput,EnsembleOutputare immutable value objects (@Value). Once built, they cannot be modified. -
Builder pattern: All domain objects use Lombok
@Builderfor construction with validation in custom builder methods. -
Strategy pattern:
WorkflowExecutoris a strategy interface withSequentialWorkflowExecutor,HierarchicalWorkflowExecutor, andParallelWorkflowExecutorimplementations.ManagerPromptStrategyis a secondary strategy interface that controls how the Manager agent’s system and user prompts are generated in hierarchical workflow —DefaultManagerPromptStrategyprovides the built-in behaviour while callers can substitute a custom implementation viaEnsemble.Builder.managerPromptStrategy(). -
Composition over inheritance:
AgentExecutorcomposes LangChain4j services rather than extending them. No deep inheritance hierarchies. -
Fail-fast: Validation happens at construction time (
build()) and atrun()time, not deep in execution. Users get clear error messages early. -
No singletons or statics: All components are instantiated, making testing straightforward.
TemplateResolveruses static methods but is stateless and pure. -
Separation of concerns: Prompt construction (AgentPromptBuilder), execution (AgentExecutor), orchestration (WorkflowExecutor), and domain model are separate classes with single responsibilities.
Build System
Section titled “Build System”- Gradle with Kotlin DSL (
.gradle.kts) - Version catalog (
gradle/libs.versions.toml) for centralized dependency management java-libraryplugin foragentensemble-core(properapivsimplementationseparation)applicationplugin foragentensemble-examples- Java 21 target
- Lombok annotation processor configured via Gradle