@axiom-lattice/gateway 4.11.0 → 6.0.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 +0 -2
- package/dist/{OrphanRecoveryRuntime-BEFILJMU.mjs → OrphanRecoveryRuntime-T4T5NOZU.mjs} +2 -2
- package/dist/{a2a-standard-PBYPNHOA.mjs → a2a-standard-3OZFXDCW.mjs} +1 -1
- package/dist/a2a-standard-3OZFXDCW.mjs.map +1 -0
- package/dist/{sandboxOpenCredentialProvider-USIU7Z7H.mjs → chunk-GL7RV5L3.mjs} +29 -59
- package/dist/chunk-GL7RV5L3.mjs.map +1 -0
- package/dist/{chunk-ZBTG3T7K.mjs → chunk-NZXKECNN.mjs} +4 -19
- package/dist/{chunk-ZBTG3T7K.mjs.map → chunk-NZXKECNN.mjs.map} +1 -1
- package/dist/embed/{embed-page-AgentDetailSideApp-FHC56ARN.js → embed-page-AgentDetailSideApp-JYVZKSUU.js} +1 -1
- package/dist/embed/embed-page-AgentGovernanceWorkbench-SD2EHW2B.js +1 -0
- package/dist/embed/{embed-page-MessageGraph-DMP5EZBM.js → embed-page-MessageGraph-GLQXKAVC.js} +1 -1
- package/dist/embed/{embed-page-ReactChart-PYGNSRHG.js → embed-page-ReactChart-74MHCE2K.js} +1 -1
- package/dist/embed/{embed-page-SkillFlow-6LPE2VG3.js → embed-page-SkillFlow-NDAK3GAD.js} +1 -1
- package/dist/embed/{embed-page-TasksSideApp-MPYOPRXW.js → embed-page-TasksSideApp-DA4LUTMD.js} +5 -5
- package/dist/embed/{embed-page-TeamWorkspace-EXUAXKAH.js → embed-page-TeamWorkspace-DUB3L6V6.js} +1 -1
- package/dist/embed/{embed-page-TopologyRuntimeView-MH4YMU7D.js → embed-page-TopologyRuntimeView-NFBHAICN.js} +1 -1
- package/dist/embed/{embed-page-WorkflowAutomationView-KQYFSLLH.js → embed-page-WorkflowAutomationView-43YGTXGF.js} +1 -1
- package/dist/embed/{embed-page-chunk-O44JEYLD.js → embed-page-chunk-2PFKLMTR.js} +5 -5
- package/dist/embed/{embed-page-chunk-NW37OVAX.js → embed-page-chunk-BVSC3MSO.js} +1 -1
- package/dist/embed/{embed-page-chunk-YQZI5LNV.js → embed-page-chunk-C4ZV4IXK.js} +2 -2
- package/dist/embed/{embed-page-chunk-QGXGVLAX.js → embed-page-chunk-DWIBLGBW.js} +1 -1
- package/dist/embed/{embed-page-chunk-I7BVN6EY.js → embed-page-chunk-GKHIPXZ2.js} +1 -1
- package/dist/embed/{embed-page-chunk-QHXKZNDU.js → embed-page-chunk-P477ZTUO.js} +307 -191
- package/dist/embed/{embed-page-chunk-JSAUTBU5.js → embed-page-chunk-UHH575CK.js} +1 -1
- package/dist/embed/{embed-page-en-PQZ2ZCEH.js → embed-page-en-GLT2HEZZ.js} +1 -1
- package/dist/embed/{embed-page-zh-D3EX4GW4.js → embed-page-zh-XMEJPDMF.js} +1 -1
- package/dist/embed/embed-page.js +1 -1
- package/dist/index.d.mts +8 -7
- package/dist/index.d.ts +8 -7
- package/dist/index.js +1028 -1235
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +349 -567
- package/dist/index.mjs.map +1 -1
- package/dist/{open-GNBMCHYA.mjs → open-MDC4VCR7.mjs} +18 -1
- package/dist/open-MDC4VCR7.mjs.map +1 -0
- package/dist/{resources-2L3KSUUU.mjs → resources-DAU5ZIPB.mjs} +2 -17
- package/dist/resources-DAU5ZIPB.mjs.map +1 -0
- package/dist/sandboxOpenCredentialProvider-AT227D4N.mjs +66 -0
- package/dist/sandboxOpenCredentialProvider-AT227D4N.mjs.map +1 -0
- package/package.json +4 -4
- package/dist/a2a-standard-PBYPNHOA.mjs.map +0 -1
- package/dist/embed/embed-page-AgentGovernanceWorkbench-KAPZJBE6.js +0 -5
- package/dist/open-GNBMCHYA.mjs.map +0 -1
- package/dist/resources-2L3KSUUU.mjs.map +0 -1
- package/dist/sandboxOpenCredentialProvider-USIU7Z7H.mjs.map +0 -1
- /package/dist/{OrphanRecoveryRuntime-BEFILJMU.mjs.map → OrphanRecoveryRuntime-T4T5NOZU.mjs.map} +0 -0
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{a as Pe,b as Ne,c as Ft,d as Pt,e as Mt,f as Et,g as Kt,h as Bt,i as Nt,j as Lt,k as Ot,l as _t}from"./embed-page-chunk-YQZI5LNV.js";import{a as qe}from"./embed-page-chunk-NW37OVAX.js";import"./embed-page-chunk-I7BVN6EY.js";import"./embed-page-chunk-JSAUTBU5.js";import"./embed-page-chunk-WTOAQDQN.js";import{b as Ue,e as $e,f as kt,g as Tt,h as wt,i as St,l as It,m as Rt}from"./embed-page-chunk-V2GBFWLG.js";import{a as ht,b as Ct,c as At,d as bt,e as vt}from"./embed-page-chunk-SV2BM3WO.js";import"./embed-page-chunk-S4XZPBRM.js";import"./embed-page-chunk-QGXGVLAX.js";import{$ as pt,Aa as yt,C as lt,Da as xt,F as ct,L as dt,Oa as je,X as gt,g as Fe,ka as mt,pb as Dt,ra as ut,s as rt,sa as ft}from"./embed-page-chunk-QHXKZNDU.js";import{D as Ce,r as _,y as nt}from"./embed-page-chunk-O44JEYLD.js";import{a as M}from"./embed-page-chunk-QV7QAJ4N.js";import"./embed-page-chunk-VW3NF5NT.js";import"./embed-page-chunk-QULNM5O2.js";import{$b as Be,Cb as ot,Fa as et,Ia as De,Ja as tt,La as te,Ua as at,W as Q,_ as Ie,aa as Re,ea as Ke,ka as Ge,la as Je,lc as it,ma as Qe,oa as Xe,ra as D,ta as j,wa as ze,xa as w,xc as st,ya as he}from"./embed-page-chunk-MHGVD4EV.js";import{a as ye}from"./embed-page-chunk-R5QL57JJ.js";import"./embed-page-chunk-QOWM3LMZ.js";import"./embed-page-chunk-EUOOO2LS.js";import"./embed-page-chunk-5JDQ456X.js";import{f as T}from"./embed-page-chunk-QBTAJ2YI.js";var u=T(ye());var ae=T(ye());var X=T(ye());var Vt=T(ye());var ce=T(M()),Gt=60,zt=72,He=(0,Vt.memo)(({data:n})=>{let s=Pe(n.type),g=Math.min(12+Math.sqrt(n.subAgentCount)*10,48);return(0,ce.jsxs)("div",{style:{display:"flex",flexDirection:"column",alignItems:"center"},children:[(0,ce.jsx)($e,{type:"target",position:Ue.Top,style:{left:"50%",top:"50%",transform:"translate(-50%, -50%)",background:"transparent",border:"none",width:0,height:0},isConnectable:!1}),(0,ce.jsx)("div",{title:n.label,style:{width:g,height:g,borderRadius:"50%",background:Ne(s.color),display:"flex",alignItems:"center",justifyContent:"center",color:"#fff",fontSize:Math.max(10,g*.4),fontWeight:600,cursor:"pointer",boxShadow:"0 2px 8px rgba(0,0,0,0.15)"},children:n.label.charAt(0).toUpperCase()}),(0,ce.jsx)("div",{style:{fontSize:11,maxWidth:120,textAlign:"center",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",marginTop:4},children:n.label}),(0,ce.jsx)($e,{type:"source",position:Ue.Top,style:{left:"50%",top:"50%",transform:"translate(-50%, -50%)",background:"transparent",border:"none",width:0,height:0},isConnectable:!1})]})});He.displayName="AgentGraphNode";var ne=T(M()),ln=({assistants:n,onNodeClick:s})=>{let[g,r,d]=wt([]),[i,e,h]=St([]),[f,l]=(0,X.useState)(null),k=(0,X.useMemo)(()=>({agent:He}),[]),O=(0,X.useMemo)(()=>Mt(n),[n]);(0,X.useEffect)(()=>{let C=O.nodes.map(o=>({id:o.id})),R=O.edges.map(o=>({source:o.source,target:o.target})),K=new Map(O.nodes.map(o=>[o.id,o])),W=bt(C).force("link",At(R).id(o=>o.id).distance(80)).force("charge",vt().strength(-220)).force("center",ht(0,0)).force("collide",Ct(45)).stop();for(let o=0;o<300;o++)W.tick();let $=C.map(o=>({id:o.id,type:"agent",data:K.get(o.id),position:{x:o.x-Gt/2,y:o.y-zt/2}})),F=O.edges.map(o=>({id:`e${o.source}-${o.target}`,source:o.source,target:o.target,style:{stroke:"#1677ff",strokeWidth:2},type:"straight"}));r($),e(F)},[O,r,e]);let G=(0,X.useMemo)(()=>f===null?g:g.map(C=>{let R=C.id===f||i.some(K=>K.source===f&&K.target===C.id||K.target===f&&K.source===C.id);return{...C,style:{opacity:R?1:.2,transition:"opacity 0.2s ease"}}}),[g,i,f]),p=(0,X.useMemo)(()=>f===null?i.map(C=>({...C,style:{stroke:"#1677ff",strokeWidth:1.5,opacity:.25,transition:"opacity 0.2s ease"}})):i.map(C=>{let R=C.source===f||C.target===f;return{...C,style:{stroke:"#1677ff",strokeWidth:R?2.5:1,opacity:R?1:.04,transition:"opacity 0.2s ease"}}}),[i,f]);return(0,ne.jsx)("div",{style:{width:"100%",height:"100%",background:"#fafafa",position:"relative"},children:(0,ne.jsxs)(Tt,{nodes:G,edges:p,onNodesChange:d,onEdgesChange:h,onNodeMouseEnter:(C,R)=>l(R.id),onNodeMouseLeave:()=>l(null),onNodeClick:(C,R)=>s?.(String(R.id)),nodeTypes:k,fitView:!0,fitViewOptions:{padding:.25},children:[(0,ne.jsx)(It,{color:"#eee",gap:20}),(0,ne.jsx)(Rt,{})]})})},jt=n=>(0,ne.jsx)(kt,{children:(0,ne.jsx)(ln,{...n})});var E=T(M()),cn=(n,s)=>{if(!n)return"\u2014";let g=Date.now()-new Date(n).getTime(),r=Math.floor(g/6e4);if(r<1)return s?s("common.time.justNow"):"just now";if(r<60)return s?s("common.time.minutesAgo",{count:r}):`${r}m ago`;let d=Math.floor(r/60);if(d<24)return s?s("common.time.hoursAgo",{count:d}):`${d}h ago`;let i=Math.floor(d/24);return s?s("common.time.daysAgo",{count:i}):`${i}d ago`},dn=n=>n===null?"#d9d9d9":n>=80?"#22c55e":n>=50?"#f59e0b":"#ef4444",gn=ut(({css:n})=>({row:n`
|
|
2
|
-
display: flex;
|
|
3
|
-
justify-content: space-between;
|
|
4
|
-
align-items: flex-end;
|
|
5
|
-
`})),Ut={fontSize:16,fontWeight:700,lineHeight:1.2,cursor:"help"},We={fontSize:10,color:"rgba(0, 0, 0, 0.45)",whiteSpace:"nowrap",marginTop:1},Ze={display:"flex",flexDirection:"column",alignItems:"center"},$t=({stats:n})=>{let{styles:s}=gn(),g=_();if(!n)return(0,E.jsxs)("div",{style:{display:"flex",fontSize:11,color:"#d9d9d9"},children:[(0,E.jsx)("span",{style:{flex:1},children:g("governance.cardStats.scoreEmpty")}),(0,E.jsx)("span",{style:{flex:1},children:g("governance.cardStats.threadsEmpty")})]});let r=n.evalScore!==null?Number(n.evalScore).toFixed(1):"\u2014",d=n.threadCount>0?n.threadCount:"\u2014",i=dn(n.evalScore),e=n.evalPassRate!==null?`${n.evalPassRate}%`:"\u2014";return(0,E.jsxs)("div",{className:s.row,children:[(0,E.jsxs)("div",{style:{display:"flex",gap:16,alignItems:"flex-end"},children:[(0,E.jsx)(Re,{title:g("governance.cardStats.evalTooltip",{score:r,passRate:e,runs:n.evalRuns}),children:(0,E.jsxs)("div",{style:Ze,children:[(0,E.jsx)("span",{style:{...Ut,color:i},children:r}),(0,E.jsx)("span",{className:"lattice-stat-label",style:We,children:g("governance.cardStats.evalScore")})]})}),(0,E.jsx)(Re,{title:n.lastActive?g("governance.cardStats.conversationsTooltipActive",{total:n.threadCount,last7d:n.last7d,last30d:n.last30d,lastActive:cn(n.lastActive,g)}):g("governance.cardStats.conversationsTooltip",{total:n.threadCount,last7d:n.last7d,last30d:n.last30d}),children:(0,E.jsxs)("div",{style:Ze,children:[(0,E.jsx)("span",{style:{...Ut,color:d==="\u2014"?"#d9d9d9":"#595959"},children:d}),(0,E.jsx)("span",{className:"lattice-stat-label",style:We,children:g("governance.cardStats.threads")})]})})]}),n.daily7d.length>0&&(0,E.jsxs)("div",{style:Ze,children:[(0,E.jsx)(Et,{values:n.daily7d,width:40,height:24,color:"#8c8c8c"}),(0,E.jsx)("span",{className:"lattice-stat-label",style:We,children:g("governance.cardStats.threads7d")})]})]})};var x=T(M()),pn=[{key:"all",labelKey:"governance.list.tab.all"},{key:"capability",labelKey:"governance.list.tab.capability"},{key:"orchestrator",labelKey:"governance.list.tab.orchestrator"},{key:"team",labelKey:"governance.list.tab.team"},{key:"workflow",labelKey:"governance.list.tab.workflow"}],qt=({items:n,assistants:s=[],stats:g,loading:r,onItemClick:d,onOpenPlayground:i,onOpenEval:e,onCreate:h,onDelete:f})=>{let l=_(),[k,O]=(0,ae.useState)("all"),[G,p]=(0,ae.useState)(null),[C,R]=(0,ae.useState)(null),K=(0,ae.useMemo)(()=>{let o=new Set;return n.forEach(P=>P.tags.forEach(ie=>o.add(ie))),Array.from(o).map(P=>({value:P,label:P}))},[n]),W=(0,ae.useMemo)(()=>n.filter(o=>!(k!=="all"&&o.type!==k||G&&!o.tags.includes(G)||C&&o.status!==C)),[n,k,G,C]),$=[{key:"edit",icon:pt,label:l("common.edit"),onClick:o=>d(o.id)},{key:"playground",icon:rt,label:l("governance.list.action.playground"),onClick:o=>i(o.id)},{key:"eval",icon:ct,label:l("governance.list.action.eval"),onClick:o=>e(o.id)}];f&&$.push({key:"delete",icon:mt,label:l("common.delete"),danger:!0,onClick:o=>f(o.id)});let F=(0,ae.useMemo)(()=>[{mode:"graph",icon:gt,label:l("governance.list.viewMode.graph"),render:()=>(0,x.jsx)(jt,{assistants:s,onNodeClick:d})}],[s,d,l]);return(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)("span",{"data-testid":"agent-list-state","data-loading":String(r),"data-count":W.length,hidden:!0,"aria-hidden":"true"}),(0,x.jsx)(yt,{title:l("governance.list.title"),itemName:"common.item.agent",items:W,loading:r,keyExtractor:o=>o.id,tabs:pn.map(o=>({key:o.key,label:l(o.labelKey)})),activeTab:k,onTabChange:o=>O(o),headerLeft:(0,x.jsxs)("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[(0,x.jsx)(je,{value:G,onChange:p,options:K,placeholder:l("governance.list.filter.domain"),allLabel:l("governance.list.filter.allDomains")}),(0,x.jsx)(je,{value:C,onChange:R,options:[{value:"enabled",label:l("governance.list.status.enabled")},{value:"draft",label:l("governance.list.status.draft")},{value:"disabled",label:l("governance.list.status.disabled")}],placeholder:l("governance.list.filter.status"),allLabel:l("governance.list.filter.allStatuses")})]}),renderIcon:o=>{let P=Ne(Pe(o.type).color);return(0,x.jsx)("div",{title:l("governance.list.typeIconTitle",{type:o.type}),style:{width:32,height:32,borderRadius:8,background:`${P}1A`,color:P,display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0},children:(0,x.jsx)(Fe,{size:18})})},renderPrimary:o=>(0,x.jsx)("span",{"data-testid":"agent-name","data-agent-id":o.id,children:o.name}),renderSecondary:o=>o.description||void 0,renderDetails:o=>(0,x.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",gap:8,flexWrap:"wrap"},children:[(0,x.jsxs)("div",{style:{display:"flex",gap:4,flexWrap:"wrap",alignItems:"center"},children:[o.tags.map(P=>(0,x.jsx)(De,{color:"magenta",style:{margin:0,borderRadius:10,border:"none"},children:P},P)),(0,x.jsx)(De,{color:Pe(o.type).color,style:{margin:0,borderRadius:10,border:"none"},children:o.type})]}),(0,x.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,flexShrink:0},children:[(0,x.jsx)(Re,{title:l("governance.list.statusTooltip",{status:o.status}),children:(0,x.jsx)("span",{style:{width:8,height:8,borderRadius:"50%",background:Ft(o.status),display:"inline-block",cursor:"help"}})}),(0,x.jsx)("span",{style:{fontSize:12,color:"#8c8c8c"},children:o.version})]})]}),renderFooter:o=>(0,x.jsx)("div",{style:{borderTop:"1px dashed #f0f0f0",paddingTop:10},children:(0,x.jsx)($t,{stats:g?.[o.id]})}),itemActions:$,actionsStyle:"icon",actionsPosition:"hover",onItemClick:o=>d(o.id),createLabel:l("governance.list.create"),onCreateClick:h,viewModeExtensions:F,emptyIcon:(0,x.jsx)(Fe,{size:48,style:{opacity:.5}}),emptyTitle:l("governance.list.emptyTitle"),emptyDescription:l("governance.list.emptyDescription")})]})};var b=T(ye());var de=T(ye());var Ae=T(M()),{Text:mn}=te,Ht=({onSelect:n,value:s,placeholder:g})=>{let r=_(),d=g??r("chatConfig.parentAgent.selectPlaceholder"),[i,e]=(0,de.useState)([]),[h,f]=(0,de.useState)(!1),{get:l}=Ce(),k=(0,de.useCallback)(async()=>{f(!0);try{let p=await l("/api/assistants");p.success&&e(p.data?.records||[])}catch(p){console.error("Failed to fetch assistants:",p)}finally{f(!1)}},[l]);return(0,de.useEffect)(()=>{k()},[k]),(0,Ae.jsx)(Ie,{showSearch:!0,allowClear:!0,value:s,placeholder:d,loading:h,onChange:p=>{if(!p){n(null);return}let C=i.find(R=>R.id===p);n(C||null)},onDropdownVisibleChange:p=>{p&&k()},optionFilterProp:"label",style:{width:"100%"},options:i.map(p=>({value:p.id,label:p.name||p.id,description:p.description})),optionRender:p=>(0,Ae.jsxs)("div",{children:[(0,Ae.jsx)("div",{children:p.label}),p.data.description&&(0,Ae.jsx)(mn,{type:"secondary",style:{fontSize:12},children:p.data.description})]})})};var L=T(M()),{Text:Wt}=te,Zt=({subAgentKeys:n,decisions:s,onChange:g})=>{let{token:r}=tt.useToken(),d=_(),i=(h,f)=>{let l=s.map(k=>k.originalKey===h?{...k,clone:f,cloneKey:f?`${h}_clone`:void 0}:k);g(l)},e=(h,f)=>{let l=s.map(k=>k.originalKey===h?{...k,cloneKey:f}:k);g(l)};return n.length===0?null:(0,L.jsxs)("div",{children:[(0,L.jsx)(Wt,{type:"secondary",style:{display:"block",marginBottom:8},children:d("chatConfig.subAgentInherit.hint")}),(0,L.jsx)(ze,{size:"small",bordered:!0,dataSource:s,style:{borderRadius:r.borderRadius},renderItem:h=>(0,L.jsxs)(ze.Item,{style:{display:"flex",flexDirection:"column",alignItems:"stretch",gap:8,padding:"8px 16px"},children:[(0,L.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center"},children:[(0,L.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[h.clone?(0,L.jsx)(Be,{style:{color:r.colorPrimary}}):(0,L.jsx)(it,{style:{color:r.colorTextSecondary}}),(0,L.jsx)(Wt,{style:{fontFamily:"monospace"},children:h.originalKey})]}),(0,L.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[(0,L.jsx)(De,{color:h.clone?"blue":"default",children:h.clone?d("chatConfig.subAgentInherit.clone"):d("chatConfig.subAgentInherit.reuse")}),(0,L.jsx)(et,{size:"small",checked:h.clone,onChange:f=>i(h.originalKey,f)})]})]}),h.clone&&(0,L.jsx)(j,{size:"small",placeholder:d("chatConfig.subAgentInherit.cloneKeyPlaceholder"),value:h.cloneKey,onChange:f=>e(h.originalKey,f.target.value),style:{fontFamily:"monospace",fontSize:12},addonBefore:d("chatConfig.keyValue.key")})]})})]})};function Yt(n,s){return n.mode!=="local"||n.templateKey||typeof n.executable=="string"&&n.executable.trim().length>0?null:s?s("chat.config.executableRequired"):"Choose a template or enter a custom executable"}var a=T(M()),{TextArea:Jt}=j,{Text:oe}=te,Qt="/.well-known/agent-card.json",un=[{value:"http://",label:"http://"},{value:"https://",label:"https://"}],fn={react:"chatConfig.createAssistant.typeDesc.react",deep_agent:"chatConfig.createAssistant.typeDesc.deepAgent",team:"chatConfig.createAssistant.typeDesc.team",processing:"chatConfig.createAssistant.typeDesc.processing",a2a_remote:"chatConfig.createAssistant.typeDesc.a2aRemote"};function Xt(n,s,g="https://"){let r=String(n??"").trim();if(!r)return"";let d=s==="http://"||s==="https://"?s:g,e=(/^https?:\/\//i.test(r)?r:`${d}${r.replace(/^\/+/,"")}`).replace(/\/+$/,"");return e.endsWith(Qt)?e:`${e}${Qt}`}function yn(n){try{return new URL(n).port||void 0}catch{return}}function hn(n){return n.some(s=>s==="--port"||s==="-p"||/^--port=/.test(s)||/^-p=/.test(s))}function en(n,s){let g=[...n.args],r=yn(s);return r&&!hn(g)&&g.push("--port",r),{...n,args:g,...n.env?{env:{...n.env}}:{}}}var tn=({open:n,onCancel:s,onSuccess:g,initialMode:r,initialValues:d})=>{let[i]=D.useForm(),e=_(),[h,f]=(0,b.useState)(!1),[l,k]=(0,b.useState)("learn"),[O,G]=(0,b.useState)(""),[p,C]=(0,b.useState)(null),[R,K]=(0,b.useState)([]),W=D.useWatch("type",i)||"react",$=W==="a2a_remote",[F,o]=(0,b.useState)("remote"),[P,ie]=(0,b.useState)(void 0),[ge,be]=(0,b.useState)([]),[pe,me]=(0,b.useState)(!1),Y=(0,b.useRef)(0),[Le,ve]=(0,b.useState)(!1),[Oe,se]=(0,b.useState)(!1),{get:J,post:Z,put:_e}=Ce(),Me=nt("agent-architect"),{workspaceId:z,trainingProjects:ue,loading:ee}=ft(),[Ve,fe]=(0,b.useState)(null),xe=JSON.stringify(d??null),B=ue.find(t=>t.id===Ve)??ue[0]??null,[ke,Te]=(0,b.useState)([]),Ee=(0,b.useCallback)(()=>{C(null),K([])},[]),re=(0,b.useCallback)(()=>{i.resetFields(),Ee(),k("learn"),G(""),Te([]),fe(null),o("remote"),ie(void 0),be([]),se(!1),ve(!1)},[i,Ee]);(0,b.useEffect)(()=>{if(n){re(),k(r??"learn");let t=d?.a2aMode;(t==="remote"||t==="local")&&o(t),i.setFieldsValue({type:"react",agentCardProtocol:"https://",a2aMode:"remote",timeout:3e5,...d})}},[n,i,r,xe,re]),(0,b.useEffect)(()=>{let t=++Y.current,c=!0;return n&&$?(i.setFieldValue("prompt",""),F==="local"?(me(!0),J("/api/local-a2a/templates").then(v=>{c&&t===Y.current&&v?.data?.records&&be(v.data.records)}).catch(()=>{c&&t===Y.current&&be([])}).finally(()=>{c&&t===Y.current&&me(!1)})):me(!1)):me(!1),()=>{c=!1,Y.current+=1}},[i,$,F,J,n]);let le=ge.find(t=>t.key===P),we=(0,b.useCallback)(()=>{let t=Yt({mode:F,templateKey:P,executable:i.getFieldValue("commandExecutable")},e);return t?(se(!0),i.setFields([{name:"commandExecutable",errors:[t]}]),w.warning(t),!1):!0},[F,P,i,e]);(0,b.useEffect)(()=>{le&&i.setFieldsValue({agentCardProtocol:"http://"})},[i,le]);let m=(0,b.useCallback)(async()=>{if(!we())return;let t=Xt(i.getFieldValue("agentCardUrl"),i.getFieldValue("agentCardProtocol"),F==="local"?"http://":"https://");if(!t){w.warning(e("chatConfig.createAssistant.a2aUrlWarning"));return}ve(!0);try{let c={agentCardUrl:t,apiKey:i.getFieldValue("apiKey")};if(F==="local"){let y=le;if(y)c.localRuntime={label:i.getFieldValue("name")||void 0,agentCardUrl:t,command:en(y.command,t)};else{let N=i.getFieldValue("commandArgs")||"",H=N?N.split(/\s+/).filter(Boolean):[],I=String(i.getFieldValue(["command","cwd"])||"").trim();c.localRuntime={label:i.getFieldValue("name")||void 0,agentCardUrl:t,command:{executable:String(i.getFieldValue("commandExecutable")||"").trim(),args:H,...I?{cwd:I}:{}}}}}let v=await Z("/api/a2a/test-connection",c);if(v.data?.reachable){let y=v.data.agentCard;w.success(e("chatConfig.createAssistant.connectedTo",{name:v.data.agentName||t}))}else w.error(v.data?.error||e("chatConfig.createAssistant.connectionFailed"))}catch{w.error(e("chatConfig.createAssistant.connectionTestFailed"))}finally{ve(!1)}},[i,Z,F,le,we,e]),A=(0,b.useCallback)(t=>{if(C(t),!t){i.resetFields(["key","name","description","type","prompt"]),K([]);return}let c=typeof t.graphDefinition=="object"&&t.graphDefinition!==null?t.graphDefinition:{},v=c.key||t.id,y=t.name||c.name||"";i.setFieldsValue({key:`${v}_ext`,name:y?`${y} (Extended)`:"",description:t.description||c.description||"",type:c.type||"react",prompt:c.prompt||""});let N=c.subAgents||[];K(N.map(H=>({originalKey:H,clone:!1})))},[i]),S=async(t,c)=>{let v=await J(`/api/assistants/${t}`);if(!v.success)throw new Error(e("chatConfig.createAssistant.cloneFetchFailed",{key:t}));let y=v.data,N=typeof y.graphDefinition=="object"?y.graphDefinition:{},H={id:c,name:`${y.name} (Clone)`,description:y.description||"",graphDefinition:{...N,key:c,name:`${y.name} (Clone)`}},I=await Z("/api/assistants",H);if(!I.success)throw new Error(I.message||e("chatConfig.createAssistant.cloneFailed",{key:t}));return I.data},q=t=>{let c={id:t.key,name:t.name,description:t.description||"",graphDefinition:{key:t.key,name:t.name,description:t.description||"",type:t.type,prompt:t.prompt||"",tools:[],skills:[],subAgents:t.type==="deep_agent"||t.type==="processing"?[]:void 0,middleware:[]}};if(t.type==="a2a_remote"&&(c.graphDefinition.agentCardUrl=Xt(t.agentCardUrl,t.agentCardProtocol,(t.a2aMode||F)==="local"?"http://":"https://"),t.apiKey&&(c.graphDefinition.apiKey=t.apiKey),t.timeout&&(c.graphDefinition.timeout=t.timeout),(t.a2aMode||F)==="local")){let v=le;if(v)c.graphDefinition.localRuntime={label:t.name||void 0,agentCardUrl:c.graphDefinition.agentCardUrl,command:en(v.command,c.graphDefinition.agentCardUrl)};else{let y=t.commandArgs||"",N=y?y.split(/\s+/).filter(Boolean):[],H=String(t.command?.cwd||"").trim();c.graphDefinition.localRuntime={label:t.name||void 0,agentCardUrl:c.graphDefinition.agentCardUrl,command:{executable:String(t.commandExecutable||"").trim(),args:N,...H?{cwd:H}:{}}}}}return c},Se=async(t,c)=>{if(!p)throw new Error(e("chatConfig.createAssistant.noParentAgent"));let v=R.filter(I=>I.clone);for(let I of v){if(!I.cloneKey||!I.cloneKey.trim())throw new Error(e("chatConfig.createAssistant.cloneKeyRequired",{key:I.originalKey}));if(!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(I.cloneKey))throw new Error(e("chatConfig.createAssistant.cloneKeyInvalid",{key:I.cloneKey,originalKey:I.originalKey}))}let y=[];for(let I of R)if(I.clone){let rn=await S(I.originalKey,I.cloneKey);c.push(rn),y.push(I.cloneKey)}else y.push(I.originalKey);let N=typeof p.graphDefinition=="object"?p.graphDefinition:{},H={key:t.key,name:t.name,description:t.description||"",extendsAgent:p.id,type:t.type||N.type};return t.prompt&&t.prompt!==N.prompt&&(H.prompt=t.prompt),(y.length>0||N.subAgents&&N.subAgents.length>0)&&(H.subAgents=y),{id:t.key,name:t.name,description:t.description||"",graphDefinition:H}},on=async()=>{if(l==="learn"){let t=O.trim();if(!t){w.error(e("chatConfig.createAssistant.trainingGoalRequired"));return}if(!B){w.error(e("chatConfig.createAssistant.noTrainingProject"));return}f(!0);try{let c=`agent-${Bt(t+Date.now())}`,v=await Z("/api/assistants",{id:c,name:c,graphDefinition:{key:c,name:c,description:"",type:"react",prompt:"To be trained",metadata:{trainingProjectId:B.id,learningPlaceholder:"true",architectureStatus:"undecided"}}});if(!v.data)throw new Error(e("chatConfig.createAssistant.agentCreateFailed"));let{roundTaskId:y}=await Lt({goal:t,targetAgentId:c,workspaceId:z??void 0,projectId:B.id,existingThreadId:Nt(Me.tenantId,c),files:ke,post:Z,put:_e});w.success(e("chatConfig.createAssistant.agentCreated")),G(""),Te([]),k("learn"),g?.(v.data,{initialMessage:Ot({goal:t,roundTaskId:y,targetAgentId:c,targetMode:"placeholder",files:ke,projectId:B.id,workspaceId:B.workspaceId??z??void 0}),projectId:B.id,initialMessageCustomRunConfig:{execution:{taskId:y}}}),s()}catch(c){w.error(c instanceof Error?c.message:e("chatConfig.createAssistant.agentCreateFailed"))}finally{f(!1)}return}try{if(l==="scratch"&&$&&!we())return;let t=await i.validateFields();f(!0);let c=[],v=l==="scratch"?q(t):await Se(t,c),y=await Z("/api/assistants",v);if(y.success){w.success(l==="extend"?e("chatConfig.createAssistant.createdByExtending",{name:p?.name??""}):e("chatConfig.createAssistant.created")),re();for(let N of c)g?.(N);g?.(y.data),s()}else w.error(y.message||e("chatConfig.createAssistant.createFailed"))}catch(t){if(t?.errorFields){let c={key:e("chatConfig.createAssistant.field.key"),name:e("chatConfig.createAssistant.field.name"),description:e("chatConfig.createAssistant.field.description"),prompt:e("chatConfig.createAssistant.field.systemPrompt")},v=t.errorFields.map(y=>c[String((y.name??[])[0])]??String((y.name??[])[0])).filter(Boolean);w.warning(v.length>0?e("chatConfig.createAssistant.requiredFields",{fields:[...new Set(v)].join(", ")}):e("chatConfig.createAssistant.requiredFieldsGeneric"));return}w.error(t.message||e("chatConfig.createAssistant.createError"))}finally{f(!1)}},Ye=p?.graphDefinition?.subAgents||[],sn=l==="extend"&&p&&Ye.length>0;return(0,a.jsxs)(he,{title:e("chatConfig.createAssistant.title"),open:n,onCancel:()=>{re(),s()},footer:[(0,a.jsx)(Q,{onClick:()=>{re(),s()},children:e("common.cancel")},"cancel"),(0,a.jsx)(Q,{type:"primary",icon:l==="extend"?(0,a.jsx)(Be,{}):l==="learn"?(0,a.jsx)(ot,{}):(0,a.jsx)(st,{}),loading:h,disabled:l==="learn"&&(ee||!B),onClick:on,children:e(l==="extend"?"chatConfig.createAssistant.createExtend":l==="learn"?"chatConfig.createAssistant.startLearning":"common.create")},"submit")],width:760,children:[l==="extend"&&(0,a.jsxs)("div",{style:{marginBottom:20},children:[(0,a.jsx)(oe,{type:"secondary",style:{display:"block",marginBottom:8},children:e("chatConfig.createAssistant.parentAgent")}),(0,a.jsx)(Ht,{value:p?.id,onSelect:A}),p&&(0,a.jsx)(oe,{type:"secondary",style:{display:"block",marginTop:4,fontSize:12},children:e("chatConfig.createAssistant.inheritHint")})]}),l==="extend"&&p&&(0,a.jsx)(Ge,{style:{margin:"12px 0"}}),l==="learn"&&(0,a.jsxs)("div",{children:[(0,a.jsx)(oe,{style:{display:"block",marginBottom:8},children:e("chatConfig.createAssistant.learnHint")}),(0,a.jsx)(j.TextArea,{rows:3,value:O,onChange:t=>G(t.target.value),placeholder:"e.g. Handle price disputes using the price protection policy"}),B&&(0,a.jsxs)("div",{style:{marginTop:12},children:[(0,a.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:12,marginBottom:8},children:[(0,a.jsx)(oe,{type:"secondary",children:e("chatConfig.createAssistant.referenceFiles")}),(0,a.jsx)(qe,{project:B,projects:ue,value:B?.id??null,onChange:fe,loading:ee})]}),(0,a.jsx)(Kt,{projectId:B.id,value:ke,onChange:Te}),(0,a.jsx)(oe,{type:"secondary",style:{display:"block",marginTop:6,fontSize:12},children:e("chatConfig.createAssistant.referenceFilesHint")})]}),!B&&!ee&&(0,a.jsx)("div",{style:{marginTop:12},children:(0,a.jsx)(qe,{project:B,projects:ue,value:null,onChange:fe,loading:ee})})]}),l!=="learn"&&(0,a.jsxs)(D,{form:i,layout:"vertical",autoComplete:"off",initialValues:{type:"react",agentCardProtocol:"https://",a2aMode:"remote"},children:[(0,a.jsx)(D.Item,{name:"key",label:e("chatConfig.createAssistant.field.key"),rules:[{required:!0,message:e("chatConfig.createAssistant.validation.keyRequired")},{pattern:/^[a-zA-Z][a-zA-Z0-9_-]*$/,message:e("chatConfig.createAssistant.validation.keyPattern")}],style:{marginBottom:16},children:(0,a.jsx)(j,{placeholder:"e.g., my_assistant"})}),(0,a.jsx)(D.Item,{name:"name",label:e("chatConfig.createAssistant.field.name"),rules:[{required:!0,message:e("chatConfig.createAssistant.validation.nameRequired")}],style:{marginBottom:16},children:(0,a.jsx)(j,{placeholder:"e.g., My Assistant"})}),(0,a.jsx)(D.Item,{name:"description",label:e("chatConfig.createAssistant.field.description"),rules:[{required:!0,message:e("chatConfig.createAssistant.validation.descriptionRequired")}],style:{marginBottom:16},children:(0,a.jsx)(Jt,{placeholder:e("chatConfig.createAssistant.descriptionPlaceholder"),autoSize:{minRows:2,maxRows:4}})}),(0,a.jsx)(D.Item,{name:"type",label:e("chatConfig.createAssistant.field.agentType"),rules:[{required:!0}],style:{marginBottom:16},children:(0,a.jsx)(Je,{options:[{value:"react",label:e("chatConfig.agentType.executor")},{value:"deep_agent",label:e("chatConfig.agentType.orchestrator")},{value:"team",label:e("chatConfig.agentType.team")},{value:"processing",label:e("chatConfig.agentType.workflow")},{value:"a2a_remote",label:e("chatConfig.agentType.a2aRemote")}],block:!0})}),(0,a.jsx)(oe,{type:"secondary",style:{fontSize:12,display:"block",marginTop:-12,marginBottom:16,lineHeight:1.5},children:e(fn[W]??"chatConfig.createAssistant.typeDesc.react")}),$&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(D.Item,{label:e("chatConfig.createAssistant.field.connectionMode"),style:{marginBottom:16},children:(0,a.jsxs)(Ke.Group,{value:F,onChange:t=>{let c=t.target.value;o(c),i.setFieldValue("a2aMode",c),c==="local"&&i.setFieldValue("agentCardProtocol","http://"),ie(void 0)},optionType:"button",buttonStyle:"solid",children:[(0,a.jsx)(Ke.Button,{value:"remote",children:e("chatConfig.createAssistant.mode.remoteUrl")}),(0,a.jsx)(Ke.Button,{value:"local",children:e("chatConfig.createAssistant.mode.localManaged")})]})}),(0,a.jsx)(D.Item,{name:"a2aMode",noStyle:!0,hidden:!0,children:(0,a.jsx)(j,{})}),F==="local"&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(D.Item,{label:e("chatConfig.createAssistant.field.template"),style:{marginBottom:16},children:(0,a.jsx)(Ie,{placeholder:e("chatConfig.createAssistant.templatePlaceholder"),allowClear:!0,loading:pe,value:P,onChange:t=>{ie(t),t&&se(!1)},options:ge.map(t=>({value:t.key,label:t.name||t.key})),notFoundContent:pe?void 0:(0,a.jsx)(oe,{type:"secondary",style:{padding:8,display:"block"},children:e("chatConfig.createAssistant.noTemplates")})})}),!P&&(0,a.jsx)(a.Fragment,{children:Oe?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(D.Item,{name:"commandExecutable",label:e("chatConfig.createAssistant.field.executable"),rules:[{required:!0,whitespace:!0,message:e("chatConfig.createAssistant.validation.executableRequired")}],style:{marginBottom:16},children:(0,a.jsx)(j,{placeholder:"e.g. node, opencode, /usr/local/bin/my-server"})}),(0,a.jsx)(D.Item,{name:"commandArgs",label:e("chatConfig.createAssistant.field.arguments"),style:{marginBottom:16},children:(0,a.jsx)(j,{placeholder:"e.g. --serve --port 4301"})}),(0,a.jsx)(D.Item,{name:["command","cwd"],label:e("chatConfig.createAssistant.field.workingDirectory"),style:{marginBottom:16},children:(0,a.jsx)(j,{placeholder:"e.g. /Users/me/project"})}),(0,a.jsx)(Q,{type:"link",onClick:()=>{se(!1),i.setFieldsValue({commandExecutable:"",commandArgs:"",command:{cwd:void 0}})},style:{padding:0,marginBottom:16,display:"block"},children:e("chatConfig.createAssistant.hideCustomCommand")})]}):(0,a.jsx)(Q,{type:"link",onClick:()=>se(!0),style:{padding:0,marginBottom:16,display:"block"},children:e("chatConfig.createAssistant.customCommand")})})]}),(0,a.jsx)(D.Item,{label:e("chatConfig.createAssistant.field.agentCardUrl"),required:!0,style:{marginBottom:16},children:(0,a.jsxs)(Xe.Compact,{style:{width:"100%"},children:[(0,a.jsx)(D.Item,{name:"agentCardProtocol",noStyle:!0,children:(0,a.jsx)(Ie,{style:{width:100},options:un})}),(0,a.jsx)(D.Item,{name:"agentCardUrl",noStyle:!0,rules:[{required:!0,message:e("chatConfig.createAssistant.validation.urlRequired")}],children:(0,a.jsx)(j,{placeholder:F==="local"?"localhost:4301":"host:port or full URL"})}),(0,a.jsx)(Q,{icon:(0,a.jsx)(at,{}),onClick:m,loading:Le,children:e("chatConfig.connection.action.test")})]})}),F==="remote"&&(0,a.jsx)(D.Item,{name:"apiKey",label:e("chatConfig.createAssistant.field.apiKeyOptional"),style:{marginBottom:16},children:(0,a.jsx)(j.Password,{placeholder:e("chatConfig.createAssistant.apiKeyPlaceholder")})}),(0,a.jsx)(D.Item,{name:"timeout",label:e("chatConfig.createAssistant.field.timeout"),style:{marginBottom:16},initialValue:3e5,children:(0,a.jsx)(Qe,{min:1e3,max:36e5,style:{width:"100%"},placeholder:"300000"})})]}),!$&&(0,a.jsx)(D.Item,{name:"prompt",label:e(l==="extend"&&p?"chatConfig.createAssistant.field.systemPromptInherit":"chatConfig.createAssistant.field.systemPrompt"),rules:l==="scratch"?[{required:!0,message:e("chatConfig.createAssistant.validation.systemPromptRequired")}]:[],children:(0,a.jsx)(Jt,{placeholder:e(l==="extend"&&p?"chatConfig.createAssistant.systemPromptInheritPlaceholder":"chatConfig.createAssistant.systemPromptPlaceholder"),autoSize:{minRows:4,maxRows:8},style:{fontFamily:"monospace",fontSize:13,lineHeight:1.6}})})]}),sn&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(Ge,{style:{margin:"12px 0"}}),(0,a.jsx)(oe,{strong:!0,style:{display:"block",marginBottom:8},children:e("chatConfig.createAssistant.subAgents")}),(0,a.jsx)(Zt,{subAgentKeys:Ye,decisions:R,onChange:K})]})]})};var V=T(M()),{Paragraph:Cn,Text:nn}=te,An=[{key:"manual",icon:Fe,titleKey:"governance.creation.manual.title",descriptionKey:"governance.creation.manual.description"},{key:"external",icon:lt,titleKey:"governance.creation.external.title",descriptionKey:"governance.creation.external.description"},{key:"learn",icon:dt,titleKey:"governance.creation.learn.title",descriptionKey:"governance.creation.learn.description"}],an=({open:n,onCancel:s,onSelectMethod:g,focusTriggerAfterClose:r=!0})=>{let d=_();return(0,V.jsx)(he,{title:d("governance.creation.title"),open:n,onCancel:s,footer:null,width:560,centered:!0,destroyOnHidden:!0,focusTriggerAfterClose:r,children:(0,V.jsxs)("div",{style:{padding:"8px 4px 4px"},children:[(0,V.jsx)(Cn,{style:{color:"#595959",fontSize:15,margin:"8px 0 24px"},children:d("governance.creation.subtitle")}),(0,V.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:12},children:An.map(i=>{let e=i.icon,h=d(i.titleKey);return(0,V.jsxs)(Q,{type:"default",onClick:()=>g(i.key),"aria-label":h,style:{display:"flex",flexDirection:"row",alignItems:"center",gap:16,width:"100%",minHeight:88,height:"auto",padding:16,borderRadius:16,textAlign:"left",whiteSpace:"normal"},children:[(0,V.jsx)("div",{style:{width:40,height:40,borderRadius:12,display:"flex",alignItems:"center",justifyContent:"center",flexShrink:0,color:"#6366f1",background:"#eeeeff"},children:(0,V.jsx)(e,{size:19})}),(0,V.jsxs)("div",{style:{minWidth:0},children:[(0,V.jsx)(nn,{strong:!0,style:{display:"block",fontSize:15,marginBottom:3},children:h}),(0,V.jsx)(nn,{style:{color:"#737373",lineHeight:1.5},children:d(i.descriptionKey)})]})]},i.key)})}),(0,V.jsx)("div",{style:{display:"flex",justifyContent:"flex-end",gap:8,flexWrap:"wrap",marginTop:24},children:(0,V.jsx)(Q,{onClick:s,children:d("governance.creation.notNow")})})]})})};var U=T(M()),bn=n=>{let s=n;if(typeof n=="string")try{s=JSON.parse(n)}catch{return{}}return s!==null&&typeof s=="object"&&!Array.isArray(s)?s:{}},La=()=>{let{get:n,del:s,put:g}=Ce(),r=_(),[d,i]=(0,u.useState)([]),[e,h]=(0,u.useState)({}),[f,l]=(0,u.useState)(null),[k,O]=(0,u.useState)(!1),[G,p]=(0,u.useState)(null),[C,R]=(0,u.useState)("graph"),[K,W]=(0,u.useState)(null),[$,F]=(0,u.useState)(null),[o,P]=(0,u.useState)(null),[ie,ge]=(0,u.useState)(!1),[be,pe]=(0,u.useState)(!0),[me,Y]=(0,u.useState)(!1),[Le,ve]=(0,u.useState)("learn"),[Oe,se]=(0,u.useState)({}),[J,Z]=(0,u.useState)(null),[_e,Me]=(0,u.useState)(!1),z=(0,u.useCallback)(async()=>{O(!0);try{let[m,A]=await Promise.all([n("/api/assistants"),n("/api/assistants/stats").catch(()=>null)]);if(m.success&&m.data?.records&&i(m.data.records),A?.success&&A.data?.records){let S={};for(let q of A.data.records)S[q.id]=q;h(S),l(A.cache?.expiresAt??null)}}catch{w.error(r("governance.workbench.loadFailed"))}finally{O(!1)}},[n,r]);(0,u.useEffect)(()=>{z()},[z]);let ue=u.default.useMemo(()=>Pt(d),[d]),ee=d.find(m=>m.id===G)??null,Ve=(0,u.useCallback)((m,A="graph")=>{p(m),R(A),W(null),P(null)},[]),fe=xt(),xe=(0,u.useCallback)((m,A)=>{let S=d.find(q=>q.id===m)?.name??r("governance.workbench.agentFallback");fe({component_key:"agent_detail_side_app",data:{assistantId:m,initialTab:A},message:S})},[d,fe,r]),B=(0,u.useCallback)(()=>{pe(!0),ge(!0)},[]),ke=(0,u.useCallback)(m=>{let S={manual:{mode:"scratch",values:{}},external:{mode:"scratch",values:{type:"a2a_remote"}},learn:{mode:"learn",values:{}}}[m];ve(S.mode),se(S.values),pe(!1),ge(!1),Y(!0)},[]),Te=(0,u.useCallback)(async(m,A)=>{let S=bn(m.graphDefinition),q;try{q=await g(`/api/assistants/${m.id}`,{name:A.name!==void 0?A.name:m.name,description:A.description!==void 0?A.description:m.description,graphDefinition:{...S,...A}})}catch(Se){throw w.error(r("governance.detail.saveFailed")),Se}if(!q.success)throw w.error(r("governance.detail.saveFailed")),new Error("Failed to save agent");w.success(r("common.saved")),z()},[g,z,r]),Ee=(0,u.useCallback)(m=>{i(A=>A.map(S=>S.id===m.id?m:S))},[]),re=(0,u.useCallback)(m=>{Z(m)},[]),le=(0,u.useCallback)(async()=>{if(J){Me(!0);try{(await s(`/api/assistants/${J}`)).success?(w.success(r("governance.detail.deleted")),i(A=>A.filter(S=>S.id!==J)),z(),Z(null)):w.error(r("governance.detail.deleteFailed"))}catch{w.error(r("governance.detail.deleteFailed"))}finally{Me(!1)}}},[J,s,z,r]),we=(0,u.useCallback)(async m=>{if(!(await s(`/api/assistants/${m}`)).success)throw new Error("Failed to delete agent");w.success(r("governance.detail.deleted")),i(S=>S.filter(q=>q.id!==m)),z()},[s,z,r]);return(0,U.jsxs)("div",{style:{height:"100%",background:"#fafafa",overflow:"hidden"},children:[ee?(0,U.jsx)(Dt,{defaultProjectId:o??void 0,children:(0,U.jsx)(_t,{assistant:ee,allAssistants:d,onBack:()=>p(null),onDeleted:we,onSave:Te,onAssistantUpdated:Ee,onAgentListInvalidated:z,initialTab:C,initialMessage:K,initialMessageCustomRunConfig:$,initialProjectId:o})},ee.id):(0,U.jsx)(U.Fragment,{children:(0,U.jsx)(qt,{items:ue,assistants:d,stats:e,statsExpiresAt:f,loading:k,onItemClick:m=>xe(m,"graph"),onOpenPlayground:m=>xe(m,"playground"),onOpenEval:m=>xe(m,"eval"),onCreate:B,onDelete:re})}),(0,U.jsx)(an,{open:ie,onCancel:()=>{pe(!0),ge(!1)},onSelectMethod:ke,focusTriggerAfterClose:be}),(0,U.jsx)(tn,{open:me,initialMode:Le,initialValues:Oe,onCancel:()=>Y(!1),onSuccess:(m,A)=>{Y(!1),i(S=>S.some(Se=>Se.id===m.id)?S:[m,...S]),Ve(m.id,"graph"),W(A?.initialMessage??null),F(A?.initialMessageCustomRunConfig??null),P(A?.projectId??null),z()}}),(0,U.jsx)(he,{title:r("governance.deleteAgent"),open:J!==null,onCancel:()=>Z(null),onOk:le,okText:r("common.delete"),okButtonProps:{danger:!0,loading:_e},cancelText:r("common.cancel"),children:(0,U.jsx)("p",{children:r("governance.delete.irreversible")})})]})};export{La as AgentGovernanceWorkbench};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/routes/open.ts","../src/services/open/openMcpServer.ts"],"sourcesContent":["/**\n * Open API surface routes: POST/DELETE /open/mcp.\n *\n * The route is a thin shell — credential resolution (OpenAuthService),\n * catalog filtering and invocation (OpenLattice), and session lifecycle\n * (mcpTransportRegistry) live in services/open/*. The transport writes the\n * response itself, so the reply is hijacked (same precedent as the Project\n * Room SSE route).\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from \"fastify\";\nimport { isInitializeRequest } from \"@modelcontextprotocol/sdk/types.js\";\nimport { getStoreLattice } from \"@axiom-lattice/core\";\nimport type { A2AApiKeyStore, OpenAuditStore, OpenGrant, ProjectStore } from \"@axiom-lattice/protocols\";\nimport { OpenCredentialService } from \"../services/open/openCredentialService\";\nimport { OpenAuditService } from \"../services/open/openAuditService\";\nimport { OpenRateLimiter } from \"../services/open/openRateLimiter\";\nimport type { OpenCredential } from \"../services/open/openCredentialService\";\nimport {\n openLattice,\n ActionNotFoundError,\n GrantDeniedError,\n ValidationError,\n} from \"../services/open/openLattice\";\nimport { buildSessionServer } from \"../services/open/openMcpServer\";\nimport { collectExposedPluginUiResources } from \"../services/open/registerExposedPlugins\";\nimport {\n buildTenantOpenPlugins,\n mergeOpenCatalog,\n type TenantOpenPlugins,\n} from \"../services/open/tenantOpenPlugins\";\nimport { getSession, deleteSession } from \"../services/open/mcpTransportRegistry\";\n\nexport interface OpenRouteDeps {\n openAuth?: OpenCredentialService;\n grantsSource?: (ctx: OpenCredential) => OpenGrant[];\n audit?: OpenAuditService;\n rateLimiter?: OpenRateLimiter;\n /**\n * Test seam: build the credential's tenant sandbox plugin bundle. Defaults to\n * {@link buildTenantOpenPlugins} with the global catalog's tool names reserved\n * so a tenant tool can never shadow a global/built-in one.\n */\n tenantPlugins?: (\n tenantId: string,\n grants: OpenGrant[],\n reservedToolNames: ReadonlySet<string>,\n ) => Promise<TenantOpenPlugins>;\n}\n\nfunction extractBearer(request: FastifyRequest): string | undefined {\n const header = request.headers.authorization;\n if (!header?.startsWith(\"Bearer \")) return undefined;\n return header.slice(\"Bearer \".length).trim() || undefined;\n}\n\nfunction readSessionId(request: FastifyRequest): string | undefined {\n const raw = request.headers[\"mcp-session-id\"];\n const value = Array.isArray(raw) ? raw[0] : raw;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/**\n * Degraded tenant plugin bundle used when the sandbox catalog cannot be read.\n *\n * A catalog read failure must not 500 the session: the MCP server still builds\n * and serves the global tools. `invoke` is unreachable through normal routing\n * (`hasTool` is always false, so calls route to OpenLattice) but returns an\n * error result if it is ever reached.\n */\nfunction emptyTenantPlugins(): TenantOpenPlugins {\n return {\n tools: [],\n uiResources: new Map(),\n hasTool: () => false,\n degraded: true,\n invoke: async (toolName) => ({\n content: [\n { type: \"text\", text: `Tenant plugin catalog unavailable for ${toolName}` },\n ],\n isError: true,\n }),\n };\n}\n\n/** JSON-RPC error codes used on the Open surface. */\nconst RPC_ERROR = {\n GRANT_DENIED: -32001,\n ACTION_NOT_FOUND: -32002,\n VALIDATION_FAILED: -32003,\n EXECUTION_ERROR: -32004,\n RATE_LIMITED: -32005,\n} as const;\n\nexport function registerOpenRoutes(\n app: FastifyInstance,\n deps: OpenRouteDeps = {},\n): void {\n const openAuth =\n deps.openAuth ??\n new OpenCredentialService(\n getStoreLattice(\"default\", \"a2aApiKey\").store as A2AApiKeyStore,\n getStoreLattice(\"default\", \"project\").store as ProjectStore,\n );\n const grantsSource =\n deps.grantsSource ?? ((ctx: OpenCredential) => ctx.grants);\n const audit =\n deps.audit ??\n (() => {\n try {\n const store = getStoreLattice(\"default\", \"openAudit\").store as OpenAuditStore;\n return new OpenAuditService(store);\n } catch {\n return undefined;\n }\n })();\n\n const rateLimiter = deps.rateLimiter ?? new OpenRateLimiter();\n\n app.post(\"/open/mcp\", async (request: FastifyRequest, reply: FastifyReply) => {\n const context = await openAuth.resolve(extractBearer(request));\n if (!context) {\n return reply.status(401).send({ error: \"AUTH_FAILED\" });\n }\n\n const body: unknown = request.body;\n const sessionId = readSessionId(request);\n\n // Existing session: reuse its server/transport. Bearer must match the\n // session's credential — a session is not usable by another key.\n if (sessionId) {\n const session = await getSession(sessionId);\n if (\n !session ||\n session.credential.credentialId !== context.credentialId\n ) {\n return reply.status(404).send({ error: \"SESSION_NOT_FOUND\" });\n }\n reply.hijack();\n await session.transport.handleRequest(request.raw, reply.raw, body);\n return;\n }\n\n // New session: only initialize may create one. Registration into the\n // session registry happens inside sessionIdGenerator (see openMcpServer).\n if (!isInitializeRequest(body)) {\n return reply.status(400).send({ error: \"SESSION_REQUIRED\" });\n }\n\n const grants = grantsSource(context);\n const catalog = await openLattice.catalogFor(grants, { tenantId: context.tenantId });\n // Tenant sandbox plugins are volume-resident and outside the OpenLattice\n // registry; merge their grant-filtered tools/UI alongside the globals.\n // Global/built-in tool names are reserved so a tenant plugin of the same\n // type (kb/sandbox/agent) can neither crash `registerTool` with a duplicate\n // nor capture the invoke routing for a global tool.\n const globalToolNames = new Set(catalog.map((t) => t.toolName));\n const buildTenant =\n deps.tenantPlugins ??\n ((tenantId, tenantGrants, reservedToolNames) =>\n buildTenantOpenPlugins(tenantId, tenantGrants, { reservedToolNames }));\n let tenant: TenantOpenPlugins;\n try {\n tenant = await buildTenant(context.tenantId, grants, globalToolNames);\n if (tenant.degraded) {\n // The catalog's common failure mode is a diagnostic, not a throw\n // (`ensureLoaded` returns error-level diagnostics). Surface it and\n // serve global tools only.\n request.log.warn(\n { tenantId: context.tenantId },\n \"open mcp: tenant plugin catalog degraded; serving global tools only\",\n );\n }\n } catch (error) {\n // Sandbox catalogs are volume-resident and can be transiently\n // unavailable; degrade to globals-only rather than failing the whole\n // session so external hosts can still connect. `err` keeps the stack.\n request.log.warn(\n { tenantId: context.tenantId, err: error },\n \"open mcp: tenant plugin catalog unavailable; serving global tools only\",\n );\n tenant = emptyTenantPlugins();\n }\n const mergedCatalog = mergeOpenCatalog(catalog, tenant.tools);\n const uiResources = new Map([\n ...collectExposedPluginUiResources(grants),\n ...tenant.uiResources,\n ]);\n const built = await buildSessionServer({\n credential: { credentialId: context.credentialId, kind: context.kind },\n grants,\n catalog: mergedCatalog,\n uiResources,\n invoke: async (toolName, args) => {\n const startedAt = Date.now();\n const sep = toolName.indexOf(\"_\");\n const auditDomain = sep > 0 ? toolName.slice(0, sep) : toolName;\n const auditAction = sep > 0 ? toolName.slice(sep + 1) : \"\";\n\n const decision = rateLimiter.check(context.credentialId, auditDomain);\n if (!decision.allowed) {\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: auditDomain,\n action: auditAction,\n args,\n status: \"error\",\n errorCode: \"RATE_LIMITED\",\n durationMs: Date.now() - startedAt,\n });\n throw Object.assign(\n new Error(\n `RATE_LIMITED: retry after ${decision.retryAfterMs ?? 1000}ms`,\n ),\n { rpcCode: RPC_ERROR.RATE_LIMITED },\n );\n }\n\n try {\n const isTenantRoute = tenant.hasTool(toolName) && !globalToolNames.has(toolName);\n const runConfig: Record<string, unknown> = {\n sandboxName: context.sandboxName,\n credentialId: context.credentialId,\n depth: context.depth,\n };\n const result = isTenantRoute\n ? await tenant.invoke(toolName, args, {\n tenantId: context.tenantId,\n projectId: context.projectId,\n workspaceId: context.workspaceId,\n runConfig,\n })\n : await openLattice.invoke(\n grants,\n {\n tenantId: context.tenantId,\n projectId: context.projectId,\n workspaceId: context.workspaceId,\n runConfig,\n },\n toolName,\n args,\n );\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: auditDomain,\n action: auditAction,\n args,\n status: result.isError ? \"error\" : \"ok\",\n ...(result.isError ? { errorCode: \"EXECUTION_ERROR\" } : {}),\n durationMs: Date.now() - startedAt,\n });\n return result;\n } catch (err) {\n const code =\n err instanceof GrantDeniedError\n ? RPC_ERROR.GRANT_DENIED\n : err instanceof ActionNotFoundError\n ? RPC_ERROR.ACTION_NOT_FOUND\n : err instanceof ValidationError\n ? RPC_ERROR.VALIDATION_FAILED\n : RPC_ERROR.EXECUTION_ERROR;\n await audit?.record({\n tenantId: context.tenantId,\n credentialId: context.credentialId,\n credentialKind: context.kind,\n projectId: context.projectId,\n domain: auditDomain,\n action: auditAction,\n args,\n status: \"error\",\n errorCode:\n err instanceof GrantDeniedError\n ? \"GRANT_DENIED\"\n : err instanceof ActionNotFoundError\n ? \"ACTION_NOT_FOUND\"\n : err instanceof ValidationError\n ? \"VALIDATION_FAILED\"\n : \"EXECUTION_ERROR\",\n durationMs: Date.now() - startedAt,\n });\n throw Object.assign(\n new Error(err instanceof Error ? err.message : String(err)),\n { rpcCode: code },\n );\n }\n },\n });\n // buildSessionServer no longer connects internally (so it is testable\n // over InMemoryTransport); the transport still needs an onmessage handler\n // before handleRequest or initialize is swallowed and the request hangs.\n await built.server.connect(built.transport);\n reply.hijack();\n await built.transport.handleRequest(request.raw, reply.raw, body);\n });\n\n app.delete(\n \"/open/mcp\",\n async (request: FastifyRequest, reply: FastifyReply) => {\n const sessionId = readSessionId(request);\n if (!sessionId) {\n return reply.status(400).send({ error: \"SESSION_REQUIRED\" });\n }\n await deleteSession(sessionId);\n return reply.status(204).send();\n },\n );\n}\n","/**\n * Builds a per-session MCP server instance whose tool list is the\n * credential-filtered OpenLattice catalog. Per-session instances are what\n * make grant-filtered tools/list possible on the official SDK.\n *\n * Session registration happens inside sessionIdGenerator — the SDK invokes\n * it exactly once while handling initialize, which guarantees the registry\n * key equals the transport-generated id that the response header carries.\n *\n * Every tool executor routes through the OpenLattice invoke kernel, so\n * authorization is re-checked on each invocation (default-deny, live grants).\n */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { randomUUID } from \"crypto\";\nimport type { McpUiCsp, OpenGrant } from \"@axiom-lattice/protocols\";\nimport type { OpenToolDescriptor } from \"./openLattice\";\nimport { registerSession } from \"./mcpTransportRegistry\";\n\nexport const OPEN_MCP_SERVER_INFO = {\n name: \"axiom-open\",\n version: \"0.1.0\",\n} as const;\n\n/**\n * A `ui://` HTML resource served by the session. `read` is invoked per\n * `resources/read`, so the caller can fetch plugin UI lazily.\n */\nexport interface OpenUiResource {\n /** MIME for the resource; defaults to \"text/html;profile=mcp-app\". */\n mimeType?: string;\n csp?: McpUiCsp;\n read: () => Promise<{ html: string; csp?: McpUiCsp }>;\n}\n\nexport interface BuiltSession {\n server: McpServer;\n transport: StreamableHTTPServerTransport;\n tools: OpenToolDescriptor[];\n}\n\n/**\n * Builds (but does not connect) a per-session MCP server. The caller MUST\n * connect it to a transport (`await built.server.connect(built.transport)`)\n * before handling requests — otherwise the transport has no onmessage\n * handler and initialize is swallowed. Deferring connect is what lets tests\n * attach the server to an `InMemoryTransport`.\n */\nexport async function buildSessionServer(options: {\n credential: { credentialId: string; kind: string };\n grants: OpenGrant[];\n catalog: OpenToolDescriptor[];\n invoke: (\n toolName: string,\n args: unknown,\n ) => Promise<{\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n }>;\n uiResources?: Map<string, OpenUiResource>;\n}): Promise<BuiltSession> {\n const { credential, catalog, invoke, uiResources } = options;\n const server = new McpServer(OPEN_MCP_SERVER_INFO, {\n capabilities: {\n // The SDK has no `extensions` field; MCP App hosts discover the UI\n // extension through `experimental`.\n experimental: { \"io.modelcontextprotocol/ui\": {} },\n },\n });\n for (const tool of catalog) {\n server.registerTool(\n tool.toolName,\n {\n description: tool.description,\n inputSchema: tool.schema,\n annotations: {\n readOnlyHint: tool.annotations.readOnlyHint,\n destructiveHint: tool.annotations.destructiveHint,\n },\n ...(tool.ui ? { _meta: { ui: { resourceUri: tool.ui.resourceUri } } } : {}),\n },\n async (args: unknown) => {\n const result = await invoke(tool.toolName, args);\n return { content: result.content, isError: result.isError };\n },\n );\n }\n for (const [uri, res] of uiResources ?? []) {\n const mimeType = res.mimeType ?? \"text/html;profile=mcp-app\";\n server.registerResource(\n `mcp-app:${uri}`,\n uri,\n {\n mimeType,\n ...(res.csp ? { _meta: { ui: { csp: res.csp } } } : {}),\n },\n async (u) => {\n const { html, csp } = await res.read();\n return {\n contents: [\n {\n uri: u.href,\n mimeType,\n text: html,\n ...(csp ? { _meta: { ui: { csp } } } : {}),\n },\n ],\n };\n },\n );\n }\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => {\n const sessionId = randomUUID();\n void registerSession(\n sessionId,\n { credentialId: credential.credentialId, kind: credential.kind },\n { server, transport },\n );\n return sessionId;\n },\n enableJsonResponse: true,\n onsessionclosed: (closedId: string) => {\n void import(\"./mcpTransportRegistry\").then(({ deleteSession }) =>\n deleteSession(closedId),\n );\n },\n });\n return { server, transport, tools: catalog };\n}\n"],"mappings":"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","names":["deleteSession"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/controllers/resources.ts","../src/services/open/sandboxGrants.ts"],"sourcesContent":["import { FastifyRequest, FastifyReply } from \"fastify\";\nimport type { ResourceAddress, ShareRecord, SharedResourceStore } from \"@axiom-lattice/protocols\";\nimport bcrypt from \"bcryptjs\";\nimport {\n generateToken,\n createSharePayload,\n TokenCache,\n SandboxLatticeManager,\n buildNamedVolumeName,\n} from \"@axiom-lattice/core\";\nimport { getContentTypeFromFilename } from \"../utils/mime\";\nimport { sendBufferWithRange } from \"../utils/http-range\";\nimport { sanitizeShareOpenGrants } from \"../services/open/sandboxGrants\";\n\ninterface ResourceControllerDeps {\n store: SharedResourceStore;\n sandboxManager: SandboxLatticeManager;\n cache: TokenCache;\n logger: { info: (msg: string, obj?: object) => void; warn: (msg: string, obj?: object) => void; error: (msg: string, obj?: object) => void };\n}\n\nexport class ResourceController {\n constructor(private deps: ResourceControllerDeps) {}\n\n async createShare(request: FastifyRequest, reply: FastifyReply) {\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const tenantId = (request.headers[\"x-tenant-id\"] as string) || \"default\";\n const workspaceId = request.headers[\"x-workspace-id\"] as string;\n const projectId = request.headers[\"x-project-id\"] as string;\n const body = request.body as any;\n\n if (!workspaceId || !projectId) {\n return reply.status(400).send({ error: \"x-workspace-id and x-project-id headers required\" });\n }\n\n const payload = createSharePayload(\n tenantId,\n workspaceId,\n projectId,\n userId as string,\n body,\n );\n const token = generateToken();\n\n try {\n await this.deps.store.create({ ...payload, token });\n this.deps.logger.info(\n \"[share] created\",\n { token, originalPath: body.resourcePath, normalizedPath: payload.address.resourcePath, volume: payload.address.volume, userId },\n );\n } catch {\n return reply.status(500).send({ error: \"Failed to create share\" });\n }\n\n return reply.status(201).send({ token, url: `/s/${token}` });\n }\n\n async listShares(request: FastifyRequest, reply: FastifyReply) {\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const tenantId = (request.headers[\"x-tenant-id\"] as string) || \"default\";\n const shares = await this.deps.store.listByUser(tenantId, userId as string);\n return reply.send(shares.filter((r: any) => (r as any).visibility !== \"internal\"));\n }\n\n async updateShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n const patch = request.body as any;\n\n const record = await this.deps.store.findByToken(token);\n if (!record || record.createdBy !== userId) {\n return reply.status(404).send({ error: \"Share not found\" });\n }\n\n await this.deps.store.update(token, patch);\n\n if (patch.revoked) {\n this.deps.cache.invalidate(token);\n }\n\n return reply.send({ ok: true });\n }\n\n async revokeShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const userId = (request as any).user\n ? (request as any).user.id ?? \"unknown\"\n : \"unknown\";\n\n const record = await this.deps.store.findByToken(token);\n if (!record || record.createdBy !== userId) {\n return reply.status(404).send({ error: \"Share not found\" });\n }\n\n await this.deps.store.update(token, { revoked: true });\n this.deps.cache.invalidate(token);\n\n return reply.send({ ok: true });\n }\n\n async resolveResource(request: FastifyRequest, reply: FastifyReply) {\n const params = request.params as unknown as { token: string; \"*\"?: string };\n const { token } = params;\n const subPath = params[\"*\"] ?? \"\";\n\n this.deps.logger.info(\"[share] resolve start\", { token, subPath });\n\n const isApi = subPath && /(^|\\/)api\\//.test(subPath) && (subPath.endsWith(\".js\") || subPath.endsWith(\".py\"));\n\n // Only API paths accept non-GET methods\n if (request.method !== \"GET\" && !isApi) {\n return reply.status(405).send({ error: \"Method not allowed\" });\n }\n\n // API runtime — proxy to sandbox. Detected by /api/ anywhere in subPath.\n if (isApi) {\n const record = await this.deps.store.findByToken(token);\n if (!record || record.revoked) return reply.status(404).send(\"Not found\");\n if (record.expiresAt && new Date(record.expiresAt) < new Date()) {\n return reply.status(410).send(\"Expired\");\n }\n // Auth check for API calls (same as file access)\n if (!this._isInternalRequest(request)) {\n if (record.visibility === \"internal\") {\n return reply.status(401).send({ error: \"Internal access only\" });\n }\n if (record.visibility === \"password\") {\n if (!this._isUnlocked(request, token)) {\n return reply.status(401).send({ error: \"Password required\" });\n }\n }\n }\n const ext = subPath.endsWith(\".py\") ? \"py\" : \"js\";\n return this._execApi(record, subPath, ext, request, reply);\n }\n\n // 1. Check cache\n const cached = this.deps.cache.get(token);\n if (cached && !cached.requiresUnlock) {\n this.deps.logger.info(\"[share] cache hit\", { token, volume: cached.address.volume, resourcePath: cached.address.resourcePath });\n return this._serveFile(cached.address, token, subPath, cached.sandboxConfig ?? { tenantId: \"default\", workspaceId: \"\", projectId: \"\", assistantId: null }, reply, request.headers.range);\n }\n this.deps.logger.info(\"[share] cache miss, querying DB\", { token });\n\n // 2. Single DB lookup\n const record = await this.deps.store.findByToken(token);\n if (!record || record.revoked) {\n this.deps.logger.warn(\"[share] token not found or revoked\", { token, found: !!record, revoked: record?.revoked });\n return reply.status(404).send(\"Not found\");\n }\n if (record.expiresAt && new Date(record.expiresAt) < new Date()) {\n this.deps.logger.info(\"[share] token expired\", { token, expiresAt: record.expiresAt });\n return reply.status(410).send(\"Expired\");\n }\n\n this.deps.logger.info(\"[share] record found\", {\n token,\n volume: record.address.volume,\n resourcePath: record.address.resourcePath,\n visibility: record.visibility,\n workspaceId: record.workspaceId,\n projectId: record.projectId,\n });\n\n // 3. Auth\n const isInternal = this._isInternalRequest(request);\n if (!isInternal) {\n // Internal shares: must be logged in\n if (record.visibility === \"internal\") {\n return reply.status(401).send({ error: \"Internal access only\" });\n }\n if (record.visibility === \"password\") {\n const unlocked = this._isUnlocked(request, token);\n if (!unlocked) {\n this.deps.logger.info(\"[share] password protected, returning password page\", { token });\n this.deps.cache.set(token, {\n address: record.address,\n requiresUnlock: true,\n sandboxConfig: { tenantId: record.tenantId, workspaceId: record.workspaceId, projectId: record.projectId, assistantId: record.assistantId },\n });\n return reply.type(\"text/html\").send(this._passwordPage(token));\n }\n this.deps.logger.info(\"[share] password unlocked\", { token });\n }\n }\n\n // 4. Access count\n if (record.maxAccess !== null) {\n const ok = await this.deps.store.atomicIncrementAccess(token);\n if (!ok) return reply.status(410).send(\"Access limit reached\");\n } else {\n this.deps.store.incrementAccess(token).catch(() => {});\n }\n\n // 5. Cache\n const sandboxConfig = { tenantId: record.tenantId, workspaceId: record.workspaceId, projectId: record.projectId, assistantId: record.assistantId };\n this.deps.cache.set(token, {\n address: record.address,\n requiresUnlock: record.visibility === \"password\" && !isInternal,\n sandboxConfig,\n });\n\n return this._serveFile(record.address, token, subPath, sandboxConfig, reply, request.headers.range);\n }\n\n /**\n * Thin redirect: /f/{uuidHex3}/{path} → /s/{internal-token}/{path}\n * Decodes 3 UUIDs (no dashes, 96 hex chars), ensures internal share, 302 redirects.\n */\n async resolveDirectFile(request: FastifyRequest, reply: FastifyReply) {\n const params = request.params as unknown as { tid: string; wid: string; pid: string; \"*\"?: string };\n const tenantId = params.tid;\n const workspaceId = params.wid;\n const projectId = params.pid;\n const subPath = (params[\"*\"] ?? \"\");\n\n const isApi = subPath && /(^|\\/)api\\//.test(subPath) && (subPath.endsWith(\".js\") || subPath.endsWith(\".py\"));\n\n // Only API paths accept non-GET methods\n if (request.method !== \"GET\" && !isApi) {\n return reply.status(405).send({ error: \"Method not allowed\" });\n }\n\n // API runtime\n if (isApi) {\n const ext = subPath.endsWith(\".py\") ? \"py\" : \"js\";\n return this._execApiCore({\n tenantId, workspaceId, projectId, assistantId: \"\",\n resourcePath: subPath,\n }, subPath, ext, request, reply);\n }\n\n const volume = buildNamedVolumeName(\"p\", \"project\", tenantId, workspaceId, projectId);\n return this._resolveAndServe(volume, subPath, reply, `/f/${tenantId}/${workspaceId}/${projectId}`,\n { tenantId, workspaceId, projectId, assistantId: null },\n request.headers.range,\n );\n }\n\n async unlockShare(request: FastifyRequest, reply: FastifyReply) {\n const { token } = request.params as unknown as { token: string };\n const { password } = request.body as unknown as { password: string };\n\n const record = await this.deps.store.findByToken(token);\n if (!record || !record.passwordHash) {\n return reply.status(404).send({ error: \"Invalid request\" });\n }\n\n const valid = await bcrypt.compare(password, record.passwordHash!);\n if (!valid) {\n return reply.status(401).send({ error: \"Incorrect password\" });\n }\n\n const cookieOpts = [\n `share_unlock_${token}=1`,\n \"Max-Age=86400\",\n `Path=/s/${token}`,\n \"SameSite=Lax\",\n \"HttpOnly\",\n ];\n if (request.protocol === \"https\") {\n cookieOpts.push(\"Secure\");\n }\n reply.header(\"Set-Cookie\", cookieOpts.join(\"; \"));\n return reply.send({ ok: true });\n }\n\n private _isInternalRequest(request: FastifyRequest): boolean {\n const user = (request as any).user;\n if (user && user.id) return true;\n // Fallback: same-origin browser request (iframe/img embed — no Auth header)\n const origin = request.headers.origin || request.headers.referer;\n if (origin) {\n try {\n const { hostname } = new URL(origin);\n if (hostname === request.hostname) return true;\n } catch { /* malformed */ }\n }\n return false;\n }\n\n private _isUnlocked(request: FastifyRequest, token: string): boolean {\n const cookie = request.headers.cookie ?? \"\";\n return cookie.includes(`share_unlock_${token}=1`);\n }\n\n /** Returns true if the path has a file extension indicating it's a file, not a directory */\n private _isFilePath(path: string): boolean {\n return /\\.[a-zA-Z0-9]+$/.test(path);\n }\n\n /**\n * Injects a `<base href>` tag into an HTML document when it does not already\n * declare one. Injects right after `<head>` when present, otherwise prefixes\n * the document.\n */\n private _injectBaseTag(html: string, baseHref: string): string {\n if (/<base\\b/i.test(html)) return html;\n const baseTag = `<base href=\"${baseHref}\">`;\n return html.includes(\"<head>\") ? html.replace(\"<head>\", `<head>${baseTag}`) : baseTag + html;\n }\n\n /**\n * Shared file resolution: directory → index.html, volume FS → sandbox, base tag, response.\n */\n private async _resolveAndServe(\n volume: string,\n resourcePath: string,\n reply: FastifyReply,\n baseTagPrefix: string,\n sandboxConfig?: { tenantId: string; workspaceId: string; projectId: string; assistantId: string | null },\n rangeHeader?: string,\n ) {\n const cleanPath = resourcePath.replace(/\\/+$/, \"\");\n const entryPath = !cleanPath\n ? \"index.html\"\n : this._isFilePath(cleanPath)\n ? cleanPath\n : `${cleanPath}/index.html`;\n\n const address: ResourceAddress = { volume, resourcePath: \"\" };\n\n let buf: Buffer;\n try {\n // Volume FS first\n const provider = this.deps.sandboxManager.getDefaultProvider();\n buf = await provider.getResourceResolver().resolve({ ...address, resourcePath: entryPath });\n } catch {\n // Sandbox fallback\n if (!sandboxConfig) return reply.status(404).send(\"File not found\");\n try {\n const sandbox = await this.deps.sandboxManager.getSandboxFromConfig({\n assistant_id: sandboxConfig.assistantId ?? \"\",\n thread_id: \"\",\n tenantId: sandboxConfig.tenantId,\n workspaceId: sandboxConfig.workspaceId,\n projectId: sandboxConfig.projectId,\n });\n buf = await sandbox.file.downloadFile({ file: `/project/${entryPath}` });\n } catch {\n return reply.status(404).send(\"File not found\");\n }\n }\n\n const filename = entryPath.split(\"/\").pop() || \"download\";\n const contentType = getContentTypeFromFilename(filename);\n\n // Inject base tag for HTML\n if (/\\.(html|htm)$/i.test(filename)) {\n const baseDir = cleanPath\n ? (this._isFilePath(cleanPath) ? cleanPath.replace(/[^/]+$/, \"\") : cleanPath)\n : \"\";\n const baseHref = `${baseTagPrefix}${baseDir ? \"/\" + baseDir : \"\"}/`;\n buf = Buffer.from(\n this._injectBaseTag(buf.toString(\"utf-8\"), baseHref),\n \"utf-8\"\n );\n }\n\n return sendBufferWithRange(reply, buf, contentType, rangeHeader, {\n \"Content-Disposition\": `inline; filename*=UTF-8''${encodeURIComponent(filename)}`,\n \"Access-Control-Allow-Origin\": \"*\",\n });\n }\n\n private async _serveFile(\n address: ResourceAddress,\n token: string,\n subPath: string,\n sandboxConfig: { tenantId: string; workspaceId: string; projectId: string; assistantId: string | null },\n reply: FastifyReply,\n rangeHeader: string | undefined,\n ) {\n const resourcePath = subPath\n ? this._resolveSafeSubPath(address.resourcePath, subPath)\n : address.resourcePath;\n return this._resolveAndServe(\n address.volume,\n resourcePath,\n reply,\n `/s/${token}`,\n sandboxConfig,\n rangeHeader,\n );\n }\n\n private async _execApi(\n record: ShareRecord,\n apiSubPath: string,\n ext: \"js\" | \"py\",\n request: FastifyRequest,\n reply: FastifyReply,\n ) {\n const basePath = this._isFilePath(record.address.resourcePath)\n ? \"\"\n : `${record.address.resourcePath}/`;\n return this._execApiCore({\n tenantId: record.tenantId,\n workspaceId: record.workspaceId,\n projectId: record.projectId,\n assistantId: record.assistantId,\n resourcePath: basePath + apiSubPath,\n openGrants: record.openGrants,\n }, apiSubPath, ext, request, reply);\n }\n\n private async _execApiCore(\n config: {\n tenantId: string;\n workspaceId: string;\n projectId: string;\n assistantId?: string | null;\n resourcePath: string;\n openGrants?: import(\"@axiom-lattice/protocols\").OpenGrant[];\n },\n apiSubPath: string,\n ext: \"js\" | \"py\",\n request: FastifyRequest,\n reply: FastifyReply,\n ) {\n let sandbox: any;\n try {\n sandbox = await this.deps.sandboxManager.getSandboxFromConfig({\n assistant_id: config.assistantId ?? \"\",\n thread_id: \"\",\n tenantId: config.tenantId,\n workspaceId: config.workspaceId,\n projectId: config.projectId,\n });\n } catch (err) {\n this.deps.logger.error(\"[share] sandbox start failed for API\", { error: (err as Error).message });\n return reply.status(502).send({ error: \"Sandbox unavailable\" });\n }\n\n const scriptPath = `/project/${config.resourcePath}`;\n const cmd = ext === \"py\" ? `python3 ${scriptPath}` : `node ${scriptPath}`;\n\n // Pass query params and body via environment\n const queryStr = request.url.includes(\"?\") ? (request.url as string).split(\"?\")[1] : \"\";\n const queryObj: Record<string, string> = {};\n if (queryStr) {\n for (const [k, v] of new URLSearchParams(queryStr)) {\n queryObj[k] = v;\n }\n }\n\n const bodyStr = (request.body as string) ?? \"\";\n\n const envVars = [\n `export API_QUERY='${JSON.stringify(queryObj).replace(/'/g, \"'\\\\''\")}'`,\n `export API_BODY='${bodyStr.replace(/'/g, \"'\\\\''\")}'`,\n `export API_METHOD='${request.method}'`,\n `export API_GATEWAY_URL='${request.protocol}://${request.headers[\"x-forwarded-host\"] ?? request.headers.host ?? request.hostname}'`,\n `export API_TENANT_ID='${config.tenantId}'`,\n `export API_ASSISTANT_ID='${config.assistantId || \"\"}'`,\n `export OPEN_API_TOKEN='${this._mintSandboxToken(sandbox.name, config)}'`,\n ].join(\" && \");\n\n const fullCmd = `${envVars} && ${cmd}`;\n\n this.deps.logger.info(\"[api] exec\", { scriptPath, cmd: cmd.substring(0, 80) });\n\n try {\n const result = await sandbox.shell.execCommand({ command: fullCmd });\n // Parse stdout as JSON\n let data: unknown;\n try {\n data = JSON.parse(result.output?.trim() || \"{}\");\n } catch {\n data = { output: result.output?.trim() || \"\" };\n }\n return reply.status(200).type(\"application/json\").send(data);\n } catch (err) {\n this.deps.logger.warn(\"[api] exec failed\", { scriptPath, error: (err as Error).message });\n return reply.status(500).send({ error: (err as Error).message });\n }\n }\n\n private _resolveSafeSubPath(entryFile: string, subPath: string): string {\n if (!subPath) return entryFile;\n if (subPath.includes(\"..\")) throw new Error(\"Path traversal denied\");\n if (subPath.startsWith(entryFile + \"/\") || subPath === entryFile) return subPath;\n const entryDir = this._isFilePath(entryFile)\n ? entryFile.replace(/[^/]+$/, \"\")\n : entryFile + \"/\";\n return (entryDir + subPath).replace(/\\/+/g, \"/\");\n }\n\n private _passwordPage(token: string): string {\n return `<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Password Protected</title><style>body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:32px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.1);width:100%;max-width:360px;text-align:center}h2{margin:0 0 8px;font-size:20px}p{margin:0 0 20px;color:#666;font-size:14px}input{width:100%;padding:10px 12px;border:1px solid #d9d9d9;border-radius:8px;font-size:14px;box-sizing:border-box;margin-bottom:12px}button{width:100%;padding:10px;background:#6366f1;color:#fff;border:none;border-radius:8px;font-size:14px;cursor:pointer}.error{color:#ef4444;font-size:13px;margin-top:8px;display:none}</style></head><body><div class=\"card\"><h2>Password Protected</h2><p>This share requires a password to access.</p><form id=\"f\"><input type=\"password\" id=\"p\" placeholder=\"Enter password\" required><button type=\"submit\">Unlock</button><div class=\"error\" id=\"e\">Incorrect password</div></form></div><script>document.getElementById('f').onsubmit=async(e)=>{e.preventDefault();const r=await fetch('/s/${token}/unlock',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:document.getElementById('p').value})});if(r.ok)location.reload();else document.getElementById('e').style.display='block'}</script></body></html>`;\n }\n\n private _mintSandboxToken(\n sandboxName: string,\n config: {\n tenantId: string;\n workspaceId: string;\n projectId: string;\n openGrants?: import(\"@axiom-lattice/protocols\").OpenGrant[];\n },\n ): string {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { signOpenToken } = require(\"../services/open/openToken\") as {\n signOpenToken: (p: unknown) => string;\n };\n return signOpenToken({\n kind: \"sandbox_token\",\n tenantId: config.tenantId,\n workspaceId: config.workspaceId,\n projectId: config.projectId,\n sandboxName,\n grants: [\n {\n domain: \"sandbox\",\n items: [\"files_read\", \"files_list\", \"files_write\", \"shell_exec\"],\n },\n ...sanitizeShareOpenGrants(config.openGrants),\n ],\n });\n }\n}\n","/**\n * Sandbox-token grant sanitation.\n *\n * Sandbox tokens always carry the self-binding sandbox grant (resolved from\n * the credential's tenant/workspace/project). Shares may append extra\n * Open-door grants, but only within the V1 whitelist: read-only kb access.\n * Anything else is dropped server-side (the share creator cannot widen scope).\n */\n\nimport type { OpenGrant } from \"@axiom-lattice/protocols\";\n\n/** V1 allowlist: domain → permitted (read-only) actions. */\nconst ALLOWED: Record<string, string[]> = {\n kb: [\"search\", \"entries_read\"],\n};\n\nexport function sanitizeShareOpenGrants(grants: OpenGrant[] | undefined): OpenGrant[] {\n const out: OpenGrant[] = [];\n for (const grant of grants ?? []) {\n const allowed = ALLOWED[grant.domain];\n if (!allowed) continue;\n const items =\n grant.items && grant.items.length > 0\n ? grant.items.filter((item) => allowed.includes(item))\n : allowed;\n if (items.length > 0) out.push({ domain: grant.domain, items });\n }\n return out;\n}\n"],"mappings":"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","names":["record"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/services/open/sandboxOpenCredentialProvider.ts","../src/services/open/sandboxOpenReflection.ts"],"sourcesContent":["/**\n * Gateway composition-root implementation of the sandbox open-credential seam.\n *\n * Mints a short-lived, self-bound `sandbox_token` for sandbox code so it can call\n * the Open MCP endpoint. Core stays credential-agnostic; only the gateway knows\n * the signing secret and the public URL.\n */\n\nimport type { OpenGrant } from \"@axiom-lattice/protocols\";\nimport type { SandboxOpenCredentialProvider } from \"@axiom-lattice/core\";\nimport { registerSandboxOpenCredentialProvider } from \"@axiom-lattice/core\";\nimport { signOpenToken } from \"./openToken\";\nimport {\n createDefaultAgentReflectionDeps,\n createDefaultPluginReflectionDeps,\n mergeGrantsByDomain,\n resolveAgentOpenGrants,\n resolvePluginOpenGrants,\n} from \"./sandboxOpenReflection\";\n\n/** Conservative default grants for sandbox-initiated Open calls (B0). */\nexport const DEFAULT_SANDBOX_OPEN_GRANTS: OpenGrant[] = [\n { domain: \"sandbox\", items: [\"files_read\", \"files_list\", \"files_write\", \"shell_exec\"] },\n { domain: \"kb\", items: [\"search\", \"entries_read\"] },\n];\n\n/** Maximum nested sandbox Open orchestration depth before minting is refused. */\nexport const MAX_SANDBOX_OPEN_DEPTH = 5;\n\n/** Reflection seam: how the provider derives caller grants for a mint. */\nexport interface SandboxOpenReflection {\n /** Reflect an agent caller's own Open capabilities. */\n agent: (tenantId: string, assistantId: string) => Promise<OpenGrant[]>;\n /** Reflect the tenant's grantable Open catalog for a plugin handler caller. */\n plugin: (tenantId: string) => Promise<OpenGrant[]>;\n}\n\n/** Options for {@link createSandboxOpenCredentialProvider}. */\nexport interface SandboxOpenCredentialProviderFactoryOptions {\n /** Public base URL of this gateway (`PUBLIC_GATEWAY_URL`). Absent ⇒ inject nothing. */\n gatewayUrl?: string;\n /** Best-effort hook for structured warnings (e.g. depth cap reached). */\n onError?: (error: unknown) => void;\n /** Test seam replacing the live reflection resolvers. */\n reflection?: SandboxOpenReflection;\n}\n\n/** Default reflection wired to the live tenant registries. */\nfunction defaultReflection(): SandboxOpenReflection {\n return {\n agent: (tenantId, assistantId) =>\n resolveAgentOpenGrants(tenantId, assistantId, createDefaultAgentReflectionDeps(tenantId)),\n plugin: (tenantId) =>\n resolvePluginOpenGrants(tenantId, createDefaultPluginReflectionDeps()),\n };\n}\n\n/**\n * Build the provider.\n *\n * Grants are the union of the conservative B0 defaults with grants reflected\n * from the caller's identity (`assistantId` ⇒ agent reflection, otherwise the\n * tenant Open catalog). Each mint increments the orchestration `depth`; past\n * {@link MAX_SANDBOX_OPEN_DEPTH} the provider refuses to mint, breaking cycles.\n *\n * @param options - Gateway URL, error hook, and optional reflection seam.\n * @returns A {@link SandboxOpenCredentialProvider}\n */\nexport function createSandboxOpenCredentialProvider(\n options: SandboxOpenCredentialProviderFactoryOptions,\n): SandboxOpenCredentialProvider {\n const reflection = options.reflection ?? defaultReflection();\n return async (context) => {\n if (!options.gatewayUrl) return undefined;\n const depth = (context.depth ?? 0) + 1;\n if (depth > MAX_SANDBOX_OPEN_DEPTH) {\n options.onError?.(new Error(\"sandbox open credential depth exceeded\"));\n return undefined;\n }\n const reflected = context.assistantId\n ? await reflection.agent(context.tenantId, context.assistantId)\n : await reflection.plugin(context.tenantId);\n const grants = mergeGrantsByDomain([...DEFAULT_SANDBOX_OPEN_GRANTS, ...reflected]);\n const token = signOpenToken({\n kind: \"sandbox_token\",\n tenantId: context.tenantId,\n workspaceId: context.workspaceId ?? \"\",\n projectId: context.projectId ?? \"\",\n sandboxName: context.sandboxName,\n grants,\n depth,\n });\n return { gatewayUrl: options.gatewayUrl, token };\n };\n}\n\n/**\n * Register the gateway provider from `PUBLIC_GATEWAY_URL`.\n *\n * @param onError - Optional hook for structured warnings when resolution fails\n * @returns An unregister function (for tests/shutdown)\n */\nexport function registerGatewaySandboxOpenCredentialProvider(\n onError?: (error: unknown) => void,\n): () => void {\n return registerSandboxOpenCredentialProvider(\n createSandboxOpenCredentialProvider({\n gatewayUrl: process.env.PUBLIC_GATEWAY_URL?.trim() || undefined,\n onError,\n }),\n { onError },\n );\n}\n","/**\n * Agent Open-grant reflection (B1).\n *\n * Computes the extra Open grants a sandbox caller may use, derived from the\n * caller agent's own configuration (never from author declarations). The\n * invariant is: *what sandbox code can call ⊆ what the caller could already\n * call*. Grants are additive to the conservative B0 defaults and are bounded by\n * tenant-scoped resolution plus depth/rate/audit on the Open door.\n *\n * Mapping (`middleware[].enabled !== false`):\n * - middleware `type` whose plugin declares `meta.openExpose` → same-name domain\n * (identity; covers `task`, `document-parser`, and plugin types);\n * - `subAgents` (DeepAgentConfig) intersected with tenant-resolvable assistants\n * → the `agent` domain;\n * - anything else → ignored.\n *\n * Results are cached per `(tenantId, assistantId)` for\n * {@link AGENT_REFLECTION_CACHE_TTL_MS}. Any resolution error degrades to `[]`\n * so the caller falls back to the default grants rather than failing.\n */\n\nimport type { AssistantStore, OpenGrant } from \"@axiom-lattice/protocols\";\nimport {\n PluginRegistry,\n agentLatticeManager,\n ensureBuiltinAgentsForTenant,\n getSandboxPluginCatalog,\n getStoreLattice,\n} from \"@axiom-lattice/core\";\n\n/** The subset of an agent config relevant to Open-grant reflection. */\nexport interface SandboxOpenReflectionContext {\n middleware?: Array<{ type: string; enabled?: boolean; allowedTools?: string[] }>;\n subAgents?: string[];\n}\n\n/** Injectable sources for {@link resolveAgentOpenGrants}. */\nexport interface AgentReflectionDeps {\n /** Optional: hydrate stored/builtin/plugin agents for the tenant before resolution. */\n ensure?: (tenantId: string) => Promise<void>;\n /** Resolve an agent's config (middleware + subAgents) or undefined. */\n getAgentConfig?: (tenantId: string, assistantId: string) => SandboxOpenReflectionContext | undefined;\n /** Fallback: the assistant's persisted middleware. */\n getAssistantMiddleware?: (tenantId: string, assistantId: string) => Promise<Array<{ type: string; enabled?: boolean; allowedTools?: string[] }> | undefined>;\n /** Normalized exposed action names for a middleware/plugin type, or [] if none. */\n exposedActionsByType: (type: string) => string[];\n /** Assistant ids resolvable in the tenant (for subAgents filtering). */\n resolvableAssistants?: (tenantId: string) => Promise<Set<string>>;\n /** Clock seam for cache TTL tests. */\n now?: () => number;\n}\n\n/** How long a per-agent reflection result is reused. */\nexport const AGENT_REFLECTION_CACHE_TTL_MS = 60_000;\n\ninterface CacheEntry {\n grants: OpenGrant[];\n expiresAt: number;\n}\n\nconst cache = new Map<string, CacheEntry>();\n\n/** Clear the reflection cache. Test-only seam. */\nexport function clearAgentReflectionCacheForTests(): void {\n cache.clear();\n}\n\nfunction cloneGrants(grants: OpenGrant[]): OpenGrant[] {\n return grants.map((grant) => ({\n ...grant,\n items: grant.items ? [...grant.items] : undefined,\n }));\n}\n\n/** Normalize `meta.openExpose` (`string[] | {name}[]`) to action names. */\nexport function normalizeOpenExpose(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n const out: string[] = [];\n for (const entry of value) {\n if (typeof entry === \"string\") {\n if (entry) out.push(entry);\n } else if (entry && typeof entry === \"object\") {\n const name = (entry as { name?: unknown }).name;\n if (typeof name === \"string\" && name) out.push(name);\n }\n }\n return out;\n}\n\n/** Extract middleware type list from an agent config / graphDefinition. */\nfunction extractMiddleware(\n container: unknown,\n): Array<{ type: string; enabled?: boolean; allowedTools?: string[] }> | undefined {\n if (!container || typeof container !== \"object\") return undefined;\n const raw = (container as { middleware?: unknown }).middleware;\n if (!Array.isArray(raw)) return undefined;\n const out: Array<{ type: string; enabled?: boolean; allowedTools?: string[] }> = [];\n for (const entry of raw) {\n if (!entry || typeof entry !== \"object\") continue;\n const type = (entry as { type?: unknown }).type;\n if (typeof type !== \"string\" || type.length === 0) continue;\n const enabled = (entry as { enabled?: unknown }).enabled;\n const rawAllowed = (entry as { allowedTools?: unknown }).allowedTools;\n const allowedTools = Array.isArray(rawAllowed)\n ? rawAllowed.filter((t): t is string => typeof t === \"string\" && t.length > 0)\n : undefined;\n out.push({ type, enabled: typeof enabled === \"boolean\" ? enabled : undefined, allowedTools });\n }\n return out;\n}\n\n/** Extract subAgent ids from an agent config. */\nfunction extractSubAgents(config: unknown): string[] | undefined {\n if (!config || typeof config !== \"object\") return undefined;\n const raw = (config as { subAgents?: unknown }).subAgents;\n if (!Array.isArray(raw)) return undefined;\n const out = raw.filter((id): id is string => typeof id === \"string\" && id.length > 0);\n return out.length > 0 ? out : undefined;\n}\n\nasync function computeGrants(\n tenantId: string,\n assistantId: string,\n deps: AgentReflectionDeps,\n): Promise<OpenGrant[]> {\n await deps.ensure?.(tenantId);\n\n let context = await deps.getAgentConfig?.(tenantId, assistantId);\n if (context === undefined) {\n const middleware = await deps.getAssistantMiddleware?.(tenantId, assistantId);\n if (middleware === undefined) return [];\n context = { middleware };\n }\n\n const byDomain = new Map<string, Set<string>>();\n const add = (domain: string, items: Iterable<string>): void => {\n let bucket = byDomain.get(domain);\n if (!bucket) {\n bucket = new Set<string>();\n byDomain.set(domain, bucket);\n }\n for (const item of items) bucket.add(item);\n };\n\n for (const entry of context.middleware ?? []) {\n if (!entry || entry.enabled === false) continue;\n if (typeof entry.type !== \"string\" || entry.type.length === 0) continue;\n let actions = deps.exposedActionsByType(entry.type);\n if (actions.length === 0) continue;\n const allowedTools = entry.allowedTools;\n if (Array.isArray(allowedTools) && allowedTools.length > 0) {\n const allowed = new Set(allowedTools);\n actions = actions.filter((action) => allowed.has(action));\n if (actions.length === 0) continue;\n }\n add(entry.type, actions);\n }\n\n const subAgents = context.subAgents ?? [];\n if (subAgents.length > 0 && deps.resolvableAssistants) {\n const resolvable = await deps.resolvableAssistants(tenantId);\n const kept = subAgents.filter(\n (id) => typeof id === \"string\" && id.length > 0 && resolvable.has(id),\n );\n if (kept.length > 0) add(\"agent\", kept);\n }\n\n return [...byDomain].map(([domain, items]) => ({ domain, items: [...items] }));\n}\n\n/**\n * Resolve the reflected Open grants for an agent caller.\n *\n * @param tenantId - Tenant scope (grants never cross tenants).\n * @param assistantId - Caller agent id.\n * @param deps - Resolvers; {@link createDefaultAgentReflectionDeps} wires the\n * real registries/store.\n * @returns Reflected grants (possibly `[]`); never throws.\n */\nexport async function resolveAgentOpenGrants(\n tenantId: string,\n assistantId: string,\n deps: AgentReflectionDeps,\n): Promise<OpenGrant[]> {\n try {\n const key = `${tenantId}:${assistantId}`;\n const now = deps.now ? deps.now() : Date.now();\n const hit = cache.get(key);\n if (hit && hit.expiresAt > now) return cloneGrants(hit.grants);\n\n const grants = await computeGrants(tenantId, assistantId, deps);\n cache.set(key, { grants, expiresAt: now + AGENT_REFLECTION_CACHE_TTL_MS });\n return cloneGrants(grants);\n } catch {\n return [];\n }\n}\n\n/**\n * Default reflection deps wired to the live registries.\n *\n * Reads the agent lattice manager (seeded with built-ins for the tenant),\n * falls back to the assistant store, resolves plugin exposes from\n * {@link PluginRegistry}, and filters subAgents against tenant-resolvable\n * assistants.\n *\n * @param tenantId - Tenant whose built-in/plugin agents are ensured.\n * @returns Deps for {@link resolveAgentOpenGrants}.\n */\nexport function createDefaultAgentReflectionDeps(tenantId: string): AgentReflectionDeps {\n ensureBuiltinAgentsForTenant(tenantId);\n return {\n ensure: (t) => agentLatticeManager.initializeStoredAssistantsForTenant(t),\n getAgentConfig: (t, assistantId) => {\n const config = agentLatticeManager.getAgentConfigWithTenant(t, assistantId);\n if (!config) return undefined;\n return {\n middleware: extractMiddleware(config),\n subAgents: extractSubAgents(config),\n };\n },\n getAssistantMiddleware: async (t, assistantId) => {\n const store = getStoreLattice(\"default\", \"assistant\").store as AssistantStore;\n const assistant = await store.getAssistantById(t, assistantId);\n return extractMiddleware(assistant?.graphDefinition);\n },\n exposedActionsByType: (type) => {\n const plugin = PluginRegistry.get(type);\n return plugin ? normalizeOpenExpose(plugin.meta.openExpose) : [];\n },\n resolvableAssistants: async (t) =>\n new Set(\n agentLatticeManager.getAllAgentLatticesByTenant(t).map((lattice) => lattice.config.key),\n ),\n };\n}\n\n/** How long a per-tenant plugin reflection result is reused. */\nexport const PLUGIN_REFLECTION_CACHE_TTL_MS = 60_000;\n\n/**\n * Injectable sources for {@link resolvePluginOpenGrants}.\n *\n * Plugin handlers have no `assistantId`, so reflection targets the tenant's\n * grantable Open catalog instead of a caller's own configuration.\n *\n * @property ensure - Optional: hydrate stored/builtin/plugin agents before reflecting the agent domain.\n * @property globalExposedDomains - Global plugin `openExpose` domains (tenant-agnostic).\n * @property tenantExposedDomains - Tenant sandbox plugin exposed domains.\n * @property resolvableAssistants - Tenant-resolvable assistant ids for the `agent` domain.\n * @property now - Clock seam for cache TTL tests.\n */\nexport interface PluginReflectionDeps {\n /** Optional: hydrate stored/builtin/plugin agents before reflecting the agent domain. */\n ensure?: (tenantId: string) => Promise<void>;\n globalExposedDomains?: () => OpenGrant[];\n tenantExposedDomains?: (tenantId: string) => Promise<OpenGrant[]>;\n resolvableAssistants?: (tenantId: string) => Promise<Set<string>>;\n now?: () => number;\n}\n\ninterface PluginCacheEntry {\n grants: OpenGrant[];\n expiresAt: number;\n}\n\nconst pluginCache = new Map<string, PluginCacheEntry>();\n\n/** Clear the plugin reflection cache. Test-only seam. */\nexport function clearPluginReflectionCacheForTests(): void {\n pluginCache.clear();\n}\n\n/**\n * Merge grants by domain, preserving first-seen domain order and unioning items.\n *\n * An absent/empty `items` list means \"every action in the domain\" per\n * {@link OpenGrant}, so a domain carrying one collapses to `{ domain }`.\n *\n * @param grants - Raw grants from every reflection source.\n * @returns One normalized grant per domain.\n */\nexport function mergeGrantsByDomain(grants: OpenGrant[]): OpenGrant[] {\n const order: string[] = [];\n const items = new Map<string, Set<string>>();\n const unrestricted = new Set<string>();\n\n for (const grant of grants) {\n if (!grant || typeof grant.domain !== \"string\" || grant.domain.length === 0) continue;\n if (!items.has(grant.domain)) {\n items.set(grant.domain, new Set());\n order.push(grant.domain);\n }\n if (!grant.items || grant.items.length === 0) {\n unrestricted.add(grant.domain);\n continue;\n }\n const bucket = items.get(grant.domain);\n if (!bucket) continue;\n for (const item of grant.items) {\n if (typeof item === \"string\" && item.length > 0) bucket.add(item);\n }\n }\n\n return order.map((domain) => {\n if (unrestricted.has(domain)) return { domain };\n return { domain, items: [...(items.get(domain) ?? [])] };\n });\n}\n\nasync function computePluginGrants(\n tenantId: string,\n deps: PluginReflectionDeps,\n): Promise<OpenGrant[]> {\n const grants: OpenGrant[] = [...(deps.globalExposedDomains?.() ?? [])];\n if (deps.tenantExposedDomains) {\n grants.push(...(await deps.tenantExposedDomains(tenantId)));\n }\n if (deps.resolvableAssistants) {\n const resolvable = await deps.resolvableAssistants(tenantId);\n if (resolvable.size > 0) {\n grants.push({ domain: \"agent\", items: [...resolvable] });\n }\n }\n return mergeGrantsByDomain(grants);\n}\n\n/**\n * Resolve the reflected Open grants for a plugin handler caller.\n *\n * Plugin handlers carry no `assistantId`, so grants come from the tenant's\n * grantable Open catalog (global plugin exposes ∪ tenant sandbox plugin\n * exposes) plus the `agent` domain for tenant-resolvable assistants. Results\n * are cached per tenant for {@link PLUGIN_REFLECTION_CACHE_TTL_MS}; any\n * resolution error degrades to `[]` so the caller falls back to the default\n * grants rather than failing.\n *\n * @param tenantId - Tenant scope (grants never cross tenants).\n * @param deps - Resolvers; {@link createDefaultPluginReflectionDeps} wires the\n * real registries/catalog.\n * @returns Reflected grants (possibly `[]`); never throws.\n */\nexport async function resolvePluginOpenGrants(\n tenantId: string,\n deps: PluginReflectionDeps,\n): Promise<OpenGrant[]> {\n try {\n const now = deps.now ? deps.now() : Date.now();\n const hit = pluginCache.get(tenantId);\n if (hit && hit.expiresAt > now) return cloneGrants(hit.grants);\n\n await deps.ensure?.(tenantId);\n const grants = await computePluginGrants(tenantId, deps);\n pluginCache.set(tenantId, { grants, expiresAt: now + PLUGIN_REFLECTION_CACHE_TTL_MS });\n return cloneGrants(grants);\n } catch {\n return [];\n }\n}\n\n/**\n * Map validated tenant plugin manifests to exposed Open grants.\n *\n * Only tools declaring `expose === true` become grant items; plugins with no\n * exposed tools are skipped. The domain is the plugin `type`.\n *\n * @param manifests - Validated tenant plugin manifests (or any shape with a\n * `type` and `tools[].name`/`tools[].expose`).\n * @returns One grant per plugin that exposes at least one tool.\n */\nexport function buildTenantExposedGrants(\n manifests: Array<{ type: string; tools?: Array<{ name: string; expose?: boolean }> }>,\n): OpenGrant[] {\n const grants: OpenGrant[] = [];\n for (const manifest of manifests) {\n const items = (manifest.tools ?? [])\n .filter((tool) => tool.expose === true)\n .map((tool) => tool.name);\n if (items.length > 0) grants.push({ domain: manifest.type, items });\n }\n return grants;\n}\n\n/**\n * Default plugin reflection deps wired to the live registries.\n *\n * Ensures stored/builtin/plugin agents for the tenant, then reads global plugin\n * exposes from {@link PluginRegistry}, tenant sandbox plugin exposes from\n * {@link getSandboxPluginCatalog} manifests, and tenant-resolvable assistants\n * from the agent lattice manager.\n *\n * @returns Deps for {@link resolvePluginOpenGrants}.\n */\nexport function createDefaultPluginReflectionDeps(): PluginReflectionDeps {\n return {\n ensure: (tenantId) => agentLatticeManager.initializeStoredAssistantsForTenant(tenantId),\n globalExposedDomains: () => {\n const grants: OpenGrant[] = [];\n for (const type of PluginRegistry.list()) {\n const plugin = PluginRegistry.get(type);\n const items = normalizeOpenExpose(plugin?.meta.openExpose);\n if (items.length > 0) grants.push({ domain: type, items });\n }\n return grants;\n },\n tenantExposedDomains: async (tenantId) => {\n const { manifests } = await getSandboxPluginCatalog().ensureLoaded(tenantId);\n return buildTenantExposedGrants(Object.values(manifests));\n },\n resolvableAssistants: async (tenantId) =>\n new Set(\n agentLatticeManager\n .getAllAgentLatticesByTenant(tenantId)\n .map((lattice) => lattice.config.key),\n ),\n };\n}\n"],"mappings":"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","names":[]}
|
/package/dist/{OrphanRecoveryRuntime-BEFILJMU.mjs.map → OrphanRecoveryRuntime-T4T5NOZU.mjs.map}
RENAMED
|
File without changes
|