Compare commits
1376
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8576ccb72 | ||
|
|
d31a2a3ba8 | ||
|
|
5d0963b3dc | ||
|
|
43e507117f | ||
|
|
4be6bbe0e4 | ||
|
|
fe9e22df3d | ||
|
|
3bd5ac9685 | ||
|
|
b41e6707b1 | ||
|
|
29dacbd3ef | ||
|
|
9f3f475685 | ||
|
|
95781c31e0 | ||
|
|
3bf96080f3 | ||
|
|
0c7042d0d5 | ||
|
|
e5613794ca | ||
|
|
69de153f6e | ||
|
|
b308e196c9 | ||
|
|
9e7e3a802c | ||
|
|
551a03102f | ||
|
|
f46c958b67 | ||
|
|
513dba842a | ||
|
|
4aac1294f1 | ||
|
|
6fb2b36a81 | ||
|
|
29d13e3311 | ||
|
|
b539282a9a | ||
|
|
7b4dc7633b | ||
|
|
af46abebb5 | ||
|
|
b7c0e541d2 | ||
|
|
f58ef57ac4 | ||
|
|
9376c21edd | ||
|
|
56da589a3e | ||
|
|
28c87cde19 | ||
|
|
cd2fed99a7 | ||
|
|
8f58088f31 | ||
|
|
2d00d86e5e | ||
|
|
0295eeb6f3 | ||
|
|
535bd35b42 | ||
|
|
63bbd19a1d | ||
|
|
24b21278c0 | ||
|
|
7e5897b848 | ||
|
|
9b08ac8203 | ||
|
|
0a0e1884f7 | ||
|
|
ed5fc2b83b | ||
|
|
9c1656c607 | ||
|
|
ba3d48e1c7 | ||
|
|
9f7dadaad5 | ||
|
|
7650020618 | ||
|
|
7a8d956ece | ||
|
|
d486bf097a | ||
|
|
3b02e5338a | ||
|
|
926ba72793 | ||
|
|
1d77e96d4d | ||
|
|
dbd6a35dd2 | ||
|
|
98e123f3e0 | ||
|
|
3d43571b94 | ||
|
|
db82a55162 | ||
|
|
67aa30c966 | ||
|
|
6daf5b30f0 | ||
|
|
5e6b9047c9 | ||
|
|
b4737d3066 | ||
|
|
d38566ae80 | ||
|
|
7f867fb782 | ||
|
|
1934d121e2 | ||
|
|
a473ae78c3 | ||
|
|
21f167eacd | ||
|
|
205aa01c7b | ||
|
|
9a1a05facd | ||
|
|
81bc7116c1 | ||
|
|
d319d276f9 | ||
|
|
732d6085be | ||
|
|
d521b3f917 | ||
|
|
71125f80ad | ||
|
|
cb5f508212 | ||
|
|
8953d082c0 | ||
|
|
57d3e9fdf8 | ||
|
|
75570ee3a6 | ||
|
|
5634f03eb1 | ||
|
|
3f473a358b | ||
|
|
d2aa07159c | ||
|
|
7d6e2ade6c | ||
|
|
c482626450 | ||
|
|
7b6a5ee894 | ||
|
|
8422887d9f | ||
|
|
b44cf97b31 | ||
|
|
59db6a4285 | ||
|
|
ca14e635f5 | ||
|
|
d278aa8057 | ||
|
|
f1057b1e0d | ||
|
|
03ccce9a99 | ||
|
|
7af2c3d351 | ||
|
|
3032b4a013 | ||
|
|
0582844a41 | ||
|
|
9ebef4b1d3 | ||
|
|
f7e28348ad | ||
|
|
939e6ba56e | ||
|
|
ba5b7485a7 | ||
|
|
f3f8ebfc25 | ||
|
|
c7cd37b61e | ||
|
|
f8a00b1491 | ||
|
|
303edff930 | ||
|
|
0570b0da7e | ||
|
|
a4ad73e08b | ||
|
|
502a86fff7 | ||
|
|
36cdeb8fda | ||
|
|
5152b9bf4c | ||
|
|
6d339671ed | ||
|
|
c1bfd60e43 | ||
|
|
d4570afabf | ||
|
|
085cf0ff34 | ||
|
|
1d3dc8bf83 | ||
|
|
1586c41ae4 | ||
|
|
cb31e0774f | ||
|
|
8bc0c38b90 | ||
|
|
c11596c637 | ||
|
|
0b5f8832b9 | ||
|
|
381b12fa87 | ||
|
|
473da2cf82 | ||
|
|
60a933b9ab | ||
|
|
d8d162d810 | ||
|
|
62b15142bd | ||
|
|
d397a2f547 | ||
|
|
279b1b9687 | ||
|
|
2c2cffd2aa | ||
|
|
e01655f4a9 | ||
|
|
ef644b6112 | ||
|
|
44ea368843 | ||
|
|
856d19f42c | ||
|
|
fa1d03ab8d | ||
|
|
e5c0afc994 | ||
|
|
5e28163ba5 | ||
|
|
5356357cf0 | ||
|
|
8efd3c2f6d | ||
|
|
fb2e3535af | ||
|
|
84977d9543 | ||
|
|
154a1f25f5 | ||
|
|
86fcfe95f1 | ||
|
|
a9e2117f5e | ||
|
|
d139c600c7 | ||
|
|
1b87115c9e | ||
|
|
ae3880f0e3 | ||
|
|
e36babd48f | ||
|
|
139a47a578 | ||
|
|
16734bbdf3 | ||
|
|
102ba716bf | ||
|
|
2d0b03f717 | ||
|
|
d3396fc5fb | ||
|
|
4d877780d3 | ||
|
|
23f4126445 | ||
|
|
d02681bf01 | ||
|
|
9f5521351e | ||
|
|
ea62f86718 | ||
|
|
6a03e45c34 | ||
|
|
3f94c417be | ||
|
|
5a93ec1b4e | ||
|
|
8e10c3ee07 | ||
|
|
b6b868f3de | ||
|
|
b2b6c6c7a9 | ||
|
|
a9abd563f9 | ||
|
|
fa422a3f44 | ||
|
|
573ec4cdac | ||
|
|
fa506e0fe8 | ||
|
|
51c715c7ef | ||
|
|
23d8c83dab | ||
|
|
f9f53f2bd8 | ||
|
|
415005be22 | ||
|
|
698f716012 | ||
|
|
f90c267ffb | ||
|
|
470ec60848 | ||
|
|
ea84055507 | ||
|
|
232dbc82f8 | ||
|
|
4c7a98c26f | ||
|
|
7b4fc7ce2e | ||
|
|
ca3ccfc9a3 | ||
|
|
fbb4e63f0a | ||
|
|
0570f7a06e | ||
|
|
d4ffde1a6e | ||
|
|
0a5ece4ae5 | ||
|
|
4b0c187a1e | ||
|
|
3084b5d107 | ||
|
|
6df62d5157 | ||
|
|
aa2fadac42 | ||
|
|
eb2075981d | ||
|
|
823af92347 | ||
|
|
5d3e6dc1b4 | ||
|
|
9fbc36ab2d | ||
|
|
1c7476ec19 | ||
|
|
242c3cddeb | ||
|
|
f8197e120f | ||
|
|
6bda549ac2 | ||
|
|
77d8de70da | ||
|
|
b81f2c5d4b | ||
|
|
a6570b6814 | ||
|
|
9cdc57d2e7 | ||
|
|
97912de8d8 | ||
|
|
2ab5d1701a | ||
|
|
882bf8bc95 | ||
|
|
eb1abbadf8 | ||
|
|
c61b30255b | ||
|
|
5b22f5562f | ||
|
|
d0755b5716 | ||
|
|
873e9bff7c | ||
|
|
bf74544a35 | ||
|
|
f5e4f5fa42 | ||
|
|
e3be42e052 | ||
|
|
825ab20b07 | ||
|
|
cb439f3e84 | ||
|
|
8c3d3407d1 | ||
|
|
224152566a | ||
|
|
4200768f59 | ||
|
|
a769d9357b | ||
|
|
f1a6e7ce2a | ||
|
|
becfefd440 | ||
|
|
4fab34c8f4 | ||
|
|
72cc012cfd | ||
|
|
d81777f297 | ||
|
|
c8b3a17bd3 | ||
|
|
c32aaeb2da | ||
|
|
63032c91c6 | ||
|
|
5aadcbb0ab | ||
|
|
a8434a60da | ||
|
|
04c55d0164 | ||
|
|
c97b5fc741 | ||
|
|
38c7eeee4c | ||
|
|
4392af5ce3 | ||
|
|
d4dba0ddb1 | ||
|
|
2a68471715 | ||
|
|
3d75254a44 | ||
|
|
81b5be274d | ||
|
|
1053f7b0bd | ||
|
|
538eddd74d | ||
|
|
fa639b889e | ||
|
|
e6cebf8557 | ||
|
|
217a6af52c | ||
|
|
249e84d21b | ||
|
|
afa837f15c | ||
|
|
d554e6b67e | ||
|
|
e78a5d01f7 | ||
|
|
5f7f62e13c | ||
|
|
507cb1d834 | ||
|
|
99ff4f3070 | ||
|
|
9005d78903 | ||
|
|
5e9024171d | ||
|
|
21d86ec923 | ||
|
|
a2138b830f | ||
|
|
275720b378 | ||
|
|
5dbae2b182 | ||
|
|
7bceb1a76b | ||
|
|
3319f6ca78 | ||
|
|
3eb5c3b4e6 | ||
|
|
2185c4e26f | ||
|
|
c197cd2422 | ||
|
|
a1a234a0b4 | ||
|
|
45a3e77351 | ||
|
|
5527f3f407 | ||
|
|
f420cfcfbf | ||
|
|
65693b30fb | ||
|
|
bbf77cce69 | ||
|
|
6040bb97e2 | ||
|
|
c17126c219 | ||
|
|
78934753ff | ||
|
|
952022c8ec | ||
|
|
a3dee6fdf5 | ||
|
|
4a8ac29775 | ||
|
|
92715f3f7b | ||
|
|
5761ad5516 | ||
|
|
85da943391 | ||
|
|
5385dda4fe | ||
|
|
01f4479138 | ||
|
|
f062124ba4 | ||
|
|
27f0e8c1ea | ||
|
|
a22a7dd68f | ||
|
|
1b7e854b05 | ||
|
|
5f50fc3daf | ||
|
|
8e088c7725 | ||
|
|
c68eadbbe0 | ||
|
|
9f85b3722e | ||
|
|
7ad51f0007 | ||
|
|
ed3776645d | ||
|
|
fb23e8807a | ||
|
|
731e36fb57 | ||
|
|
5f25d98652 | ||
|
|
40f8e94400 | ||
|
|
2f1a18e69f | ||
|
|
909b121e0a | ||
|
|
ea1a416a17 | ||
|
|
e0c4f97f32 | ||
|
|
1b6cd282f0 | ||
|
|
3d793481a0 | ||
|
|
446c2b5474 | ||
|
|
2cbfd3e93b | ||
|
|
64903b8e30 | ||
|
|
58adeec05f | ||
|
|
e8f45fcd89 | ||
|
|
db40ed3a31 | ||
|
|
be9f3ed5c0 | ||
|
|
767cc7977e | ||
|
|
8e738ce21b | ||
|
|
6505577459 | ||
|
|
e284d907b5 | ||
|
|
311e714d34 | ||
|
|
6753bbd18c | ||
|
|
01a2f93256 | ||
|
|
f7d9deb45a | ||
|
|
7e520f9cc4 | ||
|
|
9edc1b4667 | ||
|
|
28291df179 | ||
|
|
bc0c9f4b45 | ||
|
|
b3ba67d71e | ||
|
|
9ef9fc442a | ||
|
|
68294066e3 | ||
|
|
4a7a8454ba | ||
|
|
220366db00 | ||
|
|
13b85c5622 | ||
|
|
6fcab74aa9 | ||
|
|
c111f3a2d6 | ||
|
|
d3493384cf | ||
|
|
78e1a0ae5c | ||
|
|
33fff2155e | ||
|
|
02aaa34059 | ||
|
|
de9a133d48 | ||
|
|
dff8f8f4cf | ||
|
|
43b8de9b0e | ||
|
|
f62d4ad4a7 | ||
|
|
3f7c217457 | ||
|
|
a7ab91fb85 | ||
|
|
96360ccb00 | ||
|
|
bad50980c9 | ||
|
|
3d952d1334 | ||
|
|
44fed17032 | ||
|
|
498c41b8d6 | ||
|
|
5c69fc2a8a | ||
|
|
5a386d789f | ||
|
|
ffcaaa9439 | ||
|
|
627630d7e4 | ||
|
|
05ab509269 | ||
|
|
c8bef008eb | ||
|
|
e540dfb72f | ||
|
|
43a476c1e5 | ||
|
|
d8d4062547 | ||
|
|
f11bf1a05d | ||
|
|
ce27ee6038 | ||
|
|
7576c4ceb9 | ||
|
|
a2486dd00b | ||
|
|
5b927b7ceb | ||
|
|
a7c295d544 | ||
|
|
bbac4df7d3 | ||
|
|
aff7d64948 | ||
|
|
333f14e97e | ||
|
|
4b8dcac681 | ||
|
|
35a83a0885 | ||
|
|
3d71a2b3ad | ||
|
|
6e63ea875e | ||
|
|
0637454301 | ||
|
|
faad918588 | ||
|
|
51cf142bc1 | ||
|
|
b02862beee | ||
|
|
504e5a6a6e | ||
|
|
6fb7b0a05e | ||
|
|
b9932aa17b | ||
|
|
06f67695f1 | ||
|
|
c94cf4ddde | ||
|
|
0e602509aa | ||
|
|
2f1845fa4e | ||
|
|
7c1b1e4189 | ||
|
|
6e79d582e3 | ||
|
|
038c9b948f | ||
|
|
cdd4638b17 | ||
|
|
ecdd762ff5 | ||
|
|
ffa991b24f | ||
|
|
c66df06c0f | ||
|
|
7712701578 | ||
|
|
ab56148505 | ||
|
|
5b002727b0 | ||
|
|
e0d0879794 | ||
|
|
09b720b0d2 | ||
|
|
968f3e379c | ||
|
|
f2e30f46b6 | ||
|
|
358b7d79c1 | ||
|
|
43b697541a | ||
|
|
2bae550c04 | ||
|
|
81c1c460b3 | ||
|
|
e74fe3c6e8 | ||
|
|
cdf027874c | ||
|
|
d7678e2bb3 | ||
|
|
5078c7ad66 | ||
|
|
f67cc52f74 | ||
|
|
b6f4df320d | ||
|
|
b3dd45874a | ||
|
|
5e4baea64d | ||
|
|
fdaf4e31bd | ||
|
|
7a80b79698 | ||
|
|
de1b0708bd | ||
|
|
7422a85cc7 | ||
|
|
a31690041d | ||
|
|
d59d166485 | ||
|
|
5378b77be4 | ||
|
|
d7740336ff | ||
|
|
c9c25b33c3 | ||
|
|
031612f250 | ||
|
|
b58ff5cb8b | ||
|
|
7c2e30afd3 | ||
|
|
f3fabe4145 | ||
|
|
c086554d1f | ||
|
|
c704aeccae | ||
|
|
087ac46318 | ||
|
|
1413eaab7c | ||
|
|
b1ec136bd7 | ||
|
|
e1c59edec6 | ||
|
|
043f03d576 | ||
|
|
c3498fb869 | ||
|
|
6942a5b600 | ||
|
|
3b335814cc | ||
|
|
cf36f5e474 | ||
|
|
7be014bce6 | ||
|
|
9b6a308914 | ||
|
|
30d6a0b4e6 | ||
|
|
4b96c57730 | ||
|
|
3204a0b2ad | ||
|
|
f080f41e03 | ||
|
|
85b0bad2d3 | ||
|
|
677265b64b | ||
|
|
91dfafcaab | ||
|
|
4b81f692d1 | ||
|
|
b78c31eda6 | ||
|
|
34aa1d2afa | ||
|
|
5cd925631c | ||
|
|
7f32c326c6 | ||
|
|
38abc0ba28 | ||
|
|
2df95de421 | ||
|
|
eeee257913 | ||
|
|
615f97b9c7 | ||
|
|
ff6e906a25 | ||
|
|
715b8b8746 | ||
|
|
14d2d00536 | ||
|
|
af74a5a155 | ||
|
|
039808e0d9 | ||
|
|
e8526cc552 | ||
|
|
06541d1f52 | ||
|
|
1cd92553cf | ||
|
|
32370968d0 | ||
|
|
946b843e61 | ||
|
|
f26f9c3a7f | ||
|
|
ea3cf99894 | ||
|
|
44d3ae100a | ||
|
|
ae70479619 | ||
|
|
142151fef5 | ||
|
|
5d7fdf9350 | ||
|
|
d4096e01fe | ||
|
|
13c617a140 | ||
|
|
66bbebd9d3 | ||
|
|
1e74807c35 | ||
|
|
ae57e406fd | ||
|
|
b6b992ac7b | ||
|
|
66d938100b | ||
|
|
348fd0fc07 | ||
|
|
ea14b04e9f | ||
|
|
0f9ee6afd8 | ||
|
|
22cefe04b4 | ||
|
|
7493cbd3c2 | ||
|
|
41f4f9d8c9 | ||
|
|
10701e1838 | ||
|
|
0e903e9695 | ||
|
|
175dec11be | ||
|
|
8d98cc0cb7 | ||
|
|
4179b0cae1 | ||
|
|
e43c787544 | ||
|
|
fda3af8bbc | ||
|
|
dff28e6867 | ||
|
|
1dae537313 | ||
|
|
ec22c7ac06 | ||
|
|
711daacabf | ||
|
|
2b47faf601 | ||
|
|
d1a5a7c178 | ||
|
|
24c49cf392 | ||
|
|
48ae412a2f | ||
|
|
b5e898f295 | ||
|
|
4927fd5412 | ||
|
|
8f284b343a | ||
|
|
376b28aced | ||
|
|
63ed0fdef4 | ||
|
|
ca6b4e2112 | ||
|
|
b9a88bf51e | ||
|
|
3ab582c993 | ||
|
|
3b6ce98421 | ||
|
|
95a9311696 | ||
|
|
d5fd9eb6bb | ||
|
|
5d20f6b900 | ||
|
|
c59b48b47e | ||
|
|
57c08d34c3 | ||
|
|
b6e72f3879 | ||
|
|
67ef0b64b9 | ||
|
|
e51fe6ec1b | ||
|
|
5f49848536 | ||
|
|
3cddda9781 | ||
|
|
0288c3f56e | ||
|
|
477083a103 | ||
|
|
e1b2f589c1 | ||
|
|
44c8d1c449 | ||
|
|
2298359f67 | ||
|
|
d1c8beeb18 | ||
|
|
e2b83db683 | ||
|
|
49c6fc1540 | ||
|
|
a65e89cbd4 | ||
|
|
7992c2213e | ||
|
|
8e26dce1f4 | ||
|
|
eb11446b7f | ||
|
|
705e781b0e | ||
|
|
b81aeb7b86 | ||
|
|
3d1ad0c0f4 | ||
|
|
fe4a2a7477 | ||
|
|
6f16f9546d | ||
|
|
58cb8de68b | ||
|
|
b864374089 | ||
|
|
2052deef07 | ||
|
|
86b85c078b | ||
|
|
5e06d2e73c | ||
|
|
f321cdbe16 | ||
|
|
4cca28e9bd | ||
|
|
ded8934626 | ||
|
|
759aa4ffeb | ||
|
|
1a9d598d2b | ||
|
|
8fe913e461 | ||
|
|
71748388f8 | ||
|
|
f7f48929db | ||
|
|
18f01befa7 | ||
|
|
1d75e63f7f | ||
|
|
c41925689d | ||
|
|
a6b559cf54 | ||
|
|
8be601ed7f | ||
|
|
99a2ae1fc8 | ||
|
|
21dd4b33ac | ||
|
|
9a88d2d21d | ||
|
|
73893e73ea | ||
|
|
87736a3cc5 | ||
|
|
3adee400a0 | ||
|
|
676a35fa8b | ||
|
|
72a1ce488b | ||
|
|
e338f0ece3 | ||
|
|
c50b7de167 | ||
|
|
a5b8c82788 | ||
|
|
5a5bc55c25 | ||
|
|
d9980c75e8 | ||
|
|
bb5bf8fd0a | ||
|
|
5c47fd0bc8 | ||
|
|
08cdee8dc4 | ||
|
|
143ccc5a2f | ||
|
|
55a226dcf1 | ||
|
|
f66f05633c | ||
|
|
457c6e2793 | ||
|
|
bfe8967ca2 | ||
|
|
fbc93a0e08 | ||
|
|
d934a5f7b8 | ||
|
|
bbb3ae01a1 | ||
|
|
46cfa8435b | ||
|
|
0dc8f45906 | ||
|
|
d94061201d | ||
|
|
9558fd2ea8 | ||
|
|
55a8bd6b80 | ||
|
|
f584729f24 | ||
|
|
034af1f657 | ||
|
|
8bfad23f98 | ||
|
|
6b9ce05feb | ||
|
|
6d84409a68 | ||
|
|
ebb3b20576 | ||
|
|
be335a86f9 | ||
|
|
d5aced9296 | ||
|
|
4ad455e61e | ||
|
|
da94c3ebe1 | ||
|
|
13173d6bbb | ||
|
|
009b992c5b | ||
|
|
04b97a5922 | ||
|
|
15c6ab8fa7 | ||
|
|
c201fd77c6 | ||
|
|
b6a4baa659 | ||
|
|
ed837e350e | ||
|
|
ab8d45d3cc | ||
|
|
f8f8aa8eb7 | ||
|
|
6ec5ab11bd | ||
|
|
4245fd6955 | ||
|
|
5e4daaf197 | ||
|
|
262ff14693 | ||
|
|
069e6c5fbc | ||
|
|
54c1fc64b7 | ||
|
|
c6df39e9f7 | ||
|
|
94b1546ce3 | ||
|
|
19da238246 | ||
|
|
651b03225b | ||
|
|
da4a08b65b | ||
|
|
0e44fc7406 | ||
|
|
432b2c6ca3 | ||
|
|
c2723979c0 | ||
|
|
2d4724eb74 | ||
|
|
91dd7fcaec | ||
|
|
926e7fbfa2 | ||
|
|
8cfede4309 | ||
|
|
d3c990dca8 | ||
|
|
5ec576ab4c | ||
|
|
030fccb2bf | ||
|
|
816335cb46 | ||
|
|
59cf3add40 | ||
|
|
7439ed41c2 | ||
|
|
7ba5e8a146 | ||
|
|
f90e992dc1 | ||
|
|
5de6f7c37a | ||
|
|
7ae15c74c8 | ||
|
|
aeb348d8f8 | ||
|
|
40dcfdbb43 | ||
|
|
a708ae5b7a | ||
|
|
780e8d40aa | ||
|
|
6639c82a17 | ||
|
|
0eb47b76d0 | ||
|
|
497c537c6f | ||
|
|
c608910d20 | ||
|
|
5a8b81ebeb | ||
|
|
dd527b4245 | ||
|
|
0d5d1115d6 | ||
|
|
683f3c92a4 | ||
|
|
72beeaee86 | ||
|
|
d6b66faba7 | ||
|
|
bc8ea489ef | ||
|
|
29e3165bb9 | ||
|
|
51b7565f33 | ||
|
|
b454e34966 | ||
|
|
bae58f84b8 | ||
|
|
f0808c9793 | ||
|
|
702a409664 | ||
|
|
710024fa6f | ||
|
|
53b60bd9bc | ||
|
|
50b8a150f9 | ||
|
|
4af0ddc1c2 | ||
|
|
8360346a66 | ||
|
|
8fdb719a41 | ||
|
|
678aa25864 | ||
|
|
a94b2580a1 | ||
|
|
d150a4fde7 | ||
|
|
aa69acbd09 | ||
|
|
0e4b28f491 | ||
|
|
f446468c03 | ||
|
|
d15b7ca3e1 | ||
|
|
072bfc02dd | ||
|
|
3d035bfa19 | ||
|
|
1c917b2751 | ||
|
|
17285c2f55 | ||
|
|
1e2a6446f7 | ||
|
|
39c16d75a9 | ||
|
|
0db262de2a | ||
|
|
2e096788a6 | ||
|
|
b2c9376539 | ||
|
|
3ad64c6a12 | ||
|
|
855719e331 | ||
|
|
bd4f9acfd3 | ||
|
|
f09bdcbc7d | ||
|
|
b39f599b09 | ||
|
|
72ee535fcd | ||
|
|
c2daa471c3 | ||
|
|
493fc64397 | ||
|
|
3781214675 | ||
|
|
42059f19d5 | ||
|
|
faa12af454 | ||
|
|
4882a36c41 | ||
|
|
3d34b8b977 | ||
|
|
cfbf1392c5 | ||
|
|
dc72559d5d | ||
|
|
260db8bab5 | ||
|
|
4f7c08c0eb | ||
|
|
ea0a24465b | ||
|
|
fc163cd90f | ||
|
|
016861385f | ||
|
|
15e38ac173 | ||
|
|
70bdd49402 | ||
|
|
73b623f2f7 | ||
|
|
5730af0a95 | ||
|
|
37c11e6e4f | ||
|
|
13c2de684c | ||
|
|
b2011a3edd | ||
|
|
b3270dec8d | ||
|
|
ebb4abde0a | ||
|
|
c6e38860e9 | ||
|
|
b1da47b781 | ||
|
|
8d34d3b5de | ||
|
|
cd3867c373 | ||
|
|
718d9a4cd7 | ||
|
|
273ffce130 | ||
|
|
10906e3a6d | ||
|
|
48e4f6a385 | ||
|
|
53df9fe62b | ||
|
|
b57dc70ec4 | ||
|
|
480e10ba9c | ||
|
|
b58feb1420 | ||
|
|
38cf9adc38 | ||
|
|
9c61d5b67b | ||
|
|
47b1893676 | ||
|
|
bd17618c11 | ||
|
|
6f55a06fab | ||
|
|
efaf4276f9 | ||
|
|
ea24deefcc | ||
|
|
c3f80502e0 | ||
|
|
8dc3d504d8 | ||
|
|
7099583404 | ||
|
|
ac0067078b | ||
|
|
26e003715c | ||
|
|
a630b0c2ec | ||
|
|
adf6d0c1ea | ||
|
|
14bd8f8772 | ||
|
|
14f2c16fb2 | ||
|
|
9683b7f4b4 | ||
|
|
07ceb3324a | ||
|
|
b4b907e7b6 | ||
|
|
f208f907bc | ||
|
|
284e05c88b | ||
|
|
c3de04e127 | ||
|
|
4cd667875f | ||
|
|
e1c5f59aab | ||
|
|
02069a5bbf | ||
|
|
cd9ae66b3a | ||
|
|
0a1846aa45 | ||
|
|
b283215c28 | ||
|
|
199ef7779c | ||
|
|
3c6648d8a5 | ||
|
|
d7216ef514 | ||
|
|
2fdbf2234a | ||
|
|
265d80b4dd | ||
|
|
5d09cf27a9 | ||
|
|
170d498771 | ||
|
|
2a9f6aaa8e | ||
|
|
5664e69dbf | ||
|
|
e96d3fe2a6 | ||
|
|
309d9c3ea8 | ||
|
|
65b3d41b3a | ||
|
|
4616823125 | ||
|
|
611c083587 | ||
|
|
baba7d1e2e | ||
|
|
9d2bb23ff6 | ||
|
|
3875f8ded4 | ||
|
|
9798bc3a8d | ||
|
|
68bf8c2c42 | ||
|
|
444485650b | ||
|
|
2a315e1a2d | ||
|
|
d1e230c95b | ||
|
|
09b6a1604a | ||
|
|
555336e887 | ||
|
|
136cb27b05 | ||
|
|
ce6ab0ca46 | ||
|
|
f39b8684eb | ||
|
|
e57574ae29 | ||
|
|
7b76b6446d | ||
|
|
a70d4d4b3c | ||
|
|
1260ceaae6 | ||
|
|
6f36fd3b78 | ||
|
|
35cacf020c | ||
|
|
d671e6b0db | ||
|
|
b95c73742d | ||
|
|
fe54ecc388 | ||
|
|
4b6d6d5cf7 | ||
|
|
f7a5146093 | ||
|
|
8ecd1f6d5c | ||
|
|
ffd11c181e | ||
|
|
728640f4d9 | ||
|
|
022d7a7695 | ||
|
|
b300f66656 | ||
|
|
bc73546c06 | ||
|
|
2b08419d8b | ||
|
|
5d50bdc2ab | ||
|
|
8a5bf2fb3f | ||
|
|
596c16a550 | ||
|
|
90a08c0eda | ||
|
|
dbc0dd6d85 | ||
|
|
83d1f11449 | ||
|
|
4b66f62e10 | ||
|
|
f41451f64c | ||
|
|
bbe6ccc512 | ||
|
|
bbb709cfb5 | ||
|
|
c98517ce7f | ||
|
|
d77a35a32b | ||
|
|
877beeaa49 | ||
|
|
8b8d3f56db | ||
|
|
c57178c0e1 | ||
|
|
9a59475015 | ||
|
|
12f8168179 | ||
|
|
72a02b492a | ||
|
|
5358f5db01 | ||
|
|
e677360168 | ||
|
|
208c6776a8 | ||
|
|
fcf1085395 | ||
|
|
38a2500bdf | ||
|
|
7cd826d28c | ||
|
|
31384cb39c | ||
|
|
5be7541d01 | ||
|
|
9b0df3909a | ||
|
|
a15b5b4bcd | ||
|
|
3c3989ed04 | ||
|
|
854bff7fe5 | ||
|
|
b792578d89 | ||
|
|
bdb1d996be | ||
|
|
8b0a6779d4 | ||
|
|
58007c0084 | ||
|
|
1ff2753469 | ||
|
|
4697bd1be0 | ||
|
|
2ce15ab7a0 | ||
|
|
584d78c673 | ||
|
|
89015d5cad | ||
|
|
348cf95a89 | ||
|
|
22dd96ec5c | ||
|
|
e04210d690 | ||
|
|
4ab1b4ff9c | ||
|
|
06e733d3cd | ||
|
|
af3faa6c1e | ||
|
|
322600bfb2 | ||
|
|
c4a14091c9 | ||
|
|
6d4e4ffc7c | ||
|
|
f97af75d1d | ||
|
|
73a312d5b6 | ||
|
|
1a56953d7a | ||
|
|
1f65814fab | ||
|
|
4f9b65074d | ||
|
|
12a5f6fbf3 | ||
|
|
53afbf3a0c | ||
|
|
ee118ab492 | ||
|
|
c27623c29c | ||
|
|
f8fa86fb1f | ||
|
|
422d8fd8f9 | ||
|
|
62e239bf1e | ||
|
|
740f45abcd | ||
|
|
5e4b9f8c6e | ||
|
|
ae811043e9 | ||
|
|
636d44e272 | ||
|
|
8e44e78038 | ||
|
|
b98b7c8529 | ||
|
|
1ee2fff532 | ||
|
|
33dd9a5a3e | ||
|
|
c588208cc6 | ||
|
|
e28bf8ff8b | ||
|
|
e1aa6eae75 | ||
|
|
36135ef09a | ||
|
|
11f633aa83 | ||
|
|
6ae7ff7846 | ||
|
|
615de4e041 | ||
|
|
be48b0797e | ||
|
|
45629a8e26 | ||
|
|
fc8946fcf5 | ||
|
|
f01e4bdddc | ||
|
|
592637015f | ||
|
|
ebe93f5d1e | ||
|
|
8e2e9b6b53 | ||
|
|
9159cedbd7 | ||
|
|
593b404539 | ||
|
|
f663d120c7 | ||
|
|
81b48e83ec | ||
|
|
fd0e92183a | ||
|
|
44e38d7b38 | ||
|
|
b15d4e6a64 | ||
|
|
18bf7e0ff9 | ||
|
|
cfa6d66ed6 | ||
|
|
d8c35663b4 | ||
|
|
e906f41dc8 | ||
|
|
f114113409 | ||
|
|
ab459b36c2 | ||
|
|
24ede9e226 | ||
|
|
3d7fc3b9ba | ||
|
|
6ec9033065 | ||
|
|
a874b8e09b | ||
|
|
62bf8d630d | ||
|
|
4b625d1175 | ||
|
|
48298030d4 | ||
|
|
d219d93bbb | ||
|
|
a9ba47d8ce | ||
|
|
93457f29ff | ||
|
|
bc95e7415f | ||
|
|
f879ad4983 | ||
|
|
f2e3d2e25b | ||
|
|
240e6655be | ||
|
|
9235b0ae65 | ||
|
|
1c2a81f6d8 | ||
|
|
b4581b293b | ||
|
|
9f978923f2 | ||
|
|
589afcef6c | ||
|
|
556c5f88a0 | ||
|
|
2eada79b99 | ||
|
|
7fb62db5c2 | ||
|
|
6510de344e | ||
|
|
740cb35a59 | ||
|
|
ae7bee0c43 | ||
|
|
6a604be610 | ||
|
|
f201b7171f | ||
|
|
0a7ac4c67e | ||
|
|
e788ef6e76 | ||
|
|
f24a6165ff | ||
|
|
bfaaa3c2c3 | ||
|
|
c9f2e5ad94 | ||
|
|
fbea788668 | ||
|
|
78c144f3a8 | ||
|
|
1c4aca7f6e | ||
|
|
6fdc4ca62d | ||
|
|
b6728db486 | ||
|
|
b9a51592f0 | ||
|
|
5215e03a91 | ||
|
|
d5d47e9be1 | ||
|
|
30cba84222 | ||
|
|
9f9f9f274a | ||
|
|
900a7f0813 | ||
|
|
7a2007cc17 | ||
|
|
76de642c54 | ||
|
|
a4ea67a21b | ||
|
|
e0c2b9d73f | ||
|
|
24741961eb | ||
|
|
727f90958e | ||
|
|
67c54777bb | ||
|
|
2c4e9a945b | ||
|
|
4b1547b4d8 | ||
|
|
6e8c279a68 | ||
|
|
6f98c807d2 | ||
|
|
185e3d6df6 | ||
|
|
67aa6c55a4 | ||
|
|
9d67f8e02f | ||
|
|
cd5daaea6a | ||
|
|
8cb79308c6 | ||
|
|
0a03359224 | ||
|
|
fe02e8b81e | ||
|
|
896f05e7e6 | ||
|
|
d33c905d80 | ||
|
|
4715570acc | ||
|
|
4956a41f12 | ||
|
|
2739f0776b | ||
|
|
2d8ef4754c | ||
|
|
f8a8fbf72e | ||
|
|
226cb4a38c | ||
|
|
0a51a18570 | ||
|
|
499d930fe5 | ||
|
|
273fc8eb1d | ||
|
|
a951dd0cb4 | ||
|
|
4563999ec0 | ||
|
|
86d7864588 | ||
|
|
3b0718f22e | ||
|
|
ce3d8e4bac | ||
|
|
81cd7964d4 | ||
|
|
09c6ad4204 | ||
|
|
f7e87e7cfd | ||
|
|
744c65b730 | ||
|
|
b3f4fbf9e2 | ||
|
|
1752e8ee5b | ||
|
|
089bb88706 | ||
|
|
04b408ffd2 | ||
|
|
0c88f8a0b6 | ||
|
|
1d6c0816a4 | ||
|
|
d50ea9fccc | ||
|
|
daec3a6a49 | ||
|
|
0461da345a | ||
|
|
aa5364f705 | ||
|
|
1b718f7b15 | ||
|
|
dba05c3517 | ||
|
|
f2d9eb1630 | ||
|
|
fa0658eabb | ||
|
|
7c17111ff5 | ||
|
|
925347332f | ||
|
|
7be7e0d249 | ||
|
|
18be2ba3df | ||
|
|
1c6e731339 | ||
|
|
b8e7b21188 | ||
|
|
39663d5287 | ||
|
|
ab0da662c0 | ||
|
|
fa41fdf252 | ||
|
|
7fa40681ff | ||
|
|
23bb4395bb | ||
|
|
0feb92bdfa | ||
|
|
f6e59c329b | ||
|
|
c96fe54bd8 | ||
|
|
c2b55de5b9 | ||
|
|
61324e65d7 | ||
|
|
f775e80732 | ||
|
|
c96f0bc773 | ||
|
|
f4640d9a2e | ||
|
|
12d75cf63a | ||
|
|
66a9b0c84f | ||
|
|
cee2e40c33 | ||
|
|
5014fea4a0 | ||
|
|
f2c5152df0 | ||
|
|
d3e0171cd7 | ||
|
|
807db6efd7 | ||
|
|
d4a5eaac90 | ||
|
|
8f115164c2 | ||
|
|
cbab1d4d8f | ||
|
|
fb89ab43ea | ||
|
|
7762d664d8 | ||
|
|
4dd1b47f47 | ||
|
|
e108cbb510 | ||
|
|
82172b112d | ||
|
|
e9bc7fc06a | ||
|
|
8001bb155d | ||
|
|
88b7ca2ffa | ||
|
|
5b230541c9 | ||
|
|
776424f0de | ||
|
|
d688aa82fc | ||
|
|
9b4ea13c80 | ||
|
|
eaf90d8eff | ||
|
|
1f01d05603 | ||
|
|
9f3a73df17 | ||
|
|
b9b8282cf5 | ||
|
|
911ea0c586 | ||
|
|
e28e389a76 | ||
|
|
138c6988ad | ||
|
|
ddc3c87547 | ||
|
|
2bb618903a | ||
|
|
ccdb2b51aa | ||
|
|
b6c4578dac | ||
|
|
76e4a78afc | ||
|
|
af2f84582b | ||
|
|
7afd3a0dcb | ||
|
|
e043818abf | ||
|
|
d6240742f3 | ||
|
|
ff0a76e31c | ||
|
|
93786c9cd3 | ||
|
|
84bbd57e4d | ||
|
|
8927ec057c | ||
|
|
a5d9d57adc | ||
|
|
536daea107 | ||
|
|
784c27f493 | ||
|
|
c56d0da1bb | ||
|
|
ad3a162eb8 | ||
|
|
acf941da4d | ||
|
|
6eed6b9434 | ||
|
|
a61d5c0fd8 | ||
|
|
0fe5d73a63 | ||
|
|
4c23a3164b | ||
|
|
778959797c | ||
|
|
e9a06d5bdc | ||
|
|
f72b38184b | ||
|
|
05b794f29b | ||
|
|
b55120c93b | ||
|
|
b471a5cf23 | ||
|
|
96235da468 | ||
|
|
00bdb5dcd7 | ||
|
|
be667a8067 | ||
|
|
7d5376f215 | ||
|
|
f10320f53f | ||
|
|
cc1939120f | ||
|
|
f44649ffd0 | ||
|
|
8219c01b57 | ||
|
|
23d0ee5c0c | ||
|
|
fb4dd41d79 | ||
|
|
68ee52f4e7 | ||
|
|
1984346bc7 | ||
|
|
633ebbd8a4 | ||
|
|
8fc9df4331 | ||
|
|
9479720f81 | ||
|
|
f43d761c26 | ||
|
|
39e83e27f0 | ||
|
|
24eb4ab89c | ||
|
|
e39f4dddfb | ||
|
|
e2115fb642 | ||
|
|
f18924c1ca | ||
|
|
dcf8b07d39 | ||
|
|
2cf5f57b3e | ||
|
|
ea34bde619 | ||
|
|
ee33954dff | ||
|
|
d34b91722f | ||
|
|
9ca98009b2 | ||
|
|
7b5b399210 | ||
|
|
7924beef84 | ||
|
|
0034eaa9c3 | ||
|
|
779466becb | ||
|
|
5a6a93dc5f | ||
|
|
2f33df4678 | ||
|
|
0576264dd1 | ||
|
|
5d44868e91 | ||
|
|
740bb31ff9 | ||
|
|
64bcdc2186 | ||
|
|
dacb8e6f10 | ||
|
|
e24bddfb22 | ||
|
|
4d799997d3 | ||
|
|
7d75095b84 | ||
|
|
74f2742ac2 | ||
|
|
a06664a243 | ||
|
|
6cd1ff7e64 | ||
|
|
7b2edd6650 | ||
|
|
32dddfcef4 | ||
|
|
10d3a25916 | ||
|
|
98e0a49eb0 | ||
|
|
eef3bd5c4a | ||
|
|
0d8c632688 | ||
|
|
c23dbfe111 | ||
|
|
ffd4e1f97e | ||
|
|
109942465f | ||
|
|
e9991a5907 | ||
|
|
4fbbdfd250 | ||
|
|
793d3e9ab7 | ||
|
|
907f932b72 | ||
|
|
1f0ed96fcd | ||
|
|
6853d7204d | ||
|
|
d09f549e86 | ||
|
|
7aa5c9a090 | ||
|
|
be517db18a | ||
|
|
07957e12f4 | ||
|
|
ae949d129f | ||
|
|
85f7a5b374 | ||
|
|
0a9a5c231e | ||
|
|
2a49b2b217 | ||
|
|
5c3900960b | ||
|
|
68a992060b | ||
|
|
238fc0a609 | ||
|
|
a432b8a325 | ||
|
|
795e4e0160 | ||
|
|
f84f0e72fd | ||
|
|
2d58070f60 | ||
|
|
a7b6a174bc | ||
|
|
6603450d71 | ||
|
|
b14ff23041 | ||
|
|
1a4a042a83 | ||
|
|
4b9d09cb87 | ||
|
|
3589a676e2 | ||
|
|
b1809985ef | ||
|
|
e0570a0859 | ||
|
|
b20ebc8f9b | ||
|
|
2c0d8399ac | ||
|
|
625892032b | ||
|
|
66b9ad287a | ||
|
|
98229b08ba | ||
|
|
161b005cfc | ||
|
|
3f4abedbda | ||
|
|
8e14f69d96 | ||
|
|
9a02963acf | ||
|
|
a6da469134 | ||
|
|
a28ded243f | ||
|
|
d3c47efc4f | ||
|
|
dda88a6f86 | ||
|
|
9014bb9917 | ||
|
|
6581e2afa9 | ||
|
|
b95905deb1 | ||
|
|
ff6f0da271 | ||
|
|
fe478a95ab | ||
|
|
cbd3939c3d | ||
|
|
9a44e7e019 | ||
|
|
5c3923509d | ||
|
|
9fe26cfacb | ||
|
|
020792e6be | ||
|
|
b3a4819694 | ||
|
|
5dc787d5e8 | ||
|
|
ca0ae7269c | ||
|
|
690864f277 | ||
|
|
a5db2d839a | ||
|
|
3a64da194c | ||
|
|
6d50348ef1 | ||
|
|
da15a4cb1c | ||
|
|
267b49b880 | ||
|
|
b7d08fe5f6 | ||
|
|
7d4decc1d8 | ||
|
|
b96bc5ac87 | ||
|
|
4908b85731 | ||
|
|
17e27c80e3 | ||
|
|
d5e197fb97 | ||
|
|
460a5c6b48 | ||
|
|
7ab50965e8 | ||
|
|
815abce2ba | ||
|
|
31c9c751fc | ||
|
|
d365d3a69e | ||
|
|
d4a869fe5e | ||
|
|
9ceca4ec85 | ||
|
|
ba7e9e6496 | ||
|
|
14fad9835d | ||
|
|
862e0a2b27 | ||
|
|
66ec3a2aff | ||
|
|
ddba6de2ab | ||
|
|
d7b365df64 | ||
|
|
02d654760f | ||
|
|
86bdcaf3d5 | ||
|
|
aa21412c01 | ||
|
|
1b31f96240 | ||
|
|
0798b0bf03 | ||
|
|
29dcdec66d | ||
|
|
9eaca72382 | ||
|
|
51c14eeaed | ||
|
|
e73245c60f | ||
|
|
f7cdc45977 | ||
|
|
46f10478dc | ||
|
|
20d43ce24d | ||
|
|
991fb7408b | ||
|
|
a8b2bf11d2 | ||
|
|
d8db832fc2 | ||
|
|
0455bffc37 | ||
|
|
04f400d36c | ||
|
|
0b59dfb94a | ||
|
|
d9cf85d5e2 | ||
|
|
3023bc40c2 | ||
|
|
b443504d61 | ||
|
|
06329c6450 | ||
|
|
f00caf35c4 | ||
|
|
431a7c71ac | ||
|
|
9d8089095e | ||
|
|
1b0de21c55 | ||
|
|
5c51782c6b | ||
|
|
f11b32a42e | ||
|
|
a25636d780 | ||
|
|
b0f6b9de96 | ||
|
|
bbc0476237 | ||
|
|
720bd756bf | ||
|
|
4d2ee15156 | ||
|
|
1788d76eb3 | ||
|
|
d526dc93e8 | ||
|
|
6b11f6b41d | ||
|
|
e4a2d3676e | ||
|
|
efc6b391e4 | ||
|
|
e7b281799e | ||
|
|
c21e9a35f8 | ||
|
|
a560ed184d | ||
|
|
9a105bf90d | ||
|
|
bb8614595d | ||
|
|
4028680b7e | ||
|
|
99234881f5 | ||
|
|
dd3a4d0a29 | ||
|
|
0899a1a666 | ||
|
|
2fc00efa49 | ||
|
|
11f6a0b72e | ||
|
|
c45ac74d43 | ||
|
|
504698dec8 | ||
|
|
724f5d132d | ||
|
|
deb9bd4efc | ||
|
|
7619ed6b82 | ||
|
|
e4026a50ad | ||
|
|
e9d4931781 | ||
|
|
cd35572069 | ||
|
|
1b318d11d1 | ||
|
|
be60d7c7c7 | ||
|
|
60ccadfbb6 | ||
|
|
92f7208559 | ||
|
|
05a86ed10e | ||
|
|
c6ee3f7c18 | ||
|
|
327e9dcaf2 | ||
|
|
47871d5e20 | ||
|
|
b66cd024b9 | ||
|
|
c582805e7a | ||
|
|
908e7d32d9 | ||
|
|
d6f1d3d61c | ||
|
|
c39ac9fffd | ||
|
|
580a0efe40 | ||
|
|
329c98ff9d | ||
|
|
36a5e9cfd2 | ||
|
|
0b04f2a0d6 | ||
|
|
5db89b41c4 | ||
|
|
e500c00545 | ||
|
|
8ddcb3621f | ||
|
|
2e6c83c89c | ||
|
|
d9063d7141 | ||
|
|
8c33793ffc | ||
|
|
4024a8ccd6 | ||
|
|
fb563fbd19 | ||
|
|
0fd2620d56 | ||
|
|
0d0f4e669e | ||
|
|
d94108693a | ||
|
|
d612233bef | ||
|
|
f6e8b77642 | ||
|
|
d8edf0c9d5 | ||
|
|
67bd02f767 | ||
|
|
0814d845dc | ||
|
|
bb973cb10c | ||
|
|
fb3abb38fb | ||
|
|
eb81914c64 | ||
|
|
1951dca786 | ||
|
|
d71cacc74c | ||
|
|
465f1464d2 | ||
|
|
f6894f4308 | ||
|
|
a2d1dafc65 | ||
|
|
6dc4638a7e | ||
|
|
d35cdd2dab | ||
|
|
0958e62ecc | ||
|
|
3901ad8165 | ||
|
|
b84c99c122 | ||
|
|
733f4f6a36 | ||
|
|
67d14b5ac4 | ||
|
|
64efa66869 | ||
|
|
6646a66d41 | ||
|
|
378359fc11 | ||
|
|
9c260b3774 | ||
|
|
9177b37e2f | ||
|
|
50bc51ffdf | ||
|
|
044240d8eb | ||
|
|
f4d922d8f6 | ||
|
|
eaa16e1941 | ||
|
|
8a6786731e | ||
|
|
fb0f17858f | ||
|
|
2447740308 | ||
|
|
a10eac0f8c | ||
|
+2 |
ec4ec0f604 | ||
|
|
ad07f98b73 | ||
|
|
a60242092a | ||
|
|
991b1ec752 | ||
|
|
6bdd85b384 | ||
|
|
36bd8029f3 | ||
|
|
f0d7fe18f2 | ||
|
|
ccb5c53ea5 | ||
|
|
8efd9d832d | ||
|
|
7ff11d8d0f | ||
|
|
fc32d9fe6f | ||
|
|
afbcc51672 | ||
|
|
1292c47804 | ||
|
|
e241005a71 | ||
|
|
950e66a44c | ||
|
|
a1e1ac0155 | ||
|
|
cead615288 | ||
|
|
17cf60a63d | ||
|
|
2d0b1d8a29 | ||
|
|
e70822ed54 | ||
|
|
6ff246bf3c | ||
|
|
951ae28eb0 | ||
|
|
7e152ca64b | ||
|
|
208932210f | ||
|
|
f05e03aea8 | ||
|
|
63ba11b8b1 | ||
|
|
37a442447e | ||
|
|
13e9094be0 | ||
|
|
1228a109f0 | ||
|
|
8f28b969e9 | ||
|
|
2d2258890b | ||
|
|
0383fde38a | ||
|
|
f75c437a60 | ||
|
|
dff8cda844 | ||
|
|
c782746133 | ||
|
|
db8bc2c71d | ||
|
|
14d70d9870 | ||
|
|
77d395150b | ||
|
|
f195e44bc1 | ||
|
|
2f64c712fd | ||
|
|
65bc737fd4 | ||
|
|
d744940b18 | ||
|
|
e957d16f8d | ||
|
|
8fa0394d29 | ||
|
|
ed37d8e7a2 | ||
|
|
d78a92ec54 | ||
|
|
679cbe226a | ||
|
|
dff757da9c | ||
|
|
890803ca06 | ||
|
|
64a5bb92de | ||
|
|
83e3b129f0 | ||
|
|
1761253005 | ||
|
|
d897852258 | ||
|
|
b46c5af06f | ||
|
|
f200e988a6 | ||
|
|
e3621ec633 | ||
|
|
e7f0db1067 | ||
|
|
864d22164c | ||
|
|
5f5b77aa9c | ||
|
|
3fa8817fc5 | ||
|
|
a62420450c | ||
|
|
5cce797c03 | ||
|
|
d8a72be206 | ||
|
|
ba4932c364 | ||
|
|
dc14380796 | ||
|
|
3bce5e2e3a | ||
|
|
46e0b71423 | ||
|
|
c58a02c873 | ||
|
|
a86c333c7e | ||
|
|
aff0af9754 | ||
|
|
b1a4b08a7e | ||
|
|
e2e79177db | ||
|
|
ae937320ff | ||
|
|
11829ccd75 | ||
|
|
a693ae67f6 | ||
|
|
3c62c53f59 | ||
|
|
f8340d078e | ||
|
|
c9d5545b52 | ||
|
|
10404e4c5b | ||
|
|
6c6fde3e6d | ||
|
|
7b837944a1 | ||
|
|
a9ee92ddec | ||
|
|
31886d6ece | ||
|
|
fa94f41807 | ||
|
|
d75a6433b4 | ||
|
|
6506ed3d4d | ||
|
|
d4f2a49a68 | ||
|
|
9bc8705c98 | ||
|
|
1733831f78 | ||
|
|
20b7a67b0d | ||
|
|
9577ccba50 | ||
|
|
54a9d241c0 | ||
|
|
6de0ca36bb | ||
|
|
293396737d | ||
|
|
aa59dc50c7 | ||
|
|
f44f3ef9f7 | ||
|
|
8f869c8ea5 |
No files matched your search
@@ -0,0 +1,64 @@
|
||||
---
|
||||
name: 3d-animation-short-generator
|
||||
description: Develop stylized 3D narrative shorts through story, character and environment references, timed shot tables, storyboards, generation, and assembly. Use for coherent animated storytelling or its planning stages, not isolated image edits or photorealistic live action.
|
||||
metadata:
|
||||
compatibility: File-based agent workflow with sibling h3-prompt-writing. Media generation and editing require available tools or a configured backend.
|
||||
---
|
||||
|
||||
# 3D Animation Short Generator
|
||||
|
||||
Read the [portable workflow](../h3-prompt-writing/references/portable-workflow.md).
|
||||
For a complete film, progress from story to references, shot table, text storyboard,
|
||||
clips, and assembly. Keep these as local artifacts, using existing user decisions
|
||||
and authorization. If only a planning stage is requested, deliver that stage.
|
||||
|
||||
## Story and visual contract
|
||||
|
||||
Capture premise, desired emotional outcome, duration, ratio, model, and audio mode.
|
||||
Use warm stylized 3D as a default only when style is unspecified: readable geometric
|
||||
silhouettes, designed hair clumps, tactile materials, soft skin shading where
|
||||
appropriate, expressive brows/eyes, and elastic posing. User-selected 2D or other
|
||||
styles override this preset rather than receiving accidental 3D texture.
|
||||
|
||||
Create an active protagonist with a want, obstacle, meaningful choice, and payoff.
|
||||
Connect the ending to an earlier visual/emotional anchor. Use as many beats as the
|
||||
duration needs; do not pad a tiny story into an eight-beat formula. Dialogue should
|
||||
change a relationship or move the action, and use the user's requested language.
|
||||
|
||||
## Reference design
|
||||
|
||||
- Character references lock name, silhouette, proportions, face, hair, costume,
|
||||
signature props, and color. Label identity in the production document; clean
|
||||
rendering anchors should not carry labels that could leak into the video.
|
||||
- Scene references contain environments only unless the user requested a composite.
|
||||
Record landmarks, lighting direction/time of day, entrances, exits, and prop state.
|
||||
- A reference board with multiple views is for design review. Prefer appropriate
|
||||
clean views for model input so grids and pose sheets do not become final frames.
|
||||
- When an asset changes, update all affected prompts and clips, with a manifest
|
||||
identifying the current revision.
|
||||
|
||||
## Shot planning
|
||||
|
||||
Read [shot-table-spec.md](references/shot-table-spec.md) for the six-column table
|
||||
and continuity checks. Then read
|
||||
[storyboard-guidelines.md](references/storyboard-guidelines.md) for the matching
|
||||
text storyboard and optional pencil previews. The text storyboard is the source
|
||||
of shot timing; preview art does not silently replace it.
|
||||
|
||||
Vary shot size and elastic performance to serve the story. Camera tilts, close-ups,
|
||||
or exaggeration are choices for specific beats, not quotas. Track off-screen
|
||||
characters and spatial landmarks so they do not teleport back into later shots.
|
||||
|
||||
## Generation and assembly
|
||||
|
||||
Before rendering, read [model-selection.md](references/model-selection.md) and
|
||||
[fallback-policy.md](references/fallback-policy.md). Use the chosen model through
|
||||
available tools. Compile prompts using the H3 base or reference guide as appropriate.
|
||||
Remove storyboard-only labels, arrows, panel borders, and sketch styling from
|
||||
rendering inputs. Tie each clip to the current scene and character references.
|
||||
|
||||
Read [qc-checklist.md](references/qc-checklist.md) for assembly and final review.
|
||||
Keep the planned shot order and audio continuity. Use a continuous score when
|
||||
requested, duck it under dialogue/SFX, and do not add subtitles unasked. Deliver
|
||||
the actual film or the requested planning package, with reproducible prompts and
|
||||
any unresolved identity, scene, or timing defects.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "3D Animation Shorts"
|
||||
short_description: "Plan stories, character anchors, shots, and edits"
|
||||
default_prompt: "Use $3d-animation-short-generator to prepare the requested H3 prompts or video with the available tools."
|
||||
@@ -0,0 +1,21 @@
|
||||
# Targeted generation recovery
|
||||
|
||||
Compare the failed result against the shot's actual identity/spatial anchors.
|
||||
Classify the failure: wrong input or API mapping, reference drift, overloaded
|
||||
action, timing, audio, or a render/export failure. Fix transport/configuration
|
||||
errors before spending another generation attempt.
|
||||
|
||||
For drift, quote the relevant anchors and remove unrelated reference roles. For
|
||||
overloaded action, simplify or split the shot while preserving the requested total
|
||||
duration and handoffs. For a scene change, use the new scene reference and avoid
|
||||
conditioning on a previous scene when that would contradict the new setting.
|
||||
|
||||
Use the retry/resource limit from the shared portable workflow. A persistent
|
||||
failure should lead to a concrete choice (simpler action, a supplied reference,
|
||||
an authorized alternate model, or an explicitly incomplete shot), not automatic
|
||||
provider switching or an endless loop. Never present a placeholder as a finished
|
||||
clip or hide an incorrect scene in final assembly.
|
||||
|
||||
For optional pencil previews, reduce annotation or panel count. Use the text
|
||||
storyboard if visualization is not essential; do not rerender correct video
|
||||
solely because a human-review sketch changed.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Model and format selection
|
||||
|
||||
Honor an existing model choice. Otherwise prefer MiniMax H3 when available, and
|
||||
inspect the running backend for partitions, reference modes, audio, resolutions,
|
||||
duration limits, and long-video options. Do not assume hosted and local services
|
||||
have identical limits, quality, prices, or parameter names.
|
||||
|
||||
If another model is requested, use its real documented input contract. A provider
|
||||
switch needs the user's authorization; never silently use a different service
|
||||
because a preset names it as a fallback. For an authorized mixed-model workflow,
|
||||
record model and settings per shot and check cross-shot style differences.
|
||||
|
||||
Keep delivery resolution separate from native generation resolution. Record actual
|
||||
width/height, fps, frame count, and any crop, retiming, or upscaling. Do not claim
|
||||
native 2K when the video was generated at 768p and restored later.
|
||||
|
||||
Compile shot action, camera, identity, scene, and audio into the chosen model's
|
||||
prompt format. For H3 use the bundled writing guides. Strip production labels and
|
||||
preview grids. Prompt for designed silhouettes, elastic action, material and
|
||||
lighting details when these belong to the user's 3D style; do not add text/UI just
|
||||
because a model can generate them.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Assembly and review
|
||||
|
||||
Use current clip revisions in shot-table order. Preserve useful dialogue and SFX;
|
||||
mix a continuous requested score underneath them. Inspect edits at sound bridges
|
||||
and dialogue boundaries, avoiding cut vowels and accidental audio gaps. Only add
|
||||
subtitles, music, or retiming consistent with the brief.
|
||||
|
||||
Review identity, landmarks, screen direction, light/time of day, prop state,
|
||||
emotional payoff, intelligibility, SFX timing, and music balance. Look for leaked
|
||||
storyboard panels, sketch lines, arrows, labels, timecodes, or watermarks. Verify
|
||||
the complete file's duration, dimensions, fps, frame count, audio, and decode.
|
||||
|
||||
Keep planning documents, references, raw clips, and final edits in distinguishable
|
||||
folders. Record the exact assets used in the final edit. After a character, scene,
|
||||
prompt, clip, or score is revised, update its downstream dependents and archive the
|
||||
previous result; do not silently combine stale and current versions.
|
||||
|
||||
Report observed defects and what was repaired, including external editing or
|
||||
upscaling. A successful API response proves completion, not visual correctness.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Six-column shot table
|
||||
|
||||
| Shot ID & Duration | Continuity Handoff | Reference Anchors (Spatial + Identity) | Hook Type | Shot Description (Per-Second Directives) | Audio & Dialogue Track |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
|
||||
Use stable IDs such as S01. Record incoming and outgoing image state, prop
|
||||
position, eyeline, motion, and emotional state in Continuity Handoff.
|
||||
|
||||
Reference Anchors contains named landmarks and screen-relative positions; each
|
||||
character's screen position, facing and pose; recently exited characters' locations;
|
||||
lighting baseline and modifiers; and exact character/scene asset paths or IDs.
|
||||
An explicit scene/time change can replace these anchors; an accidental flip cannot.
|
||||
|
||||
Hook Type names the shot's purpose: setup, reveal, reversal, joke, suspense,
|
||||
tenderness, chase, or callback. Do not force a joke or cut into a quiet scene.
|
||||
|
||||
For each second or meaningful sub-second beat, cover action/pose/expression,
|
||||
camera, spatial/prop state, sound, and the handoff to the next interval. Use compact
|
||||
phrases rather than inventing movement in intentionally still moments. Include
|
||||
anticipation, squash/stretch, overshoot, and follow-through where appropriate.
|
||||
|
||||
Keep the complete dialogue/narration script in Audio & Dialogue Track, with
|
||||
speaker, timing, delivery, and SFX. Distinguish off-screen narration from speaking
|
||||
characters; a visible listener should not lip-sync the narrator's words.
|
||||
|
||||
Before rendering, check full time coverage, supported generation durations, a
|
||||
readable number of active characters, matching scene/identity references, and
|
||||
coherent row-to-row handoffs. Mark intentional cuts/time jumps. Fix contradictory
|
||||
states rather than using a generic continuity assurance. A visual shot may span
|
||||
multiple generation windows when the verified backend supports continuation.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Text storyboard and optional visualization
|
||||
|
||||
Maintain one `storyboard.md` with a section per shot. Each section contains:
|
||||
|
||||
1. Shot ID, title, duration, and narrative purpose.
|
||||
2. Exact scene and character reference IDs.
|
||||
3. Spatial anchors: landmarks, character positions/facing, off-screen characters,
|
||||
key/fill/rim lighting, and important props.
|
||||
4. Incoming and outgoing continuity state.
|
||||
5. Time-ordered beats: pose/expression, camera, audio, and anchor changes.
|
||||
|
||||
Use per-second or finer intervals only where meaningful; cover the complete shot.
|
||||
For narrated moments, specify whether a visible character speaks or only reacts.
|
||||
Optional ASCII staging diagrams can clarify screen direction but are not images
|
||||
to supply as rendering references.
|
||||
|
||||
For heavy revision of a shot, extract its section to a named file and link it from
|
||||
the main document. Choose one authoritative version; reintegrate or update the
|
||||
link after revision so later generation cannot read stale content.
|
||||
|
||||
Only generate pencil storyboards when requested or already authorized as previews.
|
||||
Use equal-sized time-ordered panels, with timecode, pose/expression, camera arrow,
|
||||
and audio/anchor notes. Suggested layouts: three panels in a strip, four in a 2×2
|
||||
grid, six in 2×3. More complex scenes may need fewer representative key poses.
|
||||
Keep shot/character/scene labels readable for human review, but never feed these
|
||||
annotated grids as clean final frames. The text timeline remains authoritative.
|
||||
|
||||
If preview panels fail, simplify annotation or rely on text within the agreed
|
||||
scope. An optional visualization failure need not block a usable text storyboard.
|
||||
@@ -0,0 +1,53 @@
|
||||
# MiniMax H3 skill provenance
|
||||
|
||||
Upstream: https://github.com/MiniMax-AI/MiniMax-H3
|
||||
|
||||
Source snapshot: `d21241f0a4b3acbb34c97dae47fa417b7065e438`, retrieved 2026-09-19.
|
||||
|
||||
Source directory:
|
||||
https://github.com/MiniMax-AI/MiniMax-H3/tree/d21241f0a4b3acbb34c97dae47fa417b7065e438/skills
|
||||
|
||||
The nine upstream skill names are retained. Each local skill corresponds to the
|
||||
same-named upstream `skills/<name>/` directory. Credit for the original creative
|
||||
workflows and templates belongs to MiniMax-AI and the upstream contributors.
|
||||
|
||||
## Files and adaptation
|
||||
|
||||
- `h3-prompt-writing/references/base-format.md` and `ref-format.md` are new,
|
||||
condensed descriptions of the public prompt interface. They preserve necessary
|
||||
field names and notation but do not copy the upstream guides or their examples.
|
||||
The entrypoint adds a portable execution reference and clarifies clip/window
|
||||
duration for verified long-video backends.
|
||||
- The eight style-specific `SKILL.md` files are rewritten portable adaptations of
|
||||
the upstream workflows. Their reference documents retain the relevant creative
|
||||
methods while removing host-specific execution assumptions.
|
||||
- The two `co-op-game-intro-generator/references/` templates retain the upstream
|
||||
creative structure with an added portable contract and explicit user overrides.
|
||||
Their instructions are normalized to English, and the video template expresses
|
||||
visible UI copy as localized variables with English defaults. It also removes
|
||||
an unrequested gender restriction and a fixed yellow/black environment
|
||||
transformation.
|
||||
- The five 3D animation references are condensed adaptations of their upstream
|
||||
counterparts: shot table, storyboards, model selection, fallback, and review.
|
||||
- Product, papercraft, collage, and music references extract reusable direction
|
||||
from their corresponding upstream skill. The shared portable workflow, catalog,
|
||||
and UI metadata are additions for this repository.
|
||||
|
||||
No upstream `LICENSE`, `COPYING`, or `NOTICE` file was present in the Git tree at
|
||||
the pinned snapshot. Its README links to the MiniMax H3 Community License on the
|
||||
model release. Because that license has redistribution conditions, this package
|
||||
does not include the upstream prompt guides verbatim. This provenance record
|
||||
preserves attribution and does not assert that this repository's code license
|
||||
relicenses upstream material.
|
||||
|
||||
## Runtime changes
|
||||
|
||||
Canvas documents become local files and asset manifests; choice-card UI becomes
|
||||
the host's normal clarification mechanism when a decision is actually missing.
|
||||
Available generation/editing tools replace proprietary dispatch calls. Previous
|
||||
user choices and authorization persist across steps. Providers, prices, resolution
|
||||
support, and long-video features are checked rather than hardcoded as guarantees.
|
||||
|
||||
User intent overrides style presets, including instrumental/no-text work, selected
|
||||
language, final morph shape, no-cut sequences, and custom player designs. Native
|
||||
generation and external processing remain separately identified in delivery.
|
||||
@@ -0,0 +1,96 @@
|
||||
# Portable MiniMax H3 Skills
|
||||
|
||||
This directory contains one general prompt-writing skill and eight creative
|
||||
skills adapted from
|
||||
[MiniMax-AI/MiniMax-H3](https://github.com/MiniMax-AI/MiniMax-H3/tree/main/skills).
|
||||
See [H3-SOURCES.md](H3-SOURCES.md) for the source revision, attribution, and
|
||||
adaptation scope.
|
||||
|
||||
## Skill catalog
|
||||
|
||||
| Skill | Intended use |
|
||||
| --- | --- |
|
||||
| [h3-prompt-writing](h3-prompt-writing/SKILL.md) | Structured prompts for T2VA, I2VA, FL2VA, L2VA, and Ref2VA |
|
||||
| [minimalist-product-ad-generator](minimalist-product-ad-generator/SKILL.md) | Minimal product ads, isolated product references, copy, and pacing |
|
||||
| [3d-animation-short-generator](3d-animation-short-generator/SKILL.md) | 3D narrative shorts, character and environment design, shot tables, storyboards, and editing |
|
||||
| [papercraft-stop-motion-explainer](papercraft-stop-motion-explainer/SKILL.md) | Layered paper art, puppets, mechanisms, and miniature educational scenes |
|
||||
| [brand-promo-video-generator](brand-promo-video-generator/SKILL.md) | Brand promos, verified assets and claims, product interaction, and calls to action |
|
||||
| [music-video-subtitle-generator](music-video-subtitle-generator/SKILL.md) | Music videos, instrumental visual narratives, beat planning, and optional lyric typography |
|
||||
| [co-op-game-intro-generator](co-op-game-intro-generator/SKILL.md) | Two-player game menus, confirmation images, and animated world entry |
|
||||
| [paper-collage-explainer-generator](paper-collage-explainer-generator/SKILL.md) | Halftone photo collage, incremental paper assembly, and visual metaphors |
|
||||
| [handdrawn-live-video-generator](handdrawn-live-video-generator/SKILL.md) | Live action with rough luminous drawings, physical contact, continuous morphing, and delayed pursuit |
|
||||
|
||||
## Usage
|
||||
|
||||
Codex discovers repository skills from `.agents/skills/`. Clients that scan
|
||||
skills only when a session starts may need a new session. Claude Code reads the
|
||||
same files through the same-named relative symlinks in `.claude/skills/`. Other
|
||||
agents that support Markdown skills can load the relevant `SKILL.md` directly
|
||||
and follow its links to supporting references.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
Use $music-video-subtitle-generator to design a 30-second two-dimensional
|
||||
fluid-motion graphic for this instrumental track. Do not add lyrics or
|
||||
subtitles. Preserve leftward motion and initially return only a storyboard and
|
||||
three H3 prompts.
|
||||
```
|
||||
|
||||
```text
|
||||
Use $co-op-game-intro-generator to create a two-player game intro. The players
|
||||
are Lin and Mei, the style is layered paper sculpture, and the title is
|
||||
Together. Create the confirmation image first and wait for my approval before
|
||||
generating video.
|
||||
```
|
||||
|
||||
## MV smoke test
|
||||
|
||||
Test `music-video-subtitle-generator` together with `h3-prompt-writing` using a
|
||||
user-owned song with timestamped lyrics and an original adult-character
|
||||
reference image:
|
||||
|
||||
```text
|
||||
Use $music-video-subtitle-generator and $h3-prompt-writing to turn this song
|
||||
into a historical-romance music video about a woman and a man. Intercut
|
||||
narrative acting with the woman's singing performance, do not display lyric
|
||||
text, split the work according to the backend's verified clip duration, and
|
||||
preserve the complete original song in the final master.
|
||||
```
|
||||
|
||||
Verify that the global timeline matches the source audio duration, lyrics remain
|
||||
verbatim, and each generation window records its incoming state, outgoing state,
|
||||
and local timing. Ref2VA prompts must preserve the six-section field order and
|
||||
resolve every reference label to a real input. The assembled video must decode
|
||||
completely, and its final audio must come from the supplied source rather than a
|
||||
model reconstruction.
|
||||
|
||||
When moving the collection to another repository or a user-level skill folder,
|
||||
copy all nine skill directories and preserve their sibling layout. The eight
|
||||
creative skills share `h3-prompt-writing/references/portable-workflow.md` and the
|
||||
H3 format guides, so copying only one `SKILL.md` is insufficient. Keep each
|
||||
skill's `references/` and `agents/` directories with it. `agents/openai.yaml`
|
||||
provides optional Codex UI metadata and does not restrict the workflow to an
|
||||
OpenAI-based agent or require a dedicated plugin.
|
||||
|
||||
## Execution boundaries
|
||||
|
||||
Prompt writing, storyboarding, and planning require only an agent that can read
|
||||
and write files. Actual image, video, speech, music, and editing work uses tools
|
||||
or services available in the current environment. When a capability is missing,
|
||||
deliver the complete usable production package and identify the unfinished media
|
||||
step.
|
||||
|
||||
The user's style, language, assets, audio, model selection, and existing
|
||||
authorization take priority. An MV template does not add lyrics to an
|
||||
instrumental track, and a clean motion-graphics request does not inherit film
|
||||
grain. A prompt-only request does not start generation. When the user requests
|
||||
approval of a confirmation image before rendering, preserve that checkpoint.
|
||||
|
||||
Treat vLLM-Omni long-video extensions as capabilities of the checked-out branch
|
||||
and active backend. Do not present a development branch's continuation parameters
|
||||
as a universal H3 API. Preserve real requests and raw outputs, distinguish model
|
||||
results from post-production and upscaling, and inspect actual media properties.
|
||||
|
||||
These skills contain no model weights and do not automatically start a service
|
||||
or invoke a paid generation endpoint.
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
name: brand-promo-video-generator
|
||||
description: Plan, prompt, or produce brand, product, website, app, and service promotional shorts using traceable assets, accurate claims, timed beats, and clear calls to action. Use for launch and campaign videos, not invented product evidence or long narrative films.
|
||||
metadata:
|
||||
compatibility: File-based workflow with sibling h3-prompt-writing and available research, media generation, inspection, and editing tools.
|
||||
---
|
||||
|
||||
# Brand Promo Video Generator
|
||||
|
||||
Read the [portable workflow](../h3-prompt-writing/references/portable-workflow.md).
|
||||
Use supplied brand assets, source links, and existing session decisions. No
|
||||
proprietary tool allowlist or canvas is required. A completed promo requires real
|
||||
generation/editing capability; otherwise deliver an explicitly incomplete production
|
||||
package with finished prompts and a concrete generation handoff.
|
||||
|
||||
## Establish facts and assets
|
||||
|
||||
Inspect product images, UI screenshots, logo exports, typography, colors, and
|
||||
campaign material. Resolve duration, ratio, audience, campaign focus, exact claims,
|
||||
CTA, copy language, narration, and required deliverable from context. Ask for
|
||||
missing identity-bearing assets when they are essential; do not fabricate logos,
|
||||
product UI, screenshots, results, or performance claims.
|
||||
|
||||
Build a compact truth sheet from user-supplied originals and official sources.
|
||||
Record asset ID, role, local path, source URL/note, and verification status. Do not
|
||||
confuse a retrieved search thumbnail with an original brand asset. Distinguish
|
||||
verified facts from clearly labeled concept copy. Preserve the requested language;
|
||||
chat language alone does not justify translating supplied campaign text.
|
||||
|
||||
## Design a product-specific story
|
||||
|
||||
Choose a spine that exposes real cause and effect:
|
||||
|
||||
- Software: user intent → actual interaction → useful output → evidence → CTA.
|
||||
- Physical product: reveal → interaction → mechanism/detail → use → benefit → CTA.
|
||||
- Service: situation → process → evidence → outcome → promise.
|
||||
- Image-led brand: authentic imagery → repeated visual motif → emotional payoff.
|
||||
|
||||
Plan time/frame ranges, asset IDs, one main action, product evidence, exact copy,
|
||||
readable hold, color state, camera, transition, and rhythm. Use the actual output
|
||||
fps for frame timing. Five to eight major beats can fit a 15-second promo, but
|
||||
readability takes priority over a fixed beat count.
|
||||
|
||||
Let product edges, UI movement, light, cursor paths, or matched geometry motivate
|
||||
transitions. Use a few energy peaks and deliberate settling moments. Preserve logo
|
||||
clear space and readable screenshots. Avoid invented HUDs or metrics that look like
|
||||
product proof. Summarize the truth sheet and plan before rendering; continue under
|
||||
existing authorization unless the user requested approval at that stage.
|
||||
|
||||
## Produce and inspect
|
||||
|
||||
Use authentic still/UI plates for exact content. Generated material can supply
|
||||
conceptual scenes, atmosphere, and transition geometry with clear provenance.
|
||||
Compile actual H3 references and shots using the appropriate bundled guide.
|
||||
Check backend resolution, duration, and audio support before calling it.
|
||||
|
||||
Use native instrumental/SFX direction when appropriate; do not generate a second
|
||||
score automatically. Separate narration or music is useful when requested for
|
||||
control or remixing. Preserve original SFX during assembly when they matter, and
|
||||
duck music under speech. Do not add subtitles unless requested.
|
||||
|
||||
Check claims and exact product names against sources, inspect logo geometry and
|
||||
copy, verify real UI states, and review transitions, aspect ratio, duration, audio,
|
||||
and decoding. For wrong identity-bearing content, use the correct supplied/source
|
||||
asset rather than polishing an imitation. Deliver the video, prompts/timeline,
|
||||
asset manifest, and any remaining factual or visual limitations.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Brand Promo Videos"
|
||||
short_description: "Build brand promos from verified assets and claims"
|
||||
default_prompt: "Use $brand-promo-video-generator to prepare the requested H3 prompts or video with the available tools."
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
name: co-op-game-intro-generator
|
||||
description: Design or generate a two-player co-op game menu and opening animation from player names, title, style, and optional identity references. Use for character-led game intros, not playable game implementation or complex multi-page interfaces.
|
||||
metadata:
|
||||
compatibility: File-based workflow with sibling h3-prompt-writing and bundled image/video templates. Rendering uses available generation tools.
|
||||
---
|
||||
|
||||
# Co-op Game Intro Generator
|
||||
|
||||
Read the [portable workflow](../h3-prompt-writing/references/portable-workflow.md).
|
||||
Before writing a confirmation-image prompt, read
|
||||
[h3-confirmation-image-template.md](references/h3-confirmation-image-template.md).
|
||||
Before writing the video prompt, read
|
||||
[h3-video-prompt-template.md](references/h3-video-prompt-template.md).
|
||||
Both templates are required package resources, not remote tools.
|
||||
|
||||
## Resolve player and style bindings
|
||||
|
||||
Reuse or collect the two player names, game title, visual style, desired duration,
|
||||
ratio, and optional identity references. The template defaults to a 15-second,
|
||||
16:9 menu-to-world sequence; adapt it to explicit user requirements. Do not assume
|
||||
the players' gender, body shape, outfits, or equipment from a generic example.
|
||||
|
||||
Use each portrait only for recognizable identity anchors: face silhouette, hair,
|
||||
glasses, proportions, and distinguishing traits. Reinterpret rendering, skin
|
||||
texture, lighting, and costume in the selected visual style. If a portrait or body
|
||||
comparison reference is absent, write a text design rather than inventing an asset
|
||||
label. Maintain player-to-name mapping across all references and frames.
|
||||
|
||||
## Confirmation image
|
||||
|
||||
Fill the template's style, palette, characters, title, and name variables. Keep
|
||||
the two characters central, player cards toward the upper left, menu on the right,
|
||||
and the continue action as the main interaction focus. The title establishes
|
||||
identity without competing with that focus. Buttons, icons, typography, and all
|
||||
player/equipment panels share one palette and style. Keep menu labels on one line.
|
||||
|
||||
The style changes material, shapes, fonts, and decoration; it should not randomly
|
||||
rearrange the menu hierarchy. User-requested layout or ratio changes take priority
|
||||
over template defaults. Preserve the exact supplied title/names and requested copy.
|
||||
|
||||
For image-only/prompt-only work, stop at that deliverable. For video production,
|
||||
generate and inspect the confirmation image if within scope. Honor a request to
|
||||
approve the image first; otherwise use the established end-to-end authorization
|
||||
and continue after reporting the selected image and fixing material defects.
|
||||
|
||||
## Video event plan
|
||||
|
||||
Fill the video template from the current image and player bindings. Its baseline
|
||||
sequence is menu → first player's light equipment → second player's heavy equipment
|
||||
→ shared confirmation → world loading → both enter the world. Equipment, world,
|
||||
body contrast, and timing are editable design choices; preserve requested identity
|
||||
and style instead of forcing a cyberpunk example onto another setting.
|
||||
|
||||
Bind UI reference, each actual portrait, and any real body-comparison image to
|
||||
distinct roles. Compile this creative template into the H3 mode guide's fields;
|
||||
the mixed-language template is not itself an API request. Preserve literal visible
|
||||
UI text in its required language, and remove all unfilled variables before dispatch.
|
||||
Do not treat a composition reference as an exact first-frame anchor unless the
|
||||
selected backend actually supports that role.
|
||||
|
||||
## Review and repair
|
||||
|
||||
Check both names, exact menu strings, layout, player identity, side assignment,
|
||||
equipment distinction, and the transition into the requested world. Match UI
|
||||
hover/click, mechanical locks, loading, and footsteps to the visible events.
|
||||
For identity swaps, strengthen name/position/reference bindings; for weak style,
|
||||
revise palette, material, character, and typography together. Reduce excessive
|
||||
UI text if necessary without silently changing required player names.
|
||||
|
||||
Deliver the requested prompts/assets or the inspected intro video, with reference
|
||||
roles and any text/timing limitations. Missing templates block template execution;
|
||||
missing generation capability still permits a complete prompt handoff.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Co-op Game Intros"
|
||||
short_description: "Design two-player menus and world-entry animation"
|
||||
default_prompt: "Use $co-op-game-intro-generator to prepare the requested H3 prompts or video with the available tools."
|
||||
+397
@@ -0,0 +1,397 @@
|
||||
# H3 Confirmation Image Template
|
||||
|
||||
## Portable adaptation
|
||||
|
||||
This is a creative template, not a tool call. User requirements override its
|
||||
default ratio, layout, poses, and wording. Fill every relevant variable from the
|
||||
brief; set `{character_count}` to two for this skill. When portraits are absent,
|
||||
replace portrait references with explicit character designs. Do not claim to
|
||||
reference an image that was not supplied. Use the image-generation capability
|
||||
available in the host environment; no specific image provider is required.
|
||||
|
||||
## Core Rule
|
||||
Generate a polished 16:9 landscape confirmation image for a cooperative game main menu.
|
||||
The image consists of two independent systems:
|
||||
• UI Framework (fixed)
|
||||
• Visual Style (dynamic)
|
||||
The UI Framework defines the layout, composition, information hierarchy, interaction logic, reading flow, menu structure, and readability. These elements must remain unchanged.
|
||||
{visual_style} only controls the artistic appearance, including rendering medium, materials, color language, lighting mood, environment style, character design, costume language, UI materials, icon language, typography appearance, decorative motifs, and overall atmosphere.
|
||||
Changing {visual_style} should feel like applying a different art direction to the same professionally designed game menu, never redesigning the interface itself.
|
||||
If any default description conflicts with {visual_style}, prioritize {visual_style} while preserving the UI framework.
|
||||
|
||||
---
|
||||
|
||||
## Design Goal
|
||||
Create a premium commercial console game main menu mockup in 16:9 landscape format. The image should combine the quality of a polished game promotional artwork with the clarity of a professional game UI. Characters and interface must feel naturally integrated, with strong visual hierarchy, excellent readability, clean composition, and a clear interaction focus.
|
||||
|
||||
---
|
||||
|
||||
## Overall Style
|
||||
Follow the user-selected visual style: {visual_style}.
|
||||
The selected style controls the rendering medium, illustration style, materials, palette language, environment, character appearance, outfit design, UI appearance, icon language, typography treatment, decorative elements, and atmosphere.
|
||||
All visual elements must belong to one unified artistic language.
|
||||
Do not mix incompatible visual styles within the same image.
|
||||
The UI framework, layout, hierarchy, composition, and interaction logic must remain consistent regardless of style.
|
||||
|
||||
---
|
||||
|
||||
## Color Palette
|
||||
Derive the entire color system from {visual_style}.
|
||||
Use:
|
||||
• {main_background_color} as the primary background color.
|
||||
• {ui_body_color} as the main UI color.
|
||||
• {text_color} as the primary text color.
|
||||
• {functional_accent_color} as the interaction highlight color.
|
||||
• Red only for warning, danger, or exit actions.
|
||||
Limit the overall palette to five primary colors.
|
||||
All buttons, player cards, icons, borders, highlights, decorative elements, typography, and visual effects must follow the same color system.
|
||||
Avoid introducing unrelated colors outside the selected palette.
|
||||
|
||||
---
|
||||
|
||||
## Composition
|
||||
Use a fixed 16:9 landscape layout.
|
||||
Place {character_count} playable characters in the center as the visual subject.
|
||||
The UI surrounds the characters without blocking them.
|
||||
Place the player information cards in the upper-left corner.
|
||||
Place the main menu vertically on the right.
|
||||
Place a decorative horizontal strip along the bottom, adapting naturally to {visual_style} (such as ribbon, warning strip, wooden plank, stone slab, energy bar, scroll, etc.).
|
||||
Keep a clear Z-shaped reading flow:
|
||||
Player Cards → Characters → Menu → Continue Button.
|
||||
The Continue button must always remain the primary visual focus.
|
||||
Maintain generous negative space and excellent readability.
|
||||
|
||||
---
|
||||
|
||||
## Background
|
||||
Generate a background naturally derived from {visual_style}.
|
||||
The background supports the interface rather than competing with it.
|
||||
Keep enough clean negative space behind all important UI elements.
|
||||
Use subtle textures, environmental details, and decorative motifs only where appropriate for the selected style.
|
||||
Avoid excessive visual noise, dense decoration, heavy dirt, scratches, paint splatter, or distracting textures.
|
||||
The overall background should feel polished, premium, modern, and suitable for a commercial game menu.
|
||||
|
||||
---
|
||||
|
||||
## Character Style
|
||||
All characters strictly follow {visual_style}.
|
||||
The selected style determines:
|
||||
• rendering medium
|
||||
• body proportion
|
||||
• facial stylization
|
||||
• costume language
|
||||
• material treatment
|
||||
• lighting response
|
||||
• animation style
|
||||
• overall character quality
|
||||
Only the character identity anchors and pose remain fixed. Facial rendering, eye design, nose simplification, mouth shape, skin treatment, expression style, and head proportion must be fully reinterpreted in {visual_style}.
|
||||
No default character style may override {visual_style}.
|
||||
|
||||
---
|
||||
|
||||
## Character A / PLAYER 1
|
||||
### Identity
|
||||
Use character reference image 1 only for identity mapping.
|
||||
The reference image donates identity anchors only: recognizable face silhouette, hairstyle, glasses if present, relative facial proportions, and distinctive personal traits.
|
||||
It does not donate photographic realism, real skin texture, real-world lighting, camera quality, or the original image style.
|
||||
Do not lose the character's identity anchors, but the face must be redesigned into {visual_style}.
|
||||
All facial rendering, eye design, nose simplification, mouth shape, skin treatment, expression style, and head proportion must follow {visual_style}.
|
||||
Do not swap identity with other characters.
|
||||
|
||||
### Appearance
|
||||
Character rendering, expression, outfit, materials, and accessories are fully derived from {visual_style} while maintaining a recognizable playable-game-character silhouette.
|
||||
|
||||
### Action
|
||||
Character A sits cross-legged on the ground.
|
||||
Both hands support the body on the floor.
|
||||
The upper body leans slightly backward.
|
||||
Character A looks upward toward the camera.
|
||||
|
||||
---
|
||||
|
||||
## Character B / PLAYER 2
|
||||
### Identity
|
||||
Use character reference image 2 only for identity mapping.
|
||||
The reference image donates identity anchors only: recognizable face silhouette, hairstyle, glasses if present, relative facial proportions, and distinctive personal traits.
|
||||
It does not donate photographic realism, real skin texture, real-world lighting, camera quality, or the original image style.
|
||||
Do not lose the character's identity anchors, but the face must be redesigned into {visual_style}.
|
||||
All facial rendering, eye design, nose simplification, mouth shape, skin treatment, expression style, and head proportion must follow {visual_style}.
|
||||
Do not swap identity with other characters.
|
||||
|
||||
### Appearance
|
||||
Character rendering, expression, outfit, materials, and accessories are fully derived from {visual_style} while maintaining a recognizable playable-game-character silhouette.
|
||||
|
||||
### Action
|
||||
Character B sits cross-legged on the ground.
|
||||
Both hands rest naturally in front of the legs.
|
||||
The upper body leans slightly forward.
|
||||
Character B looks directly toward the camera.
|
||||
|
||||
---
|
||||
|
||||
## Lighting
|
||||
Lighting follows {visual_style} while preserving clear readability.
|
||||
Use a primary top light, secondary fill light, soft ambient bounce, contact shadows, gentle rim lighting, and high-quality global illumination where appropriate.
|
||||
Faces should remain clearly visible.
|
||||
Characters must integrate naturally into the environment while maintaining strong separation from the background.
|
||||
|
||||
---
|
||||
|
||||
## Game UI
|
||||
Create a professional commercial console game main menu.
|
||||
The menu structure, interaction hierarchy, spacing, composition, reading flow, and information architecture remain fixed.
|
||||
{visual_style} only changes the artistic appearance of the interface.
|
||||
The selected style may affect:
|
||||
• UI materials
|
||||
• surface textures
|
||||
• border treatment
|
||||
• corner shape
|
||||
• decorative motifs
|
||||
• color rendering
|
||||
• lighting treatment
|
||||
• icon language
|
||||
• typography appearance
|
||||
• interaction effects
|
||||
It must NOT change:
|
||||
• menu hierarchy
|
||||
• button order
|
||||
• button placement
|
||||
• player-card placement
|
||||
• composition
|
||||
• interaction logic
|
||||
• information architecture
|
||||
• readability
|
||||
The entire interface should feel like one professionally designed game UI system rather than separate elements assembled together.
|
||||
|
||||
---
|
||||
|
||||
## UI Visual Language
|
||||
Derive the complete UI appearance from {visual_style}.
|
||||
The selected style determines:
|
||||
• button materials
|
||||
• border language
|
||||
• panel materials
|
||||
• decorative details
|
||||
• edge treatment
|
||||
• visual weight
|
||||
• highlight style
|
||||
• interaction feedback
|
||||
• shadow treatment
|
||||
• texture language
|
||||
Possible materials include wood, stone, paper, leather, cloth, glass, crystal, hologram, neon, metal, ceramic, carved surfaces, painted surfaces, magical energy, pixel blocks, watercolor paper, ink brush, comic graphics or any other material naturally belonging to {visual_style}.
|
||||
Every UI element must share the same material language and artistic style.
|
||||
|
||||
---
|
||||
|
||||
## Button Layout Rules
|
||||
Place all menu buttons vertically on the right side.
|
||||
Maintain a consistent vertical rhythm.
|
||||
Every button uses the same design family.
|
||||
Button width automatically adapts to text length.
|
||||
Keep all menu titles on a single line.
|
||||
No automatic wrapping.
|
||||
No stacked text.
|
||||
Text remains horizontally centered.
|
||||
Keep consistent padding.
|
||||
Maintain equal spacing between buttons.
|
||||
Avoid visual clutter.
|
||||
|
||||
---
|
||||
|
||||
## Continue Button
|
||||
The Continue button is always the primary visual focus.
|
||||
Make it visually dominant using the emphasis method naturally belonging to {visual_style}.
|
||||
Possible emphasis methods include:
|
||||
• larger size
|
||||
• stronger contrast
|
||||
• brighter color
|
||||
• unique material
|
||||
• distinctive border
|
||||
• lighting
|
||||
• glow
|
||||
• engraving
|
||||
• magical energy
|
||||
• holographic effect
|
||||
• embossed frame
|
||||
• animated visual cue
|
||||
Do not force glow or neon if they conflict with {visual_style}.
|
||||
The Continue button should immediately attract the player's attention.
|
||||
|
||||
---
|
||||
|
||||
## Start New Game Button
|
||||
Place above Continue.
|
||||
Use the standard secondary button appearance.
|
||||
Keep the visual language consistent with the selected style.
|
||||
Add one small style-appropriate icon if suitable.
|
||||
Maintain single-line text.
|
||||
|
||||
---
|
||||
|
||||
## Settings Button
|
||||
Use the standard secondary button appearance.
|
||||
Use one settings icon naturally derived from {visual_style}.
|
||||
Maintain consistent proportions, spacing, and hierarchy.
|
||||
|
||||
---
|
||||
|
||||
## Exit Game Button
|
||||
Use the standard secondary button appearance.
|
||||
Use red only as the danger indicator.
|
||||
Red should remain an accent rather than the dominant color.
|
||||
Add one style-appropriate exit icon if suitable.
|
||||
|
||||
---
|
||||
|
||||
## Player Cards
|
||||
Create an upper-left player information system for {character_count} players.
|
||||
The appearance follows {visual_style}.
|
||||
Card materials, borders, corners, textures, shadows, decorations, and icons are automatically derived from the selected style.
|
||||
Each player card contains:
|
||||
• Player label
|
||||
• Player nickname
|
||||
• READY status
|
||||
Player names:
|
||||
PLAYER 1
|
||||
{player1_name}
|
||||
PLAYER 2
|
||||
{player2_name}
|
||||
READY always uses the functional accent color.
|
||||
The cards should remain highly readable and visually connected to the rest of the interface.
|
||||
|
||||
---
|
||||
|
||||
## Icon System
|
||||
Derive all icons from {visual_style}.
|
||||
Use one unified icon family throughout the entire interface.
|
||||
Possible icon languages include:
|
||||
• minimal outline
|
||||
• solid filled
|
||||
• geometric
|
||||
• comic
|
||||
• pixel
|
||||
• engraved
|
||||
• carved
|
||||
• painted
|
||||
• brush
|
||||
• rune
|
||||
• glyph
|
||||
• holographic
|
||||
• crystal
|
||||
• paper-cut
|
||||
• origami
|
||||
• embossed
|
||||
• low-poly
|
||||
• flat design
|
||||
• stylized 3D
|
||||
All icons must share:
|
||||
• the same artistic style
|
||||
• the same material language
|
||||
• the same perspective
|
||||
• the same lighting treatment
|
||||
• the same stroke language
|
||||
• the same color hierarchy
|
||||
Icons should remain simple, recognizable, and functional.
|
||||
Each interface block may contain at most one horizontal row of icons.
|
||||
No wrapping.
|
||||
No vertical stacking.
|
||||
Icons should support the interface rather than dominate it.
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
Typography hierarchy remains fixed.
|
||||
Typography appearance follows {visual_style}.
|
||||
The selected style controls:
|
||||
• font family
|
||||
• decorative treatment
|
||||
• texture
|
||||
• material
|
||||
• outline
|
||||
• lighting
|
||||
• shadow
|
||||
• wear pattern
|
||||
Maintain:
|
||||
• excellent readability
|
||||
• strong visual hierarchy
|
||||
• single-line menu buttons
|
||||
• consistent spacing
|
||||
• high contrast
|
||||
Button width should always adapt to text length.
|
||||
Never allow menu titles to wrap onto multiple lines.
|
||||
|
||||
---
|
||||
|
||||
## Game Title
|
||||
Display the game title:
|
||||
{game_title}
|
||||
The title should become the primary branding element of the menu.
|
||||
Its material, decorative style, typography, and rendering all follow {visual_style}.
|
||||
Avoid imitating existing commercial game logos.
|
||||
Create an original title treatment inspired by the selected style.
|
||||
Keep the title highly readable.
|
||||
Avoid random symbols or meaningless letters.
|
||||
|
||||
---
|
||||
|
||||
## Interaction States
|
||||
Represent the interface as an active game menu.
|
||||
Buttons may display appropriate interaction feedback naturally belonging to {visual_style}.
|
||||
Possible interaction feedback includes:
|
||||
• hover
|
||||
• pressed state
|
||||
• magical glow
|
||||
• energy pulse
|
||||
• holographic highlight
|
||||
• carved illumination
|
||||
• ink spread
|
||||
• brush bloom
|
||||
• metallic reflection
|
||||
• paper emboss
|
||||
• animated border
|
||||
• pixel flashing
|
||||
Only use interaction effects that naturally belong to the selected style.
|
||||
Avoid forcing modern UI effects into incompatible artistic styles.
|
||||
|
||||
---
|
||||
|
||||
## Rendering
|
||||
Generate a polished AAA-quality commercial game menu artwork.
|
||||
Characters, environment, UI, typography, icons, and decorative elements should feel like one cohesive production.
|
||||
Maintain premium rendering quality.
|
||||
Strong visual hierarchy.
|
||||
Professional commercial presentation.
|
||||
High readability.
|
||||
Balanced composition.
|
||||
Clean finish.
|
||||
|
||||
---
|
||||
|
||||
## Negative Constraints
|
||||
No split screen.
|
||||
No duplicated characters.
|
||||
No identity swap.
|
||||
No loss of identity anchors. No photorealistic face unless {visual_style} explicitly requires photorealism. No realistic photo face pasted onto a stylized body. No mismatched face style.
|
||||
No hairstyle changes.
|
||||
No unreadable UI.
|
||||
No distorted buttons.
|
||||
No overlapping interface.
|
||||
No random text.
|
||||
No random symbols.
|
||||
No watermark.
|
||||
No copied game logo.
|
||||
No branded interface.
|
||||
No inconsistent icon styles.
|
||||
No mixed UI materials.
|
||||
No excessive decoration.
|
||||
No overwhelming background.
|
||||
No visual clutter.
|
||||
No broken layout.
|
||||
No low readability.
|
||||
|
||||
---
|
||||
|
||||
## Medium Lock
|
||||
Render as a polished commercial game key art combined with a professional console game main menu mockup.
|
||||
The interface remains fixed.
|
||||
Only the artistic appearance changes according to {visual_style}.
|
||||
@@ -0,0 +1,249 @@
|
||||
# H3 Video Prompt Template
|
||||
|
||||
## Portable adaptation
|
||||
|
||||
This is a creative planning template. User requirements override its default
|
||||
15-second timeline, body proportions, equipment, environment, ratio, and palette.
|
||||
Retiming must preserve readable event order. Use only supplied reference assets:
|
||||
omit `{height_ref}` or identity-image bindings when absent and replace their role
|
||||
with text design constraints. Compile the filled plan into the H3 base or Ref2VA
|
||||
format before rendering; preserve exact visible UI strings in the user's language.
|
||||
|
||||
Use available tools and the actual backend's parameter schema. Audio directions
|
||||
describe desired content rather than asserting that a particular API supports it.
|
||||
|
||||
## Template completion
|
||||
|
||||
Resolve the palette variables `{background_color}`, `{ui_color}`, `{text_color}`,
|
||||
`{functional_accent_color}`, and `{power_accent_color}` from the selected style.
|
||||
Keep the five values distinct enough for readable UI contrast. Use the power
|
||||
accent for danger, exit, and warning states unless the user supplies a separate
|
||||
semantic-color requirement.
|
||||
|
||||
Fill visible copy in the user's requested language. The following English values
|
||||
are defaults only, not mandatory output:
|
||||
|
||||
- `{player1_label}` / `{player2_label}`: `PLAYER 1` / `PLAYER 2`
|
||||
- `{ready_label}`: `READY`
|
||||
- `{start_label}`, `{continue_label}`, `{settings_label}`, `{exit_label}`:
|
||||
`START NEW GAME`, `CONTINUE`, `SETTINGS`, `EXIT GAME`
|
||||
- `{player1_equipment_label}`: `RIGHT ARM EQUIPMENT`
|
||||
- `{player1_option_a}` / `{player1_option_b}`: `PHANTOM GRIP` / `CHRONOS CLAW`
|
||||
- `{player2_equipment_label}`: `ARMAMENT CUSTOMIZATION`
|
||||
- `{hand_label}`, `{forearm_label}`, `{elbow_label}`, `{upper_arm_label}`:
|
||||
`HAND`, `FOREARM`, `ELBOW`, `UPPER ARM`
|
||||
- `{confirm_label}` / `{loading_label}`: `CONFIRM CONFIG` / `LOADING`
|
||||
|
||||
Before compiling the rendering prompt, search the filled template for every
|
||||
remaining token enclosed in braces. Replace required values. For an absent optional
|
||||
reference, remove its binding and rewrite every dependent clause as a text-only
|
||||
constraint. Do not dispatch a prompt while any template token remains.
|
||||
|
||||
## Prompt principle
|
||||
Use the same method as the GPT confirmation-image prompt:
|
||||
|
||||
**Fixed video event framework + dynamic user-style fill + locked character identity + palette-linked UI system.**
|
||||
|
||||
The video prompt must not blindly preserve the source prompt's default style. It must preserve the timeline, UI events, player positions, equipment logic, and text structure, while dynamically rewriting visual treatment, palette, character rendering, lighting, UI surface, icons, and city-world style according to the user's selected style.
|
||||
|
||||
## Priority order
|
||||
1. User-selected style: {visual_style}
|
||||
2. Confirmed image / UI reference: {ui_ref}
|
||||
3. PLAYER 1 identity reference: {player1_ref}
|
||||
4. PLAYER 2 identity reference: {player2_ref}
|
||||
5. Height/body comparison reference: {height_ref}
|
||||
6. Fixed source video event framework
|
||||
|
||||
## Reference roles
|
||||
- {ui_ref}: confirmed first image. Use it to lock UI layout, menu hierarchy, color system, typography scale, button structure, character-game integration, and overall composition logic.
|
||||
- {player1_ref}: PLAYER 1 identity anchor. Lock exact face, hairstyle, glasses if present, facial proportions, body identity, and nickname mapping to {player1_name}.
|
||||
- {player2_ref}: PLAYER 2 identity anchor. Lock exact face, hairstyle, facial proportions, body identity, and nickname mapping to {player2_name}.
|
||||
- {height_ref}: body comparison anchor. Lock the visible contrast between the two players and prevent identical body proportions.
|
||||
|
||||
## Global style baseline
|
||||
The overall art direction must prioritize the user's selected {visual_style}.
|
||||
Preserve these fixed qualities: a game main-menu interface, premium game-trailer
|
||||
finish, deep integration between the UI and characters, modern commercial game
|
||||
UI design, strong visual impact, clean composition, and restrained decoration.
|
||||
Derive the remaining visual treatment from {visual_style}: character rendering,
|
||||
expressions, costume language, color system, lighting temperature, UI materials,
|
||||
button icons, typography texture, and the world revealed after loading.
|
||||
|
||||
## Palette system
|
||||
Derive the complete video palette from {visual_style}, with linked UI colors:
|
||||
|
||||
- Use {background_color} as the primary background and world color.
|
||||
- Use {ui_color} as the main UI color.
|
||||
- Use {text_color} as the text color.
|
||||
- Use {functional_accent_color} as PLAYER 1's functional accent color.
|
||||
- Use {power_accent_color} as PLAYER 2's power accent and for danger, exit,
|
||||
and warning states.
|
||||
- Limit the complete palette to five colors.
|
||||
- Use a vivid, modern, high-contrast color language consistent with
|
||||
{visual_style}.
|
||||
|
||||
Menus, equipment panels, player cards, buttons, the HUD, loading bars, icons,
|
||||
and text must share this color system. Do not introduce unrelated colors.
|
||||
|
||||
## Character identity and style lock
|
||||
PLAYER 1 follows the facial identity in {player1_ref}. Preserve the face,
|
||||
facial proportions, hairstyle, glasses when present, personal identity, and the
|
||||
mapping to the nickname {player1_name}. Adapt expression, rendering, clothing,
|
||||
and mechanical equipment to {visual_style}. PLAYER 1 always stays on the left,
|
||||
with a taller, slender, agile build. Equipment uses the functional accent color,
|
||||
and the mechanical claw is light, narrow, and flexible.
|
||||
|
||||
PLAYER 2 follows the facial identity in {player2_ref}. Preserve the face,
|
||||
facial proportions, hairstyle, personal identity, and the mapping to the
|
||||
nickname {player2_name}. Adapt expression, rendering, clothing, and mechanical
|
||||
equipment to {visual_style}. PLAYER 2 always stays on the right, with a shorter,
|
||||
broader, power-oriented build. Equipment uses {power_accent_color}, and the
|
||||
mechanical fist is broad, heavy, and visibly weighty.
|
||||
|
||||
Do not swap character identities, merge faces, swap nicknames, or converge the
|
||||
two body types.
|
||||
|
||||
## Fixed timeline framework
|
||||
|
||||
### [0-2 seconds] - Two-player main menu
|
||||
|
||||
Composition and camera: A high-angle extreme wide shot follows the composition
|
||||
logic of {ui_ref}. The camera tilts slightly downward and slowly pushes in.
|
||||
|
||||
Visuals: PLAYER 1 ({player1_name}) and PLAYER 2 ({player2_name}) sit side by
|
||||
side at the center. PLAYER 1 remains on the left and PLAYER 2 on the right. They
|
||||
look up toward the camera with only natural breathing, blinking, and subtle body
|
||||
movement.
|
||||
|
||||
UI: The upper-left player card displays `{player1_label}`, `{player1_name}`, and
|
||||
`{ready_label}` exactly as filled. The second card in the upper-center or
|
||||
upper-left two-card system displays `{player2_label}`, `{player2_name}`, and
|
||||
`{ready_label}` exactly as filled. The vertical menu on the right displays
|
||||
`{start_label}`, `{continue_label}`, `{settings_label}`, and `{exit_label}`
|
||||
exactly as filled. `{continue_label}` is the visual center and primary
|
||||
highlighted button.
|
||||
|
||||
Dynamic style fill: Adapt the menu background, ground texture, button shapes,
|
||||
icons, typography, borders, glow, and sticker treatment to {visual_style}, while
|
||||
preserving the layout and hierarchy in {ui_ref}.
|
||||
|
||||
Sound: Menu ambience, subtle UI-hover sounds, and a low electronic atmosphere
|
||||
before the click. Ignore this direction when generating silent video.
|
||||
|
||||
### [2-4 seconds] - PLAYER 1 right-arm configuration
|
||||
|
||||
Composition and camera: In a medium shot, the camera pushes smoothly from the
|
||||
main menu toward PLAYER 1's right arm. PLAYER 2 remains visible and stable in the
|
||||
background.
|
||||
|
||||
UI: The right-side menu contracts and slides away. A panel with functional-accent
|
||||
guide lines slides in from the left and displays `{player1_label}` and
|
||||
`{player1_equipment_label}` exactly as filled. The equipment list first
|
||||
highlights `{player1_option_a}`, then moves the selection to
|
||||
`{player1_option_b}`.
|
||||
|
||||
Action: PLAYER 1's right cuff opens automatically and a lightweight mechanism
|
||||
unfolds beneath the forearm. The fingers spread as long claw-like joints slide
|
||||
into position and lock one by one, briefly revealing fine wiring, miniature
|
||||
pistons, and metal connectors. Functional-accent LEDs illuminate sequentially
|
||||
when configuration completes.
|
||||
|
||||
Dynamic style fill: Adapt the mechanism, panel material, icons, lines, locking
|
||||
animation, and light effects to {visual_style}. Keep the result light, precise,
|
||||
and flexible, proportioned to PLAYER 1 without changing the face, hairstyle, or
|
||||
main clothing design.
|
||||
|
||||
Sound: Precise mechanical unfolding, light UI switching tones, and small locking
|
||||
clicks.
|
||||
|
||||
### [4-7 seconds] - PLAYER 2 heavy-arm configuration
|
||||
|
||||
Composition and camera: A medium shot tracks smoothly between the players and
|
||||
arcs toward PLAYER 2's left side. PLAYER 1 remains in the background, quietly
|
||||
examining the configured mechanical hand.
|
||||
|
||||
UI: A {power_accent_color} panel slides in and displays `{player2_label}` and
|
||||
`{player2_equipment_label}` exactly as filled. Its grid contains `{hand_label}`,
|
||||
`{forearm_label}`, `{elbow_label}`, and `{upper_arm_label}`, with the selection
|
||||
moving quickly but legibly through all four.
|
||||
|
||||
Action: PLAYER 2's left sleeve opens in sections. Heavy forearm plates spring
|
||||
outward, the previous components detach, and new armor slides into place along
|
||||
guide rails. A thick mechanical bearing replaces the elbow joint, and the broad
|
||||
mechanical hand reassembles and locks. Thick wiring, hydraulic pistons, and a
|
||||
dark metal skeleton appear briefly during the replacement. A restrained warm
|
||||
indicator illuminates as each component locks.
|
||||
|
||||
Dynamic style fill: Adapt the heavy arm, UI panel, component icons, materials,
|
||||
and light effects to {visual_style}. Keep it broad, weighty, and powerful, in
|
||||
clear contrast with PLAYER 1's lightweight claw.
|
||||
|
||||
Sound: Low motor movement, heavy mechanical engagement, and weighty locking
|
||||
feedback.
|
||||
|
||||
### [7-8.5 seconds] - Shared configuration confirmation
|
||||
|
||||
Composition and camera: Pull back smoothly to a medium two-player composition,
|
||||
with PLAYER 1 on the left and PLAYER 2 on the right.
|
||||
|
||||
UI: The two equipment panels converge at center to form a shared button that
|
||||
displays `{confirm_label}` exactly as filled. Adapt its border, glow, icon, and
|
||||
sticker treatment to {visual_style}, while keeping the hierarchy and text legible.
|
||||
|
||||
Action: The cursor clicks the button. A functional-accent energy pulse travels
|
||||
through PLAYER 1's mechanical claw, while a {power_accent_color} pulse travels
|
||||
through PLAYER 2's fist. All UI panels contract inward and disappear. Both
|
||||
players uncross their legs and adjust their posture: PLAYER 1 lifts one knee
|
||||
lightly and articulates the claw fingers in sequence; PLAYER 2 plants one foot
|
||||
firmly and slowly closes the heavy fist.
|
||||
|
||||
Sound: Confirmation tone, two-color energy pulses, and UI contraction.
|
||||
|
||||
### [8.5-10 seconds] - Shared world loading
|
||||
|
||||
Composition and camera: A wide shot reveals a shared loading bar at the bottom.
|
||||
|
||||
UI: The loading bar displays `{loading_label}` exactly as filled and fills
|
||||
rapidly from 0% to 100%. Its left half uses {functional_accent_color} and its
|
||||
right half uses {power_accent_color}. Adapt the HUD and loading-bar shape,
|
||||
border, texture, and typography to {visual_style}, while keeping them legible.
|
||||
|
||||
Environment transformation: Continuously transform the confirmed
|
||||
{visual_style} menu background into a game world in the same style. Menu strips,
|
||||
color blocks, and patterns become corresponding roads, structures, and world
|
||||
elements. Preserve the confirmed palette rather than forcing a yellow-and-black
|
||||
or cyberpunk city.
|
||||
|
||||
Key constraint: The transformation remains continuous and natural, with no hard
|
||||
cut, smoke occlusion, or identity change.
|
||||
|
||||
Sound: Rising loading tone and an ambience transition from menu to game world.
|
||||
|
||||
### [10-15 seconds] - Two-player world entry
|
||||
|
||||
Composition and camera: Move from an extreme wide shot into a third-person
|
||||
tracking view. At 100% loading, both characters stand simultaneously. The camera
|
||||
descends smoothly and arcs behind them into a stable two-player cooperative view.
|
||||
|
||||
World style: Generate the complete world from {visual_style}. Preserve the game
|
||||
opening structure: dense buildings, roads, signal lights, signs, crowds or other
|
||||
moving background elements, passing vehicles, overhead wires, industrial pipes,
|
||||
and a distant skyline. Materials, architecture, signage, lighting, and motion
|
||||
must follow {visual_style}. Do not let the source template's cyberpunk default
|
||||
override the user unless the selected style is cyberpunk.
|
||||
|
||||
Character relationship: Clearly show the players from behind and preserve their
|
||||
body contrast. PLAYER 1 is on the left, tall and slender, with the lightweight
|
||||
claw hanging naturally. PLAYER 2 is on the right, shorter and broader, with the
|
||||
heavy fist slightly raised. PLAYER 1 steps forward first, PLAYER 2 follows, and
|
||||
they enter the street side by side.
|
||||
|
||||
HUD: The HUD fades in. A mini-map appears in the upper right. Separate status
|
||||
bars labeled `{player1_name}` and `{player2_name}` appear in the lower left.
|
||||
The first uses {functional_accent_color}; the second uses {power_accent_color}.
|
||||
A shared objective marker appears in the street ahead.
|
||||
|
||||
Sound: City ambience, distant vehicles, footsteps, and a HUD fade-in cue.
|
||||
|
||||
## Negative constraints
|
||||
No extra player, duplicated character, identity or username swapping, merged bodies, unintended face/hair changes, missing player, unrequested split screen or cuts, random camera shake, floating body parts, gruesome dismemberment, unwanted weapons, style-incompatible neon, unreadable UI, random letters, misspelled usernames, extra menu options, copied game logo, or watermark. Preserve the user's chosen character designs and palette.
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: h3-prompt-writing
|
||||
description: Write MiniMax H3 video generation prompts for T2VA, I2VA, FL2VA, L2VA, and Ref2VA. Use when rewriting multimodal requests into H3 prompt structures, composing integrated_multimodal_description, overall_soundscape, and non_diegetic_music, aligning keyframes, or defining reference labels for images, videos, and audio.
|
||||
metadata:
|
||||
compatibility: Portable to any agent that can read local files — no external API calls, MiniMax Hub tools, or proprietary runtime required. The agents/openai.yaml file only adds optional ChatGPT/Codex UI metadata; it does not restrict the skill to OpenAI agents.
|
||||
---
|
||||
|
||||
# H3 Prompt Writing
|
||||
|
||||
## Workflow
|
||||
|
||||
0. Read [portable-workflow.md](references/portable-workflow.md) for scope, available tools, durable artifacts, and generation handoff. For prompt-only work, no generation tools are required.
|
||||
1. Identify the input mode: T2VA, I2VA, FL2VA, L2VA, or full-reference Ref2VA.
|
||||
2. For base text/keyframe modes, read `references/base-format.md` and follow its final prompt structure.
|
||||
3. For full-reference mode, read `references/ref-format.md` and follow its six-section rewrite format.
|
||||
4. Preserve the exact field names, section order, labels, and timing notation from the selected guide.
|
||||
|
||||
## Base Modes
|
||||
|
||||
- T2VA: build the full audiovisual timeline from text.
|
||||
- I2VA: start from the first frame and develop forward from it.
|
||||
- FL2VA: describe the continuous path between the first and last frames.
|
||||
- L2VA: infer a plausible opening and converge to the supplied last frame.
|
||||
|
||||
Use `integrated_multimodal_description`, `overall_soundscape`, and `non_diegetic_music` in the order shown in `references/base-format.md`.
|
||||
|
||||
## Full-Reference Mode
|
||||
|
||||
Ref2VA rewrites use `subject_definitions`, `summary`, `retention_analysis`, `detailed_description`, `overall_soundscape`, and `non_diegetic_music` in that order. Reference labels stay consistent across all sections.
|
||||
|
||||
Read `references/ref-format.md` for label rules and retention analysis.
|
||||
|
||||
## Output Rules
|
||||
|
||||
- Write rewrite sections in English; preserve dialogue, lyrics, and visible scene text in their original language.
|
||||
- Describe each shot by composition, subjects, environment, actions, camera, sound, and the exact point where referenced content appears.
|
||||
- Avoid plot summaries, unresolved reference labels, and timing that does not match the requested duration.
|
||||
## Tips for Better Results
|
||||
- Match the description to the effective duration of the current clip or generation window. The upstream guides describe 4–15-second clips; longer work requires a verified backend extension or an explicit assembly plan, as described in the portable workflow.
|
||||
- Keep reference labels consistent (e.g. `<Picture 1>`, `<Video 1>`, `<Audio 1>`) across every section.
|
||||
- Prefer concrete visual and audio details over abstract words like "cinematic" or "beautiful".
|
||||
- When using keyframes (I2VA / FL2VA / L2VA), clearly state how the first and/or last frame connects to the timeline.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "H3 Prompt Writing"
|
||||
short_description: "Write structured H3 prompts for each input mode"
|
||||
default_prompt: "Use $h3-prompt-writing to prepare the requested H3 prompts or video with the available tools."
|
||||
@@ -0,0 +1,86 @@
|
||||
# H3 base-mode prompt format
|
||||
|
||||
Use this reference for T2VA, I2VA, FL2VA, and L2VA prompt writing. It is a
|
||||
compact, repository-authored description of the required output contract, not a
|
||||
copy of an upstream prompt guide.
|
||||
|
||||
## Select the anchor mode
|
||||
|
||||
- T2VA has no image anchor. Build the audiovisual sequence from the brief.
|
||||
- I2VA binds `<Picture 1>` to the first frame at 0.00 seconds.
|
||||
- FL2VA binds `<Picture 1>` to the first frame and `<Picture 2>` to the final
|
||||
frame. Describe the observable path between them.
|
||||
- L2VA binds `<Picture 1>` to the final frame. Infer a compatible opening and
|
||||
converge to the supplied image.
|
||||
|
||||
For an image-anchored mode, put a plain-English alignment statement before the
|
||||
structured fields. State each picture label, its shot, and its exact target time.
|
||||
The ending time must match the effective clip duration, formatted to two decimal
|
||||
places. Do not invent a picture label when no image was supplied.
|
||||
|
||||
## Emit three fields in order
|
||||
|
||||
```text
|
||||
integrated_multimodal_description: [Shot 1] ...
|
||||
|
||||
overall_soundscape: ...
|
||||
|
||||
non_diegetic_music: ...
|
||||
```
|
||||
|
||||
`integrated_multimodal_description` is the playback-ordered visual and diegetic
|
||||
audio plan. Establish the initial style, framing, subjects, environment, and
|
||||
spatial relationships, then describe actions and state changes. For keyframe
|
||||
modes, explicitly preserve or approach the relevant composition, identity,
|
||||
clothing, colors, objects, and geometry.
|
||||
|
||||
`overall_soundscape` summarizes ambience, physical effects, and non-verbal human
|
||||
sound. Do not repeat dialogue or music already described elsewhere. Use `N/A`
|
||||
only for explicitly silent output.
|
||||
|
||||
`non_diegetic_music` describes music heard by the audience but not the characters.
|
||||
Specify audible properties such as instrumentation, tempo, rhythm, dynamics, and
|
||||
ending behavior. Put source-visible music, singing, radio, or instrument playing
|
||||
in the main description. Use `N/A` when no score is wanted.
|
||||
|
||||
## Timeline notation
|
||||
|
||||
- Start the opening with `[Shot 1]` and no timestamp.
|
||||
- Mark each later cut with a sequential label and a strictly increasing time,
|
||||
for example `[Shot 2] At 00:03.500, ...`.
|
||||
- Use a new shot for an actual edit or meaningful viewpoint/time change. Keep a
|
||||
continuous action or morph in one shot and describe its internal timing.
|
||||
- Describe camera motion as an action: type, direction, useful amplitude, and
|
||||
speed. Do not append a disconnected list of camera keywords.
|
||||
- Keep every cut and event within the requested clip duration.
|
||||
|
||||
## Speech, text, and sound
|
||||
|
||||
Give each speaking or singing source a stable ID such as `(S1)` or `(S2)` and
|
||||
reuse it across shots. Put only the language tag and literal words inside the
|
||||
dialogue wrapper:
|
||||
|
||||
```text
|
||||
The courier (S1) says softly: <d>[English] The gate is open.</d>
|
||||
```
|
||||
|
||||
Preserve supplied dialogue, lyrics, punctuation, and visible text verbatim. State
|
||||
when a voice is off-screen and keep the visible character's lips closed when that
|
||||
is required. If a line spans a cut, describe the audio continuity on both sides
|
||||
of the cut. Place visible signs, labels, and interface copy in double quotes.
|
||||
|
||||
Tie diegetic sounds to the event that produces them. Avoid describing the same
|
||||
sound as both diegetic and non-diegetic.
|
||||
|
||||
## Anchor-specific checks
|
||||
|
||||
- I2VA: begin from the supplied frame rather than merely borrowing its style.
|
||||
- FL2VA: describe intermediate motion; do not provide two unrelated still-image
|
||||
descriptions. Reach Picture 2 at the actual end time.
|
||||
- L2VA: keep the final picture assigned to the last shot, not automatically to
|
||||
Shot 1, and make the preceding action physically plausible.
|
||||
- All modes: reference labels must map to supplied assets and remain stable.
|
||||
|
||||
Before delivery, verify the field order, shot numbering, timestamps, reference
|
||||
labels, dialogue fidelity, requested language, duration, and absence of unresolved
|
||||
template variables.
|
||||
@@ -0,0 +1,121 @@
|
||||
# Portable H3 production workflow
|
||||
|
||||
This is the runtime contract for the nine H3 skills in this repository. Read it
|
||||
alongside the selected creative skill. The bundle uses local files and available
|
||||
tools; no proprietary canvas, choice-card widget, planner, or executor is required.
|
||||
|
||||
## Scope and decisions
|
||||
|
||||
- Resolve the requested deliverable first: prompt, storyboard, assets, or finished
|
||||
video. A prompt-only request ends with the prompt; it does not start generation.
|
||||
- Reuse the user's duration, language, style, model, audio policy, supplied assets,
|
||||
and existing authorization. State reasonable defaults for optional gaps. Ask
|
||||
only about missing inputs or choices that materially affect the requested work.
|
||||
- Creative checkpoints are reviewable artifacts, not mandatory repeated approvals.
|
||||
Honor an explicit request to approve a preview before rendering. When the user
|
||||
has authorized the complete workflow or delegated creative choices, show the
|
||||
plan and continue within that scope without requiring a special UI control.
|
||||
- A skill never grants permission to publish, send messages, spend outside an
|
||||
authorized budget, or change models against the user's choice. User constraints
|
||||
override a preset's style, language, shot count, timing, or audio defaults.
|
||||
|
||||
## Tools and durable artifacts
|
||||
|
||||
1. Inspect the actual available tools, existing scripts, endpoint documentation,
|
||||
and supplied media. Do not invent a tool name, model parameter, or returned path.
|
||||
2. Write plans and prompts to the user-selected project folder. If none is given,
|
||||
use a new named folder under `outputs/`, outside the skill package. Keep useful
|
||||
artifacts such as `brief.md`, `storyboard.md`, `prompts/`, `references/`,
|
||||
`clips/`, and `final/`; create only those needed for this deliverable.
|
||||
3. Record each reference's role and path: identity, environment, style, typography,
|
||||
first/last frame, or audio. Tie generated clips to the prompt revision, input
|
||||
assets, model, settings, and output paths. Update downstream references when an
|
||||
asset changes; retain previous outputs instead of overwriting user files.
|
||||
4. Use available image generation/editing tools for requested raster assets. Use
|
||||
an available video endpoint or local service for clips, and available audio
|
||||
tooling for requested standalone speech/music. For assembly and inspection,
|
||||
use an installed editor or tools such as FFmpeg, ffprobe, and OpenCV. Follow the
|
||||
host's tool policies, including its preferred image generation mechanism.
|
||||
5. Independent tool jobs may run concurrently when resources permit; this skill
|
||||
does not require separate agents or delegated generation.
|
||||
6. If a required capability is missing, finish the useful in-scope preparation:
|
||||
complete prompts, asset-role manifest, timeline, and verified request example
|
||||
where possible. State the missing capability and unfinished media step. Do not
|
||||
silently substitute another model, claim a render happened, or call a written
|
||||
plan a completed video. Resume generation when the capability becomes available.
|
||||
|
||||
## Compile the creative plan into H3 prompts
|
||||
|
||||
Read [base-format.md](base-format.md) for T2VA / I2VA / FL2VA / L2VA, or
|
||||
[ref-format.md](ref-format.md) for Ref2VA. These are writing modes, not guaranteed API
|
||||
task names. Check the selected backend's input mapping before sending a request.
|
||||
|
||||
- Base prompts use `integrated_multimodal_description`, `overall_soundscape`,
|
||||
`non_diegetic_music`, in that order, with the appropriate keyframe preamble.
|
||||
- Ref2VA uses `subject_definitions`, `summary`, `retention_analysis`,
|
||||
`detailed_description`, `overall_soundscape`, `non_diegetic_music`, in that order.
|
||||
- Every reference label must resolve to a supplied asset, in the same order used
|
||||
by the backend. Omit nonexistent optional references and their dependencies.
|
||||
- Keep the creative brief in the user's language. Structured H3 rendering prompts
|
||||
use English prose and exact field labels, while dialogue, lyrics, and visible
|
||||
text retain their requested language and wording. If the user explicitly wants
|
||||
only a same-language creative prompt, deliver that without silently replacing it
|
||||
with English. Compile a separate rendering prompt when generation is requested.
|
||||
- `[Shot 1]` has no initial timestamp. Later shot labels mark actual cuts. For a
|
||||
continuous morph, describe timed actions inside one shot rather than turning
|
||||
each form into a new shot. Express camera direction, speed, and useful amplitude.
|
||||
- Separate image style from character identity. A style reference must not inject
|
||||
its people, scenery, layout, typography, texture, or lighting into unrelated
|
||||
shots. For literal text fidelity, inspect the rendered result; a prompt is not
|
||||
proof that the exact lettering or beat synchronization was achieved.
|
||||
|
||||
## Longer videos and audio
|
||||
|
||||
Use the actual backend's supported duration, dimensions, frame grid, reference
|
||||
count, audio modes, and model partition. Inspect this checkout's H3 implementation
|
||||
or serving documentation before building requests. Do not assume that a feature
|
||||
branch's long-video extension exists on main or on a hosted service.
|
||||
|
||||
For a verified vLLM-Omni Ref2VA continuation backend, `long_video=true` with
|
||||
`long_video_mode=continuation` can accept one `continuation_prompts` entry per
|
||||
planned window only when the Ref2VA request is executed with its local text
|
||||
encoder. Step execution and stages that use an external text encoder reject
|
||||
`continuation_prompts`; omit the field and use the supported per-step inputs in
|
||||
those configurations. Compute the window count from the aligned total frames,
|
||||
window size, and overlap. Each prompt uses local window time; track global
|
||||
shot/music time separately. Repeated overlap is guidance, not additional output
|
||||
duration. Do not use this mode on a task/partition that does not support it.
|
||||
|
||||
Otherwise split into supported clips and assemble them. Same-scene clips may use
|
||||
tail/head keyframe continuity when supported. Scene changes should have explicit
|
||||
new scene references; a previous scene's latent tail can preserve the wrong
|
||||
setting. Choose cuts, morphing, and transitions from the brief rather than imposing
|
||||
hard cuts whenever a work exceeds 15 seconds. Generation windows and visual shots
|
||||
are different: one window may contain cuts, and one shot may span multiple windows.
|
||||
|
||||
For supplied music, use the selected excerpt as the master timeline unless the
|
||||
user requests replacement. For native audio, write the musical/SFX direction in
|
||||
the prompt and verify that the backend actually returns audio. Do not invent a
|
||||
generic `generate_audio` parameter. If available, locked-source audio latents guide
|
||||
generation but the audio-VAE reconstruction is not bit-identical to the source.
|
||||
Use explicit final audio stream-copy when an exact original track is required.
|
||||
Prompted BPM is a target, not measured timing. Avoid automatically adding lyrics,
|
||||
voiceover, subtitles, or multiple competing scores to an instrumental request.
|
||||
|
||||
## Verification and bounded recovery
|
||||
|
||||
Inspect reference images before using them. After rendering, inspect representative
|
||||
frames, transitions, opening/ending states, text, identities, and scene continuity.
|
||||
Check audio by listening when possible; report any limit on audio review. Check
|
||||
duration, dimensions, fps, frame count, audio presence, and decode validity with
|
||||
media tools. If preserving audio exactly, compare extracted audio stream hashes.
|
||||
|
||||
Correct a demonstrated failure with a targeted change to the affected prompt,
|
||||
reference, or edit. Keep raw generation alongside edited/upscaled versions and
|
||||
label the difference. Use an agreed retry/resource budget; absent one, allow one
|
||||
targeted rerender, then report persistent defects and concrete options rather than
|
||||
entering an unbounded generation loop. Do not switch providers automatically.
|
||||
|
||||
Deliver actual artifact paths, the prompts/settings needed to repeat the work,
|
||||
and material visual/audio limitations. Distinguish requested behavior, observed
|
||||
model output, and post-production repairs.
|
||||
@@ -0,0 +1,105 @@
|
||||
# H3 full-reference prompt format
|
||||
|
||||
Use this reference for Ref2VA prompt writing. It is a compact,
|
||||
repository-authored description of the output contract, not a copy of an
|
||||
upstream prompt guide.
|
||||
|
||||
## Emit six fields in order
|
||||
|
||||
```text
|
||||
subject_definitions: ...
|
||||
|
||||
summary: ...
|
||||
|
||||
retention_analysis: ...
|
||||
|
||||
detailed_description: [Shot 1] ...
|
||||
|
||||
overall_soundscape: ...
|
||||
|
||||
non_diegetic_music: ...
|
||||
```
|
||||
|
||||
Write the structural prose in English. Preserve the requested language and exact
|
||||
wording for dialogue, lyrics, and visible text.
|
||||
|
||||
## Reference labels
|
||||
|
||||
Assign labels only to supplied content and keep every label stable across all six
|
||||
fields:
|
||||
|
||||
- `<Subject N>` identifies reusable visible content such as a person, object,
|
||||
environment, costume, interface, action, or visual treatment.
|
||||
- `<Picture N>` identifies an image used as a concrete frame, composition, or
|
||||
storyboard anchor. If an image only defines a subject, cite it in that subject's
|
||||
definition instead of inventing a separate target-frame role.
|
||||
- `<Video N>` identifies a source video being edited or continued, or a video
|
||||
whose temporal structure is referenced.
|
||||
- `<Audio N>` identifies a supplied audio signal that is copied or referenced.
|
||||
Audio and video label numbers are independent even when they came from one file.
|
||||
|
||||
In `subject_definitions`, give each tracked item a separate line. State its source,
|
||||
role, and the features that later sections must preserve or transform. Do not
|
||||
create labels for assets or roles that do not exist.
|
||||
|
||||
## Summary and retention
|
||||
|
||||
`summary` is one short paragraph describing the target and the principal reference
|
||||
relationships. Use only labels already defined. Distinguish these operations:
|
||||
|
||||
- a concrete image frame anchor;
|
||||
- generation guided by identity, style, action, camera, or audio characteristics;
|
||||
- direct editing of a source video;
|
||||
- continuation from a source video;
|
||||
- copying an audio signal;
|
||||
- referencing audio properties without copying the signal.
|
||||
|
||||
`retention_analysis` has one line per label and states where it is used and what
|
||||
changes. Use consistent machine-readable relationship values:
|
||||
|
||||
- Visual: `fully_preserved`, `partially_preserved`, `attribute_transfer`, or
|
||||
`weak_reference`.
|
||||
- Audio: `fully_copy`, `partially_copy`, `reference`, or `weak_reference`.
|
||||
|
||||
Explain the concrete retained and changed traits after the relationship value.
|
||||
Do not claim full preservation when identity, geometry, timing, or signal content
|
||||
is intentionally altered. Do not count newly requested target action as an
|
||||
unintended loss of reference fidelity.
|
||||
|
||||
## Detailed description
|
||||
|
||||
`detailed_description` is the playback-ordered rendering plan. For each shot,
|
||||
cover the current composition, subject appearance and position, environment,
|
||||
lighting, actions and state changes, camera behavior, diegetic sound, and the
|
||||
point at which each reference becomes relevant.
|
||||
|
||||
- Start with `[Shot 1]` and no timestamp.
|
||||
- Give later cuts sequential labels with strictly increasing times, such as
|
||||
`[Shot 2] At 00:03.500, ...`.
|
||||
- Place relevant reference labels next to the described subject, frame, motion,
|
||||
or sound; do not collect detached labels at the end.
|
||||
- Use stable `(S1)`, `(S2)`, and subsequent IDs for vocal sources. Put literal
|
||||
speech or lyrics inside `<d>[Language] ...</d>`.
|
||||
- Preserve supplied visible text verbatim and place it in double quotes.
|
||||
- Describe continuous transformations inside one shot unless an actual cut is
|
||||
intended. State camera direction, speed, and amplitude when useful.
|
||||
|
||||
For video editing, explicitly identify what stays from the source timeline and
|
||||
what is replaced. For continuation, distinguish the inherited opening state from
|
||||
new content. For style reference, transfer visual properties without accidentally
|
||||
copying people, scenery, layout, or typography.
|
||||
|
||||
## Audio fields
|
||||
|
||||
`overall_soundscape` summarizes ambience, physical action sounds, and non-verbal
|
||||
human sounds. `non_diegetic_music` describes score audible only to the audience.
|
||||
Keep dialogue and diegetic music in `detailed_description`. Use `N/A` only when
|
||||
the corresponding layer is intentionally absent.
|
||||
|
||||
If audio is copied, state whether the whole signal or only a range/layer is used.
|
||||
If it is referenced, describe the specific property—such as voice timbre, tempo,
|
||||
rhythm, or texture—without claiming signal reuse.
|
||||
|
||||
Before delivery, verify the six-field order, one-to-one label definitions,
|
||||
retention coverage, shot timing, dialogue fidelity, requested language, and
|
||||
absence of unresolved template variables.
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
name: handdrawn-live-video-generator
|
||||
description: Write or generate a continuous live-action scene with a rough luminous hand-drawn entity that contacts real objects, morphs, and escapes a slightly delayed handheld camera. Use for gentle surreal mixed-media shorts, not flat-vector-only animation or horror clips.
|
||||
metadata:
|
||||
compatibility: Portable prompt writing with sibling h3-prompt-writing; actual generation requires an available video backend and any referenced media.
|
||||
---
|
||||
|
||||
# Handdrawn Live-Action Fusion
|
||||
|
||||
Read the [portable workflow](../h3-prompt-writing/references/portable-workflow.md).
|
||||
Keep the user's requested scope and language. A creative-prompt request delivers
|
||||
the prompt, without generating media. For a requested finished video, prepare
|
||||
the prompt and proceed under existing authorization using available tools.
|
||||
|
||||
## Creative contract
|
||||
|
||||
The default is a 15-second, 16:9 continuous scene in an everyday real space. A
|
||||
flat luminous drawn entity visibly contacts a real hand/object early, transforms
|
||||
as one traceable being, escapes through connected space, and the handheld camera
|
||||
reacts slightly late. Duration and ratio follow the user's explicit choices.
|
||||
|
||||
Use rough crayon, chalk, colored pencil, pastel, or brush strokes with uneven fill,
|
||||
frayed edges, line jitter, and frame-by-frame redraw. Keep the live-action setting
|
||||
physically grounded and the drawn presence visibly planar. Uniform neon tubes,
|
||||
plush characters, polished CG, and clean vector strokes would change this style.
|
||||
|
||||
Choose a fresh setting, entity, palette, contact mechanism, transformation chain,
|
||||
escape route, camera reaction, and emotional ending within the user's constraints.
|
||||
Do not ban an otherwise requested motif simply because an upstream example used
|
||||
it. The tone is warm, playful, and gently surprising rather than threatening.
|
||||
|
||||
## Timed action structure
|
||||
|
||||
For a 15-second brief, use these intervals as a starting structure:
|
||||
|
||||
- 0–3s: establish obvious real/drawn contact, such as landing on a palm or slipping
|
||||
around a finger. The real participant reacts.
|
||||
- 3–6s: begin a continuous morph while retaining a color smear, line, curve, or tail
|
||||
from the previous shape. Give it a playful action.
|
||||
- 6–10s: let it escape into an adjacent part of the same space. The camera pans,
|
||||
tilts, or moves only after the entity starts leaving its view.
|
||||
- 10–13s: add another readable interaction or surprise, keeping the same entity.
|
||||
- 13–15s: extend an earlier drawn motif across the space into a gentle larger
|
||||
transformation, then resolve with a small emotional/comic detail.
|
||||
|
||||
Retiming changes the intervals proportionally or reorganizes beats; do not leave
|
||||
15-second timestamps in a shorter prompt. Preserve a user's explicit final form
|
||||
instead of forcing the spatial finale when it conflicts with their ending.
|
||||
|
||||
## Prompt delivery and rendering
|
||||
|
||||
For a same-language creative prompt, begin with duration, ratio, real space, and
|
||||
the live-action/drawing fusion. Then describe phone-camera texture, the timed
|
||||
action intervals, drawn material, camera lag, specific exclusions, and ambient
|
||||
sound. Avoid unrelated headings or an essay when the user asked for copy-ready text.
|
||||
|
||||
For actual H3 generation, create a separate structured rendering prompt using the
|
||||
appropriate base/Ref2VA guide: English prose with literal dialogue/visible text in
|
||||
the requested language. Preserve the creative intent and actual media bindings.
|
||||
Do not send unsupported model settings or promise exact first-frame conditioning
|
||||
merely because an image is present.
|
||||
|
||||
## Review
|
||||
|
||||
Check clear early physical contact, one continuous entity, connected geography,
|
||||
retained shape motifs, delayed camera reaction, rough planar drawing, and a
|
||||
non-threatening ending. Avoid jump scares, sudden blackouts, menacing anatomy, and
|
||||
unrequested extra characters. Deliver the actual prompt/video and state any
|
||||
remaining contact, continuity, texture, or camera-timing defects.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Handdrawn Live-Action Fusion"
|
||||
short_description: "Direct drawn morphs and real-world interactions"
|
||||
default_prompt: "Use $handdrawn-live-video-generator to prepare the requested H3 prompts or video with the available tools."
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: minimalist-product-ad-generator
|
||||
description: Plan, prompt, or produce minimalist product advertising shorts from product images, preserving variants, material, color, concise typography, and rhythmic camera motion. Use for product launches and ecommerce films, not presenter-led ads or complex UI demonstrations.
|
||||
metadata:
|
||||
compatibility: File-based agent workflow. Requires the sibling h3-prompt-writing package; rendering uses available image, video, audio, and editing tools.
|
||||
---
|
||||
|
||||
# Minimalist Product Ad Generator
|
||||
|
||||
Read the [portable workflow](../h3-prompt-writing/references/portable-workflow.md).
|
||||
Use [product direction](references/product-direction.md) when planning anchors,
|
||||
copy, and timed beats. Respect the requested output: prompt-only work needs no
|
||||
generation tool, while a finished film includes generation, inspection, and assembly.
|
||||
|
||||
## Resolve the product brief
|
||||
|
||||
Inspect supplied product photos, packaging, renders, and detail shots. Record the
|
||||
product category, main variant, actual body/accent colors, material finish, usable
|
||||
mechanisms, and requested copy. Preserve identity and product facts; visual polish
|
||||
does not authorize recoloring the product or inventing a feature.
|
||||
|
||||
Reuse the specified duration, ratio, language, and model. With no constraints,
|
||||
suggest a 10-second H3 film and one of white studio, dark rim light, brand color
|
||||
field, or light lifestyle staging. Ask for a missing product reference when exact
|
||||
identity is required; distinguish a speculative concept from an existing product.
|
||||
If the user delegates direction, record the adopted choices and proceed.
|
||||
|
||||
## Design the film
|
||||
|
||||
1. Choose a product-specific spine: launch reveal, mechanism interaction, or color
|
||||
family. Describe concrete actions such as a lid opening or a crown turning.
|
||||
2. Write short sensory/benefit copy grounded in supplied facts. Preserve the user's
|
||||
exact approved wording and language. For newly requested English copy, 3–5 words
|
||||
usually fit one readable line; do not force English on other-language campaigns.
|
||||
3. Plan three independent anchors: hero silhouette, material/mechanism detail, and
|
||||
final product/copy composition. Generate only the assets needed or requested.
|
||||
Do not combine them into a panel sheet that the video model might reproduce.
|
||||
4. Keep product color, light direction, ratio, and finish consistent across anchors.
|
||||
Original photos establish identity; generated anchors must pass that identity
|
||||
check before they can replace them as rendering references.
|
||||
5. Build the beat table from the reference. Include setup, action, impact, and a
|
||||
stable closing composition; vary shot distance only when it reveals something.
|
||||
|
||||
## Prompt and render
|
||||
|
||||
Compile each beat into the appropriate H3 fields using the sibling writing guide.
|
||||
Bind every anchor to its actual role. Include exact visible copy, entry/exit times,
|
||||
colors, and same-line text motion in the rendering prompt, not only in the plan.
|
||||
Keep typography in intentional negative space without covering the product. A
|
||||
copy-reference image does not mean its line must persist throughout the whole film.
|
||||
|
||||
For a short ad, prefer one coherent full-frame film when the backend supports it.
|
||||
Keep variants ordered: main variant first, supporting variants later, full family
|
||||
only when useful at the close. Avoid product walls, grids, or an anchor-sheet ending.
|
||||
|
||||
Use native audio when appropriate to the brief. A restrained electronic score may
|
||||
use crisp plucks, airy pads, kick/sub accents and tactile wooden percussion. Set
|
||||
tempo and energy from the user's direction. Generate a separate score only if
|
||||
requested or needed for a disclosed audio repair, using an available tool.
|
||||
|
||||
## Review and deliver
|
||||
|
||||
Verify product geometry, variant colors, functional action, final copy, aspect
|
||||
ratio, and closing readability. Listen for excessive bass, dropouts, and unfinished
|
||||
endings. If editing to supplied music, select a suitable continuous excerpt and
|
||||
align visual impacts to observed beats; do not claim synchronization from text alone.
|
||||
|
||||
For bad typography, first reduce simultaneous text or correct its reference. Exact
|
||||
lettering may need a disclosed overlay when consistent with the user's goal; keep
|
||||
the raw output. Deliver the film, prompt/beat plan, used copy and music excerpt,
|
||||
and any remaining product/text fidelity issues.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Minimalist Product Ads"
|
||||
short_description: "Direct product anchors, copy, motion, and audio"
|
||||
default_prompt: "Use $minimalist-product-ad-generator to prepare the requested H3 prompts or video with the available tools."
|
||||
@@ -0,0 +1,52 @@
|
||||
# Product anchors, typography, and beats
|
||||
|
||||
## Narrative choices
|
||||
|
||||
- Launch: negative space → hero product → material detail → real mechanism action
|
||||
→ supporting variants → stable product and copy.
|
||||
- Feature touch: stillness → interaction trigger → visible mechanism → detail
|
||||
magnification → useful result → closing.
|
||||
- Color family: main variant alone → supporting colors enter → ordered relation
|
||||
→ unified material finish → full set and copy.
|
||||
|
||||
## Independent anchor briefs
|
||||
|
||||
| Anchor | What it locks | Check |
|
||||
| --- | --- | --- |
|
||||
| Hero | Main variant, recognizable silhouette, attractive opening view | Match supplied body color and product structure |
|
||||
| Detail | Material, reflection, texture, visible mechanism | No invented ports, controls, or functionality |
|
||||
| Closing | Product position, negative space, typography treatment | Real copy, readable contrast, no panel/grid layout |
|
||||
|
||||
Each is a standalone full-frame image with the project ratio. Reference roles
|
||||
protect appearance and layout; they do not replace the storyboard or require three
|
||||
sequential static-image segments. Simplify the number of anchors if the backend
|
||||
cannot bind them all, and update the prompt labels accordingly.
|
||||
|
||||
## Typography
|
||||
|
||||
Use one readable line at a time, with a typeface appropriate to the brand. A clean
|
||||
semibold sans-serif is a useful default, not a requirement to copy a specific brand.
|
||||
For a two-part color treatment, use dark text on a light field or light text on a
|
||||
dark field, then emphasize the second part with a specific real product color.
|
||||
Check contrast rather than blindly coloring text like the product.
|
||||
|
||||
The first phrase may enter gently; the second follows while the first shifts
|
||||
slightly within the same line. Do not accidentally turn this into stacked lines.
|
||||
Use actual copy in the prompt and spell out its timing. Avoid arrows, separators,
|
||||
or placeholder marks that the model may reproduce. For a 10-second ad, one middle
|
||||
copy moment and one stable closing line are often enough. Omit copy when requested.
|
||||
|
||||
## Beat table
|
||||
|
||||
| Time range | Shot purpose | Visual lead and camera | Variant state | Exact copy | Text color/motion | Handoff | Rhythm |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
|
||||
Use one main action per beat. For 5/10/15-second films, roughly 3–4/5–7/6–9 beats
|
||||
are planning suggestions, not required cuts. Record the ending product position
|
||||
and motion vector so the next beat can inherit them. Ensure the closing line has
|
||||
time to be read rather than using every second for motion.
|
||||
|
||||
If replacing music, keep useful SFX unless replacement of the whole track was
|
||||
requested. Use a continuous excerpt with a clear entry, stable middle, and suitable
|
||||
ending. A short tail fade may resolve a click; do not hide an incomplete phrase
|
||||
behind a long fade. Confirm the entire result remains audible.
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
name: music-video-subtitle-generator
|
||||
description: Plan, write, audit, or produce music videos with coordinated music, imagery, camera motion, optional performance, and lyric typography. Use for beat-aware MVs and instrumental visual narratives, not ordinary subtitle cleanup or unrelated video edits.
|
||||
metadata:
|
||||
compatibility: File-based workflow with sibling h3-prompt-writing; audio analysis, generation, and final assembly use available tools and backends.
|
||||
---
|
||||
|
||||
# Music Video and Lyric Typography
|
||||
|
||||
Read the [portable workflow](../h3-prompt-writing/references/portable-workflow.md)
|
||||
and, when building a timeline, [music timeline](references/music-timeline.md).
|
||||
Deliver the requested scope: audit, prompt, storyboard, or complete video.
|
||||
|
||||
## Lock the musical and visual intent
|
||||
|
||||
Identify duration, ratio, output resolution, music source/excerpt, visual style,
|
||||
character/scene references, performance mode, and whether text is wanted. Treat a
|
||||
supplied song as the master track unless the user requests replacement. Preserve
|
||||
provided lyrics exactly; do not translate or rewrite them unasked. For instrumental
|
||||
work, do not invent singing, lyrics, a performer, or typography. Generate original
|
||||
lyrics only when requested or clearly within an authorized songwriting brief.
|
||||
|
||||
Measure supplied audio duration and inspect/listen for beat, phrase, breath, drop,
|
||||
and energy changes using available tools. Label estimated or planned timing when
|
||||
measurement is unavailable. If the requested excerpt exceeds the audio, resolve
|
||||
the discrepancy without silently stretching or looping it.
|
||||
|
||||
## Reference roles
|
||||
|
||||
- Character references control identity, silhouette, wardrobe, and presence.
|
||||
- Scene references control environment, time of day, spatial anchors, and lighting.
|
||||
- Typography references control letter treatment, layout, and motion, not people
|
||||
or scenery visible in those references.
|
||||
- Music references control the requested track or sound style; distinguish copying
|
||||
a supplied recording from generating similar instrumentation.
|
||||
|
||||
Do not apply a preset's grain, darkness, hard cuts, or constant close-ups to an
|
||||
incompatible brief. A bright nighttime scene remains night. A continuous flat
|
||||
vector morph keeps smooth color fields and uses elastic shape motion for accents.
|
||||
Use hard cuts, slow holds, or dissolves only when appropriate to the user's intent.
|
||||
|
||||
## Compose the timeline and H3 prompts
|
||||
|
||||
Map visual actions, camera moves, scene changes, and optional text to the music's
|
||||
global time. Build a causal visual progression instead of defaulting to one person
|
||||
singing throughout. Allow room to read a shape, gesture, or lyric before changing it.
|
||||
|
||||
For longer work, choose a supported continuation or clip-assembly approach through
|
||||
the portable workflow. Keep visual shot boundaries distinct from generation
|
||||
windows. Local window prompts must account for overlap without replaying the full
|
||||
previous action. A new scene may require a new reference rather than inheritance
|
||||
of the old scene. Record entry/exit states for each planned segment.
|
||||
|
||||
Compile the timeline into H3's base or Ref2VA fields, preserving dialogue, lyrics,
|
||||
and visible text verbatim. Include concrete instrumentation and rhythmic accents,
|
||||
but treat requested BPM and beat alignment as targets until checked in the output.
|
||||
|
||||
## Typography and finishing
|
||||
|
||||
When requested, give each shot one main readable text event. Keep words away from
|
||||
eyes and critical lip motion. Match sung text to the active phrase, and distinguish
|
||||
spatial typography from subtitle bars. Reduce text complexity if the model cannot
|
||||
render it, or use a disclosed overlay consistent with the requested deliverable.
|
||||
|
||||
For supplied audio, assemble clips to one global master track, maintaining phrase
|
||||
and lip continuity; avoid cuts inside a vowel. For native audio, inspect actual
|
||||
continuity across generation windows. Preserve useful SFX and avoid layered duplicate
|
||||
music. Retiming, grain, grading, interpolation, and upscaling are deliberate editing
|
||||
choices, not automatic finishing requirements.
|
||||
|
||||
Verify transformation/story order, identities, scene changes, requested text,
|
||||
musical continuity, timing, and full media decode. Label raw and processed versions.
|
||||
Deliver the final file and current prompt/timeline files, with measured properties
|
||||
and remaining limitations rather than claims of perfect synchronization.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Music Video Direction"
|
||||
short_description: "Plan music-driven scenes and optional lyric text"
|
||||
default_prompt: "Use $music-video-subtitle-generator to prepare the requested H3 prompts or video with the available tools."
|
||||
@@ -0,0 +1,40 @@
|
||||
# Global music and local video timing
|
||||
|
||||
Use this planning skeleton, omitting vocal/text fields when not requested:
|
||||
|
||||
```text
|
||||
Global: music/excerpt, duration, ratio, character/style/scene locks, cut policy.
|
||||
|
||||
Segment S01 — global start/end; local generation start/end
|
||||
Incoming state:
|
||||
Music cue: measured beat/phrase timestamp, or clearly labeled planned accent
|
||||
Vocal line and speaker (if present):
|
||||
Visible typography (if requested):
|
||||
Visual action and camera:
|
||||
Outgoing state and transition:
|
||||
References with exact roles:
|
||||
```
|
||||
|
||||
Keep one global music clock. For measured tempo B, the nominal quarter-note spacing
|
||||
is 60/B seconds, but real tracks may have pickups, swing, tempo changes, or inaccurate
|
||||
automatic detections. Validate important cut points against the waveform/listening.
|
||||
An onset detector also finds SFX and melodic attacks; it does not prove drum beats.
|
||||
|
||||
Choose a phrase-complete excerpt when possible. Track breaths, lyric pauses, and
|
||||
vowel continuity for a performance MV. For an instrumental morph, accent the
|
||||
physical preparation, transformation impact, and release rather than introducing
|
||||
unrequested cuts. The final shape or story payoff needs a readable ending.
|
||||
|
||||
For continuation, maintain a table of absolute output frames and local window
|
||||
times. Use the verified backend's native alignment and overlap behavior. Opening
|
||||
overlap continues the inherited state; new actions belong after it. Do not sum
|
||||
overlap twice or describe every window as a fresh opening shot.
|
||||
|
||||
For separately generated clips, use a previous tail frame only when the next shot
|
||||
continues the same scene and the backend supports that keyframe role. For an
|
||||
intentional cut, retain appropriate identity references and select the new scene.
|
||||
Preserve screen direction or a useful match element when it helps the transition.
|
||||
|
||||
When text is requested, track exact string, language, entry/exit time, screen
|
||||
region, and motion. Typography style cards must not donate their depicted characters
|
||||
or settings. Preserve user text; do not silently shorten lyrics to fit a template.
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
name: paper-collage-explainer-generator
|
||||
description: Translate narration, ideas, or knowledge points into editorial halftone paper-collage metaphors, still prompts, storyboards, or stop-motion clips. Use for photographic cutout collage and tactile assembly, distinct from paper-puppet dioramas or generic cartoons.
|
||||
metadata:
|
||||
compatibility: File-based workflow with sibling h3-prompt-writing; media creation uses available image/video tools and an editor when needed.
|
||||
---
|
||||
|
||||
# Paper Collage Explainer Generator
|
||||
|
||||
Read the [portable workflow](../h3-prompt-writing/references/portable-workflow.md)
|
||||
and [collage design](references/collage-design.md) when constructing scenes.
|
||||
Honor prompt-only and asset-only requests as well as finished video requests.
|
||||
|
||||
## Meaning and media policy
|
||||
|
||||
Extract each source line's meaning, emotion, action verb, visual metaphor, and
|
||||
three to six readable object groups. Preserve the user's topic and wording as
|
||||
context; do not put narration on screen merely because it is available.
|
||||
|
||||
Default to tactile paper SFX, with no BGM, voiceover, or subtitles unless requested.
|
||||
An explainer does not inherently require speech. Existing user requests for those
|
||||
layers already establish the choice; do not ask again. A short 16:9 clip of roughly
|
||||
four seconds is a useful default for one assembly beat, subject to backend limits.
|
||||
|
||||
## Plan the image and motion together
|
||||
|
||||
Create a concise plan of metaphor, palette, object groups, assembly order, duration,
|
||||
and sound cues. For a series, keep paper texture, halftone treatment, keylines,
|
||||
shadows, and rhythmic language consistent; vary the metaphor and color field only
|
||||
where the meaning benefits. A user's no-text or no-music requirement applies to
|
||||
every downstream asset, prompt, clip, and edit.
|
||||
|
||||
Design each still as the completed final composition. Use black-and-white
|
||||
photographic halftone cutouts, selective colored cardstock, warm cream keylines,
|
||||
subtle fiber/torn edges, and soft physical layer shadows on a bold color field.
|
||||
Keep layered depth and negative space; avoid excessive age, dirt, wrinkles, or
|
||||
automatic brown/kraft backgrounds. Exact editable layers require a compositing
|
||||
workflow, not a claim that a generated raster video is a layered project.
|
||||
|
||||
Generate final-composition stills when requested/needed and inspect them. Follow
|
||||
any requested approval gate; otherwise continue within the authorized workflow.
|
||||
|
||||
## Animate the assembly
|
||||
|
||||
Start from a clean paper field matching the planned final color. Base pieces enter,
|
||||
then the main metaphor, then supporting objects. Each piece slides or pops in,
|
||||
bounces slightly, presses flat, pauses, and locks. End with a brief hold on the
|
||||
completed composition. Use stop-motion assembly rather than global fades, smooth
|
||||
digital drifting, fast spinning, or liquid morphs unless explicitly requested.
|
||||
|
||||
Use the supplied final still as a last-frame anchor only when the backend supports
|
||||
it. Otherwise identify it honestly as composition/style guidance; do not describe
|
||||
a reference image as a guaranteed final-frame constraint. Compile the actual H3
|
||||
mode with the sibling guide and bind only real inputs.
|
||||
|
||||
Map short paper slides, pops, taps, rustles, and snaps to motion. Preserve those
|
||||
SFX during assembly. When the user adds music or narration later, mix with the
|
||||
useful SFX unless they request full replacement.
|
||||
|
||||
## Review and deliver
|
||||
|
||||
Check the metaphor without relying on text, object count/readability, matching
|
||||
opening color, visible piece-by-piece construction, final-frame resemblance,
|
||||
controlled paper texture, and no unwanted UI/letters/music/voiceover. If the
|
||||
assembly is weak, simplify the groups and make their arrival order concrete.
|
||||
|
||||
For multiple clips, preserve the planned order and SFX. Deliver prompts, current
|
||||
stills, and actual clips/assembly as requested. Explain any missing generation
|
||||
capability or remaining drift; keep raw output separate from edited fixes.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Paper Collage Explainers"
|
||||
short_description: "Animate editorial paper metaphors with tactile SFX"
|
||||
default_prompt: "Use $paper-collage-explainer-generator to prepare the requested H3 prompts or video with the available tools."
|
||||
@@ -0,0 +1,33 @@
|
||||
# Editorial collage design
|
||||
|
||||
For each source idea record meaning, emotion, one active verb, a concrete visual
|
||||
metaphor, three to six object groups, and a tactile sound cue. For example, a
|
||||
collaboration concept can become separate cutout hands fitting paper routes
|
||||
together; it need not become a screen full of the word "collaboration".
|
||||
|
||||
Style signature: flat bold color field, black-and-white halftone photographic
|
||||
cutouts, selective colored cardstock accents, warm cream keylines, soft physical
|
||||
paper shadows, fine uncoated fiber, refined irregular torn edges, layered seams.
|
||||
Control texture so the video feels handmade without becoming dirty or distressed.
|
||||
|
||||
Palette choices may support meaning: orange/red for urgency, mustard for tools or
|
||||
warning, green for reflection, purple for memory, teal for collaboration, rose for
|
||||
theatrical contrast. These are suggestions, not universal semantic rules. Use the
|
||||
user's palette and avoid an unrelated kraft-paper opening.
|
||||
|
||||
Still specification: source meaning → metaphor → ratio → background/accent colors
|
||||
→ object roles → foreground/midground/background → final composition → exclusions.
|
||||
|
||||
Motion specification: matching empty color field → base paper structures → main
|
||||
subject → secondary groups → light bounce/press-flat/pause → completed composition.
|
||||
Explicitly describe material boundaries and which piece moves at each beat. A
|
||||
static camera is usually enough to reveal assembly; add movement only when useful.
|
||||
|
||||
Sound specification: synchronize restrained slides, pops, taps, rustles, and snaps.
|
||||
Set `non_diegetic_music: N/A` for the default SFX-only H3 prompt. Do not use silence
|
||||
as a synonym for no background music. Dialogue and subtitles are optional layers.
|
||||
|
||||
Review one established clip as a style/cadence reference for subsequent clips.
|
||||
Change the specific failure: fewer groups for clutter, more physical arrival
|
||||
steps for digital drifting, less aging for dirty paper, stronger final state for
|
||||
composition drift. Do not apply an unrelated aesthetic preset to fix one defect.
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
name: papercraft-stop-motion-explainer
|
||||
description: Turn knowledge topics into layered papercraft stop-motion explainers, including visual metaphors, miniature sets, prompts, storyboards, motion and sound plans, or rendered video. Use for tactile paper dioramas and mechanisms, not ordinary vector cartoons or photographic collage.
|
||||
metadata:
|
||||
compatibility: Portable file-based workflow with sibling h3-prompt-writing; actual media generation uses tools available in the host environment.
|
||||
---
|
||||
|
||||
# Papercraft Stop-Motion Explainer
|
||||
|
||||
Read the [portable workflow](../h3-prompt-writing/references/portable-workflow.md).
|
||||
For scene/prompt planning read [paper staging](references/paper-staging.md).
|
||||
Route a single image prompt, image series, short animation prompt, or storyboard
|
||||
request directly to that artifact; do not force a full film workflow.
|
||||
|
||||
## Knowledge and direction
|
||||
|
||||
Identify the exact topic, source facts, audience, desired learning outcome, and
|
||||
output type. Preserve technical terms and causal meaning. A visual metaphor helps
|
||||
explain a mechanism; it must not turn into a false scientific claim.
|
||||
|
||||
Reuse requested duration and ratio. If unspecified, a 30-second, 16:9 general-audience
|
||||
concept is a reasonable starting point. Offer distinct directions only when useful:
|
||||
pop-up-book journey, paper laboratory, layered cross-section, miniature nature
|
||||
theater, or mechanism board. Each should identify one learning outcome, a paper
|
||||
mechanism that conveys it, and the signature visual moment.
|
||||
|
||||
## Build the paper world
|
||||
|
||||
Design characters only if they help the explanation. Specify paper construction,
|
||||
silhouette, joint/hinge design, replaceable facial parts, gestures, and repeatable
|
||||
identity cues. Keep the central knowledge object readable.
|
||||
|
||||
Plan foreground occluders, midground mechanism, background scenery, and a distant
|
||||
paper plane when the shot benefits from depth. Record each layer's material,
|
||||
thickness, cut/fold edges, shadow, movement, and educational role. Use real paper
|
||||
mechanics such as pull-tabs, sliders, rotating discs, page folds, and pinned joints.
|
||||
Motion is stepped with small pauses and rebounds, not a smooth CG melt.
|
||||
|
||||
Create an asset list by function: characters, scientific objects, information cards,
|
||||
environment, and moving mechanisms. For a complete production, prepare one to three
|
||||
preview briefs or images when useful and authorized. Respect any preview approval
|
||||
requested by the user; otherwise continue under the existing end-to-end scope.
|
||||
|
||||
## Prompts and timeline
|
||||
|
||||
Write a compact storyboard with columns: time, knowledge beat, visual action,
|
||||
paper movement, camera/transition, sound cue. Each shot explains one knowledge
|
||||
step, with a readable pause for a necessary label. Keep ratio, material, light
|
||||
direction, identity, and domain vocabulary consistent across image-series prompts.
|
||||
|
||||
For a short image-to-video prompt, begin from the actual image and animate a few
|
||||
paper mechanisms with restrained push-in or lateral parallax. Preserve thickness,
|
||||
cut edges, texture, and layer shadows. Compile final rendering prompts using the
|
||||
bundled H3 mode guide, with truthful references and local clip timing.
|
||||
|
||||
## Sound, generation, and review
|
||||
|
||||
Map paper flips, cardboard slides, joint taps, soft pops, and rustles to actual
|
||||
motion. Match any requested music to the topic and cultural context rather than
|
||||
automatically using the same whimsical score. Keep speech intelligible. If narration
|
||||
is requested, preserve its approved wording, measure its duration, and adjust the
|
||||
timeline or script within the user's scope; do not silently speed up the voice.
|
||||
|
||||
Use available generation/editing tools, then inspect both educational accuracy
|
||||
and paper construction: readable mechanism, separate layers/shadows, hinged or
|
||||
stepped motion, plausible camera movement, and a clear ending takeaway. Check
|
||||
narration tails, clicks, audio gaps, and music balance. Deliver requested artifacts
|
||||
and state missing rendering capabilities or unresolved scientific/visual issues.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Papercraft Explainers"
|
||||
short_description: "Explain ideas with layered paper mechanisms"
|
||||
default_prompt: "Use $papercraft-stop-motion-explainer to prepare the requested H3 prompts or video with the available tools."
|
||||
@@ -0,0 +1,48 @@
|
||||
# Paper staging and prompt building blocks
|
||||
|
||||
## Materials and depth
|
||||
|
||||
Use layered matte cardboard, visible thickness, fibers, folds, seams, tabs, brads,
|
||||
cut edges, and physical shadows. Separate foreground, mechanism, background, and
|
||||
far background with spacing. Roughly 4–7 layers often suffice; remove layers that
|
||||
hide the explanation. Place reading-heavy labels on stable planes. Use miniature
|
||||
macro photography and moderate depth of field without blurring necessary facts.
|
||||
|
||||
| Plane | Useful content | Motion | Purpose |
|
||||
| --- | --- | --- | --- |
|
||||
| Foreground | Paper leaves, frame, curtain, props | Small parallax or hinged reveal | Depth without concealing the mechanism |
|
||||
| Midground | Knowledge model, host, arrow/cards | Pull-tab, slider, joint, rotating disc | Main cause and effect |
|
||||
| Background | Diorama set or schematic layers | Slow paper rail shift | Context and hierarchy |
|
||||
| Far plane | Paper sky/board | Restrained change | Stable visual support |
|
||||
|
||||
## Prompt ingredients
|
||||
|
||||
Image: topic and core object → miniature diorama → layered paper construction →
|
||||
specific material edges → physical light/shadows → clear depth → necessary labels.
|
||||
One frame should communicate one main idea, not the entire lesson at once.
|
||||
|
||||
Image series: repeat the style/identity anchors, then state what changes and why
|
||||
that state explains the next knowledge step. Keep the same ratio and light direction.
|
||||
|
||||
Short animation: preserve the supplied image, make a small paper mechanism move,
|
||||
include tiny pauses/rebounds, and select one restrained camera move. Small puppet
|
||||
gestures and background rails can provide life without overwhelming the model.
|
||||
|
||||
## Camera and transitions
|
||||
|
||||
Use slow push-in, lateral parallax, static demonstration, macro detail, or a slight
|
||||
top-down cross-section view. A full orbit requires a set built for that view.
|
||||
Transitions may use a page flip, pop-up unfold, pull-tab, paper cloud, circular
|
||||
mask, cut-paper door, layer separation, confetti, or sticker reveal. Avoid liquid
|
||||
morphing, neon glitches, and glass shatter unless explicitly requested as contrast.
|
||||
|
||||
## Sound and exclusions
|
||||
|
||||
Use a few motion-specific accents: paper flip, scissors, cardboard slide, joint
|
||||
tap, tape peel, or box opening. A score, when appropriate, can use light percussion,
|
||||
plucked instruments, or topic-specific instrumentation. Do not infer narration
|
||||
merely because the video teaches something.
|
||||
|
||||
Keep constraints concise and relevant: no glossy plastic, smooth CG morphs, metal
|
||||
surfaces replacing paper, missing thickness/shadows, or frantic camera movement.
|
||||
Include them in supported prompt fields; do not invent a negative-prompt API field.
|
||||
Executable
+299
@@ -0,0 +1,299 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
# vllm-omni customized version
|
||||
# Based on: https://github.com/vllm-project/ci-infra/blob/main/buildkite/bootstrap-amd.sh
|
||||
# Last synced: 2025-12-15
|
||||
# Modifications: Use local template file instead of downloading from ci-infra
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# The bootstrap runs from the repository root; ShellCheck does not follow
|
||||
# sourced files unless invoked with -x.
|
||||
# shellcheck disable=SC1091
|
||||
source .buildkite/common/scripts/resolve_skip_ci.sh
|
||||
|
||||
AMD_SUITE_SELECTOR=".buildkite/amd/scripts/select_test_suites.py"
|
||||
|
||||
if [[ -z "${RUN_ALL:-}" ]]; then
|
||||
RUN_ALL=0
|
||||
fi
|
||||
|
||||
if [[ -z "${NIGHTLY:-}" ]]; then
|
||||
NIGHTLY=0
|
||||
fi
|
||||
|
||||
if [[ -z "${VLLM_CI_BRANCH:-}" ]]; then
|
||||
VLLM_CI_BRANCH="main"
|
||||
fi
|
||||
|
||||
if [[ -z "${AMD_MIRROR_HW:-}" ]]; then
|
||||
AMD_MIRROR_HW="amdproduction"
|
||||
fi
|
||||
|
||||
PR_LABELS=""
|
||||
# Explicit debug suites do not depend on PR labels.
|
||||
if [[ "${BUILDKITE_PULL_REQUEST:-false}" != "false" && -z "${DEBUG_TEST_YAML:-}" ]]; then
|
||||
if ! PR_LABELS=$(curl -fsSL \
|
||||
"https://api.github.com/repos/vllm-project/vllm-omni/pulls/$BUILDKITE_PULL_REQUEST" \
|
||||
| jq -r '.labels[].name'); then
|
||||
echo "ERROR: Could not read PR labels; refusing to select an incorrect AMD test tier." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
fail_fast() {
|
||||
if [[ "${BUILDKITE_PULL_REQUEST:-false}" != "false" ]]; then
|
||||
echo true
|
||||
else
|
||||
echo false # not a PR or BUILDKITE_PULL_REQUEST not set
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ -z "${COV_ENABLED:-}" ]]; then
|
||||
COV_ENABLED=0
|
||||
fi
|
||||
|
||||
resolve_test_specs() {
|
||||
local selected_specs
|
||||
if ! selected_specs=$(python3 "$AMD_SUITE_SELECTOR" \
|
||||
--branch "$BUILDKITE_BRANCH" \
|
||||
--labels "$PR_LABELS" \
|
||||
--debug-test-yaml "${DEBUG_TEST_YAML:-}" \
|
||||
--nightly "$NIGHTLY"); then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TEST_SPECS=()
|
||||
while IFS= read -r suite_spec; do
|
||||
[[ -z "$suite_spec" ]] && continue
|
||||
TEST_SPECS+=("$suite_spec")
|
||||
done <<< "$selected_specs"
|
||||
}
|
||||
|
||||
filter_test_specs_by_skip_ci() {
|
||||
local suite_spec level decision
|
||||
local skip_all=0
|
||||
local -a runnable_specs=()
|
||||
|
||||
for suite_spec in "${TEST_SPECS[@]}"; do
|
||||
case "$suite_spec" in
|
||||
READY_TESTS:*) level="l2" ;;
|
||||
MERGE_TESTS:*) level="l3" ;;
|
||||
NIGHTLY_TESTS:*)
|
||||
# Explicit PR and scheduled nightly selections must survive
|
||||
# L2/L3 diff gating, including docs-only main commits.
|
||||
runnable_specs+=("$suite_spec")
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown AMD test suite spec '$suite_spec'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if decision=$(python3 "$SKIP_CI_PY" gate amd "$level"); then
|
||||
echo "Skipping AMD $level suite due to $decision decision."
|
||||
[[ "$decision" == "skip-all" ]] && skip_all=1
|
||||
else
|
||||
runnable_specs+=("$suite_spec")
|
||||
fi
|
||||
done
|
||||
|
||||
TEST_SPECS=("${runnable_specs[@]}")
|
||||
if [[ ${#TEST_SPECS[@]} -eq 0 ]]; then
|
||||
if [[ $skip_all -eq 1 ]]; then
|
||||
buildkite-agent annotate \
|
||||
":memo: CI skipped — docs or pytest skip-mark changes only" \
|
||||
--style "info" 2>/dev/null || true
|
||||
fi
|
||||
echo "No AMD suites remain after skip-ci filtering."
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
upload_pipeline() {
|
||||
echo "Uploading pipeline..."
|
||||
# Install minijinja
|
||||
ls .buildkite || buildkite-agent annotate --style error 'Please merge upstream main branch for buildkite CI'
|
||||
curl -sSfL https://github.com/mitsuhiko/minijinja/releases/download/2.3.1/minijinja-cli-installer.sh | sh
|
||||
# Installed by the minijinja bootstrap above and only present on the CI agent.
|
||||
# shellcheck disable=SC1091
|
||||
source /var/lib/buildkite-agent/.cargo/env
|
||||
|
||||
if [[ $BUILDKITE_PIPELINE_SLUG == "fastcheck" ]]; then
|
||||
AMD_MIRROR_HW="amdtentative"
|
||||
fi
|
||||
|
||||
# Use local template file for vllm-omni
|
||||
cp .buildkite/amd/test-template-amd-omni.j2 .buildkite/amd/test-template.j2
|
||||
|
||||
|
||||
# (WIP) Use pipeline generator instead of jinja template
|
||||
if [ -e ".buildkite/amd/pipeline_generator/pipeline_generator.py" ]; then
|
||||
python -m pip install click pydantic
|
||||
python .buildkite/amd/pipeline_generator/pipeline_generator.py --run_all="$RUN_ALL" --list_file_diff="$LIST_FILE_DIFF" --nightly="$NIGHTLY" --mirror_hw="$AMD_MIRROR_HW"
|
||||
buildkite-agent pipeline upload .buildkite/amd/pipeline.yaml
|
||||
exit 0
|
||||
fi
|
||||
echo "List file diff: $LIST_FILE_DIFF"
|
||||
echo "Run all: $RUN_ALL"
|
||||
echo "Nightly: $NIGHTLY"
|
||||
echo "AMD Mirror HW: $AMD_MIRROR_HW"
|
||||
|
||||
FAIL_FAST=$(fail_fast)
|
||||
|
||||
cd .buildkite/amd
|
||||
|
||||
# Multiple label-selected or debug-selected suites share one image build.
|
||||
if [[ ${#TEST_SPECS[@]} -eq 1 ]]; then
|
||||
TEST_YAML="${TEST_SPECS[0]#*:}"
|
||||
else
|
||||
TEST_YAML=$(mktemp "${TMPDIR:-/tmp}/amd-selected-tests.XXXXXX.yml")
|
||||
python - "$TEST_YAML" "${TEST_SPECS[@]}" <<'PY'
|
||||
import sys
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
output_path, *suite_specs = sys.argv[1:]
|
||||
combined = {"env": {}, "steps": []}
|
||||
|
||||
for suite_spec in suite_specs:
|
||||
group_name, input_path = suite_spec.split(":", 1)
|
||||
with open(input_path, encoding="utf-8") as test_file:
|
||||
suite = yaml.safe_load(test_file)
|
||||
|
||||
for name, value in (suite.get("env") or {}).items():
|
||||
previous = combined["env"].get(name, value)
|
||||
if previous != value:
|
||||
raise ValueError(
|
||||
f"Conflicting environment value for {name}: {previous!r} != {value!r}"
|
||||
)
|
||||
combined["env"][name] = value
|
||||
|
||||
suite_steps = []
|
||||
for entry in suite.get("steps") or []:
|
||||
if "group" in entry:
|
||||
suite_steps.extend(entry.get("steps") or [])
|
||||
else:
|
||||
suite_steps.append(entry)
|
||||
combined["steps"].append({"group": group_name, "steps": suite_steps})
|
||||
|
||||
with open(output_path, "w", encoding="utf-8") as output_file:
|
||||
yaml.safe_dump(combined, output_file, sort_keys=False)
|
||||
PY
|
||||
fi
|
||||
echo "AMD test suites: ${TEST_SPECS[*]}"
|
||||
|
||||
(
|
||||
set -x
|
||||
# Output pipeline.yaml with all blank lines removed
|
||||
minijinja-cli test-template.j2 "$TEST_YAML" \
|
||||
-D branch="$BUILDKITE_BRANCH" \
|
||||
-D list_file_diff="$LIST_FILE_DIFF" \
|
||||
-D run_all="$RUN_ALL" \
|
||||
-D nightly="$NIGHTLY" \
|
||||
-D mirror_hw="$AMD_MIRROR_HW" \
|
||||
-D fail_fast="$FAIL_FAST" \
|
||||
-D vllm_use_precompiled="$VLLM_USE_PRECOMPILED" \
|
||||
-D vllm_merge_base_commit="$(git merge-base origin/main HEAD)" \
|
||||
-D cov_enabled="$COV_ENABLED" \
|
||||
-D vllm_ci_branch="$VLLM_CI_BRANCH" \
|
||||
| sed '/^[[:space:]]*$/d' \
|
||||
> pipeline.yaml
|
||||
)
|
||||
cat pipeline.yaml
|
||||
if [[ "$TEST_YAML" == "${TMPDIR:-/tmp}/amd-selected-tests."*.yml ]]; then
|
||||
rm -f -- "$TEST_YAML"
|
||||
fi
|
||||
buildkite-agent artifact upload pipeline.yaml
|
||||
buildkite-agent pipeline upload pipeline.yaml
|
||||
exit 0
|
||||
}
|
||||
|
||||
get_diff() {
|
||||
git diff --name-only --diff-filter=ACMDR "$(git merge-base origin/main HEAD)"
|
||||
}
|
||||
|
||||
get_diff_main() {
|
||||
git diff --name-only --diff-filter=ACMDR HEAD~1
|
||||
}
|
||||
|
||||
file_diff=$(get_diff)
|
||||
if [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||
file_diff=$(get_diff_main)
|
||||
fi
|
||||
|
||||
# Resolve PR tier labels before skip-ci so ready/merge suites can be filtered
|
||||
# independently while an explicitly selected nightly suite passes through.
|
||||
resolve_test_specs
|
||||
filter_test_specs_by_skip_ci
|
||||
|
||||
patterns=(
|
||||
"docker/Dockerfile"
|
||||
"CMakeLists.txt"
|
||||
"requirements/common.txt"
|
||||
"requirements/cuda.txt"
|
||||
"requirements/build.txt"
|
||||
"requirements/test.txt"
|
||||
"setup.py"
|
||||
"csrc/"
|
||||
"cmake/"
|
||||
)
|
||||
|
||||
ignore_patterns=(
|
||||
"docker/Dockerfile."
|
||||
"csrc/cpu"
|
||||
"csrc/rocm"
|
||||
"cmake/hipify.py"
|
||||
"cmake/cpu_extension.cmake"
|
||||
)
|
||||
|
||||
for file in $file_diff; do
|
||||
# First check if file matches any pattern
|
||||
matches_pattern=0
|
||||
for pattern in "${patterns[@]}"; do
|
||||
if [[ $file == "$pattern"* ]] || [[ $file == "$pattern" ]]; then
|
||||
matches_pattern=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If file matches pattern, check it's not in ignore patterns
|
||||
if [[ $matches_pattern -eq 1 ]]; then
|
||||
matches_ignore=0
|
||||
for ignore in "${ignore_patterns[@]}"; do
|
||||
if [[ $file == "$ignore"* ]] || [[ $file == "$ignore" ]]; then
|
||||
matches_ignore=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $matches_ignore -eq 0 ]]; then
|
||||
RUN_ALL=1
|
||||
echo "Found changes: $file. Run all tests"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Decide whether to use precompiled wheels
|
||||
# Relies on existing patterns array as a basis.
|
||||
if [[ -n "${VLLM_USE_PRECOMPILED:-}" ]]; then
|
||||
echo "VLLM_USE_PRECOMPILED is already set to: $VLLM_USE_PRECOMPILED"
|
||||
elif [[ $RUN_ALL -eq 1 ]]; then
|
||||
export VLLM_USE_PRECOMPILED=0
|
||||
echo "Detected critical changes, building wheels from source"
|
||||
else
|
||||
export VLLM_USE_PRECOMPILED=1
|
||||
echo "No critical changes, using precompiled wheels"
|
||||
fi
|
||||
|
||||
|
||||
LIST_FILE_DIFF=$(get_diff | tr ' ' '|')
|
||||
if [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||
LIST_FILE_DIFF=$(get_diff_main | tr ' ' '|')
|
||||
fi
|
||||
upload_pipeline
|
||||
Executable
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Build and push the ROCm CI image with a registry-backed BuildKit cache. The
|
||||
# AMD builders are ephemeral, so a local Docker cache cannot survive between
|
||||
# jobs. Keeping the cache beside the runtime image also reuses the registry
|
||||
# credentials already configured on the amd-cpu agents.
|
||||
|
||||
REGISTRY="${ROCM_CI_IMAGE_REGISTRY:-rocm/vllm-omni}"
|
||||
DOCKERFILE="docker/Dockerfile.rocm"
|
||||
BUILDER_NAME="vllm-omni-rocm-builder"
|
||||
ROCM_ARCH="${PYTORCH_ROCM_ARCH:-gfx942}"
|
||||
|
||||
if [[ -z "${BUILDKITE_COMMIT:-}" ]]; then
|
||||
echo "ERROR: BUILDKITE_COMMIT is not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dependency_files=(
|
||||
"$DOCKERFILE"
|
||||
"${DOCKERFILE}.dockerignore"
|
||||
pyproject.toml
|
||||
setup.py
|
||||
tools/install_torchcodec_rocm.sh
|
||||
)
|
||||
while IFS= read -r dependency_file; do
|
||||
dependency_files+=("$dependency_file")
|
||||
done < <(find requirements -maxdepth 1 -type f -name '*.txt' -print | LC_ALL=C sort)
|
||||
|
||||
for dependency_file in "${dependency_files[@]}"; do
|
||||
if [[ ! -f "$dependency_file" ]]; then
|
||||
echo "ERROR: cache-key input does not exist: $dependency_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
CACHE_KEY=$(
|
||||
{
|
||||
printf 'rocm-arch=%s\n' "$ROCM_ARCH"
|
||||
for dependency_file in "${dependency_files[@]}"; do
|
||||
printf 'path=%s\n' "$dependency_file"
|
||||
sha256sum "$dependency_file"
|
||||
done
|
||||
} | sha256sum | cut -c1-16
|
||||
)
|
||||
CACHE_REF="${REGISTRY}:rocm-deps-cache-${CACHE_KEY}"
|
||||
IMAGE_REF="${REGISTRY}:${BUILDKITE_COMMIT}"
|
||||
|
||||
echo "ROCm dependency cache: ${CACHE_REF}"
|
||||
echo "ROCm CI image: ${IMAGE_REF}"
|
||||
|
||||
# The docker-container driver supports exporting the full cache to a registry;
|
||||
# the default docker driver on CI does not.
|
||||
if ! docker buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then
|
||||
docker buildx create --name "$BUILDER_NAME" --driver docker-container
|
||||
fi
|
||||
docker buildx use "$BUILDER_NAME"
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
docker buildx build --push --pull --progress=plain \
|
||||
--target test \
|
||||
--build-arg "ARG_PYTORCH_ROCM_ARCH=${ROCM_ARCH}" \
|
||||
--cache-from "type=registry,ref=${CACHE_REF}" \
|
||||
--cache-to "type=registry,ref=${CACHE_REF},mode=max,compression=zstd,ignore-error=true" \
|
||||
--file "$DOCKERFILE" \
|
||||
--tag "$IMAGE_REF" .
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run vLLM-Omni ROCm tests directly in the MI300 Kubernetes pod. The pod's
|
||||
# container image is selected by test-template-amd-omni.j2; MI300 has no DinD.
|
||||
set -euo pipefail
|
||||
|
||||
: "${PYTHONFAULTHANDLER:=1}"
|
||||
: "${HF_HOME:=/home/buildkite-agent/huggingface}"
|
||||
: "${HF_HUB_DOWNLOAD_TIMEOUT:=300}"
|
||||
: "${HF_HUB_ETAG_TIMEOUT:=60}"
|
||||
: "${MIOPEN_DEBUG_CONV_DIRECT:=0}"
|
||||
: "${MIOPEN_DEBUG_CONV_GEMM:=0}"
|
||||
: "${VLLM_ROCM_USE_AITER:=0}"
|
||||
export PYTHONFAULTHANDLER HF_HOME HF_HUB_DOWNLOAD_TIMEOUT HF_HUB_ETAG_TIMEOUT
|
||||
export MIOPEN_DEBUG_CONV_DIRECT MIOPEN_DEBUG_CONV_GEMM VLLM_ROCM_USE_AITER
|
||||
export PYTORCH_ROCM_ARCH=""
|
||||
export PYTHONPATH="${PYTHONPATH:-..}"
|
||||
|
||||
if [[ "${VLLM_CI_DOCKER_DISABLED:-0}" != "1" ]]; then
|
||||
echo "Error: MI300 CI must run natively with Docker disabled." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "${TEST_COMMANDS:-}" ]]; then
|
||||
commands="${TEST_COMMANDS}"
|
||||
else
|
||||
commands="$*"
|
||||
fi
|
||||
if [[ -z "${commands}" ]]; then
|
||||
echo "Error: No test commands provided." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "--- Native in-pod ROCm CI"
|
||||
|
||||
job_id="${BUILDKITE_JOB_ID:-${BUILDKITE_PARALLEL_JOB:-local}}"
|
||||
job_id="${job_id//[^A-Za-z0-9_.-]/_}"
|
||||
native_cache_root="/tmp/vllm-omni-native-${job_id}"
|
||||
TMPDIR="${native_cache_root}/tmp"
|
||||
TORCHINDUCTOR_CACHE_DIR="${native_cache_root}/torchinductor"
|
||||
TRITON_CACHE_DIR="${native_cache_root}/triton"
|
||||
VLLM_CACHE_ROOT="${native_cache_root}/vllm"
|
||||
XDG_CACHE_HOME="${native_cache_root}/xdg"
|
||||
HF_DATASETS_CACHE="${native_cache_root}/huggingface/datasets"
|
||||
export TMPDIR TORCHINDUCTOR_CACHE_DIR TRITON_CACHE_DIR VLLM_CACHE_ROOT
|
||||
export XDG_CACHE_HOME HF_DATASETS_CACHE
|
||||
mkdir -p "${TMPDIR}" "${TORCHINDUCTOR_CACHE_DIR}" "${TRITON_CACHE_DIR}" \
|
||||
"${VLLM_CACHE_ROOT}" "${XDG_CACHE_HOME}" "${HF_HOME}" \
|
||||
"${HF_DATASETS_CACHE}"
|
||||
|
||||
if [[ "${VLLM_CI_REQUIRE_PERSISTENT_HF_CACHE:-0}" == "1" ]]; then
|
||||
if ! command -v findmnt >/dev/null 2>&1; then
|
||||
echo "Error: findmnt is required to verify the Hugging Face cache mount." >&2
|
||||
exit 1
|
||||
fi
|
||||
hf_mount=$(findmnt -n -T "${HF_HOME}" -o TARGET 2>/dev/null || true)
|
||||
if [[ -z "${hf_mount}" || "${hf_mount}" == "/" ]]; then
|
||||
echo "Error: MI300 CI requires a persistent volume at or above ${HF_HOME}." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
rocminfo
|
||||
|
||||
expected_gpus="${VLLM_CI_EXPECTED_GPU_COUNT:-1}"
|
||||
python3 - <<'PY'
|
||||
import os
|
||||
|
||||
import torch
|
||||
|
||||
expected = int(os.environ.get("VLLM_CI_EXPECTED_GPU_COUNT", "1"))
|
||||
assert torch.version.hip, "PyTorch is not a ROCm build"
|
||||
assert torch.cuda.is_available(), "ROCm GPU is not available to PyTorch"
|
||||
actual = torch.cuda.device_count()
|
||||
assert actual == expected, f"Expected {expected} ROCm GPU(s), found {actual}"
|
||||
PY
|
||||
|
||||
echo "Commands:${commands}"
|
||||
if /bin/bash -o pipefail -c '
|
||||
set -E
|
||||
test_status=0
|
||||
trap '\''
|
||||
command_status=$?
|
||||
# Keep running subsequent commands, but retain a failure for the final exit.
|
||||
# Prefer a test failure over pytest "no tests collected" when both occur.
|
||||
if (( test_status == 0 || (test_status == 5 && command_status != 5) )); then
|
||||
test_status=${command_status}
|
||||
fi
|
||||
'\'' ERR
|
||||
eval "$1"
|
||||
exit "${test_status}"
|
||||
' _ "${commands}"; then
|
||||
exit 0
|
||||
else
|
||||
exit_code=$?
|
||||
fi
|
||||
|
||||
if [[ ${exit_code} -eq 5 && "${VLLM_CI_ALLOW_NO_TESTS:-0}" == "1" ]]; then
|
||||
echo "Pytest collected no tests; VLLM_CI_ALLOW_NO_TESTS=1, treating exit code 5 as success."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit "${exit_code}"
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Select AMD ready/merge/nightly suites after Buildkite creates a build.
|
||||
|
||||
This repository-side selector does not decide which GitHub label events start
|
||||
the external ``vllm-omni-amd-ci`` pipeline. Its Buildkite PR build condition
|
||||
must admit the relevant label event before this code can inspect the labels.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from collections.abc import Iterable
|
||||
|
||||
SUITE_SPECS = {
|
||||
"ready": "READY_TESTS:test-amd-ready.yml",
|
||||
"merge": "MERGE_TESTS:test-amd-merge.yml",
|
||||
"nightly": "NIGHTLY_TESTS:test-amd-nightly.yml",
|
||||
}
|
||||
|
||||
|
||||
def _parse_debug_suites(value: str) -> tuple[str, ...]:
|
||||
suites = tuple(item.strip().lower() for item in value.split(",") if item.strip())
|
||||
if not suites:
|
||||
raise ValueError("DEBUG_TEST_YAML did not contain a test suite")
|
||||
|
||||
seen: set[str] = set()
|
||||
for suite in suites:
|
||||
if suite not in SUITE_SPECS:
|
||||
raise ValueError(f"DEBUG_TEST_YAML entries must be 'merge', 'nightly', or 'ready', got {suite!r}")
|
||||
if suite in seen:
|
||||
raise ValueError(f"duplicate DEBUG_TEST_YAML suite {suite!r}")
|
||||
seen.add(suite)
|
||||
return suites
|
||||
|
||||
|
||||
def select_amd_test_suites(
|
||||
*,
|
||||
branch: str,
|
||||
labels: Iterable[str],
|
||||
debug_test_yaml: str = "",
|
||||
nightly: bool = False,
|
||||
) -> tuple[str, ...]:
|
||||
"""Return ordered suite names while preserving legacy unlabeled PRs."""
|
||||
|
||||
if debug_test_yaml:
|
||||
return _parse_debug_suites(debug_test_yaml)
|
||||
if branch == "main":
|
||||
return ("nightly",) if nightly else ("merge",)
|
||||
|
||||
label_set = {label.strip() for label in labels if label.strip()}
|
||||
selected = tuple(
|
||||
suite
|
||||
for label, suite in (
|
||||
("ready", "ready"),
|
||||
("merge-test", "merge"),
|
||||
("nightly-test", "nightly"),
|
||||
)
|
||||
if label in label_set
|
||||
)
|
||||
# AMD historically uploaded the ready suite for every admitted PR build.
|
||||
# Preserve that fallback when no explicit tier label is present.
|
||||
return selected or ("ready",)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--branch", required=True)
|
||||
parser.add_argument("--labels", default="")
|
||||
parser.add_argument("--debug-test-yaml", default="")
|
||||
parser.add_argument("--nightly", type=int, choices=(0, 1), default=0)
|
||||
args = parser.parse_args()
|
||||
|
||||
labels = tuple(args.labels.splitlines())
|
||||
try:
|
||||
suites = select_amd_test_suites(
|
||||
branch=args.branch,
|
||||
labels=labels,
|
||||
debug_test_yaml=args.debug_test_yaml,
|
||||
nightly=bool(args.nightly),
|
||||
)
|
||||
except ValueError as exc:
|
||||
parser.error(str(exc))
|
||||
|
||||
label_set = {label.strip() for label in labels if label.strip()}
|
||||
if args.branch != "main" and not args.debug_test_yaml and not ({"ready", "merge-test", "nightly-test"} & label_set):
|
||||
print(
|
||||
"No AMD ready/merge/nightly label found; preserving the legacy ready-suite fallback.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
for suite in suites:
|
||||
print(SUITE_SPECS[suite])
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -7,80 +7,133 @@ steps:
|
||||
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
steps:
|
||||
- label: "Simple · Diffusion & Model Executor Test"
|
||||
agent_pool: mi325_1
|
||||
- label: "Simple · Model Executor Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 3
|
||||
depends_on: amd-build
|
||||
timeout_in_minutes: 50
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "timeout 40m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu and not omni' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Omni Processor Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- "pytest -sv tests/model_executor/models/test_omni_processing.py -m 'core_model and cpu and omni'"
|
||||
|
||||
- label: "Simple · Diffusion Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 4
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 45
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "pytest -sv tests/diffusion -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- "pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu'"
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
timeout_in_minutes: 50
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "timeout 40m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine --ignore=tests/diffusion/cache/test_teacache_extractors.py"
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
steps:
|
||||
- label: "Diffusion · LoRA Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
artifact_paths:
|
||||
- lora-server.log
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/diffusion/lora/test_images_generations_lora.py
|
||||
- pytest -sv tests/diffusion/lora/ -m 'advanced_model and cuda' --run-level "advanced_model" 2>&1 | tee lora-server.log
|
||||
|
||||
- label: "Diffusion Model CPU offloading Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- |
|
||||
timeout 20m bash -c '
|
||||
set +e
|
||||
pytest -s -v tests/diffusion/offloader/test_diffusion_cpu_offload.py
|
||||
EXIT1=\$?
|
||||
pytest -s -v tests/diffusion/offloader/test_diffusion_layerwise_offload.py
|
||||
EXIT2=\$?
|
||||
exit \$((EXIT1 | EXIT2))
|
||||
'
|
||||
- pytest -s -v tests/diffusion/offloader/test_diffusion_cpu_offload.py
|
||||
- >-
|
||||
pytest -s -v tests/diffusion/offloader/test_diffusion_layerwise_offload.py
|
||||
--deselect='tests/diffusion/offloader/test_diffusion_layerwise_offload.py::test_layerwise_offload_diffusion_model[stabilityai/stable-audio-open-1.0]'
|
||||
|
||||
- label: "Diffusion Sequence Parallelism Test (Need 4 GPUs)"
|
||||
agent_pool: mi325_4
|
||||
# TODO: Diagnose unstable Stable Audio layerwise-offload memory savings on ROCm.
|
||||
- label: "Diffusion Stable Audio Layerwise Offload Test (quarantined)"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- >-
|
||||
pytest -s -v
|
||||
'tests/diffusion/offloader/test_diffusion_layerwise_offload.py::test_layerwise_offload_diffusion_model[stabilityai/stable-audio-open-1.0]'
|
||||
|
||||
- label: "Diffusion Sequence Parallelism Test (Need 4 GPUs) · Shard 1/2"
|
||||
agent_pool: mi300_4
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
timeout_in_minutes: 40
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- timeout 20m pytest -s -v tests/diffusion/distributed/test_sequence_parallel.py
|
||||
- timeout 20m pytest -s -v tests/diffusion/distributed/test_ulysses_uaa_perf.py
|
||||
- pytest -s -v tests/diffusion/distributed/test_sequence_parallel.py
|
||||
|
||||
- label: "Diffusion Sequence Parallelism Test (Need 4 GPUs) · Shard 2/2"
|
||||
agent_pool: mi300_4
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
timeout_in_minutes: 40
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/diffusion/distributed/test_ulysses_uaa_perf.py
|
||||
|
||||
# merge-only tests
|
||||
- label: "Diffusion Tensor Parallelism Test"
|
||||
agent_pool: mi325_2
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- pytest -s -v tests/diffusion/distributed/test_zimage_parallelism.py
|
||||
- pytest -s -v tests/diffusion/distributed/test_tensor_parallel.py
|
||||
|
||||
- label: "Diffusion Model Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -88,7 +141,7 @@ steps:
|
||||
- timeout 30m pytest -s -v tests/e2e/offline_inference/test_z_image.py
|
||||
|
||||
- label: "Diffusion GPU Worker Test"
|
||||
agent_pool: mi325_2
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -96,7 +149,7 @@ steps:
|
||||
- timeout 20m pytest -s -v tests/diffusion/test_diffusion_worker.py
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -109,7 +162,7 @@ steps:
|
||||
|
||||
## ISSUE depends on `diffusers` package: https://github.com/huggingface/diffusers/issues/13274
|
||||
# - label: "Audio Generation Model Test"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -120,7 +173,7 @@ steps:
|
||||
# - timeout 20m pytest -s -v tests/e2e/offline_inference/test_stable_audio_expansion.py -m "advanced_model and diffusion and L4" --run-level advanced_model
|
||||
|
||||
- label: "Engine Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -135,7 +188,7 @@ steps:
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
steps:
|
||||
- label: "Omni Model Test Qwen2-5-Omni"
|
||||
agent_pool: mi325_4
|
||||
agent_pool: mi300_4
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
commands:
|
||||
@@ -143,60 +196,70 @@ steps:
|
||||
- pytest -s -v tests/e2e/*/test_qwen2_5_omni_expansion.py --run-level "core_model"
|
||||
|
||||
- label: "Omni Model Test Qwen3-Omni"
|
||||
agent_pool: mi325_2
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py tests/e2e/online_serving/test_qwen3_omni.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py tests/e2e/online_serving/test_qwen3_omni.py tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
|
||||
- label: "Qwen3-TTS CustomVoice E2E Test"
|
||||
agent_pool: mi325_1
|
||||
- label: "Qwen3-TTS CustomVoice E2E Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 3
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 80
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c '
|
||||
timeout --signal=TERM --kill-after=2m 80m bash -c '
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py tests/e2e/offline_inference/test_qwen3_tts_customvoice.py -m "advanced_model" --run-level "advanced_model"
|
||||
TESTS=(
|
||||
"tests/e2e/online_serving/test_qwen3_tts_customvoice.py::test_default_cuda_graph_startup[async_chunk]"
|
||||
"tests/e2e/online_serving/test_qwen3_tts_customvoice.py::test_text_to_audio_002[async_chunk]"
|
||||
"tests/e2e/offline_inference/test_qwen3_tts_customvoice.py::test_text_to_audio_001[no_cuda_graph]"
|
||||
)
|
||||
TEST="$${TESTS[$$BUILDKITE_PARALLEL_JOB]}"
|
||||
pytest -s -v "$$TEST" -m "advanced_model" --run-level "advanced_model"
|
||||
'
|
||||
|
||||
# TODO: Restore this case to the blocking sharded step once its long-running
|
||||
# Whisper validation on AMD CI is resolved.
|
||||
- label: "Qwen3-TTS CustomVoice async_chunk Test (quarantined)"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 80
|
||||
commands:
|
||||
- |
|
||||
timeout --signal=TERM --kill-after=2m 75m bash -c '
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
pytest -s -v "tests/e2e/online_serving/test_qwen3_tts_customvoice.py::test_text_to_audio_001[async_chunk]" -m "advanced_model" --run-level "advanced_model"
|
||||
'
|
||||
|
||||
- label: "Qwen3-TTS Base E2E Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c '
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_base.py tests/e2e/offline_inference/test_qwen3_tts_base.py -m "advanced_model" --run-level "advanced_model"
|
||||
'
|
||||
|
||||
- label: "Voxtral-TTS E2E Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c '
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -s -v tests/e2e/online_serving/test_voxtral_tts.py tests/e2e/offline_inference/test_voxtral_tts.py -m "advanced_model" --run-level "advanced_model"
|
||||
'
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- timeout 40m pytest -s -v tests/e2e/online_serving/test_qwen3_tts_base.py tests/e2e/offline_inference/test_qwen3_tts_base.py -m "advanced_model and cuda" --run-level "advanced_model"
|
||||
|
||||
# TODO: Bagel test on ROCm is very unstable. @tjtanaa
|
||||
# Need to debug before reneable numerical changes across large PRs
|
||||
# # split Bagel Model Test with H100 (Real Weights) into three tests
|
||||
# - label: "Bagel Text2Img Model Test (1/3)"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -208,7 +271,7 @@ steps:
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "advanced_model" --run-level "advanced_model" -k "shared_memory" -k "rocm"
|
||||
|
||||
# - label: "Bagel Img2Img Model Test (2/3)"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -220,7 +283,7 @@ steps:
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "advanced_model" --run-level "advanced_model" -k "rocm"
|
||||
|
||||
# - label: "Bagel Online Serving Test (3/3)"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -0,0 +1,84 @@
|
||||
# AMD MI300 `full_model` nightly coverage during burn-in.
|
||||
# All jobs are non-blocking until the lane has stable runtime evidence.
|
||||
# Historical build #11646 was red in Function Expansion and Accuracy (one
|
||||
# async_chunk similarity mismatch; Seed-TTS WER 0.376480 > 0.35).
|
||||
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
# MI325 is the repository's legacy ROCm pytest marker. The AMD template maps
|
||||
# agent_pool to the current MI300 Buildkite queues independently of that mark.
|
||||
- group: ":full_moon: Qwen3-Omni MI300 Nightly"
|
||||
steps:
|
||||
- label: "Qwen3-Omni Function Expansion"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni_expansion.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model"
|
||||
|
||||
- label: "Qwen3-Omni Accuracy"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json
|
||||
commands:
|
||||
- export SEED_TTS_WER_EVAL=1
|
||||
# PyTorch ROCm uses the torch.cuda device namespace.
|
||||
- export SEED_TTS_EVAL_DEVICE=cuda:1
|
||||
- pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model"
|
||||
# Native tests run from the image copy under /app/vllm-omni, while
|
||||
# Buildkite's artifact hook searches the checkout workspace.
|
||||
- |
|
||||
if [[ "$$PWD" != "$${BUILDKITE_BUILD_CHECKOUT_PATH:?}" ]]; then
|
||||
artifact_dir="$${BUILDKITE_BUILD_CHECKOUT_PATH}/tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc"
|
||||
mkdir -p "$$artifact_dir"
|
||||
cp -v tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json "$$artifact_dir/"
|
||||
fi
|
||||
|
||||
- label: "Qwen3-Omni Documentation Examples"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/examples/online_serving/test_qwen3_omni.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model"
|
||||
|
||||
- label: "Qwen3-Omni AITER-on Smoke"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=1
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni_expansion.py::test_text_to_text_audio_001 -m "full_model and rocm and MI325 and cards_2" --run-level "full_model"
|
||||
|
||||
- group: ":speaker: CosyVoice3 MI300 Nightly"
|
||||
steps:
|
||||
# Exercise all sync/async and Chinese/English cases with the platform's
|
||||
# default attention backend. On ROCm this retains end-to-end AITER
|
||||
# coverage without putting its cold JIT build on the READY critical path.
|
||||
- label: "CosyVoice3-TTS E2E Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 90
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: 134
|
||||
limit: 1
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_cosyvoice3_tts_expansion.py -m "slow" --run-level "core_model"
|
||||
@@ -0,0 +1,386 @@
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
steps:
|
||||
- label: "Simple · Model Executor Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 3
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu and not omni' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Omni Processor Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- "pytest -sv tests/model_executor/models/test_omni_processing.py -m 'core_model and cpu and omni'"
|
||||
|
||||
- label: "Simple · Diffusion Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 4
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
timeout_in_minutes: 45
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "pytest -sv tests/diffusion -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- "pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu'"
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine --ignore=tests/diffusion/cache/test_teacache_extractors.py"
|
||||
|
||||
- label: "Custom Pipeline Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/features/custom_pipeline/ -m "core_model"
|
||||
|
||||
|
||||
- label: "Voxtral TTS CUDA Unit Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 10m pytest -s -v tests/model_executor/models/voxtral_tts/test_cuda_graph_acoustic_transformer.py
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
steps:
|
||||
# Keep real FlashAttention execution out of the CPU-marked Simple lane.
|
||||
# AITER may need to build several kernels on a cold worker, so run one
|
||||
# pytest worker with job-local build directories and a bounded timeout.
|
||||
- label: "ROCm · FlashAttention/AITER GPU Coverage"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=1
|
||||
- export AITER_JIT_DIR="/tmp/vllm-omni-aiter-$$BUILDKITE_JOB_ID"
|
||||
- export TORCH_EXTENSIONS_DIR="/tmp/vllm-omni-torch-extensions-$$BUILDKITE_JOB_ID"
|
||||
- mkdir -p "$$AITER_JIT_DIR" "$$TORCH_EXTENSIONS_DIR"
|
||||
- >-
|
||||
timeout --signal=TERM --kill-after=2m 55m
|
||||
pytest -s -v -n 1
|
||||
tests/diffusion/attention/
|
||||
-m 'core_model and rocm and MI325 and cards_1'
|
||||
--run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Batch Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/batching -m 'core_model and cuda' --run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Offloader Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/diffusion/offloader -m "core_model and cuda" --run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Cache Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -sv tests/diffusion/cache -m 'core_model and cuda' --run-level "core_model"
|
||||
|
||||
- label: "Diffusion Sequence Parallelism Test"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- timeout 20m pytest -s -v tests/diffusion/distributed/test_sequence_parallel.py -m core_model
|
||||
- >-
|
||||
timeout 20m pytest -s -v
|
||||
tests/diffusion/models/ltx2/test_ltx2_transformer_ulysses.py
|
||||
-m 'core_model and rocm and cards_2'
|
||||
--run-level "core_model"
|
||||
|
||||
- label: "Diffusion GPU Worker Test"
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/diffusion/test_diffusion_worker.py
|
||||
|
||||
- label: "Diffusion · Model Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
# Preserve legacy one-GPU tests without cards_1 while excluding every
|
||||
# registered multi-GPU marker from this one-GPU job.
|
||||
- >-
|
||||
timeout 15m pytest -sv tests/diffusion/models/
|
||||
-m 'core_model and cuda and not
|
||||
(cards_2 or cards_3 or cards_4 or cards_5 or cards_6 or cards_7 or cards_8)'
|
||||
--run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_TEST_CLEAN_GPU_MEMORY=1
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_wan22_t2v.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
|
||||
## ISSUE depends on `diffusers` package: https://github.com/huggingface/diffusers/issues/13274
|
||||
# - label: "Audio Generation Model Test"
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export GPU_ARCHS=gfx942
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - timeout 20m pytest -s -v tests/e2e/offline_inference/test_stable_audio_expansion.py -m "advanced_model and diffusion and L4" --run-level advanced_model
|
||||
|
||||
- label: "ROCm · Engine & Model Executor GPU Coverage (R2-01)"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 20
|
||||
artifact_paths:
|
||||
- "artifacts/rocm-r2-01/**/*"
|
||||
commands:
|
||||
# Native AMD tests run from /app/vllm-omni, while Buildkite uploads
|
||||
# artifacts relative to its checkout directory.
|
||||
- export R2_01_ARTIFACT_DIR="$$BUILDKITE_BUILD_CHECKOUT_PATH/artifacts/rocm-r2-01"
|
||||
- mkdir -p "$$R2_01_ARTIFACT_DIR"
|
||||
# The CUDA ready job also covers tests/worker/test_batched_omni_output.py.
|
||||
# Keep the initial ROCm burn-in scoped to the requested directories.
|
||||
# Verbose pytest output and JUnit retain node IDs without a second
|
||||
# collection-only pass over the same GPU-backed test tree.
|
||||
# The CUDA/L4-only CosyVoice3 ragged-flow parity test cold-JITs multiple
|
||||
# AITER kernels on ROCm and is covered by the CUDA ready lane.
|
||||
- >-
|
||||
pytest -s -v -ra
|
||||
tests/engine/ tests/model_executor/
|
||||
-m 'core_model and cuda and not
|
||||
(cards_2 or cards_3 or cards_4 or cards_5 or cards_6 or cards_7 or cards_8)'
|
||||
-k 'not test_code2wav_streaming_batch_matches_ragged_flow_numerics'
|
||||
--run-level "core_model"
|
||||
--durations=0
|
||||
--junitxml="$$R2_01_ARTIFACT_DIR/pytest.xml"
|
||||
2>&1 | tee "$$R2_01_ARTIFACT_DIR/pytest.log"
|
||||
- >-
|
||||
tail -n 100 "$$R2_01_ARTIFACT_DIR/pytest.log" >
|
||||
"$$R2_01_ARTIFACT_DIR/pytest-summary.txt"
|
||||
|
||||
- label: "Engine Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- |
|
||||
timeout 15m bash -c '
|
||||
pytest -s -v tests/engine/test_async_omni_engine_abort.py
|
||||
'
|
||||
|
||||
- label: "ROCm · Entrypoints GPU Coverage (R2-02)"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: NonBlocking
|
||||
timeout_in_minutes: 30
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
artifact_paths:
|
||||
- "artifacts/rocm-r2-02/**/*"
|
||||
commands:
|
||||
# Native AMD tests run from /app/vllm-omni, while Buildkite uploads
|
||||
# artifacts relative to its checkout directory.
|
||||
- export R2_02_ARTIFACT_DIR="$$BUILDKITE_BUILD_CHECKOUT_PATH/artifacts/rocm-r2-02"
|
||||
- mkdir -p "$$R2_02_ARTIFACT_DIR"
|
||||
- >-
|
||||
ps -eo pid=,ppid=,lstart=,stat=,comm= >
|
||||
"$$R2_02_ARTIFACT_DIR/processes-before.txt"
|
||||
# Verbose pytest output and JUnit retain selected node IDs without a
|
||||
# second collection-only pass over the same GPU-backed test tree.
|
||||
# The inner timeout leaves five minutes for teardown verification and
|
||||
# artifact generation before the Buildkite step timeout.
|
||||
- >-
|
||||
timeout --signal=TERM --kill-after=1m 25m
|
||||
pytest -s -v -ra
|
||||
tests/entrypoints/
|
||||
-m 'core_model and cuda and not
|
||||
(cards_2 or cards_3 or cards_4 or cards_5 or cards_6 or cards_7 or cards_8)'
|
||||
--run-level "core_model"
|
||||
--durations=0
|
||||
--junitxml="$$R2_02_ARTIFACT_DIR/pytest.xml"
|
||||
2>&1 | tee "$$R2_02_ARTIFACT_DIR/pytest.log"
|
||||
- >-
|
||||
tail -n 100 "$$R2_02_ARTIFACT_DIR/pytest.log" >
|
||||
"$$R2_02_ARTIFACT_DIR/pytest-summary.txt"
|
||||
- |
|
||||
sleep 5
|
||||
ps -eo pid=,ppid=,lstart=,stat=,comm= > "$$R2_02_ARTIFACT_DIR/processes-after.txt"
|
||||
# Compare PID plus process start time so PID reuse cannot hide a leak.
|
||||
# Double dollars preserve awk field references through Buildkite interpolation.
|
||||
awk '
|
||||
NR == FNR {
|
||||
if ($$9 != "ps") {
|
||||
baseline[$$1 "|" $$3 "|" $$4 "|" $$5 "|" $$6 "|" $$7] = 1
|
||||
}
|
||||
next
|
||||
}
|
||||
$$9 != "ps" {
|
||||
identity = $$1 "|" $$3 "|" $$4 "|" $$5 "|" $$6 "|" $$7
|
||||
if (!(identity in baseline)) {
|
||||
print
|
||||
leaked = 1
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (leaked) {
|
||||
print "status=FAIL leaked_processes_detected=1"
|
||||
exit 1
|
||||
}
|
||||
print "status=PASS leaked_processes=0"
|
||||
}
|
||||
' "$$R2_02_ARTIFACT_DIR/processes-before.txt" \
|
||||
"$$R2_02_ARTIFACT_DIR/processes-after.txt" \
|
||||
2>&1 | tee "$$R2_02_ARTIFACT_DIR/process-cleanup.txt"
|
||||
|
||||
# - label: "Omni Model Test Qwen3-Omni"
|
||||
# agent_pool: mi300_2
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - timeout 10m pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py
|
||||
# - timeout 20m pytest -s -v tests/e2e/online_serving/test_qwen3_omni.py -m "core_model" --run-level "core_model"
|
||||
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
steps:
|
||||
- label: "Qwen3-TTS E2E Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- timeout 30m pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py -m "core_model" --run-level "core_model"
|
||||
|
||||
# Keep a fast model/server integration check in the blocking lane. The
|
||||
# full default-backend suite remains in the nightly pipeline because a
|
||||
# cold ROCm AITER MHA build can add more than 25 minutes to this job.
|
||||
- label: "CosyVoice3-TTS E2E Smoke (SDPA)"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
# A ROCm hardware hang aborts the interpreter with 134. Let Buildkite
|
||||
# create one fresh pod instead of retrying on the poisoned GPU process.
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: 134
|
||||
limit: 1
|
||||
commands:
|
||||
- export DIFFUSION_ATTENTION_BACKEND=TORCH_SDPA
|
||||
- pytest -s -v tests/e2e/online_serving/test_cosyvoice3_tts_expansion.py::test_voice_clone_zh_002 -m "slow" --run-level "core_model"
|
||||
|
||||
# TODO: Bagel test on ROCm is very unstable. @tjtanaa
|
||||
# Need to debug before reneable numerical changes across large PRs
|
||||
# - label: "Bagel Text2Img Model Test"
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export GPU_ARCHS=gfx942
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - export VLLM_ROCM_USE_AITER_RMSNORM=0
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "core_model" --run-level "core_model" -k "rocm"
|
||||
|
||||
# - label: "Bagel Img2Img Model Test"
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export GPU_ARCHS=gfx942
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - export VLLM_ROCM_USE_AITER_RMSNORM=0
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "core_model" --run-level "core_model" -k "rocm"
|
||||
|
||||
# - label: "Bagel Online Serving Test"
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export GPU_ARCHS=gfx942
|
||||
# - export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - export VLLM_ROCM_USE_AITER_RMSNORM=0
|
||||
# - timeout 40m pytest -s -v tests/e2e/online_serving/test_bagel.py -m "core_model" --run-level "core_model" -k "rocm"
|
||||
@@ -0,0 +1,255 @@
|
||||
{# vllm-omni customized version
|
||||
Based on: https://github.com/vllm-project/ci-infra/blob/main/buildkite/test-template-amd.j2
|
||||
Last synced: 2026-08-04
|
||||
Modifications: Use the shared MI300 queues and Omni command-passing contract
|
||||
#}
|
||||
{% set docker_registry_amd = "rocm/vllm-omni" %}
|
||||
{% set docker_image_amd = docker_registry_amd ~ ":$BUILDKITE_COMMIT" %}
|
||||
{% set default_working_dir = "/app/vllm-omni" %}
|
||||
|
||||
{# MI300 runs tests natively in Kubernetes; Docker-in-Docker is unavailable. #}
|
||||
{% macro amd_native_k8s_plugin(indent, step) -%}
|
||||
{{ indent }}plugins:
|
||||
{{ indent }} - kubernetes:
|
||||
{{ indent }} podSpecPatch:
|
||||
{{ indent }} automountServiceAccountToken: false
|
||||
{{ indent }} securityContext:
|
||||
{{ indent }} seccompProfile:
|
||||
{{ indent }} type: RuntimeDefault
|
||||
{{ indent }} imagePullSecrets:
|
||||
{{ indent }} - name: docker-config
|
||||
{{ indent }} containers:
|
||||
{{ indent }} - name: container-0
|
||||
{{ indent }} image: {{ docker_image_amd }}
|
||||
{{ indent }} imagePullPolicy: Always
|
||||
{{ indent }} securityContext:
|
||||
{{ indent }} allowPrivilegeEscalation: false
|
||||
{{ indent }} capabilities:
|
||||
{{ indent }} add:
|
||||
{{ indent }} - IPC_LOCK
|
||||
{{ indent }} resources:
|
||||
{{ indent }} limits:
|
||||
{{ indent }} amd.com/gpu: "{{ step.agent_pool[-1:] }}"
|
||||
{{ indent }} requests:
|
||||
{{ indent }} amd.com/gpu: "{{ step.agent_pool[-1:] }}"
|
||||
{{ indent }} volumeMounts:
|
||||
{{ indent }} - name: devshm
|
||||
{{ indent }} mountPath: /dev/shm
|
||||
{{ indent }} env:
|
||||
{{ indent }} - name: AMD_CI_RUNTIME
|
||||
{{ indent }} value: native
|
||||
{{ indent }} - name: NATIVE_CI
|
||||
{{ indent }} value: "true"
|
||||
{{ indent }} - name: VLLM_CI_DOCKER_DISABLED
|
||||
{{ indent }} value: "1"
|
||||
{{ indent }} - name: VLLM_CI_EXPECTED_GPU_COUNT
|
||||
{{ indent }} value: "{{ step.agent_pool[-1:] }}"
|
||||
{{ indent }} - name: HF_HOME
|
||||
{{ indent }} value: /home/buildkite-agent/huggingface
|
||||
{{ indent }} - name: MIOPEN_DEBUG_CONV_DIRECT
|
||||
{{ indent }} value: "0"
|
||||
{{ indent }} - name: MIOPEN_DEBUG_CONV_GEMM
|
||||
{{ indent }} value: "0"
|
||||
{{ indent }} - name: VLLM_ROCM_USE_AITER
|
||||
{{ indent }} value: "0"
|
||||
{{ indent }} - name: PYTORCH_ROCM_ARCH
|
||||
{{ indent }} value: ""
|
||||
{{ indent }} volumes:
|
||||
{{ indent }} - name: devshm
|
||||
{{ indent }} emptyDir:
|
||||
{{ indent }} medium: Memory
|
||||
{{ indent }} sizeLimit: 16Gi
|
||||
{%- endmacro %}
|
||||
|
||||
{% if env %}
|
||||
env:
|
||||
{% for name in env %}
|
||||
{{ name }}: "{{ env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
steps:
|
||||
- group: "AMD Tests"
|
||||
depends_on: ~
|
||||
steps:
|
||||
- label: "AMD: :docker: build image"
|
||||
depends_on: ~
|
||||
soft_fail: false
|
||||
commands:
|
||||
- "bash .buildkite/amd/scripts/build-ci-image.sh"
|
||||
key: "amd-build"
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
PYTORCH_ROCM_ARCH: "gfx942"
|
||||
ROCM_CI_IMAGE_REGISTRY: "{{ docker_registry_amd }}"
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: -1 # Agent was lost
|
||||
limit: 2
|
||||
- exit_status: -10 # Agent was lost
|
||||
limit: 2
|
||||
- exit_status: 128 # Git connectivity issues
|
||||
limit: 2
|
||||
- exit_status: 1 # Machine occasionally fail
|
||||
limit: 1
|
||||
agents:
|
||||
queue: amd-cpu
|
||||
|
||||
{% for step_group in steps %}
|
||||
{% if step_group.group %}
|
||||
- group: "{{ step_group.group }}"
|
||||
{% if step_group.depends_on %}
|
||||
depends_on: {{ step_group.depends_on }}
|
||||
{% endif %}
|
||||
steps:
|
||||
{% for step in step_group.steps %}
|
||||
{% if step.mirror_hardwares and mirror_hw in step.mirror_hardwares %}
|
||||
- label: "{{ step.agent_pool }}: {{ step.label }}"
|
||||
depends_on: amd-build
|
||||
agents:
|
||||
{% if step.agent_pool %}
|
||||
queue: amd_{{ step.agent_pool }}
|
||||
{% else %}
|
||||
queue: amd_mi300_1
|
||||
{% endif %}
|
||||
{{ amd_native_k8s_plugin(" ", step) }}
|
||||
{% set cmd_body = (step.command or (step.commands | join("\n"))) | trim %}
|
||||
{% set indented_cmd = cmd_body | replace("\n", "\n ") %}
|
||||
command: bash .buildkite/amd/scripts/run-amd-test.sh
|
||||
env:
|
||||
AMD_CI_RUNTIME: "native"
|
||||
NATIVE_CI: "true"
|
||||
VLLM_CI_DOCKER_DISABLED: "1"
|
||||
VLLM_CI_EXPECTED_GPU_COUNT: "{{ step.agent_pool[-1:] }}"
|
||||
VLLM_CI_REQUIRE_PERSISTENT_HF_CACHE: "1"
|
||||
HF_HOME: "/home/buildkite-agent/huggingface"
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: "300"
|
||||
HF_HUB_ETAG_TIMEOUT: "60"
|
||||
MIOPEN_DEBUG_CONV_DIRECT: "0"
|
||||
MIOPEN_DEBUG_CONV_GEMM: "0"
|
||||
VLLM_ROCM_USE_AITER: "0"
|
||||
PYTORCH_ROCM_ARCH: ""
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
{{ name }}: "{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
TEST_COMMANDS: |-
|
||||
(command rocm-smi || true) && cd {{ (step.working_dir or default_working_dir) | safe }}
|
||||
{% if env %}
|
||||
{% for name in env %}
|
||||
export {{ name }}="{{ env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
export {{ name }}="{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if "mi250" in step.agent_pool %}
|
||||
python3 -m pip uninstall -y amd-aiter
|
||||
{% endif %}
|
||||
{{ indented_cmd | safe }}
|
||||
priority: 100
|
||||
{% if step.parallelism %}
|
||||
parallelism: {{ step.parallelism }}
|
||||
{% endif %}
|
||||
{% if step.artifact_paths %}
|
||||
artifact_paths:
|
||||
{% for path in step.artifact_paths %}
|
||||
- "{{ path }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.retry %}
|
||||
retry:
|
||||
automatic:
|
||||
{% for retry_rule in step.retry.automatic %}
|
||||
- exit_status: {{ retry_rule.exit_status }}
|
||||
limit: {{ retry_rule.limit }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.timeout_in_minutes %}
|
||||
timeout_in_minutes: {{ step.timeout_in_minutes }}
|
||||
{% endif %}
|
||||
{% if step.grade and step.grade == "Blocking" %}
|
||||
soft_fail: false
|
||||
{% else %}
|
||||
soft_fail: true
|
||||
{% endif%}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% elif step_group.mirror_hardwares and mirror_hw in step_group.mirror_hardwares %}
|
||||
{% set step = step_group %}
|
||||
- label: "{{ step.agent_pool }}: {{ step.label }}"
|
||||
depends_on: amd-build
|
||||
agents:
|
||||
{% if step.agent_pool %}
|
||||
queue: amd_{{ step.agent_pool }}
|
||||
{% else %}
|
||||
queue: amd_mi300_1
|
||||
{% endif %}
|
||||
{{ amd_native_k8s_plugin(" ", step) }}
|
||||
{% set cmd_body = (step.command or (step.commands | join("\n"))) | trim %}
|
||||
{% set indented_cmd = cmd_body | replace("\n", "\n ") %}
|
||||
command: bash .buildkite/amd/scripts/run-amd-test.sh
|
||||
env:
|
||||
AMD_CI_RUNTIME: "native"
|
||||
NATIVE_CI: "true"
|
||||
VLLM_CI_DOCKER_DISABLED: "1"
|
||||
VLLM_CI_EXPECTED_GPU_COUNT: "{{ step.agent_pool[-1:] }}"
|
||||
VLLM_CI_REQUIRE_PERSISTENT_HF_CACHE: "1"
|
||||
HF_HOME: "/home/buildkite-agent/huggingface"
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: "300"
|
||||
HF_HUB_ETAG_TIMEOUT: "60"
|
||||
MIOPEN_DEBUG_CONV_DIRECT: "0"
|
||||
MIOPEN_DEBUG_CONV_GEMM: "0"
|
||||
VLLM_ROCM_USE_AITER: "0"
|
||||
PYTORCH_ROCM_ARCH: ""
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
{{ name }}: "{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
TEST_COMMANDS: |-
|
||||
(command rocm-smi || true) && cd {{ (step.working_dir or default_working_dir) | safe }}
|
||||
{% if env %}
|
||||
{% for name in env %}
|
||||
export {{ name }}="{{ env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
export {{ name }}="{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if "mi250" in step.agent_pool %}
|
||||
python3 -m pip uninstall -y amd-aiter
|
||||
{% endif %}
|
||||
{{ indented_cmd | safe }}
|
||||
priority: 100
|
||||
{% if step.parallelism %}
|
||||
parallelism: {{ step.parallelism }}
|
||||
{% endif %}
|
||||
{% if step.artifact_paths %}
|
||||
artifact_paths:
|
||||
{% for path in step.artifact_paths %}
|
||||
- "{{ path }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.retry %}
|
||||
retry:
|
||||
automatic:
|
||||
{% for retry_rule in step.retry.automatic %}
|
||||
- exit_status: {{ retry_rule.exit_status }}
|
||||
limit: {{ retry_rule.limit }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.timeout_in_minutes %}
|
||||
timeout_in_minutes: {{ step.timeout_in_minutes }}
|
||||
{% endif %}
|
||||
{% if step.grade and step.grade == "Blocking" %}
|
||||
soft_fail: false
|
||||
{% else %}
|
||||
soft_fail: true
|
||||
{% endif%}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -1,327 +0,0 @@
|
||||
#!/bin/bash
|
||||
# vllm-omni customized version
|
||||
# Based on: https://github.com/vllm-project/ci-infra/blob/main/buildkite/bootstrap-amd.sh
|
||||
# Last synced: 2025-12-15
|
||||
# Modifications: Use local template file instead of downloading from ci-infra
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${RUN_ALL:-}" ]]; then
|
||||
RUN_ALL=0
|
||||
fi
|
||||
|
||||
if [[ -z "${NIGHTLY:-}" ]]; then
|
||||
NIGHTLY=0
|
||||
fi
|
||||
|
||||
if [[ -z "${VLLM_CI_BRANCH:-}" ]]; then
|
||||
VLLM_CI_BRANCH="main"
|
||||
fi
|
||||
|
||||
if [[ -z "${AMD_MIRROR_HW:-}" ]]; then
|
||||
AMD_MIRROR_HW="amdproduction"
|
||||
fi
|
||||
|
||||
if [[ -z "${DOCS_ONLY_DISABLE:-}" ]]; then
|
||||
DOCS_ONLY_DISABLE=0
|
||||
fi
|
||||
|
||||
fail_fast() {
|
||||
DISABLE_LABEL="ci-no-fail-fast"
|
||||
# If BUILDKITE_PULL_REQUEST != "false", then we check the PR labels using curl and jq
|
||||
if [ "$BUILDKITE_PULL_REQUEST" != "false" ]; then
|
||||
PR_LABELS=$(curl -s "https://api.github.com/repos/vllm-project/vllm-omni/pulls/$BUILDKITE_PULL_REQUEST" | jq -r '.labels[].name')
|
||||
if [[ $PR_LABELS == *"$DISABLE_LABEL"* ]]; then
|
||||
echo false
|
||||
else
|
||||
echo true
|
||||
fi
|
||||
else
|
||||
echo false # not a PR or BUILDKITE_PULL_REQUEST not set
|
||||
fi
|
||||
}
|
||||
|
||||
check_run_all_label() {
|
||||
RUN_ALL_LABEL="ready-run-all-tests"
|
||||
# If BUILDKITE_PULL_REQUEST != "false", then we check the PR labels using curl and jq
|
||||
if [ "$BUILDKITE_PULL_REQUEST" != "false" ]; then
|
||||
PR_LABELS=$(curl -s "https://api.github.com/repos/vllm-project/vllm-omni/pulls/$BUILDKITE_PULL_REQUEST" | jq -r '.labels[].name')
|
||||
if [[ $PR_LABELS == *"$RUN_ALL_LABEL"* ]]; then
|
||||
echo true
|
||||
else
|
||||
echo false
|
||||
fi
|
||||
else
|
||||
echo false # not a PR or BUILDKITE_PULL_REQUEST not set
|
||||
fi
|
||||
}
|
||||
|
||||
is_docs_only_change() {
|
||||
local file_path
|
||||
local has_any=0
|
||||
|
||||
while IFS= read -r file_path; do
|
||||
[[ -z "${file_path}" ]] && continue
|
||||
has_any=1
|
||||
|
||||
if [[ "${file_path}" == docs/* ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ "${file_path}" == *.md ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ "${file_path}" == "mkdocs.yml" ]]; then
|
||||
continue
|
||||
fi
|
||||
return 1
|
||||
done
|
||||
|
||||
[[ "${has_any}" -eq 1 ]]
|
||||
}
|
||||
|
||||
resolve_skip_ci() {
|
||||
local is_pr_build=0
|
||||
local files
|
||||
local base_branch base_ref
|
||||
|
||||
if [[ "${BUILDKITE_PULL_REQUEST:-false}" != "false" && -n "${BUILDKITE_PULL_REQUEST:-}" ]]; then
|
||||
is_pr_build=1
|
||||
fi
|
||||
|
||||
if [[ "${is_pr_build}" -eq 1 ]]; then
|
||||
base_branch="${BUILDKITE_PULL_REQUEST_BASE_BRANCH:-main}"
|
||||
if ! git rev-parse --verify "origin/${base_branch}" >/dev/null 2>&1; then
|
||||
echo "resolve_skip_ci: origin/${base_branch} not found locally; trying fetch" >&2
|
||||
git fetch --depth=200 origin "${base_branch}" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
base_ref=""
|
||||
if git rev-parse --verify "origin/${base_branch}" >/dev/null 2>&1; then
|
||||
base_ref="origin/${base_branch}"
|
||||
elif git rev-parse --verify "${base_branch}" >/dev/null 2>&1; then
|
||||
base_ref="${base_branch}"
|
||||
else
|
||||
echo "resolve_skip_ci: cannot resolve PR base ${base_branch}; skip-ci=0" >&2
|
||||
echo -n 0
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! files="$(git diff --name-only "${base_ref}...${BUILDKITE_COMMIT}" 2>/dev/null)"; then
|
||||
echo "resolve_skip_ci: failed to compute PR changed files; skip-ci=0" >&2
|
||||
echo -n 0
|
||||
return 0
|
||||
fi
|
||||
elif [[ "${BUILDKITE_BRANCH:-}" == "main" ]]; then
|
||||
if ! git rev-parse --verify "${BUILDKITE_COMMIT}^" >/dev/null 2>&1; then
|
||||
echo "resolve_skip_ci: commit has no parent on main; skip-ci=0" >&2
|
||||
echo -n 0
|
||||
return 0
|
||||
fi
|
||||
if ! files="$(git diff --name-only "${BUILDKITE_COMMIT}^..${BUILDKITE_COMMIT}" 2>/dev/null)"; then
|
||||
echo "resolve_skip_ci: failed to compute main changed files; skip-ci=0" >&2
|
||||
echo -n 0
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
echo "resolve_skip_ci: not PR/main build; skip-ci=0" >&2
|
||||
echo -n 0
|
||||
return 0
|
||||
fi
|
||||
|
||||
if is_docs_only_change <<< "${files}"; then
|
||||
echo "resolve_skip_ci: docs-only change detected; skip-ci=1" >&2
|
||||
echo -n 1
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "resolve_skip_ci: non-doc changes detected; skip-ci=0" >&2
|
||||
echo -n 0
|
||||
}
|
||||
|
||||
if [[ -z "${COV_ENABLED:-}" ]]; then
|
||||
COV_ENABLED=0
|
||||
fi
|
||||
|
||||
upload_pipeline() {
|
||||
echo "Uploading pipeline..."
|
||||
# Install minijinja
|
||||
ls .buildkite || buildkite-agent annotate --style error 'Please merge upstream main branch for buildkite CI'
|
||||
curl -sSfL https://github.com/mitsuhiko/minijinja/releases/download/2.3.1/minijinja-cli-installer.sh | sh
|
||||
source /var/lib/buildkite-agent/.cargo/env
|
||||
|
||||
if [[ $BUILDKITE_PIPELINE_SLUG == "fastcheck" ]]; then
|
||||
AMD_MIRROR_HW="amdtentative"
|
||||
fi
|
||||
|
||||
# Use local template file for vllm-omni
|
||||
cp .buildkite/test-template-amd-omni.j2 .buildkite/test-template.j2
|
||||
|
||||
|
||||
# (WIP) Use pipeline generator instead of jinja template
|
||||
if [ -e ".buildkite/pipeline_generator/pipeline_generator.py" ]; then
|
||||
python -m pip install click pydantic
|
||||
python .buildkite/pipeline_generator/pipeline_generator.py --run_all=$RUN_ALL --list_file_diff="$LIST_FILE_DIFF" --nightly="$NIGHTLY" --mirror_hw="$AMD_MIRROR_HW"
|
||||
buildkite-agent pipeline upload .buildkite/pipeline.yaml
|
||||
exit 0
|
||||
fi
|
||||
echo "List file diff: $LIST_FILE_DIFF"
|
||||
echo "Run all: $RUN_ALL"
|
||||
echo "Nightly: $NIGHTLY"
|
||||
echo "AMD Mirror HW: $AMD_MIRROR_HW"
|
||||
|
||||
FAIL_FAST=$(fail_fast)
|
||||
|
||||
cd .buildkite
|
||||
|
||||
# Select test definition file: merge suite for main, ready suite for PRs.
|
||||
# For debugging, DEBUG_TEST_YAML can override the selection — accepts
|
||||
# "merge" or "ready" (case-insensitive).
|
||||
if [[ -n "${DEBUG_TEST_YAML:-}" ]]; then
|
||||
case "${DEBUG_TEST_YAML,,}" in
|
||||
merge)
|
||||
TEST_YAML="test-amd-merge.yml"
|
||||
;;
|
||||
ready)
|
||||
TEST_YAML="test-amd-ready.yaml"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: DEBUG_TEST_YAML must be 'merge' or 'ready', got '$DEBUG_TEST_YAML'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
echo "DEBUG_TEST_YAML override: using $TEST_YAML"
|
||||
elif [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||
TEST_YAML="test-amd-merge.yml"
|
||||
else
|
||||
TEST_YAML="test-amd-ready.yaml"
|
||||
fi
|
||||
|
||||
(
|
||||
set -x
|
||||
# Output pipeline.yaml with all blank lines removed
|
||||
minijinja-cli test-template.j2 "$TEST_YAML" \
|
||||
-D branch="$BUILDKITE_BRANCH" \
|
||||
-D list_file_diff="$LIST_FILE_DIFF" \
|
||||
-D run_all="$RUN_ALL" \
|
||||
-D nightly="$NIGHTLY" \
|
||||
-D mirror_hw="$AMD_MIRROR_HW" \
|
||||
-D fail_fast="$FAIL_FAST" \
|
||||
-D vllm_use_precompiled="$VLLM_USE_PRECOMPILED" \
|
||||
-D vllm_merge_base_commit="$(git merge-base origin/main HEAD)" \
|
||||
-D cov_enabled="$COV_ENABLED" \
|
||||
-D vllm_ci_branch="$VLLM_CI_BRANCH" \
|
||||
| sed '/^[[:space:]]*$/d' \
|
||||
> pipeline.yaml
|
||||
)
|
||||
cat pipeline.yaml
|
||||
buildkite-agent artifact upload pipeline.yaml
|
||||
buildkite-agent pipeline upload pipeline.yaml
|
||||
exit 0
|
||||
}
|
||||
|
||||
get_diff() {
|
||||
$(git add .)
|
||||
echo $(git diff --name-only --diff-filter=ACMDR $(git merge-base origin/main HEAD))
|
||||
}
|
||||
|
||||
get_diff_main() {
|
||||
$(git add .)
|
||||
echo $(git diff --name-only --diff-filter=ACMDR HEAD~1)
|
||||
}
|
||||
|
||||
file_diff=$(get_diff)
|
||||
if [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||
file_diff=$(get_diff_main)
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Early exit start: skip pipeline if conditions are met
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# Match CUDA Buildkite skip-ci behavior for docs/markdown-only changes.
|
||||
if [[ "${DOCS_ONLY_DISABLE}" != "1" ]]; then
|
||||
SKIP_CI="$(resolve_skip_ci)"
|
||||
if [[ "${SKIP_CI}" == "1" ]]; then
|
||||
echo "[docs-only] Docs/markdown-only changes detected. Exiting before pipeline upload."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Early exit end
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
patterns=(
|
||||
"docker/Dockerfile"
|
||||
"CMakeLists.txt"
|
||||
"requirements/common.txt"
|
||||
"requirements/cuda.txt"
|
||||
"requirements/build.txt"
|
||||
"requirements/test.txt"
|
||||
"setup.py"
|
||||
"csrc/"
|
||||
"cmake/"
|
||||
)
|
||||
|
||||
ignore_patterns=(
|
||||
"docker/Dockerfile."
|
||||
"csrc/cpu"
|
||||
"csrc/rocm"
|
||||
"cmake/hipify.py"
|
||||
"cmake/cpu_extension.cmake"
|
||||
)
|
||||
|
||||
for file in $file_diff; do
|
||||
# First check if file matches any pattern
|
||||
matches_pattern=0
|
||||
for pattern in "${patterns[@]}"; do
|
||||
if [[ $file == $pattern* ]] || [[ $file == $pattern ]]; then
|
||||
matches_pattern=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If file matches pattern, check it's not in ignore patterns
|
||||
if [[ $matches_pattern -eq 1 ]]; then
|
||||
matches_ignore=0
|
||||
for ignore in "${ignore_patterns[@]}"; do
|
||||
if [[ $file == $ignore* ]] || [[ $file == $ignore ]]; then
|
||||
matches_ignore=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $matches_ignore -eq 0 ]]; then
|
||||
RUN_ALL=1
|
||||
echo "Found changes: $file. Run all tests"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Check for ready-run-all-tests label
|
||||
LABEL_RUN_ALL=$(check_run_all_label)
|
||||
if [[ $LABEL_RUN_ALL == true ]]; then
|
||||
RUN_ALL=1
|
||||
NIGHTLY=1
|
||||
echo "Found 'ready-run-all-tests' label. Running all tests including optional tests."
|
||||
fi
|
||||
|
||||
# Decide whether to use precompiled wheels
|
||||
# Relies on existing patterns array as a basis.
|
||||
if [[ -n "${VLLM_USE_PRECOMPILED:-}" ]]; then
|
||||
echo "VLLM_USE_PRECOMPILED is already set to: $VLLM_USE_PRECOMPILED"
|
||||
elif [[ $RUN_ALL -eq 1 ]]; then
|
||||
export VLLM_USE_PRECOMPILED=0
|
||||
echo "Detected critical changes, building wheels from source"
|
||||
else
|
||||
export VLLM_USE_PRECOMPILED=1
|
||||
echo "No critical changes, using precompiled wheels"
|
||||
fi
|
||||
|
||||
|
||||
LIST_FILE_DIFF=$(get_diff | tr ' ' '|')
|
||||
if [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||
LIST_FILE_DIFF=$(get_diff_main | tr ' ' '|')
|
||||
fi
|
||||
upload_pipeline
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/bash
|
||||
# vllm-omni Intel bootstrap
|
||||
# Uses static pipeline-intel.yaml for Intel XPU tests
|
||||
# Based on: bootstrap-amd-omni.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${DOCS_ONLY_DISABLE:-}" ]]; then
|
||||
DOCS_ONLY_DISABLE=0
|
||||
fi
|
||||
|
||||
upload_pipeline() {
|
||||
echo "--- 🛠 Preparing Intel pipeline"
|
||||
buildkite-agent pipeline upload .buildkite/pipeline-intel.yaml
|
||||
}
|
||||
|
||||
get_diff() {
|
||||
$(git add .)
|
||||
echo $(git diff --name-only --diff-filter=ACMDR $(git merge-base origin/main HEAD))
|
||||
}
|
||||
|
||||
get_diff_main() {
|
||||
$(git add .)
|
||||
echo $(git diff --name-only --diff-filter=ACMDR HEAD~1)
|
||||
}
|
||||
|
||||
file_diff=$(get_diff)
|
||||
if [[ $BUILDKITE_BRANCH == "main" ]]; then
|
||||
file_diff=$(get_diff_main)
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Early exit: skip pipeline if all changed files are under docs/
|
||||
# ----------------------------------------------------------------------
|
||||
if [[ "${DOCS_ONLY_DISABLE}" != "1" ]] && [[ -n "${file_diff:-}" ]]; then
|
||||
docs_only=1
|
||||
while IFS= read -r f; do
|
||||
[[ -z "$f" ]] && continue
|
||||
if [[ "$f" != docs/* ]]; then
|
||||
docs_only=0
|
||||
break
|
||||
fi
|
||||
done < <(printf '%s\n' "$file_diff" | tr ' ' '\n' | tr -d '\r')
|
||||
|
||||
if [[ "$docs_only" -eq 1 ]]; then
|
||||
buildkite-agent annotate ":memo: CI skipped — docs only" --style "info"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
upload_pipeline
|
||||
@@ -0,0 +1,702 @@
|
||||
# Uploader-only hardware presets for CUDA / NPU test YAML.
|
||||
# Referenced as ``mirror_hardwares: l4_1`` on a step; ``upload_pipeline.py`` expands to
|
||||
# ``agents`` (+ optional top-level ``image`` for NPU) + ``plugins`` (+ ``retry``
|
||||
# for ``l4_*``), then strips ``mirror_hardwares`` before Buildkite upload.
|
||||
#
|
||||
# Omit the key: compose {chip}_{n} from pytest -m SKU + cards_n (max of several
|
||||
# positives; not cards_1 with no positive cards_* → that chip's highest existing preset).
|
||||
# Unset MIRROR_HW matches H100 or L4 in -m (both → H100); no match skips the step.
|
||||
# MIRROR_HW=b200 matches B200 in -m (else the step is skipped).
|
||||
# MIRROR_HW must be empty or b200 (case-insensitive); unknown values fail the upload.
|
||||
# CUDA preset strings (h100_4, l4_1) are omitted when MIRROR_HW=b200.
|
||||
# Unset MIRROR_HW keeps string presets. NPU presets ignore MIRROR_HW.
|
||||
#
|
||||
# CUDA naming: {chip}_{count}
|
||||
# l4_1, l4_2, l4_3, l4_4, h100_1 … h100_4, b200_1 … b200_4
|
||||
# NPU naming: {queue}_{resource_class}
|
||||
# a2b3_npu_1 — ascend-a2b3, resource_class npu-1 (A2/B3 CI image)
|
||||
# a2b3_npu_4 — ascend-a2b3, resource_class npu-4
|
||||
# a3_npu_2 — ascend-a3, resource_class npu-2 (A3 CI image tag …:$BUILDKITE_COMMIT-a3)
|
||||
# a5_npu_2 — ascend-a5, resource_class npu-2
|
||||
# 310p_npu_1 — ascend-310p, resource_class npu-1
|
||||
#
|
||||
# B200 (b200-k8s): matches vLLM device ``b200-k8s`` from ci-infra
|
||||
# (AgentQueue.B200_K8S + b200_plugin_template). Queue routes the K8s pool;
|
||||
# podSpec uses hostNetwork + /raid|/mnt/shared (no H100-style nodeSelector).
|
||||
#
|
||||
# The ``l4_*`` presets run on the EKS ``l4-k8s`` queue (agent-stack-k8s),
|
||||
# packed onto g6.12xlarge L4 nodes (``vllm.ci/gpu-pool=l4x4``). GPU / CPU /
|
||||
# memory / shm requests scale with card count (1 GPU = 10 CPU / 40Gi / 24Gi shm).
|
||||
# Retry covers lost agents / killed pods, not pytest or OOM (exit 1 / 137).
|
||||
# The Kubernetes HF secret deliberately uses VLLM_CI_HF_TOKEN. Scheduled
|
||||
# build-level HF_TOKEN values can override pod env entries with the same name;
|
||||
# upload_pipeline.py restores the secret-backed value inside the job shell.
|
||||
|
||||
x-npu-k8s-plugins: &npu_k8s_plugins
|
||||
- kubernetes:
|
||||
podSpecPatch:
|
||||
imagePullSecrets:
|
||||
- name: swr-secret
|
||||
|
||||
# Infra-only retry. Omit exit 1 (pytest failed) and 137 (cgroup OOM / SIGKILL
|
||||
# of the test process). ci-infra ``K8S_RETRY`` still retries exit 1.
|
||||
x-l4-k8s-retry: &l4_k8s_retry
|
||||
automatic:
|
||||
- exit_status: -1
|
||||
limit: 1
|
||||
- exit_status: 128
|
||||
limit: 1
|
||||
- signal_reason: agent_stop
|
||||
limit: 1
|
||||
- signal_reason: agent_refused
|
||||
limit: 1
|
||||
|
||||
|
||||
mirror_hardwares:
|
||||
l4_1:
|
||||
agents:
|
||||
queue: l4-k8s
|
||||
retry: *l4_k8s_retry
|
||||
plugins:
|
||||
- kubernetes:
|
||||
metadata:
|
||||
annotations:
|
||||
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
|
||||
karpenter.sh/do-not-disrupt: "true"
|
||||
podSpec:
|
||||
priorityClassName: ci
|
||||
serviceAccountName: buildkite-gpu-jobs
|
||||
tolerations:
|
||||
- key: nvidia.com/gpu
|
||||
operator: Exists
|
||||
effect: NoSchedule
|
||||
nodeSelector:
|
||||
vllm.ci/gpu-pool: l4x4
|
||||
containers:
|
||||
- image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
requests:
|
||||
nvidia.com/gpu: 1
|
||||
cpu: "10"
|
||||
memory: 40Gi
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /fsx/hf_cache
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /fsx/hf_cache
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 24Gi
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /fsx/hf_cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
l4_2:
|
||||
agents:
|
||||
queue: l4-k8s
|
||||
retry: *l4_k8s_retry
|
||||
plugins:
|
||||
- kubernetes:
|
||||
metadata:
|
||||
annotations:
|
||||
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
|
||||
karpenter.sh/do-not-disrupt: "true"
|
||||
podSpec:
|
||||
priorityClassName: ci
|
||||
serviceAccountName: buildkite-gpu-jobs
|
||||
tolerations:
|
||||
- key: nvidia.com/gpu
|
||||
operator: Exists
|
||||
effect: NoSchedule
|
||||
nodeSelector:
|
||||
vllm.ci/gpu-pool: l4x4
|
||||
containers:
|
||||
- image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
requests:
|
||||
nvidia.com/gpu: 2
|
||||
cpu: "20"
|
||||
memory: 80Gi
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /fsx/hf_cache
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /fsx/hf_cache
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 48Gi
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /fsx/hf_cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
l4_3:
|
||||
agents:
|
||||
queue: l4-k8s
|
||||
retry: *l4_k8s_retry
|
||||
plugins:
|
||||
- kubernetes:
|
||||
metadata:
|
||||
annotations:
|
||||
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
|
||||
karpenter.sh/do-not-disrupt: "true"
|
||||
podSpec:
|
||||
priorityClassName: ci
|
||||
serviceAccountName: buildkite-gpu-jobs
|
||||
tolerations:
|
||||
- key: nvidia.com/gpu
|
||||
operator: Exists
|
||||
effect: NoSchedule
|
||||
nodeSelector:
|
||||
vllm.ci/gpu-pool: l4x4
|
||||
containers:
|
||||
- image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 3
|
||||
requests:
|
||||
nvidia.com/gpu: 3
|
||||
cpu: "30"
|
||||
memory: 120Gi
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /fsx/hf_cache
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /fsx/hf_cache
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 72Gi
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /fsx/hf_cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
l4_4:
|
||||
agents:
|
||||
queue: l4-k8s
|
||||
retry: *l4_k8s_retry
|
||||
plugins:
|
||||
- kubernetes:
|
||||
metadata:
|
||||
annotations:
|
||||
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
|
||||
karpenter.sh/do-not-disrupt: "true"
|
||||
podSpec:
|
||||
priorityClassName: ci
|
||||
serviceAccountName: buildkite-gpu-jobs
|
||||
tolerations:
|
||||
- key: nvidia.com/gpu
|
||||
operator: Exists
|
||||
effect: NoSchedule
|
||||
nodeSelector:
|
||||
vllm.ci/gpu-pool: l4x4
|
||||
containers:
|
||||
- image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 4
|
||||
requests:
|
||||
nvidia.com/gpu: 4
|
||||
cpu: "40"
|
||||
memory: 160Gi
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /fsx/hf_cache
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /fsx/hf_cache
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
sizeLimit: 96Gi
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /fsx/hf_cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
h100_1:
|
||||
agents:
|
||||
queue: mithril-h100-pool
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
h100_2:
|
||||
agents:
|
||||
queue: mithril-h100-pool
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
h100_3:
|
||||
agents:
|
||||
queue: mithril-h100-pool
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 3
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
h100_4:
|
||||
agents:
|
||||
queue: mithril-h100-pool
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 4
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
# vLLM device: b200-k8s → agents.queue b200-k8s + Buildkite K8s agent-stack podSpec
|
||||
b200_1:
|
||||
agents:
|
||||
queue: b200-k8s
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
runtimeClassName: nvidia
|
||||
hostNetwork: true
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
imagePullSecrets:
|
||||
- name: k8s-ecr-login-renew-docker-secret
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- IPC_LOCK
|
||||
- SYS_RESOURCE
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: raid
|
||||
mountPath: /raid
|
||||
- name: shared
|
||||
mountPath: /mnt/shared
|
||||
env:
|
||||
- name: NCCL_CUMEM_HOST_ENABLE
|
||||
value: "0"
|
||||
- name: HF_HOME
|
||||
value: /raid/hf_cache
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: raid
|
||||
hostPath:
|
||||
path: /raid
|
||||
type: DirectoryOrCreate
|
||||
- name: shared
|
||||
hostPath:
|
||||
path: /mnt/shared
|
||||
type: DirectoryOrCreate
|
||||
|
||||
b200_2:
|
||||
agents:
|
||||
queue: b200-k8s
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
runtimeClassName: nvidia
|
||||
hostNetwork: true
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
imagePullSecrets:
|
||||
- name: k8s-ecr-login-renew-docker-secret
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- IPC_LOCK
|
||||
- SYS_RESOURCE
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: raid
|
||||
mountPath: /raid
|
||||
- name: shared
|
||||
mountPath: /mnt/shared
|
||||
env:
|
||||
- name: NCCL_CUMEM_HOST_ENABLE
|
||||
value: "0"
|
||||
- name: HF_HOME
|
||||
value: /raid/hf_cache
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: raid
|
||||
hostPath:
|
||||
path: /raid
|
||||
type: DirectoryOrCreate
|
||||
- name: shared
|
||||
hostPath:
|
||||
path: /mnt/shared
|
||||
type: DirectoryOrCreate
|
||||
|
||||
b200_3:
|
||||
agents:
|
||||
queue: b200-k8s
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
runtimeClassName: nvidia
|
||||
hostNetwork: true
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
imagePullSecrets:
|
||||
- name: k8s-ecr-login-renew-docker-secret
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 3
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- IPC_LOCK
|
||||
- SYS_RESOURCE
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: raid
|
||||
mountPath: /raid
|
||||
- name: shared
|
||||
mountPath: /mnt/shared
|
||||
env:
|
||||
- name: NCCL_CUMEM_HOST_ENABLE
|
||||
value: "0"
|
||||
- name: HF_HOME
|
||||
value: /raid/hf_cache
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: raid
|
||||
hostPath:
|
||||
path: /raid
|
||||
type: DirectoryOrCreate
|
||||
- name: shared
|
||||
hostPath:
|
||||
path: /mnt/shared
|
||||
type: DirectoryOrCreate
|
||||
|
||||
b200_4:
|
||||
agents:
|
||||
queue: b200-k8s
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
runtimeClassName: nvidia
|
||||
hostNetwork: true
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
imagePullSecrets:
|
||||
- name: k8s-ecr-login-renew-docker-secret
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 4
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- IPC_LOCK
|
||||
- SYS_RESOURCE
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: raid
|
||||
mountPath: /raid
|
||||
- name: shared
|
||||
mountPath: /mnt/shared
|
||||
env:
|
||||
- name: NCCL_CUMEM_HOST_ENABLE
|
||||
value: "0"
|
||||
- name: HF_HOME
|
||||
value: /raid/hf_cache
|
||||
- name: VLLM_CI_HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: raid
|
||||
hostPath:
|
||||
path: /raid
|
||||
type: DirectoryOrCreate
|
||||
- name: shared
|
||||
hostPath:
|
||||
path: /mnt/shared
|
||||
type: DirectoryOrCreate
|
||||
|
||||
a2b3_npu_1:
|
||||
agents:
|
||||
queue: "ascend-a2b3"
|
||||
resource_class: "npu-1"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a2b3_npu_4:
|
||||
agents:
|
||||
queue: "ascend-a2b3"
|
||||
resource_class: "npu-4"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
|
||||
a2b3_npu_8:
|
||||
agents:
|
||||
queue: "ascend-a2b3"
|
||||
resource_class: "npu-8"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a3_npu_2:
|
||||
agents:
|
||||
queue: "ascend-a3"
|
||||
resource_class: "npu-2"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a3"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a3_npu_4:
|
||||
agents:
|
||||
queue: "ascend-a3"
|
||||
resource_class: "npu-4"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a3"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a3_npu_8:
|
||||
agents:
|
||||
queue: "ascend-a3"
|
||||
resource_class: "npu-8"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a3"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a3_npu_16:
|
||||
agents:
|
||||
queue: "ascend-a3"
|
||||
resource_class: "npu-16"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a3"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a5_npu_2:
|
||||
agents:
|
||||
queue: "ascend-a5"
|
||||
resource_class: "npu-2"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a5"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a5_npu_4:
|
||||
agents:
|
||||
queue: "ascend-a5"
|
||||
resource_class: "npu-4"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a5"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a5_npu_8:
|
||||
agents:
|
||||
queue: "ascend-a5"
|
||||
resource_class: "npu-8"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a5"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
a5_npu_16:
|
||||
agents:
|
||||
queue: "ascend-a5"
|
||||
resource_class: "npu-16"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a5"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
310p_npu_1:
|
||||
agents:
|
||||
queue: "ascend-310p"
|
||||
resource_class: "npu-1"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-310p"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
310p_npu_2:
|
||||
agents:
|
||||
queue: "ascend-310p"
|
||||
resource_class: "npu-2"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-310p"
|
||||
plugins: *npu_k8s_plugins
|
||||
|
||||
310p_npu_4:
|
||||
agents:
|
||||
queue: "ascend-310p"
|
||||
resource_class: "npu-4"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-310p"
|
||||
plugins: *npu_k8s_plugins
|
||||
@@ -0,0 +1,493 @@
|
||||
# Uploader-only path-prefix presets for CUDA L2–L5 and NPU L4 test YAML.
|
||||
# Referenced as ``source_file_dependencies: omni_qwen3_omni_function`` (or a list of
|
||||
# keys) on a step; ``upload_pipeline.py`` expands the key(s) only.
|
||||
#
|
||||
# YAML anchors above the registry hold model business-code paths. Job keys
|
||||
# ({model}_function / _perf / _accuracy / _reliability / _doc / _cov) alias
|
||||
# those anchors and add the scripts the job actually runs. Feature keys below
|
||||
# are unchanged. ``source_filter_fallback`` is not a job key: when no job-key
|
||||
# prefix matches, a matching diff keeps every job for that upload.
|
||||
#
|
||||
# YAML anchors are nested lists; the loader flattens them.
|
||||
|
||||
x-qwen3-tts: &qwen3_tts
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/entrypoints/omni_base.py
|
||||
- vllm_omni/worker/gpu_model_runner.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/common/alias_free_activation.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_tts.py
|
||||
- vllm_omni/deploy/qwen3_tts.yaml
|
||||
- vllm_omni/entrypoints/openai/serving_speech.py
|
||||
- vllm_omni/entrypoints/openai/tts_adapters/
|
||||
- vllm_omni/engine/stage_pool.py
|
||||
- vllm_omni/worker_v2/
|
||||
- vllm_omni/core/sched/
|
||||
- vllm_omni/distributed/omni_connectors/
|
||||
- vllm_omni/config/stage_config.py
|
||||
- vllm_omni/config/omni_config.py
|
||||
- vllm_omni/engine/orchestrator.py
|
||||
- vllm_omni/engine/stage_engine_core_proc.py
|
||||
- vllm_omni/deploy/qwen3_tts_mrv2.yaml
|
||||
- vllm_omni/deploy/qwen3_tts_high_concurrency_mrv2.yaml
|
||||
- vllm_omni/deploy/qwen3_tts_high_concurrency_mrv2_b4.yaml
|
||||
|
||||
x-minicpmo-4-5: &minicpmo_4_5
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/entrypoints/omni_base.py
|
||||
- vllm_omni/model_executor/models/minicpmo_4_5/
|
||||
- vllm_omni/model_executor/models/step_audio2/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/code2wav_core/
|
||||
- vllm_omni/model_executor/models/cosyvoice3/utils.py
|
||||
- vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
- vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja
|
||||
|
||||
x-minicpmo-4-5-duplex: &minicpmo_4_5_duplex
|
||||
- vllm_omni/deploy/minicpmo_4_5_duplex.yaml
|
||||
- vllm_omni/engine/duplex/
|
||||
- vllm_omni/engine/duplex_omni_engine.py
|
||||
- vllm_omni/engine/duplex_orchestrator.py
|
||||
- vllm_omni/engine/omni_engine_base.py
|
||||
- vllm_omni/entrypoints/duplex/
|
||||
- vllm_omni/entrypoints/duplex_omni.py
|
||||
- vllm_omni/entrypoints/async_omni_base.py
|
||||
- vllm_omni/protocol/
|
||||
- vllm_omni/clients/
|
||||
- vllm_omni/outputs/duplex.py
|
||||
- vllm_omni/model_executor/duplex_sampling.py
|
||||
- vllm_omni/experimental/fullduplex/
|
||||
- vllm_omni/core/sched/
|
||||
- vllm_omni/outputs/multimodal_accumulation.py
|
||||
- vllm_omni/engine/stage_init_utils.py
|
||||
- vllm_omni/engine/orchestrator.py
|
||||
- vllm_omni/entrypoints/cli/serve.py
|
||||
- vllm_omni/entrypoints/openai/api_server.py
|
||||
- vllm_omni/entrypoints/openai/duplex_capability.py
|
||||
- vllm_omni/config/stage_config.py
|
||||
|
||||
x-qwen2-5-omni: &qwen2_5_omni
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/entrypoints/omni_base.py
|
||||
- vllm_omni/model_executor/models/qwen2_5_omni/
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen2_5_omni.py
|
||||
- vllm_omni/deploy/qwen2_5_omni.yaml
|
||||
|
||||
x-qwen3-omni: &qwen3_omni
|
||||
- vllm_omni/engine/async_omni_engine.py
|
||||
- vllm_omni/entrypoints/omni_base.py
|
||||
- vllm_omni/entrypoints/openai/serving_chat.py
|
||||
- vllm_omni/model_executor/models/qwen3_omni/
|
||||
- vllm_omni/model_executor/models/common/qwen3_code_predictor.py
|
||||
- vllm_omni/model_executor/models/common/snake_activation.py
|
||||
- vllm_omni/model_executor/models/qwen2_5_omni/qwen2_5_omni_thinker.py
|
||||
- vllm_omni/model_executor/models/qwen3_tts/cuda_graph_decoder_wrapper.py
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_omni.py
|
||||
- vllm_omni/deploy/qwen3_omni_moe.yaml
|
||||
- vllm_omni/deploy/qwen3_omni_moe_thinking.yaml
|
||||
|
||||
x-wan22: &wan22
|
||||
- vllm_omni/diffusion/models/wan2_2/
|
||||
- vllm_omni/diffusion/models/dmd2/
|
||||
|
||||
x-cosmos3: &cosmos3
|
||||
- vllm_omni/diffusion/models/cosmos3/
|
||||
- vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_wan.py
|
||||
- vllm_omni/experimental/world_models/
|
||||
- vllm_omni/model_extras/cosmos3.py
|
||||
|
||||
x-qwen-image: &qwen_image
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
- vllm_omni/diffusion/models/dmd2/
|
||||
- vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_qwenimage.py
|
||||
|
||||
x-hunyuan-image3: &hunyuan_image3
|
||||
- vllm_omni/diffusion/models/hunyuan_image3/
|
||||
- vllm_omni/model_executor/models/hunyuan_image3/
|
||||
- vllm_omni/deploy/hunyuan_image3_dit.yaml
|
||||
|
||||
x-minimax-h3: &minimax_h3
|
||||
- vllm_omni/diffusion/models/minimax_h3/
|
||||
- vllm_omni/diffusion/layers/indexed_modulation.py
|
||||
|
||||
x-hunyuan-video: &hunyuan_video
|
||||
- vllm_omni/diffusion/models/hunyuan_video/
|
||||
- vllm_omni/model_executor/models/hunyuan_video/
|
||||
|
||||
x-ltx2: <x2
|
||||
- vllm_omni/diffusion/models/ltx2/
|
||||
- vllm_omni/model_extras/ltx2.py
|
||||
|
||||
x-sana-video: &sana_video
|
||||
- vllm_omni/diffusion/models/sana_video/
|
||||
- vllm_omni/model_extras/sana_video.py
|
||||
|
||||
x-z-image: &z_image
|
||||
- vllm_omni/diffusion/models/z_image/
|
||||
|
||||
x-stable-audio: &stable_audio
|
||||
- vllm_omni/diffusion/models/stable_audio/
|
||||
|
||||
x-lingbot-video: &lingbot_video
|
||||
- vllm_omni/diffusion/models/lingbot_video/
|
||||
- vllm_omni/model_extras/lingbot_video.py
|
||||
|
||||
x-lingbot-world: &lingbot_world
|
||||
- vllm_omni/diffusion/models/lingbot_world/
|
||||
|
||||
|
||||
source_file_dependencies:
|
||||
# Hardware presets and shared test helpers. Not a job key — do not attach this
|
||||
# to a step. Used only when no job-key prefix matches: then a hit keeps every job.
|
||||
source_filter_fallback:
|
||||
- .buildkite/common/ci_mirror_hardwares.yml
|
||||
- tests/helpers/
|
||||
|
||||
# --- features ---
|
||||
diffusion_distributed_attention:
|
||||
- tests/diffusion/distributed/
|
||||
- tests/diffusion/attention/test_attention_sp.py
|
||||
- vllm_omni/diffusion/distributed/
|
||||
- vllm_omni/diffusion/attention/
|
||||
- vllm_omni/diffusion/data.py
|
||||
- vllm_omni/diffusion/models/
|
||||
|
||||
custom_pipeline:
|
||||
- tests/e2e/features/custom_pipeline/
|
||||
- tests/e2e/features/helpers/custom_pipeline.py
|
||||
- vllm_omni/diffusion/
|
||||
- vllm_omni/engine/
|
||||
- vllm_omni/entrypoints/
|
||||
- vllm_omni/inputs/
|
||||
- vllm_omni/outputs/
|
||||
|
||||
rlhf_verl_omni:
|
||||
- tests/e2e/features/rlhf_test/test_verl_omni_e2e.py
|
||||
- tests/e2e/features/helpers/verl_omni_server.py
|
||||
- tests/e2e/features/helpers/custom_pipeline.py
|
||||
- vllm_omni/diffusion/
|
||||
- vllm_omni/engine/
|
||||
- vllm_omni/entrypoints/
|
||||
- vllm_omni/inputs/
|
||||
- vllm_omni/outputs/
|
||||
|
||||
# Tiny-model diffusion jobs (shared across many model trees under models/).
|
||||
diffusion_tiny_model:
|
||||
- tests/model_tests/diffusion/
|
||||
- vllm_omni/diffusion/models/
|
||||
|
||||
diffusion_offloader:
|
||||
- tests/diffusion/offloader/
|
||||
- vllm_omni/diffusion/offloader/
|
||||
|
||||
diffusion_quantization:
|
||||
- tests/diffusion/quantization/
|
||||
- vllm_omni/diffusion/quantization/
|
||||
|
||||
# --- models ---
|
||||
# --- omni / tts jobs ---
|
||||
entrypoints_function:
|
||||
- tests/entrypoints/
|
||||
- vllm_omni/entrypoints/
|
||||
|
||||
omni_qwen3_omni_function:
|
||||
- *qwen3_omni
|
||||
- tests/e2e/offline_inference/test_qwen3_omni.py
|
||||
- tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py
|
||||
- tests/e2e/offline_inference/test_qwen3_omni_autoround_w4a16_expansion.py
|
||||
- tests/e2e/offline_inference/test_qwen3_omni_modelopt_nvfp4_w4a4.py
|
||||
- tests/e2e/online_serving/test_qwen3_omni.py
|
||||
- tests/e2e/online_serving/test_qwen3_omni_expansion.py
|
||||
- tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py
|
||||
|
||||
omni_qwen3_omni_accuracy:
|
||||
- *qwen3_omni
|
||||
- tests/e2e/accuracy/qwen3_omni/
|
||||
|
||||
omni_qwen3_omni_perf:
|
||||
- *qwen3_omni
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_qwen3_omni_vllm_text.json
|
||||
- tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json
|
||||
- tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json
|
||||
- tests/dfx/perf/tests/test_qwen3_omni_multi_replicas.json
|
||||
|
||||
omni_qwen3_omni_reliability:
|
||||
- *qwen3_omni
|
||||
- tests/dfx/reliability/test_reliability_qwen3_omni.py
|
||||
|
||||
omni_qwen3_omni_doc:
|
||||
- *qwen3_omni
|
||||
- examples/online_serving/qwen3_omni/
|
||||
- examples/online_serving/openai_chat_completion_client_for_multimodal_generation.py
|
||||
- tests/examples/online_serving/test_qwen3_omni.py
|
||||
|
||||
omni_qwen2_5_omni_doc:
|
||||
- *qwen2_5_omni
|
||||
- examples/online_serving/qwen2_5_omni/
|
||||
- examples/online_serving/openai_chat_completion_client_for_multimodal_generation.py
|
||||
- tests/examples/online_serving/test_qwen2_5_omni.py
|
||||
|
||||
omni_minicpmo_4_5_function:
|
||||
- *minicpmo_4_5
|
||||
- tests/e2e/offline_inference/test_minicpmo_4_5.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_expansion.py
|
||||
|
||||
omni_minicpmo_4_5_accuracy:
|
||||
- *minicpmo_4_5
|
||||
- tests/e2e/accuracy/minicpmo_4_5/
|
||||
|
||||
omni_duplex_eval_ci:
|
||||
- *minicpmo_4_5
|
||||
- *minicpmo_4_5_duplex
|
||||
- tests/e2e/accuracy/omni_duplex_eval/**
|
||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||
- vllm_omni/benchmarks/duplex/**
|
||||
- vllm_omni/entrypoints/cli/benchmark/omni_duplex_eval.py
|
||||
|
||||
omni_minicpmo_4_5_perf:
|
||||
- *minicpmo_4_5
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_minicpmo_4_5_ready.json
|
||||
- tests/dfx/perf/tests/test_minicpmo_4_5.json
|
||||
|
||||
omni_minicpmo_4_5_doc:
|
||||
- *minicpmo_4_5
|
||||
- examples/online_serving/minicpmo/realtime_web/
|
||||
- examples/online_serving/minicpmo/realtime_duplex_demo.py
|
||||
- tests/examples/test_minicpmo_realtime_web_server.py
|
||||
- tests/examples/test_minicpmo_realtime_web_static.py
|
||||
- tests/examples/test_minicpmo_realtime_duplex_simple_demo.py
|
||||
|
||||
omni_minicpmo_4_5_duplex_function:
|
||||
- *minicpmo_4_5
|
||||
- *minicpmo_4_5_duplex
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_duplex.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py
|
||||
- tests/e2e/online_serving/test_minicpmo_4_5_window.py
|
||||
- tests/e2e/online_serving/helpers/minicpmo_window_e2e.py
|
||||
- tests/e2e/online_serving/test_duplex_client_live.py
|
||||
- tests/e2e/online_serving/test_minicpmo_realtime_duplex_drivers.py
|
||||
- tests/e2e/online_serving/helpers/minicpmo_realtime_duplex_scenarios.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_multi_session.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_server_vad.py
|
||||
- tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py
|
||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||
- tests/assets/minicpmo_4_5/
|
||||
- tests/clients/
|
||||
- tests/engine/duplex/
|
||||
- tests/engine/test_duplex_omni_engine.py
|
||||
- tests/engine/test_duplex_orchestrator.py
|
||||
- tests/entrypoints/duplex/
|
||||
- tests/entrypoints/test_duplex_omni.py
|
||||
- tests/entrypoints/openai_api/test_duplex_api_server.py
|
||||
- tests/model_executor/models/minicpmo_4_5/duplex/
|
||||
- tests/protocol/
|
||||
|
||||
omni_minicpmo_4_5_duplex_perf:
|
||||
- *minicpmo_4_5
|
||||
- *minicpmo_4_5_duplex
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json
|
||||
|
||||
tts_qwen3_tts_function:
|
||||
- *qwen3_tts
|
||||
- tests/e2e/features/prefill_phase/
|
||||
- tests/e2e/offline_inference/test_qwen3_tts_base.py
|
||||
- tests/e2e/offline_inference/test_qwen3_tts_customvoice.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_base.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_base_expansion.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_customvoice.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_customvoice_expansion.py
|
||||
|
||||
tts_qwen3_tts_perf:
|
||||
- *qwen3_tts
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_tts.json
|
||||
|
||||
tts_qwen3_tts_cov:
|
||||
- *qwen3_tts
|
||||
- .buildkite/common/scripts/run_cov_split.sh
|
||||
- pyproject.toml
|
||||
- tests/e2e/offline_inference/test_qwen3_tts_base.py
|
||||
- tests/e2e/online_serving/test_qwen3_tts_base.py
|
||||
|
||||
# --- diffusion jobs ---
|
||||
diffusion_wan22_function:
|
||||
- *wan22
|
||||
- tests/e2e/offline_inference/test_wan22_t2v.py
|
||||
- tests/e2e/offline_inference/test_wan22_autoround_w4a16_expansion.py
|
||||
- tests/e2e/offline_inference/test_device_postprocess_equivalence.py
|
||||
- tests/e2e/online_serving/test_wan22_t2v.py
|
||||
- tests/e2e/online_serving/test_wan22_expansion.py
|
||||
|
||||
diffusion_wan22_accuracy:
|
||||
- *wan22
|
||||
- tests/e2e/accuracy/wan22_i2v/
|
||||
- tests/e2e/accuracy/test_diffusers_backend_similarity.py
|
||||
|
||||
diffusion_wan22_perf:
|
||||
- *wan22
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json
|
||||
|
||||
diffusion_wan22_reliability:
|
||||
- *wan22
|
||||
- tests/dfx/reliability/test_reliability_wan22.py
|
||||
|
||||
diffusion_image_to_video_doc:
|
||||
- *wan22
|
||||
- *hunyuan_video
|
||||
- *ltx2
|
||||
- *sana_video
|
||||
- *lingbot_video
|
||||
- examples/offline_inference/image_to_video/
|
||||
- tests/examples/offline_inference/test_image_to_video.py
|
||||
|
||||
diffusion_cosmos3_function:
|
||||
- *cosmos3
|
||||
- tests/e2e/online_serving/test_cosmos3.py
|
||||
|
||||
diffusion_cosmos3_accuracy:
|
||||
- *cosmos3
|
||||
- tests/e2e/accuracy/test_cosmos3_similarity.py
|
||||
|
||||
diffusion_cosmos3_perf:
|
||||
- *cosmos3
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_cosmos3_vllm_omni.json
|
||||
|
||||
diffusion_qwen_image_function:
|
||||
- *qwen_image
|
||||
- tests/e2e/online_serving/test_qwen_image.py
|
||||
- tests/e2e/online_serving/test_qwen_image_expansion.py
|
||||
- tests/e2e/offline_inference/test_qwen_image_autoround_w4a16_expansion.py
|
||||
|
||||
diffusion_qwen_image_accuracy:
|
||||
- *qwen_image
|
||||
- tests/e2e/accuracy/test_qwen_image.py
|
||||
- tests/e2e/accuracy/test_diffusers_backend_similarity.py
|
||||
|
||||
diffusion_qwen_image_perf:
|
||||
- *qwen_image
|
||||
- tests/dfx/perf/scripts/run_diffusion_benchmark.py
|
||||
- tests/dfx/perf/tests/test_qwen_image_vllm_omni.json
|
||||
|
||||
diffusion_text_to_image_doc:
|
||||
- *qwen_image
|
||||
- *z_image
|
||||
- examples/offline_inference/text_to_image/
|
||||
- examples/online_serving/text_to_image/
|
||||
- tests/examples/offline_inference/test_text_to_image.py
|
||||
- tests/examples/online_serving/test_text_to_image.py
|
||||
- vllm_omni/diffusion/models/nextstep_1_1/
|
||||
- vllm_omni/diffusion/models/longcat_image/
|
||||
- vllm_omni/diffusion/models/ovis_image/
|
||||
- vllm_omni/diffusion/models/omnigen2/
|
||||
- vllm_omni/diffusion/models/sd3/
|
||||
- vllm_omni/diffusion/models/flux/
|
||||
- vllm_omni/diffusion/models/flux2/
|
||||
- vllm_omni/diffusion/models/flux2_klein/
|
||||
- vllm_omni/diffusion/models/hidream_image/
|
||||
- vllm_omni/diffusion/models/krea2/
|
||||
- vllm_omni/diffusion/models/lingbot_video/
|
||||
|
||||
diffusion_hunyuan_image3_function:
|
||||
- *hunyuan_image3
|
||||
- tests/e2e/offline_inference/test_hunyuanimage3_i2t_expansion.py
|
||||
|
||||
diffusion_hunyuan_image3_accuracy:
|
||||
- *hunyuan_image3
|
||||
- tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py
|
||||
- tests/e2e/accuracy/test_hunyuan_image3_lora.py
|
||||
- vllm_omni/diffusion/lora/
|
||||
|
||||
diffusion_hunyuan_image3_perf:
|
||||
- *hunyuan_image3
|
||||
- tests/dfx/perf/scripts/run_diffusion_benchmark.py
|
||||
- tests/dfx/perf/tests/test_hunyuan_image_tp2_cfgp2.json
|
||||
- tests/dfx/perf/tests/test_hunyuan_image_tp2_sp2.json
|
||||
- tests/dfx/perf/tests/test_hunyuan_image_tp4.json
|
||||
|
||||
diffusion_hunyuan_image3_reliability:
|
||||
- *hunyuan_image3
|
||||
- tests/dfx/reliability/test_reliability_hunyuan_image.py
|
||||
|
||||
diffusion_minimax_h3_function:
|
||||
- *minimax_h3
|
||||
- tests/e2e/online_serving/test_minimax_h3_dlo_dp2_t2va.py
|
||||
- tests/e2e/online_serving/minimax_h3/
|
||||
- tests/diffusion/models/minimax_h3/
|
||||
- vllm_omni/diffusion/lora/
|
||||
- vllm_omni/diffusion/offloader/
|
||||
- vllm_omni/diffusion/distributed/
|
||||
- vllm_omni/entrypoints/openai/
|
||||
|
||||
diffusion_minimax_h3_accuracy:
|
||||
- *minimax_h3
|
||||
- tests/e2e/accuracy/minimax_h3/
|
||||
|
||||
diffusion_minimax_h3_perf:
|
||||
- *minimax_h3
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_minimax_h3_vllm_omni.json
|
||||
|
||||
diffusion_hunyuan_video_function:
|
||||
- *hunyuan_video
|
||||
- tests/e2e/online_serving/test_hunyuan_video_15_expansion.py
|
||||
|
||||
diffusion_hunyuan_video_accuracy:
|
||||
- *hunyuan_video
|
||||
- tests/e2e/accuracy/hunyuanvideo15_t2v/
|
||||
- tests/e2e/accuracy/hunyuanvideo15_i2v/
|
||||
|
||||
diffusion_hunyuan_video_perf:
|
||||
- *hunyuan_video
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json
|
||||
- tests/dfx/perf/tests/test_hunyuanvideo15_i2v_vllm_omni.json
|
||||
|
||||
diffusion_z_image_function:
|
||||
- *z_image
|
||||
- tests/e2e/online_serving/test_z_image.py
|
||||
- tests/e2e/online_serving/test_zimage_expansion.py
|
||||
|
||||
diffusion_sana_video_function:
|
||||
- *sana_video
|
||||
- tests/e2e/online_serving/test_sana_video_expansion.py
|
||||
- tests/e2e/accuracy/sana_video/
|
||||
|
||||
diffusion_stable_audio_function:
|
||||
- *stable_audio
|
||||
- tests/e2e/offline_inference/test_stable_audio_expansion.py
|
||||
- tests/e2e/online_serving/test_stable_audio_online_expansion.py
|
||||
|
||||
diffusion_lingbot_function:
|
||||
- *lingbot_video
|
||||
- *lingbot_world
|
||||
- tests/e2e/online_serving/test_lingbot_video.py
|
||||
- tests/e2e/online_serving/test_lingbot_video_expansion.py
|
||||
- tests/e2e/online_serving/test_lingbot_video_moe.py
|
||||
- tests/e2e/offline_inference/test_lingbot_world_v2.py
|
||||
|
||||
diffusion_lingbot_perf:
|
||||
- *lingbot_video
|
||||
- tests/dfx/perf/scripts/run_benchmark.py
|
||||
- tests/dfx/perf/tests/test_lingbot_video_vllm_omni.json
|
||||
|
||||
|
||||
# Invalid-param jobs: model business code only, plus the reliability scripts.
|
||||
reliability_invalid_param_h100:
|
||||
- *qwen3_omni
|
||||
- *minicpmo_4_5
|
||||
- *qwen_image
|
||||
- *wan22
|
||||
- tests/dfx/reliability/invalid_param_test/
|
||||
|
||||
reliability_invalid_param_l4:
|
||||
- *qwen3_tts
|
||||
- *stable_audio
|
||||
- tests/dfx/reliability/invalid_param_test/
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# Shared Buildkite skip-ci helpers for AMD / Intel bootstrap scripts.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKIP_CI_PY="${SCRIPT_DIR}/skip_ci.py"
|
||||
|
||||
# Resolve git diff once. Exit 0 when this bootstrap should stop uploading.
|
||||
# Decision details are logged by skip_ci.py; this helper only annotates skip-all.
|
||||
# Usage: gate_bootstrap_ci <platform> <l2|l3>
|
||||
gate_bootstrap_ci() {
|
||||
local platform="$1"
|
||||
local level="$2"
|
||||
local kind
|
||||
if kind="$(python3 "${SKIP_CI_PY}" gate "${platform}" "${level}")"; then
|
||||
if [[ "${kind}" == "skip-all" ]]; then
|
||||
buildkite-agent annotate \
|
||||
":memo: CI skipped — docs or pytest skip-mark changes only" \
|
||||
--style "info" 2>/dev/null || true
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run a model's E2E tests once per entry mode as separate coverage runs and upload
|
||||
# the reports, so per-mode attribution survives (see vllm-project/vllm-omni#5332).
|
||||
#
|
||||
# Usage: run_cov_split.sh --model-id <id> [--offline <paths>] [--online <paths>] \
|
||||
# -- <pytest args...>
|
||||
#
|
||||
# --model-id Names the artifacts: coverage-<id>-{offline,online}-<step id>.xml.gz.
|
||||
# Use the model's directory name under vllm_omni/*/models/.
|
||||
# --offline Pytest path(s) for the offline half. Repeatable.
|
||||
# --online Pytest path(s) for the online half. Repeatable.
|
||||
# -- Everything after this is forwarded verbatim to every pytest run,
|
||||
# quoting preserved: the job's own -m expression, --run-level, and
|
||||
# anything else it needs (e.g. --test-config-file).
|
||||
#
|
||||
# At least one of --offline/--online is required, so a job with only one mode runs
|
||||
# just that half. Total runtime is bounded by the step's timeout_in_minutes.
|
||||
#
|
||||
# Coverage + artifact upload run only on scheduled weekly E2E sweeps
|
||||
# (WEEKLY=1 and BUILDKITE_BRANCH=main — same gate as bootstrap --e2e).
|
||||
# All other invocations (PR merge-test, regular main merge, local) run the
|
||||
# same combined pytest as the job used before coverage was added.
|
||||
#
|
||||
# Exits non-zero if any half or the upload failed.
|
||||
set -uo pipefail
|
||||
|
||||
MODEL_ID=""
|
||||
OFFLINE=()
|
||||
ONLINE=()
|
||||
PYTEST_ARGS=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--model-id) MODEL_ID="$2"; shift 2 ;;
|
||||
--offline) OFFLINE+=("$2"); shift 2 ;;
|
||||
--online) ONLINE+=("$2"); shift 2 ;;
|
||||
--) shift; PYTEST_ARGS=("$@"); break ;;
|
||||
*) echo "run_cov_split.sh: unknown argument: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${MODEL_ID}" ]]; then
|
||||
echo "run_cov_split.sh: missing --model-id" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if ((${#OFFLINE[@]} == 0 && ${#ONLINE[@]} == 0)); then
|
||||
echo "run_cov_split.sh: need at least one of --offline / --online" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
_should_run_coverage() {
|
||||
[[ "${WEEKLY:-}" == "1" && "${BUILDKITE_BRANCH:-}" == "main" ]]
|
||||
}
|
||||
|
||||
if ! _should_run_coverage; then
|
||||
PATHS=("${OFFLINE[@]}" "${ONLINE[@]}")
|
||||
echo "--- pytest (no coverage): ${MODEL_ID}"
|
||||
pytest -s -v "${PATHS[@]}" "${PYTEST_ARGS[@]}"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# Two steps can test the same model, and artifacts are scoped to the build (a
|
||||
# nightly one carries the ready, merge and nightly tiers at once), so unsuffixed
|
||||
# reports would share a path -- a glob download then races to rename onto one file.
|
||||
# Not BUILDKITE_JOB_ID: the step id survives retries, so attempts collapse under
|
||||
# Buildkite's latest-attempt lookup instead of accumulating. A parallel step would
|
||||
# need BUILDKITE_PARALLEL_JOB as well; no pilot is one.
|
||||
REPORT_SUFFIX="${BUILDKITE_STEP_ID:-local}"
|
||||
OFFLINE_REPORT="coverage-${MODEL_ID}-offline-${REPORT_SUFFIX}.xml"
|
||||
ONLINE_REPORT="coverage-${MODEL_ID}-online-${REPORT_SUFFIX}.xml"
|
||||
|
||||
run_half() {
|
||||
local mode="$1"
|
||||
shift
|
||||
local report="coverage-${MODEL_ID}-${mode}-${REPORT_SUFFIX}.xml"
|
||||
echo "--- coverage: ${MODEL_ID} ${mode}"
|
||||
pytest -s -v "$@" "${PYTEST_ARGS[@]}" --cov=vllm_omni --cov-report="xml:${report}"
|
||||
local status=$?
|
||||
# Cobertura lists every statement in vllm_omni whether or not it ran, so the
|
||||
# report is ~7MB no matter how little the job covers. The repetition is what
|
||||
# dominates it, and gzip takes that to ~400KB.
|
||||
gzip -9 -f "${report}" || status=1
|
||||
return "${status}"
|
||||
}
|
||||
|
||||
# Clear both modes, not just the ones being run: the upload glob matches both, so
|
||||
# a report left by an earlier run would otherwise be published as if the mode it
|
||||
# belongs to had run this time.
|
||||
rm -f "${OFFLINE_REPORT}" "${ONLINE_REPORT}" "${OFFLINE_REPORT}.gz" "${ONLINE_REPORT}.gz"
|
||||
|
||||
EXIT=0
|
||||
((${#OFFLINE[@]})) && { run_half offline "${OFFLINE[@]}" || EXIT=1; }
|
||||
((${#ONLINE[@]})) && { run_half online "${ONLINE[@]}" || EXIT=1; }
|
||||
|
||||
buildkite-agent artifact upload "coverage-${MODEL_ID}-*-${REPORT_SUFFIX}.xml.gz" || EXIT=1
|
||||
|
||||
exit "${EXIT}"
|
||||
@@ -0,0 +1,585 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Shared Buildkite skip-ci and CI-YAML level targeting logic.
|
||||
|
||||
``resolve_ci_decision(changed_files, ...)`` buckets explicit file lists (tests, dry-run).
|
||||
``resolve_ci_context_from_git()`` resolves git diff once and returns decision + changed files
|
||||
for Buildkite bootstrap / upload scripts.
|
||||
|
||||
CLI (for bootstrap scripts; exit code is the signal):
|
||||
python3 skip_ci.py gate <platform> <level>
|
||||
Exit 0 when bootstrap should stop (skip-all, or that L2/L3 target is off).
|
||||
Prints ``skip-all`` or ``skip-l23`` on stdout; logs the decision once.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from dataclasses import dataclass, field, replace
|
||||
from pathlib import Path
|
||||
|
||||
LOG = "[skip-ci]"
|
||||
ROOT = Path(__file__).resolve().parent.parent.parent.parent
|
||||
|
||||
PLATFORMS = ("cuda", "amd", "intel", "npu")
|
||||
L23_LEVELS = frozenset({"l2", "l3"})
|
||||
|
||||
L2_YAML_FILES: dict[str, str] = {
|
||||
".buildkite/cuda/test-ready.yml": "cuda",
|
||||
".buildkite/npu/test-npu-ready.yml": "npu",
|
||||
".buildkite/amd/test-amd-ready.yml": "amd",
|
||||
".buildkite/intel/pipeline-intel.yml": "intel",
|
||||
}
|
||||
|
||||
L3_YAML_FILES: dict[str, str] = {
|
||||
".buildkite/cuda/test-merge.yml": "cuda",
|
||||
".buildkite/amd/test-amd-merge.yml": "amd",
|
||||
}
|
||||
|
||||
L45_YAML_FILES: dict[str, str] = {
|
||||
".buildkite/cuda/test-nightly.yml": "cuda",
|
||||
".buildkite/cuda/test-weekly.yml": "cuda",
|
||||
".buildkite/amd/test-amd-nightly.yml": "amd",
|
||||
".buildkite/npu/test-npu-nightly.yml": "npu",
|
||||
}
|
||||
|
||||
|
||||
def _empty_platform_buckets() -> dict[str, list[str]]:
|
||||
return {platform: [] for platform in PLATFORMS}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CiDevice:
|
||||
"""Per-platform / per-level skip flags for yaml-gated bootstrap (``skip_l2_l3``)."""
|
||||
|
||||
skip_cuda_l2: bool = False
|
||||
skip_cuda_l3: bool = False
|
||||
skip_amd_l2: bool = False
|
||||
skip_amd_l3: bool = False
|
||||
skip_intel_l2: bool = False
|
||||
skip_intel_l3: bool = False
|
||||
skip_npu_l2: bool = False
|
||||
skip_npu_l3: bool = False
|
||||
|
||||
def is_skip(self, platform: str, level: str) -> bool:
|
||||
return bool(getattr(self, f"skip_{platform}_{level}", True))
|
||||
|
||||
|
||||
@dataclass
|
||||
class DiffBuckets:
|
||||
"""Changed files grouped by doc / skip-mark / CI yaml / other."""
|
||||
|
||||
docs: list[str] = field(default_factory=list)
|
||||
skip_tests: list[str] = field(default_factory=list)
|
||||
other: list[str] = field(default_factory=list)
|
||||
l2: dict[str, list[str]] = field(default_factory=_empty_platform_buckets)
|
||||
l3: dict[str, list[str]] = field(default_factory=_empty_platform_buckets)
|
||||
l45: dict[str, list[str]] = field(default_factory=_empty_platform_buckets)
|
||||
|
||||
@property
|
||||
def has_doc_changes(self) -> bool:
|
||||
return bool(self.docs)
|
||||
|
||||
@property
|
||||
def has_skip_test_changes(self) -> bool:
|
||||
return bool(self.skip_tests)
|
||||
|
||||
@property
|
||||
def has_other_changes(self) -> bool:
|
||||
"""Product code or paths outside skip-ci scope."""
|
||||
return bool(self.other)
|
||||
|
||||
@property
|
||||
def has_l23_yaml_changes(self) -> bool:
|
||||
"""At least one whitelisted L2/L3 CI yaml file changed."""
|
||||
return any(self.l2[platform] or self.l3[platform] for platform in PLATFORMS)
|
||||
|
||||
@property
|
||||
def has_l45_yaml_changes(self) -> bool:
|
||||
"""At least one whitelisted L4/L5 (nightly/weekly) CI yaml file changed."""
|
||||
return any(self.l45[platform] for platform in PLATFORMS)
|
||||
|
||||
@property
|
||||
def has_skip_ci_scope_changes(self) -> bool:
|
||||
"""At least one doc / skip-mark / whitelisted CI yaml change."""
|
||||
return (
|
||||
self.has_doc_changes or self.has_skip_test_changes or self.has_l23_yaml_changes or self.has_l45_yaml_changes
|
||||
)
|
||||
|
||||
def l2_platforms(self) -> frozenset[str]:
|
||||
return frozenset(platform for platform in PLATFORMS if self.l2[platform])
|
||||
|
||||
def l3_platforms(self) -> frozenset[str]:
|
||||
return frozenset(platform for platform in PLATFORMS if self.l3[platform])
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SkipL2L3Basis:
|
||||
skip_all_l2: bool
|
||||
skip_all_l3: bool
|
||||
|
||||
@classmethod
|
||||
def from_buckets(cls, buckets: DiffBuckets) -> SkipL2L3Basis | None:
|
||||
"""L4/L5 yaml → skip both L2 and L3 (L2/L3 buckets may rescue).
|
||||
|
||||
Docs / skip-mark changes do not block this path; they are ignored for
|
||||
L2/L3 targeting when CI YAML is also present.
|
||||
"""
|
||||
if buckets.has_other_changes:
|
||||
return None
|
||||
if not buckets.has_l45_yaml_changes:
|
||||
return None
|
||||
return cls(
|
||||
skip_all_l2=not buckets.l2_platforms(),
|
||||
skip_all_l3=not buckets.l3_platforms(),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SkipL3Basis:
|
||||
enable_l2_platforms: frozenset[str]
|
||||
|
||||
@classmethod
|
||||
def from_buckets(cls, buckets: DiffBuckets) -> SkipL3Basis | None:
|
||||
"""L2 yaml changed → skip L3; keep L2 on touched platforms."""
|
||||
platforms = buckets.l2_platforms()
|
||||
if not platforms:
|
||||
return None
|
||||
return cls(enable_l2_platforms=platforms)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SkipL2Basis:
|
||||
enable_l3_platforms: frozenset[str]
|
||||
|
||||
@classmethod
|
||||
def from_buckets(cls, buckets: DiffBuckets) -> SkipL2Basis | None:
|
||||
"""L3 yaml changed → skip L2; keep L3 on touched platforms."""
|
||||
platforms = buckets.l3_platforms()
|
||||
if not platforms:
|
||||
return None
|
||||
return cls(enable_l3_platforms=platforms)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CiDecision:
|
||||
"""Final CI skip decision for one diff."""
|
||||
|
||||
skip_all: bool = False
|
||||
skip_l2_l3: bool = False
|
||||
device: CiDevice = field(default_factory=CiDevice)
|
||||
message: str = ""
|
||||
|
||||
@classmethod
|
||||
def skip_all_basis(cls, buckets: DiffBuckets, *, diff_range: str | None) -> bool:
|
||||
"""Docs / pytest skip-mark only → suppress entire default CI."""
|
||||
if buckets.has_other_changes:
|
||||
return False
|
||||
if (buckets.has_l23_yaml_changes or buckets.has_l45_yaml_changes) and (
|
||||
buckets.has_doc_changes or buckets.has_skip_test_changes
|
||||
):
|
||||
return False
|
||||
if not buckets.has_doc_changes and not buckets.has_skip_test_changes:
|
||||
return False
|
||||
if diff_range is None and not buckets.has_doc_changes:
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def from_yaml_basis(
|
||||
cls,
|
||||
l2_l3_basis: SkipL2L3Basis | None,
|
||||
l3_basis: SkipL3Basis | None,
|
||||
l2_basis: SkipL2Basis | None,
|
||||
) -> CiDecision:
|
||||
"""Build a yaml-gated decision by merging L2/L3 skip bases.
|
||||
|
||||
Bases are applied as a union of enables: L2 yaml keeps L2 on touched
|
||||
platforms, L3 yaml keeps L3 on touched platforms. Cross-platform mixes
|
||||
(e.g. CUDA ready + AMD merge) must preserve both enables. The resulting
|
||||
per-platform / per-level matrix is stored on ``device`` as ``skip_*``.
|
||||
"""
|
||||
run = {platform: {"l2": True, "l3": True} for platform in PLATFORMS}
|
||||
|
||||
if l2_l3_basis is not None:
|
||||
if l2_l3_basis.skip_all_l2:
|
||||
for platform in PLATFORMS:
|
||||
run[platform]["l2"] = False
|
||||
if l2_l3_basis.skip_all_l3:
|
||||
for platform in PLATFORMS:
|
||||
run[platform]["l3"] = False
|
||||
|
||||
if l3_basis is not None:
|
||||
for platform in PLATFORMS:
|
||||
run[platform]["l3"] = False
|
||||
run[platform]["l2"] = platform in l3_basis.enable_l2_platforms
|
||||
|
||||
if l2_basis is not None:
|
||||
for platform in PLATFORMS:
|
||||
if platform in l2_basis.enable_l3_platforms:
|
||||
run[platform]["l3"] = True
|
||||
if l3_basis is None or platform not in l3_basis.enable_l2_platforms:
|
||||
run[platform]["l2"] = False
|
||||
elif l3_basis is None:
|
||||
# L3-yaml-only: disable platforms that did not change L3.
|
||||
run[platform]["l2"] = False
|
||||
run[platform]["l3"] = False
|
||||
# else: leave L2 enables from SkipL3Basis; keep this platform's L3 off.
|
||||
|
||||
return cls(
|
||||
skip_l2_l3=True,
|
||||
device=cls._device_from_run(run),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _device_from_run(run: dict[str, dict[str, bool]]) -> CiDevice:
|
||||
return CiDevice(
|
||||
**{f"skip_{platform}_{level}": not run[platform][level] for platform in PLATFORMS for level in ("l2", "l3")}
|
||||
)
|
||||
|
||||
def is_run(self, platform: str, level: str) -> bool:
|
||||
if self.skip_all:
|
||||
return False
|
||||
if not self.skip_l2_l3:
|
||||
return True
|
||||
if level not in L23_LEVELS:
|
||||
return True
|
||||
return not self.device.is_skip(platform, level)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CiContext:
|
||||
"""Skip-ci decision plus changed files used for pipeline filtering."""
|
||||
|
||||
decision: CiDecision
|
||||
changed_files: list[str] | None
|
||||
|
||||
|
||||
def _log(message: str) -> None:
|
||||
print(f"{LOG}: {message}", file=sys.stderr)
|
||||
|
||||
|
||||
def _git(*args: str) -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
["git", *args],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
# --- Diff helpers ---
|
||||
|
||||
|
||||
def _resolve_diff_range() -> str | None:
|
||||
"""Return a git diff range for PR or main builds, or None when unavailable."""
|
||||
is_pr = os.environ.get("BUILDKITE_PULL_REQUEST", "false") != "false" and os.environ.get(
|
||||
"BUILDKITE_PULL_REQUEST", ""
|
||||
)
|
||||
commit = os.environ.get("BUILDKITE_COMMIT", "")
|
||||
|
||||
if is_pr:
|
||||
base_branch = os.environ.get("BUILDKITE_PULL_REQUEST_BASE_BRANCH", "main")
|
||||
base_ref = f"origin/{base_branch}"
|
||||
if _git("rev-parse", "--verify", base_ref).returncode != 0:
|
||||
_log(f"origin/{base_branch} not found locally; trying fetch")
|
||||
_git("fetch", "--depth=200", "origin", base_branch)
|
||||
if _git("rev-parse", "--verify", base_ref).returncode != 0:
|
||||
if _git("rev-parse", "--verify", base_branch).returncode == 0:
|
||||
base_ref = base_branch
|
||||
else:
|
||||
_log(f"cannot resolve PR base {base_branch}; using safe defaults")
|
||||
return None
|
||||
return f"{base_ref}...{commit}"
|
||||
|
||||
if os.environ.get("BUILDKITE_BRANCH", "") == "main":
|
||||
if _git("rev-parse", "--verify", f"{commit}^").returncode != 0:
|
||||
_log("main commit has no parent; using safe defaults")
|
||||
return None
|
||||
return f"{commit}^..{commit}"
|
||||
|
||||
_log("not PR/main build; using safe defaults")
|
||||
return None
|
||||
|
||||
|
||||
def _changed_files_for_diff_range(diff_range: str | None) -> list[str] | None:
|
||||
"""Return changed file paths for *diff_range*, or None when unavailable."""
|
||||
if diff_range is None:
|
||||
return None
|
||||
|
||||
result = _git("diff", "--name-only", diff_range)
|
||||
if result.returncode != 0:
|
||||
_log(f"git diff failed ({diff_range}); using safe defaults")
|
||||
return None
|
||||
|
||||
files = [line for line in result.stdout.splitlines() if line.strip()]
|
||||
_log(f"{len(files)} changed file(s)")
|
||||
return files
|
||||
|
||||
|
||||
def resolve_ci_context_from_git() -> CiContext:
|
||||
"""Resolve git diff once and return skip-ci decision plus changed files."""
|
||||
diff_range = _resolve_diff_range()
|
||||
changed_files = _changed_files_for_diff_range(diff_range)
|
||||
decision = resolve_ci_decision(changed_files, diff_range=diff_range)
|
||||
return CiContext(decision=decision, changed_files=changed_files)
|
||||
|
||||
|
||||
# --- Doc / skip-mark helpers ---
|
||||
|
||||
|
||||
_SKIP_MARK_RE = re.compile(r"pytest\.mark\.skip(?:if)?\b|pytest\.skip\s*\(")
|
||||
_PYTESTMARK_SKIP_RE = re.compile(r"pytest\.mark\.skip\b")
|
||||
_PYTEST_MARK_ONLY_RE = re.compile(r"pytest\.mark\.\w+")
|
||||
|
||||
|
||||
def _diff_only_contains_skip_mark_changes(diff_text: str) -> bool:
|
||||
"""Return True when a unified diff only *adds* pytest skip marks.
|
||||
|
||||
Deleting a skip mark re-enables the test and must not suppress CI. Editing an
|
||||
existing skip (``-`` old / ``+`` new) still qualifies when at least one skip
|
||||
mark is added.
|
||||
"""
|
||||
|
||||
def paren_balance(line: str) -> int:
|
||||
return line.count("(") - line.count(")")
|
||||
|
||||
def is_blank_or_comment(line: str) -> bool:
|
||||
stripped = line.strip()
|
||||
return not stripped or stripped.startswith("#")
|
||||
|
||||
def is_skip_mark_line(line: str) -> bool:
|
||||
return _SKIP_MARK_RE.search(line.strip()) is not None
|
||||
|
||||
def is_pytestmark_adjacent_line(line: str) -> bool:
|
||||
stripped = line.strip().rstrip(",")
|
||||
if not stripped or stripped in {"[", "]"} or stripped.startswith("#"):
|
||||
return True
|
||||
if stripped.startswith("pytestmark"):
|
||||
return True
|
||||
return _PYTEST_MARK_ONLY_RE.search(stripped) is not None
|
||||
|
||||
pending_depth = 0
|
||||
saw_change = False
|
||||
has_added_skip_mark = False
|
||||
for raw_line in diff_text.splitlines():
|
||||
if raw_line.startswith("@@"):
|
||||
pending_depth = 0
|
||||
continue
|
||||
if not (raw_line.startswith("+") or raw_line.startswith("-")):
|
||||
continue
|
||||
if raw_line.startswith("+++") or raw_line.startswith("---"):
|
||||
continue
|
||||
|
||||
saw_change = True
|
||||
is_add = raw_line.startswith("+")
|
||||
content = raw_line[1:]
|
||||
|
||||
if pending_depth > 0:
|
||||
pending_depth += paren_balance(content)
|
||||
if pending_depth < 0:
|
||||
pending_depth = 0
|
||||
continue
|
||||
|
||||
if is_blank_or_comment(content):
|
||||
continue
|
||||
|
||||
if is_skip_mark_line(content):
|
||||
if is_add:
|
||||
has_added_skip_mark = True
|
||||
pending_depth = max(0, paren_balance(content))
|
||||
continue
|
||||
|
||||
if is_pytestmark_adjacent_line(content):
|
||||
continue
|
||||
|
||||
return False
|
||||
|
||||
return saw_change and has_added_skip_mark
|
||||
|
||||
|
||||
def _is_skip_testcase_change(file_path: str, *, diff_range: str) -> bool:
|
||||
"""Return True when a test file diff is skip-mark-only (including new-file cases)."""
|
||||
diff_result = _git("diff", diff_range, "--", file_path)
|
||||
if diff_result.returncode != 0:
|
||||
_log(f"skip-mark-only: git diff failed for {file_path}")
|
||||
return False
|
||||
|
||||
diff_text = diff_result.stdout
|
||||
if not diff_text.strip():
|
||||
_log(f"skip-mark-only: empty diff for {file_path}")
|
||||
return False
|
||||
|
||||
if _diff_only_contains_skip_mark_changes(diff_text):
|
||||
return True
|
||||
|
||||
if "new file mode" not in diff_text and "--- /dev/null" not in diff_text:
|
||||
_log(f"skip-mark-only: non-skip changes in {file_path}")
|
||||
return False
|
||||
|
||||
commit = os.environ.get("BUILDKITE_COMMIT", "")
|
||||
if not commit:
|
||||
return False
|
||||
|
||||
content_result = _git("show", f"{commit}:{file_path}")
|
||||
if content_result.returncode != 0:
|
||||
_log(f"skip-mark-only: cannot read {file_path} at {commit}")
|
||||
return False
|
||||
|
||||
content = content_result.stdout
|
||||
match = re.search(r"^pytestmark\s*=\s*\[(.*?)^\s*\]", content, re.MULTILINE | re.DOTALL)
|
||||
if match is not None and _PYTESTMARK_SKIP_RE.search(match.group(1)) is not None:
|
||||
_log(f"skip-mark-only: new test file with module-level pytest.mark.skip: {file_path}")
|
||||
return True
|
||||
if re.search(r"^pytestmark\s*=\s*pytest\.mark\.skip\b", content, re.MULTILINE):
|
||||
_log(f"skip-mark-only: new test file with module-level pytest.mark.skip: {file_path}")
|
||||
return True
|
||||
|
||||
_log(f"skip-mark-only: new test file without module-level pytest.mark.skip: {file_path}")
|
||||
return False
|
||||
|
||||
|
||||
def _classify_changed_files_into_buckets(changed_files: list[str], *, diff_range: str | None) -> DiffBuckets:
|
||||
"""Classify each changed file path into a ``DiffBuckets`` category."""
|
||||
buckets = DiffBuckets()
|
||||
for file_path in changed_files:
|
||||
if not file_path:
|
||||
continue
|
||||
if file_path.startswith("docs/") or file_path.endswith(".md") or file_path == "mkdocs.yml":
|
||||
buckets.docs.append(file_path)
|
||||
continue
|
||||
path = Path(file_path)
|
||||
if path.suffix == ".py" and path.parts and path.parts[0] == "tests":
|
||||
if diff_range is not None and _is_skip_testcase_change(file_path, diff_range=diff_range):
|
||||
buckets.skip_tests.append(file_path)
|
||||
else:
|
||||
buckets.other.append(file_path)
|
||||
continue
|
||||
if file_path in L2_YAML_FILES:
|
||||
platform = L2_YAML_FILES[file_path]
|
||||
buckets.l2[platform].append(file_path)
|
||||
elif file_path in L3_YAML_FILES:
|
||||
platform = L3_YAML_FILES[file_path]
|
||||
buckets.l3[platform].append(file_path)
|
||||
elif file_path in L45_YAML_FILES:
|
||||
platform = L45_YAML_FILES[file_path]
|
||||
buckets.l45[platform].append(file_path)
|
||||
else:
|
||||
buckets.other.append(file_path)
|
||||
return buckets
|
||||
|
||||
|
||||
# --- Decision ---
|
||||
|
||||
|
||||
def _finish(decision: CiDecision, message: str) -> CiDecision:
|
||||
finished = replace(decision, message=message)
|
||||
_log(message)
|
||||
return finished
|
||||
|
||||
|
||||
def _format_yaml_gated_message(buckets: DiffBuckets, decision: CiDecision) -> str:
|
||||
"""Human-readable summary of which CI YAML changed and which L2/L3 targets run."""
|
||||
changed_parts: list[str] = []
|
||||
for level_name, by_platform in (("L2", buckets.l2), ("L3", buckets.l3), ("L4/L5", buckets.l45)):
|
||||
files = [path for platform in PLATFORMS for path in by_platform[platform]]
|
||||
if files:
|
||||
changed_parts.append(f"{level_name}=[{', '.join(files)}]")
|
||||
|
||||
run_targets = [
|
||||
f"{platform}/{level}" for platform in PLATFORMS for level in ("l2", "l3") if decision.is_run(platform, level)
|
||||
]
|
||||
skip_targets = [
|
||||
f"{platform}/{level}"
|
||||
for platform in PLATFORMS
|
||||
for level in ("l2", "l3")
|
||||
if not decision.is_run(platform, level)
|
||||
]
|
||||
|
||||
changed = "; ".join(changed_parts) if changed_parts else "none"
|
||||
run = ", ".join(run_targets) if run_targets else "none"
|
||||
skip = ", ".join(skip_targets) if skip_targets else "none"
|
||||
if buckets.has_doc_changes or buckets.has_skip_test_changes:
|
||||
return (
|
||||
"CI config YAML + docs/skip-mark changed — follow CI YAML gating; "
|
||||
f"changed: {changed}; run: {run}; skip: {skip}"
|
||||
)
|
||||
return f"only CI config YAML changed — changed: {changed}; run: {run}; skip: {skip}"
|
||||
|
||||
|
||||
def resolve_ci_decision(
|
||||
changed_files: list[str] | None = None,
|
||||
*,
|
||||
diff_range: str | None = None,
|
||||
) -> CiDecision:
|
||||
if changed_files is None:
|
||||
return _finish(CiDecision(), "could not resolve changed files; run normal CI")
|
||||
|
||||
buckets = _classify_changed_files_into_buckets(changed_files, diff_range=diff_range)
|
||||
if buckets.has_other_changes or not buckets.has_skip_ci_scope_changes:
|
||||
return _finish(CiDecision(), "product or non-whitelisted changes present; run normal CI")
|
||||
|
||||
if CiDecision.skip_all_basis(buckets, diff_range=diff_range):
|
||||
return _finish(
|
||||
CiDecision(skip_all=True),
|
||||
"CI skipped — docs or pytest skip-mark changes only",
|
||||
)
|
||||
|
||||
# Docs / skip-mark mixed with whitelisted CI YAML → same yaml-gated path
|
||||
# as CI-YAML-only (docs/skip-mark do not widen to normal CI).
|
||||
if not buckets.has_l23_yaml_changes and not buckets.has_l45_yaml_changes:
|
||||
if buckets.has_skip_test_changes and diff_range is None:
|
||||
message = (
|
||||
"only pytest skip-mark test changes detected, but no git diff range "
|
||||
"is available to verify them (skip-all requires diff_range); run normal CI"
|
||||
)
|
||||
elif buckets.has_skip_test_changes:
|
||||
message = "pytest skip-mark test changes did not qualify for skip-all and no ci yaml changed; run normal CI"
|
||||
else:
|
||||
message = "doc/skip-mark changes did not qualify for skip-all; run normal CI"
|
||||
return _finish(CiDecision(), message)
|
||||
|
||||
decision = CiDecision.from_yaml_basis(
|
||||
SkipL2L3Basis.from_buckets(buckets),
|
||||
SkipL3Basis.from_buckets(buckets),
|
||||
SkipL2Basis.from_buckets(buckets),
|
||||
)
|
||||
return _finish(decision, _format_yaml_gated_message(buckets, decision))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
gate_parser = subparsers.add_parser(
|
||||
"gate",
|
||||
help="exit 0 when bootstrap should stop (skip-all or PLATFORM/LEVEL disabled); logs once",
|
||||
)
|
||||
gate_parser.add_argument("platform", help="cuda, amd, intel, or npu")
|
||||
gate_parser.add_argument("level", choices=("l2", "l3"), help="test level")
|
||||
|
||||
args = parser.parse_args()
|
||||
decision = resolve_ci_context_from_git().decision
|
||||
|
||||
if args.command == "gate":
|
||||
if decision.skip_all:
|
||||
print("skip-all")
|
||||
return 0
|
||||
if not decision.is_run(args.platform, args.level):
|
||||
print("skip-l23")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,882 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Render and optionally upload Buildkite pipeline YAML with diff-aware logic.
|
||||
|
||||
Bootstrap mode (``bootstrap-upload-steps.yml``):
|
||||
- Hook uploads the entry YAML (``pipeline.yml`` / ``pipeline-npu.yml``) with one step that runs
|
||||
``upload_pipeline.py --upload <platform>/bootstrap-upload-steps.yml``.
|
||||
- Injects ``if`` by step ``key`` from skip-ci and uploads child steps (image build, L2–L5 upload).
|
||||
- Detect docs-only, pytest skip-mark-only, or combined skip-ci from git diff.
|
||||
- When only CI level YAML changes, enable **L2/L3** upload steps for affected levels only.
|
||||
|
||||
Test pipeline mode (e.g. test-merge.yml, test-nightly.yml, test-weekly.yml):
|
||||
- Drop steps whose ``source_file_dependencies`` do not match changed files
|
||||
(string/list keys from ci_source_file_dependencies.yml, or inline path
|
||||
prefixes). Filtering applies on **PR label** uploads and on post-merge
|
||||
``main`` L3 uploads. Scheduled ``main`` uploads that pass ``--all``
|
||||
(NIGHTLY/WEEKLY) or ``--e2e`` keep every selected job and still strip
|
||||
the field. If no job-key prefix matches, a change to the pipeline YAML
|
||||
being uploaded or to a path under the ``source_filter_fallback`` registry
|
||||
key keeps every job so command, env, and hardware edits can be validated
|
||||
before merge. When any job-key prefix already matches, normal filtering
|
||||
wins.
|
||||
- Expand uploader-only ``mirror_hardwares`` into ``agents`` (+ optional ``image``
|
||||
for NPU) + ``plugins`` (see ci_mirror_hardwares.yml).
|
||||
- Omit ``mirror_hardwares`` to compose ``{chip}_{n}`` from pytest ``-m`` SKU
|
||||
markers plus ``cards_n`` (max of several positives; ``not cards_1`` with no
|
||||
positive ``cards_*`` uses that chip's highest existing preset). An explicit
|
||||
preset string (``h100_2``) is used as-is (marks are ignored). Names that
|
||||
are not keys in ``ci_mirror_hardwares.yml`` fail the upload.
|
||||
|
||||
Inferred chip: unset ``MIRROR_HW`` matches ``H100`` or ``L4`` in ``-m``
|
||||
(both → H100); no match skips the step. ``MIRROR_HW=b200`` matches
|
||||
``B200`` in ``-m`` (otherwise skipped). ``-m`` is not rewritten.
|
||||
``MIRROR_HW`` must be empty or ``b200``; unknown values fail the upload.
|
||||
A CUDA preset string such as ``h100_4`` is omitted when ``MIRROR_HW=b200``.
|
||||
|
||||
Usage:
|
||||
python3 upload_pipeline.py [--upload] [--all | --e2e] <pipeline.yml>
|
||||
|
||||
Requires PyYAML (``pip install pyyaml``); installs it automatically when missing.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ModuleNotFoundError:
|
||||
subprocess.run(
|
||||
[sys.executable, "-m", "pip", "install", "-q", "pyyaml"],
|
||||
check=True,
|
||||
)
|
||||
import yaml
|
||||
|
||||
from skip_ci import (
|
||||
ROOT,
|
||||
resolve_ci_context_from_git,
|
||||
)
|
||||
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from tests.helpers.mark import ( # noqa: E402
|
||||
get_skus_for_platform,
|
||||
get_supported_card_counts,
|
||||
)
|
||||
|
||||
# --- Constants ---
|
||||
|
||||
LOG = "upload_pipeline"
|
||||
BOOTSTRAP_STEPS_FILENAME = "bootstrap-upload-steps.yml"
|
||||
BOOTSTRAP_IMAGE_BUILD_KEYS = frozenset(
|
||||
{
|
||||
"image-build",
|
||||
"image-build-a2",
|
||||
"image-build-a3",
|
||||
"image-build-a5",
|
||||
"image-build-310p",
|
||||
}
|
||||
)
|
||||
BOOTSTRAP_UPLOAD_IF_KEYS = {
|
||||
"upload-ready-pipeline": "ready",
|
||||
"upload-merge-pipeline": "merge",
|
||||
"upload-nightly-pipeline": "nightly",
|
||||
"upload-weekly-pipeline": "weekly",
|
||||
}
|
||||
E2E_GROUP_MARKER = "E2E Test"
|
||||
CI_MIRROR_HARDWARES_PATH = ROOT / ".buildkite/common/ci_mirror_hardwares.yml"
|
||||
CI_SOURCE_FILE_DEPENDENCIES_PATH = ROOT / ".buildkite/common/ci_source_file_dependencies.yml"
|
||||
# Registry key whose prefixes bypass source filtering. Paths live in
|
||||
# ci_source_file_dependencies.yml; do not attach this key to a job.
|
||||
SOURCE_FILTER_FALLBACK_KEY = "source_filter_fallback"
|
||||
CUDA_HF_TOKEN_ENV = "VLLM_CI_HF_TOKEN"
|
||||
CUDA_HF_TOKEN_EXPORT = f'if [ -n "$${{{CUDA_HF_TOKEN_ENV}:-}}" ]; then export HF_TOKEN="$${{{CUDA_HF_TOKEN_ENV}}}"; fi'
|
||||
|
||||
# Bootstrap Buildkite ``if`` expressions.
|
||||
# ``*_MAIN_IF``: main + env schedule. ``*_LABEL_IF``: PR label (and/or composed with MAIN).
|
||||
# ``*_UPLOAD_IF``: full gate for uploading that child pipeline.
|
||||
NIGHTLY_MAIN_IF = 'build.branch == "main" && build.env("NIGHTLY") == "1"'
|
||||
NIGHTLY_LABEL_IF = (
|
||||
f'({NIGHTLY_MAIN_IF}) || (build.branch != "main" && build.pull_request.labels includes "nightly-test")'
|
||||
)
|
||||
WEEKLY_E2E_IF = 'build.branch == "main" && build.env("WEEKLY") == "1"'
|
||||
WEEKLY_MAIN_IF = 'build.branch == "main" && (build.env("WEEKLY") == "1" || build.env("NON_CRITICAL") == "1")'
|
||||
WEEKLY_LABEL_IF = f'({WEEKLY_MAIN_IF}) || (build.branch != "main" && build.pull_request.labels includes "weekly-test")'
|
||||
READY_LABEL_IF = 'build.branch != "main" && build.pull_request.labels includes "ready"'
|
||||
MERGE_LABEL_IF = 'build.branch != "main" && build.pull_request.labels includes "merge-test"'
|
||||
MERGE_MAIN_IF = (
|
||||
'build.branch == "main" && build.env("NIGHTLY") != "1" && '
|
||||
'build.env("WEEKLY") != "1" && build.env("NON_CRITICAL") != "1"'
|
||||
)
|
||||
READY_UPLOAD_IF = f"({WEEKLY_E2E_IF}) || ({READY_LABEL_IF})"
|
||||
MERGE_UPLOAD_IF = f"({WEEKLY_E2E_IF}) || (({MERGE_MAIN_IF}) || ({MERGE_LABEL_IF}))"
|
||||
BOOTSTRAP_DISABLED_IF = "false"
|
||||
BOOTSTRAP_ENABLED_IF = "true"
|
||||
|
||||
|
||||
# --- Logging ---
|
||||
|
||||
|
||||
def _log(message: str) -> None:
|
||||
print(f"{LOG}: {message}", file=sys.stderr)
|
||||
|
||||
|
||||
# --- Bootstrap pipeline (bootstrap-upload-steps.yml) ---
|
||||
|
||||
|
||||
def _get_bootstrap_platform(path: Path) -> str:
|
||||
parts = path.as_posix().split("/")
|
||||
return "npu" if "npu" in parts else "cuda"
|
||||
|
||||
|
||||
def _load_bootstrap_steps(path: Path) -> str:
|
||||
if path.name != BOOTSTRAP_STEPS_FILENAME:
|
||||
raise ValueError(f"expected {BOOTSTRAP_STEPS_FILENAME}, got {path.name}")
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def _format_bootstrap_if(expr: str) -> str:
|
||||
"""Return a Buildkite ``if`` string. Buildkite rejects YAML bool ``if`` values."""
|
||||
if expr in ("true", "false"):
|
||||
return expr
|
||||
return f"({expr})"
|
||||
|
||||
|
||||
def _compute_bootstrap_if_exprs(*, decision, platform: str) -> dict[str, str]:
|
||||
if platform == "npu":
|
||||
ready_upload = READY_LABEL_IF
|
||||
merge_upload = BOOTSTRAP_DISABLED_IF
|
||||
weekly_label_if = BOOTSTRAP_DISABLED_IF
|
||||
else:
|
||||
ready_upload = READY_UPLOAD_IF
|
||||
merge_upload = MERGE_UPLOAD_IF
|
||||
weekly_label_if = WEEKLY_LABEL_IF
|
||||
|
||||
if decision.skip_all:
|
||||
# Docs / skip-mark only: no PR-label escape hatch. Main scheduled
|
||||
# NIGHTLY=1 still runs L4; WEEKLY=1 / NON_CRITICAL=1 still run L5.
|
||||
# main+WEEKLY=1 also uploads L2/L3 (those steps then pass --e2e).
|
||||
image_expr = f"({NIGHTLY_MAIN_IF}) || ({WEEKLY_MAIN_IF})" if platform == "cuda" else NIGHTLY_MAIN_IF
|
||||
ready_expr = WEEKLY_E2E_IF if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
merge_expr = WEEKLY_E2E_IF if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
nightly_expr = NIGHTLY_MAIN_IF
|
||||
weekly_expr = WEEKLY_MAIN_IF if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
elif decision.skip_l2_l3:
|
||||
l2_enabled = decision.is_run("npu", "l2") if platform == "npu" else decision.is_run("cuda", "l2")
|
||||
l3_enabled = platform == "cuda" and decision.is_run("cuda", "l3")
|
||||
|
||||
ready_expr = ready_upload if l2_enabled else BOOTSTRAP_DISABLED_IF
|
||||
merge_expr = merge_upload if l3_enabled else BOOTSTRAP_DISABLED_IF
|
||||
nightly_expr = NIGHTLY_LABEL_IF
|
||||
weekly_expr = weekly_label_if if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
|
||||
image_parts = [f"({NIGHTLY_LABEL_IF})"]
|
||||
if platform == "cuda":
|
||||
image_parts.append(f"({weekly_label_if})")
|
||||
if l2_enabled:
|
||||
image_parts.insert(0, f"({ready_upload})")
|
||||
if l3_enabled:
|
||||
image_parts.insert(1 if l2_enabled else 0, f"({merge_upload})")
|
||||
image_expr = " || ".join(image_parts)
|
||||
else:
|
||||
image_expr = BOOTSTRAP_ENABLED_IF
|
||||
ready_expr = ready_upload
|
||||
merge_expr = merge_upload if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
nightly_expr = NIGHTLY_LABEL_IF
|
||||
weekly_expr = weekly_label_if if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
|
||||
return {
|
||||
"image": _format_bootstrap_if(image_expr),
|
||||
"ready": _format_bootstrap_if(ready_expr),
|
||||
"merge": _format_bootstrap_if(merge_expr),
|
||||
"nightly": _format_bootstrap_if(nightly_expr),
|
||||
"weekly": _format_bootstrap_if(weekly_expr),
|
||||
}
|
||||
|
||||
|
||||
def _apply_bootstrap_if(steps: list[Any], if_exprs: dict[str, str]) -> list[Any]:
|
||||
"""Inject ``if`` by step key; drop steps that are unconditionally disabled."""
|
||||
kept: list[Any] = []
|
||||
for step in steps:
|
||||
if not isinstance(step, dict):
|
||||
kept.append(step)
|
||||
continue
|
||||
nested = step.get("steps")
|
||||
if isinstance(nested, list):
|
||||
nested_kept = _apply_bootstrap_if(nested, if_exprs)
|
||||
if nested_kept:
|
||||
kept.append({**step, "steps": nested_kept})
|
||||
continue
|
||||
key = step.get("key")
|
||||
if key in BOOTSTRAP_IMAGE_BUILD_KEYS:
|
||||
step["if"] = if_exprs["image"]
|
||||
elif key in BOOTSTRAP_UPLOAD_IF_KEYS:
|
||||
step["if"] = if_exprs[BOOTSTRAP_UPLOAD_IF_KEYS[key]]
|
||||
if_expr = step.get("if")
|
||||
if if_expr == "false":
|
||||
_log(f"omit disabled bootstrap step {key!r}")
|
||||
continue
|
||||
if if_expr == "true":
|
||||
# Unconditional step: omit ``if`` (Buildkite requires string ``if``, not YAML bool).
|
||||
step.pop("if", None)
|
||||
kept.append(step)
|
||||
return kept
|
||||
|
||||
|
||||
def _render_bootstrap_pipeline(
|
||||
steps_yaml: str,
|
||||
*,
|
||||
decision,
|
||||
path: Path,
|
||||
) -> str:
|
||||
"""Load bootstrap steps YAML and inject ``if`` expressions from skip-ci decision."""
|
||||
doc = yaml.safe_load(steps_yaml)
|
||||
if not isinstance(doc, dict):
|
||||
raise ValueError(f"invalid bootstrap steps YAML for {path}")
|
||||
steps = doc.get("steps")
|
||||
if not isinstance(steps, list):
|
||||
raise ValueError(f"bootstrap steps YAML must contain steps: list in {path}")
|
||||
|
||||
platform = _get_bootstrap_platform(path)
|
||||
if_exprs = _compute_bootstrap_if_exprs(decision=decision, platform=platform)
|
||||
doc["steps"] = _apply_bootstrap_if(steps, if_exprs)
|
||||
return yaml.safe_dump(doc, sort_keys=False)
|
||||
|
||||
|
||||
# --- Test pipeline (test-ready.yml, test-merge.yml, test-nightly.yml) ---
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _load_mirror_hardwares() -> dict[str, dict[str, Any]]:
|
||||
if not CI_MIRROR_HARDWARES_PATH.is_file():
|
||||
raise FileNotFoundError(f"missing CI mirror_hardwares registry: {CI_MIRROR_HARDWARES_PATH}")
|
||||
doc = yaml.safe_load(CI_MIRROR_HARDWARES_PATH.read_text(encoding="utf-8"))
|
||||
if not isinstance(doc, dict):
|
||||
raise ValueError(f"invalid CI mirror_hardwares registry: {CI_MIRROR_HARDWARES_PATH}")
|
||||
presets = doc.get("mirror_hardwares")
|
||||
if not isinstance(presets, dict):
|
||||
raise ValueError(f"mirror_hardwares must be a mapping in {CI_MIRROR_HARDWARES_PATH}")
|
||||
return presets
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _load_source_file_dependencies() -> dict[str, list[str]]:
|
||||
def flatten(value: Any, *, key: str) -> list[str]:
|
||||
"""Flatten YAML-anchor nested lists into a de-duplicated prefix list."""
|
||||
if isinstance(value, str):
|
||||
if not value.strip():
|
||||
raise ValueError(f"empty path in source_file_dependencies[{key!r}]")
|
||||
return [value]
|
||||
if isinstance(value, list):
|
||||
flattened: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for item in value:
|
||||
for path in flatten(item, key=key):
|
||||
if path not in seen:
|
||||
seen.add(path)
|
||||
flattened.append(path)
|
||||
return flattened
|
||||
raise ValueError(
|
||||
f"source_file_dependencies[{key!r}] must be a list of path prefixes, got {type(value).__name__}",
|
||||
)
|
||||
|
||||
if not CI_SOURCE_FILE_DEPENDENCIES_PATH.is_file():
|
||||
raise FileNotFoundError(
|
||||
f"missing CI source_file_dependencies registry: {CI_SOURCE_FILE_DEPENDENCIES_PATH}",
|
||||
)
|
||||
doc = yaml.safe_load(CI_SOURCE_FILE_DEPENDENCIES_PATH.read_text(encoding="utf-8"))
|
||||
if not isinstance(doc, dict):
|
||||
raise ValueError(f"invalid CI source_file_dependencies registry: {CI_SOURCE_FILE_DEPENDENCIES_PATH}")
|
||||
presets = doc.get("source_file_dependencies")
|
||||
if not isinstance(presets, dict):
|
||||
raise ValueError(f"source_file_dependencies must be a mapping in {CI_SOURCE_FILE_DEPENDENCIES_PATH}")
|
||||
loaded: dict[str, list[str]] = {}
|
||||
for key, value in presets.items():
|
||||
if not isinstance(key, str) or not key.strip():
|
||||
raise ValueError(
|
||||
f"source_file_dependencies keys must be non-empty strings in {CI_SOURCE_FILE_DEPENDENCIES_PATH}",
|
||||
)
|
||||
loaded[key] = flatten(value, key=key)
|
||||
return loaded
|
||||
|
||||
|
||||
_REGISTRY_KEY_RE = re.compile(r"^[a-z][a-z0-9_]*$")
|
||||
|
||||
|
||||
def _parse_command_text(step: dict[str, Any]) -> str:
|
||||
"""Parse step ``commands`` / ``command`` into a single string."""
|
||||
raw = step.get("commands", step.get("command"))
|
||||
if raw is None:
|
||||
return ""
|
||||
if isinstance(raw, str):
|
||||
return raw
|
||||
if isinstance(raw, list):
|
||||
return "\n".join(str(item) for item in raw if item is not None)
|
||||
return str(raw)
|
||||
|
||||
|
||||
def _resolve_source_file_dependencies(step: dict[str, Any]) -> list[str] | None:
|
||||
"""Expand a registry key (or list of keys / inline path prefixes)."""
|
||||
deps = step.get("source_file_dependencies")
|
||||
if deps is None:
|
||||
return None
|
||||
|
||||
def dedupe(*groups: list[str]) -> list[str]:
|
||||
merged: list[str] = []
|
||||
seen: set[str] = set()
|
||||
for group in groups:
|
||||
for path in group:
|
||||
if path not in seen:
|
||||
seen.add(path)
|
||||
merged.append(path)
|
||||
return merged
|
||||
|
||||
def lookup(key: str) -> list[str]:
|
||||
if key == SOURCE_FILTER_FALLBACK_KEY:
|
||||
raise ValueError(
|
||||
f"source_file_dependencies {key!r} bypasses filtering and cannot be attached to a step "
|
||||
f"({_get_step_label(step)!r})",
|
||||
)
|
||||
registry = _load_source_file_dependencies()
|
||||
paths = registry.get(key)
|
||||
if paths is None:
|
||||
known = ", ".join(sorted(registry))
|
||||
raise ValueError(
|
||||
f"unknown source_file_dependencies {key!r} in step {_get_step_label(step)!r}; known: {known}",
|
||||
)
|
||||
return list(paths)
|
||||
|
||||
prefixes: list[str]
|
||||
if isinstance(deps, str):
|
||||
prefixes = lookup(deps) if _REGISTRY_KEY_RE.fullmatch(deps) else [deps]
|
||||
elif isinstance(deps, list):
|
||||
if not all(isinstance(item, str) for item in deps):
|
||||
raise ValueError(
|
||||
f"source_file_dependencies must be a string key or list of strings in step {_get_step_label(step)!r}",
|
||||
)
|
||||
keyish = [bool(_REGISTRY_KEY_RE.fullmatch(item)) for item in deps]
|
||||
if deps and all(keyish):
|
||||
prefixes = dedupe(*(lookup(key) for key in deps))
|
||||
elif any(keyish):
|
||||
raise ValueError(
|
||||
f"source_file_dependencies in step {_get_step_label(step)!r} mixes registry keys and path prefixes",
|
||||
)
|
||||
else:
|
||||
prefixes = list(deps)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"source_file_dependencies must be a string key or list in step {_get_step_label(step)!r}",
|
||||
)
|
||||
return prefixes
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _cuda_mirror_chips() -> tuple[str, ...]:
|
||||
"""Lowercase CUDA SKUs that have at least one ``{chip}_{n}`` preset.
|
||||
|
||||
Longer tokens first so ``h100`` is not matched as a prefix of ``h200``.
|
||||
"""
|
||||
skus = get_skus_for_platform("cuda")
|
||||
known = _load_mirror_hardwares()
|
||||
chips = {
|
||||
sku.lower() for sku in skus if any(name == sku.lower() or name.startswith(f"{sku.lower()}_") for name in known)
|
||||
}
|
||||
return tuple(sorted(chips, key=lambda chip: (-len(chip), chip)))
|
||||
|
||||
|
||||
def _parse_cards_marks(expr: str) -> tuple[set[int], bool]:
|
||||
"""Parse registered ``cards_n`` / ``not cards_n`` from a pytest ``-m`` expr.
|
||||
|
||||
Returns positive card counts and whether any ``not cards_*`` is present.
|
||||
"""
|
||||
counts = get_supported_card_counts()
|
||||
alt = "|".join(str(n) for n in sorted(counts, key=lambda n: (-len(str(n)), -n))) if counts else "(?!)"
|
||||
positives: set[int] = set()
|
||||
has_not_cards = False
|
||||
for match in re.finditer(rf"\b(?:(not)\s+)?cards_({alt})\b", expr):
|
||||
if match.group(1):
|
||||
has_not_cards = True
|
||||
else:
|
||||
positives.add(int(match.group(2)))
|
||||
return positives, has_not_cards
|
||||
|
||||
|
||||
def _parse_hardware_marks(expr: str) -> set[str]:
|
||||
"""Parse lowercase positive CUDA SKUs that have a mirror preset.
|
||||
|
||||
``not H100`` is ignored. SKUs with no ``{chip}_*`` preset (e.g. H200) are dropped.
|
||||
"""
|
||||
skus = sorted(get_skus_for_platform("cuda"), key=lambda s: (-len(s), s))
|
||||
if not skus:
|
||||
return set()
|
||||
alt = "|".join(re.escape(sku) for sku in skus)
|
||||
mirror = set(_cuda_mirror_chips())
|
||||
chips: set[str] = set()
|
||||
for match in re.finditer(rf"\b(?:(not)\s+)?({alt})\b", expr):
|
||||
if match.group(1):
|
||||
continue
|
||||
chip = match.group(2).lower()
|
||||
if chip in mirror:
|
||||
chips.add(chip)
|
||||
return chips
|
||||
|
||||
|
||||
# CI policy: not pytest-mark registry.
|
||||
_SUPPORTED_MIRROR_HW_SELECTORS = frozenset({"b200"})
|
||||
# Unset MIRROR_HW: match H100 then L4 in -m (skip if neither).
|
||||
_DEFAULT_INFER_CHIPS = ("h100", "l4")
|
||||
_PYTEST_MARKER_ARG = re.compile(r"-m\s+(?:\"([^\"]*)\"|'([^']*)'|(\S+))")
|
||||
_CARDS_CHIP_MAX: Literal["max"] = "max"
|
||||
|
||||
|
||||
def _get_mirror_hw_selector() -> str:
|
||||
"""Return lowercase ``MIRROR_HW``, or empty to keep string presets / marker chips.
|
||||
|
||||
A set value must be ``b200`` (case-insensitive). Unknown values fail closed
|
||||
so a typo cannot silently drop the CUDA pipeline.
|
||||
"""
|
||||
selector = os.environ.get("MIRROR_HW", "").strip().lower()
|
||||
if not selector:
|
||||
return ""
|
||||
if selector not in _SUPPORTED_MIRROR_HW_SELECTORS:
|
||||
allowed = " or ".join(repr(s) for s in sorted(_SUPPORTED_MIRROR_HW_SELECTORS))
|
||||
raise ValueError(f"unsupported MIRROR_HW={selector!r}; expected empty or {allowed}")
|
||||
return selector
|
||||
|
||||
|
||||
def _parse_pytest_marks(step: dict[str, Any]) -> tuple[set[str], int | Literal["max"] | None]:
|
||||
"""Parse pytest ``-m`` from step commands: CUDA SKU chips and cards count.
|
||||
|
||||
*chips* are lowercase SKUs from positive markers (``not H100`` is ignored).
|
||||
*cards* is the max positive ``cards_n``, ``"max"`` when only ``not cards_*``
|
||||
is present, or ``None``.
|
||||
"""
|
||||
text = _parse_command_text(step)
|
||||
|
||||
chips: set[str] = set()
|
||||
positives: set[int] = set()
|
||||
has_not_cards = False
|
||||
for match in _PYTEST_MARKER_ARG.finditer(text):
|
||||
expr = match.group(1) or match.group(2) or match.group(3) or ""
|
||||
chips |= _parse_hardware_marks(expr)
|
||||
card_counts, not_cards = _parse_cards_marks(expr)
|
||||
positives.update(card_counts)
|
||||
has_not_cards = has_not_cards or not_cards
|
||||
|
||||
if positives:
|
||||
cards: int | Literal["max"] | None = max(positives)
|
||||
elif has_not_cards:
|
||||
cards = _CARDS_CHIP_MAX
|
||||
else:
|
||||
cards = None
|
||||
return chips, cards
|
||||
|
||||
|
||||
def _compose_mirror_hardware_name(
|
||||
chips: set[str],
|
||||
cards: int | Literal["max"] | None,
|
||||
*,
|
||||
step_label: str,
|
||||
) -> str | None:
|
||||
"""Assemble ``{chip}_{n}`` from pytest ``-m`` chips/cards, or None to skip.
|
||||
|
||||
Unset ``MIRROR_HW``: ``H100`` if in ``-m``, else ``L4``, else skip.
|
||||
Set ``MIRROR_HW``: that chip if in ``-m``, else skip.
|
||||
``cards`` is a registered ``cards_n``, ``"max"`` for that chip's highest
|
||||
existing preset, or None (error after a chip matched — no ``cards_*``).
|
||||
"""
|
||||
selector = _get_mirror_hw_selector()
|
||||
if selector:
|
||||
chip = selector if selector in chips else None
|
||||
skip_reason = f"MIRROR_HW={selector!r} not in -m SKUs {sorted(chips)}"
|
||||
else:
|
||||
chip = next((c for c in _DEFAULT_INFER_CHIPS if c in chips), None)
|
||||
skip_reason = f"no H100 or L4 in -m SKUs {sorted(chips)}"
|
||||
if chip is None:
|
||||
_log(f"skip {step_label}: {skip_reason}")
|
||||
return None
|
||||
if cards is None:
|
||||
raise ValueError(
|
||||
f"step {step_label!r} has a pytest -m SKU marker but no cards_* "
|
||||
f"(or not cards_*); add cards_n or set mirror_hardwares to force a preset",
|
||||
)
|
||||
|
||||
count_source = "not cards_*" if cards == _CARDS_CHIP_MAX else f"cards_{cards}"
|
||||
count = None if cards == _CARDS_CHIP_MAX else cards
|
||||
registered = get_supported_card_counts()
|
||||
if count is not None and count not in registered:
|
||||
supported = ", ".join(f"cards_{n}" for n in sorted(registered)) or "(none)"
|
||||
raise ValueError(
|
||||
f"{count_source} in step {step_label!r} is not a registered cards_* mark; supported: {supported}",
|
||||
)
|
||||
known = _load_mirror_hardwares()
|
||||
if count is None:
|
||||
available = [n for n in sorted(registered) if f"{chip}_{n}" in known]
|
||||
if not available:
|
||||
raise ValueError(
|
||||
f"{count_source} in step {step_label!r} has no CUDA count presets for {chip}",
|
||||
)
|
||||
count = max(available)
|
||||
chosen = f"{chip}_{count}"
|
||||
if chosen not in known:
|
||||
raise ValueError(
|
||||
f"{count_source} in step {step_label!r} has no preset {chosen!r}",
|
||||
)
|
||||
_log(f"{step_label}: {count_source} → {chosen!r}")
|
||||
return chosen
|
||||
|
||||
|
||||
def _resolve_mirror_hardware_name(hardware: Any, *, step_label: str) -> str | None:
|
||||
"""Map ``mirror_hardwares`` to a ``ci_mirror_hardwares.yml`` preset, or None to skip.
|
||||
|
||||
The value is a preset name (``h100_2``). Unknown names fail later when the
|
||||
registry is loaded. CUDA names are omitted when ``MIRROR_HW`` names a
|
||||
different chip; NPU strings ignore ``MIRROR_HW``.
|
||||
"""
|
||||
if isinstance(hardware, bool):
|
||||
raise ValueError(f"mirror_hardwares must not be a boolean in step {step_label!r}")
|
||||
if isinstance(hardware, str):
|
||||
name = hardware.strip()
|
||||
elif isinstance(hardware, int):
|
||||
name = str(hardware)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"mirror_hardwares must be a preset string in step {step_label!r}",
|
||||
)
|
||||
if not name:
|
||||
raise ValueError(f"mirror_hardwares must be a non-empty string in step {step_label!r}")
|
||||
|
||||
selector = _get_mirror_hw_selector()
|
||||
token = name.lower()
|
||||
chip = next(
|
||||
(c for c in _cuda_mirror_chips() if token == c or token.startswith(f"{c}_")),
|
||||
None,
|
||||
)
|
||||
if selector and chip is not None and chip != selector:
|
||||
_log(
|
||||
f"skip {step_label}: preset {name!r} is {chip} hardware; MIRROR_HW={selector!r}",
|
||||
)
|
||||
return None
|
||||
return name
|
||||
|
||||
|
||||
def _expand_mirror_hardwares(step: dict[str, Any]) -> dict[str, Any] | None:
|
||||
"""Replace ``mirror_hardwares`` (or infer it from ``-m``) with preset agents/plugins.
|
||||
|
||||
Explicit preset string: used as-is; pytest marks are ignored.
|
||||
Omitted key: match H100/L4 (or ``MIRROR_HW``) in ``-m``, then compose
|
||||
``{chip}_{n}`` from ``cards_n``. No match skips the step. Steps with no
|
||||
SKU/cards and no ``mirror_hardwares`` are left unchanged (CPU jobs).
|
||||
|
||||
Returns None when the current ``MIRROR_HW`` selector does not apply.
|
||||
"""
|
||||
step_label = _get_step_label(step)
|
||||
has_pool = step.get("agents") is not None or step.get("plugins") is not None or step.get("image") is not None
|
||||
|
||||
if "mirror_hardwares" not in step:
|
||||
if has_pool:
|
||||
return step
|
||||
chips, cards = _parse_pytest_marks(step)
|
||||
if not chips and cards is None:
|
||||
return step
|
||||
preset_name = _compose_mirror_hardware_name(chips, cards, step_label=step_label)
|
||||
else:
|
||||
if has_pool:
|
||||
raise ValueError(
|
||||
f"step {step_label!r} sets mirror_hardwares together with agents/plugins/image; "
|
||||
f"use mirror_hardwares only",
|
||||
)
|
||||
preset_name = _resolve_mirror_hardware_name(
|
||||
step.get("mirror_hardwares"),
|
||||
step_label=step_label,
|
||||
)
|
||||
|
||||
if preset_name is None:
|
||||
return None
|
||||
|
||||
preset = _load_mirror_hardwares().get(preset_name)
|
||||
if preset is None:
|
||||
known = ", ".join(sorted(_load_mirror_hardwares()))
|
||||
raise ValueError(
|
||||
f"unknown mirror_hardwares {preset_name!r} in step {step_label!r}; known: {known}",
|
||||
)
|
||||
|
||||
expanded = copy.deepcopy(preset)
|
||||
merged = {key: value for key, value in step.items() if key != "mirror_hardwares"} | expanded
|
||||
# A scheduled build's HF_TOKEN may override a pod env entry with the same
|
||||
# name. The preset injects the Kubernetes secret under a collision-proof
|
||||
# alias; restore the conventional name after Buildkite has merged env.
|
||||
if any(preset_name == chip or preset_name.startswith(f"{chip}_") for chip in _cuda_mirror_chips()):
|
||||
commands = merged.get("commands")
|
||||
if isinstance(commands, list):
|
||||
merged["commands"] = [CUDA_HF_TOKEN_EXPORT, *commands]
|
||||
elif commands is None:
|
||||
merged["commands"] = [CUDA_HF_TOKEN_EXPORT]
|
||||
else:
|
||||
merged["commands"] = [CUDA_HF_TOKEN_EXPORT, commands]
|
||||
# Preset retry (K8S_RETRY on l4_*) must not clobber a step that opted out.
|
||||
if "retry" in step:
|
||||
merged["retry"] = step["retry"]
|
||||
return merged
|
||||
|
||||
|
||||
def _match_source_file(changed_files: list[str], prefixes: list[str]) -> bool:
|
||||
for path in changed_files:
|
||||
for prefix in prefixes:
|
||||
normalized = prefix.rstrip("/")
|
||||
if path == normalized or path.startswith(f"{normalized}/"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _get_step_label(step: dict[str, Any]) -> str:
|
||||
return str(step.get("group") or step.get("label") or "<step>")
|
||||
|
||||
|
||||
def _process_test_steps(
|
||||
steps: list[Any],
|
||||
changed_files: list[str] | None,
|
||||
) -> list[Any]:
|
||||
"""Drop steps by ``source_file_dependencies`` when *changed_files* is set; always strip that field."""
|
||||
processed: list[Any] = []
|
||||
for step in steps:
|
||||
if not isinstance(step, dict):
|
||||
processed.append(step)
|
||||
continue
|
||||
|
||||
deps = _resolve_source_file_dependencies(step)
|
||||
if changed_files is not None and deps is not None and not _match_source_file(changed_files, deps):
|
||||
_log(f"skip {_get_step_label(step)!r} (no changes under {deps})")
|
||||
continue
|
||||
|
||||
nested = step.get("steps")
|
||||
if nested is not None:
|
||||
kept_nested = _process_test_steps(nested, changed_files)
|
||||
if not kept_nested:
|
||||
_log(f"omit empty group {_get_step_label(step)!r}")
|
||||
continue
|
||||
new_step = {key: value for key, value in step.items() if key != "source_file_dependencies"}
|
||||
new_step["steps"] = kept_nested
|
||||
processed.append(new_step)
|
||||
continue
|
||||
|
||||
leaf = {key: value for key, value in step.items() if key != "source_file_dependencies"}
|
||||
expanded = _expand_mirror_hardwares(leaf)
|
||||
if expanded is None:
|
||||
continue
|
||||
processed.append(expanded)
|
||||
|
||||
return processed
|
||||
|
||||
|
||||
def _select_e2e_group_steps(steps: list[Any]) -> list[Any]:
|
||||
"""Keep only top-level groups whose name contains ``E2E_GROUP_MARKER``."""
|
||||
selected = [
|
||||
step
|
||||
for step in steps
|
||||
if isinstance(step, dict) and isinstance(step.get("group"), str) and E2E_GROUP_MARKER in step["group"]
|
||||
]
|
||||
if not selected:
|
||||
_log(f"no group matching {E2E_GROUP_MARKER!r} found")
|
||||
else:
|
||||
_log(f"keep {len(selected)} group(s) matching {E2E_GROUP_MARKER!r}")
|
||||
return selected
|
||||
|
||||
|
||||
def _any_source_dependency_match(steps: list[Any], changed_files: list[str]) -> bool:
|
||||
"""True when any step with ``source_file_dependencies`` matches *changed_files*."""
|
||||
for step in steps:
|
||||
if not isinstance(step, dict):
|
||||
continue
|
||||
deps = _resolve_source_file_dependencies(step)
|
||||
if deps is not None and _match_source_file(changed_files, deps):
|
||||
return True
|
||||
nested = step.get("steps")
|
||||
if isinstance(nested, list) and _any_source_dependency_match(nested, changed_files):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _render_test_pipeline(
|
||||
doc: dict[str, Any],
|
||||
changed_files: list[str] | None,
|
||||
*,
|
||||
pipeline_path: Path | None = None,
|
||||
e2e_only: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Filter steps by PR diff and strip uploader-only ``source_file_dependencies`` metadata."""
|
||||
# Validate MIRROR_HW once up front. Per-step skip must not run for typos
|
||||
# (e.g. b20o), or a pipeline can shrink to leftover CPU-only steps and
|
||||
# still upload successfully.
|
||||
_get_mirror_hw_selector()
|
||||
steps = doc.get("steps")
|
||||
if not isinstance(steps, list):
|
||||
return doc
|
||||
if e2e_only:
|
||||
steps = _select_e2e_group_steps(steps)
|
||||
# Bypass is a fallback: only when no job-key prefix matched.
|
||||
if changed_files is not None and pipeline_path is not None:
|
||||
if not _any_source_dependency_match(steps, changed_files):
|
||||
bypass = _source_filter_fallback_reason(changed_files, pipeline_path)
|
||||
if bypass is not None:
|
||||
_log(f"keep all jobs (no source_file_dependencies match; bypassed by {bypass})")
|
||||
changed_files = None
|
||||
steps = _process_test_steps(steps, changed_files)
|
||||
return {**doc, "steps": steps}
|
||||
|
||||
|
||||
# --- Entry (read file → bootstrap or test render → YAML string) ---
|
||||
|
||||
|
||||
def _repo_relative_posix(path: Path) -> str:
|
||||
resolved = path.resolve()
|
||||
try:
|
||||
return resolved.relative_to(ROOT).as_posix()
|
||||
except ValueError:
|
||||
return path.as_posix().replace("\\", "/")
|
||||
|
||||
|
||||
def _source_filter_fallback_prefixes() -> list[str]:
|
||||
"""Shared uploader/registry prefixes from ``source_filter_fallback``. Not a job key."""
|
||||
registry = _load_source_file_dependencies()
|
||||
prefixes = registry.get(SOURCE_FILTER_FALLBACK_KEY)
|
||||
if not prefixes:
|
||||
raise ValueError(
|
||||
f"source_file_dependencies[{SOURCE_FILTER_FALLBACK_KEY!r}] must list shared uploader paths "
|
||||
f"in {CI_SOURCE_FILE_DEPENDENCIES_PATH}",
|
||||
)
|
||||
return prefixes
|
||||
|
||||
|
||||
def _source_filter_fallback_reason(changed_files: list[str] | None, pipeline_path: Path) -> str | None:
|
||||
"""Return the changed path that should disable source filtering, if any."""
|
||||
if not changed_files:
|
||||
return None
|
||||
changed = set(changed_files)
|
||||
pipeline_rel = _repo_relative_posix(pipeline_path)
|
||||
if pipeline_rel in changed:
|
||||
return pipeline_rel
|
||||
prefixes = _source_filter_fallback_prefixes()
|
||||
for path in changed_files:
|
||||
if _match_source_file([path], prefixes):
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
def _changed_files_for_source_filter(
|
||||
ctx,
|
||||
*,
|
||||
force_all: bool,
|
||||
e2e_only: bool,
|
||||
) -> list[str] | None:
|
||||
"""Return the diff to filter against, or None to keep every step.
|
||||
|
||||
``--all`` / ``--e2e`` disable filtering (scheduled NIGHTLY/WEEKLY full
|
||||
uploads and weekly E2E sweeps). Post-merge ``main`` L3 and PR-label
|
||||
uploads filter against the commit/PR diff. Pipeline YAML /
|
||||
``source_filter_fallback`` matches are applied later in
|
||||
``_render_test_pipeline`` only when no job-key prefix already matched.
|
||||
"""
|
||||
if force_all or e2e_only:
|
||||
return None
|
||||
return ctx.changed_files
|
||||
|
||||
|
||||
def _render_pipeline(
|
||||
path: Path,
|
||||
*,
|
||||
force_all: bool = False,
|
||||
e2e_only: bool = False,
|
||||
) -> str:
|
||||
if path.name == BOOTSTRAP_STEPS_FILENAME:
|
||||
ctx = resolve_ci_context_from_git()
|
||||
continuation = _load_bootstrap_steps(path)
|
||||
return _render_bootstrap_pipeline(
|
||||
continuation,
|
||||
decision=ctx.decision,
|
||||
path=path,
|
||||
)
|
||||
|
||||
text = path.read_text(encoding="utf-8")
|
||||
ctx = resolve_ci_context_from_git()
|
||||
changed_files = _changed_files_for_source_filter(ctx, force_all=force_all, e2e_only=e2e_only)
|
||||
|
||||
doc = yaml.safe_load(text)
|
||||
if not isinstance(doc, dict):
|
||||
raise ValueError(f"invalid pipeline YAML: {path}")
|
||||
|
||||
doc = _render_test_pipeline(
|
||||
doc,
|
||||
changed_files,
|
||||
pipeline_path=path,
|
||||
e2e_only=e2e_only,
|
||||
)
|
||||
return yaml.safe_dump(doc, sort_keys=False)
|
||||
|
||||
|
||||
def _upload_to_buildkite(content: str) -> None:
|
||||
subprocess.run(
|
||||
["buildkite-agent", "pipeline", "upload"],
|
||||
input=content,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
# --- CLI ---
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"pipeline",
|
||||
nargs="?",
|
||||
default=".buildkite/cuda/bootstrap-upload-steps.yml",
|
||||
help="Pipeline YAML path (default: .buildkite/cuda/bootstrap-upload-steps.yml)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--upload",
|
||||
action="store_true",
|
||||
help="Pipe rendered YAML to buildkite-agent pipeline upload",
|
||||
)
|
||||
mode = parser.add_mutually_exclusive_group()
|
||||
mode.add_argument(
|
||||
"--all",
|
||||
action="store_true",
|
||||
help="Keep all steps (disable diff-aware skipping)",
|
||||
)
|
||||
mode.add_argument(
|
||||
"--e2e",
|
||||
action="store_true",
|
||||
help="Keep only the E2E Test group",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
path = Path(args.pipeline)
|
||||
if not path.is_absolute():
|
||||
path = ROOT / path
|
||||
if not path.is_file():
|
||||
_log(f"missing pipeline file: {path}")
|
||||
return 1
|
||||
|
||||
rendered = _render_pipeline(path, force_all=args.all, e2e_only=args.e2e)
|
||||
if args.upload:
|
||||
_upload_to_buildkite(rendered)
|
||||
else:
|
||||
sys.stdout.write(rendered)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,66 @@
|
||||
# Uploaded by upload_pipeline.py --upload (not the Buildkite hook).
|
||||
# ``if`` is injected by step ``key`` from skip-ci at upload time.
|
||||
steps:
|
||||
- label: ":docker: Build image"
|
||||
key: image-build
|
||||
commands:
|
||||
- "bash .buildkite/cuda/scripts/build-ci-image.sh"
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L2 Test — PR ready label (diff-aware) or main+WEEKLY=1 (--e2e, full E2E group)
|
||||
- label: "Upload Ready Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-ready-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${WEEKLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--e2e"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-ready.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L3 Test — PR merge-test label or post-merge on main (both diff-aware);
|
||||
# main+WEEKLY=1 uploads the E2E group only (--e2e).
|
||||
- label: "Upload Merge Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-merge-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${WEEKLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--e2e"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-merge.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L4 Test — main+NIGHTLY=1 (full pipeline), or PR nightly-test label (diff-aware)
|
||||
- label: "Upload Nightly Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-nightly-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${NIGHTLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--all"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-nightly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L5 Test — main+WEEKLY=1 / NON_CRITICAL=1 (full pipeline), or PR weekly-test label (diff-aware)
|
||||
- label: "Upload Weekly Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-weekly-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--all"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-weekly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
@@ -0,0 +1,9 @@
|
||||
# Hook uploads this entry YAML; upload_pipeline.py --upload reads bootstrap-upload-steps.yml
|
||||
# and injects ``if`` by step ``key`` from skip-ci.
|
||||
steps:
|
||||
- label: ":github: Resolve skip-ci & upload pipeline"
|
||||
key: upload-ci-pipeline
|
||||
commands:
|
||||
- "python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/cuda/bootstrap-upload-steps.yml"
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
@@ -2,10 +2,7 @@ steps:
|
||||
- label: ":docker: Build image"
|
||||
key: image-build
|
||||
commands:
|
||||
- "aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/q9t5s3a7"
|
||||
- "docker build --progress=plain --file docker/Dockerfile.ci -t vllm-omni-ci ."
|
||||
- "docker tag vllm-omni-ci public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT"
|
||||
- "docker push public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT"
|
||||
- "bash .buildkite/cuda/scripts/build-ci-image.sh"
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
@@ -14,7 +11,7 @@ steps:
|
||||
depends_on: image-build
|
||||
key: upload-ready-pipeline
|
||||
commands:
|
||||
- python3 .buildkite/scripts/upload_pipeline.py --upload .buildkite/test-ready.yml
|
||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload --all .buildkite/cuda/test-ready.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
@@ -23,7 +20,7 @@ steps:
|
||||
depends_on: image-build
|
||||
key: upload-merge-pipeline
|
||||
commands:
|
||||
- python3 .buildkite/scripts/upload_pipeline.py --upload .buildkite/test-merge.yml
|
||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload --all .buildkite/cuda/test-merge.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
@@ -33,6 +30,6 @@ steps:
|
||||
key: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1"
|
||||
commands:
|
||||
- buildkite-agent pipeline upload .buildkite/test-nightly.yml
|
||||
- python3 .buildkite/common/scripts/upload_pipeline.py --upload --all .buildkite/cuda/test-nightly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Build and push the CI Docker image with registry-based layer caching.
|
||||
#
|
||||
# Usage: build-ci-image.sh
|
||||
#
|
||||
# Expects the following environment variables (set by Buildkite):
|
||||
# BUILDKITE_COMMIT - commit SHA used as the image tag
|
||||
ECR_NAMESPACE="public.ecr.aws/q9t5s3a7"
|
||||
REGISTRY="${ECR_NAMESPACE}/vllm-ci-test-repo"
|
||||
REGION="us-east-1"
|
||||
DOCKERFILE="docker/Dockerfile.ci"
|
||||
BUILDER_NAME="vllm-omni-builder"
|
||||
|
||||
# Ensure that the env vars are actually set, otherwise exit early
|
||||
if [ -z "${BUILDKITE_COMMIT:-}" ]; then
|
||||
echo "ERROR: BUILDKITE_COMMIT is not set"
|
||||
exit 1
|
||||
fi
|
||||
echo "BUILDKITE_COMMIT: ${BUILDKITE_COMMIT}"
|
||||
|
||||
# Authenticate to ECR Public
|
||||
aws ecr-public get-login-password --region "$REGION" \
|
||||
| docker login --username AWS --password-stdin "$ECR_NAMESPACE"
|
||||
|
||||
# Compute the cache tag for the dependencies image as the hash of the contents.
|
||||
# This is because dependencies don't change often, so most PRs will have the same hash.
|
||||
#
|
||||
# The Dockerfile is also included to avoid churn in the cached image based on the vLLM version.
|
||||
DEP_FILES="pyproject.toml setup.py requirements/*.txt docker/Dockerfile.ci"
|
||||
CACHE_KEY=$(cat ${DEP_FILES} | sha256sum | cut -c1-16)
|
||||
CACHE_TAG="deps-cache-${CACHE_KEY}"
|
||||
echo "Cache key: ${CACHE_TAG}"
|
||||
|
||||
# Set up buildx with docker-container driver; we need to do this
|
||||
# since cache export is not supported for the default docker driver
|
||||
# that is running in the CI.
|
||||
docker buildx inspect $BUILDER_NAME >/dev/null 2>&1 \
|
||||
|| docker buildx create --name $BUILDER_NAME --driver docker-container
|
||||
docker buildx use $BUILDER_NAME
|
||||
|
||||
echo "Building image tag: ${REGISTRY}:${BUILDKITE_COMMIT}"
|
||||
|
||||
# Build + push the image to the registry, using the hash from the dependencies.
|
||||
# Note that the caching here is layerwise, so we're just making sure we always
|
||||
# can cache hit on everything but the last copy at the moment.
|
||||
docker buildx build --push --progress=plain \
|
||||
--cache-from "type=registry,ref=${REGISTRY}:${CACHE_TAG}" \
|
||||
--cache-to "type=registry,ref=${REGISTRY}:${CACHE_TAG},mode=max,compression=zstd" \
|
||||
--file "$DOCKERFILE" \
|
||||
-t "${REGISTRY}:${BUILDKITE_COMMIT}" .
|
||||
@@ -0,0 +1,210 @@
|
||||
# CUDA CI L3 (`advanced_model` e2e) plus L1 CPU Simple Test (`core_model and cpu`).
|
||||
# Uploaded by Upload Merge Pipeline: PR label `merge-test`, or post-merge on main
|
||||
# (both diff-aware via source_file_dependencies).
|
||||
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "Simple · Model Executor Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Diffusion Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- "pytest -sv tests/diffusion -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "Diffusion · LoRA Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/lora/ -m 'advanced_model and cuda' --run-level "advanced_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Distributed Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- |
|
||||
timeout 55m bash -c "
|
||||
set -e
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/distributed -m 'advanced_model and cuda and H100' --run-level 'advanced_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- group: ":card_index_dividers: Entrypoints Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "Entrypoint Test with H100"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
# Turn-based server VAD over /v1/realtime is deferred to RFC #7181 PR 5
|
||||
# (see the P0 thread on #7413); the test stays in the tree and runs again there.
|
||||
- pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and H100" --run-level "advanced_model" --deselect tests/entrypoints/openai_api/test_qwen3_omni_realtime_websocket.py::TestQwen3OmniRealtimeWebSocket::test_server_vad_multi_turn_without_client_commit
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Entrypoint Test with L4"
|
||||
timeout_in_minutes: 60
|
||||
# Workaround https://github.com/vllm-project/vllm-omni/issues/8016: shutdown()
|
||||
# leaves inline UniProc DiffusionWorker VRAM mapped in the pytest parent.
|
||||
# This job does not collect the ready leftover
|
||||
# (test_diffusion_generate_request_id, core_model); isolate the
|
||||
# advanced_model DiT handshake instead. Revert to a single sweep after
|
||||
# the product shutdown fix.
|
||||
commands:
|
||||
- |
|
||||
set -eu
|
||||
pytest -s -v tests/entrypoints/test_omni_sleep_mode.py::TestOmniDiffusionSleepMode::test_diffusion_sleep_handshake -m "advanced_model and cuda and L4 and cards_1" --run-level "advanced_model"
|
||||
pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and L4 and cards_1" --run-level "advanced_model" --deselect tests/entrypoints/test_omni_sleep_mode.py::TestOmniDiffusionSleepMode::test_diffusion_sleep_handshake
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Entrypoint Test with L4 · 2-GPU"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and L4 and cards_2" --run-level "advanced_model"
|
||||
mirror_hardwares: l4_2
|
||||
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
||||
source_file_dependencies: tts_qwen3_tts_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py tests/e2e/offline_inference/test_qwen3_tts_customvoice.py tests/e2e/features/prefill_phase/test_chunked_prefill_tail.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "TTS · Qwen3-TTS Base Test"
|
||||
source_file_dependencies: tts_qwen3_tts_cov
|
||||
# 40 -> 60: the coverage split runs the model twice.
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- |
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
.buildkite/common/scripts/run_cov_split.sh \
|
||||
--model-id qwen3_tts \
|
||||
--offline tests/e2e/offline_inference/test_qwen3_tts_base.py \
|
||||
--online tests/e2e/online_serving/test_qwen3_tts_base.py \
|
||||
-- -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Omni · Qwen3-Omni Test"
|
||||
source_file_dependencies: omni_qwen3_omni_function
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py tests/e2e/online_serving/test_qwen3_omni.py tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_function
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
# h100_2, not h100_1: advanced_model asserts transcribe every audio
|
||||
# response with Whisper, and tests/helpers/media.py requires at least
|
||||
# 16 GiB free VRAM on a device to run Whisper on GPU. When the model
|
||||
# server leaves insufficient memory, Whisper falls back to CPU:
|
||||
# ~8-10 min per clip vs ~30 s, which overruns the 50-minute job timeout
|
||||
# (build 2956). h100_2 guarantees a second GPU with ample free VRAM.
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_function
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py tests/e2e/online_serving/test_minicpmo_4_5_window.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Qwen Image Test"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c '
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
'
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/offline_inference/test_wan22_t2v.py tests/e2e/online_serving/test_wan22_t2v.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · HunyuanVideo-1.5 Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · LingBot-Video Test"
|
||||
source_file_dependencies: diffusion_lingbot_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_lingbot_video.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · MiniMax-H3 L3 DLO DP2 and FastH3"
|
||||
source_file_dependencies: diffusion_minimax_h3_function
|
||||
# Keep four server lifecycles in one Buildkite job, but never in one
|
||||
# pytest process. DLO uses multiprocessing shared-memory queues; the
|
||||
# parent's resource_tracker can retain a stale /psm_* entry during
|
||||
# teardown and strand the next Ref2VA collective.
|
||||
# A per-file process plus a hard timeout also makes a regression fail
|
||||
# instead of leaving the merge queue stuck indefinitely.
|
||||
timeout_in_minutes: 150
|
||||
commands:
|
||||
- |
|
||||
set -eu
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
if [ -f vllm_omni/diffusion/models/minimax_h3/lora.py ]; then
|
||||
export VLLM_TEST_MINIMAX_H3_TURBO_LORA=$(python3 -c 'from huggingface_hub import hf_hub_download; print(hf_hub_download(repo_id="lightx2v/Minimax-h3-Turbo", filename="minimax_h3_fl2v_turbo_4step_v1.0_768p_bf16.safetensors"))')
|
||||
fi
|
||||
if [ -f vllm_omni/diffusion/models/minimax_h3/fasth3.py ]; then
|
||||
export VLLM_TEST_MINIMAX_H3_FASTH3_LORA=$(python3 -c 'from huggingface_hub import hf_hub_download; print(hf_hub_download(repo_id="FastVideo/FastVideo-FastH3-4-step-Preview-v1-LoRA", filename="dense-datafree/adapter_model.safetensors"))')
|
||||
fi
|
||||
timeout 35m pytest -s -v tests/e2e/online_serving/minimax_h3/test_minimax_h3_dlo_dp2_fl2va.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
timeout 35m pytest -s -v tests/e2e/online_serving/minimax_h3/test_minimax_h3_dlo_dp2_ref2va.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
timeout 35m pytest -s -v tests/e2e/online_serving/minimax_h3/test_minimax_h3_turbo_lora.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
timeout 35m pytest -s -v tests/e2e/online_serving/minimax_h3/test_minimax_h3_fasth3_lora.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
mirror_hardwares: h100_2
|
||||
@@ -0,0 +1,557 @@
|
||||
# CUDA CI L4 (`full_model`): nightly and release share this file.
|
||||
# Uploaded by Upload Nightly Pipeline: NIGHTLY=1, or PR labels (nightly-test / omni-test / ...).
|
||||
# Hardware: omit mirror_hardwares to compose from -m SKU + cards_n; or set a preset string to force.
|
||||
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
# Group: collapses under one heading in the Buildkite UI; child steps still run in parallel.
|
||||
- group: ":card_index_dividers: Omni Model Test"
|
||||
key: nightly-omni-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Omni · Function Test with H100 · Single-GPU"
|
||||
source_file_dependencies:
|
||||
- omni_qwen3_omni_function
|
||||
- omni_minicpmo_4_5_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -sv tests/e2e --run-level "full_model" -m "full_model and H100 and B200 and omni and cards_1" --ignore=tests/e2e/accuracy --ignore=tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py
|
||||
|
||||
- label: ":full_moon: Omni · Function Test with H100 · 2-GPU"
|
||||
source_file_dependencies:
|
||||
- omni_qwen3_omni_function
|
||||
- omni_minicpmo_4_5_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -sv tests/e2e --run-level "full_model" -m "full_model and H100 and B200 and omni and cards_2" --ignore=tests/e2e/accuracy --ignore=tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_function
|
||||
timeout_in_minutes: 50
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py -m "full_model and cuda and H100 and B200 and omni and cards_1" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Omni · Doc Test with L4 · 4-GPU"
|
||||
source_file_dependencies: omni_qwen2_5_omni_doc
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/examples/ -m "full_model and omni and L4 and B200 and cards_4" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Omni · Doc Test with H100 · 2-GPU"
|
||||
source_file_dependencies: omni_qwen3_omni_doc
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/examples/ -m "full_model and omni and H100 and B200 and cards_2" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Omni · Accuracy Test"
|
||||
source_file_dependencies: omni_qwen3_omni_accuracy
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json
|
||||
commands:
|
||||
- export SEED_TTS_WER_EVAL=1
|
||||
- export SEED_TTS_EVAL_DEVICE=cuda:1
|
||||
- pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model and H100 and B200 and cards_2" --run-level full_model
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Accuracy Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_accuracy
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/e2e/accuracy/minicpmo_4_5/results/*.json
|
||||
commands:
|
||||
- export SEED_TTS_WER_EVAL=1
|
||||
- export SEED_TTS_EVAL_DEVICE=cuda:1
|
||||
- pytest -s -v tests/e2e/accuracy/minicpmo_4_5/test_minicpmo_4_5.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level full_model
|
||||
|
||||
- label: ":full_moon: Omni · Omni-DuplexEval CI Guard"
|
||||
source_file_dependencies: omni_duplex_eval_ci
|
||||
timeout_in_minutes: 240
|
||||
env:
|
||||
VLLM_DUPLEX_EVAL_JUDGE_URL: "http://127.0.0.1:8001"
|
||||
commands:
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/e2e/accuracy/omni_duplex_eval/test_omni_duplex_eval_ci.py \
|
||||
-m "full_model and H100 and B200 and cuda and cards_2" \
|
||||
--run-level full_model \
|
||||
--basetemp /tmp/omni_duplex_ci
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/e2e/accuracy/omni_duplex_eval/results/*.json"
|
||||
exit $$EXIT
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · No Async Chunk"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: nightly-omni-performance-no-async-chunk
|
||||
timeout_in_minutes: 300
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json -m "H100 and B200 and cards_2"
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · Async Chunk"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: nightly-omni-performance-async-chunk
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json -m "H100 and B200 and full_model and cards_2"
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json -m "H100 and B200 and cards_1"
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Seed-TTS Perf Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5-duplex-seed-tts
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json -m "H100 and B200 and cards_1"
|
||||
|
||||
- label: ":full_moon: Omni · Multi-Replica Startup Test with 4x H100"
|
||||
source_file_dependencies: omni_qwen3_omni_function
|
||||
timeout_in_minutes: 45
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py -m "full_model and H100 and B200 and cards_4" --run-level "core_model"
|
||||
|
||||
- group: ":card_index_dividers: Entrypoints Test"
|
||||
key: nightly-entrypoints-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Entrypoint Test with H100"
|
||||
source_file_dependencies: entrypoints_function
|
||||
# Merge collects advanced_model (5 duplex interruptions). Nightly
|
||||
# collects full_model (20 interruptions + BAGEL sleep).
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/entrypoints/ -m "full_model and cuda and H100 and B200 and cards_2" --run-level "full_model"
|
||||
|
||||
- group: ":card_index_dividers: TTS Model Test"
|
||||
key: nightly-tts-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: TTS · Function Test with L4"
|
||||
source_file_dependencies: tts_qwen3_tts_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- export VLLM_USE_DEEP_GEMM="0"
|
||||
- export VLLM_MOE_USE_DEEP_GEMM="0"
|
||||
- pytest -s -v tests/e2e/ -m "full_model and L4 and B200 and tts and cards_1" --run-level "full_model" --ignore=tests/e2e/accuracy
|
||||
|
||||
- label: ":full_moon: TTS · Perf Test · Single-GPU"
|
||||
source_file_dependencies: tts_qwen3_tts_perf
|
||||
key: nightly-tts-performance-single
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and B200 and cards_1"
|
||||
|
||||
- label: ":full_moon: TTS · Perf Test · 2-GPU"
|
||||
source_file_dependencies: tts_qwen3_tts_perf
|
||||
key: nightly-tts-performance-2gpu
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and B200 and cards_2"
|
||||
|
||||
- group: ":card_index_dividers: Tiny Model Tests [Multi-GPU]"
|
||||
key: nightly-tiny-model-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Tiny Model Tests · Diffusion (Multi-GPU accelerations) · 2-GPU"
|
||||
source_file_dependencies: diffusion_tiny_model
|
||||
timeout_in_minutes: 30
|
||||
# NOTE: Single-GPU (core_model) tiny model tests run on the ready label,
|
||||
# so nightly only adds the multi-GPU parallelism configurations.
|
||||
#
|
||||
# This is a bit confusing, but `full_model` is used to mark the multigpu tests, and
|
||||
# --run-level `core_model` is used to indicate that we should use tiny model weights
|
||||
# for the CI, since these tests should pass irrespective of whether or not we use
|
||||
# the full weights or not.
|
||||
commands:
|
||||
- pytest -sv tests/model_tests/diffusion -m 'full_model and L4 and B200 and cuda and cards_2' --run-level "core_model"
|
||||
|
||||
- label: ":full_moon: Tiny Model Tests · Diffusion (Multi-GPU accelerations) · 4-GPU"
|
||||
source_file_dependencies: diffusion_tiny_model
|
||||
timeout_in_minutes: 30
|
||||
# CFG+TP extra_test_groups request 2×2=4 devices (see get_required_device_count).
|
||||
commands:
|
||||
- pytest -sv tests/model_tests/diffusion -m 'full_model and L4 and B200 and cuda and cards_4' --run-level "core_model"
|
||||
|
||||
- group: ":card_index_dividers: Diffusion X2I(&A&T) Model Test"
|
||||
key: nightly-diffusion-x2iat-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · Single-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_expansion.py
|
||||
-m "full_model and diffusion and H100 and B200 and cards_1"
|
||||
--run-level "full_model"
|
||||
|
||||
- label: ":robot_face: Robot Policy OpenPI · π0.5 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pip install --no-deps "openpi-client @ git+https://github.com/Physical-Intelligence/openpi.git@215abfb217dbac7d5f1273282331b9b1866c0479#subdirectory=packages/openpi-client"
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_pi05_expansion.py
|
||||
-m "full_model and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · 2-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_expansion.py
|
||||
-m "full_model and diffusion and H100 and B200 and cards_2"
|
||||
--run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with L4 · Single-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -sv tests/e2e/offline_inference/test_qwen_image_autoround_w4a16_expansion.py -m "full_model and diffusion and L4 and B200 and cards_1" --run-level "full_model"
|
||||
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Doc Test"
|
||||
source_file_dependencies: diffusion_text_to_image_doc
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -s -v tests/examples/*/test_text_to_image.py -m "full_model and example and H100 and B200 and (cards_1 or cards_2)" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Accuracy Test"
|
||||
source_file_dependencies: diffusion_qwen_image_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export VLLM_HTTP_TIMEOUT_KEEP_ALIVE=120
|
||||
- pytest -s -v tests/e2e/accuracy/test_qwen_image.py -m "H100 and B200 and cards_1" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2i_matches_diffusers' -m "full_model and H100 and B200 and cards_1" --run-level full_model
|
||||
|
||||
- label: ":full_moon: HunyuanImage3-DIT · Accuracy Test"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export HUNYUAN_IMAGE3_MODEL="tencent/HunyuanImage-3.0-Instruct"
|
||||
- export HUNYUAN_IMAGE3_DEVICES="0,1,2,3"
|
||||
- pytest -s -v tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py tests/e2e/accuracy/test_hunyuan_image3_lora.py -m "full_model and H100 and B200 and cards_4" --run-level full_model
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image · Single-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_perf
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-single
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/diffusion_result_*.json
|
||||
- tests/dfx/perf/results/logs/*.log
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export CACHE_DIT_VERSION=1.5.0
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and B200 and cards_1"
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image · 4-GPU"
|
||||
source_file_dependencies: diffusion_qwen_image_perf
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-4gpu
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/diffusion_result_*.json
|
||||
- tests/dfx/perf/results/logs/*.log
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export CACHE_DIT_VERSION=1.5.0
|
||||
# Do not pin DIFFUSION_ATTENTION_BACKEND: H100 auto-selects FLASH_ATTN;
|
||||
# B200 rejects explicit FLASH_ATTN without FA4 and uses CUDNN/TRTLLM.
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and B200 and cards_4"
|
||||
|
||||
- group: ":card_index_dividers: Diffusion X2V Model Test"
|
||||
key: nightly-diffusion-x2v-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 T2V Function Test · Single-GPU"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and B200 and cards_1" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 T2V Function Test · 2-GPU"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and B200 and cards_2" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 I2V/TI2V Function Test · Single-GPU"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and B200 and cards_1" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 I2V/TI2V Function Test · 2-GPU"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and B200 and cards_2" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Function Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · LingBot Function Test"
|
||||
source_file_dependencies: diffusion_lingbot_function
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/e2e/online_serving/test_lingbot_video_expansion.py
|
||||
tests/e2e/online_serving/test_lingbot_video_moe.py
|
||||
tests/e2e/offline_inference/test_lingbot_world_v2.py
|
||||
-m "full_model and diffusion and H100 and B200 and cards_1"
|
||||
--run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Doc Test"
|
||||
source_file_dependencies: diffusion_image_to_video_doc
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -s -v tests/examples/offline_inference/test_image_to_video.py -m "full_model and example and H100 and B200 and cards_1" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 Autoround Function Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_wan22_autoround_w4a16_expansion.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 Device-Postprocess Equivalence Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- |
|
||||
VLLM_OMNI_DEVICE_POSTPROCESS_MODEL=Wan-AI/Wan2.2-TI2V-5B-Diffusers \
|
||||
pytest -s -v tests/e2e/offline_inference/test_device_postprocess_equivalence.py -m "full_model and H100 and B200 and cuda and cards_1" --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 Accuracy Test"
|
||||
source_file_dependencies: diffusion_wan22_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/wan22_i2v/test_wan22_i2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2v_matches_diffusers' -m "full_model and H100 and B200 and cards_1" --run-level full_model
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · MiniMax H3 I2VA/Ref2VA Accuracy Test"
|
||||
source_file_dependencies: diffusion_minimax_h3_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/minimax_h3/test_minimax_h3_i2va_ref2va_similarity.py -m "full_model and H100 and B200 and cards_4" --run-level full_model
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Accuracy Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_accuracy
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/hunyuanvideo15_t2v/test_hunyuanvideo15_t2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/hunyuanvideo15_i2v/test_hunyuanvideo15_i2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · Single-GPU"
|
||||
source_file_dependencies: diffusion_wan22_perf
|
||||
key: nightly-diffusion-x2v-performance-single
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and B200 and cards_1"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · 2-GPU"
|
||||
source_file_dependencies:
|
||||
- diffusion_wan22_perf
|
||||
- diffusion_cosmos3_perf
|
||||
key: nightly-diffusion-x2v-performance-2gpu
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and B200 and cards_2"
|
||||
EXIT1=$$?
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_cosmos3_vllm_omni.json -m "H100 and B200 and cards_2"
|
||||
EXIT2=$$?
|
||||
if [ $$EXIT1 -ne 0 ]; then exit $$EXIT1; fi
|
||||
exit $$EXIT2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · HunyuanVideo-1.5"
|
||||
source_file_dependencies: diffusion_hunyuan_video_perf
|
||||
key: nightly-diffusion-x2v-performance-hunyuanvideo15
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json -m "H100 and B200 and (cards_1 or cards_2)"
|
||||
EXIT1=$$?
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_i2v_vllm_omni.json -m "H100 and B200 and (cards_1 or cards_2)"
|
||||
EXIT2=$$?
|
||||
if [ $$EXIT1 -ne 0 ]; then exit $$EXIT1; fi
|
||||
exit $$EXIT2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · MiniMax-H3"
|
||||
source_file_dependencies: diffusion_minimax_h3_perf
|
||||
key: nightly-diffusion-x2v-performance-minimax-h3
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minimax_h3_vllm_omni.json -m "H100 and B200 and cards_4"
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test · LingBot"
|
||||
source_file_dependencies: diffusion_lingbot_perf
|
||||
key: nightly-diffusion-x2v-performance-lingbot
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_lingbot_video_vllm_omni.json -m "H100 and B200 and cards_1"
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
key: nightly-diffusion-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
- label: ":full_moon: Diffusion · Distributed Test with L4 · 2-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_2' --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion · Distributed Test with L4 · 3-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_3' --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion · Distributed Test with L4 · 4-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_4' --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion · Distributed Test with H100 · 2-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and B200 and cards_2' --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion · Distributed Test with H100 · 4-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and B200 and cards_4' --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion · Offloader Test"
|
||||
source_file_dependencies: diffusion_offloader
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/offloader -m "full_model and L4 and B200 and cuda and cards_1"
|
||||
|
||||
- label: ":full_moon: Diffusion · Quantization Test with H100 · Single-GPU"
|
||||
source_file_dependencies: diffusion_quantization
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/quantization -m 'full_model and cuda and H100 and B200 and cards_1' --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion · MiniMax H3 FP8 Quality Test with H100 · 2-GPU"
|
||||
source_file_dependencies: diffusion_minimax_h3_function
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/models/minimax_h3/test_minimax_h3_quantization_quality.py -m 'full_model and cuda and H100 and B200 and cards_2' --run-level "full_model"
|
||||
|
||||
- label: ":full_moon: Diffusion · Quantization Test with L4"
|
||||
source_file_dependencies: diffusion_quantization
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pip install "vllm-gguf-plugin==0.0.4"
|
||||
- pytest -sv tests/diffusion/quantization -m 'full_model and cuda and L4 and B200 and cards_1' --run-level "full_model"
|
||||
|
||||
# NOTE: ":email: Nightly Collection & Email" is deprecated and will be removed soon.
|
||||
# Do not add new depends_on entries or extend this step.
|
||||
- label: ":email: Nightly Collection & Email"
|
||||
key: nightly-perf-distribution
|
||||
depends_on:
|
||||
- nightly-omni-performance-no-async-chunk
|
||||
- nightly-omni-performance-async-chunk
|
||||
- nightly-tts-performance-single
|
||||
- nightly-tts-performance-2gpu
|
||||
- nightly-diffusion-x2iat-performance-qwen-image-single
|
||||
- nightly-diffusion-x2iat-performance-qwen-image-4gpu
|
||||
- nightly-diffusion-x2v-performance-single
|
||||
- nightly-diffusion-x2v-performance-2gpu
|
||||
if: build.env("NIGHTLY") == "1" && build.env("EMAIL_DISTRIBUTION") == "1"
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.xlsx
|
||||
- tests/dfx/perf/results/*.html
|
||||
commands:
|
||||
- pip install openpyxl
|
||||
- export DEFAULT_INPUT_DIR=tests/dfx/perf/results
|
||||
- export DEFAULT_OUTPUT_DIR=tests/dfx/perf/results
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-tts-performance-single
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-tts-performance-2gpu
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-omni-performance-no-async-chunk
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-omni-performance-async-chunk
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2iat-performance-qwen-image-single
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2iat-performance-qwen-image-4gpu
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2v-performance-single
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2v-performance-2gpu
|
||||
- python tools/nightly/generate_nightly_perf_excel.py
|
||||
- python tools/nightly/generate_nightly_perf_html.py
|
||||
- python tools/nightly/send_nightly_email.py --report-file "tests/dfx/perf/results/*.xlsx, tests/dfx/perf/results/*.html"
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
@@ -0,0 +1,268 @@
|
||||
# CUDA CI L2 (`core_model` e2e) plus L1 CPU Simple Test (`core_model and cpu`).
|
||||
# Uploaded by Upload Ready Pipeline: PR label `ready`, or main+WEEKLY=1 with --e2e.
|
||||
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "Simple · Model Executor Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Diffusion Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- "pytest -sv tests/diffusion -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
|
||||
- label: "Diffusion · FlashAttention Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- timeout 15m pytest -s -v tests/diffusion/attention/ -m 'core_model and cuda and L4 and cards_1' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Offloader Test"
|
||||
commands:
|
||||
- timeout 40m pytest -s -v tests/diffusion/offloader -m "core_model and cuda" --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Cache Test"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/cache -m 'core_model and cuda' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Batch Test"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/batching -m 'core_model and cuda' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Distributed Test · Single-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_1' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Distributed Test · 2-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_2' --run-level "core_model"
|
||||
- timeout 10m pytest -sv tests/diffusion/attention/test_ulysses_uaa.py -m 'core_model and cuda and L4 and cards_2' --run-level "core_model"
|
||||
mirror_hardwares: l4_2
|
||||
|
||||
- label: "Diffusion · Distributed & Attention Test · 4-GPU"
|
||||
source_file_dependencies: diffusion_distributed_attention
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_4' --run-level "core_model"
|
||||
- timeout 20m pytest -sv tests/diffusion/attention/test_attention_sp.py -m 'core_model and cuda and L4 and cards_4' --run-level "core_model"
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
- label: "Diffusion · Model Test"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/models/ -m 'core_model and cuda' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Other Test"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/*.py tests/diffusion/ar_diffusion -m 'core_model and cuda' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: ":card_index_dividers: Tiny Model Tests [Single GPU]"
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
|
||||
- label: "Tiny Model Tests · Diffusion (base)"
|
||||
commands:
|
||||
- timeout 15m pytest -sv -n 4 tests/model_tests/diffusion -m 'core_model and cuda' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Engine&Model Executor Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
commands:
|
||||
- |
|
||||
timeout 15m bash -c "
|
||||
pytest -sv tests/engine/ tests/model_executor/ tests/worker/test_batched_omni_output.py tests/worker_v2/ -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Distributed Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -sv tests/distributed/ -m 'core_model and cuda and L4' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Entrypoints Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
# Workaround https://github.com/vllm-project/vllm-omni/issues/8016: shutdown()
|
||||
# leaves inline UniProc DiffusionWorker VRAM mapped in the pytest parent.
|
||||
# Isolate that leftover case in its own process so the driver drops the
|
||||
# mapping; the rest stays a directory sweep with --deselect. Revert to a
|
||||
# single sweep after the product shutdown fix.
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c "
|
||||
set -eu
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -sv tests/entrypoints/test_async_omni.py::test_diffusion_generate_request_id -m 'core_model and cuda' --run-level 'core_model'
|
||||
pytest -sv tests/entrypoints/ -m 'core_model and cuda' --run-level 'core_model' --deselect tests/entrypoints/test_async_omni.py::test_diffusion_generate_request_id
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "Custom Pipeline Test"
|
||||
source_file_dependencies: custom_pipeline
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/e2e/features/custom_pipeline/ -m "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
|
||||
- label: "RLHF · VeRL-Omni E2E Test"
|
||||
source_file_dependencies: rlhf_verl_omni
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/features/rlhf_test/test_verl_omni_e2e.py
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Omni · Qwen3-Omni Test"
|
||||
source_file_dependencies: omni_qwen3_omni_function
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_omni.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Offline Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_function
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Online Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_function
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_function
|
||||
commands:
|
||||
- |
|
||||
timeout 35m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py tests/e2e/online_serving/test_duplex_client_live.py -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Perf Test"
|
||||
timeout_in_minutes: 60
|
||||
source_file_dependencies: omni_minicpmo_4_5_perf
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_ready.json -m 'core_model and cuda'
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
||||
source_file_dependencies: tts_qwen3_tts_function
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_wan22_t2v.py -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Cosmos3 Test"
|
||||
source_file_dependencies: diffusion_cosmos3_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_cosmos3.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · MiniMax-H3 DLO DP2 T2VA Test"
|
||||
timeout_in_minutes: 90
|
||||
source_file_dependencies: diffusion_minimax_h3_function
|
||||
commands:
|
||||
- |
|
||||
timeout 80m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_minimax_h3_dlo_dp2_t2va.py -m 'core_model and cuda and diffusion' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Qwen Image Test"
|
||||
source_file_dependencies: diffusion_qwen_image_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · HunyuanVideo-1.5 Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m 'core_model and diffusion' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · LingBot-Video Test"
|
||||
source_file_dependencies: diffusion_lingbot_function
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_lingbot_video.py -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
@@ -0,0 +1,533 @@
|
||||
# CUDA CI L5 (`slow` / reliability / extra coverage).
|
||||
# Uploaded by Upload Weekly Pipeline: WEEKLY=1 / NON_CRITICAL=1, or PR label `weekly-test`.
|
||||
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
- label: "Simple · CPU Coverage Test"
|
||||
key: weekly-simple-cpu-coverage
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1"
|
||||
timeout_in_minutes: 60
|
||||
artifact_paths:
|
||||
- coverage-core-model-cpu-*.xml.gz
|
||||
commands:
|
||||
- |
|
||||
set +e
|
||||
REPORT="coverage-core-model-cpu-$${BUILDKITE_STEP_ID:-local}.xml"
|
||||
pytest -sv tests/ -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml:$${REPORT}
|
||||
EXIT=$$?
|
||||
gzip -9 -f "$${REPORT}"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: "Reliability Test"
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
steps:
|
||||
|
||||
- label: "Reliability Test · qwen3-omni"
|
||||
source_file_dependencies: omni_qwen3_omni_reliability
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_qwen3_omni.py -m "slow"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Reliability Test · wan22"
|
||||
source_file_dependencies: diffusion_wan22_reliability
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_wan22.py -m "slow"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Reliability Test · hunyuan-image"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_reliability
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_hunyuan_image.py -m "slow"
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: "Reliability Test · Invalid parameters · H100 · Single-GPU"
|
||||
source_file_dependencies: reliability_invalid_param_h100
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100 and cards_1"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Reliability Test · Invalid parameters · H100 · 2-GPU"
|
||||
source_file_dependencies: reliability_invalid_param_h100
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100 and cards_2"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Reliability Test · Invalid parameters · L4"
|
||||
source_file_dependencies: reliability_invalid_param_l4
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and L4"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: "Perf Test"
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · vLLM Text"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: weekly-omni-performance-vllm-text
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_vllm_text.json
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · Async Chunk · Random"
|
||||
key: weekly-omni-performance-async-chunk-random
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json -m "H100 and slow"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · Multi-Replica"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: weekly-omni-performance-multi-replicas
|
||||
timeout_in_minutes: 180
|
||||
artifact_paths:
|
||||
- tests/dfx/perf/results/*.json
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_multi_replicas.json
|
||||
mirror_hardwares: h100_3
|
||||
|
||||
- group: ":card_index_dividers: E2E Tests"
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("NON_CRITICAL") == "1"
|
||||
steps:
|
||||
|
||||
# Online Qwen2.5 expansion is 2-card; offline expansion + AutoRound are 4-card.
|
||||
- label: "Omni · L4 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen2_5_omni_expansion.py -m "slow and L4 and omni and cards_2" --run-level "core_model"
|
||||
mirror_hardwares: l4_2
|
||||
|
||||
- label: "Omni · L4 · 4-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen2_5_omni_expansion.py -m "slow and L4 and omni and cards_4" --run-level "core_model"
|
||||
- >-
|
||||
pytest -s -v tests/e2e/
|
||||
--ignore=tests/e2e/online_serving/test_qwen2_5_omni_expansion.py
|
||||
--ignore=tests/e2e/offline_inference/test_qwen2_5_omni_expansion.py
|
||||
-m "slow and L4 and omni and cards_4"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
- label: "Omni · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and H100 and omni and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Omni · H100 · 4-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and H100 and omni and cards_4"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: "TTS · L4"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- export VLLM_USE_DEEP_GEMM="0"
|
||||
- export VLLM_MOE_USE_DEEP_GEMM="0"
|
||||
- |
|
||||
failed=0
|
||||
for f in $(pytest --collect-only -q tests/e2e/ -m "slow and L4 and tts" --run-level "full_model" | grep '\.py::' | sed -E 's|::.*||' | sort -u); do
|
||||
pytest -s -v "$$f" -m "slow and L4 and tts" --run-level "full_model" || failed=1
|
||||
done
|
||||
exit $$failed
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "TTS · H100"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- export VLLM_USE_DEEP_GEMM="0"
|
||||
- export VLLM_MOE_USE_DEEP_GEMM="0"
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and H100 and tts"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
# Own step: the image has no NanoCodec, so this file import-skips out of
|
||||
# the mark-selected TTS steps above. The overrides keep nemo_toolkit[tts]
|
||||
# from downgrading transformers; see
|
||||
# examples/offline_inference/text_to_speech/README.md.
|
||||
- label: "TTS · Gepard-1.0 · L4"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- printf '%s\n' "transformers>=5.5.3" "huggingface-hub>=1.0" > /tmp/gepard-overrides.txt
|
||||
- uv pip install --python "$(python3 -c 'import sys; print(sys.executable)')" "nemo_toolkit[tts]==2.7.3" --overrides /tmp/gepard-overrides.txt
|
||||
- >-
|
||||
pytest -s -v tests/e2e/offline_inference/test_gepard_tts.py
|
||||
tests/e2e/online_serving/test_gepard_tts.py
|
||||
-m "tts and cuda"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · L4 · Single-GPU"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and diffusion and L4 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · L4 · 2-GPU"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and diffusion and L4 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: l4_2
|
||||
|
||||
- label: "Diffusion · L4 · 4-GPU"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and diffusion and L4 and cards_4"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
# Split the old shared H100 Single-GPU sweep: one pytest process collected
|
||||
# every slow+cards_1 diffusion file and exceeded 150 minutes.
|
||||
- label: "Diffusion · Qwen-Image · H100 · Single-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_edit.py
|
||||
tests/e2e/online_serving/test_qwen_image_edit_expansion.py
|
||||
tests/e2e/online_serving/test_qwen_image_layered.py
|
||||
tests/e2e/online_serving/test_qwen_image_layered_expansion.py
|
||||
tests/e2e/accuracy/test_qwen_image_edit.py
|
||||
tests/e2e/accuracy/test_qwen_image_layered.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Wan2.1 VACE · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_wan_2_1_vace_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · LongCat · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_longcat_image_expansion.py
|
||||
tests/e2e/online_serving/test_longcat_image_edit_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Bagel · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_bagel.py
|
||||
tests/e2e/online_serving/test_bagel_expansion.py
|
||||
tests/e2e/offline_inference/test_bagel.py
|
||||
tests/e2e/offline_inference/test_bagel_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Boogu · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_boogu_image.py
|
||||
tests/e2e/online_serving/test_boogu_image_edit.py
|
||||
tests/e2e/online_serving/test_boogu_image_expansion.py
|
||||
tests/e2e/online_serving/test_boogu_image_edit_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Flux · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_flux_2_dev_expansion.py
|
||||
tests/e2e/offline_inference/test_flux1_schnell_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · LTX · H100 · Single-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_ltx.py
|
||||
tests/e2e/online_serving/test_ltx25.py
|
||||
tests/e2e/accuracy/ltx/test_ltx_official_similarity.py
|
||||
tests/e2e/accuracy/ltx/test_ltx25_official_similarity.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Krea2 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_krea2_expansion.py
|
||||
tests/e2e/offline_inference/test_krea2_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · HiDream-I1 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_hidream_i1_full_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · SANA-Video · H100 · Single-GPU"
|
||||
source_file_dependencies: diffusion_sana_video_function
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export SANA_VIDEO_GOLDEN_BASE_URL=https://vllm-public-assets.s3.us-west-2.amazonaws.com/omni-assets/sana-video/v2
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_sana_video_expansion.py
|
||||
tests/e2e/accuracy/sana_video/
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · SenseNova-U1 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/offline_inference/test_sensenova_u1_expansion.py
|
||||
tests/e2e/offline_inference/test_sensenova_u1_text2img_expansion.py
|
||||
tests/e2e/offline_inference/test_sensenova_u1_img2img_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · MammothModa2 · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/offline_inference/test_mammoth_moda2_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Helios · H100 · Single-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/accuracy/test_video_streaming_output_similarity.py
|
||||
-m "slow and diffusion and H100 and cards_1"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
# Split the old shared H100 2-GPU sweep: one pytest process collected every
|
||||
# slow+cards_2 diffusion file and exceeded 90 minutes.
|
||||
- label: "Diffusion · Qwen-Image · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_edit_expansion.py
|
||||
tests/e2e/online_serving/test_qwen_image_layered_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Wan2.1 VACE · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_wan_2_1_vace_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · LongCat · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_longcat_image_expansion.py
|
||||
tests/e2e/online_serving/test_longcat_image_edit_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Bagel · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_bagel_expansion.py
|
||||
tests/e2e/offline_inference/test_bagel_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Boogu · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_boogu_image_expansion.py
|
||||
tests/e2e/online_serving/test_boogu_image_edit_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Flux · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_flux_2_dev_expansion.py
|
||||
tests/e2e/offline_inference/test_flux1_kontext_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · GLM-Image · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_glm_image_expansion.py
|
||||
tests/e2e/offline_inference/test_glm_image_autoround_w4a16_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · LTX · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_ltx.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · Krea2 · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/offline_inference/test_krea2_expansion.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · DreamZero · H100 · 2-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_dreamzero_expansion.py
|
||||
tests/e2e/accuracy/test_dreamzero.py
|
||||
-m "slow and diffusion and H100 and cards_2"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Diffusion · H100 · 3-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and diffusion and H100 and cards_3"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_3
|
||||
|
||||
- label: "Diffusion · H100 · 4-GPU"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and diffusion and H100 and cards_4"
|
||||
--run-level "full_model"
|
||||
--ignore=tests/e2e/online_serving/test_magi2.py
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
# Dedicated: HiDream-O1 accuracy needs a long TP2 run; the shared H100
|
||||
# 2-GPU sweep is only 90 minutes.
|
||||
- label: "Diffusion · HiDream-O1-Image Accuracy · H100 · 2-GPU"
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/test_hidream_o1_image.py -m "slow and diffusion and cuda and H100 and cards_2" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
# Dedicated: Boogu CFG-parallel size 3 needs 3 GPUs; weekly has no H100 3-GPU sweep.
|
||||
- label: "Diffusion · Boogu Edit CFG · H100 · 3-GPU"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_boogu_image_edit_expansion.py
|
||||
-k "test_double_guidance_cfg_parallel and cfg_parallel_3_full"
|
||||
-m "slow and diffusion and cuda and H100 and cards_3"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_3
|
||||
|
||||
# Dedicated: MAGI-2 Preview serving smoke needs ~30 min server init; the
|
||||
# shared H100 4-GPU sweep is only 90 minutes.
|
||||
- label: "Diffusion · MAGI-2 Preview Serving Smoke · H100 · 4-GPU"
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_magi2.py -m "slow and diffusion and cuda and H100 and cards_4" --run-level "full_model"
|
||||
mirror_hardwares: h100_4
|
||||
@@ -1,16 +1,16 @@
|
||||
# .buildkite/pipeline-intel.yaml
|
||||
# .buildkite/intel/pipeline-intel.yml
|
||||
steps:
|
||||
- group: "INTEL Tests"
|
||||
steps:
|
||||
- label: "Intel: XPU Test"
|
||||
command: "bash .buildkite/scripts/hardware_ci/run-xpu-test.sh"
|
||||
command: "bash .buildkite/intel/scripts/run-xpu-test.sh"
|
||||
agents:
|
||||
queue: "intel-gpu-omni"
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
# Buildkite will automatically replace this with the actual commit hash
|
||||
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}"
|
||||
VLLM_VERSION: "v0.22.0"
|
||||
VLLM_VERSION: "v0.30.0"
|
||||
priority: 100
|
||||
timeout_in_minutes: 60
|
||||
soft_fail: false
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
# vllm-omni Intel bootstrap
|
||||
# Uses static pipeline-intel.yml for Intel XPU tests
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
source .buildkite/common/scripts/resolve_skip_ci.sh
|
||||
|
||||
upload_pipeline() {
|
||||
echo "--- 🛠 Preparing Intel pipeline"
|
||||
buildkite-agent pipeline upload .buildkite/intel/pipeline-intel.yml
|
||||
}
|
||||
|
||||
gate_bootstrap_ci intel l2
|
||||
|
||||
upload_pipeline
|
||||
Executable
+127
@@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script build the XPU docker image and run the offline inference inside the container.
|
||||
set -ex
|
||||
|
||||
omni_source_dir=$(git rev-parse --show-toplevel)
|
||||
|
||||
: "${VLLM_VERSION:?VLLM_VERSION must be set}"
|
||||
# Official upstream XPU image. It is published from vllm's own
|
||||
# docker/Dockerfile.xpu, which is exactly what build_vllm_base() clones and
|
||||
# builds below, so pulling it is equivalent to building the fallback base.
|
||||
upstream_base_image="vllm/vllm-openai-xpu:${VLLM_VERSION}"
|
||||
local_base_image="xpu/vllm-omni-ci-base:${VLLM_VERSION}"
|
||||
image_name="xpu/vllm-omni-ci:${BUILDKITE_COMMIT:?BUILDKITE_COMMIT must be set}"
|
||||
container_name="xpu_${BUILDKITE_COMMIT}_$(
|
||||
tr -dc A-Za-z0-9 </dev/urandom | head -c 10
|
||||
echo
|
||||
)"
|
||||
|
||||
cd "${omni_source_dir}"
|
||||
|
||||
# The XPU base image is ~37GB; the default gzip layer exporter is single-threaded
|
||||
# and takes ~16min to compress it. zstd is multi-threaded (uses all cores) at a
|
||||
# similar ratio; set EXPORT_COMPRESSION=uncompressed to skip compression entirely
|
||||
# for local-only images. This requires the containerd image store (buildx docker
|
||||
# driver), which is the default here.
|
||||
EXPORT_COMPRESSION="${EXPORT_COMPRESSION:-zstd}"
|
||||
if [ "${EXPORT_COMPRESSION}" = "uncompressed" ]; then
|
||||
export_args=(--output "type=image,name={{IMAGE}},compression=uncompressed")
|
||||
else
|
||||
export_args=(--output "type=image,name={{IMAGE}},compression=${EXPORT_COMPRESSION},compression-level=3,force-compression=true")
|
||||
fi
|
||||
|
||||
docker_build() {
|
||||
# $1 = image name; remaining args passed through to docker build.
|
||||
local image="$1"
|
||||
shift
|
||||
local out=("${export_args[@]/'{{IMAGE}}'/${image}}")
|
||||
docker build "${out[@]}" "$@" -f docker/Dockerfile.xpu .
|
||||
}
|
||||
|
||||
build_vllm_base() (
|
||||
local vllm_source_dir
|
||||
vllm_source_dir=$(mktemp -d)
|
||||
trap 'rm -rf "${vllm_source_dir}"' EXIT
|
||||
|
||||
git clone --depth 1 --branch "${VLLM_VERSION}" \
|
||||
https://github.com/vllm-project/vllm "${vllm_source_dir}"
|
||||
|
||||
local out=("${export_args[@]/'{{IMAGE}}'/${base_image_name}}")
|
||||
docker build "${out[@]}" \
|
||||
--target vllm-openai \
|
||||
-f "${vllm_source_dir}/docker/Dockerfile.xpu" \
|
||||
"${vllm_source_dir}"
|
||||
)
|
||||
|
||||
# Resolve the vLLM base image, in priority order:
|
||||
# 1. the published upstream image for VLLM_VERSION, pulled fresh (so moving
|
||||
# tags like nightly are refreshed rather than served stale from disk);
|
||||
# 2. a local copy of that same image, when the registry is unreachable;
|
||||
# 3. VLLM_BASE, if that image is already on disk;
|
||||
# 4. otherwise build VLLM_BASE from the matching vLLM source tag (~30min).
|
||||
# VLLM_BASE names the fallback base and defaults to ${local_base_image}; set it
|
||||
# to reuse or produce a base under a different tag.
|
||||
resolve_vllm_base() {
|
||||
if docker pull "${upstream_base_image}"; then
|
||||
base_image_name="${upstream_base_image}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Registry unreachable, but a previous run may have left the image behind.
|
||||
if [ -n "$(docker images -q "${upstream_base_image}")" ]; then
|
||||
echo "WARNING: could not pull ${upstream_base_image}; using local copy" >&2
|
||||
base_image_name="${upstream_base_image}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "WARNING: ${upstream_base_image} unavailable remotely and locally" >&2
|
||||
base_image_name="${VLLM_BASE:-${local_base_image}}"
|
||||
if [ -z "$(docker images -q "${base_image_name}")" ]; then
|
||||
echo "WARNING: building ${base_image_name} from vLLM ${VLLM_VERSION} source" >&2
|
||||
build_vllm_base
|
||||
fi
|
||||
}
|
||||
|
||||
resolve_vllm_base
|
||||
|
||||
# Try building the docker image
|
||||
docker_build "${image_name}" --build-arg "VLLM_BASE=${base_image_name}" --build-arg "VLLM_VERSION=${VLLM_VERSION}"
|
||||
|
||||
# Setup cleanup
|
||||
remove_docker_container() {
|
||||
docker rm -f "${container_name}" || true
|
||||
docker image rm -f "${image_name}" || true
|
||||
docker system prune -f || true
|
||||
}
|
||||
trap remove_docker_container EXIT
|
||||
|
||||
HF_CACHE="${HF_CACHE:-$(realpath ~)/.cache/huggingface}"
|
||||
mkdir -p "${HF_CACHE}"
|
||||
HF_MOUNT="/root/.cache/huggingface"
|
||||
|
||||
time timeout -k 30 30m docker run \
|
||||
--device /dev/dri:/dev/dri \
|
||||
--net=host \
|
||||
--ipc=host \
|
||||
-v /dev/dri/by-path:/dev/dri/by-path \
|
||||
-v "${HF_CACHE}:${HF_MOUNT}" \
|
||||
--security-opt seccomp=unconfined \
|
||||
--entrypoint="" \
|
||||
-e VLLM_LOGGING_LEVEL \
|
||||
-e VLLM_OMNI_LOGGING_LEVEL \
|
||||
-e HF_TOKEN \
|
||||
-e ZE_AFFINITY_MASK \
|
||||
--name "${container_name}" \
|
||||
"${image_name}" \
|
||||
bash -c '
|
||||
set -e
|
||||
echo $ZE_AFFINITY_MASK
|
||||
pip install tblib==3.1.0
|
||||
cd /workspace/vllm-omni
|
||||
XPU_TEST_PATHS="tests/diffusion tests/dfx tests/e2e"
|
||||
pytest -v -s $XPU_TEST_PATHS -m "core_model and xpu and B60"
|
||||
pytest -v -s tests/diffusion/quantization/test_mxfp8_config.py
|
||||
pytest -v -s $XPU_TEST_PATHS -m "advanced_model and xpu and B60"
|
||||
pytest -v -s $XPU_TEST_PATHS -m "omni and xpu and B60"
|
||||
'
|
||||
@@ -1,10 +1,12 @@
|
||||
# Uploaded by upload_pipeline.py --upload (not the Buildkite hook).
|
||||
# ``if`` is injected by step ``key`` from skip-ci at upload time.
|
||||
steps:
|
||||
- label: ":buildkit: Build and Push NPU Test Image - A2"
|
||||
key: image-build
|
||||
agents:
|
||||
key: image-build-a2
|
||||
agents: &npu-image-build-agents
|
||||
queue: "ascend-a2b3"
|
||||
resource_class: "npu-1"
|
||||
plugins:
|
||||
plugins: &npu-image-build-plugins
|
||||
- kubernetes:
|
||||
metadata:
|
||||
annotations:
|
||||
@@ -44,69 +46,67 @@ steps:
|
||||
IMAGE_NAME: "vllm-omni-ci-npu"
|
||||
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
||||
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
||||
command: |
|
||||
set -ex
|
||||
command: bash .buildkite/npu/scripts/build-npu-image.sh Dockerfile.npu.ci "$${VLLM_IMAGE_TAG}"
|
||||
|
||||
echo "--- Building and pushing NPU Test Image"
|
||||
echo "Image: $${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG}"
|
||||
echo "buildkitd address: $${BUILDKITD_ADDR}"
|
||||
- label: ":buildkit: Build and Push NPU Test Image - A3"
|
||||
key: image-build-a3
|
||||
agents: *npu-image-build-agents
|
||||
plugins: *npu-image-build-plugins
|
||||
env:
|
||||
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}-a3"
|
||||
IMAGE_NAME: "vllm-omni-ci-npu"
|
||||
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
||||
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
||||
command: bash .buildkite/npu/scripts/build-npu-image.sh Dockerfile.npu.ci "$${VLLM_IMAGE_TAG}" -a3
|
||||
|
||||
if ! command -v buildctl &> /dev/null; then
|
||||
echo "Installing buildctl..."
|
||||
mkdir -p /tmp/buildkit
|
||||
BUILDKIT_VERSION="v0.29.0"
|
||||
wget -q "https://github.com/moby/buildkit/releases/download/$${BUILDKIT_VERSION}/buildkit-$${BUILDKIT_VERSION}.linux-arm64.tar.gz" -O /tmp/buildkit.tar.gz
|
||||
tar -xzf /tmp/buildkit.tar.gz -C /tmp/buildkit
|
||||
cp /tmp/buildkit/bin/buildctl /usr/local/bin/
|
||||
fi
|
||||
- label: ":buildkit: Build and Push NPU Test Image - A5"
|
||||
key: image-build-a5
|
||||
agents: *npu-image-build-agents
|
||||
plugins: *npu-image-build-plugins
|
||||
env:
|
||||
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}-a5"
|
||||
IMAGE_NAME: "vllm-omni-ci-npu"
|
||||
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
||||
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
||||
command: bash .buildkite/npu/scripts/build-npu-image.sh Dockerfile.npu.ci "$${VLLM_IMAGE_TAG}" -a5
|
||||
|
||||
export DOCKER_CONFIG=/home/user/.docker
|
||||
buildctl \
|
||||
--addr="$${BUILDKITD_ADDR}" \
|
||||
--tlscacert=/home/user/.docker/ca.pem \
|
||||
--tlscert=/home/user/.docker/cert.pem \
|
||||
--tlskey=/home/user/.docker/key.pem \
|
||||
build \
|
||||
--frontend dockerfile.v0 \
|
||||
--local context=. \
|
||||
--local dockerfile=./docker \
|
||||
--opt filename=Dockerfile.npu.ci \
|
||||
--secret id=dockerconfig,src=/home/user/.docker/config.json \
|
||||
--output type=image,name=$${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG},push=true \
|
||||
--progress=plain
|
||||
|
||||
echo "--- Image pushed successfully"
|
||||
echo "$${IMAGE_REGISTRY}/$${IMAGE_NAME}:$${VLLM_IMAGE_TAG}"
|
||||
- label: ":buildkit: Build and Push NPU Test Image - 310P"
|
||||
key: image-build-310p
|
||||
agents: *npu-image-build-agents
|
||||
plugins: *npu-image-build-plugins
|
||||
env:
|
||||
VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}-310p"
|
||||
IMAGE_NAME: "vllm-omni-ci-npu"
|
||||
IMAGE_REGISTRY: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry"
|
||||
BUILDKITD_ADDR: "tcp://buildkitd-service.buildkitd:1234"
|
||||
command: bash .buildkite/npu/scripts/build-npu-image.sh Dockerfile.npu.ci "$${VLLM_IMAGE_TAG}" -310p
|
||||
|
||||
- label: "Upload Ready Pipeline"
|
||||
depends_on: image-build
|
||||
depends_on:
|
||||
- image-build-a2
|
||||
- image-build-a3
|
||||
- image-build-a5
|
||||
- image-build-310p
|
||||
key: upload-ready-pipeline
|
||||
if: >-
|
||||
build.branch != "main" && (
|
||||
build.pull_request.labels includes "npu-test" ||
|
||||
build.pull_request.labels includes "ready"
|
||||
)
|
||||
agents:
|
||||
queue: "ascend-a2b3"
|
||||
resource_class: "npu-1"
|
||||
queue: "cpu_queue_premerge"
|
||||
command: |
|
||||
buildkite-agent pipeline upload .buildkite/test-npu-ready.yaml
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/npu/test-npu-ready.yml
|
||||
|
||||
# L4 Test — main+NIGHTLY=1 (scheduled), or PR with specific label (e.g. add label then Rebuild)
|
||||
# L4 Test — main+NIGHTLY=1 (scheduled), or PR nightly-test label
|
||||
- label: "Upload Nightly Pipeline"
|
||||
depends_on: image-build
|
||||
depends_on:
|
||||
- image-build-a2
|
||||
- image-build-a3
|
||||
- image-build-a5
|
||||
- image-build-310p
|
||||
key: upload-nightly-pipeline
|
||||
if: >-
|
||||
(build.branch == "main" && build.env("NIGHTLY") == "1") ||
|
||||
(build.branch != "main" && (
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "omni-test" ||
|
||||
build.pull_request.labels includes "tts-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2iat-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2v-test"
|
||||
))
|
||||
commands:
|
||||
- buildkite-agent pipeline upload .buildkite/test-npu-nightly.yaml
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${NIGHTLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--all"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/npu/test-npu-nightly.yml
|
||||
agents:
|
||||
queue: "ascend-a2b3"
|
||||
resource_class: "npu-1"
|
||||
queue: "cpu_queue_premerge"
|
||||
@@ -88,7 +88,7 @@
|
||||
# # queue: "ascend-a3"
|
||||
# # resource_class: "npu-2"
|
||||
# # command: |
|
||||
# # buildkite-agent pipeline upload .buildkite/test-npu-ready.yaml
|
||||
# # buildkite-agent pipeline upload .buildkite/npu/test-npu-ready.yml
|
||||
|
||||
# # L4 Test — main+NIGHTLY=1 (scheduled), or PR with specific label (e.g. add label then Rebuild)
|
||||
# - label: "Upload Nightly Pipeline"
|
||||
@@ -96,15 +96,9 @@
|
||||
# key: upload-nightly-pipeline
|
||||
# if: >-
|
||||
# (build.branch == "main" && build.env("NIGHTLY") == "1") ||
|
||||
# (build.branch != "main" && (
|
||||
# build.pull_request.labels includes "nightly-test" ||
|
||||
# build.pull_request.labels includes "omni-test" ||
|
||||
# build.pull_request.labels includes "tts-test" ||
|
||||
# build.pull_request.labels includes "diffusion-x2iat-test" ||
|
||||
# build.pull_request.labels includes "diffusion-x2v-test"
|
||||
# ))
|
||||
# (build.branch != "main" && build.pull_request.labels includes "nightly-test")
|
||||
# commands:
|
||||
# - buildkite-agent pipeline upload .buildkite/test-npu-nightly.yaml
|
||||
# - buildkite-agent pipeline upload .buildkite/npu/test-npu-nightly.yml
|
||||
# agents:
|
||||
# queue: "ascend-a3"
|
||||
# resource_class: "npu-2"
|
||||
@@ -0,0 +1,9 @@
|
||||
# Hook uploads this entry YAML; upload_pipeline.py --upload reads bootstrap-upload-steps.yml
|
||||
# and injects ``if`` by step ``key`` from skip-ci.
|
||||
steps:
|
||||
- label: ":github: Resolve skip-ci & upload pipeline"
|
||||
key: upload-ci-pipeline
|
||||
commands:
|
||||
- "python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/npu/bootstrap-upload-steps.yml"
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
dockerfile=${1:?Dockerfile is required}
|
||||
image_tag=${2:?Image tag is required}
|
||||
device_suffix=${3:-}
|
||||
|
||||
image_name=${IMAGE_NAME:-vllm-omni-ci-npu}
|
||||
image_registry=${IMAGE_REGISTRY:-swr.cn-southwest-2.myhuaweicloud.com/modelfoundry}
|
||||
buildkitd_addr=${BUILDKITD_ADDR:-tcp://buildkitd-service.buildkitd:1234}
|
||||
|
||||
echo "--- Building and pushing NPU Test Image"
|
||||
echo "Image: ${image_registry}/${image_name}:${image_tag}"
|
||||
echo "Dockerfile: ${dockerfile}"
|
||||
|
||||
if ! command -v buildctl &> /dev/null; then
|
||||
mkdir -p /tmp/buildkit
|
||||
buildkit_version=v0.29.0
|
||||
wget -q \
|
||||
"https://github.com/moby/buildkit/releases/download/${buildkit_version}/buildkit-${buildkit_version}.linux-arm64.tar.gz" \
|
||||
-O /tmp/buildkit.tar.gz
|
||||
tar -xzf /tmp/buildkit.tar.gz -C /tmp/buildkit
|
||||
cp /tmp/buildkit/bin/buildctl /usr/local/bin/
|
||||
fi
|
||||
|
||||
build_args=()
|
||||
if [[ -n "${device_suffix}" ]]; then
|
||||
build_args+=(--opt "build-arg:VLLM_ASCEND_DEVICE_SUFFIX=${device_suffix}")
|
||||
fi
|
||||
|
||||
export DOCKER_CONFIG=/home/user/.docker
|
||||
buildctl \
|
||||
--addr="${buildkitd_addr}" \
|
||||
--tlscacert=/home/user/.docker/ca.pem \
|
||||
--tlscert=/home/user/.docker/cert.pem \
|
||||
--tlskey=/home/user/.docker/key.pem \
|
||||
build \
|
||||
--frontend dockerfile.v0 \
|
||||
--local context=. \
|
||||
--local dockerfile=./docker \
|
||||
--opt "filename=${dockerfile}" \
|
||||
"${build_args[@]}" \
|
||||
--secret id=dockerconfig,src=/home/user/.docker/config.json \
|
||||
--output "type=image,name=${image_registry}/${image_name}:${image_tag},push=true" \
|
||||
--progress=plain
|
||||
|
||||
echo "--- Image pushed successfully"
|
||||
echo "${image_registry}/${image_name}:${image_tag}"
|
||||
@@ -0,0 +1,349 @@
|
||||
steps:
|
||||
- group: ":card_index_dividers: Omni Model Test"
|
||||
key: nightly-omni-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
- label: ":full_moon: Omni · Perf Test · No Async Chunk"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: nightly-omni-performance-no-async-chunk
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m npu --test-config-file tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · Perf Test · Async Chunk"
|
||||
source_file_dependencies: omni_qwen3_omni_perf
|
||||
key: nightly-omni-performance-async-chunk
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m npu --test-config-file tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_function
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5_expansion.py -m 'full_model' --run-level 'full_model'
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_function
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/e2e/online_serving/test_minicpmo_4_5_duplex.py
|
||||
tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py
|
||||
-m "npu and A3 and omni"
|
||||
--run-level full_model
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Accuracy Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_accuracy
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
# Pin the Seed-TTS scorer to the second card: _get_eval_device() otherwise
|
||||
# auto-picks npu:0, which the omni server under test already fills with its
|
||||
# KV cache, so Whisper OOMs on `.to(device)` and every clip reports
|
||||
# "ASR / WER failed".
|
||||
- export SEED_TTS_WER_EVAL=1
|
||||
- export SEED_TTS_EVAL_DEVICE=npu:1
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/e2e/accuracy/minicpmo_4_5/test_minicpmo_4_5.py -m "full_model and npu and A3" --run-level full_model
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/e2e/accuracy/minicpmo_4_5/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · Omni-DuplexEval CI Guard"
|
||||
source_file_dependencies: omni_duplex_eval_ci
|
||||
timeout_in_minutes: 240
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
VLLM_DUPLEX_EVAL_JUDGE_URL: "http://127.0.0.1:8001"
|
||||
commands:
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/e2e/accuracy/omni_duplex_eval/test_omni_duplex_eval_ci.py \
|
||||
-m "full_model and npu and A3 and cards_2" \
|
||||
--run-level full_model \
|
||||
--basetemp /tmp/omni_duplex_ci
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/e2e/accuracy/omni_duplex_eval/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5-npu
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m "npu and A3" --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test (A2)"
|
||||
source_file_dependencies: omni_minicpmo_4_5_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5-npu-a2
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a2b3_npu_1
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
HF_HUB_OFFLINE: "1"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m "npu and A2" --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Seed-TTS Perf Test"
|
||||
source_file_dependencies: omni_minicpmo_4_5_duplex_perf
|
||||
key: nightly-omni-performance-minicpmo-4-5-duplex-seed-tts-npu
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m "npu and A3" --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- group: ":card_index_dividers: TTS Model Test"
|
||||
key: nightly-tts-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
- label: ":full_moon: TTS · Perf Test"
|
||||
source_file_dependencies: tts_qwen3_tts_perf
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m npu --test-config-file tests/dfx/perf/tests/test_tts.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- group: ":card_index_dividers: Diffusion X2I(&A&T) Model Test"
|
||||
key: nightly-diffusion-x2iat-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
- label: ":full_moon: HunyuanImage3-DIT · Accuracy Test"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_accuracy
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HUNYUAN_IMAGE3_MODEL: "tencent/HunyuanImage-3.0-Instruct"
|
||||
HUNYUAN_IMAGE3_DEVICES: "0,1,2,3"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py -m "full_model and A3" --run-level full_model
|
||||
- label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=2 CFGP=2"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_perf
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py -m A3 --test-config-file tests/dfx/perf/tests/test_hunyuan_image_tp2_cfgp2.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=2 SP=2"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_perf
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py -m A3 --test-config-file tests/dfx/perf/tests/test_hunyuan_image_tp2_sp2.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=4"
|
||||
source_file_dependencies: diffusion_hunyuan_image3_perf
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py -m A3 --test-config-file tests/dfx/perf/tests/test_hunyuan_image_tp4.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image · Single-NPU"
|
||||
source_file_dependencies: diffusion_qwen_image_perf
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-single-npu
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py -m "npu and A3 and cards_1" --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image · 4-NPU"
|
||||
source_file_dependencies: diffusion_qwen_image_perf
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-4npu
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py -m "npu and A3 and cards_4" --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json"
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log"
|
||||
exit $$EXIT
|
||||
- group: ":card_index_dividers: Diffusion X2V Model Test"
|
||||
key: nightly-diffusion-x2v-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test"
|
||||
steps:
|
||||
- label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Function Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_function
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a2b3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
HF_HUB_OFFLINE: "1"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "npu and A2" --run-level "full_model"
|
||||
- label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Perf Test"
|
||||
source_file_dependencies: diffusion_hunyuan_video_perf
|
||||
key: nightly-diffusion-x2v-performance-hunyuanvideo15
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
HF_HUB_OFFLINE: "1"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m "npu and A3" --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Diffusion X2V · Wan 2.2 Function Test"
|
||||
source_file_dependencies: diffusion_wan22_function
|
||||
mirror_hardwares: a2b3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k npu_i2v --run-level "full_model"
|
||||
- label: ":full_moon: Diffusion X2V · Wan 2.2 Perf Test"
|
||||
source_file_dependencies: diffusion_wan22_perf
|
||||
key: nightly-diffusion-x2v-performance
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m npu --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
@@ -0,0 +1,156 @@
|
||||
steps:
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "Platforms Test"
|
||||
key: ready-platforms-test
|
||||
mirror_hardwares: a3_npu_2
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/platforms/npu/test_minicpmo_code2wav_npugraph.py
|
||||
-m 'core_model and npu and A3 and omni'
|
||||
--run-level 'core_model'
|
||||
|
||||
- label: "Diffusion NPU layer tests - A2"
|
||||
key: ready-diffusion-npu-layer-tests-a2
|
||||
mirror_hardwares: a2b3_npu_1
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/diffusion/layers/test_activation.py
|
||||
-m 'core_model and npu and A2'
|
||||
--run-level 'core_model'
|
||||
|
||||
- label: "Diffusion NPU layer tests - A3"
|
||||
key: ready-diffusion-npu-layer-tests
|
||||
mirror_hardwares: a3_npu_2
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/diffusion/layers/test_activation.py
|
||||
tests/diffusion/layers/test_fused_qk_norm_rope_npu.py
|
||||
tests/diffusion/models/minimax_h3/test_minimax_h3_qwen3vl_swiglu.py
|
||||
tests/diffusion/models/minimax_h3/test_minimax_h3_modulation.py
|
||||
-m 'core_model and npu and A3'
|
||||
--run-level 'core_model'
|
||||
|
||||
- label: "Diffusion NPU layer tests - A5"
|
||||
key: ready-diffusion-npu-layer-tests-a5
|
||||
mirror_hardwares: a5_npu_2
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/diffusion/layers/test_activation.py
|
||||
-m 'core_model and npu and A5'
|
||||
--run-level 'core_model'
|
||||
|
||||
- label: "Diffusion NPU layer tests - 310P"
|
||||
key: ready-diffusion-npu-layer-tests-310p
|
||||
mirror_hardwares: 310p_npu_1
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/diffusion/layers/test_activation.py
|
||||
-m 'core_model and npu and 310P'
|
||||
--run-level 'core_model'
|
||||
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
key: ready-e2e-group
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "Omni · MiniCPM-o 4.5 Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py -m 'core_model and npu and A3 and omni' --run-level 'core_model'
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py -m 'core_model and npu and A3 and omni' --run-level 'core_model'
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Perf Test"
|
||||
timeout_in_minutes: 60
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_ready.json -m 'core_model and npu and A3 and omni'
|
||||
|
||||
- label: "Omni · Qwen3-Omni Test"
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni.py -m 'core_model and npu and A3 and omni' --run-level 'core_model'
|
||||
timeout_in_minutes: 60
|
||||
|
||||
- label: ":sound: TTS · Qwen3-TTS CustomVoice Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py -m 'core_model and npu' --run-level 'core_model'
|
||||
|
||||
- label: "Diffusion · HunyuanVideo-1.5 Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m 'core_model and diffusion and npu' --run-level 'core_model'
|
||||
"
|
||||
timeout_in_minutes: 60
|
||||
|
||||
- label: "Diffusion · Qwen Image Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image.py -m 'core_model and npu' --run-level 'core_model'
|
||||
"
|
||||
timeout_in_minutes: 60
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_wan22_t2v.py -m 'core_model and npu' --run-level 'core_model'
|
||||
"
|
||||
timeout_in_minutes: 60
|
||||
|
||||
- label: "Diffusion · Hunyuan Image Test"
|
||||
mirror_hardwares: a3_npu_4
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_hunyuan_image.py -m 'core_model and diffusion and npu' --run-level 'core_model'
|
||||
"
|
||||
timeout_in_minutes: 60
|
||||
@@ -1,76 +0,0 @@
|
||||
# Document 1: Buildkite loads only this block on first parse. The next step resolves docs-only skip-ci
|
||||
# from git diff, then uploads document 2. When docs-only skip applies, image-build still runs for the nightly
|
||||
# exception in upload_pipeline.py (nightly-test label or main NIGHTLY=1); otherwise upload-nightly
|
||||
# can be skipped together with test-ready/test-merge. Weekly uploads also depend on image-build.
|
||||
|
||||
# Document 2: appended after `---`; same file, read by upload_pipeline.py (not evaluated as a second pipeline by Buildkite). Child uploads include test-ready.yml, test-merge.yml, test-nightly.yml, and test-weekly.yml.
|
||||
steps:
|
||||
- label: ":github: Resolve skip-ci & upload pipeline"
|
||||
key: upload-ci-pipeline
|
||||
commands:
|
||||
- "python3 .buildkite/scripts/upload_pipeline.py --upload .buildkite/pipeline.yml"
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
---
|
||||
steps:
|
||||
- label: ":docker: Build image"
|
||||
key: image-build
|
||||
if: __IMAGE_BUILD_IF__
|
||||
commands:
|
||||
- "aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/q9t5s3a7"
|
||||
- "docker build --progress=plain --file docker/Dockerfile.ci -t vllm-omni-ci ."
|
||||
- "docker tag vllm-omni-ci public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT"
|
||||
- "docker push public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT"
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L2 Test
|
||||
- label: "Upload Ready Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-ready-pipeline
|
||||
if: __UPLOAD_READY_IF__
|
||||
commands:
|
||||
- python3 .buildkite/scripts/upload_pipeline.py --upload .buildkite/test-ready.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L3 Test
|
||||
- label: "Upload Merge Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-merge-pipeline
|
||||
if: __UPLOAD_MERGE_IF__
|
||||
commands:
|
||||
- python3 .buildkite/scripts/upload_pipeline.py --upload .buildkite/test-merge.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L4 Test — main+NIGHTLY=1 (scheduled), or PR with specific label (e.g. add label then Rebuild)
|
||||
- label: "Upload Nightly Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-nightly-pipeline
|
||||
if: >-
|
||||
(build.branch == "main" && build.env("NIGHTLY") == "1") ||
|
||||
(build.branch != "main" && (
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "omni-test" ||
|
||||
build.pull_request.labels includes "tts-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2iat-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2v-test"
|
||||
))
|
||||
commands:
|
||||
- buildkite-agent pipeline upload .buildkite/test-nightly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L5 Test — main+WEEKLY=1 (scheduled), or PR with weekly-test label
|
||||
- label: "Upload Weekly Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-weekly-pipeline
|
||||
if: >-
|
||||
(build.branch == "main" && build.env("WEEKLY") == "1") ||
|
||||
(build.branch != "main" && build.pull_request.labels includes "weekly-test")
|
||||
commands:
|
||||
- buildkite-agent pipeline upload .buildkite/test-weekly.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
@@ -16,7 +16,7 @@ steps:
|
||||
- "uv venv --python=3.12 && source .venv/bin/activate"
|
||||
- "uv pip install --upgrade build"
|
||||
- "python3 -m build"
|
||||
- "bash .buildkite/scripts/upload-nightly-wheels.sh"
|
||||
- "bash .buildkite/release/scripts/upload-nightly-wheels.sh"
|
||||
|
||||
- label: "Generate and upload wheel indices"
|
||||
depends_on: "build-wheel"
|
||||
@@ -24,7 +24,7 @@ steps:
|
||||
agents:
|
||||
queue: small_cpu_queue_release
|
||||
commands:
|
||||
- "bash .buildkite/scripts/generate-and-upload-nightly-index.sh"
|
||||
- "bash .buildkite/release/scripts/generate-and-upload-nightly-index.sh"
|
||||
|
||||
- block: "Upload release wheels to PyPI"
|
||||
depends_on: "build-wheel"
|
||||
@@ -38,11 +38,13 @@ steps:
|
||||
agents:
|
||||
queue: small_cpu_queue_release
|
||||
commands:
|
||||
- "bash .buildkite/scripts/publish-release-wheels-pypi.sh"
|
||||
- "bash .buildkite/release/scripts/publish-release-wheels-pypi.sh"
|
||||
|
||||
# Auto-skip when NIGHTLY=1 (scheduled); otherwise require manual unblock.
|
||||
- block: "Unblock to build release Docker images"
|
||||
depends_on: ~
|
||||
key: block-build-release-images
|
||||
if: build.env("NIGHTLY") != "1"
|
||||
|
||||
- group: "Build release Docker images"
|
||||
key: "build-release-images"
|
||||
@@ -63,7 +65,7 @@ steps:
|
||||
--progress plain \
|
||||
-f docker/Dockerfile.cuda .
|
||||
- "docker push public.ecr.aws/q9t5s3a7/vllm-omni-release-repo:$BUILDKITE_COMMIT-$(uname -m)"
|
||||
# re-tag to default image tag and push, just in case arm64 build fails
|
||||
# Fallback default tag (no arch suffix) if arm64 build fails.
|
||||
- "docker tag public.ecr.aws/q9t5s3a7/vllm-omni-release-repo:$BUILDKITE_COMMIT-$(uname -m) public.ecr.aws/q9t5s3a7/vllm-omni-release-repo:$BUILDKITE_COMMIT"
|
||||
- "docker push public.ecr.aws/q9t5s3a7/vllm-omni-release-repo:$BUILDKITE_COMMIT"
|
||||
env:
|
||||
@@ -86,6 +88,26 @@ steps:
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
|
||||
# NIGHTLY=1 only: promote ECR images to DockerHub nightly tags, then prune.
|
||||
- label: "Publish nightly multi-arch image to DockerHub"
|
||||
depends_on:
|
||||
- build-release-image-x86
|
||||
- build-release-image-arm64
|
||||
if: build.env("NIGHTLY") == "1"
|
||||
key: publish-nightly-images-dockerhub
|
||||
agents:
|
||||
queue: small_cpu_queue_release
|
||||
commands:
|
||||
- "bash .buildkite/release/scripts/publish-release-images.sh nightly"
|
||||
- "bash .buildkite/release/scripts/cleanup-nightly-builds.sh"
|
||||
plugins:
|
||||
- docker-login#v3.0.0:
|
||||
username: vllmbot
|
||||
password-env: DOCKERHUB_TOKEN
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
DOCKERHUB_USERNAME: "vllmbot"
|
||||
|
||||
- block: "Publish release images to DockerHub"
|
||||
key: block-publish-release-images
|
||||
depends_on:
|
||||
@@ -100,7 +122,7 @@ steps:
|
||||
agents:
|
||||
queue: small_cpu_queue_release
|
||||
commands:
|
||||
- "bash .buildkite/scripts/publish-release-images.sh"
|
||||
- "bash .buildkite/release/scripts/publish-release-images.sh"
|
||||
plugins:
|
||||
- docker-login#v3.0.0:
|
||||
username: vllmbot
|
||||
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Clean up old nightly builds from DockerHub (vllm/vllm-omni), keeping the
|
||||
# newest 14 tags with the nightly- prefix.
|
||||
|
||||
set -ex
|
||||
|
||||
TAG_PREFIX="nightly-"
|
||||
REPO="vllm/vllm-omni"
|
||||
REPO_API_URL="https://hub.docker.com/v2/repositories/${REPO}/tags"
|
||||
|
||||
echo "Cleaning up tags with prefix: $TAG_PREFIX in repository: $REPO"
|
||||
|
||||
if [ -z "$DOCKERHUB_TOKEN" ]; then
|
||||
echo "Error: DOCKERHUB_TOKEN environment variable is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$DOCKERHUB_USERNAME" ]; then
|
||||
echo "Error: DOCKERHUB_USERNAME environment variable is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Getting DockerHub bearer token..."
|
||||
set +x
|
||||
BEARER_TOKEN=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"username\": \"$DOCKERHUB_USERNAME\", \"password\": \"$DOCKERHUB_TOKEN\"}" \
|
||||
"https://hub.docker.com/v2/users/login" | jq -r '.token')
|
||||
set -x
|
||||
|
||||
if [ -z "$BEARER_TOKEN" ] || [ "$BEARER_TOKEN" = "null" ]; then
|
||||
echo "Error: Failed to get DockerHub bearer token"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
get_all_tags() {
|
||||
local page=1
|
||||
local all_tags=""
|
||||
# Hub `name` is a partial match (not a strict prefix). Use it to narrow the
|
||||
# list, then enforce startswith() client-side. Exhaust API pages; do not
|
||||
# stop merely because a page has no matching tags after filtering.
|
||||
local name_query
|
||||
name_query=$(printf '%s' "$TAG_PREFIX" | jq -sRr @uri)
|
||||
|
||||
while true; do
|
||||
set +x
|
||||
local response
|
||||
response=$(curl -s -H "Authorization: Bearer $BEARER_TOKEN" \
|
||||
"$REPO_API_URL?page=$page&page_size=100&name=${name_query}")
|
||||
set -x
|
||||
|
||||
local page_count
|
||||
page_count=$(echo "$response" | jq -r '.results | length')
|
||||
if [ -z "$page_count" ] || [ "$page_count" = "0" ] || [ "$page_count" = "null" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
local tags
|
||||
tags=$(echo "$response" | jq -r --arg prefix "$TAG_PREFIX" \
|
||||
'.results[] | select(.name | startswith($prefix)) | "\(.last_updated)|\(.name)"')
|
||||
|
||||
if [ -n "$tags" ]; then
|
||||
all_tags="$all_tags$tags"$'\n'
|
||||
fi
|
||||
page=$((page + 1))
|
||||
done
|
||||
|
||||
echo "$all_tags" | sort -r | cut -d'|' -f2
|
||||
}
|
||||
|
||||
delete_tag() {
|
||||
local tag_name="$1"
|
||||
echo "Deleting tag: $tag_name"
|
||||
|
||||
local delete_url="https://hub.docker.com/v2/repositories/${REPO}/tags/$tag_name"
|
||||
set +x
|
||||
local response http_code body
|
||||
response=$(curl -s -w "\n%{http_code}" -X DELETE \
|
||||
-H "Authorization: Bearer $BEARER_TOKEN" "$delete_url")
|
||||
set -x
|
||||
http_code=$(printf '%s\n' "$response" | tail -n1)
|
||||
body=$(printf '%s\n' "$response" | sed '$d')
|
||||
|
||||
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
|
||||
echo "Successfully deleted tag: $tag_name (HTTP ${http_code})"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local detail=""
|
||||
if echo "$body" | jq -e '.detail' > /dev/null 2>&1; then
|
||||
detail=$(echo "$body" | jq -r '.detail')
|
||||
elif [ -n "$body" ]; then
|
||||
detail="$body"
|
||||
else
|
||||
detail="(empty response body)"
|
||||
fi
|
||||
echo "Error: Failed to delete tag $tag_name (HTTP ${http_code}): ${detail}"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "Fetching all tags from DockerHub..."
|
||||
all_tags=$(get_all_tags)
|
||||
|
||||
if [ -z "$all_tags" ]; then
|
||||
echo "No tags found to clean up"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
total_tags=$(echo "$all_tags" | wc -l)
|
||||
echo "Found $total_tags tags"
|
||||
|
||||
tags_to_keep=14
|
||||
tags_to_delete=$((total_tags - tags_to_keep))
|
||||
|
||||
if [ $tags_to_delete -le 0 ]; then
|
||||
echo "No tags need to be deleted (only $total_tags tags found, keeping $tags_to_keep)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Will delete $tags_to_delete old tags, keeping the newest $tags_to_keep"
|
||||
|
||||
tags_to_delete_list=$(echo "$all_tags" | tail -n +$((tags_to_keep + 1)))
|
||||
|
||||
if [ -z "$tags_to_delete_list" ]; then
|
||||
echo "No tags to delete"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Deleting old tags..."
|
||||
delete_failures=0
|
||||
while IFS= read -r tag; do
|
||||
if [ -n "$tag" ]; then
|
||||
if ! delete_tag "$tag"; then
|
||||
delete_failures=$((delete_failures + 1))
|
||||
fi
|
||||
sleep 1
|
||||
fi
|
||||
done <<< "$tags_to_delete_list"
|
||||
|
||||
if [ "$delete_failures" -gt 0 ]; then
|
||||
echo "Cleanup finished with ${delete_failures} deletion failure(s)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Cleanup completed successfully"
|
||||
+3
-3
@@ -36,12 +36,12 @@ mkdir -p "$INDICES_OUTPUT_DIR"
|
||||
|
||||
# HACK: we do not need regex module here, but it is required by pre-commit hook
|
||||
# To avoid any external dependency, we simply replace it back to the stdlib re module
|
||||
sed -i.bak 's/import regex as re/import re/g' .buildkite/scripts/generate-nightly-index.py && rm -f .buildkite/scripts/generate-nightly-index.py.bak
|
||||
sed -i.bak 's/import regex as re/import re/g' .buildkite/release/scripts/generate-nightly-index.py && rm -f .buildkite/release/scripts/generate-nightly-index.py.bak
|
||||
|
||||
# Generate indices -- the version is just the commit hash (not omni/{commit})
|
||||
# because relative paths are computed between the index and wheel directories,
|
||||
# both of which live under the omni/ prefix in S3.
|
||||
$PYTHON .buildkite/scripts/generate-nightly-index.py \
|
||||
$PYTHON .buildkite/release/scripts/generate-nightly-index.py \
|
||||
--version "$BUILDKITE_COMMIT" \
|
||||
--current-objects "$obj_json" \
|
||||
--output-dir "$INDICES_OUTPUT_DIR" \
|
||||
@@ -78,7 +78,7 @@ if [[ "$version" != *"dev"* ]]; then
|
||||
rm -rf "${INDICES_OUTPUT_DIR:?}"
|
||||
mkdir -p "$INDICES_OUTPUT_DIR"
|
||||
# wheel-dir is overridden to be the commit directory, so that the indices point to the correct wheel path
|
||||
$PYTHON .buildkite/scripts/generate-nightly-index.py \
|
||||
$PYTHON .buildkite/release/scripts/generate-nightly-index.py \
|
||||
--version "$s3_version" \
|
||||
--wheel-dir "$BUILDKITE_COMMIT" \
|
||||
--current-objects "$obj_json" \
|
||||
File renamed without changes.
+87
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Publish Docker images from ECR staging to DockerHub.
|
||||
#
|
||||
# Usage:
|
||||
# publish-release-images.sh # release mode (default)
|
||||
# publish-release-images.sh release
|
||||
# publish-release-images.sh nightly
|
||||
#
|
||||
# Release tags: latest, v<version>
|
||||
# Nightly tags: nightly, nightly-<commit>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
MODE="${1:-release}"
|
||||
|
||||
DOCKERHUB_REPO="vllm/vllm-omni"
|
||||
ECR_REPO="public.ecr.aws/q9t5s3a7/vllm-omni-release-repo"
|
||||
COMMIT="$BUILDKITE_COMMIT"
|
||||
PRIMARY_TAGS=()
|
||||
EXTRA_MANIFEST_TAGS=()
|
||||
|
||||
case "${MODE}" in
|
||||
release)
|
||||
RELEASE_VERSION=$(buildkite-agent meta-data get release-version --default "" | sed 's/^v//')
|
||||
if [ -z "${RELEASE_VERSION}" ]; then
|
||||
echo "ERROR: release-version metadata not set"
|
||||
exit 1
|
||||
fi
|
||||
PRIMARY_TAGS=("latest" "v${RELEASE_VERSION}")
|
||||
;;
|
||||
nightly)
|
||||
# Commit-pinned manifest reuses nightly-{x86_64,aarch64} arch images.
|
||||
PRIMARY_TAGS=("nightly")
|
||||
EXTRA_MANIFEST_TAGS=("nightly-${COMMIT}")
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {release|nightly}"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "========================================"
|
||||
echo "Publishing ${MODE} images to ${DOCKERHUB_REPO}"
|
||||
echo " Commit: ${COMMIT}"
|
||||
echo " Primary tags: ${PRIMARY_TAGS[*]}"
|
||||
if [ ${#EXTRA_MANIFEST_TAGS[@]} -gt 0 ]; then
|
||||
echo " Extra manifests: ${EXTRA_MANIFEST_TAGS[*]}"
|
||||
fi
|
||||
echo "========================================"
|
||||
|
||||
aws ecr-public get-login-password --region us-east-1 | \
|
||||
docker login --username AWS --password-stdin public.ecr.aws/q9t5s3a7
|
||||
|
||||
SRC_X86="${ECR_REPO}:${COMMIT}-x86_64"
|
||||
SRC_ARM="${ECR_REPO}:${COMMIT}-aarch64"
|
||||
|
||||
docker pull "${SRC_X86}"
|
||||
docker pull "${SRC_ARM}"
|
||||
|
||||
publish_manifest() {
|
||||
local tag="$1"
|
||||
local arch_tag_base="$2"
|
||||
docker manifest rm "${DOCKERHUB_REPO}:${tag}" || true
|
||||
docker manifest create \
|
||||
"${DOCKERHUB_REPO}:${tag}" \
|
||||
"${DOCKERHUB_REPO}:${arch_tag_base}-x86_64" \
|
||||
"${DOCKERHUB_REPO}:${arch_tag_base}-aarch64"
|
||||
docker manifest push "${DOCKERHUB_REPO}:${tag}"
|
||||
}
|
||||
|
||||
for tag in "${PRIMARY_TAGS[@]}"; do
|
||||
docker tag "${SRC_X86}" "${DOCKERHUB_REPO}:${tag}-x86_64"
|
||||
docker tag "${SRC_ARM}" "${DOCKERHUB_REPO}:${tag}-aarch64"
|
||||
docker push "${DOCKERHUB_REPO}:${tag}-x86_64"
|
||||
docker push "${DOCKERHUB_REPO}:${tag}-aarch64"
|
||||
publish_manifest "${tag}" "${tag}"
|
||||
done
|
||||
|
||||
ARCH_BASE="${PRIMARY_TAGS[0]}"
|
||||
for tag in "${EXTRA_MANIFEST_TAGS[@]}"; do
|
||||
publish_manifest "${tag}" "${ARCH_BASE}"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Successfully published ${MODE} images"
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,73 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Helper function to safely login to ECR Public with per-job config isolation
|
||||
# Uses DOCKER_CONFIG environment variable to prevent race conditions
|
||||
#
|
||||
# This script prevents the "device or resource busy" error by giving each
|
||||
# Buildkite job its own isolated Docker config directory.
|
||||
#
|
||||
# Usage:
|
||||
# source docker_login_ecr_public.sh && safe_docker_login_ecr_public
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Configuration
|
||||
ECR_REGISTRY="public.ecr.aws"
|
||||
|
||||
setup_isolated_docker_config() {
|
||||
# Use BUILDKITE_JOB_ID for job-specific isolation
|
||||
# Fallback to PID if running outside Buildkite
|
||||
local job_id="${BUILDKITE_JOB_ID:-$$}"
|
||||
|
||||
# Set Docker config to job-specific directory
|
||||
export DOCKER_CONFIG="/tmp/docker-config-${job_id}"
|
||||
|
||||
# Create directory if it doesn't exist
|
||||
mkdir -p "$DOCKER_CONFIG"
|
||||
|
||||
echo "[docker-config] Using isolated Docker config: $DOCKER_CONFIG"
|
||||
}
|
||||
|
||||
check_docker_auth() {
|
||||
# Check if already authenticated to the given registry
|
||||
# Returns 0 if authenticated, 1 if not
|
||||
local registry="$1"
|
||||
|
||||
# Check if credentials exist in the isolated config
|
||||
if [[ -f "$DOCKER_CONFIG/config.json" ]]; then
|
||||
# Check if registry is present in config
|
||||
if grep -q "$registry" "$DOCKER_CONFIG/config.json" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
safe_docker_login_ecr_public() {
|
||||
# Setup isolated config first
|
||||
setup_isolated_docker_config
|
||||
|
||||
local registry="$ECR_REGISTRY"
|
||||
|
||||
# Check if already authenticated (within this job)
|
||||
if check_docker_auth "$registry"; then
|
||||
echo "[docker-login] Already authenticated to $registry in this job"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Perform login to isolated config directory
|
||||
echo "[docker-login] Logging in to $ECR_REGISTRY (isolated config)..."
|
||||
if aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin "$ECR_REGISTRY"; then
|
||||
echo "[docker-login] Login successful (config: $DOCKER_CONFIG)"
|
||||
return 0
|
||||
else
|
||||
local exit_code=$?
|
||||
echo "[docker-login] ERROR: Login failed with exit code $exit_code" >&2
|
||||
return $exit_code
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute if run as script (not sourced)
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
safe_docker_login_ecr_public
|
||||
fi
|
||||
@@ -1,154 +0,0 @@
|
||||
#!/bin/bash
|
||||
# vllm-omni customized version
|
||||
# Based on: vllm/.buildkite/scripts/hardware_ci/run-amd-test.sh
|
||||
# Last synced: 2025-12-15
|
||||
# Modifications: docker image name for vllm-omni
|
||||
|
||||
# This script runs test inside the corresponding ROCm docker container.
|
||||
set -o pipefail
|
||||
|
||||
# Export Python path
|
||||
export PYTHONPATH=".."
|
||||
|
||||
# Print ROCm version
|
||||
echo "--- ROCm info"
|
||||
rocminfo
|
||||
|
||||
# cleanup older docker images
|
||||
cleanup_docker() {
|
||||
# Get Docker's root directory
|
||||
docker_root=$(docker info -f '{{.DockerRootDir}}')
|
||||
if [ -z "$docker_root" ]; then
|
||||
echo "Failed to determine Docker root directory."
|
||||
exit 1
|
||||
fi
|
||||
echo "Docker root directory: $docker_root"
|
||||
# Check disk usage of the filesystem where Docker's root directory is located
|
||||
disk_usage=$(df "$docker_root" | tail -1 | awk '{print $5}' | sed 's/%//')
|
||||
# Define the threshold
|
||||
threshold=70
|
||||
if [ "$disk_usage" -gt "$threshold" ]; then
|
||||
echo "Disk usage is above $threshold%. Cleaning up Docker images and volumes..."
|
||||
# Remove dangling images (those that are not tagged and not used by any container)
|
||||
docker image prune -f
|
||||
# Remove unused volumes / force the system prune for old images as well.
|
||||
docker volume prune -f && docker system prune --force --filter "until=72h" --all
|
||||
echo "Docker images and volumes cleanup completed."
|
||||
else
|
||||
echo "Disk usage is below $threshold%. No cleanup needed."
|
||||
fi
|
||||
}
|
||||
|
||||
# Call the cleanup docker function
|
||||
cleanup_docker
|
||||
|
||||
echo "--- Pulling container"
|
||||
## Temporary change to use AMD Docker Hub to store the vllm-omni image
|
||||
# to bypass the rate limit issue with ECR Public Gallery.
|
||||
# Images are now stored in a separate repository for vllm-omni, instead of vllm-ci.
|
||||
# TODO: @tjtanaa point back to ECR Public Gallery
|
||||
# once the amd agents are configured to use ECR Public Gallery.
|
||||
# image_name="public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:${BUILDKITE_COMMIT}-rocm-omni"
|
||||
image_name="rocm/vllm-omni:${BUILDKITE_COMMIT}"
|
||||
container_name="rocm_${BUILDKITE_COMMIT}_$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 10; echo)"
|
||||
|
||||
# TODO: @tjtanaa uncomment this once the amd agents are configured to use ECR Public Gallery.
|
||||
# # Install AWS CLI to authenticate to ECR Public Gallery to get higher rate limit for pulling images
|
||||
# sudo apt-get update && sudo apt-get install -y awscli
|
||||
## Use safe docker login helper to prevent race conditions
|
||||
# source "$(dirname "${BASH_SOURCE[0]}")/../docker_login_ecr_public.sh"
|
||||
# safe_docker_login_ecr_public
|
||||
|
||||
## Pull the container from AMD Docker Hub
|
||||
|
||||
docker pull "${image_name}"
|
||||
|
||||
remove_docker_container() {
|
||||
docker rm -f "${container_name}" || docker image rm -f "${image_name}" || true
|
||||
}
|
||||
trap remove_docker_container EXIT
|
||||
|
||||
echo "--- Running container"
|
||||
|
||||
HF_CACHE="$(realpath ~)/huggingface"
|
||||
mkdir -p "${HF_CACHE}"
|
||||
HF_MOUNT="/root/.cache/huggingface"
|
||||
|
||||
if [[ -n "${TEST_COMMAND:-}" ]]; then
|
||||
commands="$TEST_COMMAND"
|
||||
else
|
||||
commands="$@"
|
||||
fi
|
||||
echo "Commands:$commands"
|
||||
|
||||
PARALLEL_JOB_COUNT=8
|
||||
MYPYTHONPATH=".."
|
||||
|
||||
# Test that we're launching on the machine that has
|
||||
# proper access to GPUs
|
||||
render_gid=$(getent group render | cut -d: -f3)
|
||||
if [[ -z "$render_gid" ]]; then
|
||||
echo "Error: 'render' group not found. This is required for GPU access." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# check if the command contains shard flag, we will run all shards in parallel because the host have 8 GPUs.
|
||||
# TODO: @tjtanaa reenable to run VLLM_ROCM_USE_AITER=1 when AITER is shipped with prebuilt kernels.
|
||||
if [[ $commands == *"--shard-id="* ]]; then
|
||||
# assign job count as the number of shards used
|
||||
commands=$(echo "$commands" | sed -E "s/--num-shards[[:blank:]]*=[[:blank:]]*[0-9]*/--num-shards=${PARALLEL_JOB_COUNT} /g" | sed 's/ \\ / /g')
|
||||
for GPU in $(seq 0 $(($PARALLEL_JOB_COUNT-1))); do
|
||||
# assign shard-id for each shard
|
||||
commands_gpu=$(echo "$commands" | sed -E "s/--shard-id[[:blank:]]*=[[:blank:]]*[0-9]*/--shard-id=${GPU} /g" | sed 's/ \\ / /g')
|
||||
echo "Shard ${GPU} commands:$commands_gpu"
|
||||
echo "Render devices: $BUILDKITE_AGENT_META_DATA_RENDER_DEVICES"
|
||||
docker run \
|
||||
--device /dev/kfd $BUILDKITE_AGENT_META_DATA_RENDER_DEVICES \
|
||||
--network=host \
|
||||
--shm-size=16gb \
|
||||
--group-add "$render_gid" \
|
||||
--rm \
|
||||
-e MIOPEN_DEBUG_CONV_DIRECT=0 \
|
||||
-e MIOPEN_DEBUG_CONV_GEMM=0 \
|
||||
-e VLLM_ROCM_USE_AITER=0 \
|
||||
-e HIP_VISIBLE_DEVICES="${GPU}" \
|
||||
-e HF_TOKEN \
|
||||
-v "${HF_CACHE}:${HF_MOUNT}" \
|
||||
-e "HF_HOME=${HF_MOUNT}" \
|
||||
-e "PYTHONPATH=${MYPYTHONPATH}" \
|
||||
--name "${container_name}_${GPU}" \
|
||||
"${image_name}" \
|
||||
/bin/bash -c "${commands_gpu}" \
|
||||
|& while read -r line; do echo ">>Shard $GPU: $line"; done &
|
||||
PIDS+=($!)
|
||||
done
|
||||
#wait for all processes to finish and collect exit codes
|
||||
for pid in "${PIDS[@]}"; do
|
||||
wait "${pid}"
|
||||
STATUS+=($?)
|
||||
done
|
||||
for st in "${STATUS[@]}"; do
|
||||
if [[ ${st} -ne 0 ]]; then
|
||||
echo "One of the processes failed with $st"
|
||||
exit "${st}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Render devices: $BUILDKITE_AGENT_META_DATA_RENDER_DEVICES"
|
||||
docker run \
|
||||
--device /dev/kfd $BUILDKITE_AGENT_META_DATA_RENDER_DEVICES \
|
||||
--network=host \
|
||||
--shm-size=16gb \
|
||||
--group-add "$render_gid" \
|
||||
--rm \
|
||||
-e MIOPEN_DEBUG_CONV_DIRECT=0 \
|
||||
-e MIOPEN_DEBUG_CONV_GEMM=0 \
|
||||
-e VLLM_ROCM_USE_AITER=0 \
|
||||
-e HF_TOKEN \
|
||||
-v "${HF_CACHE}:${HF_MOUNT}" \
|
||||
-e "HF_HOME=${HF_MOUNT}" \
|
||||
-e "PYTHONPATH=${MYPYTHONPATH}" \
|
||||
--name "${container_name}" \
|
||||
"${image_name}" \
|
||||
/bin/bash -c "${commands}"
|
||||
fi
|
||||
@@ -1,58 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script build the XPU docker image and run the offline inference inside the container.
|
||||
set -ex
|
||||
|
||||
omni_source_dir=$(git rev-parse --show-toplevel)
|
||||
|
||||
base_image_name="xpu/vllm-omni-ci-base:${VLLM_VERSION:?VLLM_VERSION must be set}"
|
||||
image_name="xpu/vllm-omni-ci:${BUILDKITE_COMMIT:?BUILDKITE_COMMIT must be set}"
|
||||
container_name="xpu_${BUILDKITE_COMMIT}_$(
|
||||
tr -dc A-Za-z0-9 </dev/urandom | head -c 10
|
||||
echo
|
||||
)"
|
||||
|
||||
cd "${omni_source_dir}"
|
||||
if [ -z "$(docker images -q "${base_image_name}")" ]; then
|
||||
docker build --target vllm-base -t "${base_image_name}" --build-arg "VLLM_VERSION=${VLLM_VERSION}" -f docker/Dockerfile.xpu .
|
||||
fi
|
||||
|
||||
# Try building the docker image
|
||||
docker build --build-arg "VLLM_BASE=${base_image_name}" --build-arg "VLLM_VERSION=${VLLM_VERSION}" -t "${image_name}" -f docker/Dockerfile.xpu .
|
||||
|
||||
# Setup cleanup
|
||||
remove_docker_container() {
|
||||
docker rm -f "${container_name}" || true
|
||||
docker image rm -f "${image_name}" || true
|
||||
docker system prune -f || true
|
||||
}
|
||||
trap remove_docker_container EXIT
|
||||
|
||||
HF_CACHE="${HF_CACHE:-$(realpath ~)/.cache/huggingface}"
|
||||
mkdir -p "${HF_CACHE}"
|
||||
HF_MOUNT="/root/.cache/huggingface"
|
||||
|
||||
time timeout -k 30 30m docker run \
|
||||
--device /dev/dri:/dev/dri \
|
||||
--net=host \
|
||||
--ipc=host \
|
||||
-v /dev/dri/by-path:/dev/dri/by-path \
|
||||
-v "${HF_CACHE}:${HF_MOUNT}" \
|
||||
--security-opt seccomp=unconfined \
|
||||
--entrypoint="" \
|
||||
-e VLLM_LOGGING_LEVEL \
|
||||
-e VLLM_OMNI_LOGGING_LEVEL \
|
||||
-e HF_TOKEN \
|
||||
-e ZE_AFFINITY_MASK \
|
||||
--name "${container_name}" \
|
||||
"${image_name}" \
|
||||
bash -c '
|
||||
set -e
|
||||
echo $ZE_AFFINITY_MASK
|
||||
pip install tblib==3.1.0
|
||||
cd /workspace/vllm-omni
|
||||
pytest -v -s -m "core_model and xpu and B60"
|
||||
pytest -v -s tests/diffusion/quantization/test_mxfp8_config.py
|
||||
export VLLM_XPU_USE_SAMPLER_KERNEL=0 # NOTE: Remove this after vLLM v0.21.1 is merged. Fixes Qwen2-5 omni-expansion tests.
|
||||
pytest -v -s -m "advanced_model and xpu and B60"
|
||||
'
|
||||
@@ -1,145 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script build the Ascend NPU docker image and run the offline inference inside the container.
|
||||
# It serves a sanity check for compilation and basic model usage.
|
||||
set -ex
|
||||
|
||||
# Base ubuntu image with basic ascend development libraries and python installed
|
||||
VLLM_OMNI_REPO="https://github.com/vllm-project/vllm-omni.git"
|
||||
BASE_IMAGE_NAME="quay.nju.edu.cn/ascend/vllm-ascend:v0.11.0rc2"
|
||||
image_name="npu/vllm-omni-ci:${BUILDKITE_COMMIT}_${EPOCHSECONDS}"
|
||||
# image_name="npu/vllm-ci:${BUILDKITE_COMMIT}_${EPOCHSECONDS}"
|
||||
container_name="npu_${BUILDKITE_COMMIT}_$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 10; echo)"
|
||||
|
||||
# BUILDKITE_AGENT_NAME format is {hostname}-{agent_idx}-{npu_card_num}cards
|
||||
agent_idx=$(echo "${BUILDKITE_AGENT_NAME}" | awk -F'-' '{print $(NF-1)}')
|
||||
echo "agent_idx: ${agent_idx}"
|
||||
builder_name="cachebuilder${agent_idx}"
|
||||
builder_cache_dir="/mnt/docker-cache${agent_idx}"
|
||||
mkdir -p ${builder_cache_dir}
|
||||
|
||||
# Try building the docker image
|
||||
cat <<EOF | DOCKER_BUILDKIT=1 docker build \
|
||||
--add-host pypi-cache:${PYPI_CACHE_HOST} \
|
||||
--builder ${builder_name} --cache-from type=local,src=${builder_cache_dir} \
|
||||
--cache-to type=local,dest=${builder_cache_dir},mode=max \
|
||||
--build-arg BUILDKITE_PULL_REQUEST="${BUILDKITE_PULL_REQUEST}" \
|
||||
--build-arg BUILDKITE_PULL_REQUEST_REPO="${BUILDKITE_PULL_REQUEST_REPO}" \
|
||||
--progress=plain --load -t ${image_name} -f - .
|
||||
FROM ${BASE_IMAGE_NAME}
|
||||
|
||||
# Define environments
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN pip config set global.index-url http://pypi-cache:${PYPI_CACHE_PORT}/pypi/simple && \
|
||||
pip config set global.trusted-host pypi-cache && \
|
||||
apt-get update -y && \
|
||||
apt-get install -y python3-pip git vim wget net-tools gcc g++ cmake libnuma-dev && \
|
||||
rm -rf /var/cache/apt/* && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install for pytest to make the docker build cache layer always valid
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install pytest>=6.0 pytest-cov modelscope
|
||||
|
||||
COPY . .
|
||||
|
||||
# Install vllm-omni
|
||||
WORKDIR /workspace
|
||||
ARG VLLM_OMNI_REPO=https://github.com/vllm-project/vllm-omni.git
|
||||
ARG VLLM_OMNI_TAG=main
|
||||
ARG BUILDKITE_PULL_REQUEST
|
||||
ARG BUILDKITE_PULL_REQUEST_REPO
|
||||
RUN git config --global url."https://gh-proxy.test.osinfra.cn/https://github.com/".insteadOf "https://github.com/" && \
|
||||
if [ "\$BUILDKITE_PULL_REQUEST" != "false" ] && [ -n "\$BUILDKITE_PULL_REQUEST" ]; then \
|
||||
echo "Cloning and checking out PR #\$BUILDKITE_PULL_REQUEST..." && \
|
||||
git clone \$VLLM_OMNI_REPO /workspace/vllm-omni && \
|
||||
cd /workspace/vllm-omni && \
|
||||
git fetch origin pull/\$BUILDKITE_PULL_REQUEST/head:pr-\$BUILDKITE_PULL_REQUEST && \
|
||||
git checkout pr-\$BUILDKITE_PULL_REQUEST; \
|
||||
else \
|
||||
echo "Not a PR build, using main branch" && \
|
||||
git clone --depth 1 \$VLLM_OMNI_REPO /workspace/vllm-omni; \
|
||||
fi
|
||||
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
export PIP_EXTRA_INDEX_URL=https://mirrors.huaweicloud.com/ascend/repos/pypi && \
|
||||
source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||
source /usr/local/Ascend/nnal/atb/set_env.sh && \
|
||||
export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:/usr/local/Ascend/ascend-toolkit/latest/`uname -i`-linux/devlib && \
|
||||
python3 -m pip install -v -e /workspace/vllm-omni/
|
||||
|
||||
ENV VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
|
||||
WORKDIR /workspace/vllm-omni
|
||||
CMD ["/bin/bash"]
|
||||
|
||||
EOF
|
||||
|
||||
# Setup cleanup
|
||||
remove_docker_container() {
|
||||
docker rm -f "${container_name}" || true;
|
||||
docker image rm -f "${image_name}" || true;
|
||||
docker system prune -f || true;
|
||||
}
|
||||
trap remove_docker_container EXIT
|
||||
|
||||
# Generate corresponding --device args based on BUILDKITE_AGENT_NAME
|
||||
# Ascend NPU BUILDKITE_AGENT_NAME format is {hostname}-{agent_idx}-{npu_card_num}cards, and agent_idx starts from 1.
|
||||
# e.g. atlas-a2-001-1-2cards means this is the 1-th agent on atlas-a2-001 host, and it has 2 NPU cards.
|
||||
# returns --device /dev/davinci0 --device /dev/davinci1
|
||||
parse_and_gen_devices() {
|
||||
local input="$1"
|
||||
local index cards_num
|
||||
if [[ "$input" =~ ([0-9]+)-([0-9]+)cards$ ]]; then
|
||||
index="${BASH_REMATCH[1]}"
|
||||
cards_num="${BASH_REMATCH[2]}"
|
||||
else
|
||||
echo "parse error" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local devices=""
|
||||
local i=0
|
||||
while (( i < cards_num )); do
|
||||
local dev_idx=$(((index - 1)*cards_num + i ))
|
||||
devices="$devices --device /dev/davinci${dev_idx}"
|
||||
((i++))
|
||||
done
|
||||
|
||||
# trim leading space
|
||||
devices="${devices#"${devices%%[![:space:]]*}"}"
|
||||
# Output devices: assigned to the caller variable
|
||||
printf '%s' "$devices"
|
||||
}
|
||||
|
||||
devices=$(parse_and_gen_devices "${BUILDKITE_AGENT_NAME}") || exit 1
|
||||
|
||||
# Run the image and execute the Out-Of-Tree (OOT) platform interface test case on Ascend NPU hardware.
|
||||
# This test checks whether the OOT platform interface is functioning properly in conjunction with
|
||||
# the hardware plugin vllm-ascend.
|
||||
hf_model_cache_dir=/mnt/hf_cache${agent_idx}
|
||||
ms_model_cache_dir=/mnt/modelscope${agent_idx}
|
||||
mkdir -p ${hf_model_cache_dir}
|
||||
mkdir -p ${ms_model_cache_dir}
|
||||
docker run \
|
||||
--init \
|
||||
${devices} \
|
||||
--device /dev/davinci_manager \
|
||||
--device /dev/devmm_svm \
|
||||
--device /dev/hisi_hdc \
|
||||
-v /usr/local/dcmi:/usr/local/dcmi \
|
||||
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
|
||||
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
|
||||
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
|
||||
-v /etc/ascend_install.info:/etc/ascend_install.info \
|
||||
-v ${hf_model_cache_dir}:/root/.cache/huggingface \
|
||||
-v ${ms_model_cache_dir}:/root/.cache/modelscope \
|
||||
--network host \
|
||||
--entrypoint="" \
|
||||
--name "${container_name}" \
|
||||
"${image_name}" \
|
||||
bash -c '
|
||||
set -e
|
||||
VLLM_USE_MODELSCOPE=True pytest -s -v tests/e2e/offline_inference/test_qwen2_5_omni_expansion.py
|
||||
'
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Publish release Docker images from ECR to DockerHub.
|
||||
# Pulls per-arch images, tags with `latest` and versioned tags, pushes them,
|
||||
# then creates and pushes a multi-arch manifest.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
RELEASE_VERSION=$(buildkite-agent meta-data get release-version --default "" | sed 's/^v//')
|
||||
if [ -z "${RELEASE_VERSION}" ]; then
|
||||
echo "ERROR: release-version metadata not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
COMMIT="$BUILDKITE_COMMIT"
|
||||
DOCKERHUB_REPO="vllm/vllm-omni"
|
||||
ECR_REPO="public.ecr.aws/q9t5s3a7/vllm-omni-release-repo"
|
||||
|
||||
echo "========================================"
|
||||
echo "Publishing release images v${RELEASE_VERSION}"
|
||||
echo " Commit: ${COMMIT}"
|
||||
echo "========================================"
|
||||
|
||||
# Login to ECR to pull staging images
|
||||
aws ecr-public get-login-password --region us-east-1 | \
|
||||
docker login --username AWS --password-stdin public.ecr.aws/q9t5s3a7
|
||||
|
||||
docker pull "${ECR_REPO}:${COMMIT}-x86_64"
|
||||
docker pull "${ECR_REPO}:${COMMIT}-aarch64"
|
||||
|
||||
docker tag "${ECR_REPO}:${COMMIT}-x86_64" "${DOCKERHUB_REPO}:latest-x86_64"
|
||||
docker tag "${ECR_REPO}:${COMMIT}-x86_64" "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-x86_64"
|
||||
docker push "${DOCKERHUB_REPO}:latest-x86_64"
|
||||
docker push "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-x86_64"
|
||||
|
||||
docker tag "${ECR_REPO}:${COMMIT}-aarch64" "${DOCKERHUB_REPO}:latest-aarch64"
|
||||
docker tag "${ECR_REPO}:${COMMIT}-aarch64" "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-aarch64"
|
||||
docker push "${DOCKERHUB_REPO}:latest-aarch64"
|
||||
docker push "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-aarch64"
|
||||
|
||||
docker manifest rm "${DOCKERHUB_REPO}:latest" || true
|
||||
docker manifest rm "${DOCKERHUB_REPO}:v${RELEASE_VERSION}" || true
|
||||
docker manifest create "${DOCKERHUB_REPO}:latest" "${DOCKERHUB_REPO}:latest-x86_64" "${DOCKERHUB_REPO}:latest-aarch64"
|
||||
docker manifest create "${DOCKERHUB_REPO}:v${RELEASE_VERSION}" "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-x86_64" "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-aarch64"
|
||||
docker manifest push "${DOCKERHUB_REPO}:latest"
|
||||
docker manifest push "${DOCKERHUB_REPO}:v${RELEASE_VERSION}"
|
||||
|
||||
echo ""
|
||||
echo "Successfully published release images for v${RELEASE_VERSION}"
|
||||
@@ -1,308 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
"""Render and optionally upload Buildkite pipeline YAML with diff-aware logic.
|
||||
|
||||
Bootstrap mode (pipeline.yml with __IMAGE_BUILD_IF__ placeholders):
|
||||
- Detect docs-only PR/main changes and substitute skip-ci ``if`` expressions.
|
||||
|
||||
Test pipeline mode (e.g. test-merge.yml):
|
||||
- Drop steps or groups whose ``source_file_dependencies`` do not match changed files.
|
||||
- ``source_file_dependencies`` may be set on a leaf step or on a group step.
|
||||
- Always strip ``source_file_dependencies`` from uploaded YAML (Buildkite does not
|
||||
recognize this uploader-only key).
|
||||
|
||||
Usage:
|
||||
python3 upload_pipeline.py [--upload] <pipeline.yml>
|
||||
|
||||
# Bootstrap (replaces upload_pipeline_with_skip_ci.sh):
|
||||
python3 upload_pipeline.py --upload .buildkite/pipeline.yml
|
||||
|
||||
# Test pipeline (replaces upload_test_pipeline_with_diff_skip.py):
|
||||
python3 upload_pipeline.py --upload .buildkite/test-merge.yml
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
subprocess.check_call(
|
||||
[sys.executable, "-m", "pip", "install", "-q", "pyyaml"],
|
||||
)
|
||||
import yaml
|
||||
|
||||
LOG = "upload_pipeline"
|
||||
ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
DOC_SEP = "\n---\n"
|
||||
BOOTSTRAP_MARKER = "__IMAGE_BUILD_IF__"
|
||||
|
||||
|
||||
def _log(message: str) -> None:
|
||||
print(f"{LOG}: {message}", file=sys.stderr)
|
||||
|
||||
|
||||
def _git(*args: str) -> subprocess.CompletedProcess[str]:
|
||||
return subprocess.run(
|
||||
["git", *args],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
|
||||
def resolve_changed_files() -> list[str] | None:
|
||||
"""Return changed file paths, or None when diff cannot be resolved."""
|
||||
is_pr = os.environ.get("BUILDKITE_PULL_REQUEST", "false") != "false" and os.environ.get(
|
||||
"BUILDKITE_PULL_REQUEST", ""
|
||||
)
|
||||
commit = os.environ.get("BUILDKITE_COMMIT", "")
|
||||
|
||||
if is_pr:
|
||||
base_branch = os.environ.get("BUILDKITE_PULL_REQUEST_BASE_BRANCH", "main")
|
||||
base_ref = f"origin/{base_branch}"
|
||||
if _git("rev-parse", "--verify", base_ref).returncode != 0:
|
||||
_log(f"origin/{base_branch} not found locally; trying fetch")
|
||||
_git("fetch", "--depth=200", "origin", base_branch)
|
||||
if _git("rev-parse", "--verify", base_ref).returncode != 0:
|
||||
if _git("rev-parse", "--verify", base_branch).returncode == 0:
|
||||
base_ref = base_branch
|
||||
else:
|
||||
_log(f"cannot resolve PR base {base_branch}; using safe defaults")
|
||||
return None
|
||||
diff_range = f"{base_ref}...{commit}"
|
||||
elif os.environ.get("BUILDKITE_BRANCH", "") == "main":
|
||||
if _git("rev-parse", "--verify", f"{commit}^").returncode != 0:
|
||||
_log("main commit has no parent; using safe defaults")
|
||||
return None
|
||||
diff_range = f"{commit}^..{commit}"
|
||||
else:
|
||||
_log("not PR/main build; using safe defaults")
|
||||
return None
|
||||
|
||||
result = _git("diff", "--name-only", diff_range)
|
||||
if result.returncode != 0:
|
||||
_log(f"git diff failed ({diff_range}); using safe defaults")
|
||||
return None
|
||||
|
||||
files = [line for line in result.stdout.splitlines() if line.strip()]
|
||||
_log(f"{len(files)} changed file(s)")
|
||||
return files
|
||||
|
||||
|
||||
def is_docs_only_change(changed_files: list[str]) -> bool:
|
||||
has_any = False
|
||||
for file_path in changed_files:
|
||||
if not file_path:
|
||||
continue
|
||||
has_any = True
|
||||
if file_path.startswith("docs/"):
|
||||
continue
|
||||
if file_path.endswith(".md"):
|
||||
continue
|
||||
if file_path == "mkdocs.yml":
|
||||
continue
|
||||
return False
|
||||
return has_any
|
||||
|
||||
|
||||
def resolve_skip_ci(changed_files: list[str] | None) -> bool:
|
||||
if changed_files is None:
|
||||
_log("skip-ci=0 (could not resolve changed files)")
|
||||
return False
|
||||
if is_docs_only_change(changed_files):
|
||||
_log("docs-only change detected; skip-ci=1")
|
||||
return True
|
||||
_log("non-doc changes detected; skip-ci=0")
|
||||
return False
|
||||
|
||||
|
||||
def render_bootstrap_pipeline(text: str, *, skip_ci: bool) -> str:
|
||||
if DOC_SEP in text:
|
||||
_, continuation = text.split(DOC_SEP, 1)
|
||||
else:
|
||||
continuation = text
|
||||
|
||||
nightly_only = (
|
||||
'(build.pull_request.labels includes "nightly-test") || (build.branch == "main" && build.env("NIGHTLY") == "1")'
|
||||
)
|
||||
if skip_ci:
|
||||
image_if = f"'{nightly_only}'"
|
||||
ready_if = "'false'"
|
||||
merge_if = "'false'"
|
||||
else:
|
||||
image_if = "'true'"
|
||||
ready_if = '\'build.branch != "main" && build.pull_request.labels includes "ready"\''
|
||||
merge_if = (
|
||||
'\'(build.branch == "main" && build.env("NIGHTLY") != "1" '
|
||||
'&& build.env("WEEKLY") != "1") || '
|
||||
'(build.branch != "main" && build.pull_request.labels includes "merge-test")\''
|
||||
)
|
||||
|
||||
return (
|
||||
continuation.replace("__IMAGE_BUILD_IF__", image_if)
|
||||
.replace("__UPLOAD_READY_IF__", ready_if)
|
||||
.replace("__UPLOAD_MERGE_IF__", merge_if)
|
||||
)
|
||||
|
||||
|
||||
def _matches_dependencies(changed_files: list[str], prefixes: list[str]) -> bool:
|
||||
for path in changed_files:
|
||||
for prefix in prefixes:
|
||||
normalized = prefix.rstrip("/")
|
||||
if path == normalized or path.startswith(f"{normalized}/"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _strip_source_file_dependencies(step: dict[str, Any]) -> dict[str, Any]:
|
||||
return {key: value for key, value in step.items() if key != "source_file_dependencies"}
|
||||
|
||||
|
||||
def _step_label(step: dict[str, Any]) -> str:
|
||||
return str(step.get("group") or step.get("label") or "<step>")
|
||||
|
||||
|
||||
def _filter_steps(steps: list[Any], changed_files: list[str]) -> list[Any]:
|
||||
filtered: list[Any] = []
|
||||
for step in steps:
|
||||
if not isinstance(step, dict):
|
||||
filtered.append(step)
|
||||
continue
|
||||
|
||||
deps = step.get("source_file_dependencies")
|
||||
if deps is not None and not isinstance(deps, list):
|
||||
raise ValueError(
|
||||
f"source_file_dependencies must be a list in step {_step_label(step)!r}",
|
||||
)
|
||||
if deps is not None and not _matches_dependencies(changed_files, deps):
|
||||
_log(
|
||||
f"skip {_step_label(step)!r} (no changes under {deps})",
|
||||
)
|
||||
continue
|
||||
|
||||
nested = step.get("steps")
|
||||
if nested is not None:
|
||||
kept_nested = _filter_steps(nested, changed_files)
|
||||
if not kept_nested:
|
||||
_log(f"omit empty group {_step_label(step)!r}")
|
||||
continue
|
||||
new_step = _strip_source_file_dependencies(step)
|
||||
new_step["steps"] = kept_nested
|
||||
filtered.append(new_step)
|
||||
continue
|
||||
|
||||
if deps is not None:
|
||||
filtered.append(_strip_source_file_dependencies(step))
|
||||
else:
|
||||
filtered.append(step)
|
||||
|
||||
return filtered
|
||||
|
||||
|
||||
def _strip_uploader_metadata_from_steps(steps: list[Any]) -> list[Any]:
|
||||
"""Remove uploader-only keys while keeping all steps (no diff filtering)."""
|
||||
stripped: list[Any] = []
|
||||
for step in steps:
|
||||
if not isinstance(step, dict):
|
||||
stripped.append(step)
|
||||
continue
|
||||
|
||||
deps = step.get("source_file_dependencies")
|
||||
if deps is not None and not isinstance(deps, list):
|
||||
raise ValueError(
|
||||
f"source_file_dependencies must be a list in step {_step_label(step)!r}",
|
||||
)
|
||||
|
||||
nested = step.get("steps")
|
||||
new_step = _strip_source_file_dependencies(step)
|
||||
if nested is not None:
|
||||
new_step["steps"] = _strip_uploader_metadata_from_steps(nested)
|
||||
stripped.append(new_step)
|
||||
|
||||
return stripped
|
||||
|
||||
|
||||
def render_test_pipeline(
|
||||
doc: dict[str, Any],
|
||||
changed_files: list[str] | None,
|
||||
) -> dict[str, Any]:
|
||||
steps = doc.get("steps")
|
||||
if not isinstance(steps, list):
|
||||
return doc
|
||||
if changed_files is not None:
|
||||
steps = _filter_steps(steps, changed_files)
|
||||
else:
|
||||
steps = _strip_uploader_metadata_from_steps(steps)
|
||||
return {**doc, "steps": steps}
|
||||
|
||||
|
||||
def resolve_pipeline_path(arg: str) -> Path:
|
||||
path = Path(arg)
|
||||
if path.is_absolute():
|
||||
return path
|
||||
return ROOT / path
|
||||
|
||||
|
||||
def render_pipeline(path: Path) -> str:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
changed_files = resolve_changed_files()
|
||||
|
||||
if BOOTSTRAP_MARKER in text:
|
||||
rendered = render_bootstrap_pipeline(text, skip_ci=resolve_skip_ci(changed_files))
|
||||
return rendered
|
||||
|
||||
doc = yaml.safe_load(text)
|
||||
if not isinstance(doc, dict):
|
||||
raise ValueError(f"invalid pipeline YAML: {path}")
|
||||
|
||||
doc = render_test_pipeline(doc, changed_files)
|
||||
|
||||
return yaml.safe_dump(doc, sort_keys=False)
|
||||
|
||||
|
||||
def upload_to_buildkite(content: str) -> None:
|
||||
subprocess.run(
|
||||
["buildkite-agent", "pipeline", "upload"],
|
||||
input=content,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"pipeline",
|
||||
nargs="?",
|
||||
default=".buildkite/pipeline.yml",
|
||||
help="Pipeline YAML path (default: .buildkite/pipeline.yml)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--upload",
|
||||
action="store_true",
|
||||
help="Pipe rendered YAML to buildkite-agent pipeline upload",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
path = resolve_pipeline_path(args.pipeline)
|
||||
if not path.is_file():
|
||||
_log(f"missing pipeline file: {path}")
|
||||
return 1
|
||||
|
||||
rendered = render_pipeline(path)
|
||||
if args.upload:
|
||||
upload_to_buildkite(rendered)
|
||||
else:
|
||||
sys.stdout.write(rendered)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,250 +0,0 @@
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
steps:
|
||||
- label: "Simple · Diffusion & Model Executor Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "timeout 40m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM
|
||||
# that is not supported on CPU
|
||||
- "timeout 40m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
|
||||
- label: "Custom Pipeline Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/e2e/offline_inference/custom_pipeline/ -m "core_model"
|
||||
|
||||
|
||||
- label: "Voxtral TTS CUDA Unit Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 10m pytest -s -v tests/model_executor/models/voxtral_tts/test_cuda_graph_acoustic_transformer.py
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
steps:
|
||||
- label: "Diffusion · Batch Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/batching -m 'core_model and cuda' --run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Offloader Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- |
|
||||
timeout 20m bash -c '
|
||||
set +e
|
||||
pytest -s -v tests/diffusion/offloader/test_diffusion_cpu_offload.py
|
||||
EXIT1=\$?
|
||||
pytest -s -v tests/diffusion/offloader/test_diffusion_layerwise_offload.py
|
||||
EXIT2=\$?
|
||||
exit \$((EXIT1 | EXIT2))
|
||||
'
|
||||
|
||||
- label: "Diffusion · Cache Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- timeout 15m pytest -s -v -m "core_model and cache and diffusion and not distributed_cuda and L4"
|
||||
|
||||
- label: "Diffusion Sequence Parallelism Test"
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- timeout 20m pytest -s -v tests/diffusion/distributed/test_sequence_parallel.py -m core_model
|
||||
|
||||
- label: "Diffusion GPU Worker Test"
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/diffusion/test_diffusion_worker.py
|
||||
|
||||
- label: "Diffusion · Model Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/models/ -m 'core_model and cuda' --run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_TEST_CLEAN_GPU_MEMORY=1
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_wan22_t2v.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
|
||||
## ISSUE depends on `diffusers` package: https://github.com/huggingface/diffusers/issues/13274
|
||||
# - label: "Audio Generation Model Test"
|
||||
# agent_pool: mi325_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export GPU_ARCHS=gfx942
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - timeout 20m pytest -s -v tests/e2e/offline_inference/test_stable_audio_expansion.py -m "advanced_model and diffusion and L4" --run-level advanced_model
|
||||
|
||||
- label: "Engine Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- |
|
||||
timeout 15m bash -c '
|
||||
pytest -s -v tests/engine/test_async_omni_engine_abort.py
|
||||
'
|
||||
|
||||
# - label: "Omni Model Test Qwen3-Omni"
|
||||
# agent_pool: mi325_2
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - timeout 10m pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py
|
||||
# - timeout 20m pytest -s -v tests/e2e/online_serving/test_qwen3_omni.py -m "core_model" --run-level "core_model"
|
||||
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
steps:
|
||||
- label: "MiMo-Audio E2E Test with H100"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c '
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -s -v tests/e2e/online_serving/test_mimo_audio.py -m "core_model" --run-level "core_model"
|
||||
'
|
||||
|
||||
- label: "Qwen3-TTS E2E Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- timeout 30m pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py -m "core_model" --run-level "core_model"
|
||||
|
||||
- label: "Voxtral-TTS E2E Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c '
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -s -v tests/e2e/online_serving/test_voxtral_tts.py -m "advanced_model" --run-level "advanced_model"
|
||||
pytest -s -v tests/e2e/offline_inference/test_voxtral_tts.py -m "advanced_model" --run-level "advanced_model"
|
||||
'
|
||||
|
||||
- label: "CosyVoice3-TTS E2E Test"
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c '
|
||||
pytest -s -v tests/e2e/online_serving/test_cosyvoice3_tts_expansion.py -m "full_model" --run-level "core_model"
|
||||
'
|
||||
|
||||
# TODO: Bagel test on ROCm is very unstable. @tjtanaa
|
||||
# Need to debug before reneable numerical changes across large PRs
|
||||
# - label: "Bagel Text2Img Model Test"
|
||||
# agent_pool: mi325_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export GPU_ARCHS=gfx942
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - export VLLM_ROCM_USE_AITER_RMSNORM=0
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "core_model" --run-level "core_model" -k "rocm"
|
||||
|
||||
# - label: "Bagel Img2Img Model Test"
|
||||
# agent_pool: mi325_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export GPU_ARCHS=gfx942
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - export VLLM_ROCM_USE_AITER_RMSNORM=0
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "core_model" --run-level "core_model" -k "rocm"
|
||||
|
||||
# - label: "Bagel Online Serving Test"
|
||||
# agent_pool: mi325_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
# commands:
|
||||
# - export GPU_ARCHS=gfx942
|
||||
# - export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
# - export VLLM_LOGGING_LEVEL=DEBUG
|
||||
# - export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
# - export VLLM_ROCM_USE_AITER_RMSNORM=0
|
||||
# - timeout 40m pytest -s -v tests/e2e/online_serving/test_bagel.py -m "core_model" --run-level "core_model" -k "rocm"
|
||||
@@ -1,118 +0,0 @@
|
||||
steps:
|
||||
|
||||
- label: "Diffusion Model Test"
|
||||
timeout_in_minutes: 30
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- pytest -s -v tests/e2e/offline_inference/test_z_image.py
|
||||
|
||||
- label: "Diffusion Images API LoRA E2E"
|
||||
timeout_in_minutes: 30
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/diffusion/lora/test_images_generations_lora.py
|
||||
|
||||
- label: "Diffusion Model CPU offloading Test"
|
||||
timeout_in_minutes: 20
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/diffusion/offloader/test_diffusion_cpu_offload.py
|
||||
- pytest -s -v tests/diffusion/offloader/test_diffusion_layerwise_offload.py
|
||||
|
||||
- label: "Diffusion Cache Backend Test"
|
||||
timeout_in_minutes: 15
|
||||
agent_pool: mi325_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v -m 'core_model and cache and diffusion and not distributed_rocm and MI325'
|
||||
|
||||
- label: "Diffusion Sequence Parallelism Test"
|
||||
timeout_in_minutes: 20
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/diffusion/distributed/test_sequence_parallel.py -m core_model
|
||||
|
||||
- label: "Diffusion Tensor Parallelism Test"
|
||||
timeout_in_minutes: 20
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/diffusion/distributed/test_zimage_parallelism.py
|
||||
|
||||
- label: "Diffusion GPU Worker Test"
|
||||
timeout_in_minutes: 20
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- pytest -s -v tests/diffusion/test_diffusion_worker.py
|
||||
|
||||
- label: "Omni Model Test Qwen2-5-Omni"
|
||||
timeout_in_minutes: 15
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen2_5_omni_expansion.py
|
||||
- pytest -s -v tests/engine/test_async_omni_engine_abort.py
|
||||
|
||||
- label: "Omni Model Test Qwen3-Omni"
|
||||
timeout_in_minutes: 15
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_omni.py
|
||||
|
||||
|
||||
- label: "Omni Sleep Mode Test"
|
||||
timeout_in_minutes: 40
|
||||
agent_pool: mi325_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/entrypoints/test_omni_sleep_mode.py -m "advanced_model and omni and MI325" --run-level "advanced_model"
|
||||
@@ -1,884 +0,0 @@
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_USE_FLASHINFER_MOE_FP16: 0
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "Simple · Diffusion & Model Executor Test"
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
commands:
|
||||
- "timeout 20m pytest -sv -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "Diffusion · LoRA Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -sv tests/diffusion/lora/ -m 'advanced_model and cuda' --run-level "advanced_model"
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Distributed Test"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- |
|
||||
timeout 55m bash -c "
|
||||
set -e
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/distributed -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- group: ":card_index_dividers: Entrypoints Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "Entrypoint Test with H100"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and H100" --run-level "advanced_model"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Entrypoint Test with L4"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and L4" --run-level "advanced_model"
|
||||
agents:
|
||||
queue: "gpu_4_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py tests/e2e/offline_inference/test_qwen3_tts_customvoice.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_4_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "TTS · Qwen3-TTS Base Test"
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_base.py tests/e2e/offline_inference/test_qwen3_tts_base.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_4_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "TTS · Ming-Omni-TTS Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
pytest -s -v tests/e2e/online_serving/test_ming_tts.py tests/e2e/offline_inference/test_ming_tts.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "TTS · Voxtral-TTS Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_voxtral_tts.py
|
||||
- tests/e2e/online_serving/test_voxtral_tts.py
|
||||
- vllm_omni/model_executor/models/voxtral_tts/
|
||||
- vllm_omni/model_executor/stage_input_processors/voxtral_tts.py
|
||||
- vllm_omni/deploy/voxtral_tts.yaml
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
pytest -s -v tests/e2e/offline_inference/test_voxtral_tts.py tests/e2e/online_serving/test_voxtral_tts.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "TTS · GLM-TTS Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_glm_tts.py
|
||||
- tests/e2e/offline_inference/test_glm_tts.py
|
||||
- vllm_omni/model_executor/models/glm_tts/
|
||||
- vllm_omni/model_executor/stage_input_processors/glm_tts.py
|
||||
- vllm_omni/deploy/glm_tts.yaml
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
pytest -s -v tests/e2e/online_serving/test_glm_tts.py tests/e2e/offline_inference/test_glm_tts.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Omni · Qwen3-Omni Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_qwen3_omni.py
|
||||
- tests/e2e/online_serving/test_qwen3_omni.py
|
||||
- vllm_omni/model_executor/models/qwen3_omni/
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_omni.py
|
||||
- vllm_omni/deploy/qwen3_omni_moe.yaml
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py tests/e2e/online_serving/test_qwen3_omni.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Omni · Mimo Audio Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_mimo_audio.py
|
||||
- vllm_omni/model_executor/models/mimo_audio/
|
||||
- vllm_omni/model_executor/stage_input_processors/mimo_audio.py
|
||||
- vllm_omni/deploy/mimo_audio.yaml
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_mimo_audio.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "TTS · VoxCPM2 Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -s -v tests/e2e/offline_inference/test_voxcpm2_tts.py tests/e2e/online_serving/test_voxcpm2_tts.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Omni · Higgs-Audio V2 Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_USE_DEEP_GEMM=0
|
||||
export VLLM_MOE_USE_DEEP_GEMM=0
|
||||
pytest -s -v tests/e2e/online_serving/test_higgs_audio_v2.py tests/e2e/offline_inference/test_higgs_audio_v2.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · Qwen Image Edit Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image_edit.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen_image_edit.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Longcat Image Edit Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_longcat_image_edit.py
|
||||
- vllm_omni/diffusion/models/longcat_image/
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_longcat_image_edit.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Longcat Image Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_longcat_image.py
|
||||
- vllm_omni/diffusion/models/longcat_image/
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_longcat_image.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Bagel Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_bagel.py
|
||||
- tests/e2e/online_serving/test_bagel.py
|
||||
- vllm_omni/model_executor/models/bagel/
|
||||
- vllm_omni/diffusion/models/bagel/
|
||||
- vllm_omni/model_executor/stage_input_processors/bagel.py
|
||||
- vllm_omni/deploy/bagel.yaml
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_bagel.py tests/e2e/online_serving/test_bagel.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
|
||||
- label: "Diffusion · Qwen Image Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c '
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
'
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Qwen Image Layered Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image_layered.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image_layered.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_wan22_t2v.py
|
||||
- tests/e2e/online_serving/test_wan22_t2v.py
|
||||
- vllm_omni/diffusion/models/wan2_2/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/offline_inference/test_wan22_t2v.py tests/e2e/online_serving/test_wan22_t2v.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · HunyuanVideo 1.5 Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_hunyuan_video_15.py
|
||||
- vllm_omni/diffusion/models/hunyuan_video/
|
||||
timeout_in_minutes: 40
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Z Image Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_z_image.py tests/e2e/online_serving/test_z_image.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · FLUX.2 Klein Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_flux2_klein.py tests/e2e/online_serving/test_flux2_klein.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · SD3 Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_sd3.py
|
||||
- vllm_omni/diffusion/models/sd3/
|
||||
timeout_in_minutes: 45
|
||||
commands:
|
||||
- |
|
||||
timeout 45m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_sd3.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 4
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,24 +0,0 @@
|
||||
steps:
|
||||
- group: ":card_index_dividers: Diffusion X2V Model Test"
|
||||
key: nightly-diffusion-x2v-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: >-
|
||||
build.env("NIGHTLY") == "1" ||
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2v-test"
|
||||
steps:
|
||||
- label: ":full_moon: Diffusion X2V · Function Test"
|
||||
agents:
|
||||
queue: "ascend-a2b3"
|
||||
resource_class: "npu-4"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpecPatch:
|
||||
imagePullSecrets:
|
||||
- name: swr-secret
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k npu_i2v --run-level "full_model"
|
||||
@@ -1,21 +0,0 @@
|
||||
steps:
|
||||
- group: ":card_index_dividers: TTS Model Test"
|
||||
key: ready-tts-group
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: ":sound: TTS · Qwen3-TTS CustomVoice Test"
|
||||
agents:
|
||||
queue: "ascend-a2b3"
|
||||
resource_class: "npu-1"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpecPatch:
|
||||
imagePullSecrets:
|
||||
- name: swr-secret
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py -m 'core_model' --run-level 'core_model'
|
||||
@@ -1,624 +0,0 @@
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_USE_FLASHINFER_MOE_FP16: 0
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "Simple · Diffusion & Model Executor Test"
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
commands:
|
||||
- "timeout 20m pytest -sv -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Custom Pipeline Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/e2e/offline_inference/custom_pipeline/ -m "core_model"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "Diffusion · Offloader Test"
|
||||
commands:
|
||||
- timeout 10m pytest -s -v tests/diffusion/offloader -m "core_model and cuda" --run-level "core_model"
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · Cache Test"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/cache -m 'core_model and cuda' --run-level "core_model"
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · Batch Test"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/batching -m 'core_model and cuda' --run-level "core_model"
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · Distributed Test"
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda' --run-level "core_model"
|
||||
agents:
|
||||
queue: "gpu_4_queue" # g6.12xlarge instance on AWS, has 4 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · Model Test"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/models/ -m 'core_model and cuda' --run-level "core_model"
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · Other Test"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/diffusion/*.py -m 'core_model and cuda' --run-level "core_model"
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.4xlarge instance on AWS, has 1 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
|
||||
- label: "Engine&Model Executor Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
commands:
|
||||
- |
|
||||
timeout 15m bash -c "
|
||||
pytest -sv tests/engine/ tests/model_executor/ -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_1_queue" # g6.12xlarge instance on AWS, has 4 L4 GPU
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
|
||||
- label: "Distributed Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -sv tests/distributed/ -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Entrypoints Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c "
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -sv tests/entrypoints/ -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "RLHF · VeRL-Omni E2E Test"
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/offline_inference/rlhf_test/test_verl_omni_e2e.py
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Omni · Qwen3-Omni Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen3_omni.py
|
||||
- vllm_omni/model_executor/models/qwen3_omni/
|
||||
- vllm_omni/model_executor/stage_input_processors/qwen3_omni.py
|
||||
- vllm_omni/deploy/qwen3_omni_moe.yaml
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_omni.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "TTS · VoxCPM2 Test"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -s -v tests/e2e/offline_inference/test_voxcpm2_tts.py tests/e2e/online_serving/test_voxcpm2_tts.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "TTS · Qwen3-TTS CustomVoice Test"
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_4_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "TTS · Qwen3-TTS Base Test"
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
export VLLM_OMNI_USE_V2_RUNNER=1
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_base.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_4_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "TTS · Higgs-Audio-V3 Test"
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_USE_DEEP_GEMM=0
|
||||
export VLLM_MOE_USE_DEEP_GEMM=0
|
||||
pytest -s -v tests/e2e/online_serving/test_higgs_audio_v3.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "gpu_4_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
|
||||
- label: "Diffusion · Qwen Image Edit Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image_edit.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image_edit.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Bagel Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_bagel.py
|
||||
- vllm_omni/model_executor/models/bagel/
|
||||
- vllm_omni/diffusion/models/bagel/
|
||||
- vllm_omni/model_executor/stage_input_processors/bagel.py
|
||||
- vllm_omni/deploy/bagel.yaml
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_bagel.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_wan22_t2v.py
|
||||
- vllm_omni/diffusion/models/wan2_2/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_wan22_t2v.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
|
||||
- label: "Diffusion · Qwen Image Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Diffusion · Qwen Image Layered Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image_layered.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image_layered.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 1
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
@@ -1,141 +0,0 @@
|
||||
{# vllm-omni customized version
|
||||
Based on: https://github.com/vllm-project/ci-infra/blob/main/buildkite/test-template-amd.j2
|
||||
Last synced: 2025-12-15
|
||||
Modifications: Removed unused CUDA/NVIDIA logic, keeping only AMD tests
|
||||
#}
|
||||
{% set docker_image_amd = "rocm/vllm-omni:$BUILDKITE_COMMIT" %}
|
||||
{% set default_working_dir = "/app/vllm-omni" %}
|
||||
|
||||
{% if env %}
|
||||
env:
|
||||
{% for name in env %}
|
||||
{{ name }}: "{{ env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
steps:
|
||||
- group: "AMD Tests"
|
||||
depends_on: ~
|
||||
steps:
|
||||
- label: "AMD: :docker: build image"
|
||||
depends_on: ~
|
||||
soft_fail: false
|
||||
commands:
|
||||
- "docker build -f docker/Dockerfile.rocm -t {{ docker_image_amd }} --target test --build-arg ARG_PYTORCH_ROCM_ARCH=gfx942 --progress plain ."
|
||||
- "docker push {{ docker_image_amd }}"
|
||||
key: "amd-build"
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
retry:
|
||||
automatic:
|
||||
- exit_status: -1 # Agent was lost
|
||||
limit: 2
|
||||
- exit_status: -10 # Agent was lost
|
||||
limit: 2
|
||||
- exit_status: 128 # Git connectivity issues
|
||||
limit: 2
|
||||
- exit_status: 1 # Machine occasionally fail
|
||||
limit: 1
|
||||
agents:
|
||||
queue: amd-cpu
|
||||
|
||||
{% for step_group in steps %}
|
||||
{% if step_group.group %}
|
||||
- group: "{{ step_group.group }}"
|
||||
{% if step_group.depends_on %}
|
||||
depends_on: {{ step_group.depends_on }}
|
||||
{% endif %}
|
||||
steps:
|
||||
{% for step in step_group.steps %}
|
||||
{% if step.mirror_hardwares and mirror_hw in step.mirror_hardwares %}
|
||||
- label: "{{ step.agent_pool }}: {{ step.label }}"
|
||||
depends_on: amd-build
|
||||
agents:
|
||||
{% if step.agent_pool %}
|
||||
queue: amd_{{ step.agent_pool }}
|
||||
{% else %}
|
||||
queue: amd_mi325_1
|
||||
{% endif %}
|
||||
{% set cmd_body = (step.command or (step.commands | join("\n"))) | trim %}
|
||||
{% set indented_cmd = cmd_body | replace("\n", "\n ") %}
|
||||
command: bash .buildkite/scripts/hardware_ci/run-amd-test.sh
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
{{ name }}: "{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
TEST_COMMAND: |-
|
||||
(command rocm-smi || true) && cd {{ (step.working_dir or default_working_dir) | safe }}
|
||||
{% if env %}
|
||||
{% for name in env %}
|
||||
export {{ name }}="{{ env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
export {{ name }}="{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if "mi250" in step.agent_pool %}
|
||||
python3 -m pip uninstall -y amd-aiter
|
||||
{% endif %}
|
||||
{{ indented_cmd | safe }}
|
||||
priority: 100
|
||||
{% if step.timeout_in_minutes %}
|
||||
timeout_in_minutes: {{ step.timeout_in_minutes }}
|
||||
{% endif %}
|
||||
{% if step.grade and step.grade == "Blocking" %}
|
||||
soft_fail: false
|
||||
{% else %}
|
||||
soft_fail: true
|
||||
{% endif%}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% elif step_group.mirror_hardwares and mirror_hw in step_group.mirror_hardwares %}
|
||||
{% set step = step_group %}
|
||||
- label: "{{ step.agent_pool }}: {{ step.label }}"
|
||||
depends_on: amd-build
|
||||
agents:
|
||||
{% if step.agent_pool %}
|
||||
queue: amd_{{ step.agent_pool }}
|
||||
{% else %}
|
||||
queue: amd_mi325_1
|
||||
{% endif %}
|
||||
{% set cmd_body = (step.command or (step.commands | join("\n"))) | trim %}
|
||||
{% set indented_cmd = cmd_body | replace("\n", "\n ") %}
|
||||
command: bash .buildkite/scripts/hardware_ci/run-amd-test.sh
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
{{ name }}: "{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
TEST_COMMAND: |-
|
||||
(command rocm-smi || true) && cd {{ (step.working_dir or default_working_dir) | safe }}
|
||||
{% if env %}
|
||||
{% for name in env %}
|
||||
export {{ name }}="{{ env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
export {{ name }}="{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if "mi250" in step.agent_pool %}
|
||||
python3 -m pip uninstall -y amd-aiter
|
||||
{% endif %}
|
||||
{{ indented_cmd | safe }}
|
||||
priority: 100
|
||||
{% if step.timeout_in_minutes %}
|
||||
timeout_in_minutes: {{ step.timeout_in_minutes }}
|
||||
{% endif %}
|
||||
{% if step.grade and step.grade == "Blocking" %}
|
||||
soft_fail: false
|
||||
{% else %}
|
||||
soft_fail: true
|
||||
{% endif%}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -1,148 +0,0 @@
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_USE_FLASHINFER_MOE_FP16: 0
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: 300
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
- label: "Reliability Test - qwen3-omni"
|
||||
timeout_in_minutes: 180
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_qwen3_omni.py -m "slow"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
- label: "Reliability Test - wan22"
|
||||
timeout_in_minutes: 180
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_wan22.py -m "slow"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
# Invalid HTTP / WS payloads vs live Omni servers (Issue #3649 tracks known skips).
|
||||
- group: "Reliability Test - Invalid parameters Test"
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
steps:
|
||||
- label: "Invalid parameters Test · H100"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100"
|
||||
agents:
|
||||
queue: "mithril-h100-pool"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpec:
|
||||
containers:
|
||||
- image: 936637512419.dkr.ecr.us-west-2.amazonaws.com/vllm-ci-pull-through-cache/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: 2
|
||||
volumeMounts:
|
||||
- name: devshm
|
||||
mountPath: /dev/shm
|
||||
- name: hf-cache
|
||||
mountPath: /root/.cache/huggingface
|
||||
env:
|
||||
- name: HF_HOME
|
||||
value: /root/.cache/huggingface
|
||||
- name: HF_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hf-token-secret
|
||||
key: token
|
||||
nodeSelector:
|
||||
node.kubernetes.io/instance-type: gpu-h100-sxm
|
||||
volumes:
|
||||
- name: devshm
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
- name: hf-cache
|
||||
hostPath:
|
||||
path: /mnt/hf-cache
|
||||
type: DirectoryOrCreate
|
||||
|
||||
# Stable Audio Open, Qwen3-TTS speech/batch/voices paths marked ``L4``.
|
||||
- label: "Invalid parameters Test · L4"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and L4"
|
||||
agents:
|
||||
queue: "gpu_1_queue"
|
||||
plugins:
|
||||
- docker#v5.2.0:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
- "HF_TOKEN"
|
||||
volumes:
|
||||
- "/fsx/hf_cache:/fsx/hf_cache"
|
||||
@@ -0,0 +1 @@
|
||||
../../.agents/skills/3d-animation-short-generator
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: add-diffusion-model
|
||||
description: Add a new diffusion model (text-to-image, text-to-video, image-to-video, text-to-audio, image editing) to vLLM-Omni, including Cache-DiT acceleration and parallelism support (TP, SP/USP, CFG-Parallel, HSDP). Use when integrating a new diffusion model, porting a diffusers pipeline or a custom model repo to vllm-omni, creating a new DiT transformer adapter, adding diffusion model support, or enabling multi-GPU parallelism and cache acceleration for an existing model.
|
||||
description: Add a new diffusion model (text-to-image, text-to-video, image-to-video, text-to-audio, image editing) to vLLM-Omni, including native non-Diffusers ports, reference-parity validation, Cache-DiT, offload, and parallelism support (TP, SP/USP, CFG-Parallel, HSDP). Use when integrating or reviewing a new diffusion model, porting a Diffusers pipeline or custom model repository, creating a DiT adapter, reusing shared examples, or qualifying multi-GPU and memory optimizations.
|
||||
---
|
||||
|
||||
# Adding a Diffusion Model to vLLM-Omni
|
||||
@@ -24,11 +24,18 @@ Check the model's HF repo for `model_index.json`. This determines your path:
|
||||
|
||||
| Scenario | How to identify | Migration path |
|
||||
|----------|----------------|----------------|
|
||||
| **Already supported** | `_class_name` in `model_index.json` matches a key in `_DIFFUSION_MODELS` in `registry.py` | Skip to Step 5 (test) and Step 7 (docs) |
|
||||
| **Already supported** | `_class_name` in `model_index.json` matches a key in `_DIFFUSION_MODELS` in `registry.py` | Skip implementation, then validate model-specific examples, tests, and docs as needed |
|
||||
| **Diffusers-based** | Has standard `model_index.json` with `_diffusers_version`, subfolders for `transformer/`, `vae/`, etc. | Follow **Path A** below |
|
||||
| **Custom/private repo** | No diffusers `model_index.json`, weights in non-standard format, custom model code in a separate git repo | Follow **Path B** below |
|
||||
| **Native non-Diffusers model** | No Diffusers index, non-standard checkpoint hierarchy, or custom architecture in a separate repo | Follow **Path B** below; port the runtime natively unless an external adapter was explicitly requested |
|
||||
| **Hybrid** | Has some diffusers components (VAE) but custom transformer/fusion | Mix of Path A and Path B |
|
||||
|
||||
Before coding, write a short integration contract covering runtime ownership,
|
||||
checkpoint discovery, reference revision, I/O geometry, attention semantics,
|
||||
CFG behavior, auxiliary components, target hardware, and the default deployment.
|
||||
For Path B, hybrid models, or any optimization work, read
|
||||
[references/native-model-integration-checklist.md](references/native-model-integration-checklist.md)
|
||||
and use its phase gates.
|
||||
|
||||
## Path A: Diffusers-Based Model
|
||||
|
||||
For models with a standard diffusers layout. See [references/transformer-adaptation.md](references/transformer-adaptation.md) for detailed code patterns.
|
||||
@@ -52,7 +59,7 @@ vllm_omni/diffusion/models/your_model_name/
|
||||
2. Replace attention with `vllm_omni.diffusion.attention.layer.Attention` (QKV shape: `[B, seq, heads, head_dim]`).
|
||||
3. Add `od_config: OmniDiffusionConfig | None = None` to `__init__`.
|
||||
4. Add `load_weights()` method mapping diffusers weight names to vllm-omni names.
|
||||
5. Add class attributes: `_repeated_blocks`, `_layerwise_offload_blocks_attr`.
|
||||
5. Add class attributes for acceleration features such as `_repeated_blocks` and `_layerwise_offload_blocks_attrs` (see [references/transformer-adaptation.md](references/transformer-adaptation.md) for examples).
|
||||
|
||||
### A4. Adapt pipeline
|
||||
|
||||
@@ -78,13 +85,40 @@ class YourPipeline(nn.Module):
|
||||
|
||||
Add post/pre-process functions in the same pipeline file. Register them in `registry.py`.
|
||||
|
||||
### A4.1 Add progress bar support (recommended)
|
||||
|
||||
For pipelines with a standard denoising loop, prefer the existing progress bar pattern instead of hand-rolled logging.
|
||||
|
||||
```python
|
||||
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
|
||||
|
||||
class YourPipeline(nn.Module, ProgressBarMixin):
|
||||
def forward(self, req: OmniDiffusionRequest) -> DiffusionOutput:
|
||||
# ... prepare timesteps / latents ...
|
||||
with self.progress_bar(total=len(timesteps)) as progress_bar:
|
||||
for i, t in enumerate(timesteps):
|
||||
# predict noise / scheduler step
|
||||
latents = ...
|
||||
progress_bar.update()
|
||||
|
||||
return DiffusionOutput(output=output)
|
||||
```
|
||||
|
||||
For custom loop structures, follow `vllm_omni/diffusion/models/progress_bar.py` and existing pipelines using `ProgressBarMixin`.
|
||||
|
||||
### A5. Register, test, docs → continue at Step 4 below.
|
||||
|
||||
---
|
||||
|
||||
## Path B: Custom/Private Repo Model
|
||||
## Path B: Native / Non-Diffusers Model
|
||||
|
||||
For models without a diffusers pipeline — weights in custom format, model code in a private repo. Real examples: DreamID-Omni, BAGEL, HunyuanImage3.
|
||||
For models without a Diffusers pipeline—weights in custom formats and model
|
||||
code in another public or private repository. Treat that repository as a pinned
|
||||
correctness oracle. A request for native support means the vLLM-Omni runtime
|
||||
must not import the reference implementation; an external adapter is appropriate
|
||||
only when the requested scope explicitly permits that dependency. See
|
||||
[references/custom-model-patterns.md](references/custom-model-patterns.md) for
|
||||
concrete integration patterns.
|
||||
|
||||
### B1. Understand the reference repo
|
||||
|
||||
@@ -105,16 +139,25 @@ This is the key design decision for custom models. Follow these placement rules:
|
||||
| **Pipeline orchestration** (init, forward, denoise loop) | `vllm_omni/diffusion/models/<name>/pipeline_<name>.py` | Always required |
|
||||
| **Custom transformer/backbone** (ported and adapted to vllm-omni) | `vllm_omni/diffusion/models/<name>/<name>_transformer.py` or similar | `wan2_2.py`, `fusion.py`, `bagel_transformer.py` |
|
||||
| **Custom sub-models** (VAE, fusion, autoencoder) | `vllm_omni/diffusion/models/<name>/` as separate files | `autoencoder.py`, `fusion.py` |
|
||||
| **External dependency code** (original repo utilities) | **External repo**, installed via download script or pip | `dreamid_omni` package via git clone |
|
||||
| **Reference-only code** | Keep outside the runtime; use a pinned revision for golden outputs and architecture analysis | Reference inference script |
|
||||
| **Explicit external adapter dependency** | External package, only when the requested scope and maintainer direction allow it | Compatibility adapter, not native support |
|
||||
| **Hardcoded model configs** | Module-level dicts in pipeline file | `VIDEO_CONFIG`, `AUDIO_CONFIG` dicts |
|
||||
| **Download/setup script** | `examples/offline_inference/<name>/download_<name>.py` | `download_dreamid_omni.py` |
|
||||
| **Download/setup script** | `examples/offline_inference/<name>/download_<name>.py` | `download_<name>.py` |
|
||||
| **Custom `model_index.json`** | Generated by download script, placed at model root | Minimal: `{"_class_name": "YourPipeline", ...}` |
|
||||
|
||||
### B3. Handle external dependencies
|
||||
|
||||
If the model's code lives in a separate git repo:
|
||||
If the model's code lives in a separate git repo, first decide whether the
|
||||
requested deliverable is native support or an external adapter. Do not silently
|
||||
choose the adapter path.
|
||||
|
||||
**Option 1: Import with graceful fallback** (recommended for models with external utils)
|
||||
**Option 1: Port the code directly** (default for native support)
|
||||
|
||||
Copy the essential model files into `vllm_omni/diffusion/models/<name>/` and
|
||||
adapt them to shared vLLM-Omni contracts. Keep checkpoint loading strict and
|
||||
use the pinned reference only to generate parity evidence.
|
||||
|
||||
**Option 2: Import with graceful fallback** (adapter scope only)
|
||||
|
||||
```python
|
||||
try:
|
||||
@@ -126,17 +169,15 @@ except ImportError:
|
||||
)
|
||||
```
|
||||
|
||||
**Option 2: Port the code directly** (preferred when feasible)
|
||||
|
||||
Copy the essential model files into `vllm_omni/diffusion/models/<name>/` and adapt them. This avoids external dependencies. BAGEL does this — `autoencoder.py` and `bagel_transformer.py` are ported directly.
|
||||
|
||||
**Decision criteria**: Port if the code is self-contained and won't diverge. Use external deps if the model repo is actively maintained and the code is complex.
|
||||
Use an external runtime dependency only when the user explicitly requested an
|
||||
adapter or a maintainer approved the exception. Document the dependency,
|
||||
pinned revision, installation path, and unsupported native features.
|
||||
|
||||
### B4. Handle custom weight loading
|
||||
|
||||
Custom models have two patterns for weight loading:
|
||||
Custom models have two common patterns for weight loading:
|
||||
|
||||
**Pattern 1: Bypass standard loader** (DreamID-Omni style)
|
||||
**Pattern 1: Bypass standard loader** (eager custom init)
|
||||
|
||||
When the original model has complex custom init functions that load weights in `__init__`:
|
||||
|
||||
@@ -149,8 +190,10 @@ class CustomPipeline(nn.Module):
|
||||
self.vae = custom_init_vae(model, device=self.device)
|
||||
self.text_encoder = custom_init_text_encoder(model, device=self.device)
|
||||
self.transformer = CustomFusionModel(CONFIG)
|
||||
load_custom_checkpoint(self.transformer,
|
||||
checkpoint_path=os.path.join(model, "model.safetensors"))
|
||||
load_custom_checkpoint(
|
||||
self.transformer,
|
||||
checkpoint_path=os.path.join(model, "model.safetensors"),
|
||||
)
|
||||
# NO weights_sources defined — bypasses standard loader
|
||||
|
||||
def load_weights(self, weights):
|
||||
@@ -162,6 +205,8 @@ class CustomPipeline(nn.Module):
|
||||
When weights are in safetensors format but need name remapping:
|
||||
|
||||
```python
|
||||
from vllm.model_executor.model_loader.weight_utils import default_weight_loader
|
||||
|
||||
class CustomPipeline(nn.Module):
|
||||
def __init__(self, *, od_config, prefix=""):
|
||||
super().__init__()
|
||||
@@ -187,14 +232,17 @@ class CustomPipeline(nn.Module):
|
||||
# Remap original weight names to vllm-omni module names
|
||||
name = self._remap_weight_name(name)
|
||||
if name in params:
|
||||
default_weight_loader(params[name], tensor)
|
||||
param = params[name]
|
||||
weight_loader = getattr(param, "weight_loader", default_weight_loader)
|
||||
weight_loader(param, tensor)
|
||||
loaded.add(name)
|
||||
return loaded
|
||||
```
|
||||
|
||||
### B5. Create the `model_index.json`
|
||||
|
||||
Custom models need a `model_index.json` at the model root for vllm-omni to discover them. For custom models, this is minimal:
|
||||
Prefer a `model_index.json` at the model root when vLLM-Omni owns an assembled
|
||||
checkpoint directory. For custom models, this is minimal:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -203,7 +251,14 @@ Custom models need a `model_index.json` at the model root for vllm-omni to disco
|
||||
}
|
||||
```
|
||||
|
||||
The `_class_name` must match a key in `_DIFFUSION_MODELS` in `registry.py`. Additional keys are model-specific (accessed via `od_config.model_config`).
|
||||
The `_class_name` must match a key in `_DIFFUSION_MODELS` in `registry.py`.
|
||||
Additional keys are model-specific (accessed via `od_config.model_config`).
|
||||
|
||||
If the released repository is immutable and has neither a root `config.json`
|
||||
nor a Diffusers index, add it to a generic native-checkpoint signature resolver:
|
||||
match the exact Hub ID or a distinctive set of local files and return the
|
||||
pipeline class. Do not use model-name substrings or add parallel one-off
|
||||
predicates in CLI, config, and serving consumers.
|
||||
|
||||
If the model's weights come from multiple HF repos, write a **download script** that:
|
||||
1. Downloads from each repo
|
||||
@@ -265,7 +320,9 @@ Use the appropriate existing example script:
|
||||
| Image-to-Image | `examples/offline_inference/image_to_image/image_edit.py` |
|
||||
| Text-to-Audio | `examples/offline_inference/text_to_audio/text_to_audio.py` |
|
||||
|
||||
For custom/Omni models that don't fit these categories, create a dedicated example script.
|
||||
Reuse these shared scripts even for custom models when their request and output
|
||||
contracts fit. Create a dedicated model script only when the shared category
|
||||
cannot represent the protocol, and document that gap in the PR.
|
||||
|
||||
**Validation**: No errors, output is meaningful, quality matches reference implementation.
|
||||
|
||||
@@ -273,125 +330,70 @@ See [references/troubleshooting.md](references/troubleshooting.md) for common er
|
||||
|
||||
### Step 6: Add Example Scripts
|
||||
|
||||
For Omni or custom models, create:
|
||||
Only when the shared category scripts cannot represent the model, create:
|
||||
- `examples/offline_inference/your_model_name/` — offline script + README
|
||||
- `examples/online_serving/your_model_name/` — server script + client
|
||||
- Download script if weights require assembly from multiple sources
|
||||
|
||||
### Step 7: Update Documentation
|
||||
|
||||
Follow the [`add-recipe` skill](../add-recipe/SKILL.md) to add or update the
|
||||
model-family recipe and its `recipes/README.md` row with verified specifications,
|
||||
hardware, commands, feature links, and qualification evidence.
|
||||
|
||||
Required updates:
|
||||
1. `docs/user_guide/diffusion/parallelism_acceleration.md` — parallelism support table
|
||||
2. `docs/user_guide/diffusion/cpu_offload_diffusion.md` — if CPU offload supported (add to supported models table)
|
||||
3. `docs/user_guide/diffusion/teacache.md` — if TeaCache supported
|
||||
4. `docs/user_guide/diffusion/cache_dit_acceleration.md` — if Cache-DiT supported
|
||||
5. `examples/offline_inference/xxx/README.md` — offline example docs
|
||||
6. `examples/online_serve/xxx/README.md` — online serve docs
|
||||
1. `docs/user_guide/diffusion/parallelism/overview.md` — parallelism support overview/table
|
||||
2. `docs/user_guide/diffusion/cpu_offload.md` — if CPU offload supported (add to supported models table)
|
||||
3. `docs/user_guide/diffusion/cache_acceleration/teacache.md` — if TeaCache supported
|
||||
4. `docs/user_guide/diffusion/cache_acceleration/cache_dit.md` — if Cache-DiT supported
|
||||
5. Offline example docs under `examples/offline_inference/<name>/` (`README.md` or category-specific `.md`)
|
||||
6. `examples/online_serving/<name>/README.md` — online serving docs
|
||||
|
||||
### Step 8: Add E2E Tests (Recommended)
|
||||
### Step 8: Add E2E Tests
|
||||
|
||||
Create `tests/e2e/online_serving/test_your_model_expansion.py`.
|
||||
**Follow the [vllm-omni-test skill](../vllm-omni-test/SKILL.md)** for markers, file naming, Buildkite wiring, and run commands. Also read [l4_functionality_tests.inc.md](https://github.com/vllm-project/vllm-omni/blob/main/docs/contributing/ci/test_examples/l4_functionality_tests.inc.md), [test_system_overview.md](https://github.com/vllm-project/vllm-omni/blob/main/docs/contributing/ci/test_system_overview.md), and [test_writing_guide.md](https://github.com/vllm-project/vllm-omni/blob/main/docs/contributing/ci/test_writing_guide.md).
|
||||
|
||||
Classify the model's **CI priority** first:
|
||||
|
||||
| Priority | Required test levels | Files & markers |
|
||||
|----------|---------------------|-----------------|
|
||||
| **High** (listed in [#1832](https://github.com/vllm-project/vllm-omni/issues/1832) or on the diffusion hot path) | **L1** · **L2** online · **L3** online + offline · **L4** feature + performance | See table below |
|
||||
| **Medium** (*normal priority* in L4 docs) | **L3** online + offline · **L4** feature only | Fewer L4 parametrized rows |
|
||||
| **Low** | **L4** feature only | One or two `*_expansion.py` cases |
|
||||
|
||||
**Per-level deliverables (diffusion / `pytest.mark.diffusion`):**
|
||||
|
||||
| Level | Location | Marker | CI pipeline | Notes |
|
||||
|-------|----------|--------|-------------|-------|
|
||||
| **L1** | `tests/diffusion/models/{slug}/`, `tests/diffusion/cache/`, transformer unit tests | `core_model` + `cpu` | `test-ready.yml` | Weight remap, `_sp_plan`, cache enabler registration, shape contracts |
|
||||
| **L2** | `tests/e2e/online_serving/test_{slug}.py` (and offline if the category is offline-first) | **`core_model` + `advanced_model`** (both on baseline smoke) + `diffusion` + `@hardware_test` / `hardware_marks` | `test-ready.yml` | Default deploy smoke — minimal `num_inference_steps`, single prompt |
|
||||
| **L3** | `tests/e2e/online_serving/test_{slug}.py` **and** `tests/e2e/offline_inference/test_{slug}.py` when offline matters | Baseline smoke: **`core_model` + `advanced_model`**; heavier cases: `advanced_model` only (+ `diffusion`) | `test-merge.yml` **or** merged into nightly diffusion function job | Real weights, streaming/API paths, LoRA/offload smoke |
|
||||
| **L4** | `tests/e2e/online_serving/test_{slug}_expansion.py` (+ offline expansion if needed) | `full_model` + `diffusion` | `test-nightly.yml` (X2I / X2V / X2A function groups) | Feature combos per [#1832](https://github.com/vllm-project/vllm-omni/issues/1832); perf → `tests/dfx/perf/tests/test_{model}_vllm_omni.json` with per-case **`mark`** (`hardware_marks` + `full_model` + `diffusion`) |
|
||||
|
||||
**L2 & L3 online — same file, dual marks on the baseline smoke:** The **first / simplest** case in `test_{slug}.py` (default deploy, minimal steps, single prompt) should carry **both** `@pytest.mark.core_model` and `@pytest.mark.advanced_model` on the **same** function so L2 (`test-ready.yml`) and L3 (`test-merge.yml`) share one smoke test. Heavier deploy variants or API paths in the same file use **`advanced_model` only**. When L3 moves to nightly, migrate those heavier cases into `test_{slug}_expansion.py` with `full_model` and remove the dedicated `test-merge.yml` job (see `test_longcat_image_expansion.py`, `test_qwen_image_expansion.py`).
|
||||
|
||||
**L4 design (high priority):** Combine multiple supported features (Cache-DiT, TP, USP, CFG, HSDP, CPU offload, quantization) into **few parametrized** `OmniServerParams` rows so each feature appears in at least one case without exploding GPU jobs. Shard single-GPU vs multi-GPU cases across the nightly X2I/X2V function steps (`cards_1` vs `not cards_1`).
|
||||
|
||||
**L4 design (medium / low):** One or two parametrized rows covering the best quality/perf trade-off; skip perf JSON unless the model is high priority.
|
||||
|
||||
**Reference implementations:** `tests/e2e/online_serving/test_qwen_image_edit_expansion.py`, `tests/e2e/online_serving/test_longcat_image_expansion.py`, `tests/e2e/online_serving/test_hunyuan_video_15_expansion.py`.
|
||||
|
||||
**Keep model-specific code inside test modules — not `tests/helpers/{slug}.py`:** deploy constants, prompts, sampling dicts, and inline `request_config` / `form_data` belong in each `test_{slug}.py` and `test_{slug}_expansion.py`. Do not add per-model files under `tests/helpers/`; reuse only repo-wide harness (`mark`, `media`, `runtime`, `stage_config`, `assertions`). **L2+ online/offline e2e:** reuse or add `send_*_request` in `tests/helpers/runtime.py` — tests call the handler, not raw `omni.generate` / HTTP. See [vllm-omni-test skill](../vllm-omni-test/SKILL.md) § **Runtime send helpers**.
|
||||
|
||||
Keep the model suite proportional using the six distinct failure owners in the
|
||||
native integration checklist. Combine supported features into a few
|
||||
parametrized E2E rows instead of creating one test per optimization.
|
||||
|
||||
### Step 9: Add Cache-DiT Acceleration
|
||||
|
||||
Cache-DiT accelerates inference by caching intermediate computation results across denoising steps. After your model is working correctly on a single GPU, add cache-dit support.
|
||||
Add caching only after uncached single-device correctness. Read
|
||||
[references/cache-dit-patterns.md](references/cache-dit-patterns.md), use the
|
||||
automatic single-block-list path when possible, and add a registered
|
||||
`BlockAdapter` only for genuinely custom block topology.
|
||||
|
||||
See [references/cache-dit-patterns.md](references/cache-dit-patterns.md) for detailed code patterns.
|
||||
|
||||
#### 9a. Determine your model type
|
||||
|
||||
| Model Type | Description | Action |
|
||||
|------------|-------------|--------|
|
||||
| **Standard single-transformer** | One transformer with one `ModuleList` of blocks | No code needed — `CacheDiTBackend` auto-detects via `enable_cache_for_dit()` |
|
||||
| **Multi-block-list** | One transformer with multiple block lists (e.g., `transformer_blocks` + `single_transformer_blocks`) | Write custom enabler with `BlockAdapter` |
|
||||
| **Dual-transformer** | Two transformers (e.g., high-noise + low-noise) | Write custom enabler with `BlockAdapter` wrapping both |
|
||||
|
||||
#### 9b. Standard models — verify automatic support
|
||||
|
||||
For standard single-transformer models, test directly:
|
||||
|
||||
```python
|
||||
omni = Omni(
|
||||
model="your-model-name",
|
||||
cache_backend="cache_dit",
|
||||
cache_config={
|
||||
"Fn_compute_blocks": 1,
|
||||
"Bn_compute_blocks": 0,
|
||||
"max_warmup_steps": 4,
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
Check logs for "Cache-dit enabled successfully on xxx". If it works, skip to Step 9e.
|
||||
|
||||
#### 9c. Custom architectures — write a custom enabler
|
||||
|
||||
For multi-block-list or dual-transformer models, write a custom enabler function:
|
||||
|
||||
```python
|
||||
from cache_dit import BlockAdapter, ForwardPattern, ParamsModifier, DBCacheConfig
|
||||
|
||||
def enable_cache_for_your_model(pipeline, cache_config):
|
||||
db_cache_config = DBCacheConfig(
|
||||
num_inference_steps=None,
|
||||
Fn_compute_blocks=cache_config.Fn_compute_blocks,
|
||||
Bn_compute_blocks=cache_config.Bn_compute_blocks,
|
||||
max_warmup_steps=cache_config.max_warmup_steps,
|
||||
max_cached_steps=cache_config.max_cached_steps,
|
||||
max_continuous_cached_steps=cache_config.max_continuous_cached_steps,
|
||||
residual_diff_threshold=cache_config.residual_diff_threshold,
|
||||
)
|
||||
|
||||
cache_dit.enable_cache(
|
||||
BlockAdapter(
|
||||
transformer=pipeline.transformer,
|
||||
blocks=[
|
||||
pipeline.transformer.transformer_blocks,
|
||||
pipeline.transformer.single_transformer_blocks,
|
||||
],
|
||||
forward_pattern=[ForwardPattern.Pattern_1, ForwardPattern.Pattern_1],
|
||||
params_modifiers=[ParamsModifier(...)],
|
||||
),
|
||||
cache_config=db_cache_config,
|
||||
)
|
||||
|
||||
def refresh_cache_context(pipeline, num_inference_steps, verbose=True):
|
||||
cache_dit.refresh_context(
|
||||
pipeline.transformer, num_inference_steps=num_inference_steps, verbose=verbose
|
||||
)
|
||||
return refresh_cache_context
|
||||
```
|
||||
|
||||
#### 9d. Register the custom enabler
|
||||
|
||||
Add your enabler to `CUSTOM_DIT_ENABLERS` in `vllm_omni/diffusion/cache/cache_dit_backend.py`:
|
||||
|
||||
```python
|
||||
CUSTOM_DIT_ENABLERS = {
|
||||
"Wan22Pipeline": enable_cache_for_wan22,
|
||||
"LongCatImagePipeline": enable_cache_for_longcat_image,
|
||||
"YourModelPipeline": enable_cache_for_your_model, # Add here
|
||||
}
|
||||
```
|
||||
|
||||
#### 9e. Test Cache-DiT
|
||||
|
||||
```python
|
||||
omni = Omni(
|
||||
model="your-model-name",
|
||||
cache_backend="cache_dit",
|
||||
cache_config={
|
||||
"Fn_compute_blocks": 1, "Bn_compute_blocks": 0,
|
||||
"max_warmup_steps": 4, "residual_diff_threshold": 0.24,
|
||||
}
|
||||
)
|
||||
images = omni.generate("a beautiful landscape",
|
||||
OmniDiffusionSamplingParams(num_inference_steps=50))
|
||||
```
|
||||
|
||||
**Verify**: 1) logs show cache enabled, 2) 1.5-2x speedup, 3) output quality acceptable vs baseline.
|
||||
|
||||
If quality degrades, lower `residual_diff_threshold` (try 0.12-0.18) or increase `max_warmup_steps` (try 6-8).
|
||||
Verify a real cache hit and compare quality with the uncached baseline. Make a
|
||||
speed claim only at a realistic step count where warmup permits hits; an
|
||||
all-warmup smoke proves integration, not acceleration.
|
||||
|
||||
---
|
||||
|
||||
@@ -405,112 +407,35 @@ See [references/parallelism-patterns.md](references/parallelism-patterns.md) for
|
||||
|
||||
#### 10a. Tensor Parallelism (TP)
|
||||
|
||||
Shards DiT linear layers across GPUs. Requires code changes in the transformer.
|
||||
|
||||
**What to change in the transformer**:
|
||||
1. Replace `nn.Linear` with `ColumnParallelLinear` / `RowParallelLinear` / `QKVParallelLinear`
|
||||
2. Update `load_weights()` to handle QKV fusion with `stacked_params_mapping`
|
||||
3. Use `self.to_qkv.num_heads` (local heads) instead of total heads for split sizes
|
||||
|
||||
```python
|
||||
from vllm.model_executor.layers.linear import (
|
||||
QKVParallelLinear, RowParallelLinear, ColumnParallelLinear,
|
||||
)
|
||||
|
||||
# Attention: QKV → RowParallel output
|
||||
self.to_qkv = QKVParallelLinear(dim, head_dim, num_heads, num_kv_heads)
|
||||
self.to_out = RowParallelLinear(dim, dim, input_is_parallel=True)
|
||||
|
||||
# FFN: ColumnParallel → RowParallel
|
||||
self.w1 = ColumnParallelLinear(dim, ffn_dim)
|
||||
self.w2 = RowParallelLinear(ffn_dim, dim, input_is_parallel=True)
|
||||
```
|
||||
|
||||
**Constraints**: `num_heads % tp_size == 0` and `num_kv_heads % tp_size == 0`.
|
||||
|
||||
**Test**: `--tensor-parallel-size 2`
|
||||
Replace compatible projections with vLLM parallel linears, preserve checkpoint
|
||||
fusion/loading, and use local head counts. Require query/KV head divisibility
|
||||
and compare a multi-rank forward with the one-rank oracle.
|
||||
|
||||
#### 10b. Sequence Parallelism (SP / USP)
|
||||
|
||||
Splits sequence tokens across GPUs. Non-intrusive via `_sp_plan` on the transformer class — no changes to `forward()`.
|
||||
|
||||
**What to change in the transformer**:
|
||||
|
||||
Add `_sp_plan` class attribute:
|
||||
|
||||
```python
|
||||
from vllm_omni.diffusion.distributed.sp_plan import (
|
||||
SequenceParallelInput, SequenceParallelOutput,
|
||||
)
|
||||
|
||||
class YourTransformer(nn.Module):
|
||||
_sp_plan = {
|
||||
"blocks.0": {
|
||||
"hidden_states": SequenceParallelInput(split_dim=1, expected_dims=3),
|
||||
},
|
||||
"proj_out": SequenceParallelOutput(gather_dim=1, expected_dims=3),
|
||||
}
|
||||
```
|
||||
|
||||
If inline tensor ops (e.g., `torch.cat`) exist between shard/gather points, extract them into `nn.Module` submodules so hooks can intercept them.
|
||||
|
||||
For RoPE that needs splitting, add an entry for the RoPE module with `split_output=True`.
|
||||
|
||||
**Test**: `--ulysses-degree 2` (offline) or `--usp 2` (online serving)
|
||||
Prefer the declarative `_sp_plan`. For packed variable-length attention or
|
||||
learned-sink LSE correction, keep model math explicit and reuse shared exchange
|
||||
utilities. Validate uneven sequence splits, RoPE coordinates, and outputs
|
||||
against the one-rank oracle.
|
||||
|
||||
#### 10c. CFG Parallel
|
||||
|
||||
Distributes positive/negative CFG branches across 2 GPUs. Requires the pipeline to inherit `CFGParallelMixin`.
|
||||
|
||||
**What to change in the pipeline**:
|
||||
|
||||
```python
|
||||
from vllm_omni.diffusion.distributed.cfg_parallel import CFGParallelMixin
|
||||
|
||||
class YourPipeline(nn.Module, CFGParallelMixin):
|
||||
def diffuse(self, ...) -> torch.Tensor:
|
||||
for i, t in enumerate(timesteps):
|
||||
positive_kwargs = {...}
|
||||
negative_kwargs = {...} if do_true_cfg else None
|
||||
noise_pred = self.predict_noise_maybe_with_cfg(
|
||||
do_true_cfg=do_true_cfg, true_cfg_scale=cfg_scale,
|
||||
positive_kwargs=positive_kwargs, negative_kwargs=negative_kwargs,
|
||||
)
|
||||
latents = self.scheduler_step_maybe_with_cfg(
|
||||
noise_pred, t, latents, do_true_cfg
|
||||
)
|
||||
return latents
|
||||
```
|
||||
|
||||
Override `predict_noise()` if your transformer call is non-standard. Override `combine_cfg_noise()` for multi-output models (e.g., video + audio).
|
||||
|
||||
**Constraint**: Exactly 2 GPUs. Only for models using classifier-free guidance.
|
||||
|
||||
**Test**: `--cfg-parallel-size 2`
|
||||
Confirm the model uses CFG. Then reuse `CFGParallelMixin`, overriding prediction
|
||||
or recombination only for non-standard or multi-output pipelines. Distinguish a
|
||||
packed positive/negative implementation from two independent branches and
|
||||
validate the two-rank result against the packed one-rank oracle.
|
||||
|
||||
#### 10d. HSDP (Hybrid Sharded Data Parallel)
|
||||
|
||||
Shards transformer weights via PyTorch FSDP2 to reduce per-GPU VRAM. No code changes to the forward pass — just add a class attribute.
|
||||
|
||||
**What to change in the transformer**:
|
||||
|
||||
```python
|
||||
class YourTransformer(nn.Module):
|
||||
@staticmethod
|
||||
def _is_transformer_block(name: str, module) -> bool:
|
||||
return "blocks" in name and name.split(".")[-1].isdigit()
|
||||
|
||||
_hsdp_shard_conditions = [_is_transformer_block]
|
||||
```
|
||||
|
||||
**Constraint**: Cannot combine with TP. For standalone HSDP, set `hsdp_shard_size` explicitly.
|
||||
|
||||
**Test**: `--use-hsdp` or `DiffusionParallelConfig(use_hsdp=True)`
|
||||
Declare layer shard conditions and ignored rank-local modules; preserve mixed
|
||||
checkpoint dtypes. HSDP cannot combine with TP. Measure parameter loading,
|
||||
FSDP materialization, warm HBM, and host PSS rather than assuming sharding saves
|
||||
peak memory. Keep the resident layout as default if HSDP is worse.
|
||||
|
||||
#### 10e. Update parallelism documentation
|
||||
|
||||
After adding parallelism support, update:
|
||||
1. `docs/user_guide/diffusion/parallelism_acceleration.md` — add your model to the support table
|
||||
1. `docs/user_guide/diffusion/parallelism/overview.md` — add your model to the support overview/table
|
||||
2. Record which parallelism methods are supported (USP, Ring, CFG, TP, HSDP, VAE-Patch)
|
||||
|
||||
### Step 11: Add CPU Offload Support
|
||||
@@ -544,6 +469,12 @@ Pipelines without `SupportsComponentDiscovery` fall back to scanning
|
||||
well-known attribute names (`transformer`, `text_encoder`, `vae`,
|
||||
etc.), which fails for non-standard names.
|
||||
|
||||
Keep model-specific checkpoint paths, nested block aliases, layout transforms,
|
||||
and component lifecycles in the model package. Change a shared offloader only
|
||||
for a general contract, demonstrate another consumer or a framework-level bug,
|
||||
and add one focused shared regression. Avoid `if ModelName` branches in shared
|
||||
backends.
|
||||
|
||||
### Step 12: Performance Profiling
|
||||
|
||||
After verifying correctness and implementing parallelism/caching, profile the model's performance to identify bottlenecks and ensure optimal execution.
|
||||
@@ -553,8 +484,32 @@ See the [Profiling Single-Stage Diffusion](../../../docs/contributing/profiling.
|
||||
2. Using Nsight Systems (`nsys`) with `profiler: "cuda"` for low-overhead CUDA traces.
|
||||
3. Controlling profiling via `omni.start_profile()` and `omni.stop_profile()`.
|
||||
|
||||
Report cold E2E, warm user latency, steady-state wave time, peak allocated and
|
||||
reserved HBM, host PSS for the full process tree, and stage boundaries. State
|
||||
whether prompt encoding and VAE/audio decoding are included. For multi-device
|
||||
layouts, plot user latency against throughput per device and keep different
|
||||
denoising-step counts on separate Pareto frontiers.
|
||||
|
||||
---
|
||||
|
||||
## Pre-commit conventions
|
||||
|
||||
New library files must pass the local gates in
|
||||
[docs/contributing/README.md](../../../docs/contributing/README.md#linting).
|
||||
That page is the full hook list (SPDX, forbidden imports including Hugging Face
|
||||
Hub / Triton / pickle, `torch.cuda`, mypy, test marks, markdownlint, Buildkite,
|
||||
shellcheck). In particular:
|
||||
|
||||
- SPDX copyright is `vLLM-Omni project` (stale `vLLM project` is rewritten).
|
||||
- Use `import regex as re` and `pybase64` in `vllm_omni/`; do not import stdlib
|
||||
`re` or `base64`. Hugging Face Hub downloads go through
|
||||
`vllm.transformers_utils.repo_utils`.
|
||||
- Do not add `torch.cuda.*` call sites; use `current_omni_platform`.
|
||||
- New `tests/**/test_*.py` files need a CI level mark and a hardware mark.
|
||||
- Do not expand `CHECK_IMPORTS[*].allowed_files` or `ALLOWED_FILES` without review.
|
||||
- GitHub Actions skips SPDX/shellcheck/mypy-3.10/test-marks/markdownlint; run
|
||||
`pre-commit` locally.
|
||||
|
||||
## Iterative Development Tips
|
||||
|
||||
1. **Start minimal**: Basic generation first, no parallelism/caching
|
||||
@@ -562,14 +517,16 @@ See the [Profiling Single-Stage Diffusion](../../../docs/contributing/profiling.
|
||||
3. **Use small models**: Test with smaller variants first
|
||||
4. **Check tensor shapes**: Most errors are reshape mismatches in attention
|
||||
5. **Add features incrementally**: Single GPU → TP → SP → CFG → HSDP → Cache-DiT
|
||||
6. **For custom models**: Get the model running with the original code first, then progressively replace components with vllm-omni equivalents
|
||||
6. **For custom models**: Run the pinned reference separately, then port the runtime natively; do not ship temporary imports from the reference implementation
|
||||
7. **Cache-DiT before parallelism tuning**: Cache-DiT is lossy — verify quality at baseline before combining with parallelism
|
||||
8. **Combine lossless + lossy**: e.g., TP + SP + Cache-DiT for maximum throughput
|
||||
|
||||
## Reference Files
|
||||
|
||||
- [vllm-omni-test skill](../vllm-omni-test/SKILL.md) — L1–L4 markers, naming, Buildkite wiring, run commands
|
||||
- [Transformer Adaptation](references/transformer-adaptation.md) — porting transformers from diffusers
|
||||
- [Custom Model Patterns](references/custom-model-patterns.md) — patterns for non-diffusers models
|
||||
- [Native Model Integration Checklist](references/native-model-integration-checklist.md) — ownership boundaries, phase gates, qualification matrix, and review evidence
|
||||
- [Parallelism Patterns](references/parallelism-patterns.md) — TP, SP/USP, CFG parallel, HSDP implementation details
|
||||
- [Cache-DiT Patterns](references/cache-dit-patterns.md) — cache-dit acceleration for standard and custom architectures
|
||||
- [Troubleshooting](references/troubleshooting.md) — common errors and fixes
|
||||
@@ -9,7 +9,9 @@ Three caching strategies:
|
||||
- **TaylorSeer**: Calibration-based prediction using Taylor expansion to estimate block outputs
|
||||
- **SCM** (Step Computation Masking): Dynamic step skipping based on configurable policies
|
||||
|
||||
**Typical speedup**: 1.5-2.5x depending on model and configuration.
|
||||
Speedup is model-, step-, and policy-dependent. Treat a cache-enabled run as
|
||||
integration evidence until logs or a focused test show real hits and repeated
|
||||
timings show an improvement over the uncached baseline.
|
||||
|
||||
**Official docs**: https://docs.vllm.ai/projects/vllm-omni/en/latest/design/feature/cache_dit
|
||||
|
||||
@@ -29,8 +31,13 @@ vLLM-Omni integrates cache-dit through `CacheDiTBackend`:
|
||||
| `cache_dit.refresh_context()` | Updates cache context when `num_inference_steps` changes |
|
||||
|
||||
**Source files**:
|
||||
- `vllm_omni/diffusion/cache/cache_dit_backend.py` — `CacheDiTBackend`, enablers, `CUSTOM_DIT_ENABLERS`
|
||||
- `vllm_omni/diffusion/cache/` — cache backend implementations
|
||||
- `vllm_omni/diffusion/cache/cachedit/__init__.py` — public package API
|
||||
- `vllm_omni/diffusion/cache/cachedit/backend.py` — generic backend lifecycle and integration
|
||||
- `vllm_omni/diffusion/cache/cachedit/config.py` — Cache-DiT configuration types
|
||||
- `vllm_omni/diffusion/cache/cachedit/model_specific.py` — model-specific adapters, enablers, and registry
|
||||
|
||||
Outside `vllm_omni/diffusion/cache`, import Cache-DiT symbols only from
|
||||
`vllm_omni.diffusion.cache.cachedit`.
|
||||
|
||||
## Standard Models: Automatic Support
|
||||
|
||||
@@ -175,7 +182,8 @@ Inspect your block's `forward()` return type and residual connection pattern to
|
||||
|
||||
## Registering Custom Enablers
|
||||
|
||||
Add your enabler to `CUSTOM_DIT_ENABLERS` in `vllm_omni/diffusion/cache/cache_dit_backend.py`:
|
||||
Add your enabler to `CUSTOM_DIT_ENABLERS` in
|
||||
`vllm_omni/diffusion/cache/cachedit/model_specific.py`:
|
||||
|
||||
```python
|
||||
CUSTOM_DIT_ENABLERS = {
|
||||
@@ -237,8 +245,10 @@ vllm serve your-model --omni --port 8098 \
|
||||
|
||||
**Verification checklist**:
|
||||
1. Logs show "Cache-dit enabled successfully on xxx"
|
||||
2. Performance: 1.5-2x speedup vs no cache
|
||||
3. Quality: compare output with `cache_backend=None`
|
||||
2. A focused test or summary confirms at least one real cache hit
|
||||
3. Quality is compared with `cache_backend=None`
|
||||
4. Performance uses a realistic step count, repeated timings, and a policy
|
||||
whose warmup does not consume the whole run
|
||||
|
||||
## Excluded Models
|
||||
|
||||
@@ -248,7 +258,7 @@ Models listed in `_NO_CACHE_ACCELERATION` in `vllm_omni/diffusion/registry.py` d
|
||||
|
||||
| Model | Path | Notes |
|
||||
|-------|------|-------|
|
||||
| Standard DiT | `cache_dit_backend.py::enable_cache_for_dit` | Default enabler, automatic |
|
||||
| Wan2.2 | `cache_dit_backend.py::enable_cache_for_wan22` | Dual-transformer, auto-detects mode |
|
||||
| LongCat | `cache_dit_backend.py::enable_cache_for_longcat_image` | Multi-block-list |
|
||||
| BAGEL | `cache_dit_backend.py::enable_cache_for_bagel` | Complex omni model |
|
||||
| Standard DiT | `cachedit.backend::enable_cache_for_dit` | Default enabler, automatic |
|
||||
| Wan2.2 | `cachedit.model_specific::enable_cache_for_wan22` | Dual-transformer, auto-detects mode |
|
||||
| LongCat | `cachedit.config::CacheDiTAdapterConfig` | Declarative multi-block-list adapter |
|
||||
| BAGEL | `cachedit.model_specific::BagelCachedAdapter` | Custom cached adapter |
|
||||
@@ -16,20 +16,22 @@ vllm_omni/diffusion/models/wan2_2/
|
||||
|
||||
The transformer is loaded separately via `weights_sources` + `load_weights()`. Non-transformer components (VAE, text encoder) are loaded in `__init__` via `from_pretrained()`.
|
||||
|
||||
### Custom model with external deps (e.g., DreamID-Omni)
|
||||
### External adapter (not native support)
|
||||
|
||||
```
|
||||
vllm_omni/diffusion/models/dreamid_omni/
|
||||
vllm_omni/diffusion/models/<name>/
|
||||
├── __init__.py # Exports pipeline only
|
||||
├── pipeline_dreamid_omni.py # Pipeline: loads ALL weights in __init__ via custom helpers
|
||||
├── fusion.py # Custom fusion architecture (video + audio cross-attention)
|
||||
└── wan2_2.py # Re-implemented Wan backbone with split API
|
||||
├── pipeline_<name>.py # Pipeline: loads ALL weights in __init__ via custom helpers
|
||||
└── <backbone>.py # Custom transformer / fusion architecture
|
||||
|
||||
examples/offline_inference/x_to_video_audio/
|
||||
└── download_dreamid_omni.py # Downloads weights from 3 HF repos + clones code repo
|
||||
examples/offline_inference/<task>/
|
||||
└── download_<name>.py # Downloads weights and/or clones code repo
|
||||
```
|
||||
|
||||
All weights loaded eagerly in `__init__`. `load_weights()` is a no-op. External dependency (`dreamid_omni` package) imported with try/except.
|
||||
All weights are loaded eagerly in `__init__`. `load_weights()` is a no-op. The
|
||||
external dependency is imported with try/except. Use this pattern only when the
|
||||
requested scope explicitly allows an adapter; it does not satisfy a request for
|
||||
a native vLLM-Omni implementation.
|
||||
|
||||
### Custom model with ported code (e.g., BAGEL)
|
||||
|
||||
@@ -76,7 +78,7 @@ self.weights_sources = [
|
||||
]
|
||||
```
|
||||
|
||||
### Pattern 3: Fully custom loading (DreamID-Omni)
|
||||
### Pattern 3: Fully custom loading
|
||||
|
||||
```
|
||||
init → load ALL weights eagerly via custom helpers → load_weights() = no-op
|
||||
@@ -87,7 +89,7 @@ init → load ALL weights eagerly via custom helpers → load_weights() = no-op
|
||||
- `load_weights()` is `pass`
|
||||
- Weights may come from multiple HF repos in different formats (`.pth`, `.safetensors`)
|
||||
|
||||
Use this when:
|
||||
Use this only for an explicitly approved external adapter when:
|
||||
- The original model has complex, well-tested loading code you don't want to rewrite
|
||||
- Weights span multiple HF repos
|
||||
- Weight format is non-standard (e.g., a single `.pth` file, not sharded safetensors)
|
||||
@@ -108,16 +110,23 @@ Standard diffusers `model_index.json`:
|
||||
Custom model `model_index.json` (minimal):
|
||||
```json
|
||||
{
|
||||
"_class_name": "DreamIDOmniPipeline",
|
||||
"fusion": "DreamID-Omni/dreamid_omni.safetensors"
|
||||
"_class_name": "YourCustomPipeline",
|
||||
"fusion": "weights/model.safetensors"
|
||||
}
|
||||
```
|
||||
|
||||
The only **required** field is `_class_name` — it must match a key in `_DIFFUSION_MODELS` in `registry.py`. Other fields are model-specific and accessible via `od_config.model_config` dict.
|
||||
The only **required** field is `_class_name` — it must match a key in
|
||||
`_DIFFUSION_MODELS` in `registry.py`. Other fields are model-specific and
|
||||
accessible via `od_config.model_config`.
|
||||
|
||||
When the released repository cannot be modified and contains neither this file
|
||||
nor a root `config.json`, use the generic native-checkpoint signature resolver.
|
||||
Match the exact Hub ID or a distinctive local file set; never infer support from
|
||||
a model-name substring.
|
||||
|
||||
## External Dependency Management
|
||||
|
||||
### Git clone + .pth injection (DreamID-Omni pattern)
|
||||
### Git clone + .pth injection
|
||||
|
||||
```python
|
||||
def download_dependency():
|
||||
@@ -142,6 +151,10 @@ def download_dependency():
|
||||
|
||||
Copy essential files from the original repo into `vllm_omni/diffusion/models/<name>/`. Adapt imports to use vllm-omni utilities. Benefits: no external dependency, no git clone step. Drawback: must maintain the ported code.
|
||||
|
||||
This is the default for native model support. Keep the reference repository at
|
||||
a pinned revision for architecture analysis and golden outputs, but do not
|
||||
import it from production code.
|
||||
|
||||
## Multi-Modal Input/Output Protocols
|
||||
|
||||
Custom models that handle images, audio, or video I/O should implement protocol classes:
|
||||
@@ -163,7 +176,7 @@ The engine checks `isinstance(pipeline, SupportImageInput)` at startup to config
|
||||
|
||||
Diffusers models use `config.json` in each subfolder. Custom models often use:
|
||||
|
||||
**Module-level config dicts** (DreamID-Omni):
|
||||
**Module-level config dicts**:
|
||||
```python
|
||||
VIDEO_CONFIG = {
|
||||
"patch_size": [1, 2, 2], "model_type": "ti2v",
|
||||
@@ -181,7 +194,7 @@ vae_cfg = bagel_cfg.get("vae_config", {})
|
||||
|
||||
## Custom Architecture Patterns
|
||||
|
||||
### Split forward API (DreamID-Omni)
|
||||
### Split forward API
|
||||
|
||||
When a fusion model needs to interleave blocks from two backbones:
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
# Native Diffusion Model Integration Checklist
|
||||
|
||||
Use this checklist for native non-Diffusers models, hybrid pipelines, and
|
||||
model-specific optimization work.
|
||||
|
||||
## 1. Freeze the contract before coding
|
||||
|
||||
Record:
|
||||
|
||||
- Reference repository and immutable revision.
|
||||
- Official checkpoint ID, local layout, license, and required auxiliary files.
|
||||
- Pipeline stages: prompt/image encoding, denoising, video/image/audio decoding,
|
||||
and muxing.
|
||||
- Token packing, RoPE coordinates, attention sinks/LSE behavior, MoE layout,
|
||||
scheduler equations, CFG formulation, dtypes, and checkpoint transforms.
|
||||
- Output geometry, frame count/FPS, audio rate/channels, supported tasks, and
|
||||
default generation steps.
|
||||
- Available local hardware versus the official qualification hardware.
|
||||
- Intended default deployment and optional optimization paths.
|
||||
|
||||
State whether the deliverable is a native implementation or an external
|
||||
adapter. For native support, use the reference as an oracle only.
|
||||
|
||||
## 2. Use phase gates
|
||||
|
||||
| Phase | Required exit evidence |
|
||||
|---|---|
|
||||
| Architecture | Component/weight inventory; unsupported reference dependencies identified; ownership decisions documented |
|
||||
| Native correctness | Strict checkpoint load; tiny forward or one-step golden vs pinned reference; output contract validated |
|
||||
| Framework integration | Registry/discovery, shared request types, existing category example, serving route, docs, and recipe work without model-name branching in shared scripts |
|
||||
| Lossless distribution | One-rank oracle vs each supported TP/SP/CFG/HSDP/VAE layout; released-checkpoint smoke for the recommended layout |
|
||||
| Memory optimization | Ordinary/layerwise/DLO behavior, peak HBM, full-tree host PSS, and stage timeline; shared backend unchanged unless a general contract is proven |
|
||||
| Lossy optimization | Cache hit demonstrated; quality delta measured; speed claim made only when warmup permits hits |
|
||||
| Full qualification | Default-resolution E2E at official step count for every supported task; media metadata and hashes recorded |
|
||||
| Review readiness | Focused tests, Ruff/format, strict docs, DCO, current-main rebase, issue/RFC for large changes, concise PR evidence and limitations |
|
||||
|
||||
Do not start performance tuning before native one-step parity. Do not claim a
|
||||
feature from topology validation alone when released weights can exercise it.
|
||||
|
||||
## 3. Keep ownership narrow
|
||||
|
||||
Default placement:
|
||||
|
||||
| Concern | Owner |
|
||||
|---|---|
|
||||
| Architecture, checkpoint remap, packed attention math, nested block alias, auxiliary lifecycle | Model package |
|
||||
| Kernel/version dispatch already useful to multiple models | Shared attention utility |
|
||||
| Request-dependent example defaults | Typed model-extra entry consumed through a registry |
|
||||
| Exact-ID/local-file detection for repositories without standard metadata | Generic native-checkpoint signature table |
|
||||
| General offload/cache/HSDP bug | Shared layer plus one focused shared regression |
|
||||
|
||||
Before changing shared code, answer:
|
||||
|
||||
1. Is this a framework contract or only this checkpoint's layout?
|
||||
2. Can the model expose an existing declarative hook instead?
|
||||
3. Is there a second consumer or a framework-level failing test?
|
||||
4. Can the shared change avoid importing or naming the model?
|
||||
|
||||
If the answers do not justify a shared change, keep it model-local.
|
||||
|
||||
## 4. Reuse examples without leaking model logic
|
||||
|
||||
- Reuse the existing `x_to_y.py` category script.
|
||||
- Resolve the pipeline class through standard metadata or native signature
|
||||
discovery, not path substrings.
|
||||
- Put dynamic model defaults and validation in `model_extras`; let shared
|
||||
examples consume only the generic typed API.
|
||||
- Do not create image/speech/default abstractions without a real consumer.
|
||||
- Add a dedicated example only when the shared request/output protocol cannot
|
||||
express the model.
|
||||
|
||||
## 5. Build a bounded evidence matrix
|
||||
|
||||
Start with the recommended resident layout. Add only supported, useful points:
|
||||
|
||||
- Single request: TP, SP, or hybrid TP/SP.
|
||||
- Throughput: DLO/DP layouts when concurrent requests are valid.
|
||||
- CFG: compare CFG-parallel output with the packed-CFG oracle only if the model
|
||||
actually uses CFG.
|
||||
- HSDP: record loading and materialization peaks; it can use more HBM than a
|
||||
resident SP layout.
|
||||
- VAE patch parallelism: compare decoded tensors or media exactly where the
|
||||
algorithm should be lossless.
|
||||
- Cache: separate cache integration from acceleration evidence.
|
||||
|
||||
With four devices, qualify four-device layouts such as DP4, DP2SP2, SP4, or
|
||||
CFG2xSP2. Do not present CFG2xSP4 or an official eight-device runtime as locally
|
||||
validated.
|
||||
|
||||
For each measured layout record:
|
||||
|
||||
- Cold E2E and warm user latency.
|
||||
- Steady-state wave time and throughput per device.
|
||||
- Prompt, denoise, video decode, audio decode, and mux times.
|
||||
- Peak allocated/reserved HBM and full-process-tree host PSS.
|
||||
- Step count, seed, output geometry, frame/FPS/audio metadata, and parity metric.
|
||||
|
||||
Plot latency versus throughput/device. Keep one-step, four-step, and full-step
|
||||
results separate because they are not quality-equivalent.
|
||||
|
||||
## 6. Keep tests proportional
|
||||
|
||||
Prefer a small set with distinct failure ownership:
|
||||
|
||||
1. Strict weight-key/dtype/load contract.
|
||||
2. Tiny native golden or one-step reference parity.
|
||||
3. One parametrized distributed-parity test covering supported layouts.
|
||||
4. Pipeline/request/output geometry and serving smoke.
|
||||
5. Shared-example/default test when the category script changes.
|
||||
6. One shared regression only for a genuine shared-layer fix.
|
||||
|
||||
Avoid duplicating the same shape or configuration assertion across
|
||||
model-specific files. Keep expensive released-checkpoint evidence in the PR or
|
||||
recipe unless the repository's CI tier explicitly requires it.
|
||||
|
||||
## 7. Write evidence, not marketing
|
||||
|
||||
In the PR description include:
|
||||
|
||||
- A compact architecture/data-flow explanation.
|
||||
- Default deployment and why it is recommended.
|
||||
- Code-change counts by component.
|
||||
- Accuracy and distributed-parity evidence tied to commands/scripts.
|
||||
- Separate Pareto figures for different step counts.
|
||||
- Supported versus validated versus planned optimizations.
|
||||
- Hardware gaps and untested official-runtime claims.
|
||||
|
||||
Call a result a bounded local qualification unless it includes repeated timing
|
||||
and variance. State whether latency includes text/image encoding and all
|
||||
decoders. Preserve the reference revision and exact commands needed to
|
||||
reproduce the evidence.
|
||||
@@ -569,4 +569,4 @@ Check which parallelism methods a model supports:
|
||||
| **TP** | Uses `ColumnParallelLinear` / `QKVParallelLinear`. Search: `grep -r 'ParallelLinear\|QKVParallel' vllm_omni/diffusion/models/<model>/` |
|
||||
| **HSDP** | Transformer defines `_hsdp_shard_conditions`. Search: `grep -r '_hsdp_shard_conditions' vllm_omni/diffusion/models/` |
|
||||
|
||||
The canonical per-model support table is in `docs/user_guide/diffusion/parallelism_acceleration.md`.
|
||||
The canonical per-model support overview/table is in `docs/user_guide/diffusion/parallelism/overview.md`.
|
||||
@@ -219,13 +219,14 @@ def load_weights(self, weights):
|
||||
|
||||
### Class-Level Attributes for Features
|
||||
|
||||
|
||||
```python
|
||||
class MyTransformer(nn.Module):
|
||||
# torch.compile: list block class names that repeat and can be compiled
|
||||
_repeated_blocks = ["MyTransformerBlock"]
|
||||
|
||||
# CPU offload: attribute name of the nn.ModuleList containing blocks
|
||||
_layerwise_offload_blocks_attr = "blocks"
|
||||
_layerwise_offload_blocks_attrs = ["blocks"]
|
||||
|
||||
# LoRA: mapping of fused param names to original param names
|
||||
packed_modules_mapping = {"to_qkv": ["to_q", "to_k", "to_v"]}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
---
|
||||
name: add-recipe
|
||||
description: Add or update an in-repository vLLM-Omni model recipe with verified task, input, output, hardware, command, feature, and validation contracts. Use when creating files under recipes/, restructuring a recipe after review, documenting a newly supported model, or synchronizing recipe claims with support tables and shared feature guides.
|
||||
---
|
||||
|
||||
# Add a vLLM-Omni Recipe
|
||||
|
||||
## Source the contract
|
||||
|
||||
Read [`recipes/TEMPLATE.md`](../../../recipes/TEMPLATE.md) and
|
||||
[`recipes/README.md`](../../../recipes/README.md) before editing. Inspect the
|
||||
canonical model card/repository, implementation, shared examples, tests, and
|
||||
available local qualification evidence.
|
||||
|
||||
Do not infer support from a model name, sibling recipe, registry entry, or
|
||||
topology validator. Mark unexecuted configurations as configuration-only.
|
||||
|
||||
## Route by model family
|
||||
|
||||
Read only the contributor and user documentation relevant to the model:
|
||||
|
||||
| Family | Contributor guide | User-facing documentation to synchronize |
|
||||
|---|---|---|
|
||||
| Diffusion | [`adding a diffusion model`](../add-diffusion-model/SKILL.md) | `docs/user_guide/diffusion_features.md`, applicable diffusion feature guides, and shared image/video/audio examples |
|
||||
| TTS | [`adding a TTS model`](../add-tts-model/SKILL.md) | `examples/offline_inference/text_to_speech/README.md`, `examples/online_serving/text_to_speech/README.md`, and `docs/serving/speech_api.md` |
|
||||
| Omni | [`adding an omni model`](../../../docs/contributing/model/adding_omni_model.md) | model-family offline/online example docs, `docs/serving/chat_completions_api.md`, and `docs/user_guide/feature_compatibility.md` |
|
||||
|
||||
All families must update `docs/models/supported_models.md` and the matching row
|
||||
in `recipes/README.md`. Do not add a modality-specific support document when
|
||||
the repository has no such table; update the closest shared user contract.
|
||||
|
||||
## Structure the recipe
|
||||
|
||||
Keep the recipe task-oriented and use one hardware-specific file named
|
||||
`recipes/<vendor>/<model>-<hardware>.md`. A recipe may contain multiple
|
||||
deployment topologies on that hardware, but each additional accelerator model
|
||||
or platform requires its own suffixed file.
|
||||
|
||||
1. **Summary:** vendor, exact model ID, runtime, modes, named hardware,
|
||||
recommended deployment, and maintainer.
|
||||
2. **Supported model contract:** put task, input, output, and provided-profile
|
||||
tables before setup or commands.
|
||||
3. **References:** link the canonical model source, shared examples, supported
|
||||
model table, and feature matrix.
|
||||
4. **Checkpoint/setup:** pin revisions when possible and state required assets.
|
||||
5. **Hardware:** document the single accelerator named by the file suffix,
|
||||
including every validated device-count/topology profile on it.
|
||||
6. **Commands:** reuse shared `examples/` entrypoints unless the model contract
|
||||
truly requires a dedicated script. Include offline and online paths that
|
||||
were validated.
|
||||
7. **Supported features:** use a compact model-specific topology/status table
|
||||
with links to shared feature guides.
|
||||
8. **Verification:** provide a quick command and exact expected output
|
||||
contract.
|
||||
9. **Qualification evidence:** report correctness, memory, and timing evidence
|
||||
with its measurement scope and caveats.
|
||||
|
||||
## Separate hardware from software
|
||||
|
||||
For every locally validated hardware profile, record:
|
||||
|
||||
- accelerator vendor/model and per-device memory;
|
||||
- number of devices;
|
||||
- interconnect (`NVLink`, `PCIe`, or the platform equivalent);
|
||||
- host memory when CPU staging/offload is material;
|
||||
- whether the profile is runtime-qualified or configuration-only.
|
||||
|
||||
Record OS, Python, driver/runtime, framework versions, and the vLLM-Omni
|
||||
revision in a separate software-environment table. Keep precision, worker
|
||||
count, and DP/TP/SP/PP sizes with the deployment profile or exact command.
|
||||
|
||||
Never generalize a result from one accelerator family to another or combine
|
||||
NVIDIA, AMD, NPU, or distinct accelerator models in one recipe. Create a
|
||||
separate hardware-suffixed recipe and `recipes/README.md` row. Distinguish
|
||||
upstream requirements from hardware exercised by the PR.
|
||||
|
||||
## Keep shared documentation concise
|
||||
|
||||
Link the applicable diffusion, TTS, omni, serving, or design guide for generic
|
||||
feature semantics and launch instructions. The recipe should contain only the
|
||||
model-specific status, valid topology, required flag difference, and evidence
|
||||
boundary.
|
||||
|
||||
Put unsupported combinations in the same feature table. Avoid repeating the
|
||||
same model-specific prose below the global feature matrix; the recipe is the
|
||||
detailed source of truth.
|
||||
|
||||
## Report evidence precisely
|
||||
|
||||
For every performance or memory value, state:
|
||||
|
||||
- checkpoint/revision and workload;
|
||||
- accelerator and device count;
|
||||
- precision and topology;
|
||||
- cold/warm scope, step count, and concurrency;
|
||||
- peak HBM and host-memory metric when measured;
|
||||
- output/quality guard and sample count;
|
||||
- monitoring overhead or other known variance.
|
||||
|
||||
Call a single bounded run qualification evidence, not a benchmark. Do not add
|
||||
a benchmark script unless the contribution explicitly requires one.
|
||||
|
||||
## Synchronize repository documentation
|
||||
|
||||
Update all applicable locations:
|
||||
|
||||
- the row in `recipes/README.md`;
|
||||
- `docs/models/supported_models.md`;
|
||||
- the family-specific documentation selected in **Route by model family**;
|
||||
- shared example documentation when commands or flags change.
|
||||
|
||||
Keep global support tables compact. Link to the recipe instead of duplicating
|
||||
its deployment explanation.
|
||||
|
||||
## Validate
|
||||
|
||||
Run, at minimum:
|
||||
|
||||
```bash
|
||||
pre-commit run --files <changed recipe/docs/skill files>
|
||||
mkdocs build --strict
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Remove generated documentation artifacts after validation. Confirm every
|
||||
recipe link resolves and every claimed profile has matching code or evidence.
|
||||
@@ -138,9 +138,12 @@ A shared buffer silently corrupts audio across concurrent requests — the sympt
|
||||
- Load codec weights (may need lazy loading from separate checkpoint)
|
||||
- Implement `forward()`: codec codes -> audio waveform
|
||||
- Return `OmniOutput` with `multimodal_outputs`
|
||||
5. **Create stage config YAML** defining both stages, memory allocation, and model paths
|
||||
6. **Create stage input processor** for prompt building
|
||||
7. **Write end2end.py** test script
|
||||
5. **Define and register the pipeline topology** in
|
||||
`vllm_omni/model_executor/models/<model>/pipeline.py`
|
||||
6. **Create the deploy YAML** under `vllm_omni/deploy/` for placement,
|
||||
memory sizing, connectors, and runtime overrides
|
||||
7. **Create stage input processor** for prompt building and inter-stage handoff
|
||||
8. **Write end2end.py** test script
|
||||
|
||||
### Critical Parameters to Get Right
|
||||
|
||||
@@ -174,7 +177,7 @@ These bugs appear in almost every new TTS PR. Check all before the first push. S
|
||||
- **All return paths must emit `model_outputs`** — if any early-return branch skips setting `model_outputs`, the serving layer silently drops that step's audio (fish speech: `fix: ensure ALL return paths emit model_outputs`)
|
||||
- **Per-request state isolation** — for batched concurrent requests, key all state by request ID; a shared buffer corrupts audio across requests (fish speech: `fix: per-request vocode + delta emission`)
|
||||
- **Codec tensor device** — move codec codes to the codec decoder's device before calling decode; mismatches cause silent CPU fallback or crashes (fish speech: `fix: use model device for CUDA stream`)
|
||||
- **AR stage `max_num_seqs`** — set to at least 4 in production configs; for single-stage models this is the only stage. For two-stage models, Stage 0 (AR) needs `max_num_seqs ≥ 4` to pipeline concurrent requests; Stage 1 (codec decoder) typically uses `max_num_seqs: 1` intentionally. Default of 1 everywhere causes audio gaps under concurrency because the codec window round-robins across requests (RFC #2568)
|
||||
- **AR stage `max_num_seqs`** — set to at least 4 in production deploy configs; for single-stage models this is the only stage. For two-stage models, Stage 0 (AR) needs `max_num_seqs ≥ 4` to pipeline concurrent requests; Stage 1 (codec decoder) is model-specific and may intentionally use `max_num_seqs: 1`. Defaulting the AR stage to 1 causes audio gaps under concurrency because the codec window round-robins across requests (RFC #2568)
|
||||
|
||||
### Optional Dependency Handling
|
||||
|
||||
@@ -190,18 +193,18 @@ pattern, signature constraints, and MOSS-TTS-Nano reference.
|
||||
When the upstream model cannot be cleanly split into an AR stage and a
|
||||
separate decoder, run the full pipeline inside a single AR worker and
|
||||
stream audio through a per-request `inference_stream()` generator keyed by
|
||||
`_omni_req_id`. Stage config must set `worker_type: ar`,
|
||||
`engine_output_type: audio`, `final_output: true`, `is_comprehension: true`,
|
||||
and `async_chunk: false` at the top level. Only extract params from
|
||||
`_omni_req_id`. Define one `StagePipelineConfig` with
|
||||
`execution_type=StageExecutionType.LLM_AR`, `engine_output_type="audio"`,
|
||||
`final_output=True`, and `owns_tokenizer=True`. Set `async_chunk: false` in
|
||||
the deploy YAML. Only extract params from
|
||||
`additional_information` that you actually forward, or pre-commit fails
|
||||
`ruff F841`.
|
||||
|
||||
Full walkthrough with the complete `forward()` / `_create_stream_gen()`
|
||||
skeleton and stage-config fields:
|
||||
skeleton plus pipeline/deploy definitions:
|
||||
[references/single-stage-ar.md](references/single-stage-ar.md). For an
|
||||
in-tree reference, look for any single-stage AR model under
|
||||
`vllm_omni/model_executor/models/` — e.g. the MOSS-TTS-Nano integration when
|
||||
it lands.
|
||||
`vllm_omni/model_executor/models/`, such as MOSS-TTS-Nano.
|
||||
|
||||
**VoxCPM2 is a different pattern** and should not reuse this skeleton — it
|
||||
runs the base LM under vLLM PagedAttention with external side-computation.
|
||||
@@ -210,7 +213,8 @@ See `plan/voxcpm2_native_ar_design.md`.
|
||||
### Deliverables
|
||||
|
||||
- Model files in `vllm_omni/model_executor/models/<model_name>/`
|
||||
- Stage config YAML
|
||||
- Registered `pipeline.py` topology
|
||||
- Deploy YAML under `vllm_omni/deploy/`
|
||||
- Working `end2end.py` at `examples/offline_inference/text_to_speech/<model>/end2end.py`
|
||||
- New section in `examples/offline_inference/text_to_speech/README.md` (table row + per-model section). Do **not** create a top-level `examples/offline_inference/<model>/` dir or a per-model `README.md` inside `text_to_speech/<model>/` — the hub README is the documented surface and the mkdocs `generate_examples` hook only descends one level into `examples/<category>/`.
|
||||
|
||||
@@ -220,65 +224,70 @@ See `plan/voxcpm2_native_ar_design.md`.
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Register in `serving_speech.py`** — add all 5 points in a **single commit**;
|
||||
partial integration causes hard-to-debug failures. This file is modified by every
|
||||
model PR and is the most common source of rebase conflicts — see conflict note below.
|
||||
1. **Write one adapter** under `vllm_omni/entrypoints/openai/tts_adapters/`.
|
||||
`serving_speech.py` should not need an edit — detection, stage discovery and
|
||||
dispatch are all derived from what the adapter declares.
|
||||
|
||||
**Point 1** — stage constant (near the top, alongside the other `_*_TTS_MODEL_STAGES` sets):
|
||||
Create `vllm_omni/entrypoints/openai/tts_adapters/your_model.py`:
|
||||
```python
|
||||
_YOUR_MODEL_TTS_MODEL_STAGES = {"your_stage_key"}
|
||||
@register_tts_adapter
|
||||
class YourModelAdapter(ARTTSAdapter):
|
||||
name = "your_model" # registry key + log label
|
||||
stage_keys = frozenset({"your_stage_key"}) # the deploy yaml's model_stage
|
||||
|
||||
def validate(self, request) -> str | None:
|
||||
if not request.input or not request.input.strip():
|
||||
return "Input text cannot be empty"
|
||||
return None
|
||||
|
||||
async def build(self, request, sampling_params_list, has_inline_ref_audio):
|
||||
params = {"text": [request.input]}
|
||||
if request.voice is not None:
|
||||
params["voice"] = [request.voice]
|
||||
return PreparedRequest(
|
||||
prompt={"prompt": request.input},
|
||||
tts_params=params,
|
||||
model_type=self.name,
|
||||
)
|
||||
```
|
||||
|
||||
**Point 2** — union into `_TTS_MODEL_STAGES`:
|
||||
```python
|
||||
_TTS_MODEL_STAGES: set[str] = (
|
||||
...
|
||||
| _YOUR_MODEL_TTS_MODEL_STAGES
|
||||
)
|
||||
```
|
||||
Then add the module to the import block at the bottom of
|
||||
`tts_adapters/__init__.py` so it registers. That import line is the only shared
|
||||
file a new model touches — which is also why the old rebase-conflict hotspot is
|
||||
gone.
|
||||
|
||||
**Point 3** — model type detection in `_detect_tts_model_type()`:
|
||||
```python
|
||||
if model_stage in _YOUR_MODEL_TTS_MODEL_STAGES:
|
||||
return "your_model"
|
||||
```
|
||||
> **Pure-diffusion TTS does not go through adapters yet.** Under
|
||||
> `for_diffusion()`, `create_speech()` routes straight to
|
||||
> `_create_diffusion_speech()` and never calls `validate()`/`build()`.
|
||||
> `DiffusionTTSAdapter` is scaffolding with no production subclass, so logic
|
||||
> placed in one would silently never run. Diffusion-engine models follow the
|
||||
> existing diffusion path; wiring it through adapters is open work (#4855).
|
||||
|
||||
**Point 4** — validation dispatch in `_validate_tts_request()`:
|
||||
```python
|
||||
if self._tts_model_type == "your_model":
|
||||
return self._validate_your_model_request(request)
|
||||
```
|
||||
**If a stage key alone cannot identify the model**, declare
|
||||
`model_archs = frozenset({"YourModelForConditionalGeneration"})`; add
|
||||
`arch_identifies_entry_stage = True` when the model owns no stage key at all
|
||||
(Ming dense). For a rule that is not set membership, override `matches()` (see
|
||||
`covo_audio.py`). For a genuine overlap with another adapter, give one an
|
||||
explicit `detect_priority` — `test_tts_detection.py` fails on an unordered
|
||||
overlap. Models that only serve speech in some topologies override
|
||||
`stage_serves_speech()` (see `audex.py`).
|
||||
|
||||
**Point 5** — validation + parameter-builder methods:
|
||||
```python
|
||||
def _validate_your_model_request(self, request) -> str | None:
|
||||
if not request.input or not request.input.strip():
|
||||
return "Input text cannot be empty"
|
||||
return None
|
||||
**Reuse shared helpers via `self.ctx.server`** rather than reimplementing them:
|
||||
`_resolve_ref_audio`, `_apply_uploaded_speaker`, `_validate_ref_audio_format`,
|
||||
`_max_instructions_length`. Read a comparable adapter first — `fish_speech.py`
|
||||
(voice cloning), `higgs_audio_v3.py` (parameter-heavy), `moss_tts.py` (family
|
||||
sharing a base class).
|
||||
|
||||
def _build_your_model_params(self, request) -> dict:
|
||||
params = {"text": [request.input]}
|
||||
if request.voice is not None:
|
||||
params["voice"] = [request.voice]
|
||||
return params
|
||||
```
|
||||
Wire `_build_your_model_params` into `_create_tts_request()` alongside the other
|
||||
model-specific param builders.
|
||||
> **Do not add `self._tts_model_type == ...` branches to `serving_speech.py`.**
|
||||
> Older models predate the adapter framework and still have them; they are being
|
||||
> migrated out (RFC #4327, #4855). `tools/pre_commit/check_tts_adapter.py` is a
|
||||
> ratchet on the remaining count and fails the commit if it grows. Behaviour that
|
||||
> no adapter hook can express is a missing hook — propose it on the RFC.
|
||||
|
||||
> **Two dispatch patterns coexist**: Fish Speech uses a `self._is_fish_speech` boolean
|
||||
> instance attribute checked before `elif self._is_tts`, while all newer models
|
||||
> (CosyVoice3, MOSS-TTS-Nano) use the `_tts_model_type` string returned by
|
||||
> `_detect_tts_model_type()`. For new models, always use the `_tts_model_type` string
|
||||
> pattern — do not add new `_is_*` flags.
|
||||
|
||||
> **Unused variable rule**: only extract fields in `_build_your_model_params` that
|
||||
> are actually forwarded to the model. Unused extractions fail `ruff F841`.
|
||||
> For voice-cloning fields (`ref_audio` → `prompt_audio_path`, `ref_text` →
|
||||
> `prompt_text`), add them to the param builder and verify they reach the model call.
|
||||
|
||||
**Rebase conflict note**: when rebasing onto `main` after another model was merged,
|
||||
`serving_speech.py` will conflict. Resolution: always keep *both* the upstream
|
||||
model's additions and your own — never discard either side.
|
||||
> **Unused variable rule**: only extract fields in `build()` that are actually
|
||||
> forwarded to the model. Unused extractions fail `ruff F841`. For voice-cloning
|
||||
> fields (`ref_audio` -> `prompt_audio_path`, `ref_text` -> `prompt_text`), add
|
||||
> them to the params and verify they reach the model call.
|
||||
|
||||
2. **Handle model-specific parameters**:
|
||||
- Voice cloning: `ref_audio` encoding and prompt injection
|
||||
@@ -295,7 +304,7 @@ import base64
|
||||
from pathlib import Path
|
||||
|
||||
def build_voice_clone_prompt(ref_audio_path: str, text: str, codec) -> list:
|
||||
"""Build prompt with reference audio for voice cloning in serving_speech.py."""
|
||||
"""Build prompt with reference audio for voice cloning, called from the adapter."""
|
||||
audio_bytes = Path(ref_audio_path).read_bytes()
|
||||
codes = codec.encode(audio_bytes) # Encode on CPU using model's codec (e.g., DAC)
|
||||
token_ids = [code + codec.vocab_offset for code in codes.flatten().tolist()]
|
||||
@@ -305,13 +314,72 @@ def build_voice_clone_prompt(ref_audio_path: str, text: str, codec) -> list:
|
||||
]
|
||||
```
|
||||
|
||||
### Test Case Writing (CI Levels)
|
||||
|
||||
**Follow the [vllm-omni-test skill](../vllm-omni-test/SKILL.md)** for markers, file naming (`test_{slug}.py` / `test_{slug}_expansion.py`), Buildkite wiring, and copy-paste run commands. Also read [test_system_overview.md](https://github.com/vllm-project/vllm-omni/blob/main/docs/contributing/ci/test_system_overview.md) and [test_writing_guide.md](https://github.com/vllm-project/vllm-omni/blob/main/docs/contributing/ci/test_writing_guide.md).
|
||||
|
||||
Classify the model's **CI priority** first (high / medium / low). High-priority TTS models are typically those on the integration hot path or listed in tracking issues such as [#1832](https://github.com/vllm-project/vllm-omni/issues/1832); medium and low tiers cover the long tail. When unsure, ask the reviewer which tier applies.
|
||||
|
||||
| Priority | Required test levels | Files & markers |
|
||||
|----------|---------------------|-----------------|
|
||||
| **High** | **L1** unit/logic · **L2** online smoke · **L3** online + offline integration · **L4** feature + performance | See table below |
|
||||
| **Medium** | **L3** online + offline · **L4** feature only | Skip dedicated L1/L2 unless fixing a logic bug |
|
||||
| **Low** | **L4** feature only | One or two `*_expansion.py` parametrized cases |
|
||||
|
||||
**Per-level deliverables (TTS / `pytest.mark.tts`):**
|
||||
|
||||
| Level | Location | Marker | CI pipeline | Notes |
|
||||
|-------|----------|--------|-------------|-------|
|
||||
| **L1** | `tests/model_executor/…`, `tests/entrypoints/openai_api/…`, stage-processor tests | `core_model` + `cpu` | `test-ready.yml` | Prompt assembly, async_chunk helpers, adapter validation — no GPU |
|
||||
| **L2** | `tests/e2e/online_serving/test_{slug}.py` | **`core_model` + `advanced_model`** (both on baseline smoke) + `tts` + `@hardware_test(...)` | `test-ready.yml` (`ready` label) | Default deploy smoke: single `/v1/audio/speech` or offline `OmniRunner` path |
|
||||
| **L3** | `tests/e2e/online_serving/test_{slug}.py` **and** `tests/e2e/offline_inference/test_{slug}.py` | Baseline smoke: **`core_model` + `advanced_model`**; heavier cases: `advanced_model` only (+ `tts`) | `test-merge.yml` **or** merged into nightly TTS function job | Streaming, voice clone, batch/queue, async_chunk |
|
||||
| **L4** | `tests/e2e/online_serving/test_{slug}_expansion.py`, optional offline expansion | `full_model` + `tts` | `test-nightly.yml` (`:full_moon: TTS · Function Test with L4`) | Feature matrix; perf → `tests/dfx/perf/tests/test_tts.json` |
|
||||
|
||||
**L2 & L3 online — same file, dual marks on the baseline smoke:** The **first / simplest** case in `test_{slug}.py` (default deploy, single non-streaming `/v1/audio/speech` or equivalent offline path) should carry **both** `@pytest.mark.core_model` **and** `@pytest.mark.advanced_model` on the **same** function so it runs in L2 (`test-ready.yml`, `--run-level core_model`, basic validation) and L3 (`test-merge.yml`, `--run-level advanced_model`, deeper validation) without duplicating the test. In-tree examples: `test_voxcpm2_tts.py::test_text_to_audio_001`, `test_qwen3_tts_customvoice.py::test_text_to_audio_001`.
|
||||
|
||||
Heavier scenarios in the same file use **`advanced_model` only** (streaming, extra languages, concurrency, async_chunk, batch). Example: `test_voice_clone_en_streaming_001` → `advanced_model` only. When migrating L3 to nightly, move those heavier cases into `test_{slug}_expansion.py` with `full_model` and drop the dedicated merge job (see `test_ming_tts_expansion.py`, `test_glm_tts_expansion.py`).
|
||||
|
||||
```python
|
||||
@pytest.mark.core_model
|
||||
@pytest.mark.advanced_model
|
||||
@pytest.mark.tts
|
||||
@hardware_test(res={"cuda": "L4"}, num_cards=1)
|
||||
@pytest.mark.parametrize("omni_server", tts_server_params, indirect=True)
|
||||
def test_voice_clone_en_non_streaming_001(omni_server, online_client) -> None:
|
||||
online_client.send_audio_speech_request({...})
|
||||
```
|
||||
|
||||
**L4 consolidation:** Prefer parametrized `OmniServerParams` rows (`default`, `async_chunk`, feature flags) in one expansion module rather than many merge-only files ([#1832](https://github.com/vllm-project/vllm-omni/issues/1832)).
|
||||
|
||||
**L4 performance (high-priority models):** Add latency / throughput / stress rows in `tests/dfx/perf/tests/test_tts.json`, or a dedicated `tests/dfx/perf/tests/test_{slug}.json` when the model must not join the shared nightly server matrix before integration lands (see VoxCPM2 / Coqui XTTS pattern). Register the model in `benchmarks/tts/model_configs.yaml` for local `bench_tts.py`. Wire a **separate** `test-nightly.yml` Perf Test step when the JSON is not merged into `test_tts.json` yet.
|
||||
|
||||
**Keep model-specific code inside test modules — not `tests/helpers/{slug}.py`:**
|
||||
|
||||
- Put `MODEL`, deploy path, vendored `REF_AUDIO_URL`, `get_prompt()`, and inline `request_config` dicts **in each** `test_{slug}.py`, `test_{slug}_expansion.py`, offline `test_{slug}.py`, and L1 `test_{slug}_*.py` as needed.
|
||||
- **Do not** add `tests/helpers/{slug}.py` (or `tests/helpers/{model_name}.py`) to deduplicate constants or request builders across those files. A little duplication is intentional; follow in-tree references such as `tests/e2e/online_serving/test_glm_tts.py` and `tests/e2e/online_serving/test_cosyvoice3_tts_expansion.py`.
|
||||
- `tests/helpers/` is for **repo-wide** harness code only (`mark.py`, `media.py`, `runtime.py`, `stage_config.py`, `assertions.py`, `fixtures/`). Import those; do not extend the tree with per-model modules.
|
||||
|
||||
**Runtime send helpers (`tests/helpers/runtime.py`) — online and offline e2e:**
|
||||
|
||||
| Path | Fixture | Call |
|
||||
|------|---------|------|
|
||||
| Online `/v1/*` | `online_client` | `online_client.send_*_request(request_config)` |
|
||||
| Offline inference | `offline_client` | `offline_client.send_*_request(request_config)` |
|
||||
|
||||
1. **Grep `runtime.py` first** — reuse `send_omni_request`, `send_diffusion_request`, `send_audio_speech_request` (online + offline Qwen-style TTS), `send_single_stage_tts_request` (Coqui XTTS / MOSS-TTS-Nano offline), etc.
|
||||
2. **No matching helper** → add `send_<feature>_request` (or `send_<route>_http_request` for negative/dfx) in **`runtime.py`** with general `assert_*` bundled inside, **then** call it from the test.
|
||||
3. **Test file** holds `request_config` dicts only — not `omni.generate`, not `_collect_audio()`, not raw HTTP/SDK.
|
||||
4. Wire `tests/helpers/runtime.py` into Buildkite `source_file_dependencies` when you add helpers.
|
||||
|
||||
See [vllm-omni-test skill](../vllm-omni-test/SKILL.md) § **Runtime send helpers** for full tables and exceptions.
|
||||
|
||||
### Deliverables
|
||||
|
||||
- Updated `serving_speech.py` with all 5 integration points (single commit)
|
||||
- One adapter file under `tts_adapters/` plus its line in the package import block
|
||||
- Client scripts and server launcher under `examples/online_serving/text_to_speech/<model>/`
|
||||
- Gradio demo with streaming and voice cloning UI in the same dir
|
||||
- E2E online serving test (`tests/e2e/online_serving/test_<model>.py`)
|
||||
- Buildkite CI entry in `.buildkite/test-merge.yml`
|
||||
- E2E tests per **Test Case Writing (CI Levels)** above (priority tier determines L1–L4 scope)
|
||||
- Buildkite wired per level: `test-ready.yml` (L1/L2), `test-merge.yml` or nightly function job (L3), `test-nightly.yml` (L4) — see [vllm-omni-test skill](../vllm-omni-test/SKILL.md)
|
||||
- New section in `examples/online_serving/text_to_speech/README.md` (table row + per-model section). Do **not** create a top-level `examples/online_serving/<model>/` dir or a per-model `README.md` inside `text_to_speech/<model>/`.
|
||||
|
||||
### E2E test pitfalls to avoid
|
||||
@@ -326,9 +394,9 @@ def build_voice_clone_prompt(ref_audio_path: str, text: str, codec) -> list:
|
||||
- **Use the harness readiness gate.** The fixture waits for HTTP 200 on
|
||||
`/health`; don't add `time.sleep` in tests. If warmup is incomplete, make
|
||||
`/health` return non-200 until you're actually ready.
|
||||
- **Mark with `@pytest.mark.core_model` + `hardware_test(res={"cuda": "H100"})`**
|
||||
so the test lands in `test-ready.yml` (triggered by the `ready` label) rather
|
||||
than only nightly.
|
||||
- **Mark tests per the CI Levels table** — baseline smoke: `core_model` + `advanced_model`; heavier cases: `advanced_model` only; L4 expansion: `full_model`
|
||||
- **No per-model helper modules** — do not create `tests/helpers/{slug}.py`; keep constants and `request_config` payloads in the test file
|
||||
- **Online and offline e2e go through `runtime.py`** — `online_client.send_audio_speech_request` (online); `offline_client.send_audio_speech_request` (Qwen-style offline) or `send_single_stage_tts_request` (single-stage offline). Add a new `send_*_request` in `runtime.py` when none fits; do not embed `omni.generate` or HTTP in tests
|
||||
|
||||
## Phase 4: Async Chunk (Streaming)
|
||||
|
||||
@@ -336,21 +404,29 @@ def build_voice_clone_prompt(ref_audio_path: str, text: str, codec) -> list:
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Update stage config YAML**:
|
||||
1. **Update the pipeline topology** so the producing stage declares its async
|
||||
handoff processor with `async_chunk_process_next_stage_input_func`.
|
||||
2. **Update the deploy YAML** to enable async chunk and configure the connector:
|
||||
```yaml
|
||||
async_chunk: true
|
||||
codec_chunk_frames: 25 # frames per chunk
|
||||
codec_left_context_frames: 25 # overlap for smooth boundaries
|
||||
|
||||
connectors:
|
||||
connector_of_shared_memory:
|
||||
name: SharedMemoryConnector
|
||||
extra:
|
||||
codec_streaming: true
|
||||
codec_chunk_frames: 25
|
||||
codec_left_context_frames: 25
|
||||
```
|
||||
2. **Implement chunk handling in Stage 1**:
|
||||
3. **Implement chunk handling in Stage 1**:
|
||||
- Accept partial input (chunk of codec codes)
|
||||
- Handle left context for smooth audio boundaries
|
||||
- Return partial audio in `OmniOutput`
|
||||
3. **Test streaming**:
|
||||
4. **Test streaming**:
|
||||
- Verify audio quality matches non-streaming output
|
||||
- Check for artifacts at chunk boundaries
|
||||
- Measure TTFA (time to first audio)
|
||||
4. **Update online serving** to support `stream=true` with PCM output
|
||||
5. **Update online serving** to support `stream=true` with PCM output
|
||||
|
||||
### Streaming Architecture
|
||||
|
||||
@@ -371,7 +447,8 @@ Stage 0 (AR) Stage 1 (Decoder)
|
||||
|
||||
### Deliverables
|
||||
|
||||
- Updated stage config with async_chunk enabled
|
||||
- Updated pipeline async handoff processor and deploy config with
|
||||
`async_chunk: true`
|
||||
- Smooth streaming audio without boundary artifacts
|
||||
- TTFA metrics
|
||||
|
||||
@@ -422,6 +499,13 @@ Common pre-commit failures, recovery commands for missing sign-off, and the
|
||||
full `pre-commit run` invocation for a TTS model:
|
||||
[references/precommit-dco.md](references/precommit-dco.md).
|
||||
|
||||
## Documentation and recipe
|
||||
|
||||
Follow the [`add-recipe` skill](../add-recipe/SKILL.md) to add or update the
|
||||
in-repository model-family recipe, the `recipes/README.md` index, the supported
|
||||
models table, TTS example documentation, and the speech API contract using
|
||||
validated evidence.
|
||||
|
||||
## Integration Checklist
|
||||
|
||||
Use this checklist when integrating a new TTS model:
|
||||
@@ -443,31 +527,34 @@ Use this checklist when integrating a new TTS model:
|
||||
- [ ] Config classes created with `model_type` registration
|
||||
- [ ] Stage 0 (AR) implemented and generates correct tokens
|
||||
- [ ] Stage 1 (Decoder) produces correct audio from tokens — dtype float32 for codec decoder
|
||||
- [ ] Stage 1 `max_num_seqs` ≥ 4 in production config (default 1 causes gaps under concurrency)
|
||||
- [ ] AR stage `max_num_seqs` ≥ 4 in the production deploy config unless the model has a tested lower limit
|
||||
- [ ] Optional dependency fallbacks handled at `load_weights()` time (torchaudio/soundfile/etc.)
|
||||
- [ ] Streaming: codec codes accumulated across AR steps (not reset per step)
|
||||
- [ ] Streaming: delta audio emitted per chunk, not full re-decoded waveform
|
||||
- [ ] Streaming: all `forward()` return paths emit `model_outputs`
|
||||
- [ ] Streaming: per-request state keyed by request ID (not shared across requests)
|
||||
- [ ] Streaming: codec tensors moved to codec decoder device before decode
|
||||
- [ ] Stage config YAML created
|
||||
- [ ] Pipeline topology defined in `pipeline.py` and registered in `OMNI_PIPELINES`
|
||||
- [ ] Deploy YAML created under `vllm_omni/deploy/`
|
||||
- [ ] `end2end.py` produces audio matching reference quality
|
||||
- [ ] README.md written
|
||||
|
||||
### Phase 3: Online Serving
|
||||
- [ ] All 5 `serving_speech.py` integration points added in one commit
|
||||
- [ ] Only extract params in `_build_*_params` that are forwarded to the model call (ruff F841)
|
||||
- [ ] Adapter written under `tts_adapters/` and registered in the import block
|
||||
- [ ] Only extract params in `build()` that are forwarded to the model call (ruff F841)
|
||||
- [ ] Prompt builder handles text input correctly
|
||||
- [ ] Voice cloning works (if supported)
|
||||
- [ ] All response formats work (wav, mp3, flac, pcm)
|
||||
- [ ] Client scripts and server launcher created
|
||||
- [ ] E2E online serving test written (`tests/e2e/online_serving/test_<model>.py`)
|
||||
- [ ] Buildkite CI entry added to `.buildkite/test-merge.yml`
|
||||
- [ ] E2E tests added per model priority tier (see **Test Case Writing (CI Levels)**)
|
||||
- [ ] Buildkite entries match level: `test-ready.yml` / `test-merge.yml` or nightly TTS job / `test-nightly.yml`
|
||||
- [ ] Gradio demo working
|
||||
- [ ] Documentation added (offline + online docs, nav, supported models)
|
||||
- [ ] In-repository recipe and `recipes/README.md` row added via the `add-recipe` skill
|
||||
|
||||
### Phase 4: Async Chunk
|
||||
- [ ] Stage config updated with `async_chunk: true`
|
||||
- [ ] Pipeline declares the async handoff processor
|
||||
- [ ] Deploy config sets `async_chunk: true` and connector chunk parameters
|
||||
- [ ] Stage 1 handles partial chunks correctly
|
||||
- [ ] No audio artifacts at chunk boundaries
|
||||
- [ ] Streaming via API (`stream=true`) works
|
||||
@@ -484,7 +571,7 @@ Use this checklist when integrating a new TTS model:
|
||||
- [ ] `pre-commit run --files <changed>` passes before every push
|
||||
- [ ] Every commit has `Signed-off-by` matching the author email (`git commit -s`)
|
||||
- [ ] `git config user.email` matches the email registered on your GitHub account
|
||||
- [ ] Details and failure-recovery commands: [references/precommit-dco.md](references/precommit-dco.md)
|
||||
- [ ] Hook list, failure table, and DCO recovery: [references/precommit-dco.md](references/precommit-dco.md)
|
||||
|
||||
## References
|
||||
|
||||
@@ -500,5 +587,6 @@ Project docs and adjacent skills:
|
||||
- [TTS audio skill](../vllm-omni-audio-tts/SKILL.md) — supported models and usage
|
||||
- [Fish Speech integration](../vllm-omni-audio-tts/references/fish-speech.md) — complete example of Phases 1–3
|
||||
- [Qwen3-TTS reference](../vllm-omni-audio-tts/references/qwen-tts.md) — complete example of all 5 phases
|
||||
- [vllm-omni-test skill](../vllm-omni-test/SKILL.md) — L1–L4 markers, naming, Buildkite wiring, run commands
|
||||
- [Adding a TTS model (developer guide)](https://github.com/vllm-project/vllm-omni/blob/main/docs/contributing/model/adding_tts_model.md)
|
||||
- `plan/voxcpm2_native_ar_design.md` — VoxCPM2's vLLM-native AR + side-computation pattern (distinct from the generator-based single-stage described above)
|
||||
@@ -30,6 +30,18 @@ but the changes are correct — stage the modified files and re-commit.
|
||||
| `ruff F841` | Variable extracted but never forwarded to model call | Remove the extraction or wire it through |
|
||||
| `ruff E402` | Import added below function definitions | Move to top-level import block |
|
||||
| `ruff format` | Line length, spacing, quote style | Accept auto-fix, stage, re-commit |
|
||||
| `check-spdx-header` | Missing header, or copyright still says `vLLM project` | Two-line Omni header (`vLLM-Omni project`); restage the rewrite |
|
||||
| `check-forbidden-imports` | Stdlib `re`/`base64`, pickle, Hugging Face Hub API, or direct Triton/TileLang | `import regex as re` and `pybase64`; use `vllm.transformers_utils.repo_utils`. Do **not** add the file to `allowed_files` without review |
|
||||
| `check-torch-cuda-call` | New `torch.cuda.*` call site | Use `current_omni_platform` / `OmniPlatform`; do not grow `ALLOWED_FILES` without review |
|
||||
| `check-tts-adapter-migration` | New `self._tts_model_type` branch in `serving_speech.py` | Put per-model logic in `tts_adapters/`. Lower `MAX_MODEL_TYPE_BRANCHES` when removing branches; do not raise it without review |
|
||||
| `check-mark` | New `tests/**/test_*.py` missing level/hardware mark, or direct `pytest.mark.H100` | Add `core_model`/`advanced_model`/… plus `cpu`/`cuda`/`hardware_test(`; SKU marks only via helpers |
|
||||
| `mypy-3.10` | Type error on changed `vllm_omni/` files | Fix the types; model trees are excluded. Extra versions: `pre-commit run --hook-stage manual mypy-3.12` |
|
||||
| `markdownlint-cli2` | Docs/README markdown lint | Accept auto-fix under `docs/` / `recipes/` / root README |
|
||||
| `check-buildkite` | Invalid `.buildkite/*.yml` | Fix the YAML; do not grow `SKIP_FILES` without review |
|
||||
| `shellcheck` | No `shellcheck` on PATH, or script warning | `apt-get`/`dnf`/`brew install shellcheck`, or `shellcheck.exe` on Windows PATH |
|
||||
|
||||
Canonical policy, CI `SKIP` list, and allowlist locations:
|
||||
[docs/contributing/README.md](../../../docs/contributing/README.md#linting).
|
||||
|
||||
## DCO sign-off
|
||||
|
||||
|
||||
Loaded 100 of 3699 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user