Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,18 @@
CatalogAzureFoundryApiKeyAuth,
CatalogAzureFoundryProviderConfig,
CatalogBedrockAccessKeyAuth,
CatalogListLlmProviderModelsRequest,
CatalogListLlmProviderModelsResponse,
CatalogLlmProvider,
CatalogLlmProviderDocument,
CatalogLlmProviderModel,
CatalogLlmProviderPatch,
CatalogLlmProviderPatchDocument,
CatalogOpenAiApiKeyAuth,
CatalogOpenAiProviderConfig,
CatalogTestLlmProviderByIdRequest,
CatalogTestLlmProviderDefinitionRequest,
CatalogTestLlmProviderResponse,
)
from gooddata_sdk.catalog.organization.entity_model.organization import CatalogOrganization
from gooddata_sdk.catalog.organization.entity_model.setting import CatalogOrganizationSetting
Expand Down Expand Up @@ -249,6 +254,15 @@
CatalogUserDataFilterAttributes,
CatalogUserDataFilterRelationships,
)
from gooddata_sdk.catalog.workspace.entity_model.analytics_catalog import (
CatalogGenerateTitleRequest,
CatalogGenerateTitleResponse,
)
from gooddata_sdk.catalog.workspace.entity_model.llm_resolved import (
CatalogResolvedLlmEndpoint,
CatalogResolvedLlmProvider,
CatalogResolvedLlms,
)
from gooddata_sdk.catalog.workspace.entity_model.workspace import CatalogWorkspace
from gooddata_sdk.client import GoodDataApiClient
from gooddata_sdk.compute.compute_to_sdk_converter import ComputeToSdkConverter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@
from gooddata_api_client.model.json_api_llm_provider_in_document import JsonApiLlmProviderInDocument
from gooddata_api_client.model.json_api_llm_provider_patch import JsonApiLlmProviderPatch
from gooddata_api_client.model.json_api_llm_provider_patch_document import JsonApiLlmProviderPatchDocument
from gooddata_api_client.model.list_llm_provider_models_request import ListLlmProviderModelsRequest
from gooddata_api_client.model.list_llm_provider_models_response import ListLlmProviderModelsResponse
from gooddata_api_client.model.open_ai_provider_auth import OpenAiProviderAuth
from gooddata_api_client.model.open_ai_provider_config import OpenAIProviderConfig
from gooddata_api_client.model.test_llm_provider_by_id_request import TestLlmProviderByIdRequest
from gooddata_api_client.model.test_llm_provider_definition_request import TestLlmProviderDefinitionRequest
from gooddata_api_client.model.test_llm_provider_response import TestLlmProviderResponse

from gooddata_sdk.catalog.base import Base
from gooddata_sdk.utils import safeget
Expand Down Expand Up @@ -333,3 +338,136 @@ class CatalogLlmProviderPatchAttributes(Base):
@staticmethod
def client_class() -> type[JsonApiLlmProviderInAttributes]:
return JsonApiLlmProviderInAttributes


# --- Action request/response model types ---


@define(kw_only=True)
class CatalogModelTestResult(Base):
"""Result for a single model connectivity test."""

model_id: str
success: bool
message: str | None = None

@staticmethod
def client_class() -> type:
raise NotImplementedError()

@classmethod
def from_api(cls, data: dict[str, Any]) -> CatalogModelTestResult:
return cls(
model_id=safeget(data, ["modelId"]) or "",
success=safeget(data, ["success"]) or False,
message=safeget(data, ["message"]),
)


@define(kw_only=True)
class CatalogTestLlmProviderResponse(Base):
"""Response from test LLM provider endpoint."""

success: bool
message: str | None = None
model_results: list[CatalogModelTestResult] | None = None

@staticmethod
def client_class() -> type[TestLlmProviderResponse]:
return TestLlmProviderResponse

@classmethod
def from_api(cls, data: dict[str, Any]) -> CatalogTestLlmProviderResponse:
raw_model_results = safeget(data, ["modelResults"]) or []
model_results = [CatalogModelTestResult.from_api(r) for r in raw_model_results]
return cls(
success=safeget(data, ["success"]) or False,
message=safeget(data, ["message"]),
model_results=model_results if model_results else None,
)


@define(kw_only=True)
class CatalogTestLlmProviderDefinitionRequest(Base):
"""Request for testing LLM provider connectivity with a full definition."""

provider_config: CatalogLlmProviderConfig
models: list[CatalogLlmProviderModel] | None = None

@staticmethod
def client_class() -> type[TestLlmProviderDefinitionRequest]:
return TestLlmProviderDefinitionRequest

def to_api(self) -> TestLlmProviderDefinitionRequest:
kwargs: dict[str, Any] = {}
if self.models is not None:
kwargs["models"] = [m.to_api() for m in self.models]
return TestLlmProviderDefinitionRequest(
provider_config=self.provider_config.to_api(),
**kwargs,
)


@define(kw_only=True)
class CatalogTestLlmProviderByIdRequest(Base):
"""Request for testing an existing LLM provider by ID with optional overrides."""

provider_config: CatalogLlmProviderConfig | None = None
models: list[CatalogLlmProviderModel] | None = None

@staticmethod
def client_class() -> type[TestLlmProviderByIdRequest]:
return TestLlmProviderByIdRequest

def to_api(self) -> TestLlmProviderByIdRequest:
kwargs: dict[str, Any] = {}
if self.provider_config is not None:
kwargs["provider_config"] = self.provider_config.to_api()
if self.models is not None:
kwargs["models"] = [m.to_api() for m in self.models]
return TestLlmProviderByIdRequest(**kwargs)


@define(kw_only=True)
class CatalogListLlmProviderModelsRequest(Base):
"""Request for listing models available on an LLM provider."""

provider_config: CatalogLlmProviderConfig

@staticmethod
def client_class() -> type[ListLlmProviderModelsRequest]:
return ListLlmProviderModelsRequest

def to_api(self) -> ListLlmProviderModelsRequest:
return ListLlmProviderModelsRequest(
provider_config=self.provider_config.to_api(),
)


@define(kw_only=True)
class CatalogListLlmProviderModelsResponse(Base):
"""Response from list LLM provider models endpoint."""

success: bool
models: list[CatalogLlmProviderModel] | None = None
message: str | None = None

@staticmethod
def client_class() -> type[ListLlmProviderModelsResponse]:
return ListLlmProviderModelsResponse

@classmethod
def from_api(cls, data: dict[str, Any]) -> CatalogListLlmProviderModelsResponse:
raw_models = safeget(data, ["models"]) or []
models = [
CatalogLlmProviderModel(
id=safeget(m, ["id"]) or "",
family=safeget(m, ["family"]) or "",
)
for m in raw_models
]
return cls(
success=safeget(data, ["success"]) or False,
models=models if models else None,
message=safeget(data, ["message"]),
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@
from gooddata_sdk.catalog.organization.entity_model.identity_provider import CatalogIdentityProvider
from gooddata_sdk.catalog.organization.entity_model.jwk import CatalogJwk, CatalogJwkDocument
from gooddata_sdk.catalog.organization.entity_model.llm_provider import (
CatalogListLlmProviderModelsRequest,
CatalogListLlmProviderModelsResponse,
CatalogLlmProvider,
CatalogLlmProviderDocument,
CatalogLlmProviderPatch,
CatalogLlmProviderPatchDocument,
CatalogTestLlmProviderByIdRequest,
CatalogTestLlmProviderDefinitionRequest,
CatalogTestLlmProviderResponse,
)
from gooddata_sdk.catalog.organization.entity_model.setting import CatalogOrganizationSetting
from gooddata_sdk.catalog.organization.layout.identity_provider import CatalogDeclarativeIdentityProvider
Expand Down Expand Up @@ -584,6 +589,70 @@ def delete_llm_provider(self, id: str) -> None:
"""
self._entities_api.delete_entity_llm_providers(id, _check_return_type=False)

def test_llm_provider(self, request: CatalogTestLlmProviderDefinitionRequest) -> CatalogTestLlmProviderResponse:
"""Test LLM provider connectivity with a full definition.

Args:
request: Test request with provider config and optional models

Returns:
CatalogTestLlmProviderResponse: Test result
"""
response = self._actions_api.test_llm_provider(request.to_api(), _check_return_type=False)
return CatalogTestLlmProviderResponse.from_api(response)

def test_llm_provider_by_id(
self,
llm_provider_id: str,
request: CatalogTestLlmProviderByIdRequest | None = None,
) -> CatalogTestLlmProviderResponse:
"""Test an existing LLM provider connectivity by its ID.

Args:
llm_provider_id: LLM provider identifier
request: Optional override request body

Returns:
CatalogTestLlmProviderResponse: Test result
"""
kwargs: dict[str, Any] = {"_check_return_type": False}
if request is not None:
kwargs["test_llm_provider_by_id_request"] = request.to_api()
response = self._actions_api.test_llm_provider_by_id(llm_provider_id, **kwargs)
return CatalogTestLlmProviderResponse.from_api(response)

def list_llm_provider_models(
self, request: CatalogListLlmProviderModelsRequest
) -> CatalogListLlmProviderModelsResponse:
"""List models available on an LLM provider with a full definition.

Args:
request: Request with provider config

Returns:
CatalogListLlmProviderModelsResponse: Available models
"""
response = self._actions_api.list_llm_provider_models(request.to_api(), _check_return_type=False)
return CatalogListLlmProviderModelsResponse.from_api(response)

def list_llm_provider_models_by_id(
self,
llm_provider_id: str,
request: CatalogListLlmProviderModelsRequest | None = None,
) -> CatalogListLlmProviderModelsResponse:
"""List models available on an existing LLM provider by its ID.

Args:
llm_provider_id: LLM provider identifier
request: Optional request body (not used by the API but kept for symmetry)

Returns:
CatalogListLlmProviderModelsResponse: Available models
"""
kwargs: dict[str, Any] = {"_check_return_type": False}
response = self._actions_api.list_llm_provider_models_by_id(llm_provider_id, **kwargs)
return CatalogListLlmProviderModelsResponse.from_api(response)

# Layout APIs

def get_declarative_notification_channels(self) -> list[CatalogDeclarativeNotificationChannel]:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# (C) 2026 GoodData Corporation
from __future__ import annotations

from typing import Any

from attr import define
from gooddata_api_client.model.generate_title_request import GenerateTitleRequest
from gooddata_api_client.model.generate_title_response import GenerateTitleResponse

from gooddata_sdk.catalog.base import Base
from gooddata_sdk.utils import safeget


@define(kw_only=True)
class CatalogGenerateTitleRequest(Base):
"""Request for generating a title for an analytics object."""

object_id: str
object_type: str

@staticmethod
def client_class() -> type[GenerateTitleRequest]:
return GenerateTitleRequest

def to_api(self) -> GenerateTitleRequest:
return GenerateTitleRequest(
object_id=self.object_id,
object_type=self.object_type,
)


@define(kw_only=True)
class CatalogGenerateTitleResponse(Base):
"""Response from the generate title endpoint."""

title: str
note: str | None = None

@staticmethod
def client_class() -> type[GenerateTitleResponse]:
return GenerateTitleResponse

@classmethod
def from_api(cls, data: dict[str, Any]) -> CatalogGenerateTitleResponse:
return cls(
title=safeget(data, ["title"]) or "",
note=safeget(data, ["note"]),
)
Loading
Loading