AmanPriyanshu/tool-reasoning-sft-RESEARCH-explorations
Explorations Trajectories — Cleaned & Stripped 149,025 multi-turn code exploration agent trajectories converted into a strict reasoning + tool-call format with validated FSM transitions. Origin Derived from AmanPriyanshu/random-small-github-repositories and AmanPriyanshu/random-python-github-repositories. Each trajectory is a search session where an agent navigates a GitHub repository using terminal commands to locate a target file. The agent reasons about project… See the full description on the dataset page: https://huggingface.co/datasets/AmanPriyanshu/tool-reasoning-sft-RESEARCH-explorations.
Explorations Trajectories — Cleaned & Stripped
149,025 multi-turn code exploration agent trajectories converted into a strict reasoning + tool-call format with validated FSM transitions.
Origin
Derived from AmanPriyanshu/random-small-github-repositories and AmanPriyanshu/random-python-github-repositories.
Each trajectory is a search session where an agent navigates a GitHub repository using terminal commands to locate a target file. The agent reasons about project structure, runs grep/ls/find/cat commands, and submits ranked file recommendations. Trajectories were filtered to the goldilocks zone (7–15 turns with successful file discovery) and expanded across 3 rounds per seed.
Format
Each row contains a structured multi-turn conversation with explicit reasoning traces and validated tool calls.
Message Roles
Trajectory Structure
system → user → reasoning → [tool_call → tool_output → reasoning →]* answerFor trajectories that needed bridging (14.2%), mid-trajectory file submissions are converted into multi-turn rejection loops:
... → reasoning → answer → user(rejection) → reasoning(retry) → tool_call → ... → answerTrajectories range from 4 to 58 turns, with an average of ~32 messages per row.
Schema
Single Parquet file with zstd compression.
Tools
2 tools available per trajectory:
Conversion Details
- Source trajectories use
type/text/name/arguments/outputfields — conversion maps these to the canonical 6-role FSM format reasoningoutputs →<think>…</think>messages; consecutive reasoning blocks mergedfunction_calloutputs (terminal) →<tool_call>+<tool_response>pairsfunction_calloutputs (submitrecommendedfiles) →<answer>with ranked file listmessageoutputs (text-based submissions) →<answer>with raw content- Mid-trajectory submissions (agent submits files then keeps exploring) →
answer → user(synthetic rejection) → reasoning(retry)bridging with 12-variation template pools - Bridge reasoning and tail reasoning drawn from 12 domain-appropriate templates each
- 100% conversion rate on all 149,025 rows; zero FSM violations, zero content-tag failures
- Two validation layers: FSM transition check + content-tag non-empty regex check + tool_call JSON schema check
Distribution
Usage
import json, random, re
from datasets import load_dataset
VALID_NEXT = {
"system": {"user"}, "user": {"reasoning"},
"reasoning": {"tool_call", "answer"}, "tool_call": {"tool_output"},
"tool_output": {"reasoning"}, "answer": {"user"},
}
ds = load_dataset("AmanPriyanshu/tool-reasoning-sft-RESEARCH-explorations", split="train")
print(f"Loaded: {len(ds):,} rows\n")
idx = random.randint(0, len(ds) - 1)
row = ds[idx]
msgs = json.loads(row["messages"])
roles = [m["role"] for m in msgs]
tc = sum(1 for r in roles if r == "tool_call")
print(f"Row {idx} | repo={row['repo_id']} | target={row['seed_file_selected']}")
print(f" {len(msgs)} turns | {tc} tool_calls | bridged={row['needed_to_bridge']}")
print(f" Roles: {' -> '.join(roles[:15])}{'...' if len(roles)>15 else ''}\n")
# ── Validation 1: FSM transitions
bad = [(j, roles[j], roles[j+1]) for j in range(len(roles)-1)
if roles[j+1] not in VALID_NEXT.get(roles[j], set())]
if bad:
print(f"!! FSM VIOLATIONS: {len(bad)}")
for pos, a, b in bad[:5]:
print(f" [{pos}] {a} -> {b}")
else:
print("✓ FSM transitions: all valid")
# ── Validation 2: content tags
tag_ok = True
for i, t in enumerate(msgs):
r, c = t["role"], t["content"]
if r == "reasoning" and not re.search(r'<think>.+</think>', c, re.DOTALL):
tag_ok = False
elif r == "tool_call" and not re.search(r'<tool_call>.+</tool_call>', c, re.DOTALL):
tag_ok = False
elif r == "answer" and not re.search(r'<answer>.+</answer>', c, re.DOTALL):
tag_ok = False
elif r == "tool_output" and not re.search(r'<tool_response>.+</tool_response>', c, re.DOTALL):
tag_ok = False
print(f"{'✓' if tag_ok else '!!'} Content tags: {'all valid' if tag_ok else 'errors found'}")
# ── Print sample turns
print(f"\n{'='*70}")
for i, m in enumerate(msgs[:10]):
content = m["content"]
if m["role"] == "system":
content = content[:150] + "..."
elif len(content) > 200:
content = content[:200] + "..."
print(f"[{i}] {m['role']}:\n{content}\n")
if len(msgs) > 10:
print(f"... ({len(msgs) - 10} more turns)")