Reference
Logs and adapters¶
Find what is worth replacing, diagnose the logs, and read them into trajectories.
Both scan and check_logs read the logs only and call no LLM. The guide is
Check and debug logs.
import tabagent
print(tabagent.scan("./agent_logs").summary())
check = tabagent.check_logs("./agent_logs", decision="ToolShortlist")
print(check.summary(), check.ok)
scan
¶
scan(
logs: str | Path | list[Trajectory],
*,
adapter: Any = "auto",
prices: Prices | None = None,
top: int = 3,
lazy: bool | None = None,
on_other_formats: str = "skip",
) -> ScanReport
Rank the components of an agent's logs that call an LLM by what replacing them could save.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logs
|
str | Path | list[Trajectory]
|
a file or directory of agent logs, or a list of |
required |
adapter
|
Any
|
the log adapter, or |
'auto'
|
prices
|
Prices | None
|
|
None
|
top
|
int
|
how many closed-set candidates the summary details, with their next step. |
3
|
lazy
|
bool | None
|
read runs again from their files when needed instead of holding them (default: from 256 MB of logs). |
None
|
on_other_formats
|
str
|
with |
'skip'
|
Returns:
| Type | Description |
|---|---|
ScanReport
|
A |
ScanReport
dataclass
¶
ScanReport(
logs: str,
adapter: str,
n_runs: int,
n_successful: int,
n_calls: int,
ranked_by: str,
cost_source: str | None,
components: list[ComponentScan],
notes: list[str] = list(),
prices: Any = None,
top: int = 3,
)
The ranked components of a scan: summary(), to_markdown(), to_json().
Attributes:
| Name | Type | Description |
|---|---|---|
components |
list[ComponentScan]
|
every component of the agent that calls an LLM, ranked by |
candidates |
list[ComponentScan]
|
the closed-set components, best first. |
n_runs |
int
|
the scanned runs, the successful ones and the LLM calls. |
n_successful |
int
|
the scanned runs, the successful ones and the LLM calls. |
n_calls |
int
|
the scanned runs, the successful ones and the LLM calls. |
notes |
list[str]
|
how the logs record usage, and what could not be counted. |
Examples:
import tabagent
report = tabagent.scan("./agent_logs", prices=(PRICE_IN, PRICE_OUT))
print(report.summary())
report.candidates[0].next_steps # the onboard command for the top closed-set component
summary
¶
The report as plain text for a terminal, prose wrapped at width characters.
check_logs
¶
check_logs(
logs: str | Path,
*,
adapter: Any = "auto",
decision: str | None = None,
sample: int = 200,
lazy: bool | None = None,
on_other_formats: str = "skip",
) -> LogCheck
Diagnose agent logs before an onboarding; reads the logs only, calls no LLM.
Reports which files were read, skipped or repaired (and why), the runs and their outcomes and, for the
decision (default: every decision the adapter builds candidates and labels for), its decision points,
candidates and labels (chosen candidates that are not among the offered ones, with near-miss names), the
train/serve parity of its prefixes on sample decision points (spread evenly; all of them when there
are fewer), and the adapter's check that no prefix holds post-decision data. LogCheck.ok is False when
an onboarding would stop; every finding says what is wrong, where and how to fix it. lazy and
on_other_formats are read as by onboard. CLI: tabagent check-logs LOGS [--decision NAME].
LogCheck
dataclass
¶
LogCheck(
logs: str,
adapter: str | None,
files: int,
runs: int,
successful: int,
components: dict[str, int],
decisions: list[DecisionCheck],
findings: list[Finding],
)
The diagnosis of a log folder (see check_logs): ok when nothing would stop onboarding;
summary(), to_dict(), to_json().
Attributes:
| Name | Type | Description |
|---|---|---|
ok |
bool
|
False when a finding of level |
findings |
list[Finding]
|
what is wrong, where and how to fix it, each with a level ( |
decisions |
list[DecisionCheck]
|
one |
components |
dict[str, int]
|
the LLM-calling components found, with their call counts. |
files |
int
|
how many files were read, runs found and runs that succeeded. |
runs |
int
|
how many files were read, runs found and runs that succeeded. |
successful |
int
|
how many files were read, runs found and runs that succeeded. |
Examples:
import tabagent
check = tabagent.check_logs("./agent_logs", decision="ToolShortlist")
print(check.summary())
assert check.ok # the CLI exits with status 1 when this is False
adapters
¶
Trajectory adapters: read an agent's native logs into TabSchema trajectories and decision points.
An adapter implements load(path) -> list[Trajectory], decision_points(traj, target),
candidates(dp), labels(dp) and components(trajs), and exposes outcome_keys. A decision
point's prefix holds only what was known before the decision ({<task fields>, "steps": [{"name": ...,
...}]}); labels may read the full run (for tool shortlisting, the tools the successful run used).
For tabagent.scan an adapter may also implement llm_calls(traj) -> list[LLMCall]: every LLM call of a
run, with what it chose, what it was offered, the free text it wrote and the tokens, latency and cost the log
records (read_usage reads the common shapes), plus scan_notes on how its logs record them. All the
adapters below implement it.
OpenAIMessagesAdapter: chat-message runs (OpenAI, Anthropic Messages API format, LangChain dumps);Tau2Adapter: τ²-bench results files;CugaAdapter: CUGA agent trajectories (the API shortlister built in);GenericJsonAdapter: any log with named steps, with your own candidates and labels;detect_adapter(path): picks one of the above from the first files.
Every adapter reads files through tabagent.adapters.logfiles: encodings, damaged JSON and JSON Lines,
linked folders, values nested too deeply, and large inputs read again from their files instead of held in
memory. Whatever is skipped or repaired is reported in the adapter's warnings, runs of another log format
included (detect_adapter(..., on_other_formats="error") refuses them with MixedFormatsError).
tabagent.check_logs (CLI tabagent check-logs) diagnoses a log folder before an onboarding.
At decision time, live_prefix(adapter, run, target) builds a live run's prefix exactly as in training, and
describe_adapter / adapter_from_description record and rebuild the adapter a head was trained with.
OpenAIMessagesAdapter
¶
OpenAIMessagesAdapter(
granularity: str = "task",
tools: Any = None,
success: str | Callable[[dict], bool] | None = None,
task_id_key: str | None = None,
task_keys: Iterable[str] = TASK_KEYS,
outcome_keys: Iterable[str] = OUTCOME_KEYS,
max_chars: int | None = 20000,
)
Chat-message runs -> trajectories and tool-selection decision points (see the module docstring).
Candidates come from the run's own tools, else the tools catalog given here, else the union of
the tools called across the loaded runs (argument hints then list the argument names observed in calls;
calls answered with a tool-not-found error are left out).
success is an outcome key or a function of the run; runs without an outcome count as successful, and
runs whose outcome cannot be read (see tabagent.tabschema.trajectory.read_outcome) as failed; both
are reported in warnings, with every file, line or record load skipped or repaired.
warnings
property
¶
Data notes for the onboarding report: files and records skipped or repaired, runs without an outcome or with an unreadable one.
load
¶
The runs in one file or every .json/.jsonl file below a directory (see the module
docstring); what was skipped or repaired, runs of another log format (τ²-bench results, step logs)
included, is reported in warnings. lazy: read runs again from their files when needed instead
of holding them (default: from 256 MB of logs, logfiles.LAZY_INPUT_BYTES).
decision_points
¶
The decision points of a run (see the module docstring). The prefixes of one run share their step
objects (see DecisionPoint): treat them as read-only.
labels
¶
The tools chosen at the decision (for ToolShortlist: every tool the run called).
components
¶
The decision this adapter builds -> number of successful runs with at least one tool call.
llm_calls
¶
The agent's LLM calls in a run, for tabagent.scan: one per assistant turn (see
assistant_turns). A turn that calls tools is a NextToolCall: its choices are the tools it
called, its catalog the run's tools (else the catalog given here), its free text the content and
the arguments it wrote. A turn that only writes text is a TextReply. Usage is read from the turn's
own fields (usage, usage_metadata, response_metadata, cost, ...) when recorded.
live_prefix
¶
The prefix of a live decision, built exactly as in training.
run has the shape of a logged run: messages holds the conversation so far (for
ToolShortlist, the messages before the first tool call) and the run-level task fields
(instruction, domain, ... as listed in task_keys) sit next to it, as in the logs the head
was trained on. A field the training runs had and run lacks is missing from the prefix too.
Tau2Adapter
¶
Tau2Adapter(
granularity: str = "task",
tools: Any = None,
include_policy: bool = False,
max_chars: int | None = 20000,
)
Bases: OpenAIMessagesAdapter
τ²-bench simulations -> trajectories and tool-selection decision points (see the module docstring).
load
¶
The simulations of one results file or of every results file below a directory. Files and
records that are not τ²-bench results (another log format included) are skipped with a warning, and
so are simulations that are not objects; simulations without a task id, naming a task the file does
not list, or seen in an earlier file are reported in warnings. Runs are always held in memory
(they are built from a results file and its task list), whatever lazy says.
CugaAdapter
¶
CugaAdapter(
catalog: Any = None,
success: Callable[[dict], bool] | None = None,
outcome_keys: Iterable[str] = ("score", "eval", "actions_count"),
outcome_steps: Iterable[str] = ("EvaluationResult",),
candidates_fn: Callable[[DecisionPoint], list[Candidate]] | None = None,
labels_fn: Callable[[DecisionPoint, dict], set[str]] | None = None,
task_keys: Iterable[str] | None = TASK_KEYS,
app_labels: str = "used",
)
Bases: GenericJsonAdapter
CUGA trajectories -> decision points for any agent node; candidates and labels built in for the
ShortlisterAgent and the TaskAnalyzerAgent (see the module docstring). A run succeeds when
score > 0; a missing or unreadable score counts as a failure and is reported in warnings.
app_labels is "used" (the apps the run called) or "offered" (the apps the analyzer chose).
load
¶
Every trajectory under path (recursive; results.json/metadata.json skipped); see
GenericJsonAdapter.load. A run is an object with a steps list.
llm_calls
¶
The LLM calls of a run, for tabagent.scan: each step of an agent node (or with recorded
prompts), one call per recorded generation (see the module docstring).
decision_points
¶
See GenericJsonAdapter.decision_points. For the built-in decisions the labels are read from
the full run now and kept (a few names per decision point), so they need not read the run again.
labels
¶
Shortlister: the APIs the CodeAgent called after this shortlisting and before the next one. App
analyzer: the apps the run called after it (app_labels="used"), or the apps it chose
("offered"). Read from the full trajectory.
GenericJsonAdapter
¶
GenericJsonAdapter(
steps_key: str = "steps",
step_name_key: str = "name",
success: str | Callable[[dict], bool] | None = None,
group_key: str | None = "task_id",
outcome_keys: Iterable[str] = ("score", "eval", "evaluation", "reward", "success", "outcome"),
outcome_steps: Iterable[str] = ("EvaluationResult",),
candidates_fn: Callable[[DecisionPoint], list[Candidate]] | None = None,
labels_fn: Callable[[DecisionPoint, dict], set[str]] | None = None,
task_keys: Iterable[str] | None = TASK_KEYS,
)
Reads JSON trajectories with named steps, {..., "steps": [{"name": <component>, ...}, ...],
<outcome>}: one per .json file, a list of them in one file, or one per line of a .jsonl file.
A run succeeds by its first outcome field among success, reward and score (see
read_outcome); runs without one count as successful and are reported in warnings, and so are
unreadable outcomes, which count as failures. Pass success (a field name or a function of the run) to
decide otherwise. Prefixes keep only the top-level fields in task_keys (None keeps every field but
the outcome keys); the fields left out are reported in warnings. The task id (group_key) is never
in a prefix: it is the cross-validation group, not a feature.
Candidates and labels are benchmark-specific; pass candidates_fn(dp) and labels_fn(dp) (for
example, the catalog of tools and the tools the successful run actually called), or use a dedicated
adapter (tabagent.adapters).
load reads the files as described in tabagent.adapters.logfiles (encodings, damaged JSON, JSON
Lines, linked folders) and reports in warnings every file, line or record it skipped or repaired; it
refuses a folder that also holds runs of another log format. A step that is not an object, or has no
string name, stays in the prefixes but is never a decision.
warnings
property
¶
Data notes for the onboarding report: files and records skipped or repaired, runs without an outcome or with an unreadable one, fields kept out of prefixes.
load
¶
Trajectories from one file or every .json/.jsonl file below a directory (recursive, linked
folders followed; hidden files and the results.json/metadata.json run summaries skipped). A
.json file holds one run or a list of runs, a .jsonl file one run per line. A trajectory's id
is its path below the directory (:<index> for a run in a list or on a line). Files, lines and
records that cannot be read, records without the steps key and runs of another log format are skipped
and reported in warnings (see on_other_formats). lazy: read runs again from their files
when needed instead of holding them (default: from 256 MB of logs, logfiles.LAZY_INPUT_BYTES).
decision_points
¶
Every step named target, with its redacted prefix (see redact; the prefixes of one run
share their steps, see DecisionPoint). Steps that are not objects, or have no string name,
are kept in prefixes but are never decisions.
live_prefix
¶
The prefix of a live decision: the trajectory so far, redacted exactly as in training.
components
¶
Step name -> number of successful trajectories containing it (the replaceable components), most frequent first (ties by name).
candidates
¶
The legal candidates of a decision point (from candidates_fn).
labels
¶
The chosen candidates, read from the full trajectory (e.g. the tools the successful run used).
Available for decision points produced by this adapter's decision_points.
llm_calls
¶
The LLM calls of a run, for tabagent.scan: one per step that records an LLM call (a usage,
model, prompt or messages field). When no step of the run records one, every named step counts as a
call, marked inferred. The output is the step's output, data, result, response,
completion, answer, decision or choice field (JSON text is parsed), else its other
fields; usage is read with read_usage.
detect_adapter
¶
The adapter for the logs at path, chosen from the first files; kwargs go to its constructor.
The first records of the first files (up to 20, run summaries skipped) decide: CUGA trajectories over
generic step logs, else the format most of them hold. Runs of another format are skipped by the adapter's
load with a warning (on_other_formats="skip"), or stop it with MixedFormatsError
("error").
live_prefix
¶
The prefix adapter builds for a live run (the run so far, in the logged format) before the
decision target.
Chat-message adapters take {<task fields>, "messages": [...], "tools": [...]}; CUGA and generic step
adapters take the trajectory so far ({<task fields>, "steps": [...]}), redacted as in training.