From 0e15988233081520f179cd9302909ad181325f58 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Fri, 24 Apr 2026 16:58:14 -0300 Subject: [PATCH] feat(providers): register codex auto review and expand icon coverage Add the Codex Auto Review model to the provider registry and prefer Codex when resolving unprefixed `codex-auto-review` and `gpt-5.5` requests. Broaden provider icon mappings and bundled PNG assets so more providers render correctly in the shared UI. Also tighten chatCore stream cleanup behavior so streaming responses return immediately while semaphore slots and model locks are released on completion or failure, with tests and artifact policy coverage updated accordingly. --- open-sse/config/providerRegistry.ts | 1 + open-sse/handlers/chatCore.ts | 186 +++++++++++------- open-sse/services/model.ts | 9 + public/providers/aws-polly.png | Bin 0 -> 1734 bytes public/providers/blackbox-web.png | Bin 0 -> 1259 bytes public/providers/cliproxyapi.png | Bin 0 -> 1297 bytes public/providers/databricks.png | Bin 0 -> 2307 bytes public/providers/empower.png | Bin 0 -> 1374 bytes public/providers/gigachat.png | Bin 0 -> 3202 bytes public/providers/gitlab-duo.png | Bin 0 -> 1196 bytes public/providers/gitlab.png | Bin 0 -> 1196 bytes public/providers/heroku.png | Bin 0 -> 1787 bytes public/providers/linkup-search.png | Bin 0 -> 2249 bytes public/providers/llamagate.png | Bin 0 -> 2315 bytes public/providers/maritalk.png | Bin 0 -> 1742 bytes public/providers/modal.png | Bin 0 -> 2705 bytes public/providers/nanogpt.png | Bin 0 -> 3262 bytes public/providers/nscale.png | Bin 0 -> 1713 bytes public/providers/oci.png | Bin 0 -> 1243 bytes public/providers/ovhcloud.png | Bin 0 -> 1167 bytes public/providers/piapi.png | Bin 0 -> 1616 bytes public/providers/poe.png | Bin 0 -> 2509 bytes public/providers/predibase.png | Bin 0 -> 2091 bytes public/providers/qoder.png | Bin 10327 -> 1934 bytes public/providers/recraft.png | Bin 0 -> 1176 bytes public/providers/reka.png | Bin 0 -> 2492 bytes public/providers/runwayml.png | Bin 0 -> 1218 bytes public/providers/triton.png | Bin 0 -> 1829 bytes public/providers/venice.png | Bin 0 -> 1372 bytes public/providers/voyage-ai.png | Bin 0 -> 1223 bytes public/providers/wandb.png | Bin 0 -> 1242 bytes public/providers/youcom-search.png | Bin 0 -> 3024 bytes scripts/i18n_autotranslate.py | 2 +- src/shared/components/ProviderIcon.tsx | 57 ++++++ tests/unit/chatcore-translation-paths.test.ts | 149 ++++++++++++++ tests/unit/pack-artifact-policy.test.ts | 2 + 36 files changed, 336 insertions(+), 70 deletions(-) create mode 100644 public/providers/aws-polly.png create mode 100644 public/providers/blackbox-web.png create mode 100644 public/providers/cliproxyapi.png create mode 100644 public/providers/databricks.png create mode 100644 public/providers/empower.png create mode 100644 public/providers/gigachat.png create mode 100644 public/providers/gitlab-duo.png create mode 100644 public/providers/gitlab.png create mode 100644 public/providers/heroku.png create mode 100644 public/providers/linkup-search.png create mode 100644 public/providers/llamagate.png create mode 100644 public/providers/maritalk.png create mode 100644 public/providers/modal.png create mode 100644 public/providers/nanogpt.png create mode 100644 public/providers/nscale.png create mode 100644 public/providers/oci.png create mode 100644 public/providers/ovhcloud.png create mode 100644 public/providers/piapi.png create mode 100644 public/providers/poe.png create mode 100644 public/providers/predibase.png create mode 100644 public/providers/recraft.png create mode 100644 public/providers/reka.png create mode 100644 public/providers/runwayml.png create mode 100644 public/providers/triton.png create mode 100644 public/providers/venice.png create mode 100644 public/providers/voyage-ai.png create mode 100644 public/providers/wandb.png create mode 100644 public/providers/youcom-search.png diff --git a/open-sse/config/providerRegistry.ts b/open-sse/config/providerRegistry.ts index a8cfac03b0..efb4174f06 100644 --- a/open-sse/config/providerRegistry.ts +++ b/open-sse/config/providerRegistry.ts @@ -480,6 +480,7 @@ export const REGISTRY: Record = { tokenUrl: "https://auth.openai.com/oauth/token", }, models: [ + { id: "codex-auto-review", name: "Codex Auto Review", targetFormat: "openai-responses" }, { id: "gpt-5.5", name: "GPT 5.5", targetFormat: "openai-responses" }, { id: "gpt-5.4", name: "GPT 5.4", targetFormat: "openai-responses" }, { id: "gpt-5.4-mini", name: "GPT 5.4 Mini", targetFormat: "openai-responses" }, diff --git a/open-sse/handlers/chatCore.ts b/open-sse/handlers/chatCore.ts index e7fbeba6fd..e52cd50c05 100644 --- a/open-sse/handlers/chatCore.ts +++ b/open-sse/handlers/chatCore.ts @@ -24,7 +24,7 @@ import { parseUpstreamError, formatProviderError, } from "../utils/error.ts"; -import { HTTP_STATUS, PROVIDER_MAX_TOKENS } from "../config/constants.ts"; +import { COOLDOWN_MS, HTTP_STATUS, PROVIDER_MAX_TOKENS } from "../config/constants.ts"; import { classifyProviderError, PROVIDER_ERROR_TYPES, @@ -96,6 +96,7 @@ import { buildAccountSemaphoreKey, markBlocked as markAccountSemaphoreBlocked, } from "../services/accountSemaphore.ts"; +import { lockModelIfPerModelQuota } from "../services/accountFallback.ts"; import { generateSignature, getCachedResponse, @@ -490,6 +491,45 @@ function isSemaphoreTimeoutError(error: unknown): error is Error & { code: strin ); } +function wrapReadableStreamWithFinalize( + readable: ReadableStream, + finalize: () => void +): ReadableStream { + const reader = readable.getReader(); + let finalized = false; + + const runFinalize = () => { + if (finalized) return; + finalized = true; + finalize(); + }; + + return new ReadableStream({ + async pull(controller) { + try { + const { done, value } = await reader.read(); + if (done) { + runFinalize(); + controller.close(); + return; + } + controller.enqueue(value); + } catch (error) { + runFinalize(); + controller.error(error); + } + }, + + async cancel(reason) { + try { + await reader.cancel(reason); + } finally { + runFinalize(); + } + }, + }); +} + function resolveAccountSemaphoreAccountKey( connectionId: string | null | undefined, credentials: Record | null | undefined @@ -1968,82 +2008,90 @@ export async function handleChatCore({ }) : () => {}; - const rawResult = await withRateLimit(provider, connectionId, modelToCall, async () => { - let attempts = 0; - const maxAttempts = provider === "qwen" ? 3 : 1; + try { + const rawResult = await withRateLimit(provider, connectionId, modelToCall, async () => { + let attempts = 0; + const maxAttempts = provider === "qwen" ? 3 : 1; - while (attempts < maxAttempts) { - const res = await executor.execute({ - model: modelToCall, - body: bodyToSend, - stream: upstreamStream, - credentials: executionCredentials, - signal: streamController.signal, - log, - extendedContext, - upstreamExtraHeaders: buildUpstreamHeadersForExecute(modelToCall), - clientHeaders: buildExecutorClientHeaders(clientRawRequest?.headers, userAgent), - onCredentialsRefreshed, - }); + while (attempts < maxAttempts) { + const res = await executor.execute({ + model: modelToCall, + body: bodyToSend, + stream: upstreamStream, + credentials: executionCredentials, + signal: streamController.signal, + log, + extendedContext, + upstreamExtraHeaders: buildUpstreamHeadersForExecute(modelToCall), + clientHeaders: buildExecutorClientHeaders(clientRawRequest?.headers, userAgent), + onCredentialsRefreshed, + }); - // Qwen 429 strict quota backoff (wait 1.5s, 3s and retry) - if (provider === "qwen" && res.response.status === 429 && attempts < maxAttempts - 1) { - const bodyPeek = await res.response - .clone() - .text() - .catch(() => ""); - if (bodyPeek.toLowerCase().includes("exceeded your current quota")) { - const delay = 1500 * (attempts + 1); - log?.warn?.("QWEN_RETRY", `Quota 429 hit. Retrying in ${delay}ms...`); - await new Promise((r) => setTimeout(r, delay)); - attempts++; - continue; + // Qwen 429 strict quota backoff (wait 1.5s, 3s and retry) + if (provider === "qwen" && res.response.status === 429 && attempts < maxAttempts - 1) { + const bodyPeek = await res.response + .clone() + .text() + .catch(() => ""); + if (bodyPeek.toLowerCase().includes("exceeded your current quota")) { + const delay = 1500 * (attempts + 1); + log?.warn?.("QWEN_RETRY", `Quota 429 hit. Retrying in ${delay}ms...`); + await new Promise((r) => setTimeout(r, delay)); + attempts++; + continue; + } } - } - // For streaming: wrap response body to release semaphore only when stream is fully consumed - if (stream) { - const originalBody = res.response.body; - const wrappedBody = originalBody - ? originalBody.pipeThrough( - new TransformStream({ - flush: () => { - acquireAccountSemaphoreRelease(); - }, - }) - ) - : null; - return { - ...res, - response: new Response(wrappedBody, { - status: res.response.status, - statusText: res.response.statusText, - headers: res.response.headers, - }), - }; - } + // For streaming: release the semaphore when the client drains or cancels the stream. + if (stream) { + const originalBody = res.response.body; + if (!originalBody) { + acquireAccountSemaphoreRelease(); + return res; + } - return res; + return { + ...res, + response: new Response( + wrapReadableStreamWithFinalize(originalBody, acquireAccountSemaphoreRelease), + { + status: res.response.status, + statusText: res.response.statusText, + headers: res.response.headers, + } + ), + }; + } + + return res; + } + }); + + if (stream) { + return rawResult; } - }); - // Non-stream: release semaphore immediately after reading full response body - const status = rawResult.response.status; - const statusText = rawResult.response.statusText; - const headers = Array.from(rawResult.response.headers.entries()) as [string, string][]; - const payload = await rawResult.response.text(); - acquireAccountSemaphoreRelease(); + // Non-stream: release semaphore immediately after reading full response body. + const status = rawResult.response.status; + const statusText = rawResult.response.statusText; + const headers = Array.from(rawResult.response.headers.entries()) as [string, string][]; + const payload = await rawResult.response.text(); + acquireAccountSemaphoreRelease(); - return { - ...rawResult, - response: new Response(payload, { status, statusText, headers }), - _dedupSnapshot: { - status, - statusText, - headers, - payload, - }, - }; + return { + ...rawResult, + response: new Response(payload, { status, statusText, headers }), + _dedupSnapshot: { + status, + statusText, + headers, + payload, + }, + }; + } catch (error) { + acquireAccountSemaphoreRelease(); + throw error; + } }; if (allowDedup && dedupEnabled && dedupHash) { diff --git a/open-sse/services/model.ts b/open-sse/services/model.ts index 5c5e7bb470..6719d1431c 100644 --- a/open-sse/services/model.ts +++ b/open-sse/services/model.ts @@ -73,6 +73,7 @@ for (const [aliasOrId, models] of Object.entries(PROVIDER_MODELS)) { } } const KNOWN_MODEL_IDS = new Set(MODEL_TO_PROVIDERS.keys()); +const CODEX_PREFERRED_UNPREFIXED_MODELS = new Set(["codex-auto-review", "gpt-5.5"]); /** * Resolve provider alias to provider ID @@ -286,6 +287,14 @@ function resolveModelByProviderInference(modelId, extendedContext) { } const nonOpenAIProviders = providers.filter((p) => p !== "openai"); + if (providers.includes("codex") && CODEX_PREFERRED_UNPREFIXED_MODELS.has(modelId)) { + return { + provider: "codex", + model: modelId, + extendedContext, + }; + } + if (nonOpenAIProviders.length === 1) { const provider = nonOpenAIProviders[0]; const canonicalModel = resolveProviderModelAlias(provider, modelId); diff --git a/public/providers/aws-polly.png b/public/providers/aws-polly.png new file mode 100644 index 0000000000000000000000000000000000000000..7bc66fa485b2aa5eaba731ed8191d8b1bf5d7e6b GIT binary patch literal 1734 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 VG77706Q2M8002ovPDHLkV1gSWLjV8( literal 0 HcmV?d00001 diff --git a/public/providers/cliproxyapi.png b/public/providers/cliproxyapi.png new file mode 100644 index 0000000000000000000000000000000000000000..4aaacd3118e97383b8fb0723cc3e5203b411c0e7 GIT binary patch literal 1297 zcmV+s1@8KZP)dB1PnCfYKsGMR6F^k#Xcniaz`7-{c=aJA=a$jv|ccI8rXH zLPvojlwQ&Xnl@>YCOIeDht)s}Z3sp9W-`rb_u1=P-&*@y-9iO%6Krp%Rb0Nb42KZ5 zV`xQa6>wMs40sq42njI^;`2j3&$;A9nXjx7fTms(4d!{*7ET%H6lekJ0T;o=V6BA! zLK#CI$QwgSgi&DFFLS0?$3U`A<{f}wjvm|M6mU|Y0kD^*v1Tao2oMorBk&f`ZCiwb zc`V}QlHGLFM1x_z1-=FvVU5|=1`BY3t(G7Wm+O}6avX@GnZGVH7{h)EbJD`$GoXW| zvcG!RA~ajj;{aW#^e?`P1r1S%t%vndh`8Veq3FT*G>nYHn{BYA4YGL{yafwIFxpr3 z2-_WFXcNJGk)WXRDH?P=uMZ*1S-HsTsI+ zUzJ!n#VQ0gHNnvX@YSc#(FUQw^1qinNM-b>-JO7Y6OeeMl6yX+voM*2VyQamX9$RB zrU!Pzu^z2=1?944`8epLHrBrr`gu6Jy392baBO&^8IHaK2j5;EJe}2`=Lg`z6}bIC z3B4?q5r~B0^TV)jn;J?5nJiqm3g4ZD@uW(+n{MZSW9N&j|1@i#V1); zYpRzb;5b@>$YS<>8Rq8U@=dt*j~YqM8{2Bxj;-&l){xIMVO-2jlP`&9aODEx`X7!N9b^80?hN_ca zMj*EU=db9%iEmW`u?F~Hzn+Bgq^|LNeHKxfqweA;4ned|dt@f9$26VOQr1KuUw~f+ zb6_d2nkK z&R)`^cI+UuH>o1KwrB}vGf!r^F-pYq)qXQMxIL;yHJhmt6+kE(Ls>R|Va7z*06aeV zp#ZpHt>fWN=-R1j1RQm|i6lIlgIobJ^DyyHtvHp@5*0ly(Q}YBhLj`1BoJOopit7! zd``Rf#)vjzz)=;ldHv~m8Z4XFz=cvxfh$-5rW_IO7()z*J-woG49BKx-n3>In87e; zm0`dbrUC!|53?$Kfl(38S%EVBVlf2Fy+#6aSPbV~&RJoX1Qw?e`hgiC0000dP)t-sM{rF4 zFdF|d8~-&P|1=)|Gadgl9se{Q|1=)|G#>vn9{)5R|1}>aR?x=)000eiQchC<4j#s~ zFhp6TfRk<65ZNvq000PnNkl>*N)?I6Sx-(j{ zO+xlg;5;7xUmsj1U4LeNdd6#-{scoXKQGI&Ez1lL{>J`m4cBV}2tP((l6~)-^D83w z9fV*V%x_@dS{o3c6MlpNKR#Lq^KiL{VSfH55ZU?G?!mN;Ai}?LAii%N?K`{gJA8Wd z1N=KU;oGTTqW4SitqV&aEQIhMdr5^aVxZs$iw@(yz?Jd=-0{^l8SH~C%sl7Q=Z0#? zed1Ce?ze8xzE8pTkoD+nbj+IXtmV#~<}vv3J0af53cDMz*_fA<3U`5ED?i4*iL_za z;Zjw&GZ5tb{PC&mmG{R0A%^sn=PvrpdipvK5so45toB3?EJ>F6<5Z}seq8Ha-xh+h zcQFJrkD(n@d?Ow≻oRSznOdUJJf_{!voFQz|T1Q^92Wqu^^l%Vcqxqw3(l^CCjP z8RE@U5R~uOOHTeeLMROJHc6Fq-uEltApD1~cqb4dio3lg`DjhXmqY~T-a&bcLL(QH z3yI9u&>NMJ1z!~PD+@_fk?6-U0Hifq#2?l&o(jmHgZCs_&3f+^nVD0;4*@VfOPPBM zo8+LrqBHZ$l#VtBKSrNX{^x{>>tUINfNAPEC$hUW4cLnp6HpDKnTd&gf4i!KFX86r zxel%gnuk@MFDdIRoR+OwlL0^~T6-#5U$9RJ2|fKHm&Ei84v6;cxr%YwJ|>#;n>11Y zxNkW?QjB{^03ifPPC8nEcY-KI5$*4`27qlB7J=CF-I|A@Z?GBw#zG_Ud(l2?AFUDs zE&-F8ysg=1om=Gh80r?l12U0>z-`TbjD31-lJ>z99RP(rz1jj^FmJ>gVV<#V+bg(0 z1)z?*QkqZ8ha?!`P?*Lda6K@Q(~P*aR-8!olZL=4gD9bED;gkhCu^Ftc04WG=C!o{l{D zS{cn{7H?OI2mrX9_d^r+8oV|~wU-KIIO8ey!oDo>l_n$rT1(b4gwitcUbqu{F>a(Ezv=4dl7tI2E9Hvaa$t_*rbWIcyMsh1f&`oynlk zjV_hvxyY(M(86vY|Hv;;oeZ_&B$oWoFrB(OH!M%um{t z(kK5+EX0uGr4|T2Z*qf81O{MA1dumJ8eN!luGqLlwv;8Z%zOA2lTPWT0EnW6(YdAz z*{aXAE5)|TSapj@y)u9lp{xZkbDg3Knc_*gBGwC*@1m$0FIJ8)6@ZXygZL5cuYNrY zzM4m7s+A27L9y_xzH(N+G9F;4B1BtER%|hG@b!!+0q~WL=V2HT<5Rw@-CtB{3CxHZ zF2F*xR0+?!+LGzzeh5|lacqB4tETFVD6^q$en48FmkL}=8@clPw6OYiMuc=sE@RMW zvY|2=jo)bP&=yON7M!k#HgAszplkwlCb(jM5t2`(g^g%IpAnU`ZI+d?A1Gd4?=N;V zK`vemfTU(Sp`N014^rV|@M%QUHYUwB(NNTs+GmW|8_|PL8%S0SL1_l<-e14;0N=^s zBB3uR$@w6+Q~*$ZbC8BwfN2}WHGE^Ds;KZgtud)0>E+h%L8##n$+ltpIMxJ_H(*J3 zhEy$Fl>o$wSl4ul#$}0C6-LIY*sKg@M2W}c*1@Et0%mJGN5p3c)uUWjU|aVb&WM!F zlP=pK-}ar=o;;W!(*^*@&BIln2w$5cHNj_X#BfH$2tZl&B^9^#1xa|g$a1C z1Hdp|sR%$B3}D%a;4`y44I z>{ZrE6M`no8Q+<1Rchy8M#QL6sh=r0a|7UL@3<3N?*4iPR6W4E$ygbh&ZG>X?64W+ zqQ@vMdNr#Br#RwFQtQGe)ptjFq^kuY1}wkI4XrZxo?z5M&C0L*j<&+_8BwnKav71( z8lFiSogoo@pT#x`u5yS_qXi!P(b;3u$9D$m>R6F~F8w&lNashSblDxKf+;~>uTd~-eSQPt!d&KK9jMjm=q zz}?1P7wtYh6QwnS;#_ffz-XPIzvo=B=m2_?52ofTA$`-|TZH#N`QUGKw!Gg;T!%md zhJHz_nkiRL+djO+fr3MZa5^n~e6j4-x*aOb=gy#C#~=m=lnP=7bovbX6$oN*khKpx zCv=kXuLCHf-lG0+mn+MI^_3c%Z`gmd%?}uSy;x$Lru>gEJn76h81-lM-hB}GJ~>|B z4t@oo>K1Q4hWs{!bgrTr1N;I*-p=>GbH0R-rc_vV|K{(0ao=wFVel&iD2V>-FRu{; d7bO4Y^&d>5smKptylDUc002ovPDHLkV1o6LR=fZJ literal 0 HcmV?d00001 diff --git a/public/providers/empower.png b/public/providers/empower.png new file mode 100644 index 0000000000000000000000000000000000000000..1540ddb37d896e873cc6532f3129d396379c662b GIT binary patch literal 1374 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 AeEC0000aP)t-sM{rE! zNGR!1DD`0{>sBc4UMJ^DDDYz^`I095Z6@MFDg2`*QfPji00009bW%=J06iM_k7&`c z_D=d(Q~&@3E=fc|RCt{2TgjHAFboU^LQMYue+L2vBWv{nhn~81KUpfPN(Msmdi@6m zHx9$-p3CRn^MZFZ2IhS8j#>n)`MR*6t5e^c?;RFQbqGu$-&+^&=3_w>7r0|X$`%Yq z{5;kmFrN7a)q*p=js{bdP!r$H#sw1Md>Rb~>jD9n4JkBmaeNI8rb|NE*5f6A6=NCRua)PjW?U(Bx71Bx-D)Bw8%wv4=Ef9Q;mGsYSS7HosahN1^RESWl#lE6?$!A#?kvBcdyO8Vp%Q&kY>X_>z6(gH z>6Mad)dZ}Nf8zvNGy$*EzwrN8r$CmW2~=f3S78X$a{?i=NT3!2u0BtojtqPSY6_|~ zLCP-?C}kj~M^C~lO6rTrr*J#aqzTgY{dz+HuZ9&FDC#d)!%h>HC4(k!zucC-HGvrn zRB7MmJz-@Es=jXbgc=i=8EA9<9t@OZ4PMk|+#U_J;aUdj`hI&jbovD<8T8ru{UZvk z4Rs6*$&L?c3~MAA4Bgxw%#1ErQEB_Z0owzzX(8PNQ=0glfitb77?|4c{pGV-^=Y)D zc>DVq6n#`#%)po+c>!RvK_Y{({T_K~WM$wh*DqpVT}iw@xB4K+VBLPIf52!?l~cdx zzQd8hz`CO6-@ut=_!#5G_iwiA!sq+7F;KjFa=N?JP=A3wUiWPfr=G{}4sHCTeF3YR zhR^qaN(RpTNfQ(dqWUTZg8L!FY4`$2@#eSB{4{)EeW?iN&EwVL|tzhJTRUB0000< KMNUMnLSTaQfgj%h literal 0 HcmV?d00001 diff --git a/public/providers/gitlab.png b/public/providers/gitlab.png new file mode 100644 index 0000000000000000000000000000000000000000..8dfcb517800620eccece4360ab023eabbdc9c7d4 GIT binary patch literal 1196 zcmV;d1XKHoP)C0000aP)t-sM{rE! zNGR!1DD`0{>sBc4UMJ^DDDYz^`I095Z6@MFDg2`*QfPji00009bW%=J06iM_k7&`c z_D=d(Q~&@3E=fc|RCt{2TgjHAFboU^LQMYue+L2vBWv{nhn~81KUpfPN(Msmdi@6m zHx9$-p3CRn^MZFZ2IhS8j#>n)`MR*6t5e^c?;RFQbqGu$-&+^&=3_w>7r0|X$`%Yq z{5;kmFrN7a)q*p=js{bdP!r$H#sw1Md>Rb~>jD9n4JkBmaeNI8rb|NE*5f6A6=NCRua)PjW?U(Bx71Bx-D)Bw8%wv4=Ef9Q;mGsYSS7HosahN1^RESWl#lE6?$!A#?kvBcdyO8Vp%Q&kY>X_>z6(gH z>6Mad)dZ}Nf8zvNGy$*EzwrN8r$CmW2~=f3S78X$a{?i=NT3!2u0BtojtqPSY6_|~ zLCP-?C}kj~M^C~lO6rTrr*J#aqzTgY{dz+HuZ9&FDC#d)!%h>HC4(k!zucC-HGvrn zRB7MmJz-@Es=jXbgc=i=8EA9<9t@OZ4PMk|+#U_J;aUdj`hI&jbovD<8T8ru{UZvk z4Rs6*$&L?c3~MAA4Bgxw%#1ErQEB_Z0owzzX(8PNQ=0glfitb77?|4c{pGV-^=Y)D zc>DVq6n#`#%)po+c>!RvK_Y{({T_K~WM$wh*DqpVT}iw@xB4K+VBLPIf52!?l~cdx zzQd8hz`CO6-@ut=_!#5G_iwiA!sq+7F;KjFa=N?JP=A3wUiWPfr=G{}4sHCTeF3YR zhR^qaN(RpTNfQ(dqWUTZg8L!FY4`$2@#eSB{4{)EeW?iN&EwVL|tzhJTRUB0000< KMNUMnLSTaQfgj%h literal 0 HcmV?d00001 diff --git a/public/providers/heroku.png b/public/providers/heroku.png new file mode 100644 index 0000000000000000000000000000000000000000..b96cb3f6a7d8e5a23715db2ec7cc7ed05914e9ae GIT binary patch literal 1787 zcmb7Ec{H0@8^3Qtg2obS(ApZMwn)o_*ouyl9<&H*X)3DI##F~XC}ob$r;BP@>C}=b zgBnULsb!34>SJmtLy#JbVv@!(6baq=UUQ~r&iwg3_m6wd{hj+;o_o);J-$5yR45)^ z9sq&>fZzqTCqXulN1^4=D0w-woPvVhh(g8O!~iTn+LFRAQNOFAuK>( zAtV;s?gF~7K?HKg>ZgJL3LztlM#7+z3P3;zge+QKR{n1oLLg;iu_&}EvBA*hctl)$ zshZK=gRWW3+rt_M++v@oYvSDx`%!1-;Op8j?Z2quejsHKvM_|l!m@uA@{=^oOq9W@ z9x!xOJFXrP>$W`sFffR~BC)^)EOG?r=segyzyLV_#sMx1;DByHCIoK)r~s&*h_D7I z06eD*4go;63*41*wX=NL@lJp+zghI%e9*{Do$rWzr+&#qH?LPIiSW&I1h&Hb=@CAu zvDD)AMWr=St@Lh7OhjY}kio~O!1BDd#rK8N$;_EZQJPzEQK<1x1!0aEb+uI!7kxu) zhTb--b}7C5Pw>`nxg$ls^cVbo$p>dgg%r)T%6D^;RVn9JKS`|vHwf2$)>W)~_REeD zQHHi|>&7B`>$#t^MwxrP3?9U&z>%#cI$pN0g|o*b&&CwRJ}lf;pZIrv^#@+b@j zcoF`GqVvLAp*-pDTAdyJ|BcjP(jHMIiyH}qi^~ru6U?jp5*a=fUiLn5akn!BFZM5VC9V$fm;m5(vmv|^fn_SePnqFK%Jta761Z3Nn>JL?yJ4Lr+u53Pkh$gzrrzVVfj5- zGoRoj2@=21BIOq+1#aC*^}of+E1-$6N);WK>9+RK)Y795NG3Buj)foXCEp5duubAQ zd*^BwX{=-2{Dc#^++~v;pxFLJ9nEU$z??=_2@9DZud z%w6`Nb{ZwX%*#KXk|2?s=7@xLy*Dgr`5_I~8{BQcd}->}#Po2`w0*2OTDmeFJvTUe z#{PKjH5K^r+uYnw0gQ5!?$U!)4bx+-Y%*0Z{<>c1$&W(s=z~+8pqKoyi1fdEJlr1f6K36sI z{O(b0&-#hc<*0ZEz0EMiFxt7~JO4;#Ha+$~oxK{@xavr%lEr zuB@n!{Vb?}Ndzs|)XRA(Y2mh7cD3UQG1CU?BKLu#9Px@FlbQBBAaHHPM>t3gK zrb128*>ldU!KIjAG5KY#Vr{{ccueoIAo&`a_L+C|`+(e|*sL7wp$+NJ(O1;Uk4^}L zDHe+{jc?g`X;!F*R-$RAA5mi^a)38wXqXA0&D^oCLq?k}AJMVJSJ>5c3I6O^yYc=A z?Lrpc{S=*-C9iGQ>viGU07U=z=9i$x=OUM?dv8W#XO%Jz=DmotS#Xo|h$ueC*T0J1 zu()qF;`4*i?)&|!0Cd;G9RqN4Q7Fr71F$n>0VWh66S6Z64Zt(Zp)B|eg2ynf9vJ9v G|MowrC;2%5 literal 0 HcmV?d00001 diff --git a/public/providers/linkup-search.png b/public/providers/linkup-search.png new file mode 100644 index 0000000000000000000000000000000000000000..43452df5754df4f06132208aa4c0c53561a4998c GIT binary patch literal 2249 zcmV;)2sZbLP)C0003LP)t-s|Ns9~ zz5gVm>i?(!|6wP3-O0x!bymTx;FSXENDZA5R!+PBSHJ%No#`p2?EC%y|Dyoh@c%}& z_`M%)|N8jt`uF=|C++wDd&>XmL;z&N|K#%hnE+4UkpRXSabCx>{M5+*@95k0@cHcB z`Q^v7-1z(N^{d?f&rgf(!PkSw^W253{rCI-`RmS&s{75p|Fxd~S`_``+wNa6@{Don zHvr1%|NDhu|8z(Cz_0&nH|y8n*Ppt|ah%S8q~gQV?ZbxWqZ{z8GyKw&-m=EeUX<&v zNd2uQ|IUHBV~O_Fp8xUK?w$dwD`@GlTGw!&|GQ4PNPqd>vz7ov<)6U*!e7rlhQ#XP z_nm?7aZsDy(Ra)Et4G`njrLV9U zX!@i;S}0oT?NTy!I9;ReiGPCDWGEOMW$qsk^!v}YXY;SuAqHO_F*GP9mxBMLy#I(o2?m+}I)kR? z8GPnGKS3*>2p_IQ{}BUK{~oVDWngCpXP?CHk8qLghOH&pKVhJl2c5Q{KV{&h7AI?f z|3>R`YVe{5_aFa!b+gGn$xX97In(0{8WfFmUUMMy3F00kft zoKk}$Pyj;UyGkCqb4&o8_pkYh!SfSDfW`$~;?ExFpFkxBVN=dP8iS-9T|yZct{>0`0m8ohKj((3sGjcm-yFY7zuU1c(F)fzvfafJS4;5jd9#{G~#GDj*3U z5|9-T2*@d*qyQ^Jk^o`|WdAG#XbvisA}b+a$Pu8m5GTNr@Ej$el7t-tt^(;ctes#4 zeozBi2<1(nR0_=iQ6N2zXd#mPx7dOB0o#QtIY^QK&H+{i$XSFCXt1ti`)dylfl34j z?3jR5hqCiHkpLBdNB|O0K960f4x|}Cuz3ib1V3_Z+50QG4yYc61fd}j(1LthIF#!^ zYm#q{x8fl1hw-&y0AdE>HqZjTIX@L8XdUvM@z%R5p&KdVKhmI?JB&0|E0W=wk5kkj0?YxHtt2#$V6-{eI-Ue|=o8E05uZ zzU}C`6L^+~lqrmU?skdy2(Mqic_mX=nLea=ys)rPmV$4j_oKKR+v1>Tu)n*QU_Qd@ zJuwg)kD3341RG`iX9EIyJrM^K2fN+8f5Kq(C1-H+Q1D-hfj^hZ&zb_w$!joRpU?ag ztd5GlzZ3&Y9MI&O@(81yuH>JKf(iLwSWwIZQ%~cM3@CozmHiV2uTldp|1wO~2zc=Q zJWIrNAOJDgR!9TD`&SHtX|n)`^8q%X*aHH>&;i8(Ccyk^ zLSO|appu150r6^9o`CFMiGYVrNb2_ypdqN?1XM!cHn9|7Nx0fY2nb0yD**$Wkg)6N zEk;1thO+;uN^3#~6u^u~C`6Kfu@K1wZWR0{H&bvxA(UcS0al7v?*2g;NDm`vKoO=E z$zg;Fz$BPa0Bk@Z9mk^od{cA>5>WI{&qHijA7KDUz%?Xs5N0|H6GX*`A5b`acOJK7 z-1iGDS#%;lp4mUqpq-aM;|Dac20OcaJ2Vmu%qh>HY+LLG&9;{OWT$Bk(v~ytU|UWy zF-KsA%Sp$#ofrW!pjiL8xBrGCX@GHPH-Owr;)R`U6_q|S$K}ZbT**0MqBrhoDoDh7(VTSC9h2e{@3-}e923AT6 zV3F0?4Yh8EfPs@yiyT9PH>i6xb(p?1 zps@Kb2*f7_B7>ZN+E-{L7-XM^^aH*;LD1^?M6l8kPp+|2W)R9RIQWjpl0L7_&rnQm z#FSdVxhlbIr~l0jC^C&5X!-oFO7I(q{5KTA2ba(NY?qF3#I})1kSQdz*1&E81VCR< zFa>SIAWbt5egsmN8!HGd@_nhqX^6xZ2C2m8Cph@KvFmV4wr1m`qZuF}g*NsRI zbBh@WFDL?0J*(Yp78-O&6!IeuyOe+O1-6k6D8RNnd19d@Pb?sVT1X9|6`V3XG5dc% zuyyjUwhzolVhUa|!U%jMxWpicEYKD1gW2i0Zl@@9iAAU2W~N|Jp+bcU6)IGy@ZaNa X!CK~4HO;3Y00000NkvXXu0mjfwy-Px literal 0 HcmV?d00001 diff --git a/public/providers/llamagate.png b/public/providers/llamagate.png new file mode 100644 index 0000000000000000000000000000000000000000..2fe71a5a2254537e8ccf5086e88883ad3b9cd3e1 GIT binary patch literal 2315 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 b9xbP*q<6?ik=3&eeuex&KK;)?*kgYKggpG2 literal 0 HcmV?d00001 diff --git a/public/providers/maritalk.png b/public/providers/maritalk.png new file mode 100644 index 0000000000000000000000000000000000000000..c80425a0ef93d0a1e9b052fa40e60976ec69ad79 GIT binary patch literal 1742 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 literal 0 HcmV?d00001 diff --git a/public/providers/nscale.png b/public/providers/nscale.png new file mode 100644 index 0000000000000000000000000000000000000000..cb6cdf41ea24051db9a13270fac7401167e383b5 GIT binary patch literal 1713 zcmV;i22S~jP)C0000sP)t-sM{rCJ zKIZ@b{|-Ff4?yt`LGunj><>Zm4?*z{K=BPZ)1R^PaE$N(DAZPS>!-N%%GCBMQs#vZ z7?c12019+cPE!E?|NoT#|L#}LHeM7{000IcNkltfn4429YLCIi43+Ak^T(3WOS5un6Y3UE2bo39i)lO>i~9r9J4n@LGWT)d1Fk zOJ|{*hyMXCU5DIC^dI0~2e@DLj`-gM0JszYVCbiJ$#6gG?EskZ$3Q6BuH`830`WXH;-5K%wut0I~_k1C;s!06jPypwf>HoCQ$pTL48Y zI2b_CPXKTRfTZsL)JXs^2>KZSjs}qRJwUeLK!6#20sw~s%;{SIO)S_6pnk70t4{!S za{#7cFdSiCKLV)z0AP5HHhPM%pifHxdjP;NzFdqiB!DG->VRd~4B+&~m;dThCoJka zfJ9)n1El<&1)~YBF6$Ej`*_$0;Pn&2IE2D3>r)3d1CabZfFD#^|0Mvmy$7=XhyZFO z{{WzOaUl0!q_BhPReb~qUAO^&`|k|UszE;hpatIpRQmn9Nk0RqO#qVqyG7pubRRkZ zW}1qnKIxA{U$^N;2Xs4t{jJu;1ngLqf2)3Wps@td#~AW!?iT$|0Z_m1O7??EZOIe!MQ04k;$TPH2WSXg})kn__&~Ltc44-iYx^&q_b?1e*NqIDBMd z-}q`BE97nnV-lMi<4vEH<(&oWkJkafhE|#djuemts%8!xsdm8l&kYqQ2Nr&cKIr(A zPA7zKA(%dQ01PAx!V*y%L5dSdzQ>6Anw>)uEJzV3s5<@&+5w1s>$+wrTn6q008I7( z8T5RhA;>^L8Y-Y92TBB~5*3DUQ=ULfKOpeac#wcq!e0`F;v%JPSJY=w-;MUmh`@!wSz6CVWbB;u^DhC8ni&EvKcilllc&tAW?m}Dp*J1%xcz$fuX1a zGb0Yf97)43V8nT?%9GoH`M@Tm*pL||t7dubN$!&bt<If0#_NmWp+kVgj|(iV>>Ppd#$a<(Iu>cdEA@J%kU0dgl4 z2ufNRKH$hJ7;ORR1pknKGNO2WDvR(b4YlAQZFEW=U>V4KP{apF`h;L{t`uvBd+^*= zFPx028Ou%p1(XWA6K}QIg8S`+^Gb0xR=pVJBkHjJz@;-*W}d@6j%>Ru3Xo?bp(sgI zS{on^n2s=8#Il3~koDzl7HLI{uMWy6W&xiXbiq>0qCEuW$XKoE*fEZd@FqQZD984|wNJAdyy?>rlb10eJyOI|n_I+a-fs^0cH z(+HS7E=q=pnbHwuI8Avcm@>QfT0GYu_*}@V6Z2xK6(wIR!0guVz;G*H8i2k*uycXu zUUDpj1zOqsjug24-|zp&naC#tT_sJt%78xn{~qvM-2VR;nq5Irfm^@u00000NkvXX Hu0mjf#Zw?u literal 0 HcmV?d00001 diff --git a/public/providers/oci.png b/public/providers/oci.png new file mode 100644 index 0000000000000000000000000000000000000000..96672d7bd4382f74b2cbd229ca37fa520f99231e GIT binary patch literal 1243 zcmV<11SI>3P)_^UXWZkX~I{U zcrO?ix=HCJ=#~&1Km{Tbl#)+EP(7lGebLbyVC6W9zK03K?z?*_gG zK2x9ve9#(r5ZL}d!E5;qco_J!)&3#SQS$0%8XZ3YdsYFsEzbg{8}&87(+ccpDZX+I zz-xK6Ro|(=mPW%x@}av{a;(CrWs3rv8V#p`Vzto3p=0?|2Ny;z{M?A%o1*AMXp#0L z)3@D~OEBmcdD5j06aq<5t@?uHxOuiQ=614Itctim5unf<16=5va9b(4Z4^1Hz^TTV zS>Tb?A}|bap%3S0V2~ruqrhxZSnR?=kCO@t`AZ!>S0FJRcykFUI48;(%rWLTcv#s)&%_WZfcNyP;wmT81zd%o*VK!1E7RBcX0>-Mm<=H zJU0|hxUfGM>j0$A@h*eoKAkPsqE->eS@1%?VBgw;gEUf*Nb2RB-Joz7IR}$)D5$=m zuv3w{)F-0lB!SB@0}41-3a5ah3I{quQ3&+vq)8wy%xC0001uP)t-s01ll0 z|Nj60m%P2)005c*37hHa^#BH&yT9d=meBC=`34!Joub$P6QKCx2eTw}YXsn>sl#jUa2 zCoQGonaJw)Uc}mENmG>;M0G=K!HV!V9FHapuhI^HGz{vYWkR+v_n5!!QiPFbu;m z48t(Ye~duTFP;B-2Uz`z2K43urlI^NC#c5nkdF~kU?EIhZ?cFQ-kX9dLKh=&{(7j4 zrJLs)G>{YpUwEGy9>Mvem7%u`j}f^$g*Jh=#rwo7azNkQL_06oIGaGy{;#k%w2#hH zq`=VFqYi&oqs$TC($8D{{GZ- zp=*%jr}E~tnoB}A&G%iP=dkOs&Ad-Jl3>t%_CE~!g3k}o+76DyzWo|Di$Cdv- zbPof1u8NKe<%kt$xq@hDD)Rm}Uu0ydQ z1a;1qgfw)iN8;Yxyd!M@B>kvE#olVFc$)%#+UKcoUMD$WlS!wgk5>Fl0dJe^Cir== zt{5~%D}Jg#(xB2i`nI!V!nyE)%VWs7$0d3FxCFoIi!E^ijnj6H3)6$zY@(!)gL^P>RdbKs5Q% zB+hSOLkK1~m1FqwwHclBEZJ;;wUYukp;`>G93%-omh?Io1qhZji~K268#!g1#wN6E zHfM>2ZbK%GAz1Bd+L7U1$Mf?}50?o|d~tf4iEX#@M<3b&CtL+HwvJD;H`w}B80#u1 zc7dM(_D$ia0hyqwtQ2DNUQJ#eGA1Avj;=!*`~WUfgqH5a#W%3P&T&4_Qo{ literal 0 HcmV?d00001 diff --git a/public/providers/piapi.png b/public/providers/piapi.png new file mode 100644 index 0000000000000000000000000000000000000000..ac4b72706b3b6389ef25f35089d5851daebacaf8 GIT binary patch literal 1616 zcmV-W2Cw;vP)C0000aP)t-sM{rC4 ze*XY|{{Vjf0Dk`fe*XY|{{Vjf0Dk`fe*XY|{{Vjf_Sh*A0000BbW%=J0Pu<+WDzo~ z-ABbS5r6Ce00q!VL_t(|oW)z&f~znHbxG7@{{Me(o!TpKAR$pZytT$~ShEPj&_{7e zAxv+YJLl+T9j0ykp_IPJe9D~nFO6U0z9I8pTKK>ipI~otmjGS{+HUuYlx^-DKs-#8 z!;S1iL3jz^L^|FDAt-KV0+{LFw?IfW={bPJA8c14%&UVv1+d6Rc_~a^rQl*u0YrQ_ z^^0%0{c2Epx$lD}cU3V@d# zr8_ziNaWUQRRFk*xDW{WZTEEm03|pO2>(;9?*{<-ta{?&AMXPoHCl_1(uOBm5WAUVLJ0OQE)d6lSu&2b3; zIX(Z6M6wZeC?G~WxE+){7lcFw$^J`aJf|?Nc`Mvmjay!)u*@YKinyl*^i}9!Z1XjM zBpt_@4i9z&60QQXa@KD_qO2<KQT&E?rWIU$`s0LJFT9}*Y9ZOS762*<>Eptc?XKvtx{6@o)=@BszD=>(bmQqtfv8aQR%z3`0l za?IWcfasMOM9IU?03cpC)1|G9^+o_pXo5x=`HTjL*@LjhmjIl(FAx^mdEg-cXZD{6 z3+?LUAs?Us&Y0A8Ll0@-Wcud-@?Qg3D*zty0Y890*T5G5l*90=c|c1!sY;QTAmV?w&i?j{{(;6lTe>;}6V^tplO zW`|Aba{xX@=9^Of>nj>Kqc9K3!Q^=joPX>G6F8cwB?!0B3O<-Pzhl6XM<6*@bpVbS zKOaF)6~EJ@JT31S1z|>b}qb*=T)I2NL8{9i~5+=5W&*9EM$@u_GJK2*6ynjVq!um z8LQTnb%s<$V-BSXkwS?Gk0mVT+WT9kHRmZPGNk?EX3p!Ba5-cA3&m_gk?QSA53y;> zH9}%lzf_uUOj;?l5bNF@EfTqfKjfT3QLB#@9zAu55;8vDF?#`6mK{3g;b3tRCmdCgsG^entiRax2`YodE|5FI5Tkd}ktvfH-CYz)H O0000zv zw`bq|Klk^tilIpX2H<$t6MzN4T%ZD&1VlWZDU4S1LZ)I|KMdZbRDJCsB6|RjLUJQ&ERUf5I6$lc@HvD?Su&vg7eF94HdwZp?ukW&3Pfw4u zw6w^>4?jFoOZZqH1E|6EDLdUumSu@jN;YoXC?X_3q2-(@$j2}Oqj*boh9LE{v%>Zu&Ksy7`o#Hm8X^Lf8 z0!V&-zO=WukDBJ=Y0a87fu&8;6w@@*S-{8IuDpw3wLf|CWL|ysRZ2=qsIIQ2si`T@ zqMueJO-hVUy*`hKkei#!^5x5^tgK||(xvR!u_NJ~q5AVkGnj;aFin~?Nj7iZEDa3} z($Uc&t*xz6R8(|Tiqw`ZTSP=;|Ni|_S63%XmMqCMum=~wvMkxVcW;83*R5M8fMjK5 zCAgMlSyEV77`R=$8^rVF<>dvz>hpxdVNps+VPTrxzx_6c4SVj?24Y}v8|?Ez9(S0^GOj^l`k$m-Rr10LV}1qB7t+uNI<-I9_L z0fK(Uj2R=RPMs1Fk^cUE(OS#n-&rN4;R?Ai=Oz~$sVO$?G%dNp#s`$2>LyN{h}N2D zG>YRm6crVv^pl^TPgYhITI)db6DLkg_(pQDDy8VQyO?wR0#;A`DWEV6E2Zz$J0m2= zaWD)6r4)u?VB2;IkJcKkHHKjXV71o6_N_4JmmVs|-v@DEa-Ws;Y!6_3q#HOIGAM`R0^oWY?VcC9kYf?tSj45M-ht zBc-p9rKP2^V8H^}uwjGPwk_+|ua~i7$BtSBHceCJ&6_7}ZEf=ApWl=vi3bL)l!ZdhVYo0;J7ChGEdu)I?KL6ZQ4=G&VL;Q&Yprl`A=O=1jU*Gp6k9 zY|6{aY1rMs-Sh7TU~0IWg@s??3k6jyDEK0~n*W5LUC4t_S`GQb3V%4TfB*i>hL` zv@mn#Ok%MZrfCL4iV;i+6G$mVI2`8K$)kLI(zjSK;UPY})XFbUZ{;87{z_BlVNS$O zG3(wfDDw&nnTP~M%QVg4+_J8$9=^5vEjrJ2F@NTlxDf5-8}BV;Z)*dQ;yV~Wy^6{y zcT+NVF(>xbdqNvtCc1)3>^KglX>#n?G2VFN4YZP=(@e-u(I21wm`%Uggkx*Ua?7Y~ zsbz0#1C`5u%dPWQU~9N^sh`sa{=$2&eUId+i-kKW7;!~5O_K{3F0k9PaNl&scTqU`~(IDmT?_|@*0Rzan}mL@a}yDhwX zaUYXrET`ksHg^5GifHde@5}zIFPMZWpwj}*jzoY+B!X$0JpI(u)a|U}fx>(E@n^n| zA;KTe@20c=Vq6;Yh9e&M!OlTpqp`)|_h(<@K=(lw6>sIE#vMd^FJhQsw2ndIbk)at z*1}yJuZ3c*kV@erpHNxBa1 zdgHEeD2G}1ZlGw|9ei}?ckX@Bkec0m9W^T4#i1>XFc$Jc*HeG{D}46Gxzv5KorUi` zO2xFtc<{b0h~dsOL=7Bu+_@;wanH5#%QBcbaJKnh?A%&K*M;VIw}~eo>thPI2{;Oj zB}Hec6gETHIQ*peyF6R|635QJ#hiU#=DKlHdHied&>ih&=k6zn+1;M1Bti4yACtZ$ z%Hx$7|338&(Y|)i0)uK_5x2Am?n0@M!Q!r=+`-r9^JdEHcf2Cg$COAYD^H$$^dtG% zI*}ne2g#q;1w_xckSI@vdjEKhACgYf2UOcP-OP)KX5(42#aBugEo~x zO9S3t0*!gvPuSq7_Lwr-;4qDln97v$DNAMJvmy`8ukprCR@{hj)SHj(B@eUdTfoHK zw#j&l$zLIeWEaS+@^4Ex6cJEYW&a=v(;?jLuwaV`2C`2n?nYWhLR`b!nln|wa` zt~3jGOVc;mFfpO7rrX5t7oYR6#bZsO|LcwJWFaEBfgRt`wf@zhANO~MF`0t*Dc-+s z!>!bQY+Q?W4)+I>=|f-&C|%VZ?01`cfO)t(BNKt#Vfx5~G;j&{77Gd X+l|7ty#Vzt00000NkvXXu0mjfAgkXR literal 0 HcmV?d00001 diff --git a/public/providers/predibase.png b/public/providers/predibase.png new file mode 100644 index 0000000000000000000000000000000000000000..55ecaed763093f00bda68c33d82887a37726ff27 GIT binary patch literal 2091 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 VKK!Pvr6&LY002ovPDHLkV1kQ+5cL26 literal 0 HcmV?d00001 diff --git a/public/providers/qoder.png b/public/providers/qoder.png index 1bddeae625daf5f1a972f3ebe2a0fb736804dc91..fd03f28dd275ebe77a24cda4b94ca9d7f02da185 100644 GIT binary patch delta 1931 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 diff --git a/public/providers/recraft.png b/public/providers/recraft.png new file mode 100644 index 0000000000000000000000000000000000000000..dff533eb8ccf3fbe578169b89b95dc97fed533d7 GIT binary patch literal 1176 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 Ue|%J*0m=NtSP)C0001HP)t-s@9yRd z3=9AO0Q2(d`uXt)2nf8qwfFY!)zr=A<=&c^lr=Rp6ciMtq@ExjAKBQ^hJ}I5%f*tB zjcjXZRaH`be0U}%B|SYm#KXODacxORMzXQ1W@ckeO-dLT7vJ93U0qr(E-f=SHPQe8 z1Q$s}K~#90?OJVjvmgxB1Vr1~+Sl3IPW%7=Fqpy&gL+j-96ep_Y9^@1TJL{UIM zKtMo1KtMo1z<&W0f>}ZcL~q`sa(Cchhug8Lg%=7UD^AiNkFD_J+azo<19Ogf5~9yFbPEC>TQSkHm-3Bc|rri;|rEUQ`zoY%GlXbgfgYk%Li4EXr! zW@Hkfw4DRdkpIree~UADuo*Lp85y~-CBRni7ll1l8dG9+J8G6)-b3x9AtP>b9C|Xo zxJA(txK1IEbO`VPYCQt&I)d9g1jc8U60rUby%5;91onSHfQ~HwfPlyc7xJ$V!0eL* z&Gfekps4S}#NE=p@n<-AFiHzhHZ$wZ$cO+RJ1!|3_jt&3CLkFMAXWe$_8E~G0YljD zg?`u9bE!^zFRCjtOR*Fw#70*@edO`WR)W&~*D>%RQD z$+HPXBD1|rGZ&itlR57X<)b+t+Wg} z8muD+28P?QHs9%KaF~yPp$7Sk=K>QAI9U6)$cRidaOj&@q+|vf%yl|8*TDXCYL%1@ zXh5pX_62*ptXQwXme^?KC7{=UwdG#EV!g*+31~GyTBVwsfKCIYtUNmbjRxKb3>K^7 z@t8=afIARqcYUSQjvLYlQ4eHY4ag$2uM&w1VNcDH8oUfIA1VVy17!xR`vtUV21TnM zlBN+~W!;UJXn=SboJIp+MFVNuwA#?{c97@KWmg07hiolnEgiE|j*N z%t?F62juM0%wx*zz{Nf#5m&Wwc{&%xtyBMeG|iNd|9siyE=d+QWqrCdF1x++ei7ok z4}^8B8L5)uE`<_y8*g5}=e5V62dB=hvfi~;-%SwQj5Baq0T0lQhsNrXe4E*QWGDyM z;~8y|_WUbWyWfI3v~n($$!Ih%3()znF=_@F@JSbW2CnhQPpunR5DV?l$rp*XOI-@6 ztADa`-Dd#2oOqQAql(k7`te7z(Hh0<+`YL0=ge{aQM;nt-`j%drKpE)s3A+Q-_4?D zHz_`Ere9`zQHauNS4b?94UQE+QPlbM6$&rMYD%THXBou<_|Mw69QeM_=*@dTKtMo1 gKtMo1K)|f{0z8j2+q=P)aR2}S07*qoM6N<$g0MF?761SM literal 0 HcmV?d00001 diff --git a/public/providers/triton.png b/public/providers/triton.png new file mode 100644 index 0000000000000000000000000000000000000000..9670b2ca22d8badb3407cf7f9d54af1c1be51260 GIT binary patch literal 1829 zcmV+=2io|FP)C0001NP)t-s|Ns90 z008Uj>*VC*=jZ1$Gc(}e;M&^S92^`&Lqq%f`|B5!tq4#vy z?KW)Kuwlc74I4IW_&>srvJ{Qz>-~Qq-OWyxfbI+8{o)y}D&KuFQ_tj|HJ)kR*Hi+r_57vmyCAVd8M+Ie>0A^m zEyGPM|By0Sc~gMzd*OrKUMoBUtboV#b`5X)h&=HheogJtcIy!6UW=V3iyc9Hd-JAG z1XMTqIynKo)=H&YE@I+Ov9Ee2X^AJU!T>KNdXyJCOn&8R9y+e)1}@e!zYcilKaTpx z$ggsxevFXdWQXAT2>G{tpY~Ht>>6Po6I)uW>IXgR2-;W@@40a(r=9@2sq>2$_%SG( znHqBcBr6~BKjacX>PNj?{=T%P1U!0K%EtFHswk%r`Q!ejUo8J-Su+AQz8Dhehe0BA zN@t-(%P?1aq5Le@5|Ce?dnG{%#))to=mPZvsQL3IDQ5)4-`Tt%0ELh`9?6!=YEnX$ zbCR8XenY^kAtjYb4W+px`6qZR_ClX@|IV034sQs!+)az|r+yEY6}AI5j-reB3{vNt zmn!uHctL10n(z(?3=!JOD)Jpj8Xd4HwFHWR$wGoxcA%89Cdn`}m+xblPZB?B0$#@( z;a)DsH=uCGe-%4p5CzZ&l?1rfb zb1Zrk1VDVnw*`e|BR&3 z;CBMAG62ABkx^4XJO`9!Kp+>&fGa;=84w_O0D4Kffd2&n%io0qqX2KvYoE~p7tui` zK(+dTfGxCWtd`JcOxzInk`|~o0#)@U;uBD}#xR>9bzz|`d{4eU=60lb`1CLl8z zasLt2zY=&D?bAEF*E&f#HRDa7Vl97N0wfjiNFuDj6&}g-_tZw~5eP^-(@y%V0VqiI z@W@<5O`tP&!q=Ll)tXG=g97Z3LXhlXcc>wd8HeEuBoeF~$x7Hm;U8$H#gng&Kskx2 zFA=d#)?^OHcjM0_2oh;fuOvW{*UW7`;sDL}L$-q#fzXBztn>s(JvNrl27L;j+XbOx zNoYe)OW-gpa)IeVKq_x9_R{$ka^EB(QjHf(DZI9&75lWNglgsL#s)8w}h0{4!&vQ4^ru%mNRf&Wl?)AA!MN zEw>-CtNhNZg_3|vjkLf3bc;%N6cHTF3`NaHAYz*}C*bZvLcCozC&Q_*q#BlHkp!nu zN>FnGJ!87?+ytwSZ)t*9%6ZcieVGwpcrHENCjKJ?-$j^+meZa1JQFge%TL#F7)aCh zj*bG#NsUaHKzd`(ho<)*4lGFcNwWNUbcH;dbP3?0EZSUl!yqYNc^0Gj_($Tp~ zTc5U&#$sLs+HYow7DpxeCH_Rf*0@9o%Sl1eFzx5{Y|BT^dR96&-?5<`#RFwXxNa4j zejf^d= z`iCDly4j2ZTHF0U;BXTS(PqcB@~;WHqDLsr!su^5F5R$U!-fqTHf-3iVJ-Xv_`^{I TsU_hQ00000NkvXXu0mjf;`d{p literal 0 HcmV?d00001 diff --git a/public/providers/venice.png b/public/providers/venice.png new file mode 100644 index 0000000000000000000000000000000000000000..a72e8ba1df658918d5eb497b8524e3128cfd77dc GIT binary patch literal 1372 zcmV-i1*7_jP)C0000RP)t-sM{rEt zGXUK)0NpbH-ZKE*GXUN*0NpbH-7^4&9DZ~F000PdQchC<%9i75HXXLo(k|5i00ihs zL_t(|ob8+0lB^&MhGkLv{h#=Z$`V30?3S)m)w!7|HT)l85rVxeKl|B#Xny#{XDz&T z`i6VCIr=Y}VE?-@f#A@8y@+7%=Z(h+E`1^fd%E#3!KokjJ_g67Jw8t0&PvAfZxe%4 ze~EN(K4>8UoCF{Smwp0xG6V&njX~0%3IJn}_2&ZA7!>`<067L#{}TY)W(T+kJdm^i z$O=($ZvoP%tS$xs2i!@0*&hL11l2(YaIHVGRh>*Rz)>K0Tm?uWTV(*Dgbu(r^N|LS z^jU!Ar4hUbko8|Ip-S);fI(j+cn83wuMxZfVANkWk>EanRezCVa2ufL%QLM?a2H^p z{xZQ$fI)qsA6x)|17N&H^%p({0hiPOFiu15kCjkiU0onRzPHmpVHvReR_F)jBPeKrQbjQS!0ug}j&!}=0|uQnP3T^|(AhoIP2 zOD_LP1f2d>pBi};fyM{`h9_Y4!BYdT0swH9tP%+N^{HC`sbqyf)Gtrn0VpMl1d4tp zxB&o4<_KH}-24YRUAPC()Qls*M(JM!!vH9-FPNoI#b9Rr z8v<}%FjF7LV0Qf*0{@Nrw*=p)e?#yk{f=O|KH5f&y=y;D@D+W~|DQap?X4Vpf&Jf( z?>%VcV6EA|UUQ;+B=#}=ivaDP{h}R-ea6z@b6Ec%a5DyEm%`Y(D-Vx|UJVmGtB(lI z+OAXe8-f(=b*erfD6PFdrN8>!{n;L2$Ey9mY|Lv)7Os`oczOGq-7+?rUYEx=9Dfe$ zR|3Y{ZbY8W_tzcPPftb0+g|&MzOJ=0YsVFPF%ME~jrTwlvX4u%TFLg+oLj&Ep~#j) zqU>FYGs;st50v>|bLMHwkB4qX0&-*PM*7sS$&0S}%9b6@d`d&mWLR#U+_qyH7M_Nc z_c_Kn`%63|7D`&FDw~)!rQ5mWp?Z2)yLmL;fL2F@H{QSo7Tc(zV6^e>^%+D78praf zlmeh<$s_==5nwN3n}DqZ+^eunAg@?*6@m->8O?D~Y)22gQ9T{-mKO1_?kEBg*5nEA z@_@3-aBLLM_EVsl9O!%JA^rZ=12V?xC!;`N^U=x}L*mHg0>!ZLn4{Xvrpa)Q# z2TVWG5NATQ6L&uhXw32h1^yHipSE)PQZsAsv(4*o!)vK}?`;Uyj?|*GESHq^!0}+e zDCJhWjTu)&jQ0mtL~sYhuL;?~W?B;}AKzO5cy|kcGE%?2F8~X3?!zJ5@qM=_rLR*) z$7(f}Kz}q-TUOU+zKvr(7~=`(-LXZV{5{#gm#M_}u)EzGIiyxtl^scIWq*=dVYBQ= zkkuTKkI~cZ%3JL(hxeTv(L!d)1_~guWaEjtHq*BcW*gV$d%7EW!mE^cq)K-mZ{<4Q e^Zwb-rrAGc#c#qeIC0001cP)t-s|Ns91 zE;9ftFulge6g)uyC@lacEc^WY05LWIBPjqMCHVRI@AC5J>+9a*aIK44`#TV7Xoc~x(7rLweeiHjgXMRJCTQD7e|QPRI{WtPBkM|w z4Uj}Jc79{>(QO9-xQy95IL(zJt%c3PqD`0ek-y_vpm>=4EfdfAYkdTO@u84_{3(^Q zG3XYxt3d+)!rwupl1*+*Vb?*&4WN)`0of@$Y;0rYO_w7}px}sChlQ*<3y{?UUJZ9% z)1Vm?5Pa;uK61B|OVIcvCXfL)4FWtQ;Ev$z8ivfl2BxWw^^teRsuJAc=MyagAoR;6 zm^L%z`3eM3@1n}_Z$&x8lSaj8A7PyWAUEZnNSbtJ!3t6^QFibu)@Lq3+(3db7eLLu zKH;T&0}U+6`(Xmmq;b`#N3x__|nmbp9#4Hw9enw6A++V zBl3zTSyGL|L)E|+jTw-!;3u)hk^;~Qx9`Qv5$!3)vrj)fvI9f9wW4JROQPEkKl4{? z1IkT&J+3H5_6G?TtP>*Y*O+>a4tM2hOA2-@1Dw15^`9)MQiAaW1khRoa@?c1B~>*V z{)NI3(4K-BYav0^EolY<=;_4X@X|tos#{Vq(zy4Kf*G}zhA#gZ(0IRe0*pG10nOEi}abnvL_efT3= zQ48LLhC7_2KFv}=lHk>n@|J=2Dgd%>Vs7?Qk71hg(JFPY;1ax8Qra_hr}WL(jkVcC-0l(GWVZw6$@mLy34mnWiQB2t5U7nXFl#9tu;`tjjsN-YV7 zVkFjg9jwNZT$x)ERN>Yi2GkIiL<&oS@}N4+ZHpx=sW|l;=EGFaNT{BTxFv1Dl6LG2 zHXEPlK(Ztz0ZdaH&(OLfEQ#C@`#i?pNB=dTz>0+R9mh$(lY$x6=8{~JVS4d$T<^h` lj)1{nFc=I5gTY|X#Xq+GFAra^!002ovPDHLkV1jp(IRO9w literal 0 HcmV?d00001 diff --git a/public/providers/wandb.png b/public/providers/wandb.png new file mode 100644 index 0000000000000000000000000000000000000000..3594e7807170bd50506d45ee1664f51286858949 GIT binary patch literal 1242 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 = { "github-copilot": "githubcopilot", github: "github", mistralai: "mistral", + "azure-ai": "azureai", + baseten: "baseten", + "black-forest-labs": "bfl", + deepinfra: "deepinfra", + "fal-ai": "fal", + "featherless-ai": "featherless", + friendliai: "friendli", + "glm-cn": "zhipu", + "inference-net": "inference", + "jina-ai": "jina", + "lambda-ai": "lambda", + "lm-studio": "lmstudio", + "meta-llama": "meta", + "muse-spark-web": "meta", + "nous-research": "nousresearch", + novita: "novita", + sambanova: "sambanova", + "searchapi-search": "searchapi", + snowflake: "snowflake", + upstage: "upstage", + "v0-vercel": "v0", + "vercel-ai-gateway": "vercelaigateway", + "vertex-partner": "vertexai", + vllm: "vllm", + volcengine: "volcengine", + watsonx: "ibm", + "xiaomi-mimo": "xiaomimimo", + xinference: "xinference", }; interface ProviderIconProps { @@ -186,6 +214,35 @@ const KNOWN_PNGS = new Set([ "together", "xai", "zeroclaw", + "aws-polly", + "blackbox-web", + "cliproxyapi", + "databricks", + "empower", + "gigachat", + "gitlab-duo", + "gitlab", + "heroku", + "linkup-search", + "llamagate", + "maritalk", + "modal", + "nanogpt", + "nscale", + "oci", + "ovhcloud", + "piapi", + "poe", + "predibase", + "qoder", + "recraft", + "reka", + "runwayml", + "triton", + "venice", + "voyage-ai", + "wandb", + "youcom-search", ]); const KNOWN_SVGS = new Set([ "apikey", diff --git a/tests/unit/chatcore-translation-paths.test.ts b/tests/unit/chatcore-translation-paths.test.ts index 2ccbb96e7f..326de77cd0 100644 --- a/tests/unit/chatcore-translation-paths.test.ts +++ b/tests/unit/chatcore-translation-paths.test.ts @@ -18,6 +18,13 @@ const { clearCache, getCachedResponse, generateSignature } = await import("../../src/lib/semanticCache.ts"); const { clearIdempotency } = await import("../../src/lib/idempotencyLayer.ts"); const { clearInflight } = await import("../../open-sse/services/requestDedup.ts"); +const { + buildAccountSemaphoreKey, + getStats: getAccountSemaphoreStats, + resetAll: resetAccountSemaphores, +} = await import("../../open-sse/services/accountSemaphore.ts"); +const { clearModelLock, isModelLocked } = + await import("../../open-sse/services/accountFallback.ts"); const { saveModelsDevCapabilities, clearModelsDevCapabilities } = await import("../../src/lib/modelsDevSync.ts"); const { @@ -346,12 +353,14 @@ async function invokeChatCore({ test.afterEach(async () => { globalThis.fetch = originalFetch; + resetAccountSemaphores(); await waitForAsyncSideEffects(); await resetStorage(); }); test.after(async () => { globalThis.fetch = originalFetch; + resetAccountSemaphores(); await waitForAsyncSideEffects(); await resetStorage(); fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true }); @@ -2007,6 +2016,146 @@ test("chatCore maps upstream aborts to request-aborted errors", async () => { assert.equal(result.error, "Request aborted"); }); +test("chatCore returns streaming responses without waiting for upstream completion", async () => { + const encoder = new TextEncoder(); + let closeUpstream: (() => void) | null = null; + + const invocation = invokeChatCore({ + provider: "openai", + model: "gpt-4o-mini", + accept: "text/event-stream", + body: { + model: "gpt-4o-mini", + stream: true, + messages: [{ role: "user", content: "do not buffer streaming" }], + }, + responseFactory() { + return new Response( + new ReadableStream({ + start(controller) { + controller.enqueue( + encoder.encode( + `data: ${JSON.stringify({ + id: "chatcmpl-stream", + object: "chat.completion.chunk", + choices: [ + { + index: 0, + delta: { role: "assistant", content: "streamed-without-buffering" }, + }, + ], + })}\n\n` + ) + ); + closeUpstream = () => { + controller.enqueue(encoder.encode("data: [DONE]\n\n")); + controller.close(); + }; + }, + }), + { + status: 200, + headers: { "Content-Type": "text/event-stream" }, + } + ); + }, + }); + + const raceResult = await Promise.race([ + invocation.then(() => "returned"), + new Promise((resolve) => setTimeout(() => resolve("blocked"), 1000)), + ]); + + if (raceResult !== "returned") { + closeUpstream?.(); + } + const { result } = await invocation; + + assert.equal(raceResult, "returned"); + closeUpstream?.(); + + const streamText = await result.response.text(); + assert.equal(result.success, true); + assert.match(streamText, /streamed-without-buffering/); +}); + +test("chatCore releases account semaphore slots when upstream execution throws", async () => { + const connectionId = "sem-exception"; + const semaphoreKey = buildAccountSemaphoreKey({ + provider: "openai", + accountKey: connectionId, + }); + + const { result } = await invokeChatCore({ + provider: "openai", + model: "gpt-4o-mini", + connectionId, + credentials: { + apiKey: "sk-test", + maxConcurrent: 1, + providerSpecificData: {}, + }, + body: { + model: "gpt-4o-mini", + stream: false, + messages: [{ role: "user", content: "executor throws" }], + }, + responseFactory() { + throw new Error("simulated upstream network failure"); + }, + }); + + await waitForAsyncSideEffects(); + + assert.equal(result.success, false); + assert.equal(result.status, 502); + assert.equal(getAccountSemaphoreStats()[semaphoreKey], undefined); +}); + +test("chatCore locks per-model quota failures without dropping quota helper references", async () => { + const model = "gemini-1.5-pro"; + const connection = await providersDb.createProviderConnection({ + provider: "gemini", + authType: "apikey", + name: "gemini-quota-lock", + apiKey: "gemini-key", + isActive: true, + providerSpecificData: {}, + }); + + try { + const { result } = await invokeChatCore({ + provider: "gemini", + model, + connectionId: connection.id, + credentials: { + apiKey: "gemini-key", + providerSpecificData: {}, + }, + body: { + model, + stream: false, + messages: [{ role: "user", content: "quota lock" }], + }, + responseFactory() { + return new Response( + JSON.stringify({ error: { message: "insufficient_quota: quota exhausted" } }), + { + status: 402, + headers: { "Content-Type": "application/json" }, + } + ); + }, + }); + + assert.equal(result.success, false); + assert.equal(result.status, 402); + assert.equal(isModelLocked("gemini", connection.id, model), true); + } finally { + clearModelLock("gemini", connection.id, model); + } +}); + // ── Streaming semantic cache tests ────────────────────────────────────────── test("chatCore caches streaming response and serves cache HIT on repeat", async () => { diff --git a/tests/unit/pack-artifact-policy.test.ts b/tests/unit/pack-artifact-policy.test.ts index a8e5ef7655..64811a50a9 100644 --- a/tests/unit/pack-artifact-policy.test.ts +++ b/tests/unit/pack-artifact-policy.test.ts @@ -56,6 +56,8 @@ test("findMissingArtifactPaths flags missing root runtime files in the tarball", ); assert.deepEqual(missingPaths, [ + "app/responses-ws-proxy.mjs", + "app/server-ws.mjs", "bin/mcp-server.mjs", "bin/nodeRuntimeSupport.mjs", "scripts/native-binary-compat.mjs",