# Architecture Overview

## Module Dependency Graph

Twelve runtime modules on one lockstep version. Their Maven runtime
dependencies form four layers, plus a BOM that pins the runtime artifacts.

![Module Dependency Graph — TnsAI 12 runtime modules across Foundation / Core-backed / Composed / Application + BOM meta layer](https://tnsai.dev/assets/diagrams/architecture-modules.svg)

<details>
<summary>ASCII fallback (for terminal / plain-text readers)</summary>

```
FOUNDATION
  tnsai-core            Agent · Role · Action · Events · SPI · ToolMethodRegistry
                        (no inter-module dependencies)
       │
       ▼
CORE-BACKED — depend on tnsai-core and no other runtime module
  tnsai-llm             LLMClient impls for 31 providers · prompt caching
  tnsai-coordination    Group topologies · council · voting
  tnsai-mcp             Model Context Protocol client + server
  tnsai-channels        Telegram · CLI · Email · Slack · Discord · WhatsApp
                        adapters via adapter SPI
  tnsai-payments        x402 payments · wallet SPI · liability records
  tnsai-integration     SCOPBridge + framework adapters
       │
       ▼
COMPOSED — add one runtime module dependency beyond core
  tnsai-intelligence    → core, coordination (runtime scope)
                          RAG · planning · reasoning · context
  tnsai-quality         → core, llm
                          Observability · security enforcement
  tnsai-evaluation      → core, quality
                          Benchmarks · quality gates · evaluators
  tnsai-tools           → core, quality
                          63 POJO toolkits · 209 @Tool methods · 29 categories
       │
       ▼
APPLICATION
  tnsai-server          → core, llm, coordination (runtime scope), quality
                          WebSocket backend · RAG service · tool execution

META
  tnsai-bom             Bill of Materials — pins all 12 runtime modules
                        to one version
```

</details>

## Core Concepts

### Agent Lifecycle

![Agent lifecycle: a user message flows through agent.chat into Memory, System Prompt, and LLM call. The LLM response branches into either a text reply (returned to the user) or a tool call routed to ActionExecutor. ActionExecutor dispatches one of four ActionType handlers (LOCAL, WEB_SERVICE, LLM, MCP_TOOL), and the tool result loops back to the LLM for multi-turn execution.](https://tnsai.dev/assets/diagrams/agent-lifecycle.svg)

<details>
<summary>ASCII fallback (for terminal / plain-text readers)</summary>

```
User Message
    │
    ▼
agent.chat(message)
    │
    ├──  Memory         append to conversation history
    ├──  System Prompt  identity + roles + invariants + state
    └──  LLM call       request with tool definitions
                                │
                                ▼
                        LLM Response
                                │
                ┌───────────────┴───────────────┐
                │                               │
                ▼                               ▼
            Text reply                      Tool Call
                │                               │
                │                               ▼
                │                         ActionExecutor
                │                               │
                │                               │   ActionType:
                │                               ├──  LOCAL        Java method on Role
                │                               ├──  WEB_SERVICE  HTTP / REST endpoint
                │                               ├──  LLM          LLM dispatch via ToolMethodDispatcher
                │                               └──  MCP_TOOL     Model Context Protocol tool
                │                               │
                │                               ▼
                │                         Tool Result
                │                               │
                │                               ▼
                │                     back to LLM (multi-turn loop)
                │
                ▼
          return to user
```

</details>

### Action Routing

Actions are discovered from Roles via `@ActionSpec` annotations. The `ActionExecutor` routes each action to the correct executor based on `ActionType`:

| Type | Source | Example |
|------|--------|---------|
| `LOCAL` | Java method on Role | `@ActionSpec(type = ActionType.LOCAL) String greet(String name)` |
| `WEB_SERVICE` | HTTP / REST endpoint | `@ActionSpec(type = ActionType.WEB_SERVICE) + @WebService(...)` |
| `LLM` | LLM dispatch using the agent's `ToolMethodDispatcher` | `@ActionSpec(type = ActionType.LLM)` + agent-level `.builtInTools(...)` / `.toolPojos(...)` |
| `MCP_TOOL` | Model Context Protocol server tool | `@ActionSpec(type = ActionType.MCP_TOOL) + @MCPTool(serverUrl = "...")` |

Which of `@ActionSpec`, `@Tool`, and `BuiltInTool` to reach for is a
separate decision — see [Actions vs Tools](../capabilities/tools/actions-vs-tools.md).

### Extension Points (SPI)

TnsAI uses Java's `ServiceLoader` pattern for modular extensibility.
TnsAI 0.14.0 (`TnsAI@b021c635`, TAN-2903) caches most provider
lookups through `com.tnsai.spi.SpiLoader` — see
[SPI Reference](../reference/spi.md). Maven Central `0.14.1` uses
that cached loader; `0.13.0` called `ServiceLoader.load()` on every lookup.

| SPI Interface | Module | Purpose |
|---------------|--------|---------|
| `LLMClientProvider` | Core | Register LLM providers |
| `CheckpointerProvider` | Core | State persistence |
| `PlannerHandle.Factory` | Intelligence | Planning algorithms |
| `ReasoningStrategyHandle.Factory` | Intelligence | Reasoning patterns |
| `ContextManagerHandle.Factory` | Intelligence | Decision tracing |
| `EvalHandle.Factory` | Quality | Evaluation hooks |
| `SecurityEnforcerHandle.Factory` | Quality | Security policies |

Register implementations in `META-INF/services/<interface-name>`.

### Agent Internal Architecture

The `Agent` facade composes a small set of focused collaborators — each
owns one slice of behavior, so extending or replacing one piece doesn't
ripple through the whole class. If you're subclassing `Agent` or
swapping out one of these collaborators via SPI, this is the map.

![Agent internal architecture: the Agent facade composes focused collaborators — AgentOrchestrator (chat loop, tool-call routing, KB integration), AgentStreamingSupport (streaming chat + ChatChunk events), AgentCapabilities (planning, reasoning, eval, feedback, environment, variant, resilience), AgentCognitiveSupport, AgentHierarchyManager (parent/child relationships), AgentMessagingHandler (inter-agent messaging via communication SPI), AgentGroupManager (group membership).](https://tnsai.dev/assets/diagrams/agent-internal.svg)

<details>
<summary>ASCII fallback (for terminal / plain-text readers)</summary>

```
Agent                       identity · lifecycle · template methods · facade
   │
   ├── AgentOrchestrator    chat · streaming hooks · tool-call loop · KB
   │
   ├── AgentCapabilities    planning · reasoning · eval · feedback ·
   │                        environment · variant · resilience
   │
   ├── AgentCognitiveSupport
   │                        internal cognitive support (public for visibility)
   │
   ├── AgentHierarchyManager
   │                        parent / child relationships
   │
   ├── AgentStreamingSupport
   │                        streaming chat + ChatChunk events
   │
   ├── AgentMessagingHandler
   │                        inter-agent messaging via communication SPI
   │
   └── AgentGroupManager    group membership
```

</details>

## Design Principles

1. **Annotation-first** — `@ActionSpec` and `@AgentSpec` over programmatic config; channels are `ChannelAdapter` implementations
2. **SPI for extensibility** — modules register via `META-INF/services/`
3. **Composition over inheritance** — Agent delegates to focused managers
4. **Immutability** — records for data, `List.of()`, `Map.of()`
5. **Thread safety** — `ConcurrentHashMap`, `CopyOnWriteArrayList`, virtual threads
