Apply user agent result filtering feedback

This commit is contained in:
2026-07-01 00:55:48 +08:00
parent 1d43efd5b4
commit 1e8339e237
4 changed files with 39 additions and 7 deletions

View File

@@ -74,6 +74,8 @@ def evaluate_project() -> dict:
and "resultRoleFilter" in frontend_text and "resultRoleFilter" in frontend_text
and "familyOptions" in frontend_text and "familyOptions" in frontend_text
and "roleOptions" in frontend_text and "roleOptions" in frontend_text
and "resultQuery" in frontend_text
and "Run / Path" in frontend_text
and "/api/results?limit=1000" in frontend_text and "/api/results?limit=1000" in frontend_text
and "setResults(resultsNext)" in frontend_text and "setResults(resultsNext)" in frontend_text
and "slice(0, 240)" not in frontend_text, and "slice(0, 240)" not in frontend_text,
@@ -143,6 +145,7 @@ def evaluate_project() -> dict:
"agent_panel_ui": "runAgentValidation" in frontend_text and "评价建议" in frontend_text and "Validation Agent" in frontend_text, "agent_panel_ui": "runAgentValidation" in frontend_text and "评价建议" in frontend_text and "Validation Agent" in frontend_text,
"user_agent_api": "/api/agents/user" in backend_text and "run_user_agent" in backend_text, "user_agent_api": "/api/agents/user" in backend_text and "run_user_agent" in backend_text,
"user_agent_ui": "runUserAgent" in frontend_text and "使用者模拟" in frontend_text and "User Agent" in frontend_text, "user_agent_ui": "runUserAgent" in frontend_text and "使用者模拟" in frontend_text and "User Agent" in frontend_text,
"user_agent_suggestion_applied": "resultQuery" in frontend_text and "run id, filename, path" in frontend_text,
"coverage_api": "/api/coverage" in backend_text and coverage["task_build_passed"], "coverage_api": "/api/coverage" in backend_text and coverage["task_build_passed"],
"visual_tools": "visual.yolo11_heatmap_v2" in catalog["task_types"] and "visual.fps" in catalog["task_types"], "visual_tools": "visual.yolo11_heatmap_v2" in catalog["task_types"] and "visual.fps" in catalog["task_types"],
"yolo_custom_train": "yolo.train_custom" in catalog["task_types"], "yolo_custom_train": "yolo.train_custom" in catalog["task_types"],

View File

@@ -18,6 +18,7 @@ def test_evaluation_agent_returns_checks():
assert checks["dataset_preparation_doc"] is True assert checks["dataset_preparation_doc"] is True
assert checks["user_agent_api"] is True assert checks["user_agent_api"] is True
assert checks["user_agent_ui"] is True assert checks["user_agent_ui"] is True
assert checks["user_agent_suggestion_applied"] is True
def test_validation_agent_lightweight(monkeypatch): def test_validation_agent_lightweight(monkeypatch):

View File

@@ -544,6 +544,7 @@ function App() {
const [selectedCurvePath, setSelectedCurvePath] = useState(""); const [selectedCurvePath, setSelectedCurvePath] = useState("");
const [resultFamilyFilter, setResultFamilyFilter] = useState("all"); const [resultFamilyFilter, setResultFamilyFilter] = useState("all");
const [resultRoleFilter, setResultRoleFilter] = useState("all"); const [resultRoleFilter, setResultRoleFilter] = useState("all");
const [resultQuery, setResultQuery] = useState("");
const [selectedGpuIds, setSelectedGpuIds] = useState<number[]>([]); const [selectedGpuIds, setSelectedGpuIds] = useState<number[]>([]);
const [selectedCondaEnv, setSelectedCondaEnv] = useState("auto"); const [selectedCondaEnv, setSelectedCondaEnv] = useState("auto");
const [uploadKind, setUploadKind] = useState<"images" | "labels" | "masks">("images"); const [uploadKind, setUploadKind] = useState<"images" | "labels" | "masks">("images");
@@ -616,11 +617,18 @@ function App() {
const resultFamilyOptions = useMemo(() => ["all", ...Array.from(new Set(results.map((item) => item.family ?? "artifact"))).sort()], [results]); const resultFamilyOptions = useMemo(() => ["all", ...Array.from(new Set(results.map((item) => item.family ?? "artifact"))).sort()], [results]);
const resultRoleOptions = useMemo(() => ["all", ...Array.from(new Set(results.map((item) => item.role ?? "artifact"))).sort()], [results]); const resultRoleOptions = useMemo(() => ["all", ...Array.from(new Set(results.map((item) => item.role ?? "artifact"))).sort()], [results]);
const filteredResults = useMemo( const filteredResults = useMemo(
() => results.filter((item) => () => {
(resultFamilyFilter === "all" || (item.family ?? "artifact") === resultFamilyFilter) && const query = resultQuery.trim().toLowerCase();
(resultRoleFilter === "all" || (item.role ?? "artifact") === resultRoleFilter) return results.filter((item) => {
), const family = item.family ?? "artifact";
[resultFamilyFilter, resultRoleFilter, results] const role = item.role ?? "artifact";
const text = `${item.name} ${item.relative_path} ${family} ${role}`.toLowerCase();
return (resultFamilyFilter === "all" || family === resultFamilyFilter) &&
(resultRoleFilter === "all" || role === resultRoleFilter) &&
(!query || text.includes(query));
});
},
[resultFamilyFilter, resultQuery, resultRoleFilter, results]
); );
const modelWeightOptions = useMemo<ModelWeightOption[]>(() => { const modelWeightOptions = useMemo<ModelWeightOption[]>(() => {
const options = new Map<string, ModelWeightOption>(); const options = new Map<string, ModelWeightOption>();
@@ -1732,8 +1740,10 @@ function App() {
roleOptions={resultRoleOptions} roleOptions={resultRoleOptions}
familyFilter={resultFamilyFilter} familyFilter={resultFamilyFilter}
roleFilter={resultRoleFilter} roleFilter={resultRoleFilter}
query={resultQuery}
onFamilyFilter={setResultFamilyFilter} onFamilyFilter={setResultFamilyFilter}
onRoleFilter={setResultRoleFilter} onRoleFilter={setResultRoleFilter}
onQuery={setResultQuery}
/> />
</div> </div>
</section> </section>
@@ -1910,8 +1920,10 @@ function ResultBrowser({
roleOptions, roleOptions,
familyFilter, familyFilter,
roleFilter, roleFilter,
query,
onFamilyFilter, onFamilyFilter,
onRoleFilter onRoleFilter,
onQuery
}: { }: {
results: ResultItem[]; results: ResultItem[];
total: number; total: number;
@@ -1919,12 +1931,23 @@ function ResultBrowser({
roleOptions: string[]; roleOptions: string[];
familyFilter: string; familyFilter: string;
roleFilter: string; roleFilter: string;
query: string;
onFamilyFilter: (value: string) => void; onFamilyFilter: (value: string) => void;
onRoleFilter: (value: string) => void; onRoleFilter: (value: string) => void;
onQuery: (value: string) => void;
}) { }) {
return ( return (
<div className="resultBrowser"> <div className="resultBrowser">
<div className="resultFilters"> <div className="resultFilters">
<label className="wide">
<span>Run / Path</span>
<input
value={query}
onChange={(event) => onQuery(event.target.value)}
placeholder="run id, filename, path"
aria-label="result run or path"
/>
</label>
<label> <label>
<span>Family</span> <span>Family</span>
<select value={familyFilter} onChange={(event) => onFamilyFilter(event.target.value)} aria-label="result family"> <select value={familyFilter} onChange={(event) => onFamilyFilter(event.target.value)} aria-label="result family">

View File

@@ -1318,6 +1318,10 @@ textarea {
gap: 8px; gap: 8px;
} }
.resultFilters .wide {
grid-column: 1 / -1;
}
.resultFilters label { .resultFilters label {
min-width: 0; min-width: 0;
display: grid; display: grid;
@@ -1329,7 +1333,8 @@ textarea {
font-size: 11px; font-size: 11px;
} }
.resultFilters select { .resultFilters select,
.resultFilters input {
width: 100%; width: 100%;
height: 36px; height: 36px;
padding: 0 9px; padding: 0 9px;