@@ -212,6 +212,21 @@ type (
212212 CreateExperimentResponse = Response [ExperimentView ]
213213)
214214
215+ // DatasetRecordItemV2 is the wire format for a single item in the v2 dataset-records list response.
216+ // The v2 endpoint returns a flat object (id, input, expected_output, metadata at the top level),
217+ // unlike the unstable endpoint which wraps fields under "attributes".
218+ type DatasetRecordItemV2 struct {
219+ ID string `json:"id"`
220+ Input any `json:"input"`
221+ ExpectedOutput any `json:"expected_output"`
222+ Metadata any `json:"metadata"`
223+ }
224+
225+ type GetDatasetRecordsResponseV2 struct {
226+ Data []DatasetRecordItemV2 `json:"data"`
227+ Meta ResponseMeta `json:"meta"`
228+ }
229+
215230func (c * Transport ) GetDatasetByName (ctx context.Context , name , projectID string ) (* DatasetView , error ) {
216231 q := url.Values {}
217232 q .Set ("filter[name]" , name )
@@ -353,60 +368,83 @@ func (c *Transport) BatchUpdateDataset(
353368}
354369
355370// GetDatasetRecordsPage fetches a single page of records for the given dataset.
371+ // projectID is the LLM Observability project UUID that owns the dataset.
372+ // version, when non-nil, requests a specific historical snapshot; nil fetches the latest version.
356373// Returns the records, the cursor for the next page (empty string if no more pages), and any error.
357- func (c * Transport ) GetDatasetRecordsPage (ctx context.Context , datasetID , cursor string ) ([]DatasetRecordView , string , error ) {
358- method := http . MethodGet
359- recordsPath := fmt . Sprintf ( "%s/datasets/%s/records" , endpointPrefixDNE , url .PathEscape (datasetID ))
374+ func (c * Transport ) GetDatasetRecordsPage (ctx context.Context , projectID , datasetID , cursor string , version * int ) ([]DatasetRecordView , string , error ) {
375+ recordsPath := fmt . Sprintf ( "%s/%s/datasets/%s/records" , endpointPrefixDNEStable ,
376+ url . PathEscape ( projectID ) , url .PathEscape (datasetID ))
360377
378+ q := url.Values {}
379+ if version != nil {
380+ q .Set ("filter[version]" , fmt .Sprintf ("%d" , * version ))
381+ }
361382 if cursor != "" {
362- recordsPath = fmt .Sprintf ("%s?page[cursor]=%s" , recordsPath , url .QueryEscape (cursor ))
383+ q .Set ("page[cursor]" , cursor )
384+ }
385+ if len (q ) > 0 {
386+ recordsPath = recordsPath + "?" + q .Encode ()
363387 }
364388
365- result , err := c .jsonRequest (ctx , method , recordsPath , subdomainDNE , nil , getDatasetRecordsTimeout )
389+ result , err := c .jsonRequest (ctx , http . MethodGet , recordsPath , subdomainDNE , nil , getDatasetRecordsTimeout )
366390 if err != nil {
367391 return nil , "" , err
368392 }
369393 if result .statusCode != http .StatusOK {
370394 return nil , "" , fmt .Errorf ("unexpected status %d: %s" , result .statusCode , string (result .body ))
371395 }
372396
373- var recordsResp GetDatasetRecordsResponse
397+ var recordsResp GetDatasetRecordsResponseV2
374398 if err := json .Unmarshal (result .body , & recordsResp ); err != nil {
375399 return nil , "" , fmt .Errorf ("failed to decode json response: %w" , err )
376400 }
377401
378402 records := make ([]DatasetRecordView , 0 , len (recordsResp .Data ))
379403 for _ , r := range recordsResp .Data {
380- rec := r .Attributes
381- rec .ID = r .ID
382- records = append (records , rec )
404+ records = append (records , DatasetRecordView {
405+ ID : r .ID ,
406+ Input : r .Input ,
407+ ExpectedOutput : r .ExpectedOutput ,
408+ Metadata : r .Metadata ,
409+ })
383410 }
384411
385412 return records , recordsResp .Meta .After , nil
386413}
387414
388415// GetDatasetWithRecords fetches the given Dataset and all its records from DataDog.
416+ // version, when non-nil, requests a specific historical snapshot; nil fetches the latest version.
389417// This eagerly fetches all pages of records.
390- func (c * Transport ) GetDatasetWithRecords (ctx context.Context , name , projectID string ) (* DatasetView , []DatasetRecordView , error ) {
418+ func (c * Transport ) GetDatasetWithRecords (ctx context.Context , name , projectID string , version * int ) (* DatasetView , []DatasetRecordView , error ) {
391419 // 1) Fetch dataset by name
392420 ds , err := c .GetDatasetByName (ctx , name , projectID )
393421 if err != nil {
394422 return nil , nil , err
395423 }
396424
397- // 2) Fetch all records with pagination support
425+ // 2) Fetch all records with pagination support.
426+ // The v2 records endpoint has no per-record version field, so stamp the effective
427+ // version (requested snapshot or the dataset's current version) onto every record.
428+ effectiveVersion := ds .CurrentVersion
429+ if version != nil {
430+ effectiveVersion = * version
431+ }
432+
398433 var allRecords []DatasetRecordView
399434 nextCursor := ""
400435 pageNum := 0
401436
402437 for {
403438 log .Debug ("llmobs/transport: fetching dataset records page %d" , pageNum )
404439
405- records , cursor , err := c .GetDatasetRecordsPage (ctx , ds .ID , nextCursor )
440+ records , cursor , err := c .GetDatasetRecordsPage (ctx , projectID , ds .ID , nextCursor , version )
406441 if err != nil {
407442 return nil , nil , fmt .Errorf ("get dataset records failed on page %d: %w" , pageNum , err )
408443 }
409444
445+ for i := range records {
446+ records [i ].Version = effectiveVersion
447+ }
410448 allRecords = append (allRecords , records ... )
411449
412450 nextCursor = cursor
0 commit comments