fix(openai): 自动透传预检 instructions 并本地 403 拦截
This commit is contained in:
@@ -1276,6 +1276,29 @@ func (s *OpenAIGatewayService) forwardOpenAIPassthrough(
|
||||
startTime time.Time,
|
||||
) (*OpenAIForwardResult, error) {
|
||||
if account != nil && account.Type == AccountTypeOAuth {
|
||||
if rejectReason := detectOpenAIPassthroughInstructionsRejectReason(reqModel, body); rejectReason != "" {
|
||||
rejectMsg := "OpenAI codex passthrough requires a non-empty instructions field"
|
||||
setOpsUpstreamError(c, http.StatusForbidden, rejectMsg, "")
|
||||
appendOpsUpstreamError(c, OpsUpstreamErrorEvent{
|
||||
Platform: account.Platform,
|
||||
AccountID: account.ID,
|
||||
AccountName: account.Name,
|
||||
UpstreamStatusCode: http.StatusForbidden,
|
||||
Passthrough: true,
|
||||
Kind: "request_error",
|
||||
Message: rejectMsg,
|
||||
Detail: rejectReason,
|
||||
})
|
||||
logOpenAIPassthroughInstructionsRejected(ctx, c, account, reqModel, rejectReason, body)
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": gin.H{
|
||||
"type": "forbidden_error",
|
||||
"message": rejectMsg,
|
||||
},
|
||||
})
|
||||
return nil, fmt.Errorf("openai passthrough rejected before upstream: %s", rejectReason)
|
||||
}
|
||||
|
||||
normalizedBody, normalized, err := normalizeOpenAIPassthroughOAuthBody(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1395,6 +1418,37 @@ func (s *OpenAIGatewayService) forwardOpenAIPassthrough(
|
||||
}, nil
|
||||
}
|
||||
|
||||
func logOpenAIPassthroughInstructionsRejected(
|
||||
ctx context.Context,
|
||||
c *gin.Context,
|
||||
account *Account,
|
||||
reqModel string,
|
||||
rejectReason string,
|
||||
body []byte,
|
||||
) {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
accountID := int64(0)
|
||||
accountName := ""
|
||||
accountType := ""
|
||||
if account != nil {
|
||||
accountID = account.ID
|
||||
accountName = strings.TrimSpace(account.Name)
|
||||
accountType = strings.TrimSpace(string(account.Type))
|
||||
}
|
||||
fields := []zap.Field{
|
||||
zap.String("component", "service.openai_gateway"),
|
||||
zap.Int64("account_id", accountID),
|
||||
zap.String("account_name", accountName),
|
||||
zap.String("account_type", accountType),
|
||||
zap.String("request_model", strings.TrimSpace(reqModel)),
|
||||
zap.String("reject_reason", strings.TrimSpace(rejectReason)),
|
||||
}
|
||||
fields = appendCodexCLIOnlyRejectedRequestFields(fields, c, body)
|
||||
logger.FromContext(ctx).With(fields...).Warn("OpenAI passthrough 本地拦截:Codex 请求缺少有效 instructions")
|
||||
}
|
||||
|
||||
func (s *OpenAIGatewayService) buildUpstreamRequestOpenAIPassthrough(
|
||||
ctx context.Context,
|
||||
c *gin.Context,
|
||||
@@ -2948,3 +3002,22 @@ func normalizeOpenAIReasoningEffort(raw string) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
func detectOpenAIPassthroughInstructionsRejectReason(reqModel string, body []byte) string {
|
||||
model := strings.ToLower(strings.TrimSpace(reqModel))
|
||||
if !strings.Contains(model, "codex") {
|
||||
return ""
|
||||
}
|
||||
|
||||
instructions := gjson.GetBytes(body, "instructions")
|
||||
if !instructions.Exists() {
|
||||
return "instructions_missing"
|
||||
}
|
||||
if instructions.Type != gjson.String {
|
||||
return "instructions_not_string"
|
||||
}
|
||||
if strings.TrimSpace(instructions.String()) == "" {
|
||||
return "instructions_empty"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user