Simplify search agent activity state

This commit is contained in:
wuyang
2026-07-08 14:11:13 +08:00
parent 894c914e26
commit 4892e7afad
3 changed files with 97 additions and 59 deletions
+19 -17
View File
@@ -521,22 +521,26 @@ function routeButtons(routes) {
`; `;
} }
function searchSteps(steps = []) { function searchActivity(steps = []) {
const current =
steps.find((step) => step.status === "running") ||
[...steps].reverse().find((step) => step.status === "done") ||
steps[0] ||
{};
const doneCount = steps.filter((step) => step.status === "done").length;
const currentIndex = Math.min(doneCount + (current.status === "running" ? 1 : 0), steps.length || 1);
const statusLabel = current.status === "running" ? "working" : current.status || "pending";
return ` return `
<div class="agent-steps"> <div class="agent-activity ${escapeHtml(current.status || "pending")}">
${steps <span class="activity-dot"></span>
.map( <div class="activity-copy">
(step) => ` <div class="activity-title">
<div class="agent-step ${escapeHtml(step.status)}"> <span>Search Agent</span>
<span class="step-dot"></span> <strong>${escapeHtml(current.label || "准备搜索")}</strong>
<div>
<strong>${escapeHtml(step.label)}</strong>
<span>${escapeHtml(step.detail || step.status)}</span>
</div> </div>
<div class="activity-detail">${escapeHtml(current.detail || "正在准备检索上下文")}</div>
</div> </div>
`, <div class="activity-meta">${escapeHtml(statusLabel)} · ${currentIndex}/${steps.length || 1}</div>
)
.join("")}
</div> </div>
`; `;
} }
@@ -596,10 +600,7 @@ function renderSearchRunning(job) {
elements.lensTitle.textContent = job?.query || elements.searchInput.value.trim() || "搜索"; elements.lensTitle.textContent = job?.query || elements.searchInput.value.trim() || "搜索";
elements.lensBody.innerHTML = ` elements.lensBody.innerHTML = `
<section class="section"> <section class="section">
<p class="statement">Search Agent 正在理解问题、扩展关键词并检索本地论文库。</p> ${searchActivity(job?.steps || [])}
</section>
<section class="section">
${searchSteps(job?.steps || [])}
</section> </section>
`; `;
} }
@@ -873,6 +874,7 @@ async function runSearch() {
], ],
}; };
renderSearchRunning(starter); renderSearchRunning(starter);
scrollLensIntoView();
try { try {
const payload = await api("/api/search/agent", { const payload = await api("/api/search/agent", {
method: "POST", method: "POST",
+2 -2
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Agent Knowledge Atlas</title> <title>Agent Knowledge Atlas</title>
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='12' fill='%23cfe8e3'/%3E%3Ctext x='32' y='40' text-anchor='middle' font-size='24' font-family='Arial' font-weight='700' fill='%23064c47'%3EAK%3C/text%3E%3C/svg%3E" /> <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Crect width='64' height='64' rx='12' fill='%23cfe8e3'/%3E%3Ctext x='32' y='40' text-anchor='middle' font-size='24' font-family='Arial' font-weight='700' fill='%23064c47'%3EAK%3C/text%3E%3C/svg%3E" />
<link rel="stylesheet" href="/static/styles.css?v=atlas-20260708-10" /> <link rel="stylesheet" href="/static/styles.css?v=atlas-20260708-12" />
</head> </head>
<body> <body>
<main class="atlas-app"> <main class="atlas-app">
@@ -79,6 +79,6 @@
</footer> </footer>
</main> </main>
<script src="/static/app.js?v=atlas-20260708-10"></script> <script src="/static/app.js?v=atlas-20260708-12"></script>
</body> </body>
</html> </html>
+74 -38
View File
@@ -521,55 +521,83 @@ button {
padding: 3px 6px; padding: 3px 6px;
} }
.agent-steps { .agent-activity {
display: grid; display: grid;
gap: 10px; grid-template-columns: auto minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
border: 1px solid var(--line);
border-radius: 8px;
background: #fbfaf6;
padding: 12px;
} }
.agent-step { .activity-dot {
display: grid; width: 12px;
grid-template-columns: 13px 1fr; height: 12px;
gap: 10px;
align-items: start;
color: var(--muted);
}
.step-dot {
width: 9px;
height: 9px;
margin-top: 6px;
border: 1px solid #aab3ad;
border-radius: 50%; border-radius: 50%;
background: #ffffff;
}
.agent-step strong {
display: block;
color: #17201d;
font-size: 13px;
}
.agent-step span:last-child {
display: block;
margin-top: 2px;
font-size: 12px;
line-height: 1.42;
}
.agent-step.running .step-dot {
border-color: var(--teal);
background: var(--teal); background: var(--teal);
box-shadow: 0 0 0 5px rgba(13, 118, 111, 0.12); box-shadow: 0 0 0 7px rgba(13, 118, 111, 0.12);
} }
.agent-step.done .step-dot { .agent-activity.running .activity-dot {
border-color: var(--green); animation: activityPulse 1.5s ease-in-out infinite;
}
.agent-activity.done .activity-dot {
background: var(--green); background: var(--green);
box-shadow: 0 0 0 7px rgba(82, 127, 70, 0.12);
} }
.agent-step.error .step-dot { .agent-activity.error .activity-dot {
border-color: var(--coral);
background: var(--coral); background: var(--coral);
box-shadow: 0 0 0 7px rgba(186, 86, 68, 0.12);
}
.activity-copy {
min-width: 0;
}
.activity-title {
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: baseline;
color: var(--muted);
font-size: 12px;
}
.activity-title strong {
color: #17201d;
font-size: 14px;
}
.activity-detail {
margin-top: 3px;
color: #4c5550;
font-size: 13px;
line-height: 1.38;
overflow-wrap: anywhere;
}
.activity-meta {
color: var(--muted);
font-size: 11px;
font-weight: 760;
white-space: nowrap;
}
@keyframes activityPulse {
0%,
100% {
transform: scale(1);
box-shadow: 0 0 0 7px rgba(13, 118, 111, 0.1);
}
50% {
transform: scale(0.82);
box-shadow: 0 0 0 10px rgba(13, 118, 111, 0.18);
}
} }
.search-brief h3 { .search-brief h3 {
@@ -885,6 +913,14 @@ button {
max-width: 100%; max-width: 100%;
} }
.agent-activity {
grid-template-columns: auto minmax(0, 1fr);
}
.activity-meta {
grid-column: 2;
}
.route-band, .route-band,
.timeline-band { .timeline-band {
margin-top: 12px; margin-top: 12px;