@anvia/studio 0.5.14 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/dist/index.d.ts +78 -2
- package/dist/index.js +506 -9
- package/dist/index.js.map +1 -1
- package/dist/ui/assets/{ArrowClockwise.es-cF7OPZy5.js → ArrowClockwise.es-BA79KX3F.js} +2 -2
- package/dist/ui/assets/{ArrowClockwise.es-cF7OPZy5.js.map → ArrowClockwise.es-BA79KX3F.js.map} +1 -1
- package/dist/ui/assets/{Path.es-D-NB-Xon.js → Path.es-DTZ3zsLn.js} +2 -2
- package/dist/ui/assets/{Path.es-D-NB-Xon.js.map → Path.es-DTZ3zsLn.js.map} +1 -1
- package/dist/ui/assets/{Play.es-BoMnJL28.js → Play.es-CJTRfv9R.js} +2 -2
- package/dist/ui/assets/{Play.es-BoMnJL28.js.map → Play.es-CJTRfv9R.js.map} +1 -1
- package/dist/ui/assets/{evals-page-Cx4Ycr-Y.js → evals-page-rS-P7eLF.js} +2 -2
- package/dist/ui/assets/{evals-page-Cx4Ycr-Y.js.map → evals-page-rS-P7eLF.js.map} +1 -1
- package/dist/ui/assets/index-B1s3oC-V.css +1 -0
- package/dist/ui/assets/index-ChlKOnbD.js +54 -0
- package/dist/ui/assets/index-ChlKOnbD.js.map +1 -0
- package/dist/ui/assets/{knowledge-page-DASnGzYP.js → knowledge-page-CR0JUneq.js} +2 -2
- package/dist/ui/assets/{knowledge-page-DASnGzYP.js.map → knowledge-page-CR0JUneq.js.map} +1 -1
- package/dist/ui/assets/{mcps-page-B7VAqsoU.js → mcps-page-D3P0UAWf.js} +2 -2
- package/dist/ui/assets/{mcps-page-B7VAqsoU.js.map → mcps-page-D3P0UAWf.js.map} +1 -1
- package/dist/ui/assets/{memory-page-BCv19Tw_.js → memory-page-kVDqOAOd.js} +2 -2
- package/dist/ui/assets/{memory-page-BCv19Tw_.js.map → memory-page-kVDqOAOd.js.map} +1 -1
- package/dist/ui/assets/{pipelines-page-Byb_JYxi.js → pipelines-page-lMfsVNRy.js} +2 -2
- package/dist/ui/assets/{pipelines-page-Byb_JYxi.js.map → pipelines-page-lMfsVNRy.js.map} +1 -1
- package/dist/ui/assets/{renderers-C8RHOlPz.js → renderers-Bc89UGTN.js} +2 -2
- package/dist/ui/assets/{renderers-C8RHOlPz.js.map → renderers-Bc89UGTN.js.map} +1 -1
- package/dist/ui/assets/{sessions-page-CV8GZKjN.js → sessions-page-CVlkRPfT.js} +2 -2
- package/dist/ui/assets/{sessions-page-CV8GZKjN.js.map → sessions-page-CVlkRPfT.js.map} +1 -1
- package/dist/ui/assets/{status-page-a6SMAcLu.js → status-page-XKvTGruQ.js} +2 -2
- package/dist/ui/assets/{status-page-a6SMAcLu.js.map → status-page-XKvTGruQ.js.map} +1 -1
- package/dist/ui/assets/{tools-page-Dpj7hI8q.js → tools-page-DJt_QdDe.js} +2 -2
- package/dist/ui/assets/{tools-page-Dpj7hI8q.js.map → tools-page-DJt_QdDe.js.map} +1 -1
- package/dist/ui/assets/{trace-browser-dvGDi7ji.js → trace-browser-BBITQELO.js} +2 -2
- package/dist/ui/assets/{trace-browser-dvGDi7ji.js.map → trace-browser-BBITQELO.js.map} +1 -1
- package/dist/ui/assets/{transcript-item-GmOQdc53.js → transcript-item-BvaA1PBu.js} +3 -3
- package/dist/ui/assets/transcript-item-BvaA1PBu.js.map +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/index-BBfu6qlV.css +0 -1
- package/dist/ui/assets/index-rc2RWnWD.js +0 -54
- package/dist/ui/assets/index-rc2RWnWD.js.map +0 -1
- package/dist/ui/assets/transcript-item-GmOQdc53.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e,s as t,t as n}from"./jsx-runtime-ZfyQks-z.js";import{t as r}from"./ArrowClockwise.es-cF7OPZy5.js";import{L as i}from"./index-rc2RWnWD.js";import{t as a}from"./badge-CNbpc5Sm.js";import{n as o}from"./renderers-C8RHOlPz.js";var s=t(e(),1),c=n(),l=50;function u(e){let[t,n]=(0,s.useState)(``),[a,o]=(0,s.useState)(),u=e.summary?.agents??[],m=e.summary?.evidence??[],g=(0,s.useMemo)(()=>y(u),[u]),v=E(e.activeTab),b=(0,s.useMemo)(()=>v===void 0?[]:g.filter(e=>e.source.kind===v),[v,g]),x=b.find(e=>e.key===t)??b[0];(0,s.useEffect)(()=>{if(b.length===0){n(``);return}b.some(e=>e.key===t)||n((b.find(e=>e.source.inspectable===!0&&(e.source.itemCount??0)>0)??b.find(e=>e.source.inspectable===!0)??b[0])?.key??``)},[t,b]);let C=(0,s.useCallback)(async(e,t)=>{o(n=>({key:e.key,loading:!0,inspectable:n?.key===e.key?n.inspectable:e.source.inspectable===!0,items:t.append&&n?.key===e.key?n.items:[],...t.append&&n?.key===e.key&&n.nextCursor!==void 0?{nextCursor:n.nextCursor}:{},...n?.key===e.key&&n.totalCount!==void 0?{totalCount:n.totalCount}:{}}));try{let n=new URLSearchParams({agentId:e.agentId,sourceId:S(e.source),limit:String(l)});t.cursor!==void 0&&n.set(`cursor`,t.cursor);let r=await fetch(`/knowledge/items?${n.toString()}`);if(!r.ok)throw Error(`Knowledge items failed with HTTP ${r.status}`);let i=await r.json();o(n=>({key:e.key,loading:!1,inspectable:i.inspectable,items:t.append&&n?.key===e.key?[...n.items,...i.items]:i.items,...i.nextCursor===void 0?{}:{nextCursor:i.nextCursor},...i.totalCount===void 0?{}:{totalCount:i.totalCount},...i.message===void 0?{}:{message:i.message}}))}catch(t){o(n=>({key:e.key,loading:!1,inspectable:n?.inspectable??!1,items:n?.items??[],error:t instanceof Error?t.message:String(t)}))}},[]);return(0,s.useEffect)(()=>{if(x===void 0){o(void 0);return}C(x,{append:!1})},[C,x]),e.enabled?(0,c.jsxs)(`section`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55`,children:[(0,c.jsx)(`header`,{className:`bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur`,children:(0,c.jsxs)(`div`,{className:`grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1`,children:[(0,c.jsxs)(`div`,{className:`grid min-w-0 gap-2`,children:[(0,c.jsx)(`div`,{className:`font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary`,children:`Agent context`}),(0,c.jsx)(`h1`,{className:`m-0 text-2xl font-semibold leading-none tracking-tight text-foreground`,children:`Knowledge`}),(0,c.jsx)(`p`,{className:`m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground`,children:`Browse configured context, dynamic chunks, and retrieval evidence.`})]}),(0,c.jsxs)(i,{className:`h-8 min-h-8 gap-2`,type:`button`,variant:`secondary`,onClick:e.onRefresh,children:[(0,c.jsx)(r,{"aria-hidden":`true`}),`Refresh`]})]})}),(0,c.jsxs)(`div`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)] gap-4 overflow-hidden pb-6 pl-0 pr-6 pt-0`,children:[(0,c.jsx)(d,{activeTab:e.activeTab,sources:g,evidenceCount:m.length,onSelectTab:e.onSelectTab}),e.activeTab===`retrieval-log`?(0,c.jsx)(h,{evidence:m,onOpenTrace:e.onOpenTrace}):(0,c.jsx)(f,{sources:b,selectedKey:x?.key??``,loading:e.loading,activeTab:e.activeTab,onSelect:n,children:(0,c.jsx)(p,{source:x,state:a,onLoadMore:()=>{x!==void 0&&C(x,a?.nextCursor===void 0?{append:!0}:{append:!0,cursor:a.nextCursor})}})})]})]}):(0,c.jsx)(_,{title:`Knowledge unavailable`,text:`No registered agent exposes inspectable context.`})}function d(e){return(0,c.jsx)(`nav`,{className:`flex min-w-0 gap-7 overflow-x-auto border-b border-border/80`,"aria-label":`Knowledge sections`,children:b.map(t=>{let n=e.activeTab===t.id;return(0,c.jsxs)(`button`,{className:[`flex min-h-10 shrink-0 items-center gap-2 border-b px-0 pb-2 pt-1 text-left transition duration-200 hover:text-foreground focus-visible:outline-none`,n?`border-primary text-foreground`:`border-transparent text-muted-foreground hover:border-border`].join(` `),type:`button`,"aria-current":n?`page`:void 0,onClick:()=>e.onSelectTab(t.id),children:[(0,c.jsx)(`span`,{className:`text-sm font-semibold`,children:t.label}),(0,c.jsx)(`span`,{className:`font-mono text-[10px] text-muted-foreground`,children:O(t.id,e.sources,e.evidenceCount)})]},t.id)})})}function f(e){let t=e.sources.length!==1||e.loading;return(0,c.jsxs)(`div`,{className:[`grid min-h-0 gap-3 overflow-hidden`,t?`grid-rows-[auto_minmax(0,1fr)]`:`grid-rows-[minmax(0,1fr)]`].join(` `),children:[t?(0,c.jsx)(`div`,{className:`min-w-0 overflow-x-auto rounded-xl border border-border/80 bg-card/55`,children:(0,c.jsxs)(`div`,{className:`flex min-h-11 min-w-max items-center gap-2 px-3`,children:[(0,c.jsx)(`span`,{className:`mr-2 font-mono text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground`,children:D(e.activeTab)}),e.loading&&e.sources.length===0?(0,c.jsx)(`span`,{className:`font-mono text-[11px] text-muted-foreground`,children:`Loading sources`}):null,!e.loading&&e.sources.length===0?(0,c.jsx)(`span`,{className:`font-mono text-[11px] text-muted-foreground`,children:`No knowledge sources`}):null,e.sources.map(t=>(0,c.jsxs)(`button`,{className:[`flex h-7 items-center gap-2 rounded-lg border border-border/80 bg-background/45 px-2.5 font-mono text-[11px] font-semibold text-muted-foreground transition duration-200 hover:border-primary/45 hover:bg-primary/10 hover:text-foreground focus-visible:border-ring focus-visible:outline-none`,e.selectedKey===t.key?`border-primary/45 bg-primary/10 text-primary`:``].join(` `),type:`button`,onClick:()=>e.onSelect(t.key),children:[(0,c.jsx)(`span`,{children:t.source.label??T(t.source.kind)}),t.source.itemCount===void 0?null:(0,c.jsx)(`span`,{className:`text-muted-foreground`,children:t.source.itemCount})]},t.key))]})}):null,e.children]})}function p(e){let t=e.state;return(0,c.jsxs)(`section`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-xl border border-border/80 bg-card/55`,children:[(0,c.jsx)(`div`,{className:`border-b border-border/80 px-4 py-3`,children:(0,c.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0`,children:[(0,c.jsx)(`h2`,{className:`m-0 truncate text-sm font-semibold text-foreground`,children:e.source?.source.label??`Knowledge items`}),(0,c.jsx)(`p`,{className:`m-0 mt-1 truncate font-mono text-xs text-muted-foreground`,children:e.source===void 0?`No source selected`:`${e.source.agentId} / ${S(e.source.source)}`})]}),t?.totalCount===void 0?null:(0,c.jsxs)(a,{children:[t.totalCount,` total`]})]})}),(0,c.jsx)(`div`,{className:`min-h-0 overflow-auto`,children:(0,c.jsxs)(`div`,{className:`p-4`,children:[e.source===void 0?(0,c.jsx)(v,{text:`No knowledge source selected`}):null,t?.loading===!0&&t.items.length===0?(0,c.jsx)(v,{text:`Loading items`}):null,t?.error===void 0?null:(0,c.jsx)(v,{text:t.error}),t?.inspectable===!1?(0,c.jsx)(v,{text:t.message??`This source does not expose browseable chunks.`}):null,t?.inspectable!==!1&&t?.loading===!1&&t.items.length===0?(0,c.jsx)(v,{text:`No items in this source`}):null,(0,c.jsx)(`div`,{className:`grid gap-3`,children:t?.items.map(e=>(0,c.jsx)(m,{item:e},`${e.kind}:${e.id}`))})]})}),(0,c.jsxs)(`div`,{className:`flex min-h-12 items-center justify-between gap-3 bg-muted/10 px-4 py-2`,children:[(0,c.jsx)(`span`,{className:`font-mono text-[11px] text-muted-foreground`,children:t===void 0?`0 loaded`:`${t.items.length} loaded`}),(0,c.jsx)(i,{className:`h-8 min-h-8`,type:`button`,variant:`secondary`,disabled:t?.loading===!0||t?.nextCursor===void 0,onClick:e.onLoadMore,children:`Load more`})]})]})}function m(e){return(0,c.jsxs)(`article`,{className:`grid gap-3 rounded-xl border border-border/80 bg-background/55 p-4`,children:[(0,c.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0`,children:[(0,c.jsx)(`div`,{className:`truncate font-mono text-xs font-semibold text-primary`,children:e.item.toolName??e.item.id}),(0,c.jsx)(`div`,{className:`mt-1 font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground`,children:k(e.item.kind)})]}),e.item.parameterKeys===void 0||e.item.parameterKeys.length===0?null:(0,c.jsxs)(a,{children:[e.item.parameterKeys.length,` params`]})]}),e.item.description===void 0||e.item.description.length===0?null:(0,c.jsx)(`p`,{className:`m-0 text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]`,children:e.item.description}),e.item.text===void 0?null:(0,c.jsx)(`p`,{className:`m-0 whitespace-pre-wrap text-sm leading-6 text-foreground [overflow-wrap:anywhere]`,children:e.item.text}),e.item.document===void 0?null:(0,c.jsx)(g,{title:`Document`,value:e.item.document}),e.item.metadata===void 0?null:(0,c.jsx)(g,{title:`Metadata`,value:e.item.metadata}),e.item.parameterKeys===void 0||e.item.parameterKeys.length===0?null:(0,c.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:e.item.parameterKeys.map(e=>(0,c.jsx)(a,{children:e},e))})]})}function h(e){return(0,c.jsxs)(`section`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-xl border border-border/80 bg-card/55`,children:[(0,c.jsx)(`div`,{className:`border-b border-border/80 px-4 py-3`,children:(0,c.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0`,children:[(0,c.jsx)(`h2`,{className:`m-0 truncate text-sm font-semibold text-foreground`,children:`Retrieval log`}),(0,c.jsx)(`p`,{className:`m-0 mt-1 truncate font-mono text-xs text-muted-foreground`,children:`traces / retrieval-evidence`})]}),(0,c.jsxs)(a,{children:[e.evidence.length,` entries`]})]})}),(0,c.jsxs)(`div`,{className:`min-h-0 overflow-auto p-4`,children:[e.evidence.length===0?(0,c.jsx)(v,{text:`No retrieval evidence captured yet`}):null,(0,c.jsx)(`div`,{className:`grid gap-3`,children:e.evidence.map(t=>(0,c.jsxs)(`article`,{className:`grid gap-3 rounded-xl border border-border/80 bg-background/45 p-3`,children:[(0,c.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0`,children:[(0,c.jsx)(`div`,{className:`truncate text-sm font-semibold text-foreground`,children:t.observationName}),(0,c.jsxs)(`div`,{className:`mt-1 font-mono text-[11px] text-muted-foreground`,children:[`Turn `,t.turn]})]}),(0,c.jsx)(i,{className:`h-auto min-h-0 rounded-lg border border-border bg-muted px-2 py-1 font-mono text-[10px] text-muted-foreground`,type:`button`,variant:`ghost`,onClick:()=>e.onOpenTrace(t.traceId),children:`Trace`})]}),(0,c.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,c.jsxs)(a,{children:[t.documentCount,` docs`]}),(0,c.jsxs)(a,{children:[t.toolCount,` tools`]})]}),t.query===void 0?null:(0,c.jsxs)(`p`,{className:`m-0 text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]`,children:[(0,c.jsx)(`span`,{className:`font-mono text-xs font-semibold uppercase tracking-[0.14em] text-foreground`,children:`Query`}),` `,t.query]}),t.documents.slice(0,2).map(e=>(0,c.jsxs)(`p`,{className:`m-0 text-xs leading-5 text-muted-foreground [overflow-wrap:anywhere]`,children:[(0,c.jsx)(`span`,{className:`font-mono text-foreground`,children:e.id??`document`}),` `,e.text??``]},`${e.id??`doc`}:${e.text??``}`)),t.tools.length===0?null:(0,c.jsxs)(`p`,{className:`m-0 text-xs leading-5 text-muted-foreground`,children:[`Tools: `,t.tools.join(`, `)]})]},`${t.traceId}:${t.observationId}`))})]})]})}function g(e){return(0,c.jsxs)(`div`,{className:`grid gap-2 border-t border-border/70 pt-3`,children:[(0,c.jsx)(`div`,{className:`font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground`,children:e.title}),(0,c.jsx)(o,{value:e.value})]})}function _(e){return(0,c.jsx)(`section`,{className:`grid h-full place-items-center p-8`,children:(0,c.jsxs)(`div`,{className:`grid max-w-sm gap-2 text-center`,children:[(0,c.jsx)(`h1`,{className:`m-0 text-base font-semibold text-foreground`,children:e.title}),(0,c.jsx)(`p`,{className:`m-0 text-sm font-medium leading-6 text-muted-foreground`,children:e.text})]})})}function v(e){return(0,c.jsx)(`div`,{className:`rounded-lg border border-dashed border-border px-4 py-3 text-sm font-medium text-muted-foreground`,children:e.text})}function y(e){return e.flatMap(e=>e.sources.map((t,n)=>({key:`${e.agentId}:${S(t,n)}`,agentId:e.agentId,agentName:e.agentName??e.agentId,source:x(t,n)})))}var b=[{id:`static-context`,label:`Static Context`},{id:`dynamic-context`,label:`Dynamic Context`},{id:`dynamic-tools`,label:`Dynamic Tools`},{id:`retrieval-log`,label:`Retrieval Log`}];function x(e,t){return e.sourceId===void 0?{...e,sourceId:C(e,t)}:e}function S(e,t=0){return e.sourceId??C(e,t)}function C(e,t){switch(e.kind){case`static_context`:return`static-context`;case`dynamic_context`:return`dynamic-context-${e.registrationIndex??t}`;case`dynamic_tools`:return`dynamic-tools-${e.registrationIndex??t}`}}function w(e,t){return e.filter(e=>e.kind===t).reduce((e,t)=>e+(t.itemCount??t.count),0)}function T(e){switch(e){case`static_context`:return`Static context`;case`dynamic_context`:return`Dynamic context`;case`dynamic_tools`:return`Dynamic tools`}}function E(e){switch(e){case`static-context`:return`static_context`;case`dynamic-context`:return`dynamic_context`;case`dynamic-tools`:return`dynamic_tools`;case`retrieval-log`:return}}function D(e){return b.find(t=>t.id===e)?.label??`Knowledge`}function O(e,t,n){let r=E(e);if(r===void 0)return`${n} entries`;let i=t.filter(e=>e.source.kind===r),a=w(i.map(e=>e.source),r);return`${i.length} sources / ${a} items`}function k(e){switch(e){case`static_context`:return`Static context`;case`dynamic_context`:return`Dynamic context`;case`dynamic_tool`:return`Dynamic tool`}}export{u as KnowledgePage};
|
|
2
|
-
//# sourceMappingURL=knowledge-page-
|
|
1
|
+
import{i as e,s as t,t as n}from"./jsx-runtime-ZfyQks-z.js";import{t as r}from"./ArrowClockwise.es-BA79KX3F.js";import{L as i}from"./index-ChlKOnbD.js";import{t as a}from"./badge-CNbpc5Sm.js";import{n as o}from"./renderers-Bc89UGTN.js";var s=t(e(),1),c=n(),l=50;function u(e){let[t,n]=(0,s.useState)(``),[a,o]=(0,s.useState)(),u=e.summary?.agents??[],m=e.summary?.evidence??[],g=(0,s.useMemo)(()=>y(u),[u]),v=E(e.activeTab),b=(0,s.useMemo)(()=>v===void 0?[]:g.filter(e=>e.source.kind===v),[v,g]),x=b.find(e=>e.key===t)??b[0];(0,s.useEffect)(()=>{if(b.length===0){n(``);return}b.some(e=>e.key===t)||n((b.find(e=>e.source.inspectable===!0&&(e.source.itemCount??0)>0)??b.find(e=>e.source.inspectable===!0)??b[0])?.key??``)},[t,b]);let C=(0,s.useCallback)(async(e,t)=>{o(n=>({key:e.key,loading:!0,inspectable:n?.key===e.key?n.inspectable:e.source.inspectable===!0,items:t.append&&n?.key===e.key?n.items:[],...t.append&&n?.key===e.key&&n.nextCursor!==void 0?{nextCursor:n.nextCursor}:{},...n?.key===e.key&&n.totalCount!==void 0?{totalCount:n.totalCount}:{}}));try{let n=new URLSearchParams({agentId:e.agentId,sourceId:S(e.source),limit:String(l)});t.cursor!==void 0&&n.set(`cursor`,t.cursor);let r=await fetch(`/knowledge/items?${n.toString()}`);if(!r.ok)throw Error(`Knowledge items failed with HTTP ${r.status}`);let i=await r.json();o(n=>({key:e.key,loading:!1,inspectable:i.inspectable,items:t.append&&n?.key===e.key?[...n.items,...i.items]:i.items,...i.nextCursor===void 0?{}:{nextCursor:i.nextCursor},...i.totalCount===void 0?{}:{totalCount:i.totalCount},...i.message===void 0?{}:{message:i.message}}))}catch(t){o(n=>({key:e.key,loading:!1,inspectable:n?.inspectable??!1,items:n?.items??[],error:t instanceof Error?t.message:String(t)}))}},[]);return(0,s.useEffect)(()=>{if(x===void 0){o(void 0);return}C(x,{append:!1})},[C,x]),e.enabled?(0,c.jsxs)(`section`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55`,children:[(0,c.jsx)(`header`,{className:`bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur`,children:(0,c.jsxs)(`div`,{className:`grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1`,children:[(0,c.jsxs)(`div`,{className:`grid min-w-0 gap-2`,children:[(0,c.jsx)(`div`,{className:`font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary`,children:`Agent context`}),(0,c.jsx)(`h1`,{className:`m-0 text-2xl font-semibold leading-none tracking-tight text-foreground`,children:`Knowledge`}),(0,c.jsx)(`p`,{className:`m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground`,children:`Browse configured context, dynamic chunks, and retrieval evidence.`})]}),(0,c.jsxs)(i,{className:`h-8 min-h-8 gap-2`,type:`button`,variant:`secondary`,onClick:e.onRefresh,children:[(0,c.jsx)(r,{"aria-hidden":`true`}),`Refresh`]})]})}),(0,c.jsxs)(`div`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)] gap-4 overflow-hidden pb-6 pl-0 pr-6 pt-0`,children:[(0,c.jsx)(d,{activeTab:e.activeTab,sources:g,evidenceCount:m.length,onSelectTab:e.onSelectTab}),e.activeTab===`retrieval-log`?(0,c.jsx)(h,{evidence:m,onOpenTrace:e.onOpenTrace}):(0,c.jsx)(f,{sources:b,selectedKey:x?.key??``,loading:e.loading,activeTab:e.activeTab,onSelect:n,children:(0,c.jsx)(p,{source:x,state:a,onLoadMore:()=>{x!==void 0&&C(x,a?.nextCursor===void 0?{append:!0}:{append:!0,cursor:a.nextCursor})}})})]})]}):(0,c.jsx)(_,{title:`Knowledge unavailable`,text:`No registered agent exposes inspectable context.`})}function d(e){return(0,c.jsx)(`nav`,{className:`flex min-w-0 gap-7 overflow-x-auto border-b border-border/80`,"aria-label":`Knowledge sections`,children:b.map(t=>{let n=e.activeTab===t.id;return(0,c.jsxs)(`button`,{className:[`flex min-h-10 shrink-0 items-center gap-2 border-b px-0 pb-2 pt-1 text-left transition duration-200 hover:text-foreground focus-visible:outline-none`,n?`border-primary text-foreground`:`border-transparent text-muted-foreground hover:border-border`].join(` `),type:`button`,"aria-current":n?`page`:void 0,onClick:()=>e.onSelectTab(t.id),children:[(0,c.jsx)(`span`,{className:`text-sm font-semibold`,children:t.label}),(0,c.jsx)(`span`,{className:`font-mono text-[10px] text-muted-foreground`,children:O(t.id,e.sources,e.evidenceCount)})]},t.id)})})}function f(e){let t=e.sources.length!==1||e.loading;return(0,c.jsxs)(`div`,{className:[`grid min-h-0 gap-3 overflow-hidden`,t?`grid-rows-[auto_minmax(0,1fr)]`:`grid-rows-[minmax(0,1fr)]`].join(` `),children:[t?(0,c.jsx)(`div`,{className:`min-w-0 overflow-x-auto rounded-xl border border-border/80 bg-card/55`,children:(0,c.jsxs)(`div`,{className:`flex min-h-11 min-w-max items-center gap-2 px-3`,children:[(0,c.jsx)(`span`,{className:`mr-2 font-mono text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground`,children:D(e.activeTab)}),e.loading&&e.sources.length===0?(0,c.jsx)(`span`,{className:`font-mono text-[11px] text-muted-foreground`,children:`Loading sources`}):null,!e.loading&&e.sources.length===0?(0,c.jsx)(`span`,{className:`font-mono text-[11px] text-muted-foreground`,children:`No knowledge sources`}):null,e.sources.map(t=>(0,c.jsxs)(`button`,{className:[`flex h-7 items-center gap-2 rounded-lg border border-border/80 bg-background/45 px-2.5 font-mono text-[11px] font-semibold text-muted-foreground transition duration-200 hover:border-primary/45 hover:bg-primary/10 hover:text-foreground focus-visible:border-ring focus-visible:outline-none`,e.selectedKey===t.key?`border-primary/45 bg-primary/10 text-primary`:``].join(` `),type:`button`,onClick:()=>e.onSelect(t.key),children:[(0,c.jsx)(`span`,{children:t.source.label??T(t.source.kind)}),t.source.itemCount===void 0?null:(0,c.jsx)(`span`,{className:`text-muted-foreground`,children:t.source.itemCount})]},t.key))]})}):null,e.children]})}function p(e){let t=e.state;return(0,c.jsxs)(`section`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-xl border border-border/80 bg-card/55`,children:[(0,c.jsx)(`div`,{className:`border-b border-border/80 px-4 py-3`,children:(0,c.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0`,children:[(0,c.jsx)(`h2`,{className:`m-0 truncate text-sm font-semibold text-foreground`,children:e.source?.source.label??`Knowledge items`}),(0,c.jsx)(`p`,{className:`m-0 mt-1 truncate font-mono text-xs text-muted-foreground`,children:e.source===void 0?`No source selected`:`${e.source.agentId} / ${S(e.source.source)}`})]}),t?.totalCount===void 0?null:(0,c.jsxs)(a,{children:[t.totalCount,` total`]})]})}),(0,c.jsx)(`div`,{className:`min-h-0 overflow-auto`,children:(0,c.jsxs)(`div`,{className:`p-4`,children:[e.source===void 0?(0,c.jsx)(v,{text:`No knowledge source selected`}):null,t?.loading===!0&&t.items.length===0?(0,c.jsx)(v,{text:`Loading items`}):null,t?.error===void 0?null:(0,c.jsx)(v,{text:t.error}),t?.inspectable===!1?(0,c.jsx)(v,{text:t.message??`This source does not expose browseable chunks.`}):null,t?.inspectable!==!1&&t?.loading===!1&&t.items.length===0?(0,c.jsx)(v,{text:`No items in this source`}):null,(0,c.jsx)(`div`,{className:`grid gap-3`,children:t?.items.map(e=>(0,c.jsx)(m,{item:e},`${e.kind}:${e.id}`))})]})}),(0,c.jsxs)(`div`,{className:`flex min-h-12 items-center justify-between gap-3 bg-muted/10 px-4 py-2`,children:[(0,c.jsx)(`span`,{className:`font-mono text-[11px] text-muted-foreground`,children:t===void 0?`0 loaded`:`${t.items.length} loaded`}),(0,c.jsx)(i,{className:`h-8 min-h-8`,type:`button`,variant:`secondary`,disabled:t?.loading===!0||t?.nextCursor===void 0,onClick:e.onLoadMore,children:`Load more`})]})]})}function m(e){return(0,c.jsxs)(`article`,{className:`grid gap-3 rounded-xl border border-border/80 bg-background/55 p-4`,children:[(0,c.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0`,children:[(0,c.jsx)(`div`,{className:`truncate font-mono text-xs font-semibold text-primary`,children:e.item.toolName??e.item.id}),(0,c.jsx)(`div`,{className:`mt-1 font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground`,children:k(e.item.kind)})]}),e.item.parameterKeys===void 0||e.item.parameterKeys.length===0?null:(0,c.jsxs)(a,{children:[e.item.parameterKeys.length,` params`]})]}),e.item.description===void 0||e.item.description.length===0?null:(0,c.jsx)(`p`,{className:`m-0 text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]`,children:e.item.description}),e.item.text===void 0?null:(0,c.jsx)(`p`,{className:`m-0 whitespace-pre-wrap text-sm leading-6 text-foreground [overflow-wrap:anywhere]`,children:e.item.text}),e.item.document===void 0?null:(0,c.jsx)(g,{title:`Document`,value:e.item.document}),e.item.metadata===void 0?null:(0,c.jsx)(g,{title:`Metadata`,value:e.item.metadata}),e.item.parameterKeys===void 0||e.item.parameterKeys.length===0?null:(0,c.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:e.item.parameterKeys.map(e=>(0,c.jsx)(a,{children:e},e))})]})}function h(e){return(0,c.jsxs)(`section`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-xl border border-border/80 bg-card/55`,children:[(0,c.jsx)(`div`,{className:`border-b border-border/80 px-4 py-3`,children:(0,c.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0`,children:[(0,c.jsx)(`h2`,{className:`m-0 truncate text-sm font-semibold text-foreground`,children:`Retrieval log`}),(0,c.jsx)(`p`,{className:`m-0 mt-1 truncate font-mono text-xs text-muted-foreground`,children:`traces / retrieval-evidence`})]}),(0,c.jsxs)(a,{children:[e.evidence.length,` entries`]})]})}),(0,c.jsxs)(`div`,{className:`min-h-0 overflow-auto p-4`,children:[e.evidence.length===0?(0,c.jsx)(v,{text:`No retrieval evidence captured yet`}):null,(0,c.jsx)(`div`,{className:`grid gap-3`,children:e.evidence.map(t=>(0,c.jsxs)(`article`,{className:`grid gap-3 rounded-xl border border-border/80 bg-background/45 p-3`,children:[(0,c.jsxs)(`div`,{className:`flex min-w-0 items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`min-w-0`,children:[(0,c.jsx)(`div`,{className:`truncate text-sm font-semibold text-foreground`,children:t.observationName}),(0,c.jsxs)(`div`,{className:`mt-1 font-mono text-[11px] text-muted-foreground`,children:[`Turn `,t.turn]})]}),(0,c.jsx)(i,{className:`h-auto min-h-0 rounded-lg border border-border bg-muted px-2 py-1 font-mono text-[10px] text-muted-foreground`,type:`button`,variant:`ghost`,onClick:()=>e.onOpenTrace(t.traceId),children:`Trace`})]}),(0,c.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,c.jsxs)(a,{children:[t.documentCount,` docs`]}),(0,c.jsxs)(a,{children:[t.toolCount,` tools`]})]}),t.query===void 0?null:(0,c.jsxs)(`p`,{className:`m-0 text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]`,children:[(0,c.jsx)(`span`,{className:`font-mono text-xs font-semibold uppercase tracking-[0.14em] text-foreground`,children:`Query`}),` `,t.query]}),t.documents.slice(0,2).map(e=>(0,c.jsxs)(`p`,{className:`m-0 text-xs leading-5 text-muted-foreground [overflow-wrap:anywhere]`,children:[(0,c.jsx)(`span`,{className:`font-mono text-foreground`,children:e.id??`document`}),` `,e.text??``]},`${e.id??`doc`}:${e.text??``}`)),t.tools.length===0?null:(0,c.jsxs)(`p`,{className:`m-0 text-xs leading-5 text-muted-foreground`,children:[`Tools: `,t.tools.join(`, `)]})]},`${t.traceId}:${t.observationId}`))})]})]})}function g(e){return(0,c.jsxs)(`div`,{className:`grid gap-2 border-t border-border/70 pt-3`,children:[(0,c.jsx)(`div`,{className:`font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground`,children:e.title}),(0,c.jsx)(o,{value:e.value})]})}function _(e){return(0,c.jsx)(`section`,{className:`grid h-full place-items-center p-8`,children:(0,c.jsxs)(`div`,{className:`grid max-w-sm gap-2 text-center`,children:[(0,c.jsx)(`h1`,{className:`m-0 text-base font-semibold text-foreground`,children:e.title}),(0,c.jsx)(`p`,{className:`m-0 text-sm font-medium leading-6 text-muted-foreground`,children:e.text})]})})}function v(e){return(0,c.jsx)(`div`,{className:`rounded-lg border border-dashed border-border px-4 py-3 text-sm font-medium text-muted-foreground`,children:e.text})}function y(e){return e.flatMap(e=>e.sources.map((t,n)=>({key:`${e.agentId}:${S(t,n)}`,agentId:e.agentId,agentName:e.agentName??e.agentId,source:x(t,n)})))}var b=[{id:`static-context`,label:`Static Context`},{id:`dynamic-context`,label:`Dynamic Context`},{id:`dynamic-tools`,label:`Dynamic Tools`},{id:`retrieval-log`,label:`Retrieval Log`}];function x(e,t){return e.sourceId===void 0?{...e,sourceId:C(e,t)}:e}function S(e,t=0){return e.sourceId??C(e,t)}function C(e,t){switch(e.kind){case`static_context`:return`static-context`;case`dynamic_context`:return`dynamic-context-${e.registrationIndex??t}`;case`dynamic_tools`:return`dynamic-tools-${e.registrationIndex??t}`}}function w(e,t){return e.filter(e=>e.kind===t).reduce((e,t)=>e+(t.itemCount??t.count),0)}function T(e){switch(e){case`static_context`:return`Static context`;case`dynamic_context`:return`Dynamic context`;case`dynamic_tools`:return`Dynamic tools`}}function E(e){switch(e){case`static-context`:return`static_context`;case`dynamic-context`:return`dynamic_context`;case`dynamic-tools`:return`dynamic_tools`;case`retrieval-log`:return}}function D(e){return b.find(t=>t.id===e)?.label??`Knowledge`}function O(e,t,n){let r=E(e);if(r===void 0)return`${n} entries`;let i=t.filter(e=>e.source.kind===r),a=w(i.map(e=>e.source),r);return`${i.length} sources / ${a} items`}function k(e){switch(e){case`static_context`:return`Static context`;case`dynamic_context`:return`Dynamic context`;case`dynamic_tool`:return`Dynamic tool`}}export{u as KnowledgePage};
|
|
2
|
+
//# sourceMappingURL=knowledge-page-CR0JUneq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledge-page-DASnGzYP.js","names":[],"sources":["../../../src/ui/app/modules/knowledge/knowledge-page.tsx"],"sourcesContent":["import { ArrowClockwise } from \"@phosphor-icons/react\";\nimport { type ReactNode, useCallback, useEffect, useMemo, useState } from \"react\";\nimport type {\n StudioAgentKnowledgeConfig,\n StudioKnowledgeItem,\n StudioKnowledgeItemsPage,\n StudioKnowledgeSourceKind,\n StudioKnowledgeSourceSummary,\n StudioKnowledgeSummary,\n} from \"../../../../types\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { JsonValueView } from \"../shared/renderers\";\nimport type { KnowledgeTab } from \"../shared/types\";\n\nconst itemLimit = 50;\n\ntype KnowledgeSourceRef = {\n key: string;\n agentId: string;\n agentName: string;\n source: StudioKnowledgeSourceSummary;\n};\n\ntype ItemState = {\n key: string;\n loading: boolean;\n items: StudioKnowledgeItem[];\n nextCursor?: string;\n totalCount?: number;\n inspectable: boolean;\n message?: string;\n error?: string;\n};\n\nexport function KnowledgePage(props: {\n activeTab: KnowledgeTab;\n enabled: boolean;\n summary: StudioKnowledgeSummary | undefined;\n loading: boolean;\n onOpenTrace: (traceId: string) => void;\n onRefresh: () => void;\n onSelectTab: (tab: KnowledgeTab) => void;\n}) {\n const [selectedKey, setSelectedKey] = useState(\"\");\n const [itemState, setItemState] = useState<ItemState | undefined>();\n\n const agents = props.summary?.agents ?? [];\n const evidence = props.summary?.evidence ?? [];\n const sources = useMemo(() => flattenSources(agents), [agents]);\n const activeSourceKind = sourceKindForTab(props.activeTab);\n const visibleSources = useMemo(\n () =>\n activeSourceKind === undefined\n ? []\n : sources.filter((source) => source.source.kind === activeSourceKind),\n [activeSourceKind, sources],\n );\n const selectedSource =\n visibleSources.find((source) => source.key === selectedKey) ?? visibleSources[0];\n\n useEffect(() => {\n if (visibleSources.length === 0) {\n setSelectedKey(\"\");\n return;\n }\n if (visibleSources.some((source) => source.key === selectedKey)) {\n return;\n }\n const next =\n visibleSources.find(\n (source) => source.source.inspectable === true && (source.source.itemCount ?? 0) > 0,\n ) ??\n visibleSources.find((source) => source.source.inspectable === true) ??\n visibleSources[0];\n setSelectedKey(next?.key ?? \"\");\n }, [selectedKey, visibleSources]);\n\n const loadItems = useCallback(\n async (source: KnowledgeSourceRef, options: { append: boolean; cursor?: string }) => {\n setItemState((current) => ({\n key: source.key,\n loading: true,\n inspectable:\n current?.key === source.key ? current.inspectable : source.source.inspectable === true,\n items: options.append && current?.key === source.key ? current.items : [],\n ...(options.append && current?.key === source.key && current.nextCursor !== undefined\n ? { nextCursor: current.nextCursor }\n : {}),\n ...(current?.key === source.key && current.totalCount !== undefined\n ? { totalCount: current.totalCount }\n : {}),\n }));\n\n try {\n const params = new URLSearchParams({\n agentId: source.agentId,\n sourceId: sourceId(source.source),\n limit: String(itemLimit),\n });\n if (options.cursor !== undefined) {\n params.set(\"cursor\", options.cursor);\n }\n const response = await fetch(`/knowledge/items?${params.toString()}`);\n if (!response.ok) {\n throw new Error(`Knowledge items failed with HTTP ${response.status}`);\n }\n const page = (await response.json()) as StudioKnowledgeItemsPage;\n setItemState((current) => ({\n key: source.key,\n loading: false,\n inspectable: page.inspectable,\n items:\n options.append && current?.key === source.key\n ? [...current.items, ...page.items]\n : page.items,\n ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),\n ...(page.totalCount === undefined ? {} : { totalCount: page.totalCount }),\n ...(page.message === undefined ? {} : { message: page.message }),\n }));\n } catch (error) {\n setItemState((current) => ({\n key: source.key,\n loading: false,\n inspectable: current?.inspectable ?? false,\n items: current?.items ?? [],\n error: error instanceof Error ? error.message : String(error),\n }));\n }\n },\n [],\n );\n\n useEffect(() => {\n if (selectedSource === undefined) {\n setItemState(undefined);\n return;\n }\n void loadItems(selectedSource, { append: false });\n }, [loadItems, selectedSource]);\n\n if (!props.enabled) {\n return (\n <EmptyState\n title=\"Knowledge unavailable\"\n text=\"No registered agent exposes inspectable context.\"\n />\n );\n }\n\n return (\n <section className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55\">\n <header className=\"bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur\">\n <div className=\"grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1\">\n <div className=\"grid min-w-0 gap-2\">\n <div className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary\">\n Agent context\n </div>\n <h1 className=\"m-0 text-2xl font-semibold leading-none tracking-tight text-foreground\">\n Knowledge\n </h1>\n <p className=\"m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground\">\n Browse configured context, dynamic chunks, and retrieval evidence.\n </p>\n </div>\n <Button\n className=\"h-8 min-h-8 gap-2\"\n type=\"button\"\n variant=\"secondary\"\n onClick={props.onRefresh}\n >\n <ArrowClockwise aria-hidden=\"true\" />\n Refresh\n </Button>\n </div>\n </header>\n <div className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] gap-4 overflow-hidden pb-6 pl-0 pr-6 pt-0\">\n <KnowledgeTabs\n activeTab={props.activeTab}\n sources={sources}\n evidenceCount={evidence.length}\n onSelectTab={props.onSelectTab}\n />\n {props.activeTab === \"retrieval-log\" ? (\n <RetrievalLogPanel evidence={evidence} onOpenTrace={props.onOpenTrace} />\n ) : (\n <SourceWorkspace\n sources={visibleSources}\n selectedKey={selectedSource?.key ?? \"\"}\n loading={props.loading}\n activeTab={props.activeTab}\n onSelect={setSelectedKey}\n >\n <ItemBrowser\n source={selectedSource}\n state={itemState}\n onLoadMore={() => {\n if (selectedSource === undefined) {\n return;\n }\n void loadItems(\n selectedSource,\n itemState?.nextCursor === undefined\n ? { append: true }\n : { append: true, cursor: itemState.nextCursor },\n );\n }}\n />\n </SourceWorkspace>\n )}\n </div>\n </section>\n );\n}\n\nfunction KnowledgeTabs(props: {\n activeTab: KnowledgeTab;\n sources: KnowledgeSourceRef[];\n evidenceCount: number;\n onSelectTab: (tab: KnowledgeTab) => void;\n}) {\n return (\n <nav\n className=\"flex min-w-0 gap-7 overflow-x-auto border-b border-border/80\"\n aria-label=\"Knowledge sections\"\n >\n {knowledgeTabs.map((tab) => {\n const active = props.activeTab === tab.id;\n return (\n <button\n className={[\n \"flex min-h-10 shrink-0 items-center gap-2 border-b px-0 pb-2 pt-1 text-left transition duration-200 hover:text-foreground focus-visible:outline-none\",\n active\n ? \"border-primary text-foreground\"\n : \"border-transparent text-muted-foreground hover:border-border\",\n ].join(\" \")}\n key={tab.id}\n type=\"button\"\n aria-current={active ? \"page\" : undefined}\n onClick={() => props.onSelectTab(tab.id)}\n >\n <span className=\"text-sm font-semibold\">{tab.label}</span>\n <span className=\"font-mono text-[10px] text-muted-foreground\">\n {tabCountLabel(tab.id, props.sources, props.evidenceCount)}\n </span>\n </button>\n );\n })}\n </nav>\n );\n}\n\nfunction SourceWorkspace(props: {\n sources: KnowledgeSourceRef[];\n selectedKey: string;\n loading: boolean;\n activeTab: KnowledgeTab;\n onSelect: (key: string) => void;\n children: ReactNode;\n}) {\n const showSources = props.sources.length !== 1 || props.loading;\n return (\n <div\n className={[\n \"grid min-h-0 gap-3 overflow-hidden\",\n showSources ? \"grid-rows-[auto_minmax(0,1fr)]\" : \"grid-rows-[minmax(0,1fr)]\",\n ].join(\" \")}\n >\n {showSources ? (\n <div className=\"min-w-0 overflow-x-auto rounded-xl border border-border/80 bg-card/55\">\n <div className=\"flex min-h-11 min-w-max items-center gap-2 px-3\">\n <span className=\"mr-2 font-mono text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground\">\n {tabLabel(props.activeTab)}\n </span>\n {props.loading && props.sources.length === 0 ? (\n <span className=\"font-mono text-[11px] text-muted-foreground\">Loading sources</span>\n ) : null}\n {!props.loading && props.sources.length === 0 ? (\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n No knowledge sources\n </span>\n ) : null}\n {props.sources.map((source) => (\n <button\n className={[\n \"flex h-7 items-center gap-2 rounded-lg border border-border/80 bg-background/45 px-2.5 font-mono text-[11px] font-semibold text-muted-foreground transition duration-200 hover:border-primary/45 hover:bg-primary/10 hover:text-foreground focus-visible:border-ring focus-visible:outline-none\",\n props.selectedKey === source.key\n ? \"border-primary/45 bg-primary/10 text-primary\"\n : \"\",\n ].join(\" \")}\n key={source.key}\n type=\"button\"\n onClick={() => props.onSelect(source.key)}\n >\n <span>{source.source.label ?? sourceLabel(source.source.kind)}</span>\n {source.source.itemCount === undefined ? null : (\n <span className=\"text-muted-foreground\">{source.source.itemCount}</span>\n )}\n </button>\n ))}\n </div>\n </div>\n ) : null}\n {props.children}\n </div>\n );\n}\n\nfunction ItemBrowser(props: {\n source: KnowledgeSourceRef | undefined;\n state: ItemState | undefined;\n onLoadMore: () => void;\n}) {\n const state = props.state;\n return (\n <section className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-xl border border-border/80 bg-card/55\">\n <div className=\"border-b border-border/80 px-4 py-3\">\n <div className=\"flex min-w-0 items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h2 className=\"m-0 truncate text-sm font-semibold text-foreground\">\n {props.source?.source.label ?? \"Knowledge items\"}\n </h2>\n <p className=\"m-0 mt-1 truncate font-mono text-xs text-muted-foreground\">\n {props.source === undefined\n ? \"No source selected\"\n : `${props.source.agentId} / ${sourceId(props.source.source)}`}\n </p>\n </div>\n {state?.totalCount === undefined ? null : <Badge>{state.totalCount} total</Badge>}\n </div>\n </div>\n <div className=\"min-h-0 overflow-auto\">\n <div className=\"p-4\">\n {props.source === undefined ? <MutedRow text=\"No knowledge source selected\" /> : null}\n {state?.loading === true && state.items.length === 0 ? (\n <MutedRow text=\"Loading items\" />\n ) : null}\n {state?.error === undefined ? null : <MutedRow text={state.error} />}\n {state?.inspectable === false ? (\n <MutedRow text={state.message ?? \"This source does not expose browseable chunks.\"} />\n ) : null}\n {state?.inspectable !== false && state?.loading === false && state.items.length === 0 ? (\n <MutedRow text=\"No items in this source\" />\n ) : null}\n <div className=\"grid gap-3\">\n {state?.items.map((item) => (\n <KnowledgeItemCard item={item} key={`${item.kind}:${item.id}`} />\n ))}\n </div>\n </div>\n </div>\n <div className=\"flex min-h-12 items-center justify-between gap-3 bg-muted/10 px-4 py-2\">\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n {state === undefined ? \"0 loaded\" : `${state.items.length} loaded`}\n </span>\n <Button\n className=\"h-8 min-h-8\"\n type=\"button\"\n variant=\"secondary\"\n disabled={state?.loading === true || state?.nextCursor === undefined}\n onClick={props.onLoadMore}\n >\n Load more\n </Button>\n </div>\n </section>\n );\n}\n\nfunction KnowledgeItemCard(props: { item: StudioKnowledgeItem }) {\n return (\n <article className=\"grid gap-3 rounded-xl border border-border/80 bg-background/55 p-4\">\n <div className=\"flex min-w-0 items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"truncate font-mono text-xs font-semibold text-primary\">\n {props.item.toolName ?? props.item.id}\n </div>\n <div className=\"mt-1 font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground\">\n {itemKindLabel(props.item.kind)}\n </div>\n </div>\n {props.item.parameterKeys === undefined || props.item.parameterKeys.length === 0 ? null : (\n <Badge>{props.item.parameterKeys.length} params</Badge>\n )}\n </div>\n {props.item.description === undefined || props.item.description.length === 0 ? null : (\n <p className=\"m-0 text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]\">\n {props.item.description}\n </p>\n )}\n {props.item.text === undefined ? null : (\n <p className=\"m-0 whitespace-pre-wrap text-sm leading-6 text-foreground [overflow-wrap:anywhere]\">\n {props.item.text}\n </p>\n )}\n {props.item.document === undefined ? null : (\n <JsonBlock title=\"Document\" value={props.item.document} />\n )}\n {props.item.metadata === undefined ? null : (\n <JsonBlock title=\"Metadata\" value={props.item.metadata} />\n )}\n {props.item.parameterKeys === undefined || props.item.parameterKeys.length === 0 ? null : (\n <div className=\"flex flex-wrap gap-2\">\n {props.item.parameterKeys.map((key) => (\n <Badge key={key}>{key}</Badge>\n ))}\n </div>\n )}\n </article>\n );\n}\n\nfunction RetrievalLogPanel(props: {\n evidence: NonNullable<StudioKnowledgeSummary[\"evidence\"]>;\n onOpenTrace: (traceId: string) => void;\n}) {\n return (\n <section className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-xl border border-border/80 bg-card/55\">\n <div className=\"border-b border-border/80 px-4 py-3\">\n <div className=\"flex min-w-0 items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h2 className=\"m-0 truncate text-sm font-semibold text-foreground\">Retrieval log</h2>\n <p className=\"m-0 mt-1 truncate font-mono text-xs text-muted-foreground\">\n traces / retrieval-evidence\n </p>\n </div>\n <Badge>{props.evidence.length} entries</Badge>\n </div>\n </div>\n <div className=\"min-h-0 overflow-auto p-4\">\n {props.evidence.length === 0 ? (\n <MutedRow text=\"No retrieval evidence captured yet\" />\n ) : null}\n <div className=\"grid gap-3\">\n {props.evidence.map((item) => (\n <article\n className=\"grid gap-3 rounded-xl border border-border/80 bg-background/45 p-3\"\n key={`${item.traceId}:${item.observationId}`}\n >\n <div className=\"flex min-w-0 items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-semibold text-foreground\">\n {item.observationName}\n </div>\n <div className=\"mt-1 font-mono text-[11px] text-muted-foreground\">\n Turn {item.turn}\n </div>\n </div>\n <Button\n className=\"h-auto min-h-0 rounded-lg border border-border bg-muted px-2 py-1 font-mono text-[10px] text-muted-foreground\"\n type=\"button\"\n variant=\"ghost\"\n onClick={() => props.onOpenTrace(item.traceId)}\n >\n Trace\n </Button>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Badge>{item.documentCount} docs</Badge>\n <Badge>{item.toolCount} tools</Badge>\n </div>\n {item.query === undefined ? null : (\n <p className=\"m-0 text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]\">\n <span className=\"font-mono text-xs font-semibold uppercase tracking-[0.14em] text-foreground\">\n Query\n </span>{\" \"}\n {item.query}\n </p>\n )}\n {item.documents.slice(0, 2).map((document) => (\n <p\n className=\"m-0 text-xs leading-5 text-muted-foreground [overflow-wrap:anywhere]\"\n key={`${document.id ?? \"doc\"}:${document.text ?? \"\"}`}\n >\n <span className=\"font-mono text-foreground\">{document.id ?? \"document\"}</span>{\" \"}\n {document.text ?? \"\"}\n </p>\n ))}\n {item.tools.length === 0 ? null : (\n <p className=\"m-0 text-xs leading-5 text-muted-foreground\">\n Tools: {item.tools.join(\", \")}\n </p>\n )}\n </article>\n ))}\n </div>\n </div>\n </section>\n );\n}\n\nfunction JsonBlock(props: { title: string; value: unknown }) {\n return (\n <div className=\"grid gap-2 border-t border-border/70 pt-3\">\n <div className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground\">\n {props.title}\n </div>\n <JsonValueView value={props.value} />\n </div>\n );\n}\n\nfunction EmptyState(props: { title: string; text: string }) {\n return (\n <section className=\"grid h-full place-items-center p-8\">\n <div className=\"grid max-w-sm gap-2 text-center\">\n <h1 className=\"m-0 text-base font-semibold text-foreground\">{props.title}</h1>\n <p className=\"m-0 text-sm font-medium leading-6 text-muted-foreground\">{props.text}</p>\n </div>\n </section>\n );\n}\n\nfunction MutedRow(props: { text: string }) {\n return (\n <div className=\"rounded-lg border border-dashed border-border px-4 py-3 text-sm font-medium text-muted-foreground\">\n {props.text}\n </div>\n );\n}\n\nfunction flattenSources(agents: StudioAgentKnowledgeConfig[]): KnowledgeSourceRef[] {\n return agents.flatMap((agent) =>\n agent.sources.map((source, index) => ({\n key: `${agent.agentId}:${sourceId(source, index)}`,\n agentId: agent.agentId,\n agentName: agent.agentName ?? agent.agentId,\n source: withSourceId(source, index),\n })),\n );\n}\n\nconst knowledgeTabs: Array<{ id: KnowledgeTab; label: string }> = [\n { id: \"static-context\", label: \"Static Context\" },\n { id: \"dynamic-context\", label: \"Dynamic Context\" },\n { id: \"dynamic-tools\", label: \"Dynamic Tools\" },\n { id: \"retrieval-log\", label: \"Retrieval Log\" },\n];\n\nfunction withSourceId(\n source: StudioKnowledgeSourceSummary,\n index: number,\n): StudioKnowledgeSourceSummary {\n return source.sourceId === undefined\n ? { ...source, sourceId: fallbackSourceId(source, index) }\n : source;\n}\n\nfunction sourceId(source: StudioKnowledgeSourceSummary, index = 0): string {\n return source.sourceId ?? fallbackSourceId(source, index);\n}\n\nfunction fallbackSourceId(source: StudioKnowledgeSourceSummary, index: number): string {\n switch (source.kind) {\n case \"static_context\":\n return \"static-context\";\n case \"dynamic_context\":\n return `dynamic-context-${source.registrationIndex ?? index}`;\n case \"dynamic_tools\":\n return `dynamic-tools-${source.registrationIndex ?? index}`;\n }\n}\n\nfunction sumKind(sources: StudioKnowledgeSourceSummary[], kind: StudioKnowledgeSourceKind): number {\n return sources\n .filter((source) => source.kind === kind)\n .reduce((total, source) => total + (source.itemCount ?? source.count), 0);\n}\n\nfunction sourceLabel(kind: StudioKnowledgeSourceKind): string {\n switch (kind) {\n case \"static_context\":\n return \"Static context\";\n case \"dynamic_context\":\n return \"Dynamic context\";\n case \"dynamic_tools\":\n return \"Dynamic tools\";\n }\n}\n\nfunction sourceKindForTab(tab: KnowledgeTab): StudioKnowledgeSourceKind | undefined {\n switch (tab) {\n case \"static-context\":\n return \"static_context\";\n case \"dynamic-context\":\n return \"dynamic_context\";\n case \"dynamic-tools\":\n return \"dynamic_tools\";\n case \"retrieval-log\":\n return undefined;\n }\n}\n\nfunction tabLabel(tab: KnowledgeTab): string {\n return knowledgeTabs.find((item) => item.id === tab)?.label ?? \"Knowledge\";\n}\n\nfunction tabCountLabel(\n tab: KnowledgeTab,\n sources: KnowledgeSourceRef[],\n evidenceCount: number,\n): string {\n const sourceKind = sourceKindForTab(tab);\n if (sourceKind === undefined) {\n return `${evidenceCount} entries`;\n }\n const tabSources = sources.filter((source) => source.source.kind === sourceKind);\n const itemCount = sumKind(\n tabSources.map((source) => source.source),\n sourceKind,\n );\n return `${tabSources.length} sources / ${itemCount} items`;\n}\n\nfunction itemKindLabel(kind: StudioKnowledgeItem[\"kind\"]): string {\n switch (kind) {\n case \"static_context\":\n return \"Static context\";\n case \"dynamic_context\":\n return \"Dynamic context\";\n case \"dynamic_tool\":\n return \"Dynamic tool\";\n }\n}\n"],"mappings":"iQAeM,EAAY,GAoBlB,SAAgB,EAAc,EAQ3B,CACD,GAAM,CAAC,EAAa,IAAA,EAAA,EAAA,UAA2B,GAAG,CAC5C,CAAC,EAAW,IAAA,EAAA,EAAA,WAAiD,CAE7D,EAAS,EAAM,SAAS,QAAU,EAAE,CACpC,EAAW,EAAM,SAAS,UAAY,EAAE,CACxC,GAAA,EAAA,EAAA,aAAwB,EAAe,EAAO,CAAE,CAAC,EAAO,CAAC,CACzD,EAAmB,EAAiB,EAAM,UAAU,CACpD,GAAA,EAAA,EAAA,aAEF,IAAqB,IAAA,GACjB,EAAE,CACF,EAAQ,OAAQ,GAAW,EAAO,OAAO,OAAS,EAAiB,CACzE,CAAC,EAAkB,EAAQ,CAC5B,CACK,EACJ,EAAe,KAAM,GAAW,EAAO,MAAQ,EAAY,EAAI,EAAe,IAEhF,EAAA,EAAA,eAAgB,CACd,GAAI,EAAe,SAAW,EAAG,CAC/B,EAAe,GAAG,CAClB,OAEE,EAAe,KAAM,GAAW,EAAO,MAAQ,EAAY,EAS/D,GALE,EAAe,KACZ,GAAW,EAAO,OAAO,cAAgB,KAAS,EAAO,OAAO,WAAa,GAAK,EACpF,EACD,EAAe,KAAM,GAAW,EAAO,OAAO,cAAgB,GAAK,EACnE,EAAe,KACI,KAAO,GAAG,EAC9B,CAAC,EAAa,EAAe,CAAC,CAEjC,IAAM,GAAA,EAAA,EAAA,aACJ,MAAO,EAA4B,IAAkD,CACnF,EAAc,IAAa,CACzB,IAAK,EAAO,IACZ,QAAS,GACT,YACE,GAAS,MAAQ,EAAO,IAAM,EAAQ,YAAc,EAAO,OAAO,cAAgB,GACpF,MAAO,EAAQ,QAAU,GAAS,MAAQ,EAAO,IAAM,EAAQ,MAAQ,EAAE,CACzE,GAAI,EAAQ,QAAU,GAAS,MAAQ,EAAO,KAAO,EAAQ,aAAe,IAAA,GACxE,CAAE,WAAY,EAAQ,WAAY,CAClC,EAAE,CACN,GAAI,GAAS,MAAQ,EAAO,KAAO,EAAQ,aAAe,IAAA,GACtD,CAAE,WAAY,EAAQ,WAAY,CAClC,EAAE,CACP,EAAE,CAEH,GAAI,CACF,IAAM,EAAS,IAAI,gBAAgB,CACjC,QAAS,EAAO,QAChB,SAAU,EAAS,EAAO,OAAO,CACjC,MAAO,OAAO,EAAU,CACzB,CAAC,CACE,EAAQ,SAAW,IAAA,IACrB,EAAO,IAAI,SAAU,EAAQ,OAAO,CAEtC,IAAM,EAAW,MAAM,MAAM,oBAAoB,EAAO,UAAU,GAAG,CACrE,GAAI,CAAC,EAAS,GACZ,MAAU,MAAM,oCAAoC,EAAS,SAAS,CAExE,IAAM,EAAQ,MAAM,EAAS,MAAM,CACnC,EAAc,IAAa,CACzB,IAAK,EAAO,IACZ,QAAS,GACT,YAAa,EAAK,YAClB,MACE,EAAQ,QAAU,GAAS,MAAQ,EAAO,IACtC,CAAC,GAAG,EAAQ,MAAO,GAAG,EAAK,MAAM,CACjC,EAAK,MACX,GAAI,EAAK,aAAe,IAAA,GAAY,EAAE,CAAG,CAAE,WAAY,EAAK,WAAY,CACxE,GAAI,EAAK,aAAe,IAAA,GAAY,EAAE,CAAG,CAAE,WAAY,EAAK,WAAY,CACxE,GAAI,EAAK,UAAY,IAAA,GAAY,EAAE,CAAG,CAAE,QAAS,EAAK,QAAS,CAChE,EAAE,OACI,EAAO,CACd,EAAc,IAAa,CACzB,IAAK,EAAO,IACZ,QAAS,GACT,YAAa,GAAS,aAAe,GACrC,MAAO,GAAS,OAAS,EAAE,CAC3B,MAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAC9D,EAAE,GAGP,EAAE,CACH,CAmBD,OAjBA,EAAA,EAAA,eAAgB,CACd,GAAI,IAAmB,IAAA,GAAW,CAChC,EAAa,IAAA,GAAU,CACvB,OAEG,EAAU,EAAgB,CAAE,OAAQ,GAAO,CAAC,EAChD,CAAC,EAAW,EAAe,CAAC,CAE1B,EAAM,SAUT,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,wFAAnB,EACE,EAAA,EAAA,KAAC,SAAD,CAAQ,UAAU,+DAChB,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,yFAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,8BAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wFAA+E,gBAExF,CAAA,EACN,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,kFAAyE,YAElF,CAAA,EACL,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,oEAA2D,qEAEpE,CAAA,CACA,IACN,EAAA,EAAA,MAAC,EAAD,CACE,UAAU,oBACV,KAAK,SACL,QAAQ,YACR,QAAS,EAAM,mBAJjB,EAME,EAAA,EAAA,KAAC,EAAD,CAAgB,cAAY,OAAS,CAAA,CAAA,UAE9B,GACL,GACC,CAAA,EACT,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,iGAAf,EACE,EAAA,EAAA,KAAC,EAAD,CACE,UAAW,EAAM,UACR,UACT,cAAe,EAAS,OACxB,YAAa,EAAM,YACnB,CAAA,CACD,EAAM,YAAc,iBACnB,EAAA,EAAA,KAAC,EAAD,CAA6B,WAAU,YAAa,EAAM,YAAe,CAAA,EAEzE,EAAA,EAAA,KAAC,EAAD,CACE,QAAS,EACT,YAAa,GAAgB,KAAO,GACpC,QAAS,EAAM,QACf,UAAW,EAAM,UACjB,SAAU,YAEV,EAAA,EAAA,KAAC,EAAD,CACE,OAAQ,EACR,MAAO,EACP,eAAkB,CACZ,IAAmB,IAAA,IAGlB,EACH,EACA,GAAW,aAAe,IAAA,GACtB,CAAE,OAAQ,GAAM,CAChB,CAAE,OAAQ,GAAM,OAAQ,EAAU,WAAY,CACnD,EAEH,CAAA,CACc,CAAA,CAEhB,GACE,IApER,EAAA,EAAA,KAAC,EAAD,CACE,MAAM,wBACN,KAAK,mDACL,CAAA,CAqER,SAAS,EAAc,EAKpB,CACD,OACE,EAAA,EAAA,KAAC,MAAD,CACE,UAAU,+DACV,aAAW,8BAEV,EAAc,IAAK,GAAQ,CAC1B,IAAM,EAAS,EAAM,YAAc,EAAI,GACvC,OACE,EAAA,EAAA,MAAC,SAAD,CACE,UAAW,CACT,uJACA,EACI,iCACA,+DACL,CAAC,KAAK,IAAI,CAEX,KAAK,SACL,eAAc,EAAS,OAAS,IAAA,GAChC,YAAe,EAAM,YAAY,EAAI,GAAG,UAV1C,EAYE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,iCAAyB,EAAI,MAAa,CAAA,EAC1D,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,uDACb,EAAc,EAAI,GAAI,EAAM,QAAS,EAAM,cAAc,CACrD,CAAA,CACA,EATF,EAAI,GASF,EAEX,CACE,CAAA,CAIV,SAAS,EAAgB,EAOtB,CACD,IAAM,EAAc,EAAM,QAAQ,SAAW,GAAK,EAAM,QACxD,OACE,EAAA,EAAA,MAAC,MAAD,CACE,UAAW,CACT,qCACA,EAAc,iCAAmC,4BAClD,CAAC,KAAK,IAAI,UAJb,CAMG,GACC,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,kFACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,2DAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,sGACb,EAAS,EAAM,UAAU,CACrB,CAAA,CACN,EAAM,SAAW,EAAM,QAAQ,SAAW,GACzC,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,uDAA8C,kBAAsB,CAAA,CAClF,KACH,CAAC,EAAM,SAAW,EAAM,QAAQ,SAAW,GAC1C,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,uDAA8C,uBAEvD,CAAA,CACL,KACH,EAAM,QAAQ,IAAK,IAClB,EAAA,EAAA,MAAC,SAAD,CACE,UAAW,CACT,kSACA,EAAM,cAAgB,EAAO,IACzB,+CACA,GACL,CAAC,KAAK,IAAI,CAEX,KAAK,SACL,YAAe,EAAM,SAAS,EAAO,IAAI,UAT3C,EAWE,EAAA,EAAA,KAAC,OAAD,CAAA,SAAO,EAAO,OAAO,OAAS,EAAY,EAAO,OAAO,KAAK,CAAQ,CAAA,CACpE,EAAO,OAAO,YAAc,IAAA,GAAY,MACvC,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,iCAAyB,EAAO,OAAO,UAAiB,CAAA,CAEnE,EARF,EAAO,IAQL,CACT,CACE,GACF,CAAA,CACJ,KACH,EAAM,SACH,GAIV,SAAS,EAAY,EAIlB,CACD,IAAM,EAAQ,EAAM,MACpB,OACE,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,0HAAnB,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gDACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0DAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mBAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,8DACX,EAAM,QAAQ,OAAO,OAAS,kBAC5B,CAAA,EACL,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,qEACV,EAAM,SAAW,IAAA,GACd,qBACA,GAAG,EAAM,OAAO,QAAQ,KAAK,EAAS,EAAM,OAAO,OAAO,GAC5D,CAAA,CACA,GACL,GAAO,aAAe,IAAA,GAAY,MAAO,EAAA,EAAA,MAAC,EAAD,CAAA,SAAA,CAAQ,EAAM,WAAW,SAAc,CAAA,CAAA,CAC7E,GACF,CAAA,EACN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,kCACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,eAAf,CACG,EAAM,SAAW,IAAA,IAAY,EAAA,EAAA,KAAC,EAAD,CAAU,KAAK,+BAAiC,CAAA,CAAG,KAChF,GAAO,UAAY,IAAQ,EAAM,MAAM,SAAW,GACjD,EAAA,EAAA,KAAC,EAAD,CAAU,KAAK,gBAAkB,CAAA,CAC/B,KACH,GAAO,QAAU,IAAA,GAAY,MAAO,EAAA,EAAA,KAAC,EAAD,CAAU,KAAM,EAAM,MAAS,CAAA,CACnE,GAAO,cAAgB,IACtB,EAAA,EAAA,KAAC,EAAD,CAAU,KAAM,EAAM,SAAW,iDAAoD,CAAA,CACnF,KACH,GAAO,cAAgB,IAAS,GAAO,UAAY,IAAS,EAAM,MAAM,SAAW,GAClF,EAAA,EAAA,KAAC,EAAD,CAAU,KAAK,0BAA4B,CAAA,CACzC,MACJ,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,sBACZ,GAAO,MAAM,IAAK,IACjB,EAAA,EAAA,KAAC,EAAD,CAAyB,OAAwC,CAA7B,GAAG,EAAK,KAAK,GAAG,EAAK,KAAQ,CACjE,CACE,CAAA,CACF,GACF,CAAA,EACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kFAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,uDACb,IAAU,IAAA,GAAY,WAAa,GAAG,EAAM,MAAM,OAAO,SACrD,CAAA,EACP,EAAA,EAAA,KAAC,EAAD,CACE,UAAU,cACV,KAAK,SACL,QAAQ,YACR,SAAU,GAAO,UAAY,IAAQ,GAAO,aAAe,IAAA,GAC3D,QAAS,EAAM,oBAChB,YAEQ,CAAA,CACL,GACE,GAId,SAAS,EAAkB,EAAsC,CAC/D,OACE,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,8EAAnB,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0DAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mBAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iEACZ,EAAM,KAAK,UAAY,EAAM,KAAK,GAC/B,CAAA,EACN,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,sGACZ,EAAc,EAAM,KAAK,KAAK,CAC3B,CAAA,CACF,GACL,EAAM,KAAK,gBAAkB,IAAA,IAAa,EAAM,KAAK,cAAc,SAAW,EAAI,MACjF,EAAA,EAAA,MAAC,EAAD,CAAA,SAAA,CAAQ,EAAM,KAAK,cAAc,OAAO,UAAe,CAAA,CAAA,CAErD,GACL,EAAM,KAAK,cAAgB,IAAA,IAAa,EAAM,KAAK,YAAY,SAAW,EAAI,MAC7E,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,gFACV,EAAM,KAAK,YACV,CAAA,CAEL,EAAM,KAAK,OAAS,IAAA,GAAY,MAC/B,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,8FACV,EAAM,KAAK,KACV,CAAA,CAEL,EAAM,KAAK,WAAa,IAAA,GAAY,MACnC,EAAA,EAAA,KAAC,EAAD,CAAW,MAAM,WAAW,MAAO,EAAM,KAAK,SAAY,CAAA,CAE3D,EAAM,KAAK,WAAa,IAAA,GAAY,MACnC,EAAA,EAAA,KAAC,EAAD,CAAW,MAAM,WAAW,MAAO,EAAM,KAAK,SAAY,CAAA,CAE3D,EAAM,KAAK,gBAAkB,IAAA,IAAa,EAAM,KAAK,cAAc,SAAW,EAAI,MACjF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gCACZ,EAAM,KAAK,cAAc,IAAK,IAC7B,EAAA,EAAA,KAAC,EAAD,CAAA,SAAkB,EAAY,CAAlB,EAAkB,CAC9B,CACE,CAAA,CAEA,GAId,SAAS,EAAkB,EAGxB,CACD,OACE,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,qHAAnB,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gDACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0DAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mBAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,8DAAqD,gBAAkB,CAAA,EACrF,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,qEAA4D,8BAErE,CAAA,CACA,IACN,EAAA,EAAA,MAAC,EAAD,CAAA,SAAA,CAAQ,EAAM,SAAS,OAAO,WAAgB,CAAA,CAAA,CAC1C,GACF,CAAA,EACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,qCAAf,CACG,EAAM,SAAS,SAAW,GACzB,EAAA,EAAA,KAAC,EAAD,CAAU,KAAK,qCAAuC,CAAA,CACpD,MACJ,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,sBACZ,EAAM,SAAS,IAAK,IACnB,EAAA,EAAA,MAAC,UAAD,CACE,UAAU,8EADZ,EAIE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0DAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mBAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,0DACZ,EAAK,gBACF,CAAA,EACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,4DAAf,CAAkE,QAC1D,EAAK,KACP,GACF,IACN,EAAA,EAAA,KAAC,EAAD,CACE,UAAU,gHACV,KAAK,SACL,QAAQ,QACR,YAAe,EAAM,YAAY,EAAK,QAAQ,UAC/C,QAEQ,CAAA,CACL,IACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,gCAAf,EACE,EAAA,EAAA,MAAC,EAAD,CAAA,SAAA,CAAQ,EAAK,cAAc,QAAa,CAAA,CAAA,EACxC,EAAA,EAAA,MAAC,EAAD,CAAA,SAAA,CAAQ,EAAK,UAAU,SAAc,CAAA,CAAA,CACjC,GACL,EAAK,QAAU,IAAA,GAAY,MAC1B,EAAA,EAAA,MAAC,IAAD,CAAG,UAAU,gFAAb,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,uFAA8E,QAEvF,CAAA,CAAC,IACP,EAAK,MACJ,GAEL,EAAK,UAAU,MAAM,EAAG,EAAE,CAAC,IAAK,IAC/B,EAAA,EAAA,MAAC,IAAD,CACE,UAAU,gFADZ,EAIE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,qCAA6B,EAAS,IAAM,WAAkB,CAAA,CAAC,IAC9E,EAAS,MAAQ,GAChB,EAJG,GAAG,EAAS,IAAM,MAAM,GAAG,EAAS,MAAQ,KAI/C,CACJ,CACD,EAAK,MAAM,SAAW,EAAI,MACzB,EAAA,EAAA,MAAC,IAAD,CAAG,UAAU,uDAAb,CAA2D,UACjD,EAAK,MAAM,KAAK,KAAK,CAC3B,GAEE,EA9CH,GAAG,EAAK,QAAQ,GAAG,EAAK,gBA8CrB,CACV,CACE,CAAA,CACF,GACE,GAId,SAAS,EAAU,EAA0C,CAC3D,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,qDAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,iGACZ,EAAM,MACH,CAAA,EACN,EAAA,EAAA,KAAC,EAAD,CAAe,MAAO,EAAM,MAAS,CAAA,CACjC,GAIV,SAAS,EAAW,EAAwC,CAC1D,OACE,EAAA,EAAA,KAAC,UAAD,CAAS,UAAU,+CACjB,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,2CAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,uDAA+C,EAAM,MAAW,CAAA,EAC9E,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,mEAA2D,EAAM,KAAS,CAAA,CACnF,GACE,CAAA,CAId,SAAS,EAAS,EAAyB,CACzC,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,6GACZ,EAAM,KACH,CAAA,CAIV,SAAS,EAAe,EAA4D,CAClF,OAAO,EAAO,QAAS,GACrB,EAAM,QAAQ,KAAK,EAAQ,KAAW,CACpC,IAAK,GAAG,EAAM,QAAQ,GAAG,EAAS,EAAQ,EAAM,GAChD,QAAS,EAAM,QACf,UAAW,EAAM,WAAa,EAAM,QACpC,OAAQ,EAAa,EAAQ,EAAM,CACpC,EAAE,CACJ,CAGH,IAAM,EAA4D,CAChE,CAAE,GAAI,iBAAkB,MAAO,iBAAkB,CACjD,CAAE,GAAI,kBAAmB,MAAO,kBAAmB,CACnD,CAAE,GAAI,gBAAiB,MAAO,gBAAiB,CAC/C,CAAE,GAAI,gBAAiB,MAAO,gBAAiB,CAChD,CAED,SAAS,EACP,EACA,EAC8B,CAC9B,OAAO,EAAO,WAAa,IAAA,GACvB,CAAE,GAAG,EAAQ,SAAU,EAAiB,EAAQ,EAAM,CAAE,CACxD,EAGN,SAAS,EAAS,EAAsC,EAAQ,EAAW,CACzE,OAAO,EAAO,UAAY,EAAiB,EAAQ,EAAM,CAG3D,SAAS,EAAiB,EAAsC,EAAuB,CACrF,OAAQ,EAAO,KAAf,CACE,IAAK,iBACH,MAAO,iBACT,IAAK,kBACH,MAAO,mBAAmB,EAAO,mBAAqB,IACxD,IAAK,gBACH,MAAO,iBAAiB,EAAO,mBAAqB,KAI1D,SAAS,EAAQ,EAAyC,EAAyC,CACjG,OAAO,EACJ,OAAQ,GAAW,EAAO,OAAS,EAAK,CACxC,QAAQ,EAAO,IAAW,GAAS,EAAO,WAAa,EAAO,OAAQ,EAAE,CAG7E,SAAS,EAAY,EAAyC,CAC5D,OAAQ,EAAR,CACE,IAAK,iBACH,MAAO,iBACT,IAAK,kBACH,MAAO,kBACT,IAAK,gBACH,MAAO,iBAIb,SAAS,EAAiB,EAA0D,CAClF,OAAQ,EAAR,CACE,IAAK,iBACH,MAAO,iBACT,IAAK,kBACH,MAAO,kBACT,IAAK,gBACH,MAAO,gBACT,IAAK,gBACH,QAIN,SAAS,EAAS,EAA2B,CAC3C,OAAO,EAAc,KAAM,GAAS,EAAK,KAAO,EAAI,EAAE,OAAS,YAGjE,SAAS,EACP,EACA,EACA,EACQ,CACR,IAAM,EAAa,EAAiB,EAAI,CACxC,GAAI,IAAe,IAAA,GACjB,MAAO,GAAG,EAAc,UAE1B,IAAM,EAAa,EAAQ,OAAQ,GAAW,EAAO,OAAO,OAAS,EAAW,CAC1E,EAAY,EAChB,EAAW,IAAK,GAAW,EAAO,OAAO,CACzC,EACD,CACD,MAAO,GAAG,EAAW,OAAO,aAAa,EAAU,QAGrD,SAAS,EAAc,EAA2C,CAChE,OAAQ,EAAR,CACE,IAAK,iBACH,MAAO,iBACT,IAAK,kBACH,MAAO,kBACT,IAAK,eACH,MAAO"}
|
|
1
|
+
{"version":3,"file":"knowledge-page-CR0JUneq.js","names":[],"sources":["../../../src/ui/app/modules/knowledge/knowledge-page.tsx"],"sourcesContent":["import { ArrowClockwise } from \"@phosphor-icons/react\";\nimport { type ReactNode, useCallback, useEffect, useMemo, useState } from \"react\";\nimport type {\n StudioAgentKnowledgeConfig,\n StudioKnowledgeItem,\n StudioKnowledgeItemsPage,\n StudioKnowledgeSourceKind,\n StudioKnowledgeSourceSummary,\n StudioKnowledgeSummary,\n} from \"../../../../types\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { JsonValueView } from \"../shared/renderers\";\nimport type { KnowledgeTab } from \"../shared/types\";\n\nconst itemLimit = 50;\n\ntype KnowledgeSourceRef = {\n key: string;\n agentId: string;\n agentName: string;\n source: StudioKnowledgeSourceSummary;\n};\n\ntype ItemState = {\n key: string;\n loading: boolean;\n items: StudioKnowledgeItem[];\n nextCursor?: string;\n totalCount?: number;\n inspectable: boolean;\n message?: string;\n error?: string;\n};\n\nexport function KnowledgePage(props: {\n activeTab: KnowledgeTab;\n enabled: boolean;\n summary: StudioKnowledgeSummary | undefined;\n loading: boolean;\n onOpenTrace: (traceId: string) => void;\n onRefresh: () => void;\n onSelectTab: (tab: KnowledgeTab) => void;\n}) {\n const [selectedKey, setSelectedKey] = useState(\"\");\n const [itemState, setItemState] = useState<ItemState | undefined>();\n\n const agents = props.summary?.agents ?? [];\n const evidence = props.summary?.evidence ?? [];\n const sources = useMemo(() => flattenSources(agents), [agents]);\n const activeSourceKind = sourceKindForTab(props.activeTab);\n const visibleSources = useMemo(\n () =>\n activeSourceKind === undefined\n ? []\n : sources.filter((source) => source.source.kind === activeSourceKind),\n [activeSourceKind, sources],\n );\n const selectedSource =\n visibleSources.find((source) => source.key === selectedKey) ?? visibleSources[0];\n\n useEffect(() => {\n if (visibleSources.length === 0) {\n setSelectedKey(\"\");\n return;\n }\n if (visibleSources.some((source) => source.key === selectedKey)) {\n return;\n }\n const next =\n visibleSources.find(\n (source) => source.source.inspectable === true && (source.source.itemCount ?? 0) > 0,\n ) ??\n visibleSources.find((source) => source.source.inspectable === true) ??\n visibleSources[0];\n setSelectedKey(next?.key ?? \"\");\n }, [selectedKey, visibleSources]);\n\n const loadItems = useCallback(\n async (source: KnowledgeSourceRef, options: { append: boolean; cursor?: string }) => {\n setItemState((current) => ({\n key: source.key,\n loading: true,\n inspectable:\n current?.key === source.key ? current.inspectable : source.source.inspectable === true,\n items: options.append && current?.key === source.key ? current.items : [],\n ...(options.append && current?.key === source.key && current.nextCursor !== undefined\n ? { nextCursor: current.nextCursor }\n : {}),\n ...(current?.key === source.key && current.totalCount !== undefined\n ? { totalCount: current.totalCount }\n : {}),\n }));\n\n try {\n const params = new URLSearchParams({\n agentId: source.agentId,\n sourceId: sourceId(source.source),\n limit: String(itemLimit),\n });\n if (options.cursor !== undefined) {\n params.set(\"cursor\", options.cursor);\n }\n const response = await fetch(`/knowledge/items?${params.toString()}`);\n if (!response.ok) {\n throw new Error(`Knowledge items failed with HTTP ${response.status}`);\n }\n const page = (await response.json()) as StudioKnowledgeItemsPage;\n setItemState((current) => ({\n key: source.key,\n loading: false,\n inspectable: page.inspectable,\n items:\n options.append && current?.key === source.key\n ? [...current.items, ...page.items]\n : page.items,\n ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),\n ...(page.totalCount === undefined ? {} : { totalCount: page.totalCount }),\n ...(page.message === undefined ? {} : { message: page.message }),\n }));\n } catch (error) {\n setItemState((current) => ({\n key: source.key,\n loading: false,\n inspectable: current?.inspectable ?? false,\n items: current?.items ?? [],\n error: error instanceof Error ? error.message : String(error),\n }));\n }\n },\n [],\n );\n\n useEffect(() => {\n if (selectedSource === undefined) {\n setItemState(undefined);\n return;\n }\n void loadItems(selectedSource, { append: false });\n }, [loadItems, selectedSource]);\n\n if (!props.enabled) {\n return (\n <EmptyState\n title=\"Knowledge unavailable\"\n text=\"No registered agent exposes inspectable context.\"\n />\n );\n }\n\n return (\n <section className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55\">\n <header className=\"bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur\">\n <div className=\"grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1\">\n <div className=\"grid min-w-0 gap-2\">\n <div className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary\">\n Agent context\n </div>\n <h1 className=\"m-0 text-2xl font-semibold leading-none tracking-tight text-foreground\">\n Knowledge\n </h1>\n <p className=\"m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground\">\n Browse configured context, dynamic chunks, and retrieval evidence.\n </p>\n </div>\n <Button\n className=\"h-8 min-h-8 gap-2\"\n type=\"button\"\n variant=\"secondary\"\n onClick={props.onRefresh}\n >\n <ArrowClockwise aria-hidden=\"true\" />\n Refresh\n </Button>\n </div>\n </header>\n <div className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] gap-4 overflow-hidden pb-6 pl-0 pr-6 pt-0\">\n <KnowledgeTabs\n activeTab={props.activeTab}\n sources={sources}\n evidenceCount={evidence.length}\n onSelectTab={props.onSelectTab}\n />\n {props.activeTab === \"retrieval-log\" ? (\n <RetrievalLogPanel evidence={evidence} onOpenTrace={props.onOpenTrace} />\n ) : (\n <SourceWorkspace\n sources={visibleSources}\n selectedKey={selectedSource?.key ?? \"\"}\n loading={props.loading}\n activeTab={props.activeTab}\n onSelect={setSelectedKey}\n >\n <ItemBrowser\n source={selectedSource}\n state={itemState}\n onLoadMore={() => {\n if (selectedSource === undefined) {\n return;\n }\n void loadItems(\n selectedSource,\n itemState?.nextCursor === undefined\n ? { append: true }\n : { append: true, cursor: itemState.nextCursor },\n );\n }}\n />\n </SourceWorkspace>\n )}\n </div>\n </section>\n );\n}\n\nfunction KnowledgeTabs(props: {\n activeTab: KnowledgeTab;\n sources: KnowledgeSourceRef[];\n evidenceCount: number;\n onSelectTab: (tab: KnowledgeTab) => void;\n}) {\n return (\n <nav\n className=\"flex min-w-0 gap-7 overflow-x-auto border-b border-border/80\"\n aria-label=\"Knowledge sections\"\n >\n {knowledgeTabs.map((tab) => {\n const active = props.activeTab === tab.id;\n return (\n <button\n className={[\n \"flex min-h-10 shrink-0 items-center gap-2 border-b px-0 pb-2 pt-1 text-left transition duration-200 hover:text-foreground focus-visible:outline-none\",\n active\n ? \"border-primary text-foreground\"\n : \"border-transparent text-muted-foreground hover:border-border\",\n ].join(\" \")}\n key={tab.id}\n type=\"button\"\n aria-current={active ? \"page\" : undefined}\n onClick={() => props.onSelectTab(tab.id)}\n >\n <span className=\"text-sm font-semibold\">{tab.label}</span>\n <span className=\"font-mono text-[10px] text-muted-foreground\">\n {tabCountLabel(tab.id, props.sources, props.evidenceCount)}\n </span>\n </button>\n );\n })}\n </nav>\n );\n}\n\nfunction SourceWorkspace(props: {\n sources: KnowledgeSourceRef[];\n selectedKey: string;\n loading: boolean;\n activeTab: KnowledgeTab;\n onSelect: (key: string) => void;\n children: ReactNode;\n}) {\n const showSources = props.sources.length !== 1 || props.loading;\n return (\n <div\n className={[\n \"grid min-h-0 gap-3 overflow-hidden\",\n showSources ? \"grid-rows-[auto_minmax(0,1fr)]\" : \"grid-rows-[minmax(0,1fr)]\",\n ].join(\" \")}\n >\n {showSources ? (\n <div className=\"min-w-0 overflow-x-auto rounded-xl border border-border/80 bg-card/55\">\n <div className=\"flex min-h-11 min-w-max items-center gap-2 px-3\">\n <span className=\"mr-2 font-mono text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground\">\n {tabLabel(props.activeTab)}\n </span>\n {props.loading && props.sources.length === 0 ? (\n <span className=\"font-mono text-[11px] text-muted-foreground\">Loading sources</span>\n ) : null}\n {!props.loading && props.sources.length === 0 ? (\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n No knowledge sources\n </span>\n ) : null}\n {props.sources.map((source) => (\n <button\n className={[\n \"flex h-7 items-center gap-2 rounded-lg border border-border/80 bg-background/45 px-2.5 font-mono text-[11px] font-semibold text-muted-foreground transition duration-200 hover:border-primary/45 hover:bg-primary/10 hover:text-foreground focus-visible:border-ring focus-visible:outline-none\",\n props.selectedKey === source.key\n ? \"border-primary/45 bg-primary/10 text-primary\"\n : \"\",\n ].join(\" \")}\n key={source.key}\n type=\"button\"\n onClick={() => props.onSelect(source.key)}\n >\n <span>{source.source.label ?? sourceLabel(source.source.kind)}</span>\n {source.source.itemCount === undefined ? null : (\n <span className=\"text-muted-foreground\">{source.source.itemCount}</span>\n )}\n </button>\n ))}\n </div>\n </div>\n ) : null}\n {props.children}\n </div>\n );\n}\n\nfunction ItemBrowser(props: {\n source: KnowledgeSourceRef | undefined;\n state: ItemState | undefined;\n onLoadMore: () => void;\n}) {\n const state = props.state;\n return (\n <section className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden rounded-xl border border-border/80 bg-card/55\">\n <div className=\"border-b border-border/80 px-4 py-3\">\n <div className=\"flex min-w-0 items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h2 className=\"m-0 truncate text-sm font-semibold text-foreground\">\n {props.source?.source.label ?? \"Knowledge items\"}\n </h2>\n <p className=\"m-0 mt-1 truncate font-mono text-xs text-muted-foreground\">\n {props.source === undefined\n ? \"No source selected\"\n : `${props.source.agentId} / ${sourceId(props.source.source)}`}\n </p>\n </div>\n {state?.totalCount === undefined ? null : <Badge>{state.totalCount} total</Badge>}\n </div>\n </div>\n <div className=\"min-h-0 overflow-auto\">\n <div className=\"p-4\">\n {props.source === undefined ? <MutedRow text=\"No knowledge source selected\" /> : null}\n {state?.loading === true && state.items.length === 0 ? (\n <MutedRow text=\"Loading items\" />\n ) : null}\n {state?.error === undefined ? null : <MutedRow text={state.error} />}\n {state?.inspectable === false ? (\n <MutedRow text={state.message ?? \"This source does not expose browseable chunks.\"} />\n ) : null}\n {state?.inspectable !== false && state?.loading === false && state.items.length === 0 ? (\n <MutedRow text=\"No items in this source\" />\n ) : null}\n <div className=\"grid gap-3\">\n {state?.items.map((item) => (\n <KnowledgeItemCard item={item} key={`${item.kind}:${item.id}`} />\n ))}\n </div>\n </div>\n </div>\n <div className=\"flex min-h-12 items-center justify-between gap-3 bg-muted/10 px-4 py-2\">\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n {state === undefined ? \"0 loaded\" : `${state.items.length} loaded`}\n </span>\n <Button\n className=\"h-8 min-h-8\"\n type=\"button\"\n variant=\"secondary\"\n disabled={state?.loading === true || state?.nextCursor === undefined}\n onClick={props.onLoadMore}\n >\n Load more\n </Button>\n </div>\n </section>\n );\n}\n\nfunction KnowledgeItemCard(props: { item: StudioKnowledgeItem }) {\n return (\n <article className=\"grid gap-3 rounded-xl border border-border/80 bg-background/55 p-4\">\n <div className=\"flex min-w-0 items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"truncate font-mono text-xs font-semibold text-primary\">\n {props.item.toolName ?? props.item.id}\n </div>\n <div className=\"mt-1 font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground\">\n {itemKindLabel(props.item.kind)}\n </div>\n </div>\n {props.item.parameterKeys === undefined || props.item.parameterKeys.length === 0 ? null : (\n <Badge>{props.item.parameterKeys.length} params</Badge>\n )}\n </div>\n {props.item.description === undefined || props.item.description.length === 0 ? null : (\n <p className=\"m-0 text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]\">\n {props.item.description}\n </p>\n )}\n {props.item.text === undefined ? null : (\n <p className=\"m-0 whitespace-pre-wrap text-sm leading-6 text-foreground [overflow-wrap:anywhere]\">\n {props.item.text}\n </p>\n )}\n {props.item.document === undefined ? null : (\n <JsonBlock title=\"Document\" value={props.item.document} />\n )}\n {props.item.metadata === undefined ? null : (\n <JsonBlock title=\"Metadata\" value={props.item.metadata} />\n )}\n {props.item.parameterKeys === undefined || props.item.parameterKeys.length === 0 ? null : (\n <div className=\"flex flex-wrap gap-2\">\n {props.item.parameterKeys.map((key) => (\n <Badge key={key}>{key}</Badge>\n ))}\n </div>\n )}\n </article>\n );\n}\n\nfunction RetrievalLogPanel(props: {\n evidence: NonNullable<StudioKnowledgeSummary[\"evidence\"]>;\n onOpenTrace: (traceId: string) => void;\n}) {\n return (\n <section className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-xl border border-border/80 bg-card/55\">\n <div className=\"border-b border-border/80 px-4 py-3\">\n <div className=\"flex min-w-0 items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h2 className=\"m-0 truncate text-sm font-semibold text-foreground\">Retrieval log</h2>\n <p className=\"m-0 mt-1 truncate font-mono text-xs text-muted-foreground\">\n traces / retrieval-evidence\n </p>\n </div>\n <Badge>{props.evidence.length} entries</Badge>\n </div>\n </div>\n <div className=\"min-h-0 overflow-auto p-4\">\n {props.evidence.length === 0 ? (\n <MutedRow text=\"No retrieval evidence captured yet\" />\n ) : null}\n <div className=\"grid gap-3\">\n {props.evidence.map((item) => (\n <article\n className=\"grid gap-3 rounded-xl border border-border/80 bg-background/45 p-3\"\n key={`${item.traceId}:${item.observationId}`}\n >\n <div className=\"flex min-w-0 items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-sm font-semibold text-foreground\">\n {item.observationName}\n </div>\n <div className=\"mt-1 font-mono text-[11px] text-muted-foreground\">\n Turn {item.turn}\n </div>\n </div>\n <Button\n className=\"h-auto min-h-0 rounded-lg border border-border bg-muted px-2 py-1 font-mono text-[10px] text-muted-foreground\"\n type=\"button\"\n variant=\"ghost\"\n onClick={() => props.onOpenTrace(item.traceId)}\n >\n Trace\n </Button>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Badge>{item.documentCount} docs</Badge>\n <Badge>{item.toolCount} tools</Badge>\n </div>\n {item.query === undefined ? null : (\n <p className=\"m-0 text-sm leading-6 text-muted-foreground [overflow-wrap:anywhere]\">\n <span className=\"font-mono text-xs font-semibold uppercase tracking-[0.14em] text-foreground\">\n Query\n </span>{\" \"}\n {item.query}\n </p>\n )}\n {item.documents.slice(0, 2).map((document) => (\n <p\n className=\"m-0 text-xs leading-5 text-muted-foreground [overflow-wrap:anywhere]\"\n key={`${document.id ?? \"doc\"}:${document.text ?? \"\"}`}\n >\n <span className=\"font-mono text-foreground\">{document.id ?? \"document\"}</span>{\" \"}\n {document.text ?? \"\"}\n </p>\n ))}\n {item.tools.length === 0 ? null : (\n <p className=\"m-0 text-xs leading-5 text-muted-foreground\">\n Tools: {item.tools.join(\", \")}\n </p>\n )}\n </article>\n ))}\n </div>\n </div>\n </section>\n );\n}\n\nfunction JsonBlock(props: { title: string; value: unknown }) {\n return (\n <div className=\"grid gap-2 border-t border-border/70 pt-3\">\n <div className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground\">\n {props.title}\n </div>\n <JsonValueView value={props.value} />\n </div>\n );\n}\n\nfunction EmptyState(props: { title: string; text: string }) {\n return (\n <section className=\"grid h-full place-items-center p-8\">\n <div className=\"grid max-w-sm gap-2 text-center\">\n <h1 className=\"m-0 text-base font-semibold text-foreground\">{props.title}</h1>\n <p className=\"m-0 text-sm font-medium leading-6 text-muted-foreground\">{props.text}</p>\n </div>\n </section>\n );\n}\n\nfunction MutedRow(props: { text: string }) {\n return (\n <div className=\"rounded-lg border border-dashed border-border px-4 py-3 text-sm font-medium text-muted-foreground\">\n {props.text}\n </div>\n );\n}\n\nfunction flattenSources(agents: StudioAgentKnowledgeConfig[]): KnowledgeSourceRef[] {\n return agents.flatMap((agent) =>\n agent.sources.map((source, index) => ({\n key: `${agent.agentId}:${sourceId(source, index)}`,\n agentId: agent.agentId,\n agentName: agent.agentName ?? agent.agentId,\n source: withSourceId(source, index),\n })),\n );\n}\n\nconst knowledgeTabs: Array<{ id: KnowledgeTab; label: string }> = [\n { id: \"static-context\", label: \"Static Context\" },\n { id: \"dynamic-context\", label: \"Dynamic Context\" },\n { id: \"dynamic-tools\", label: \"Dynamic Tools\" },\n { id: \"retrieval-log\", label: \"Retrieval Log\" },\n];\n\nfunction withSourceId(\n source: StudioKnowledgeSourceSummary,\n index: number,\n): StudioKnowledgeSourceSummary {\n return source.sourceId === undefined\n ? { ...source, sourceId: fallbackSourceId(source, index) }\n : source;\n}\n\nfunction sourceId(source: StudioKnowledgeSourceSummary, index = 0): string {\n return source.sourceId ?? fallbackSourceId(source, index);\n}\n\nfunction fallbackSourceId(source: StudioKnowledgeSourceSummary, index: number): string {\n switch (source.kind) {\n case \"static_context\":\n return \"static-context\";\n case \"dynamic_context\":\n return `dynamic-context-${source.registrationIndex ?? index}`;\n case \"dynamic_tools\":\n return `dynamic-tools-${source.registrationIndex ?? index}`;\n }\n}\n\nfunction sumKind(sources: StudioKnowledgeSourceSummary[], kind: StudioKnowledgeSourceKind): number {\n return sources\n .filter((source) => source.kind === kind)\n .reduce((total, source) => total + (source.itemCount ?? source.count), 0);\n}\n\nfunction sourceLabel(kind: StudioKnowledgeSourceKind): string {\n switch (kind) {\n case \"static_context\":\n return \"Static context\";\n case \"dynamic_context\":\n return \"Dynamic context\";\n case \"dynamic_tools\":\n return \"Dynamic tools\";\n }\n}\n\nfunction sourceKindForTab(tab: KnowledgeTab): StudioKnowledgeSourceKind | undefined {\n switch (tab) {\n case \"static-context\":\n return \"static_context\";\n case \"dynamic-context\":\n return \"dynamic_context\";\n case \"dynamic-tools\":\n return \"dynamic_tools\";\n case \"retrieval-log\":\n return undefined;\n }\n}\n\nfunction tabLabel(tab: KnowledgeTab): string {\n return knowledgeTabs.find((item) => item.id === tab)?.label ?? \"Knowledge\";\n}\n\nfunction tabCountLabel(\n tab: KnowledgeTab,\n sources: KnowledgeSourceRef[],\n evidenceCount: number,\n): string {\n const sourceKind = sourceKindForTab(tab);\n if (sourceKind === undefined) {\n return `${evidenceCount} entries`;\n }\n const tabSources = sources.filter((source) => source.source.kind === sourceKind);\n const itemCount = sumKind(\n tabSources.map((source) => source.source),\n sourceKind,\n );\n return `${tabSources.length} sources / ${itemCount} items`;\n}\n\nfunction itemKindLabel(kind: StudioKnowledgeItem[\"kind\"]): string {\n switch (kind) {\n case \"static_context\":\n return \"Static context\";\n case \"dynamic_context\":\n return \"Dynamic context\";\n case \"dynamic_tool\":\n return \"Dynamic tool\";\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./jsx-runtime-ZfyQks-z.js";import{_ as t,g as n,h as r,v as i,y as a}from"./index-
|
|
2
|
-
//# sourceMappingURL=mcps-page-
|
|
1
|
+
import{t as e}from"./jsx-runtime-ZfyQks-z.js";import{_ as t,g as n,h as r,v as i,y as a}from"./index-ChlKOnbD.js";import{t as o}from"./badge-CNbpc5Sm.js";import{t as s}from"./renderers-Bc89UGTN.js";var c=e();function l(e){let s=e.agents.find(t=>t.id===e.selectedAgentId)??e.agents[0],l=e.summary?.servers??[],d=l.reduce((e,t)=>e+t.toolCount,0);return(0,c.jsxs)(`section`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55`,"aria-label":`MCPs`,children:[(0,c.jsx)(`header`,{className:`bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur`,children:(0,c.jsxs)(`div`,{className:`grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1`,children:[(0,c.jsxs)(`div`,{className:`grid min-w-0 gap-2`,children:[(0,c.jsx)(`div`,{className:`font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary`,children:`External context`}),(0,c.jsx)(`h1`,{className:`m-0 text-2xl font-semibold leading-none tracking-tight text-foreground`,children:`MCPs`}),(0,c.jsx)(`p`,{className:`m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground`,children:`MCP servers and remote tools registered on Studio agents, grouped by server.`})]}),(0,c.jsxs)(`div`,{className:`flex min-w-0 items-center gap-3 max-md:grid max-md:grid-cols-1`,children:[(0,c.jsxs)(o,{className:`h-9 justify-center border-border/80 bg-card/70 text-muted-foreground`,children:[l.length,` servers / `,d,` tools`]}),e.agents.length>1?(0,c.jsxs)(r,{value:s?.id??``,onValueChange:e.onSelectAgent,children:[(0,c.jsx)(i,{className:`h-9 min-h-9 w-64 rounded-lg border-border bg-card/80 font-mono text-xs max-md:w-full`,children:(0,c.jsx)(a,{placeholder:`Agent`})}),(0,c.jsx)(n,{align:`end`,children:e.agents.map(e=>(0,c.jsx)(t,{value:e.id,children:e.name??e.id},e.id))})]}):null]})]})}),(0,c.jsx)(`div`,{className:`min-h-0 overflow-auto pb-6 pl-0 pr-6`,children:(0,c.jsx)(`div`,{className:`grid w-full gap-5`,children:e.enabled?e.loading?(0,c.jsx)(p,{title:`Loading MCPs`,message:`Reading registered MCP metadata.`}):l.length===0?(0,c.jsx)(p,{title:`No MCPs`,message:`The selected agent has no registered MCP tools.`}):l.map(e=>(0,c.jsx)(u,{server:e},e.name)):(0,c.jsx)(p,{title:`MCPs unavailable`,message:`No registered Studio agent exposes MCP tools.`})})})]})}function u(e){return(0,c.jsxs)(`section`,{className:`overflow-hidden rounded-xl border border-border/80 bg-card/55 p-2 shadow-sm`,children:[(0,c.jsxs)(`header`,{className:`grid min-h-14 grid-cols-[minmax(0,1fr)_auto] items-center gap-4 rounded-lg border border-border/60 bg-muted/20 px-4`,children:[(0,c.jsxs)(`div`,{className:`grid min-w-0 gap-1`,children:[(0,c.jsx)(`h2`,{className:`m-0 truncate font-mono text-[15px] font-semibold text-foreground`,children:e.server.name}),(0,c.jsx)(`span`,{className:`truncate font-mono text-[11px] font-medium text-muted-foreground`,children:e.server.agentId})]}),(0,c.jsxs)(o,{className:`border-border/80 bg-background/50 text-muted-foreground`,children:[e.server.toolCount,` tools`]})]}),(0,c.jsx)(`div`,{className:`mt-1 grid gap-1`,children:e.server.tools.map(e=>(0,c.jsx)(d,{tool:e},`${e.source}:${e.name}`))})]})}function d(e){return(0,c.jsxs)(`article`,{className:`grid grid-cols-[minmax(300px,0.75fr)_minmax(0,1fr)] gap-2 rounded-lg border border-transparent bg-background/25 p-2 transition duration-200 hover:border-border/70 hover:bg-background/35 max-lg:grid-cols-1`,children:[(0,c.jsxs)(`div`,{className:`grid content-start gap-4 rounded-lg bg-card/25 p-3`,children:[(0,c.jsxs)(`div`,{className:`grid gap-1`,children:[(0,c.jsx)(`h3`,{className:`m-0 truncate font-mono text-[15px] font-semibold text-foreground`,children:e.tool.name}),(0,c.jsx)(`span`,{className:`font-mono text-[11px] font-medium text-muted-foreground`,children:e.tool.source})]}),(0,c.jsx)(`p`,{className:`m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground`,children:e.tool.description}),(0,c.jsxs)(`div`,{className:`flex min-w-0 flex-wrap gap-2`,children:[(0,c.jsx)(o,{className:m(e.tool.source),children:e.tool.source}),(0,c.jsxs)(o,{className:`border-border/80 bg-transparent text-muted-foreground`,children:[g(e.tool.parameters),` fields`]})]})]}),(0,c.jsx)(f,{value:e.tool.parameters})]})}function f(e){return(0,c.jsxs)(`section`,{className:`grid min-w-0 content-start overflow-hidden rounded-lg bg-background/45`,children:[(0,c.jsxs)(`div`,{className:`flex min-h-9 items-center justify-between gap-3 bg-muted/20 px-4`,children:[(0,c.jsx)(`span`,{className:`font-mono text-[10px] font-semibold uppercase tracking-[0.2em] text-muted-foreground`,children:`Parameter schema`}),(0,c.jsx)(`span`,{className:`font-mono text-[10px] text-muted-foreground`,children:h(e.value)})]}),(0,c.jsx)(`div`,{className:`min-w-0 overflow-x-auto`,children:(0,c.jsx)(`pre`,{className:`m-0 max-h-80 min-w-max p-4 font-mono text-[12px] leading-5 text-foreground`,children:(0,c.jsx)(`code`,{children:(0,c.jsx)(s,{text:_(e.value)})})})})]})}function p(e){return(0,c.jsx)(`div`,{className:`grid min-h-80 place-items-center rounded-xl border border-dashed border-border/80 bg-card/35 px-6 text-center`,children:(0,c.jsxs)(`div`,{className:`grid max-w-md gap-2`,children:[(0,c.jsx)(`h2`,{className:`m-0 text-base font-semibold text-foreground`,children:e.title}),(0,c.jsx)(`p`,{className:`m-0 text-sm leading-6 text-muted-foreground`,children:e.message})]})})}function m(e){return e===`dynamic`?`border-primary/35 bg-primary/10 text-primary`:`border-border/80 bg-muted/55 text-muted-foreground`}function h(e){if(typeof e!=`object`||!e||Array.isArray(e))return`value`;let t=e.type;return typeof t==`string`?t:`object`}function g(e){if(typeof e!=`object`||!e||Array.isArray(e))return 0;let t=e.properties;return typeof t==`object`&&t&&!Array.isArray(t)?Object.keys(t).length:0}function _(e){try{return JSON.stringify(e,null,2)}catch{return String(e)}}export{l as McpsPage};
|
|
2
|
+
//# sourceMappingURL=mcps-page-D3P0UAWf.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcps-page-B7VAqsoU.js","names":[],"sources":["../../../src/ui/app/modules/mcps/mcps-page.tsx"],"sourcesContent":["import type {\n StudioAgentMcpServerMetadata,\n StudioAgentMcpsSummary,\n StudioAgentMcpToolMetadata,\n StudioConfig,\n} from \"../../../../types\";\nimport { Badge } from \"../../components/ui/badge\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../components/ui/select\";\nimport { JsonSyntax } from \"../shared/renderers\";\n\nexport function McpsPage(props: {\n agents: StudioConfig[\"agents\"];\n selectedAgentId: string;\n summary: StudioAgentMcpsSummary | undefined;\n enabled: boolean;\n loading: boolean;\n onSelectAgent: (agentId: string) => void;\n}) {\n const selectedAgent =\n props.agents.find((agent) => agent.id === props.selectedAgentId) ?? props.agents[0];\n const servers = props.summary?.servers ?? [];\n const toolCount = servers.reduce((total, server) => total + server.toolCount, 0);\n\n return (\n <section\n className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55\"\n aria-label=\"MCPs\"\n >\n <header className=\"bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur\">\n <div className=\"grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1\">\n <div className=\"grid min-w-0 gap-2\">\n <div className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary\">\n External context\n </div>\n <h1 className=\"m-0 text-2xl font-semibold leading-none tracking-tight text-foreground\">\n MCPs\n </h1>\n <p className=\"m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground\">\n MCP servers and remote tools registered on Studio agents, grouped by server.\n </p>\n </div>\n <div className=\"flex min-w-0 items-center gap-3 max-md:grid max-md:grid-cols-1\">\n <Badge className=\"h-9 justify-center border-border/80 bg-card/70 text-muted-foreground\">\n {servers.length} servers / {toolCount} tools\n </Badge>\n {props.agents.length > 1 ? (\n <Select value={selectedAgent?.id ?? \"\"} onValueChange={props.onSelectAgent}>\n <SelectTrigger className=\"h-9 min-h-9 w-64 rounded-lg border-border bg-card/80 font-mono text-xs max-md:w-full\">\n <SelectValue placeholder=\"Agent\" />\n </SelectTrigger>\n <SelectContent align=\"end\">\n {props.agents.map((agent) => (\n <SelectItem value={agent.id} key={agent.id}>\n {agent.name ?? agent.id}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n </div>\n </div>\n </header>\n\n <div className=\"min-h-0 overflow-auto pb-6 pl-0 pr-6\">\n <div className=\"grid w-full gap-5\">\n {!props.enabled ? (\n <EmptyState\n title=\"MCPs unavailable\"\n message=\"No registered Studio agent exposes MCP tools.\"\n />\n ) : props.loading ? (\n <EmptyState title=\"Loading MCPs\" message=\"Reading registered MCP metadata.\" />\n ) : servers.length === 0 ? (\n <EmptyState title=\"No MCPs\" message=\"The selected agent has no registered MCP tools.\" />\n ) : (\n servers.map((server) => <McpServerSection server={server} key={server.name} />)\n )}\n </div>\n </div>\n </section>\n );\n}\n\nfunction McpServerSection(props: { server: StudioAgentMcpServerMetadata }) {\n return (\n <section className=\"overflow-hidden rounded-xl border border-border/80 bg-card/55 p-2 shadow-sm\">\n <header className=\"grid min-h-14 grid-cols-[minmax(0,1fr)_auto] items-center gap-4 rounded-lg border border-border/60 bg-muted/20 px-4\">\n <div className=\"grid min-w-0 gap-1\">\n <h2 className=\"m-0 truncate font-mono text-[15px] font-semibold text-foreground\">\n {props.server.name}\n </h2>\n <span className=\"truncate font-mono text-[11px] font-medium text-muted-foreground\">\n {props.server.agentId}\n </span>\n </div>\n <Badge className=\"border-border/80 bg-background/50 text-muted-foreground\">\n {props.server.toolCount} tools\n </Badge>\n </header>\n <div className=\"mt-1 grid gap-1\">\n {props.server.tools.map((tool) => (\n <McpToolRow tool={tool} key={`${tool.source}:${tool.name}`} />\n ))}\n </div>\n </section>\n );\n}\n\nfunction McpToolRow(props: { tool: StudioAgentMcpToolMetadata }) {\n return (\n <article className=\"grid grid-cols-[minmax(300px,0.75fr)_minmax(0,1fr)] gap-2 rounded-lg border border-transparent bg-background/25 p-2 transition duration-200 hover:border-border/70 hover:bg-background/35 max-lg:grid-cols-1\">\n <div className=\"grid content-start gap-4 rounded-lg bg-card/25 p-3\">\n <div className=\"grid gap-1\">\n <h3 className=\"m-0 truncate font-mono text-[15px] font-semibold text-foreground\">\n {props.tool.name}\n </h3>\n <span className=\"font-mono text-[11px] font-medium text-muted-foreground\">\n {props.tool.source}\n </span>\n </div>\n <p className=\"m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground\">\n {props.tool.description}\n </p>\n <div className=\"flex min-w-0 flex-wrap gap-2\">\n <Badge className={sourceBadgeClass(props.tool.source)}>{props.tool.source}</Badge>\n <Badge className=\"border-border/80 bg-transparent text-muted-foreground\">\n {schemaPropertyCount(props.tool.parameters)} fields\n </Badge>\n </div>\n </div>\n <SchemaBlock value={props.tool.parameters} />\n </article>\n );\n}\n\nfunction SchemaBlock(props: { value: unknown }) {\n return (\n <section className=\"grid min-w-0 content-start overflow-hidden rounded-lg bg-background/45\">\n <div className=\"flex min-h-9 items-center justify-between gap-3 bg-muted/20 px-4\">\n <span className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.2em] text-muted-foreground\">\n Parameter schema\n </span>\n <span className=\"font-mono text-[10px] text-muted-foreground\">\n {schemaType(props.value)}\n </span>\n </div>\n <div className=\"min-w-0 overflow-x-auto\">\n <pre className=\"m-0 max-h-80 min-w-max p-4 font-mono text-[12px] leading-5 text-foreground\">\n <code>\n <JsonSyntax text={formatSchema(props.value)} />\n </code>\n </pre>\n </div>\n </section>\n );\n}\n\nfunction EmptyState(props: { title: string; message: string }) {\n return (\n <div className=\"grid min-h-80 place-items-center rounded-xl border border-dashed border-border/80 bg-card/35 px-6 text-center\">\n <div className=\"grid max-w-md gap-2\">\n <h2 className=\"m-0 text-base font-semibold text-foreground\">{props.title}</h2>\n <p className=\"m-0 text-sm leading-6 text-muted-foreground\">{props.message}</p>\n </div>\n </div>\n );\n}\n\nfunction sourceBadgeClass(source: \"static\" | \"dynamic\"): string {\n return source === \"dynamic\"\n ? \"border-primary/35 bg-primary/10 text-primary\"\n : \"border-border/80 bg-muted/55 text-muted-foreground\";\n}\n\nfunction schemaType(value: unknown): string {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return \"value\";\n }\n const type = (value as { type?: unknown }).type;\n return typeof type === \"string\" ? type : \"object\";\n}\n\nfunction schemaPropertyCount(value: unknown): number {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return 0;\n }\n const properties = (value as { properties?: unknown }).properties;\n return typeof properties === \"object\" && properties !== null && !Array.isArray(properties)\n ? Object.keys(properties).length\n : 0;\n}\n\nfunction formatSchema(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mcps-page-D3P0UAWf.js","names":[],"sources":["../../../src/ui/app/modules/mcps/mcps-page.tsx"],"sourcesContent":["import type {\n StudioAgentMcpServerMetadata,\n StudioAgentMcpsSummary,\n StudioAgentMcpToolMetadata,\n StudioConfig,\n} from \"../../../../types\";\nimport { Badge } from \"../../components/ui/badge\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../components/ui/select\";\nimport { JsonSyntax } from \"../shared/renderers\";\n\nexport function McpsPage(props: {\n agents: StudioConfig[\"agents\"];\n selectedAgentId: string;\n summary: StudioAgentMcpsSummary | undefined;\n enabled: boolean;\n loading: boolean;\n onSelectAgent: (agentId: string) => void;\n}) {\n const selectedAgent =\n props.agents.find((agent) => agent.id === props.selectedAgentId) ?? props.agents[0];\n const servers = props.summary?.servers ?? [];\n const toolCount = servers.reduce((total, server) => total + server.toolCount, 0);\n\n return (\n <section\n className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55\"\n aria-label=\"MCPs\"\n >\n <header className=\"bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur\">\n <div className=\"grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1\">\n <div className=\"grid min-w-0 gap-2\">\n <div className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary\">\n External context\n </div>\n <h1 className=\"m-0 text-2xl font-semibold leading-none tracking-tight text-foreground\">\n MCPs\n </h1>\n <p className=\"m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground\">\n MCP servers and remote tools registered on Studio agents, grouped by server.\n </p>\n </div>\n <div className=\"flex min-w-0 items-center gap-3 max-md:grid max-md:grid-cols-1\">\n <Badge className=\"h-9 justify-center border-border/80 bg-card/70 text-muted-foreground\">\n {servers.length} servers / {toolCount} tools\n </Badge>\n {props.agents.length > 1 ? (\n <Select value={selectedAgent?.id ?? \"\"} onValueChange={props.onSelectAgent}>\n <SelectTrigger className=\"h-9 min-h-9 w-64 rounded-lg border-border bg-card/80 font-mono text-xs max-md:w-full\">\n <SelectValue placeholder=\"Agent\" />\n </SelectTrigger>\n <SelectContent align=\"end\">\n {props.agents.map((agent) => (\n <SelectItem value={agent.id} key={agent.id}>\n {agent.name ?? agent.id}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n </div>\n </div>\n </header>\n\n <div className=\"min-h-0 overflow-auto pb-6 pl-0 pr-6\">\n <div className=\"grid w-full gap-5\">\n {!props.enabled ? (\n <EmptyState\n title=\"MCPs unavailable\"\n message=\"No registered Studio agent exposes MCP tools.\"\n />\n ) : props.loading ? (\n <EmptyState title=\"Loading MCPs\" message=\"Reading registered MCP metadata.\" />\n ) : servers.length === 0 ? (\n <EmptyState title=\"No MCPs\" message=\"The selected agent has no registered MCP tools.\" />\n ) : (\n servers.map((server) => <McpServerSection server={server} key={server.name} />)\n )}\n </div>\n </div>\n </section>\n );\n}\n\nfunction McpServerSection(props: { server: StudioAgentMcpServerMetadata }) {\n return (\n <section className=\"overflow-hidden rounded-xl border border-border/80 bg-card/55 p-2 shadow-sm\">\n <header className=\"grid min-h-14 grid-cols-[minmax(0,1fr)_auto] items-center gap-4 rounded-lg border border-border/60 bg-muted/20 px-4\">\n <div className=\"grid min-w-0 gap-1\">\n <h2 className=\"m-0 truncate font-mono text-[15px] font-semibold text-foreground\">\n {props.server.name}\n </h2>\n <span className=\"truncate font-mono text-[11px] font-medium text-muted-foreground\">\n {props.server.agentId}\n </span>\n </div>\n <Badge className=\"border-border/80 bg-background/50 text-muted-foreground\">\n {props.server.toolCount} tools\n </Badge>\n </header>\n <div className=\"mt-1 grid gap-1\">\n {props.server.tools.map((tool) => (\n <McpToolRow tool={tool} key={`${tool.source}:${tool.name}`} />\n ))}\n </div>\n </section>\n );\n}\n\nfunction McpToolRow(props: { tool: StudioAgentMcpToolMetadata }) {\n return (\n <article className=\"grid grid-cols-[minmax(300px,0.75fr)_minmax(0,1fr)] gap-2 rounded-lg border border-transparent bg-background/25 p-2 transition duration-200 hover:border-border/70 hover:bg-background/35 max-lg:grid-cols-1\">\n <div className=\"grid content-start gap-4 rounded-lg bg-card/25 p-3\">\n <div className=\"grid gap-1\">\n <h3 className=\"m-0 truncate font-mono text-[15px] font-semibold text-foreground\">\n {props.tool.name}\n </h3>\n <span className=\"font-mono text-[11px] font-medium text-muted-foreground\">\n {props.tool.source}\n </span>\n </div>\n <p className=\"m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground\">\n {props.tool.description}\n </p>\n <div className=\"flex min-w-0 flex-wrap gap-2\">\n <Badge className={sourceBadgeClass(props.tool.source)}>{props.tool.source}</Badge>\n <Badge className=\"border-border/80 bg-transparent text-muted-foreground\">\n {schemaPropertyCount(props.tool.parameters)} fields\n </Badge>\n </div>\n </div>\n <SchemaBlock value={props.tool.parameters} />\n </article>\n );\n}\n\nfunction SchemaBlock(props: { value: unknown }) {\n return (\n <section className=\"grid min-w-0 content-start overflow-hidden rounded-lg bg-background/45\">\n <div className=\"flex min-h-9 items-center justify-between gap-3 bg-muted/20 px-4\">\n <span className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.2em] text-muted-foreground\">\n Parameter schema\n </span>\n <span className=\"font-mono text-[10px] text-muted-foreground\">\n {schemaType(props.value)}\n </span>\n </div>\n <div className=\"min-w-0 overflow-x-auto\">\n <pre className=\"m-0 max-h-80 min-w-max p-4 font-mono text-[12px] leading-5 text-foreground\">\n <code>\n <JsonSyntax text={formatSchema(props.value)} />\n </code>\n </pre>\n </div>\n </section>\n );\n}\n\nfunction EmptyState(props: { title: string; message: string }) {\n return (\n <div className=\"grid min-h-80 place-items-center rounded-xl border border-dashed border-border/80 bg-card/35 px-6 text-center\">\n <div className=\"grid max-w-md gap-2\">\n <h2 className=\"m-0 text-base font-semibold text-foreground\">{props.title}</h2>\n <p className=\"m-0 text-sm leading-6 text-muted-foreground\">{props.message}</p>\n </div>\n </div>\n );\n}\n\nfunction sourceBadgeClass(source: \"static\" | \"dynamic\"): string {\n return source === \"dynamic\"\n ? \"border-primary/35 bg-primary/10 text-primary\"\n : \"border-border/80 bg-muted/55 text-muted-foreground\";\n}\n\nfunction schemaType(value: unknown): string {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return \"value\";\n }\n const type = (value as { type?: unknown }).type;\n return typeof type === \"string\" ? type : \"object\";\n}\n\nfunction schemaPropertyCount(value: unknown): number {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return 0;\n }\n const properties = (value as { properties?: unknown }).properties;\n return typeof properties === \"object\" && properties !== null && !Array.isArray(properties)\n ? Object.keys(properties).length\n : 0;\n}\n\nfunction formatSchema(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e,s as t,t as n}from"./jsx-runtime-ZfyQks-z.js";import{L as r,o as i}from"./index-
|
|
2
|
-
//# sourceMappingURL=memory-page-
|
|
1
|
+
import{i as e,s as t,t as n}from"./jsx-runtime-ZfyQks-z.js";import{L as r,o as i}from"./index-ChlKOnbD.js";import{t as a}from"./badge-CNbpc5Sm.js";import{t as o}from"./renderers-Bc89UGTN.js";var s=t(e(),1),c=n();function l(e){let[t,n]=(0,s.useState)([]),[o,l]=(0,s.useState)([]),[g,_]=(0,s.useState)(``),[v,y]=(0,s.useState)(``),[b,x]=(0,s.useState)(),[S,C]=(0,s.useState)(),[w,T]=(0,s.useState)(!1),[E,D]=(0,s.useState)(!1),[O,k]=(0,s.useState)(``),A=(0,s.useCallback)(async()=>{if(!e.enabled){n([]),l([]),x(void 0),C(void 0);return}T(!0),k(``);try{let[e,t]=await Promise.all([fetch(`/memory/users?limit=50`),fetch(`/memory/conversations?limit=100`)]);if(!e.ok)throw Error(`Memory users failed with HTTP ${e.status}`);if(!t.ok)throw Error(`Memory conversations failed with HTTP ${t.status}`);let r=await e.json(),i=await t.json();n(r.users),l(i.conversations),y(e=>e||i.conversations[0]?.id||``)}catch(e){k(e instanceof Error?e.message:String(e))}finally{T(!1)}},[e.enabled]);(0,s.useEffect)(()=>{A()},[A]),(0,s.useEffect)(()=>{if(!e.enabled||v.length===0){x(void 0),C(void 0);return}let t=!1;async function n(){D(!0);try{let[e,n]=await Promise.all([fetch(`/memory/conversations/${encodeURIComponent(v)}/messages`),fetch(`/memory/conversations/${encodeURIComponent(v)}/steps`)]);if(!e.ok)throw Error(`Conversation messages failed with HTTP ${e.status}`);if(!n.ok)throw Error(`Conversation steps failed with HTTP ${n.status}`);t||(x(await e.json()),C(await n.json()))}catch(e){t||(k(e instanceof Error?e.message:String(e)),x(void 0),C(void 0))}finally{t||D(!1)}}return n(),()=>{t=!0}},[e.enabled,v]);let j=g.length===0?o:o.filter(e=>e.userId===g),M=o.find(e=>e.id===v)??j[0];return(0,c.jsxs)(`section`,{className:`grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55`,"aria-label":`Memory`,children:[(0,c.jsx)(`header`,{className:`bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur`,children:(0,c.jsxs)(`div`,{className:`grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1`,children:[(0,c.jsxs)(`div`,{className:`grid min-w-0 gap-2`,children:[(0,c.jsx)(`div`,{className:`font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary`,children:`Conversation store`}),(0,c.jsx)(`h1`,{className:`m-0 text-2xl font-semibold leading-none tracking-tight text-foreground`,children:`Memory`}),(0,c.jsx)(`p`,{className:`m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground`,children:`Stored users, conversations, raw messages, and transcript steps from the Studio session store.`})]}),(0,c.jsx)(r,{className:`h-9 min-h-9 rounded-lg px-3 font-mono text-xs`,type:`button`,variant:`secondary`,disabled:w,onClick:()=>void A(),children:`Refresh`})]})}),(0,c.jsx)(`div`,{className:`min-h-0 overflow-auto pb-6 pl-0 pr-6`,children:e.enabled?w&&o.length===0?(0,c.jsx)(m,{title:`Loading memory`,text:`Reading users and conversations.`}):O.length>0&&o.length===0?(0,c.jsx)(m,{title:`Memory error`,text:O}):(0,c.jsxs)(`div`,{className:`grid min-h-0 gap-4 xl:grid-cols-[280px_minmax(320px,0.8fr)_minmax(0,1.2fr)]`,children:[(0,c.jsxs)(`section`,{className:`grid content-start gap-2 rounded-xl border border-border/80 bg-card/45 p-3`,children:[(0,c.jsx)(f,{title:`Users`,value:t.length}),(0,c.jsx)(r,{className:`h-auto min-h-9 justify-start rounded-lg px-3 py-2 text-left font-mono text-xs`,type:`button`,variant:g.length===0?`secondary`:`ghost`,onClick:()=>_(``),children:`All users`}),t.map(e=>(0,c.jsxs)(r,{className:`grid h-auto min-h-14 justify-start rounded-lg px-3 py-2 text-left`,type:`button`,variant:g===e.userId?`secondary`:`ghost`,onClick:()=>_(e.userId),children:[(0,c.jsx)(`span`,{className:`min-w-0 truncate font-mono text-xs font-semibold`,children:e.userId}),(0,c.jsxs)(`span`,{className:`min-w-0 truncate text-xs text-muted-foreground`,children:[e.conversationCount,` conversations ·`,` `,i(e.lastInteractionAt)]})]},e.userId))]}),(0,c.jsxs)(`section`,{className:`grid content-start gap-2 rounded-xl border border-border/80 bg-card/45 p-3`,children:[(0,c.jsx)(f,{title:`Conversations`,value:j.length}),j.length===0?(0,c.jsx)(`div`,{className:`rounded-lg border border-dashed border-border/80 bg-background/45 px-3 py-8 text-center text-sm text-muted-foreground`,children:`No conversations.`}):j.map(t=>(0,c.jsx)(u,{conversation:t,agentName:h(e.agents,t.agentId),active:t.id===v,onSelect:()=>y(t.id)},t.id))]}),(0,c.jsx)(`section`,{className:`grid min-h-0 content-start gap-4`,children:M===void 0?(0,c.jsx)(m,{title:`No conversation selected`,text:`Choose a conversation to inspect.`}):(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)(`article`,{className:`grid gap-3 rounded-xl border border-border/80 bg-card/45 p-5`,children:[(0,c.jsxs)(`div`,{className:`flex min-w-0 flex-wrap items-start justify-between gap-3`,children:[(0,c.jsxs)(`div`,{className:`grid min-w-0 gap-1`,children:[(0,c.jsx)(`h2`,{className:`m-0 min-w-0 truncate text-lg font-semibold text-foreground`,children:M.title??`Untitled conversation`}),(0,c.jsx)(`span`,{className:`min-w-0 break-all font-mono text-xs text-muted-foreground`,children:M.id})]}),(0,c.jsx)(a,{className:`border-primary/35 bg-primary/10 text-primary`,children:h(e.agents,M.agentId)})]}),(0,c.jsxs)(`div`,{className:`grid gap-2 sm:grid-cols-3`,children:[(0,c.jsx)(p,{label:`user`,value:M.userId}),(0,c.jsx)(p,{label:`messages`,value:M.messageCount}),(0,c.jsx)(p,{label:`updated`,value:i(M.updatedAt)})]})]}),E?(0,c.jsx)(m,{title:`Loading detail`,text:`Reading message and transcript data.`}):(0,c.jsxs)(`div`,{className:`grid gap-4`,children:[(0,c.jsx)(d,{title:`messages`,value:b?.messages??[]}),(0,c.jsx)(d,{title:`steps`,value:S?.steps??[]})]})]})})]}):(0,c.jsx)(m,{title:`Memory unavailable`,text:`This Studio runtime has no session store.`})})]})}function u(e){return(0,c.jsxs)(r,{className:`grid h-auto min-h-20 justify-start gap-2 rounded-lg px-3 py-3 text-left`,type:`button`,variant:e.active?`secondary`:`ghost`,onClick:e.onSelect,children:[(0,c.jsxs)(`div`,{className:`grid min-w-0 gap-1`,children:[(0,c.jsx)(`span`,{className:`min-w-0 truncate text-sm font-semibold text-foreground`,children:e.conversation.title??`Untitled conversation`}),(0,c.jsxs)(`span`,{className:`min-w-0 truncate font-mono text-[11px] text-muted-foreground`,children:[e.agentName,` · `,e.conversation.userId]})]}),(0,c.jsxs)(`span`,{className:`font-mono text-[11px] text-muted-foreground`,children:[e.conversation.messageCount,` messages ·`,` `,i(e.conversation.updatedAt)]})]})}function d(e){let t=Array.isArray(e.value)?e.value.length:void 0;return(0,c.jsxs)(`section`,{className:`grid min-w-0 overflow-hidden rounded-xl border border-border/80 bg-card/45`,children:[(0,c.jsx)(`div`,{className:`flex min-h-10 items-center justify-between gap-3 border-b border-border/80 bg-muted/20 px-4`,children:(0,c.jsx)(f,{title:e.title,...t===void 0?{}:{value:t}})}),(0,c.jsx)(`div`,{className:`min-w-0 overflow-x-auto`,children:(0,c.jsx)(`pre`,{className:`m-0 max-h-96 min-w-max p-4 font-mono text-[12px] leading-5 text-foreground`,children:(0,c.jsx)(`code`,{children:(0,c.jsx)(o,{text:JSON.stringify(e.value,null,2)})})})})]})}function f(e){return(0,c.jsxs)(`div`,{className:`flex min-w-0 items-center justify-between gap-3`,children:[(0,c.jsx)(`h2`,{className:`m-0 font-mono text-[10px] font-semibold uppercase tracking-[0.2em] text-muted-foreground`,children:e.title}),e.value===void 0?null:(0,c.jsx)(`span`,{className:`font-mono text-[10px] font-semibold text-muted-foreground`,children:e.value})]})}function p(e){return(0,c.jsxs)(`div`,{className:`grid min-w-0 gap-1 rounded-lg bg-background/45 px-3 py-2`,children:[(0,c.jsx)(`span`,{className:`font-mono text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground`,children:e.label}),(0,c.jsx)(`span`,{className:`min-w-0 truncate font-mono text-xs text-foreground`,title:String(e.value),children:e.value})]})}function m(e){return(0,c.jsx)(`div`,{className:`grid min-h-80 place-items-center rounded-xl border border-dashed border-border/80 bg-card/35 px-6 text-center`,children:(0,c.jsxs)(`div`,{className:`grid max-w-md gap-2`,children:[(0,c.jsx)(`h2`,{className:`m-0 text-base font-semibold text-foreground`,children:e.title}),(0,c.jsx)(`p`,{className:`m-0 text-sm leading-6 text-muted-foreground`,children:e.text})]})})}function h(e,t){return e.find(e=>e.id===t)?.name??t}export{l as MemoryPage};
|
|
2
|
+
//# sourceMappingURL=memory-page-kVDqOAOd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-page-BCv19Tw_.js","names":[],"sources":["../../../src/ui/app/modules/memory/memory-page.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\nimport type {\n StudioConfig,\n StudioMemoryConversationMessages,\n StudioMemoryConversationSteps,\n StudioMemoryConversationSummary,\n StudioMemoryConversationsPage,\n StudioMemoryUsersPage,\n} from \"../../../../types\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { formatRelativeTime } from \"../shared/format\";\nimport { JsonSyntax } from \"../shared/renderers\";\n\nexport function MemoryPage(props: { agents: StudioConfig[\"agents\"]; enabled: boolean }) {\n const [users, setUsers] = useState<StudioMemoryUsersPage[\"users\"]>([]);\n const [conversations, setConversations] = useState<StudioMemoryConversationSummary[]>([]);\n const [selectedUserId, setSelectedUserId] = useState(\"\");\n const [selectedConversationId, setSelectedConversationId] = useState(\"\");\n const [messages, setMessages] = useState<StudioMemoryConversationMessages | undefined>();\n const [steps, setSteps] = useState<StudioMemoryConversationSteps | undefined>();\n const [loading, setLoading] = useState(false);\n const [detailLoading, setDetailLoading] = useState(false);\n const [error, setError] = useState(\"\");\n\n const loadMemory = useCallback(async () => {\n if (!props.enabled) {\n setUsers([]);\n setConversations([]);\n setMessages(undefined);\n setSteps(undefined);\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n const [usersResponse, conversationsResponse] = await Promise.all([\n fetch(\"/memory/users?limit=50\"),\n fetch(\"/memory/conversations?limit=100\"),\n ]);\n if (!usersResponse.ok) {\n throw new Error(`Memory users failed with HTTP ${usersResponse.status}`);\n }\n if (!conversationsResponse.ok) {\n throw new Error(`Memory conversations failed with HTTP ${conversationsResponse.status}`);\n }\n const usersBody = (await usersResponse.json()) as StudioMemoryUsersPage;\n const conversationsBody =\n (await conversationsResponse.json()) as StudioMemoryConversationsPage;\n setUsers(usersBody.users);\n setConversations(conversationsBody.conversations);\n setSelectedConversationId(\n (current) => current || conversationsBody.conversations[0]?.id || \"\",\n );\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError.message : String(loadError));\n } finally {\n setLoading(false);\n }\n }, [props.enabled]);\n\n useEffect(() => {\n void loadMemory();\n }, [loadMemory]);\n\n useEffect(() => {\n if (!props.enabled || selectedConversationId.length === 0) {\n setMessages(undefined);\n setSteps(undefined);\n return;\n }\n let cancelled = false;\n async function loadDetail() {\n setDetailLoading(true);\n try {\n const [messagesResponse, stepsResponse] = await Promise.all([\n fetch(`/memory/conversations/${encodeURIComponent(selectedConversationId)}/messages`),\n fetch(`/memory/conversations/${encodeURIComponent(selectedConversationId)}/steps`),\n ]);\n if (!messagesResponse.ok) {\n throw new Error(`Conversation messages failed with HTTP ${messagesResponse.status}`);\n }\n if (!stepsResponse.ok) {\n throw new Error(`Conversation steps failed with HTTP ${stepsResponse.status}`);\n }\n if (!cancelled) {\n setMessages((await messagesResponse.json()) as StudioMemoryConversationMessages);\n setSteps((await stepsResponse.json()) as StudioMemoryConversationSteps);\n }\n } catch (loadError) {\n if (!cancelled) {\n setError(loadError instanceof Error ? loadError.message : String(loadError));\n setMessages(undefined);\n setSteps(undefined);\n }\n } finally {\n if (!cancelled) {\n setDetailLoading(false);\n }\n }\n }\n void loadDetail();\n return () => {\n cancelled = true;\n };\n }, [props.enabled, selectedConversationId]);\n\n const visibleConversations =\n selectedUserId.length === 0\n ? conversations\n : conversations.filter((conversation) => conversation.userId === selectedUserId);\n const selectedConversation =\n conversations.find((conversation) => conversation.id === selectedConversationId) ??\n visibleConversations[0];\n\n return (\n <section\n className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55\"\n aria-label=\"Memory\"\n >\n <header className=\"bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur\">\n <div className=\"grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1\">\n <div className=\"grid min-w-0 gap-2\">\n <div className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary\">\n Conversation store\n </div>\n <h1 className=\"m-0 text-2xl font-semibold leading-none tracking-tight text-foreground\">\n Memory\n </h1>\n <p className=\"m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground\">\n Stored users, conversations, raw messages, and transcript steps from the Studio\n session store.\n </p>\n </div>\n <Button\n className=\"h-9 min-h-9 rounded-lg px-3 font-mono text-xs\"\n type=\"button\"\n variant=\"secondary\"\n disabled={loading}\n onClick={() => void loadMemory()}\n >\n Refresh\n </Button>\n </div>\n </header>\n\n <div className=\"min-h-0 overflow-auto pb-6 pl-0 pr-6\">\n {!props.enabled ? (\n <EmptyState title=\"Memory unavailable\" text=\"This Studio runtime has no session store.\" />\n ) : loading && conversations.length === 0 ? (\n <EmptyState title=\"Loading memory\" text=\"Reading users and conversations.\" />\n ) : error.length > 0 && conversations.length === 0 ? (\n <EmptyState title=\"Memory error\" text={error} />\n ) : (\n <div className=\"grid min-h-0 gap-4 xl:grid-cols-[280px_minmax(320px,0.8fr)_minmax(0,1.2fr)]\">\n <section className=\"grid content-start gap-2 rounded-xl border border-border/80 bg-card/45 p-3\">\n <PanelHeader title=\"Users\" value={users.length} />\n <Button\n className=\"h-auto min-h-9 justify-start rounded-lg px-3 py-2 text-left font-mono text-xs\"\n type=\"button\"\n variant={selectedUserId.length === 0 ? \"secondary\" : \"ghost\"}\n onClick={() => setSelectedUserId(\"\")}\n >\n All users\n </Button>\n {users.map((user) => (\n <Button\n className=\"grid h-auto min-h-14 justify-start rounded-lg px-3 py-2 text-left\"\n type=\"button\"\n variant={selectedUserId === user.userId ? \"secondary\" : \"ghost\"}\n onClick={() => setSelectedUserId(user.userId)}\n key={user.userId}\n >\n <span className=\"min-w-0 truncate font-mono text-xs font-semibold\">\n {user.userId}\n </span>\n <span className=\"min-w-0 truncate text-xs text-muted-foreground\">\n {user.conversationCount} conversations ·{\" \"}\n {formatRelativeTime(user.lastInteractionAt)}\n </span>\n </Button>\n ))}\n </section>\n\n <section className=\"grid content-start gap-2 rounded-xl border border-border/80 bg-card/45 p-3\">\n <PanelHeader title=\"Conversations\" value={visibleConversations.length} />\n {visibleConversations.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border/80 bg-background/45 px-3 py-8 text-center text-sm text-muted-foreground\">\n No conversations.\n </div>\n ) : (\n visibleConversations.map((conversation) => (\n <ConversationButton\n key={conversation.id}\n conversation={conversation}\n agentName={agentLabel(props.agents, conversation.agentId)}\n active={conversation.id === selectedConversationId}\n onSelect={() => setSelectedConversationId(conversation.id)}\n />\n ))\n )}\n </section>\n\n <section className=\"grid min-h-0 content-start gap-4\">\n {selectedConversation === undefined ? (\n <EmptyState\n title=\"No conversation selected\"\n text=\"Choose a conversation to inspect.\"\n />\n ) : (\n <>\n <article className=\"grid gap-3 rounded-xl border border-border/80 bg-card/45 p-5\">\n <div className=\"flex min-w-0 flex-wrap items-start justify-between gap-3\">\n <div className=\"grid min-w-0 gap-1\">\n <h2 className=\"m-0 min-w-0 truncate text-lg font-semibold text-foreground\">\n {selectedConversation.title ?? \"Untitled conversation\"}\n </h2>\n <span className=\"min-w-0 break-all font-mono text-xs text-muted-foreground\">\n {selectedConversation.id}\n </span>\n </div>\n <Badge className=\"border-primary/35 bg-primary/10 text-primary\">\n {agentLabel(props.agents, selectedConversation.agentId)}\n </Badge>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-3\">\n <Fact label=\"user\" value={selectedConversation.userId} />\n <Fact label=\"messages\" value={selectedConversation.messageCount} />\n <Fact\n label=\"updated\"\n value={formatRelativeTime(selectedConversation.updatedAt)}\n />\n </div>\n </article>\n {detailLoading ? (\n <EmptyState\n title=\"Loading detail\"\n text=\"Reading message and transcript data.\"\n />\n ) : (\n <div className=\"grid gap-4\">\n <JsonPanel title=\"messages\" value={messages?.messages ?? []} />\n <JsonPanel title=\"steps\" value={steps?.steps ?? []} />\n </div>\n )}\n </>\n )}\n </section>\n </div>\n )}\n </div>\n </section>\n );\n}\n\nfunction ConversationButton(props: {\n conversation: StudioMemoryConversationSummary;\n agentName: string;\n active: boolean;\n onSelect: () => void;\n}) {\n return (\n <Button\n className=\"grid h-auto min-h-20 justify-start gap-2 rounded-lg px-3 py-3 text-left\"\n type=\"button\"\n variant={props.active ? \"secondary\" : \"ghost\"}\n onClick={props.onSelect}\n >\n <div className=\"grid min-w-0 gap-1\">\n <span className=\"min-w-0 truncate text-sm font-semibold text-foreground\">\n {props.conversation.title ?? \"Untitled conversation\"}\n </span>\n <span className=\"min-w-0 truncate font-mono text-[11px] text-muted-foreground\">\n {props.agentName} · {props.conversation.userId}\n </span>\n </div>\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n {props.conversation.messageCount} messages ·{\" \"}\n {formatRelativeTime(props.conversation.updatedAt)}\n </span>\n </Button>\n );\n}\n\nfunction JsonPanel(props: { title: string; value: unknown }) {\n const count = Array.isArray(props.value) ? props.value.length : undefined;\n return (\n <section className=\"grid min-w-0 overflow-hidden rounded-xl border border-border/80 bg-card/45\">\n <div className=\"flex min-h-10 items-center justify-between gap-3 border-b border-border/80 bg-muted/20 px-4\">\n <PanelHeader title={props.title} {...(count === undefined ? {} : { value: count })} />\n </div>\n <div className=\"min-w-0 overflow-x-auto\">\n <pre className=\"m-0 max-h-96 min-w-max p-4 font-mono text-[12px] leading-5 text-foreground\">\n <code>\n <JsonSyntax text={JSON.stringify(props.value, null, 2)} />\n </code>\n </pre>\n </div>\n </section>\n );\n}\n\nfunction PanelHeader(props: { title: string; value?: number }) {\n return (\n <div className=\"flex min-w-0 items-center justify-between gap-3\">\n <h2 className=\"m-0 font-mono text-[10px] font-semibold uppercase tracking-[0.2em] text-muted-foreground\">\n {props.title}\n </h2>\n {props.value === undefined ? null : (\n <span className=\"font-mono text-[10px] font-semibold text-muted-foreground\">\n {props.value}\n </span>\n )}\n </div>\n );\n}\n\nfunction Fact(props: { label: string; value: string | number }) {\n return (\n <div className=\"grid min-w-0 gap-1 rounded-lg bg-background/45 px-3 py-2\">\n <span className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground\">\n {props.label}\n </span>\n <span\n className=\"min-w-0 truncate font-mono text-xs text-foreground\"\n title={String(props.value)}\n >\n {props.value}\n </span>\n </div>\n );\n}\n\nfunction EmptyState(props: { title: string; text: string }) {\n return (\n <div className=\"grid min-h-80 place-items-center rounded-xl border border-dashed border-border/80 bg-card/35 px-6 text-center\">\n <div className=\"grid max-w-md gap-2\">\n <h2 className=\"m-0 text-base font-semibold text-foreground\">{props.title}</h2>\n <p className=\"m-0 text-sm leading-6 text-muted-foreground\">{props.text}</p>\n </div>\n </div>\n );\n}\n\nfunction agentLabel(agents: StudioConfig[\"agents\"], agentId: string): string {\n return agents.find((agent) => agent.id === agentId)?.name ?? agentId;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory-page-kVDqOAOd.js","names":[],"sources":["../../../src/ui/app/modules/memory/memory-page.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\nimport type {\n StudioConfig,\n StudioMemoryConversationMessages,\n StudioMemoryConversationSteps,\n StudioMemoryConversationSummary,\n StudioMemoryConversationsPage,\n StudioMemoryUsersPage,\n} from \"../../../../types\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { formatRelativeTime } from \"../shared/format\";\nimport { JsonSyntax } from \"../shared/renderers\";\n\nexport function MemoryPage(props: { agents: StudioConfig[\"agents\"]; enabled: boolean }) {\n const [users, setUsers] = useState<StudioMemoryUsersPage[\"users\"]>([]);\n const [conversations, setConversations] = useState<StudioMemoryConversationSummary[]>([]);\n const [selectedUserId, setSelectedUserId] = useState(\"\");\n const [selectedConversationId, setSelectedConversationId] = useState(\"\");\n const [messages, setMessages] = useState<StudioMemoryConversationMessages | undefined>();\n const [steps, setSteps] = useState<StudioMemoryConversationSteps | undefined>();\n const [loading, setLoading] = useState(false);\n const [detailLoading, setDetailLoading] = useState(false);\n const [error, setError] = useState(\"\");\n\n const loadMemory = useCallback(async () => {\n if (!props.enabled) {\n setUsers([]);\n setConversations([]);\n setMessages(undefined);\n setSteps(undefined);\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n const [usersResponse, conversationsResponse] = await Promise.all([\n fetch(\"/memory/users?limit=50\"),\n fetch(\"/memory/conversations?limit=100\"),\n ]);\n if (!usersResponse.ok) {\n throw new Error(`Memory users failed with HTTP ${usersResponse.status}`);\n }\n if (!conversationsResponse.ok) {\n throw new Error(`Memory conversations failed with HTTP ${conversationsResponse.status}`);\n }\n const usersBody = (await usersResponse.json()) as StudioMemoryUsersPage;\n const conversationsBody =\n (await conversationsResponse.json()) as StudioMemoryConversationsPage;\n setUsers(usersBody.users);\n setConversations(conversationsBody.conversations);\n setSelectedConversationId(\n (current) => current || conversationsBody.conversations[0]?.id || \"\",\n );\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError.message : String(loadError));\n } finally {\n setLoading(false);\n }\n }, [props.enabled]);\n\n useEffect(() => {\n void loadMemory();\n }, [loadMemory]);\n\n useEffect(() => {\n if (!props.enabled || selectedConversationId.length === 0) {\n setMessages(undefined);\n setSteps(undefined);\n return;\n }\n let cancelled = false;\n async function loadDetail() {\n setDetailLoading(true);\n try {\n const [messagesResponse, stepsResponse] = await Promise.all([\n fetch(`/memory/conversations/${encodeURIComponent(selectedConversationId)}/messages`),\n fetch(`/memory/conversations/${encodeURIComponent(selectedConversationId)}/steps`),\n ]);\n if (!messagesResponse.ok) {\n throw new Error(`Conversation messages failed with HTTP ${messagesResponse.status}`);\n }\n if (!stepsResponse.ok) {\n throw new Error(`Conversation steps failed with HTTP ${stepsResponse.status}`);\n }\n if (!cancelled) {\n setMessages((await messagesResponse.json()) as StudioMemoryConversationMessages);\n setSteps((await stepsResponse.json()) as StudioMemoryConversationSteps);\n }\n } catch (loadError) {\n if (!cancelled) {\n setError(loadError instanceof Error ? loadError.message : String(loadError));\n setMessages(undefined);\n setSteps(undefined);\n }\n } finally {\n if (!cancelled) {\n setDetailLoading(false);\n }\n }\n }\n void loadDetail();\n return () => {\n cancelled = true;\n };\n }, [props.enabled, selectedConversationId]);\n\n const visibleConversations =\n selectedUserId.length === 0\n ? conversations\n : conversations.filter((conversation) => conversation.userId === selectedUserId);\n const selectedConversation =\n conversations.find((conversation) => conversation.id === selectedConversationId) ??\n visibleConversations[0];\n\n return (\n <section\n className=\"grid min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden bg-background/55\"\n aria-label=\"Memory\"\n >\n <header className=\"bg-background/70 pb-5 pl-0 pr-6 pt-0 backdrop-blur\">\n <div className=\"grid w-full grid-cols-[minmax(0,1fr)_auto] items-end gap-4 max-md:grid-cols-1\">\n <div className=\"grid min-w-0 gap-2\">\n <div className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.24em] text-primary\">\n Conversation store\n </div>\n <h1 className=\"m-0 text-2xl font-semibold leading-none tracking-tight text-foreground\">\n Memory\n </h1>\n <p className=\"m-0 max-w-[62ch] text-sm leading-6 text-muted-foreground\">\n Stored users, conversations, raw messages, and transcript steps from the Studio\n session store.\n </p>\n </div>\n <Button\n className=\"h-9 min-h-9 rounded-lg px-3 font-mono text-xs\"\n type=\"button\"\n variant=\"secondary\"\n disabled={loading}\n onClick={() => void loadMemory()}\n >\n Refresh\n </Button>\n </div>\n </header>\n\n <div className=\"min-h-0 overflow-auto pb-6 pl-0 pr-6\">\n {!props.enabled ? (\n <EmptyState title=\"Memory unavailable\" text=\"This Studio runtime has no session store.\" />\n ) : loading && conversations.length === 0 ? (\n <EmptyState title=\"Loading memory\" text=\"Reading users and conversations.\" />\n ) : error.length > 0 && conversations.length === 0 ? (\n <EmptyState title=\"Memory error\" text={error} />\n ) : (\n <div className=\"grid min-h-0 gap-4 xl:grid-cols-[280px_minmax(320px,0.8fr)_minmax(0,1.2fr)]\">\n <section className=\"grid content-start gap-2 rounded-xl border border-border/80 bg-card/45 p-3\">\n <PanelHeader title=\"Users\" value={users.length} />\n <Button\n className=\"h-auto min-h-9 justify-start rounded-lg px-3 py-2 text-left font-mono text-xs\"\n type=\"button\"\n variant={selectedUserId.length === 0 ? \"secondary\" : \"ghost\"}\n onClick={() => setSelectedUserId(\"\")}\n >\n All users\n </Button>\n {users.map((user) => (\n <Button\n className=\"grid h-auto min-h-14 justify-start rounded-lg px-3 py-2 text-left\"\n type=\"button\"\n variant={selectedUserId === user.userId ? \"secondary\" : \"ghost\"}\n onClick={() => setSelectedUserId(user.userId)}\n key={user.userId}\n >\n <span className=\"min-w-0 truncate font-mono text-xs font-semibold\">\n {user.userId}\n </span>\n <span className=\"min-w-0 truncate text-xs text-muted-foreground\">\n {user.conversationCount} conversations ·{\" \"}\n {formatRelativeTime(user.lastInteractionAt)}\n </span>\n </Button>\n ))}\n </section>\n\n <section className=\"grid content-start gap-2 rounded-xl border border-border/80 bg-card/45 p-3\">\n <PanelHeader title=\"Conversations\" value={visibleConversations.length} />\n {visibleConversations.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border/80 bg-background/45 px-3 py-8 text-center text-sm text-muted-foreground\">\n No conversations.\n </div>\n ) : (\n visibleConversations.map((conversation) => (\n <ConversationButton\n key={conversation.id}\n conversation={conversation}\n agentName={agentLabel(props.agents, conversation.agentId)}\n active={conversation.id === selectedConversationId}\n onSelect={() => setSelectedConversationId(conversation.id)}\n />\n ))\n )}\n </section>\n\n <section className=\"grid min-h-0 content-start gap-4\">\n {selectedConversation === undefined ? (\n <EmptyState\n title=\"No conversation selected\"\n text=\"Choose a conversation to inspect.\"\n />\n ) : (\n <>\n <article className=\"grid gap-3 rounded-xl border border-border/80 bg-card/45 p-5\">\n <div className=\"flex min-w-0 flex-wrap items-start justify-between gap-3\">\n <div className=\"grid min-w-0 gap-1\">\n <h2 className=\"m-0 min-w-0 truncate text-lg font-semibold text-foreground\">\n {selectedConversation.title ?? \"Untitled conversation\"}\n </h2>\n <span className=\"min-w-0 break-all font-mono text-xs text-muted-foreground\">\n {selectedConversation.id}\n </span>\n </div>\n <Badge className=\"border-primary/35 bg-primary/10 text-primary\">\n {agentLabel(props.agents, selectedConversation.agentId)}\n </Badge>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-3\">\n <Fact label=\"user\" value={selectedConversation.userId} />\n <Fact label=\"messages\" value={selectedConversation.messageCount} />\n <Fact\n label=\"updated\"\n value={formatRelativeTime(selectedConversation.updatedAt)}\n />\n </div>\n </article>\n {detailLoading ? (\n <EmptyState\n title=\"Loading detail\"\n text=\"Reading message and transcript data.\"\n />\n ) : (\n <div className=\"grid gap-4\">\n <JsonPanel title=\"messages\" value={messages?.messages ?? []} />\n <JsonPanel title=\"steps\" value={steps?.steps ?? []} />\n </div>\n )}\n </>\n )}\n </section>\n </div>\n )}\n </div>\n </section>\n );\n}\n\nfunction ConversationButton(props: {\n conversation: StudioMemoryConversationSummary;\n agentName: string;\n active: boolean;\n onSelect: () => void;\n}) {\n return (\n <Button\n className=\"grid h-auto min-h-20 justify-start gap-2 rounded-lg px-3 py-3 text-left\"\n type=\"button\"\n variant={props.active ? \"secondary\" : \"ghost\"}\n onClick={props.onSelect}\n >\n <div className=\"grid min-w-0 gap-1\">\n <span className=\"min-w-0 truncate text-sm font-semibold text-foreground\">\n {props.conversation.title ?? \"Untitled conversation\"}\n </span>\n <span className=\"min-w-0 truncate font-mono text-[11px] text-muted-foreground\">\n {props.agentName} · {props.conversation.userId}\n </span>\n </div>\n <span className=\"font-mono text-[11px] text-muted-foreground\">\n {props.conversation.messageCount} messages ·{\" \"}\n {formatRelativeTime(props.conversation.updatedAt)}\n </span>\n </Button>\n );\n}\n\nfunction JsonPanel(props: { title: string; value: unknown }) {\n const count = Array.isArray(props.value) ? props.value.length : undefined;\n return (\n <section className=\"grid min-w-0 overflow-hidden rounded-xl border border-border/80 bg-card/45\">\n <div className=\"flex min-h-10 items-center justify-between gap-3 border-b border-border/80 bg-muted/20 px-4\">\n <PanelHeader title={props.title} {...(count === undefined ? {} : { value: count })} />\n </div>\n <div className=\"min-w-0 overflow-x-auto\">\n <pre className=\"m-0 max-h-96 min-w-max p-4 font-mono text-[12px] leading-5 text-foreground\">\n <code>\n <JsonSyntax text={JSON.stringify(props.value, null, 2)} />\n </code>\n </pre>\n </div>\n </section>\n );\n}\n\nfunction PanelHeader(props: { title: string; value?: number }) {\n return (\n <div className=\"flex min-w-0 items-center justify-between gap-3\">\n <h2 className=\"m-0 font-mono text-[10px] font-semibold uppercase tracking-[0.2em] text-muted-foreground\">\n {props.title}\n </h2>\n {props.value === undefined ? null : (\n <span className=\"font-mono text-[10px] font-semibold text-muted-foreground\">\n {props.value}\n </span>\n )}\n </div>\n );\n}\n\nfunction Fact(props: { label: string; value: string | number }) {\n return (\n <div className=\"grid min-w-0 gap-1 rounded-lg bg-background/45 px-3 py-2\">\n <span className=\"font-mono text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground\">\n {props.label}\n </span>\n <span\n className=\"min-w-0 truncate font-mono text-xs text-foreground\"\n title={String(props.value)}\n >\n {props.value}\n </span>\n </div>\n );\n}\n\nfunction EmptyState(props: { title: string; text: string }) {\n return (\n <div className=\"grid min-h-80 place-items-center rounded-xl border border-dashed border-border/80 bg-card/35 px-6 text-center\">\n <div className=\"grid max-w-md gap-2\">\n <h2 className=\"m-0 text-base font-semibold text-foreground\">{props.title}</h2>\n <p className=\"m-0 text-sm leading-6 text-muted-foreground\">{props.text}</p>\n </div>\n </div>\n );\n}\n\nfunction agentLabel(agents: StudioConfig[\"agents\"], agentId: string): string {\n return agents.find((agent) => agent.id === agentId)?.name ?? agentId;\n}\n"],"mappings":"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"}
|