# Variants

A variant names a quality, speed and cost tier: `HIGH`, `MEDIUM`, `MINI` or `AUTO`. An agent stores a variant and can suggest one for a task. Not implemented: nothing in the framework reads the variant, so it does not change the model, tokens, tools or timeout of a call. Use it as advice when you choose a client yourself.

## `AgentVariant`

`com.tnsai.enums.AgentVariant` has four values.

| Variant | Quality | Speed | Cost |
|---|---|---|---|
| `HIGH` | `MAX` | `SLOW` | `HIGH` |
| `MEDIUM` | `BALANCED` | `NORMAL` | `MEDIUM` |
| `MINI` | `BASIC` | `FAST` | `LOW` |
| `AUTO` | `ADAPTIVE` | `ADAPTIVE` | `OPTIMAL` |

`isQualityFocused()` is true for `HIGH` and `MEDIUM`, `isSpeedFocused()` for `MINI`, and `isCostOptimized()` for `MINI` and `AUTO`.

`AgentVariant.forTask(description)` matches keywords. It returns `HIGH` when the text contains `refactor`, `architect`, `complex`, `critical`, `security` or `review`; otherwise `MINI` for `typo`, `fix`, `simple`, `quick`, `minor` or `small`; otherwise `MEDIUM`. A blank description gives `MEDIUM`.

## On an agent

| Method | Does |
|---|---|
| `setVariant(AgentVariant)` | Stores the variant and logs the change |
| `getVariant()` | Returns it |
| `setVariantSelector(VariantSelector)` | Stores a selector for `AUTO` |
| `resolveVariant(task)` | Returns the stored variant. For `AUTO`, returns the selector's choice, or `AgentVariant.forTask(task)` without a selector. |

<!-- java-contract: src/main/java/com/example/tnsai/docs/VariantsAgentExample.java -->
```java
package com.example.tnsai.docs;

import com.tnsai.accountability.AuthorityScope;
import com.tnsai.accountability.LiabilitySink;
import com.tnsai.agents.Agent;
import com.tnsai.agents.AgentBuilder;
import com.tnsai.agents.variant.VariantSpec;
import com.tnsai.enums.AgentVariant;
import com.tnsai.identity.AgentPrincipal;
import com.tnsai.llm.providers.OpenAIClient;
import com.tnsai.roles.Role;

import java.util.Set;

public final class VariantsAgentExample {
    private VariantsAgentExample() {}

    public static Agent build(Role myRole, AgentPrincipal principal,
                              LiabilitySink sink, AuthorityScope scope) {
        Agent agent = AgentBuilder.create()
            .llm(new OpenAIClient("gpt-4o"))
            .role(myRole)
            .principal(principal)
            .liabilitySink(sink)
            .authorityScope(scope)
            .build();
        agent.setVariant(AgentVariant.AUTO);
        return agent;
    }

    // The variant is advice. Read it and choose the model yourself.
    static String modelFor(Agent agent, String task, Set<String> availableModels) {
        AgentVariant variant = agent.resolveVariant(task);
        return VariantSpec.forVariant(variant).getEffectiveModel(availableModels);
    }
}
```

## `VariantSpec`

`com.tnsai.agents.variant.VariantSpec` holds settings for a tier. `VariantSpec.forVariant(variant)` returns a built-in spec; `AUTO` gets the `MEDIUM` spec.

| | `HIGH` | `MEDIUM` | `MINI` |
|---|---|---|---|
| Preferred model | `claude-opus-4` | `claude-sonnet-4` | `claude-haiku-3` |
| Fallback models | `gpt-4`, `gemini-1.5-pro` | `gpt-4o`, `gemini-1.5-flash` | `gpt-4o-mini`, `gemini-1.5-flash-8b` |
| Max input tokens | 128,000 | 64,000 | 32,000 |
| Max output tokens | 16,384 | 8,192 | 4,096 |
| Tool set | `ALL` | `STANDARD` | `MINIMAL` |
| Timeout | 10 min | 5 min | 2 min |
| Max retries | 3 | 2 | 1 |
| Temperature | 0.7 | 0.5 | 0.3 |
| Streaming | Yes | Yes | No |

`getEffectiveModel(available)` returns the preferred model if it is in the set, else the first fallback in the set, else the preferred model. `VariantSpec.builder()` makes a custom spec, and `withVariant` and `withModel` return changed copies.

`VariantSpec.ToolSet` has `ALL`, `STANDARD`, `MINIMAL` and `NONE`. These are labels; no tool filtering uses them.

## `VariantManager`

`com.tnsai.agents.variant.VariantManager` is a standalone helper. It holds a current variant and a spec per tier, suggests a variant from a complexity score in auto mode, notifies change listeners and records task statistics. It is not connected to any agent.

## `@Variant`

`@Variant(value, reason, recordStats, fallback)` on an action method is read into the action's metadata. Not implemented: no code reads it, so the action runs with the same client as any other.

## Related

- [Create an agent](create.md): the builder and its required settings.
- [Resilience](resilience.md): retries and timeouts that do apply.
