@langfuse/core 5.5.3 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +220 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +232 -9
- package/dist/index.d.ts +232 -9
- package/dist/index.mjs +217 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
CommentObjectType: () => CommentObjectType,
|
|
35
35
|
CreateChatPromptType: () => CreateChatPromptType,
|
|
36
36
|
CreateTextPromptType: () => CreateTextPromptType,
|
|
37
|
+
DatasetItemMediaReferenceField: () => DatasetItemMediaReferenceField,
|
|
37
38
|
DatasetStatus: () => DatasetStatus,
|
|
38
39
|
Error: () => Error2,
|
|
39
40
|
LANGFUSE_SDK_EXPERIMENT_ENVIRONMENT: () => LANGFUSE_SDK_EXPERIMENT_ENVIRONMENT,
|
|
@@ -45,6 +46,7 @@ __export(index_exports, {
|
|
|
45
46
|
LangfuseAPIError: () => LangfuseAPIError,
|
|
46
47
|
LangfuseAPITimeoutError: () => LangfuseAPITimeoutError,
|
|
47
48
|
LangfuseMedia: () => LangfuseMedia,
|
|
49
|
+
LangfuseMediaReference: () => LangfuseMediaReference,
|
|
48
50
|
LangfuseOtelContextKeys: () => LangfuseOtelContextKeys,
|
|
49
51
|
LangfuseOtelSpanAttributes: () => LangfuseOtelSpanAttributes,
|
|
50
52
|
LlmAdapter: () => LlmAdapter,
|
|
@@ -111,6 +113,7 @@ __export(index_exports, {
|
|
|
111
113
|
setLangfuseTraceIdInBaggage: () => setLangfuseTraceIdInBaggage,
|
|
112
114
|
trace: () => trace_exports,
|
|
113
115
|
unstable: () => unstable_exports,
|
|
116
|
+
uploadMedia: () => uploadMedia,
|
|
114
117
|
utils: () => utils_exports
|
|
115
118
|
});
|
|
116
119
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -387,7 +390,7 @@ var resetGlobalLogger = () => {
|
|
|
387
390
|
// package.json
|
|
388
391
|
var package_default = {
|
|
389
392
|
name: "@langfuse/core",
|
|
390
|
-
version: "5.
|
|
393
|
+
version: "5.7.0",
|
|
391
394
|
description: "Core functions and utilities for Langfuse packages",
|
|
392
395
|
type: "module",
|
|
393
396
|
sideEffects: false,
|
|
@@ -573,6 +576,7 @@ var commons_exports = {};
|
|
|
573
576
|
__export(commons_exports, {
|
|
574
577
|
AccessDeniedError: () => AccessDeniedError,
|
|
575
578
|
CommentObjectType: () => CommentObjectType,
|
|
579
|
+
DatasetItemMediaReferenceField: () => DatasetItemMediaReferenceField,
|
|
576
580
|
DatasetStatus: () => DatasetStatus,
|
|
577
581
|
Error: () => Error2,
|
|
578
582
|
MethodNotAllowedError: () => MethodNotAllowedError,
|
|
@@ -586,6 +590,13 @@ __export(commons_exports, {
|
|
|
586
590
|
UnauthorizedError: () => UnauthorizedError
|
|
587
591
|
});
|
|
588
592
|
|
|
593
|
+
// src/api/api/resources/commons/types/DatasetItemMediaReferenceField.ts
|
|
594
|
+
var DatasetItemMediaReferenceField = {
|
|
595
|
+
Input: "input",
|
|
596
|
+
ExpectedOutput: "expectedOutput",
|
|
597
|
+
Metadata: "metadata"
|
|
598
|
+
};
|
|
599
|
+
|
|
589
600
|
// src/api/api/resources/commons/types/PricingTierOperator.ts
|
|
590
601
|
var PricingTierOperator = {
|
|
591
602
|
Gt: "gt",
|
|
@@ -6912,8 +6923,10 @@ var Media = class {
|
|
|
6912
6923
|
*
|
|
6913
6924
|
* @example
|
|
6914
6925
|
* await client.media.getUploadUrl({
|
|
6915
|
-
* traceId:
|
|
6926
|
+
* traceId: undefined,
|
|
6916
6927
|
* observationId: undefined,
|
|
6928
|
+
* datasetId: undefined,
|
|
6929
|
+
* datasetItemId: undefined,
|
|
6917
6930
|
* contentType: "image/png",
|
|
6918
6931
|
* contentLength: 1,
|
|
6919
6932
|
* sha256Hash: "sha256Hash",
|
|
@@ -12101,7 +12114,12 @@ var Sessions = class {
|
|
|
12101
12114
|
this._options = _options;
|
|
12102
12115
|
}
|
|
12103
12116
|
/**
|
|
12104
|
-
* Get sessions
|
|
12117
|
+
* Get sessions.
|
|
12118
|
+
*
|
|
12119
|
+
* This legacy endpoint is not recommended for new data extraction workflows.
|
|
12120
|
+
* Use the v2 observations endpoint with a bounded time range and group rows by
|
|
12121
|
+
* `sessionId` instead:
|
|
12122
|
+
* `GET /api/public/v2/observations?fromStartTime=<from>&toStartTime=<to>`.
|
|
12105
12123
|
*
|
|
12106
12124
|
* @param {LangfuseAPI.GetSessionsRequest} request
|
|
12107
12125
|
* @param {Sessions.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -12225,7 +12243,12 @@ var Sessions = class {
|
|
|
12225
12243
|
}
|
|
12226
12244
|
}
|
|
12227
12245
|
/**
|
|
12228
|
-
* Get a session.
|
|
12246
|
+
* Get a session.
|
|
12247
|
+
*
|
|
12248
|
+
* Please note that `traces` on this endpoint are not paginated. For large
|
|
12249
|
+
* sessions or new data extraction workflows, use the v2 observations endpoint
|
|
12250
|
+
* with a URL-encoded `sessionId` filter and a bounded time range:
|
|
12251
|
+
* `GET /api/public/v2/observations?filter=<sessionId filter>&fromStartTime=<from>&toStartTime=<to>`.
|
|
12229
12252
|
*
|
|
12230
12253
|
* @param {string} sessionId - The unique id of a session
|
|
12231
12254
|
* @param {Sessions.RequestOptions} requestOptions - Request-specific configuration.
|
|
@@ -14744,6 +14767,196 @@ var LangfuseMedia = class {
|
|
|
14744
14767
|
return this.base64DataUri;
|
|
14745
14768
|
}
|
|
14746
14769
|
};
|
|
14770
|
+
var LangfuseMediaReference = class {
|
|
14771
|
+
constructor(params) {
|
|
14772
|
+
Object.assign(this, params);
|
|
14773
|
+
}
|
|
14774
|
+
/**
|
|
14775
|
+
* Serializes to the original `@@@langfuseMedia:…@@@` reference string.
|
|
14776
|
+
*
|
|
14777
|
+
* This makes resolved references round-trip losslessly through anything that
|
|
14778
|
+
* serializes with `JSON.stringify` — the dataset item API, experiment/trace
|
|
14779
|
+
* span attributes — so a re-used item links back to its media instead of
|
|
14780
|
+
* persisting a JSON object with a soon-to-expire signed URL.
|
|
14781
|
+
*/
|
|
14782
|
+
toJSON() {
|
|
14783
|
+
return this.referenceString;
|
|
14784
|
+
}
|
|
14785
|
+
/**
|
|
14786
|
+
* Returns whether the signed download URL is expired or near expiry.
|
|
14787
|
+
*
|
|
14788
|
+
* @param thresholdSeconds - Treat the URL as expired this many seconds before
|
|
14789
|
+
* its actual expiry to account for clock skew and download time (default: 60).
|
|
14790
|
+
* @returns true if the URL is expired or within the threshold of expiry. If
|
|
14791
|
+
* the expiry is unknown or unparseable, returns false.
|
|
14792
|
+
*/
|
|
14793
|
+
isUrlExpired(thresholdSeconds = 60) {
|
|
14794
|
+
if (!this.urlExpiry) {
|
|
14795
|
+
return false;
|
|
14796
|
+
}
|
|
14797
|
+
const expiryMs = Date.parse(this.urlExpiry);
|
|
14798
|
+
if (Number.isNaN(expiryMs)) {
|
|
14799
|
+
return false;
|
|
14800
|
+
}
|
|
14801
|
+
return expiryMs - Date.now() <= thresholdSeconds * 1e3;
|
|
14802
|
+
}
|
|
14803
|
+
/**
|
|
14804
|
+
* Fetches the media content from the signed URL over the network.
|
|
14805
|
+
*
|
|
14806
|
+
* Useful for local evaluators / image libraries, manual base64 conversion, or
|
|
14807
|
+
* the Vercel AI SDK (`{ type: "image", image: await media.fetchBytes() }`).
|
|
14808
|
+
*
|
|
14809
|
+
* @returns The media content as raw bytes
|
|
14810
|
+
* @throws {Error} If the download fails
|
|
14811
|
+
*/
|
|
14812
|
+
async fetchBytes() {
|
|
14813
|
+
const response = await fetch(this.url, { method: "GET", headers: {} });
|
|
14814
|
+
if (!response.ok) {
|
|
14815
|
+
throw new Error(
|
|
14816
|
+
`Failed to fetch media ${this.mediaId}: HTTP ${response.status}`
|
|
14817
|
+
);
|
|
14818
|
+
}
|
|
14819
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
14820
|
+
}
|
|
14821
|
+
/**
|
|
14822
|
+
* Fetches the media over the network and returns raw base64 (no data URI prefix).
|
|
14823
|
+
*
|
|
14824
|
+
* Useful for Anthropic (`{ source: { type: "base64", media_type: media.contentType, data: await media.fetchBase64() } }`)
|
|
14825
|
+
* or LangChain (`{ type: "image", base64: await media.fetchBase64(), mime_type: media.contentType }`).
|
|
14826
|
+
*
|
|
14827
|
+
* @returns The media content as a base64 string
|
|
14828
|
+
* @throws {Error} If the download fails
|
|
14829
|
+
*/
|
|
14830
|
+
async fetchBase64() {
|
|
14831
|
+
return bytesToBase64(await this.fetchBytes());
|
|
14832
|
+
}
|
|
14833
|
+
/**
|
|
14834
|
+
* Fetches the media over the network and returns a `data:<contentType>;base64,...` URI.
|
|
14835
|
+
*
|
|
14836
|
+
* Useful for OpenAI (`{ type: "input_image", image_url: await media.fetchDataUri() }`).
|
|
14837
|
+
*
|
|
14838
|
+
* @returns The media content as a base64 data URI
|
|
14839
|
+
* @throws {Error} If the download fails
|
|
14840
|
+
*/
|
|
14841
|
+
async fetchDataUri() {
|
|
14842
|
+
return `data:${this.contentType};base64,${await this.fetchBase64()}`;
|
|
14843
|
+
}
|
|
14844
|
+
};
|
|
14845
|
+
|
|
14846
|
+
// src/mediaUpload.ts
|
|
14847
|
+
async function uploadMedia(params) {
|
|
14848
|
+
var _a2;
|
|
14849
|
+
const {
|
|
14850
|
+
apiClient,
|
|
14851
|
+
media,
|
|
14852
|
+
traceId,
|
|
14853
|
+
observationId,
|
|
14854
|
+
datasetId,
|
|
14855
|
+
datasetItemId,
|
|
14856
|
+
field,
|
|
14857
|
+
maxRetries = 3,
|
|
14858
|
+
baseDelay = 1e3
|
|
14859
|
+
} = params;
|
|
14860
|
+
const logger = (_a2 = params.logger) != null ? _a2 : getGlobalLogger();
|
|
14861
|
+
const contentSha256Hash = await media.getSha256Hash();
|
|
14862
|
+
if (!media.contentLength || !media._contentType || !contentSha256Hash || !media._contentBytes) {
|
|
14863
|
+
throw new Error("Cannot upload media: media content is incomplete.");
|
|
14864
|
+
}
|
|
14865
|
+
const { uploadUrl, mediaId } = await apiClient.media.getUploadUrl({
|
|
14866
|
+
contentLength: media.contentLength,
|
|
14867
|
+
traceId,
|
|
14868
|
+
observationId,
|
|
14869
|
+
datasetId,
|
|
14870
|
+
datasetItemId,
|
|
14871
|
+
field,
|
|
14872
|
+
contentType: media._contentType,
|
|
14873
|
+
sha256Hash: contentSha256Hash
|
|
14874
|
+
});
|
|
14875
|
+
if (!uploadUrl) {
|
|
14876
|
+
logger.debug(
|
|
14877
|
+
`Media status: Media with ID ${mediaId} already uploaded. Skipping duplicate upload.`
|
|
14878
|
+
);
|
|
14879
|
+
return;
|
|
14880
|
+
}
|
|
14881
|
+
const clientSideMediaId = await media.getId();
|
|
14882
|
+
if (clientSideMediaId !== mediaId) {
|
|
14883
|
+
throw new Error(
|
|
14884
|
+
`Media integrity error: Media ID mismatch between SDK (${clientSideMediaId}) and Server (${mediaId}). Upload cancelled.`
|
|
14885
|
+
);
|
|
14886
|
+
}
|
|
14887
|
+
logger.debug(`Uploading media ${mediaId}...`);
|
|
14888
|
+
const startTime = Date.now();
|
|
14889
|
+
const uploadResponse = await uploadWithBackoff({
|
|
14890
|
+
uploadUrl,
|
|
14891
|
+
contentBytes: media._contentBytes,
|
|
14892
|
+
contentType: media._contentType,
|
|
14893
|
+
contentSha256Hash,
|
|
14894
|
+
maxRetries,
|
|
14895
|
+
baseDelay
|
|
14896
|
+
});
|
|
14897
|
+
if (!uploadResponse) {
|
|
14898
|
+
throw new Error("Media upload process failed");
|
|
14899
|
+
}
|
|
14900
|
+
const uploadSucceeded = uploadResponse.status === 200 || uploadResponse.status === 201;
|
|
14901
|
+
await apiClient.media.patch(mediaId, {
|
|
14902
|
+
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14903
|
+
uploadHttpStatus: uploadResponse.status,
|
|
14904
|
+
uploadHttpError: await uploadResponse.text(),
|
|
14905
|
+
uploadTimeMs: Date.now() - startTime
|
|
14906
|
+
});
|
|
14907
|
+
logger.debug(`Media upload status reported for ${mediaId}`);
|
|
14908
|
+
if (!uploadSucceeded) {
|
|
14909
|
+
throw new Error(
|
|
14910
|
+
`Media upload failed with HTTP ${uploadResponse.status} after ${maxRetries} retries.`
|
|
14911
|
+
);
|
|
14912
|
+
}
|
|
14913
|
+
}
|
|
14914
|
+
async function uploadWithBackoff(params) {
|
|
14915
|
+
const {
|
|
14916
|
+
uploadUrl,
|
|
14917
|
+
contentType,
|
|
14918
|
+
contentSha256Hash,
|
|
14919
|
+
contentBytes,
|
|
14920
|
+
maxRetries,
|
|
14921
|
+
baseDelay
|
|
14922
|
+
} = params;
|
|
14923
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
14924
|
+
try {
|
|
14925
|
+
let parsedHostname;
|
|
14926
|
+
try {
|
|
14927
|
+
parsedHostname = new URL(uploadUrl).hostname;
|
|
14928
|
+
} catch {
|
|
14929
|
+
parsedHostname = "";
|
|
14930
|
+
}
|
|
14931
|
+
const isSelfHostedGcsBucket = parsedHostname === "storage.googleapis.com" || parsedHostname.endsWith(".storage.googleapis.com");
|
|
14932
|
+
const headers = isSelfHostedGcsBucket ? { "Content-Type": contentType } : {
|
|
14933
|
+
"Content-Type": contentType,
|
|
14934
|
+
"x-amz-checksum-sha256": contentSha256Hash,
|
|
14935
|
+
"x-ms-blob-type": "BlockBlob"
|
|
14936
|
+
};
|
|
14937
|
+
const uploadResponse = await fetch(uploadUrl, {
|
|
14938
|
+
method: "PUT",
|
|
14939
|
+
// Recent fetch typings narrow BodyInit to an ArrayBuffer-backed view,
|
|
14940
|
+
// while Uint8Array now defaults to Uint8Array<ArrayBufferLike>. The
|
|
14941
|
+
// media bytes are always ArrayBuffer-backed, so assert the narrower type.
|
|
14942
|
+
body: contentBytes,
|
|
14943
|
+
headers
|
|
14944
|
+
});
|
|
14945
|
+
if (attempt < maxRetries && uploadResponse.status !== 200 && uploadResponse.status !== 201) {
|
|
14946
|
+
throw new Error(`Upload failed with status ${uploadResponse.status}`);
|
|
14947
|
+
}
|
|
14948
|
+
return uploadResponse;
|
|
14949
|
+
} catch (e) {
|
|
14950
|
+
if (attempt === maxRetries) {
|
|
14951
|
+
throw e;
|
|
14952
|
+
}
|
|
14953
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
14954
|
+
const jitter = Math.random() * 1e3;
|
|
14955
|
+
await new Promise((resolve) => setTimeout(resolve, delay + jitter));
|
|
14956
|
+
}
|
|
14957
|
+
}
|
|
14958
|
+
return void 0;
|
|
14959
|
+
}
|
|
14747
14960
|
|
|
14748
14961
|
// src/propagation.ts
|
|
14749
14962
|
var import_api = require("@opentelemetry/api");
|
|
@@ -15175,6 +15388,7 @@ function getSpanKeyFromBaggageKey(baggageKey) {
|
|
|
15175
15388
|
CommentObjectType,
|
|
15176
15389
|
CreateChatPromptType,
|
|
15177
15390
|
CreateTextPromptType,
|
|
15391
|
+
DatasetItemMediaReferenceField,
|
|
15178
15392
|
DatasetStatus,
|
|
15179
15393
|
Error,
|
|
15180
15394
|
LANGFUSE_SDK_EXPERIMENT_ENVIRONMENT,
|
|
@@ -15186,6 +15400,7 @@ function getSpanKeyFromBaggageKey(baggageKey) {
|
|
|
15186
15400
|
LangfuseAPIError,
|
|
15187
15401
|
LangfuseAPITimeoutError,
|
|
15188
15402
|
LangfuseMedia,
|
|
15403
|
+
LangfuseMediaReference,
|
|
15189
15404
|
LangfuseOtelContextKeys,
|
|
15190
15405
|
LangfuseOtelSpanAttributes,
|
|
15191
15406
|
LlmAdapter,
|
|
@@ -15252,6 +15467,7 @@ function getSpanKeyFromBaggageKey(baggageKey) {
|
|
|
15252
15467
|
setLangfuseTraceIdInBaggage,
|
|
15253
15468
|
trace,
|
|
15254
15469
|
unstable,
|
|
15470
|
+
uploadMedia,
|
|
15255
15471
|
utils
|
|
15256
15472
|
});
|
|
15257
15473
|
//# sourceMappingURL=index.cjs.map
|