Repository navigation
Releases
agentpile 0.3.1
Examples that run as pasted and on your own runs, and capture with the framework versions a fresh install now gets. The record format and the readers are unchanged.
Added
- Capture and the OTLP reader accept spans from Pydantic AI 2.61.0, which builds the same records as 2.58.0 to 2.60.0 from the fixture scripts. With 0.3.0,
cap.runraisedUnsupportedVersionfor it, and 2.61.0 is whatpip install "agentpile[pydantic-ai]"installs. - Every recipe in
examples/integrations/also runs on your own runs:python <recipe>.py <dataset name or trace file> --limit Nruns the integration on them and prints a short result, and with no source it runs on the bundled fixtures with its checks, as CI does. Each recipe now opens with the code to copy, followed by its checks.
Changed
- The
openai-agentsextra installs openinference-instrumentation-openai-agents below 2.6. With 0.3.0 it installed 2.6.0, andcap.runraisedUnsupportedVersion. 2.6.0 writes the same spans as 2.5.3 but ignores a trace that began before the capture block opened, which capture records from its first event inside the block with 2.5.3, so it is not added to the tested versions. - README snippets each run when pasted alone, with the extras named in their first line; section 5 runs a Pydantic AI agent on its
TestModel, with no model key. The two showcase scripts write their figure to the current directory unless given a path, and keep only the code the figure needs.
agentpile 0.3.0
A reader for the session files Claude Code writes, with their subagent files, and the trace_commons dataset of 28 public sessions read with it. The record format and every existing reader are unchanged.
Added
- A reader for the session files Claude Code writes under
~/.claude/projects/<project>/<session>.jsonl, registered asclaude-code-jsonl, soap.load(path)reads a local session and every existing output (run.events(), tables,to_chat,to_otlp,show) works on it. Claude Code writes one record per content block; the records of one message become one agent step, placed at the message's first line, and each tool result pairs with its call by id even when Claude Code wrote the result before the rest of the message. Subagent files under<session>/subagents/load with the session as subagent trajectories, linked to the Agent call that names their id or the Workflow call that names their folder. Attachments are kept verbatim; other bookkeeping records are counted, every line of the file is accounted for inrun.dataset["accounting"], and an index of every record'suuidand parent keeps the session's tree, including edited or rewound branches, which are labelled and never pruned. The format is Claude Code's own and has no public specification; the reader was built on 2.1.x files. - The
trace_commonsdataset: the 28 Claude Code sessions oftrace-commons/agent-traces, read with the new reader at a pinned revision.
agentpile 0.2.0
Chat rows for training and evaluation, OTLP output that follows the OpenInference and OTel GenAI conventions, a labels table that saves to Parquet, and recipes for downstream tools. The labels table's value column changes type, which can silently empty an existing filter (see Changed).
Added
ap.to_chat(runs, path=None, *, perspective=None, arguments="json", report=None)turns trajectories into OpenAI-style chat rows,{"messages": [...], "tools": [...]}, returned as a list or written as JSON Lines topath; thechat-jsonlwriter does the same for one run. The rows have the message shape that OpenAI fine-tuning files, Hugging Face chat templates and message-list auditors use, and writing them needs only the standard library. Messages followrun.events(), each tool result follows the assistant turn that issued its call, and tool definitions in the OpenAI, MCP or Anthropic shape become OpenAI function tools. Withperspective="X", agent X is the assistant and every other agent's turns become user text that starts with the agent's id; tau2-bench's simulated user is user text either way. Where the chat shape needs a value the source lacks, the row holds{},{"_raw": ...}or"". The optionalreportcounts each such change and gives the position and address of every event behind each message, so a row can be traced back to the record.- Seven recipes in
examples/integrations/hand agentpile output to downstream tools and check the result: tool-call scoring with Ragas and DeepEval, fine-tuning input with Hugging Facedatasetsand TRL, rule checks with Invariant Guardrails, table queries with DuckDB and Polars, and viewing in Harbor, Inspect AI and OTLP trace viewers (Phoenix, Jaeger, MLflow). Each pins its own environment and runs offline on the bundled fixtures. A CI workflow runs them weekly, and the README's Works With table shows each check's status and the date it last passed. The recipes are examples, not part of the package.
Changed
- The labels table of
ap.table(runs, "labels")andap.to_pandas(runs, "labels")stores eachvalueas text, orNonefor a null value. A newvalue_typecolumn recordsbool,int,float,str,jsonorNone. Keepvalueas it is whenvalue_typeisstrorNone, and usejson.loads(value)otherwise; into_pandasthese two columns keepNonerather than NaN, so the same rule works on a DataFrame. A value JSON cannot hold (a date, a tuple) comes back in its JSON form, andrun.labelskeeps the original typed values. Datasets label with booleans, numbers and strings alike, so the old column mixed types, and saving the labels table to Parquet (or any other Arrow conversion) failed for 7 of the 13 dataset fixtures and for all 13 together. A filter written for the old types needs the new form:df[df.value == True]now matches nothing, anddf[(df.value_type == "bool") & (df.value == "true")]replaces it.df.value.astype(float)still works on numeric labels. - OTLP export follows two pinned conventions: the attribute names of OpenInference 0.1.41, and the OTel GenAI attribute names and value schemas at revision
9ffc7e00c639be7712e544e3e54331e885dccf84. The record attributes (agentpile.*) are unchanged, and the reader still rebuilds the exact record, from new exports and from those 0.1.x wrote. What a trace viewer shows changes:- Tool spans that agentpile writes sit under the span of the step that made the call instead of directly under the trajectory span. Every span agentpile adds lies inside its parent and takes time, except under a source span that itself takes none; a source span without an end time counts as one, and a missing start time no longer lands after the recorded end. In 0.1.x, 187 of the 535 spans agentpile added across the fixtures lasted zero time: every tool span, and steps such as a trajectory's last one when it called no tool. A step whose source timestamp falls outside the source span or call it is drawn under moves inside it, marked
agentpile.time_synthetic; the record keeps the timestamp. - On a tool span,
input.valueandoutput.valuegive the call's arguments and result as the source recorded them.gen_ai.tool.call.argumentsandgen_ai.tool.call.resultnow appear only for a JSON object, as the GenAI schemas require; on the dataset fixtures this leaves out 6 of 94 argument values, the ones that did not parse, and 72 of 78 results, mostly plain text. Code that read either attribute for text should readinput.valueoroutput.value. A newtool.parametersholds the tool's parameter schema from an OpenAI, MCP or Anthropic definition, left out where two tools of the call's name could have different ones. - Model spans show in
input.valuewhat came in since the previous model call: system and user messages, the text of a step that made no model call (a scripted greeting), and tool results with their call ids. The value is markedagentpile.input_reconstructed, since ATIF does not record the prompt a model was given;llm.input_messagesandgen_ai.input.messagesstay absent. - The resource's
service.namefalls back to the run's dataset when the agent's name is missing orunknown, and toagentpilewithout a dataset.openinference.project.nameis the dataset, so Phoenix files each dataset under its own project. The dataset goes by the nameap.loadtakes, such astau_bench; a record from a dataset agentpile does not register keeps the source's own id, such as a hub repository. - Attributes the record does not hold stay absent, including ones the conventions require, such as
gen_ai.provider.name. Spans adopted from a source trace keep their attributes, parents and times.
- Tool spans that agentpile writes sit under the span of the step that made the call instead of directly under the trajectory span. Every span agentpile adds lies inside its parent and takes time, except under a source span that itself takes none; a source span without an end time counts as one, and a missing start time no longer lands after the recorded end. In 0.1.x, 187 of the 535 spans agentpile added across the fixtures lasted zero time: every tool span, and steps such as a trajectory's last one when it called no tool. A step whose source timestamp falls outside the source span or call it is drawn under moves inside it, marked
Fixed
- A model span in an OTLP export names a model when its step records none: the model the record's roster gives the step's agent, else the trajectory's model. tau-bench records its model only once per run, so its model spans named none before. A step the harness scripted, such as tau2-bench's fixed greeting, still names none, and the record itself is unchanged. The span is then named
chat <model>.
agentpile 0.1.2
Pydantic AI 2.60.0 came out after 0.1.1, and pip install "agentpile[pydantic-ai]" installs it.
Added
- Capture and the OTLP reader accept spans from Pydantic AI 2.60.0, which builds the same records as 2.58.0 and 2.59.0 from the fixture scripts. With 0.1.1,
cap.runraisedUnsupportedVersionfor it.
This release changes nothing else. It is cut from 0.1.1 on the release-0.1.x branch; the labels-table and OTLP changes on main wait for 0.2.0.
Install: pip install -U agentpile (PyPI).
agentpile 0.1.1
Fixes found by running 0.1.0 on Google Colab, where the preinstalled google-adk caps OpenTelemetry at 1.42.1.
Changed
- The
otelextra installs onlyopentelemetry-proto, whichap.send_otlpuses for a receiver that takes only protobuf. The OpenTelemetry SDK comes with thepydantic-aiandopenai-agentsextras, since capture is the only code that uses it. - The OpenTelemetry lower bound of the
otel,pydantic-aiandopenai-agentsextras is 1.42.1, down from 1.45.1, so installing them on Colab no longer upgrades OpenTelemetry past what google-adk accepts. The tests pass on both versions.
Fixed
- Loading a gated dataset (TRAIL) without access raises
ap.GatedDataset, which names the page where you accept the terms and the ways to give huggingface_hub a token (hf auth login,HF_TOKEN, Colab Secrets). The hub's own error is kept as the cause. ap.show(run, file=...)writes tofileinside a Jupyter notebook too. Before, rich drew the view as cell output and the file stayed empty. Withoutfile, a notebook still shows the rich view as cell output.- The capture error for a missing OpenTelemetry SDK names the extra of the framework being captured instead of
otel. - The README's compare-failures example says that TRAIL is gated.
Install: pip install -U agentpile (PyPI).
agentpile 0.1.0
The first release.
Added
ap.load(name)for 13 public agent-trace datasets, each at a pinned revision and checked against the run count in its manifest: Who&When, MAST, TRAIL, tau-bench, tau2-bench, AgentRewardBench, AgentDojo, SWE-rebench OpenHands, SWE-agent (Nebius), SWE-Gym OpenHands, SWE-smith, ADP and CatchBench PRE. Withlimit=N, a Hugging Face dataset downloads only the files its first N runs come from (five AgentRewardBench runs fetch about 25 MB of its 30 GB); a later full load fetches the rest and runs the count check.ap.load(path)andap.load(record)for ATIF v1.7, OpenAI-style message lists, OTLP JSON (OpenInference and OTel GenAI attributes), MCPtools/listresults, OpenAI and Anthropic tool lists, and agentpile config records. The format is detected, and an input that more than one reader claims is an error.- The run record: an ATIF v1.7 trajectory with an
extra["agentpile"]extension for source identity, labels with targets, agents and tools with permissions, source spans, and the source values behind every stand-in ATIF requires. A configuration without execution is anagentpile-config/0record. Harbor 0.22.0's ATIF models accept every trajectory checked: the first 3,000 runs of each dataset, or all of a smaller one. Run.events(): messages, tool calls and tool results in the order the source recorded them, with each event's address in the record.ap.derive_deps(run, rules=[...])with six named, versioned rules (tool_call_id_v1,full_context_v1,resource_chain_v1,last_writer_v1,prior_reads_v1,value_flow_v1), andRun.with_deps(rules=[...]), which returns a copy whose steps carry the entries.run.to_json()andrun.to_otlp(); an OTLP export reads back to an equal record, and a run loaded from a trace writes each source span once.ap.show(run): a terminal view of one run, with labels beside the events they target and the record's stand-in and pairing marks; rich output with theviewextra, plain text without it.ap.table(runs, level)for flat rows of runs, events or labels (standard library),ap.to_pandas(runs, level)(pandasextra), andap.to_networkx(run, rules), an event graph with pairings and inferred dependencies as edges (graphextra).ap.send_otlp(runs, endpoint): posts each trajectory's OTLP JSON to a tracing backend such as Jaeger or MLflow, and switches to protobuf for one that answers 415, such as Arize Phoenix (needsopentelemetry-protofrom theotelextra).ap.capture(agent=...)andap.config_from(agent)for Pydantic AI (2.58.0 and 2.59.0) and the OpenAI Agents SDK (0.24.0, through openinference-instrumentation-openai-agents 2.5.3). Spans from any other version of the instrumentation (Pydantic AI's own, or OpenInference's for the Agents SDK) raiseUnsupportedVersionunlessallow_untested_version=True, which builds the run and marks it.ap.validate(record), the JSON schema of the extension, and plugin registries for readers, writers and datasets (ap.registerand theagentpile.readers,agentpile.writersandagentpile.datasetsentry-point groups).- One download cache,
~/.cache/agentpile/(AGENTPILE_CACHE), withap.cache_info()andap.clear_cache().
Install: pip install agentpile (PyPI).