Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ input_data = {
|--------|-------------------|-------------|
| JSON | `json` | Top-level array, each element is one sample |
| JSONL | `jsonl` | One JSON object per line |
| ms-swift | `ms_swift` | Agent trajectory JSONL; preserves raw fields and prepares selected evaluator fields |
| CSV | `csv` | Comma-separated values with header |
| Parquet | `parquet` | Apache Parquet columnar format |
| Plain text | `plaintext` | One line per sample, mapped to `content` |
Expand All @@ -170,6 +171,22 @@ input_data = {

MinerU formats automatically flatten blocks into `Data` objects, preserving all original fields (type, bbox, page_idx, etc.) via Pydantic `extra="allow"`. Use `dataset.mineru_config.include_types` to filter by block type.

The `ms_swift` converter lives in `dingo/data/converter/ms_swift.py`. It prepares
independent `<EvaluatorName>_<field>` fields for all 9 deterministic Agent rules
and 7 Agent LLM metrics, only when selected in `evaluator[].evals`.
Each deterministic rule owns its parsing and field assembly in its `prepare_*`
function; LLM metrics continue sharing `_messages_content()`.
Map these fields in a separate evaluator block for each metric. Initial LLM
inputs contain only message `role`/`content`, with empty prompts; Plan Adherence
also receives an empty context. Tool results are paired by call ID; execution
status and duration extensions are copied only when explicitly present.
See `docs/agent_trace/ms_swift.md` and `examples/dataset/ms_swift.json` for mappings
and limitations.
Each converted record privately tracks the fields actually generated by its
selected preparers. Local result output removes these fields from a copy via
`ResultInfo.without_derived_fields()`, preserving both existing output formats
and conflict backups. No manually maintained cleanup list is needed.

### Execution Modes

| Mode | Class | Use Case |
Expand Down
1 change: 1 addition & 0 deletions dingo/data/converter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import dingo.data.converter.mineru # noqa: F401 — registers mineru / mineru_v2
import dingo.data.converter.ms_swift # noqa: F401 — registers ms_swift
from dingo.data.converter.base import BaseConverter

converters = BaseConverter.converters
521 changes: 521 additions & 0 deletions dingo/data/converter/ms_swift.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dingo/data/datasource/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def _find_all_files(self, path: str, file_list: List[str]):
for _f in os.listdir(path):
f = os.path.join(path, _f)
if os.path.isfile(f):
if getattr(self.input_args.dataset, "format", None) == "jsonl":
if getattr(self.input_args.dataset, "format", None) in ("jsonl", "ms_swift"):
if f.lower().endswith(".jsonl"):
file_list.append(f)
elif getattr(self.input_args.dataset, "format", None) == "json":
Expand Down
8 changes: 7 additions & 1 deletion dingo/exec/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ def execute(self) -> SummaryModel:
futures_results = []
for data in batch:
dingo_id += 1
r_i = ResultInfo(dingo_id = str(dingo_id), raw_data = data.to_dict())
r_i = ResultInfo(
dingo_id=str(dingo_id),
raw_data=data.to_dict(),
derived_fields=data._derived_fields,
)
futures_results.append(r_i)

for e_p in self.input_args.evaluator:
Expand Down Expand Up @@ -419,6 +423,8 @@ def _should_write_to_file(self, input_args: InputArgs, file_path: str) -> bool:

def _build_output_json(self, input_args: InputArgs, result_info: ResultInfo) -> str:
field_list = self._resolve_field_list(input_args)
if input_args.dataset.format == "ms_swift":
result_info = result_info.without_derived_fields()
if input_args.executor.result_save.raw:
output_data = result_info.to_raw_dict(field_list=field_list)
else:
Expand Down
7 changes: 5 additions & 2 deletions dingo/io/input/data.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Dict
from typing import Any, Dict, Set

from pydantic import BaseModel
from pydantic import BaseModel, PrivateAttr


class Data(BaseModel):
Expand All @@ -9,6 +9,9 @@ class Data(BaseModel):
Flexible data structure that allows any fields to be configured.
"""

# Per-record converter metadata; never included in evaluator field mappings.
_derived_fields: Set[str] = PrivateAttr(default_factory=set)

class Config:
extra = "allow"

Expand Down
11 changes: 10 additions & 1 deletion dingo/io/output/result_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from collections.abc import Mapping
from datetime import date, datetime
from decimal import Decimal
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Optional, Set

from pydantic import BaseModel, Field

Expand All @@ -23,6 +23,15 @@ class ResultInfo(BaseModel):
default_factory=dict,
exclude=True,
)
derived_fields: Set[str] = Field(default_factory=set, exclude=True)

def without_derived_fields(self) -> "ResultInfo":
"""Return an output copy without converter-generated top-level raw fields."""
cleaned_raw_data = {
key: value for key, value in self.raw_data.items()
if key not in self.derived_fields
}
return self.model_copy(update={"raw_data": cleaned_raw_data})

@staticmethod
def _eval_detail_to_dict(model_res: EvalDetail) -> Dict[str, Any]:
Expand Down
Loading
Loading