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]