langsmith 0.3.28 → 0.3.29
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/client.cjs +89 -33
- package/dist/client.d.ts +2 -0
- package/dist/client.js +90 -34
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/singletons/fetch.cjs +12 -1
- package/dist/singletons/fetch.d.ts +1 -0
- package/dist/singletons/fetch.js +10 -0
- package/dist/singletons/traceable.cjs +6 -16
- package/dist/singletons/traceable.d.ts +3 -1
- package/dist/singletons/traceable.js +4 -14
- package/dist/traceable.d.ts +1 -1
- package/dist/utils/fast-safe-stringify/index.cjs +3 -3
- package/dist/utils/fast-safe-stringify/index.d.ts +1 -1
- package/dist/utils/fast-safe-stringify/index.js +3 -3
- package/dist/wrappers/openai.d.ts +1 -1
- package/package.json +3 -3
package/dist/client.cjs
CHANGED
|
@@ -145,7 +145,7 @@ class AutoBatchQueue {
|
|
|
145
145
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
|
|
146
146
|
itemPromiseResolve = resolve;
|
|
147
147
|
});
|
|
148
|
-
const size = (0, index_js_2.serialize)(item.item).length;
|
|
148
|
+
const size = (0, index_js_2.serialize)(item.item, `Serializing run with id: ${item.item.id}`).length;
|
|
149
149
|
this.items.push({
|
|
150
150
|
action: item.action,
|
|
151
151
|
payload: item.item,
|
|
@@ -736,7 +736,7 @@ class Client {
|
|
|
736
736
|
const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/runs`, {
|
|
737
737
|
method: "POST",
|
|
738
738
|
headers,
|
|
739
|
-
body: (0, index_js_2.serialize)(mergedRunCreateParam),
|
|
739
|
+
body: (0, index_js_2.serialize)(mergedRunCreateParam, `Creating run with id: ${mergedRunCreateParam.id}`),
|
|
740
740
|
signal: AbortSignal.timeout(this.timeout_ms),
|
|
741
741
|
...this.fetchOptions,
|
|
742
742
|
});
|
|
@@ -797,7 +797,11 @@ class Client {
|
|
|
797
797
|
}
|
|
798
798
|
}
|
|
799
799
|
if (batchChunks.post.length > 0 || batchChunks.patch.length > 0) {
|
|
800
|
-
|
|
800
|
+
const runIds = batchChunks.post
|
|
801
|
+
.map((item) => item.id)
|
|
802
|
+
.concat(batchChunks.patch.map((item) => item.id))
|
|
803
|
+
.join(",");
|
|
804
|
+
await this._postBatchIngestRuns((0, index_js_2.serialize)(batchChunks, `Ingesting runs with ids: ${runIds}`));
|
|
801
805
|
}
|
|
802
806
|
}
|
|
803
807
|
async _postBatchIngestRuns(body) {
|
|
@@ -892,7 +896,7 @@ class Client {
|
|
|
892
896
|
const { inputs, outputs, events, attachments, ...payload } = originalPayload;
|
|
893
897
|
const fields = { inputs, outputs, events };
|
|
894
898
|
// encode the main run payload
|
|
895
|
-
const stringifiedPayload = (0, index_js_2.serialize)(payload);
|
|
899
|
+
const stringifiedPayload = (0, index_js_2.serialize)(payload, `Serializing for multipart ingestion of run with id: ${payload.id}`);
|
|
896
900
|
accumulatedParts.push({
|
|
897
901
|
name: `${method}.${payload.id}`,
|
|
898
902
|
payload: new Blob([stringifiedPayload], {
|
|
@@ -904,7 +908,7 @@ class Client {
|
|
|
904
908
|
if (value === undefined) {
|
|
905
909
|
continue;
|
|
906
910
|
}
|
|
907
|
-
const stringifiedValue = (0, index_js_2.serialize)(value);
|
|
911
|
+
const stringifiedValue = (0, index_js_2.serialize)(value, `Serializing ${key} for multipart ingestion of run with id: ${payload.id}`);
|
|
908
912
|
accumulatedParts.push({
|
|
909
913
|
name: `${method}.${payload.id}.${key}`,
|
|
910
914
|
payload: new Blob([stringifiedValue], {
|
|
@@ -948,34 +952,84 @@ class Client {
|
|
|
948
952
|
}
|
|
949
953
|
await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "));
|
|
950
954
|
}
|
|
955
|
+
async _createNodeFetchBody(parts, boundary) {
|
|
956
|
+
// Create multipart form data manually using Blobs
|
|
957
|
+
const chunks = [];
|
|
958
|
+
for (const part of parts) {
|
|
959
|
+
// Add field boundary
|
|
960
|
+
chunks.push(new Blob([`--${boundary}\r\n`]));
|
|
961
|
+
chunks.push(new Blob([
|
|
962
|
+
`Content-Disposition: form-data; name="${part.name}"\r\n`,
|
|
963
|
+
`Content-Type: ${part.payload.type}\r\n\r\n`,
|
|
964
|
+
]));
|
|
965
|
+
chunks.push(part.payload);
|
|
966
|
+
chunks.push(new Blob(["\r\n"]));
|
|
967
|
+
}
|
|
968
|
+
// Add final boundary
|
|
969
|
+
chunks.push(new Blob([`--${boundary}--\r\n`]));
|
|
970
|
+
// Combine all chunks into a single Blob
|
|
971
|
+
const body = new Blob(chunks);
|
|
972
|
+
// Convert Blob to ArrayBuffer for compatibility
|
|
973
|
+
const arrayBuffer = await body.arrayBuffer();
|
|
974
|
+
return arrayBuffer;
|
|
975
|
+
}
|
|
976
|
+
async _createMultipartStream(parts, boundary) {
|
|
977
|
+
const encoder = new TextEncoder();
|
|
978
|
+
// Create a ReadableStream for streaming the multipart data
|
|
979
|
+
// Only do special handling if we're using node-fetch
|
|
980
|
+
const stream = new ReadableStream({
|
|
981
|
+
async start(controller) {
|
|
982
|
+
// Helper function to write a chunk to the stream
|
|
983
|
+
const writeChunk = async (chunk) => {
|
|
984
|
+
if (typeof chunk === "string") {
|
|
985
|
+
controller.enqueue(encoder.encode(chunk));
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
controller.enqueue(chunk);
|
|
989
|
+
}
|
|
990
|
+
};
|
|
991
|
+
// Write each part to the stream
|
|
992
|
+
for (const part of parts) {
|
|
993
|
+
// Write boundary and headers
|
|
994
|
+
await writeChunk(`--${boundary}\r\n`);
|
|
995
|
+
await writeChunk(`Content-Disposition: form-data; name="${part.name}"\r\n`);
|
|
996
|
+
await writeChunk(`Content-Type: ${part.payload.type}\r\n\r\n`);
|
|
997
|
+
// Write the payload
|
|
998
|
+
const payloadStream = part.payload.stream();
|
|
999
|
+
const reader = payloadStream.getReader();
|
|
1000
|
+
try {
|
|
1001
|
+
let result;
|
|
1002
|
+
while (!(result = await reader.read()).done) {
|
|
1003
|
+
controller.enqueue(result.value);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
finally {
|
|
1007
|
+
reader.releaseLock();
|
|
1008
|
+
}
|
|
1009
|
+
await writeChunk("\r\n");
|
|
1010
|
+
}
|
|
1011
|
+
// Write final boundary
|
|
1012
|
+
await writeChunk(`--${boundary}--\r\n`);
|
|
1013
|
+
controller.close();
|
|
1014
|
+
},
|
|
1015
|
+
});
|
|
1016
|
+
return stream;
|
|
1017
|
+
}
|
|
951
1018
|
async _sendMultipartRequest(parts, context) {
|
|
952
1019
|
try {
|
|
953
|
-
// Create multipart form data
|
|
1020
|
+
// Create multipart form data boundary
|
|
954
1021
|
const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
|
|
955
|
-
const
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
chunks.push(new Blob([`--${boundary}\r\n`]));
|
|
959
|
-
chunks.push(new Blob([
|
|
960
|
-
`Content-Disposition: form-data; name="${part.name}"\r\n`,
|
|
961
|
-
`Content-Type: ${part.payload.type}\r\n\r\n`,
|
|
962
|
-
]));
|
|
963
|
-
chunks.push(part.payload);
|
|
964
|
-
chunks.push(new Blob(["\r\n"]));
|
|
965
|
-
}
|
|
966
|
-
// Add final boundary
|
|
967
|
-
chunks.push(new Blob([`--${boundary}--\r\n`]));
|
|
968
|
-
// Combine all chunks into a single Blob
|
|
969
|
-
const body = new Blob(chunks);
|
|
970
|
-
// Convert Blob to ArrayBuffer for compatibility
|
|
971
|
-
const arrayBuffer = await body.arrayBuffer();
|
|
1022
|
+
const body = await ((0, fetch_js_1._globalFetchImplementationIsNodeFetch)()
|
|
1023
|
+
? this._createNodeFetchBody(parts, boundary)
|
|
1024
|
+
: this._createMultipartStream(parts, boundary));
|
|
972
1025
|
const res = await this.batchIngestCaller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/runs/multipart`, {
|
|
973
1026
|
method: "POST",
|
|
974
1027
|
headers: {
|
|
975
1028
|
...this.headers,
|
|
976
1029
|
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
977
1030
|
},
|
|
978
|
-
body
|
|
1031
|
+
body,
|
|
1032
|
+
duplex: "half",
|
|
979
1033
|
signal: AbortSignal.timeout(this.timeout_ms),
|
|
980
1034
|
...this.fetchOptions,
|
|
981
1035
|
});
|
|
@@ -1020,7 +1074,7 @@ class Client {
|
|
|
1020
1074
|
const response = await this.caller.call((0, fetch_js_1._getFetchImplementation)(this.debug), `${this.apiUrl}/runs/${runId}`, {
|
|
1021
1075
|
method: "PATCH",
|
|
1022
1076
|
headers,
|
|
1023
|
-
body: (0, index_js_2.serialize)(run),
|
|
1077
|
+
body: (0, index_js_2.serialize)(run, `Serializing payload to update run with id: ${runId}`),
|
|
1024
1078
|
signal: AbortSignal.timeout(this.timeout_ms),
|
|
1025
1079
|
...this.fetchOptions,
|
|
1026
1080
|
});
|
|
@@ -1491,7 +1545,9 @@ class Client {
|
|
|
1491
1545
|
const result = await response.json();
|
|
1492
1546
|
if (!response.ok) {
|
|
1493
1547
|
if ("detail" in result) {
|
|
1494
|
-
throw new Error(`Failed to list shared examples.\nStatus: ${response.status}\nMessage: ${result.detail
|
|
1548
|
+
throw new Error(`Failed to list shared examples.\nStatus: ${response.status}\nMessage: ${Array.isArray(result.detail)
|
|
1549
|
+
? result.detail.join("\n")
|
|
1550
|
+
: "Unspecified error"}`);
|
|
1495
1551
|
}
|
|
1496
1552
|
throw new Error(`Failed to list shared examples: ${response.status} ${response.statusText}`);
|
|
1497
1553
|
}
|
|
@@ -3006,14 +3062,14 @@ class Client {
|
|
|
3006
3062
|
...(example.split && { split: example.split }),
|
|
3007
3063
|
};
|
|
3008
3064
|
// Add main example data
|
|
3009
|
-
const stringifiedExample = (0, index_js_2.serialize)(exampleBody);
|
|
3065
|
+
const stringifiedExample = (0, index_js_2.serialize)(exampleBody, `Serializing body for example with id: ${exampleId}`);
|
|
3010
3066
|
const exampleBlob = new Blob([stringifiedExample], {
|
|
3011
3067
|
type: "application/json",
|
|
3012
3068
|
});
|
|
3013
3069
|
formData.append(exampleId, exampleBlob);
|
|
3014
3070
|
// Add inputs if present
|
|
3015
3071
|
if (example.inputs) {
|
|
3016
|
-
const stringifiedInputs = (0, index_js_2.serialize)(example.inputs);
|
|
3072
|
+
const stringifiedInputs = (0, index_js_2.serialize)(example.inputs, `Serializing inputs for example with id: ${exampleId}`);
|
|
3017
3073
|
const inputsBlob = new Blob([stringifiedInputs], {
|
|
3018
3074
|
type: "application/json",
|
|
3019
3075
|
});
|
|
@@ -3021,7 +3077,7 @@ class Client {
|
|
|
3021
3077
|
}
|
|
3022
3078
|
// Add outputs if present
|
|
3023
3079
|
if (example.outputs) {
|
|
3024
|
-
const stringifiedOutputs = (0, index_js_2.serialize)(example.outputs);
|
|
3080
|
+
const stringifiedOutputs = (0, index_js_2.serialize)(example.outputs, `Serializing outputs whle updating example with id: ${exampleId}`);
|
|
3025
3081
|
const outputsBlob = new Blob([stringifiedOutputs], {
|
|
3026
3082
|
type: "application/json",
|
|
3027
3083
|
});
|
|
@@ -3046,7 +3102,7 @@ class Client {
|
|
|
3046
3102
|
}
|
|
3047
3103
|
}
|
|
3048
3104
|
if (example.attachments_operations) {
|
|
3049
|
-
const stringifiedAttachmentsOperations = (0, index_js_2.serialize)(example.attachments_operations);
|
|
3105
|
+
const stringifiedAttachmentsOperations = (0, index_js_2.serialize)(example.attachments_operations, `Serializing attachments while updating example with id: ${exampleId}`);
|
|
3050
3106
|
const attachmentsOperationsBlob = new Blob([stringifiedAttachmentsOperations], {
|
|
3051
3107
|
type: "application/json",
|
|
3052
3108
|
});
|
|
@@ -3092,14 +3148,14 @@ class Client {
|
|
|
3092
3148
|
}),
|
|
3093
3149
|
};
|
|
3094
3150
|
// Add main example data
|
|
3095
|
-
const stringifiedExample = (0, index_js_2.serialize)(exampleBody);
|
|
3151
|
+
const stringifiedExample = (0, index_js_2.serialize)(exampleBody, `Serializing body for uploaded example with id: ${exampleId}`);
|
|
3096
3152
|
const exampleBlob = new Blob([stringifiedExample], {
|
|
3097
3153
|
type: "application/json",
|
|
3098
3154
|
});
|
|
3099
3155
|
formData.append(exampleId, exampleBlob);
|
|
3100
3156
|
// Add inputs if present
|
|
3101
3157
|
if (example.inputs) {
|
|
3102
|
-
const stringifiedInputs = (0, index_js_2.serialize)(example.inputs);
|
|
3158
|
+
const stringifiedInputs = (0, index_js_2.serialize)(example.inputs, `Serializing inputs for uploaded example with id: ${exampleId}`);
|
|
3103
3159
|
const inputsBlob = new Blob([stringifiedInputs], {
|
|
3104
3160
|
type: "application/json",
|
|
3105
3161
|
});
|
|
@@ -3107,7 +3163,7 @@ class Client {
|
|
|
3107
3163
|
}
|
|
3108
3164
|
// Add outputs if present
|
|
3109
3165
|
if (example.outputs) {
|
|
3110
|
-
const stringifiedOutputs = (0, index_js_2.serialize)(example.outputs);
|
|
3166
|
+
const stringifiedOutputs = (0, index_js_2.serialize)(example.outputs, `Serializing outputs for uploaded example with id: ${exampleId}`);
|
|
3111
3167
|
const outputsBlob = new Blob([stringifiedOutputs], {
|
|
3112
3168
|
type: "application/json",
|
|
3113
3169
|
});
|
package/dist/client.d.ts
CHANGED
|
@@ -351,6 +351,8 @@ export declare class Client implements LangSmithTracingClientInterface {
|
|
|
351
351
|
runCreates?: RunCreate[];
|
|
352
352
|
runUpdates?: RunUpdate[];
|
|
353
353
|
}): Promise<void>;
|
|
354
|
+
private _createNodeFetchBody;
|
|
355
|
+
private _createMultipartStream;
|
|
354
356
|
private _sendMultipartRequest;
|
|
355
357
|
updateRun(runId: string, run: RunUpdate): Promise<void>;
|
|
356
358
|
readRun(runId: string, { loadChildRuns }?: {
|
package/dist/client.js
CHANGED
|
@@ -7,7 +7,7 @@ import { assertUuid } from "./utils/_uuid.js";
|
|
|
7
7
|
import { warnOnce } from "./utils/warn.js";
|
|
8
8
|
import { parsePromptIdentifier } from "./utils/prompts.js";
|
|
9
9
|
import { raiseForStatus } from "./utils/error.js";
|
|
10
|
-
import { _getFetchImplementation } from "./singletons/fetch.js";
|
|
10
|
+
import { _globalFetchImplementationIsNodeFetch, _getFetchImplementation, } from "./singletons/fetch.js";
|
|
11
11
|
import { serialize as serializePayloadForTracing } from "./utils/fast-safe-stringify/index.js";
|
|
12
12
|
export function mergeRuntimeEnvIntoRunCreate(run) {
|
|
13
13
|
const runtimeEnv = getRuntimeEnvironment();
|
|
@@ -108,7 +108,7 @@ export class AutoBatchQueue {
|
|
|
108
108
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise
|
|
109
109
|
itemPromiseResolve = resolve;
|
|
110
110
|
});
|
|
111
|
-
const size = serializePayloadForTracing(item.item).length;
|
|
111
|
+
const size = serializePayloadForTracing(item.item, `Serializing run with id: ${item.item.id}`).length;
|
|
112
112
|
this.items.push({
|
|
113
113
|
action: item.action,
|
|
114
114
|
payload: item.item,
|
|
@@ -698,7 +698,7 @@ export class Client {
|
|
|
698
698
|
const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/runs`, {
|
|
699
699
|
method: "POST",
|
|
700
700
|
headers,
|
|
701
|
-
body: serializePayloadForTracing(mergedRunCreateParam),
|
|
701
|
+
body: serializePayloadForTracing(mergedRunCreateParam, `Creating run with id: ${mergedRunCreateParam.id}`),
|
|
702
702
|
signal: AbortSignal.timeout(this.timeout_ms),
|
|
703
703
|
...this.fetchOptions,
|
|
704
704
|
});
|
|
@@ -759,7 +759,11 @@ export class Client {
|
|
|
759
759
|
}
|
|
760
760
|
}
|
|
761
761
|
if (batchChunks.post.length > 0 || batchChunks.patch.length > 0) {
|
|
762
|
-
|
|
762
|
+
const runIds = batchChunks.post
|
|
763
|
+
.map((item) => item.id)
|
|
764
|
+
.concat(batchChunks.patch.map((item) => item.id))
|
|
765
|
+
.join(",");
|
|
766
|
+
await this._postBatchIngestRuns(serializePayloadForTracing(batchChunks, `Ingesting runs with ids: ${runIds}`));
|
|
763
767
|
}
|
|
764
768
|
}
|
|
765
769
|
async _postBatchIngestRuns(body) {
|
|
@@ -854,7 +858,7 @@ export class Client {
|
|
|
854
858
|
const { inputs, outputs, events, attachments, ...payload } = originalPayload;
|
|
855
859
|
const fields = { inputs, outputs, events };
|
|
856
860
|
// encode the main run payload
|
|
857
|
-
const stringifiedPayload = serializePayloadForTracing(payload);
|
|
861
|
+
const stringifiedPayload = serializePayloadForTracing(payload, `Serializing for multipart ingestion of run with id: ${payload.id}`);
|
|
858
862
|
accumulatedParts.push({
|
|
859
863
|
name: `${method}.${payload.id}`,
|
|
860
864
|
payload: new Blob([stringifiedPayload], {
|
|
@@ -866,7 +870,7 @@ export class Client {
|
|
|
866
870
|
if (value === undefined) {
|
|
867
871
|
continue;
|
|
868
872
|
}
|
|
869
|
-
const stringifiedValue = serializePayloadForTracing(value);
|
|
873
|
+
const stringifiedValue = serializePayloadForTracing(value, `Serializing ${key} for multipart ingestion of run with id: ${payload.id}`);
|
|
870
874
|
accumulatedParts.push({
|
|
871
875
|
name: `${method}.${payload.id}.${key}`,
|
|
872
876
|
payload: new Blob([stringifiedValue], {
|
|
@@ -910,34 +914,84 @@ export class Client {
|
|
|
910
914
|
}
|
|
911
915
|
await this._sendMultipartRequest(accumulatedParts, accumulatedContext.join("; "));
|
|
912
916
|
}
|
|
917
|
+
async _createNodeFetchBody(parts, boundary) {
|
|
918
|
+
// Create multipart form data manually using Blobs
|
|
919
|
+
const chunks = [];
|
|
920
|
+
for (const part of parts) {
|
|
921
|
+
// Add field boundary
|
|
922
|
+
chunks.push(new Blob([`--${boundary}\r\n`]));
|
|
923
|
+
chunks.push(new Blob([
|
|
924
|
+
`Content-Disposition: form-data; name="${part.name}"\r\n`,
|
|
925
|
+
`Content-Type: ${part.payload.type}\r\n\r\n`,
|
|
926
|
+
]));
|
|
927
|
+
chunks.push(part.payload);
|
|
928
|
+
chunks.push(new Blob(["\r\n"]));
|
|
929
|
+
}
|
|
930
|
+
// Add final boundary
|
|
931
|
+
chunks.push(new Blob([`--${boundary}--\r\n`]));
|
|
932
|
+
// Combine all chunks into a single Blob
|
|
933
|
+
const body = new Blob(chunks);
|
|
934
|
+
// Convert Blob to ArrayBuffer for compatibility
|
|
935
|
+
const arrayBuffer = await body.arrayBuffer();
|
|
936
|
+
return arrayBuffer;
|
|
937
|
+
}
|
|
938
|
+
async _createMultipartStream(parts, boundary) {
|
|
939
|
+
const encoder = new TextEncoder();
|
|
940
|
+
// Create a ReadableStream for streaming the multipart data
|
|
941
|
+
// Only do special handling if we're using node-fetch
|
|
942
|
+
const stream = new ReadableStream({
|
|
943
|
+
async start(controller) {
|
|
944
|
+
// Helper function to write a chunk to the stream
|
|
945
|
+
const writeChunk = async (chunk) => {
|
|
946
|
+
if (typeof chunk === "string") {
|
|
947
|
+
controller.enqueue(encoder.encode(chunk));
|
|
948
|
+
}
|
|
949
|
+
else {
|
|
950
|
+
controller.enqueue(chunk);
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
// Write each part to the stream
|
|
954
|
+
for (const part of parts) {
|
|
955
|
+
// Write boundary and headers
|
|
956
|
+
await writeChunk(`--${boundary}\r\n`);
|
|
957
|
+
await writeChunk(`Content-Disposition: form-data; name="${part.name}"\r\n`);
|
|
958
|
+
await writeChunk(`Content-Type: ${part.payload.type}\r\n\r\n`);
|
|
959
|
+
// Write the payload
|
|
960
|
+
const payloadStream = part.payload.stream();
|
|
961
|
+
const reader = payloadStream.getReader();
|
|
962
|
+
try {
|
|
963
|
+
let result;
|
|
964
|
+
while (!(result = await reader.read()).done) {
|
|
965
|
+
controller.enqueue(result.value);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
finally {
|
|
969
|
+
reader.releaseLock();
|
|
970
|
+
}
|
|
971
|
+
await writeChunk("\r\n");
|
|
972
|
+
}
|
|
973
|
+
// Write final boundary
|
|
974
|
+
await writeChunk(`--${boundary}--\r\n`);
|
|
975
|
+
controller.close();
|
|
976
|
+
},
|
|
977
|
+
});
|
|
978
|
+
return stream;
|
|
979
|
+
}
|
|
913
980
|
async _sendMultipartRequest(parts, context) {
|
|
914
981
|
try {
|
|
915
|
-
// Create multipart form data
|
|
982
|
+
// Create multipart form data boundary
|
|
916
983
|
const boundary = "----LangSmithFormBoundary" + Math.random().toString(36).slice(2);
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
chunks.push(new Blob([`--${boundary}\r\n`]));
|
|
921
|
-
chunks.push(new Blob([
|
|
922
|
-
`Content-Disposition: form-data; name="${part.name}"\r\n`,
|
|
923
|
-
`Content-Type: ${part.payload.type}\r\n\r\n`,
|
|
924
|
-
]));
|
|
925
|
-
chunks.push(part.payload);
|
|
926
|
-
chunks.push(new Blob(["\r\n"]));
|
|
927
|
-
}
|
|
928
|
-
// Add final boundary
|
|
929
|
-
chunks.push(new Blob([`--${boundary}--\r\n`]));
|
|
930
|
-
// Combine all chunks into a single Blob
|
|
931
|
-
const body = new Blob(chunks);
|
|
932
|
-
// Convert Blob to ArrayBuffer for compatibility
|
|
933
|
-
const arrayBuffer = await body.arrayBuffer();
|
|
984
|
+
const body = await (_globalFetchImplementationIsNodeFetch()
|
|
985
|
+
? this._createNodeFetchBody(parts, boundary)
|
|
986
|
+
: this._createMultipartStream(parts, boundary));
|
|
934
987
|
const res = await this.batchIngestCaller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/runs/multipart`, {
|
|
935
988
|
method: "POST",
|
|
936
989
|
headers: {
|
|
937
990
|
...this.headers,
|
|
938
991
|
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
939
992
|
},
|
|
940
|
-
body
|
|
993
|
+
body,
|
|
994
|
+
duplex: "half",
|
|
941
995
|
signal: AbortSignal.timeout(this.timeout_ms),
|
|
942
996
|
...this.fetchOptions,
|
|
943
997
|
});
|
|
@@ -982,7 +1036,7 @@ export class Client {
|
|
|
982
1036
|
const response = await this.caller.call(_getFetchImplementation(this.debug), `${this.apiUrl}/runs/${runId}`, {
|
|
983
1037
|
method: "PATCH",
|
|
984
1038
|
headers,
|
|
985
|
-
body: serializePayloadForTracing(run),
|
|
1039
|
+
body: serializePayloadForTracing(run, `Serializing payload to update run with id: ${runId}`),
|
|
986
1040
|
signal: AbortSignal.timeout(this.timeout_ms),
|
|
987
1041
|
...this.fetchOptions,
|
|
988
1042
|
});
|
|
@@ -1453,7 +1507,9 @@ export class Client {
|
|
|
1453
1507
|
const result = await response.json();
|
|
1454
1508
|
if (!response.ok) {
|
|
1455
1509
|
if ("detail" in result) {
|
|
1456
|
-
throw new Error(`Failed to list shared examples.\nStatus: ${response.status}\nMessage: ${result.detail
|
|
1510
|
+
throw new Error(`Failed to list shared examples.\nStatus: ${response.status}\nMessage: ${Array.isArray(result.detail)
|
|
1511
|
+
? result.detail.join("\n")
|
|
1512
|
+
: "Unspecified error"}`);
|
|
1457
1513
|
}
|
|
1458
1514
|
throw new Error(`Failed to list shared examples: ${response.status} ${response.statusText}`);
|
|
1459
1515
|
}
|
|
@@ -2968,14 +3024,14 @@ export class Client {
|
|
|
2968
3024
|
...(example.split && { split: example.split }),
|
|
2969
3025
|
};
|
|
2970
3026
|
// Add main example data
|
|
2971
|
-
const stringifiedExample = serializePayloadForTracing(exampleBody);
|
|
3027
|
+
const stringifiedExample = serializePayloadForTracing(exampleBody, `Serializing body for example with id: ${exampleId}`);
|
|
2972
3028
|
const exampleBlob = new Blob([stringifiedExample], {
|
|
2973
3029
|
type: "application/json",
|
|
2974
3030
|
});
|
|
2975
3031
|
formData.append(exampleId, exampleBlob);
|
|
2976
3032
|
// Add inputs if present
|
|
2977
3033
|
if (example.inputs) {
|
|
2978
|
-
const stringifiedInputs = serializePayloadForTracing(example.inputs);
|
|
3034
|
+
const stringifiedInputs = serializePayloadForTracing(example.inputs, `Serializing inputs for example with id: ${exampleId}`);
|
|
2979
3035
|
const inputsBlob = new Blob([stringifiedInputs], {
|
|
2980
3036
|
type: "application/json",
|
|
2981
3037
|
});
|
|
@@ -2983,7 +3039,7 @@ export class Client {
|
|
|
2983
3039
|
}
|
|
2984
3040
|
// Add outputs if present
|
|
2985
3041
|
if (example.outputs) {
|
|
2986
|
-
const stringifiedOutputs = serializePayloadForTracing(example.outputs);
|
|
3042
|
+
const stringifiedOutputs = serializePayloadForTracing(example.outputs, `Serializing outputs whle updating example with id: ${exampleId}`);
|
|
2987
3043
|
const outputsBlob = new Blob([stringifiedOutputs], {
|
|
2988
3044
|
type: "application/json",
|
|
2989
3045
|
});
|
|
@@ -3008,7 +3064,7 @@ export class Client {
|
|
|
3008
3064
|
}
|
|
3009
3065
|
}
|
|
3010
3066
|
if (example.attachments_operations) {
|
|
3011
|
-
const stringifiedAttachmentsOperations = serializePayloadForTracing(example.attachments_operations);
|
|
3067
|
+
const stringifiedAttachmentsOperations = serializePayloadForTracing(example.attachments_operations, `Serializing attachments while updating example with id: ${exampleId}`);
|
|
3012
3068
|
const attachmentsOperationsBlob = new Blob([stringifiedAttachmentsOperations], {
|
|
3013
3069
|
type: "application/json",
|
|
3014
3070
|
});
|
|
@@ -3054,14 +3110,14 @@ export class Client {
|
|
|
3054
3110
|
}),
|
|
3055
3111
|
};
|
|
3056
3112
|
// Add main example data
|
|
3057
|
-
const stringifiedExample = serializePayloadForTracing(exampleBody);
|
|
3113
|
+
const stringifiedExample = serializePayloadForTracing(exampleBody, `Serializing body for uploaded example with id: ${exampleId}`);
|
|
3058
3114
|
const exampleBlob = new Blob([stringifiedExample], {
|
|
3059
3115
|
type: "application/json",
|
|
3060
3116
|
});
|
|
3061
3117
|
formData.append(exampleId, exampleBlob);
|
|
3062
3118
|
// Add inputs if present
|
|
3063
3119
|
if (example.inputs) {
|
|
3064
|
-
const stringifiedInputs = serializePayloadForTracing(example.inputs);
|
|
3120
|
+
const stringifiedInputs = serializePayloadForTracing(example.inputs, `Serializing inputs for uploaded example with id: ${exampleId}`);
|
|
3065
3121
|
const inputsBlob = new Blob([stringifiedInputs], {
|
|
3066
3122
|
type: "application/json",
|
|
3067
3123
|
});
|
|
@@ -3069,7 +3125,7 @@ export class Client {
|
|
|
3069
3125
|
}
|
|
3070
3126
|
// Add outputs if present
|
|
3071
3127
|
if (example.outputs) {
|
|
3072
|
-
const stringifiedOutputs = serializePayloadForTracing(example.outputs);
|
|
3128
|
+
const stringifiedOutputs = serializePayloadForTracing(example.outputs, `Serializing outputs for uploaded example with id: ${exampleId}`);
|
|
3073
3129
|
const outputsBlob = new Blob([stringifiedOutputs], {
|
|
3074
3130
|
type: "application/json",
|
|
3075
3131
|
});
|
package/dist/index.cjs
CHANGED
|
@@ -8,4 +8,4 @@ Object.defineProperty(exports, "RunTree", { enumerable: true, get: function () {
|
|
|
8
8
|
var fetch_js_1 = require("./singletons/fetch.cjs");
|
|
9
9
|
Object.defineProperty(exports, "overrideFetchImplementation", { enumerable: true, get: function () { return fetch_js_1.overrideFetchImplementation; } });
|
|
10
10
|
// Update using yarn bump-version
|
|
11
|
-
exports.__version__ = "0.3.
|
|
11
|
+
exports.__version__ = "0.3.29";
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export { Client, type ClientConfig, type LangSmithTracingClientInterface, } from
|
|
|
2
2
|
export type { Dataset, Example, TracerSession, Run, Feedback, RetrieverOutput, } from "./schemas.js";
|
|
3
3
|
export { RunTree, type RunTreeConfig } from "./run_trees.js";
|
|
4
4
|
export { overrideFetchImplementation } from "./singletons/fetch.js";
|
|
5
|
-
export declare const __version__ = "0.3.
|
|
5
|
+
export declare const __version__ = "0.3.29";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports._getFetchImplementation = exports.overrideFetchImplementation = void 0;
|
|
3
|
+
exports._getFetchImplementation = exports._globalFetchImplementationIsNodeFetch = exports.overrideFetchImplementation = void 0;
|
|
4
4
|
const env_js_1 = require("../utils/env.cjs");
|
|
5
5
|
// Wrap the default fetch call due to issues with illegal invocations
|
|
6
6
|
// in some environments:
|
|
@@ -18,6 +18,17 @@ const overrideFetchImplementation = (fetch) => {
|
|
|
18
18
|
globalThis[LANGSMITH_FETCH_IMPLEMENTATION_KEY] = fetch;
|
|
19
19
|
};
|
|
20
20
|
exports.overrideFetchImplementation = overrideFetchImplementation;
|
|
21
|
+
const _globalFetchImplementationIsNodeFetch = () => {
|
|
22
|
+
const fetchImpl = globalThis[LANGSMITH_FETCH_IMPLEMENTATION_KEY];
|
|
23
|
+
if (!fetchImpl)
|
|
24
|
+
return false;
|
|
25
|
+
// Check if the implementation has node-fetch specific properties
|
|
26
|
+
return (typeof fetchImpl === "function" &&
|
|
27
|
+
"Headers" in fetchImpl &&
|
|
28
|
+
"Request" in fetchImpl &&
|
|
29
|
+
"Response" in fetchImpl);
|
|
30
|
+
};
|
|
31
|
+
exports._globalFetchImplementationIsNodeFetch = _globalFetchImplementationIsNodeFetch;
|
|
21
32
|
/**
|
|
22
33
|
* @internal
|
|
23
34
|
*/
|
package/dist/singletons/fetch.js
CHANGED
|
@@ -14,6 +14,16 @@ const LANGSMITH_FETCH_IMPLEMENTATION_KEY = Symbol.for("ls:fetch_implementation")
|
|
|
14
14
|
export const overrideFetchImplementation = (fetch) => {
|
|
15
15
|
globalThis[LANGSMITH_FETCH_IMPLEMENTATION_KEY] = fetch;
|
|
16
16
|
};
|
|
17
|
+
export const _globalFetchImplementationIsNodeFetch = () => {
|
|
18
|
+
const fetchImpl = globalThis[LANGSMITH_FETCH_IMPLEMENTATION_KEY];
|
|
19
|
+
if (!fetchImpl)
|
|
20
|
+
return false;
|
|
21
|
+
// Check if the implementation has node-fetch specific properties
|
|
22
|
+
return (typeof fetchImpl === "function" &&
|
|
23
|
+
"Headers" in fetchImpl &&
|
|
24
|
+
"Request" in fetchImpl &&
|
|
25
|
+
"Response" in fetchImpl);
|
|
26
|
+
};
|
|
17
27
|
/**
|
|
18
28
|
* @internal
|
|
19
29
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ROOT = exports.
|
|
3
|
+
exports.ROOT = exports.AsyncLocalStorageProviderSingleton = void 0;
|
|
4
|
+
exports.getCurrentRunTree = getCurrentRunTree;
|
|
4
5
|
exports.withRunTree = withRunTree;
|
|
5
6
|
exports.isTraceableFunction = isTraceableFunction;
|
|
6
7
|
const run_trees_js_1 = require("../run_trees.cjs");
|
|
@@ -28,24 +29,13 @@ class AsyncLocalStorageProvider {
|
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
exports.AsyncLocalStorageProviderSingleton = new AsyncLocalStorageProvider();
|
|
31
|
-
|
|
32
|
-
* Return the current run tree from within a traceable-wrapped function.
|
|
33
|
-
* Will throw an error if called outside of a traceable function.
|
|
34
|
-
*
|
|
35
|
-
* @returns The run tree for the given context.
|
|
36
|
-
*/
|
|
37
|
-
const getCurrentRunTree = () => {
|
|
32
|
+
function getCurrentRunTree(permitAbsentRunTree = false) {
|
|
38
33
|
const runTree = exports.AsyncLocalStorageProviderSingleton.getInstance().getStore();
|
|
39
|
-
if (!(0, run_trees_js_1.isRunTree)(runTree)) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
"Could not get the current run tree.",
|
|
42
|
-
"",
|
|
43
|
-
"Please make sure you are calling this method within a traceable function and that tracing is enabled.",
|
|
44
|
-
].join("\n"));
|
|
34
|
+
if (!permitAbsentRunTree && !(0, run_trees_js_1.isRunTree)(runTree)) {
|
|
35
|
+
throw new Error("Could not get the current run tree.\n\nPlease make sure you are calling this method within a traceable function and that tracing is enabled.");
|
|
45
36
|
}
|
|
46
37
|
return runTree;
|
|
47
|
-
}
|
|
48
|
-
exports.getCurrentRunTree = getCurrentRunTree;
|
|
38
|
+
}
|
|
49
39
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
40
|
function withRunTree(runTree, fn) {
|
|
51
41
|
const storage = exports.AsyncLocalStorageProviderSingleton.getInstance();
|
|
@@ -15,7 +15,9 @@ export declare const AsyncLocalStorageProviderSingleton: AsyncLocalStorageProvid
|
|
|
15
15
|
*
|
|
16
16
|
* @returns The run tree for the given context.
|
|
17
17
|
*/
|
|
18
|
-
export declare
|
|
18
|
+
export declare function getCurrentRunTree(): RunTree;
|
|
19
|
+
export declare function getCurrentRunTree(permitAbsentRunTree: false): RunTree;
|
|
20
|
+
export declare function getCurrentRunTree(permitAbsentRunTree: boolean): RunTree | undefined;
|
|
19
21
|
export declare function withRunTree<Fn extends (...args: any[]) => any>(runTree: RunTree, fn: Fn): Promise<Awaited<ReturnType<Fn>>>;
|
|
20
22
|
export declare const ROOT: unique symbol;
|
|
21
23
|
export declare function isTraceableFunction(x: unknown): x is TraceableFunction<any>;
|
|
@@ -23,23 +23,13 @@ class AsyncLocalStorageProvider {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
export const AsyncLocalStorageProviderSingleton = new AsyncLocalStorageProvider();
|
|
26
|
-
|
|
27
|
-
* Return the current run tree from within a traceable-wrapped function.
|
|
28
|
-
* Will throw an error if called outside of a traceable function.
|
|
29
|
-
*
|
|
30
|
-
* @returns The run tree for the given context.
|
|
31
|
-
*/
|
|
32
|
-
export const getCurrentRunTree = () => {
|
|
26
|
+
export function getCurrentRunTree(permitAbsentRunTree = false) {
|
|
33
27
|
const runTree = AsyncLocalStorageProviderSingleton.getInstance().getStore();
|
|
34
|
-
if (!isRunTree(runTree)) {
|
|
35
|
-
throw new Error(
|
|
36
|
-
"Could not get the current run tree.",
|
|
37
|
-
"",
|
|
38
|
-
"Please make sure you are calling this method within a traceable function and that tracing is enabled.",
|
|
39
|
-
].join("\n"));
|
|
28
|
+
if (!permitAbsentRunTree && !isRunTree(runTree)) {
|
|
29
|
+
throw new Error("Could not get the current run tree.\n\nPlease make sure you are calling this method within a traceable function and that tracing is enabled.");
|
|
40
30
|
}
|
|
41
31
|
return runTree;
|
|
42
|
-
}
|
|
32
|
+
}
|
|
43
33
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
34
|
export function withRunTree(runTree, fn) {
|
|
45
35
|
const storage = AsyncLocalStorageProviderSingleton.getInstance();
|
package/dist/traceable.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { TraceableFunction } from "./singletons/types.js";
|
|
|
15
15
|
* @param config Additional metadata such as name, tags or providing
|
|
16
16
|
* a custom LangSmith client instance
|
|
17
17
|
*/
|
|
18
|
-
export declare function traceable<Func extends (...args: any[]) => any>(wrappedFunc: Func, config?: Partial<RunTreeConfig
|
|
18
|
+
export declare function traceable<Func extends (...args: any[]) => any>(wrappedFunc: Func, config?: Partial<Omit<RunTreeConfig, "inputs" | "outputs">> & {
|
|
19
19
|
aggregator?: (args: any[]) => any;
|
|
20
20
|
argsConfigPath?: [number] | [number, string];
|
|
21
21
|
__finalTracedIteratorKey?: string;
|
|
@@ -18,7 +18,7 @@ function encodeString(str) {
|
|
|
18
18
|
return encoder.encode(str);
|
|
19
19
|
}
|
|
20
20
|
// Regular stringify
|
|
21
|
-
function serialize(obj, replacer, spacer, options) {
|
|
21
|
+
function serialize(obj, errorContext, replacer, spacer, options) {
|
|
22
22
|
try {
|
|
23
23
|
const str = JSON.stringify(obj, replacer, spacer);
|
|
24
24
|
return encodeString(str);
|
|
@@ -26,10 +26,10 @@ function serialize(obj, replacer, spacer, options) {
|
|
|
26
26
|
catch (e) {
|
|
27
27
|
// Fall back to more complex stringify if circular reference
|
|
28
28
|
if (!e.message?.includes("Converting circular structure to JSON")) {
|
|
29
|
-
console.warn(
|
|
29
|
+
console.warn(`[WARNING]: LangSmith received unserializable value.${errorContext ? `\nContext: ${errorContext}` : ""}`);
|
|
30
30
|
return encodeString("[Unserializable]");
|
|
31
31
|
}
|
|
32
|
-
console.warn(
|
|
32
|
+
console.warn(`[WARNING]: LangSmith received circular JSON. This will decrease tracer performance. ${errorContext ? `\nContext: ${errorContext}` : ""}`);
|
|
33
33
|
if (typeof options === "undefined") {
|
|
34
34
|
options = defaultOptions();
|
|
35
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function serialize(obj: any, replacer?: any, spacer?: any, options?: any): Uint8Array<ArrayBufferLike>;
|
|
1
|
+
export declare function serialize(obj: any, errorContext?: any, replacer?: any, spacer?: any, options?: any): Uint8Array<ArrayBufferLike>;
|
|
@@ -15,7 +15,7 @@ function encodeString(str) {
|
|
|
15
15
|
return encoder.encode(str);
|
|
16
16
|
}
|
|
17
17
|
// Regular stringify
|
|
18
|
-
export function serialize(obj, replacer, spacer, options) {
|
|
18
|
+
export function serialize(obj, errorContext, replacer, spacer, options) {
|
|
19
19
|
try {
|
|
20
20
|
const str = JSON.stringify(obj, replacer, spacer);
|
|
21
21
|
return encodeString(str);
|
|
@@ -23,10 +23,10 @@ export function serialize(obj, replacer, spacer, options) {
|
|
|
23
23
|
catch (e) {
|
|
24
24
|
// Fall back to more complex stringify if circular reference
|
|
25
25
|
if (!e.message?.includes("Converting circular structure to JSON")) {
|
|
26
|
-
console.warn(
|
|
26
|
+
console.warn(`[WARNING]: LangSmith received unserializable value.${errorContext ? `\nContext: ${errorContext}` : ""}`);
|
|
27
27
|
return encodeString("[Unserializable]");
|
|
28
28
|
}
|
|
29
|
-
console.warn(
|
|
29
|
+
console.warn(`[WARNING]: LangSmith received circular JSON. This will decrease tracer performance. ${errorContext ? `\nContext: ${errorContext}` : ""}`);
|
|
30
30
|
if (typeof options === "undefined") {
|
|
31
31
|
options = defaultOptions();
|
|
32
32
|
}
|
|
@@ -29,7 +29,7 @@ type PatchedOpenAIClient<T extends OpenAIType> = T & {
|
|
|
29
29
|
} & {
|
|
30
30
|
(arg: OpenAI.ChatCompletionCreateParamsNonStreaming, arg2?: OpenAI.RequestOptions & {
|
|
31
31
|
langsmithExtra?: ExtraRunTreeConfig;
|
|
32
|
-
}): APIPromise<OpenAI.
|
|
32
|
+
}): APIPromise<OpenAI.ChatCompletion>;
|
|
33
33
|
};
|
|
34
34
|
};
|
|
35
35
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "langsmith",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.29",
|
|
4
4
|
"description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",
|
|
5
5
|
"packageManager": "yarn@1.22.19",
|
|
6
6
|
"files": [
|
|
@@ -142,9 +142,9 @@
|
|
|
142
142
|
"@langchain/openai": "^0.3.11",
|
|
143
143
|
"@opentelemetry/api": "^1.9.0",
|
|
144
144
|
"@opentelemetry/auto-instrumentations-node": "^0.58.0",
|
|
145
|
+
"@opentelemetry/sdk-node": "^0.200.0",
|
|
145
146
|
"@opentelemetry/sdk-trace-base": "^2.0.0",
|
|
146
147
|
"@opentelemetry/sdk-trace-node": "^2.0.0",
|
|
147
|
-
"@opentelemetry/sdk-node": "^0.200.0",
|
|
148
148
|
"@tsconfig/recommended": "^1.0.2",
|
|
149
149
|
"@types/jest": "^29.5.1",
|
|
150
150
|
"@typescript-eslint/eslint-plugin": "^5.59.8",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"typedoc": "^0.27.6",
|
|
169
169
|
"typedoc-plugin-expand-object-like-types": "^0.1.2",
|
|
170
170
|
"typescript": "^5.4.5",
|
|
171
|
-
"vitest": "^3.
|
|
171
|
+
"vitest": "^3.1.3",
|
|
172
172
|
"zod": "^3.23.8"
|
|
173
173
|
},
|
|
174
174
|
"peerDependencies": {
|