langsmith 0.3.81 → 0.3.82
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/README.md +2 -1
- package/dist/evaluation/evaluate_comparative.cjs +2 -2
- package/dist/evaluation/evaluate_comparative.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/run_trees.cjs +212 -8
- package/dist/run_trees.d.ts +5 -0
- package/dist/run_trees.js +213 -9
- package/dist/singletons/constants.cjs +2 -1
- package/dist/singletons/constants.d.ts +1 -0
- package/dist/singletons/constants.js +1 -0
- package/dist/utils/async_caller.cjs +3 -3
- package/dist/utils/async_caller.js +2 -2
- package/dist/utils/context_vars.cjs +31 -0
- package/dist/utils/context_vars.d.ts +8 -0
- package/dist/utils/context_vars.js +27 -0
- package/dist/utils/is-network-error/index.cjs +42 -0
- package/dist/utils/is-network-error/index.d.ts +1 -0
- package/dist/utils/is-network-error/index.js +39 -0
- package/dist/utils/jestlike/reporter.d.ts +1 -1
- package/dist/utils/p-retry/index.cjs +200 -0
- package/dist/utils/p-retry/index.d.ts +5 -0
- package/dist/utils/p-retry/index.js +191 -0
- package/dist/vitest/reporter.cjs +6 -0
- package/dist/vitest/reporter.d.mts +6 -0
- package/dist/vitest/reporter.d.ts +2 -0
- package/dist/vitest/reporter.js +7 -1
- package/dist/vitest/reporter.mjs +20 -1
- package/dist/vitest/utils/reporter.cjs +14 -1
- package/dist/vitest/utils/reporter.d.ts +30 -0
- package/dist/vitest/utils/reporter.js +12 -0
- package/package.json +1 -2
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.AsyncCaller = void 0;
|
|
7
|
-
const
|
|
7
|
+
const index_js_1 = __importDefault(require("../utils/p-retry/index.cjs"));
|
|
8
8
|
const p_queue_1 = __importDefault(require("p-queue"));
|
|
9
9
|
const STATUS_RETRYABLE = [
|
|
10
10
|
408, // Request Timeout
|
|
@@ -100,7 +100,7 @@ class AsyncCaller {
|
|
|
100
100
|
this.queueSizeBytes += sizeBytes;
|
|
101
101
|
}
|
|
102
102
|
const onFailedResponseHook = this.onFailedResponseHook;
|
|
103
|
-
let promise = this.queue.add(() => (0,
|
|
103
|
+
let promise = this.queue.add(() => (0, index_js_1.default)(() => callable(...args).catch((error) => {
|
|
104
104
|
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
105
105
|
if (error instanceof Error) {
|
|
106
106
|
throw error;
|
|
@@ -110,7 +110,7 @@ class AsyncCaller {
|
|
|
110
110
|
}
|
|
111
111
|
}), {
|
|
112
112
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
|
-
async onFailedAttempt(error) {
|
|
113
|
+
async onFailedAttempt({ error }) {
|
|
114
114
|
if (error.message.startsWith("Cancel") ||
|
|
115
115
|
error.message.startsWith("TimeoutError") ||
|
|
116
116
|
error.name === "TimeoutError" ||
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import pRetry from "p-retry";
|
|
1
|
+
import pRetry from "../utils/p-retry/index.js";
|
|
2
2
|
import PQueueMod from "p-queue";
|
|
3
3
|
const STATUS_RETRYABLE = [
|
|
4
4
|
408, // Request Timeout
|
|
@@ -104,7 +104,7 @@ export class AsyncCaller {
|
|
|
104
104
|
}
|
|
105
105
|
}), {
|
|
106
106
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
107
|
-
async onFailedAttempt(error) {
|
|
107
|
+
async onFailedAttempt({ error }) {
|
|
108
108
|
if (error.message.startsWith("Cancel") ||
|
|
109
109
|
error.message.startsWith("TimeoutError") ||
|
|
110
110
|
error.name === "TimeoutError" ||
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getContextVar = getContextVar;
|
|
4
|
+
exports.setContextVar = setContextVar;
|
|
5
|
+
const constants_js_1 = require("../singletons/constants.cjs");
|
|
6
|
+
/**
|
|
7
|
+
* Get a context variable from a run tree instance
|
|
8
|
+
*/
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
function getContextVar(runTree, key) {
|
|
11
|
+
if (constants_js_1._LC_CONTEXT_VARIABLES_KEY in runTree) {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
const contextVars = runTree[constants_js_1._LC_CONTEXT_VARIABLES_KEY];
|
|
14
|
+
return contextVars[key];
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Set a context variable on a run tree instance
|
|
20
|
+
*/
|
|
21
|
+
function setContextVar(
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
runTree, key, value) {
|
|
24
|
+
const contextVars = constants_js_1._LC_CONTEXT_VARIABLES_KEY in runTree
|
|
25
|
+
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
runTree[constants_js_1._LC_CONTEXT_VARIABLES_KEY]
|
|
27
|
+
: {};
|
|
28
|
+
contextVars[key] = value;
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
runTree[constants_js_1._LC_CONTEXT_VARIABLES_KEY] = contextVars;
|
|
31
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get a context variable from a run tree instance
|
|
3
|
+
*/
|
|
4
|
+
export declare function getContextVar(runTree: any, key: symbol): unknown;
|
|
5
|
+
/**
|
|
6
|
+
* Set a context variable on a run tree instance
|
|
7
|
+
*/
|
|
8
|
+
export declare function setContextVar(runTree: any, key: symbol, value: unknown): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { _LC_CONTEXT_VARIABLES_KEY } from "../singletons/constants.js";
|
|
2
|
+
/**
|
|
3
|
+
* Get a context variable from a run tree instance
|
|
4
|
+
*/
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
export function getContextVar(runTree, key) {
|
|
7
|
+
if (_LC_CONTEXT_VARIABLES_KEY in runTree) {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
const contextVars = runTree[_LC_CONTEXT_VARIABLES_KEY];
|
|
10
|
+
return contextVars[key];
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Set a context variable on a run tree instance
|
|
16
|
+
*/
|
|
17
|
+
export function setContextVar(
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
runTree, key, value) {
|
|
20
|
+
const contextVars = _LC_CONTEXT_VARIABLES_KEY in runTree
|
|
21
|
+
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
runTree[_LC_CONTEXT_VARIABLES_KEY]
|
|
23
|
+
: {};
|
|
24
|
+
contextVars[key] = value;
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
runTree[_LC_CONTEXT_VARIABLES_KEY] = contextVars;
|
|
27
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = isNetworkError;
|
|
4
|
+
/* eslint-disable */
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
// is-network-error vendored to avoid import issues
|
|
7
|
+
// Source: https://github.com/sindresorhus/is-network-error
|
|
8
|
+
const objectToString = Object.prototype.toString;
|
|
9
|
+
const isError = (value) => objectToString.call(value) === "[object Error]";
|
|
10
|
+
const errorMessages = new Set([
|
|
11
|
+
"network error", // Chrome
|
|
12
|
+
"Failed to fetch", // Chrome
|
|
13
|
+
"NetworkError when attempting to fetch resource.", // Firefox
|
|
14
|
+
"The Internet connection appears to be offline.", // Safari 16
|
|
15
|
+
"Network request failed", // `cross-fetch`
|
|
16
|
+
"fetch failed", // Undici (Node.js)
|
|
17
|
+
"terminated", // Undici (Node.js)
|
|
18
|
+
" A network error occurred.", // Bun (WebKit)
|
|
19
|
+
"Network connection lost", // Cloudflare Workers (fetch)
|
|
20
|
+
]);
|
|
21
|
+
function isNetworkError(error) {
|
|
22
|
+
const isValid = error &&
|
|
23
|
+
isError(error) &&
|
|
24
|
+
error.name === "TypeError" &&
|
|
25
|
+
typeof error.message === "string";
|
|
26
|
+
if (!isValid) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const { message, stack } = error;
|
|
30
|
+
// Safari 17+ has generic message but no stack for network errors
|
|
31
|
+
if (message === "Load failed") {
|
|
32
|
+
return (stack === undefined ||
|
|
33
|
+
// Sentry adds its own stack trace to the fetch error, so also check for that
|
|
34
|
+
"__sentry_captured__" in error);
|
|
35
|
+
}
|
|
36
|
+
// Deno network errors start with specific text
|
|
37
|
+
if (message.startsWith("error sending request for url")) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
// Standard network error messages
|
|
41
|
+
return errorMessages.has(message);
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function isNetworkError(error: any): boolean;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
// is-network-error vendored to avoid import issues
|
|
4
|
+
// Source: https://github.com/sindresorhus/is-network-error
|
|
5
|
+
const objectToString = Object.prototype.toString;
|
|
6
|
+
const isError = (value) => objectToString.call(value) === "[object Error]";
|
|
7
|
+
const errorMessages = new Set([
|
|
8
|
+
"network error", // Chrome
|
|
9
|
+
"Failed to fetch", // Chrome
|
|
10
|
+
"NetworkError when attempting to fetch resource.", // Firefox
|
|
11
|
+
"The Internet connection appears to be offline.", // Safari 16
|
|
12
|
+
"Network request failed", // `cross-fetch`
|
|
13
|
+
"fetch failed", // Undici (Node.js)
|
|
14
|
+
"terminated", // Undici (Node.js)
|
|
15
|
+
" A network error occurred.", // Bun (WebKit)
|
|
16
|
+
"Network connection lost", // Cloudflare Workers (fetch)
|
|
17
|
+
]);
|
|
18
|
+
export default function isNetworkError(error) {
|
|
19
|
+
const isValid = error &&
|
|
20
|
+
isError(error) &&
|
|
21
|
+
error.name === "TypeError" &&
|
|
22
|
+
typeof error.message === "string";
|
|
23
|
+
if (!isValid) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const { message, stack } = error;
|
|
27
|
+
// Safari 17+ has generic message but no stack for network errors
|
|
28
|
+
if (message === "Load failed") {
|
|
29
|
+
return (stack === undefined ||
|
|
30
|
+
// Sentry adds its own stack trace to the fetch error, so also check for that
|
|
31
|
+
"__sentry_captured__" in error);
|
|
32
|
+
}
|
|
33
|
+
// Deno network errors start with specific text
|
|
34
|
+
if (message.startsWith("error sending request for url")) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
// Standard network error messages
|
|
38
|
+
return errorMessages.has(message);
|
|
39
|
+
}
|
|
@@ -2,4 +2,4 @@ export declare function printReporterTable(testSuiteName: string, results: {
|
|
|
2
2
|
title: string;
|
|
3
3
|
duration: number;
|
|
4
4
|
status: "pass" | "passed" | "fail" | "failed" | "pending" | "skipped";
|
|
5
|
-
}[], testStatus: "pass" | "skip" | "fail", failureMessage?: string): Promise<void>;
|
|
5
|
+
}[], testStatus: "pass" | "skip" | "fail" | "passed" | "failed" | "skipped", failureMessage?: string): Promise<void>;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AbortError = void 0;
|
|
7
|
+
exports.default = pRetry;
|
|
8
|
+
exports.makeRetriable = makeRetriable;
|
|
9
|
+
/* eslint-disable */
|
|
10
|
+
// @ts-nocheck
|
|
11
|
+
// p-retry code vendored to avoid import issues
|
|
12
|
+
// Source: https://github.com/sindresorhus/p-retry
|
|
13
|
+
const index_js_1 = __importDefault(require("../is-network-error/index.cjs"));
|
|
14
|
+
function validateRetries(retries) {
|
|
15
|
+
if (typeof retries === "number") {
|
|
16
|
+
if (retries < 0) {
|
|
17
|
+
throw new TypeError("Expected `retries` to be a non-negative number.");
|
|
18
|
+
}
|
|
19
|
+
if (Number.isNaN(retries)) {
|
|
20
|
+
throw new TypeError("Expected `retries` to be a valid number or Infinity, got NaN.");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else if (retries !== undefined) {
|
|
24
|
+
throw new TypeError("Expected `retries` to be a number or Infinity.");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function validateNumberOption(name, value, { min = 0, allowInfinity = false } = {}) {
|
|
28
|
+
if (value === undefined) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
32
|
+
throw new TypeError(`Expected \`${name}\` to be a number${allowInfinity ? " or Infinity" : ""}.`);
|
|
33
|
+
}
|
|
34
|
+
if (!allowInfinity && !Number.isFinite(value)) {
|
|
35
|
+
throw new TypeError(`Expected \`${name}\` to be a finite number.`);
|
|
36
|
+
}
|
|
37
|
+
if (value < min) {
|
|
38
|
+
throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
class AbortError extends Error {
|
|
42
|
+
constructor(message) {
|
|
43
|
+
super();
|
|
44
|
+
if (message instanceof Error) {
|
|
45
|
+
this.originalError = message;
|
|
46
|
+
({ message } = message);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.originalError = new Error(message);
|
|
50
|
+
this.originalError.stack = this.stack;
|
|
51
|
+
}
|
|
52
|
+
this.name = "AbortError";
|
|
53
|
+
this.message = message;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.AbortError = AbortError;
|
|
57
|
+
function calculateDelay(retriesConsumed, options) {
|
|
58
|
+
const attempt = Math.max(1, retriesConsumed + 1);
|
|
59
|
+
const random = options.randomize ? Math.random() + 1 : 1;
|
|
60
|
+
let timeout = Math.round(random * options.minTimeout * options.factor ** (attempt - 1));
|
|
61
|
+
timeout = Math.min(timeout, options.maxTimeout);
|
|
62
|
+
return timeout;
|
|
63
|
+
}
|
|
64
|
+
function calculateRemainingTime(start, max) {
|
|
65
|
+
if (!Number.isFinite(max)) {
|
|
66
|
+
return max;
|
|
67
|
+
}
|
|
68
|
+
return max - (performance.now() - start);
|
|
69
|
+
}
|
|
70
|
+
async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTime, options, }) {
|
|
71
|
+
const normalizedError = error instanceof Error
|
|
72
|
+
? error
|
|
73
|
+
: new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`);
|
|
74
|
+
if (normalizedError instanceof AbortError) {
|
|
75
|
+
throw normalizedError.originalError;
|
|
76
|
+
}
|
|
77
|
+
const retriesLeft = Number.isFinite(options.retries)
|
|
78
|
+
? Math.max(0, options.retries - retriesConsumed)
|
|
79
|
+
: options.retries;
|
|
80
|
+
const maxRetryTime = options.maxRetryTime ?? Number.POSITIVE_INFINITY;
|
|
81
|
+
const context = Object.freeze({
|
|
82
|
+
error: normalizedError,
|
|
83
|
+
attemptNumber,
|
|
84
|
+
retriesLeft,
|
|
85
|
+
retriesConsumed,
|
|
86
|
+
});
|
|
87
|
+
await options.onFailedAttempt(context);
|
|
88
|
+
if (calculateRemainingTime(startTime, maxRetryTime) <= 0) {
|
|
89
|
+
throw normalizedError;
|
|
90
|
+
}
|
|
91
|
+
const consumeRetry = await options.shouldConsumeRetry(context);
|
|
92
|
+
const remainingTime = calculateRemainingTime(startTime, maxRetryTime);
|
|
93
|
+
if (remainingTime <= 0 || retriesLeft <= 0) {
|
|
94
|
+
throw normalizedError;
|
|
95
|
+
}
|
|
96
|
+
if (normalizedError instanceof TypeError &&
|
|
97
|
+
!(0, index_js_1.default)(normalizedError)) {
|
|
98
|
+
if (consumeRetry) {
|
|
99
|
+
throw normalizedError;
|
|
100
|
+
}
|
|
101
|
+
options.signal?.throwIfAborted();
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (!(await options.shouldRetry(context))) {
|
|
105
|
+
throw normalizedError;
|
|
106
|
+
}
|
|
107
|
+
if (!consumeRetry) {
|
|
108
|
+
options.signal?.throwIfAborted();
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const delayTime = calculateDelay(retriesConsumed, options);
|
|
112
|
+
const finalDelay = Math.min(delayTime, remainingTime);
|
|
113
|
+
if (finalDelay > 0) {
|
|
114
|
+
await new Promise((resolve, reject) => {
|
|
115
|
+
const onAbort = () => {
|
|
116
|
+
clearTimeout(timeoutToken);
|
|
117
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
118
|
+
reject(options.signal.reason);
|
|
119
|
+
};
|
|
120
|
+
const timeoutToken = setTimeout(() => {
|
|
121
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
122
|
+
resolve();
|
|
123
|
+
}, finalDelay);
|
|
124
|
+
if (options.unref) {
|
|
125
|
+
timeoutToken.unref?.();
|
|
126
|
+
}
|
|
127
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
options.signal?.throwIfAborted();
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
async function pRetry(input, options = {}) {
|
|
134
|
+
options = { ...options };
|
|
135
|
+
validateRetries(options.retries);
|
|
136
|
+
if (Object.hasOwn(options, "forever")) {
|
|
137
|
+
throw new Error("The `forever` option is no longer supported. For many use-cases, you can set `retries: Infinity` instead.");
|
|
138
|
+
}
|
|
139
|
+
options.retries ??= 10;
|
|
140
|
+
options.factor ??= 2;
|
|
141
|
+
options.minTimeout ??= 1000;
|
|
142
|
+
options.maxTimeout ??= Number.POSITIVE_INFINITY;
|
|
143
|
+
options.maxRetryTime ??= Number.POSITIVE_INFINITY;
|
|
144
|
+
options.randomize ??= false;
|
|
145
|
+
options.onFailedAttempt ??= () => { };
|
|
146
|
+
options.shouldRetry ??= () => true;
|
|
147
|
+
options.shouldConsumeRetry ??= () => true;
|
|
148
|
+
// Validate numeric options and normalize edge cases
|
|
149
|
+
validateNumberOption("factor", options.factor, {
|
|
150
|
+
min: 0,
|
|
151
|
+
allowInfinity: false,
|
|
152
|
+
});
|
|
153
|
+
validateNumberOption("minTimeout", options.minTimeout, {
|
|
154
|
+
min: 0,
|
|
155
|
+
allowInfinity: false,
|
|
156
|
+
});
|
|
157
|
+
validateNumberOption("maxTimeout", options.maxTimeout, {
|
|
158
|
+
min: 0,
|
|
159
|
+
allowInfinity: true,
|
|
160
|
+
});
|
|
161
|
+
validateNumberOption("maxRetryTime", options.maxRetryTime, {
|
|
162
|
+
min: 0,
|
|
163
|
+
allowInfinity: true,
|
|
164
|
+
});
|
|
165
|
+
// Treat non-positive factor as 1 to avoid zero backoff or negative behavior
|
|
166
|
+
if (!(options.factor > 0)) {
|
|
167
|
+
options.factor = 1;
|
|
168
|
+
}
|
|
169
|
+
options.signal?.throwIfAborted();
|
|
170
|
+
let attemptNumber = 0;
|
|
171
|
+
let retriesConsumed = 0;
|
|
172
|
+
const startTime = performance.now();
|
|
173
|
+
while (Number.isFinite(options.retries) ? retriesConsumed <= options.retries : true) {
|
|
174
|
+
attemptNumber++;
|
|
175
|
+
try {
|
|
176
|
+
options.signal?.throwIfAborted();
|
|
177
|
+
const result = await input(attemptNumber);
|
|
178
|
+
options.signal?.throwIfAborted();
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
if (await onAttemptFailure({
|
|
183
|
+
error,
|
|
184
|
+
attemptNumber,
|
|
185
|
+
retriesConsumed,
|
|
186
|
+
startTime,
|
|
187
|
+
options,
|
|
188
|
+
})) {
|
|
189
|
+
retriesConsumed++;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Should not reach here, but in case it does, throw an error
|
|
194
|
+
throw new Error("Retry attempts exhausted without throwing an error.");
|
|
195
|
+
}
|
|
196
|
+
function makeRetriable(function_, options) {
|
|
197
|
+
return function (...arguments_) {
|
|
198
|
+
return pRetry(() => function_.apply(this, arguments_), options);
|
|
199
|
+
};
|
|
200
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
// p-retry code vendored to avoid import issues
|
|
4
|
+
// Source: https://github.com/sindresorhus/p-retry
|
|
5
|
+
import isNetworkError from "../is-network-error/index.js";
|
|
6
|
+
function validateRetries(retries) {
|
|
7
|
+
if (typeof retries === "number") {
|
|
8
|
+
if (retries < 0) {
|
|
9
|
+
throw new TypeError("Expected `retries` to be a non-negative number.");
|
|
10
|
+
}
|
|
11
|
+
if (Number.isNaN(retries)) {
|
|
12
|
+
throw new TypeError("Expected `retries` to be a valid number or Infinity, got NaN.");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
else if (retries !== undefined) {
|
|
16
|
+
throw new TypeError("Expected `retries` to be a number or Infinity.");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function validateNumberOption(name, value, { min = 0, allowInfinity = false } = {}) {
|
|
20
|
+
if (value === undefined) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
24
|
+
throw new TypeError(`Expected \`${name}\` to be a number${allowInfinity ? " or Infinity" : ""}.`);
|
|
25
|
+
}
|
|
26
|
+
if (!allowInfinity && !Number.isFinite(value)) {
|
|
27
|
+
throw new TypeError(`Expected \`${name}\` to be a finite number.`);
|
|
28
|
+
}
|
|
29
|
+
if (value < min) {
|
|
30
|
+
throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class AbortError extends Error {
|
|
34
|
+
constructor(message) {
|
|
35
|
+
super();
|
|
36
|
+
if (message instanceof Error) {
|
|
37
|
+
this.originalError = message;
|
|
38
|
+
({ message } = message);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
this.originalError = new Error(message);
|
|
42
|
+
this.originalError.stack = this.stack;
|
|
43
|
+
}
|
|
44
|
+
this.name = "AbortError";
|
|
45
|
+
this.message = message;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function calculateDelay(retriesConsumed, options) {
|
|
49
|
+
const attempt = Math.max(1, retriesConsumed + 1);
|
|
50
|
+
const random = options.randomize ? Math.random() + 1 : 1;
|
|
51
|
+
let timeout = Math.round(random * options.minTimeout * options.factor ** (attempt - 1));
|
|
52
|
+
timeout = Math.min(timeout, options.maxTimeout);
|
|
53
|
+
return timeout;
|
|
54
|
+
}
|
|
55
|
+
function calculateRemainingTime(start, max) {
|
|
56
|
+
if (!Number.isFinite(max)) {
|
|
57
|
+
return max;
|
|
58
|
+
}
|
|
59
|
+
return max - (performance.now() - start);
|
|
60
|
+
}
|
|
61
|
+
async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTime, options, }) {
|
|
62
|
+
const normalizedError = error instanceof Error
|
|
63
|
+
? error
|
|
64
|
+
: new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`);
|
|
65
|
+
if (normalizedError instanceof AbortError) {
|
|
66
|
+
throw normalizedError.originalError;
|
|
67
|
+
}
|
|
68
|
+
const retriesLeft = Number.isFinite(options.retries)
|
|
69
|
+
? Math.max(0, options.retries - retriesConsumed)
|
|
70
|
+
: options.retries;
|
|
71
|
+
const maxRetryTime = options.maxRetryTime ?? Number.POSITIVE_INFINITY;
|
|
72
|
+
const context = Object.freeze({
|
|
73
|
+
error: normalizedError,
|
|
74
|
+
attemptNumber,
|
|
75
|
+
retriesLeft,
|
|
76
|
+
retriesConsumed,
|
|
77
|
+
});
|
|
78
|
+
await options.onFailedAttempt(context);
|
|
79
|
+
if (calculateRemainingTime(startTime, maxRetryTime) <= 0) {
|
|
80
|
+
throw normalizedError;
|
|
81
|
+
}
|
|
82
|
+
const consumeRetry = await options.shouldConsumeRetry(context);
|
|
83
|
+
const remainingTime = calculateRemainingTime(startTime, maxRetryTime);
|
|
84
|
+
if (remainingTime <= 0 || retriesLeft <= 0) {
|
|
85
|
+
throw normalizedError;
|
|
86
|
+
}
|
|
87
|
+
if (normalizedError instanceof TypeError &&
|
|
88
|
+
!isNetworkError(normalizedError)) {
|
|
89
|
+
if (consumeRetry) {
|
|
90
|
+
throw normalizedError;
|
|
91
|
+
}
|
|
92
|
+
options.signal?.throwIfAborted();
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
if (!(await options.shouldRetry(context))) {
|
|
96
|
+
throw normalizedError;
|
|
97
|
+
}
|
|
98
|
+
if (!consumeRetry) {
|
|
99
|
+
options.signal?.throwIfAborted();
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const delayTime = calculateDelay(retriesConsumed, options);
|
|
103
|
+
const finalDelay = Math.min(delayTime, remainingTime);
|
|
104
|
+
if (finalDelay > 0) {
|
|
105
|
+
await new Promise((resolve, reject) => {
|
|
106
|
+
const onAbort = () => {
|
|
107
|
+
clearTimeout(timeoutToken);
|
|
108
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
109
|
+
reject(options.signal.reason);
|
|
110
|
+
};
|
|
111
|
+
const timeoutToken = setTimeout(() => {
|
|
112
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
113
|
+
resolve();
|
|
114
|
+
}, finalDelay);
|
|
115
|
+
if (options.unref) {
|
|
116
|
+
timeoutToken.unref?.();
|
|
117
|
+
}
|
|
118
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
options.signal?.throwIfAborted();
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
export default async function pRetry(input, options = {}) {
|
|
125
|
+
options = { ...options };
|
|
126
|
+
validateRetries(options.retries);
|
|
127
|
+
if (Object.hasOwn(options, "forever")) {
|
|
128
|
+
throw new Error("The `forever` option is no longer supported. For many use-cases, you can set `retries: Infinity` instead.");
|
|
129
|
+
}
|
|
130
|
+
options.retries ??= 10;
|
|
131
|
+
options.factor ??= 2;
|
|
132
|
+
options.minTimeout ??= 1000;
|
|
133
|
+
options.maxTimeout ??= Number.POSITIVE_INFINITY;
|
|
134
|
+
options.maxRetryTime ??= Number.POSITIVE_INFINITY;
|
|
135
|
+
options.randomize ??= false;
|
|
136
|
+
options.onFailedAttempt ??= () => { };
|
|
137
|
+
options.shouldRetry ??= () => true;
|
|
138
|
+
options.shouldConsumeRetry ??= () => true;
|
|
139
|
+
// Validate numeric options and normalize edge cases
|
|
140
|
+
validateNumberOption("factor", options.factor, {
|
|
141
|
+
min: 0,
|
|
142
|
+
allowInfinity: false,
|
|
143
|
+
});
|
|
144
|
+
validateNumberOption("minTimeout", options.minTimeout, {
|
|
145
|
+
min: 0,
|
|
146
|
+
allowInfinity: false,
|
|
147
|
+
});
|
|
148
|
+
validateNumberOption("maxTimeout", options.maxTimeout, {
|
|
149
|
+
min: 0,
|
|
150
|
+
allowInfinity: true,
|
|
151
|
+
});
|
|
152
|
+
validateNumberOption("maxRetryTime", options.maxRetryTime, {
|
|
153
|
+
min: 0,
|
|
154
|
+
allowInfinity: true,
|
|
155
|
+
});
|
|
156
|
+
// Treat non-positive factor as 1 to avoid zero backoff or negative behavior
|
|
157
|
+
if (!(options.factor > 0)) {
|
|
158
|
+
options.factor = 1;
|
|
159
|
+
}
|
|
160
|
+
options.signal?.throwIfAborted();
|
|
161
|
+
let attemptNumber = 0;
|
|
162
|
+
let retriesConsumed = 0;
|
|
163
|
+
const startTime = performance.now();
|
|
164
|
+
while (Number.isFinite(options.retries) ? retriesConsumed <= options.retries : true) {
|
|
165
|
+
attemptNumber++;
|
|
166
|
+
try {
|
|
167
|
+
options.signal?.throwIfAborted();
|
|
168
|
+
const result = await input(attemptNumber);
|
|
169
|
+
options.signal?.throwIfAborted();
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (await onAttemptFailure({
|
|
174
|
+
error,
|
|
175
|
+
attemptNumber,
|
|
176
|
+
retriesConsumed,
|
|
177
|
+
startTime,
|
|
178
|
+
options,
|
|
179
|
+
})) {
|
|
180
|
+
retriesConsumed++;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Should not reach here, but in case it does, throw an error
|
|
185
|
+
throw new Error("Retry attempts exhausted without throwing an error.");
|
|
186
|
+
}
|
|
187
|
+
export function makeRetriable(function_, options) {
|
|
188
|
+
return function (...arguments_) {
|
|
189
|
+
return pRetry(() => function_.apply(this, arguments_), options);
|
|
190
|
+
};
|
|
191
|
+
}
|
package/dist/vitest/reporter.cjs
CHANGED
|
@@ -10,5 +10,11 @@ class LangSmithEvalReporter extends reporters_1.DefaultReporter {
|
|
|
10
10
|
super.onFinished(files, errors);
|
|
11
11
|
await (0, reporter_js_1.printVitestReporterTable)(files, this.ctx);
|
|
12
12
|
}
|
|
13
|
+
// @ts-expect-error Vitest 4.x introduces a new `onTestRunEnd` method
|
|
14
|
+
async onTestRunEnd(testModules, unhandledErrors, reason) {
|
|
15
|
+
// @ts-expect-error Vitest 4.x introduces a new `onTestRunEnd` method
|
|
16
|
+
super.onTestRunEnd(testModules, unhandledErrors, reason);
|
|
17
|
+
await (0, reporter_js_1.printVitestTestModulesReporterTable)(testModules);
|
|
18
|
+
}
|
|
13
19
|
}
|
|
14
20
|
exports.default = LangSmithEvalReporter;
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import { type VitestTestModule } from "./utils/reporter.js";
|
|
1
2
|
declare const DefaultReporter: any;
|
|
2
3
|
declare class LangSmithEvalReporter extends DefaultReporter {
|
|
4
|
+
private skipOnFinished;
|
|
3
5
|
onFinished(files: unknown[], errors: unknown[]): Promise<void>;
|
|
6
|
+
onTestRunEnd(testModules: VitestTestModule[], unhandledErrors: {
|
|
7
|
+
message: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
}[], reason: "passed" | "interrupted" | "failed"): Promise<void>;
|
|
4
10
|
}
|
|
5
11
|
export default LangSmithEvalReporter;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { DefaultReporter } from "vitest/reporters";
|
|
2
2
|
import { RunnerTestFile } from "vitest";
|
|
3
|
+
import { type VitestTestModule } from "./utils/reporter.js";
|
|
3
4
|
declare class LangSmithEvalReporter extends DefaultReporter {
|
|
4
5
|
onFinished(files: RunnerTestFile[], errors: unknown[]): Promise<void>;
|
|
6
|
+
onTestRunEnd(testModules: VitestTestModule[], unhandledErrors: unknown[], reason: "passed" | "interrupted" | "failed"): Promise<void>;
|
|
5
7
|
}
|
|
6
8
|
export default LangSmithEvalReporter;
|
package/dist/vitest/reporter.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3
3
|
// @ts-ignore Import throws an error in internal CJS build, but seems to work fine after build
|
|
4
4
|
import { DefaultReporter } from "vitest/reporters";
|
|
5
|
-
import { printVitestReporterTable } from "./utils/reporter.js";
|
|
5
|
+
import { printVitestReporterTable, printVitestTestModulesReporterTable, } from "./utils/reporter.js";
|
|
6
6
|
class LangSmithEvalReporter extends DefaultReporter {
|
|
7
7
|
async onFinished(files, errors) {
|
|
8
8
|
super.onFinished(files, errors);
|
|
9
9
|
await printVitestReporterTable(files, this.ctx);
|
|
10
10
|
}
|
|
11
|
+
// @ts-expect-error Vitest 4.x introduces a new `onTestRunEnd` method
|
|
12
|
+
async onTestRunEnd(testModules, unhandledErrors, reason) {
|
|
13
|
+
// @ts-expect-error Vitest 4.x introduces a new `onTestRunEnd` method
|
|
14
|
+
super.onTestRunEnd(testModules, unhandledErrors, reason);
|
|
15
|
+
await printVitestTestModulesReporterTable(testModules);
|
|
16
|
+
}
|
|
11
17
|
}
|
|
12
18
|
export default LangSmithEvalReporter;
|