Last active
August 4, 2026 01:46
-
-
Save benedictjohannes/dab3d7a0ecca27530f305aebf97104f2 to your computer and use it in GitHub Desktop.
proxy to agentrouter.org - fixing bugs and fixing headers to opencode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| https://agentrouter.org/register?aff=U6vc | |
| Click: Sign In, | |
| then, | |
| Continue with GitHub |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // the agentrouter.org proxy has some problematic SSE response that needs to be filtered out. | |
| // This go program filters SSE events that makes OpenCode error out. | |
| package main | |
| import ( | |
| "bufio" | |
| "bytes" | |
| "io" | |
| "log/slog" | |
| "net/http" | |
| "os" | |
| "strings" | |
| ) | |
| const targetBaseURL = "https://agentrouter.org" | |
| func handleProxy(w http.ResponseWriter, r *http.Request) { | |
| // Log incoming request details and headers | |
| var headers []any | |
| for key, values := range r.Header { | |
| if strings.ToLower(key) == "authorization" { | |
| headers = append(headers, slog.String(key, "[MASKED]")) | |
| } else { | |
| headers = append(headers, slog.String(key, strings.Join(values, ", "))) | |
| } | |
| } | |
| slog.Info("Incoming Request", | |
| slog.String("method", r.Method), | |
| slog.String("url", r.URL.String()), | |
| slog.Group("headers", headers...), | |
| ) | |
| // Construct the upstream URL | |
| upstreamURL := targetBaseURL + r.URL.Path | |
| if r.URL.RawQuery != "" { | |
| upstreamURL += "?" + r.URL.RawQuery | |
| } | |
| // Read body for forwarding | |
| bodyBytes, _ := io.ReadAll(r.Body) | |
| req, err := http.NewRequest(r.Method, upstreamURL, bytes.NewBuffer(bodyBytes)) | |
| if err != nil { | |
| http.Error(w, err.Error(), http.StatusInternalServerError) | |
| return | |
| } | |
| // Copy incoming headers EXCEPT transport-level headers, user-agent, and encoding configurations | |
| ignoredHeaders := map[string]bool{ | |
| "accept-encoding": true, | |
| "content-length": true, | |
| "connection": true, | |
| "keep-alive": true, | |
| "proxy-connection": true, | |
| "transfer-encoding": true, | |
| "upgrade": true, | |
| "user-agent": true, | |
| } | |
| for key, values := range r.Header { | |
| if ignoredHeaders[strings.ToLower(key)] { | |
| continue | |
| } | |
| for _, val := range values { | |
| req.Header.Add(key, val) | |
| } | |
| } | |
| // Spoof User-Agent to match OpenCode client | |
| req.Header.Set("User-Agent", "opencode/1.18.3 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.14") | |
| // Execute request to AgentRouter | |
| client := &http.Client{} | |
| resp, err := client.Do(req) | |
| if err != nil { | |
| http.Error(w, err.Error(), http.StatusBadGateway) | |
| return | |
| } | |
| defer resp.Body.Close() | |
| // Log upstream response status and headers | |
| var respHeaders []any | |
| for key, values := range resp.Header { | |
| respHeaders = append(respHeaders, slog.String(key, strings.Join(values, ", "))) | |
| } | |
| slog.Info("Upstream Response", | |
| slog.Int("status_code", resp.StatusCode), | |
| slog.Group("headers", respHeaders...), | |
| ) | |
| // Read and log response body if it's an error status | |
| if resp.StatusCode >= 400 { | |
| bodyBytes, _ := io.ReadAll(resp.Body) | |
| slog.Warn("Upstream Response Error Body", | |
| slog.Int("status_code", resp.StatusCode), | |
| slog.String("body", string(bodyBytes)), | |
| ) | |
| resp.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) | |
| } | |
| // Copy response headers back EXCEPT encoding variations | |
| for key, values := range resp.Header { | |
| if strings.ToLower(key) == "content-encoding" || strings.ToLower(key) == "content-length" { | |
| continue // Let the local response figure out its own length/encoding | |
| } | |
| for _, val := range values { | |
| w.Header().Add(key, val) | |
| } | |
| } | |
| w.WriteHeader(resp.StatusCode) | |
| // Check if this is an Event-Stream (SSE) | |
| if strings.Contains(resp.Header.Get("Content-Type"), "text/event-stream") { | |
| reader := bufio.NewReader(resp.Body) | |
| for { | |
| line, err := reader.ReadString('\n') | |
| if err != nil { | |
| if err != io.EOF { | |
| slog.Error("Stream read error", slog.Any("error", err)) | |
| } | |
| break | |
| } | |
| trimmedLine := strings.TrimSpace(line) | |
| // Fix 1: Skip the old malformed null chunk | |
| if trimmedLine == "data: null" { | |
| continue | |
| } | |
| // Fix 2: Skip the custom metadata billing summary block injected by the proxy | |
| if strings.Contains(trimmedLine, `"object":"billing.summary"`) { | |
| continue | |
| } | |
| // Forward valid lines down the pipe | |
| w.Write([]byte(line)) | |
| if flusher, ok := w.(http.Flusher); ok { | |
| flusher.Flush() | |
| } | |
| } | |
| return | |
| } | |
| // Standard non-streaming fallback | |
| io.Copy(w, resp.Body) | |
| } | |
| func main() { | |
| slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, nil))) | |
| http.HandleFunc("/", handleProxy) | |
| slog.Info("Filtering proxy active on :8080...") | |
| if err := http.ListenAndServe(":8080", nil); err != nil { | |
| slog.Error("Server failed to start", slog.Any("error", err)) | |
| os.Exit(1) | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ~/.config/systemd/user/opencode-web.service | |
| # you can then run systemctl --user start opencode-web.service | |
| [Unit] | |
| Description=OpenCode Web | |
| After=network.target | |
| StartLimitIntervalSec=0 | |
| [Service] | |
| Type=simple | |
| Restart=always | |
| RestartSec=10 | |
| ExecStart=%h/.bun/bin/opencode serve --hostname 10.10.20.20 --port 8724 --cors opencode.bench01.t.haiyaa.my.id | |
| [Install] | |
| WantedBy=default.target |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
| // ~/.config/opencode/opencode.jsonc | |
| { | |
| "$schema": "https://opencode.ai/config.json", | |
| "provider": { | |
| "agentrouter": { | |
| "npm": "@ai-sdk/openai-compatible", | |
| "name": "AgentRouter (OpenAI Compatible)", | |
| "options": { | |
| "baseURL": "https://agentrouter.localhost/v1" | |
| }, | |
| "models": { | |
| "claude-opus-5": { | |
| "name": "claude-opus-5" | |
| }, | |
| "claude-opus-4-8": { | |
| "name": "claude-opus-4-8" | |
| }, | |
| "gpt-5.6-sol": { | |
| "name": "gpt-5.6-sol" | |
| } | |
| } | |
| }, | |
| }, | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment