fix(providers): correct pollinations requests and provider dashboard state

Update Pollinations request transformation to send the selected model
and stream flag so requests match the active endpoint behavior.

Align the ChatGPT TLS client with shared proxy resolution so dashboard
proxy context is honored before falling back to environment settings.
Also refresh provider display names across dashboard pages, correct the
Claude extra-usage toggle messaging and visual state, and mark
Pollinations as offering a free public endpoint.
This commit is contained in:
diegosouzapw
2026-05-11 15:51:05 -03:00
parent fea8e5a1e9
commit 0594b1d2ea
9 changed files with 32 additions and 38 deletions

View File

@@ -52,8 +52,8 @@ AGENTS.md
bun.lock
# Build artifacts (pre-built goes inside app/)
.next/
node_modules/
/.next/
/node_modules/
# Ignore large binary files and other build directories
*.tgz

View File

@@ -41,8 +41,10 @@ export class PollinationsExecutor extends BaseExecutor {
return headers;
}
transformRequest(model: string, body: any, _stream: boolean, _credentials: any): any {
transformRequest(model: string, body: any, stream: boolean, _credentials: any): any {
if (typeof body === "object" && body !== null) {
body.model = model;
body.stream = stream;
body.jsonMode = true;
}
return body;

View File

@@ -209,23 +209,24 @@ export interface TlsFetchOptions {
proxyUrl?: string;
}
import { resolveProxyForRequest } from "../utils/proxyFetch.ts";
/**
* Resolve the proxy URL for a tls-client request. Per-call value wins;
* otherwise we fall back to env. Returns undefined when no proxy is
* configured (caller passes `undefined` through to tls-client-node, which
* treats it as "no proxy").
* otherwise we use the standard proxy fetch resolution which reads from
* the dashboard AsyncLocalStorage context or falls back to env vars.
*/
function resolveProxyUrl(perCall: string | undefined): string | undefined {
if (perCall && perCall.length > 0) return perCall;
const fromEnv =
process.env.OMNIROUTE_TLS_PROXY_URL ||
process.env.HTTPS_PROXY ||
process.env.https_proxy ||
process.env.HTTP_PROXY ||
process.env.http_proxy ||
process.env.ALL_PROXY ||
process.env.all_proxy;
return fromEnv && fromEnv.length > 0 ? fromEnv : undefined;
try {
const proxyInfo = resolveProxyForRequest("https://chatgpt.com");
if (proxyInfo && proxyInfo.proxyUrl) {
return proxyInfo.proxyUrl;
}
} catch {
// Ignore resolution errors
}
return undefined;
}
export interface TlsFetchResult {

View File

@@ -133,7 +133,7 @@ function resolveEnvProxyUrl(targetUrl) {
return normalizeProxyUrl(proxyUrl, "environment proxy");
}
function resolveProxyForRequest(targetUrl) {
export function resolveProxyForRequest(targetUrl) {
let target;
try {
target = new URL(targetUrl);

12
package-lock.json generated
View File

@@ -25,6 +25,7 @@
"express": "^5.2.1",
"fetch-socks": "^1.3.3",
"fuse.js": "^7.3.0",
"gray-matter": "^4.0.3",
"http-proxy-middleware": "^3.0.5",
"https-proxy-agent": "^9.0.0",
"ioredis": "^5.10.1",
@@ -83,7 +84,6 @@
"eslint": "^9.39.4",
"eslint-config-next": "16.2.6",
"glob": "^13.0.6",
"gray-matter": "^4.0.3",
"husky": "^9.1.7",
"jsdom": "^29.1.1",
"lint-staged": "^16.4.0",
@@ -8258,7 +8258,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"license": "BSD-2-Clause",
"bin": {
"esparse": "bin/esparse.js",
@@ -8460,7 +8459,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-extendable": "^0.1.0"
@@ -9101,7 +9099,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"js-yaml": "^3.13.1",
@@ -9117,7 +9114,6 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
@@ -9127,7 +9123,6 @@
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
@@ -9859,7 +9854,6 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -10607,7 +10601,6 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -13914,7 +13907,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"dev": true,
"license": "MIT",
"dependencies": {
"extend-shallow": "^2.0.1",
@@ -14386,7 +14378,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/stable-hash": {
@@ -14672,7 +14663,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"

View File

@@ -6,6 +6,7 @@ import { Card, Button, Input, Modal, CardSkeleton, SegmentedControl } from "@/sh
import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard";
import { useDisplayBaseUrl } from "@/shared/hooks";
import { AI_PROVIDERS, getProviderByAlias } from "@/shared/constants/providers";
import { getProviderDisplayName } from "@/lib/display/names";
import { useTranslations } from "next-intl";
const BUILD_TIME_CLOUD_URL = process.env.NEXT_PUBLIC_CLOUD_URL || null;
@@ -2482,7 +2483,7 @@ function EndpointSection({
const resolveProvider = (id) => AI_PROVIDERS[id] || getProviderByAlias(id);
const providerColor = (id) => resolveProvider(id)?.color || "#888";
const providerName = (id) => resolveProvider(id)?.name || id;
const providerName = (id) => getProviderDisplayName(id, resolveProvider(id));
const copyId = `endpoint_${path}`;
return (

View File

@@ -15,6 +15,7 @@
import { useState, useEffect, useCallback } from "react";
import { Card } from "@/shared/components";
import { AI_PROVIDERS } from "@/shared/constants/providers";
import { getProviderDisplayName } from "@/lib/display/names";
import { useTranslations } from "next-intl";
import TelemetryCard from "./TelemetryCard";
@@ -762,7 +763,7 @@ export default function HealthPage() {
{unhealthy.map(([provider, cb]: [string, any]) => {
const style = CB_STYLES[cb.state] || CB_STYLES.OPEN;
const providerInfo = AI_PROVIDERS[provider];
const displayName = providerInfo?.name || provider;
const displayName = getProviderDisplayName(provider, providerInfo);
return (
<div
key={provider}
@@ -820,7 +821,7 @@ export default function HealthPage() {
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-2">
{healthy.map(([provider]) => {
const providerInfo = AI_PROVIDERS[provider];
const displayName = providerInfo?.name || provider;
const displayName = getProviderDisplayName(provider, providerInfo);
return (
<div
key={provider}
@@ -873,7 +874,7 @@ export default function HealthPage() {
if (customName.length > 12) displayName += ` (${customName.slice(0, 8)}…)`;
else if (customName) displayName += ` (${customName})`;
} else {
displayName = providerInfo?.name || providerId;
displayName = getProviderDisplayName(providerId, providerInfo);
}
return { providerId, displayName, providerInfo, connectionId, model };

View File

@@ -1630,9 +1630,7 @@ export default function ProviderDetailPage() {
: connection
)
);
notify.success(
enabled ? "Claude extra-usage blocking enabled" : "Claude extra-usage blocking disabled"
);
notify.success(enabled ? "Claude extra-usage blocked" : "Claude extra-usage allowed");
} catch (error) {
console.error("Error toggling Claude extra-usage policy:", error);
notify.error("Failed to update Claude extra-usage policy");
@@ -5377,7 +5375,7 @@ function ConnectionRow({
<button
onClick={() => onToggleClaudeExtraUsage?.(!claudeBlockExtraUsageEnabled)}
className={`inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-xs font-medium transition-all cursor-pointer ${
claudeBlockExtraUsageEnabled
!claudeBlockExtraUsageEnabled
? "bg-amber-500/15 text-amber-500 hover:bg-amber-500/25"
: "bg-black/[0.03] dark:bg-white/[0.03] text-text-muted/50 hover:text-text-muted hover:bg-black/[0.06] dark:hover:bg-white/[0.06]"
}`}
@@ -5385,7 +5383,7 @@ function ConnectionRow({
>
<span className="material-symbols-outlined text-[13px]">payments</span>
{t("claudeExtraUsageShort")}{" "}
{claudeBlockExtraUsageEnabled ? t("toggleOnShort") : t("toggleOffShort")}
{!claudeBlockExtraUsageEnabled ? t("toggleOnShort") : t("toggleOffShort")}
</button>
</>
)}

View File

@@ -793,8 +793,9 @@ export const APIKEY_PROVIDERS = {
color: "#4CAF50",
textIcon: "PO",
website: "https://pollinations.ai",
hasFree: false,
freeNote: "API key required. Spore tier: ~0.01 pollen/hour ($0.01/hr).",
hasFree: true,
freeNote:
"No API key required for free public endpoint. Optional Spore tier: ~0.01 pollen/hour.",
},
puter: {
id: "puter",