Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extend coverage of API #326

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e86dc3c
feat: add fetchScores method to LangfuseCoreStateless class
RichardKruemmel Aug 1, 2024
376712c
chore: Add types for fetching Langfuse scores API endpoint
RichardKruemmel Aug 1, 2024
628a175
feat: add test for creating and fetching scores in Langfuse Node.js i…
RichardKruemmel Aug 1, 2024
a6f8893
fix: update expect assertion in Langfuse Node.js integration test
RichardKruemmel Aug 1, 2024
f35c15a
feat: add test for creating and fetching prompts in Langfuse Node.js …
RichardKruemmel Aug 1, 2024
9525a21
feat: add fetchPrompts method to LangfuseCoreStateless class
RichardKruemmel Aug 1, 2024
9e28453
chore: Add types for fetching Langfuse prompts API endpoint
RichardKruemmel Aug 1, 2024
b6ae6fa
chore: Update Langfuse integration test to fetch prompts without spec…
RichardKruemmel Aug 1, 2024
edf042b
refactor: update LangfuseCoreStateless fetchPrompts method to use v2 …
RichardKruemmel Aug 1, 2024
1b05203
feat: add multiple prompts creation and fetching in Langfuse Node.js …
RichardKruemmel Aug 1, 2024
a8641a9
feat: add getDatasetItems method to LangfuseCoreStateless class
RichardKruemmel Aug 1, 2024
a3c1a84
feat: add create and fetch dataset items in Langfuse Node.js integrat…
RichardKruemmel Aug 1, 2024
8adcc27
refactor: Update LangfuseCoreStateless fetchPrompts method to use v2 …
RichardKruemmel Aug 1, 2024
d47a5ac
refactor: Update LangfuseCoreStateless fetchPrompts method to use v2 …
RichardKruemmel Aug 1, 2024
a708d08
refactor: Remove unnecessary code in Langfuse Node.js integration test
RichardKruemmel Aug 1, 2024
29c611a
refactor: Update Langfuse integration test to use v2 API endpoint for…
RichardKruemmel Aug 1, 2024
14e8256
refactor: Update getDatasets method in LangfuseCore to accept optiona…
RichardKruemmel Aug 1, 2024
dd15bfd
refactor: Update Langfuse integration test to use getDatasetItems met…
RichardKruemmel Aug 1, 2024
00f6b3e
refactor: Update getDatasetItems method in LangfuseCoreStateless clas…
RichardKruemmel Aug 1, 2024
e29019a
refactor: Update Langfuse integration test to use getDatasetItems met…
RichardKruemmel Aug 1, 2024
4029b73
refactor: Update Langfuse integration test to use getDatasetItems met…
RichardKruemmel Aug 1, 2024
961c1b1
refactor: Update Langfuse integration test to use getDatasetItems met…
RichardKruemmel Aug 1, 2024
54873ba
refactor: Update Langfuse integration test to use getDatasetItems met…
RichardKruemmel Aug 1, 2024
65cf038
refactor: Update Langfuse integration test to use getDatasetItems met…
RichardKruemmel Aug 1, 2024
83bacd2
fix: remove console.log
RichardKruemmel Aug 2, 2024
342fd62
Merge branch 'main' into richard/lfe-1312
RichardKruemmel Aug 2, 2024
fce8297
feat: Add GetLangfuseScoreResponse type definition
RichardKruemmel Aug 2, 2024
11c6268
feat: Add fetchScore method to LangfuseCoreStateless class
RichardKruemmel Aug 2, 2024
4bb583c
feat: Add create and fetch score by id integration test
RichardKruemmel Aug 2, 2024
730a63a
feat: Add create and fetch scores integration tests
RichardKruemmel Aug 2, 2024
583de1a
refactor: Rearrange score variables in Langfuse integration test
RichardKruemmel Aug 2, 2024
c1751cb
refactor: Rearrange score variables in Langfuse integration test
RichardKruemmel Aug 2, 2024
f651ffb
refactor: Rearrange score variables in Langfuse integration test
RichardKruemmel Aug 2, 2024
c945abd
feat: Add console log for fetched score in Langfuse integration test
RichardKruemmel Aug 2, 2024
304811b
refactor: Update assertion in Langfuse integration test for fetched s…
RichardKruemmel Aug 2, 2024
d93f985
refactor: Rearrange score variables in Langfuse integration test
RichardKruemmel Aug 2, 2024
bada350
refactor: Rearrange score variables and update assertion in Langfuse …
RichardKruemmel Aug 2, 2024
2a6ee06
refactor: Rearrange score variables and update assertion in Langfuse …
RichardKruemmel Aug 2, 2024
064a4e5
Merge branch 'main' into richard/lfe-1312
RichardKruemmel Aug 20, 2024
0729e45
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
f7a249e
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
8b1c512
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
2cc5fd1
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
481a199
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
79365b8
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
69881c7
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
80c7fc6
Refactor score data retrieval URL in LangfuseCoreStateless class
RichardKruemmel Aug 20, 2024
9006b3d
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
ca3c24d
Refactor score data retrieval in langfuse-integration-node.spec.ts
RichardKruemmel Aug 20, 2024
15a08f9
Merge branch 'main' into richard/lfe-1312
RichardKruemmel Aug 26, 2024
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
70 changes: 70 additions & 0 deletions integration-test/langfuse-integration-datasets.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// uses the compiled node.js version, run yarn build after making changes to the SDKs
import { utils } from "../langfuse-core/src";
import Langfuse from "../langfuse-node";

describe("Langfuse Node.js", () => {
Expand Down Expand Up @@ -324,4 +325,73 @@ describe("Langfuse Node.js", () => {
});
}, 10000);
});
it("create and fetch dataset items", async () => {
const datasetName = utils.generateUUID();
langfuse.createDataset({
name: datasetName,
description: "My first dataset",
metadata: {
author: "Alice",
date: "2022-01-01",
type: "benchmark",
},
});
langfuse.createDatasetItem({
datasetName: datasetName,
input: {
text: "hello world",
},
expectedOutput: {
text: "hello world",
},
metadata: {
model: "llama3",
},
});
langfuse.createDatasetItem({
datasetName: datasetName,
input: {
text: "goodbye world",
},
expectedOutput: {
text: "goodbye world",
},
metadata: {
model: "llama4",
},
});

await langfuse.flushAsync();

const datasetItems = await langfuse.getDatasetItems({ datasetName: datasetName });

expect(datasetItems.meta["totalItems"]).toEqual(2);
expect(datasetItems.data[0]).toMatchObject({ datasetName: datasetName });
expect(datasetItems.data[1]).toMatchObject({ datasetName: datasetName });
});

it("create and fetch datasets", async () => {
const datasetName1 = utils.generateUUID();
const datasetName2 = utils.generateUUID();
const datasetName3 = utils.generateUUID();

// Create multiple datasets
langfuse.createDataset({
name: datasetName1,
description: "My first dataset",
});
langfuse.createDataset({
name: datasetName2,
description: "My second dataset",
});
langfuse.createDataset({
name: datasetName3,
description: "My third dataset",
});

const datasets = await langfuse.getDatasets();
expect(datasets.data).toContainEqual(expect.objectContaining({ name: datasetName1 }));
expect(datasets.data).toContainEqual(expect.objectContaining({ name: datasetName2 }));
expect(datasets.data).toContainEqual(expect.objectContaining({ name: datasetName3 }));
});
});
110 changes: 110 additions & 0 deletions integration-test/langfuse-integration-node.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Langfuse from "../langfuse-node";
import axios from "axios";
import { LANGFUSE_BASEURL, getHeaders } from "./integration-utils";
import { utils } from "../langfuse-core/src";
import exp from "constants";

describe("Langfuse Node.js", () => {
let langfuse: Langfuse;
Expand Down Expand Up @@ -551,6 +552,71 @@ describe("Langfuse Node.js", () => {
});
});

it("create and fetch scores", async () => {
const traceName = utils.generateUUID();
const trace = langfuse.trace({
name: traceName,
});
const score = trace.score({
name: "quality",
value: 1,
comment: "Factually correct",
});
await langfuse.flushAsync();

const scores = await langfuse.fetchScores({ name: "quality" });
expect(scores.data).toContainEqual(expect.objectContaining({ traceId: score.id, name: "quality" }));
});

it("create and fetch score by id", async () => {
const traceName = utils.generateUUID();
const trace = langfuse.trace({
name: traceName,
});
trace.score({
name: "harmfulness",
value: 0.5,
});
trace.score({
name: "quality",
value: 1,
comment: "Factually correct",
});
trace.score({
name: "relevance",
value: 0.8,
comment: "Mostly relevant",
});

await langfuse.flushAsync();
const scores = await langfuse.fetchScores();
const score1 = scores.data[2];
const score2 = scores.data[1];
const score3 = scores.data[0];
const fetchedScore1 = await langfuse.fetchScore(score1.id);
expect(fetchedScore1.data).toMatchObject(
expect.objectContaining({ traceId: trace.id, name: "harmfulness", value: 0.5 })
);
const fetchedScore2 = await langfuse.fetchScore(score2.id);
expect(fetchedScore2.data).toMatchObject(
expect.objectContaining({
traceId: trace.id,
name: "quality",
value: 1,
comment: "Factually correct",
})
);
const fetchedScore3 = await langfuse.fetchScore(score3.id);
expect(fetchedScore3.data).toMatchObject(
expect.objectContaining({
traceId: trace.id,
name: "relevance",
value: 0.8,
comment: "Mostly relevant",
})
);
});

it("create 3 traces with different timestamps and fetch the middle one using to and from timestamp", async () => {
const traceName = utils.generateUUID();
const traceParams = [
Expand Down Expand Up @@ -627,4 +693,48 @@ describe("Langfuse Node.js", () => {
const sessions = await langfuse.fetchSessions();
expect(sessions.data).toContainEqual(expect.objectContaining({ id: sessionId }));
});

it("create and fetch prompts", async () => {
RichardKruemmel marked this conversation as resolved.
Show resolved Hide resolved
const promptName1 = utils.generateUUID();
const promptName2 = utils.generateUUID();
const promptName3 = utils.generateUUID();

// Create multiple prompts
await langfuse.createPrompt({
name: promptName1,
prompt: "This is prompt 1",
});
await langfuse.createPrompt({
name: promptName2,
prompt: "This is prompt 2",
});
await langfuse.createPrompt({
name: promptName3,
prompt: "This is prompt 3",
});

// Create multiple versions of the same prompt
await langfuse.createPrompt({
name: promptName1,
prompt: "This is prompt 1 version 2",
});
await langfuse.createPrompt({
name: promptName1,
prompt: "This is prompt 1 version 3",
});

const prompts = await langfuse.fetchPrompts();
expect(prompts.data).toContainEqual(expect.objectContaining({ name: promptName1 }));
expect(prompts.data).toContainEqual(expect.objectContaining({ name: promptName2 }));
expect(prompts.data).toContainEqual(expect.objectContaining({ name: promptName3 }));

// Fetch specific versions of the prompt
const prompt1Version1 = await langfuse.getPrompt(promptName1, 1);
const prompt1Version2 = await langfuse.getPrompt(promptName1, 2);
const prompt1Version3 = await langfuse.getPrompt(promptName1, 3);

expect(prompt1Version1.prompt).toEqual("This is prompt 1");
expect(prompt1Version2.prompt).toEqual("This is prompt 1 version 2");
expect(prompt1Version3.prompt).toEqual("This is prompt 1 version 3");
});
});
51 changes: 51 additions & 0 deletions langfuse-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ import {
type ChatMessage,
type GetLangfuseSessionsQuery,
type GetLangfuseSessionsResponse,
type GetLangfuseScoresQuery,
type GetLangfuseScoresResponse,
type GetLangfusePromptsQuery,
type GetLangfusePromptsResponse,
type GetLangfuseDatasetsQuery,
type GetLangfuseDatasetsResponse,
type GetLangfuseScoreResponse,
} from "./types";
import {
generateUUID,
Expand Down Expand Up @@ -339,6 +346,36 @@ abstract class LangfuseCoreStateless {
return { data, meta };
}

async fetchScore(scoreId: string): Promise<{ data: GetLangfuseScoreResponse }> {
const res = await this.fetch(
`${this.baseUrl}/api/public/scores/${scoreId}`,
this._getFetchOptions({ method: "GET" })
);

const score = (await res.json()) as GetLangfuseScoreResponse;
return { data: score };
}

async fetchScores(query?: GetLangfuseScoresQuery): Promise<GetLangfuseScoresResponse> {
const res = await this.fetch(
`${this.baseUrl}/api/public/scores?${encodeQueryParams(query)}`,
this._getFetchOptions({ method: "GET" })
);
// destructure the response into data and meta to be explicit about the shape of the response and add type-warnings in case the API changes
const { data, meta } = (await res.json()) as GetLangfuseScoresResponse;
return { data, meta };
}

async fetchPrompts(query?: GetLangfusePromptsQuery): Promise<GetLangfusePromptsResponse> {
const res = await this.fetch(
`${this.baseUrl}/api/public/v2/prompts?${encodeQueryParams(query)}`,
this._getFetchOptions({ method: "GET" })
);
// destructure the response into data and meta to be explicit about the shape of the response and add type-warnings in case the API changes
const { data, meta } = (await res.json()) as GetLangfusePromptsResponse;
return { data, meta };
}

async getDatasetRun(params: GetLangfuseDatasetRunParams): Promise<GetLangfuseDatasetRunResponse> {
const encodedDatasetName = encodeURIComponent(params.datasetName);
const encodedRunName = encodeURIComponent(params.runName);
Expand Down Expand Up @@ -405,6 +442,13 @@ abstract class LangfuseCoreStateless {
);
}

async getDatasetItems(query?: GetLangfuseDatasetItemsQuery): Promise<GetLangfuseDatasetItemsResponse> {
return this.fetch(
`${this.baseUrl}/api/public/dataset-items?${encodeQueryParams(query)}`,
this._getFetchOptions({ method: "GET" })
).then((res) => res.json());
}

protected _parsePayload(response: any): any {
try {
return JSON.parse(response);
Expand Down Expand Up @@ -874,6 +918,13 @@ export abstract class LangfuseCore extends LangfuseCoreStateless {
return this;
}

async getDatasets(query?: GetLangfuseDatasetsQuery): Promise<GetLangfuseDatasetsResponse> {
return this.fetch(
`${this.baseUrl}/api/public/datasets?${encodeQueryParams(query)}`,
this._getFetchOptions({ method: "GET" })
).then((res) => res.json());
}

async getDataset(
name: string,
options?: {
Expand Down
15 changes: 15 additions & 0 deletions langfuse-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,27 @@ export type GetLangfuseSessionsQuery = FixTypes<paths["/api/public/sessions"]["g
export type GetLangfuseSessionsResponse = FixTypes<
paths["/api/public/sessions"]["get"]["responses"]["200"]["content"]["application/json"]
>;
export type GetLangfuseScoreResponse = FixTypes<
paths["/api/public/scores/{scoreId}"]["get"]["responses"]["200"]["content"]["application/json"]
>;
export type GetLangfuseScoresQuery = FixTypes<paths["/api/public/scores"]["get"]["parameters"]["query"]>;
export type GetLangfuseScoresResponse = FixTypes<
paths["/api/public/scores"]["get"]["responses"]["200"]["content"]["application/json"]
>;
export type GetLangfusePromptsQuery = FixTypes<paths["/api/public/v2/prompts"]["get"]["parameters"]["query"]>;
export type GetLangfusePromptsResponse = FixTypes<
paths["/api/public/v2/prompts"]["get"]["responses"]["200"]["content"]["application/json"]
>;
export type GetLangfuseDatasetParams = FixTypes<
paths["/api/public/v2/datasets/{datasetName}"]["get"]["parameters"]["path"]
>;
export type GetLangfuseDatasetResponse = FixTypes<
paths["/api/public/v2/datasets/{datasetName}"]["get"]["responses"]["200"]["content"]["application/json"]
>;
export type GetLangfuseDatasetsQuery = FixTypes<paths["/api/public/v2/datasets"]["get"]["parameters"]["query"]>;
export type GetLangfuseDatasetsResponse = FixTypes<
paths["/api/public/v2/datasets"]["get"]["responses"]["200"]["content"]["application/json"]
>;
export type GetLangfuseDatasetItemsQuery = paths["/api/public/dataset-items"]["get"]["parameters"]["query"];
export type GetLangfuseDatasetItemsResponse = FixTypes<
paths["/api/public/dataset-items"]["get"]["responses"]["200"]["content"]["application/json"]
Expand Down
Loading