Skip to content

02 - Architecture

agentensemble/ # Root project
agentensemble-core/ # Core library (the framework)
agentensemble-examples/ # Example applications
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).

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 object
  1. Immutability: Agent, Task, TaskOutput, EnsembleOutput are immutable value objects (@Value). Once built, they cannot be modified.

  2. Builder pattern: All domain objects use Lombok @Builder for construction with validation in custom builder methods.

  3. Strategy pattern: WorkflowExecutor is a strategy interface with SequentialWorkflowExecutor, HierarchicalWorkflowExecutor, and ParallelWorkflowExecutor implementations. ManagerPromptStrategy is a secondary strategy interface that controls how the Manager agent’s system and user prompts are generated in hierarchical workflow — DefaultManagerPromptStrategy provides the built-in behaviour while callers can substitute a custom implementation via Ensemble.Builder.managerPromptStrategy().

  4. Composition over inheritance: AgentExecutor composes LangChain4j services rather than extending them. No deep inheritance hierarchies.

  5. Fail-fast: Validation happens at construction time (build()) and at run() time, not deep in execution. Users get clear error messages early.

  6. No singletons or statics: All components are instantiated, making testing straightforward. TemplateResolver uses static methods but is stateless and pure.

  7. Separation of concerns: Prompt construction (AgentPromptBuilder), execution (AgentExecutor), orchestration (WorkflowExecutor), and domain model are separate classes with single responsibilities.

  • Gradle with Kotlin DSL (.gradle.kts)
  • Version catalog (gradle/libs.versions.toml) for centralized dependency management
  • java-library plugin for agentensemble-core (proper api vs implementation separation)
  • application plugin for agentensemble-examples
  • Java 21 target
  • Lombok annotation processor configured via Gradle