Research
Trajectory mining
Measured behavior
Evaluation |
Input |
Result |
What it establishes |
|---|---|---|---|
Public Plumbline corpus |
7 trajectories, 118 events |
8 activities, 6 exact variants |
The process miner accepts a heterogeneous action log through its data API |
Planted successful-path corpus |
13 known invariants |
Precision |
Every planted call, order, ceiling, outcome, and absence rule was recovered |
Path matching fixtures |
4 comparisons |
|
Strict, unordered, subsequence, and negative comparisons retain their intended semantics |
Four-cluster vector fixture |
12 trajectories, 4 selected |
|
Greedy farthest-point selection covers every planted neighborhood |
Trace adapters |
OpenAI, Anthropic, OTLP |
|
The three adapters preserve tool identity and explicit versus unknown outcomes |
The public corpus contains many repeated adversarial actions. Its measured
rework rate of 0.695 describes that input. Known-answer rows check algorithm
semantics. The public-corpus row covers data-shape compatibility. Application
quality requires evaluation with the target agent and workload.
Process model example
Run |
Observed activities |
Process result |
|---|---|---|
A |
|
Variant A, four edges including start and end |
B |
|
Variant A support becomes two |
C |
|
One sequential rework event |
D |
two |
Parallel batch, excluded from sequential rework |
Normalize trace exports
The adapters translate common export shapes into TrajectoryStep. Their output
keeps metadata selected by the schema. Tool-result bodies stay with the host.
Model calls and trace storage also remain application operations. Success
requires an explicit source field.
from mari_components.trajectories import normalize_openai_trajectory
result = normalize_openai_trajectory(messages, maximum_events=10_000)
step = result.steps[0]
assert step.tool == "search"
assert step.ok is None # portable status unavailable
Function |
Input and options |
Output |
|---|---|---|
|
Chat Completions messages or Responses API items |
Steps, positioned adapter issues, dropped-record count |
|
|
Same result. |
|
OpenTelemetry GenAI attribute spellings |
Time-ordered steps with IDs, parents, token counts, cost, and status when supplied |
|
Mari’s small |
Privacy-bounded |
Sensitive argument names are removed by normalize_steps. A missing outcome
remains None. Procedure mining and success-invariant mining require an
explicit successful outcome.
Mine process structure
canonicalize_activity removes call arguments, generated numeric IDs, path
arguments, and retry suffixes. Resource names such as chat:model-name reduce
to the activity chat. The caller can retain the model separately.
from mari_components.trajectories import TrajectoryRun, mine_trajectory_process
process = mine_trajectory_process(
[TrajectoryRun(trajectory_id="run-17", steps=result.steps)],
activity_aliases={"vector_search": "retrieve"},
)
for edge in process.transitions:
print(edge.source, edge.target, edge.occurrences, edge.parallel)
Value |
How it is computed |
|---|---|
Direct-follow transition |
Adjacent canonical activities, plus explicit start and end nodes |
Exact variant |
Complete canonical activity tuple with exact equality |
Sequential rework |
A repeated activity within one run |
Parallel event |
Sibling steps with the same non-empty parent. Excluded from sequential rework |
Variant reuse |
Fraction of runs belonging to a variant observed more than once |
Cost and duration |
Sums of caller-observed values. Missing measurements contribute zero |
Compare paths
from mari_components.trajectories import (
TrajectoryMatchMode,
compare_trajectories,
)
match = compare_trajectories(
observed,
reference,
mode=TrajectoryMatchMode.SUBSEQUENCE,
matches=lambda actual, expected: actual.tool == expected.tool,
)
assert match.matched
print(match.missing_reference_indices)
Mode |
Condition |
|---|---|
|
Same length and matching steps at every position |
|
Same multiset under the supplied matcher |
|
Every observed step appears in reference order. Reference extras are allowed |
|
Every reference step appears in observed order. Observed extras are allowed |
Every result includes aligned index pairs and unmatched positions. It also
reports Levenshtein edit distance with normalized similarity. Tool arguments
use exact equality by default. Pass matches= to define domain-specific
equivalence.
Mine and check invariants
mine_trajectory_invariants requires runs explicitly marked success.
It emits evidence-bearing candidates. Callers can turn reviewed candidates
into tests, policies, or gates.
from mari_components.trajectories import (
check_trajectory_invariant,
mine_trajectory_invariants,
)
candidates = mine_trajectory_invariants(
historical_runs,
available_tools={"search", "read", "answer", "delete"},
argument_names={"scope"},
minimum_support=0.95,
minimum_applicable=20,
)
violations = [
violation
for candidate in candidates
if (violation := check_trajectory_invariant(candidate, new_run)) is not None
]
Candidate kind |
Applicability and evidence |
|---|---|
|
All successful runs. Support names runs containing the tool |
|
Tools in caller-supplied |
|
Runs containing the paired tools. Every occurrence of the first must precede every occurrence of the second |
|
Runs containing the tool. Ceiling is the maximum observed successful count |
|
Runs containing the tool. Support requires explicit successful outcomes |
|
Caller-selected argument names. Observed scalar values remain visible |
Select trajectories for inspection
select_diverse_trajectories(vectors, *, limit, relevance=None, density=None, distance_exponent=1.0) applies greedy farthest-point sampling in
the original normalized embedding space. The optional relevance and density
weights are supplied by the caller. The result retains each selection score,
minimum distance, rank, and every excluded ID.
Sampling weights multiply relevance, density, and distance. Equal scores break ties by trajectory ID. Keep the embedding model and weight recipe fixed across comparisons, and include rare failure cases explicitly in the review set. Feed selected observations into conversation knowledge for searchable lessons, or successful traces into procedure mining.
Research and implementations
Hodoscope: action abstraction and diverse trajectory inspectionAgentEvals trajectory matchingTraceRoutine process miningTrace-to-Evals invariant miningPlumbline intent-relative trajectory analysisProcess Mining: Data Science in Action
Mari uses independent immutable values and pure functions. Applications supply dashboards and model clients. CI generation, enforcement, and trace storage connect through the returned records.