Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
146 commits
Select commit Hold shift + click to select a range
79191dd
Update `uv.lock` (#22556)
mlflow-app[bot] Apr 13, 2026
e71cefc
Forward client telemetry to Databricks (#22295)
smoorjani Apr 14, 2026
6aae050
Enhance Gateway quick start cards with logos, multi-model options, an…
xq-yin Apr 14, 2026
b1e37b4
Add click-to-expand modal for trace attachment images (#22461)
kriscon-db Apr 14, 2026
4dedf9d
Fix `ui-preview.yml` Databricks auth flakiness by forcing `oauth-m2m`…
Copilot Apr 14, 2026
0236f4c
Update lints in preparation for UI sync (#22567)
daniellok-db Apr 14, 2026
75c5f50
Move sql store tests to the same folder (#22565)
serena-ruan Apr 14, 2026
dae6099
Fast-path trace-id search in frontend to avoid `spans.content` scan (…
harupy Apr 14, 2026
369da3c
Add GuardrailDetailModal for viewing and editing guardrail configs (#…
TomeHirata Apr 14, 2026
511def9
Add Guardrails tab to endpoint editor (#22360)
TomeHirata Apr 14, 2026
f9fb2c6
Implement guardrail execution in gateway API handlers (#22306)
TomeHirata Apr 14, 2026
64afe4b
Remove `docs/docs/genai/governance/ai-gateway/legacy/*` and redirect …
Copilot Apr 14, 2026
ab13be1
Move `.claude/statusline.sh` to `.claude/scripts/statusline.sh` (#22578)
Copilot Apr 14, 2026
d1618c4
#21037 Add presigned upload URL endpoint for S3 artifact uploads (#21…
henishborad Apr 14, 2026
cc9009f
Add rendering size guards for large media content (#22574)
kriscon-db Apr 14, 2026
31c4867
Add `sqlstate`/`error_class` to `MlflowException` for error classific…
kriscon-db Apr 15, 2026
ccea6a4
Deprecate `mlflow gateway start` CLI command (#22580)
Copilot Apr 15, 2026
04afc14
Add `gateway_create_model_definition` telemetry with `model_name` and…
Copilot Apr 15, 2026
ca5a75b
Update `uv.lock` (#22613)
mlflow-app[bot] Apr 16, 2026
7ff7345
Refactor guardrails table: bulk selection, DS Table components, click…
TomeHirata Apr 16, 2026
9bdafa7
Add `TraceAttachmentsEvent` telemetry for multimodal trace attachment…
kriscon-db Apr 17, 2026
c429371
Fix checkbox/expand toggle hitbox overlap in session grouped row head…
daniellok-db Apr 17, 2026
9646b31
Unify execution duration cell rendering in session header rows (#22631)
daniellok-db Apr 17, 2026
0a94c6f
Add MLflow tracing spans to guardrail execution in gateway (#22581)
TomeHirata Apr 17, 2026
60eb8ef
fix(r): install `pak` from pre-built binary distribution before `devt…
Copilot Apr 18, 2026
ad9616e
Fix anthropic autolog tests for SDK v0.88.0 `stop_details` field (#22…
Copilot Apr 18, 2026
8ad2557
Bump Claude Code CLI to `2.1.98` in `install-claude.sh` (#22655)
Copilot Apr 18, 2026
7e39fa4
Rename `maintainer-approval.yml` and `require-core-maintainer-approva…
Copilot Apr 18, 2026
a8a2dcd
Inline `Popen` args and use `sys.executable -m mlflow` in `tests/test…
Copilot Apr 18, 2026
adb420f
Allow `mlflow-app[bot]` approval to satisfy maintainer-approval check…
Copilot Apr 18, 2026
28e4bbf
Fix pydantic-ai `run_stream_sync` autologging broken by `AgentSpec` f…
Copilot Apr 18, 2026
a0baf64
Fix `cast_df_types_according_to_schema` StringDtype downgrade for `Te…
Copilot Apr 18, 2026
767b663
perf: cache `SymbolIndex` per worker in `clint` via `ProcessPoolExecu…
Copilot Apr 18, 2026
3ea7107
Consolidate comment tokenization in `clint` to a single pass per file…
Copilot Apr 18, 2026
2c1810f
Skip Python tokenization in `clint` when no suppression markers are p…
Copilot Apr 18, 2026
c23ff16
Bump `urlopen_with_retry` `max_retries` from 5 to 7 in `bin/install.p…
Copilot Apr 19, 2026
ccfe1e9
Fix `docs / r` CI failure due to missing `libuv.so.1` in R Docker ima…
Copilot Apr 19, 2026
368b9b7
Pin `langgraph-prebuilt<1.0.9` for `langchain==1.0.*` and `langgraph<…
Copilot Apr 19, 2026
bd3a18f
Skip `dev/js.sh` on CI (#22688)
Copilot Apr 19, 2026
1b4fdd1
Eliminate `tiktoken` from `analyze-ci` skill (#22689)
Copilot Apr 19, 2026
23d4d75
Cache `.mypy_cache` in `lint.yml` workflow (#22690)
Copilot Apr 19, 2026
cfb7d24
Simplify and speed up `typos` pre-commit hook (#22686)
Copilot Apr 19, 2026
1046e18
Broaden `langgraph-prebuilt<1.0.9` pin to cover `langchain < 1.2` (#2…
Copilot Apr 19, 2026
6f8639a
Add `noIndex` to versioned doc builds for SEO (#22508)
daniellok-db Apr 20, 2026
e9f9a57
Vendor design system changes (#22691)
daniellok-db Apr 20, 2026
a0e9c53
Update `uv.lock` (#22695)
mlflow-app[bot] Apr 20, 2026
a1d1c4a
Update model catalog from upstream sources (#22694)
mlflow-app[bot] Apr 20, 2026
f73f338
Add modality/tool pricing extraction to `dev/update_model_catalog.py`…
Copilot Apr 20, 2026
3af5d86
Allow different PGPORT in docker compose (#22646)
riklopfer Apr 20, 2026
73045d5
Extract `service.name` from OTLP resource attributes for usage teleme…
kriscon-db Apr 20, 2026
d380537
Use `usage_tracking` flag in `maybe_traced_gateway_call` and `_create…
Copilot Apr 20, 2026
fcef717
Use SQL `MAX()` in `create_model_version` instead of loading all rows…
neolunar7 Apr 20, 2026
5783110
Auto-select first endpoint and API key in issue detection modal (#22633)
serena-ruan Apr 20, 2026
00d7cb8
Add `logEventWithMetadata_I_CONFIRM_THERE_IS_NO_PII` to `TelemetryCli…
PattaraS Apr 20, 2026
e0647fe
fix: Extract `cached_tokens` in OpenAI streaming responses to correct…
Rishabh-git10 Apr 20, 2026
880c05e
Preserve `predict_fn` signature in simulation turn tracing (#22610)
rogalski Apr 20, 2026
496308a
docs: add guardrails documentation for AI Gateway (#22577)
TomeHirata Apr 20, 2026
268ffd9
Fix AI Gateway provider dropdown by flattening OpenAI / Azure OpenAI …
harupy Apr 20, 2026
0f8c5f0
Fix Bedrock tool-use chat response parsing (#22677)
lavaFreak Apr 20, 2026
9003576
Add JSON OTLP encoding support for trace ingestion (#22408)
kriscon-db Apr 20, 2026
d8278a4
Encode attachment size in `mlflow-attachment://` URI (#22614)
kriscon-db Apr 20, 2026
b554059
Add `GeminiCliTranslator` for Gemini CLI OTLP span type mapping (#22409)
kriscon-db Apr 20, 2026
53e36ec
Force-update `model-catalog/latest` git tag in `update-model-catalog`…
Copilot Apr 20, 2026
e807ffb
Add size limit for trace attachments (#22575)
kriscon-db Apr 20, 2026
4489ef2
Fix conversation simulator adding wrapper span that breaks custom sco…
B-Step62 Apr 20, 2026
6318d02
Fix `model-catalog/latest` tag to point at master HEAD (#22707)
Copilot Apr 20, 2026
f6b0891
Fix pandas 3.x `datetime64` resolution compatibility in `cast_df_type…
Copilot Apr 20, 2026
9d4aad7
Support `PYPI_URL` env var for PyPI proxy in dev scripts (#22708)
harupy Apr 20, 2026
4a6c783
Fix branch name collision in `update-model-catalog` workflow on same-…
Copilot Apr 20, 2026
b65ea7a
Add `mlflow.diffusers` flavor for diffusion model LoRA adapters (#22253)
Rasaboun Apr 20, 2026
7b4e1d1
Skip already-labeled `duplicate` PRs in `duplicate-prs.js` (#22711)
Copilot Apr 20, 2026
4cdf424
Fix CrewAI autolog test failures on `crewai>=1.13.0` (#22713)
Copilot Apr 20, 2026
c094176
Add `enable-uv-cache` input to `setup-python` composite action (#22714)
Copilot Apr 20, 2026
c3c4799
Disable uv cache and pin-micro-version in `review.yml` (#22718)
Copilot Apr 20, 2026
989ee3d
Add Share button to trace detail view (#22608)
alkispoly-db Apr 20, 2026
f5e00ae
Fix `R / r` CI: install `libuv1-dev` in `Dockerfile.r-devel` (#22715)
Copilot Apr 21, 2026
f2e3d9f
MLflow UI Sync (#22697)
daniellok-db Apr 21, 2026
3b5f49f
Fix non-ASCII characters being escaped in judge template variables (#…
harupy Apr 21, 2026
e9bb2f0
Add TypeScript Codex CLI tracing via `notify` hook (#22410)
kriscon-db Apr 21, 2026
f90c746
Restyle share button in trace modal (#22735)
daniellok-db Apr 21, 2026
fcb49c6
Bump demo generator versions and always refresh in ui-preview app (#2…
kriscon-db Apr 21, 2026
d2bf628
Compact `/review` comment format: single `---` rule, in-place status …
Copilot Apr 21, 2026
bc35e7f
Fix JSON parsing failure for judge model responses containing newline…
harupy Apr 21, 2026
f7b8d4a
Clarify full text search availability in search traces docs (#22627)
xsh310 Apr 21, 2026
cd4be31
Exclude `mlflow/assistant/skills` submodule from typos checker (#22744)
Copilot Apr 21, 2026
aa3f3c2
Fix `AsyncHttpxClientWrapper` `AttributeError` by avoiding `deepcopy`…
harupy Apr 21, 2026
63be07c
Disable Create button when experiment name is empty (#22649)
ssam18 Apr 21, 2026
7db8090
Hide `_issue_discovery_judge` from experiment overview Quality tab (#…
serena-ruan Apr 21, 2026
a04545a
Update multimodal tracing docs with bug fix improvements (#22629)
kriscon-db Apr 21, 2026
60103f7
Update ML package versions (#22749)
harupy Apr 21, 2026
720352c
Fix incorrect cost calculation for Anthropic cached requests (#22516)
ajgassner Apr 21, 2026
2cbec19
Reorganize Settings into section-based routing with sub-sidebar navig…
serena-ruan Apr 21, 2026
2e092bd
[3/3/] Trace table tooltip (#21482)
B-Step62 Apr 21, 2026
74517ea
Add Bedrock Converse models to model catalog (#22515)
ajgassner Apr 21, 2026
b621562
Fix `ValueError: Circular reference detected` crash in `dump_span_att…
barry3406 Apr 21, 2026
12bbb16
Fix Vertex AI gateway `global` location handling for Gemini 3 models …
harupy Apr 21, 2026
4a3d513
Refetch traces on grouping toggle to fill viewport (#22632)
daniellok-db Apr 21, 2026
9cce7d3
Flip pagination flag (#22447)
daniellok-db Apr 21, 2026
d851fb5
Skip redundant `json.loads` pass in `Span.to_dict()` (#22755)
Copilot Apr 21, 2026
ec6f1da
Persist immediate gateway usage-tracking updates and preserve dirty e…
Copilot Apr 21, 2026
ed336a7
Use `cached_property` for `Span.trace_id` (#22756)
Copilot Apr 21, 2026
53e3f71
Fix `EvaluationDataset` type references in GenAI datasets docs (#22761)
harupy Apr 22, 2026
a2b7c32
Pin `arize-phoenix-evals<3.0.0` to unblock GenAI CI (#22762)
harupy Apr 22, 2026
076c047
Fix ABFSS URI double-encoding in `_parse_abfss_uri` (#22759)
artjen Apr 22, 2026
a9c5616
Add Application Default Credentials auth mode for Vertex AI gateway (…
harupy Apr 22, 2026
eb9c091
Gate PR auto-approval on author role (#22765)
harupy Apr 22, 2026
7bb5c74
Replace `_CachedSpanAttributesRegistry.get` `lru_cache` with per-inst…
Copilot Apr 22, 2026
bfb8ae2
Add `componentId` registry and CI consistency check (#22558)
PattaraS Apr 22, 2026
c559f5d
Fix OPENAI_API_KEY requirement when guardrails use gateway:/ judge mo…
TomeHirata Apr 22, 2026
4f303d6
Replace `@lru_cache` with `@cached_property` on `ScorerVersion.serial…
Copilot Apr 22, 2026
8542e02
[UI Consistency] Replace gateway hover tooltips with `InfoTooltip` (#…
Copilot Apr 22, 2026
bba0029
Disable `Guardrails` tab in `EditEndpointFormRenderer` when `endpoint…
Copilot Apr 22, 2026
c8232dd
Rename guardrail stage terminology to `Pre-LLM` / `Post-LLM` across `…
Copilot Apr 22, 2026
f48286e
Clarify yes/no semantics and stage picker wording in guardrail modal …
TomeHirata Apr 22, 2026
2134988
Disable `Create Guardrail` in `AddGuardrailModal` until a `Guardrail …
Copilot Apr 22, 2026
91e4210
Add `--frozen` flag to `uv run` in `.pre-commit-config.yaml` (#22782)
Copilot Apr 22, 2026
6624f69
Add RBAC data model, migration, and store CRUD (#22721)
PattaraS Apr 22, 2026
068d106
Migrate `setup_storage` fixture in optuna tests from FileStore to SQL…
Copilot Apr 22, 2026
be6151c
Migrate tests from `FileStore` to SQLite (`db_uri` fixture) (#22787)
Copilot Apr 22, 2026
1d386fe
Add aggregate_anthropic_messages_stream_chunks for streaming trace ou…
TomeHirata Apr 22, 2026
d8ec1c2
Collapse `delete_trace_tag` two-query pattern into a single DELETE (#…
Copilot Apr 22, 2026
d01b61f
Docs: Adds Middleware in the tracing section for integrated observabi…
luharshekhar2000-dot Apr 22, 2026
9a3c118
Add `--auth` flag to gateway benchmark for measuring basic-auth overh…
PattaraS Apr 23, 2026
977df90
Update `uv.lock` (#22812)
mlflow-app[bot] Apr 23, 2026
085a180
Fix flaky `OptimizeModal` close button test (#22815)
harupy Apr 23, 2026
13e2bda
Remove rendering size guards from artifact image and video views (#22…
kriscon-db Apr 23, 2026
fccbca5
Support `model_kwargs` in DeepEval scorers for LLM parameter control …
debu-sinha Apr 23, 2026
455aff7
Add aggregate_openai_responses_stream_chunks for streaming trace outp…
TomeHirata Apr 23, 2026
8cc6ab9
Fix `_get_token_usage` dropping cache token fields (#22818)
harupy Apr 23, 2026
d622460
Stabilize `test_search_traces_yields_expected_dataframe_contents` tim…
Copilot Apr 23, 2026
27b6dc4
Add TypeScript Qwen Code tracing via Stop hook (#22411)
kriscon-db Apr 23, 2026
e22f3fd
Update api key documentation to LLM connections (#22781)
serena-ruan Apr 23, 2026
87c2460
Fix `_get_token_usage` dropping zero-valued token counts (#22748)
Copilot Apr 23, 2026
3b58dd1
Fix sessions pagination not auto-loading after virtualizer settles (#…
daniellok-db Apr 23, 2026
e55aa68
[Trace UI Improvement][1/6] Condense chat messages (#22800)
daniellok-db Apr 23, 2026
e755fe6
Add aggregate_gemini_stream_generate_content_chunks for streaming tra…
TomeHirata Apr 23, 2026
1bd9e74
Migrate Claude Code tracing to TypeScript-based plugin for simpler in…
B-Step62 Apr 23, 2026
adf06b9
Propagate `workspace_id` as `X-Databricks-Org-Id` header for SPOG sup…
B-Step62 Apr 23, 2026
1094ec1
Add RBAC REST API, permission resolution integration, and client (#22…
PattaraS Apr 23, 2026
5742648
Auto-start SQL warehouse before V4/V5 MLflow tracing calls (#22798)
artjen Apr 23, 2026
7a6b0ae
Add job persistence schema for execution recovery (#22520)
mprahl Apr 13, 2026
5096ab7
Expose recovery job state through the API surface
mprahl Apr 10, 2026
a3a12a5
Address feedback
mprahl Apr 22, 2026
aed80e5
Address feedback on job progress APIs
mprahl Apr 23, 2026
7b05a1f
Preserve omitted job progress helper fields
mprahl Apr 23, 2026
5ed8b88
Simplify job progress update semantics
mprahl Apr 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .claude/scripts/install-claude.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ if [ "${CI:-}" != "true" ]; then
exit 1
fi

VERSION="2.1.85"
CHECKSUM="ff0b23dba11c97a53386c61ebe47d46d768a8ad33f98c7d22186c9a63f179f4d"
VERSION="2.1.98"
CHECKSUM="d40827b5aa8d737a7eb68e3aad990b80e2521540a6bc8a405259b63b25d42ed8"
GCS_BUCKET="https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases"
PLATFORM="linux-x64"

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"statusLine": {
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/statusline.sh"
"command": "$CLAUDE_PROJECT_DIR/.claude/scripts/statusline.sh"
},
"hooks": {
"PreToolUse": [
Expand Down
13 changes: 11 additions & 2 deletions .claude/skills/pr-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,17 @@ For each issue found, use the `add-review-comment` skill to post review comments

### 6. Approve the PR

Approve the PR when there are no issues or only minor issues.
Approve the PR when there are no issues or only minor issues, but **only if the PR author has the `admin` or `maintain` role**.

First, check the PR author's role:

```bash
gh pr review <PR_NUMBER> --repo <owner/repo> --approve
author=$(gh api repos/<owner>/<repo>/pulls/<PR_NUMBER> --jq '.user.login')
gh api repos/<owner>/<repo>/collaborators/"$author"/permission --jq '.role_name'
```

- If the role is `admin` or `maintain` -> approve the PR:
```bash
gh pr review <PR_NUMBER> --repo <owner/repo> --approve
```
- Otherwise (including API errors, e.g., 404 for non-collaborators) -> do NOT approve. Do not mention the reason for not approving in the review.
8 changes: 1 addition & 7 deletions .claude/skills/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,7 @@
name = "skills"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
"aiohttp",
"claude-agent-sdk",
"pydantic",
"tiktoken",
"typing_extensions",
]
dependencies = ["aiohttp", "claude-agent-sdk", "pydantic", "typing_extensions"]

[project.scripts]
skills = "skills.cli:main"
16 changes: 6 additions & 10 deletions .claude/skills/src/skills/commands/analyze_ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
from dataclasses import dataclass
from typing import Any

import tiktoken
from claude_agent_sdk import (
AssistantMessage,
ClaudeAgentOptions,
Expand All @@ -26,6 +25,7 @@
from skills.github import GitHubClient, Job, JobStep, get_github_token

MAX_LOG_TOKENS = 100_000
CHARS_PER_TOKEN = 2


@dataclass
Expand Down Expand Up @@ -111,21 +111,17 @@ async def compact_logs(lines: AsyncIterator[str]) -> str:
result.append(line)

logs = "\n".join(result)
tokens = tiktoken.get_encoding("p50k_base").encode(logs)
log(f"Compacted logs: {len(tokens):,} tokens")
log(f"Compacted logs: {len(logs) // CHARS_PER_TOKEN:,} tokens")
return logs


def truncate_logs(logs: str, max_tokens: int = MAX_LOG_TOKENS) -> str:
"""Truncate logs to fit within token limit, keeping the end (where errors are)."""
# Note: tiktoken token count is an estimation and may differ slightly from
# the official token count API
tokenizer = tiktoken.get_encoding("p50k_base")
tokens = tokenizer.encode(logs)
if len(tokens) <= max_tokens:
estimated_tokens = len(logs) // CHARS_PER_TOKEN
if estimated_tokens <= max_tokens:
return logs
log(f"Truncating logs from {len(tokens):,} to {max_tokens:,} tokens")
truncated = tokenizer.decode(tokens[-max_tokens:])
log(f"Truncating logs from {estimated_tokens:,} to {max_tokens:,} tokens")
truncated = logs[-(max_tokens * CHARS_PER_TOKEN) :]
return f"(showing last {max_tokens:,} tokens)\n{truncated}"


Expand Down
10 changes: 10 additions & 0 deletions .github/actions/check-component-ids/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: "check-component-ids"
description: "Verify that all componentIds in the MLflow UI are registered in the componentId registry and vice versa."
runs:
using: "composite"
steps:
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 20
- run: node ${GITHUB_ACTION_PATH}/index.js
shell: bash
1,999 changes: 1,999 additions & 0 deletions .github/actions/check-component-ids/componentId-registry.js

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions .github/actions/check-component-ids/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { extractComponentIdsFromSource } = require("./utils");

const registry = require("./componentId-registry");

// --- Main ---
const codeIds = extractComponentIdsFromSource(__dirname);
const registryKeys = new Set(Object.keys(registry));

// Check 1: componentIds in code but not in registry
const unregistered = [...codeIds].filter((id) => !registryKeys.has(id)).sort();

// Check 2: componentIds in registry but not in code (stale)
const stale = [...registryKeys].filter((id) => !codeIds.has(id)).sort();

let failed = false;

if (unregistered.length > 0) {
failed = true;
console.error(
`\n❌ Found ${unregistered.length} componentId(s) in code but NOT in the registry:\n`
);
for (const id of unregistered) {
console.error(` + ${id}`);
}
console.error("\nAdd these to .github/actions/check-component-ids/componentId-registry.js");
}

if (stale.length > 0) {
failed = true;
console.error(`\n❌ Found ${stale.length} stale componentId(s) in registry but NOT in code:\n`);
for (const id of stale) {
console.error(` - ${id}`);
}
console.error("\nRemove these from .github/actions/check-component-ids/componentId-registry.js");
}

if (failed) {
process.exit(1);
} else {
console.log(`✅ componentId registry is in sync. ${registryKeys.size} entries verified.`);
}
70 changes: 70 additions & 0 deletions .github/actions/check-component-ids/regenerate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env node

/**
* Regenerates the componentId registry from source code.
*
* Usage (from repo root):
* node .github/actions/check-component-ids/regenerate.js
*/

const fs = require("fs");
const path = require("path");
const { extractComponentIdsFromSource } = require("./utils");

const codeIds = extractComponentIdsFromSource(__dirname);
const sorted = [...codeIds].sort();

// Group by prefix for readability
const groups = {};
for (const id of sorted) {
let prefix;
if (id.startsWith("codegen_")) {
prefix = "Codegen (auto-generated)";
} else if (id.startsWith("mlflow.")) {
const parts = id.split(".");
prefix = parts[0] + "." + parts[1];
} else if (id.startsWith("shared.")) {
const parts = id.split(".");
prefix = parts[0] + "." + parts[1];
} else {
prefix = "Other";
}
if (!groups[prefix]) groups[prefix] = [];
groups[prefix].push(id);
}

// Load existing registry to preserve descriptions
let existingDescriptions = {};
try {
existingDescriptions = require("./componentId-registry");
} catch {
// First run or broken registry — start fresh
}

let output = `/**
* Curated registry of all componentIds used in the MLflow UI.
*
* Every static componentId string literal in non-test source files must
* have an entry here. The CI job \`check-component-ids\` verifies this
* bidirectionally: code IDs must be in the registry, and registry
* entries must exist in code.
*
* Format: key = componentId string, value = optional description of the
* component (blank by default, especially for generated entries)
*/
module.exports = {\n`;

for (const gk of Object.keys(groups).sort()) {
output += ` // -- ${gk} --\n`;
for (const id of groups[gk]) {
const escaped = id.replace(/"/g, '\\"');
const desc = (existingDescriptions[id] || "").replace(/"/g, '\\"');
output += ` "${escaped}": "${desc}",\n`;
}
output += "\n";
}
output += "};\n";

const outPath = path.join(__dirname, "componentId-registry.js");
fs.writeFileSync(outPath, output);
console.log(`✅ Registry regenerated with ${sorted.length} entries at ${outPath}`);
66 changes: 66 additions & 0 deletions .github/actions/check-component-ids/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const fs = require("fs");
const path = require("path");

const EXTENSIONS = [".js", ".jsx", ".ts", ".tsx"];
// Skip test files — they don't need registered componentIds
const TEST_PATTERN = /\.test\.[jt]sx?$/;

const EXTRACT_PATTERNS = [
/(?:componentId|data-component-id)=["']([^"']+)["']/g,
/componentId:\s*["']([^"']+)["']/g,
// Match static strings inside JSX expressions like componentId={"value"},
// componentId={cond ?? "fallback"}, componentId={cond ? "a" : "b"}, etc.
// Uses [^\n}]* to avoid matching across lines.
/componentId=\{[^\n}]*["']([^"'\n`]+)["'][^\n}]*\}/g,
];

function findFiles(dir) {
const results = [];
function walk(d) {
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
const full = path.join(d, entry.name);
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
walk(full);
} else if (
entry.isFile() &&
EXTENSIONS.some((ext) => full.endsWith(ext)) &&
!TEST_PATTERN.test(full)
) {
results.push(full);
}
}
}
walk(dir);
return results;
}

function extractComponentIds(files) {
const ids = new Set();
for (const file of files) {
const content = fs.readFileSync(file, "utf8");
for (const pat of EXTRACT_PATTERNS) {
pat.lastIndex = 0;
let m;
while ((m = pat.exec(content)) !== null) {
ids.add(m[1]);
}
}
}
return ids;
}

/**
* Extract all static componentIds from the MLflow UI source directory.
* @param {string} actionDir - path to this action's directory (used to resolve the repo root)
* @returns {Set<string>} set of componentId strings found in source
*/
function extractComponentIdsFromSource(actionDir) {
const srcDir = path.resolve(
process.env.GITHUB_WORKSPACE || path.join(actionDir, "../../.."),
"mlflow/server/js/src"
);
const files = findFiles(srcDir);
return extractComponentIds(files);
}

module.exports = { extractComponentIdsFromSource };
5 changes: 5 additions & 0 deletions .github/actions/setup-python/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ inputs:
description: "Whether to pin to a specific micro version for Anaconda compatibility. Set to false for workflows that don't need conda/pyenv to hit the runner's pre-installed Python cache and avoid a ~9s download."
required: false
default: "true"
enable-uv-cache:
description: "Enable uv's built-in cache. Set to false for short jobs where cache restore/save overhead isn't worth it."
required: false
default: "true"
outputs:
python-version:
description: "The installed python version"
Expand Down Expand Up @@ -52,6 +56,7 @@ runs:
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
version: "0.10.12"
enable-cache: ${{ inputs.enable-uv-cache }}
- run: |
# The default `first-index` strategy is too strict. Use `unsafe-first-match` instead.
# https://docs.astral.sh/uv/configuration/environment/#uv_index_strategy
Expand Down
6 changes: 4 additions & 2 deletions .github/ui-preview/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ def setup():
_logger.info("Extracting UI assets to %s", target_dir)
subprocess.check_call(["tar", "xzf", tar_path, "-C", target_dir])

# Generate demo data
# Generate demo data. Always refresh so the preview app reflects the latest
# demo content (e.g. new trace types) even if the SQLite database persisted
# from a previous deploy with stale demo data.
os.environ["MLFLOW_TRACKING_URI"] = "sqlite:///mlflow.db"
_logger.info("Generating demo data...")
generate_all_demos()
generate_all_demos(refresh=True)
_logger.info("Demo data generated.")


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ module.exports = async ({ github, context, core }) => {
pull_number: context.issue.number,
});
const maintainerApproved = reviews.some(
({ state, user: { login } }) => state === "APPROVED" && maintainers.includes(login)
({ state, user }) =>
state === "APPROVED" &&
(maintainers.includes(user.login) ||
(user.type.toLowerCase() === "bot" && user.login === "mlflow-app[bot]"))
);

const { pull_request: pr } = context.payload;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Maintainer approval
name: Approval

on:
pull_request_target:
Expand All @@ -24,5 +24,5 @@ jobs:
with:
retries: 3
script: |
const script = require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/require-core-maintainer-approval.js`);
const script = require(`${process.env.GITHUB_WORKSPACE}/.github/workflows/approval.js`);
await script({ context, github, core });
3 changes: 3 additions & 0 deletions .github/workflows/cross-version-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ jobs:
ref: ${{ github.event.inputs.ref }}
- uses: ./.github/actions/untracked
- uses: ./.github/actions/setup-python
with:
pin-micro-version: false
enable-uv-cache: false
- name: Install dependencies
run: |
uv pip install --system -r dev/requirements.txt
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/duplicate-prs.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const QUERY = `
url
author { login }
authorAssociation
labels(first: 20) { nodes { name } }
closingIssuesReferences(first: 10) {
nodes {
number
Expand All @@ -42,6 +43,9 @@ const shouldProcessPR = (pr) => {
if (memberAssociations.includes(pr.authorAssociation)) {
return false;
}
// Skip PRs already labeled as duplicate
const labels = pr.labels?.nodes?.map((l) => l.name) ?? [];
if (labels.includes(DUPLICATE_LABEL)) return false;
return true;
};

Expand Down
Loading
Loading