# Swarm Intelligence System

This project provides a local web harness for:

- creating agents and assigning them to swarms,
- evaluating agents with a local GGUF model via `llama.cpp`,
- recording fitness history and promotion-gate decisions,
- validating/attaching adapters per agent,
- launching adapter training jobs.

The app runs from `training.py` and is controlled by `launch.sh`.

# Swarm Evaluation Logic
## Promotion Gate & Swarm-Health Score (U_SIS)

The Swarm Intelligence System evaluates agents using two complementary mechanisms:

1. **A strict, auditable Promotion Gate**
2. **A holistic Swarm-Health Score (U_SIS)**

These serve different purposes and must remain separate.
The gate controls promotion into QLoRA fine-tuning.
U_SIS measures overall swarm health and diversity.

---

## 1. Promotion Gate (Binary)

The Promotion Gate is a hard pass/fail check that determines whether an agent is eligible for Tier-B fine-tuning.
It is intentionally simple, deterministic, and auditable.

### Gate Conditions

An agent is promoted only if:

```text
mean_fitness >= f_threshold
min_fitness  >= f_floor
```

And optionally:

```text
Phi >= Phi_threshold
```

Where:

- **mean_fitness** - average fitness over the evaluation window
- **min_fitness** - lowest fitness in the window
- **Phi** - niche-diversity score
- **Thresholds** - configured in the Gate Config panel

### Why the gate is simple

Promotion triggers expensive, irreversible QLoRA training, so the gate must be:

- predictable
- explainable
- resistant to noise
- easy to audit

This is why the gate uses only mean, min, and optionally Phi, rather than the full U_SIS equation.

---

## 2. Swarm-Health Score (U_SIS)

U_SIS is a continuous scalar score that evaluates the health, diversity, and stability of the swarm.
It does **not** control promotion.
Instead, it is used for:

- ranking agents
- pruning weak agents
- monitoring swarm diversity
- visualizing ecosystem stability
- guiding mutation and exploration strategies

### U_SIS Equation

```text
U_SIS =
  alpha * mean_fitness
+ beta * min_fitness
+ gamma * Phi
- delta * Cost
+ epsilon * Exploration
- zeta * OutputEntropy
```

Where:

- **mean_fitness** - average fitness
- **min_fitness** - minimum fitness
- **Phi** - niche diversity (entropy-normalized)
- **Cost** - latency/compute penalty
- **Exploration** - novelty in strategy space
- **OutputEntropy** - inconsistency/erratic behaviour
- **alpha, beta, gamma, delta, epsilon, zeta** - configurable weights

### Why U_SIS is richer

U_SIS incorporates multiple behavioural signals to give a holistic view of swarm health.
It is intentionally more expressive than the gate, because it is diagnostic, not decisive.

---

## 3. Phi - Niche Diversity (Entropy-Normalized)

Phi measures how evenly agents are distributed across the defined niches.

### Definition

Let `niche_counts = [n1, n2, ..., nK]`.

```text
p_k = n_k / sum(niche_counts)
H   = -Sigma (p_k * log(p_k))
Phi = H / log(K)
```

### Range

- **Phi = 1.0** -> agents evenly distributed
- **Phi = 0.0** -> swarm collapsed into one niche
- **0 < Phi < 1** -> partial diversity

### Important Edge Case

If only one niche exists (`K == 1`):

```text
Phi = 1.0
```

This distinguishes:

- "taxonomy defines only one niche" -> diversity cannot collapse
- "many niches exist but agents pile into one" -> true collapse -> Phi = 0.0

---

## 4. How the Two Equations Work Together

### Promotion Gate
- Binary
- Minimal inputs
- Controls QLoRA training
- Must remain simple and auditable

### U_SIS
- Continuous
- Multi-signal
- Used for ranking, pruning, diagnostics
- Does not trigger promotion

### They complement each other

- The **gate** protects the system from bad promotions.
- **U_SIS** helps the system understand itself.

This separation makes the SIS architecture robust, predictable, and self-improving.

---

## 5) Start The App

```bash
./launch.sh start
```

Open:

- http://0.0.0.0:5023

Useful launcher commands:

```bash
./launch.sh restart
./launch.sh stop
```

## Visit Logging

The Flask app automatically forwards successful HTML page visits to the
VisitLogs service. By default, it sends events to
`http://127.0.0.1:5020/api/visit-trigger`. Set `VISITLOG_SERVICE_URL` before
starting the app to use another service endpoint:

```bash
export VISITLOG_SERVICE_URL="https://visits.example.com/api/visit-trigger"
```

If the service requires a shared secret, set `VISIT_TRIGGER_SECRET` in the
server environment. When running behind a reverse proxy, set
`VISITLOG_TRUSTED_PROXY_COUNT` to the number of trusted proxy hops used to
select the visitor IP from `X-Forwarded-For` (default: `1`). Successful HTML GET
page responses are logged, including `304 Not Modified` responses when the
browser reuses a cached page; API responses and static files are not.

## 6) Model Setup (GGUF Local)

In the UI (`Model Endpoint Config`):

1. Set `Model source` to `gguf local`.
2. Select your GGUF model in `Model name`.
3. Click `Save Model Config`.

Recommended model quality for 32GB RAM:

- prefer `Q5_K_M`,
- fallback to `Q4_K_M` for speed.

## 7) Create An Agent

An agent is created when you first record fitness or run eval+record with an `agent_id`.

In the UI (`Record Fitness` or `LLM Eval and Record`):

1. Set `Swarm id` (for example `swarm-alpha`).
2. Set `Agent id` (for example `agent-alpha`).
3. Run either:
   - `Record + Check`, or
   - `Run LLM Eval + Record`.

After this, the agent appears in `Agent Registry`.

## 8) Create A Swarm

A swarm is represented by shared `Swarm id` across multiple agents.

To create a swarm:

1. Use the same `Swarm id` for multiple different `Agent id` values.
2. Record/eval each agent at least once.
3. Confirm all agents are listed under that same swarm in `Agent Registry`.

Example:

- `swarm-alpha` + `agent-a`
- `swarm-alpha` + `agent-b`
- `swarm-alpha` + `agent-c`

## 9) Train And Attach An Adapter (Per Agent)

### Important

For `gguf local`, adapter attach requires a llama.cpp-compatible GGUF adapter artifact (`.gguf`) at the adapter path.

The default training pipeline now runs real LoRA/QLoRA fine-tuning in-process inside `training.py` and then, for `gguf local`, converts the produced PEFT adapter to `adapter.gguf` using `convert_lora_to_gguf.py` from llama.cpp.

When your serving model is a `.gguf` file, the trainer needs a Hugging Face base model id for training. You can set this once in `Model Endpoint Config` as `Training base model` or provide `training_base_model` in the train request payload (example: `meta-llama/Llama-3.1-8B-Instruct`).

### Recommended flow

1. Select `Agent id`.
2. In `Agent Registry`, set:
   - `Adapter path` (output directory or artifact path),
   - `Adapter type` (`lora` or `qlora`).
3. Click `Train Adapter`.
4. Wait for completion status.
5. Click `Validate Adapter`.
6. Click `Attach Adapter`.

If training succeeds, adapter metadata is bound to that agent.

## 10) Verify Adapter Is Being Used

Run `Run LLM Eval + Record` for the same `Agent id`.

Check:

1. `Current Status` chip `Adapter:` should show `applied`.
2. Server log file:
   - `.training.log`
3. Structured llama adapter log:
   - `model_output/logs/llama_cpp_lora.log`

Useful log markers:

- `event=adapter_resolution`
- `event=llama_constructor_with_adapter`
- `event=gguf_inference_ok`

## 11) Data Persistence

State is persisted in:

- `model_output/agent_registry.json`

This includes:

- agent history,
- swarm mapping,
- adapter mapping.

## 12) API Shortcuts

Common endpoints:

- `GET /api/agents`
- `POST /api/record`
- `POST /api/check`
- `POST /api/eval-record`
- `POST /api/eval-record/start`
- `GET /api/eval-record/status`
- `GET /api/diversity`
- `GET /api/health`
- `GET /api/config`
- `POST /api/config`
- `POST /api/agents/<agent_id>/adapter`
- `POST /api/agents/adapter/preflight`
- `POST /api/agents/<agent_id>/train/start`
- `GET /api/agents/train/status`

## 13) Troubleshooting

### Error: adapter_path is required

- Ensure `Adapter path` is filled.
- Default expected path is `model_output/adapters/agents`.

### Error: gguf_local requires a llama.cpp-compatible GGUF adapter artifact

- No valid `.gguf` adapter exists at the configured path.
- Run `Train Adapter` first, then re-validate and attach.

### Default trainer needs a Hugging Face base model id

- This occurs when `llm_source=gguf_local` and `base_model` is a `.gguf` path/basename.
- Fix by sending `training_base_model` in `POST /api/agents/<agent_id>/train/start`.

## 14) Minimal Workflow Example

1. Start app: `./launch.sh restart`
2. Set source to `gguf local` and choose GGUF model.
3. Create agent:
   - `swarm-alpha`, `agent-alpha`, run eval.
4. Create swarm members:
   - repeat with `agent-beta`, `agent-gamma` under `swarm-alpha`.
5. Train adapter for `agent-alpha`.
6. Validate + attach adapter for `agent-alpha`.
7. Run eval again and confirm `Adapter: applied`.
