mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
feat(composite): support Codex endpoints
This commit is contained in:
@@ -30,8 +30,8 @@ func (h *OpenAIGatewayHandler) AlphaSearch(c *gin.Context) {
|
||||
h.errorResponse(c, http.StatusUnauthorized, "authentication_error", "Invalid API key")
|
||||
return
|
||||
}
|
||||
if apiKey.Group.Platform != service.PlatformOpenAI {
|
||||
h.errorResponse(c, http.StatusNotFound, "not_found_error", "Codex alpha search is only available for OpenAI groups")
|
||||
if apiKey.Group.Platform != service.PlatformOpenAI && apiKey.Group.Platform != service.PlatformComposite {
|
||||
h.errorResponse(c, http.StatusNotFound, "not_found_error", "Codex alpha search is only available for OpenAI and Composite groups")
|
||||
return
|
||||
}
|
||||
subject, ok := middleware2.GetAuthSubjectFromContext(c)
|
||||
@@ -75,6 +75,10 @@ func (h *OpenAIGatewayHandler) AlphaSearch(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
requestedModel := strings.TrimSpace(modelResult.String())
|
||||
if !compositeTargetPlatformAllowed(c, apiKey, requestedModel, service.PlatformOpenAI) {
|
||||
h.errorResponse(c, http.StatusNotFound, "not_found_error", "Codex alpha search only supports OpenAI models for Composite groups")
|
||||
return
|
||||
}
|
||||
reqLog = reqLog.With(zap.String("model", requestedModel))
|
||||
setOpsRequestContext(c, requestedModel, false)
|
||||
setOpsEndpointContext(c, "", int16(service.RequestTypeSync))
|
||||
|
||||
@@ -27,8 +27,8 @@ func (h *OpenAIGatewayHandler) CodexModels(c *gin.Context) {
|
||||
h.errorResponse(c, http.StatusUnauthorized, "invalid_request_error", "API key group is required")
|
||||
return
|
||||
}
|
||||
if apiKey.Group.Platform != service.PlatformOpenAI {
|
||||
h.errorResponse(c, http.StatusNotFound, "not_found_error", "Codex models manifest is only available for OpenAI groups")
|
||||
if apiKey.Group.Platform != service.PlatformOpenAI && apiKey.Group.Platform != service.PlatformComposite {
|
||||
h.errorResponse(c, http.StatusNotFound, "not_found_error", "Codex models manifest is only available for OpenAI and Composite groups")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,19 @@ func TestCodexModelsCanceledRequestDoesNotWriteResponse(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompositeCodexModelsReusesExistingManifestSelection(t *testing.T) {
|
||||
handler, upstream, groupID := newCodexModelsFailoverTestHandler(http.StatusServiceUnavailable)
|
||||
|
||||
recorder := performCodexModelsRequestForPlatform(t, handler, groupID, service.PlatformComposite)
|
||||
|
||||
if got, want := upstream.calls(), []int64{1, 2}; !equalInt64Slices(got, want) {
|
||||
t.Fatalf("upstream account calls: got %v, want %v", got, want)
|
||||
}
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d; body=%s", recorder.Code, http.StatusOK, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodexModelsFailsOverFromRetryableUpstreamStatus(t *testing.T) {
|
||||
retryableStatuses := []int{
|
||||
http.StatusTooManyRequests,
|
||||
@@ -287,13 +300,17 @@ func newCodexModelsFailoverTestHandlerWithAccountCount(firstStatus, accountCount
|
||||
}
|
||||
|
||||
func performCodexModelsRequest(t *testing.T, handler *OpenAIGatewayHandler, groupID int64) *httptest.ResponseRecorder {
|
||||
return performCodexModelsRequestForPlatform(t, handler, groupID, service.PlatformOpenAI)
|
||||
}
|
||||
|
||||
func performCodexModelsRequestForPlatform(t *testing.T, handler *OpenAIGatewayHandler, groupID int64, platform string) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
recorder := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(recorder)
|
||||
c.Request = httptest.NewRequest(http.MethodGet, "/v1/models?client_version=0.144.0", nil)
|
||||
c.Set(string(middleware2.ContextKeyAPIKey), &service.APIKey{
|
||||
GroupID: &groupID,
|
||||
Group: &service.Group{ID: groupID, Platform: service.PlatformOpenAI},
|
||||
Group: &service.Group{ID: groupID, Platform: platform},
|
||||
})
|
||||
|
||||
handler.CodexModels(c)
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
coderws "github.com/coder/websocket"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -29,7 +30,7 @@ func (h *OpenAIGatewayHandler) Live(c *gin.Context) {
|
||||
h.errorResponse(c, http.StatusInternalServerError, "api_error", "User context not found")
|
||||
return
|
||||
}
|
||||
if apiKey.Group == nil || apiKey.Group.Platform != service.PlatformOpenAI {
|
||||
if apiKey.Group == nil || (apiKey.Group.Platform != service.PlatformOpenAI && apiKey.Group.Platform != service.PlatformComposite) {
|
||||
h.errorResponse(c, http.StatusNotFound, "not_found_error", "Live is not supported for this platform")
|
||||
return
|
||||
}
|
||||
@@ -43,6 +44,18 @@ func (h *OpenAIGatewayHandler) Live(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
model := strings.TrimSpace(gjson.GetBytes(request.Session, "model").String())
|
||||
if !compositeTargetPlatformAllowed(c, apiKey, model, service.PlatformOpenAI) {
|
||||
h.errorResponse(c, http.StatusNotFound, "not_found_error", "Live only supports OpenAI models for Composite groups")
|
||||
return
|
||||
}
|
||||
if upstreamModel, ok := service.ResolvedUpstreamModelFromContext(c.Request.Context()); ok && upstreamModel != model {
|
||||
rewrittenSession, rewriteErr := sjson.SetBytes(request.Session, "model", upstreamModel)
|
||||
if rewriteErr != nil {
|
||||
h.errorResponse(c, http.StatusInternalServerError, "api_error", "Failed to apply Composite model route")
|
||||
return
|
||||
}
|
||||
request.Session = rewrittenSession
|
||||
}
|
||||
reqLog := requestLogger(
|
||||
c,
|
||||
"handler.openai_gateway.live",
|
||||
@@ -231,6 +244,6 @@ func (h *OpenAIGatewayHandler) LiveSideband(c *gin.Context) {
|
||||
func liveEnabledForAPIKey(apiKey *service.APIKey) bool {
|
||||
return apiKey != nil &&
|
||||
apiKey.Group != nil &&
|
||||
apiKey.Group.Platform == service.PlatformOpenAI &&
|
||||
(apiKey.Group.Platform == service.PlatformOpenAI || apiKey.Group.Platform == service.PlatformComposite) &&
|
||||
apiKey.Group.AllowLive
|
||||
}
|
||||
|
||||
@@ -87,6 +87,9 @@ func TestLiveEnabledForAPIKey(t *testing.T) {
|
||||
require.True(t, liveEnabledForAPIKey(&service.APIKey{
|
||||
Group: &service.Group{Platform: service.PlatformOpenAI, AllowLive: true},
|
||||
}))
|
||||
require.True(t, liveEnabledForAPIKey(&service.APIKey{
|
||||
Group: &service.Group{Platform: service.PlatformComposite, AllowLive: true},
|
||||
}))
|
||||
}
|
||||
|
||||
func TestLiveAttestationErrorIsExplicit(t *testing.T) {
|
||||
|
||||
@@ -133,6 +133,78 @@ func TestCompositeTargetPlatformMiddlewareUsesExplicitRouteAndRewritesBody(t *te
|
||||
require.Equal(t, http.StatusNoContent, w.Code)
|
||||
}
|
||||
|
||||
func TestCompositeTargetPlatformMiddlewareRewritesNestedLiveModel(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
resolver := service.NewCompositeRouteResolver(compositeRouteRepoStub{
|
||||
routes: []service.CompositeModelRoute{
|
||||
{
|
||||
ID: 1,
|
||||
GroupID: 1,
|
||||
PublicModel: "live-alias",
|
||||
MatchType: service.CompositeRouteMatchExact,
|
||||
TargetPlatform: service.PlatformOpenAI,
|
||||
UpstreamModel: "gpt-live",
|
||||
Endpoint: service.CompositeRouteEndpointAny,
|
||||
Priority: 100,
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
router.Use(gin.HandlerFunc(servermiddleware.APIKeyAuthMiddleware(func(c *gin.Context) {
|
||||
groupID := int64(1)
|
||||
c.Set(string(servermiddleware.ContextKeyAPIKey), &service.APIKey{
|
||||
GroupID: &groupID,
|
||||
Group: &service.Group{ID: groupID, Platform: service.PlatformComposite},
|
||||
})
|
||||
c.Next()
|
||||
})))
|
||||
router.Use(compositeTargetPlatformMiddleware(resolver))
|
||||
router.POST("/backend-api/codex/realtime/calls", func(c *gin.Context) {
|
||||
platform, ok := service.ResolvedTargetPlatformFromContext(c.Request.Context())
|
||||
require.True(t, ok)
|
||||
require.Equal(t, service.PlatformOpenAI, platform)
|
||||
|
||||
body, err := io.ReadAll(c.Request.Body)
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, `{"session":{"model":"gpt-live"},"sdp":"v=0"}`, string(body))
|
||||
c.Status(http.StatusNoContent)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(
|
||||
http.MethodPost,
|
||||
"/backend-api/codex/realtime/calls",
|
||||
strings.NewReader(`{"session":{"model":"live-alias"},"sdp":"v=0"}`),
|
||||
)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusNoContent, w.Code)
|
||||
}
|
||||
|
||||
func TestCompositeRequestModelFromMultipartLiveSession(t *testing.T) {
|
||||
var body bytes.Buffer
|
||||
writer := multipart.NewWriter(&body)
|
||||
require.NoError(t, writer.WriteField("sdp", "v=0"))
|
||||
require.NoError(t, writer.WriteField("session", `{"model":"live-alias"}`))
|
||||
require.NoError(t, writer.Close())
|
||||
|
||||
require.Equal(t, "live-alias", compositeRequestModelFromBody(writer.FormDataContentType(), body.Bytes()))
|
||||
}
|
||||
|
||||
func TestCompositeCodexControlPathsUseResponsesRoutes(t *testing.T) {
|
||||
for _, path := range []string{
|
||||
"/v1/alpha/search",
|
||||
"/backend-api/codex/alpha/search",
|
||||
"/v1/live",
|
||||
"/backend-api/codex/realtime/calls",
|
||||
} {
|
||||
require.Equal(t, service.CompositeRouteEndpointResponses, compositeRouteEndpointForPath(path), "path=%s", path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompositeTargetPlatformMiddlewareUsesExplicitRouteForMultipartImages(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
|
||||
@@ -55,9 +55,6 @@ func RegisterGatewayRoutes(
|
||||
return false
|
||||
}
|
||||
}
|
||||
isOpenAIGatewayPlatform := func(c *gin.Context) bool {
|
||||
return getGroupPlatform(c) == service.PlatformOpenAI
|
||||
}
|
||||
countTokensHandler := func(c *gin.Context) {
|
||||
switch getGroupPlatform(c) {
|
||||
case service.PlatformOpenAI, service.PlatformKimi, service.PlatformZhipu, service.PlatformDeepseek:
|
||||
@@ -69,9 +66,12 @@ func RegisterGatewayRoutes(
|
||||
}
|
||||
}
|
||||
modelsHandler := func(c *gin.Context) {
|
||||
if isOpenAIGatewayPlatform(c) && c.Query("client_version") != "" {
|
||||
h.OpenAIGateway.CodexModels(c)
|
||||
return
|
||||
if c.Query("client_version") != "" {
|
||||
switch getGroupPlatform(c) {
|
||||
case service.PlatformOpenAI, service.PlatformComposite:
|
||||
h.OpenAIGateway.CodexModels(c)
|
||||
return
|
||||
}
|
||||
}
|
||||
h.Gateway.Models(c)
|
||||
}
|
||||
@@ -551,8 +551,10 @@ func compositeTargetPlatformMiddleware(resolver *service.CompositeRouteResolver)
|
||||
if decision.Matched {
|
||||
c.Request = c.Request.WithContext(service.WithCompositeRouteDecision(c.Request.Context(), decision))
|
||||
if upstreamModel := strings.TrimSpace(decision.UpstreamModel); upstreamModel != "" && upstreamModel != model && gjson.ValidBytes(body) {
|
||||
if rewritten, rewriteErr := sjson.SetBytes(body, "model", upstreamModel); rewriteErr == nil {
|
||||
body = rewritten
|
||||
if _, modelPath := compositeJSONRequestModel(body); modelPath != "" {
|
||||
if rewritten, rewriteErr := sjson.SetBytes(body, modelPath, upstreamModel); rewriteErr == nil {
|
||||
body = rewritten
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -563,12 +565,25 @@ func compositeTargetPlatformMiddleware(resolver *service.CompositeRouteResolver)
|
||||
}
|
||||
|
||||
func compositeRequestModelFromBody(contentType string, body []byte) string {
|
||||
if model := strings.TrimSpace(gjson.GetBytes(body, "model").String()); model != "" {
|
||||
if model, _ := compositeJSONRequestModel(body); model != "" {
|
||||
return model
|
||||
}
|
||||
return compositeMultipartModelFromBody(contentType, body)
|
||||
}
|
||||
|
||||
func compositeJSONRequestModel(body []byte) (string, string) {
|
||||
for _, path := range []string{"model", "session.model"} {
|
||||
model := gjson.GetBytes(body, path)
|
||||
if model.Type != gjson.String {
|
||||
continue
|
||||
}
|
||||
if value := strings.TrimSpace(model.String()); value != "" {
|
||||
return value, path
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func compositeMultipartModelFromBody(contentType string, body []byte) string {
|
||||
mediaType, params, err := mime.ParseMediaType(strings.TrimSpace(contentType))
|
||||
if err != nil || !strings.EqualFold(mediaType, "multipart/form-data") {
|
||||
@@ -587,14 +602,22 @@ func compositeMultipartModelFromBody(contentType string, body []byte) string {
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if part.FormName() != "model" || part.FileName() != "" {
|
||||
fieldName := part.FormName()
|
||||
if part.FileName() != "" || (fieldName != "model" && fieldName != "session") {
|
||||
continue
|
||||
}
|
||||
data, err := io.ReadAll(part)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(string(data))
|
||||
switch fieldName {
|
||||
case "model":
|
||||
return strings.TrimSpace(string(data))
|
||||
case "session":
|
||||
if model, _ := compositeJSONRequestModel(data); model != "" {
|
||||
return model
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,7 +693,10 @@ func compositeRouteEndpointForPath(path string) string {
|
||||
return service.CompositeRouteEndpointCountTokens
|
||||
case strings.Contains(path, "/messages"):
|
||||
return service.CompositeRouteEndpointMessages
|
||||
case strings.Contains(path, "/responses"):
|
||||
case strings.Contains(path, "/responses"),
|
||||
strings.Contains(path, "/alpha/search"),
|
||||
strings.Contains(path, "/realtime/calls"),
|
||||
strings.HasSuffix(strings.TrimRight(path, "/"), "/live"):
|
||||
return service.CompositeRouteEndpointResponses
|
||||
case strings.Contains(path, "/chat/completions"):
|
||||
return service.CompositeRouteEndpointChatCompletions
|
||||
|
||||
@@ -94,7 +94,7 @@ func TestGatewayRoutesOpenAIAlphaSearchPathsAreRegistered(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGatewayRoutesAlphaSearchRejectsNonOpenAIGroup(t *testing.T) {
|
||||
func TestGatewayRoutesAlphaSearchRejectsUnsupportedGroup(t *testing.T) {
|
||||
router := newGatewayRoutesTestRouter(service.PlatformGrok)
|
||||
req := httptest.NewRequest(http.MethodPost, "/v1/alpha/search", strings.NewReader(`{"model":"gpt-5.6-sol"}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
@@ -103,7 +103,7 @@ func TestGatewayRoutesAlphaSearchRejectsNonOpenAIGroup(t *testing.T) {
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusNotFound, w.Code)
|
||||
require.Contains(t, w.Body.String(), "only available for OpenAI groups")
|
||||
require.Contains(t, w.Body.String(), "only available for OpenAI and Composite groups")
|
||||
}
|
||||
|
||||
func TestGatewayRoutesOpenAIImagesPathsAreRegistered(t *testing.T) {
|
||||
|
||||
@@ -510,7 +510,7 @@ func (s *adminServiceImpl) CreateGroup(ctx context.Context, input *CreateGroupIn
|
||||
ReasoningEffortMappings: reasoningEffortMappings,
|
||||
}
|
||||
sanitizeGroupMessagesDispatchFields(group)
|
||||
if group.Platform != PlatformOpenAI {
|
||||
if group.Platform != PlatformOpenAI && group.Platform != PlatformComposite {
|
||||
group.AllowLive = false
|
||||
}
|
||||
sanitizeGroupReasoningEffortPolicy(group)
|
||||
@@ -890,7 +890,7 @@ func (s *adminServiceImpl) UpdateGroup(ctx context.Context, id int64, input *Upd
|
||||
group.ReasoningEffortMappings = reasoningEffortMappings
|
||||
}
|
||||
sanitizeGroupMessagesDispatchFields(group)
|
||||
if group.Platform != PlatformOpenAI {
|
||||
if group.Platform != PlatformOpenAI && group.Platform != PlatformComposite {
|
||||
group.AllowLive = false
|
||||
}
|
||||
sanitizeGroupReasoningEffortPolicy(group)
|
||||
|
||||
@@ -1029,6 +1029,44 @@ func TestAdminService_CreateGroup_ClearsMessagesDispatchFieldsForNonOpenAIPlatfo
|
||||
require.Equal(t, OpenAIMessagesDispatchModelConfig{}, repo.created.MessagesDispatchModelConfig)
|
||||
}
|
||||
|
||||
func TestAdminService_CreateCompositeGroupPreservesLive(t *testing.T) {
|
||||
repo := &groupRepoStubForAdmin{}
|
||||
svc := &adminServiceImpl{groupRepo: repo}
|
||||
|
||||
group, err := svc.CreateGroup(context.Background(), &CreateGroupInput{
|
||||
Name: "composite-group",
|
||||
Platform: PlatformComposite,
|
||||
RateMultiplier: 1.0,
|
||||
AllowLive: true,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, group)
|
||||
require.NotNil(t, repo.created)
|
||||
require.True(t, repo.created.AllowLive)
|
||||
}
|
||||
|
||||
func TestAdminService_UpdateCompositeGroupPreservesLive(t *testing.T) {
|
||||
existingGroup := &Group{
|
||||
ID: 1,
|
||||
Name: "composite-group",
|
||||
Platform: PlatformComposite,
|
||||
Status: StatusActive,
|
||||
}
|
||||
repo := &groupRepoStubForAdmin{getByID: existingGroup}
|
||||
svc := &adminServiceImpl{groupRepo: repo}
|
||||
allowLive := true
|
||||
|
||||
group, err := svc.UpdateGroup(context.Background(), existingGroup.ID, &UpdateGroupInput{
|
||||
AllowLive: &allowLive,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, group)
|
||||
require.NotNil(t, repo.updated)
|
||||
require.True(t, repo.updated.AllowLive)
|
||||
}
|
||||
|
||||
func TestAdminService_UpdateGroup_ClearsMessagesDispatchFieldsWhenPlatformChangesAwayFromOpenAI(t *testing.T) {
|
||||
existingGroup := &Group{
|
||||
ID: 1,
|
||||
|
||||
@@ -53,6 +53,12 @@ route's `upstream_model` before dispatch. For Gemini native paths such as
|
||||
`/v1beta/models/{model}:generateContent`, the gateway resolves `{model}` and
|
||||
the handler forwards the resolved upstream model.
|
||||
|
||||
Codex Alpha Search and Live requests use the `responses` route domain. Live
|
||||
requests resolve the model from `session.model`, including multipart `session`
|
||||
payloads, and apply the configured `upstream_model` before dispatch.
|
||||
Codex model manifest requests reuse the existing OpenAI account selection and
|
||||
failover path within the Composite group.
|
||||
|
||||
## Built-In Detection
|
||||
|
||||
Composite routing detects common public model IDs and provider-prefixed IDs:
|
||||
|
||||
@@ -1581,9 +1581,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- OpenAI Live 开关(仅 openai 平台) -->
|
||||
<!-- Codex Live 开关(OpenAI 与 Composite 平台) -->
|
||||
<div
|
||||
v-if="createForm.platform === 'openai'"
|
||||
v-if="supportsLivePlatform(createForm.platform)"
|
||||
class="border-t border-gray-200 dark:border-dark-400 pt-4 mt-4"
|
||||
>
|
||||
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
|
||||
@@ -3303,9 +3303,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- OpenAI Live 开关(仅 openai 平台) -->
|
||||
<!-- Codex Live 开关(OpenAI 与 Composite 平台) -->
|
||||
<div
|
||||
v-if="editForm.platform === 'openai'"
|
||||
v-if="supportsLivePlatform(editForm.platform)"
|
||||
class="border-t border-gray-200 dark:border-dark-400 pt-4 mt-4"
|
||||
>
|
||||
<h4 class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
|
||||
@@ -4501,6 +4501,9 @@ import {
|
||||
videoModelPriceFamilyRows,
|
||||
} from "./groupsVideoModelPricing";
|
||||
|
||||
const supportsLivePlatform = (platform: string): boolean =>
|
||||
platform === "openai" || platform === "composite";
|
||||
|
||||
const emptyGroupPricing = (): PricingFormEntry => ({
|
||||
models: [],
|
||||
billing_mode: "token",
|
||||
@@ -6663,6 +6666,8 @@ watch(
|
||||
}
|
||||
if (newVal !== "openai") {
|
||||
resetMessagesDispatchFormState(createForm);
|
||||
}
|
||||
if (!supportsLivePlatform(newVal)) {
|
||||
createForm.allow_live = false;
|
||||
}
|
||||
if (!isProfitControlPlatform(newVal)) {
|
||||
@@ -6711,6 +6716,8 @@ watch(
|
||||
}
|
||||
if (newVal !== "openai") {
|
||||
resetMessagesDispatchFormState(editForm);
|
||||
}
|
||||
if (!supportsLivePlatform(newVal)) {
|
||||
editForm.allow_live = false;
|
||||
}
|
||||
if (!isProfitControlPlatform(newVal)) {
|
||||
@@ -6761,9 +6768,11 @@ watch(
|
||||
}
|
||||
if (newVal !== 'openai') {
|
||||
editForm.allow_messages_dispatch = false
|
||||
editForm.allow_live = false
|
||||
editForm.default_mapped_model = ''
|
||||
}
|
||||
if (!supportsLivePlatform(newVal)) {
|
||||
editForm.allow_live = false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user