Loading Tasks from External Sources¶
TraceLens evaluations are built around Task objects, but your data
almost certainly already lives in a spreadsheet, a log file, or a Hugging Face dataset.
The loaders in this page let you point TraceLens at those files directly — no conversion
step required.
Overview¶
| Loader | Format | Extra required |
|---|---|---|
JSONTaskLoader |
JSON file(s) / directory | — (core) |
JSONLTaskLoader |
Newline-delimited JSON (.jsonl) |
— (stdlib) |
CSVTaskLoader |
Comma-separated values (.csv) |
— (stdlib) |
HFDatasetLoader |
Hugging Face Hub / saved Dataset |
tracelens[datasets] |
All loaders implement the same TaskLoader ABC, so
their load() and save() result contracts remain consistent:
loader = CSVTaskLoader(input_field="prompt") # or any other loader
tasks = loader.load("eval_data.csv")
eval_set = EvalSet(name="My Suite", tasks=tasks)
Using the loaders from the CLI¶
tracelens run --eval-set PATH picks the loader from the file suffix, so a
.jsonl or .csv file works exactly like a JSON eval set:
--eval-set |
Loader | Options |
|---|---|---|
tasks.json |
JSONTaskLoader |
none (native Task shape) |
tasks.jsonl |
JSONLTaskLoader |
--input-field, --metadata-fields |
tasks.csv |
CSVTaskLoader |
--input-field, --metadata-fields |
| a directory | the loader named by --eval-set-format |
as above |
# A JSONL file whose records keep the task input under "prompt"
tracelens run \
--eval-set data/evals.jsonl \
--input-field prompt \
--metadata-fields subject source \
--adapter myproject.eval.adapters.MyAgentAdapter \
--graders myproject.eval.graders.QualityGrader
# A directory of CSV files: say which format to load, TraceLens never guesses
tracelens run --eval-set data/csv-suites/ --eval-set-format csv ...
Rules that keep this predictable:
- The format comes from the suffix (
.json,.jsonl,.csv); any other suffix is an error unless--eval-set-formatnames the format. - A directory always needs
--eval-set-format; every file with that format's suffix inside it (recursively, sorted) is loaded. --input-fieldand--metadata-fieldsapply to JSONL and CSV only; a JSON eval set already uses the nativeTaskshape and rejects them.- Loading problems (missing path, invalid JSON, a malformed record, a missing input column) are usage errors: the CLI prints the file and, where the loader knows it, the line, and exits 2 before any agent is called.
- Hugging Face Hub datasets are not dispatched from the CLI; load them with
HFDatasetLoaderin Python and save to JSON or JSONL first.
Migrating from the Python API:
# before
tasks = CSVTaskLoader(input_field="prompt", metadata_fields=["subject"]).load("evals.csv")
eval_set = EvalSet(name="My Suite", tasks=tasks)
# after: the same mapping, no glue script
tracelens run --eval-set evals.csv --input-field prompt --metadata-fields subject ...
The same dispatch is available as tracelens.loaders.load_tasks(path,
format=..., input_field=..., metadata_fields=...), which raises
EvalSetLoadError with the CLI's message.
JSONLTaskLoader¶
Read one JSON object per line from a .jsonl file.
Installation¶
No extra dependencies — ships with the tracelens core package.
Basic usage¶
Each line must be a valid JSON object with at least an "input" key:
{"input": {"goal": "Write a haiku about autumn"}, "name": "Haiku task"}
{"input": {"goal": "Summarise the paper"}, "name": "Summarisation", "difficulty": "hard"}
Custom field names¶
If your file uses a different column name for the input, pass input_field:
Limit which extra keys end up in Task.metadata with metadata_fields:
tasks = JSONLTaskLoader(
input_field="prompt",
metadata_fields=["subject", "source"],
).load("benchmarks.jsonl")
metadata_fields may select only foreign keys. Native Task fields such as
difficulty and category always map to their corresponding Task attributes,
so a field never has two meanings. It filters flat foreign keys only; an embedded
canonical metadata object is already normalized and is therefore loaded intact.
Directory loading¶
Pass a directory path and every *.jsonl file inside (including subdirectories)
is loaded in sorted order:
Saving¶
save() writes one JSON object per line, renaming input_data back to your
configured input_field so round-trips work cleanly:
loader = JSONLTaskLoader()
loader.save(tasks, "output.jsonl")
tasks2 = loader.load("output.jsonl") # identical to `tasks`
CSVTaskLoader¶
Read a .csv file via the standard-library csv
module.
Installation¶
No extra dependencies — ships with the tracelens core package.
Basic usage¶
A minimal CSV looks like:
input,name,difficulty
"What is 2 + 2?",Math addition,easy
"Summarise the abstract",Summarisation,hard
Custom column names¶
Map a different column to Task.input_data with input_field, and select
which columns become Task.metadata with metadata_fields:
tasks = CSVTaskLoader(
input_field="prompt",
metadata_fields=["subject", "source"],
).load("my_data.csv")
When metadata_fields is omitted, all columns that are not input_field and
not one of the reserved Task fields (name, difficulty, category, …) are
collected into Task.metadata automatically.
The configured input field is required. A missing JSONL field or CSV column is
reported as an error instead of producing an empty task. It must not reuse a
native Task field name such as name or metadata.
CSV headers must be unique and non-blank, and every row must have no more values than the header. Malformed source structure fails with the file and line location instead of silently dropping data.
JSON-encoded cells¶
Cells that contain a valid JSON object or array are parsed automatically, so you can store structured input data in a single CSV column:
Directory loading¶
Saving¶
TraceLens writes structured Task fields as JSON and uses one canonical JSON
metadata column. This preserves arbitrary JSON-compatible metadata,
including keys such as name or input that would collide with ordinary CSV
columns. External CSV files may instead use flat extra columns as metadata,
but a row cannot combine a metadata column with flat metadata columns: that
ambiguous representation is rejected.
Design policy: wrap parsers, own only the mapping¶
TraceLens loaders never implement file-format parsing. JSONLTaskLoader and
CSVTaskLoader delegate to the stdlib json and csv modules — the
maintained parsers for those formats — and own only the row-to-Task
mapping (which columns are Task fields, what gets JSON-parsed vs kept as
text, how metadata is collected). The same rule applies to future sources:
a Parquet loader would wrap pyarrow, a database loader would wrap its
driver, and hosted-dataset sources wrap their ecosystem client. Optional
integrations remain isolated from core imports and reuse the same record
mapping contract as local loaders.
HFDatasetLoader¶
Install the optional dependency:
Hub datasets require an explicit split. Pin revision to a commit SHA for
reproducible CI evaluations:
from tracelens.loaders import HFDatasetLoader
loader = HFDatasetLoader(
input_field="question",
metadata_fields=["subject"],
config_name="all",
split="test",
revision="<dataset-commit-sha>",
)
tasks = loader.load("cais/mmlu")
String sources are always treated as Hub dataset identifiers. A local
dataset previously written by datasets.Dataset.save_to_disk() uses an
explicit Path:
from pathlib import Path
loader.save(tasks, Path("eval-data/mmlu"))
reloaded = loader.load(Path("eval-data/mmlu"))
HFDatasetLoader does not stream or push datasets to the Hub. Its load()
contract returns a materialized list[Task], and save() writes only a local
Hugging Face dataset directory. Saving an empty Task list is rejected because
Hugging Face cannot infer a reloadable dataset schema without any rows.