Skip to content
Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Langfuse API credentials for integration tests.
# Copy this file to .env and fill in your values.
#
# Required prompts in the Langfuse project:
# - "test-chat-prompt" : chat type, at least one message with role + content
# - "test-text-prompt" : text type, non-empty prompt text
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://cloud.langfuse.com
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ build/
.vscode/

### Mac OS ###
.DS_Store
.DS_Store

### Environment ###
.env
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,41 @@ try {
}
```

## Testing

### Unit tests

Unit tests (deserialization, query string mapping) run without any credentials:

```bash
mvn test
```

### Integration tests

Integration tests connect to a real Langfuse project. They require credentials and are excluded from `mvn test`.

1. Copy `.env.example` to `.env` and fill in your API keys:
```bash
cp .env.example .env
```

2. Ensure your Langfuse project contains the following prompts:
- `test-chat-prompt` — chat type, at least one message with `role` and `content`
- `test-text-prompt` — text type, non-empty prompt text

3. Run all tests (unit + integration):
```bash
mvn verify
```

Or run only integration tests:
```bash
mvn failsafe:integration-test
```

Integration tests skip gracefully when credentials are absent.

## Drafting a Release

Run `./mvnw release:prepare -DreleaseVersion=` with the version you want to create.
Expand Down Expand Up @@ -78,6 +113,6 @@ To publish to Maven Central, you need to configure the following secrets in your
```
3. Generate the new client code using `npx fern-api generate --api server`.
4. Manually set the `package` across all files to `com.langfuse.client`.
5. Overwrite `this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + encodedToken);` to `Basic` in LangfuseClientBuilder.java.
5. Overwrite `this.clientOptionsBuilder.addHeader("Authorization", "Basic " + encodedToken);` to `Basic` in com.langfuse.client.LangfuseClientBuilder.java.
6. Adjust Javadoc strings with HTML properties as the apidocs package does not support them.
7. Commit the changes in langfuse-java and push them to the repository.
55 changes: 55 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,37 @@
</execution>
</executions>
</plugin>

<!-- Surefire: runs unit tests (mvn test), excludes integration -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<excludedGroups>integration</excludedGroups>
</configuration>
</plugin>

<!-- Failsafe: runs integration tests (mvn verify) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<groups>integration</groups>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Expand Down Expand Up @@ -157,5 +188,29 @@
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
</dependency>

<!-- JUnit Jupiter Engine (required to run tests) -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<!-- AssertJ -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.25.3</version>
<scope>test</scope>
</dependency>

<!-- dotenv-java for loading .env files -->
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>3.0.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
8 changes: 8 additions & 0 deletions src/main/java/com/langfuse/client/.fern/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"cliVersion": "3.88.0",
"generatorName": "fernapi/fern-java-sdk",
"generatorVersion": "3.38.1",
"generatorConfig": {
"client-class-name": "LangfuseClient"
}
}
227 changes: 227 additions & 0 deletions src/main/java/com/langfuse/client/AsyncLangfuseClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
package com.langfuse.client; /**
* This file was auto-generated by Fern from our API Definition.
*/

import com.langfuse.client.core.ClientOptions;
import com.langfuse.client.core.Suppliers;
import java.util.function.Supplier;
import com.langfuse.client.resources.annotationqueues.AsyncAnnotationQueuesClient;
import com.langfuse.client.resources.blobstorageintegrations.AsyncBlobStorageIntegrationsClient;
import com.langfuse.client.resources.comments.AsyncCommentsClient;
import com.langfuse.client.resources.datasetitems.AsyncDatasetItemsClient;
import com.langfuse.client.resources.datasetrunitems.AsyncDatasetRunItemsClient;
import com.langfuse.client.resources.datasets.AsyncDatasetsClient;
import com.langfuse.client.resources.health.AsyncHealthClient;
import com.langfuse.client.resources.ingestion.AsyncIngestionClient;
import com.langfuse.client.resources.llmconnections.AsyncLlmConnectionsClient;
import com.langfuse.client.resources.media.AsyncMediaClient;
import com.langfuse.client.resources.metrics.AsyncMetricsClient;
import com.langfuse.client.resources.metricsv2.AsyncMetricsV2Client;
import com.langfuse.client.resources.models.AsyncModelsClient;
import com.langfuse.client.resources.observations.AsyncObservationsClient;
import com.langfuse.client.resources.observationsv2.AsyncObservationsV2Client;
import com.langfuse.client.resources.opentelemetry.AsyncOpentelemetryClient;
import com.langfuse.client.resources.organizations.AsyncOrganizationsClient;
import com.langfuse.client.resources.projects.AsyncProjectsClient;
import com.langfuse.client.resources.prompts.AsyncPromptsClient;
import com.langfuse.client.resources.promptversion.AsyncPromptVersionClient;
import com.langfuse.client.resources.scim.AsyncScimClient;
import com.langfuse.client.resources.score.AsyncScoreClient;
import com.langfuse.client.resources.scoreconfigs.AsyncScoreConfigsClient;
import com.langfuse.client.resources.scorev2.AsyncScoreV2Client;
import com.langfuse.client.resources.sessions.AsyncSessionsClient;
import com.langfuse.client.resources.trace.AsyncTraceClient;

public class AsyncLangfuseClient {
protected final ClientOptions clientOptions;

protected final Supplier<AsyncAnnotationQueuesClient> annotationQueuesClient;

protected final Supplier<AsyncBlobStorageIntegrationsClient> blobStorageIntegrationsClient;

protected final Supplier<AsyncCommentsClient> commentsClient;

protected final Supplier<AsyncDatasetItemsClient> datasetItemsClient;

protected final Supplier<AsyncDatasetRunItemsClient> datasetRunItemsClient;

protected final Supplier<AsyncDatasetsClient> datasetsClient;

protected final Supplier<AsyncHealthClient> healthClient;

protected final Supplier<AsyncIngestionClient> ingestionClient;

protected final Supplier<AsyncLlmConnectionsClient> llmConnectionsClient;

protected final Supplier<AsyncMediaClient> mediaClient;

protected final Supplier<AsyncMetricsV2Client> metricsV2Client;

protected final Supplier<AsyncMetricsClient> metricsClient;

protected final Supplier<AsyncModelsClient> modelsClient;

protected final Supplier<AsyncObservationsV2Client> observationsV2Client;

protected final Supplier<AsyncObservationsClient> observationsClient;

protected final Supplier<AsyncOpentelemetryClient> opentelemetryClient;

protected final Supplier<AsyncOrganizationsClient> organizationsClient;

protected final Supplier<AsyncProjectsClient> projectsClient;

protected final Supplier<AsyncPromptVersionClient> promptVersionClient;

protected final Supplier<AsyncPromptsClient> promptsClient;

protected final Supplier<AsyncScimClient> scimClient;

protected final Supplier<AsyncScoreConfigsClient> scoreConfigsClient;

protected final Supplier<AsyncScoreV2Client> scoreV2Client;

protected final Supplier<AsyncScoreClient> scoreClient;

protected final Supplier<AsyncSessionsClient> sessionsClient;

protected final Supplier<AsyncTraceClient> traceClient;

public AsyncLangfuseClient(ClientOptions clientOptions) {
this.clientOptions = clientOptions;
this.annotationQueuesClient = Suppliers.memoize(() -> new AsyncAnnotationQueuesClient(clientOptions));
this.blobStorageIntegrationsClient = Suppliers.memoize(() -> new AsyncBlobStorageIntegrationsClient(clientOptions));
this.commentsClient = Suppliers.memoize(() -> new AsyncCommentsClient(clientOptions));
this.datasetItemsClient = Suppliers.memoize(() -> new AsyncDatasetItemsClient(clientOptions));
this.datasetRunItemsClient = Suppliers.memoize(() -> new AsyncDatasetRunItemsClient(clientOptions));
this.datasetsClient = Suppliers.memoize(() -> new AsyncDatasetsClient(clientOptions));
this.healthClient = Suppliers.memoize(() -> new AsyncHealthClient(clientOptions));
this.ingestionClient = Suppliers.memoize(() -> new AsyncIngestionClient(clientOptions));
this.llmConnectionsClient = Suppliers.memoize(() -> new AsyncLlmConnectionsClient(clientOptions));
this.mediaClient = Suppliers.memoize(() -> new AsyncMediaClient(clientOptions));
this.metricsV2Client = Suppliers.memoize(() -> new AsyncMetricsV2Client(clientOptions));
this.metricsClient = Suppliers.memoize(() -> new AsyncMetricsClient(clientOptions));
this.modelsClient = Suppliers.memoize(() -> new AsyncModelsClient(clientOptions));
this.observationsV2Client = Suppliers.memoize(() -> new AsyncObservationsV2Client(clientOptions));
this.observationsClient = Suppliers.memoize(() -> new AsyncObservationsClient(clientOptions));
this.opentelemetryClient = Suppliers.memoize(() -> new AsyncOpentelemetryClient(clientOptions));
this.organizationsClient = Suppliers.memoize(() -> new AsyncOrganizationsClient(clientOptions));
this.projectsClient = Suppliers.memoize(() -> new AsyncProjectsClient(clientOptions));
this.promptVersionClient = Suppliers.memoize(() -> new AsyncPromptVersionClient(clientOptions));
this.promptsClient = Suppliers.memoize(() -> new AsyncPromptsClient(clientOptions));
this.scimClient = Suppliers.memoize(() -> new AsyncScimClient(clientOptions));
this.scoreConfigsClient = Suppliers.memoize(() -> new AsyncScoreConfigsClient(clientOptions));
this.scoreV2Client = Suppliers.memoize(() -> new AsyncScoreV2Client(clientOptions));
this.scoreClient = Suppliers.memoize(() -> new AsyncScoreClient(clientOptions));
this.sessionsClient = Suppliers.memoize(() -> new AsyncSessionsClient(clientOptions));
this.traceClient = Suppliers.memoize(() -> new AsyncTraceClient(clientOptions));
}

public AsyncAnnotationQueuesClient annotationQueues() {
return this.annotationQueuesClient.get();
}

public AsyncBlobStorageIntegrationsClient blobStorageIntegrations() {
return this.blobStorageIntegrationsClient.get();
}

public AsyncCommentsClient comments() {
return this.commentsClient.get();
}

public AsyncDatasetItemsClient datasetItems() {
return this.datasetItemsClient.get();
}

public AsyncDatasetRunItemsClient datasetRunItems() {
return this.datasetRunItemsClient.get();
}

public AsyncDatasetsClient datasets() {
return this.datasetsClient.get();
}

public AsyncHealthClient health() {
return this.healthClient.get();
}

public AsyncIngestionClient ingestion() {
return this.ingestionClient.get();
}

public AsyncLlmConnectionsClient llmConnections() {
return this.llmConnectionsClient.get();
}

public AsyncMediaClient media() {
return this.mediaClient.get();
}

public AsyncMetricsV2Client metricsV2() {
return this.metricsV2Client.get();
}

public AsyncMetricsClient metrics() {
return this.metricsClient.get();
}

public AsyncModelsClient models() {
return this.modelsClient.get();
}

public AsyncObservationsV2Client observationsV2() {
return this.observationsV2Client.get();
}

public AsyncObservationsClient observations() {
return this.observationsClient.get();
}

public AsyncOpentelemetryClient opentelemetry() {
return this.opentelemetryClient.get();
}

public AsyncOrganizationsClient organizations() {
return this.organizationsClient.get();
}

public AsyncProjectsClient projects() {
return this.projectsClient.get();
}

public AsyncPromptVersionClient promptVersion() {
return this.promptVersionClient.get();
}

public AsyncPromptsClient prompts() {
return this.promptsClient.get();
}

public AsyncScimClient scim() {
return this.scimClient.get();
}

public AsyncScoreConfigsClient scoreConfigs() {
return this.scoreConfigsClient.get();
}

public AsyncScoreV2Client scoreV2() {
return this.scoreV2Client.get();
}

public AsyncScoreClient score() {
return this.scoreClient.get();
}

public AsyncSessionsClient sessions() {
return this.sessionsClient.get();
}

public AsyncTraceClient trace() {
return this.traceClient.get();
}

public static AsyncLangfuseClientBuilder builder() {
return new AsyncLangfuseClientBuilder();
}
}
Loading