Skip to content

feat(api): update API spec from langfuse/langfuse 5633a79#1762

Closed
langfuse-bot wants to merge 1 commit into
mainfrom
api-spec-bot-5633a79
Closed

feat(api): update API spec from langfuse/langfuse 5633a79#1762
langfuse-bot wants to merge 1 commit into
mainfrom
api-spec-bot-5633a79

Conversation

@langfuse-bot

@langfuse-bot langfuse-bot commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Greptile Summary

This PR syncs Fern-generated Python API bindings from the langfuse/langfuse upstream (commit 5633a79), adding a new dashboards module and expanding the existing dashboard_widgets module with list/get/update/delete operations.

  • New dashboards module (raw_client.py, client.py, 13 type files): covers full CRUD for dashboards and their placements (widget tiles and preset tiles), using a discriminated union for DashboardPlacement.
  • Extended dashboard_widgets module: adds list, get, update, delete methods; new types DashboardWidgetChartConfigInput, DashboardWidgetList, DeleteDashboardWidgetResponse, UpdateDashboardWidgetRequest; switches the create endpoint to accept DashboardWidgetChartConfigInput instead of DashboardWidgetChartConfig.
  • __init__.py updates: all new and changed types are re-exported under the TYPE_CHECKING guard, consistent with existing patterns.

Confidence Score: 4/5

Safe to merge. This is entirely Fern-generated code syncing new dashboard and dashboard-placement API endpoints; no handwritten logic is changed.

The only finding is dead code in the generated error-handler chains: status codes 400/401/403/405 are matched by an unstable_errors block first, so the subsequent commons_errors fallback for those same codes is never reached. This is a code-generator artifact present in existing files too; it does not alter runtime behaviour for callers.

langfuse/api/unstable/dashboards/raw_client.py and langfuse/api/unstable/dashboard_widgets/raw_client.py contain the duplicate error-handler blocks worth tracking upstream in the Fern template.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller
    participant DashboardsClient
    participant RawDashboardsClient
    participant HTTPClient
    participant LangfuseAPI

    Caller->>DashboardsClient: list(page, limit)
    DashboardsClient->>RawDashboardsClient: list(page, limit)
    RawDashboardsClient->>HTTPClient: GET /api/public/unstable/dashboards
    HTTPClient->>LangfuseAPI: HTTP Request
    LangfuseAPI-->>HTTPClient: 200 DashboardList / 4xx Error
    HTTPClient-->>RawDashboardsClient: _response
    RawDashboardsClient-->>DashboardsClient: HttpResponse[DashboardList]
    DashboardsClient-->>Caller: DashboardList

    Caller->>DashboardsClient: create(name, definition)
    DashboardsClient->>RawDashboardsClient: create(name, definition)
    RawDashboardsClient->>HTTPClient: POST /api/public/unstable/dashboards
    HTTPClient->>LangfuseAPI: HTTP Request
    LangfuseAPI-->>HTTPClient: 201 Dashboard / 4xx Error
    HTTPClient-->>RawDashboardsClient: _response
    RawDashboardsClient-->>DashboardsClient: HttpResponse[Dashboard]
    DashboardsClient-->>Caller: Dashboard

    Caller->>DashboardsClient: create_placement(dashboard_id, ...)
    DashboardsClient->>RawDashboardsClient: create_placement(...)
    RawDashboardsClient->>HTTPClient: "POST /api/public/unstable/dashboards/{id}/placements"
    HTTPClient->>LangfuseAPI: HTTP Request
    LangfuseAPI-->>HTTPClient: 201 DashboardPlacement / 4xx Error
    HTTPClient-->>RawDashboardsClient: _response
    RawDashboardsClient-->>DashboardsClient: HttpResponse[DashboardPlacement]
    DashboardsClient-->>Caller: DashboardPlacement
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller
    participant DashboardsClient
    participant RawDashboardsClient
    participant HTTPClient
    participant LangfuseAPI

    Caller->>DashboardsClient: list(page, limit)
    DashboardsClient->>RawDashboardsClient: list(page, limit)
    RawDashboardsClient->>HTTPClient: GET /api/public/unstable/dashboards
    HTTPClient->>LangfuseAPI: HTTP Request
    LangfuseAPI-->>HTTPClient: 200 DashboardList / 4xx Error
    HTTPClient-->>RawDashboardsClient: _response
    RawDashboardsClient-->>DashboardsClient: HttpResponse[DashboardList]
    DashboardsClient-->>Caller: DashboardList

    Caller->>DashboardsClient: create(name, definition)
    DashboardsClient->>RawDashboardsClient: create(name, definition)
    RawDashboardsClient->>HTTPClient: POST /api/public/unstable/dashboards
    HTTPClient->>LangfuseAPI: HTTP Request
    LangfuseAPI-->>HTTPClient: 201 Dashboard / 4xx Error
    HTTPClient-->>RawDashboardsClient: _response
    RawDashboardsClient-->>DashboardsClient: HttpResponse[Dashboard]
    DashboardsClient-->>Caller: Dashboard

    Caller->>DashboardsClient: create_placement(dashboard_id, ...)
    DashboardsClient->>RawDashboardsClient: create_placement(...)
    RawDashboardsClient->>HTTPClient: "POST /api/public/unstable/dashboards/{id}/placements"
    HTTPClient->>LangfuseAPI: HTTP Request
    LangfuseAPI-->>HTTPClient: 201 DashboardPlacement / 4xx Error
    HTTPClient-->>RawDashboardsClient: _response
    RawDashboardsClient-->>DashboardsClient: HttpResponse[DashboardPlacement]
    DashboardsClient-->>Caller: DashboardPlacement
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
langfuse/api/unstable/dashboards/raw_client.py:171-214
**Dead code: duplicate status code handlers (400/401/403/405)**

Each handler method in both `dashboards/raw_client.py` and `dashboard_widgets/raw_client.py` checks status codes 400, 401, 403, and 405 twice in sequence. Since the first matching `if` block raises immediately, the second group of handlers for those same codes (using the `commons_errors` exception types) is permanently unreachable. Only the 404 `NotFoundError` from the second group is reachable (because 404 isn't present in the first group). This pattern repeats across all ~16 handler methods in the new `dashboards/raw_client.py` and continues into the modified `dashboard_widgets/raw_client.py`. Since this is Fern-generated code the fix belongs upstream in the API generator template, but it is worth tracking.

Reviews (1): Last reviewed commit: "feat(api): update API spec from langfuse..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@langfuse-bot
langfuse-bot requested a review from LysanderKie July 16, 2026 10:10
@github-actions

Copy link
Copy Markdown

@claude review

Comment on lines +171 to +214
if _response.status_code == 400:
raise Error(
headers=dict(_response.headers),
body=typing.cast(
typing.Any,
parse_obj_as(
type_=typing.Any, # type: ignore
object_=_response.json(),
),
),
)
if _response.status_code == 401:
raise commons_errors_unauthorized_error_UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
typing.Any,
parse_obj_as(
type_=typing.Any, # type: ignore
object_=_response.json(),
),
),
)
if _response.status_code == 403:
raise commons_errors_access_denied_error_AccessDeniedError(
headers=dict(_response.headers),
body=typing.cast(
typing.Any,
parse_obj_as(
type_=typing.Any, # type: ignore
object_=_response.json(),
),
),
)
if _response.status_code == 405:
raise commons_errors_method_not_allowed_error_MethodNotAllowedError(
headers=dict(_response.headers),
body=typing.cast(
typing.Any,
parse_obj_as(
type_=typing.Any, # type: ignore
object_=_response.json(),
),
),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Dead code: duplicate status code handlers (400/401/403/405)

Each handler method in both dashboards/raw_client.py and dashboard_widgets/raw_client.py checks status codes 400, 401, 403, and 405 twice in sequence. Since the first matching if block raises immediately, the second group of handlers for those same codes (using the commons_errors exception types) is permanently unreachable. Only the 404 NotFoundError from the second group is reachable (because 404 isn't present in the first group). This pattern repeats across all ~16 handler methods in the new dashboards/raw_client.py and continues into the modified dashboard_widgets/raw_client.py. Since this is Fern-generated code the fix belongs upstream in the API generator template, but it is worth tracking.

Prompt To Fix With AI
This is a comment left during a code review.
Path: langfuse/api/unstable/dashboards/raw_client.py
Line: 171-214

Comment:
**Dead code: duplicate status code handlers (400/401/403/405)**

Each handler method in both `dashboards/raw_client.py` and `dashboard_widgets/raw_client.py` checks status codes 400, 401, 403, and 405 twice in sequence. Since the first matching `if` block raises immediately, the second group of handlers for those same codes (using the `commons_errors` exception types) is permanently unreachable. Only the 404 `NotFoundError` from the second group is reachable (because 404 isn't present in the first group). This pattern repeats across all ~16 handler methods in the new `dashboards/raw_client.py` and continues into the modified `dashboard_widgets/raw_client.py`. Since this is Fern-generated code the fix belongs upstream in the API generator template, but it is worth tracking.

How can I resolve this? If you propose a fix, please make it concise.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — this is an auto-generated Fern SDK update mirroring an upstream API spec change (dashboards/dashboard-widgets endpoints), consistent with the recurring "update API spec" PRs already merged in this repo's history.

Extended reasoning...

Overview

This PR is entirely auto-generated (Fern) client code regenerated from an updated langfuse/langfuse API spec. It adds a new dashboards resource (list/create/get/update/delete + placement management) and extends dashboard_widgets with list/get/update/delete, plus a new DashboardWidgetChartConfigInput type that makes chartConfig/description optional on create and removes the `minVersion" field from responses. All files carry the "This file was auto-generated by Fern from our API Definition" header, and the diff follows the exact repetitive raw_client/client/types scaffolding pattern seen in prior merged PRs in this repo's history (e.g. 9593d37, 2f3d7c0).

Security risks

None identified. This is typed request/response plumbing over httpx with no auth, crypto, or permission logic — it only shapes HTTP calls and pydantic models for a REST API client.

Level of scrutiny

Low-to-mechanical. This class of PR (spec-driven SDK regeneration) is generated by tooling, not hand-written, and this repo has a track record of merging these without incident. The bug hunting system found no issues, and the two candidate issues it investigated (missing camelCase aliases on the new input type, and DashboardDefinition reusing the placement output type for create/update input) were both ruled out as non-issues.

Other factors

The change is additive (new dashboards module, new optional fields) and one field removal (widget response no longer includes minVersion) that mirrors the corresponding server-side API contract change — since this is a generated client mirroring the server spec, there's no drift risk to reconcile. No hand-written logic changes are present that would benefit from deeper human review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant