11import atexit
2+ import json
23from typing import Any
34from typing import Dict
45from typing import List
2526from ddtrace .internal .utils .retry import fibonacci_backoff_with_jitter
2627from ddtrace .llmobs import _telemetry as telemetry
2728from ddtrace .llmobs ._constants import AGENTLESS_EVAL_BASE_URL
29+ from ddtrace .llmobs ._constants import AGENTLESS_EXP_BASE_URL
2830from ddtrace .llmobs ._constants import AGENTLESS_SPAN_BASE_URL
2931from ddtrace .llmobs ._constants import DROPPED_IO_COLLECTION_ERROR
3032from ddtrace .llmobs ._constants import DROPPED_VALUE_TEXT
3840from ddtrace .llmobs ._constants import SPAN_SUBDOMAIN_NAME
3941from ddtrace .llmobs ._experiment import Dataset
4042from ddtrace .llmobs ._experiment import DatasetRecord
43+ from ddtrace .llmobs ._experiment import JSONType
4144from ddtrace .llmobs ._utils import safe_json
4245from ddtrace .settings ._agent import config as agent_config
4346
@@ -269,58 +272,77 @@ def _data(self, events: List[LLMObsEvaluationMetricEvent]) -> Dict[str, Any]:
269272
270273
271274class LLMObsExperimentsClient (BaseLLMObsWriter ):
275+ AGENTLESS_BASE_URL = AGENTLESS_EXP_BASE_URL
272276
273- def request (self , method : str , path : str , body : bytes = b"" ) -> Response :
277+ def request (self , method : str , path : str , body : JSONType = None ) -> Response :
274278 headers = {
275279 "Content-Type" : "application/json" ,
276280 "DD-API-KEY" : self ._api_key ,
277281 "DD-APPLICATION-KEY" : self ._app_key ,
278282 }
279- site = self ._site
280- if site == "datad0g.com" :
281- base = "https://dd.datad0g.com"
282- else :
283- base = f"https://api.{ site } "
284-
285- conn = get_connection (base )
283+ body = json .dumps (body ).encode ("utf-8" ) if body else b""
284+ conn = get_connection (self ._intake )
286285 try :
287- url = base + path
286+ url = self . _intake + path
288287 logger .debug ("requesting %s" , url )
289288 conn .request (method , url , body , headers )
290289 resp = conn .getresponse ()
291- if resp .status >= 300 :
292- raise ValueError (f"Failed to { method } { path } : { resp .status } " )
293290 return Response .from_http_response (resp )
294291 finally :
295292 conn .close ()
296293
297- def dataset_pull (self , name : str ) -> Dataset :
294+ def dataset_delete (self , dataset_id : str ) -> None :
295+ path = "/api/unstable/llm-obs/v1/datasets/delete"
296+ resp = self .request (
297+ "POST" ,
298+ path ,
299+ body = {
300+ "data" : {
301+ "type" : "datasets" ,
302+ "attributes" : {
303+ "type" : "soft" ,
304+ "dataset_ids" : [dataset_id ],
305+ },
306+ },
307+ },
308+ )
309+ assert resp .status == 200 , f"Failed to delete dataset { id } : { resp .get_json ()} "
310+ return None
311+
312+ def dataset_create (self , name : str , description : str ) -> Dataset :
313+ path = "/api/unstable/llm-obs/v1/datasets"
314+ body = {
315+ "data" : {
316+ "type" : "datasets" ,
317+ "attributes" : {"name" : name , "description" : description },
318+ }
319+ }
320+ resp = self .request ("POST" , path , body )
321+ response_data = resp .get_json ()
322+ dataset_id = response_data ["data" ]["id" ]
323+ return Dataset (name , dataset_id , [])
298324
325+ def dataset_pull (self , name : str ) -> Dataset :
299326 path = f"/api/unstable/llm-obs/v1/datasets?filter[name]={ quote (name )} "
300327 resp = self .request ("GET" , path )
301328
302329 response_data = resp .get_json ()
303- datasets = response_data .get ("data" , [])
304-
305- if not datasets :
330+ data = response_data ["data" ]
331+ if not data :
306332 raise ValueError (f"Dataset '{ name } ' not found" )
307333
308- dataset_id = datasets [0 ]["id" ]
334+ dataset_id = data [0 ]["id" ]
309335 url = f"/api/unstable/llm-obs/v1/datasets/{ dataset_id } /records"
310- try :
311- resp = self .request ("GET" , url )
312- records_data = resp .get_json ()
313- except ValueError as e :
314- if "404" in str (e ):
315- raise ValueError (f"Dataset '{ name } ' not found" ) from e
316- raise
336+ resp = self .request ("GET" , url )
337+ if resp .status == 404 :
338+ raise ValueError (f"Dataset '{ name } ' not found" )
339+ records_data = resp .get_json ()
317340
318341 class_records : List [DatasetRecord ] = []
319342 for record in records_data .get ("data" , []):
320343 attrs = record .get ("attributes" , {})
321344 input_data = attrs .get ("input" )
322345 expected_output = attrs .get ("expected_output" )
323-
324346 class_records .append (
325347 {
326348 "record_id" : record .get ("id" ),
@@ -329,7 +351,6 @@ def dataset_pull(self, name: str) -> Dataset:
329351 ** attrs .get ("metadata" , {}),
330352 }
331353 )
332-
333354 return Dataset (name , dataset_id , class_records )
334355
335356
0 commit comments