Repository navigation
fix(mlflow): get() fetches spans via 3.x API; materialize() - #152
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe MLflow adapter adds MLflow 3 trace creation and file upload workflows, normalizes trace data, preserves workspace-scoped artifact paths, and concurrently materializes complete trace payloads. Unit tests cover the updated parsing and materialization responses. ChangesMLflow 3 trace creation and upload
Trace retrieval and materialization
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant TraceFile
participant TracesNamespace
participant OTLPTraceAPI
participant MLflow3TraceAPI
TraceFile->>TracesNamespace: upload_trace_file(experiment_id, trace_path)
TracesNamespace->>TracesNamespace: normalize spans and timestamps
TracesNamespace->>OTLPTraceAPI: POST /v1/traces
OTLPTraceAPI-->>TracesNamespace: upload response
TracesNamespace->>MLflow3TraceAPI: POST /api/3.0/mlflow/traces
MLflow3TraceAPI-->>TracesNamespace: trace_id
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
cc @hemajv |
julpayne
left a comment
There was a problem hiding this comment.
@suppathak this looks good - thanks - I did have a question though, do you know in which mlflow version this v3 API was introduced so that we can provide some compatability guidance?
@julpayne . Thanks for checking. TThe /api/3.0/mlflow trace endpoints were introduced in MLflow 3.0 (released 2025). Trace fetching with spans requires MLflow server ≥ 3.0. MLflow 2.x servers do not expose these endpoints. |
|
cc @ruivieira |
|
@suppathak can you check the failing tests please? |
|
@julpayne , Please check! Thanks |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/evalhub/adapter/mlflow.py (1)
790-793: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider cleaning up the unused
experiment_idparameter.The
experiment_idparameter is no longer used by the v3 trace retrieval endpoint. If this method must maintain its existing signature for backwards compatibility, consider prefixing the parameter with an underscore (e.g.,_experiment_id: str) or adding a brief docstring note. If not, it can be safely removed.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/evalhub/adapter/mlflow.py` around lines 790 - 793, Clean up the unused experiment_id parameter in the trace-fetching method surrounding _client._get_v3("/traces/get"). Remove it if the method’s API permits; otherwise retain the signature for compatibility by renaming it to _experiment_id and briefly documenting that it is unused by the v3 endpoint.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/evalhub/adapter/mlflow.py`:
- Around line 862-882: Update the trace materialization loop around self.get and
file writing to use a bounded ThreadPoolExecutor, fetching and processing full
traces concurrently while preserving the existing trace filename sanitization
and JSON structure. Submit one task per trace, collect task results so
exceptions still propagate, and avoid unbounded concurrency against the tracking
server.
---
Nitpick comments:
In `@src/evalhub/adapter/mlflow.py`:
- Around line 790-793: Clean up the unused experiment_id parameter in the
trace-fetching method surrounding _client._get_v3("/traces/get"). Remove it if
the method’s API permits; otherwise retain the signature for compatibility by
renaming it to _experiment_id and briefly documenting that it is unused by the
v3 endpoint.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d9543a24-d0a3-429f-8598-acbf41cdc338
📒 Files selected for processing (2)
src/evalhub/adapter/mlflow.pytests/unit/test_mlflow_traces.py
ruivieira
left a comment
There was a problem hiding this comment.
Thanks @suppathak , LGTM, just add one question (inlined).
Also, is it possible to rebase this on main? Thank you!
| collected += 1 | ||
| if collected >= max_results: | ||
| break | ||
| for future in as_completed(future_to_id): |
There was a problem hiding this comment.
@suppathak Should we wrap future.result() in a try/except so a single unreachable or 404'd trace doesn't abort the entire batch?
With the old loop, a failed trace skipped that entry and the rest of the batch continued.
So instead of
for future in as_completed(future_to_id):
full_trace = future.result() # raises on any failurewe could have
for future in as_completed(future_to_id):
try:
full_trace = future.result()
except Exception:
rid = future_to_id[future]
logger.warning("Failed to fetch trace %s, skipping", rid, exc_info=True)
continuewdyt?
There was a problem hiding this comment.
Sounds good! Thanks @ruivieira .
I have addressed both your comments. Ptal.
fd81eaa to
a164fa0
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/evalhub/adapter/mlflow.py`:
- Around line 791-796: Update the v3 trace retrieval flow around _parse_trace to
normalize trace_info.request_time into the parsed trace start timestamp and
execution_duration into its duration before materializing the trace, while
preserving existing field handling where applicable. Adjust the trace tests to
use the documented {"trace": {"trace_info": ..., "spans": [...]}} response shape
and verify the normalized timing values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e5e9d7b1-f3cc-49f4-8054-de1adfdd5061
📒 Files selected for processing (2)
src/evalhub/adapter/mlflow.pytests/unit/test_mlflow_traces.py
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/unit/test_mlflow_traces.py
4ae6ea6 to
9f522a5
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/unit/test_mlflow_traces.py`:
- Around line 329-331: Update the mock_client._get_v3 assertion in the test
around TracesNamespace.get() to verify calls include the exact path
"/traces/get" together with each trace_id parameter. Match calls without relying
on ordering, since trace materialization is concurrent, while retaining the
existing response side effect.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1ab658ee-0f9b-42e5-9d3b-b7bce599be68
📒 Files selected for processing (2)
src/evalhub/adapter/mlflow.pytests/unit/test_mlflow_traces.py
| mock_client._get_v3 = MagicMock( | ||
| side_effect=lambda path, params: _get_v3_responses[params["trace_id"]] | ||
| ) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Assert the v3 endpoint path.
The side effect ignores path, so this test passes even if TracesNamespace.get() calls the wrong v3 endpoint. Assert calls include ("/traces/get", {"trace_id": ...}); use order-independent matching because materialization is concurrent.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/unit/test_mlflow_traces.py` around lines 329 - 331, Update the
mock_client._get_v3 assertion in the test around TracesNamespace.get() to verify
calls include the exact path "/traces/get" together with each trace_id
parameter. Match calls without relying on ordering, since trace materialization
is concurrent, while retaining the existing response side effect.
9f522a5 to
e880a37
Compare
Latest updateAdded in this push:
Downstream PR: eval-hub/eval-hub-contrib#104 |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/evalhub/adapter/mlflow.py (1)
587-596: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winDo not inject
workspaces/defaultwhenMLFLOW_WORKSPACEis unset.The fallback now always adds a
workspaces/{workspace}segment. WhenMLFLOW_WORKSPACEis unset, the code uses the literaldefaultworkspace. Upstream MLflow 3.x has no workspace concept, so the PUT then targets a path that the artifact store does not expect. The docstring at Line 571-573 still documents the unscoped fallback{experiment_id}/{run_id}/artifacts/{path}, which no longer matches the code.Apply the workspace prefix only when the environment variable is set, and align the docstring.
🛠️ Proposed fix
if experiment_id and run_id: - workspace = os.environ.get("MLFLOW_WORKSPACE", "default") - return ( - f"{_ARTIFACTS_API}/workspaces/{workspace}/{experiment_id}/{run_id}/artifacts/{artifact_path}" - ) + workspace = os.environ.get("MLFLOW_WORKSPACE") + prefix = f"workspaces/{workspace}/" if workspace else "" + return ( + f"{_ARTIFACTS_API}/{prefix}" + f"{experiment_id}/{run_id}/artifacts/{artifact_path}" + )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/evalhub/adapter/mlflow.py` around lines 587 - 596, Update the artifact upload path resolution around the experiment_id/run_id fallback to add the workspaces/{workspace} segment only when MLFLOW_WORKSPACE is explicitly set; otherwise return the unscoped {experiment_id}/{run_id}/artifacts/{artifact_path} path. Align the method’s docstring with both resulting formats and remove the default workspace fallback.
🧹 Nitpick comments (4)
src/evalhub/adapter/mlflow.py (4)
1086-1096: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse
_to_msfor the timing fields.
_to_msalready converts integer ms, ISO-8601 strings, and duration strings. This block repeats the ISO parsing and missesexecution_duration.♻️ Proposed refactor
- exec_ms = info.get("execution_time_ms") or info.get("execution_duration_ms") - ts_ms = info.get("timestamp_ms") - if not ts_ms: - req_time = info.get("request_time") - if isinstance(req_time, str): - import datetime - try: - dt = datetime.datetime.fromisoformat(req_time.replace("Z", "+00:00")) - ts_ms = int(dt.timestamp() * 1000) - except (ValueError, TypeError): - ts_ms = None + exec_ms = _to_ms( + info.get("execution_time_ms") + or info.get("execution_duration_ms") + or info.get("execution_duration") + ) + ts_ms = _to_ms(info.get("timestamp_ms") or info.get("request_time"))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/evalhub/adapter/mlflow.py` around lines 1086 - 1096, Update the timing-field conversion in the surrounding evaluation logic to reuse the existing _to_ms helper for request_time, execution_time_ms, execution_duration_ms, and timestamp_ms. Replace the duplicated ISO parsing and ensure execution_duration is included while preserving the existing fallback precedence and millisecond values.
1228-1230: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueCancel remaining futures when
max_resultsis reached.The
breakexits theas_completedloop, butThreadPoolExecutor.__exit__callsshutdown(wait=True), so all pending fetches still run. Cancel them to avoid unnecessary calls to the tracking server.♻️ Proposed refactor
collected += 1 if collected >= max_results: + for pending in future_to_id: + pending.cancel() break🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/evalhub/adapter/mlflow.py` around lines 1228 - 1230, When the max_results threshold is reached in the as_completed loop, cancel all still-pending futures before breaking so ThreadPoolExecutor cleanup does not wait for unnecessary tracking-server fetches. Update the surrounding future collection logic to identify unfinished futures and invoke their cancellation, while preserving the existing collected results and break behavior.
942-945: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueFunction-local imports repeat across the new trace code. Four new call paths import modules inside function bodies. Move the standard-library imports to module scope. Keep only the optional third-party import local, and then document why.
src/evalhub/adapter/mlflow.py#L942-L945: keep theopentelemetry.protoimports local only if the dependency is optional, and add a comment that states this.src/evalhub/adapter/mlflow.py#L705-L705: movedatetimeto the module imports.src/evalhub/adapter/mlflow.py#L1062-L1062: movebase64to the module imports.src/evalhub/adapter/mlflow.py#L1091-L1091: remove thisdatetimeimport; the module-level import covers it.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/evalhub/adapter/mlflow.py` around lines 942 - 945, Move the standard-library imports used by the new trace paths into module scope: add datetime for the code around line 705 and base64 for the code around line 1062, then remove the redundant datetime import around line 1091. In the trace code around line 942, keep the opentelemetry imports local only if that dependency is optional, and add a comment documenting that rationale. Apply these changes in src/evalhub/adapter/mlflow.py at lines 942-945, 705, 1062, and 1091.
340-349: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the unused
_put_jsonand_patchhelpers.These methods only define client methods and have no callers in the tracked Python code. Drop them to keep the MLflow client surface minimal.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/evalhub/adapter/mlflow.py` around lines 340 - 349, Remove the unused _put_json and _patch methods from the MLflow client class, including their URL construction, HTTP calls, and response handling, while leaving the remaining client methods unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/evalhub/adapter/mlflow.py`:
- Around line 1007-1015: Update src/evalhub/adapter/mlflow.py at lines 1007-1015
to declare root_inputs and root_outputs as str initialized to "{}"; annotate
proto_spans at lines 959-959 as list[trace_pb2.Span] and span_dicts at lines
1098-1098 as list[dict[str, Any]], ensuring the surrounding MLflow
span-processing code passes mypy strict mode and supports string slicing.
- Around line 969-980: Update the span construction in create() to use each
span’s computed status_raw value instead of always assigning
trace_pb2.Status.STATUS_CODE_OK. Map the documented per-span status to the
corresponding trace_pb2.Status code while preserving OK as the default when no
status is provided.
- Around line 745-754: Update the span attribute normalization block around
raw_attrs and normalized: treat a null or otherwise absent non-list attributes
value as an empty mapping before calling dict, while preserving existing list
handling. Add an explicit type annotation to normalized using the appropriate
span/result type so mypy strict mode can infer its contents.
- Around line 1075-1084: Update _decode_span_id to recognize exactly 16
hexadecimal characters case-insensitively and return the normalized hex value.
Decode other inputs with base64 validation enabled, accept the result only when
it is exactly 8 bytes (returning its 16-character hex form), and preserve the
existing fallback behavior for invalid or incorrectly sized values.
---
Outside diff comments:
In `@src/evalhub/adapter/mlflow.py`:
- Around line 587-596: Update the artifact upload path resolution around the
experiment_id/run_id fallback to add the workspaces/{workspace} segment only
when MLFLOW_WORKSPACE is explicitly set; otherwise return the unscoped
{experiment_id}/{run_id}/artifacts/{artifact_path} path. Align the method’s
docstring with both resulting formats and remove the default workspace fallback.
---
Nitpick comments:
In `@src/evalhub/adapter/mlflow.py`:
- Around line 1086-1096: Update the timing-field conversion in the surrounding
evaluation logic to reuse the existing _to_ms helper for request_time,
execution_time_ms, execution_duration_ms, and timestamp_ms. Replace the
duplicated ISO parsing and ensure execution_duration is included while
preserving the existing fallback precedence and millisecond values.
- Around line 1228-1230: When the max_results threshold is reached in the
as_completed loop, cancel all still-pending futures before breaking so
ThreadPoolExecutor cleanup does not wait for unnecessary tracking-server
fetches. Update the surrounding future collection logic to identify unfinished
futures and invoke their cancellation, while preserving the existing collected
results and break behavior.
- Around line 942-945: Move the standard-library imports used by the new trace
paths into module scope: add datetime for the code around line 705 and base64
for the code around line 1062, then remove the redundant datetime import around
line 1091. In the trace code around line 942, keep the opentelemetry imports
local only if that dependency is optional, and add a comment documenting that
rationale. Apply these changes in src/evalhub/adapter/mlflow.py at lines
942-945, 705, 1062, and 1091.
- Around line 340-349: Remove the unused _put_json and _patch methods from the
MLflow client class, including their URL construction, HTTP calls, and response
handling, while leaving the remaining client methods unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 960a0af3-9a90-4cd3-aee2-d2ec0efa6f95
📒 Files selected for processing (2)
src/evalhub/adapter/mlflow.pytests/unit/test_mlflow_traces.py
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/unit/test_mlflow_traces.py
| root_inputs = {} | ||
| root_outputs = {} | ||
| for span in spans: | ||
| if not span.get("parent_span_id"): | ||
| attrs = span.get("attributes", {}) | ||
| ri = attrs.get("mlflow.spanInputs", "{}") | ||
| ro = attrs.get("mlflow.spanOutputs", "{}") | ||
| root_inputs = ri if isinstance(ri, str) else json.dumps(ri, default=str) | ||
| root_outputs = ro if isinstance(ro, str) else json.dumps(ro, default=str) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Missing and conflicting type annotations break mypy strict mode. The new code assigns empty collections without annotations, and root_inputs/root_outputs start as dict and are reassigned to str. mypy strict reports Need type annotation and Incompatible types in assignment for these sites, and root_inputs[:100] at Line 1040 is invalid for a dict.
src/evalhub/adapter/mlflow.py#L1007-L1015: declareroot_inputs: str = "{}"androot_outputs: str = "{}", so the JSON string type is consistent and the slicing at Line 1040-1041 type-checks.src/evalhub/adapter/mlflow.py#L959-L959: annotateproto_spans: list[trace_pb2.Span] = [].src/evalhub/adapter/mlflow.py#L1098-L1098: annotatespan_dicts: list[dict[str, Any]] = [].
As per coding guidelines "Pass mypy strict-mode type checking, targeting Python 3.11".
🧰 Tools
🪛 ast-grep (0.45.0)
[info] 1013-1013: use jsonify instead of json.dumps for JSON output
Context: json.dumps(ri, default=str)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
[info] 1014-1014: use jsonify instead of json.dumps for JSON output
Context: json.dumps(ro, default=str)
Note: [CWE-116] Improper Encoding or Escaping of Output.
(use-jsonify)
📍 Affects 1 file
src/evalhub/adapter/mlflow.py#L1007-L1015(this comment)src/evalhub/adapter/mlflow.py#L959-L959src/evalhub/adapter/mlflow.py#L1098-L1098
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/evalhub/adapter/mlflow.py` around lines 1007 - 1015, Update
src/evalhub/adapter/mlflow.py at lines 1007-1015 to declare root_inputs and
root_outputs as str initialized to "{}"; annotate proto_spans at lines 959-959
as list[trace_pb2.Span] and span_dicts at lines 1098-1098 as list[dict[str,
Any]], ensuring the surrounding MLflow span-processing code passes mypy strict
mode and supports string slicing.
Source: Coding guidelines
e880a37 to
5f6a847
Compare
|
@suppathak can you run |
|
@julpayne, apologies for the delayed update. I've run pre-commit run --all-files and pushed the fixes — mostly formatting (ruff-format) and added type: ignore for the opentelemetry protobuf imports that lack stubs. Also updated two artifact path tests to match the workspace-preserving behavior. The only remaining mypy error is a pre-existing one in cli/formatter.py (unrelated to this PR). |
| f"{_ARTIFACTS_API}/{experiment_id}/{run_id}/artifacts/{artifact_path}" | ||
| ) | ||
| workspace = os.environ.get("MLFLOW_WORKSPACE", "default") | ||
| return f"{_ARTIFACTS_API}/workspaces/{workspace}/{experiment_id}/{run_id}/artifacts/{artifact_path}" |
There was a problem hiding this comment.
@suppathak this unconditionally adds workspaces/default/ even when the workspace is not defined. Should we have a fallback for when it's not defined? wdyt?
Other Improvements NeededBeyond that last comment, there are several other issues in this PR worth addressing:
Summary: ruivieira's last comment is valid and should be addressed before merging. The workspace prefix issue (#1 above) is the most critical outstanding item. Items #2-3 are worth fixing in this PR; items #4-7 are nice-to-haves that could be deferred. |
|
@suppathak could you please rebase, fix the failing checks and look at the other proposed enhancements? Sorry to be so picky... |
…spans
- Add _API_V3 = "/api/3.0/mlflow" constant and _get_v3() on MlflowClient
- Update TracesNamespace.get() to call GET /api/3.0/mlflow/traces/get?trace_id=...
(previously used /api/2.0/mlflow/traces/{id}/info which returns only metadata)
- Update materialize() to call get() per trace so each written file includes
full span data instead of an empty data: {} dict
…elds MLflow v3 returns span attributes as protobuf-wrapped key-value pairs. Downstream consumers like CLEAR expect top-level inputs, outputs, and span_type fields. Add unwrap and normalize helpers in _parse_trace().
…reate()
- _artifact_server_path: keep workspaces/{name}/ prefix when present in
artifact_uri (required when bypassing the EvalHub sidecar on OpenShift AI)
- Add _post_v3, _put_json, _patch HTTP helpers for v3/v2 API calls
- TracesNamespace.create(): upload spans via OTLP protobuf + register
trace metadata via v3 API (mirrors official MLflow SDK behavior)
- TracesNamespace.upload_trace_file(): convenience method for uploading
trace JSON files exported from MLflow UI or materialize()
- Add debug logging to _put_artifact for troubleshooting
6296421 to
766a643
Compare
What and why
Minor follow-up to #144 . After the 3.x compatibility update,
get()still calledGET /api/2.0/mlflow/traces/{id}/infowhich returns only trace metadata — no span data. As a result,materialize()produced files with"data": {}— empty spans — causing downstream consumers (e.g. the CLEAR adapter) to see zero LLM calls and skip all traces.Verified against a local MLflow 3.13.0 server end-to-end.
Type
Changes
_API_V3 = "/api/3.0/mlflow"constant_get_v3()onMlflowClientusing the 3.x base pathTracesNamespace.get()to callGET /api/3.0/mlflow/traces/get?trace_id=...— this endpoint returns the full trace with spansmaterialize()to callget()per trace so each written.jsonfile includesdata.spansTesting
materialize()now writes files with spans includedBreaking changes
None —
get()signature is unchanged, behavior is now correct.Summary by CodeRabbit