Skip to content
Open
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
350 changes: 350 additions & 0 deletions langfuse/api/llm_connections/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,169 @@ def delete(
_response = self._raw_client.delete(id, request_options=request_options)
return _response.data

def list_organization(
self,
*,
page: typing.Optional[int] = None,
limit: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> PaginatedLlmConnections:
"""
Get all organization-level LLM connections. Requires an organization-scoped API key.

Parameters
----------
page : typing.Optional[int]
page number, starts at 1

limit : typing.Optional[int]
limit of items per page

request_options : typing.Optional[RequestOptions]
Request-specific configuration.

Returns
-------
PaginatedLlmConnections

Examples
--------
from langfuse import LangfuseAPI

client = LangfuseAPI(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
client.llm_connections.list_organization()
"""
_response = self._raw_client.list_organization(
page=page, limit=limit, request_options=request_options
)
return _response.data

def upsert_organization(
self,
*,
provider: str,
adapter: LlmAdapter,
secret_key: str,
base_url: typing.Optional[str] = OMIT,
custom_models: typing.Optional[typing.Sequence[str]] = OMIT,
with_default_models: typing.Optional[bool] = OMIT,
extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT,
config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> LlmConnection:
"""
Create or update an organization-level LLM connection. The connection is upserted on provider and inherited by projects without a provider override. Requires an organization-scoped API key.

Parameters
----------
provider : str
Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting.

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 Provider scope is unclear

The new upsert_organization documentation says provider must be unique in a project, although this method updates a connection shared across the organization. Users get conflicting guidance about which connection a repeated provider name updates.

Change this to organization-wide uniqueness in both clients and their raw counterparts.

Prompt To Fix With AI
This is a comment left during a code review.
Path: langfuse/api/llm_connections/client.py
Line: 256

Comment:
**Provider scope is unclear**

The new `upsert_organization` documentation says `provider` must be unique in a project, although this method updates a connection shared across the organization. Users get conflicting guidance about which connection a repeated provider name updates.

Change this to organization-wide uniqueness in both clients and their raw counterparts.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!


adapter : LlmAdapter
The adapter used to interface with the LLM

secret_key : str
Secret key for the LLM API.

base_url : typing.Optional[str]
Custom base URL for the LLM API

custom_models : typing.Optional[typing.Sequence[str]]
List of custom model names

with_default_models : typing.Optional[bool]
Whether to include default models. Default is true.

extra_headers : typing.Optional[typing.Dict[str, str]]
Extra headers to send with requests

config : typing.Optional[typing.Dict[str, typing.Any]]
Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": "<aws-region>"}` (e.g., `{"region":"us-east-1"}`) - **OpenAI**: Optional. If provided, must be `{"useResponsesApi": <boolean>}` to control whether Langfuse routes calls through OpenAI's Responses API. - **VertexAI**: Optional. If provided, must be `{"location": "<gcp-location>"}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null.

request_options : typing.Optional[RequestOptions]
Request-specific configuration.

Returns
-------
LlmConnection

Examples
--------
from langfuse import LangfuseAPI
from langfuse.llm_connections import LlmAdapter
Comment on lines +288 to +289

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 New examples fail to import

The new examples import LangfuseAPI and AsyncLangfuseAPI from langfuse, but those classes are exported from langfuse.api. The upsert examples also import LlmAdapter from the nonexistent langfuse.llm_connections package. Copying these examples fails before sending a request.

Use from langfuse.api import LangfuseAPI (or AsyncLangfuseAPI) and from langfuse.api.llm_connections import LlmAdapter throughout the new examples.

Prompt To Fix With AI
This is a comment left during a code review.
Path: langfuse/api/llm_connections/client.py
Line: 288-289

Comment:
**New examples fail to import**

The new examples import `LangfuseAPI` and `AsyncLangfuseAPI` from `langfuse`, but those classes are exported from `langfuse.api`. The upsert examples also import `LlmAdapter` from the nonexistent `langfuse.llm_connections` package. Copying these examples fails before sending a request.

Use `from langfuse.api import LangfuseAPI` (or `AsyncLangfuseAPI`) and `from langfuse.api.llm_connections import LlmAdapter` throughout the new examples.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.


client = LangfuseAPI(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
client.llm_connections.upsert_organization(
provider="provider",
adapter=LlmAdapter.ANTHROPIC,
secret_key="secretKey",
)
"""
_response = self._raw_client.upsert_organization(
provider=provider,
adapter=adapter,
secret_key=secret_key,
base_url=base_url,
custom_models=custom_models,
with_default_models=with_default_models,
extra_headers=extra_headers,
config=config,
request_options=request_options,
)
return _response.data

def delete_organization(
self, id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> DeleteLlmConnectionResponse:
"""
Delete an organization-level LLM connection by id. Evaluators in projects without an override for the provider are automatically paused. Requires an organization-scoped API key.

Parameters
----------
id : str

request_options : typing.Optional[RequestOptions]
Request-specific configuration.

Returns
-------
DeleteLlmConnectionResponse

Examples
--------
from langfuse import LangfuseAPI

client = LangfuseAPI(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)
client.llm_connections.delete_organization(
id="id",
)
"""
_response = self._raw_client.delete_organization(
id, request_options=request_options
)
return _response.data


class AsyncLlmConnectionsClient:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
Expand Down Expand Up @@ -390,3 +553,190 @@ async def main() -> None:
"""
_response = await self._raw_client.delete(id, request_options=request_options)
return _response.data

async def list_organization(
self,
*,
page: typing.Optional[int] = None,
limit: typing.Optional[int] = None,
request_options: typing.Optional[RequestOptions] = None,
) -> PaginatedLlmConnections:
"""
Get all organization-level LLM connections. Requires an organization-scoped API key.

Parameters
----------
page : typing.Optional[int]
page number, starts at 1

limit : typing.Optional[int]
limit of items per page

request_options : typing.Optional[RequestOptions]
Request-specific configuration.

Returns
-------
PaginatedLlmConnections

Examples
--------
import asyncio

from langfuse import AsyncLangfuseAPI

client = AsyncLangfuseAPI(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)


async def main() -> None:
await client.llm_connections.list_organization()


asyncio.run(main())
"""
_response = await self._raw_client.list_organization(
page=page, limit=limit, request_options=request_options
)
return _response.data

async def upsert_organization(
self,
*,
provider: str,
adapter: LlmAdapter,
secret_key: str,
base_url: typing.Optional[str] = OMIT,
custom_models: typing.Optional[typing.Sequence[str]] = OMIT,
with_default_models: typing.Optional[bool] = OMIT,
extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT,
config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
) -> LlmConnection:
"""
Create or update an organization-level LLM connection. The connection is upserted on provider and inherited by projects without a provider override. Requires an organization-scoped API key.

Parameters
----------
provider : str
Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting.

adapter : LlmAdapter
The adapter used to interface with the LLM

secret_key : str
Secret key for the LLM API.

base_url : typing.Optional[str]
Custom base URL for the LLM API

custom_models : typing.Optional[typing.Sequence[str]]
List of custom model names

with_default_models : typing.Optional[bool]
Whether to include default models. Default is true.

extra_headers : typing.Optional[typing.Dict[str, str]]
Extra headers to send with requests

config : typing.Optional[typing.Dict[str, typing.Any]]
Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": "<aws-region>"}` (e.g., `{"region":"us-east-1"}`) - **OpenAI**: Optional. If provided, must be `{"useResponsesApi": <boolean>}` to control whether Langfuse routes calls through OpenAI's Responses API. - **VertexAI**: Optional. If provided, must be `{"location": "<gcp-location>"}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null.

request_options : typing.Optional[RequestOptions]
Request-specific configuration.

Returns
-------
LlmConnection

Examples
--------
import asyncio

from langfuse import AsyncLangfuseAPI
from langfuse.llm_connections import LlmAdapter

client = AsyncLangfuseAPI(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)


async def main() -> None:
await client.llm_connections.upsert_organization(
provider="provider",
adapter=LlmAdapter.ANTHROPIC,
secret_key="secretKey",
)


asyncio.run(main())
"""
_response = await self._raw_client.upsert_organization(
provider=provider,
adapter=adapter,
secret_key=secret_key,
base_url=base_url,
custom_models=custom_models,
with_default_models=with_default_models,
extra_headers=extra_headers,
config=config,
request_options=request_options,
)
return _response.data

async def delete_organization(
self, id: str, *, request_options: typing.Optional[RequestOptions] = None
) -> DeleteLlmConnectionResponse:
"""
Delete an organization-level LLM connection by id. Evaluators in projects without an override for the provider are automatically paused. Requires an organization-scoped API key.

Parameters
----------
id : str

request_options : typing.Optional[RequestOptions]
Request-specific configuration.

Returns
-------
DeleteLlmConnectionResponse

Examples
--------
import asyncio

from langfuse import AsyncLangfuseAPI

client = AsyncLangfuseAPI(
x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME",
x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION",
x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY",
username="YOUR_USERNAME",
password="YOUR_PASSWORD",
base_url="https://yourhost.com/path/to/api",
)


async def main() -> None:
await client.llm_connections.delete_organization(
id="id",
)


asyncio.run(main())
"""
_response = await self._raw_client.delete_organization(
id, request_options=request_options
)
return _response.data
Loading
Loading