@@ -2149,3 +2149,163 @@ def test_multiturn_regen(
21492149 chat = row .columns ["AI" ].content .strip ()
21502150 assert chat != "How are you?" , f"{ row .columns = } "
21512151 assert "10" in chat , f"{ row .columns = } "
2152+
2153+
2154+ @pytest .mark .parametrize ("table_type" , TABLE_TYPES )
2155+ @pytest .mark .parametrize ("stream" , ** STREAM_PARAMS )
2156+ def test_null_input_llm_output (
2157+ setup : ServingContext ,
2158+ table_type : TableType ,
2159+ stream : bool ,
2160+ ):
2161+ """
2162+ Test that LLM output columns handle null input values correctly.
2163+ When an input column is None:
2164+ - For non-file columns (str, int, float): interpolated as "None" string
2165+ - For file columns (document, image, audio): interpolated as empty string ""
2166+ The LLM execution should complete normally without errors in both cases.
2167+ """
2168+ client = JamAI (user_id = setup .superuser_id , project_id = setup .project_id )
2169+ cols = [
2170+ ColumnSchemaCreate (id = "input_text" , dtype = "str" ),
2171+ ColumnSchemaCreate (id = "input_int" , dtype = "int" ),
2172+ ColumnSchemaCreate (id = "input_float" , dtype = "float" ),
2173+ ColumnSchemaCreate (id = "input_document" , dtype = "document" ),
2174+ ColumnSchemaCreate (id = "input_image" , dtype = "image" ),
2175+ ColumnSchemaCreate (id = "input_audio" , dtype = "audio" ),
2176+ ColumnSchemaCreate (
2177+ id = "llm_output" ,
2178+ dtype = "str" ,
2179+ gen_config = LLMGenConfig (
2180+ model = setup .lorem_llm_model_id ,
2181+ system_prompt = "You are a helpful assistant." ,
2182+ prompt = (
2183+ "Input text: ${input_text}, Input int: ${input_int}, Input float: ${input_float}. "
2184+ "Document: ${input_document}, Image: ${input_image}, Audio: ${input_audio}. "
2185+ "Respond with 'OK'."
2186+ ),
2187+ max_tokens = 10 ,
2188+ ),
2189+ ),
2190+ ]
2191+ with create_table (client , table_type , cols = cols ) as table :
2192+ # Test with various combinations of null and non-null inputs
2193+ data = [
2194+ # All null inputs
2195+ {
2196+ "input_text" : None ,
2197+ "input_int" : None ,
2198+ "input_float" : None ,
2199+ "input_document" : None ,
2200+ "input_image" : None ,
2201+ "input_audio" : None ,
2202+ },
2203+ # All non-null inputs
2204+ {
2205+ "input_text" : "test" ,
2206+ "input_int" : 42 ,
2207+ "input_float" : 3.14 ,
2208+ "input_document" : setup .document_uri ,
2209+ "input_image" : setup .image_uri ,
2210+ "input_audio" : setup .audio_uri ,
2211+ },
2212+ # Mixed: null primitives, non-null files
2213+ {
2214+ "input_text" : None ,
2215+ "input_int" : None ,
2216+ "input_float" : None ,
2217+ "input_document" : setup .document_uri ,
2218+ "input_image" : setup .image_uri ,
2219+ "input_audio" : setup .audio_uri ,
2220+ },
2221+ # Mixed: non-null primitives, null files
2222+ {
2223+ "input_text" : "test" ,
2224+ "input_int" : 10 ,
2225+ "input_float" : 2.5 ,
2226+ "input_document" : None ,
2227+ "input_image" : None ,
2228+ "input_audio" : None ,
2229+ },
2230+ ]
2231+ response = add_table_rows (
2232+ client , table_type , table .id , data , stream = stream , check_usage = False
2233+ )
2234+ assert len (response .rows ) == len (data )
2235+
2236+ # Verify all rows completed without errors
2237+ rows = list_table_rows (client , table_type , table .id )
2238+ assert rows .total == len (data )
2239+
2240+ for i , row in enumerate (rows .values ):
2241+ llm_output = row ["llm_output" ]
2242+ assert llm_output is not None , f"Row { i } : LLM output should not be None"
2243+ assert not llm_output .startswith ("[ERROR]" ), (
2244+ f"Row { i } : LLM output should not contain error: { llm_output } "
2245+ )
2246+ assert len (llm_output ) > 0 , f"Row { i } : LLM output should not be empty"
2247+
2248+
2249+ @pytest .mark .parametrize ("stream" , ** STREAM_PARAMS )
2250+ async def test_null_input_python_fixed_function (
2251+ setup : ServingContext ,
2252+ stream : bool ,
2253+ ):
2254+ """
2255+ Test that Python fixed function output columns handle null input values correctly.
2256+ The Python code should be able to handle None values in the row data gracefully.
2257+ """
2258+ table_type = TableType .ACTION
2259+ client = JamAI (user_id = setup .superuser_id , project_id = setup .project_id )
2260+
2261+ # Python code that handles null values
2262+ python_code = """
2263+ if row.get('input_str') is None:
2264+ row['output'] = 'Input was None'
2265+ else:
2266+ row['output'] = f"Input was: {row['input_str']}"
2267+ """
2268+
2269+ cols = [
2270+ ColumnSchemaCreate (id = "input_str" , dtype = "str" ),
2271+ ColumnSchemaCreate (id = "input_int" , dtype = "int" ),
2272+ ColumnSchemaCreate (
2273+ id = "output" ,
2274+ dtype = "str" ,
2275+ gen_config = PythonGenConfig (python_code = python_code ),
2276+ ),
2277+ ]
2278+ with create_table (client , table_type , cols = cols ) as table :
2279+ data = [
2280+ {"input_str" : None , "input_int" : None },
2281+ {"input_str" : "test value" , "input_int" : 42 },
2282+ {"input_str" : None , "input_int" : 10 },
2283+ {"input_str" : "" , "input_int" : None },
2284+ ]
2285+ response = add_table_rows (
2286+ client , table_type , table .id , data , stream = stream , check_usage = False
2287+ )
2288+ assert len (response .rows ) == len (data )
2289+
2290+ rows = list_table_rows (client , table_type , table .id )
2291+ row_ids = [r .row_id for r in response .rows ]
2292+ assert rows .total == len (data )
2293+
2294+ assert rows .values [0 ]["output" ] == "Input was None"
2295+ assert rows .values [1 ]["output" ] == "Input was: test value"
2296+ assert rows .values [2 ]["output" ] == "Input was None"
2297+ assert rows .values [3 ]["output" ] == "Input was: "
2298+
2299+ # Test regen with null values
2300+ response = regen_table_rows (
2301+ client , table_type , table .id , row_ids , stream = stream , check_usage = False
2302+ )
2303+ assert len (response .rows ) == len (data )
2304+
2305+ rows = list_table_rows (client , table_type , table .id )
2306+ assert rows .total == len (data )
2307+
2308+ assert rows .values [0 ]["output" ] == "Input was None"
2309+ assert rows .values [1 ]["output" ] == "Input was: test value"
2310+ assert rows .values [2 ]["output" ] == "Input was None"
2311+ assert rows .values [3 ]["output" ] == "Input was: "
0 commit comments