feat(agent): full-width control page, Copy-logs button, quiet HTTP log noise
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 19s
CI / backend-lint-and-test (push) Successful in 27s
CI / integration (push) Successful in 3m25s

- Page fills the viewport horizontally (drop the 780px cap).
- Copy button on the Logs card → copies the console (clipboard API on localhost,
  textarea-execCommand fallback), with a brief "Copied" confirmation.
- Silence httpx/httpcore/huggingface_hub/urllib3/filelock/uvicorn.access/
  ultralytics to WARNING so the console shows agent activity (detector loads,
  job errors, autoscale moves) instead of per-request HF-download spam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ttrj5P7upUTueSfoJcxEqa
This commit is contained in:
2026-06-30 18:41:49 -04:00
parent c1b099e5a3
commit 9eaefac385
2 changed files with 24 additions and 6 deletions
+16 -2
View File
@@ -86,7 +86,7 @@ _PAGE = """<!doctype html><html><head><meta charset=utf-8>
*{box-sizing:border-box} *{box-sizing:border-box}
body{font:14px/1.5 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;margin:0; body{font:14px/1.5 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;margin:0;
background:radial-gradient(1200px 600px at 50% -10%,#1a2029,#0f1216);color:var(--fg)} background:radial-gradient(1200px 600px at 50% -10%,#1a2029,#0f1216);color:var(--fg)}
.wrap{max-width:780px;margin:0 auto;padding:28px 20px 48px} .wrap{max-width:none;margin:0;padding:28px 28px 48px}
header{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px} header{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px}
.brand{display:flex;align-items:center;gap:10px;font-size:19px;font-weight:700;letter-spacing:.2px} .brand{display:flex;align-items:center;gap:10px;font-size:19px;font-weight:700;letter-spacing:.2px}
.logo{color:var(--acc);font-size:20px} .logo{color:var(--acc);font-size:20px}
@@ -137,6 +137,11 @@ _PAGE = """<!doctype html><html><head><meta charset=utf-8>
.queue{font:13px ui-monospace,monospace;color:var(--mut)} .queue{font:13px ui-monospace,monospace;color:var(--mut)}
.banner{margin:0 0 14px;padding:.7rem .9rem;border-radius:10px;background:#3a2f12; .banner{margin:0 0 14px;padding:.7rem .9rem;border-radius:10px;background:#3a2f12;
border:1px solid #5a4a17;color:#ffd98a;font-size:13px} border:1px solid #5a4a17;color:#ffd98a;font-size:13px}
.logs-h{display:flex;align-items:center;justify-content:space-between}
.copybtn{font:600 11px system-ui;letter-spacing:.04em;text-transform:uppercase;
background:#262c34;color:var(--fg);border:1px solid var(--bd);border-radius:7px;
padding:5px 11px;cursor:pointer}
.copybtn:hover{border-color:var(--acc)}
.logs{margin:0;background:#0b0e12;border:1px solid var(--bd);border-radius:10px;padding:12px; .logs{margin:0;background:#0b0e12;border:1px solid var(--bd);border-radius:10px;padding:12px;
height:230px;overflow:auto;font:12px/1.55 ui-monospace,SFMono-Regular,Menlo,monospace; height:230px;overflow:auto;font:12px/1.55 ui-monospace,SFMono-Regular,Menlo,monospace;
color:#b9c4d0;white-space:pre-wrap;word-break:break-word} color:#b9c4d0;white-space:pre-wrap;word-break:break-word}
@@ -187,7 +192,9 @@ _PAGE = """<!doctype html><html><head><meta charset=utf-8>
</section> </section>
<section class=card> <section class=card>
<div class=card-h>Logs</div> <div class="card-h logs-h">Logs
<button class=copybtn id=copybtn onclick=copyLogs()>Copy</button>
</div>
<pre class=logs id=logs>waiting for activity…</pre> <pre class=logs id=logs>waiting for activity…</pre>
</section> </section>
</div> </div>
@@ -238,6 +245,13 @@ _PAGE = """<!doctype html><html><head><meta charset=utf-8>
if(atBottom) el.scrollTop=el.scrollHeight if(atBottom) el.scrollTop=el.scrollHeight
}catch{} }catch{}
} }
async function copyLogs(){
const txt=logs.textContent||''
try{ await navigator.clipboard.writeText(txt) }
catch{ const t=document.createElement('textarea'); t.value=txt; document.body.appendChild(t);
t.select(); try{document.execCommand('copy')}catch{}; t.remove() }
copybtn.textContent='Copied'; setTimeout(()=>{copybtn.textContent='Copy'},1200)
}
refresh(); refreshLogs() refresh(); refreshLogs()
setInterval(refresh,3000); setInterval(refreshLogs,2500) setInterval(refresh,3000); setInterval(refreshLogs,2500)
</script></body></html>""" </script></body></html>"""
+8 -4
View File
@@ -34,7 +34,11 @@ def install(level: int = logging.INFO) -> None:
root.addHandler(h) root.addHandler(h)
if root.level == logging.NOTSET or root.level > level: if root.level == logging.NOTSET or root.level > level:
root.setLevel(level) root.setLevel(level)
# Keep the buffer signal-rich: drop the per-request access spam + ultralytics # Keep the buffer signal-rich: silence the chatty HTTP/download libs (every
# banner noise to WARNING. # HF model fetch logs per-request) so the console shows agent activity —
logging.getLogger("uvicorn.access").setLevel(logging.WARNING) # detector loads, job errors, autoscale moves — not request spam.
logging.getLogger("ultralytics").setLevel(logging.WARNING) for noisy in (
"uvicorn.access", "ultralytics", "httpx", "httpcore",
"huggingface_hub", "urllib3", "filelock",
):
logging.getLogger(noisy).setLevel(logging.WARNING)