@@ -251,6 +251,42 @@ def test_no_poll_token_when_empty(self):
251251 assert "poll_token" not in widget
252252 assert "download_token_url" not in widget
253253
254+ def test_artifact_id_included_in_widget_and_text (self ):
255+ """When artifact_id is provided, it appears in widget JSON and text summary."""
256+ preview = [{"a" : 1 }]
257+ csv_url = f"{ FAKE_SERVER_URL } /api/results/task-aid/download?token=abc"
258+ result = _build_result_response (
259+ task_id = "task-aid" ,
260+ csv_url = csv_url ,
261+ preview_records = preview ,
262+ total = 1 ,
263+ columns = ["a" ],
264+ offset = 0 ,
265+ page_size = 10 ,
266+ artifact_id = "abc-123-def" ,
267+ )
268+ widget = json .loads (result [0 ].text )
269+ assert widget ["artifact_id" ] == "abc-123-def"
270+ assert "abc-123-def" in result [1 ].text
271+ assert "Output artifact_id" in result [1 ].text
272+
273+ def test_no_artifact_id_when_empty (self ):
274+ """When artifact_id is empty, widget JSON and text omit it."""
275+ preview = [{"a" : 1 }]
276+ csv_url = f"{ FAKE_SERVER_URL } /api/results/task-noaid/download?token=abc"
277+ result = _build_result_response (
278+ task_id = "task-noaid" ,
279+ csv_url = csv_url ,
280+ preview_records = preview ,
281+ total = 1 ,
282+ columns = ["a" ],
283+ offset = 0 ,
284+ page_size = 10 ,
285+ )
286+ widget = json .loads (result [0 ].text )
287+ assert "artifact_id" not in widget
288+ assert "Output artifact_id" not in result [1 ].text
289+
254290
255291# ── Async functions ────────────────────────────────────────────
256292
@@ -325,6 +361,29 @@ async def test_preserves_session_url_from_meta(self, _http_state):
325361 widget = json .loads (result [0 ].text )
326362 assert widget ["session_url" ] == "https://everyrow.io/sessions/xyz"
327363
364+ @pytest .mark .asyncio
365+ async def test_preserves_artifact_id_from_meta (self , _http_state ):
366+ meta = json .dumps (
367+ {
368+ "total" : 1 ,
369+ "columns" : ["a" ],
370+ "artifact_id" : "cached-artifact-789" ,
371+ }
372+ )
373+ page = json .dumps ([{"a" : 1 }])
374+ task_id = "task-cached-aid"
375+
376+ await redis_store .store_result_meta (task_id , meta )
377+ await redis_store .store_result_page (task_id , 0 , 10 , page )
378+ await redis_store .store_poll_token (task_id , "test-token" )
379+
380+ result = await try_cached_result (task_id , 0 , 10 , mcp_server_url = FAKE_SERVER_URL )
381+
382+ assert result is not None
383+ widget = json .loads (result [0 ].text )
384+ assert widget ["artifact_id" ] == "cached-artifact-789"
385+ assert "cached-artifact-789" in result [1 ].text
386+
328387 @pytest .mark .asyncio
329388 async def test_returns_none_when_json_expired (self , _http_state ):
330389 """When metadata exists but JSON is gone, fall back to API (return None)."""
@@ -383,6 +442,35 @@ async def test_stores_and_returns_response(self, sample_df, _http_state):
383442 assert meta ["total" ] == 3
384443 assert meta ["columns" ] == ["name" , "score" ]
385444
445+ @pytest .mark .asyncio
446+ async def test_stores_artifact_id_in_meta_and_response (
447+ self , sample_df , _http_state
448+ ):
449+ task_id = "task-aid-store"
450+ await redis_store .store_poll_token (task_id , "test-token" )
451+
452+ result = await try_store_result (
453+ task_id ,
454+ sample_df ,
455+ 0 ,
456+ 10 ,
457+ mcp_server_url = FAKE_SERVER_URL ,
458+ artifact_id = "output-artifact-456" ,
459+ )
460+
461+ # Verify artifact_id in Redis metadata
462+ meta_raw = await redis_store .get_result_meta (task_id )
463+ assert meta_raw is not None
464+ meta = json .loads (meta_raw )
465+ assert meta ["artifact_id" ] == "output-artifact-456"
466+
467+ # Verify artifact_id in widget JSON
468+ widget = json .loads (result [0 ].text )
469+ assert widget ["artifact_id" ] == "output-artifact-456"
470+
471+ # Verify artifact_id in text summary
472+ assert "output-artifact-456" in result [1 ].text
473+
386474 @pytest .mark .asyncio
387475 async def test_includes_session_url_in_meta (self , sample_df , _http_state ):
388476 task_id = "task-sess"
0 commit comments