[PR #2434] feat(openrouter): add support for custom API endpoint URL #2474

Open
opened 2026-02-16 11:17:05 -05:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/langgenius/dify-official-plugins/pull/2434
Author: @onlylhf
Created: 1/15/2026
Status: 🔄 Open

Base: mainHead: main


📝 Commits (4)

  • b01d167 feat(openrouter): add support for custom API endpoint URL
  • fd2abb4 Merge branch 'main' into main
  • 50c7fd3 Merge branch 'main' into main
  • 3fee60e Merge branch 'main' into main

📊 Changes

5 files changed (+141 additions, -6 deletions)

View changed files

📝 models/openrouter/manifest.yaml (+1 -1)
📝 models/openrouter/models/llm/llm.py (+20 -1)
📝 models/openrouter/provider/openrouter.yaml (+20 -0)
📝 models/openrouter/pyproject.toml (+1 -2)
📝 models/openrouter/requirements.txt (+99 -2)

📄 Description

  • Add endpoint_url configuration to provider and model credential schemas
  • Implement _normalize_endpoint_url() method to handle user-provided URLs
  • Ensure endpoint URL is properly formatted with /v1 suffix
  • Update dify-plugin dependency to 0.7.1
  • Bump version to 0.0.32

OpenRouter reverse proxy script example


package main

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
)

// Configuration for the target host
const TargetHost = "https://openrouter.ai"

func main() {
	// 1. Parse the target URL
	targetURL, err := url.Parse(TargetHost)
	if err != nil {
		log.Fatalf("Failed to parse target URL: %v", err)
	}

	// 2. Create the reverse proxy
	proxy := httputil.NewSingleHostReverseProxy(targetURL)

	// 3. Custom Director to modify the request
	originalDirector := proxy.Director
	proxy.Director = func(req *http.Request) {
		// Execute default forwarding logic
		originalDirector(req)

		// -------------------------------------------------------
		// Key Step: Hide Source IP
		// -------------------------------------------------------
		// Explicitly remove headers usually added by proxies to ensure
		// OpenRouter sees this server's IP, not the original client's.
		req.Header.Del("X-Forwarded-For")
		req.Header.Del("X-Real-Ip")
		req.Header.Del("Forwarded")

		// Set the Host header to match the target.
		// This is crucial for passing Cloudflare checks.
		req.Host = targetURL.Host

		log.Printf("Forwarding request: Path=%s, Method=%s", req.URL.Path, req.Method)
	}

	// 4. Custom ModifyResponse (Optional)
	// Used to handle CORS headers
	proxy.ModifyResponse = func(resp *http.Response) error {
		resp.Header.Set("Access-Control-Allow-Origin", "*")
		resp.Header.Set("Access-Control-Allow-Headers", "*")
		return nil
	}

	// 5. Set up the handler function
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// Handle CORS preflight requests (OPTIONS)
		if r.Method == http.MethodOptions {
			w.Header().Set("Access-Control-Allow-Origin", "*")
			w.Header().Set("Access-Control-Allow-Headers", "*")
			w.WriteHeader(http.StatusOK)
			return
		}

		// Execute proxy
		proxy.ServeHTTP(w, r)
	})

	// 6. Start the server
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Printf("OpenRouter proxy server started on :%s -> %s", port, TargetHost)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatalf("Server failed to start: %v", err)
	}
}

Related Issues or Context

This PR contains Changes to Non-Plugin

  • Documentation
  • Other

This PR contains Changes to Non-LLM Models Plugin

  • I have Run Comprehensive Tests Relevant to My Changes

This PR contains Changes to LLM Models Plugin

  • My Changes Affect Message Flow Handling (System Messages and User→Assistant Turn-Taking)
  • My Changes Affect Tool Interaction Flow (Multi-Round Usage and Output Handling, for both Agent App and Agent Node)
  • My Changes Affect Multimodal Input Handling (Images, PDFs, Audio, Video, etc.)
  • My Changes Affect Multimodal Output Generation (Images, Audio, Video, etc.)
  • My Changes Affect Structured Output Format (JSON, XML, etc.)
  • My Changes Affect Token Consumption Metrics
  • My Changes Affect Other LLM Functionalities (Reasoning Process, Grounding, Prompt Caching, etc.)
  • Other Changes (Add New Models, Fix Model Parameters etc.)

Version Control (Any Changes to the Plugin Will Require Bumping the Version)

  • I have Bumped Up the Version in Manifest.yaml (Top-Level Version Field, Not in Meta Section)

Dify Plugin SDK Version

  • I have Ensured dify_plugin>=0.3.0,<0.6.0 is in requirements.txt (SDK docs)

Environment Verification (If Any Code Changes)

Local Deployment Environment

  • Dify Version is: , I have Tested My Changes on Local Deployment Dify with a Clean Environment That Matches the Production Configuration.

SaaS Environment

  • I have Tested My Changes on cloud.dify.ai with a Clean Environment That Matches the Production Configuration

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/langgenius/dify-official-plugins/pull/2434 **Author:** [@onlylhf](https://github.com/onlylhf) **Created:** 1/15/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `main` --- ### 📝 Commits (4) - [`b01d167`](https://github.com/langgenius/dify-official-plugins/commit/b01d1672bc6d21a41f135ea2ce897a9c90eaa926) feat(openrouter): add support for custom API endpoint URL - [`fd2abb4`](https://github.com/langgenius/dify-official-plugins/commit/fd2abb4e5ec292aa2f378a3ba48ab92c53581a16) Merge branch 'main' into main - [`50c7fd3`](https://github.com/langgenius/dify-official-plugins/commit/50c7fd35503e1dd20902b7f62b1992c45a3ebfee) Merge branch 'main' into main - [`3fee60e`](https://github.com/langgenius/dify-official-plugins/commit/3fee60ebc424e1d04289e212a5fad53859d73e3a) Merge branch 'main' into main ### 📊 Changes **5 files changed** (+141 additions, -6 deletions) <details> <summary>View changed files</summary> 📝 `models/openrouter/manifest.yaml` (+1 -1) 📝 `models/openrouter/models/llm/llm.py` (+20 -1) 📝 `models/openrouter/provider/openrouter.yaml` (+20 -0) 📝 `models/openrouter/pyproject.toml` (+1 -2) 📝 `models/openrouter/requirements.txt` (+99 -2) </details> ### 📄 Description - Add endpoint_url configuration to provider and model credential schemas - Implement _normalize_endpoint_url() method to handle user-provided URLs - Ensure endpoint URL is properly formatted with /v1 suffix - Update dify-plugin dependency to 0.7.1 - Bump version to 0.0.32 OpenRouter reverse proxy script example ```go package main import ( "log" "net/http" "net/http/httputil" "net/url" "os" ) // Configuration for the target host const TargetHost = "https://openrouter.ai" func main() { // 1. Parse the target URL targetURL, err := url.Parse(TargetHost) if err != nil { log.Fatalf("Failed to parse target URL: %v", err) } // 2. Create the reverse proxy proxy := httputil.NewSingleHostReverseProxy(targetURL) // 3. Custom Director to modify the request originalDirector := proxy.Director proxy.Director = func(req *http.Request) { // Execute default forwarding logic originalDirector(req) // ------------------------------------------------------- // Key Step: Hide Source IP // ------------------------------------------------------- // Explicitly remove headers usually added by proxies to ensure // OpenRouter sees this server's IP, not the original client's. req.Header.Del("X-Forwarded-For") req.Header.Del("X-Real-Ip") req.Header.Del("Forwarded") // Set the Host header to match the target. // This is crucial for passing Cloudflare checks. req.Host = targetURL.Host log.Printf("Forwarding request: Path=%s, Method=%s", req.URL.Path, req.Method) } // 4. Custom ModifyResponse (Optional) // Used to handle CORS headers proxy.ModifyResponse = func(resp *http.Response) error { resp.Header.Set("Access-Control-Allow-Origin", "*") resp.Header.Set("Access-Control-Allow-Headers", "*") return nil } // 5. Set up the handler function http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // Handle CORS preflight requests (OPTIONS) if r.Method == http.MethodOptions { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Headers", "*") w.WriteHeader(http.StatusOK) return } // Execute proxy proxy.ServeHTTP(w, r) }) // 6. Start the server port := os.Getenv("PORT") if port == "" { port = "8080" } log.Printf("OpenRouter proxy server started on :%s -> %s", port, TargetHost) if err := http.ListenAndServe(":"+port, nil); err != nil { log.Fatalf("Server failed to start: %v", err) } } ``` ## Related Issues or Context <!-- ⚠️ NOTE: This repository is for Dify Official Plugins only. For community contributions, please submit to https://github.com/langgenius/dify-plugins instead. - Link Related Issues if Applicable: #issue_number - Or Provide Context about Why this Change is Needed --> ## This PR contains Changes to *Non-Plugin* <!-- Put an `x` in all the boxes that apply by replacing [ ] with [x] For example: - [x] Documentation --> - [ ] Documentation - [ ] Other ## This PR contains Changes to *Non-LLM Models Plugin* - [x] I have Run Comprehensive Tests Relevant to My Changes <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> ## This PR contains Changes to *LLM Models Plugin* <!-- LLM Models Test Example: --> <!-- https://github.com/langgenius/dify-official-plugins/blob/main/.assets/test-examples/llm-plugin-tests/llm_test_example.md --> - [ ] My Changes Affect Message Flow Handling (System Messages and User→Assistant Turn-Taking) <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> - [ ] My Changes Affect Tool Interaction Flow (Multi-Round Usage and Output Handling, for both Agent App and Agent Node) <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> - [ ] My Changes Affect Multimodal Input Handling (Images, PDFs, Audio, Video, etc.) <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> - [ ] My Changes Affect Multimodal Output Generation (Images, Audio, Video, etc.) <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> - [ ] My Changes Affect Structured Output Format (JSON, XML, etc.) <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> - [ ] My Changes Affect Token Consumption Metrics <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> - [ ] My Changes Affect Other LLM Functionalities (Reasoning Process, Grounding, Prompt Caching, etc.) <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> - [ ] Other Changes (Add New Models, Fix Model Parameters etc.) <!-- 📷 Include Screenshots/Videos Demonstrating the Fix, New Feature, or the Behavior Before/After Breaking Changes. --> ## Version Control (Any Changes to the Plugin Will Require Bumping the Version) - [ ] I have Bumped Up the Version in Manifest.yaml (Top-Level `Version` Field, Not in Meta Section) <!-- ⚠️ NOTE: Version Format: MAJOR.MINOR.PATCH - MAJOR (0.x.x): Reserved for Significant architectural changes or incompatible API modifications - MINOR (x.0.x): For New feature additions while maintaining backward compatibility - PATCH (x.x.0): For Backward-compatible bug fixes and minor improvements - Note: Each Version Component (MAJOR, MINOR, PATCH) Can Be 2 Digits, e.g., 10.11.22 --> ## Dify Plugin SDK Version - [ ] I have Ensured `dify_plugin>=0.3.0,<0.6.0` is in requirements.txt ([SDK docs](https://github.com/langgenius/dify-plugin-sdks/blob/main/python/README.md)) ## Environment Verification (If Any Code Changes) <!-- ⚠️ NOTE: At Least One Environment Must Be Tested. --> ### Local Deployment Environment - [ ] Dify Version is: <!-- Specify Your Version (e.g., 1.2.0) -->, I have Tested My Changes on Local Deployment Dify with a Clean Environment That Matches the Production Configuration. <!-- - Python Virtual Env Matching Manifest.yaml & requirements.txt - No Breaking Changes in Dify That May Affect the Testing Result --> ### SaaS Environment - [ ] I have Tested My Changes on cloud.dify.ai with a Clean Environment That Matches the Production Configuration <!-- - Python Virtual Env Matching Manifest.yaml & requirements.txt --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-02-16 11:17:05 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify-official-plugins#2474