@@ -1058,6 +1058,81 @@ var _ = Describe("NIXL Connector (v2)", func() {
10581058 Expect (testInfo .prefillHandler .GetCompletionHeaders ()[0 ].Get (requestHeaderDataParallelRank )).To (BeEmpty ())
10591059 Expect (testInfo .decodeHandler .GetCompletionHeaders ()[0 ].Get (requestHeaderDataParallelRank )).To (BeEmpty ())
10601060 })
1061+
1062+ // EC+PD regression: ec_transfer_params is injected into the prefill request
1063+ // by the encoder stage but must not appear in the decode request. The decode
1064+ // pod has no EC connector and vLLM logs a warning when the field is present.
1065+ It ("does not forward ec_transfer_params to the decode request in EPD mode" , func () {
1066+ encoderBackend := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
1067+ w .Header ().Set ("Content-Type" , "application/json" )
1068+ w .WriteHeader (http .StatusOK )
1069+ _ , _ = w .Write ([]byte (`{"choices":[],"ec_transfer_params":{"hash-0":{"peer_host":"10.0.0.1"}}}` ))
1070+ }))
1071+ DeferCleanup (encoderBackend .Close )
1072+
1073+ prefillHandler := & mock.ChatCompletionHandler {
1074+ Connector : KVConnectorNIXLV2 ,
1075+ Role : mock .RolePrefill ,
1076+ }
1077+ prefillBackend := httptest .NewServer (prefillHandler )
1078+ DeferCleanup (prefillBackend .Close )
1079+
1080+ decodeHandler := & mock.ChatCompletionHandler {
1081+ Connector : KVConnectorNIXLV2 ,
1082+ Role : mock .RoleDecode ,
1083+ }
1084+ decodeBackend := httptest .NewServer (decodeHandler )
1085+ DeferCleanup (decodeBackend .Close )
1086+
1087+ decodeURL , err := url .Parse (decodeBackend .URL )
1088+ Expect (err ).ToNot (HaveOccurred ())
1089+
1090+ cfg := Config {
1091+ Port : "0" ,
1092+ DecoderURL : decodeURL ,
1093+ KVConnector : KVConnectorNIXLV2 ,
1094+ ECConnector : ECConnectorNIXL ,
1095+ }
1096+ proxy := NewProxy (cfg )
1097+
1098+ ctx , cancelFn := context .WithCancel (newTestContext ())
1099+ stoppedCh := make (chan struct {})
1100+ DeferCleanup (func () {
1101+ cancelFn ()
1102+ <- stoppedCh
1103+ })
1104+
1105+ go func () {
1106+ defer GinkgoRecover ()
1107+ proxy .allowlistValidator = & AllowlistValidator {enabled : false }
1108+ err := proxy .Start (ctx )
1109+ Expect (err ).ToNot (HaveOccurred ())
1110+ stoppedCh <- struct {}{}
1111+ }()
1112+ <- proxy .readyCh
1113+
1114+ reqBody , _ := json .Marshal (userMessageRequest (imageURLItem ("https://example.com/img.jpg" )))
1115+ req , err := http .NewRequest (http .MethodPost , "http://" + proxy .addr .String ()+ ChatCompletionsPath , bytes .NewReader (reqBody ))
1116+ Expect (err ).ToNot (HaveOccurred ())
1117+ req .Header .Set ("Content-Type" , "application/json" )
1118+ req .Header .Add (routing .PrefillEndpointHeader , prefillBackend .URL [len ("http://" ):])
1119+ req .Header .Add (routing .EncoderEndpointsHeader , encoderBackend .URL [len ("http://" ):])
1120+
1121+ rp , err := http .DefaultClient .Do (req )
1122+ Expect (err ).ToNot (HaveOccurred ())
1123+ defer rp .Body .Close ()
1124+ body , _ := io .ReadAll (rp .Body )
1125+ Expect (rp .StatusCode ).To (Equal (http .StatusOK ), string (body ))
1126+
1127+ Expect (prefillHandler .RequestCount .Load ()).To (BeNumerically ("==" , 1 ))
1128+ Expect (decodeHandler .RequestCount .Load ()).To (BeNumerically ("==" , 1 ))
1129+
1130+ prefillReq := prefillHandler .CompletionRequests [0 ]
1131+ Expect (prefillReq ).To (HaveKey (requestFieldECTransferParams ), "prefill request must carry ec_transfer_params" )
1132+
1133+ decodeReq := decodeHandler .CompletionRequests [0 ]
1134+ Expect (decodeReq ).ToNot (HaveKey (requestFieldECTransferParams ), "decode request must not carry ec_transfer_params" )
1135+ })
10611136})
10621137
10631138// moriProxyEnv bundles a running MoRI-IO proxy with its mock prefill/decode
0 commit comments