Class AgentBuilder

java.lang.Object
com.tnsai.agents.AgentBuilder

public final class AgentBuilder extends Object
Fluent builder for creating Agent instances without subclassing.

This builder provides a fluent API for constructing agents with custom configurations, ideal for:

  • Testing with mock dependencies
  • Creating agents programmatically at runtime
  • Dynamic agent configuration from external sources

Example usage:

 // Simple agent with LLM and role
 Agent agent = AgentBuilder.create()
     .id("support-agent")
     .llm(new GeminiClient("gemini-2.0-flash"))
     .role(new CustomerSupportRole())
     .build();

 // Full configuration
 Agent agent = AgentBuilder.create()
     .id("research-agent")
     .llm(llmClient)
     .memoryStore(new FileMemoryStore("./memory"))
     .roles(List.of(researchRole, analysisRole))
     .communication(Communication.formal())
     .maxContextTokens(8000)
     .build();

 // Testing with mocks
 Agent testAgent = AgentBuilder.create()
     .id("test-agent")
     .llm(mockLLM)
     .memoryStore(mockMemory)
     .actionExecutor(mockExecutor)
     .build(); // McpClient de builder'a eklenmeli
 
See Also:
  • Method Details

    • create

      public static AgentBuilder create()
      Creates a new AgentBuilder instance.
      Returns:
      a new builder
    • id

      public AgentBuilder id(String id)
      Sets the agent ID. If not set, a UUID will be generated.
      Parameters:
      id - the agent identifier
      Returns:
      this builder
    • description

      public AgentBuilder description(String description)
      Sets the agent's human-readable description — programmatic parity for AgentSpec.description() (TNS-534).
      Parameters:
      description - agent description (surfaces in the LLM identity prompt)
      Returns:
      this builder
      Since:
      0.11.0
    • version

      public AgentBuilder version(String version)
      Sets the agent version — programmatic parity for AgentSpec.version() (TNS-534).
      Parameters:
      version - semantic version string (default "1.0.0")
      Returns:
      this builder
      Since:
      0.11.0
    • autoStart

      public AgentBuilder autoStart(boolean autoStart)
      Sets whether the agent auto-starts its protocols — programmatic parity for AgentSpec.autoStart() (TNS-534).
      Parameters:
      autoStart - true to auto-start (annotation default)
      Returns:
      this builder
      Since:
      0.11.0
    • idleTimeoutMs

      public AgentBuilder idleTimeoutMs(int idleTimeoutMs)
      Sets the idle timeout before the agent may suspend — programmatic parity for AgentSpec.idleTimeoutMs() (TNS-534).
      Parameters:
      idleTimeoutMs - timeout in milliseconds (0 = never suspend)
      Returns:
      this builder
      Since:
      0.11.0
    • did

      public AgentBuilder did(DIDConfig did)
      Sets the agent's decentralized identity configuration — programmatic parity for AgentSpec.did() (TNS-534).
      Parameters:
      did - DID configuration, or null to fall back to the annotation / default DID
      Returns:
      this builder
      Since:
      0.11.0
    • groupMembership

      public AgentBuilder groupMembership(GroupMemberSpec groupMembership)
      Sets the agent's group membership configuration — programmatic parity for AgentSpec.groups() (TNS-534).
      Parameters:
      groupMembership - group membership spec (see GroupMemberSpec.of(String...))
      Returns:
      this builder
      Since:
      0.11.0
    • llm

      public AgentBuilder llm(LLMClient llmClient)
      Sets the LLM client for this agent.

      LLM is optional since 2.17.0. Traditional agents can operate without LLM using only LOCAL and WEB_SERVICE actions.

      If not set:

      • LLM actions will throw IllegalStateException
      • LOCAL and WEB_SERVICE actions work normally
      • Role-level LLM can still be used
      Parameters:
      llmClient - the LLM client, or null for traditional agents
      Returns:
      this builder
    • memoryStore

      public AgentBuilder memoryStore(MemoryStore memoryStore)
      Sets the memory store for conversation history. Defaults to InMemoryStore if not set.
      Parameters:
      memoryStore - the memory store
      Returns:
      this builder
    • memoryConfig

      public AgentBuilder memoryConfig(MemoryConfig config)
      Configures memory declaratively from a MemoryConfig — the programmatic equivalent of @MemorySpec (TNS-546), so a builder user gets full memory configuration without hand-building a MemoryStore or knowing the per-store implementation classes.

      Resolves the config into a store immediately via MemoryStoreFactory.create(MemoryConfig) (like memoryStore(MemoryStore)), so it takes precedence over a class-level @MemorySpec. For a fully custom store implementation use memoryStore(MemoryStore) instead.

      
       AgentBuilder.create()
           .memoryConfig(MemoryConfig.builder()
               .type(MemorySpec.MemoryType.HYBRID)
               .capacity(200)
               .maxContextTokens(8000)
               .build())
           .role(role)
           .build();
       
      Parameters:
      config - the memory configuration (non-null)
      Returns:
      this builder
      Since:
      0.12.0 (TNS-546)
    • actionExecutor

      public AgentBuilder actionExecutor(ActionExecutor actionExecutor)
      Sets the action executor for tool execution. Defaults to standard ActionExecutor if not set.
      Parameters:
      actionExecutor - the action executor
      Returns:
      this builder
    • role

      public AgentBuilder role(Role role)
      Adds a role to the agent.
      Parameters:
      role - the role to add
      Returns:
      this builder
    • roles

      public AgentBuilder roles(List<Role> roles)
      Adds multiple roles to the agent.
      Parameters:
      roles - the roles to add
      Returns:
      this builder
    • identity

      public AgentBuilder identity(AgentIdentity identity)
      Adds an identity to the agent.
      Parameters:
      identity - the identity to add
      Returns:
      this builder
    • identities

      public AgentBuilder identities(List<AgentIdentity> identities)
      Adds multiple identities to the agent.
      Parameters:
      identities - the identities to add
      Returns:
      this builder
    • principal

      public AgentBuilder principal(AgentPrincipal principal)
      Attribute every action this agent dispatches to principal (TNS-298). The configured LiabilitySink sees this principal's id / version on every record.

      Required. build() throws when this is unset — the framework treats accountability as a deployment decision, not a silent default. Use LocalIdentityProvider for single-tenant deployments where the framework is the trust boundary, or an external attestation provider (ERC-8004 / X.509 / AIUC-1) when an outside trust root is needed.

      Returns:
      this builder
      Since:
      0.10.0 (TNS-298)
    • liabilitySink

      public AgentBuilder liabilitySink(LiabilitySink sink)
      Configure the LiabilitySink that receives an AgentLiabilityRecord per dispatch (TNS-298).

      Optional. When unset, no liability records are constructed or retained. RecordingLiabilitySink is an explicit in-memory option for tests; consumers may supply their own retention sink.

      Returns:
      this builder
      Since:
      0.10.0 (TNS-298)
    • authorityScope

      public AgentBuilder authorityScope(AuthorityScope scope)
      Pre-declared authority bounds recorded on every dispatch (TNS-298). Auditors compare attempted actions against this scope to flag scope violations.

      Required. build() throws when this is unset. Consumers who deliberately don't want to narrow pass AuthorityScope.unrestricted(java.time.Duration) — the explicit-decision-recorded-in-audit path is preferred over a silent default.

      Returns:
      this builder
      Since:
      0.10.0 (TNS-298)
    • paymentBroker

      public AgentBuilder paymentBroker(PaymentBroker broker)
      Plug a PaymentBroker into this agent (TNS-298 / TNS-449). The broker prices and settles agent-to-agent payments — chain-level rails (x402 via tnsai-payments), card rails (Stripe), or an internal credit ledger.

      Optional. Unset means the agent uses NoOpPaymentBroker: quotes at $0.00, settlements succeed instantly, accountability machinery threads through untouched. Suitable for internal multi-agent setups where no real money flows. Auto-discovery is intentionally not provided — a broker that moves real funds must be wired explicitly, never picked up off the classpath.

      Returns:
      this builder
      Since:
      0.11.0 (TNS-449 P4.5)
    • skillStore

      public AgentBuilder skillStore(SkillStore store)
      Wire a SkillStore so the agent can surface on-demand modular knowledge between role and tools (TNS-289). When set without an explicit skillResolverPolicy, the policy upgrades from OFF to AUTO, which matches the consumer's intent ("I wired a store, surface candidates automatically").
      Returns:
      this builder
      Since:
      0.10.0 (TNS-289)
    • skillResolver

      public AgentBuilder skillResolver(SkillResolver resolver)
      Override the resolver used when skillResolverPolicy is AUTO. Defaults to KeywordSkillResolver (cheap, no extra round trip). Use LLMSkillResolver for semantic ranking.
      Returns:
      this builder
      Since:
      0.10.0 (TNS-289)
    • skillResolverPolicy

      public AgentBuilder skillResolverPolicy(SkillResolverPolicy policy)
      Explicit skill resolver policy override (AUTO, MANUAL_ONLY, or OFF).
      Returns:
      this builder
      Since:
      0.10.0 (TNS-289)
    • maxActiveSkills

      public AgentBuilder maxActiveSkills(int limit)
      Cap the number of skill descriptions surfaced in the system prompt per turn (TNS-289). Defaults to 3 — keeps prompt overhead bounded while still covering the common case where one or two skills are intent-relevant.
      Returns:
      this builder
      Throws:
      IllegalArgumentException - if limit < 1
      Since:
      0.10.0 (TNS-289)
    • communication

      public AgentBuilder communication(Communication communication)
      Sets the communication style for the agent.
      Parameters:
      communication - the communication style
      Returns:
      this builder
    • promptStrategy

      public AgentBuilder promptStrategy(PromptStrategy strategy)
      Adds a prompt strategy to the agent.

      Prompt strategies enhance the agent's prompts with techniques like Chain-of-Thought, Verification, Confidence scoring, etc.

      Example:

      
       AgentBuilder.create()
           .llm(llmClient)
           .role(myRole)
           .promptStrategy(PromptStrategy.CHAIN_OF_THOUGHT)
           .promptStrategy(PromptStrategy.CONFIDENCE_WEIGHTED)
           .build();
       
      Parameters:
      strategy - the prompt strategy to add
      Returns:
      this builder
    • promptStrategies

      public AgentBuilder promptStrategies(List<PromptStrategy> strategies)
      Adds multiple prompt strategies to the agent.
      Parameters:
      strategies - the prompt strategies to add
      Returns:
      this builder
    • promptEnhancer

      public AgentBuilder promptEnhancer(PromptEnhancer enhancer)
      Sets a custom prompt enhancer for the agent.

      Use this when you need more control than simple strategies provide.

      Example:

      
       PromptEnhancer enhancer = PromptEnhancer.builder()
           .role("Expert researcher")
           .objective("Provide accurate information")
           .strategy(PromptStrategy.CHAIN_OF_VERIFICATION)
           .constraint("Always cite sources")
           .positiveExample("Question", "Good answer", "Why it's good")
           .build();
      
       AgentBuilder.create()
           .llm(llmClient)
           .role(myRole)
           .promptEnhancer(enhancer)
           .build();
       
      Parameters:
      enhancer - the prompt enhancer
      Returns:
      this builder
    • plan

      public AgentBuilder plan(Plan plan)
      Adds a plan to the agent.
      Parameters:
      plan - the plan to add
      Returns:
      this builder
    • plans

      public AgentBuilder plans(List<Plan> plans)
      Adds multiple plans to the agent.
      Parameters:
      plans - the plans to add
      Returns:
      this builder
    • errorRecoveryScenario

      public AgentBuilder errorRecoveryScenario(ErrorRecoveryScenario scenario)
      Adds an error recovery scenario to the agent.
      Parameters:
      scenario - the error recovery scenario
      Returns:
      this builder
    • errorRecoveryScenarios

      public AgentBuilder errorRecoveryScenarios(List<ErrorRecoveryScenario> scenarios)
      Adds multiple error recovery scenarios to the agent.
      Parameters:
      scenarios - the error recovery scenarios
      Returns:
      this builder
    • maxContextTokens

      public AgentBuilder maxContextTokens(int maxTokens)
      Sets the maximum context tokens for memory pruning.
      Parameters:
      maxTokens - the maximum context tokens
      Returns:
      this builder
    • idempotencyStore

      public AgentBuilder idempotencyStore(IdempotencyStore store)
      Sets the IdempotencyStore consulted for tools guarded by @Idempotent. Defaults to a per-process InMemoryIdempotencyStore. For tools declared idempotencyHint = REQUIRED (payments, irreversible deletes) pass a durable implementation — RedisIdempotencyStore or PostgresIdempotencyStore — because the default loses every record on restart, and a lost record is a duplicated effect after recovery (TAN-5933).
      Parameters:
      store - the store to route through the tool dispatcher
      Returns:
      this builder
      Since:
      0.16.0
    • knowledge

      public AgentBuilder knowledge(KnowledgeEntry... entries)
      Gives the agent knowledge entries, layered over its @AgentSpec knowledge by name: an entry whose name the annotation declares replaces that entry (a role entry stays a role entry), and any other entry is added to the agent's chat scope. The knowledge rules run on the layered list, so a chat scope still holds one MEMORY entry and no other SEARCH entry beside it. Repeated calls add to the entries already given.
      Parameters:
      entries - the entries
      Returns:
      this builder
      Since:
      0.18.0
    • actionKnowledge

      public AgentBuilder actionKnowledge(String action, String... entryNames)
      Names the knowledge one action uses, replacing the list its @ActionSpec names. Each name refers to an entry of the layered knowledge. The action and the names are checked when the agent first initializes, not by build(): an action the agent does not have fails with the list of its actions.
      Parameters:
      action - the action's name
      entryNames - the knowledge names the action uses
      Returns:
      this builder
      Since:
      0.18.0
    • knowledgeScope

      public AgentBuilder knowledgeScope(KnowledgeScope scope)
      Shares action-level source snapshots and ordered cursors with other agents and bridges using the same explicit knowledge scope. The host owns the scope and closes it when that lifetime is replaced; active leased turns finish before its resources are released. When unset, action retrieval retains the existing process-wide behavior.
      Parameters:
      scope - knowledge-source lifetime, including one closing after this thread's turn has already acquired a lease
      Returns:
      this builder
      Since:
      0.17.4
    • knowledgeUsageListener

      public AgentBuilder knowledgeUsageListener(BiConsumer<String,List<KnowledgeUsage>> listener)
      Receives what each knowledge source gave every chat turn (scope "chat") and every action call that runs knowledge (scope = the action name): one KnowledgeUsage row per source, in declaration order. The listener runs on the calling thread; if it throws, the failure is logged at WARN with the agent id and scope, and the turn or action continues.
      Parameters:
      listener - receives the scope and the rows
      Returns:
      this builder
      Since:
      0.18.0
    • plannerHandle

      public AgentBuilder plannerHandle(PlannerHandle plannerHandle)
      Sets the planner handle for goal-oriented planning.

      If not set and tnsai-intelligence is on the classpath, a PlannerHandle will be auto-discovered via SPI from the first role's class.

      Parameters:
      plannerHandle - the planner handle
      Returns:
      this builder
    • reasoningStrategy

      public AgentBuilder reasoningStrategy(String strategyName)
      Sets the reasoning strategy by name (e.g., "react", "tot", "got", "self-consistency").

      The strategy handle is created via SPI auto-discovery from tnsai-intelligence. If tnsai-intelligence is not on the classpath, this is silently ignored.

      Parameters:
      strategyName - the strategy identifier
      Returns:
      this builder
    • reasoningStrategy

      public AgentBuilder reasoningStrategy(ReasoningStrategyHandle strategy)
      Sets an explicit reasoning strategy handle.

      Use this when you have a pre-configured strategy instance. Takes precedence over reasoningStrategy(String).

      Parameters:
      strategy - the reasoning strategy handle
      Returns:
      this builder
    • toolPojos

      public AgentBuilder toolPojos(Object... pojos)
      Adds tools by reflecting over POJO instances bearing @Tool-annotated methods (the function-shape pattern, see RFC #188). Each discovered @Tool method becomes a StaticToolMethod in the agent's ToolMethodRegistry at build() time.

      Example with the server's POJO tools:

      
       Path workingDir = Path.of("/projects/my-app");
       AgentBuilder.create()
           .llm(llmClient)
           .role(myRole)
           .toolPojos(
               new ServerFileTools(workingDir),
               new ServerShellTools(workingDir),
               new ServerGitTools(workingDir)
           )
           .build();
       

      Multiple calls accumulate. A single ToolMethodRegistry is built at build() time across every POJO and every dynamic tool, so duplicate names across the entire registration set are caught by the registry's fail-fast.

      Parameters:
      pojos - one or more objects whose public methods are annotated with @Tool
      Returns:
      this builder
      Since:
      0.5.7
    • builtInTools

      public AgentBuilder builtInTools(BuiltInTool... tools)
      Adds one or more shipped
      invalid reference
      BuiltInTool
      toolkits to the agent. Each enum value is reflectively instantiated via
      invalid reference
      BuiltInTool#instantiate()
      and registered through the same pipeline as toolPojos(Object...). Use this as the compile-time-safe shorthand when the toolkit you want is part of the curated catalog in tnsai-tools.
      
       Agent agent = AgentBuilder.create()
           .id("data-analyst")
           .llm(llmClient)
           .role(myRole)
           .builtInTools(
               BuiltInTool.CSV_TOOLS,
               BuiltInTool.JSON_TOOLS,
               BuiltInTool.PDF_TOOLS
           )
           .build();
       

      Each invocation accumulates; a single ToolMethodRegistry is built at build() time across every registered toolkit (so duplicate @Tool names across the selected toolkits are caught by the registry's fail-fast).

      Parameters:
      tools - one or more
      invalid reference
      BuiltInTool
      entries to register
      Returns:
      this builder
      Throws:
      BuiltInToolInstantiationException - if a backing POJO class is missing from the classpath (typically because tnsai-tools is not a runtime dependency)
      Since:
      0.8.0
    • dynamicTool

      public AgentBuilder dynamicTool(DynamicToolMethod dynamicTool)
      Adds a DynamicToolMethod — a tool whose name, description, schema, and dispatch handler are all supplied at construction time. Use for tools whose identity is only known at runtime (e.g. MCP proxies fronting remote server catalogs).

      For static @Tool-annotated methods on POJOs, prefer toolPojos(Object...).

      Parameters:
      dynamicTool - the runtime-defined tool (non-null)
      Returns:
      this builder
      Since:
      0.7.0 (replaced the legacy tool(Tool) / tools(List<Tool>) registration paths together with the Tool interface itself)
    • dynamicTools

      public AgentBuilder dynamicTools(List<DynamicToolMethod> dynamicTools)
      Adds a batch of DynamicToolMethods. null list is a no-op; null entries are skipped.
      Parameters:
      dynamicTools - the runtime-defined tools (may be empty)
      Returns:
      this builder
      Since:
      0.7.0
    • toolCallFilter

      public AgentBuilder toolCallFilter(ToolCallFilter filter)
      Pre-build wiring of a ToolCallFilter — the runtime gate consulted before each tool invocation. Equivalent to calling Agent.setToolCallFilter(com.tnsai.agents.execution.ToolCallFilter) after build(), but visible to the validation pipeline so ToolApprovalValidator (AGENT-V006) can detect when a tool declares @Tool(requiresConfirmation = true) but no approval filter is configured.
      Parameters:
      filter - the filter, or null to clear
      Returns:
      this builder
      Since:
      0.8.5 (issue #234)
    • tenantId

      public AgentBuilder tenantId(String tenantId)
      Declares the tenant this agent is scoped to. The tenant id is plumbed through the validation context so AGENT-V012 (TenantScopeValidator) can complain when the agent is wired to a component that does not implement TenantAware.

      At runtime, public agent turns bind the value to TenantContext. Memory stores that implement TenantAware are guarded against calls with a missing or mismatched tenant scope. Tool-side tenant hooks and tenant fields on audit events remain separate work.

      Pass null or blank to clear (treated as "no tenant scope").

      Parameters:
      tenantId - stable, non-blank identifier for the tenant; or null/blank to clear
      Returns:
      this builder
      Since:
      0.8.5 (issue #235)
    • build

      public Agent build()
      Builds and returns the configured Agent instance.

      Runs the pre-flight validation pipeline (issue #85) first. Every detected Severity.ERROR is collected into a ValidationReport and surfaced together via AgentValidationException. Warnings are logged at WARN but do not block the build.

      Returns:
      the configured Agent
      Throws:
      AgentValidationException - if the pipeline detects any error-level issues
    • relaxValidation

      public AgentBuilder relaxValidation(String issueCode)
      Suppress a specific ValidationIssue.code() from the build() pipeline. Use sparingly and document each suppression — this is the explicit, auditable opt-out for unusual configurations the validators flag but the user has decided are intentional.
      Parameters:
      issueCode - validator code to ignore (e.g. "AGENT-V002")
      Returns:
      this builder
      Since:
      0.5.0 (issue #85)
    • relaxValidation

      public AgentBuilder relaxValidation(Set<String> issueCodes)
      Bulk variant of relaxValidation(String) (issue #85 phase 3 acceptance bullet). Identical semantics, accepts a Set of codes for the common case of suppressing several validators at once (e.g. CI build that wants to skip all reachability probes: .relaxValidation(Set.of("AGENT-V005", "AGENT-V010", "AGENT-V099"))).

      Null entries in the set are rejected eagerly so a typo surfaces at the configuration site rather than silently passing every issue through.

      Parameters:
      issueCodes - validator codes to ignore; non-null and non-null contents
      Returns:
      this builder
      Since:
      0.8.5 (issue #85 phase 3)
    • withReachabilityChecks

      public AgentBuilder withReachabilityChecks(boolean enabled)
      Enable opt-in reachability probes during build() (issue #85 phase 2a). When true, every ReachabilityValidator registered on the pipeline runs in parallel after the sync validators, each bounded by reachabilityCheckTimeout(Duration).

      Default false. The probes touch out-of-process resources (network call to the LLM provider, write to the memory store, MCP handshake) — turn this on in CI or staging environments where you want build-time confirmation that runtime dependencies are actually reachable, leave it off in tests where the probes would spend money or perturb state.

      Since:
      0.8.4 (issue #85 phase 2a)
    • reachabilityCheckTimeout

      public AgentBuilder reachabilityCheckTimeout(Duration timeout)
      Per-probe wall-clock budget passed to each ReachabilityValidator when reachability checks are enabled. Default 5 seconds. Probes that exceed this budget are reported as unreachable (timeout) and the validation pipeline continues.
      Since:
      0.8.4 (issue #85 phase 2a)
    • validateFully

      public ValidationReport validateFully()
      Run the full validator pipeline against the current builder state and return the resulting ValidationReport. Public so tests and callers that want the report without throwing can introspect issues. Codes added via relaxValidation(String) are filtered out before the report is returned.
      Since:
      0.5.0 (issue #85)