aigetwey 1.4.0 → 1.4.2

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.
Files changed (145) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dashboard/.next/BUILD_ID +1 -1
  3. package/dashboard/.next/build-manifest.json +3 -3
  4. package/dashboard/.next/diagnostics/route-bundle-stats.json +4 -4
  5. package/dashboard/.next/fallback-build-manifest.json +3 -3
  6. package/dashboard/.next/server/app/(console)/providers/[id]/page_client-reference-manifest.js +1 -1
  7. package/dashboard/.next/server/app/(console)/providers/page_client-reference-manifest.js +1 -1
  8. package/dashboard/.next/server/app/_global-error.html +1 -1
  9. package/dashboard/.next/server/app/_global-error.rsc +1 -1
  10. package/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/dashboard/.next/server/app/_not-found.html +1 -1
  16. package/dashboard/.next/server/app/_not-found.rsc +1 -1
  17. package/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  18. package/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  20. package/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  23. package/dashboard/.next/server/app/combos.html +1 -1
  24. package/dashboard/.next/server/app/combos.rsc +1 -1
  25. package/dashboard/.next/server/app/combos.segments/!KGNvbnNvbGUp/combos/__PAGE__.segment.rsc +1 -1
  26. package/dashboard/.next/server/app/combos.segments/!KGNvbnNvbGUp/combos.segment.rsc +1 -1
  27. package/dashboard/.next/server/app/combos.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  28. package/dashboard/.next/server/app/combos.segments/_full.segment.rsc +1 -1
  29. package/dashboard/.next/server/app/combos.segments/_head.segment.rsc +1 -1
  30. package/dashboard/.next/server/app/combos.segments/_index.segment.rsc +1 -1
  31. package/dashboard/.next/server/app/combos.segments/_tree.segment.rsc +1 -1
  32. package/dashboard/.next/server/app/config.html +1 -1
  33. package/dashboard/.next/server/app/config.rsc +1 -1
  34. package/dashboard/.next/server/app/config.segments/!KGNvbnNvbGUp/config/__PAGE__.segment.rsc +1 -1
  35. package/dashboard/.next/server/app/config.segments/!KGNvbnNvbGUp/config.segment.rsc +1 -1
  36. package/dashboard/.next/server/app/config.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  37. package/dashboard/.next/server/app/config.segments/_full.segment.rsc +1 -1
  38. package/dashboard/.next/server/app/config.segments/_head.segment.rsc +1 -1
  39. package/dashboard/.next/server/app/config.segments/_index.segment.rsc +1 -1
  40. package/dashboard/.next/server/app/config.segments/_tree.segment.rsc +1 -1
  41. package/dashboard/.next/server/app/console.html +1 -1
  42. package/dashboard/.next/server/app/console.rsc +1 -1
  43. package/dashboard/.next/server/app/console.segments/!KGNvbnNvbGUp/console/__PAGE__.segment.rsc +1 -1
  44. package/dashboard/.next/server/app/console.segments/!KGNvbnNvbGUp/console.segment.rsc +1 -1
  45. package/dashboard/.next/server/app/console.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  46. package/dashboard/.next/server/app/console.segments/_full.segment.rsc +1 -1
  47. package/dashboard/.next/server/app/console.segments/_head.segment.rsc +1 -1
  48. package/dashboard/.next/server/app/console.segments/_index.segment.rsc +1 -1
  49. package/dashboard/.next/server/app/console.segments/_tree.segment.rsc +1 -1
  50. package/dashboard/.next/server/app/endpoint.html +1 -1
  51. package/dashboard/.next/server/app/endpoint.rsc +1 -1
  52. package/dashboard/.next/server/app/endpoint.segments/!KGNvbnNvbGUp/endpoint/__PAGE__.segment.rsc +1 -1
  53. package/dashboard/.next/server/app/endpoint.segments/!KGNvbnNvbGUp/endpoint.segment.rsc +1 -1
  54. package/dashboard/.next/server/app/endpoint.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  55. package/dashboard/.next/server/app/endpoint.segments/_full.segment.rsc +1 -1
  56. package/dashboard/.next/server/app/endpoint.segments/_head.segment.rsc +1 -1
  57. package/dashboard/.next/server/app/endpoint.segments/_index.segment.rsc +1 -1
  58. package/dashboard/.next/server/app/endpoint.segments/_tree.segment.rsc +1 -1
  59. package/dashboard/.next/server/app/index.html +1 -1
  60. package/dashboard/.next/server/app/index.rsc +1 -1
  61. package/dashboard/.next/server/app/index.segments/!KGNvbnNvbGUp/__PAGE__.segment.rsc +1 -1
  62. package/dashboard/.next/server/app/index.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  63. package/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
  64. package/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  65. package/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
  66. package/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  67. package/dashboard/.next/server/app/keys.html +1 -1
  68. package/dashboard/.next/server/app/keys.rsc +1 -1
  69. package/dashboard/.next/server/app/keys.segments/!KGNvbnNvbGUp/keys/__PAGE__.segment.rsc +1 -1
  70. package/dashboard/.next/server/app/keys.segments/!KGNvbnNvbGUp/keys.segment.rsc +1 -1
  71. package/dashboard/.next/server/app/keys.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  72. package/dashboard/.next/server/app/keys.segments/_full.segment.rsc +1 -1
  73. package/dashboard/.next/server/app/keys.segments/_head.segment.rsc +1 -1
  74. package/dashboard/.next/server/app/keys.segments/_index.segment.rsc +1 -1
  75. package/dashboard/.next/server/app/keys.segments/_tree.segment.rsc +1 -1
  76. package/dashboard/.next/server/app/login.html +1 -1
  77. package/dashboard/.next/server/app/login.rsc +1 -1
  78. package/dashboard/.next/server/app/login.segments/_full.segment.rsc +1 -1
  79. package/dashboard/.next/server/app/login.segments/_head.segment.rsc +1 -1
  80. package/dashboard/.next/server/app/login.segments/_index.segment.rsc +1 -1
  81. package/dashboard/.next/server/app/login.segments/_tree.segment.rsc +1 -1
  82. package/dashboard/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  83. package/dashboard/.next/server/app/login.segments/login.segment.rsc +1 -1
  84. package/dashboard/.next/server/app/providers.html +1 -1
  85. package/dashboard/.next/server/app/providers.rsc +2 -2
  86. package/dashboard/.next/server/app/providers.segments/!KGNvbnNvbGUp/providers/__PAGE__.segment.rsc +2 -2
  87. package/dashboard/.next/server/app/providers.segments/!KGNvbnNvbGUp/providers.segment.rsc +1 -1
  88. package/dashboard/.next/server/app/providers.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  89. package/dashboard/.next/server/app/providers.segments/_full.segment.rsc +2 -2
  90. package/dashboard/.next/server/app/providers.segments/_head.segment.rsc +1 -1
  91. package/dashboard/.next/server/app/providers.segments/_index.segment.rsc +1 -1
  92. package/dashboard/.next/server/app/providers.segments/_tree.segment.rsc +1 -1
  93. package/dashboard/.next/server/app/quota.html +1 -1
  94. package/dashboard/.next/server/app/quota.rsc +1 -1
  95. package/dashboard/.next/server/app/quota.segments/!KGNvbnNvbGUp/quota/__PAGE__.segment.rsc +1 -1
  96. package/dashboard/.next/server/app/quota.segments/!KGNvbnNvbGUp/quota.segment.rsc +1 -1
  97. package/dashboard/.next/server/app/quota.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  98. package/dashboard/.next/server/app/quota.segments/_full.segment.rsc +1 -1
  99. package/dashboard/.next/server/app/quota.segments/_head.segment.rsc +1 -1
  100. package/dashboard/.next/server/app/quota.segments/_index.segment.rsc +1 -1
  101. package/dashboard/.next/server/app/quota.segments/_tree.segment.rsc +1 -1
  102. package/dashboard/.next/server/app/tools.html +1 -1
  103. package/dashboard/.next/server/app/tools.rsc +1 -1
  104. package/dashboard/.next/server/app/tools.segments/!KGNvbnNvbGUp/tools/__PAGE__.segment.rsc +1 -1
  105. package/dashboard/.next/server/app/tools.segments/!KGNvbnNvbGUp/tools.segment.rsc +1 -1
  106. package/dashboard/.next/server/app/tools.segments/!KGNvbnNvbGUp.segment.rsc +1 -1
  107. package/dashboard/.next/server/app/tools.segments/_full.segment.rsc +1 -1
  108. package/dashboard/.next/server/app/tools.segments/_head.segment.rsc +1 -1
  109. package/dashboard/.next/server/app/tools.segments/_index.segment.rsc +1 -1
  110. package/dashboard/.next/server/app/tools.segments/_tree.segment.rsc +1 -1
  111. package/dashboard/.next/server/chunks/[root-of-the-server]__07euc03._.js.map +1 -1
  112. package/dashboard/.next/server/chunks/[root-of-the-server]__0uqpr_c._.js.map +1 -1
  113. package/dashboard/.next/server/chunks/ssr/_0p90gyy._.js.map +1 -1
  114. package/dashboard/.next/server/chunks/ssr/_1mumvwn._.js.map +1 -1
  115. package/dashboard/.next/server/chunks/ssr/src_components_ProviderDetail_tsx_06sxu0r._.js +1 -1
  116. package/dashboard/.next/server/chunks/ssr/src_components_ProviderDetail_tsx_06sxu0r._.js.map +1 -1
  117. package/dashboard/.next/server/chunks/ssr/src_components_ProviderManager_tsx_09d2dzw._.js +1 -1
  118. package/dashboard/.next/server/chunks/ssr/src_components_ProviderManager_tsx_09d2dzw._.js.map +1 -1
  119. package/dashboard/.next/server/middleware-build-manifest.js +3 -3
  120. package/dashboard/.next/server/pages/404.html +1 -1
  121. package/dashboard/.next/server/pages/500.html +1 -1
  122. package/dashboard/.next/static/chunks/{0pf-u__m67vld.js → 03xhjt1ta90pp.js} +1 -1
  123. package/dashboard/.next/static/chunks/{3y0b8yet0vgwr.js → 15d148buj9byd.js} +1 -1
  124. package/dashboard/.next/trace +1 -1
  125. package/dashboard/.next/trace-build +1 -1
  126. package/dashboard/src/components/ProviderDetail.tsx +10 -5
  127. package/dashboard/src/components/ProviderManager.tsx +7 -3
  128. package/dashboard/src/lib/client.ts +1 -0
  129. package/dashboard/src/lib/gateway.ts +2 -1
  130. package/dist/cli.js +10 -4
  131. package/dist/cli.js.map +1 -1
  132. package/dist/config.js +1 -0
  133. package/dist/config.js.map +1 -1
  134. package/dist/headroom/process.js +22 -6
  135. package/dist/headroom/process.js.map +1 -1
  136. package/dist/routes/admin.js +1 -0
  137. package/dist/routes/admin.js.map +1 -1
  138. package/package.json +1 -1
  139. package/src/cli.ts +8 -4
  140. package/src/config.ts +2 -0
  141. package/src/headroom/process.ts +19 -5
  142. package/src/routes/admin.ts +2 -0
  143. /package/dashboard/.next/static/{WxqdtupTIrBh47rvaXxLB → jKcczqYA93-Kuqa9A9H9h}/_buildManifest.js +0 -0
  144. /package/dashboard/.next/static/{WxqdtupTIrBh47rvaXxLB → jKcczqYA93-Kuqa9A9H9h}/_clientMiddlewareManifest.js +0 -0
  145. /package/dashboard/.next/static/{WxqdtupTIrBh47rvaXxLB → jKcczqYA93-Kuqa9A9H9h}/_ssgManifest.js +0 -0
@@ -1,3 +1,3 @@
1
- module.exports=[33410,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(50944),e=a.i(56173),f=a.i(47153),g=a.i(2693),h=a.i(2799),i=a.i(85732),j=a.i(7078),k=a.i(93026),l=a.i(58918);function m({checked:a,indeterminate:c,onChange:d,className:e,ariaLabel:f}){let g=a||c;return(0,b.jsx)("button",{type:"button",role:"checkbox","aria-checked":c?"mixed":a,"aria-label":f,onClick:a=>{a.stopPropagation(),d()},className:`flex h-[18px] w-[18px] flex-none items-center justify-center rounded-[5px] border transition-colors ${g?"border-accent bg-accent text-accent-ink":"border-border bg-bg text-transparent hover:border-text-subtle"}${e?` ${e}`:""}`,children:(0,b.jsx)(k.Icon,{name:c?"remove":"check",size:13})})}function n({models:a,busy:d,onAdd:e,onClose:f}){let[g,h]=(0,c.useState)(""),[i,l]=(0,c.useState)(()=>new Set(a.filter(a=>!a.added).map(a=>a.id))),o=(0,c.useMemo)(()=>{let b=g.trim().toLowerCase();return b?a.filter(a=>a.id.toLowerCase().includes(b)):a},[a,g]);function p(a){l(b=>{let c=new Set(b);return c.has(a)?c.delete(a):c.add(a),c})}let q=o.filter(a=>i.has(a.id)).length,r=o.length>0&&q===o.length;function s(){l(a=>{let b=new Set(a);return r?o.forEach(a=>b.delete(a.id)):o.forEach(a=>b.add(a.id)),b})}return(0,b.jsx)("div",{className:"fixed inset-0 z-50 grid place-items-center bg-black/50 p-6",onClick:f,children:(0,b.jsxs)("div",{className:"flex max-h-[80vh] w-full max-w-[480px] flex-col overflow-hidden rounded-brand-lg border border-border bg-surface shadow-elevated",onClick:a=>a.stopPropagation(),children:[(0,b.jsxs)("header",{className:"flex items-center justify-between border-b border-border-subtle px-4 py-3",children:[(0,b.jsxs)("span",{className:"text-[14px] font-semibold text-text",children:[a.length," models found"]}),(0,b.jsx)("button",{onClick:f,className:"text-text-subtle hover:text-text","aria-label":"Close",children:(0,b.jsx)(k.Icon,{name:"close",size:18})})]}),(0,b.jsx)("div",{className:"border-b border-border-subtle px-4 py-2.5",children:(0,b.jsx)(j.Input,{value:g,onChange:a=>h(a.target.value),placeholder:"filter…",autoFocus:!0})}),o.length>0&&(0,b.jsxs)("button",{onClick:s,className:"flex items-center gap-2.5 border-b border-border-subtle px-4 py-2 text-left hover:bg-surface-2",children:[(0,b.jsx)(m,{checked:r,indeterminate:q>0&&!r,onChange:s,ariaLabel:"Select all"}),(0,b.jsxs)("span",{className:"text-[12.5px] font-medium text-text",children:["Select all",g?" (filtered)":""]}),(0,b.jsxs)("span",{className:"ml-auto tnum text-[11px] text-text-subtle",children:[q,"/",o.length]})]}),(0,b.jsx)("div",{className:"flex-1 overflow-y-auto px-2 py-2",children:0===o.length?(0,b.jsx)("div",{className:"px-2 py-6 text-center text-[13px] text-text-muted",children:"No matches."}):o.map(a=>{let c=i.has(a.id);return(0,b.jsxs)("button",{onClick:()=>p(a.id),className:`flex w-full items-center gap-2.5 rounded-brand border px-2.5 py-2 text-left transition-colors ${c?"border-accent/40 bg-accent-soft":"border-transparent hover:bg-surface-2"}`,children:[(0,b.jsx)(m,{checked:c,onChange:()=>p(a.id),ariaLabel:a.id}),(0,b.jsx)("span",{className:"flex-1 truncate text-[12.5px] text-text",children:a.id}),a.added&&(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"in catalog"})]},a.id)})}),(0,b.jsxs)("footer",{className:"flex items-center justify-between gap-3 border-t border-border-subtle bg-bg-alt px-4 py-2.5",children:[(0,b.jsxs)("span",{className:"tnum text-[12px] text-text-muted",children:[i.size," selected"]}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:f,children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:0===i.size||d,onClick:()=>e([...i]),children:d?"Adding…":`Add ${i.size}`})]})]})]})})}var o=a.i(52065),p=a.i(73858);function q({k:a,v:c}){return(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)("span",{className:"text-text-subtle",children:a}),(0,b.jsx)("span",{className:"truncate text-text",children:c})]})}a.s(["ProviderDetail",0,function({id:a}){let m=(0,d.useRouter)(),[r,s]=(0,c.useState)(null),[t,u]=(0,c.useState)(null),[v,w]=(0,c.useState)(""),[x,y]=(0,c.useState)(null),[z,A]=(0,c.useState)(""),[B,C]=(0,c.useState)(""),[D,E]=(0,c.useState)(""),[F,G]=(0,c.useState)(null),[H,I]=(0,c.useState)(""),[J,K]=(0,c.useState)(""),[L,M]=(0,c.useState)(""),[N,O]=(0,c.useState)(""),[P,Q]=(0,c.useState)(null),[R,S]=(0,c.useState)({}),[T,U]=(0,c.useState)({}),[V,W]=(0,c.useState)(!1),[X,Y]=(0,c.useState)(null),Z=(0,c.useRef)(!1),[$,_]=(0,c.useState)(!1),[aa,ab]=(0,c.useState)(""),[ac,ad]=(0,c.useState)(""),[ae,af]=(0,c.useState)({}),[ag,ah]=(0,c.useState)(!1);async function ai(b){S(a=>({...a,[b]:"testing"}));let c=await e.adminApi.testModel(a,b);S(a=>({...a,[b]:c.ok&&c.data?.ok?"ok":"fail"}))}async function aj(b){U(a=>({...a,[b]:"testing"}));let c=await e.adminApi.testKey(a,b);U(a=>({...a,[b]:c.data??{ok:!1,reachable:!1,status:0,error:c.error}}))}async function ak(b){Z.current=!1,W(!0),Y(null),U({});let c=0,d=0;for(let f=0;f<b&&!Z.current;f++){U(a=>({...a,[f]:"testing"}));let g=await e.adminApi.testKey(a,f),h=g.data??{ok:!1,reachable:!1,status:0,error:g.error};U(a=>({...a,[f]:h})),h.ok?c++:d++,f<b-1&&!Z.current&&await new Promise(a=>setTimeout(a,500))}W(!1),Y({total:b,passed:c,failed:d})}let al=(0,c.useCallback)(async()=>{let[b,c]=await Promise.all([fetch("/api/gw/admin/config"),e.adminApi.providers()]);if(!b.ok)return void w("could not reach the gateway");let d=(await b.json()).providers.find(b=>b.id===a)??null;d?(w(""),s(d),u(c.data?.providers.find(b=>b.id===a)??null)):w(`provider "${a}" not found`)},[a]);if((0,c.useEffect)(()=>{al()},[al]),v)return(0,b.jsx)(l.Empty,{children:v});if(!r)return(0,b.jsx)(l.Empty,{children:"Loading…"});let am=r.api_keys??(r.api_key?[r.api_key]:[]),an=N.trim().toLowerCase(),ao=an?r.models.filter(a=>a.id.toLowerCase().includes(an)):r.models;async function ap(a,b){A(a);let c=await b();A(""),c.ok?(w(""),await al()):w(c.error??"action failed")}return(0,b.jsxs)("div",{children:[(0,b.jsxs)("button",{onClick:()=>m.push("/providers"),className:"mb-4 inline-flex items-center gap-1 text-[12px] text-text-muted hover:text-text",children:[(0,b.jsx)(k.Icon,{name:"arrow_back",size:15})," Providers"]}),(0,b.jsxs)("div",{className:"mb-6 flex items-center gap-3",children:[(0,b.jsx)(f.Lamp,{state:r.disabled?"idle":t?.keys.some(a=>a.healthy)??!0?"live":"down"}),(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-[22px] font-semibold tracking-tight text-text",children:r.name||r.id}),r.name&&(0,b.jsxs)("span",{className:"text-[12px] text-text-subtle",children:[r.id,"/"]})]}),(0,b.jsx)(g.FormatBadge,{format:r.format}),r.free&&(0,b.jsx)(g.Badge,{tone:"info",children:"free"}),r.service_account&&(0,b.jsx)(g.Badge,{tone:"info",children:"service-account"}),r.disabled&&(0,b.jsx)(g.Badge,{tone:"down",children:"disabled"})]}),(0,b.jsxs)("div",{className:`grid gap-4 lg:grid-cols-2 transition-opacity ${r.disabled?"opacity-50":""}`,children:[(0,b.jsx)(i.RichCard,{header:(0,b.jsx)(i.CardTitle,{title:"Connection"}),children:$?(0,b.jsxs)("div",{className:"space-y-3",children:[(0,b.jsx)(j.Field,{label:"Name",hint:"the id — also the call prefix (name/model) & combos",children:(0,b.jsx)(j.Input,{value:ac,onChange:a=>ad(a.target.value),placeholder:"e.g. openai",className:"font-mono text-[12.5px]"})}),ac.trim()&&ac.trim()!==a&&(0,b.jsxs)("p",{className:"flex items-start gap-1.5 rounded-brand border border-warning/40 bg-warning/8 px-2.5 py-2 text-[11.5px] text-warning",children:[(0,b.jsx)(k.Icon,{name:"warning",size:14,className:"mt-0.5 flex-none"}),(0,b.jsxs)("span",{children:["Renaming rewrites the call string. CLI tools pointing at"," ",(0,b.jsxs)("code",{className:"tnum",children:[a,"/…"]})," will break until repointed; combos that target it are updated automatically."]})]}),(0,b.jsx)(j.Field,{label:"Base URL",children:(0,b.jsx)(j.Input,{value:aa,onChange:a=>ab(a.target.value),placeholder:"https://...",className:"font-mono text-[12.5px]"})}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:()=>_(!1),children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:"editconn"===z,onClick:()=>ap("editconn",async()=>{let b=ac.trim(),c=a;if(b&&b!==a){let d=await e.adminApi.renameProvider(a,b);if(!d.ok)return d;c=b}let d=await e.adminApi.editProvider(c,{base_url:aa.trim()||void 0});return d.ok&&(_(!1),c!==a&&m.push(`/providers/${encodeURIComponent(c)}`)),d}),children:"Save"})]})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("div",{className:"space-y-2 text-[13px]",children:[(0,b.jsx)(q,{k:"Base URL",v:r.base_url}),(0,b.jsx)(q,{k:"Format",v:r.format}),(0,b.jsx)(q,{k:"Cooldown base",v:`${r.cooldown_base_ms}ms`}),(0,b.jsx)(q,{k:"Max retries",v:String(r.max_retries)})]}),(0,b.jsxs)("div",{className:"mt-4 flex items-center gap-2",children:[(0,b.jsxs)(j.Button,{variant:"ghost",onClick:()=>{_(!0),ab(r.base_url),ad(r.id)},children:[(0,b.jsx)(k.Icon,{name:"edit",size:15})," Edit"]}),(0,b.jsxs)(j.Button,{variant:"ghost",disabled:"test"===z,onClick:()=>ap("test",async()=>{let b=await e.adminApi.testProvider(a);return b.ok&&y(b.data),b}),children:[(0,b.jsx)(k.Icon,{name:"wifi_tethering",size:16})," ","test"===z?"Testing…":"Test connection"]}),(0,b.jsxs)(j.Button,{variant:"ghost",disabled:"discover"===z,onClick:()=>ap("discover",async()=>{let b=await e.adminApi.discoverModels(a);return b.ok&&Q(b.data?.models??[]),b}),children:[(0,b.jsx)(k.Icon,{name:"sync",size:16})," ","discover"===z?"Fetching…":"Fetch models"]})]}),x&&(0,b.jsxs)("div",{className:"mt-3 text-[12px]",children:[(0,b.jsx)(g.Badge,{tone:x.ok?"live":x.reachable?"warn":"down",children:x.ok?`ok (${x.status})`:x.reachable?`reachable (${x.status})`:"unreachable"}),x.error&&(0,b.jsx)("span",{className:"ml-2 text-text-subtle",children:x.error})]})]})}),(0,b.jsxs)(i.RichCard,{header:(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(i.CardTitle,{title:"Keys",sub:`${am.length} configured`}),(0,b.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[am.length>1&&(0,b.jsxs)(j.Button,{variant:"ghost",disabled:V,onClick:()=>ak(am.length),children:[(0,b.jsx)(k.Icon,{name:V?"progress_activity":"sync",size:15}),V?"Testing…":"Test All"]}),V&&(0,b.jsxs)(j.Button,{variant:"ghost",onClick:()=>{Z.current=!0},children:[(0,b.jsx)(k.Icon,{name:"stop",size:15})," Stop"]}),(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"Round Robin"}),(0,b.jsx)("button",{onClick:()=>{let b="round-robin"===r.strategy?null:"round-robin";e.adminApi.setProviderStrategy(a,b,r.sticky??1).then(()=>al())},className:`relative h-5 w-9 rounded-full transition-colors ${"round-robin"===r.strategy?"bg-accent":"bg-border-subtle"}`,"aria-label":"Toggle round-robin",children:(0,b.jsx)("span",{className:`absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-white transition-transform ${"round-robin"===r.strategy?"translate-x-[18px]":"translate-x-0"}`})}),"round-robin"===r.strategy&&(0,b.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"Sticky:"}),(0,b.jsxs)("div",{className:"flex items-center rounded-brand border border-border-subtle",children:[(0,b.jsx)("button",{type:"button",disabled:(r.sticky??1)<=1,onClick:()=>void e.adminApi.setProviderStrategy(a,"round-robin",Math.max(1,(r.sticky??1)-1)).then(()=>al()),className:"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text disabled:opacity-30","aria-label":"Decrease sticky",children:(0,b.jsx)(k.Icon,{name:"remove",size:13})}),(0,b.jsx)("span",{className:"tnum w-6 text-center text-[11px] text-text",children:r.sticky??1}),(0,b.jsx)("button",{type:"button",onClick:()=>void e.adminApi.setProviderStrategy(a,"round-robin",(r.sticky??1)+1).then(()=>al()),className:"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text","aria-label":"Increase sticky",children:(0,b.jsx)(k.Icon,{name:"add",size:13})})]})]})]})]}),children:[X&&(0,b.jsx)("div",{className:"mb-3 flex items-center gap-2 text-[11.5px]",children:(0,b.jsxs)(g.Badge,{tone:0===X.failed?"live":"warn",children:[X.total," tested: ",X.passed," valid, ",X.failed," failed"]})}),0===am.length?(0,b.jsx)(l.Empty,{children:"No keys (free / service-account provider)."}):(0,b.jsx)("div",{className:"space-y-1.5",children:am.map((c,d)=>{let i=t?.keys[d],l=T[d],m=l&&"testing"!==l?l:null,n=m?m.ok?"live":m.reachable?"idle":"down":i?i.healthy?"live":"down":"idle",o=r.key_names?.[c],p=r.disabled_keys?.includes(d)??!1;return F===d?(0,b.jsxs)("div",{className:"space-y-2 rounded-brand border border-accent bg-accent-soft/40 px-3 py-2.5",children:[(0,b.jsx)(j.Input,{value:H,onChange:a=>I(a.target.value),placeholder:"key name (optional)"}),(0,b.jsx)(j.Input,{value:J,onChange:a=>K(a.target.value),placeholder:"new key value (leave blank to keep)",className:"font-mono text-[12.5px]"}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:()=>G(null),children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:z===`editkey${d}`,onClick:()=>ap(`editkey${d}`,async()=>{let b=await e.adminApi.editKey(a,d,{name:H,key:J.trim()||void 0});return b.ok&&G(null),b}),children:"Save"})]})]},d):(0,b.jsxs)("div",{className:`rounded-brand border border-border-subtle px-3 py-2${p?" opacity-60":""}`,children:[(0,b.jsxs)("div",{className:"flex items-center gap-2",children:[(0,b.jsxs)("div",{className:"flex flex-col",children:[(0,b.jsx)("button",{onClick:()=>ap(`reorder${d}up`,()=>e.adminApi.reorderKey(a,d,d-1)),disabled:0===d,className:"p-0.5 text-text-subtle hover:text-text disabled:opacity-30","aria-label":"Move up",children:(0,b.jsx)(k.Icon,{name:"keyboard_arrow_up",size:14})}),(0,b.jsx)("button",{onClick:()=>ap(`reorder${d}dn`,()=>e.adminApi.reorderKey(a,d,d+1)),disabled:d===am.length-1,className:"p-0.5 text-text-subtle hover:text-text disabled:opacity-30","aria-label":"Move down",children:(0,b.jsx)(k.Icon,{name:"keyboard_arrow_down",size:14})})]}),(0,b.jsx)(f.Lamp,{state:n}),(0,b.jsxs)("div",{className:"min-w-0 flex-1",children:[o&&(0,b.jsx)("div",{className:"text-[12px] font-semibold text-text-muted",children:o}),(0,b.jsx)("span",{className:"block truncate font-mono text-[12.5px] text-text",children:ae[d]??c})]}),ae[d]&&(0,b.jsx)("button",{onClick:()=>{navigator.clipboard.writeText(ae[d])},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":"Copy key",title:"Copy to clipboard",children:(0,b.jsx)(k.Icon,{name:"content_copy",size:14})}),i&&i.cooldown_ms>0&&(0,b.jsx)(h.CooldownTimer,{ms:i.cooldown_ms}),(0,b.jsx)("button",{onClick:async()=>{if(ae[d])return void af(a=>{let b={...a};return delete b[d],b});let b=await e.adminApi.revealKey(a,d);b.ok&&b.data?.key&&af(a=>({...a,[d]:b.data.key}))},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":ae[d]?"Hide key":"Show key",title:ae[d]?"Hide key":"Show key",children:(0,b.jsx)(k.Icon,{name:ae[d]?"visibility_off":"visibility",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`toggle${d}`,()=>e.adminApi.toggleKey(a,d,p)),className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":p?"Enable key":"Disable key",title:p?"Enable this key":"Disable this key",children:(0,b.jsx)(k.Icon,{name:p?"toggle_off":"toggle_on",size:20,className:p?"text-text-subtle":"text-success"})}),(0,b.jsx)("button",{onClick:()=>aj(d),disabled:"testing"===l,className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text disabled:opacity-60","aria-label":`Check key ${d+1}`,title:"Check this key against the base URL",children:(0,b.jsx)(k.Icon,{name:"testing"===l?"progress_activity":"wifi_tethering",size:15})}),(0,b.jsx)("button",{onClick:()=>{G(d),I(o??""),K("")},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":`Edit key ${d+1}`,title:"Rename or replace this key",children:(0,b.jsx)(k.Icon,{name:"edit",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`rmkey${d}`,()=>e.adminApi.removeKey(a,d)),className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-danger","aria-label":"Remove key",children:(0,b.jsx)(k.Icon,{name:"delete",size:15})})]}),m&&(0,b.jsxs)("div",{className:"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]",children:[(0,b.jsx)(g.Badge,{tone:m.ok?"live":m.reachable?"warn":"down",children:m.ok?"valid":m.reachable?`reachable (${m.status})`:"invalid"}),m.error&&(0,b.jsx)("span",{className:"truncate text-danger",children:m.error})]}),!m&&i?.last_error&&(0,b.jsxs)("div",{className:"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]",children:[(0,b.jsxs)("span",{className:"text-danger",children:[i.last_error.status?`${i.last_error.status}: `:"",i.last_error.message]}),(0,b.jsx)("span",{className:"text-text-subtle",children:new Date(i.last_error.at).toLocaleTimeString()})]})]},d)})}),(0,b.jsxs)("div",{className:"mt-3 space-y-2",children:[(0,b.jsx)(j.Input,{value:D,onChange:a=>E(a.target.value),placeholder:"key name (optional, e.g. primary)"}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)(j.Input,{value:B,onChange:a=>C(a.target.value),placeholder:"add a key…",className:"font-mono text-[12.5px]"}),(0,b.jsx)(j.Button,{disabled:!B||"addkey"===z,onClick:()=>ap("addkey",async()=>{let b=await e.adminApi.addKey(a,B,D.trim()||void 0);return b.ok&&(C(""),E("")),b}),children:"Add"})]})]})]}),(0,b.jsxs)(i.RichCard,{className:"lg:col-span-2",header:(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(i.CardTitle,{title:"Models served",sub:`${r.models.length} in catalog`}),r.models.length>0&&(0,b.jsx)("button",{onClick:()=>ap("clear",()=>e.adminApi.clearModels(a)),disabled:"clear"===z,className:"text-[12px] text-text-subtle hover:text-danger",children:"Clear all"})]}),children:[0===r.models.length?(0,b.jsx)(l.Empty,{children:"No models. Add one below, or fetch them for a free/auto provider."}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("p",{className:"mb-2.5 text-[12px] text-text-subtle",children:["Call any of these as ",(0,b.jsxs)("span",{className:"tnum text-text-muted",children:[r.id,"/<model>"]}),", as a combo alias, or by the bare id."]}),r.models.length>8&&(0,b.jsxs)("div",{className:"mb-2.5 flex items-center gap-2",children:[(0,b.jsxs)("div",{className:"relative flex-1",children:[(0,b.jsx)(k.Icon,{name:"search",size:15,className:"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-text-subtle"}),(0,b.jsx)(j.Input,{value:N,onChange:a=>O(a.target.value),placeholder:"filter models…",className:"pl-8"})]}),(0,b.jsx)("span",{className:"tnum whitespace-nowrap text-[12px] text-text-subtle",children:an?`${ao.length} of ${r.models.length}`:`${r.models.length}`})]}),0===ao.length?(0,b.jsxs)(l.Empty,{children:["No model matches “",N,"”."]}):(0,b.jsx)("div",{className:"max-h-[360px] divide-y divide-border-subtle overflow-y-auto rounded-brand border border-border-subtle",children:ao.map(c=>{let d=R[c.id];return(0,b.jsxs)("div",{className:"group flex items-center justify-between gap-3 px-3 py-2 hover:bg-bg",children:[(0,b.jsxs)("div",{className:"flex min-w-0 items-center gap-2",children:[(0,b.jsx)(k.Icon,{name:"ok"===d?"check_circle":"fail"===d?"cancel":"smart_toy",size:15,className:`flex-none ${"ok"===d?"text-success":"fail"===d?"text-danger":"text-text-subtle"}`}),(0,b.jsxs)("span",{className:"tnum truncate text-[12.5px]",children:[(0,b.jsxs)("span",{className:"text-text-subtle",children:[r.id,"/"]}),(0,b.jsx)("span",{className:"text-text",children:c.id})]}),(0,b.jsx)(o.CapacityBadges,{model:c.id,provider:r.id}),(void 0!==c.price_in||void 0!==c.price_out)&&(0,b.jsxs)("span",{className:"tnum whitespace-nowrap text-[11px] text-text-subtle",children:[l.fmt.cost(c.price_in??0),"/",l.fmt.cost(c.price_out??0)," per 1M"]})]}),(0,b.jsxs)("div",{className:"flex flex-none items-center gap-0.5",children:[(0,b.jsx)("button",{onClick:()=>ai(c.id),disabled:"testing"===d,className:"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-accent disabled:opacity-60","aria-label":`Test ${c.id}`,title:"fail"===d?"Test failed — click to retry":"Test this model",children:(0,b.jsx)(k.Icon,{name:"testing"===d?"progress_activity":"science",size:15})}),(0,b.jsx)("button",{onClick:()=>ap(`rmmodel${c.id}`,()=>e.adminApi.removeModel(a,c.id)),disabled:z===`rmmodel${c.id}`,className:"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-danger disabled:opacity-40","aria-label":`Remove ${c.id}`,children:(0,b.jsx)(k.Icon,{name:"delete",size:16})})]})]},c.id)})})]}),(0,b.jsxs)("div",{className:"mt-3 flex gap-2",children:[(0,b.jsx)(j.Input,{value:L,onChange:a=>M(a.target.value),placeholder:"add a model id…"}),(0,b.jsx)(j.Button,{disabled:!L||"addmodel"===z,onClick:()=>ap("addmodel",async()=>{let b=await e.adminApi.addModel(a,L);return b.ok&&M(""),b}),children:"Add"})]})]})]}),P&&(0,b.jsx)(n,{models:P,busy:"addmodels"===z,onClose:()=>Q(null),onAdd:b=>ap("addmodels",async()=>{let c=await e.adminApi.addModels(a,b);return c.ok&&Q(null),c})}),(0,b.jsx)("div",{className:"mt-6",children:(0,b.jsxs)(j.Button,{variant:"danger",onClick:()=>ah(!0),children:[(0,b.jsx)(k.Icon,{name:"delete",size:16})," Remove provider"]})}),ag&&(0,b.jsx)(p.ConfirmModal,{title:"Remove provider",message:`Delete "${r.name??a}"? All keys and model associations will be lost.`,confirmLabel:"Remove",busy:"rmprov"===z,onCancel:()=>ah(!1),onConfirm:()=>ap("rmprov",async()=>{let b=await e.adminApi.removeProvider(a);return b.ok?m.push("/providers"):ah(!1),b})})]})}],33410)}];
1
+ module.exports=[33410,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(50944),e=a.i(56173),f=a.i(47153),g=a.i(2693),h=a.i(2799),i=a.i(85732),j=a.i(7078),k=a.i(93026),l=a.i(58918);function m({checked:a,indeterminate:c,onChange:d,className:e,ariaLabel:f}){let g=a||c;return(0,b.jsx)("button",{type:"button",role:"checkbox","aria-checked":c?"mixed":a,"aria-label":f,onClick:a=>{a.stopPropagation(),d()},className:`flex h-[18px] w-[18px] flex-none items-center justify-center rounded-[5px] border transition-colors ${g?"border-accent bg-accent text-accent-ink":"border-border bg-bg text-transparent hover:border-text-subtle"}${e?` ${e}`:""}`,children:(0,b.jsx)(k.Icon,{name:c?"remove":"check",size:13})})}function n({models:a,busy:d,onAdd:e,onClose:f}){let[g,h]=(0,c.useState)(""),[i,l]=(0,c.useState)(()=>new Set(a.filter(a=>!a.added).map(a=>a.id))),o=(0,c.useMemo)(()=>{let b=g.trim().toLowerCase();return b?a.filter(a=>a.id.toLowerCase().includes(b)):a},[a,g]);function p(a){l(b=>{let c=new Set(b);return c.has(a)?c.delete(a):c.add(a),c})}let q=o.filter(a=>i.has(a.id)).length,r=o.length>0&&q===o.length;function s(){l(a=>{let b=new Set(a);return r?o.forEach(a=>b.delete(a.id)):o.forEach(a=>b.add(a.id)),b})}return(0,b.jsx)("div",{className:"fixed inset-0 z-50 grid place-items-center bg-black/50 p-6",onClick:f,children:(0,b.jsxs)("div",{className:"flex max-h-[80vh] w-full max-w-[480px] flex-col overflow-hidden rounded-brand-lg border border-border bg-surface shadow-elevated",onClick:a=>a.stopPropagation(),children:[(0,b.jsxs)("header",{className:"flex items-center justify-between border-b border-border-subtle px-4 py-3",children:[(0,b.jsxs)("span",{className:"text-[14px] font-semibold text-text",children:[a.length," models found"]}),(0,b.jsx)("button",{onClick:f,className:"text-text-subtle hover:text-text","aria-label":"Close",children:(0,b.jsx)(k.Icon,{name:"close",size:18})})]}),(0,b.jsx)("div",{className:"border-b border-border-subtle px-4 py-2.5",children:(0,b.jsx)(j.Input,{value:g,onChange:a=>h(a.target.value),placeholder:"filter…",autoFocus:!0})}),o.length>0&&(0,b.jsxs)("button",{onClick:s,className:"flex items-center gap-2.5 border-b border-border-subtle px-4 py-2 text-left hover:bg-surface-2",children:[(0,b.jsx)(m,{checked:r,indeterminate:q>0&&!r,onChange:s,ariaLabel:"Select all"}),(0,b.jsxs)("span",{className:"text-[12.5px] font-medium text-text",children:["Select all",g?" (filtered)":""]}),(0,b.jsxs)("span",{className:"ml-auto tnum text-[11px] text-text-subtle",children:[q,"/",o.length]})]}),(0,b.jsx)("div",{className:"flex-1 overflow-y-auto px-2 py-2",children:0===o.length?(0,b.jsx)("div",{className:"px-2 py-6 text-center text-[13px] text-text-muted",children:"No matches."}):o.map(a=>{let c=i.has(a.id);return(0,b.jsxs)("button",{onClick:()=>p(a.id),className:`flex w-full items-center gap-2.5 rounded-brand border px-2.5 py-2 text-left transition-colors ${c?"border-accent/40 bg-accent-soft":"border-transparent hover:bg-surface-2"}`,children:[(0,b.jsx)(m,{checked:c,onChange:()=>p(a.id),ariaLabel:a.id}),(0,b.jsx)("span",{className:"flex-1 truncate text-[12.5px] text-text",children:a.id}),a.added&&(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"in catalog"})]},a.id)})}),(0,b.jsxs)("footer",{className:"flex items-center justify-between gap-3 border-t border-border-subtle bg-bg-alt px-4 py-2.5",children:[(0,b.jsxs)("span",{className:"tnum text-[12px] text-text-muted",children:[i.size," selected"]}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:f,children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:0===i.size||d,onClick:()=>e([...i]),children:d?"Adding…":`Add ${i.size}`})]})]})]})})}var o=a.i(52065),p=a.i(73858);function q({k:a,v:c}){return(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)("span",{className:"text-text-subtle",children:a}),(0,b.jsx)("span",{className:"truncate text-text",children:c})]})}a.s(["ProviderDetail",0,function({id:a}){let m=(0,d.useRouter)(),[r,s]=(0,c.useState)(null),[t,u]=(0,c.useState)(null),[v,w]=(0,c.useState)(""),[x,y]=(0,c.useState)(null),[z,A]=(0,c.useState)(""),[B,C]=(0,c.useState)(""),[D,E]=(0,c.useState)(""),[F,G]=(0,c.useState)(null),[H,I]=(0,c.useState)(""),[J,K]=(0,c.useState)(""),[L,M]=(0,c.useState)(""),[N,O]=(0,c.useState)(""),[P,Q]=(0,c.useState)(null),[R,S]=(0,c.useState)({}),[T,U]=(0,c.useState)({}),[V,W]=(0,c.useState)(!1),[X,Y]=(0,c.useState)(null),Z=(0,c.useRef)(!1),[$,_]=(0,c.useState)(!1),[aa,ab]=(0,c.useState)(""),[ac,ad]=(0,c.useState)(""),[ae,af]=(0,c.useState)(""),[ag,ah]=(0,c.useState)({}),[ai,aj]=(0,c.useState)(!1);async function ak(b){S(a=>({...a,[b]:"testing"}));let c=await e.adminApi.testModel(a,b);S(a=>({...a,[b]:c.ok&&c.data?.ok?"ok":"fail"}))}async function al(b){U(a=>({...a,[b]:"testing"}));let c=await e.adminApi.testKey(a,b);U(a=>({...a,[b]:c.data??{ok:!1,reachable:!1,status:0,error:c.error}}))}async function am(b){Z.current=!1,W(!0),Y(null),U({});let c=0,d=0;for(let f=0;f<b&&!Z.current;f++){U(a=>({...a,[f]:"testing"}));let g=await e.adminApi.testKey(a,f),h=g.data??{ok:!1,reachable:!1,status:0,error:g.error};U(a=>({...a,[f]:h})),h.ok?c++:d++,f<b-1&&!Z.current&&await new Promise(a=>setTimeout(a,500))}W(!1),Y({total:b,passed:c,failed:d})}let an=(0,c.useCallback)(async()=>{let[b,c]=await Promise.all([fetch("/api/gw/admin/config"),e.adminApi.providers()]);if(!b.ok)return void w("could not reach the gateway");let d=(await b.json()).providers.find(b=>b.id===a)??null;d?(w(""),s(d),u(c.data?.providers.find(b=>b.id===a)??null)):w(`provider "${a}" not found`)},[a]);if((0,c.useEffect)(()=>{an()},[an]),v)return(0,b.jsx)(l.Empty,{children:v});if(!r)return(0,b.jsx)(l.Empty,{children:"Loading…"});let ao=r.api_keys??(r.api_key?[r.api_key]:[]),ap=N.trim().toLowerCase(),aq=ap?r.models.filter(a=>a.id.toLowerCase().includes(ap)):r.models;async function ar(a,b){A(a);let c=await b();A(""),c.ok?(w(""),await an()):w(c.error??"action failed")}return(0,b.jsxs)("div",{children:[(0,b.jsxs)("button",{onClick:()=>m.push("/providers"),className:"mb-4 inline-flex items-center gap-1 text-[12px] text-text-muted hover:text-text",children:[(0,b.jsx)(k.Icon,{name:"arrow_back",size:15})," Providers"]}),(0,b.jsxs)("div",{className:"mb-6 flex items-center gap-3",children:[(0,b.jsx)(f.Lamp,{state:r.disabled?"idle":t?.keys.some(a=>a.healthy)??!0?"live":"down"}),(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-[22px] font-semibold tracking-tight text-text",children:r.name||r.id}),r.name&&(0,b.jsxs)("span",{className:"text-[12px] text-text-subtle",children:[r.id,"/"]})]}),(0,b.jsx)(g.FormatBadge,{format:r.format}),r.free&&(0,b.jsx)(g.Badge,{tone:"info",children:"free"}),r.service_account&&(0,b.jsx)(g.Badge,{tone:"info",children:"service-account"}),r.disabled&&(0,b.jsx)(g.Badge,{tone:"down",children:"disabled"})]}),(0,b.jsxs)("div",{className:`grid gap-4 lg:grid-cols-2 transition-opacity ${r.disabled?"opacity-50":""}`,children:[(0,b.jsx)(i.RichCard,{header:(0,b.jsx)(i.CardTitle,{title:"Connection"}),children:$?(0,b.jsxs)("div",{className:"space-y-3",children:[(0,b.jsx)(j.Field,{label:"Label",hint:"display name in dashboard (optional, does not affect routing)",children:(0,b.jsx)(j.Input,{value:ae,onChange:a=>af(a.target.value),placeholder:ac||"e.g. My Provider",className:"text-[12.5px]"})}),(0,b.jsx)(j.Field,{label:"ID / Prefix",hint:"the call prefix (id/model) — changing this breaks CLI tools",children:(0,b.jsx)(j.Input,{value:ac,onChange:a=>ad(a.target.value),placeholder:"e.g. openai",className:"font-mono text-[12.5px]"})}),ac.trim()&&ac.trim()!==a&&(0,b.jsxs)("p",{className:"flex items-start gap-1.5 rounded-brand border border-warning/40 bg-warning/8 px-2.5 py-2 text-[11.5px] text-warning",children:[(0,b.jsx)(k.Icon,{name:"warning",size:14,className:"mt-0.5 flex-none"}),(0,b.jsxs)("span",{children:["Renaming rewrites the call string. CLI tools pointing at"," ",(0,b.jsxs)("code",{className:"tnum",children:[a,"/…"]})," will break until repointed; combos that target it are updated automatically."]})]}),(0,b.jsx)(j.Field,{label:"Base URL",children:(0,b.jsx)(j.Input,{value:aa,onChange:a=>ab(a.target.value),placeholder:"https://...",className:"font-mono text-[12.5px]"})}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:()=>_(!1),children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:"editconn"===z,onClick:()=>ar("editconn",async()=>{let b=ac.trim(),c=a;if(b&&b!==a){let d=await e.adminApi.renameProvider(a,b);if(!d.ok)return d;c=b}let d=ae.trim()||void 0,f=await e.adminApi.editProvider(c,{base_url:aa.trim()||void 0,name:d});return f.ok&&(_(!1),c!==a&&m.push(`/providers/${encodeURIComponent(c)}`)),f}),children:"Save"})]})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("div",{className:"space-y-2 text-[13px]",children:[r.name&&(0,b.jsx)(q,{k:"Label",v:r.name}),(0,b.jsx)(q,{k:"ID / Prefix",v:r.id}),(0,b.jsx)(q,{k:"Base URL",v:r.base_url}),(0,b.jsx)(q,{k:"Format",v:r.format}),(0,b.jsx)(q,{k:"Cooldown base",v:`${r.cooldown_base_ms}ms`}),(0,b.jsx)(q,{k:"Max retries",v:String(r.max_retries)})]}),(0,b.jsxs)("div",{className:"mt-4 flex items-center gap-2",children:[(0,b.jsxs)(j.Button,{variant:"ghost",onClick:()=>{_(!0),ab(r.base_url),ad(r.id),af(r.name??"")},children:[(0,b.jsx)(k.Icon,{name:"edit",size:15})," Edit"]}),(0,b.jsxs)(j.Button,{variant:"ghost",disabled:"test"===z,onClick:()=>ar("test",async()=>{let b=await e.adminApi.testProvider(a);return b.ok&&y(b.data),b}),children:[(0,b.jsx)(k.Icon,{name:"wifi_tethering",size:16})," ","test"===z?"Testing…":"Test connection"]}),(0,b.jsxs)(j.Button,{variant:"ghost",disabled:"discover"===z,onClick:()=>ar("discover",async()=>{let b=await e.adminApi.discoverModels(a);return b.ok&&Q(b.data?.models??[]),b}),children:[(0,b.jsx)(k.Icon,{name:"sync",size:16})," ","discover"===z?"Fetching…":"Fetch models"]})]}),x&&(0,b.jsxs)("div",{className:"mt-3 text-[12px]",children:[(0,b.jsx)(g.Badge,{tone:x.ok?"live":x.reachable?"warn":"down",children:x.ok?`ok (${x.status})`:x.reachable?`reachable (${x.status})`:"unreachable"}),x.error&&(0,b.jsx)("span",{className:"ml-2 text-text-subtle",children:x.error})]})]})}),(0,b.jsxs)(i.RichCard,{header:(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(i.CardTitle,{title:"Keys",sub:`${ao.length} configured`}),(0,b.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[ao.length>1&&(0,b.jsxs)(j.Button,{variant:"ghost",disabled:V,onClick:()=>am(ao.length),children:[(0,b.jsx)(k.Icon,{name:V?"progress_activity":"sync",size:15}),V?"Testing…":"Test All"]}),V&&(0,b.jsxs)(j.Button,{variant:"ghost",onClick:()=>{Z.current=!0},children:[(0,b.jsx)(k.Icon,{name:"stop",size:15})," Stop"]}),(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"Round Robin"}),(0,b.jsx)("button",{onClick:()=>{let b="round-robin"===r.strategy?null:"round-robin";e.adminApi.setProviderStrategy(a,b,r.sticky??1).then(()=>an())},className:`relative h-5 w-9 rounded-full transition-colors ${"round-robin"===r.strategy?"bg-accent":"bg-border-subtle"}`,"aria-label":"Toggle round-robin",children:(0,b.jsx)("span",{className:`absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-white transition-transform ${"round-robin"===r.strategy?"translate-x-[18px]":"translate-x-0"}`})}),"round-robin"===r.strategy&&(0,b.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,b.jsx)("span",{className:"text-[11px] text-text-subtle",children:"Sticky:"}),(0,b.jsxs)("div",{className:"flex items-center rounded-brand border border-border-subtle",children:[(0,b.jsx)("button",{type:"button",disabled:(r.sticky??1)<=1,onClick:()=>void e.adminApi.setProviderStrategy(a,"round-robin",Math.max(1,(r.sticky??1)-1)).then(()=>an()),className:"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text disabled:opacity-30","aria-label":"Decrease sticky",children:(0,b.jsx)(k.Icon,{name:"remove",size:13})}),(0,b.jsx)("span",{className:"tnum w-6 text-center text-[11px] text-text",children:r.sticky??1}),(0,b.jsx)("button",{type:"button",onClick:()=>void e.adminApi.setProviderStrategy(a,"round-robin",(r.sticky??1)+1).then(()=>an()),className:"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text","aria-label":"Increase sticky",children:(0,b.jsx)(k.Icon,{name:"add",size:13})})]})]})]})]}),children:[X&&(0,b.jsx)("div",{className:"mb-3 flex items-center gap-2 text-[11.5px]",children:(0,b.jsxs)(g.Badge,{tone:0===X.failed?"live":"warn",children:[X.total," tested: ",X.passed," valid, ",X.failed," failed"]})}),0===ao.length?(0,b.jsx)(l.Empty,{children:"No keys (free / service-account provider)."}):(0,b.jsx)("div",{className:"space-y-1.5",children:ao.map((c,d)=>{let i=t?.keys[d],l=T[d],m=l&&"testing"!==l?l:null,n=m?m.ok?"live":m.reachable?"idle":"down":i?i.healthy?"live":"down":"idle",o=r.key_names?.[c],p=r.disabled_keys?.includes(d)??!1;return F===d?(0,b.jsxs)("div",{className:"space-y-2 rounded-brand border border-accent bg-accent-soft/40 px-3 py-2.5",children:[(0,b.jsx)(j.Input,{value:H,onChange:a=>I(a.target.value),placeholder:"key name (optional)"}),(0,b.jsx)(j.Input,{value:J,onChange:a=>K(a.target.value),placeholder:"new key value (leave blank to keep)",className:"font-mono text-[12.5px]"}),(0,b.jsxs)("div",{className:"flex justify-end gap-2",children:[(0,b.jsx)(j.Button,{variant:"ghost",onClick:()=>G(null),children:"Cancel"}),(0,b.jsx)(j.Button,{disabled:z===`editkey${d}`,onClick:()=>ar(`editkey${d}`,async()=>{let b=await e.adminApi.editKey(a,d,{name:H,key:J.trim()||void 0});return b.ok&&G(null),b}),children:"Save"})]})]},d):(0,b.jsxs)("div",{className:`rounded-brand border border-border-subtle px-3 py-2${p?" opacity-60":""}`,children:[(0,b.jsxs)("div",{className:"flex items-center gap-2",children:[(0,b.jsxs)("div",{className:"flex flex-col",children:[(0,b.jsx)("button",{onClick:()=>ar(`reorder${d}up`,()=>e.adminApi.reorderKey(a,d,d-1)),disabled:0===d,className:"p-0.5 text-text-subtle hover:text-text disabled:opacity-30","aria-label":"Move up",children:(0,b.jsx)(k.Icon,{name:"keyboard_arrow_up",size:14})}),(0,b.jsx)("button",{onClick:()=>ar(`reorder${d}dn`,()=>e.adminApi.reorderKey(a,d,d+1)),disabled:d===ao.length-1,className:"p-0.5 text-text-subtle hover:text-text disabled:opacity-30","aria-label":"Move down",children:(0,b.jsx)(k.Icon,{name:"keyboard_arrow_down",size:14})})]}),(0,b.jsx)(f.Lamp,{state:n}),(0,b.jsxs)("div",{className:"min-w-0 flex-1",children:[o&&(0,b.jsx)("div",{className:"text-[12px] font-semibold text-text-muted",children:o}),(0,b.jsx)("span",{className:"block truncate font-mono text-[12.5px] text-text",children:ag[d]??c})]}),ag[d]&&(0,b.jsx)("button",{onClick:()=>{navigator.clipboard.writeText(ag[d])},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":"Copy key",title:"Copy to clipboard",children:(0,b.jsx)(k.Icon,{name:"content_copy",size:14})}),i&&i.cooldown_ms>0&&(0,b.jsx)(h.CooldownTimer,{ms:i.cooldown_ms}),(0,b.jsx)("button",{onClick:async()=>{if(ag[d])return void ah(a=>{let b={...a};return delete b[d],b});let b=await e.adminApi.revealKey(a,d);b.ok&&b.data?.key&&ah(a=>({...a,[d]:b.data.key}))},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":ag[d]?"Hide key":"Show key",title:ag[d]?"Hide key":"Show key",children:(0,b.jsx)(k.Icon,{name:ag[d]?"visibility_off":"visibility",size:15})}),(0,b.jsx)("button",{onClick:()=>ar(`toggle${d}`,()=>e.adminApi.toggleKey(a,d,p)),className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":p?"Enable key":"Disable key",title:p?"Enable this key":"Disable this key",children:(0,b.jsx)(k.Icon,{name:p?"toggle_off":"toggle_on",size:20,className:p?"text-text-subtle":"text-success"})}),(0,b.jsx)("button",{onClick:()=>al(d),disabled:"testing"===l,className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text disabled:opacity-60","aria-label":`Check key ${d+1}`,title:"Check this key against the base URL",children:(0,b.jsx)(k.Icon,{name:"testing"===l?"progress_activity":"wifi_tethering",size:15})}),(0,b.jsx)("button",{onClick:()=>{G(d),I(o??""),K("")},className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text","aria-label":`Edit key ${d+1}`,title:"Rename or replace this key",children:(0,b.jsx)(k.Icon,{name:"edit",size:15})}),(0,b.jsx)("button",{onClick:()=>ar(`rmkey${d}`,()=>e.adminApi.removeKey(a,d)),className:"flex-none rounded p-1 text-text-subtle transition-colors hover:text-danger","aria-label":"Remove key",children:(0,b.jsx)(k.Icon,{name:"delete",size:15})})]}),m&&(0,b.jsxs)("div",{className:"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]",children:[(0,b.jsx)(g.Badge,{tone:m.ok?"live":m.reachable?"warn":"down",children:m.ok?"valid":m.reachable?`reachable (${m.status})`:"invalid"}),m.error&&(0,b.jsx)("span",{className:"truncate text-danger",children:m.error})]}),!m&&i?.last_error&&(0,b.jsxs)("div",{className:"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]",children:[(0,b.jsxs)("span",{className:"text-danger",children:[i.last_error.status?`${i.last_error.status}: `:"",i.last_error.message]}),(0,b.jsx)("span",{className:"text-text-subtle",children:new Date(i.last_error.at).toLocaleTimeString()})]})]},d)})}),(0,b.jsxs)("div",{className:"mt-3 space-y-2",children:[(0,b.jsx)(j.Input,{value:D,onChange:a=>E(a.target.value),placeholder:"key name (optional, e.g. primary)"}),(0,b.jsxs)("div",{className:"flex gap-2",children:[(0,b.jsx)(j.Input,{value:B,onChange:a=>C(a.target.value),placeholder:"add a key…",className:"font-mono text-[12.5px]"}),(0,b.jsx)(j.Button,{disabled:!B||"addkey"===z,onClick:()=>ar("addkey",async()=>{let b=await e.adminApi.addKey(a,B,D.trim()||void 0);return b.ok&&(C(""),E("")),b}),children:"Add"})]})]})]}),(0,b.jsxs)(i.RichCard,{className:"lg:col-span-2",header:(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(i.CardTitle,{title:"Models served",sub:`${r.models.length} in catalog`}),r.models.length>0&&(0,b.jsx)("button",{onClick:()=>ar("clear",()=>e.adminApi.clearModels(a)),disabled:"clear"===z,className:"text-[12px] text-text-subtle hover:text-danger",children:"Clear all"})]}),children:[0===r.models.length?(0,b.jsx)(l.Empty,{children:"No models. Add one below, or fetch them for a free/auto provider."}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("p",{className:"mb-2.5 text-[12px] text-text-subtle",children:["Call any of these as ",(0,b.jsxs)("span",{className:"tnum text-text-muted",children:[r.id,"/<model>"]}),", as a combo alias, or by the bare id."]}),r.models.length>8&&(0,b.jsxs)("div",{className:"mb-2.5 flex items-center gap-2",children:[(0,b.jsxs)("div",{className:"relative flex-1",children:[(0,b.jsx)(k.Icon,{name:"search",size:15,className:"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-text-subtle"}),(0,b.jsx)(j.Input,{value:N,onChange:a=>O(a.target.value),placeholder:"filter models…",className:"pl-8"})]}),(0,b.jsx)("span",{className:"tnum whitespace-nowrap text-[12px] text-text-subtle",children:ap?`${aq.length} of ${r.models.length}`:`${r.models.length}`})]}),0===aq.length?(0,b.jsxs)(l.Empty,{children:["No model matches “",N,"”."]}):(0,b.jsx)("div",{className:"max-h-[360px] divide-y divide-border-subtle overflow-y-auto rounded-brand border border-border-subtle",children:aq.map(c=>{let d=R[c.id];return(0,b.jsxs)("div",{className:"group flex items-center justify-between gap-3 px-3 py-2 hover:bg-bg",children:[(0,b.jsxs)("div",{className:"flex min-w-0 items-center gap-2",children:[(0,b.jsx)(k.Icon,{name:"ok"===d?"check_circle":"fail"===d?"cancel":"smart_toy",size:15,className:`flex-none ${"ok"===d?"text-success":"fail"===d?"text-danger":"text-text-subtle"}`}),(0,b.jsxs)("span",{className:"tnum truncate text-[12.5px]",children:[(0,b.jsxs)("span",{className:"text-text-subtle",children:[r.id,"/"]}),(0,b.jsx)("span",{className:"text-text",children:c.id})]}),(0,b.jsx)(o.CapacityBadges,{model:c.id,provider:r.id}),(void 0!==c.price_in||void 0!==c.price_out)&&(0,b.jsxs)("span",{className:"tnum whitespace-nowrap text-[11px] text-text-subtle",children:[l.fmt.cost(c.price_in??0),"/",l.fmt.cost(c.price_out??0)," per 1M"]})]}),(0,b.jsxs)("div",{className:"flex flex-none items-center gap-0.5",children:[(0,b.jsx)("button",{onClick:()=>ak(c.id),disabled:"testing"===d,className:"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-accent disabled:opacity-60","aria-label":`Test ${c.id}`,title:"fail"===d?"Test failed — click to retry":"Test this model",children:(0,b.jsx)(k.Icon,{name:"testing"===d?"progress_activity":"science",size:15})}),(0,b.jsx)("button",{onClick:()=>ar(`rmmodel${c.id}`,()=>e.adminApi.removeModel(a,c.id)),disabled:z===`rmmodel${c.id}`,className:"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-danger disabled:opacity-40","aria-label":`Remove ${c.id}`,children:(0,b.jsx)(k.Icon,{name:"delete",size:16})})]})]},c.id)})})]}),(0,b.jsxs)("div",{className:"mt-3 flex gap-2",children:[(0,b.jsx)(j.Input,{value:L,onChange:a=>M(a.target.value),placeholder:"add a model id…"}),(0,b.jsx)(j.Button,{disabled:!L||"addmodel"===z,onClick:()=>ar("addmodel",async()=>{let b=await e.adminApi.addModel(a,L);return b.ok&&M(""),b}),children:"Add"})]})]})]}),P&&(0,b.jsx)(n,{models:P,busy:"addmodels"===z,onClose:()=>Q(null),onAdd:b=>ar("addmodels",async()=>{let c=await e.adminApi.addModels(a,b);return c.ok&&Q(null),c})}),(0,b.jsx)("div",{className:"mt-6",children:(0,b.jsxs)(j.Button,{variant:"danger",onClick:()=>aj(!0),children:[(0,b.jsx)(k.Icon,{name:"delete",size:16})," Remove provider"]})}),ai&&(0,b.jsx)(p.ConfirmModal,{title:"Remove provider",message:`Delete "${r.name??a}"? All keys and model associations will be lost.`,confirmLabel:"Remove",busy:"rmprov"===z,onCancel:()=>aj(!1),onConfirm:()=>ar("rmprov",async()=>{let b=await e.adminApi.removeProvider(a);return b.ok?m.push("/providers"):aj(!1),b})})]})}],33410)}];
2
2
 
3
3
  //# sourceMappingURL=src_components_ProviderDetail_tsx_06sxu0r._.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/ProviderDetail.tsx","../../../../src/components/Checkbox.tsx","../../../../src/components/ModelSelectModal.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState, useCallback, useRef } from \"react\";\nimport { useRouter } from \"next/navigation\";\nimport { adminApi } from \"@/lib/client\";\nimport { Lamp } from \"@/components/Lamp\";\nimport { Badge, FormatBadge } from \"@/components/Badge\";\nimport { CooldownTimer } from \"@/components/CooldownTimer\";\nimport { RichCard, CardTitle } from \"@/components/RichCard\";\nimport { Button, Input, Field } from \"@/components/Button\";\nimport { Icon } from \"@/components/Icon\";\nimport { fmt, Empty } from \"@/components/ui\";\nimport { ModelSelectModal, type DiscoveredModel } from \"@/components/ModelSelectModal\";\nimport { CapacityBadges } from \"@/components/CapacityBadges\";\nimport { ConfirmModal } from \"@/components/ConfirmModal\";\nimport type { MaskedConfig, MaskedProvider, ProviderSnapshot, PingResult } from \"@/lib/gateway\";\n\nexport function ProviderDetail({ id }: { id: string }) {\n const router = useRouter();\n const [provider, setProvider] = useState<MaskedProvider | null>(null);\n const [health, setHealth] = useState<ProviderSnapshot | null>(null);\n const [error, setError] = useState(\"\");\n const [ping, setPing] = useState<PingResult | null>(null);\n const [busy, setBusy] = useState(\"\");\n const [newKey, setNewKey] = useState(\"\");\n const [newKeyName, setNewKeyName] = useState(\"\");\n const [editIdx, setEditIdx] = useState<number | null>(null);\n const [editName, setEditName] = useState(\"\");\n const [editVal, setEditVal] = useState(\"\");\n const [newModel, setNewModel] = useState(\"\");\n const [modelFilter, setModelFilter] = useState(\"\");\n const [discovered, setDiscovered] = useState<DiscoveredModel[] | null>(null);\n const [modelTest, setModelTest] = useState<Record<string, \"testing\" | \"ok\" | \"fail\">>({});\n const [keyTest, setKeyTest] = useState<Record<number, \"testing\" | PingResult>>({});\n const [testingAll, setTestingAll] = useState(false);\n const [testAllSummary, setTestAllSummary] = useState<{ total: number; passed: number; failed: number } | null>(null);\n const stopTestAll = useRef(false);\n const [editingConn, setEditingConn] = useState(false);\n const [connUrl, setConnUrl] = useState(\"\");\n const [connPrefix, setConnPrefix] = useState(\"\");\n const [revealedKeys, setRevealedKeys] = useState<Record<number, string>>({});\n const [confirmDelete, setConfirmDelete] = useState(false);\n\n async function testModel(mid: string) {\n setModelTest((t) => ({ ...t, [mid]: \"testing\" }));\n const r = await adminApi.testModel(id, mid);\n setModelTest((t) => ({ ...t, [mid]: r.ok && r.data?.ok ? \"ok\" : \"fail\" }));\n }\n\n async function testKey(i: number) {\n setKeyTest((t) => ({ ...t, [i]: \"testing\" }));\n const r = await adminApi.testKey(id, i);\n setKeyTest((t) => ({ ...t, [i]: r.data ?? { ok: false, reachable: false, status: 0, error: r.error } }));\n }\n\n async function testAllKeys(count: number) {\n stopTestAll.current = false;\n setTestingAll(true);\n setTestAllSummary(null);\n setKeyTest({});\n let passed = 0;\n let failed = 0;\n for (let i = 0; i < count; i++) {\n if (stopTestAll.current) break;\n setKeyTest((t) => ({ ...t, [i]: \"testing\" }));\n const r = await adminApi.testKey(id, i);\n const result = r.data ?? { ok: false, reachable: false, status: 0, error: r.error };\n setKeyTest((t) => ({ ...t, [i]: result }));\n if (result.ok) passed++;\n else failed++;\n if (i < count - 1 && !stopTestAll.current) await new Promise((resolve) => setTimeout(resolve, 500));\n }\n setTestingAll(false);\n setTestAllSummary({ total: count, passed, failed });\n }\n\n const reload = useCallback(async () => {\n const [cfgRes, provRes] = await Promise.all([fetch(\"/api/gw/admin/config\"), adminApi.providers()]);\n if (!cfgRes.ok) {\n setError(\"could not reach the gateway\");\n return;\n }\n const cfg = (await cfgRes.json()) as MaskedConfig;\n const p = cfg.providers.find((x) => x.id === id) ?? null;\n if (!p) {\n setError(`provider \"${id}\" not found`);\n return;\n }\n setError(\"\");\n setProvider(p);\n setHealth(provRes.data?.providers.find((x) => x.id === id) ?? null);\n }, [id]);\n\n useEffect(() => {\n void reload();\n }, [reload]);\n\n if (error) return <Empty>{error}</Empty>;\n if (!provider) return <Empty>Loading…</Empty>;\n\n const keys = provider.api_keys ?? (provider.api_key ? [provider.api_key] : []);\n const q = modelFilter.trim().toLowerCase();\n const shownModels = q ? provider.models.filter((m) => m.id.toLowerCase().includes(q)) : provider.models;\n\n async function run(label: string, fn: () => Promise<{ ok: boolean; error?: string }>) {\n setBusy(label);\n const res = await fn();\n setBusy(\"\");\n if (!res.ok) setError(res.error ?? \"action failed\");\n else {\n setError(\"\");\n await reload();\n }\n }\n\n return (\n <div>\n <button onClick={() => router.push(\"/providers\")} className=\"mb-4 inline-flex items-center gap-1 text-[12px] text-text-muted hover:text-text\">\n <Icon name=\"arrow_back\" size={15} /> Providers\n </button>\n\n <div className=\"mb-6 flex items-center gap-3\">\n <Lamp state={provider.disabled ? \"idle\" : (health?.keys.some((k) => k.healthy) ?? true) ? \"live\" : \"down\"} />\n <div>\n <h1 className=\"text-[22px] font-semibold tracking-tight text-text\">{provider.name || provider.id}</h1>\n {provider.name && <span className=\"text-[12px] text-text-subtle\">{provider.id}/</span>}\n </div>\n <FormatBadge format={provider.format} />\n {provider.free && <Badge tone=\"info\">free</Badge>}\n {provider.service_account && <Badge tone=\"info\">service-account</Badge>}\n {/* enable/disable lives on the Providers list (one place); here we just\n flag the state. Disabled = red badge + the content below fades. */}\n {provider.disabled && <Badge tone=\"down\">disabled</Badge>}\n </div>\n\n <div className={`grid gap-4 lg:grid-cols-2 transition-opacity ${provider.disabled ? \"opacity-50\" : \"\"}`}>\n <RichCard header={<CardTitle title=\"Connection\" />}>\n {editingConn ? (\n <div className=\"space-y-3\">\n <Field label=\"Name\" hint=\"the id — also the call prefix (name/model) & combos\">\n <Input value={connPrefix} onChange={(e) => setConnPrefix(e.target.value)} placeholder=\"e.g. openai\" className=\"font-mono text-[12.5px]\" />\n </Field>\n {connPrefix.trim() && connPrefix.trim() !== id && (\n <p className=\"flex items-start gap-1.5 rounded-brand border border-warning/40 bg-warning/8 px-2.5 py-2 text-[11.5px] text-warning\">\n <Icon name=\"warning\" size={14} className=\"mt-0.5 flex-none\" />\n <span>\n Renaming rewrites the call string. CLI tools pointing at{\" \"}\n <code className=\"tnum\">{id}/…</code> will break until repointed; combos that target it are\n updated automatically.\n </span>\n </p>\n )}\n <Field label=\"Base URL\">\n <Input value={connUrl} onChange={(e) => setConnUrl(e.target.value)} placeholder=\"https://...\" className=\"font-mono text-[12.5px]\" />\n </Field>\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" onClick={() => setEditingConn(false)}>Cancel</Button>\n <Button disabled={busy === \"editconn\"} onClick={() => run(\"editconn\", async () => {\n // One identifier: Name == id == call prefix. Rename it (cascades to\n // combos, moves this page to the new id) then apply base_url.\n const newId = connPrefix.trim();\n let activeId = id;\n if (newId && newId !== id) {\n const rr = await adminApi.renameProvider(id, newId);\n if (!rr.ok) return rr;\n activeId = newId;\n }\n const r = await adminApi.editProvider(activeId, { base_url: connUrl.trim() || undefined });\n if (r.ok) {\n setEditingConn(false);\n if (activeId !== id) { router.push(`/providers/${encodeURIComponent(activeId)}`); return r; }\n }\n return r;\n })}>Save</Button>\n </div>\n </div>\n ) : (\n <>\n <div className=\"space-y-2 text-[13px]\">\n <Row k=\"Base URL\" v={provider.base_url} />\n <Row k=\"Format\" v={provider.format} />\n <Row k=\"Cooldown base\" v={`${provider.cooldown_base_ms}ms`} />\n <Row k=\"Max retries\" v={String(provider.max_retries)} />\n </div>\n <div className=\"mt-4 flex items-center gap-2\">\n <Button variant=\"ghost\" onClick={() => { setEditingConn(true); setConnUrl(provider.base_url); setConnPrefix(provider.id); }}>\n <Icon name=\"edit\" size={15} /> Edit\n </Button>\n <Button variant=\"ghost\" disabled={busy === \"test\"} onClick={() => run(\"test\", async () => {\n const r = await adminApi.testProvider(id);\n if (r.ok) setPing(r.data);\n return r;\n })}>\n <Icon name=\"wifi_tethering\" size={16} /> {busy === \"test\" ? \"Testing…\" : \"Test connection\"}\n </Button>\n <Button variant=\"ghost\" disabled={busy === \"discover\"} onClick={() => run(\"discover\", async () => {\n const r = await adminApi.discoverModels(id);\n if (r.ok) setDiscovered(r.data?.models ?? []);\n return r;\n })}>\n <Icon name=\"sync\" size={16} /> {busy === \"discover\" ? \"Fetching…\" : \"Fetch models\"}\n </Button>\n </div>\n {ping && (\n <div className=\"mt-3 text-[12px]\">\n <Badge tone={ping.ok ? \"live\" : ping.reachable ? \"warn\" : \"down\"}>\n {ping.ok ? `ok (${ping.status})` : ping.reachable ? `reachable (${ping.status})` : \"unreachable\"}\n </Badge>\n {ping.error && <span className=\"ml-2 text-text-subtle\">{ping.error}</span>}\n </div>\n )}\n </>\n )}\n </RichCard>\n\n <RichCard\n header={\n <>\n <CardTitle title=\"Keys\" sub={`${keys.length} configured`} />\n <div className=\"flex flex-wrap items-center gap-3\">\n {keys.length > 1 && (\n <Button variant=\"ghost\" disabled={testingAll} onClick={() => testAllKeys(keys.length)}>\n <Icon name={testingAll ? \"progress_activity\" : \"sync\"} size={15} />\n {testingAll ? \"Testing…\" : \"Test All\"}\n </Button>\n )}\n {testingAll && (\n <Button variant=\"ghost\" onClick={() => { stopTestAll.current = true; }}>\n <Icon name=\"stop\" size={15} /> Stop\n </Button>\n )}\n <span className=\"text-[11px] text-text-subtle\">Round Robin</span>\n <button\n onClick={() => {\n const next = provider.strategy === \"round-robin\" ? null : \"round-robin\";\n void adminApi.setProviderStrategy(id, next as \"round-robin\" | null, provider.sticky ?? 1).then(() => reload());\n }}\n className={`relative h-5 w-9 rounded-full transition-colors ${provider.strategy === \"round-robin\" ? \"bg-accent\" : \"bg-border-subtle\"}`}\n aria-label=\"Toggle round-robin\"\n >\n <span className={`absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-white transition-transform ${provider.strategy === \"round-robin\" ? \"translate-x-[18px]\" : \"translate-x-0\"}`} />\n </button>\n {provider.strategy === \"round-robin\" && (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[11px] text-text-subtle\">Sticky:</span>\n <div className=\"flex items-center rounded-brand border border-border-subtle\">\n <button\n type=\"button\"\n disabled={(provider.sticky ?? 1) <= 1}\n onClick={() => void adminApi.setProviderStrategy(id, \"round-robin\", Math.max(1, (provider.sticky ?? 1) - 1)).then(() => reload())}\n className=\"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text disabled:opacity-30\"\n aria-label=\"Decrease sticky\"\n >\n <Icon name=\"remove\" size={13} />\n </button>\n <span className=\"tnum w-6 text-center text-[11px] text-text\">{provider.sticky ?? 1}</span>\n <button\n type=\"button\"\n onClick={() => void adminApi.setProviderStrategy(id, \"round-robin\", (provider.sticky ?? 1) + 1).then(() => reload())}\n className=\"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text\"\n aria-label=\"Increase sticky\"\n >\n <Icon name=\"add\" size={13} />\n </button>\n </div>\n </div>\n )}\n </div>\n </>\n }\n >\n {testAllSummary && (\n <div className=\"mb-3 flex items-center gap-2 text-[11.5px]\">\n <Badge tone={testAllSummary.failed === 0 ? \"live\" : \"warn\"}>\n {testAllSummary.total} tested: {testAllSummary.passed} valid, {testAllSummary.failed} failed\n </Badge>\n </div>\n )}\n {keys.length === 0 ? (\n <Empty>No keys (free / service-account provider).</Empty>\n ) : (\n <div className=\"space-y-1.5\">\n {keys.map((k, i) => {\n const ks = health?.keys[i];\n const test = keyTest[i];\n const tested = test && test !== \"testing\" ? test : null;\n const lamp = tested ? (tested.ok ? \"live\" : tested.reachable ? \"idle\" : \"down\") : ks ? (ks.healthy ? \"live\" : \"down\") : \"idle\";\n const name = provider.key_names?.[k];\n const disabled = provider.disabled_keys?.includes(i) ?? false;\n if (editIdx === i) {\n return (\n <div key={i} className=\"space-y-2 rounded-brand border border-accent bg-accent-soft/40 px-3 py-2.5\">\n <Input value={editName} onChange={(e) => setEditName(e.target.value)} placeholder=\"key name (optional)\" />\n <Input value={editVal} onChange={(e) => setEditVal(e.target.value)} placeholder=\"new key value (leave blank to keep)\" className=\"font-mono text-[12.5px]\" />\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" onClick={() => setEditIdx(null)}>Cancel</Button>\n <Button disabled={busy === `editkey${i}`} onClick={() => run(`editkey${i}`, async () => {\n const r = await adminApi.editKey(id, i, { name: editName, key: editVal.trim() || undefined });\n if (r.ok) setEditIdx(null);\n return r;\n })}>Save</Button>\n </div>\n </div>\n );\n }\n return (\n <div key={i} className={`rounded-brand border border-border-subtle px-3 py-2${disabled ? \" opacity-60\" : \"\"}`}>\n <div className=\"flex items-center gap-2\">\n {/* reorder */}\n <div className=\"flex flex-col\">\n <button\n onClick={() => run(`reorder${i}up`, () => adminApi.reorderKey(id, i, i - 1))}\n disabled={i === 0}\n className=\"p-0.5 text-text-subtle hover:text-text disabled:opacity-30\"\n aria-label=\"Move up\"\n >\n <Icon name=\"keyboard_arrow_up\" size={14} />\n </button>\n <button\n onClick={() => run(`reorder${i}dn`, () => adminApi.reorderKey(id, i, i + 1))}\n disabled={i === keys.length - 1}\n className=\"p-0.5 text-text-subtle hover:text-text disabled:opacity-30\"\n aria-label=\"Move down\"\n >\n <Icon name=\"keyboard_arrow_down\" size={14} />\n </button>\n </div>\n <Lamp state={lamp} />\n <div className=\"min-w-0 flex-1\">\n {name && <div className=\"text-[12px] font-semibold text-text-muted\">{name}</div>}\n <span className=\"block truncate font-mono text-[12.5px] text-text\">{revealedKeys[i] ?? k}</span>\n </div>\n {revealedKeys[i] && (\n <button\n onClick={() => { void navigator.clipboard.writeText(revealedKeys[i]!); }}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text\"\n aria-label=\"Copy key\"\n title=\"Copy to clipboard\"\n >\n <Icon name=\"content_copy\" size={14} />\n </button>\n )}\n {ks && ks.cooldown_ms > 0 && <CooldownTimer ms={ks.cooldown_ms} />}\n {/* actions: reveal > toggle > test > edit > delete */}\n <button\n onClick={async () => {\n if (revealedKeys[i]) { setRevealedKeys((r) => { const n = { ...r }; delete n[i]; return n; }); return; }\n const r = await adminApi.revealKey(id, i);\n if (r.ok && r.data?.key) setRevealedKeys((prev) => ({ ...prev, [i]: r.data!.key }));\n }}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text\"\n aria-label={revealedKeys[i] ? \"Hide key\" : \"Show key\"}\n title={revealedKeys[i] ? \"Hide key\" : \"Show key\"}\n >\n <Icon name={revealedKeys[i] ? \"visibility_off\" : \"visibility\"} size={15} />\n </button>\n <button\n onClick={() => run(`toggle${i}`, () => adminApi.toggleKey(id, i, disabled))}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text\"\n aria-label={disabled ? \"Enable key\" : \"Disable key\"}\n title={disabled ? \"Enable this key\" : \"Disable this key\"}\n >\n <Icon name={disabled ? \"toggle_off\" : \"toggle_on\"} size={20} className={disabled ? \"text-text-subtle\" : \"text-success\"} />\n </button>\n <button\n onClick={() => testKey(i)}\n disabled={test === \"testing\"}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text disabled:opacity-60\"\n aria-label={`Check key ${i + 1}`}\n title=\"Check this key against the base URL\"\n >\n <Icon name={test === \"testing\" ? \"progress_activity\" : \"wifi_tethering\"} size={15} />\n </button>\n <button\n onClick={() => { setEditIdx(i); setEditName(name ?? \"\"); setEditVal(\"\"); }}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text\"\n aria-label={`Edit key ${i + 1}`}\n title=\"Rename or replace this key\"\n >\n <Icon name=\"edit\" size={15} />\n </button>\n <button\n onClick={() => run(`rmkey${i}`, () => adminApi.removeKey(id, i))}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-danger\"\n aria-label=\"Remove key\"\n >\n <Icon name=\"delete\" size={15} />\n </button>\n </div>\n {tested && (\n <div className=\"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]\">\n <Badge tone={tested.ok ? \"live\" : tested.reachable ? \"warn\" : \"down\"}>\n {tested.ok ? \"valid\" : tested.reachable ? `reachable (${tested.status})` : \"invalid\"}\n </Badge>\n {tested.error && <span className=\"truncate text-danger\">{tested.error}</span>}\n </div>\n )}\n {!tested && ks?.last_error && (\n <div className=\"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]\">\n <span className=\"text-danger\">{ks.last_error.status ? `${ks.last_error.status}: ` : \"\"}{ks.last_error.message}</span>\n <span className=\"text-text-subtle\">{new Date(ks.last_error.at).toLocaleTimeString()}</span>\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n <div className=\"mt-3 space-y-2\">\n <Input value={newKeyName} onChange={(e) => setNewKeyName(e.target.value)} placeholder=\"key name (optional, e.g. primary)\" />\n <div className=\"flex gap-2\">\n <Input value={newKey} onChange={(e) => setNewKey(e.target.value)} placeholder=\"add a key…\" className=\"font-mono text-[12.5px]\" />\n <Button disabled={!newKey || busy === \"addkey\"} onClick={() => run(\"addkey\", async () => {\n const r = await adminApi.addKey(id, newKey, newKeyName.trim() || undefined);\n if (r.ok) { setNewKey(\"\"); setNewKeyName(\"\"); }\n return r;\n })}>Add</Button>\n </div>\n </div>\n </RichCard>\n\n <RichCard\n className=\"lg:col-span-2\"\n header={\n <>\n <CardTitle title=\"Models served\" sub={`${provider.models.length} in catalog`} />\n {provider.models.length > 0 && (\n <button\n onClick={() => run(\"clear\", () => adminApi.clearModels(id))}\n disabled={busy === \"clear\"}\n className=\"text-[12px] text-text-subtle hover:text-danger\"\n >\n Clear all\n </button>\n )}\n </>\n }\n >\n {provider.models.length === 0 ? (\n <Empty>No models. Add one below, or fetch them for a free/auto provider.</Empty>\n ) : (\n <>\n <p className=\"mb-2.5 text-[12px] text-text-subtle\">\n Call any of these as <span className=\"tnum text-text-muted\">{provider.id}/&lt;model&gt;</span>, as a combo alias, or by the bare id.\n </p>\n {/* filter only earns its space once the catalog is long enough to scroll */}\n {provider.models.length > 8 && (\n <div className=\"mb-2.5 flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Icon name=\"search\" size={15} className=\"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-text-subtle\" />\n <Input value={modelFilter} onChange={(e) => setModelFilter(e.target.value)} placeholder=\"filter models…\" className=\"pl-8\" />\n </div>\n <span className=\"tnum whitespace-nowrap text-[12px] text-text-subtle\">\n {q ? `${shownModels.length} of ${provider.models.length}` : `${provider.models.length}`}\n </span>\n </div>\n )}\n {shownModels.length === 0 ? (\n <Empty>No model matches “{modelFilter}”.</Empty>\n ) : (\n <div className=\"max-h-[360px] divide-y divide-border-subtle overflow-y-auto rounded-brand border border-border-subtle\">\n {shownModels.map((m) => {\n const st = modelTest[m.id];\n const statusIcon = st === \"ok\" ? \"check_circle\" : st === \"fail\" ? \"cancel\" : \"smart_toy\";\n const statusColor = st === \"ok\" ? \"text-success\" : st === \"fail\" ? \"text-danger\" : \"text-text-subtle\";\n return (\n <div key={m.id} className=\"group flex items-center justify-between gap-3 px-3 py-2 hover:bg-bg\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <Icon name={statusIcon} size={15} className={`flex-none ${statusColor}`} />\n {/* the prefix (= provider id) is what makes the call string; show it aigetwey-style */}\n <span className=\"tnum truncate text-[12.5px]\">\n <span className=\"text-text-subtle\">{provider.id}/</span>\n <span className=\"text-text\">{m.id}</span>\n </span>\n <CapacityBadges model={m.id} provider={provider.id} />\n {(m.price_in !== undefined || m.price_out !== undefined) && (\n <span className=\"tnum whitespace-nowrap text-[11px] text-text-subtle\">\n {fmt.cost(m.price_in ?? 0)}/{fmt.cost(m.price_out ?? 0)} per 1M\n </span>\n )}\n </div>\n <div className=\"flex flex-none items-center gap-0.5\">\n <button\n onClick={() => testModel(m.id)}\n disabled={st === \"testing\"}\n className=\"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-accent disabled:opacity-60\"\n aria-label={`Test ${m.id}`}\n title={st === \"fail\" ? \"Test failed — click to retry\" : \"Test this model\"}\n >\n <Icon name={st === \"testing\" ? \"progress_activity\" : \"science\"} size={15} />\n </button>\n <button\n onClick={() => run(`rmmodel${m.id}`, () => adminApi.removeModel(id, m.id))}\n disabled={busy === `rmmodel${m.id}`}\n className=\"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-danger disabled:opacity-40\"\n aria-label={`Remove ${m.id}`}\n >\n <Icon name=\"delete\" size={16} />\n </button>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </>\n )}\n <div className=\"mt-3 flex gap-2\">\n <Input value={newModel} onChange={(e) => setNewModel(e.target.value)} placeholder=\"add a model id…\" />\n <Button disabled={!newModel || busy === \"addmodel\"} onClick={() => run(\"addmodel\", async () => {\n const r = await adminApi.addModel(id, newModel);\n if (r.ok) setNewModel(\"\");\n return r;\n })}>Add</Button>\n </div>\n </RichCard>\n </div>\n\n {discovered && (\n <ModelSelectModal\n models={discovered}\n busy={busy === \"addmodels\"}\n onClose={() => setDiscovered(null)}\n onAdd={(ids) => run(\"addmodels\", async () => {\n const r = await adminApi.addModels(id, ids);\n if (r.ok) setDiscovered(null);\n return r;\n })}\n />\n )}\n\n <div className=\"mt-6\">\n <Button variant=\"danger\" onClick={() => setConfirmDelete(true)}>\n <Icon name=\"delete\" size={16} /> Remove provider\n </Button>\n </div>\n\n {confirmDelete && (\n <ConfirmModal\n title=\"Remove provider\"\n message={`Delete \"${provider.name ?? id}\"? All keys and model associations will be lost.`}\n confirmLabel=\"Remove\"\n busy={busy === \"rmprov\"}\n onCancel={() => setConfirmDelete(false)}\n onConfirm={() => run(\"rmprov\", async () => {\n const r = await adminApi.removeProvider(id);\n if (r.ok) router.push(\"/providers\");\n else setConfirmDelete(false);\n return r;\n })}\n />\n )}\n </div>\n );\n}\n\nfunction Row({ k, v }: { k: string; v: string }) {\n return (\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-text-subtle\">{k}</span>\n <span className=\"truncate text-text\">{v}</span>\n </div>\n );\n}\n","import { Icon } from \"./Icon\";\n\n/**\n * Themed checkbox. Native checkboxes look out of place on the dark Haulix\n * surface, so this is a button styled to match: filled with the accent + a\n * check glyph when on, a bordered box when off. `indeterminate` renders a dash\n * for \"some selected\" (drives the select-all row).\n */\nexport function Checkbox({\n checked,\n indeterminate,\n onChange,\n className,\n ariaLabel,\n}: {\n checked: boolean;\n indeterminate?: boolean;\n onChange: () => void;\n className?: string;\n ariaLabel?: string;\n}) {\n const on = checked || indeterminate;\n return (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={indeterminate ? \"mixed\" : checked}\n aria-label={ariaLabel}\n onClick={(e) => {\n e.stopPropagation();\n onChange();\n }}\n className={`flex h-[18px] w-[18px] flex-none items-center justify-center rounded-[5px] border transition-colors ${\n on ? \"border-accent bg-accent text-accent-ink\" : \"border-border bg-bg text-transparent hover:border-text-subtle\"\n }${className ? ` ${className}` : \"\"}`}\n >\n <Icon name={indeterminate ? \"remove\" : \"check\"} size={13} />\n </button>\n );\n}\n","\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport { Button, Input } from \"@/components/Button\";\nimport { Checkbox } from \"@/components/Checkbox\";\nimport { Icon } from \"@/components/Icon\";\n\nexport interface DiscoveredModel {\n id: string;\n added: boolean; // already in the provider catalog\n}\n\n/**\n * Pick which discovered models to add. Free providers can return hundreds of\n * ids, so this is a filterable checklist (defaulting to only the not-yet-added\n * ones selected) rather than dumping everything into the catalog.\n */\nexport function ModelSelectModal({\n models,\n busy,\n onAdd,\n onClose,\n}: {\n models: DiscoveredModel[];\n busy: boolean;\n onAdd: (ids: string[]) => void;\n onClose: () => void;\n}) {\n const [filter, setFilter] = useState(\"\");\n const [picked, setPicked] = useState<Set<string>>(() => new Set(models.filter((m) => !m.added).map((m) => m.id)));\n\n const shown = useMemo(() => {\n const q = filter.trim().toLowerCase();\n return q ? models.filter((m) => m.id.toLowerCase().includes(q)) : models;\n }, [models, filter]);\n\n function toggle(id: string) {\n setPicked((s) => {\n const next = new Set(s);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }\n\n const shownPickedCount = shown.filter((m) => picked.has(m.id)).length;\n const allShownPicked = shown.length > 0 && shownPickedCount === shown.length;\n const someShownPicked = shownPickedCount > 0 && !allShownPicked;\n function toggleAllShown() {\n setPicked((s) => {\n const next = new Set(s);\n if (allShownPicked) shown.forEach((m) => next.delete(m.id));\n else shown.forEach((m) => next.add(m.id));\n return next;\n });\n }\n\n return (\n <div className=\"fixed inset-0 z-50 grid place-items-center bg-black/50 p-6\" onClick={onClose}>\n <div\n className=\"flex max-h-[80vh] w-full max-w-[480px] flex-col overflow-hidden rounded-brand-lg border border-border bg-surface shadow-elevated\"\n onClick={(e) => e.stopPropagation()}\n >\n <header className=\"flex items-center justify-between border-b border-border-subtle px-4 py-3\">\n <span className=\"text-[14px] font-semibold text-text\">{models.length} models found</span>\n <button onClick={onClose} className=\"text-text-subtle hover:text-text\" aria-label=\"Close\">\n <Icon name=\"close\" size={18} />\n </button>\n </header>\n\n <div className=\"border-b border-border-subtle px-4 py-2.5\">\n <Input value={filter} onChange={(e) => setFilter(e.target.value)} placeholder=\"filter…\" autoFocus />\n </div>\n\n {/* select-all row: an obvious clickable control, not an ambiguous button */}\n {shown.length > 0 && (\n <button\n onClick={toggleAllShown}\n className=\"flex items-center gap-2.5 border-b border-border-subtle px-4 py-2 text-left hover:bg-surface-2\"\n >\n <Checkbox checked={allShownPicked} indeterminate={someShownPicked} onChange={toggleAllShown} ariaLabel=\"Select all\" />\n <span className=\"text-[12.5px] font-medium text-text\">Select all{filter ? \" (filtered)\" : \"\"}</span>\n <span className=\"ml-auto tnum text-[11px] text-text-subtle\">\n {shownPickedCount}/{shown.length}\n </span>\n </button>\n )}\n\n <div className=\"flex-1 overflow-y-auto px-2 py-2\">\n {shown.length === 0 ? (\n <div className=\"px-2 py-6 text-center text-[13px] text-text-muted\">No matches.</div>\n ) : (\n shown.map((m) => {\n const sel = picked.has(m.id);\n return (\n <button\n key={m.id}\n onClick={() => toggle(m.id)}\n className={`flex w-full items-center gap-2.5 rounded-brand border px-2.5 py-2 text-left transition-colors ${\n sel ? \"border-accent/40 bg-accent-soft\" : \"border-transparent hover:bg-surface-2\"\n }`}\n >\n <Checkbox checked={sel} onChange={() => toggle(m.id)} ariaLabel={m.id} />\n <span className=\"flex-1 truncate text-[12.5px] text-text\">{m.id}</span>\n {m.added && <span className=\"text-[11px] text-text-subtle\">in catalog</span>}\n </button>\n );\n })\n )}\n </div>\n\n <footer className=\"flex items-center justify-between gap-3 border-t border-border-subtle bg-bg-alt px-4 py-2.5\">\n <span className=\"tnum text-[12px] text-text-muted\">{picked.size} selected</span>\n <div className=\"flex gap-2\">\n <Button variant=\"ghost\" onClick={onClose}>\n Cancel\n </Button>\n <Button disabled={picked.size === 0 || busy} onClick={() => onAdd([...picked])}>\n {busy ? \"Adding…\" : `Add ${picked.size}`}\n </Button>\n </div>\n </footer>\n </div>\n </div>\n );\n}\n"],"names":["Checkbox","checked","indeterminate","onChange","className","ariaLabel","on","type","role","onClick","e","stopPropagation","name","size"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/components/ProviderDetail.tsx","../../../../src/components/Checkbox.tsx","../../../../src/components/ModelSelectModal.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState, useCallback, useRef } from \"react\";\nimport { useRouter } from \"next/navigation\";\nimport { adminApi } from \"@/lib/client\";\nimport { Lamp } from \"@/components/Lamp\";\nimport { Badge, FormatBadge } from \"@/components/Badge\";\nimport { CooldownTimer } from \"@/components/CooldownTimer\";\nimport { RichCard, CardTitle } from \"@/components/RichCard\";\nimport { Button, Input, Field } from \"@/components/Button\";\nimport { Icon } from \"@/components/Icon\";\nimport { fmt, Empty } from \"@/components/ui\";\nimport { ModelSelectModal, type DiscoveredModel } from \"@/components/ModelSelectModal\";\nimport { CapacityBadges } from \"@/components/CapacityBadges\";\nimport { ConfirmModal } from \"@/components/ConfirmModal\";\nimport type { MaskedConfig, MaskedProvider, ProviderSnapshot, PingResult } from \"@/lib/gateway\";\n\nexport function ProviderDetail({ id }: { id: string }) {\n const router = useRouter();\n const [provider, setProvider] = useState<MaskedProvider | null>(null);\n const [health, setHealth] = useState<ProviderSnapshot | null>(null);\n const [error, setError] = useState(\"\");\n const [ping, setPing] = useState<PingResult | null>(null);\n const [busy, setBusy] = useState(\"\");\n const [newKey, setNewKey] = useState(\"\");\n const [newKeyName, setNewKeyName] = useState(\"\");\n const [editIdx, setEditIdx] = useState<number | null>(null);\n const [editName, setEditName] = useState(\"\");\n const [editVal, setEditVal] = useState(\"\");\n const [newModel, setNewModel] = useState(\"\");\n const [modelFilter, setModelFilter] = useState(\"\");\n const [discovered, setDiscovered] = useState<DiscoveredModel[] | null>(null);\n const [modelTest, setModelTest] = useState<Record<string, \"testing\" | \"ok\" | \"fail\">>({});\n const [keyTest, setKeyTest] = useState<Record<number, \"testing\" | PingResult>>({});\n const [testingAll, setTestingAll] = useState(false);\n const [testAllSummary, setTestAllSummary] = useState<{ total: number; passed: number; failed: number } | null>(null);\n const stopTestAll = useRef(false);\n const [editingConn, setEditingConn] = useState(false);\n const [connUrl, setConnUrl] = useState(\"\");\n const [connPrefix, setConnPrefix] = useState(\"\");\n const [connLabel, setConnLabel] = useState(\"\");\n const [revealedKeys, setRevealedKeys] = useState<Record<number, string>>({});\n const [confirmDelete, setConfirmDelete] = useState(false);\n\n async function testModel(mid: string) {\n setModelTest((t) => ({ ...t, [mid]: \"testing\" }));\n const r = await adminApi.testModel(id, mid);\n setModelTest((t) => ({ ...t, [mid]: r.ok && r.data?.ok ? \"ok\" : \"fail\" }));\n }\n\n async function testKey(i: number) {\n setKeyTest((t) => ({ ...t, [i]: \"testing\" }));\n const r = await adminApi.testKey(id, i);\n setKeyTest((t) => ({ ...t, [i]: r.data ?? { ok: false, reachable: false, status: 0, error: r.error } }));\n }\n\n async function testAllKeys(count: number) {\n stopTestAll.current = false;\n setTestingAll(true);\n setTestAllSummary(null);\n setKeyTest({});\n let passed = 0;\n let failed = 0;\n for (let i = 0; i < count; i++) {\n if (stopTestAll.current) break;\n setKeyTest((t) => ({ ...t, [i]: \"testing\" }));\n const r = await adminApi.testKey(id, i);\n const result = r.data ?? { ok: false, reachable: false, status: 0, error: r.error };\n setKeyTest((t) => ({ ...t, [i]: result }));\n if (result.ok) passed++;\n else failed++;\n if (i < count - 1 && !stopTestAll.current) await new Promise((resolve) => setTimeout(resolve, 500));\n }\n setTestingAll(false);\n setTestAllSummary({ total: count, passed, failed });\n }\n\n const reload = useCallback(async () => {\n const [cfgRes, provRes] = await Promise.all([fetch(\"/api/gw/admin/config\"), adminApi.providers()]);\n if (!cfgRes.ok) {\n setError(\"could not reach the gateway\");\n return;\n }\n const cfg = (await cfgRes.json()) as MaskedConfig;\n const p = cfg.providers.find((x) => x.id === id) ?? null;\n if (!p) {\n setError(`provider \"${id}\" not found`);\n return;\n }\n setError(\"\");\n setProvider(p);\n setHealth(provRes.data?.providers.find((x) => x.id === id) ?? null);\n }, [id]);\n\n useEffect(() => {\n void reload();\n }, [reload]);\n\n if (error) return <Empty>{error}</Empty>;\n if (!provider) return <Empty>Loading…</Empty>;\n\n const keys = provider.api_keys ?? (provider.api_key ? [provider.api_key] : []);\n const q = modelFilter.trim().toLowerCase();\n const shownModels = q ? provider.models.filter((m) => m.id.toLowerCase().includes(q)) : provider.models;\n\n async function run(label: string, fn: () => Promise<{ ok: boolean; error?: string }>) {\n setBusy(label);\n const res = await fn();\n setBusy(\"\");\n if (!res.ok) setError(res.error ?? \"action failed\");\n else {\n setError(\"\");\n await reload();\n }\n }\n\n return (\n <div>\n <button onClick={() => router.push(\"/providers\")} className=\"mb-4 inline-flex items-center gap-1 text-[12px] text-text-muted hover:text-text\">\n <Icon name=\"arrow_back\" size={15} /> Providers\n </button>\n\n <div className=\"mb-6 flex items-center gap-3\">\n <Lamp state={provider.disabled ? \"idle\" : (health?.keys.some((k) => k.healthy) ?? true) ? \"live\" : \"down\"} />\n <div>\n <h1 className=\"text-[22px] font-semibold tracking-tight text-text\">{provider.name || provider.id}</h1>\n {provider.name && <span className=\"text-[12px] text-text-subtle\">{provider.id}/</span>}\n </div>\n <FormatBadge format={provider.format} />\n {provider.free && <Badge tone=\"info\">free</Badge>}\n {provider.service_account && <Badge tone=\"info\">service-account</Badge>}\n {/* enable/disable lives on the Providers list (one place); here we just\n flag the state. Disabled = red badge + the content below fades. */}\n {provider.disabled && <Badge tone=\"down\">disabled</Badge>}\n </div>\n\n <div className={`grid gap-4 lg:grid-cols-2 transition-opacity ${provider.disabled ? \"opacity-50\" : \"\"}`}>\n <RichCard header={<CardTitle title=\"Connection\" />}>\n {editingConn ? (\n <div className=\"space-y-3\">\n <Field label=\"Label\" hint=\"display name in dashboard (optional, does not affect routing)\">\n <Input value={connLabel} onChange={(e) => setConnLabel(e.target.value)} placeholder={connPrefix || \"e.g. My Provider\"} className=\"text-[12.5px]\" />\n </Field>\n <Field label=\"ID / Prefix\" hint=\"the call prefix (id/model) — changing this breaks CLI tools\">\n <Input value={connPrefix} onChange={(e) => setConnPrefix(e.target.value)} placeholder=\"e.g. openai\" className=\"font-mono text-[12.5px]\" />\n </Field>\n {connPrefix.trim() && connPrefix.trim() !== id && (\n <p className=\"flex items-start gap-1.5 rounded-brand border border-warning/40 bg-warning/8 px-2.5 py-2 text-[11.5px] text-warning\">\n <Icon name=\"warning\" size={14} className=\"mt-0.5 flex-none\" />\n <span>\n Renaming rewrites the call string. CLI tools pointing at{\" \"}\n <code className=\"tnum\">{id}/…</code> will break until repointed; combos that target it are\n updated automatically.\n </span>\n </p>\n )}\n <Field label=\"Base URL\">\n <Input value={connUrl} onChange={(e) => setConnUrl(e.target.value)} placeholder=\"https://...\" className=\"font-mono text-[12.5px]\" />\n </Field>\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" onClick={() => setEditingConn(false)}>Cancel</Button>\n <Button disabled={busy === \"editconn\"} onClick={() => run(\"editconn\", async () => {\n const newId = connPrefix.trim();\n let activeId = id;\n if (newId && newId !== id) {\n const rr = await adminApi.renameProvider(id, newId);\n if (!rr.ok) return rr;\n activeId = newId;\n }\n const newName = connLabel.trim() || undefined;\n const r = await adminApi.editProvider(activeId, { base_url: connUrl.trim() || undefined, name: newName });\n if (r.ok) {\n setEditingConn(false);\n if (activeId !== id) { router.push(`/providers/${encodeURIComponent(activeId)}`); return r; }\n }\n return r;\n })}>Save</Button>\n </div>\n </div>\n ) : (\n <>\n <div className=\"space-y-2 text-[13px]\">\n {provider.name && <Row k=\"Label\" v={provider.name} />}\n <Row k=\"ID / Prefix\" v={provider.id} />\n <Row k=\"Base URL\" v={provider.base_url} />\n <Row k=\"Format\" v={provider.format} />\n <Row k=\"Cooldown base\" v={`${provider.cooldown_base_ms}ms`} />\n <Row k=\"Max retries\" v={String(provider.max_retries)} />\n </div>\n <div className=\"mt-4 flex items-center gap-2\">\n <Button variant=\"ghost\" onClick={() => { setEditingConn(true); setConnUrl(provider.base_url); setConnPrefix(provider.id); setConnLabel(provider.name ?? \"\"); }}>\n <Icon name=\"edit\" size={15} /> Edit\n </Button>\n <Button variant=\"ghost\" disabled={busy === \"test\"} onClick={() => run(\"test\", async () => {\n const r = await adminApi.testProvider(id);\n if (r.ok) setPing(r.data);\n return r;\n })}>\n <Icon name=\"wifi_tethering\" size={16} /> {busy === \"test\" ? \"Testing…\" : \"Test connection\"}\n </Button>\n <Button variant=\"ghost\" disabled={busy === \"discover\"} onClick={() => run(\"discover\", async () => {\n const r = await adminApi.discoverModels(id);\n if (r.ok) setDiscovered(r.data?.models ?? []);\n return r;\n })}>\n <Icon name=\"sync\" size={16} /> {busy === \"discover\" ? \"Fetching…\" : \"Fetch models\"}\n </Button>\n </div>\n {ping && (\n <div className=\"mt-3 text-[12px]\">\n <Badge tone={ping.ok ? \"live\" : ping.reachable ? \"warn\" : \"down\"}>\n {ping.ok ? `ok (${ping.status})` : ping.reachable ? `reachable (${ping.status})` : \"unreachable\"}\n </Badge>\n {ping.error && <span className=\"ml-2 text-text-subtle\">{ping.error}</span>}\n </div>\n )}\n </>\n )}\n </RichCard>\n\n <RichCard\n header={\n <>\n <CardTitle title=\"Keys\" sub={`${keys.length} configured`} />\n <div className=\"flex flex-wrap items-center gap-3\">\n {keys.length > 1 && (\n <Button variant=\"ghost\" disabled={testingAll} onClick={() => testAllKeys(keys.length)}>\n <Icon name={testingAll ? \"progress_activity\" : \"sync\"} size={15} />\n {testingAll ? \"Testing…\" : \"Test All\"}\n </Button>\n )}\n {testingAll && (\n <Button variant=\"ghost\" onClick={() => { stopTestAll.current = true; }}>\n <Icon name=\"stop\" size={15} /> Stop\n </Button>\n )}\n <span className=\"text-[11px] text-text-subtle\">Round Robin</span>\n <button\n onClick={() => {\n const next = provider.strategy === \"round-robin\" ? null : \"round-robin\";\n void adminApi.setProviderStrategy(id, next as \"round-robin\" | null, provider.sticky ?? 1).then(() => reload());\n }}\n className={`relative h-5 w-9 rounded-full transition-colors ${provider.strategy === \"round-robin\" ? \"bg-accent\" : \"bg-border-subtle\"}`}\n aria-label=\"Toggle round-robin\"\n >\n <span className={`absolute left-0.5 top-0.5 h-4 w-4 rounded-full bg-white transition-transform ${provider.strategy === \"round-robin\" ? \"translate-x-[18px]\" : \"translate-x-0\"}`} />\n </button>\n {provider.strategy === \"round-robin\" && (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[11px] text-text-subtle\">Sticky:</span>\n <div className=\"flex items-center rounded-brand border border-border-subtle\">\n <button\n type=\"button\"\n disabled={(provider.sticky ?? 1) <= 1}\n onClick={() => void adminApi.setProviderStrategy(id, \"round-robin\", Math.max(1, (provider.sticky ?? 1) - 1)).then(() => reload())}\n className=\"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text disabled:opacity-30\"\n aria-label=\"Decrease sticky\"\n >\n <Icon name=\"remove\" size={13} />\n </button>\n <span className=\"tnum w-6 text-center text-[11px] text-text\">{provider.sticky ?? 1}</span>\n <button\n type=\"button\"\n onClick={() => void adminApi.setProviderStrategy(id, \"round-robin\", (provider.sticky ?? 1) + 1).then(() => reload())}\n className=\"px-1.5 py-0.5 text-text-subtle transition-colors hover:text-text\"\n aria-label=\"Increase sticky\"\n >\n <Icon name=\"add\" size={13} />\n </button>\n </div>\n </div>\n )}\n </div>\n </>\n }\n >\n {testAllSummary && (\n <div className=\"mb-3 flex items-center gap-2 text-[11.5px]\">\n <Badge tone={testAllSummary.failed === 0 ? \"live\" : \"warn\"}>\n {testAllSummary.total} tested: {testAllSummary.passed} valid, {testAllSummary.failed} failed\n </Badge>\n </div>\n )}\n {keys.length === 0 ? (\n <Empty>No keys (free / service-account provider).</Empty>\n ) : (\n <div className=\"space-y-1.5\">\n {keys.map((k, i) => {\n const ks = health?.keys[i];\n const test = keyTest[i];\n const tested = test && test !== \"testing\" ? test : null;\n const lamp = tested ? (tested.ok ? \"live\" : tested.reachable ? \"idle\" : \"down\") : ks ? (ks.healthy ? \"live\" : \"down\") : \"idle\";\n const name = provider.key_names?.[k];\n const disabled = provider.disabled_keys?.includes(i) ?? false;\n if (editIdx === i) {\n return (\n <div key={i} className=\"space-y-2 rounded-brand border border-accent bg-accent-soft/40 px-3 py-2.5\">\n <Input value={editName} onChange={(e) => setEditName(e.target.value)} placeholder=\"key name (optional)\" />\n <Input value={editVal} onChange={(e) => setEditVal(e.target.value)} placeholder=\"new key value (leave blank to keep)\" className=\"font-mono text-[12.5px]\" />\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"ghost\" onClick={() => setEditIdx(null)}>Cancel</Button>\n <Button disabled={busy === `editkey${i}`} onClick={() => run(`editkey${i}`, async () => {\n const r = await adminApi.editKey(id, i, { name: editName, key: editVal.trim() || undefined });\n if (r.ok) setEditIdx(null);\n return r;\n })}>Save</Button>\n </div>\n </div>\n );\n }\n return (\n <div key={i} className={`rounded-brand border border-border-subtle px-3 py-2${disabled ? \" opacity-60\" : \"\"}`}>\n <div className=\"flex items-center gap-2\">\n {/* reorder */}\n <div className=\"flex flex-col\">\n <button\n onClick={() => run(`reorder${i}up`, () => adminApi.reorderKey(id, i, i - 1))}\n disabled={i === 0}\n className=\"p-0.5 text-text-subtle hover:text-text disabled:opacity-30\"\n aria-label=\"Move up\"\n >\n <Icon name=\"keyboard_arrow_up\" size={14} />\n </button>\n <button\n onClick={() => run(`reorder${i}dn`, () => adminApi.reorderKey(id, i, i + 1))}\n disabled={i === keys.length - 1}\n className=\"p-0.5 text-text-subtle hover:text-text disabled:opacity-30\"\n aria-label=\"Move down\"\n >\n <Icon name=\"keyboard_arrow_down\" size={14} />\n </button>\n </div>\n <Lamp state={lamp} />\n <div className=\"min-w-0 flex-1\">\n {name && <div className=\"text-[12px] font-semibold text-text-muted\">{name}</div>}\n <span className=\"block truncate font-mono text-[12.5px] text-text\">{revealedKeys[i] ?? k}</span>\n </div>\n {revealedKeys[i] && (\n <button\n onClick={() => { void navigator.clipboard.writeText(revealedKeys[i]!); }}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text\"\n aria-label=\"Copy key\"\n title=\"Copy to clipboard\"\n >\n <Icon name=\"content_copy\" size={14} />\n </button>\n )}\n {ks && ks.cooldown_ms > 0 && <CooldownTimer ms={ks.cooldown_ms} />}\n {/* actions: reveal > toggle > test > edit > delete */}\n <button\n onClick={async () => {\n if (revealedKeys[i]) { setRevealedKeys((r) => { const n = { ...r }; delete n[i]; return n; }); return; }\n const r = await adminApi.revealKey(id, i);\n if (r.ok && r.data?.key) setRevealedKeys((prev) => ({ ...prev, [i]: r.data!.key }));\n }}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text\"\n aria-label={revealedKeys[i] ? \"Hide key\" : \"Show key\"}\n title={revealedKeys[i] ? \"Hide key\" : \"Show key\"}\n >\n <Icon name={revealedKeys[i] ? \"visibility_off\" : \"visibility\"} size={15} />\n </button>\n <button\n onClick={() => run(`toggle${i}`, () => adminApi.toggleKey(id, i, disabled))}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text\"\n aria-label={disabled ? \"Enable key\" : \"Disable key\"}\n title={disabled ? \"Enable this key\" : \"Disable this key\"}\n >\n <Icon name={disabled ? \"toggle_off\" : \"toggle_on\"} size={20} className={disabled ? \"text-text-subtle\" : \"text-success\"} />\n </button>\n <button\n onClick={() => testKey(i)}\n disabled={test === \"testing\"}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text disabled:opacity-60\"\n aria-label={`Check key ${i + 1}`}\n title=\"Check this key against the base URL\"\n >\n <Icon name={test === \"testing\" ? \"progress_activity\" : \"wifi_tethering\"} size={15} />\n </button>\n <button\n onClick={() => { setEditIdx(i); setEditName(name ?? \"\"); setEditVal(\"\"); }}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-text\"\n aria-label={`Edit key ${i + 1}`}\n title=\"Rename or replace this key\"\n >\n <Icon name=\"edit\" size={15} />\n </button>\n <button\n onClick={() => run(`rmkey${i}`, () => adminApi.removeKey(id, i))}\n className=\"flex-none rounded p-1 text-text-subtle transition-colors hover:text-danger\"\n aria-label=\"Remove key\"\n >\n <Icon name=\"delete\" size={15} />\n </button>\n </div>\n {tested && (\n <div className=\"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]\">\n <Badge tone={tested.ok ? \"live\" : tested.reachable ? \"warn\" : \"down\"}>\n {tested.ok ? \"valid\" : tested.reachable ? `reachable (${tested.status})` : \"invalid\"}\n </Badge>\n {tested.error && <span className=\"truncate text-danger\">{tested.error}</span>}\n </div>\n )}\n {!tested && ks?.last_error && (\n <div className=\"mt-1.5 flex items-center gap-2 pl-8 text-[11.5px]\">\n <span className=\"text-danger\">{ks.last_error.status ? `${ks.last_error.status}: ` : \"\"}{ks.last_error.message}</span>\n <span className=\"text-text-subtle\">{new Date(ks.last_error.at).toLocaleTimeString()}</span>\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n <div className=\"mt-3 space-y-2\">\n <Input value={newKeyName} onChange={(e) => setNewKeyName(e.target.value)} placeholder=\"key name (optional, e.g. primary)\" />\n <div className=\"flex gap-2\">\n <Input value={newKey} onChange={(e) => setNewKey(e.target.value)} placeholder=\"add a key…\" className=\"font-mono text-[12.5px]\" />\n <Button disabled={!newKey || busy === \"addkey\"} onClick={() => run(\"addkey\", async () => {\n const r = await adminApi.addKey(id, newKey, newKeyName.trim() || undefined);\n if (r.ok) { setNewKey(\"\"); setNewKeyName(\"\"); }\n return r;\n })}>Add</Button>\n </div>\n </div>\n </RichCard>\n\n <RichCard\n className=\"lg:col-span-2\"\n header={\n <>\n <CardTitle title=\"Models served\" sub={`${provider.models.length} in catalog`} />\n {provider.models.length > 0 && (\n <button\n onClick={() => run(\"clear\", () => adminApi.clearModels(id))}\n disabled={busy === \"clear\"}\n className=\"text-[12px] text-text-subtle hover:text-danger\"\n >\n Clear all\n </button>\n )}\n </>\n }\n >\n {provider.models.length === 0 ? (\n <Empty>No models. Add one below, or fetch them for a free/auto provider.</Empty>\n ) : (\n <>\n <p className=\"mb-2.5 text-[12px] text-text-subtle\">\n Call any of these as <span className=\"tnum text-text-muted\">{provider.id}/&lt;model&gt;</span>, as a combo alias, or by the bare id.\n </p>\n {/* filter only earns its space once the catalog is long enough to scroll */}\n {provider.models.length > 8 && (\n <div className=\"mb-2.5 flex items-center gap-2\">\n <div className=\"relative flex-1\">\n <Icon name=\"search\" size={15} className=\"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-text-subtle\" />\n <Input value={modelFilter} onChange={(e) => setModelFilter(e.target.value)} placeholder=\"filter models…\" className=\"pl-8\" />\n </div>\n <span className=\"tnum whitespace-nowrap text-[12px] text-text-subtle\">\n {q ? `${shownModels.length} of ${provider.models.length}` : `${provider.models.length}`}\n </span>\n </div>\n )}\n {shownModels.length === 0 ? (\n <Empty>No model matches “{modelFilter}”.</Empty>\n ) : (\n <div className=\"max-h-[360px] divide-y divide-border-subtle overflow-y-auto rounded-brand border border-border-subtle\">\n {shownModels.map((m) => {\n const st = modelTest[m.id];\n const statusIcon = st === \"ok\" ? \"check_circle\" : st === \"fail\" ? \"cancel\" : \"smart_toy\";\n const statusColor = st === \"ok\" ? \"text-success\" : st === \"fail\" ? \"text-danger\" : \"text-text-subtle\";\n return (\n <div key={m.id} className=\"group flex items-center justify-between gap-3 px-3 py-2 hover:bg-bg\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <Icon name={statusIcon} size={15} className={`flex-none ${statusColor}`} />\n {/* the prefix (= provider id) is what makes the call string; show it aigetwey-style */}\n <span className=\"tnum truncate text-[12.5px]\">\n <span className=\"text-text-subtle\">{provider.id}/</span>\n <span className=\"text-text\">{m.id}</span>\n </span>\n <CapacityBadges model={m.id} provider={provider.id} />\n {(m.price_in !== undefined || m.price_out !== undefined) && (\n <span className=\"tnum whitespace-nowrap text-[11px] text-text-subtle\">\n {fmt.cost(m.price_in ?? 0)}/{fmt.cost(m.price_out ?? 0)} per 1M\n </span>\n )}\n </div>\n <div className=\"flex flex-none items-center gap-0.5\">\n <button\n onClick={() => testModel(m.id)}\n disabled={st === \"testing\"}\n className=\"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-accent disabled:opacity-60\"\n aria-label={`Test ${m.id}`}\n title={st === \"fail\" ? \"Test failed — click to retry\" : \"Test this model\"}\n >\n <Icon name={st === \"testing\" ? \"progress_activity\" : \"science\"} size={15} />\n </button>\n <button\n onClick={() => run(`rmmodel${m.id}`, () => adminApi.removeModel(id, m.id))}\n disabled={busy === `rmmodel${m.id}`}\n className=\"rounded p-1 text-text-subtle transition-colors hover:bg-surface hover:text-danger disabled:opacity-40\"\n aria-label={`Remove ${m.id}`}\n >\n <Icon name=\"delete\" size={16} />\n </button>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </>\n )}\n <div className=\"mt-3 flex gap-2\">\n <Input value={newModel} onChange={(e) => setNewModel(e.target.value)} placeholder=\"add a model id…\" />\n <Button disabled={!newModel || busy === \"addmodel\"} onClick={() => run(\"addmodel\", async () => {\n const r = await adminApi.addModel(id, newModel);\n if (r.ok) setNewModel(\"\");\n return r;\n })}>Add</Button>\n </div>\n </RichCard>\n </div>\n\n {discovered && (\n <ModelSelectModal\n models={discovered}\n busy={busy === \"addmodels\"}\n onClose={() => setDiscovered(null)}\n onAdd={(ids) => run(\"addmodels\", async () => {\n const r = await adminApi.addModels(id, ids);\n if (r.ok) setDiscovered(null);\n return r;\n })}\n />\n )}\n\n <div className=\"mt-6\">\n <Button variant=\"danger\" onClick={() => setConfirmDelete(true)}>\n <Icon name=\"delete\" size={16} /> Remove provider\n </Button>\n </div>\n\n {confirmDelete && (\n <ConfirmModal\n title=\"Remove provider\"\n message={`Delete \"${provider.name ?? id}\"? All keys and model associations will be lost.`}\n confirmLabel=\"Remove\"\n busy={busy === \"rmprov\"}\n onCancel={() => setConfirmDelete(false)}\n onConfirm={() => run(\"rmprov\", async () => {\n const r = await adminApi.removeProvider(id);\n if (r.ok) router.push(\"/providers\");\n else setConfirmDelete(false);\n return r;\n })}\n />\n )}\n </div>\n );\n}\n\nfunction Row({ k, v }: { k: string; v: string }) {\n return (\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-text-subtle\">{k}</span>\n <span className=\"truncate text-text\">{v}</span>\n </div>\n );\n}\n","import { Icon } from \"./Icon\";\n\n/**\n * Themed checkbox. Native checkboxes look out of place on the dark Haulix\n * surface, so this is a button styled to match: filled with the accent + a\n * check glyph when on, a bordered box when off. `indeterminate` renders a dash\n * for \"some selected\" (drives the select-all row).\n */\nexport function Checkbox({\n checked,\n indeterminate,\n onChange,\n className,\n ariaLabel,\n}: {\n checked: boolean;\n indeterminate?: boolean;\n onChange: () => void;\n className?: string;\n ariaLabel?: string;\n}) {\n const on = checked || indeterminate;\n return (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={indeterminate ? \"mixed\" : checked}\n aria-label={ariaLabel}\n onClick={(e) => {\n e.stopPropagation();\n onChange();\n }}\n className={`flex h-[18px] w-[18px] flex-none items-center justify-center rounded-[5px] border transition-colors ${\n on ? \"border-accent bg-accent text-accent-ink\" : \"border-border bg-bg text-transparent hover:border-text-subtle\"\n }${className ? ` ${className}` : \"\"}`}\n >\n <Icon name={indeterminate ? \"remove\" : \"check\"} size={13} />\n </button>\n );\n}\n","\"use client\";\n\nimport { useState, useMemo } from \"react\";\nimport { Button, Input } from \"@/components/Button\";\nimport { Checkbox } from \"@/components/Checkbox\";\nimport { Icon } from \"@/components/Icon\";\n\nexport interface DiscoveredModel {\n id: string;\n added: boolean; // already in the provider catalog\n}\n\n/**\n * Pick which discovered models to add. Free providers can return hundreds of\n * ids, so this is a filterable checklist (defaulting to only the not-yet-added\n * ones selected) rather than dumping everything into the catalog.\n */\nexport function ModelSelectModal({\n models,\n busy,\n onAdd,\n onClose,\n}: {\n models: DiscoveredModel[];\n busy: boolean;\n onAdd: (ids: string[]) => void;\n onClose: () => void;\n}) {\n const [filter, setFilter] = useState(\"\");\n const [picked, setPicked] = useState<Set<string>>(() => new Set(models.filter((m) => !m.added).map((m) => m.id)));\n\n const shown = useMemo(() => {\n const q = filter.trim().toLowerCase();\n return q ? models.filter((m) => m.id.toLowerCase().includes(q)) : models;\n }, [models, filter]);\n\n function toggle(id: string) {\n setPicked((s) => {\n const next = new Set(s);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }\n\n const shownPickedCount = shown.filter((m) => picked.has(m.id)).length;\n const allShownPicked = shown.length > 0 && shownPickedCount === shown.length;\n const someShownPicked = shownPickedCount > 0 && !allShownPicked;\n function toggleAllShown() {\n setPicked((s) => {\n const next = new Set(s);\n if (allShownPicked) shown.forEach((m) => next.delete(m.id));\n else shown.forEach((m) => next.add(m.id));\n return next;\n });\n }\n\n return (\n <div className=\"fixed inset-0 z-50 grid place-items-center bg-black/50 p-6\" onClick={onClose}>\n <div\n className=\"flex max-h-[80vh] w-full max-w-[480px] flex-col overflow-hidden rounded-brand-lg border border-border bg-surface shadow-elevated\"\n onClick={(e) => e.stopPropagation()}\n >\n <header className=\"flex items-center justify-between border-b border-border-subtle px-4 py-3\">\n <span className=\"text-[14px] font-semibold text-text\">{models.length} models found</span>\n <button onClick={onClose} className=\"text-text-subtle hover:text-text\" aria-label=\"Close\">\n <Icon name=\"close\" size={18} />\n </button>\n </header>\n\n <div className=\"border-b border-border-subtle px-4 py-2.5\">\n <Input value={filter} onChange={(e) => setFilter(e.target.value)} placeholder=\"filter…\" autoFocus />\n </div>\n\n {/* select-all row: an obvious clickable control, not an ambiguous button */}\n {shown.length > 0 && (\n <button\n onClick={toggleAllShown}\n className=\"flex items-center gap-2.5 border-b border-border-subtle px-4 py-2 text-left hover:bg-surface-2\"\n >\n <Checkbox checked={allShownPicked} indeterminate={someShownPicked} onChange={toggleAllShown} ariaLabel=\"Select all\" />\n <span className=\"text-[12.5px] font-medium text-text\">Select all{filter ? \" (filtered)\" : \"\"}</span>\n <span className=\"ml-auto tnum text-[11px] text-text-subtle\">\n {shownPickedCount}/{shown.length}\n </span>\n </button>\n )}\n\n <div className=\"flex-1 overflow-y-auto px-2 py-2\">\n {shown.length === 0 ? (\n <div className=\"px-2 py-6 text-center text-[13px] text-text-muted\">No matches.</div>\n ) : (\n shown.map((m) => {\n const sel = picked.has(m.id);\n return (\n <button\n key={m.id}\n onClick={() => toggle(m.id)}\n className={`flex w-full items-center gap-2.5 rounded-brand border px-2.5 py-2 text-left transition-colors ${\n sel ? \"border-accent/40 bg-accent-soft\" : \"border-transparent hover:bg-surface-2\"\n }`}\n >\n <Checkbox checked={sel} onChange={() => toggle(m.id)} ariaLabel={m.id} />\n <span className=\"flex-1 truncate text-[12.5px] text-text\">{m.id}</span>\n {m.added && <span className=\"text-[11px] text-text-subtle\">in catalog</span>}\n </button>\n );\n })\n )}\n </div>\n\n <footer className=\"flex items-center justify-between gap-3 border-t border-border-subtle bg-bg-alt px-4 py-2.5\">\n <span className=\"tnum text-[12px] text-text-muted\">{picked.size} selected</span>\n <div className=\"flex gap-2\">\n <Button variant=\"ghost\" onClick={onClose}>\n Cancel\n </Button>\n <Button disabled={picked.size === 0 || busy} onClick={() => onAdd([...picked])}>\n {busy ? \"Adding…\" : `Add ${picked.size}`}\n </Button>\n </div>\n </footer>\n </div>\n </div>\n );\n}\n"],"names":["Checkbox","checked","indeterminate","onChange","className","ariaLabel","on","type","role","onClick","e","stopPropagation","name","size"],"mappings":"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"}