Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions packages/gooddata-sdk/src/gooddata_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
CatalogRsaSpecification,
)
from gooddata_sdk.catalog.organization.entity_model.llm_provider import (
CatalogAnthropicApiKeyAuth,
CatalogAnthropicProviderConfig,
CatalogAwsBedrockProviderConfig,
CatalogAzureFoundryApiKeyAuth,
CatalogAzureFoundryProviderConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ def client_class() -> type[AzureFoundryProviderAuth]:

CatalogAzureFoundryAuth = Union[CatalogAzureFoundryApiKeyAuth]

# --- Anthropic auth ---


@define(kw_only=True)
class CatalogAnthropicApiKeyAuth(Base):
"""API key authentication for the Anthropic provider."""

api_key: str | None = None
type: str = "API_KEY"


CatalogAnthropicAuth = Union[CatalogAnthropicApiKeyAuth]

# --- Provider config types ---


Expand Down Expand Up @@ -118,10 +131,20 @@ def client_class() -> type[AzureFoundryProviderConfig]:
return AzureFoundryProviderConfig


@define(kw_only=True)
class CatalogAnthropicProviderConfig(Base):
"""Anthropic provider configuration."""

auth: CatalogAnthropicAuth | None = None
base_url: str | None = None
type: str = "ANTHROPIC"


CatalogLlmProviderConfig = Union[
CatalogOpenAiProviderConfig,
CatalogAwsBedrockProviderConfig,
CatalogAzureFoundryProviderConfig,
CatalogAnthropicProviderConfig,
]


Expand Down Expand Up @@ -157,6 +180,16 @@ def _azure_foundry_auth_from_api(data: dict[str, Any]) -> CatalogAzureFoundryAut
raise ValueError(f"Unknown Azure Foundry auth type: {auth_type}")


def _anthropic_auth_from_api(data: dict[str, Any]) -> CatalogAnthropicAuth:
auth_type = safeget(data, ["type"]) or "API_KEY"
if auth_type == "API_KEY":
return CatalogAnthropicApiKeyAuth(
api_key="", # Credentials are not returned for security reasons
type=auth_type,
)
raise ValueError(f"Unknown Anthropic auth type: {auth_type}")


def _provider_config_from_api(data: dict[str, Any]) -> CatalogLlmProviderConfig:
provider_type = safeget(data, ["type"]) or "OPENAI"
auth_data = safeget(data, ["auth"])
Expand All @@ -173,6 +206,12 @@ def _provider_config_from_api(data: dict[str, Any]) -> CatalogLlmProviderConfig:
endpoint=safeget(data, ["endpoint"]),
)

if provider_type == "ANTHROPIC":
return CatalogAnthropicProviderConfig(
auth=_anthropic_auth_from_api(auth_data) if auth_data is not None else None,
base_url=safeget(data, ["baseUrl"]),
)

# Default: OpenAI
return CatalogOpenAiProviderConfig(
auth=_openai_auth_from_api(auth_data) if auth_data is not None else None,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
interactions:
- request:
body: null
headers:
Accept-Encoding:
- br, gzip, deflate
X-GDC-VALIDATE-RELATIONS:
- 'true'
X-Requested-With:
- XMLHttpRequest
method: DELETE
uri: http://localhost:3000/api/v1/entities/llmProviders/test-anthropic-provider
response:
body:
string: ''
headers:
Content-Type:
- application/vnd.gooddata.api+json
DATE: &id001
- PLACEHOLDER
Expires:
- '0'
Pragma:
- no-cache
X-Content-Type-Options:
- nosniff
X-GDC-TRACE-ID: *id001
status:
code: 204
message: No Content
- request:
body: null
headers:
Accept-Encoding:
- br, gzip, deflate
X-GDC-VALIDATE-RELATIONS:
- 'true'
X-Requested-With:
- XMLHttpRequest
method: DELETE
uri: http://localhost:3000/api/v1/entities/llmProviders/test-anthropic-provider
response:
body:
string: ''
headers:
Content-Type:
- application/vnd.gooddata.api+json
DATE: *id001
Expires:
- '0'
Pragma:
- no-cache
X-Content-Type-Options:
- nosniff
X-GDC-TRACE-ID: *id001
status:
code: 204
message: No Content
version: 1
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@

from gooddata_api_client.exceptions import NotFoundException
from gooddata_sdk import (
CatalogAnthropicApiKeyAuth,
CatalogAnthropicProviderConfig,
CatalogCspDirective,
CatalogDeclarativeNotificationChannel,
CatalogJwk,
CatalogLlmProvider,
CatalogLlmProviderModel,
CatalogOrganization,
CatalogOrganizationSetting,
CatalogRsaSpecification,
Expand Down Expand Up @@ -563,3 +567,30 @@ def test_layout_notification_channels(test_config, snapshot_notification_channel
# sdk.catalog_organization.put_declarative_identity_providers([])
# idps = sdk.catalog_organization.get_declarative_identity_providers()
# assert len(idps) == 0


@gd_vcr.use_cassette(str(_fixtures_dir / "test_create_llm_provider_anthropic.yaml"))
def test_create_llm_provider_anthropic(test_config):
"""Verify that an Anthropic LLM provider can be created, retrieved and deleted."""
sdk = GoodDataSdk.create(host_=test_config["host"], token_=test_config["token"])

provider_id = "test-anthropic-provider"
provider = CatalogLlmProvider.init(
id=provider_id,
models=[CatalogLlmProviderModel(id="claude-3-5-sonnet-20241022", family="ANTHROPIC")],
provider_config=CatalogAnthropicProviderConfig(
auth=CatalogAnthropicApiKeyAuth(api_key="test-api-key"),
),
name="Test Anthropic Provider",
)

try:
created = sdk.catalog_organization.create_llm_provider(provider)
assert created.id == provider_id
retrieved = sdk.catalog_organization.get_llm_provider(provider_id)
assert retrieved.id == provider_id
assert retrieved.attributes is not None
assert isinstance(retrieved.attributes.provider_config, CatalogAnthropicProviderConfig)
assert retrieved.attributes.provider_config.type == "ANTHROPIC"
finally:
safe_delete(sdk.catalog_organization.delete_llm_provider, provider_id)
Loading