@tonyclaw/llm-inspector 1.9.0 → 1.9.1
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/.output/nitro.json +1 -1
- package/.output/public/assets/{index-DyKLPMPn.js → index-BmEH5jeO.js} +3 -3
- package/.output/public/assets/{main-Cu0oTDfX.js → main-GVpFMVGE.js} +1 -1
- package/.output/server/_ssr/{index-COIATcfa.mjs → index-D0d6QxPt.mjs} +13 -5
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{router-CwmgKXBJ.mjs → router-D9uLXa9A.mjs} +63 -14
- package/.output/server/{_tanstack-start-manifest_v-C7hQOzvX.mjs → _tanstack-start-manifest_v-ByfnNZV_.mjs} +1 -1
- package/.output/server/index.mjs +28 -28
- package/package.json +1 -1
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +12 -3
- package/src/proxy/handler.ts +11 -1
- package/src/proxy/logIndex.ts +30 -9
- package/src/proxy/logger.ts +13 -7
- package/src/proxy/store.ts +9 -5
|
@@ -14,4 +14,4 @@ Error generating stack: `+l.message+`
|
|
|
14
14
|
`)}else{const p=o.indexOf(`
|
|
15
15
|
`);if(p>=0){const v=o.slice(0,p).trim();o=o.slice(p+1),v.length>0&&(h=JSON.parse(v),f=!0)}}}return(async()=>{try{for(;;){const{value:y,done:m}=await r.read();y&&(o+=y);const p=o.lastIndexOf(`
|
|
16
16
|
`);if(p>=0){const v=o.slice(0,p);o=o.slice(p+1);const S=v.split(`
|
|
17
|
-
`).filter(Boolean);for(const _ of S)try{u(JSON.parse(_))}catch(R){i?.(`Invalid JSON line: ${_}`,R)}}if(m)break}}catch(y){i?.("Stream processing error:",y)}})(),u(h)}async function dR({jsonStream:a,onMessage:u,onError:i}){const r=a.getReader(),{value:o,done:f}=await r.read();if(f||!o)throw new Error("Stream ended before first object");const h=JSON.parse(o);return(async()=>{try{for(;;){const{value:y,done:m}=await r.read();if(m)break;if(y)try{u(JSON.parse(y))}catch(p){i?.(`Invalid JSON: ${y}`,p)}}}catch(y){i?.("Stream processing error:",y)}})(),u(h)}function hR(a){const u="/_serverFn/"+a;return Object.assign((...o)=>{const f=vg()?.serverFns?.fetch;return rR(u,o,f??fetch)},{url:u,serverFnMeta:{id:a},[Zo]:!0})}const mR={key:"$TSS/serverfn",test:a=>typeof a!="function"||!(Zo in a)?!1:!!a[Zo],toSerializable:({serverFnMeta:a})=>({functionId:a.id}),fromSerializable:({functionId:a})=>hR(a)};var lp=cg();const Eg=0,Rg=1,Tg=2,ip=3;var up=Object.prototype.hasOwnProperty;function Ko(a,u){var i,r;if(a===u)return!0;if(a&&u&&(i=a.constructor)===u.constructor){if(i===Date)return a.getTime()===u.getTime();if(i===RegExp)return a.toString()===u.toString();if(i===Array){if((r=a.length)===u.length)for(;r--&&Ko(a[r],u[r]););return r===-1}if(!i||typeof a=="object"){r=0;for(i in a)if(up.call(a,i)&&++r&&!up.call(u,i)||!(i in u)||!Ko(a[i],u[i]))return!1;return Object.keys(u).length===r}}return a!==a&&u!==u}const Bn=new WeakMap,Hn=()=>{},ge=Hn(),Xs=Object,_t=a=>a===ge,sn=a=>typeof a=="function",Gn=(a,u)=>({...a,...u}),Ag=a=>sn(a.then),No={},As={},pf="undefined",lu=typeof window!=pf,Jo=typeof document!=pf,yR=lu&&"Deno"in window,pR=()=>lu&&typeof window.requestAnimationFrame!=pf,Og=(a,u)=>{const i=Bn.get(a);return[()=>!_t(u)&&a.get(u)||No,r=>{if(!_t(u)){const o=a.get(u);u in As||(As[u]=o),i[5](u,Gn(o,r),o||No)}},i[6],()=>!_t(u)&&u in As?As[u]:!_t(u)&&a.get(u)||No]};let ko=!0;const gR=()=>ko,[Fo,Po]=lu&&window.addEventListener?[window.addEventListener.bind(window),window.removeEventListener.bind(window)]:[Hn,Hn],vR=()=>{const a=Jo&&document.visibilityState;return _t(a)||a!=="hidden"},SR=a=>(Jo&&document.addEventListener("visibilitychange",a),Fo("focus",a),()=>{Jo&&document.removeEventListener("visibilitychange",a),Po("focus",a)}),bR=a=>{const u=()=>{ko=!0,a()},i=()=>{ko=!1};return Fo("online",u),Fo("offline",i),()=>{Po("online",u),Po("offline",i)}},_R={isOnline:gR,isVisible:vR},ER={initFocus:SR,initReconnect:bR},sp=!qn.useId,Fl=!lu||yR,RR=a=>pR()?window.requestAnimationFrame(a):setTimeout(a,1),Ds=Fl?$.useEffect:$.useLayoutEffect,Uo=typeof navigator<"u"&&navigator.connection,rp=!Fl&&Uo&&(["slow-2g","2g"].includes(Uo.effectiveType)||Uo.saveData),Os=new WeakMap,TR=a=>Xs.prototype.toString.call(a),Bo=(a,u)=>a===`[object ${u}]`;let AR=0;const Wo=a=>{const u=typeof a,i=TR(a),r=Bo(i,"Date"),o=Bo(i,"RegExp"),f=Bo(i,"Object");let h,y;if(Xs(a)===a&&!r&&!o){if(h=Os.get(a),h)return h;if(h=++AR+"~",Os.set(a,h),Array.isArray(a)){for(h="@",y=0;y<a.length;y++)h+=Wo(a[y])+",";Os.set(a,h)}if(f){h="#";const m=Xs.keys(a).sort();for(;!_t(y=m.pop());)_t(a[y])||(h+=y+":"+Wo(a[y])+",");Os.set(a,h)}}else h=r?a.toJSON():u=="symbol"?a.toString():u=="string"?JSON.stringify(a):""+a;return h},gf=a=>{if(sn(a))try{a=a()}catch{a=""}const u=a;return a=typeof a=="string"?a:(Array.isArray(a)?a.length:a)?Wo(a):"",[a,u]};let OR=0;const $o=()=>++OR;async function wg(...a){const[u,i,r,o]=a,f=Gn({populateCache:!0,throwOnError:!0},typeof o=="boolean"?{revalidate:o}:o||{});let h=f.populateCache;const y=f.rollbackOnError;let m=f.optimisticData;const p=_=>typeof y=="function"?y(_):y!==!1,v=f.throwOnError;if(sn(i)){const _=i,R=[],z=u.keys();for(const A of z)!/^\$(inf|sub)\$/.test(A)&&_(u.get(A)._k)&&R.push(A);return Promise.all(R.map(S))}return S(i);async function S(_){const[R]=gf(_);if(!R)return;const[z,A]=Og(u,R),[x,Y,B,Z]=Bn.get(u),H=()=>{const it=x[R];return(sn(f.revalidate)?f.revalidate(z().data,_):f.revalidate!==!1)&&(delete B[R],delete Z[R],it&&it[0])?it[0](Tg).then(()=>z().data):z().data};if(a.length<3)return H();let k=r,I,Q=!1;const X=$o();Y[R]=[X,0];const K=!_t(m),rt=z(),nt=rt.data,lt=rt._c,ht=_t(lt)?nt:lt;if(K&&(m=sn(m)?m(ht,nt):m,A({data:m,_c:ht})),sn(k))try{k=k(ht)}catch(it){I=it,Q=!0}if(k&&Ag(k))if(k=await k.catch(it=>{I=it,Q=!0}),X!==Y[R][0]){if(Q)throw I;return k}else Q&&K&&p(I)&&(h=!0,A({data:ht,_c:ge}));if(h&&!Q)if(sn(h)){const it=h(k,ht);A({data:it,error:ge,_c:ge})}else A({data:k,error:ge,_c:ge});if(Y[R][1]=$o(),Promise.resolve(H()).then(()=>{A({_c:ge})}),Q){if(v)throw I;return}return k}}const cp=(a,u)=>{for(const i in a)a[i][0]&&a[i][0](u)},Mg=(a,u)=>{if(!Bn.has(a)){const i=Gn(ER,u),r=Object.create(null),o=wg.bind(ge,a);let f=Hn;const h=Object.create(null),y=(v,S)=>{const _=h[v]||[];return h[v]=_,_.push(S),()=>_.splice(_.indexOf(S),1)},m=(v,S,_)=>{a.set(v,S);const R=h[v];if(R)for(const z of R)z(S,_)},p=()=>{if(!Bn.has(a)&&(Bn.set(a,[r,Object.create(null),Object.create(null),Object.create(null),o,m,y]),!Fl)){const v=i.initFocus(setTimeout.bind(ge,cp.bind(ge,r,Eg))),S=i.initReconnect(setTimeout.bind(ge,cp.bind(ge,r,Rg)));f=()=>{v&&v(),S&&S(),Bn.delete(a)}}};return p(),[a,o,p,f]}return[a,Bn.get(a)[4]]},wR=(a,u,i,r,o)=>{const f=i.errorRetryCount,h=o.retryCount,y=~~((Math.random()+.5)*(1<<(h<8?h:8)))*i.errorRetryInterval;!_t(f)&&h>f||setTimeout(r,y,o)},MR=Ko,[vf,xR]=Mg(new Map),xg=Gn({onLoadingSlow:Hn,onSuccess:Hn,onError:Hn,onErrorRetry:wR,onDiscarded:Hn,revalidateOnFocus:!0,revalidateOnReconnect:!0,revalidateIfStale:!0,shouldRetryOnError:!0,errorRetryInterval:rp?1e4:5e3,focusThrottleInterval:5*1e3,dedupingInterval:2*1e3,loadingTimeout:rp?5e3:3e3,compare:MR,isPaused:()=>!1,cache:vf,mutate:xR,fallback:{}},_R),zg=(a,u)=>{const i=Gn(a,u);if(u){const{use:r,fallback:o}=a,{use:f,fallback:h}=u;r&&f&&(i.use=r.concat(f)),o&&h&&(i.fallback=Gn(o,h))}return i},Io=$.createContext({}),zR=a=>{const{value:u}=a,i=$.useContext(Io),r=sn(u),o=$.useMemo(()=>r?u(i):u,[r,i,u]),f=$.useMemo(()=>r?o:zg(i,o),[r,i,o]),h=o&&o.provider,y=$.useRef(ge);h&&!y.current&&(y.current=Mg(h(f.cache||vf),o));const m=y.current;return m&&(f.cache=m[0],f.mutate=m[1]),Ds(()=>{if(m)return m[2]&&m[2](),m[3]},[]),$.createElement(Io.Provider,Gn(a,{value:f}))},CR="$inf$",Cg=lu&&window.__SWR_DEVTOOLS_USE__,DR=Cg?window.__SWR_DEVTOOLS_USE__:[],LR=()=>{Cg&&(window.__SWR_DEVTOOLS_REACT__=qn)},NR=a=>sn(a[1])?[a[0],a[1],a[2]||{}]:[a[0],null,(a[1]===null?a[2]:a[1])||{}],UR=()=>{const a=$.useContext(Io);return $.useMemo(()=>Gn(xg,a),[a])},BR=a=>(u,i,r)=>a(u,i&&((...f)=>{const[h]=gf(u),[,,,y]=Bn.get(vf);if(h.startsWith(CR))return i(...f);const m=y[h];return _t(m)?i(...f):(delete y[h],m)}),r),jR=DR.concat(BR),HR=a=>function(...i){const r=UR(),[o,f,h]=NR(i),y=zg(r,h);let m=a;const{use:p}=y,v=(p||[]).concat(jR);for(let S=v.length;S--;)m=v[S](m);return m(o,f||y.fetcher||null,y)},qR=(a,u,i)=>{const r=u[a]||(u[a]=[]);return r.push(i),()=>{const o=r.indexOf(i);o>=0&&(r[o]=r[r.length-1],r.pop())}};LR();const jo=qn.use||(a=>{switch(a.status){case"pending":throw a;case"fulfilled":return a.value;case"rejected":throw a.reason;default:throw a.status="pending",a.then(u=>{a.status="fulfilled",a.value=u},u=>{a.status="rejected",a.reason=u}),a}}),Ho={dedupe:!0},op=Promise.resolve(ge),VR=()=>Hn,YR=(a,u,i)=>{const{cache:r,compare:o,suspense:f,fallbackData:h,revalidateOnMount:y,revalidateIfStale:m,refreshInterval:p,refreshWhenHidden:v,refreshWhenOffline:S,keepPreviousData:_,strictServerPrefetchWarning:R}=i,[z,A,x,Y]=Bn.get(r),[B,Z]=gf(a),H=$.useRef(!1),k=$.useRef(!1),I=$.useRef(B),Q=$.useRef(u),X=$.useRef(i),K=()=>X.current,rt=()=>K().isVisible()&&K().isOnline(),[nt,lt,ht,it]=Og(r,B),jt=$.useRef({}).current,N=_t(h)?_t(i.fallback)?ge:i.fallback[B]:h,F=(Et,Lt)=>{for(const At in jt){const qt=At;if(qt==="data"){if(!o(Et[qt],Lt[qt])&&(!_t(Et[qt])||!o(ot,Lt[qt])))return!1}else if(Lt[qt]!==Et[qt])return!1}return!0},ut=!H.current,Tt=$.useMemo(()=>{const Et=nt(),Lt=it(),At=Jt=>{const Vt=Gn(Jt);return delete Vt._k,(()=>{if(!B||!u||K().isPaused())return!1;if(ut&&!_t(y))return y;const xt=_t(N)?Vt.data:N;return _t(xt)||m})()?{isValidating:!0,isLoading:!0,...Vt}:Vt},qt=At(Et),ve=Et===Lt?qt:At(Lt);let oe=qt;return[()=>{const Jt=At(nt());return F(Jt,oe)?(oe.data=Jt.data,oe.isLoading=Jt.isLoading,oe.isValidating=Jt.isValidating,oe.error=Jt.error,oe):(oe=Jt,Jt)},()=>ve]},[r,B]),pt=lp.useSyncExternalStore($.useCallback(Et=>ht(B,(Lt,At)=>{F(At,Lt)||Et()}),[r,B]),Tt[0],Tt[1]),w=z[B]&&z[B].length>0,q=pt.data,J=_t(q)?N&&Ag(N)?jo(N):N:q,P=pt.error,ct=$.useRef(J),ot=_?_t(q)?_t(ct.current)?J:ct.current:q:J,ft=B&&_t(J),Xt=$.useRef(null);!Fl&&lp.useSyncExternalStore(VR,()=>(Xt.current=!1,Xt),()=>(Xt.current=!0,Xt));const Ht=Xt.current;R&&Ht&&!f&&ft&&console.warn(`Missing pre-initiated data for serialized key "${B}" during server-side rendering. Data fetching should be initiated on the server and provided to SWR via fallback data. You can set "strictServerPrefetchWarning: false" to disable this warning.`);const De=!B||!u||K().isPaused()||w&&!_t(P)?!1:ut&&!_t(y)?y:f?_t(J)?!1:m:_t(J)||m,Xe=ut&&De,Qn=_t(pt.isValidating)?Xe:pt.isValidating,Ta=_t(pt.isLoading)?Xe:pt.isLoading,_e=$.useCallback(async Et=>{const Lt=Q.current;if(!B||!Lt||k.current||K().isPaused())return!1;let At,qt,ve=!0;const oe=Et||{},Jt=!x[B]||!oe.dedupe,Vt=()=>sp?!k.current&&B===I.current&&H.current:B===I.current,yn={isValidating:!1,isLoading:!1},xt=()=>{lt(yn)},$t=()=>{const fe=x[B];fe&&fe[1]===qt&&delete x[B]},ae={isValidating:!0};_t(nt().data)&&(ae.isLoading=!0);try{if(Jt&&(lt(ae),i.loadingTimeout&&_t(nt().data)&&setTimeout(()=>{ve&&Vt()&&K().onLoadingSlow(B,i)},i.loadingTimeout),x[B]=[Lt(Z),$o()]),[At,qt]=x[B],At=await At,Jt&&setTimeout($t,i.dedupingInterval),!x[B]||x[B][1]!==qt)return Jt&&Vt()&&K().onDiscarded(B),!1;yn.error=ge;const fe=A[B];if(!_t(fe)&&(qt<=fe[0]||qt<=fe[1]||fe[1]===0))return xt(),Jt&&Vt()&&K().onDiscarded(B),!1;const Qe=nt().data;yn.data=o(Qe,At)?Qe:At,Jt&&Vt()&&K().onSuccess(At,B,i)}catch(fe){$t();const Qe=K(),{shouldRetryOnError:Wl}=Qe;Qe.isPaused()||(yn.error=fe,Jt&&Vt()&&(Qe.onError(fe,B,Qe),(Wl===!0||sn(Wl)&&Wl(fe))&&(!K().revalidateOnFocus||!K().revalidateOnReconnect||rt())&&Qe.onErrorRetry(fe,B,Qe,$s=>{const pn=z[B];pn&&pn[0]&&pn[0](ip,$s)},{retryCount:(oe.retryCount||0)+1,dedupe:!0})))}return ve=!1,xt(),!0},[B,r]),mn=$.useCallback((...Et)=>wg(r,I.current,...Et),[]);if(Ds(()=>{Q.current=u,X.current=i,_t(q)||(ct.current=q)}),Ds(()=>{if(!B)return;const Et=_e.bind(ge,Ho);let Lt=0;K().revalidateOnFocus&&(Lt=Date.now()+K().focusThrottleInterval);const qt=qR(B,z,(ve,oe={})=>{if(ve==Eg){const Jt=Date.now();K().revalidateOnFocus&&Jt>Lt&&rt()&&(Lt=Jt+K().focusThrottleInterval,Et())}else if(ve==Rg)K().revalidateOnReconnect&&rt()&&Et();else{if(ve==Tg)return _e();if(ve==ip)return _e(oe)}});return k.current=!1,I.current=B,H.current=!0,lt({_k:Z}),De&&(x[B]||(_t(J)||Fl?Et():RR(Et))),()=>{k.current=!0,qt()}},[B]),Ds(()=>{let Et;function Lt(){const qt=sn(p)?p(nt().data):p;qt&&Et!==-1&&(Et=setTimeout(At,qt))}function At(){!nt().error&&(v||K().isVisible())&&(S||K().isOnline())?_e(Ho).then(Lt):Lt()}return Lt(),()=>{Et&&(clearTimeout(Et),Et=-1)}},[p,v,S,B]),$.useDebugValue(ot),f){if(!sp&&Fl&&ft)throw new Error("Fallback data is required when using Suspense in SSR.");ft&&(Q.current=u,X.current=i,k.current=!1);const Et=Y[B],Lt=!_t(Et)&&ft?mn(Et):op;if(jo(Lt),!_t(P)&&ft)throw P;const At=ft?_e(Ho):op;!_t(ot)&&ft&&(At.status="fulfilled",At.value=!0),jo(At)}return{mutate:mn,get data(){return jt.data=!0,ot},get error(){return jt.error=!0,P},get isValidating(){return jt.isValidating=!0,Qn},get isLoading(){return jt.isLoading=!0,Ta}}},GR=Xs.defineProperty(zR,"defaultValue",{value:xg}),oT=HR(YR),XR="/assets/index-DdJSLfxK.css",Dg=DE({head:()=>({meta:[{charSet:"utf-8"},{name:"viewport",content:"width=device-width, initial-scale=1"},{title:"llm-inspector"}],links:[{rel:"stylesheet",href:XR}]}),component:QR});function QR(){return W.jsx(ZR,{children:W.jsx(yg,{})})}function ZR({children:a}){return W.jsxs("html",{lang:"en",className:"dark",children:[W.jsx("head",{children:W.jsx(kE,{})}),W.jsxs("body",{children:[W.jsx(GR,{value:{revalidateOnFocus:!1,revalidateIfStale:!1},children:a}),W.jsx(FE,{})]})]})}const KR="modulepreload",JR=function(a){return"/"+a},fp={},kR=function(u,i,r){let o=Promise.resolve();if(i&&i.length>0){let m=function(p){return Promise.all(p.map(v=>Promise.resolve(v).then(S=>({status:"fulfilled",value:S}),S=>({status:"rejected",reason:S}))))};document.getElementsByTagName("link");const h=document.querySelector("meta[property=csp-nonce]"),y=h?.nonce||h?.getAttribute("nonce");o=m(i.map(p=>{if(p=JR(p),p in fp)return;fp[p]=!0;const v=p.endsWith(".css"),S=v?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${p}"]${S}`))return;const _=document.createElement("link");if(_.rel=v?"stylesheet":KR,v||(_.as="script"),_.crossOrigin="",_.href=p,y&&_.setAttribute("nonce",y),document.head.appendChild(_),v)return new Promise((R,z)=>{_.addEventListener("load",R),_.addEventListener("error",()=>z(new Error(`Unable to preload CSS for ${p}`)))})}))}function f(h){const y=new Event("vite:preloadError",{cancelable:!0});if(y.payload=h,window.dispatchEvent(y),!y.defaultPrevented)throw h}return o.then(h=>{for(const y of h||[])y.status==="rejected"&&f(y.reason);return u().catch(f)})},FR=()=>kR(()=>import("./index-DyKLPMPn.js"),[]),PR=Qo("/")({component:LE(FR,"component")}),WR=PR.update({id:"/",path:"/",getParentRoute:()=>Dg}),$R={IndexRoute:WR},IR=Dg._addFileChildren($R);function tT(){return YE({routeTree:IR,scrollRestoration:!1})}async function eT(){const a=await tT();let u;return u=[],window.__TSS_START_OPTIONS__={serializationAdapters:u},u.push(mR),a.options.serializationAdapters&&u.push(...a.options.serializationAdapters),a.update({basepath:"",serializationAdapters:u}),a.state.matches.length||await WE(a),a}async function nT(){const a=await eT();return window.$_TSR?.h(),a}let qo;function aT(){return qo||(qo=nT()),W.jsx(rE,{promise:qo,children:a=>W.jsx(QE,{router:a})})}$.startTransition(()=>{iS.hydrateRoot(document,W.jsx($.StrictMode,{children:W.jsx(aT,{})}))});export{qn as R,fg as a,I0 as b,lT as c,rT as d,dp as g,W as j,$ as r,oT as u};
|
|
17
|
+
`).filter(Boolean);for(const _ of S)try{u(JSON.parse(_))}catch(R){i?.(`Invalid JSON line: ${_}`,R)}}if(m)break}}catch(y){i?.("Stream processing error:",y)}})(),u(h)}async function dR({jsonStream:a,onMessage:u,onError:i}){const r=a.getReader(),{value:o,done:f}=await r.read();if(f||!o)throw new Error("Stream ended before first object");const h=JSON.parse(o);return(async()=>{try{for(;;){const{value:y,done:m}=await r.read();if(m)break;if(y)try{u(JSON.parse(y))}catch(p){i?.(`Invalid JSON: ${y}`,p)}}}catch(y){i?.("Stream processing error:",y)}})(),u(h)}function hR(a){const u="/_serverFn/"+a;return Object.assign((...o)=>{const f=vg()?.serverFns?.fetch;return rR(u,o,f??fetch)},{url:u,serverFnMeta:{id:a},[Zo]:!0})}const mR={key:"$TSS/serverfn",test:a=>typeof a!="function"||!(Zo in a)?!1:!!a[Zo],toSerializable:({serverFnMeta:a})=>({functionId:a.id}),fromSerializable:({functionId:a})=>hR(a)};var lp=cg();const Eg=0,Rg=1,Tg=2,ip=3;var up=Object.prototype.hasOwnProperty;function Ko(a,u){var i,r;if(a===u)return!0;if(a&&u&&(i=a.constructor)===u.constructor){if(i===Date)return a.getTime()===u.getTime();if(i===RegExp)return a.toString()===u.toString();if(i===Array){if((r=a.length)===u.length)for(;r--&&Ko(a[r],u[r]););return r===-1}if(!i||typeof a=="object"){r=0;for(i in a)if(up.call(a,i)&&++r&&!up.call(u,i)||!(i in u)||!Ko(a[i],u[i]))return!1;return Object.keys(u).length===r}}return a!==a&&u!==u}const Bn=new WeakMap,Hn=()=>{},ge=Hn(),Xs=Object,_t=a=>a===ge,sn=a=>typeof a=="function",Gn=(a,u)=>({...a,...u}),Ag=a=>sn(a.then),No={},As={},pf="undefined",lu=typeof window!=pf,Jo=typeof document!=pf,yR=lu&&"Deno"in window,pR=()=>lu&&typeof window.requestAnimationFrame!=pf,Og=(a,u)=>{const i=Bn.get(a);return[()=>!_t(u)&&a.get(u)||No,r=>{if(!_t(u)){const o=a.get(u);u in As||(As[u]=o),i[5](u,Gn(o,r),o||No)}},i[6],()=>!_t(u)&&u in As?As[u]:!_t(u)&&a.get(u)||No]};let ko=!0;const gR=()=>ko,[Fo,Po]=lu&&window.addEventListener?[window.addEventListener.bind(window),window.removeEventListener.bind(window)]:[Hn,Hn],vR=()=>{const a=Jo&&document.visibilityState;return _t(a)||a!=="hidden"},SR=a=>(Jo&&document.addEventListener("visibilitychange",a),Fo("focus",a),()=>{Jo&&document.removeEventListener("visibilitychange",a),Po("focus",a)}),bR=a=>{const u=()=>{ko=!0,a()},i=()=>{ko=!1};return Fo("online",u),Fo("offline",i),()=>{Po("online",u),Po("offline",i)}},_R={isOnline:gR,isVisible:vR},ER={initFocus:SR,initReconnect:bR},sp=!qn.useId,Fl=!lu||yR,RR=a=>pR()?window.requestAnimationFrame(a):setTimeout(a,1),Ds=Fl?$.useEffect:$.useLayoutEffect,Uo=typeof navigator<"u"&&navigator.connection,rp=!Fl&&Uo&&(["slow-2g","2g"].includes(Uo.effectiveType)||Uo.saveData),Os=new WeakMap,TR=a=>Xs.prototype.toString.call(a),Bo=(a,u)=>a===`[object ${u}]`;let AR=0;const Wo=a=>{const u=typeof a,i=TR(a),r=Bo(i,"Date"),o=Bo(i,"RegExp"),f=Bo(i,"Object");let h,y;if(Xs(a)===a&&!r&&!o){if(h=Os.get(a),h)return h;if(h=++AR+"~",Os.set(a,h),Array.isArray(a)){for(h="@",y=0;y<a.length;y++)h+=Wo(a[y])+",";Os.set(a,h)}if(f){h="#";const m=Xs.keys(a).sort();for(;!_t(y=m.pop());)_t(a[y])||(h+=y+":"+Wo(a[y])+",");Os.set(a,h)}}else h=r?a.toJSON():u=="symbol"?a.toString():u=="string"?JSON.stringify(a):""+a;return h},gf=a=>{if(sn(a))try{a=a()}catch{a=""}const u=a;return a=typeof a=="string"?a:(Array.isArray(a)?a.length:a)?Wo(a):"",[a,u]};let OR=0;const $o=()=>++OR;async function wg(...a){const[u,i,r,o]=a,f=Gn({populateCache:!0,throwOnError:!0},typeof o=="boolean"?{revalidate:o}:o||{});let h=f.populateCache;const y=f.rollbackOnError;let m=f.optimisticData;const p=_=>typeof y=="function"?y(_):y!==!1,v=f.throwOnError;if(sn(i)){const _=i,R=[],z=u.keys();for(const A of z)!/^\$(inf|sub)\$/.test(A)&&_(u.get(A)._k)&&R.push(A);return Promise.all(R.map(S))}return S(i);async function S(_){const[R]=gf(_);if(!R)return;const[z,A]=Og(u,R),[x,Y,B,Z]=Bn.get(u),H=()=>{const it=x[R];return(sn(f.revalidate)?f.revalidate(z().data,_):f.revalidate!==!1)&&(delete B[R],delete Z[R],it&&it[0])?it[0](Tg).then(()=>z().data):z().data};if(a.length<3)return H();let k=r,I,Q=!1;const X=$o();Y[R]=[X,0];const K=!_t(m),rt=z(),nt=rt.data,lt=rt._c,ht=_t(lt)?nt:lt;if(K&&(m=sn(m)?m(ht,nt):m,A({data:m,_c:ht})),sn(k))try{k=k(ht)}catch(it){I=it,Q=!0}if(k&&Ag(k))if(k=await k.catch(it=>{I=it,Q=!0}),X!==Y[R][0]){if(Q)throw I;return k}else Q&&K&&p(I)&&(h=!0,A({data:ht,_c:ge}));if(h&&!Q)if(sn(h)){const it=h(k,ht);A({data:it,error:ge,_c:ge})}else A({data:k,error:ge,_c:ge});if(Y[R][1]=$o(),Promise.resolve(H()).then(()=>{A({_c:ge})}),Q){if(v)throw I;return}return k}}const cp=(a,u)=>{for(const i in a)a[i][0]&&a[i][0](u)},Mg=(a,u)=>{if(!Bn.has(a)){const i=Gn(ER,u),r=Object.create(null),o=wg.bind(ge,a);let f=Hn;const h=Object.create(null),y=(v,S)=>{const _=h[v]||[];return h[v]=_,_.push(S),()=>_.splice(_.indexOf(S),1)},m=(v,S,_)=>{a.set(v,S);const R=h[v];if(R)for(const z of R)z(S,_)},p=()=>{if(!Bn.has(a)&&(Bn.set(a,[r,Object.create(null),Object.create(null),Object.create(null),o,m,y]),!Fl)){const v=i.initFocus(setTimeout.bind(ge,cp.bind(ge,r,Eg))),S=i.initReconnect(setTimeout.bind(ge,cp.bind(ge,r,Rg)));f=()=>{v&&v(),S&&S(),Bn.delete(a)}}};return p(),[a,o,p,f]}return[a,Bn.get(a)[4]]},wR=(a,u,i,r,o)=>{const f=i.errorRetryCount,h=o.retryCount,y=~~((Math.random()+.5)*(1<<(h<8?h:8)))*i.errorRetryInterval;!_t(f)&&h>f||setTimeout(r,y,o)},MR=Ko,[vf,xR]=Mg(new Map),xg=Gn({onLoadingSlow:Hn,onSuccess:Hn,onError:Hn,onErrorRetry:wR,onDiscarded:Hn,revalidateOnFocus:!0,revalidateOnReconnect:!0,revalidateIfStale:!0,shouldRetryOnError:!0,errorRetryInterval:rp?1e4:5e3,focusThrottleInterval:5*1e3,dedupingInterval:2*1e3,loadingTimeout:rp?5e3:3e3,compare:MR,isPaused:()=>!1,cache:vf,mutate:xR,fallback:{}},_R),zg=(a,u)=>{const i=Gn(a,u);if(u){const{use:r,fallback:o}=a,{use:f,fallback:h}=u;r&&f&&(i.use=r.concat(f)),o&&h&&(i.fallback=Gn(o,h))}return i},Io=$.createContext({}),zR=a=>{const{value:u}=a,i=$.useContext(Io),r=sn(u),o=$.useMemo(()=>r?u(i):u,[r,i,u]),f=$.useMemo(()=>r?o:zg(i,o),[r,i,o]),h=o&&o.provider,y=$.useRef(ge);h&&!y.current&&(y.current=Mg(h(f.cache||vf),o));const m=y.current;return m&&(f.cache=m[0],f.mutate=m[1]),Ds(()=>{if(m)return m[2]&&m[2](),m[3]},[]),$.createElement(Io.Provider,Gn(a,{value:f}))},CR="$inf$",Cg=lu&&window.__SWR_DEVTOOLS_USE__,DR=Cg?window.__SWR_DEVTOOLS_USE__:[],LR=()=>{Cg&&(window.__SWR_DEVTOOLS_REACT__=qn)},NR=a=>sn(a[1])?[a[0],a[1],a[2]||{}]:[a[0],null,(a[1]===null?a[2]:a[1])||{}],UR=()=>{const a=$.useContext(Io);return $.useMemo(()=>Gn(xg,a),[a])},BR=a=>(u,i,r)=>a(u,i&&((...f)=>{const[h]=gf(u),[,,,y]=Bn.get(vf);if(h.startsWith(CR))return i(...f);const m=y[h];return _t(m)?i(...f):(delete y[h],m)}),r),jR=DR.concat(BR),HR=a=>function(...i){const r=UR(),[o,f,h]=NR(i),y=zg(r,h);let m=a;const{use:p}=y,v=(p||[]).concat(jR);for(let S=v.length;S--;)m=v[S](m);return m(o,f||y.fetcher||null,y)},qR=(a,u,i)=>{const r=u[a]||(u[a]=[]);return r.push(i),()=>{const o=r.indexOf(i);o>=0&&(r[o]=r[r.length-1],r.pop())}};LR();const jo=qn.use||(a=>{switch(a.status){case"pending":throw a;case"fulfilled":return a.value;case"rejected":throw a.reason;default:throw a.status="pending",a.then(u=>{a.status="fulfilled",a.value=u},u=>{a.status="rejected",a.reason=u}),a}}),Ho={dedupe:!0},op=Promise.resolve(ge),VR=()=>Hn,YR=(a,u,i)=>{const{cache:r,compare:o,suspense:f,fallbackData:h,revalidateOnMount:y,revalidateIfStale:m,refreshInterval:p,refreshWhenHidden:v,refreshWhenOffline:S,keepPreviousData:_,strictServerPrefetchWarning:R}=i,[z,A,x,Y]=Bn.get(r),[B,Z]=gf(a),H=$.useRef(!1),k=$.useRef(!1),I=$.useRef(B),Q=$.useRef(u),X=$.useRef(i),K=()=>X.current,rt=()=>K().isVisible()&&K().isOnline(),[nt,lt,ht,it]=Og(r,B),jt=$.useRef({}).current,N=_t(h)?_t(i.fallback)?ge:i.fallback[B]:h,F=(Et,Lt)=>{for(const At in jt){const qt=At;if(qt==="data"){if(!o(Et[qt],Lt[qt])&&(!_t(Et[qt])||!o(ot,Lt[qt])))return!1}else if(Lt[qt]!==Et[qt])return!1}return!0},ut=!H.current,Tt=$.useMemo(()=>{const Et=nt(),Lt=it(),At=Jt=>{const Vt=Gn(Jt);return delete Vt._k,(()=>{if(!B||!u||K().isPaused())return!1;if(ut&&!_t(y))return y;const xt=_t(N)?Vt.data:N;return _t(xt)||m})()?{isValidating:!0,isLoading:!0,...Vt}:Vt},qt=At(Et),ve=Et===Lt?qt:At(Lt);let oe=qt;return[()=>{const Jt=At(nt());return F(Jt,oe)?(oe.data=Jt.data,oe.isLoading=Jt.isLoading,oe.isValidating=Jt.isValidating,oe.error=Jt.error,oe):(oe=Jt,Jt)},()=>ve]},[r,B]),pt=lp.useSyncExternalStore($.useCallback(Et=>ht(B,(Lt,At)=>{F(At,Lt)||Et()}),[r,B]),Tt[0],Tt[1]),w=z[B]&&z[B].length>0,q=pt.data,J=_t(q)?N&&Ag(N)?jo(N):N:q,P=pt.error,ct=$.useRef(J),ot=_?_t(q)?_t(ct.current)?J:ct.current:q:J,ft=B&&_t(J),Xt=$.useRef(null);!Fl&&lp.useSyncExternalStore(VR,()=>(Xt.current=!1,Xt),()=>(Xt.current=!0,Xt));const Ht=Xt.current;R&&Ht&&!f&&ft&&console.warn(`Missing pre-initiated data for serialized key "${B}" during server-side rendering. Data fetching should be initiated on the server and provided to SWR via fallback data. You can set "strictServerPrefetchWarning: false" to disable this warning.`);const De=!B||!u||K().isPaused()||w&&!_t(P)?!1:ut&&!_t(y)?y:f?_t(J)?!1:m:_t(J)||m,Xe=ut&&De,Qn=_t(pt.isValidating)?Xe:pt.isValidating,Ta=_t(pt.isLoading)?Xe:pt.isLoading,_e=$.useCallback(async Et=>{const Lt=Q.current;if(!B||!Lt||k.current||K().isPaused())return!1;let At,qt,ve=!0;const oe=Et||{},Jt=!x[B]||!oe.dedupe,Vt=()=>sp?!k.current&&B===I.current&&H.current:B===I.current,yn={isValidating:!1,isLoading:!1},xt=()=>{lt(yn)},$t=()=>{const fe=x[B];fe&&fe[1]===qt&&delete x[B]},ae={isValidating:!0};_t(nt().data)&&(ae.isLoading=!0);try{if(Jt&&(lt(ae),i.loadingTimeout&&_t(nt().data)&&setTimeout(()=>{ve&&Vt()&&K().onLoadingSlow(B,i)},i.loadingTimeout),x[B]=[Lt(Z),$o()]),[At,qt]=x[B],At=await At,Jt&&setTimeout($t,i.dedupingInterval),!x[B]||x[B][1]!==qt)return Jt&&Vt()&&K().onDiscarded(B),!1;yn.error=ge;const fe=A[B];if(!_t(fe)&&(qt<=fe[0]||qt<=fe[1]||fe[1]===0))return xt(),Jt&&Vt()&&K().onDiscarded(B),!1;const Qe=nt().data;yn.data=o(Qe,At)?Qe:At,Jt&&Vt()&&K().onSuccess(At,B,i)}catch(fe){$t();const Qe=K(),{shouldRetryOnError:Wl}=Qe;Qe.isPaused()||(yn.error=fe,Jt&&Vt()&&(Qe.onError(fe,B,Qe),(Wl===!0||sn(Wl)&&Wl(fe))&&(!K().revalidateOnFocus||!K().revalidateOnReconnect||rt())&&Qe.onErrorRetry(fe,B,Qe,$s=>{const pn=z[B];pn&&pn[0]&&pn[0](ip,$s)},{retryCount:(oe.retryCount||0)+1,dedupe:!0})))}return ve=!1,xt(),!0},[B,r]),mn=$.useCallback((...Et)=>wg(r,I.current,...Et),[]);if(Ds(()=>{Q.current=u,X.current=i,_t(q)||(ct.current=q)}),Ds(()=>{if(!B)return;const Et=_e.bind(ge,Ho);let Lt=0;K().revalidateOnFocus&&(Lt=Date.now()+K().focusThrottleInterval);const qt=qR(B,z,(ve,oe={})=>{if(ve==Eg){const Jt=Date.now();K().revalidateOnFocus&&Jt>Lt&&rt()&&(Lt=Jt+K().focusThrottleInterval,Et())}else if(ve==Rg)K().revalidateOnReconnect&&rt()&&Et();else{if(ve==Tg)return _e();if(ve==ip)return _e(oe)}});return k.current=!1,I.current=B,H.current=!0,lt({_k:Z}),De&&(x[B]||(_t(J)||Fl?Et():RR(Et))),()=>{k.current=!0,qt()}},[B]),Ds(()=>{let Et;function Lt(){const qt=sn(p)?p(nt().data):p;qt&&Et!==-1&&(Et=setTimeout(At,qt))}function At(){!nt().error&&(v||K().isVisible())&&(S||K().isOnline())?_e(Ho).then(Lt):Lt()}return Lt(),()=>{Et&&(clearTimeout(Et),Et=-1)}},[p,v,S,B]),$.useDebugValue(ot),f){if(!sp&&Fl&&ft)throw new Error("Fallback data is required when using Suspense in SSR.");ft&&(Q.current=u,X.current=i,k.current=!1);const Et=Y[B],Lt=!_t(Et)&&ft?mn(Et):op;if(jo(Lt),!_t(P)&&ft)throw P;const At=ft?_e(Ho):op;!_t(ot)&&ft&&(At.status="fulfilled",At.value=!0),jo(At)}return{mutate:mn,get data(){return jt.data=!0,ot},get error(){return jt.error=!0,P},get isValidating(){return jt.isValidating=!0,Qn},get isLoading(){return jt.isLoading=!0,Ta}}},GR=Xs.defineProperty(zR,"defaultValue",{value:xg}),oT=HR(YR),XR="/assets/index-DdJSLfxK.css",Dg=DE({head:()=>({meta:[{charSet:"utf-8"},{name:"viewport",content:"width=device-width, initial-scale=1"},{title:"llm-inspector"}],links:[{rel:"stylesheet",href:XR}]}),component:QR});function QR(){return W.jsx(ZR,{children:W.jsx(yg,{})})}function ZR({children:a}){return W.jsxs("html",{lang:"en",className:"dark",children:[W.jsx("head",{children:W.jsx(kE,{})}),W.jsxs("body",{children:[W.jsx(GR,{value:{revalidateOnFocus:!1,revalidateIfStale:!1},children:a}),W.jsx(FE,{})]})]})}const KR="modulepreload",JR=function(a){return"/"+a},fp={},kR=function(u,i,r){let o=Promise.resolve();if(i&&i.length>0){let m=function(p){return Promise.all(p.map(v=>Promise.resolve(v).then(S=>({status:"fulfilled",value:S}),S=>({status:"rejected",reason:S}))))};document.getElementsByTagName("link");const h=document.querySelector("meta[property=csp-nonce]"),y=h?.nonce||h?.getAttribute("nonce");o=m(i.map(p=>{if(p=JR(p),p in fp)return;fp[p]=!0;const v=p.endsWith(".css"),S=v?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${p}"]${S}`))return;const _=document.createElement("link");if(_.rel=v?"stylesheet":KR,v||(_.as="script"),_.crossOrigin="",_.href=p,y&&_.setAttribute("nonce",y),document.head.appendChild(_),v)return new Promise((R,z)=>{_.addEventListener("load",R),_.addEventListener("error",()=>z(new Error(`Unable to preload CSS for ${p}`)))})}))}function f(h){const y=new Event("vite:preloadError",{cancelable:!0});if(y.payload=h,window.dispatchEvent(y),!y.defaultPrevented)throw h}return o.then(h=>{for(const y of h||[])y.status==="rejected"&&f(y.reason);return u().catch(f)})},FR=()=>kR(()=>import("./index-BmEH5jeO.js"),[]),PR=Qo("/")({component:LE(FR,"component")}),WR=PR.update({id:"/",path:"/",getParentRoute:()=>Dg}),$R={IndexRoute:WR},IR=Dg._addFileChildren($R);function tT(){return YE({routeTree:IR,scrollRestoration:!1})}async function eT(){const a=await tT();let u;return u=[],window.__TSS_START_OPTIONS__={serializationAdapters:u},u.push(mR),a.options.serializationAdapters&&u.push(...a.options.serializationAdapters),a.update({basepath:"",serializationAdapters:u}),a.state.matches.length||await WE(a),a}async function nT(){const a=await eT();return window.$_TSR?.h(),a}let qo;function aT(){return qo||(qo=nT()),W.jsx(rE,{promise:qo,children:a=>W.jsx(QE,{router:a})})}$.startTransition(()=>{iS.hydrateRoot(document,W.jsx($.StrictMode,{children:W.jsx(aT,{})}))});export{qn as R,fg as a,I0 as b,lT as c,rT as d,dp as g,W as j,$ as r,oT as u};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, a as React } from "../_libs/react.mjs";
|
|
2
|
-
import { C as CapturedLogSchema, a as parseRequest, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-
|
|
2
|
+
import { C as CapturedLogSchema, a as parseRequest, p as parseOpenAIResponse, I as InspectorResponseSchema } from "./router-D9uLXa9A.mjs";
|
|
3
3
|
import { u as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
4
4
|
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
5
5
|
import { c as clsx } from "../_libs/clsx.mjs";
|
|
@@ -199,7 +199,7 @@ async function exportLogsAsZip(logs) {
|
|
|
199
199
|
document.body.removeChild(anchor);
|
|
200
200
|
URL.revokeObjectURL(url);
|
|
201
201
|
}
|
|
202
|
-
const version = "1.9.
|
|
202
|
+
const version = "1.9.1";
|
|
203
203
|
const packageJson = {
|
|
204
204
|
version
|
|
205
205
|
};
|
|
@@ -1726,6 +1726,7 @@ function StreamingChunkSequence({
|
|
|
1726
1726
|
const [expandedIndices, setExpandedIndices] = reactExports.useState(/* @__PURE__ */ new Set());
|
|
1727
1727
|
reactExports.useEffect(() => {
|
|
1728
1728
|
if (!containerExpanded || chunkState.status !== "idle") return;
|
|
1729
|
+
let cancelled = false;
|
|
1729
1730
|
setChunkState({ status: "loading" });
|
|
1730
1731
|
fetch(`/api/logs/${logId}/chunks`).then((res) => {
|
|
1731
1732
|
if (!res.ok) {
|
|
@@ -1733,11 +1734,18 @@ function StreamingChunkSequence({
|
|
|
1733
1734
|
}
|
|
1734
1735
|
return res.json();
|
|
1735
1736
|
}).then((data) => {
|
|
1736
|
-
|
|
1737
|
+
if (!cancelled) {
|
|
1738
|
+
setChunkState({ status: "success", chunks: data.chunks });
|
|
1739
|
+
}
|
|
1737
1740
|
}).catch(() => {
|
|
1738
|
-
|
|
1741
|
+
if (!cancelled) {
|
|
1742
|
+
setChunkState({ status: "error", message: "Chunk data unavailable" });
|
|
1743
|
+
}
|
|
1739
1744
|
});
|
|
1740
|
-
|
|
1745
|
+
return () => {
|
|
1746
|
+
cancelled = true;
|
|
1747
|
+
};
|
|
1748
|
+
}, [containerExpanded, logId]);
|
|
1741
1749
|
const groups = reactExports.useMemo(() => {
|
|
1742
1750
|
if (chunkState.status !== "success") return [];
|
|
1743
1751
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -197,7 +197,7 @@ function getResponse() {
|
|
|
197
197
|
return event.res;
|
|
198
198
|
}
|
|
199
199
|
async function getStartManifest(matchedRoutes) {
|
|
200
|
-
const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-
|
|
200
|
+
const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-ByfnNZV_.mjs");
|
|
201
201
|
const startManifest = tsrStartManifest();
|
|
202
202
|
const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
|
|
203
203
|
rootRoute.assets = rootRoute.assets || [];
|
|
@@ -766,7 +766,7 @@ let entriesPromise;
|
|
|
766
766
|
let baseManifestPromise;
|
|
767
767
|
let cachedFinalManifestPromise;
|
|
768
768
|
async function loadEntries() {
|
|
769
|
-
const routerEntry = await import("./router-
|
|
769
|
+
const routerEntry = await import("./router-D9uLXa9A.mjs").then((n) => n.r);
|
|
770
770
|
const startEntry = await import("./start-HYkvq4Ni.mjs");
|
|
771
771
|
return { startEntry, routerEntry };
|
|
772
772
|
}
|
|
@@ -3,7 +3,7 @@ import { j as jsxRuntimeExports } from "../_libs/react.mjs";
|
|
|
3
3
|
import { S as SWRConfig } from "../_libs/swr.mjs";
|
|
4
4
|
import { mkdirSync, writeFileSync, renameSync, copyFileSync, unlinkSync, existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import path, { join, isAbsolute, dirname } from "node:path";
|
|
6
|
-
import { mkdir, appendFile, readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import { mkdir, appendFile, readFile, writeFile, readdir, stat, unlink } from "node:fs/promises";
|
|
7
7
|
import { C as Conf } from "../_libs/conf.mjs";
|
|
8
8
|
import { randomUUID } from "crypto";
|
|
9
9
|
import { exec } from "node:child_process";
|
|
@@ -68,12 +68,12 @@ function RootDocument({ children }) {
|
|
|
68
68
|
] })
|
|
69
69
|
] });
|
|
70
70
|
}
|
|
71
|
-
const $$splitComponentImporter = () => import("./index-
|
|
71
|
+
const $$splitComponentImporter = () => import("./index-D0d6QxPt.mjs");
|
|
72
72
|
const Route$f = createFileRoute("/")({
|
|
73
73
|
component: lazyRouteComponent($$splitComponentImporter, "component")
|
|
74
74
|
});
|
|
75
75
|
const LOG_DIR_ENV = process.env["LOG_DIR"];
|
|
76
|
-
Number(process.env["LOG_RETENTION_DAYS"] ?? "7");
|
|
76
|
+
const RETENTION_DAYS = Number(process.env["LOG_RETENTION_DAYS"] ?? "7");
|
|
77
77
|
const LOG_FILE_ENV = process.env["LLM_INSPECTOR_LOG_FILE"];
|
|
78
78
|
function getUserDataDir() {
|
|
79
79
|
if (process.platform === "win32") {
|
|
@@ -106,6 +106,27 @@ function getInspectorLogPath() {
|
|
|
106
106
|
const base = getUserDataDir();
|
|
107
107
|
return path.join(base, ".llm-inspector", "logs", "inspector.log");
|
|
108
108
|
}
|
|
109
|
+
async function initLogger() {
|
|
110
|
+
const dir = resolveLogDir();
|
|
111
|
+
const retentionMs = RETENTION_DAYS * 24 * 60 * 60 * 1e3;
|
|
112
|
+
const cutoff = Date.now() - retentionMs;
|
|
113
|
+
try {
|
|
114
|
+
const entries = await readdir(dir);
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
if (!entry.endsWith(".jsonl")) continue;
|
|
117
|
+
const fullPath = path.join(dir, entry);
|
|
118
|
+
try {
|
|
119
|
+
const s = await stat(fullPath);
|
|
120
|
+
if (s.mtimeMs < cutoff) {
|
|
121
|
+
await unlink(fullPath);
|
|
122
|
+
}
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (err) {
|
|
127
|
+
console.error("[logger] Failed to initialize log directory:", err);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
109
130
|
async function writeAppLog(message) {
|
|
110
131
|
try {
|
|
111
132
|
const logPath = getInspectorLogPath();
|
|
@@ -114,7 +135,8 @@ async function writeAppLog(message) {
|
|
|
114
135
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
115
136
|
await appendFile(logPath, `[${timestamp}] ${message}
|
|
116
137
|
`, "utf-8");
|
|
117
|
-
} catch {
|
|
138
|
+
} catch (err) {
|
|
139
|
+
console.error(`[logger] Failed to write to ${getInspectorLogPath()}:`, err);
|
|
118
140
|
}
|
|
119
141
|
}
|
|
120
142
|
const logger = {
|
|
@@ -149,7 +171,8 @@ async function flushWriteBuffer() {
|
|
|
149
171
|
const filePath = getLogFilePath();
|
|
150
172
|
await mkdir(path.dirname(filePath), { recursive: true });
|
|
151
173
|
await appendFile(filePath, toWrite, "utf-8");
|
|
152
|
-
} catch {
|
|
174
|
+
} catch (err) {
|
|
175
|
+
console.error("[logger] Failed to flush write buffer:", err);
|
|
153
176
|
} finally {
|
|
154
177
|
isFlushing = false;
|
|
155
178
|
}
|
|
@@ -251,12 +274,30 @@ async function findInIndex(id) {
|
|
|
251
274
|
const index = await loadIndex();
|
|
252
275
|
return index.entries[id] ?? null;
|
|
253
276
|
}
|
|
254
|
-
let
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
277
|
+
let idGenerationPromise = null;
|
|
278
|
+
let releaseLock = null;
|
|
279
|
+
async function acquireLock() {
|
|
280
|
+
if (releaseLock === null) {
|
|
281
|
+
idGenerationPromise = new Promise((resolve) => {
|
|
282
|
+
releaseLock = resolve;
|
|
283
|
+
});
|
|
284
|
+
} else {
|
|
285
|
+
await idGenerationPromise;
|
|
286
|
+
idGenerationPromise = new Promise((resolve) => {
|
|
287
|
+
releaseLock = resolve;
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function releaseLockFn() {
|
|
292
|
+
if (releaseLock) {
|
|
293
|
+
const resolve = releaseLock;
|
|
294
|
+
releaseLock = null;
|
|
295
|
+
idGenerationPromise = null;
|
|
296
|
+
resolve();
|
|
258
297
|
}
|
|
259
|
-
|
|
298
|
+
}
|
|
299
|
+
async function getNextLogId() {
|
|
300
|
+
await acquireLock();
|
|
260
301
|
try {
|
|
261
302
|
const index = await loadIndex();
|
|
262
303
|
const nextId = index.maxId + 1;
|
|
@@ -264,7 +305,7 @@ async function getNextLogId() {
|
|
|
264
305
|
cachedIndex = index;
|
|
265
306
|
return nextId;
|
|
266
307
|
} finally {
|
|
267
|
-
|
|
308
|
+
releaseLockFn();
|
|
268
309
|
}
|
|
269
310
|
}
|
|
270
311
|
function getCurrentLogFile() {
|
|
@@ -877,8 +918,7 @@ async function getLogById(id) {
|
|
|
877
918
|
return null;
|
|
878
919
|
}
|
|
879
920
|
function getFilteredLogs(sessionId, model) {
|
|
880
|
-
|
|
881
|
-
return cachedLogs.filter((l) => {
|
|
921
|
+
return [...memoryCache.values()].filter((l) => {
|
|
882
922
|
if (sessionId !== void 0 && l.sessionId !== sessionId) return false;
|
|
883
923
|
if (model !== void 0 && l.model !== model) return false;
|
|
884
924
|
return true;
|
|
@@ -915,13 +955,17 @@ function onLogUpdate(handler) {
|
|
|
915
955
|
};
|
|
916
956
|
}
|
|
917
957
|
function emitLogUpdate(log) {
|
|
958
|
+
const failedHandlers = [];
|
|
918
959
|
for (const handler of sseHandlers) {
|
|
919
960
|
try {
|
|
920
961
|
handler(log);
|
|
921
962
|
} catch {
|
|
922
|
-
|
|
963
|
+
failedHandlers.push(handler);
|
|
923
964
|
}
|
|
924
965
|
}
|
|
966
|
+
for (const handler of failedHandlers) {
|
|
967
|
+
sseHandlers.delete(handler);
|
|
968
|
+
}
|
|
925
969
|
}
|
|
926
970
|
const DEFAULT_UPSTREAM$1 = "https://api.anthropic.com";
|
|
927
971
|
const DEFAULT_OPENAI_UPSTREAM$1 = "https://api.openai.com/v1";
|
|
@@ -1858,6 +1902,11 @@ async function getClientInfo(request) {
|
|
|
1858
1902
|
setCache(port, info);
|
|
1859
1903
|
return info;
|
|
1860
1904
|
}
|
|
1905
|
+
initLogger().then(() => {
|
|
1906
|
+
logger.info("Proxy handler initialized");
|
|
1907
|
+
}).catch((err) => {
|
|
1908
|
+
console.error("[handler] Logger initialization failed:", err);
|
|
1909
|
+
});
|
|
1861
1910
|
function buildProxyHeaders(originalHeaders) {
|
|
1862
1911
|
const rawHeaders = {};
|
|
1863
1912
|
const headers = new Headers();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/api/config/paths"], "preloads": ["/assets/main-
|
|
1
|
+
const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/health", "/api/logs", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/api/config/paths"], "preloads": ["/assets/main-GVpFMVGE.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-BmEH5jeO.js"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.import.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts" } }, "clientEntry": "/assets/main-GVpFMVGE.js" });
|
|
2
2
|
export {
|
|
3
3
|
tsrStartManifest
|
|
4
4
|
};
|
package/.output/server/index.mjs
CHANGED
|
@@ -97,54 +97,54 @@ const headers = ((m) => function headersRouteRule(event) {
|
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
const assets = {
|
|
100
|
+
"/assets/index-DdJSLfxK.css": {
|
|
101
|
+
"type": "text/css; charset=utf-8",
|
|
102
|
+
"etag": '"10da0-LYeZ5d/vwqh4bAnuP/9hr6Wka6g"',
|
|
103
|
+
"mtime": "2026-06-04T06:33:11.914Z",
|
|
104
|
+
"size": 69024,
|
|
105
|
+
"path": "../public/assets/index-DdJSLfxK.css"
|
|
106
|
+
},
|
|
100
107
|
"/assets/alibaba-TTwafVwX.svg": {
|
|
101
108
|
"type": "image/svg+xml",
|
|
102
109
|
"etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
|
|
103
|
-
"mtime": "2026-06-
|
|
110
|
+
"mtime": "2026-06-04T06:33:11.914Z",
|
|
104
111
|
"size": 5915,
|
|
105
112
|
"path": "../public/assets/alibaba-TTwafVwX.svg"
|
|
106
113
|
},
|
|
107
|
-
"/assets/
|
|
108
|
-
"type": "
|
|
109
|
-
"etag": '"
|
|
110
|
-
"mtime": "2026-06-
|
|
111
|
-
"size":
|
|
112
|
-
"path": "../public/assets/
|
|
114
|
+
"/assets/qwen-CONDcHqt.png": {
|
|
115
|
+
"type": "image/png",
|
|
116
|
+
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
117
|
+
"mtime": "2026-06-04T06:33:11.914Z",
|
|
118
|
+
"size": 357059,
|
|
119
|
+
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
113
120
|
},
|
|
114
121
|
"/assets/minimax-BPMzvuL-.jpeg": {
|
|
115
122
|
"type": "image/jpeg",
|
|
116
123
|
"etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
|
|
117
|
-
"mtime": "2026-06-
|
|
124
|
+
"mtime": "2026-06-04T06:33:11.914Z",
|
|
118
125
|
"size": 6918,
|
|
119
126
|
"path": "../public/assets/minimax-BPMzvuL-.jpeg"
|
|
120
127
|
},
|
|
128
|
+
"/assets/main-GVpFMVGE.js": {
|
|
129
|
+
"type": "text/javascript; charset=utf-8",
|
|
130
|
+
"etag": '"50591-hoJGkyrSE5hjQqC3+NP6Sje9YUs"',
|
|
131
|
+
"mtime": "2026-06-04T06:33:11.914Z",
|
|
132
|
+
"size": 329105,
|
|
133
|
+
"path": "../public/assets/main-GVpFMVGE.js"
|
|
134
|
+
},
|
|
121
135
|
"/assets/zhipuai-BPNAnxo-.svg": {
|
|
122
136
|
"type": "image/svg+xml",
|
|
123
137
|
"etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
|
|
124
|
-
"mtime": "2026-06-
|
|
138
|
+
"mtime": "2026-06-04T06:33:11.914Z",
|
|
125
139
|
"size": 11256,
|
|
126
140
|
"path": "../public/assets/zhipuai-BPNAnxo-.svg"
|
|
127
141
|
},
|
|
128
|
-
"/assets/
|
|
129
|
-
"type": "text/javascript; charset=utf-8",
|
|
130
|
-
"etag": '"50591-/K5L0AnXTcumA7dHm7kmA5HXlCE"',
|
|
131
|
-
"mtime": "2026-06-04T03:52:13.283Z",
|
|
132
|
-
"size": 329105,
|
|
133
|
-
"path": "../public/assets/main-Cu0oTDfX.js"
|
|
134
|
-
},
|
|
135
|
-
"/assets/qwen-CONDcHqt.png": {
|
|
136
|
-
"type": "image/png",
|
|
137
|
-
"etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
|
|
138
|
-
"mtime": "2026-06-04T03:52:13.283Z",
|
|
139
|
-
"size": 357059,
|
|
140
|
-
"path": "../public/assets/qwen-CONDcHqt.png"
|
|
141
|
-
},
|
|
142
|
-
"/assets/index-DyKLPMPn.js": {
|
|
142
|
+
"/assets/index-BmEH5jeO.js": {
|
|
143
143
|
"type": "text/javascript; charset=utf-8",
|
|
144
|
-
"etag": '"
|
|
145
|
-
"mtime": "2026-06-
|
|
146
|
-
"size":
|
|
147
|
-
"path": "../public/assets/index-
|
|
144
|
+
"etag": '"84a50-Thjv3JmUhqN6aR4NbGQypCxkmgY"',
|
|
145
|
+
"mtime": "2026-06-04T06:33:11.914Z",
|
|
146
|
+
"size": 543312,
|
|
147
|
+
"path": "../public/assets/index-BmEH5jeO.js"
|
|
148
148
|
}
|
|
149
149
|
};
|
|
150
150
|
function readAsset(id) {
|
package/package.json
CHANGED
|
@@ -31,6 +31,7 @@ export function StreamingChunkSequence({
|
|
|
31
31
|
useEffect(() => {
|
|
32
32
|
if (!containerExpanded || chunkState.status !== "idle") return;
|
|
33
33
|
|
|
34
|
+
let cancelled = false;
|
|
34
35
|
setChunkState({ status: "loading" });
|
|
35
36
|
|
|
36
37
|
fetch(`/api/logs/${logId}/chunks`)
|
|
@@ -41,12 +42,20 @@ export function StreamingChunkSequence({
|
|
|
41
42
|
return res.json();
|
|
42
43
|
})
|
|
43
44
|
.then((data: { chunks: StreamingChunk[]; truncated?: boolean }) => {
|
|
44
|
-
|
|
45
|
+
if (!cancelled) {
|
|
46
|
+
setChunkState({ status: "success", chunks: data.chunks });
|
|
47
|
+
}
|
|
45
48
|
})
|
|
46
49
|
.catch(() => {
|
|
47
|
-
|
|
50
|
+
if (!cancelled) {
|
|
51
|
+
setChunkState({ status: "error", message: "Chunk data unavailable" });
|
|
52
|
+
}
|
|
48
53
|
});
|
|
49
|
-
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
cancelled = true;
|
|
57
|
+
};
|
|
58
|
+
}, [containerExpanded, logId]);
|
|
50
59
|
|
|
51
60
|
const groups = useMemo<ChunkGroup[]>(() => {
|
|
52
61
|
if (chunkState.status !== "success") return [];
|
package/src/proxy/handler.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createLog, emitLogUpdate, type CapturedLog } from "./store";
|
|
2
|
-
import { appendLogEntry, logger } from "./logger";
|
|
2
|
+
import { appendLogEntry, initLogger, logger } from "./logger";
|
|
3
3
|
import { writeChunks } from "./chunkStorage";
|
|
4
4
|
import { extractModelFromBody, type RequestFormat } from "./schemas";
|
|
5
5
|
import { registry } from "./formats";
|
|
@@ -28,6 +28,16 @@ import {
|
|
|
28
28
|
STATUS_BAD_GATEWAY,
|
|
29
29
|
} from "./constants";
|
|
30
30
|
|
|
31
|
+
// Initialize logger at startup
|
|
32
|
+
initLogger()
|
|
33
|
+
.then(() => {
|
|
34
|
+
logger.info("Proxy handler initialized");
|
|
35
|
+
})
|
|
36
|
+
.catch((err) => {
|
|
37
|
+
// eslint-disable-next-line no-console
|
|
38
|
+
console.error("[handler] Logger initialization failed:", err);
|
|
39
|
+
});
|
|
40
|
+
|
|
31
41
|
/**
|
|
32
42
|
* Strips all custom/non-standard headers from the request and replaces with
|
|
33
43
|
* unified proxy identity. Only preserves standard HTTP headers needed for API calls.
|
package/src/proxy/logIndex.ts
CHANGED
|
@@ -201,16 +201,37 @@ export async function rebuildIndex(): Promise<LogIndex> {
|
|
|
201
201
|
return newIndex;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
//
|
|
205
|
-
|
|
204
|
+
// Async mutex for atomic ID generation to prevent race conditions
|
|
205
|
+
// Uses a promise queue instead of busy-waiting
|
|
206
|
+
let idGenerationPromise: Promise<void> | null = null;
|
|
207
|
+
let releaseLock: (() => void) | null = null;
|
|
208
|
+
|
|
209
|
+
async function acquireLock(): Promise<void> {
|
|
210
|
+
if (releaseLock === null) {
|
|
211
|
+
idGenerationPromise = new Promise<void>((resolve) => {
|
|
212
|
+
releaseLock = resolve;
|
|
213
|
+
});
|
|
214
|
+
} else {
|
|
215
|
+
// Wait for the previous lock to be released
|
|
216
|
+
await idGenerationPromise;
|
|
217
|
+
// After waiting, we need to create a new promise for the next waiter
|
|
218
|
+
idGenerationPromise = new Promise<void>((resolve) => {
|
|
219
|
+
releaseLock = resolve;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
206
223
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
224
|
+
function releaseLockFn(): void {
|
|
225
|
+
if (releaseLock) {
|
|
226
|
+
const resolve = releaseLock;
|
|
227
|
+
releaseLock = null;
|
|
228
|
+
idGenerationPromise = null;
|
|
229
|
+
resolve();
|
|
212
230
|
}
|
|
213
|
-
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export async function getNextLogId(): Promise<number> {
|
|
234
|
+
await acquireLock();
|
|
214
235
|
try {
|
|
215
236
|
const index = await loadIndex();
|
|
216
237
|
const nextId = index.maxId + 1;
|
|
@@ -219,7 +240,7 @@ export async function getNextLogId(): Promise<number> {
|
|
|
219
240
|
cachedIndex = index;
|
|
220
241
|
return nextId;
|
|
221
242
|
} finally {
|
|
222
|
-
|
|
243
|
+
releaseLockFn();
|
|
223
244
|
}
|
|
224
245
|
}
|
|
225
246
|
|
package/src/proxy/logger.ts
CHANGED
|
@@ -60,11 +60,13 @@ export async function initLogger(): Promise<void> {
|
|
|
60
60
|
await unlink(fullPath);
|
|
61
61
|
}
|
|
62
62
|
} catch {
|
|
63
|
-
// Skip files that can't be stat
|
|
63
|
+
// Skip files that can't be stat - not critical
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
} catch {
|
|
67
|
-
//
|
|
66
|
+
} catch (err) {
|
|
67
|
+
// Log directory initialization errors but don't fail startup
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
69
|
+
console.error("[logger] Failed to initialize log directory:", err);
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
72
|
|
|
@@ -76,8 +78,10 @@ async function writeAppLog(message: string): Promise<void> {
|
|
|
76
78
|
await mkdir(logDirPath, { recursive: true });
|
|
77
79
|
const timestamp = new Date().toISOString();
|
|
78
80
|
await appendFile(logPath, `[${timestamp}] ${message}\n`, "utf-8");
|
|
79
|
-
} catch {
|
|
80
|
-
//
|
|
81
|
+
} catch (err) {
|
|
82
|
+
// Log to stderr since file logging failed
|
|
83
|
+
// eslint-disable-next-line no-console
|
|
84
|
+
console.error(`[logger] Failed to write to ${getInspectorLogPath()}:`, err);
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
|
|
@@ -119,8 +123,10 @@ async function flushWriteBuffer(): Promise<void> {
|
|
|
119
123
|
const filePath = getLogFilePath();
|
|
120
124
|
await mkdir(path.dirname(filePath), { recursive: true });
|
|
121
125
|
await appendFile(filePath, toWrite, "utf-8");
|
|
122
|
-
} catch {
|
|
123
|
-
//
|
|
126
|
+
} catch (err) {
|
|
127
|
+
// Log write buffer errors but don't throw to prevent cascading failures
|
|
128
|
+
// eslint-disable-next-line no-console
|
|
129
|
+
console.error("[logger] Failed to flush write buffer:", err);
|
|
124
130
|
} finally {
|
|
125
131
|
isFlushing = false;
|
|
126
132
|
}
|
package/src/proxy/store.ts
CHANGED
|
@@ -266,9 +266,8 @@ export async function getLogById(id: number): Promise<CapturedLog | null> {
|
|
|
266
266
|
|
|
267
267
|
export function getFilteredLogs(sessionId?: string, model?: string): CapturedLog[] {
|
|
268
268
|
// Cache maintains insertion order (sorted by ID since logs are added in ID order)
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
return cachedLogs.filter((l) => {
|
|
269
|
+
// Use spread instead of Array.from for slightly better performance
|
|
270
|
+
return [...memoryCache.values()].filter((l) => {
|
|
272
271
|
if (sessionId !== undefined && l.sessionId !== sessionId) return false;
|
|
273
272
|
if (model !== undefined && l.model !== model) return false;
|
|
274
273
|
return true;
|
|
@@ -385,12 +384,17 @@ export function onLogUpdate(handler: LogUpdateHandler): () => void {
|
|
|
385
384
|
}
|
|
386
385
|
|
|
387
386
|
export function emitLogUpdate(log: CapturedLog): void {
|
|
387
|
+
const failedHandlers: LogUpdateHandler[] = [];
|
|
388
388
|
for (const handler of sseHandlers) {
|
|
389
389
|
try {
|
|
390
390
|
handler(log);
|
|
391
391
|
} catch {
|
|
392
|
-
//
|
|
393
|
-
|
|
392
|
+
// Collect failed handlers to remove after iteration
|
|
393
|
+
failedHandlers.push(handler);
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
|
+
// Remove failed handlers after iteration to avoid Set mutation during for...of
|
|
397
|
+
for (const handler of failedHandlers) {
|
|
398
|
+
sseHandlers.delete(handler);
|
|
399
|
+
}
|
|
396
400
|
}
|