Instructions to use mstrasser/jeff-adapter-emotion with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use mstrasser/jeff-adapter-emotion with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Configuration Parsing Warning:In adapter_config.json: "peft.task_type" must be a string
jeff-adapter-emotion
Emotion in short comments. Picks the strongest of 27 emotions, or neutral, in a short comment or message.
A LoRA adapter for jeff-base v1.3, a small open decision model
(a fine-tune of Qwen3.5-0.8B). You send a situation (the state) and questions with named options; Jeff returns a
calibrated probability for every option from one forward pass, with no generated text to parse. One Jeff server loads
the base once and any number of adapters beside it; each request picks an adapter by name ("model": "emotion").
Adapter page, with the full data card: jeffhub.ai/adapters/emotion.
Results
On this adapter's held-out test set, never trained on, scored three ways on the same rows: the untrained model Jeff is built from, the Jeff v1.3 base alone, and the base with this adapter. Every question has 28 options. As of 2026-10-05. All adapters
| Test set | Test rows | Qwen3.5-0.8B untrained | Jeff base v1.3 alone | Jeff base v1.3 + adapter |
|---|---|---|---|---|
test |
5,408 | 12.6% · 0.045 | 25.3% · 0.080 | 60.5% · 0.018 |
Each cell: accuracy · calibration error (ECE; lower is better, 0 is perfect).
With llama.cpp (GGUF)
The same test, through llama.cpp: the base GGUF (mstrasser/jeff-base-gguf) plus this adapter's LoRA GGUF (mstrasser/jeff-adapter-emotion-gguf), with the temperature refitted for each format. Running Jeff with llama.cpp
| Test set | Full precision | Q8_0 | Q4_K_M |
|---|---|---|---|
test |
60.5% · 0.018 | 60.1% · 0.012 | 60.2% · 0.017 |
Not measured yet for v1.3: calibration charts, the commonest confusions and accuracy per answer.
Source of these numbers: results/sources/v1.3/retrained-adapters.table.json in the JeffHub repository, also collected in jeffhub-v1.3.json.
When to use it
- You want a finer reading of feeling than positive or negative, for example gratitude, confusion or disappointment.
- Your texts are short, informal English comments or messages.
- You are happy to read the result as a spread of probabilities. Many comments carry more than one emotion.
When not to use it
- Your texts are long, formal or not in English. All training text is English Reddit comments.
- You need a clinical or safety judgement, such as risk of self-harm. The adapter only names emotions.
- You need every emotion in a text listed separately. The question asks for the one expressed most.
How to use it
The adapter runs with Jeff's server, on the main branch of firelex/jeff, on the
jeff-base v1.3 base.
git clone https://github.com/firelex/jeff && cd jeff
uv sync --no-default-groups --extra lora # add --extra cuda on NVIDIA GPUs, --extra mac on Apple silicon
uv run --no-default-groups hf download mstrasser/jeff-base --revision v1.3 --local-dir checkpoints/jeff-base
uv run --no-default-groups hf download mstrasser/jeff-adapter-emotion --revision v1.3 --local-dir adapters/emotion
JEFF_CHECKPOINT=checkpoints/jeff-base JEFF_ADAPTERS=adapters/ PORT=8765 \
uv run --no-default-groups jeff-serve # on a Mac, add JEFF_BACKEND=mlx
Every folder in adapters/ is served under its folder name; add or replace adapters while the server runs with
curl -X POST http://localhost:8765/v1/adapters/reload. Each adapter records the exact base it was trained on, and
the server refuses an adapter trained on a different one, so this adapter loads only on jeff-base v1.3 (a v1.2 adapter
does not load on v1.3). For llama.cpp, use mstrasser/jeff-adapter-emotion-gguf.
Request format
State (the situation), in this order:
| Key | Changes per request | What it holds |
|---|---|---|
source |
no | One short phrase on where the text comes from. In training this was always "Reddit comment ([NAME] and [RELIGION] replace removed names)". |
comment |
yes | The comment or message to read. |
Questions:
emotion(choice): Which emotion the comment expresses most strongly, or neutral if it expresses no particular emotion. Options: 28 options: 27 emotions and neutral, keyed by their GoEmotions names (admiration, amusement, anger and so on), each with a one-line description. The full list is GOEMOTIONS in descriptions.py in the source.
Rules:
- Use the option keys and descriptions from descriptions.py; the adapter was trained on them.
- Comments with several gold emotions were trained with the probability spread evenly over them, so a split answer is expected, not a fault.
- Use the instructions below word for word; the adapter was trained mostly on them.
General rules for every request: the request format guide.
Example
The request below is also in this repository as example.json.
{
"model": "emotion",
"state": {
"source": "Reddit comment ([NAME] and [RELIGION] replace removed names)",
"comment": "Thanks so much for the tip, I had no idea the library lent out tools. Saved me a fortune."
},
"questions": {
"emotion": {
"type": "choice",
"instructions": "Which emotion does the comment express most? Choose the emotion that is strongest in the comment, or neutral if it expresses no particular emotion.",
"criteria": {
"gratitude": "Gratitude: feeling thankful or appreciative.",
"joy": "Joy: a feeling of pleasure and happiness.",
"surprise": "Surprise: being astonished or startled by something unexpected.",
"realization": "Realization: becoming aware of something.",
"admiration": "Admiration: finding something impressive or worthy of respect.",
"relief": "Relief: reassurance and relaxation after anxiety or distress ends.",
"annoyance": "Annoyance: mild anger or irritation.",
"confusion": "Confusion: lack of understanding or uncertainty.",
"sadness": "Sadness: feeling sorrow or unhappiness.",
"neutral": "Neutral: no particular emotion is expressed."
}
}
}
}
curl -s localhost:8765/v1/systemone -H 'content-type: application/json' -d @adapters/emotion/example.json
The answer holds a probability for each option of each question. A recorded response from the v1.3 adapter is not published yet.
Files
adapter_model.safetensors,adapter_config.json: the LoRA weights (PEFT format);readout.safetensors: the adapter's own readout over the answer codes;decision_config.json: answer codes, temperature, prompt layout and the checksum of the base it was trained on;test.jsonl: the held-out test set the results below were measured on;calibration.jsonl: the calibration rows the adapter's temperature was fitted on;example.json: the example request above.
adapter_config.json and decision_config.json name the base as mstrasser/jeff-base, revision v1.3; the server
checks the base by the checksum of its weights.
Training
| Base | mstrasser/jeff-base, revision v1.3 (a fine-tune of Qwen3.5-0.8B) |
| Prompt layout | live-last: the fixed part of the request first, the changing state field last |
| Training code | The git_commit recorded in decision_config.json is the training machine's copy and was not published. It builds exactly the same prompt as main of firelex/jeff (from commit 6d0d7da) for a text state and for an object with at least one field; the format is in docs/v1.3-request-format.md |
| Run | 0.8b-emotion-20261003-0149, final checkpoint |
| Adapter files | 41.5 MB (adapter_model.safetensors and readout.safetensors) |
| LoRA GGUF for llama.cpp | mstrasser/jeff-adapter-emotion-gguf |
- 1.3.0 (2026-10-03): Trained on Jeff v1.3 with the live-last prompt layout (LoRA rank 16, one epoch, about 10% of the base model's own training data mixed in).
Data card
Report attached. The shortcut report and data card are included and pass the JeffHub checks; the numbers are the maintainers’ own. What the levels mean
- Test set: included in this repository as
test.jsonl, so anyone can check the numbers - Calibration rows: included in this repository as
calibration.jsonl, the rows its threshold is chosen on - QA report, sanitised: the data-quality checks run before training
How the test set was held out. The official GoEmotions test split (simplified configuration); never trained on.
Training data. Built from public data sets, listed under Data and licence.
The source data sets are public (listed under Data and licence). A script to rebuild our rows from them will follow.
Training mixed in a replay sample of the Jeff base model's own training data: 4,607 rows, about 10% on top of the adapter's 46,067 (inherited from the v1.2 recipe as a precaution; its effect has not been measured).
Data and licence
Adapter licence: Apache-2.0.
Qwen3.5-0.8B notice: these weights were modified from Qwen3.5-0.8B by the Jeff project: jeff-base is a fine-tune of Qwen3.5-0.8B, and this adapter was trained on top of it. Qwen3.5-0.8B is Copyright 2026 Alibaba Cloud and licensed under the Apache License, Version 2.0; a copy of that licence is in LICENSE.
It was trained on:
GoEmotions, simplified configuration. Licence: Apache-2.0 (open licence)
English Reddit comments with names removed. Option descriptions were written by hand from the label names.
Limitations
- Tied to jeff-base v1.3. It will not load on any other base or version; the server checks the base weights' checksum.
- Jeff chooses between the options you give it. It does not write text or reason in several steps.
- Calibration was fitted on this adapter's own calibration rows. On very different data, check it again.
- Everything listed under When not to use it above.
Links
- Adapter page: jeffhub.ai/adapters/emotion
- Base model: mstrasser/jeff-base (revision v1.3)
- LoRA GGUF for llama.cpp: mstrasser/jeff-adapter-emotion-gguf
- What changed in v1.3: release notes
- Code and server: github.com/firelex/jeff
Jeff is an independent project. It uses the same request format as Jev but is not affiliated with or endorsed by TypeSafe, the makers of Jev.
- Downloads last month
- 19