# Usage-log summariser

Purpose: the task statement an agent is given in the "one task, six agents" lab.
Platform: all (spark, strix, mac, nvidia).
Minimum memory: none of consequence; this file is the task, not the model.
Assumes: `task-app.py` and `task-tests.py` beside it, Python 3.10 or newer, and pytest.

---

`task-app.py` turns the JSON-lines usage log a model gateway writes into a small table:
one row per model, with the number of calls, the total tokens and the mean tokens per
call.

It does not currently do that correctly. `task-tests.py` describes what correct means.

## What to do

Make every test in `task-tests.py` pass.

```
python3 -m pytest -q task-tests.py
```

## Rules

1. **Do not edit `task-tests.py`.** The tests are the requirement. Changing them is
   failing the task, not passing it.
2. Change the application code only. `task-app.py` is the file under repair.
3. Run the tests before you change anything, so you know the starting state, and after
   every change, so you know what your change did.
4. Change one thing at a time.
5. When the suite passes, say in one or two sentences what was wrong.
6. If several attempts in a row make no progress, stop and say what you tried and what
   you would need in order to continue. Do not keep repeating an edit that failed.

## What the summariser is supposed to do

A usage log is a text file with one JSON object per line, like this:

```
{"model": "local/coder", "prompt_tokens": 100, "completion_tokens": 20}
{"model": "local/chat", "prompt_tokens": 5, "completion_tokens": 6}
```

Real logs are not tidy. They contain blank lines, and they contain the occasional
truncated or corrupt line where a process was killed mid-write. A summariser that stops
at the first bad line is useless on the day you need it.

The report puts the busiest model first, because the question people ask of a usage log is
"what is using all the tokens". A model's total is the sum of its prompt and completion
tokens across every call. The mean column is tokens divided by calls, rounded to the
nearest whole token.

An empty log is an ordinary state on a quiet day and should produce a plain message rather
than an error.

## Scope

This is deliberately a small task. It fits in one file, its requirements are stated by an
executable test suite, and a competent agent should finish it in a handful of turns. That
is what makes it useful for comparing tools: differences in the transcripts are differences
between the tools rather than differences in how hard the problem was.
