MCPcopy Index your code
hub / github.com/coder/coder / NewRequestBridge

Function NewRequestBridge

aibridge/bridge.go:113–201  ·  view source on GitHub ↗

NewRequestBridge creates a new *[RequestBridge] and registers the HTTP routes defined by the given providers. Any routes which are requested but not registered will be reverse-proxied to the upstream service. A [intercept.Recorder] is also required to record prompt, tool, and token use. mcpProxy w

(ctx context.Context, providers []provider.Provider, rec recorder.Recorder, mcpProxy mcp.ServerProxier, logger slog.Logger, m *metrics.Metrics, tracer trace.Tracer)

Source from the content-addressed store, hash-verified

111// Circuit breaker configuration is obtained from each provider's CircuitBreakerConfig() method.
112// Providers returning nil will not have circuit breaker protection.
113func NewRequestBridge(ctx context.Context, providers []provider.Provider, rec recorder.Recorder, mcpProxy mcp.ServerProxier, logger slog.Logger, m *metrics.Metrics, tracer trace.Tracer) (*RequestBridge, error) {
114 if err := validateProviders(providers); err != nil {
115 return nil, err
116 }
117
118 mux := http.NewServeMux()
119
120 for _, prov := range providers {
121 // Disabled providers serve a 503 sentinel on every path under
122 // "/<name>/". Bound to the bare name (not RoutePrefix) so paths
123 // outside the provider's normal "/v1" subtree are also caught.
124 if !prov.Enabled() {
125 prefix := fmt.Sprintf("/%s/", prov.Name())
126 mux.HandleFunc(prefix, disabledProviderHandler(prov.Name(), logger))
127 continue
128 }
129 // Create per-provider circuit breaker if configured
130 cfg := prov.CircuitBreakerConfig()
131 providerName := prov.Name()
132 onChange := func(endpoint, model string, from, to gobreaker.State) {
133 logger.Info(context.Background(), "circuit breaker state change",
134 slog.F("provider", providerName),
135 slog.F("endpoint", endpoint),
136 slog.F("model", model),
137 slog.F("from", from.String()),
138 slog.F("to", to.String()),
139 )
140 if m != nil {
141 m.CircuitBreakerState.WithLabelValues(providerName, endpoint, model).Set(circuitbreaker.StateToGaugeValue(to))
142 if to == gobreaker.StateOpen {
143 m.CircuitBreakerTrips.WithLabelValues(providerName, endpoint, model).Inc()
144 }
145 }
146 }
147 cbs := circuitbreaker.NewProviderCircuitBreakers(providerName, cfg, onChange, m)
148
149 // Add the known provider-specific routes which are bridged (i.e. intercepted and augmented).
150 for _, path := range prov.BridgedRoutes() {
151 handler := newInterceptionProcessor(prov, cbs, rec, mcpProxy, logger, m, tracer)
152 route, err := url.JoinPath(prov.RoutePrefix(), path)
153 if err != nil {
154 logger.Error(ctx, "failed to join path",
155 slog.Error(err),
156 slog.F("provider", providerName),
157 slog.F("prefix", prov.RoutePrefix()),
158 slog.F("path", path),
159 )
160 return nil, xerrors.Errorf("failed to configure provider '%v': failed to join bridged path: %w", providerName, err)
161 }
162 mux.Handle(route, handler)
163 }
164
165 // Any requests which passthrough to this will be reverse-proxied to the upstream.
166 //
167 // We have to whitelist the known-safe routes because an API key with elevated privileges (i.e. admin) might be
168 // configured, so we should just reverse-proxy known-safe routes.
169 ftr := newPassthroughRouter(prov, logger.Named(fmt.Sprintf("passthrough.%s", prov.Name())), m, tracer)
170 for _, path := range prov.PassthroughRoutes() {

Callers 6

AcquireMethod · 0.92
TestValidateProvidersFunction · 0.92
TestRequestBodySizeLimitFunction · 0.92
newBridgeTestServerFunction · 0.92

Calls 15

StateToGaugeValueFunction · 0.92
validateProvidersFunction · 0.85
disabledProviderHandlerFunction · 0.85
newInterceptionProcessorFunction · 0.85
newPassthroughRouterFunction · 0.85
WithLabelValuesMethod · 0.80
NamedMethod · 0.80
EnabledMethod · 0.65
NameMethod · 0.65
CircuitBreakerConfigMethod · 0.65
SetMethod · 0.65

Tested by 4

TestValidateProvidersFunction · 0.74
TestRequestBodySizeLimitFunction · 0.74