Knowledge Chat: surface LangSmith trace link when tracing enabled (reads /rag/config)
This commit is contained in:
@@ -40,6 +40,7 @@ export function KnowledgeChatView({ onGpuActivity }: Props = {}) {
|
|||||||
const [catalogDocs, setCatalogDocs] = useState<number | null>(null)
|
const [catalogDocs, setCatalogDocs] = useState<number | null>(null)
|
||||||
const [showArch, setShowArch] = useState(true)
|
const [showArch, setShowArch] = useState(true)
|
||||||
const [activeStage, setActiveStage] = useState<number | null>(null)
|
const [activeStage, setActiveStage] = useState<number | null>(null)
|
||||||
|
const [traceCfg, setTraceCfg] = useState<{ tracing: boolean; project: string; smith_url: string } | null>(null)
|
||||||
const bottomRef = useRef<HTMLDivElement>(null)
|
const bottomRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
const loadMeta = useCallback(async () => {
|
const loadMeta = useCallback(async () => {
|
||||||
@@ -77,6 +78,13 @@ export function KnowledgeChatView({ onGpuActivity }: Props = {}) {
|
|||||||
loadCatalog()
|
loadCatalog()
|
||||||
}, [loadMeta, loadCatalog])
|
}, [loadMeta, loadCatalog])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/rag/config')
|
||||||
|
.then((r) => (r.ok ? r.json() : null))
|
||||||
|
.then((c) => { if (c) setTraceCfg(c) })
|
||||||
|
.catch(() => {})
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
|
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
|
||||||
}, [messages, loading])
|
}, [messages, loading])
|
||||||
@@ -351,6 +359,17 @@ export function KnowledgeChatView({ onGpuActivity }: Props = {}) {
|
|||||||
<StatusPill ok={health.llm} label="LLM" />
|
<StatusPill ok={health.llm} label="LLM" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{traceCfg?.tracing && (
|
||||||
|
<a
|
||||||
|
href={traceCfg.smith_url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
title={`LangSmith project: ${traceCfg.project}`}
|
||||||
|
className="inline-flex items-center gap-1 rounded border border-emerald-400/50 bg-emerald-500/15 px-2 py-1 text-[10px] font-medium text-emerald-300 hover:bg-emerald-500/25"
|
||||||
|
>
|
||||||
|
<Workflow className="h-3.5 w-3.5" /> LangSmith ↗
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowArch((v) => !v)}
|
onClick={() => setShowArch((v) => !v)}
|
||||||
@@ -369,7 +388,7 @@ export function KnowledgeChatView({ onGpuActivity }: Props = {}) {
|
|||||||
|
|
||||||
{showArch && (
|
{showArch && (
|
||||||
<div className="shrink-0 border-b border-border bg-surface-overlay/20 px-4 py-3">
|
<div className="shrink-0 border-b border-border bg-surface-overlay/20 px-4 py-3">
|
||||||
<RagFlow loading={loading} ingesting={ingesting} activeStage={activeStage} />
|
<RagFlow loading={loading} ingesting={ingesting} activeStage={activeStage} smithUrl={traceCfg?.tracing ? traceCfg.smith_url : null} project={traceCfg?.project} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -565,7 +584,7 @@ const QUERY_STAGES = [
|
|||||||
|
|
||||||
const STAGE_LABEL = ['Question', 'Embed', 'Retrieve', 'Context', 'LLM', 'Answer']
|
const STAGE_LABEL = ['Question', 'Embed', 'Retrieve', 'Context', 'LLM', 'Answer']
|
||||||
|
|
||||||
function RagFlow({ loading, ingesting, activeStage }: { loading: boolean; ingesting: boolean; activeStage: number | null }) {
|
function RagFlow({ loading, ingesting, activeStage, smithUrl, project }: { loading: boolean; ingesting: boolean; activeStage: number | null; smithUrl?: string | null; project?: string }) {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex flex-wrap items-center gap-2 text-[9px] font-semibold uppercase tracking-wider text-foreground-faint">
|
<div className="flex flex-wrap items-center gap-2 text-[9px] font-semibold uppercase tracking-wider text-foreground-faint">
|
||||||
@@ -574,6 +593,9 @@ function RagFlow({ loading, ingesting, activeStage }: { loading: boolean; ingest
|
|||||||
<span className="h-1.5 w-1.5 rounded-full bg-emerald-400" /> orchestrated by LangChain
|
<span className="h-1.5 w-1.5 rounded-full bg-emerald-400" /> orchestrated by LangChain
|
||||||
</span>
|
</span>
|
||||||
<span className="rounded bg-docker/15 px-1.5 py-0.5 font-mono text-[8px] normal-case text-docker">ChromaDB · Docling · sentence-transformers</span>
|
<span className="rounded bg-docker/15 px-1.5 py-0.5 font-mono text-[8px] normal-case text-docker">ChromaDB · Docling · sentence-transformers</span>
|
||||||
|
{smithUrl && (
|
||||||
|
<a href={smithUrl} target="_blank" rel="noreferrer" title={project ? `LangSmith project: ${project}` : 'LangSmith'} className="inline-flex items-center gap-1 rounded-md border border-emerald-400/40 bg-emerald-500/10 px-1.5 py-0.5 font-mono text-[8px] normal-case text-emerald-300 hover:bg-emerald-500/20">LangSmith traces ↗</a>
|
||||||
|
)}
|
||||||
{activeStage != null && (
|
{activeStage != null && (
|
||||||
<span className="ml-auto flex items-center gap-1 normal-case text-docker">
|
<span className="ml-auto flex items-center gap-1 normal-case text-docker">
|
||||||
<span className="h-1.5 w-1.5 animate-ping rounded-full bg-docker" /> {STAGE_LABEL[activeStage] || 'working'}…
|
<span className="h-1.5 w-1.5 animate-ping rounded-full bg-docker" /> {STAGE_LABEL[activeStage] || 'working'}…
|
||||||
|
|||||||
Reference in New Issue
Block a user