Skip to content

Commit 706e907

Browse files
authored
feat: sync server UI history traces from backend (#1386)
* feat: preload existing traces in server ui * feat: sync history traces from server and local storage * chore: remove server ui test file
1 parent 471eb30 commit 706e907

3 files changed

Lines changed: 92 additions & 35 deletions

File tree

rdagent/log/server/app.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,36 @@ def read_trace(log_path: Path, id: str = "") -> None:
275275
)
276276

277277

278-
# load all traces from the log folder
279-
# for p in log_folder_path.glob("*/*/"):
280-
# read_trace(p, id=str(p))
278+
def _collect_existing_trace_ids(trace_root: Path) -> list[str]:
279+
"""Return trace ids that should be visible in the UI history panel."""
280+
281+
if not trace_root.exists():
282+
return []
283+
284+
trace_ids: list[str] = []
285+
for trace_dir in sorted(trace_root.glob("*/*"), key=lambda p: str(p)):
286+
if not trace_dir.is_dir():
287+
continue
288+
if "uploads" in trace_dir.relative_to(trace_root).parts:
289+
continue
290+
if not any(trace_dir.rglob("*.pkl")):
291+
continue
292+
293+
trace_ids.append(trace_dir.relative_to(trace_root).as_posix())
294+
295+
return trace_ids
296+
297+
298+
def _load_existing_traces(trace_root: Path) -> None:
299+
"""Load persisted traces into memory so the UI survives a server restart."""
300+
301+
for trace_id in _collect_existing_trace_ids(trace_root):
302+
trace_dir = trace_root / trace_id
303+
304+
try:
305+
read_trace(trace_dir, id=str(trace_dir))
306+
except Exception:
307+
app.logger.exception("Failed to load trace from %s", trace_dir)
281308

282309

283310
@app.route("/trace", methods=["POST"])
@@ -347,6 +374,14 @@ def download_stdout_file():
347374
)
348375

349376

377+
@app.route("/traces", methods=["GET"])
378+
def list_traces():
379+
"""Return trace ids that are available for history browsing."""
380+
381+
trace_ids = _collect_existing_trace_ids(log_folder_path)
382+
return jsonify(trace_ids), 200
383+
384+
350385
@app.route("/upload", methods=["POST"])
351386
def upload_file():
352387
# 获取请求体中的字段
@@ -555,6 +590,7 @@ def server_static_files(fn):
555590

556591
def main(port: int = 19899):
557592
app.config["UI_SERVER_PORT"] = port
593+
_load_existing_traces(log_folder_path)
558594
app.run(debug=False, host="0.0.0.0", port=port)
559595

560596

web/src/utils/api.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ export function trace(data) {
2929
})
3030
}
3131

32+
export function getHistoryTraceIds() {
33+
return request({
34+
url: url + "traces",
35+
method: 'get'
36+
})
37+
}
38+
3239
export function control(data) {
3340
return request({
3441
url: url + "control",
@@ -54,4 +61,4 @@ export function submitUserInteraction(data) {
5461
export function getStdoutDownloadUrl(traceId) {
5562
const query = new URLSearchParams({ id: traceId });
5663
return url + "stdout?" + query.toString();
57-
}
64+
}

web/src/views/Playground.vue

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@
372372
<script setup>
373373
import { computed, ref, watch, reactive, onMounted, onUnmounted, nextTick } from "vue";
374374
import { ElMessage } from "element-plus";
375-
import { uploadFile } from "../utils/api";
375+
import { getHistoryTraceIds, uploadFile } from "../utils/api";
376376
import selectComponent from "../components/select-component.vue";
377377
import smSelectComponent from "../components/sm-select-component.vue";
378378
import loadingSvg from "../components/loading-dot.vue";
@@ -830,39 +830,53 @@ const Back = () => {
830830
831831
function getCompletedIdList() {
832832
const data = localStorage.getItem(completedTraceStorageKey);
833-
return data ? JSON.parse(data) : [];
834-
}
833+
if (!data) {
834+
return [];
835+
}
835836
836-
function buildHistoryTraceList() {
837-
const groupedTraceMap = new Map();
838-
const completedIdList = getCompletedIdList();
837+
try {
838+
return JSON.parse(data);
839+
} catch {
840+
return [];
841+
}
842+
}
839843
840-
completedIdList.forEach((traceId) => {
841-
const normalizedTraceId = String(traceId || "").trim();
844+
function appendTraceId(groupedTraceMap, traceId) {
845+
const normalizedTraceId = String(traceId || "").trim();
842846
843-
if (!normalizedTraceId) {
844-
return;
845-
}
847+
if (!normalizedTraceId) {
848+
return;
849+
}
846850
847-
const separatorIndex = normalizedTraceId.indexOf("/");
848-
const scenario =
849-
separatorIndex === -1
850-
? normalizedTraceId
851-
: normalizedTraceId.slice(0, separatorIndex);
852-
const traceName =
853-
separatorIndex === -1
854-
? normalizedTraceId
855-
: normalizedTraceId.slice(separatorIndex + 1);
856-
857-
if (!groupedTraceMap.has(scenario)) {
858-
groupedTraceMap.set(scenario, new Map());
859-
}
851+
const separatorIndex = normalizedTraceId.indexOf("/");
852+
const scenario =
853+
separatorIndex === -1
854+
? normalizedTraceId
855+
: normalizedTraceId.slice(0, separatorIndex);
856+
const traceName =
857+
separatorIndex === -1
858+
? normalizedTraceId
859+
: normalizedTraceId.slice(separatorIndex + 1);
860+
861+
if (!groupedTraceMap.has(scenario)) {
862+
groupedTraceMap.set(scenario, new Map());
863+
}
860864
861-
groupedTraceMap.get(scenario).set(traceName, {
862-
name: traceName,
863-
id: normalizedTraceId,
864-
});
865+
groupedTraceMap.get(scenario).set(traceName, {
866+
name: traceName,
867+
id: normalizedTraceId,
865868
});
869+
}
870+
871+
async function buildHistoryTraceList() {
872+
const groupedTraceMap = new Map();
873+
const completedIdList = getCompletedIdList();
874+
const backendTraceIds = await getHistoryTraceIds().then((response) =>
875+
Array.isArray(response) ? response : []
876+
).catch(() => []);
877+
878+
const traceIdList = [...new Set([...completedIdList, ...backendTraceIds])];
879+
traceIdList.forEach((traceId) => appendTraceId(groupedTraceMap, traceId));
866880
867881
historyScenarioList.value = Array.from(groupedTraceMap.entries()).map(
868882
([scenario, traceMap]) => ({
@@ -924,8 +938,8 @@ const viewTracePage = () => {
924938
showPlayground.value = true;
925939
};
926940
927-
const openHistoryPanel = () => {
928-
buildHistoryTraceList();
941+
const openHistoryPanel = async () => {
942+
await buildHistoryTraceList();
929943
showPanel.value = 3;
930944
showPlayground.value = false;
931945
};
@@ -979,7 +993,7 @@ function moveSlider(index) {
979993
}
980994
981995
onMounted(() => {
982-
buildHistoryTraceList();
996+
void buildHistoryTraceList();
983997
});
984998
</script>
985999

0 commit comments

Comments
 (0)