diff --git a/js/eslint.config.ts b/js/eslint.config.ts index 22c71b817..6cf54f8c3 100644 --- a/js/eslint.config.ts +++ b/js/eslint.config.ts @@ -82,30 +82,6 @@ export default [ "@typescript-eslint/no-empty-object-type": "error", "@typescript-eslint/no-unsafe-function-type": "error", "@typescript-eslint/prefer-as-const": "error", - // Require node: protocol for Node.js built-in imports (for Deno compatibility) - // This plugin automatically detects ALL Node.js built-ins - no manual list needed! - "node-import/prefer-node-protocol": "error", - }, - }, - { - files: ["src/**/*.ts", "src/**/*.tsx"], - ignores: [ - "src/cli/**", - "src/debug-logger.ts", - "src/framework.ts", - "src/framework2.ts", - "src/isomorph.ts", - "src/sandbox.ts", - "src/template/**", - "src/reporters/**", - "src/prompt-cache/**", - "src/eval-parameters.ts", - "src/wrappers/**", - "src/instrumentation/**", - "src/auto-instrumentations/**", - "src/queue.bench.ts", - ], - rules: { "no-restricted-properties": [ "error", { @@ -139,6 +115,35 @@ export default [ message: "Use debugLogger instead of console for SDK logging.", }, ], + // Require node: protocol for Node.js built-in imports (for Deno compatibility) + // This plugin automatically detects ALL Node.js built-ins - no manual list needed! + "node-import/prefer-node-protocol": "error", + }, + }, + { + files: ["src/queue.bench.ts"], + rules: { + "no-restricted-properties": "off", + }, + }, + { + files: ["src/**/*.ts", "src/**/*.tsx"], + ignores: [ + "src/cli/**", + "src/debug-logger.ts", + "src/framework.ts", + "src/framework2.ts", + "src/isomorph.ts", + "src/sandbox.ts", + "src/template/**", + "src/reporters/**", + "src/prompt-cache/**", + "src/eval-parameters.ts", + "src/wrappers/**", + "src/instrumentation/**", + "src/auto-instrumentations/**", + ], + rules: { "no-restricted-imports": [ "error", { diff --git a/js/src/cli/functions/infer-source.ts b/js/src/cli/functions/infer-source.ts index 179b5c50d..73d6a977c 100644 --- a/js/src/cli/functions/infer-source.ts +++ b/js/src/cli/functions/infer-source.ts @@ -71,6 +71,7 @@ export async function findCodeDefinition({ if (location.type === "experiment" || location.type === "sandbox") { const evaluator = outFileModule.evaluators[location.eval_name]?.evaluator; if (!evaluator) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Warning: failed to find evaluator for ${location.eval_name}. Will not display preview.`, @@ -94,6 +95,7 @@ export async function findCodeDefinition({ } if (!fn) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Warning: failed to find ${locationToString(location)}. Will not display preview.`, @@ -118,6 +120,7 @@ export async function findCodeDefinition({ } if (columnNumber === -1) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Warning: failed to find code definition for ${fn.name}. Will not display preview.`, @@ -195,6 +198,7 @@ async function getTsModule() { try { tsModule = require("typescript"); } catch { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( "Failed to load TypeScript module. Will not use TypeScript to derive preview.", diff --git a/js/src/cli/functions/upload.ts b/js/src/cli/functions/upload.ts index ce67f44d9..b1ce0f429 100644 --- a/js/src/cli/functions/upload.ts +++ b/js/src/cli/functions/upload.ts @@ -82,6 +82,7 @@ export async function uploadHandleBundles({ setCurrent: boolean; defaultIfExists: IfExists; }) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( `Processing ${buildResults.length} ${pluralize("file", buildResults.length)}...`, ); @@ -276,6 +277,7 @@ export async function uploadHandleBundles({ const numUploaded = uploadResults.length; const numFailed = uploadResults.filter((result) => !result).length; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( `${numUploaded} ${pluralize("file", numUploaded)} uploaded ${ numFailed > 0 @@ -344,12 +346,14 @@ async function uploadBundles({ ); } catch (e) { if (showDetailedErrors) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(e); } const msg = e instanceof FailedHTTPResponse ? `Unable to upload your code. ${e.status} (${e.text}): ${e.data}` : `Unable to upload your code. You most likely need to update the API: ${e}`; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(warning(msg)); return false; } @@ -422,12 +426,14 @@ async function uploadBundles({ }); } catch (e) { if (showDetailedErrors) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(e); } const msg = e instanceof FailedHTTPResponse ? `Failed to save function definitions for '${sourceFile}'. ${e.status} (${e.text}): ${e.data}` : `Failed to save function definitions for '${sourceFile}'. You most likely need to update the API: ${e}`; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(warning(msg)); return false; } diff --git a/js/src/cli/index.ts b/js/src/cli/index.ts index 48a38be3f..863f19987 100755 --- a/js/src/cli/index.ts +++ b/js/src/cli/index.ts @@ -127,6 +127,7 @@ async function initExperiment( fallback: (_text: string, url: string) => url, }) : "locally"; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( chalk.cyan("▶") + ` Experiment ${chalk.bold(info.experimentName)} is running at ${linkText}`, @@ -219,13 +220,17 @@ function buildWatchPluginForEvaluator( name: "run-evalutator-on-end", setup(build: esbuild.PluginBuild) { build.onEnd(async (result) => { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Done building ${inFile}`); if (!result.outputFiles) { if (opts.showDetailedErrors) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(`Failed to compile ${inFile}`); + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(result.errors); } else { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(`Failed to compile ${inFile}: ${result.errors}`); } return; @@ -306,6 +311,7 @@ function buildWatchPluginForEvaluator( )) { const success = await reporter.reportRun(await Promise.all(results)); if (!success) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(error(`Reporter ${reporterName} failed.`)); } } @@ -421,9 +427,12 @@ export function handleBuildFailure({ if (terminateOnFailure) { throw result.error; } else if (showDetailedErrors) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(`Failed to compile ${result.sourceFile}`); + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(result.error); } else { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( `Failed to compile ${result.sourceFile}: ${result.error.message}`, ); @@ -466,6 +475,7 @@ function updateEvaluators( evaluators.reporters[reporterName] && evaluators.reporters[reporterName] !== reporter ) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Reporter '${reporterName}' already exists. Will skip '${reporterName}' from ${result.sourceFile}.`, @@ -486,12 +496,14 @@ async function runAndWatch({ onExit?: () => void; }) { const count = Object.keys(handles).length; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Watching ${pluralize("file", count, true)}...`); Object.values(handles).map((handle) => handle.watch()); ["SIGINT", "SIGTERM"].forEach((signal: string) => { process.on(signal, function () { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Stopped watching."); for (const handle of Object.values(handles)) { handle.destroy(); @@ -540,6 +552,7 @@ async function runOnce( if (opts.list) { for (const evaluator of evaluators.evaluators) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.log(evaluator.evaluator.evalName); } return true; @@ -581,6 +594,7 @@ async function runOnce( } }); + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( chalk.dim( `Processing ${chalk.bold(resultPromises.length)} evaluator${resultPromises.length === 1 ? "" : "s"}...`, @@ -588,6 +602,7 @@ async function runOnce( ); const allEvalsResults = await Promise.all(resultPromises); opts.progressReporter.stop(); + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(""); const evalReports: Record< @@ -685,6 +700,7 @@ async function collectFiles( try { pathStat = fs.lstatSync(inputPath); } catch (e) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(error(`Error reading ${inputPath}: ${e}`)); process.exit(1); } @@ -699,6 +715,7 @@ async function collectFiles( ) ) { const prefix = mode === "eval" ? ".eval" : ""; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Reading ${inputPath} because it was specified directly. Rename it to end in ${prefix}.ts or ` + @@ -848,6 +865,7 @@ export async function initializeHandles({ for (const inputPath of inputPaths) { const newFiles = await collectFiles(inputPath, mode); if (newFiles.length == 0) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Provided path ${inputPath} is not an eval file or a directory containing eval files, skipping...`, @@ -860,6 +878,7 @@ export async function initializeHandles({ } if (Object.keys(files).length == 0) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning("No eval files were found in any of the provided paths."), ); @@ -906,6 +925,7 @@ async function run(args: RunArgs) { // Load via dotenv library const loaded = dotenv.config({ path: args.env_file }); if (loaded.error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(error(`Error loading ${args.env_file}: ${loaded.error}`)); process.exit(1); } @@ -930,6 +950,7 @@ async function run(args: RunArgs) { }; if (args.list && args.watch) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(error("Cannot specify both --list and --watch.")); process.exit(1); } diff --git a/js/src/cli/reporters/eval.ts b/js/src/cli/reporters/eval.ts index f10c1fc17..5093bd464 100644 --- a/js/src/cli/reporters/eval.ts +++ b/js/src/cli/reporters/eval.ts @@ -174,6 +174,7 @@ export const fancyReporter: ReporterDef = { ); if (failingResults.length > 0) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( warning( `Evaluator ${evaluator.evalName} failed with ${pluralize("error", failingResults.length, true)}. This evaluation ("${evaluator.evalName}") will not be fully logged.`, @@ -186,6 +187,7 @@ export const fancyReporter: ReporterDef = { } } else if (verbose) { for (const result of failingResults) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(result); } } diff --git a/js/src/cli/util/bundle.ts b/js/src/cli/util/bundle.ts index dfb2b01c2..9eb18bced 100644 --- a/js/src/cli/util/bundle.ts +++ b/js/src/cli/util/bundle.ts @@ -20,6 +20,7 @@ export async function loadCLIEnv(args: AuthArgs & CommonArgs) { // Load via dotenv library const loaded = dotenv.config({ path: args.env_file }); if (loaded.error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(error(`Error loading ${args.env_file}: ${loaded.error}`)); process.exit(1); } diff --git a/js/src/cli/util/debug-logging.ts b/js/src/cli/util/debug-logging.ts index 41b3bc8ba..544514a11 100644 --- a/js/src/cli/util/debug-logging.ts +++ b/js/src/cli/util/debug-logging.ts @@ -21,6 +21,7 @@ export function normalizeDebugLoggingArgs< if (!hasWarnedAboutVerboseFlag) { hasWarnedAboutVerboseFlag = true; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(warning(VERBOSE_DEPRECATION_MESSAGE)); } diff --git a/js/src/cli/util/pull.ts b/js/src/cli/util/pull.ts index a6e5e7a79..a25eff17c 100644 --- a/js/src/cli/util/pull.ts +++ b/js/src/cli/util/pull.ts @@ -46,6 +46,7 @@ export async function pullCommand(args: PullArgs) { typeof rawFunc === "object" && rawFunc && "id" in rawFunc ? ` ${rawFunc.id}` : ""; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning(`Failed to parse function${id}: ${parsedFunc.error.message}`), ); @@ -60,8 +61,10 @@ export async function pullCommand(args: PullArgs) { projectNameToFunctions[projectName].push(func); } + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.log("Found functions in the following projects:"); for (const projectName of Object.keys(projectNameToFunctions)) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.log(` * ${projectName}`); } @@ -92,6 +95,7 @@ export async function pullCommand(args: PullArgs) { ); if (args.force) { if (fileExists) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Overwriting ${doubleQuote(projectFile)} because --force is set.`, @@ -99,6 +103,7 @@ export async function pullCommand(args: PullArgs) { ); } } else if (dirtyFiles.has(resolvedProjectFile)) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Skipping project ${projectName} because ${doubleQuote(projectFile)} has uncommitted changes.`, @@ -107,6 +112,7 @@ export async function pullCommand(args: PullArgs) { continue; } else if (fileExists) { if (!git) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Project ${projectName} already exists in ${doubleQuote(projectFile)}. Skipping since this is not a git repository...`, @@ -114,6 +120,7 @@ export async function pullCommand(args: PullArgs) { ); continue; } else { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Project ${projectName} already exists in ${doubleQuote(projectFile)}. Overwriting...`, @@ -130,6 +137,7 @@ export async function pullCommand(args: PullArgs) { hasSpecifiedFunction: !!args.slug || !!args.id, }); await fs.writeFile(projectFile, projectFileContents || ""); + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.log(`Wrote ${projectName} to ${doubleQuote(projectFile)}`); } } @@ -178,6 +186,7 @@ ${functionDefinitions.join("\n")} }); return formatted; } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Failed to format with prettier (${error instanceof Error ? error.message : error}). Using unformatted output.`, @@ -199,6 +208,7 @@ function makeFunctionDefinition({ }): string | null { if (func.function_data.type !== "prompt") { if (hasSpecifiedFunction) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Skipping function ${doubleQuote(func.name)} because it is not a prompt.`, @@ -218,6 +228,7 @@ function makeFunctionDefinition({ varNames[varName] = func.slug; if (!func.prompt_data || !func.prompt_data.prompt) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Prompt ${doubleQuote(func.name)} has an invalid (empty) prompt definition.`, @@ -240,6 +251,7 @@ function makeFunctionDefinition({ : undefined; if (rawToolsParsed && !rawToolsParsed.success) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( `Prompt ${doubleQuote(func.name)} has an invalid tools definition: ${rawToolsParsed.error.message}. Skipping...`, @@ -348,6 +360,7 @@ async function getPrettierModule() { prettierModule = await importWithTimeout(); } catch { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( warning( "Failed to load prettier module. Will not use prettier to format output.", diff --git a/js/src/debug-logger.ts b/js/src/debug-logger.ts index 91afecc7a..5b21bde4a 100644 --- a/js/src/debug-logger.ts +++ b/js/src/debug-logger.ts @@ -34,6 +34,7 @@ function warnInvalidEnvValue(value: string) { return; } hasWarnedAboutInvalidEnvValue = true; + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( PREFIX, `Invalid BRAINTRUST_DEBUG_LOG_LEVEL value "${value}". Expected "error", "warn", "info", or "debug".`, @@ -135,12 +136,16 @@ function emit( } if (method === "info") { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.log(PREFIX, ...args); } else if (method === "debug") { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.debug(PREFIX, ...args); } else if (method === "warn") { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(PREFIX, ...args); } else { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(PREFIX, ...args); } } diff --git a/js/src/eval-parameters.ts b/js/src/eval-parameters.ts index e33d5c911..80ebff257 100644 --- a/js/src/eval-parameters.ts +++ b/js/src/eval-parameters.ts @@ -124,6 +124,7 @@ function validateParametersWithZod< return [name, schemaCasted.parse(value)]; } } catch (e) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error validating parameter", name, e); throw Error( `Invalid parameter '${name}': ${e instanceof Error ? e.message : String(e)}`, diff --git a/js/src/framework.ts b/js/src/framework.ts index cfdd62bde..6388bd900 100644 --- a/js/src/framework.ts +++ b/js/src/framework.ts @@ -773,8 +773,10 @@ export async function Eval< return ret; } finally { if (experiment) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. await experiment.flush().catch(console.error); } else if (options.parent) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. await flush({ state: evaluator.state }).catch(console.error); } } @@ -1485,8 +1487,10 @@ export const warning = (text: string) => `Warning: ${text}`; export function logError(e: unknown, verbose: boolean) { if (!verbose) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`${e}`); } else { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(e); } } @@ -1562,12 +1566,14 @@ export function reportFailures< // TODO: We may want to support a non-strict mode (and make this the "strict" behavior), so that // users can still log imperfect evaluations. In the meantime, they should handle these cases inside // of their tasks. + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( warning( `Evaluator ${evaluator.evalName} failed with ${failingResults.length} error${failingResults.length === 1 ? "" : "s"}. This evaluation ("${evaluator.evalName}") will not be fully logged.`, ), ); if (jsonl) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.log( JSON.stringify({ evaluatorName: evaluator.evalName, @@ -1582,6 +1588,7 @@ export function reportFailures< } } if (!verbose && !jsonl) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( warning( "Use --debug-logging debug to see full stack traces and troubleshooting details.", diff --git a/js/src/framework2.ts b/js/src/framework2.ts index 9c15946d5..14aff18af 100644 --- a/js/src/framework2.ts +++ b/js/src/framework2.ts @@ -117,6 +117,7 @@ export class Project { async publish() { if (globalThis._lazy_load) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("publish() is a no-op when running `braintrust push`."); return; } @@ -124,6 +125,7 @@ export class Project { const projectMap = new ProjectNameIdMap(); const functionDefinitions: FunctionEvent[] = []; if (this._publishableCodeFunctions.length > 0) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( "Code functions cannot be published directly. Use `braintrust push` instead.", ); diff --git a/js/src/instrumentation/core/channel-tracing.ts b/js/src/instrumentation/core/channel-tracing.ts index 96a64a472..2d1f70c94 100644 --- a/js/src/instrumentation/core/channel-tracing.ts +++ b/js/src/instrumentation/core/channel-tracing.ts @@ -198,6 +198,7 @@ function startSpanForEvent< metadata: mergeInputMetadata(metadata, spanInfoMetadata), }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting input for ${channelName}:`, error); } @@ -351,6 +352,7 @@ export function traceAsyncChannel( metrics, }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting output for ${channelName}:`, error); } finally { span.end(); @@ -460,6 +462,7 @@ export function traceStreamingChannel( metrics, }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( `Error extracting output for ${channelName}:`, error, @@ -516,6 +519,7 @@ export function traceStreamingChannel( metrics, }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting output for ${channelName}:`, error); } finally { span.end(); @@ -610,6 +614,7 @@ export function traceSyncStreamChannel( }); } } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( `Error extracting chatCompletion for ${channelName}:`, error, @@ -637,6 +642,7 @@ export function traceSyncStreamChannel( span.log(extracted); } } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting event for ${channelName}:`, error); } }); diff --git a/js/src/instrumentation/core/plugin.ts b/js/src/instrumentation/core/plugin.ts index 7d1147c5a..41e1d7c3d 100644 --- a/js/src/instrumentation/core/plugin.ts +++ b/js/src/instrumentation/core/plugin.ts @@ -109,6 +109,7 @@ export abstract class BasePlugin { metadata: mergeInputMetadata(metadata, spanInfoMetadata), }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting input for ${channelName}:`, error); } }, @@ -132,6 +133,7 @@ export abstract class BasePlugin { metrics, }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting output for ${channelName}:`, error); } finally { span.end(); @@ -216,6 +218,7 @@ export abstract class BasePlugin { metadata: mergeInputMetadata(metadata, spanInfoMetadata), }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting input for ${channelName}:`, error); } }, @@ -279,6 +282,7 @@ export abstract class BasePlugin { metrics, }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( `Error extracting output for ${channelName}:`, error, @@ -315,6 +319,7 @@ export abstract class BasePlugin { metrics, }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting output for ${channelName}:`, error); } finally { span.end(); @@ -389,6 +394,7 @@ export abstract class BasePlugin { metadata: mergeInputMetadata(metadata, spanInfoMetadata), }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error(`Error extracting input for ${channelName}:`, error); } }, @@ -430,6 +436,7 @@ export abstract class BasePlugin { output: completion.choices, }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( `Error extracting chatCompletion for ${channelName}:`, error, @@ -455,6 +462,7 @@ export abstract class BasePlugin { span.log(extracted); } } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( `Error extracting event for ${channelName}:`, error, diff --git a/js/src/instrumentation/core/stream-patcher.ts b/js/src/instrumentation/core/stream-patcher.ts index efdd379de..3ecfc8aa6 100644 --- a/js/src/instrumentation/core/stream-patcher.ts +++ b/js/src/instrumentation/core/stream-patcher.ts @@ -101,6 +101,7 @@ export function patchStreamIfNeeded( // Check if object is extensible (can be patched) if (Object.isFrozen(stream) || Object.isSealed(stream)) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( "Cannot patch frozen/sealed stream. Stream output will not be collected.", ); @@ -137,6 +138,7 @@ export function patchStreamIfNeeded( try { await options.onComplete(chunks); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error in stream onComplete handler:", error); } } @@ -157,6 +159,7 @@ export function patchStreamIfNeeded( try { await options.onChunk(chunk); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error in stream onChunk handler:", error); } } @@ -175,6 +178,7 @@ export function patchStreamIfNeeded( chunks, ); } catch (handlerError) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error in stream onError handler:", handlerError); } } @@ -193,6 +197,7 @@ export function patchStreamIfNeeded( try { await options.onComplete(chunks); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error in stream onComplete handler:", error); } } @@ -215,6 +220,7 @@ export function patchStreamIfNeeded( try { await options.onError(error, chunks); } catch (handlerError) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error in stream onError handler:", handlerError); } } @@ -237,6 +243,7 @@ export function patchStreamIfNeeded( return stream; } catch (error) { // If patching fails for any reason, log warning and return original + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Failed to patch stream:", error); return stream; } @@ -305,6 +312,7 @@ export function wrapStreamResult( const processed = options.processChunks(chunks); options.onResult(processed); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error processing stream chunks:", error); if (options.onError) { options.onError( @@ -325,6 +333,7 @@ export function wrapStreamResult( : result; options.onResult(processed); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error processing non-stream result:", error); if (options.onError) { options.onError( diff --git a/js/src/instrumentation/plugins/claude-agent-sdk-plugin.ts b/js/src/instrumentation/plugins/claude-agent-sdk-plugin.ts index c6f5aeb8a..e7c1fa8da 100644 --- a/js/src/instrumentation/plugins/claude-agent-sdk-plugin.ts +++ b/js/src/instrumentation/plugins/claude-agent-sdk-plugin.ts @@ -756,6 +756,7 @@ export class ClaudeAgentSDKPlugin extends BasePlugin { metadata: filterSerializableOptions(options), }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error extracting input for Claude Agent SDK:", error); } @@ -828,6 +829,7 @@ export class ClaudeAgentSDKPlugin extends BasePlugin { state.processing = state.processing .then(() => handleStreamMessage(state, message)) .catch((error) => { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error( "Error processing Claude Agent SDK stream chunk:", error, @@ -859,6 +861,7 @@ export class ClaudeAgentSDKPlugin extends BasePlugin { try { state.span.log({ output: eventResult }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error extracting output for Claude Agent SDK:", error); } finally { state.span.end(); diff --git a/js/src/instrumentation/registry.ts b/js/src/instrumentation/registry.ts index 844b9efd2..79825abeb 100644 --- a/js/src/instrumentation/registry.ts +++ b/js/src/instrumentation/registry.ts @@ -35,6 +35,7 @@ class PluginRegistry { */ configure(config: InstrumentationConfig): void { if (this.enabled) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( "Braintrust: Cannot configure instrumentation after it has been enabled. " + "Call configureInstrumentation() before importing any AI SDKs.", diff --git a/js/src/isomorph.ts b/js/src/isomorph.ts index 4091ba206..130793ae2 100644 --- a/js/src/isomorph.ts +++ b/js/src/isomorph.ts @@ -301,6 +301,7 @@ const iso: Common = { ) => new DefaultTracingChannel(nameOrChannels), processOn: (_0, _1) => {}, basename: (filepath: string) => filepath.split(/[\\/]/).pop() || filepath, + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. writeln: (text: string) => console.log(text), }; export default iso; diff --git a/js/src/prompt-cache/disk-cache.ts b/js/src/prompt-cache/disk-cache.ts index e99c7e7d9..8d5dc256c 100644 --- a/js/src/prompt-cache/disk-cache.ts +++ b/js/src/prompt-cache/disk-cache.ts @@ -96,6 +96,7 @@ export class DiskCache { return undefined; } if (this.logWarnings) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Failed to read from disk cache", e); } return undefined; @@ -121,6 +122,7 @@ export class DiskCache { await this.evictOldestIfFull(); } catch (e) { if (this.logWarnings) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Failed to write to disk cache", e); } return; diff --git a/js/src/reporters/progress.ts b/js/src/reporters/progress.ts index bf897e407..d1a8e5303 100644 --- a/js/src/reporters/progress.ts +++ b/js/src/reporters/progress.ts @@ -2,6 +2,7 @@ import type { ProgressReporter } from "./types"; export class SimpleProgressReporter implements ProgressReporter { public start(name: string, _total: number) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.log(`Running evaluator ${name}`); } public stop() {} diff --git a/js/src/template/registry.ts b/js/src/template/registry.ts index a0686eb10..6ebcace61 100644 --- a/js/src/template/registry.ts +++ b/js/src/template/registry.ts @@ -67,6 +67,7 @@ class TemplatePluginRegistry { register(plugin: TemplateRendererPlugin): void { if (this.plugins.has(plugin.name)) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( `Template plugin '${plugin.name}' already registered, overwriting`, ); diff --git a/js/src/wrappers/ai-sdk/ai-sdk.ts b/js/src/wrappers/ai-sdk/ai-sdk.ts index d65bf3e16..7572e823f 100644 --- a/js/src/wrappers/ai-sdk/ai-sdk.ts +++ b/js/src/wrappers/ai-sdk/ai-sdk.ts @@ -1725,6 +1725,7 @@ const processContentPart = (part: any): any => { } } } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Error processing content part:", error); } @@ -1787,6 +1788,7 @@ const convertImageToAttachment = ( return image; } } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Error converting image to attachment:", error); } @@ -1835,6 +1837,7 @@ const convertDataToAttachment = ( }); } } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Error converting data to attachment:", error); } @@ -1898,6 +1901,7 @@ const processOutputAttachments = async (output: AISDKResult) => { try { return await doProcessOutputAttachments(output); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.error("Error processing output attachments:", error); return output; } @@ -1955,6 +1959,7 @@ const convertFileToAttachment = ( } if (!blob) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(`Failed to convert file at index ${index} to Blob`); return file; // Return original if conversion fails } @@ -1965,6 +1970,7 @@ const convertFileToAttachment = ( contentType: mediaType, }); } catch (error) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn(`Error processing file at index ${index}:`, error); return file; // Return original on error } diff --git a/js/src/wrappers/ai-sdk/deprecated/wrapAISDKModel.ts b/js/src/wrappers/ai-sdk/deprecated/wrapAISDKModel.ts index 059a0ec22..c3f928d84 100644 --- a/js/src/wrappers/ai-sdk/deprecated/wrapAISDKModel.ts +++ b/js/src/wrappers/ai-sdk/deprecated/wrapAISDKModel.ts @@ -25,6 +25,7 @@ export function wrapAISDKModel(model: T): T { ) { return new BraintrustLanguageModelWrapper(m) as any as T; } else { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Unsupported AI SDK model. Not wrapping."); return model; } diff --git a/js/src/wrappers/anthropic.ts b/js/src/wrappers/anthropic.ts index 7048e5f40..c3135320b 100644 --- a/js/src/wrappers/anthropic.ts +++ b/js/src/wrappers/anthropic.ts @@ -28,6 +28,7 @@ export function wrapAnthropic(anthropic: T): T { return anthropicProxy(au as AnthropicClient) as T; } + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Unsupported Anthropic library. Not wrapping."); return anthropic; } diff --git a/js/src/wrappers/claude-agent-sdk/claude-agent-sdk.ts b/js/src/wrappers/claude-agent-sdk/claude-agent-sdk.ts index 66c9f01b1..28f2af611 100644 --- a/js/src/wrappers/claude-agent-sdk/claude-agent-sdk.ts +++ b/js/src/wrappers/claude-agent-sdk/claude-agent-sdk.ts @@ -24,6 +24,7 @@ export function wrapClaudeAgentSDK(sdk: T): T { return claudeAgentSDKProxy(s as ClaudeAgentSDKModule) as unknown as T; } + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Unsupported Claude Agent SDK. Not wrapping."); return sdk; } diff --git a/js/src/wrappers/google-genai.ts b/js/src/wrappers/google-genai.ts index 88c69eb0c..8a7e5fc61 100644 --- a/js/src/wrappers/google-genai.ts +++ b/js/src/wrappers/google-genai.ts @@ -27,11 +27,13 @@ export function wrapGoogleGenAI>( googleGenAI: T, ): T { if (!googleGenAI || typeof googleGenAI !== "object") { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Invalid Google GenAI module. Not wrapping."); return googleGenAI; } if (!("GoogleGenAI" in googleGenAI)) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( "GoogleGenAI class not found in module. Not wrapping. Make sure you're passing the module itself (import * as googleGenAI from '@google/genai').", ); diff --git a/js/src/wrappers/oai.ts b/js/src/wrappers/oai.ts index 6411020b8..c57143faf 100644 --- a/js/src/wrappers/oai.ts +++ b/js/src/wrappers/oai.ts @@ -63,6 +63,7 @@ export function wrapOpenAI(openai: T): T { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions return wrapOpenAIv4(typedOpenAI) as T; } else { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Unsupported OpenAI library (potentially v3). Not wrapping."); return openai; } diff --git a/js/src/wrappers/openrouter.ts b/js/src/wrappers/openrouter.ts index 70228c964..69d38873a 100644 --- a/js/src/wrappers/openrouter.ts +++ b/js/src/wrappers/openrouter.ts @@ -36,6 +36,7 @@ export function wrapOpenRouter(openrouter: T): T { return openRouterProxy(or as OpenRouterClient) as T; } + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Unsupported OpenRouter library. Not wrapping."); return openrouter; } diff --git a/js/src/wrappers/shared/flush.ts b/js/src/wrappers/shared/flush.ts index 907389d3b..e7e009d70 100644 --- a/js/src/wrappers/shared/flush.ts +++ b/js/src/wrappers/shared/flush.ts @@ -13,6 +13,7 @@ export async function summarizeAndFlush( const shouldDisplay = options.displaySummary ?? true; const summary = await experiment.summarize(); if (shouldDisplay) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.log(formatExperimentSummary(summary)); } } diff --git a/js/src/wrappers/shared/scorers.ts b/js/src/wrappers/shared/scorers.ts index c5cb4619c..43080027f 100644 --- a/js/src/wrappers/shared/scorers.ts +++ b/js/src/wrappers/shared/scorers.ts @@ -44,6 +44,7 @@ export async function runScorers(args: { } catch (scorerError) { // Log scorer error but don't fail the test — use metadata instead // of top-level error field to avoid marking the span as errored + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn("Braintrust: Scorer failed:", scorerError); const errorStr = scorerError instanceof Error diff --git a/js/src/wrappers/vitest/index.ts b/js/src/wrappers/vitest/index.ts index 3671c8be9..5ff41b157 100644 --- a/js/src/wrappers/vitest/index.ts +++ b/js/src/wrappers/vitest/index.ts @@ -102,6 +102,7 @@ export function wrapVitest< flushExperiment: async (options?: { displaySummary?: boolean }) => { const ctx = getExperimentContext(); if (!ctx) { + // eslint-disable-next-line no-restricted-properties -- preserving intentional console usage. console.warn( "Braintrust: No experiment context found. Make sure you're using bt.describe() and calling flushExperiment() within an afterAll() hook.", );