Skip to content

Ensemble Configuration Reference

All fields available on Ensemble.builder().

MethodDescription
Ensemble.run(ChatModel model, Task... tasks)Zero-ceremony: create and run a sequential ensemble with the given LLM. Agents are synthesized from task descriptions.

FieldTypeRequiredDefaultDescription
tasksList<Task>YesAll tasks to execute. Add with .task(t) (singular) or .tasks(list).
chatLanguageModelChatModelNonullDefault LLM for all tasks without an explicit agent or task-level LLM. Required when any task lacks an explicit agent and does not set its own chatLanguageModel. Also used as the Manager LLM in hierarchical workflow if managerLlm is not set.
agentSynthesizerAgentSynthesizerNoAgentSynthesizer.template()Strategy for synthesizing agents for agentless tasks. AgentSynthesizer.template() (default) derives role, goal, and backstory from the task description deterministically. AgentSynthesizer.llmBased() invokes the LLM once per agentless task for a higher-quality persona.
inputsMap<String, String>No{}Template variable values applied to all task descriptions and expected outputs at run time. Add individual entries with .input("key", "value") or a batch with .inputs(map). Run-time values passed to run(Map) are merged on top; run-time values win on conflicts. See Template Variables guide.
workflowWorkflowNonull (inferred)Execution strategy. SEQUENTIAL, HIERARCHICAL, or PARALLEL. When null (not set), the framework infers: if any task declares a context dependency on another ensemble task, PARALLEL is inferred; otherwise SEQUENTIAL. An explicit value always overrides inference. See Workflows guide.
managerLlmChatModelNoFirst agent’s LLMLLM for the auto-created Manager agent (hierarchical workflow only).
managerMaxIterationsintNo20Maximum tool-call iterations for the Manager agent. Must be greater than zero (hierarchical only).
managerPromptStrategyManagerPromptStrategyNoDefaultManagerPromptStrategy.DEFAULTStrategy that builds the Manager agent’s system and user prompts. Implement ManagerPromptStrategy to inject domain-specific context without forking internals. Only exercised for hierarchical workflow. See Workflows guide.
parallelErrorStrategyParallelErrorStrategyNoFAIL_FASTError handling for parallel workflow. FAIL_FAST stops on first failure; CONTINUE_ON_ERROR lets independent tasks finish and reports all failures in a ParallelExecutionException.
verbosebooleanNofalseWhen true, elevates all agent logging to INFO level.
memoryStoreMemoryStoreNonullScoped memory store for cross-execution persistence (v2.0.0). Tasks with declared memory scopes automatically read from and write to this store. Use MemoryStore.inMemory() for development/testing or MemoryStore.embeddings(model, store) for production. See Memory guide.
maxDelegationDepthintNo3Maximum peer-delegation depth. Applies when agents have allowDelegation = true. Must be greater than zero.
delegationPoliciesList<DelegationPolicy>No[]Pluggable hooks evaluated before each delegation attempt (after built-in guards). Add individual policies with .delegationPolicy(policy) (Lombok singular) or a collection with .delegationPolicies(list). Policies run in registration order. A REJECT result blocks the delegation; a MODIFY result replaces the request; an ALLOW result continues evaluation. Applies to both peer and hierarchical delegation. See Delegation guide.
hierarchicalConstraintsHierarchicalConstraintsNonullOptional guardrails for the delegation graph (hierarchical workflow only). Enforces required workers, allowed workers, per-worker caps, global delegation cap, and stage ordering. When requiredWorkers are not called by run end, ConstraintViolationException is thrown. See the Delegation guide for full documentation.
costConfigurationCostConfigurationNonullOptional per-token cost rates. When set, each task’s LLM token usage is multiplied by inputTokenRate / outputTokenRate to produce a CostEstimate on both TaskMetrics and ExecutionMetrics. Requires the LLM provider to return token usage metadata. See Metrics guide.
traceExporterExecutionTraceExporterNonullOptional exporter called at the end of each run() with the complete ExecutionTrace. Use JsonTraceExporter to write traces to JSON files, or implement the functional interface for custom destinations. See Metrics guide.
captureModeCaptureModeNoOFFDepth of data collection during execution. OFF captures the base trace (prompts, tool args/results, timing, tokens). STANDARD also captures full LLM message history per iteration and wires memory operation counts. FULL adds auto-export to ./traces/ and enriched tool I/O with parsed JSON arguments. Can also be activated without code changes via the agentensemble.captureMode JVM system property or AGENTENSEMBLE_CAPTURE_MODE environment variable (resolution order: builder > system property > env var > OFF). CaptureMode.OFF has zero performance overhead beyond the always-active base trace. See CaptureMode guide.
reviewHandlerReviewHandlerNonullOptional review handler for human-in-the-loop gates (requires agentensemble-review on the classpath). When set, the workflow executor fires review gates at configured timing points. Built-in factories: ReviewHandler.console(), ReviewHandler.autoApprove(), ReviewHandler.autoApproveWithDelay(Duration), ReviewHandler.web(URI) (stub). See Review guide.
reviewPolicyReviewPolicyNonull (treated as NEVER)Ensemble-level policy controlling when after-execution review gates fire for tasks without an explicit .review() configuration. NEVER (default): only tasks with .review(Review.required()) fire. AFTER_EVERY_TASK: all tasks fire; tasks with .review(Review.skip()) are exempt. AFTER_LAST_TASK: only the final task fires. Requires reviewHandler to be set. See Review guide.

At Ensemble.run() time:

  • At least one task must be registered
  • Every task must have an LLM source: explicit agent, task-level chatLanguageModel, or ensemble-level chatLanguageModel
  • No circular context dependencies
  • Context task ordering is valid (sequential workflow only)
  • maxDelegationDepth must be greater than zero

ensemble.run() returns an EnsembleOutput with:

MethodTypeDescription
getRaw()StringRaw text of the final task output (or manager synthesis in hierarchical workflow)
getTaskOutputs()List<TaskOutput>All task outputs in execution order
getTotalDuration()DurationWall-clock time for the entire run
getTotalToolCalls()intTotal number of tool calls across all agents
getMetrics()ExecutionMetricsAggregated metrics: total token counts, LLM latency, tool execution time, cost estimate, etc.
getTrace()ExecutionTraceComplete execution trace with every LLM interaction, tool call, prompt text, and delegation record. Serializes to JSON via getTrace().toJson().
getExitReason()ExitReasonWhy the run terminated: COMPLETED (full run), USER_EXIT_EARLY (reviewer chose ExitEarly), TIMEOUT (review gate expired with EXIT_EARLY action), or ERROR (unrecoverable exception). When not COMPLETED, getTaskOutputs() contains only the tasks that finished before the termination signal.
isComplete()booleantrue when all tasks finished with ExitReason.COMPLETED. Convenience shorthand for getExitReason() == ExitReason.COMPLETED.
completedTasks()List<TaskOutput>All task outputs that finished before (or caused) the termination signal. Always safe to call regardless of exit reason. Alias for getTaskOutputs().
lastCompletedOutput()Optional<TaskOutput>The last TaskOutput in the completed list, or empty if no tasks completed.
getOutput(Task task)Optional<TaskOutput>Output for a specific task, using object identity for the lookup. Pass the same Task instance given to .task(...) on the builder. Returns empty if the task did not complete or was never started.

Each TaskOutput contains:

MethodTypeDescription
getRaw()StringRaw text output from the agent
getAgentRole()StringRole of the agent that produced this output
getTaskDescription()StringDescription of the task (after template resolution)
getDuration()DurationTime taken for this task
getToolCallCount()intNumber of tool calls made for this task
getCompletedAt()InstantTimestamp when this task completed
getMetrics()TaskMetricsPer-task metrics: input/output token counts, LLM latency, tool execution time, prompt build time, cost estimate. Token counts are -1 when the provider did not return usage metadata.
getTrace()TaskTraceComplete task trace: all LLM interactions with their tool calls, system/user prompts, delegation records, and final output.

Zero-ceremony:

EnsembleOutput output = Ensemble.run(model,
Task.of("Research AI agents"),
Task.of("Write a blog post based on the research"));

Explicit agents with memory:

EnsembleOutput output = Ensemble.builder()
.task(researchTask) // researchTask has .agent(researcher)
.task(writeTask) // writeTask has .agent(writer)
.task(editTask) // editTask has .agent(editor)
.workflow(Workflow.SEQUENTIAL)
.input("topic", "AI agents")
.input("audience", "developers")
.verbose(false)
.memoryStore(MemoryStore.inMemory())
.maxDelegationDepth(2)
.build()
.run();

Synthesized agents with LLM-based synthesis:

EnsembleOutput output = Ensemble.builder()
.chatLanguageModel(model)
.agentSynthesizer(AgentSynthesizer.llmBased())
.task(Task.of("Research AI trends"))
.task(Task.of("Analyse the findings"))
.task(Task.of("Write an executive summary"))
.workflow(Workflow.SEQUENTIAL)
.build()
.run();

Use .input("key", "value") on the builder to supply {variable} placeholder values for all task descriptions and expected outputs. For dynamic multi-run scenarios, pass values to run(Map<String, String>) instead; those values are merged on top of any builder inputs. See Template Variables guide.


MapReduceEnsemble<T> automates the fan-out / tree-reduce pattern, keeping each reducer’s context bounded. It supports two strategies, selected by the fields you configure:

  • Static (chunkSize): DAG pre-built at build() time.
  • Adaptive (targetTokenBudget): DAG built at runtime from actual token counts.

All fields listed below are in MapReduceEnsemble.Builder<T>.

See the MapReduceEnsemble guide and Kitchen example for full documentation.

FieldTypeDescription
itemsList<T>Input items to fan out over. Must not be null or empty.
mapAgentFunction<T, Agent>Factory called once per item to create the map-phase agent.
mapTaskBiFunction<T, Agent, Task>Factory called once per item to create the map-phase task.
reduceAgentSupplier<Agent>Factory called once per reduce group (including the final reduce).
reduceTaskBiFunction<Agent, List<Task>, Task>Factory for reduce tasks. Must wire .context(chunkTasks).

chunkSize and targetTokenBudget are mutually exclusive. When neither is set, the default is static mode with chunkSize=5.

FieldTypeDefaultDescription
chunkSizeint5Static mode. Maximum upstream tasks per reduce group. Must be >= 2. Mutually exclusive with targetTokenBudget.
targetTokenBudgetintAdaptive mode. Token limit per reduce group. Must be > 0. Mutually exclusive with chunkSize.
contextWindowSizeintAdaptive mode (convenience). Derives targetTokenBudget = contextWindowSize * budgetRatio. Must be set together with budgetRatio.
budgetRatiodouble0.5Adaptive mode (convenience). Fraction of context window to use. Range: (0.0, 1.0]. Must be set together with contextWindowSize.
FieldTypeDefaultDescription
maxReduceLevelsint10Maximum adaptive reduce iterations before the final reduce is forced. Must be >= 1.
tokenEstimatorFunction<String, Integer>built-inCustom token estimator function. Overrides heuristic fallback (rawText.length() / 4) when the LLM provider does not return token counts.
directAgentSupplier<Agent>nullShort-circuit (adaptive only). Factory for the agent that executes the single direct task when the total estimated input size fits within targetTokenBudget. Must be set together with directTask; setting one without the other is a ValidationException. Not allowed in static (chunkSize) mode.
directTaskBiFunction<Agent, List<T>, Task>nullShort-circuit (adaptive only). Factory for the direct task. Receives the agent and the complete List<T> of all items. Must be set together with directAgent; setting one without the other is a ValidationException. Not allowed in static (chunkSize) mode.
inputEstimatorFunction<T, String>Object::toStringShort-circuit estimator (used only in adaptive mode). Converts each input item to a text representation used for pre-execution input size estimation in adaptive short-circuiting. Defaults to toString(). Provide a compact representation (e.g., a JSON summary) when toString() is verbose or not representative of the context window cost. May also be set in static (chunkSize) mode, where it is accepted but ignored. Can be set without directAgent/directTask (no constraint).
FieldTypeDefaultDescription
verbosebooleanfalsePassed through to the inner Ensemble.
listenerEnsembleListenerRepeatable listener registration.
captureModeCaptureModeOFFPassed through to the inner Ensemble.
parallelErrorStrategyParallelErrorStrategyFAIL_FASTPassed through to the inner Ensemble.
costConfigurationCostConfigurationnullPassed through to the inner Ensemble.
traceExporterExecutionTraceExporternullPassed through to the inner Ensemble.
toolExecutorExecutorvirtual-threadPassed through to the inner Ensemble.
toolMetricsToolMetricsNoOpToolMetricsPassed through to the inner Ensemble.
input / inputsMap<String,String>{}Template variable inputs.
MethodReturnsNotes
build()MapReduceEnsemble<T>Validates and builds. Static: constructs full DAG. Adaptive: stores configuration for runtime execution.
run()EnsembleOutputExecutes; returns result from the final reduce task.
run(Map<String,String>)EnsembleOutputRuntime variable overrides merged on top of builder inputs.
toEnsemble()EnsembleStatic mode only. Pre-built inner ensemble for devtools inspection. Throws UnsupportedOperationException in adaptive mode.
isAdaptiveMode()booleanReturns true when targetTokenBudget was set (directly or derived).