Skip to content

Conversation

@kxzk
Copy link
Collaborator

@kxzk kxzk commented Feb 8, 2026

TL;DR

Add project-scoped URL generation for traces, datasets, and dataset runs — matching the actual Langfuse UI paths.

Why

trace_url previously returned /traces/:id which doesn't resolve in the Langfuse UI (requires /project/:pid/traces/:id). This lazily fetches the project ID from GET /api/public/projects, caches it, and uses it across all URL helpers. ExperimentRunner now surfaces dataset_run_url on results. Also documents the single-dataset-per-run invariant and simplifies tests that were encoding accidental mixed-dataset behavior.

Checklist

  • Has label
  • Has linked issue
  • Tests added for new behavior
  • Docs updated (if user-facing)

…nd runs

Fetch project ID lazily from the API so trace_url, dataset_url, and
dataset_run_url return fully-qualified project-scoped paths matching
the Langfuse UI. ExperimentRunner now surfaces dataset_run_url on
results. Includes single-dataset-per-run invariant comment and
simplified tests that no longer encode accidental mixed-dataset behavior.
Copilot AI review requested due to automatic review settings February 8, 2026 22:18
@greptile-apps
Copy link

greptile-apps bot commented Feb 8, 2026

Greptile Overview

Greptile Summary

This PR updates the SDK’s UI URL helpers to generate Langfuse project-scoped paths (e.g., /project/:pid/traces/:id) by lazily fetching the first accessible project ID from GET /api/public/projects and caching it. It adds new helpers for datasets and dataset runs, exposes dataset_run_url on ExperimentResult via ExperimentRunner, and updates/specs accordingly.

The main correctness issue is in spec/langfuse/client_spec.rb: some “project ID unavailable” examples appear to be shadowed by an outer success stub, meaning the nil-return behavior may not actually be tested.

Confidence Score: 4/5

  • This PR is likely safe to merge after fixing the identified test-stubbing issue so failure paths are actually covered.
  • Core code changes are small and consistent with existing patterns (lazy lookup + caching). The primary concern is that some new specs for the nil-path seem to be ineffective due to WebMock stub precedence, reducing confidence in coverage of the error case. Unable to run the test suite in this environment (bundler not available), so confidence is not a full 5/5.
  • spec/langfuse/client_spec.rb

Important Files Changed

Filename Overview
lib/langfuse/api_client.rb Adds get_projects API call for fetching accessible projects; error handling mirrors other GET endpoints.
lib/langfuse/client.rb Adds lazy cached project_id lookup and project-scoped URL helpers (trace_url, dataset_url, dataset_run_url).
lib/langfuse/dataset_client.rb Adds DatasetClient#url delegating to Client#dataset_url when client is present.
lib/langfuse/experiment_runner.rb Tracks dataset_id alongside dataset_run_id and exposes dataset_run_url on ExperimentResult.
spec/langfuse/api_client_spec.rb Adds tests for ApiClient#get_projects covering success, 401, timeout, and retriable errors.
spec/langfuse/base_observation_spec.rb Updates trace_url expectations to include /project/:pid/... and stubs project lookup.
spec/langfuse/client_spec.rb Adds specs for project_id caching and new URL helpers; failure-case stubs appear to be shadowed by outer success stub (tests may not cover nil-path).
spec/langfuse/dataset_client_spec.rb Adds specs for DatasetClient#url with/without client delegation.
spec/langfuse/experiment_runner_spec.rb Adds specs for dataset_run_url population on experiment results and dataset_id selection behavior.

Sequence Diagram

sequenceDiagram
  participant U as User
  participant C as Client
  participant A as ApiClient
  participant LF as LangfuseAPI
  participant ER as ExperimentRunner
  participant RES as ExperimentResult

  U->>C: trace_url(trace_id)
  alt project_id cached
    C-->>U: url
  else first call
    C->>A: get_projects()
    A->>LF: GET /api/public/projects
    alt success
      LF-->>A: 200 {data:[{id: pid}]}
      A-->>C: body
      C-->>U: url
    else failure/empty
      LF-->>A: error/empty
      A-->>C: error/body
      C-->>U: nil
    end
  end

  U->>ER: execute()
  ER->>C: create_dataset_run_item(...)
  ER->>C: dataset_run_url(dataset_id, dataset_run_id)
  ER->>RES: new(dataset_run_url)
  RES-->>U: dataset_run_url
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@kxzk kxzk added the enhancement New feature or request label Feb 8, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Ruby SDK’s UI URL helpers to generate project-scoped Langfuse URLs (matching the UI’s /project/:projectId/... routing) by lazily fetching and caching the project ID, and surfaces a dataset-run URL on experiment results.

Changes:

  • Add lazy project_id lookup (via GET /api/public/projects) and use it to build project-scoped trace_url, dataset_url, and dataset_run_url.
  • Surface dataset_run_url on ExperimentResult (via ExperimentRunner) and add DatasetClient#url.
  • Update/add specs to cover the new URL behavior and caching/failure behavior.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
lib/langfuse/client.rb Adds lazy, cached project ID lookup and builds project-scoped UI URLs for traces/datasets/dataset runs.
lib/langfuse/api_client.rb Adds get_projects API call used by the client for project ID lookup.
lib/langfuse/experiment_runner.rb Captures dataset ID for URL building and returns dataset_run_url on experiment results.
lib/langfuse/dataset_client.rb Adds #url delegating to client.dataset_url.
spec/langfuse/client_spec.rb Tests project ID caching/failure behavior and updated URL formats.
spec/langfuse/api_client_spec.rb Adds tests for get_projects.
spec/langfuse/experiment_runner_spec.rb Adds tests ensuring dataset_run_url is populated (or nil) correctly.
spec/langfuse/dataset_client_spec.rb Adds coverage for DatasetClient#url.
spec/langfuse/base_observation_spec.rb Updates trace URL expectations to project-scoped paths and stubs project lookup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

end

# Invariant: all items in a single run belong to the same dataset.
def link_to_dataset_run(item, trace_id, observation_id)
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new comment states a single-run invariant (all items belong to the same dataset), but this method doesn’t enforce it. If a caller passes DatasetItemClient objects from different datasets, the run will still link items and later URL generation will use whichever dataset_id was captured first, producing an incorrect dataset_run_url. Consider validating that subsequent items match the initially captured dataset_id (and either raise or warn/skip linking when they don’t).

Suggested change
def link_to_dataset_run(item, trace_id, observation_id)
def link_to_dataset_run(item, trace_id, observation_id)
if @dataset_id && item.dataset_id && item.dataset_id != @dataset_id
@logger.warn(
"Dataset run item linking skipped: item dataset_id=#{item.dataset_id} " \
"does not match run dataset_id=#{@dataset_id}"
)
return nil
end

Copilot uses AI. Check for mistakes.
@kxzk kxzk merged commit e2c014c into main Feb 8, 2026
17 checks passed
@kxzk kxzk deleted the feat/project-scoped-urls branch February 8, 2026 22:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant