# Advanced Intelligence Patterns

Advanced cognitive capabilities in TnsAI.Intelligence for reasoning, memory consolidation, output validation, and iterative refinement.

## Reasoning Strategies

TnsAI.Intelligence provides three advanced reasoning executors that go beyond simple prompt-response patterns. Each implements a different strategy for exploring solution spaces.

### ReActExecutor

The `ReActExecutor` implements the ReAct (Reason + Act + Observe) pattern where an LLM explicitly reasons about what to do, takes an action, observes the result, and repeats until the goal is achieved. This produces structured Thought/Action/Observation traces for interpretability and decision auditing.

Based on "ReAct: Synergizing Reasoning and Acting in Language Models" (Yao et al., 2022).

```java
ReActExecutor react = ReActExecutor.builder()
    .llm(client)
    .actionHandler((name, input) -> {
        if ("search".equals(name)) return Optional.of(searchService.search(input));
        if ("calculate".equals(name)) return Optional.of(calculator.eval(input));
        return Optional.empty();
    })
    .maxSteps(10)
    .thoughtFormat(ThoughtFormat.STRUCTURED)
    .stopCondition(StopCondition.finalAnswerDetected())
    .availableActions("search, calculate")
    .timeout(Duration.ofMinutes(5))
    .build();

ReActResult result = react.execute("Find the population of Tokyo and compare it to NYC");

System.out.println("Answer: " + result.getFinalAnswer());
System.out.println("Status: " + result.getStatus());    // SUCCESS, TIMEOUT, ERROR, MAX_STEPS_REACHED, STOPPED
System.out.println("Steps: " + result.getSteps().size());
System.out.println("LLM calls: " + result.getTotalLLMCalls());
System.out.println("Duration: " + result.getDuration());

// Inspect individual reasoning steps
for (ReActStep step : result.getSteps()) {
    System.out.println("Step " + step.getStepNumber());
    System.out.println("  Thought: " + step.getThought());
    System.out.println("  Action: " + step.getAction());
    System.out.println("  Observation: " + step.getObservation());
}
```

**ThoughtFormat options**: `STRUCTURED` (formal Thought/Action/Observation format) or `FREE_FORM` (open-ended reasoning). The `ActionHandler` is a `@FunctionalInterface` that takes an action name and input, returning `Optional<String>` (empty means action not available).

**ReActStatus values**: `SUCCESS`, `TIMEOUT`, `ERROR`, `MAX_STEPS_REACHED`, `STOPPED`.

### TreeOfThoughtsExecutor

The `TreeOfThoughtsExecutor` explores multiple reasoning paths by generating candidate thoughts at each step, evaluating them for promise, pruning low-quality branches, and continuing on promising paths.

Based on "Tree of Thoughts: Deliberate Problem Solving with Large Language Models" (Yao et al., 2023).

```java
TreeOfThoughtsExecutor tot = TreeOfThoughtsExecutor.builder()
    .llm(client)
    .evaluator(BranchEvaluator.llm(evalClient))
    .pruning(PruningStrategy.BEAM_SEARCH)
    .beamWidth(3)
    .maxDepth(5)
    .branchingFactor(3)
    .pruneThreshold(0.3)
    .timeout(Duration.ofMinutes(10))
    .build();

ToTResult result = tot.explore("Design a REST API for a todo app");

System.out.println("Best path: " + result.getBestPath());
System.out.println("Total nodes: " + result.getTotalNodes());
System.out.println("Pruned: " + result.getPrunedNodes());
System.out.println("Max depth reached: " + result.getMaxDepthReached());
```

**PruningStrategy options**:

| Strategy | Behavior |
|---|---|
| `BEAM_SEARCH` | Keep top-K nodes by score at each level (default) |
| `BEST_FIRST` | Sort by cumulative score, keep top-K |
| `GREEDY` | Keep only the single best node |
| `DEPTH_LIMITED` | No score-based pruning, only depth limit |
| `EXHAUSTIVE` | No pruning at all |

### GraphOfThoughtsExecutor

The `GraphOfThoughtsExecutor` extends Tree of Thoughts by allowing cycles and merging of thought branches. Better for problems where partial solutions can be combined.

Based on "Graph of Thoughts" (Besta et al., 2023).

```java
GraphOfThoughtsExecutor got = GraphOfThoughtsExecutor.builder()
    .llm(client)
    .evaluator(BranchEvaluator.llm(client))
    .operations(List.of(GoTOperation.GENERATE, GoTOperation.AGGREGATE, GoTOperation.REFINE))
    .maxNodes(20)
    .branchingFactor(3)
    .timeout(Duration.ofMinutes(10))
    .build();

GoTResult result = got.explore("Design a database schema for e-commerce");

System.out.println("Best thought: " + result.getBestThought());
System.out.println("Aggregated insight: " + result.aggregatedInsight());
System.out.println("Total nodes: " + result.totalNodes());
System.out.println("Merges performed: " + result.mergeCount());
System.out.println("Duration: " + result.duration());
```

**GoTOperation types**: `GENERATE` (create child thoughts), `AGGREGATE` (merge top-scoring nodes into a unified solution), `REFINE` (improve existing thoughts), `SCORE` (evaluate nodes).

The executor uses a frontier-based exploration: each iteration generates children, refines promising nodes (score > 0.3), and aggregates top nodes from different branches. The frontier is pruned to the top `branchingFactor` nodes each round.

> **Cross-reference**: For basic reasoning configuration, see [Reasoning](reasoning.md).

## Atom of Thought (AoT)

The `AotProcessor` implements the Atom of Thought reasoning technique that decomposes complex problems into independent "atoms" solved in parallel. Unlike Chain-of-Thought where errors in early steps propagate, AoT isolates atoms so one bad result does not ruin the answer.

Based on "Atom of Thoughts for Markov LLM Test-Time Scaling" (arXiv, Feb 2025).

### Benefits and Trade-offs

- +30-40% accuracy improvement on complex reasoning tasks
- Error isolation between atoms
- Parallel execution of independent atoms
- Per-atom confidence tracking
- Trade-off: +20-30% token usage due to multiple LLM calls

### Usage

```java
// Simple usage
AotProcessor aot = new AotProcessor(llmClient);
AotResult result = aot.process("Calculate compound interest for $1000 at 5% for 3 years");

System.out.println("Answer: " + result.getAnswer());
System.out.println("Confidence: " + result.getConfidence() + "%");

// With configuration
AotProcessor aot = AotProcessor.builder()
    .llmClient(llmClient)
    .maxAtoms(8)
    .parallelExecution(true)
    .minConfidence(40f)
    .complexityThreshold(50)
    .synthesisStrategy(AtomSynthesizer.SynthesisStrategy.WEIGHTED_COMBINATION)
    .build();

AotResult result = aot.process(complexQuestion);
System.out.println(result.getDetailedTrace());

// Force AoT even for simple questions
AotResult forced = aot.processForced("What is 2+2?");

// Check question complexity before processing
int score = aot.getComplexityScore("Compare Python and Java for web development");
```

### How It Works

1. **Complexity check**: The processor scores the question for complexity (multi-step indicators, calculation keywords, comparison keywords). Below the threshold, it processes as a single atom.
2. **AtomGenerator**: Decomposes the problem into atoms. Tries heuristic patterns first (calculation, comparison, list), then falls back to LLM-based decomposition. Each atom has an `id`, `description`, `prompt`, `type` (REASONING, RETRIEVAL, COMPUTATION, VALIDATION, SYNTHESIS), `dependencies`, and `priority`.
3. **AtomSolver**: Solves atoms in parallel with dependency resolution. Groups atoms by level (independent atoms first, then dependent ones). Includes dependency context in prompts and extracts confidence scores from LLM responses.
4. **AtomSynthesizer**: Combines atom solutions into a final answer using the configured synthesis strategy, weighting by confidence.

Call `aot.shutdown()` to release the executor thread pool when done.

## Memory Consolidation

The `MemoryConsolidationPipeline` automates the transition from short-term conversation memory to long-term knowledge storage.

### Pipeline Steps

1. Extract knowledge from the session (via `KnowledgeExtractor`)
2. Filter by confidence threshold
3. Apply forgetting curve to older knowledge
4. Store high-value knowledge (via `KnowledgeStore`)
5. Compact conversation context if compactor provided

```java
MemoryConsolidationPipeline pipeline = MemoryConsolidationPipeline.builder()
    .knowledgeExtractor(extractor)
    .contextCompactor(compactor)
    .knowledgeStore(store)
    .forgettingCurve(ForgettingCurve.EXPONENTIAL)
    .compactionConfig(compactionConfig)
    .minKnowledgeConfidence(0.5)
    .build();

ConsolidationResult result = pipeline.consolidate(session);
System.out.println("Extracted: " + result.knowledgeCount() + " knowledge items");
System.out.println("Original turns: " + result.originalCount());
System.out.println("Consolidated turns: " + result.consolidatedCount());
System.out.println("Summary: " + result.summary());
System.out.println("Duration: " + result.duration());
```

### ForgettingCurve

Controls how memory importance decays over time when not accessed. Knowledge that decays below 0.1 is automatically deleted from the store.

| Curve | Formula | Behavior |
|---|---|---|
| `NONE` | No decay | All memories retain full importance forever |
| `LINEAR` | `score * max(0, 1 - days * 0.01)` | Gradual linear decline, reaches zero after ~100 days |
| `EXPONENTIAL` | `score * e^(-0.05 * days)` | Ebbinghaus-inspired rapid initial decay that slows over time |

```java
double decayed = ForgettingCurve.EXPONENTIAL.decay(0.9, Duration.ofDays(7));
```

> **Cross-reference**: For context management fundamentals, see [Context](context.md).

## Context Compaction

The `ContextCompactor` interface provides strategies for reducing conversation context size when approaching the token limit.

### ContextCompactor Interface

```java
public interface ContextCompactor {
    CompactionResult compact(List<Map<String, Object>> messages, CompactionConfig config);
    boolean shouldCompact(int currentTokens, int maxTokens, CompactionConfig config);
    int estimateTokens(List<Map<String, Object>> messages);
}
```

### TwoPhaseCompactor

Combines truncation and LLM summarization in two phases for optimal context reduction.

- **Phase 1** (`TruncatingCompactor`): Truncates large tool-call arguments and tool-result content in older messages. Fast, requires no LLM call.
- **Phase 2** (`LLMContextCompactor`): Summarizes older messages using an LLM. Only runs if phase 1 alone is insufficient.

```java
LLMClient summarizer = LLMClientFactory.create("openai", "gpt-4o-mini");
TwoPhaseCompactor compactor = new TwoPhaseCompactor(
    new TruncatingCompactor(200),       // max 200 chars per truncated field
    new LLMContextCompactor(summarizer)
);

CompactionConfig config = CompactionConfig.builder()
    .thresholdRatio(0.85)       // trigger compaction at 85% capacity
    .preserveLastN(5)           // keep last 5 messages intact
    .build();

if (compactor.shouldCompact(currentTokens, maxTokens, config)) {
    CompactionResult result = compactor.compact(messages, config);
    String summary = result.summary();
    int savedTokens = result.originalTokenCount() - result.compactedTokenCount();
}
```

## Structured Output Validation

The `StructuredOutputExecutor` ensures LLM outputs conform to an expected schema with automatic retry on validation failure.

```java
StructuredOutputExecutor<OrderSummary> executor = StructuredOutputExecutor.<OrderSummary>builder()
    .llm(client)
    .targetType(OrderSummary.class)
    .outputFormat(OutputFormat.JSON)
    .rules(List.of(
        ValidationRule.notNull("orderId"),
        ValidationRule.range("total", 0, 100000),
        ValidationRule.pattern("email", "^[\\w.-]+@[\\w.-]+$")
    ))
    .maxRetries(3)
    .systemPrompt("You are an order processing assistant.")
    .build();

StructuredOutputExecutor.StructuredOutputResult<OrderSummary> result =
    executor.generate("Summarize this order: ...");

if (result.success()) {
    OrderSummary order = result.value();
    System.out.println("Parsed in " + result.attempts() + " attempts");
} else {
    System.out.println("Failed after " + result.attempts() + " attempts");
    System.out.println("Errors: " + result.errors());
}
```

### ValidationRule

Built-in validation rules for common checks:

| Factory Method | Behavior |
|---|---|
| `ValidationRule.notNull(fieldName)` | Field must exist and be non-null |
| `ValidationRule.range(fieldName, min, max)` | Numeric field must be within range |
| `ValidationRule.pattern(fieldName, regex)` | String field must match regex |
| `ValidationRule.custom(description, predicate)` | Custom predicate on the entire data map |

On validation failure, the executor sends a correction prompt containing the specific errors and re-requests a valid response, up to `maxRetries` times.

## NormEngine

The `NormEngine` evaluates and enforces behavioral norms (obligations, prohibitions, permissions) on agent actions at runtime. Norms can be defined via `@Norm` annotations on role classes or programmatically.

### Annotation-Based Norms

```java
@Norms({
    @Norm(type = NormType.OBLIGATION, action = "logActivity",
          description = "Must log all activities", priority = 10),
    @Norm(type = NormType.PROHIBITION, action = "shareData",
          condition = "isConfidential",
          description = "Must not share confidential data", priority = 20),
    @Norm(type = NormType.PERMISSION, action = "readPublicData",
          description = "May read public data")
})
public class AnalystRole { }

NormEngine engine = NormEngine.fromAnnotations(AnalystRole.class);
```

### Programmatic Norms

```java
NormEngine engine = NormEngine.of(
    new NormEntry(NormType.PROHIBITION, "isConfidential", "shareData",
                  "Must not share confidential data", 20),
    new NormEntry(NormType.OBLIGATION, "", "logActivity",
                  "Must log all activities", 10)
);

// Add norms dynamically at runtime
engine.addNorm(new NormEntry(NormType.PERMISSION, "", "readData", "May read data", 5));
```

### Checking Actions

```java
// Check if an action is permitted (evaluates prohibitions)
NormEngine.CheckResult result = engine.checkAction("shareData",
    condition -> condition.equals("isConfidential") && context.isConfidential());

if (result.isViolation()) {
    for (NormViolation v : result.violations()) {
        System.out.println("Violated: " + v.norm().description());
    }
}

// Check for unfulfilled obligations
NormEngine.CheckResult obligations = engine.checkObligations(
    Set.of("readData"),       // actions already performed
    condition -> true          // condition evaluator
);

// Query active norms for current context
List<NormEntry> activeObligations = engine.getActiveObligations(cond -> true);
List<NormEntry> activeProhibitions = engine.getActiveProhibitions(cond -> true);
List<NormEntry> activePermissions = engine.getActivePermissions(cond -> true);
List<NormEntry> allNorms = engine.getAllNorms();
```

### NormEntry Record

Fields: `type()` (NormType), `condition()`, `action()`, `description()`, `priority()`. The `hasCondition()` method returns true if the norm has a non-blank condition expression.

## RefinementLoop

The `RefinementLoop` iteratively refines LLM outputs until they meet predefined quality standards. Inspired by Claude's Ralph plugin, it repeatedly evaluates output against completion criteria and re-prompts for corrections.

```java
RefinementLoop loop = RefinementLoop.builder()
    .task("Convert Python to TypeScript")
    .completionCriteria(CompletionCriteria.builder()
        .compilerCheck("tsc --noEmit")
        .testCommand("npm test")
        .mustNotContain("def ", "import ")
        .mustContain("interface", "type")
        .customCheck("no-any", code -> !code.contains(": any"))
        .build())
    .maxIterations(10)
    .timeout(Duration.ofMinutes(30))
    .stopHook(StopHook.onAllTestsPass())
    .onIteration(iter -> log.info("Iteration {} score: {}",
        iter.iterationNumber(), iter.evaluation().overallScore()))
    .build();

RefinementResult result = loop.execute(agent, pythonCode);    // or loop.execute(llmClient, input)

System.out.println("Final output: " + result.getFinalOutput());
System.out.println("Iterations: " + result.getIterationCount());
System.out.println("Status: " + result.getStatus());         // SUCCESS, TIMEOUT, MAX_ITERATIONS, STOPPED, ERROR
System.out.println("Duration: " + result.getDuration());
System.out.println("Metrics: " + result.getMetrics());       // totalIterations, totalDurationMs, totalTokens, scoreProgression, finalScore
```

### CompletionCriteria

Defines when the refinement loop should stop. Combines multiple check types:

```java
CompletionCriteria criteria = CompletionCriteria.builder()
    .withLLM(llmClient)                        // required for llmCheck
    .compilerCheck("tsc --noEmit")             // shell command (exit 0 = pass)
    .testCommand("npm test")                   // shell command
    .lintCheck("eslint .")                     // shell command
    .mustContain("interface", "type")          // required content
    .mustNotContain("def ", "import ")         // forbidden content
    .matchesPattern("export default .*")       // regex match
    .wordCount(50, 5000)                       // word count range
    .minLines(10)                              // minimum line count
    .validJson()                               // valid JSON check
    .customCheck("no-any", code -> !code.contains(": any"))
    .llmCheck("Is this idiomatic TypeScript?", 0.8)  // LLM-based quality check
    .build();

EvaluationResult eval = criteria.evaluate(output);
boolean done = eval.allCriteriaMet();
double score = eval.overallScore();          // 0.0 - 1.0
List<CheckResult> passed = eval.passed();
List<CheckResult> failed = eval.failed();
List<String> reasons = eval.getFailureReasons();
```

### RefinementStatus

Possible terminal states: `SUCCESS` (all criteria met), `TIMEOUT`, `MAX_ITERATIONS`, `STOPPED` (stop hook triggered), `ERROR`.

The refinement prompt includes failed checks as issues to fix and passed checks as elements to preserve, guiding the LLM toward incremental improvement.
