This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git


The following commit(s) were added to refs/heads/master by this push:
     new 1054d1e  feat(providers): add an OpenAI Responses provider type
1054d1e is described below

commit 1054d1ee7d42474624e895da97de6a188916bb2c
Author: Yang Luo <[email protected]>
AuthorDate: Sun Sep 6 18:31:21 2026 +0800

    feat(providers): add an OpenAI Responses provider type
---
 object/provider.go                          |  9 ++++++++-
 web/src/components/shared/brand-options.tsx |  5 +++--
 web/src/lib/providers.ts                    | 18 ++++++++++++++++--
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/object/provider.go b/object/provider.go
index 7532847..58c3ddf 100644
--- a/object/provider.go
+++ b/object/provider.go
@@ -223,8 +223,12 @@ const (
        maxProviderModelChars = 100
 )
 
+// ProviderTypeOpenAiResponses is an OpenAI-shaped upstream that answers on the
+// Responses endpoint instead of chat completions.
+const ProviderTypeOpenAiResponses = "openai-responses"
+
 var (
-       providerTypes    = []string{"openai", "custom", "anthropic"}
+       providerTypes    = []string{"openai", ProviderTypeOpenAiResponses, 
"custom", "anthropic"}
        providerStatuses = []string{"enabled", "disabled"}
 )
 
@@ -277,6 +281,9 @@ func ProviderProtocol(provider *Provider) string {
        if provider.Type == "anthropic" {
                return ProtocolAnthropic
        }
+       if provider.Type == ProviderTypeOpenAiResponses {
+               return ProtocolResponses
+       }
        return ProtocolOpenAi
 }
 
diff --git a/web/src/components/shared/brand-options.tsx 
b/web/src/components/shared/brand-options.tsx
index 3130d86..a318f1c 100644
--- a/web/src/components/shared/brand-options.tsx
+++ b/web/src/components/shared/brand-options.tsx
@@ -18,7 +18,7 @@ import {Bot, Cloud, Folder, Globe, Settings2} from 
"lucide-react";
 import {AgentIcon} from "@/components/AgentIcon";
 import {ProviderIcon} from "@/components/ProviderIcon";
 import type {SelectOption} from "@/components/shared/simple-select";
-import {providerPresets} from "@/lib/providers";
+import {presetType, providerPresets, typeOpenAiResponses} from 
"@/lib/providers";
 
 /** A dropdown item that names a brand is read by its mark first. */
 function brandOption(value: string, text: string, mark: React.ReactNode): 
SelectOption {
@@ -74,6 +74,7 @@ export function wireApiOptions(fromType: string): 
SelectOption[] {
 /** The Type field of both provider forms: two vendors and everything else. */
 export const providerTypeOptions: SelectOption[] = [
   ...protocolOptions,
+  vendorOption(typeOpenAiResponses, "OpenAI Responses", "openai.com"),
   brandOption("custom", "Custom", <Settings2 className="size-4 opacity-50" />),
 ];
 
@@ -96,7 +97,7 @@ export function storageOption(kind: string, label: string): 
SelectOption {
  *  mark comes from the vendor's own site: an API host often has no icon. */
 export function baseUrlOptions(type: string): SelectOption[] {
   return providerPresets
-    .filter(preset => preset.type === type)
+    .filter(preset => preset.type === presetType(type))
     .map(preset =>
       brandOption(
         preset.baseUrl,
diff --git a/web/src/lib/providers.ts b/web/src/lib/providers.ts
index 5c08981..e2076e0 100644
--- a/web/src/lib/providers.ts
+++ b/web/src/lib/providers.ts
@@ -20,6 +20,9 @@ export function providerIdOf(provider: Pick<Provider, "owner" 
| "name">) {
   return `${provider.owner}/${provider.name}`;
 }
 
+/** Mirrors object.ProviderTypeOpenAiResponses: OpenAI on its Responses 
endpoint. */
+export const typeOpenAiResponses = "openai-responses";
+
 /** Mirrors object.ProviderApiFamily: the family a provider's base URL belongs 
to. */
 export function providerProtocol(type: string) {
   return type === "anthropic" ? "anthropic" : "openai";
@@ -28,12 +31,23 @@ export function providerProtocol(type: string) {
 /** The wire formats the gateway can talk to an upstream in. */
 export const wireApis = ["openai", "responses", "anthropic"] as const;
 
+/** The wire format a type serves on its own, before the provider names one. */
+function typeWireApi(type: string) {
+  return type === typeOpenAiResponses ? "responses" : providerProtocol(type);
+}
+
 /** Mirrors object.ProviderProtocol: the API the gateway posts to. */
 export function providerWireApi(provider: {type?: string; protocol?: string} | 
undefined) {
   const named = provider?.protocol ?? "";
   return wireApis.includes(named as (typeof wireApis)[number])
     ? named
-    : providerProtocol(provider?.type ?? "");
+    : typeWireApi(provider?.type ?? "");
+}
+
+/** The type whose vendors a form offers: Responses is OpenAI's own API, so it
+ *  is filled in from the same base URLs and models. */
+export function presetType(type: string) {
+  return type === typeOpenAiResponses ? "openai" : type;
 }
 
 /** The path one wire format is appended to the base URL as. */
@@ -628,7 +642,7 @@ export function presetOfSource(source: ProviderSource) {
 
 /** The base URLs and models offered for a provider type, from the vendors of 
it. */
 export function modelPresets(type: string) {
-  return providerPresets.filter(preset => preset.type === type).flatMap(preset 
=> preset.models);
+  return providerPresets.filter(preset => preset.type === 
presetType(type)).flatMap(preset => preset.models);
 }
 
 export function baseUrlPlaceholder(type: string) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to