Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e1498a094 | ||
|
|
38f020e482 | ||
|
|
07e1d4e960 | ||
|
|
602d00a5bb | ||
|
|
7395bd8d83 | ||
|
|
63d164ad52 | ||
|
|
f1b915c8b7 | ||
|
|
e3886b94c1 | ||
|
|
44376c2a9f | ||
|
|
2e85c9ac15 | ||
|
|
7cc81deb65 | ||
|
|
a13ddd41ae |
+12
-5
@@ -12,8 +12,15 @@ RUN apt-get update && \
|
||||
postgresql-client \
|
||||
redis-tools \
|
||||
less nano \
|
||||
sudo \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# ---------- Docker -----------------------------------------------------------
|
||||
# Install Docker for background agents that need container capabilities
|
||||
RUN curl -fsSL https://get.docker.com -o get-docker.sh && \
|
||||
sh get-docker.sh && \
|
||||
rm get-docker.sh
|
||||
|
||||
# ---------- pnpm -------------------------------------------------------------
|
||||
# Langfuse monorepo relies on pnpm 9.5.0 (see CONTRIBUTING.md)
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
@@ -29,11 +36,11 @@ RUN wget -qO- "https://github.com/golang-migrate/migrate/releases/download/v${MI
|
||||
chmod +x /usr/local/bin/migrate
|
||||
|
||||
# ---------- Non-root user -----------------------------------------------------
|
||||
# Use root for convenience in development containers
|
||||
WORKDIR /workspace
|
||||
|
||||
# Create non-root user
|
||||
RUN useradd -ms /bin/bash ubuntu
|
||||
# Create non-root user with sudo privileges and docker group access
|
||||
RUN useradd -ms /bin/bash ubuntu && \
|
||||
usermod -aG sudo ubuntu && \
|
||||
usermod -aG docker ubuntu && \
|
||||
echo "ubuntu ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
|
||||
# Pre-create pnpm store and set correct ownership to avoid first-run cost & permission issues
|
||||
RUN pnpm store path > /dev/null && \
|
||||
|
||||
@@ -4,5 +4,11 @@
|
||||
"context": ".",
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"start": "pnpm dx-f"
|
||||
"start": "sudo service docker start",
|
||||
"terminals": [
|
||||
{
|
||||
"name": "dev server",
|
||||
"command": "pnpm run dx-f"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,4 +5,5 @@ alwaysApply: true
|
||||
---
|
||||
# General rules
|
||||
|
||||
- Linting in this repo only works if the development server is running
|
||||
- Linting in this repo only works if the development server is running
|
||||
- Always run the full mono-repo via `pnpm run dx` (use `pnpm dx-f` when you run this in a background agent). Thereby the database will also be seeded.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "langfuse",
|
||||
"version": "3.78.1",
|
||||
"version": "3.78.2",
|
||||
"author": "engineering@langfuse.com",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "tsc --watch",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 72",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 0",
|
||||
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
|
||||
"db:migrate": "DISABLE_ERD=false dotenv -e ../../.env -- npx prisma migrate dev",
|
||||
"db:push": "DISABLE_ERD=false dotenv -e ../../.env -- npx prisma db push",
|
||||
@@ -84,7 +84,7 @@
|
||||
"jsonpath-plus": "10.3.0",
|
||||
"kysely": "^0.27.4",
|
||||
"langchain": "^0.3.28",
|
||||
"langfuse-langchain": "3.37.4",
|
||||
"langfuse-langchain": "3.38.1",
|
||||
"lodash": "^4.17.21",
|
||||
"lossless-json": "^4.1.1",
|
||||
"next-auth": "^4.24.11",
|
||||
|
||||
@@ -178,7 +178,7 @@ async function main() {
|
||||
|
||||
const seedApiKey = {
|
||||
id: "seed-api-key",
|
||||
secret: process.env.SEED_SECRET_KEY ?? "sk-lf-1234567890",
|
||||
secret: process.env.SEED_SECRET_KEY ?? "sk-lf-1234567890", // eslint-disable-line turbo/no-undeclared-env-vars
|
||||
public: "pk-lf-1234567890",
|
||||
note: "seeded key",
|
||||
};
|
||||
@@ -241,7 +241,7 @@ async function main() {
|
||||
|
||||
const secondKey = {
|
||||
id: "seed-api-key-2",
|
||||
secret: process.env.SEED_SECRET_KEY ?? "sk-lf-asdfghjkl",
|
||||
secret: process.env.SEED_SECRET_KEY ?? "sk-lf-asdfghjkl", // eslint-disable-line turbo/no-undeclared-env-vars
|
||||
public: "pk-lf-asdfghjkl",
|
||||
note: "seeded key 2",
|
||||
};
|
||||
@@ -274,7 +274,7 @@ async function main() {
|
||||
await createTraceSessions(project1, project2);
|
||||
|
||||
// If openai key is in environment, add it to the projects LLM API keys
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
|
||||
const OPENAI_API_KEY = process.env.OPENAI_API_KEY; // eslint-disable-line turbo/no-undeclared-env-vars
|
||||
|
||||
if (OPENAI_API_KEY) {
|
||||
await prisma.llmApiKeys.create({
|
||||
|
||||
@@ -88,7 +88,7 @@ declare const globalThis: {
|
||||
kyselyPrismaGlobal: { $kysely: Kysely<DB> } | undefined;
|
||||
} & typeof global;
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
if (process.env.NODE_ENV === "development") { // eslint-disable-line turbo/no-undeclared-env-vars
|
||||
globalThis.prismaGlobal ??= createPrismaInstance(); // regular instantiation
|
||||
globalThis.kyselyPrismaGlobal ??= globalThis.prismaGlobal.$extends(
|
||||
kyselyExtension({
|
||||
|
||||
@@ -3,11 +3,11 @@ import { orderBy } from "../interfaces/orderBy";
|
||||
import z from "zod/v4";
|
||||
|
||||
export enum TableViewPresetTableName {
|
||||
Traces = "traces",
|
||||
Observations = "observations",
|
||||
Scores = "scores",
|
||||
Sessions = "sessions",
|
||||
Datasets = "datasets",
|
||||
Traces = "traces", // eslint-disable-line no-unused-vars
|
||||
Observations = "observations", // eslint-disable-line no-unused-vars
|
||||
Scores = "scores", // eslint-disable-line no-unused-vars
|
||||
Sessions = "sessions", // eslint-disable-line no-unused-vars
|
||||
Datasets = "datasets", // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
const TableViewPresetDomainSchema = z.object({
|
||||
|
||||
@@ -105,10 +105,11 @@ const EnvSchema = z.object({
|
||||
.number()
|
||||
.default(80e6), // 80MB
|
||||
LANGFUSE_CLICKHOUSE_DELETION_TIMEOUT_MS: z.coerce.number().default(240_000), // 4 minutes
|
||||
LANGFUSE_CLICKHOUSE_QUERY_MAX_ATTEMPTS: z.coerce.number().default(3), // Maximum attempts for socket hang up errors
|
||||
LANGFUSE_SKIP_S3_LIST_FOR_OBSERVATIONS_PROJECT_IDS: z.string().optional(),
|
||||
});
|
||||
|
||||
export const env: z.infer<typeof EnvSchema> =
|
||||
process.env.DOCKER_BUILD === "1"
|
||||
process.env.DOCKER_BUILD === "1" // eslint-disable-line turbo/no-undeclared-env-vars
|
||||
? (process.env as any)
|
||||
: EnvSchema.parse(removeEmptyEnvVariables(process.env));
|
||||
|
||||
@@ -7,3 +7,4 @@ export { MethodNotAllowedError } from "./MethodNotAllowedError";
|
||||
export { ApiError } from "./ApiError";
|
||||
export { InternalServerError } from "./InternalServerError";
|
||||
export { LangfuseConflictError } from "./ConflictError";
|
||||
export { QUEUE_ERROR_MESSAGES } from "./utils/constants";
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
export const QUEUE_ERROR_MESSAGES = {
|
||||
API_KEY_ERROR: "API key for provider",
|
||||
NO_DEFAULT_MODEL_ERROR: "No default model or custom model found for project",
|
||||
MAPPED_DATA_ERROR:
|
||||
"Please ensure the mapped data exists and consider extending the job delay.",
|
||||
INVALID_JSON_ERROR: "is not valid JSON",
|
||||
TOO_LOW_MAX_TOKENS_ERROR: "Error: Unterminated string in JSON at position",
|
||||
OUTPUT_TOKENS_TOO_LONG_ERROR:
|
||||
"Could not parse response content as the length limit was reached",
|
||||
};
|
||||
@@ -8,16 +8,16 @@ import { BatchTableNames } from "../../interfaces/tableNames";
|
||||
import { TracingSearchType } from "../../interfaces/search";
|
||||
|
||||
export enum BatchExportStatus {
|
||||
QUEUED = "QUEUED",
|
||||
PROCESSING = "PROCESSING",
|
||||
COMPLETED = "COMPLETED",
|
||||
FAILED = "FAILED",
|
||||
QUEUED = "QUEUED", // eslint-disable-line no-unused-vars
|
||||
PROCESSING = "PROCESSING", // eslint-disable-line no-unused-vars
|
||||
COMPLETED = "COMPLETED", // eslint-disable-line no-unused-vars
|
||||
FAILED = "FAILED", // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
export enum BatchExportFileFormat {
|
||||
JSON = "JSON",
|
||||
CSV = "CSV",
|
||||
JSONL = "JSONL",
|
||||
JSON = "JSON", // eslint-disable-line no-unused-vars
|
||||
CSV = "CSV", // eslint-disable-line no-unused-vars
|
||||
JSONL = "JSONL", // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
// Use shared BatchTableNames enum for consistency across batch operations
|
||||
|
||||
@@ -42,7 +42,7 @@ function parseJsonDefault(selectedColumn: unknown, jsonSelector: string) {
|
||||
export function extractValueFromObject(
|
||||
obj: Record<string, unknown>,
|
||||
mapping: z.infer<typeof variableMapping>,
|
||||
parseJson?: (selectedColumn: unknown, jsonSelector: string) => unknown,
|
||||
parseJson?: (selectedColumn: unknown, jsonSelector: string) => unknown, // eslint-disable-line no-unused-vars
|
||||
): { value: string; error: Error | null } {
|
||||
const selectedColumn = obj[mapping.selectedColumnId];
|
||||
const jsonParser = parseJson || parseJsonDefault;
|
||||
|
||||
@@ -37,13 +37,13 @@ const ScorePropsAgainstConfigNumeric = z
|
||||
dataType: z.literal("NUMERIC"),
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
if (isPresent(data.maxValue) && data.value >= data.maxValue) {
|
||||
if (isPresent(data.maxValue) && data.value > data.maxValue) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `Value exceeds maximum value of ${data.maxValue} defined in config`,
|
||||
});
|
||||
}
|
||||
if (isPresent(data.minValue) && data.value <= data.minValue) {
|
||||
if (isPresent(data.minValue) && data.value < data.minValue) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: `Value is below minimum value of ${data.minValue} defined in config`,
|
||||
|
||||
@@ -150,7 +150,7 @@ const ValidatedScoreConfigSchema = z
|
||||
*/
|
||||
export const filterAndValidateDbScoreConfigList = (
|
||||
scoreConfigs: ScoreConfigDbType[],
|
||||
onParseError?: (error: z.ZodError) => void,
|
||||
onParseError?: (error: z.ZodError) => void, // eslint-disable-line no-unused-vars
|
||||
): ValidatedScoreConfig[] =>
|
||||
scoreConfigs.reduce((acc, ts) => {
|
||||
const result = ValidatedScoreConfigSchema.safeParse(ts);
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
* to avoid coupling between different batch operation types.
|
||||
*/
|
||||
export enum BatchTableNames {
|
||||
Scores = "scores",
|
||||
Sessions = "sessions",
|
||||
Traces = "traces",
|
||||
Observations = "observations",
|
||||
DatasetRunItems = "dataset_run_items",
|
||||
DatasetItems = "dataset_items",
|
||||
AuditLogs = "audit_logs",
|
||||
Scores = "scores", // eslint-disable-line no-unused-vars
|
||||
Sessions = "sessions", // eslint-disable-line no-unused-vars
|
||||
Traces = "traces", // eslint-disable-line no-unused-vars
|
||||
Observations = "observations", // eslint-disable-line no-unused-vars
|
||||
DatasetRunItems = "dataset_run_items", // eslint-disable-line no-unused-vars
|
||||
DatasetItems = "dataset_items", // eslint-disable-line no-unused-vars
|
||||
AuditLogs = "audit_logs", // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const getS3StorageServiceClient = (bucketName: string): StorageService => {
|
||||
return s3StorageServiceClient;
|
||||
};
|
||||
|
||||
export type TokenCountDelegate = (p: {
|
||||
export type TokenCountDelegate = (p: { // eslint-disable-line no-unused-vars
|
||||
model: Model;
|
||||
text: unknown;
|
||||
}) => number | undefined;
|
||||
|
||||
@@ -22,7 +22,7 @@ export type SpanCtx = {
|
||||
traceContext?: TCarrier;
|
||||
};
|
||||
|
||||
type AsyncCallbackFn<T> = (span: opentelemetry.Span) => Promise<T>;
|
||||
type AsyncCallbackFn<T> = (span: opentelemetry.Span) => Promise<T>; // eslint-disable-line no-unused-vars
|
||||
|
||||
export async function instrumentAsync<T>(
|
||||
ctx: SpanCtx,
|
||||
@@ -64,7 +64,7 @@ export async function instrumentAsync<T>(
|
||||
);
|
||||
}
|
||||
|
||||
type SyncCallbackFn<T> = (span: opentelemetry.Span) => T;
|
||||
type SyncCallbackFn<T> = (span: opentelemetry.Span) => T; // eslint-disable-line no-unused-vars
|
||||
|
||||
export function instrumentSync<T>(
|
||||
ctx: SpanCtx,
|
||||
|
||||
@@ -63,7 +63,7 @@ type FetchLLMCompletionParams = LLMCompletionParams & {
|
||||
};
|
||||
|
||||
export async function fetchLLMCompletion(
|
||||
params: LLMCompletionParams & {
|
||||
params: LLMCompletionParams & { // eslint-disable-line no-unused-vars
|
||||
streaming: true;
|
||||
},
|
||||
): Promise<{
|
||||
@@ -72,7 +72,7 @@ export async function fetchLLMCompletion(
|
||||
}>;
|
||||
|
||||
export async function fetchLLMCompletion(
|
||||
params: LLMCompletionParams & {
|
||||
params: LLMCompletionParams & { // eslint-disable-line no-unused-vars
|
||||
streaming: false;
|
||||
},
|
||||
): Promise<{
|
||||
@@ -81,7 +81,7 @@ export async function fetchLLMCompletion(
|
||||
}>;
|
||||
|
||||
export async function fetchLLMCompletion(
|
||||
params: LLMCompletionParams & {
|
||||
params: LLMCompletionParams & { // eslint-disable-line no-unused-vars
|
||||
streaming: false;
|
||||
structuredOutputSchema: ZodSchema;
|
||||
},
|
||||
@@ -91,7 +91,7 @@ export async function fetchLLMCompletion(
|
||||
}>;
|
||||
|
||||
export async function fetchLLMCompletion(
|
||||
params: LLMCompletionParams & {
|
||||
params: LLMCompletionParams & { // eslint-disable-line no-unused-vars
|
||||
tools: LLMToolDefinition[];
|
||||
streaming: false;
|
||||
},
|
||||
|
||||
@@ -432,19 +432,19 @@ export class FilterList {
|
||||
this.filters.push(...filter);
|
||||
}
|
||||
|
||||
find(predicate: (filter: Filter) => boolean) {
|
||||
find(predicate: (filter: Filter) => boolean) { // eslint-disable-line no-unused-vars
|
||||
return this.filters.find(predicate);
|
||||
}
|
||||
|
||||
filter(predicate: (filter: Filter) => boolean) {
|
||||
filter(predicate: (filter: Filter) => boolean) { // eslint-disable-line no-unused-vars
|
||||
return new FilterList(this.filters.filter(predicate));
|
||||
}
|
||||
|
||||
some(predicate: (filter: Filter) => boolean) {
|
||||
some(predicate: (filter: Filter) => boolean) { // eslint-disable-line no-unused-vars
|
||||
return this.filters.some(predicate);
|
||||
}
|
||||
|
||||
forEach(callback: (filter: Filter) => void) {
|
||||
forEach(callback: (filter: Filter) => void) { // eslint-disable-line no-unused-vars
|
||||
this.filters.forEach(callback);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,8 +70,9 @@ export function getQueue(
|
||||
return ScoreDeleteQueue.getInstance();
|
||||
case QueueName.DeadLetterRetryQueue:
|
||||
return DeadLetterRetryQueue.getInstance();
|
||||
default:
|
||||
const exhaustiveCheckDefault: never = queueName;
|
||||
default: {
|
||||
const exhaustiveCheckDefault: never = queueName; // eslint-disable-line no-case-declarations, no-unused-vars
|
||||
throw new Error(`Queue ${queueName} not found`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,9 +167,9 @@ const createRedisClient = () => {
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var redis: undefined | ReturnType<typeof createRedisClient>;
|
||||
var redis: undefined | ReturnType<typeof createRedisClient>; // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
export const redis = globalThis.redis ?? createRedisClient();
|
||||
export const redis = globalThis.redis ?? createRedisClient(); // eslint-disable-line no-undef
|
||||
|
||||
if (env.NODE_ENV !== "production") globalThis.redis = redis;
|
||||
if (env.NODE_ENV !== "production") globalThis.redis = redis; // eslint-disable-line no-undef
|
||||
|
||||
@@ -9,6 +9,7 @@ import { randomUUID } from "crypto";
|
||||
import { getClickhouseEntityType } from "../clickhouse/schemaUtils";
|
||||
import { NodeClickHouseClientConfigOptions } from "@clickhouse/client/dist/config";
|
||||
import { context, SpanKind, trace } from "@opentelemetry/api";
|
||||
import { backOff } from "exponential-backoff";
|
||||
import {
|
||||
StorageService,
|
||||
StorageServiceFactory,
|
||||
@@ -203,6 +204,18 @@ export async function* queryClickhouseStream<T>(opts: {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an error is retryable (socket hang up, connection reset, etc.)
|
||||
*/
|
||||
function isRetryableError(error: unknown): boolean {
|
||||
if (!error || typeof error !== "object") return false;
|
||||
|
||||
const errorMessage = (error as Error).message?.toLowerCase() || "";
|
||||
|
||||
// Check for socket hang up and other network-related errors
|
||||
return errorMessage.includes("socket hang up");
|
||||
}
|
||||
|
||||
export async function queryClickhouse<T>(opts: {
|
||||
query: string;
|
||||
params?: Record<string, unknown> | undefined;
|
||||
@@ -218,40 +231,78 @@ export async function queryClickhouse<T>(opts: {
|
||||
span.setAttribute("db.query.text", opts.query);
|
||||
span.setAttribute("db.operation.name", "SELECT");
|
||||
|
||||
const res = await clickhouseClient(opts.clickhouseConfigs).query({
|
||||
query: opts.query,
|
||||
format: "JSONEachRow",
|
||||
query_params: opts.params,
|
||||
clickhouse_settings: {
|
||||
log_comment: JSON.stringify(opts.tags ?? {}),
|
||||
},
|
||||
});
|
||||
// same logic as for prisma. we want to see queries in development
|
||||
if (env.NODE_ENV === "development") {
|
||||
logger.info(`clickhouse:query ${res.query_id} ${opts.query}`);
|
||||
}
|
||||
// Retry logic for socket hang up and other network errors
|
||||
return await backOff(
|
||||
async () => {
|
||||
const res = await clickhouseClient(opts.clickhouseConfigs).query({
|
||||
query: opts.query,
|
||||
format: "JSONEachRow",
|
||||
query_params: opts.params,
|
||||
clickhouse_settings: {
|
||||
log_comment: JSON.stringify(opts.tags ?? {}),
|
||||
},
|
||||
});
|
||||
|
||||
span.setAttribute("ch.queryId", res.query_id);
|
||||
|
||||
// add summary headers to the span. Helps to tune performance
|
||||
const summaryHeader = res.response_headers["x-clickhouse-summary"];
|
||||
if (summaryHeader) {
|
||||
try {
|
||||
const summary = Array.isArray(summaryHeader)
|
||||
? JSON.parse(summaryHeader[0])
|
||||
: JSON.parse(summaryHeader);
|
||||
for (const key in summary) {
|
||||
span.setAttribute(`ch.${key}`, summary[key]);
|
||||
// same logic as for prisma. we want to see queries in development
|
||||
if (env.NODE_ENV === "development") {
|
||||
logger.info(`clickhouse:query ${res.query_id} ${opts.query}`);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.debug(
|
||||
`Failed to parse clickhouse summary header ${summaryHeader}`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return await res.json<T>();
|
||||
span.setAttribute("ch.queryId", res.query_id);
|
||||
|
||||
// add summary headers to the span. Helps to tune performance
|
||||
const summaryHeader = res.response_headers["x-clickhouse-summary"];
|
||||
if (summaryHeader) {
|
||||
try {
|
||||
const summary = Array.isArray(summaryHeader)
|
||||
? JSON.parse(summaryHeader[0])
|
||||
: JSON.parse(summaryHeader);
|
||||
for (const key in summary) {
|
||||
span.setAttribute(`ch.${key}`, summary[key]);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.debug(
|
||||
`Failed to parse clickhouse summary header ${summaryHeader}`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return await res.json<T>();
|
||||
},
|
||||
{
|
||||
numOfAttempts: env.LANGFUSE_CLICKHOUSE_QUERY_MAX_ATTEMPTS,
|
||||
retry: (error: Error, attemptNumber: number) => {
|
||||
const shouldRetry = isRetryableError(error);
|
||||
if (shouldRetry) {
|
||||
logger.warn(
|
||||
`ClickHouse query failed with retryable error (attempt ${attemptNumber}/${env.LANGFUSE_CLICKHOUSE_QUERY_MAX_ATTEMPTS}): ${error.message}`,
|
||||
{
|
||||
error: error.message,
|
||||
attemptNumber,
|
||||
tags: opts.tags,
|
||||
},
|
||||
);
|
||||
span.addEvent("clickhouse-query-retry", {
|
||||
"retry.attempt": attemptNumber,
|
||||
"retry.error": error.message,
|
||||
});
|
||||
} else {
|
||||
logger.error(
|
||||
`ClickHouse query failed with non-retryable error: ${error.message}`,
|
||||
{
|
||||
error: error.message,
|
||||
tags: opts.tags,
|
||||
},
|
||||
);
|
||||
}
|
||||
return shouldRetry;
|
||||
},
|
||||
startingDelay: 100,
|
||||
timeMultiple: 1,
|
||||
maxDelay: 100,
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
import z from "zod/v4";
|
||||
import { prisma } from "../../../db";
|
||||
import { LangfuseNotFoundError } from "../../../errors";
|
||||
import { LangfuseNotFoundError, QUEUE_ERROR_MESSAGES } from "../../../errors";
|
||||
import { LLMApiKeySchema, ZodModelConfig } from "../../llm/types";
|
||||
|
||||
type ValidConfig = {
|
||||
@@ -156,7 +156,7 @@ export class DefaultEvalModelService {
|
||||
if (!selectedModel) {
|
||||
return {
|
||||
valid: false,
|
||||
error: `No default model or custom model found for project ${projectId}.`,
|
||||
error: `${QUEUE_ERROR_MESSAGES.NO_DEFAULT_MODEL_ERROR} ${projectId}.`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ export class DefaultEvalModelService {
|
||||
if (!parsedKey.success) {
|
||||
return {
|
||||
valid: false,
|
||||
error: `API key for provider "${selectedModel.provider}" not found in project ${projectId}.`,
|
||||
error: `${QUEUE_ERROR_MESSAGES.API_KEY_ERROR} "${selectedModel.provider}" not found in project ${projectId}.`,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export class InMemoryFilterService {
|
||||
static evaluateFilter<T>(
|
||||
data: T,
|
||||
filter: FilterState,
|
||||
fieldMapper: (data: T, column: string) => unknown,
|
||||
fieldMapper: (data: T, column: string) => unknown, // eslint-disable-line no-unused-vars
|
||||
): boolean {
|
||||
try {
|
||||
// If no filters, data matches
|
||||
@@ -45,7 +45,7 @@ export class InMemoryFilterService {
|
||||
private static evaluateFilterCondition<T>(
|
||||
data: T,
|
||||
condition: FilterCondition,
|
||||
fieldMapper: (data: T, column: string) => unknown,
|
||||
fieldMapper: (data: T, column: string) => unknown, // eslint-disable-line no-unused-vars
|
||||
): boolean {
|
||||
const { column, type, operator } = condition;
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ export type PromptParams = {
|
||||
);
|
||||
|
||||
export enum PromptServiceMetrics {
|
||||
PromptCacheHit = "prompt_cache_hit",
|
||||
PromptCacheMiss = "prompt_cache_miss",
|
||||
PromptCacheHit = "prompt_cache_hit", // eslint-disable-line no-unused-vars
|
||||
PromptCacheMiss = "prompt_cache_miss", // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
export type PartialPrompt = Pick<
|
||||
|
||||
@@ -28,21 +28,21 @@ type UploadFile = {
|
||||
};
|
||||
|
||||
export interface StorageService {
|
||||
uploadFile(params: UploadFile): Promise<{ signedUrl: string }>;
|
||||
uploadFile(params: UploadFile): Promise<{ signedUrl: string }>; // eslint-disable-line no-unused-vars
|
||||
|
||||
uploadJson(path: string, body: Record<string, unknown>[]): Promise<void>;
|
||||
uploadJson(path: string, body: Record<string, unknown>[]): Promise<void>; // eslint-disable-line no-unused-vars
|
||||
|
||||
download(path: string): Promise<string>;
|
||||
download(path: string): Promise<string>; // eslint-disable-line no-unused-vars
|
||||
|
||||
listFiles(prefix: string): Promise<{ file: string; createdAt: Date }[]>;
|
||||
listFiles(prefix: string): Promise<{ file: string; createdAt: Date }[]>; // eslint-disable-line no-unused-vars
|
||||
|
||||
getSignedUrl(
|
||||
fileName: string,
|
||||
ttlSeconds: number,
|
||||
asAttachment?: boolean,
|
||||
fileName: string, // eslint-disable-line no-unused-vars
|
||||
ttlSeconds: number, // eslint-disable-line no-unused-vars
|
||||
asAttachment?: boolean, // eslint-disable-line no-unused-vars
|
||||
): Promise<string>;
|
||||
|
||||
getSignedUploadUrl(params: {
|
||||
getSignedUploadUrl(params: { // eslint-disable-line no-unused-vars
|
||||
path: string;
|
||||
ttlSeconds: number;
|
||||
sha256Hash: string;
|
||||
@@ -50,7 +50,7 @@ export interface StorageService {
|
||||
contentLength: number;
|
||||
}): Promise<string>;
|
||||
|
||||
deleteFiles(paths: string[]): Promise<void>;
|
||||
deleteFiles(paths: string[]): Promise<void>; // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
export class StorageServiceFactory {
|
||||
@@ -213,7 +213,7 @@ class AzureBlobStorageService implements StorageService {
|
||||
}
|
||||
|
||||
private async streamToString(
|
||||
readableStream: NodeJS.ReadableStream,
|
||||
readableStream: NodeJS.ReadableStream, // eslint-disable-line no-undef
|
||||
): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks: string[] = [];
|
||||
|
||||
@@ -24,12 +24,12 @@ export class DatabaseReadStream<EntityType> extends Readable {
|
||||
|
||||
constructor(
|
||||
// the delegate function takes care of querying the database in a paginated manner
|
||||
private queryDelegate: (
|
||||
pageSize: number,
|
||||
offset: number
|
||||
private queryDelegate: ( // eslint-disable-line no-unused-vars
|
||||
pageSize: number, // eslint-disable-line no-unused-vars
|
||||
offset: number // eslint-disable-line no-unused-vars
|
||||
) => Promise<Array<EntityType>>,
|
||||
private pageSize: number,
|
||||
private maxRecords?: number
|
||||
private pageSize: number, // eslint-disable-line no-unused-vars
|
||||
private maxRecords?: number // eslint-disable-line no-unused-vars
|
||||
) {
|
||||
super({ objectMode: true }); // Set object mode to true to allow pushing objects to the stream rather than strings or buffers
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export function transformStreamToCsv(): Transform {
|
||||
objectMode: true,
|
||||
transform(
|
||||
row: Record<string, any>,
|
||||
encoding: BufferEncoding,
|
||||
encoding: BufferEncoding, // eslint-disable-line no-undef
|
||||
callback: TransformCallback,
|
||||
): void {
|
||||
if (isFirstChunk) {
|
||||
|
||||
@@ -9,8 +9,8 @@ export function transformStreamToJson(): Transform {
|
||||
|
||||
transform(
|
||||
row: any,
|
||||
encoding: BufferEncoding,
|
||||
callback: TransformCallback
|
||||
encoding: BufferEncoding, // eslint-disable-line no-undef, no-unused-vars
|
||||
callback: TransformCallback,
|
||||
): void {
|
||||
if (isFirstElement) {
|
||||
this.push("["); // Push the opening bracket for the first element
|
||||
|
||||
@@ -7,7 +7,7 @@ export function transformStreamToJsonl(): Transform {
|
||||
|
||||
transform(
|
||||
row: Record<string, any>,
|
||||
encoding: BufferEncoding,
|
||||
encoding: BufferEncoding, // eslint-disable-line no-undef, no-unused-vars
|
||||
callback: TransformCallback,
|
||||
): void {
|
||||
this.push(stringify(row) + "\n");
|
||||
|
||||
Generated
+214
-132
@@ -112,7 +112,7 @@ importers:
|
||||
version: 7.12.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@vercel/style-guide':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(@next/eslint-plugin-next@14.2.15)(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8))(prettier@3.5.3)(typescript@5.4.5)(vitest@2.1.2(@types/node@20.14.8))
|
||||
version: 6.0.0(@next/eslint-plugin-next@14.2.15)(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0))(prettier@3.5.3)(typescript@5.4.5)(vitest@2.1.2(@types/node@20.14.8)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5))(terser@5.43.1))
|
||||
eslint-config-next:
|
||||
specifier: ^14.2.15
|
||||
version: 14.2.15(eslint@8.57.0)(typescript@5.4.5)
|
||||
@@ -224,8 +224,8 @@ importers:
|
||||
specifier: ^0.3.28
|
||||
version: 0.3.28(@langchain/anthropic@0.3.22(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/aws@0.1.11(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(@langchain/google-genai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/google-vertexai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(zod@3.25.62))(axios@1.8.2)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.104.0(zod@3.25.62))
|
||||
langfuse-langchain:
|
||||
specifier: 3.37.4
|
||||
version: 3.37.4(langchain@0.3.28(@langchain/anthropic@0.3.22(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/aws@0.1.11(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(@langchain/google-genai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/google-vertexai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(zod@3.25.62))(axios@1.8.2)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.104.0(zod@3.25.62)))
|
||||
specifier: 3.38.1
|
||||
version: 3.38.1(langchain@0.3.28(@langchain/anthropic@0.3.22(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/aws@0.1.11(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(@langchain/google-genai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/google-vertexai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(zod@3.25.62))(axios@1.8.2)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.104.0(zod@3.25.62)))
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
@@ -328,7 +328,7 @@ importers:
|
||||
version: 5.4.5
|
||||
vitest:
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2(@types/node@20.11.29)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(terser@5.43.0)
|
||||
version: 2.1.2(@types/node@20.11.29)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(terser@5.43.1)
|
||||
|
||||
web:
|
||||
dependencies:
|
||||
@@ -758,7 +758,7 @@ importers:
|
||||
version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))
|
||||
'@testing-library/jest-dom':
|
||||
specifier: ^6.4.6
|
||||
version: 6.4.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.10.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))(vitest@2.1.2(@types/node@20.10.5))
|
||||
version: 6.4.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.10.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))(vitest@2.1.2(@types/node@20.10.5)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.10.5)(typescript@5.4.5))(terser@5.43.1))
|
||||
'@testing-library/react':
|
||||
specifier: ^15.0.7
|
||||
version: 15.0.7(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
@@ -1038,7 +1038,7 @@ importers:
|
||||
version: 5.4.5
|
||||
vitest:
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2(@types/node@20.11.29)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(terser@5.43.0)
|
||||
version: 2.1.2(@types/node@20.11.29)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(terser@5.43.1)
|
||||
wait-for-expect:
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
@@ -8936,18 +8936,18 @@ packages:
|
||||
typeorm:
|
||||
optional: true
|
||||
|
||||
langfuse-core@3.37.4:
|
||||
resolution: {integrity: sha512-yqXkQ1/8V9TxF8q6oULWPQ4cYZlUs1egN6JfGuhJSWb5x2Ymgt4Qh9of/Kz//CTM7IZgzZqvrlnx0VXhNKDITg==}
|
||||
langfuse-core@3.38.1:
|
||||
resolution: {integrity: sha512-qZsHZZ05eHv+EQoPmfrm6bWUflzvlCSAfT8EP1PP1WeHSwEcwT4p7qAs9H0EnWcUtm0dAdyd6U75HGWu3/ETUA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
langfuse-langchain@3.37.4:
|
||||
resolution: {integrity: sha512-yh2+Rg+NqN6k+E29VW9lnLp9qpldBE3Ldhh/qsvInyk0hdhF64I/z0hWPFY4tYNvbzBXDHgApJ+66nSnXBf4Tg==}
|
||||
langfuse-langchain@3.38.1:
|
||||
resolution: {integrity: sha512-lkgEwUuGEtkmtxcMhfFn90FRAlGOSGVWczyBFMXck+1YcqnYLIuE/MNg3ufN54yPRVJFfEXj0kesZSLERGQ8eQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
langchain: '>=0.0.157 <0.4.0'
|
||||
|
||||
langfuse@3.37.4:
|
||||
resolution: {integrity: sha512-MxnJXkS3xqlydMKWouanghkWZb8OqoDns+NIAZoD+y/WQh1mtx40n8c0dOaT7OahzSfB9ZbWj+j+yqJww/PJYQ==}
|
||||
langfuse@3.38.1:
|
||||
resolution: {integrity: sha512-rv0x+NWi4JDN8KUyGcl8JQ7xmM/0UBXEcYmtBR+msLLImsM3I07CPE6imp3N2I4AbByPNKF4IU8Kq/LFS3D34A==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
langium@3.0.0:
|
||||
@@ -11310,11 +11310,6 @@ packages:
|
||||
uglify-js:
|
||||
optional: true
|
||||
|
||||
terser@5.43.0:
|
||||
resolution: {integrity: sha512-CqNNxKSGKSZCunSvwKLTs8u8sGGlp27sxNZ4quGh0QeNuyHM0JSEM/clM9Mf4zUp6J+tO2gUXhgXT2YMMkwfKQ==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
terser@5.43.1:
|
||||
resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -14359,12 +14354,26 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.8
|
||||
|
||||
'@inquirer/confirm@5.0.2(@types/node@20.10.5)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.1.0(@types/node@20.10.5)
|
||||
'@inquirer/type': 3.0.1(@types/node@20.10.5)
|
||||
'@types/node': 20.10.5
|
||||
optional: true
|
||||
|
||||
'@inquirer/confirm@5.0.2(@types/node@20.11.29)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.1.0(@types/node@20.11.29)
|
||||
'@inquirer/type': 3.0.1(@types/node@20.11.29)
|
||||
'@types/node': 20.11.29
|
||||
|
||||
'@inquirer/confirm@5.0.2(@types/node@20.14.8)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.1.0(@types/node@20.14.8)
|
||||
'@inquirer/type': 3.0.1(@types/node@20.14.8)
|
||||
'@types/node': 20.14.8
|
||||
optional: true
|
||||
|
||||
'@inquirer/confirm@5.1.12(@types/node@20.14.8)':
|
||||
dependencies:
|
||||
'@inquirer/core': 10.1.13(@types/node@20.14.8)
|
||||
@@ -14372,6 +14381,21 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.8
|
||||
|
||||
'@inquirer/core@10.1.0(@types/node@20.10.5)':
|
||||
dependencies:
|
||||
'@inquirer/figures': 1.0.8
|
||||
'@inquirer/type': 3.0.4(@types/node@20.10.5)
|
||||
ansi-escapes: 4.3.2
|
||||
cli-width: 4.1.0
|
||||
mute-stream: 2.0.0
|
||||
signal-exit: 4.1.0
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
yoctocolors-cjs: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
optional: true
|
||||
|
||||
'@inquirer/core@10.1.0(@types/node@20.11.29)':
|
||||
dependencies:
|
||||
'@inquirer/figures': 1.0.8
|
||||
@@ -14386,6 +14410,21 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
|
||||
'@inquirer/core@10.1.0(@types/node@20.14.8)':
|
||||
dependencies:
|
||||
'@inquirer/figures': 1.0.8
|
||||
'@inquirer/type': 3.0.4(@types/node@20.14.8)
|
||||
ansi-escapes: 4.3.2
|
||||
cli-width: 4.1.0
|
||||
mute-stream: 2.0.0
|
||||
signal-exit: 4.1.0
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
yoctocolors-cjs: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
optional: true
|
||||
|
||||
'@inquirer/core@10.1.13(@types/node@20.14.8)':
|
||||
dependencies:
|
||||
'@inquirer/figures': 1.0.12
|
||||
@@ -14483,14 +14522,34 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.8
|
||||
|
||||
'@inquirer/type@3.0.1(@types/node@20.10.5)':
|
||||
dependencies:
|
||||
'@types/node': 20.10.5
|
||||
optional: true
|
||||
|
||||
'@inquirer/type@3.0.1(@types/node@20.11.29)':
|
||||
dependencies:
|
||||
'@types/node': 20.11.29
|
||||
|
||||
'@inquirer/type@3.0.1(@types/node@20.14.8)':
|
||||
dependencies:
|
||||
'@types/node': 20.14.8
|
||||
optional: true
|
||||
|
||||
'@inquirer/type@3.0.4(@types/node@20.10.5)':
|
||||
optionalDependencies:
|
||||
'@types/node': 20.10.5
|
||||
optional: true
|
||||
|
||||
'@inquirer/type@3.0.4(@types/node@20.11.29)':
|
||||
optionalDependencies:
|
||||
'@types/node': 20.11.29
|
||||
|
||||
'@inquirer/type@3.0.4(@types/node@20.14.8)':
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.8
|
||||
optional: true
|
||||
|
||||
'@inquirer/type@3.0.7(@types/node@20.14.8)':
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.8
|
||||
@@ -17685,7 +17744,7 @@ snapshots:
|
||||
lz-string: 1.5.0
|
||||
pretty-format: 27.5.1
|
||||
|
||||
'@testing-library/jest-dom@6.4.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.10.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))(vitest@2.1.2(@types/node@20.10.5))':
|
||||
'@testing-library/jest-dom@6.4.6(@jest/globals@29.7.0)(@types/jest@29.5.12)(jest@29.7.0(@types/node@20.10.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5)))(vitest@2.1.2(@types/node@20.10.5)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.10.5)(typescript@5.4.5))(terser@5.43.1))':
|
||||
dependencies:
|
||||
'@adobe/css-tools': 4.4.0
|
||||
'@babel/runtime': 7.24.7
|
||||
@@ -17699,7 +17758,7 @@ snapshots:
|
||||
'@jest/globals': 29.7.0
|
||||
'@types/jest': 29.5.12
|
||||
jest: 29.7.0(@types/node@20.10.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
vitest: 2.1.2(@types/node@20.10.5)
|
||||
vitest: 2.1.2(@types/node@20.10.5)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.10.5)(typescript@5.4.5))(terser@5.43.1)
|
||||
|
||||
'@testing-library/react@15.0.7(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||
dependencies:
|
||||
@@ -18358,7 +18417,7 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
'@vercel/style-guide@6.0.0(@next/eslint-plugin-next@14.2.15)(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8))(prettier@3.5.3)(typescript@5.4.5)(vitest@2.1.2(@types/node@20.14.8))':
|
||||
'@vercel/style-guide@6.0.0(@next/eslint-plugin-next@14.2.15)(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0))(prettier@3.5.3)(typescript@5.4.5)(vitest@2.1.2(@types/node@20.14.8)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5))(terser@5.43.1))':
|
||||
dependencies:
|
||||
'@babel/core': 7.24.3
|
||||
'@babel/eslint-parser': 7.24.1(@babel/core@7.24.3)(eslint@8.57.0)
|
||||
@@ -18366,19 +18425,19 @@ snapshots:
|
||||
'@typescript-eslint/eslint-plugin': 7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
|
||||
'@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
eslint-config-prettier: 9.1.0(eslint@8.57.0)
|
||||
eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0))
|
||||
eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1)
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8))(typescript@5.4.5)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0))(typescript@5.4.5)
|
||||
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
|
||||
eslint-plugin-playwright: 1.5.4(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8))(typescript@5.4.5))(eslint@8.57.0)
|
||||
eslint-plugin-playwright: 1.5.4(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0))(typescript@5.4.5))(eslint@8.57.0)
|
||||
eslint-plugin-react: 7.34.1(eslint@8.57.0)
|
||||
eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0)
|
||||
eslint-plugin-testing-library: 6.2.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
eslint-plugin-tsdoc: 0.2.17
|
||||
eslint-plugin-unicorn: 51.0.1(eslint@8.57.0)
|
||||
eslint-plugin-vitest: 0.3.26(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)(vitest@2.1.2(@types/node@20.14.8))
|
||||
eslint-plugin-vitest: 0.3.26(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)(vitest@2.1.2(@types/node@20.14.8)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5))(terser@5.43.1))
|
||||
prettier-plugin-packagejson: 2.4.12(prettier@3.5.3)
|
||||
optionalDependencies:
|
||||
'@next/eslint-plugin-next': 14.2.15
|
||||
@@ -18399,31 +18458,33 @@ snapshots:
|
||||
chai: 5.1.1
|
||||
tinyrainbow: 1.2.0
|
||||
|
||||
'@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(vite@5.2.14(@types/node@20.11.29)(terser@5.43.0))':
|
||||
'@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(msw@2.6.5(@types/node@20.10.5)(typescript@5.4.5))(vite@5.2.14(@types/node@20.10.5)(terser@5.43.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 2.1.2
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.11
|
||||
optionalDependencies:
|
||||
msw: 2.6.5(@types/node@20.10.5)(typescript@5.4.5)
|
||||
vite: 5.2.14(@types/node@20.10.5)(terser@5.43.1)
|
||||
optional: true
|
||||
|
||||
'@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(vite@5.2.14(@types/node@20.11.29)(terser@5.43.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 2.1.2
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.11
|
||||
optionalDependencies:
|
||||
msw: 2.6.5(@types/node@20.11.29)(typescript@5.4.5)
|
||||
vite: 5.2.14(@types/node@20.11.29)(terser@5.43.0)
|
||||
vite: 5.2.14(@types/node@20.11.29)(terser@5.43.1)
|
||||
|
||||
'@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.2.14(@types/node@20.10.5))':
|
||||
'@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5))(vite@5.2.14(@types/node@20.14.8)(terser@5.43.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 2.1.2
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.11
|
||||
optionalDependencies:
|
||||
vite: 5.2.14(@types/node@20.10.5)
|
||||
optional: true
|
||||
|
||||
'@vitest/mocker@2.1.2(@vitest/spy@2.1.2)(vite@5.2.14(@types/node@20.14.8))':
|
||||
dependencies:
|
||||
'@vitest/spy': 2.1.2
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.11
|
||||
optionalDependencies:
|
||||
vite: 5.2.14(@types/node@20.14.8)
|
||||
msw: 2.6.5(@types/node@20.14.8)(typescript@5.4.5)
|
||||
vite: 5.2.14(@types/node@20.14.8)(terser@5.43.1)
|
||||
optional: true
|
||||
|
||||
'@vitest/pretty-format@2.1.2':
|
||||
@@ -19505,7 +19566,7 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
create-jest@29.7.0(@types/node@20.14.8):
|
||||
create-jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0):
|
||||
dependencies:
|
||||
'@jest/types': 29.6.3
|
||||
chalk: 4.1.2
|
||||
@@ -20319,7 +20380,7 @@ snapshots:
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
|
||||
eslint-plugin-react: 7.34.1(eslint@8.57.0)
|
||||
eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0)
|
||||
@@ -20336,7 +20397,7 @@ snapshots:
|
||||
eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.4.0(eslint@8.57.0))(eslint@8.57.0):
|
||||
dependencies:
|
||||
eslint: 8.57.0
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-n: 16.6.2(eslint@8.57.0)
|
||||
eslint-plugin-promise: 6.4.0(eslint@8.57.0)
|
||||
|
||||
@@ -20346,9 +20407,9 @@ snapshots:
|
||||
eslint-plugin-turbo: 2.5.4(eslint@8.57.0)(turbo@2.5.4)
|
||||
turbo: 2.5.4
|
||||
|
||||
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)):
|
||||
eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1):
|
||||
dependencies:
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
|
||||
eslint-import-resolver-node@0.3.9:
|
||||
dependencies:
|
||||
@@ -20363,8 +20424,8 @@ snapshots:
|
||||
debug: 4.3.7(supports-color@5.5.0)
|
||||
enhanced-resolve: 5.17.1
|
||||
eslint: 8.57.0
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
fast-glob: 3.3.3
|
||||
get-tsconfig: 4.8.1
|
||||
is-core-module: 2.15.1
|
||||
@@ -20381,7 +20442,7 @@ snapshots:
|
||||
enhanced-resolve: 5.17.1
|
||||
eslint: 8.57.0
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
|
||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
fast-glob: 3.3.3
|
||||
get-tsconfig: 4.8.1
|
||||
is-core-module: 2.15.1
|
||||
@@ -20392,17 +20453,6 @@ snapshots:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
@@ -20414,6 +20464,17 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-es-x@7.8.0(eslint@8.57.0):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.7.0(eslint@8.57.0)
|
||||
@@ -20427,7 +20488,7 @@ snapshots:
|
||||
eslint: 8.57.0
|
||||
ignore: 5.3.2
|
||||
|
||||
eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
|
||||
eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0):
|
||||
dependencies:
|
||||
array-includes: 3.1.7
|
||||
array.prototype.findlastindex: 1.2.4
|
||||
@@ -20454,40 +20515,13 @@ snapshots:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0):
|
||||
dependencies:
|
||||
array-includes: 3.1.7
|
||||
array.prototype.findlastindex: 1.2.4
|
||||
array.prototype.flat: 1.3.2
|
||||
array.prototype.flatmap: 1.3.2
|
||||
debug: 3.2.7
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.57.0
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.15.1
|
||||
is-glob: 4.0.3
|
||||
minimatch: 3.1.2
|
||||
object.fromentries: 2.0.8
|
||||
object.groupby: 1.0.3
|
||||
object.values: 1.2.0
|
||||
semver: 6.3.1
|
||||
tsconfig-paths: 3.15.0
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
transitivePeerDependencies:
|
||||
- eslint-import-resolver-typescript
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8))(typescript@5.4.5):
|
||||
eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0))(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.5)
|
||||
eslint: 8.57.0
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/eslint-plugin': 7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
|
||||
jest: 29.7.0(@types/node@20.14.8)
|
||||
jest: 29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
@@ -20529,12 +20563,12 @@ snapshots:
|
||||
|
||||
eslint-plugin-only-warn@1.1.0: {}
|
||||
|
||||
eslint-plugin-playwright@1.5.4(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8))(typescript@5.4.5))(eslint@8.57.0):
|
||||
eslint-plugin-playwright@1.5.4(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0))(typescript@5.4.5))(eslint@8.57.0):
|
||||
dependencies:
|
||||
eslint: 8.57.0
|
||||
globals: 13.24.0
|
||||
optionalDependencies:
|
||||
eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8))(typescript@5.4.5)
|
||||
eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0))(typescript@5.4.5)
|
||||
|
||||
eslint-plugin-prettier@5.1.3(@types/eslint@8.56.12)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.3):
|
||||
dependencies:
|
||||
@@ -20617,13 +20651,13 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-vitest@0.3.26(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)(vitest@2.1.2(@types/node@20.14.8)):
|
||||
eslint-plugin-vitest@0.3.26(@typescript-eslint/eslint-plugin@7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)(vitest@2.1.2(@types/node@20.14.8)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5))(terser@5.43.1)):
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 7.3.1(eslint@8.57.0)(typescript@5.4.5)
|
||||
eslint: 8.57.0
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/eslint-plugin': 7.3.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
|
||||
vitest: 2.1.2(@types/node@20.14.8)
|
||||
vitest: 2.1.2(@types/node@20.14.8)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5))(terser@5.43.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
@@ -21884,13 +21918,13 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jest-cli@29.7.0(@types/node@20.14.8):
|
||||
jest-cli@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0):
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
'@jest/test-result': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
chalk: 4.1.2
|
||||
create-jest: 29.7.0(@types/node@20.14.8)
|
||||
create-jest: 29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0)
|
||||
exit: 0.1.2
|
||||
import-local: 3.1.0
|
||||
jest-config: 29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
@@ -22191,7 +22225,7 @@ snapshots:
|
||||
|
||||
jest-worker@27.5.1:
|
||||
dependencies:
|
||||
'@types/node': 20.10.5
|
||||
'@types/node': 20.14.8
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
|
||||
@@ -22214,12 +22248,12 @@ snapshots:
|
||||
- supports-color
|
||||
- ts-node
|
||||
|
||||
jest@29.7.0(@types/node@20.14.8):
|
||||
jest@29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0):
|
||||
dependencies:
|
||||
'@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.10.5)(typescript@5.4.5))
|
||||
'@jest/types': 29.6.3
|
||||
import-local: 3.1.0
|
||||
jest-cli: 29.7.0(@types/node@20.14.8)
|
||||
jest-cli: 29.7.0(@types/node@20.14.8)(babel-plugin-macros@3.1.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
@@ -22417,19 +22451,19 @@ snapshots:
|
||||
- openai
|
||||
- ws
|
||||
|
||||
langfuse-core@3.37.4:
|
||||
langfuse-core@3.38.1:
|
||||
dependencies:
|
||||
mustache: 4.2.0
|
||||
|
||||
langfuse-langchain@3.37.4(langchain@0.3.28(@langchain/anthropic@0.3.22(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/aws@0.1.11(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(@langchain/google-genai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/google-vertexai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(zod@3.25.62))(axios@1.8.2)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.104.0(zod@3.25.62))):
|
||||
langfuse-langchain@3.38.1(langchain@0.3.28(@langchain/anthropic@0.3.22(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/aws@0.1.11(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(@langchain/google-genai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/google-vertexai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(zod@3.25.62))(axios@1.8.2)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.104.0(zod@3.25.62))):
|
||||
dependencies:
|
||||
langchain: 0.3.28(@langchain/anthropic@0.3.22(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/aws@0.1.11(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(@langchain/google-genai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62))))(@langchain/google-vertexai@0.2.12(@langchain/core@0.3.58(openai@4.104.0(zod@3.25.62)))(zod@3.25.62))(axios@1.8.2)(cheerio@1.0.0)(handlebars@4.7.8)(openai@4.104.0(zod@3.25.62))
|
||||
langfuse: 3.37.4
|
||||
langfuse-core: 3.37.4
|
||||
langfuse: 3.38.1
|
||||
langfuse-core: 3.38.1
|
||||
|
||||
langfuse@3.37.4:
|
||||
langfuse@3.38.1:
|
||||
dependencies:
|
||||
langfuse-core: 3.37.4
|
||||
langfuse-core: 3.38.1
|
||||
|
||||
langium@3.0.0:
|
||||
dependencies:
|
||||
@@ -23127,6 +23161,32 @@ snapshots:
|
||||
optionalDependencies:
|
||||
msgpackr-extract: 3.0.3
|
||||
|
||||
msw@2.6.5(@types/node@20.10.5)(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@bundled-es-modules/cookie': 2.0.1
|
||||
'@bundled-es-modules/statuses': 1.0.1
|
||||
'@bundled-es-modules/tough-cookie': 0.1.6
|
||||
'@inquirer/confirm': 5.0.2(@types/node@20.10.5)
|
||||
'@mswjs/interceptors': 0.37.1
|
||||
'@open-draft/deferred-promise': 2.2.0
|
||||
'@open-draft/until': 2.1.0
|
||||
'@types/cookie': 0.6.0
|
||||
'@types/statuses': 2.0.5
|
||||
chalk: 4.1.2
|
||||
graphql: 16.9.0
|
||||
headers-polyfill: 4.0.3
|
||||
is-node-process: 1.2.0
|
||||
outvariant: 1.4.3
|
||||
path-to-regexp: 6.3.0
|
||||
strict-event-emitter: 0.5.1
|
||||
type-fest: 4.27.0
|
||||
yargs: 17.7.2
|
||||
optionalDependencies:
|
||||
typescript: 5.4.5
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
optional: true
|
||||
|
||||
msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@bundled-es-modules/cookie': 2.0.1
|
||||
@@ -23152,6 +23212,32 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
|
||||
msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@bundled-es-modules/cookie': 2.0.1
|
||||
'@bundled-es-modules/statuses': 1.0.1
|
||||
'@bundled-es-modules/tough-cookie': 0.1.6
|
||||
'@inquirer/confirm': 5.0.2(@types/node@20.14.8)
|
||||
'@mswjs/interceptors': 0.37.1
|
||||
'@open-draft/deferred-promise': 2.2.0
|
||||
'@open-draft/until': 2.1.0
|
||||
'@types/cookie': 0.6.0
|
||||
'@types/statuses': 2.0.5
|
||||
chalk: 4.1.2
|
||||
graphql: 16.9.0
|
||||
headers-polyfill: 4.0.3
|
||||
is-node-process: 1.2.0
|
||||
outvariant: 1.4.3
|
||||
path-to-regexp: 6.3.0
|
||||
strict-event-emitter: 0.5.1
|
||||
type-fest: 4.27.0
|
||||
yargs: 17.7.2
|
||||
optionalDependencies:
|
||||
typescript: 5.4.5
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
optional: true
|
||||
|
||||
mustache@4.2.0: {}
|
||||
|
||||
mute-stream@2.0.0: {}
|
||||
@@ -25180,14 +25266,6 @@ snapshots:
|
||||
terser: 5.43.1
|
||||
webpack: 5.97.1
|
||||
|
||||
terser@5.43.0:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.6
|
||||
acorn: 8.15.0
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
optional: true
|
||||
|
||||
terser@5.43.1:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.6
|
||||
@@ -25681,12 +25759,12 @@ snapshots:
|
||||
'@egjs/hammerjs': 2.0.17
|
||||
component-emitter: 1.3.1
|
||||
|
||||
vite-node@2.1.2(@types/node@20.10.5):
|
||||
vite-node@2.1.2(@types/node@20.10.5)(terser@5.43.1):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.7(supports-color@5.5.0)
|
||||
pathe: 1.1.2
|
||||
vite: 5.2.14(@types/node@20.10.5)
|
||||
vite: 5.2.14(@types/node@20.10.5)(terser@5.43.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
@@ -25698,12 +25776,12 @@ snapshots:
|
||||
- terser
|
||||
optional: true
|
||||
|
||||
vite-node@2.1.2(@types/node@20.11.29)(terser@5.43.0):
|
||||
vite-node@2.1.2(@types/node@20.11.29)(terser@5.43.1):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.7(supports-color@5.5.0)
|
||||
pathe: 1.1.2
|
||||
vite: 5.2.14(@types/node@20.11.29)(terser@5.43.0)
|
||||
vite: 5.2.14(@types/node@20.11.29)(terser@5.43.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
@@ -25714,12 +25792,12 @@ snapshots:
|
||||
- supports-color
|
||||
- terser
|
||||
|
||||
vite-node@2.1.2(@types/node@20.14.8):
|
||||
vite-node@2.1.2(@types/node@20.14.8)(terser@5.43.1):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.7(supports-color@5.5.0)
|
||||
pathe: 1.1.2
|
||||
vite: 5.2.14(@types/node@20.14.8)
|
||||
vite: 5.2.14(@types/node@20.14.8)(terser@5.43.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
@@ -25731,7 +25809,7 @@ snapshots:
|
||||
- terser
|
||||
optional: true
|
||||
|
||||
vite@5.2.14(@types/node@20.10.5):
|
||||
vite@5.2.14(@types/node@20.10.5)(terser@5.43.1):
|
||||
dependencies:
|
||||
esbuild: 0.20.2
|
||||
postcss: 8.5.3
|
||||
@@ -25739,9 +25817,10 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/node': 20.10.5
|
||||
fsevents: 2.3.3
|
||||
terser: 5.43.1
|
||||
optional: true
|
||||
|
||||
vite@5.2.14(@types/node@20.11.29)(terser@5.43.0):
|
||||
vite@5.2.14(@types/node@20.11.29)(terser@5.43.1):
|
||||
dependencies:
|
||||
esbuild: 0.20.2
|
||||
postcss: 8.5.3
|
||||
@@ -25749,9 +25828,9 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/node': 20.11.29
|
||||
fsevents: 2.3.3
|
||||
terser: 5.43.0
|
||||
terser: 5.43.1
|
||||
|
||||
vite@5.2.14(@types/node@20.14.8):
|
||||
vite@5.2.14(@types/node@20.14.8)(terser@5.43.1):
|
||||
dependencies:
|
||||
esbuild: 0.20.2
|
||||
postcss: 8.5.3
|
||||
@@ -25759,12 +25838,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.8
|
||||
fsevents: 2.3.3
|
||||
terser: 5.43.1
|
||||
optional: true
|
||||
|
||||
vitest@2.1.2(@types/node@20.10.5):
|
||||
vitest@2.1.2(@types/node@20.10.5)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.10.5)(typescript@5.4.5))(terser@5.43.1):
|
||||
dependencies:
|
||||
'@vitest/expect': 2.1.2
|
||||
'@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.2.14(@types/node@20.10.5))
|
||||
'@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(msw@2.6.5(@types/node@20.10.5)(typescript@5.4.5))(vite@5.2.14(@types/node@20.10.5)(terser@5.43.1))
|
||||
'@vitest/pretty-format': 2.1.2
|
||||
'@vitest/runner': 2.1.2
|
||||
'@vitest/snapshot': 2.1.2
|
||||
@@ -25779,11 +25859,12 @@ snapshots:
|
||||
tinyexec: 0.3.0
|
||||
tinypool: 1.0.1
|
||||
tinyrainbow: 1.2.0
|
||||
vite: 5.2.14(@types/node@20.10.5)
|
||||
vite-node: 2.1.2(@types/node@20.10.5)
|
||||
vite: 5.2.14(@types/node@20.10.5)(terser@5.43.1)
|
||||
vite-node: 2.1.2(@types/node@20.10.5)(terser@5.43.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.10.5
|
||||
jsdom: 20.0.3
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
- lightningcss
|
||||
@@ -25795,10 +25876,10 @@ snapshots:
|
||||
- terser
|
||||
optional: true
|
||||
|
||||
vitest@2.1.2(@types/node@20.11.29)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(terser@5.43.0):
|
||||
vitest@2.1.2(@types/node@20.11.29)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(terser@5.43.1):
|
||||
dependencies:
|
||||
'@vitest/expect': 2.1.2
|
||||
'@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(vite@5.2.14(@types/node@20.11.29)(terser@5.43.0))
|
||||
'@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(msw@2.6.5(@types/node@20.11.29)(typescript@5.4.5))(vite@5.2.14(@types/node@20.11.29)(terser@5.43.1))
|
||||
'@vitest/pretty-format': 2.1.2
|
||||
'@vitest/runner': 2.1.2
|
||||
'@vitest/snapshot': 2.1.2
|
||||
@@ -25813,8 +25894,8 @@ snapshots:
|
||||
tinyexec: 0.3.0
|
||||
tinypool: 1.0.1
|
||||
tinyrainbow: 1.2.0
|
||||
vite: 5.2.14(@types/node@20.11.29)(terser@5.43.0)
|
||||
vite-node: 2.1.2(@types/node@20.11.29)(terser@5.43.0)
|
||||
vite: 5.2.14(@types/node@20.11.29)(terser@5.43.1)
|
||||
vite-node: 2.1.2(@types/node@20.11.29)(terser@5.43.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.11.29
|
||||
@@ -25829,10 +25910,10 @@ snapshots:
|
||||
- supports-color
|
||||
- terser
|
||||
|
||||
vitest@2.1.2(@types/node@20.14.8):
|
||||
vitest@2.1.2(@types/node@20.14.8)(jsdom@20.0.3)(msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5))(terser@5.43.1):
|
||||
dependencies:
|
||||
'@vitest/expect': 2.1.2
|
||||
'@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(vite@5.2.14(@types/node@20.14.8))
|
||||
'@vitest/mocker': 2.1.2(@vitest/spy@2.1.2)(msw@2.6.5(@types/node@20.14.8)(typescript@5.4.5))(vite@5.2.14(@types/node@20.14.8)(terser@5.43.1))
|
||||
'@vitest/pretty-format': 2.1.2
|
||||
'@vitest/runner': 2.1.2
|
||||
'@vitest/snapshot': 2.1.2
|
||||
@@ -25847,11 +25928,12 @@ snapshots:
|
||||
tinyexec: 0.3.0
|
||||
tinypool: 1.0.1
|
||||
tinyrainbow: 1.2.0
|
||||
vite: 5.2.14(@types/node@20.14.8)
|
||||
vite-node: 2.1.2(@types/node@20.14.8)
|
||||
vite: 5.2.14(@types/node@20.14.8)(terser@5.43.1)
|
||||
vite-node: 2.1.2(@types/node@20.14.8)(terser@5.43.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.8
|
||||
jsdom: 20.0.3
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
- lightningcss
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "3.78.1",
|
||||
"version": "3.78.2",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -244,6 +244,67 @@ describe("/api/public/scores API Endpoint", () => {
|
||||
"test-key": "test-value-updated",
|
||||
});
|
||||
});
|
||||
|
||||
it("should post score with score config if in valid range", async () => {
|
||||
const configId = v4();
|
||||
const traceId = v4();
|
||||
const scoreId = v4();
|
||||
|
||||
const { projectId: projectId, auth } = await createOrgProjectAndApiKey();
|
||||
|
||||
const config = await prisma.scoreConfig.create({
|
||||
data: {
|
||||
name: "score-name",
|
||||
id: configId,
|
||||
dataType: "NUMERIC",
|
||||
maxValue: 100,
|
||||
projectId: projectId,
|
||||
},
|
||||
});
|
||||
|
||||
const trace = createTrace({
|
||||
id: traceId,
|
||||
project_id: projectId,
|
||||
});
|
||||
await createTracesCh([trace]);
|
||||
|
||||
const score = createTraceScore({
|
||||
id: scoreId,
|
||||
project_id: projectId,
|
||||
trace_id: traceId,
|
||||
name: "score-name",
|
||||
value: 100,
|
||||
source: "API",
|
||||
comment: "comment",
|
||||
metadata: { "test-key": "test-value" },
|
||||
observation_id: null,
|
||||
environment: "production",
|
||||
config_id: config.id,
|
||||
});
|
||||
await createScoresCh([score]);
|
||||
|
||||
const fetchedScore = await makeZodVerifiedAPICall(
|
||||
GetScoreResponseV1,
|
||||
"GET",
|
||||
`/api/public/scores/${scoreId}`,
|
||||
undefined,
|
||||
auth,
|
||||
);
|
||||
|
||||
expect(fetchedScore.body?.id).toBe(scoreId);
|
||||
expect(fetchedScore.body?.traceId).toBe(traceId);
|
||||
expect(fetchedScore.body?.name).toBe("score-name");
|
||||
expect(fetchedScore.body?.value).toBe(100);
|
||||
expect(fetchedScore.body?.configId).toBe(configId);
|
||||
expect(fetchedScore.body?.observationId).toBeNull();
|
||||
expect(fetchedScore.body?.comment).toBe("comment");
|
||||
expect(fetchedScore.body?.source).toBe("API");
|
||||
expect(fetchedScore.body?.projectId).toBe(projectId);
|
||||
expect(fetchedScore.body?.environment).toBe("production");
|
||||
expect(fetchedScore.body?.metadata).toEqual({
|
||||
"test-key": "test-value",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET /api/public/scores", () => {
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v3.78.1";
|
||||
export const VERSION = "v3.78.2";
|
||||
|
||||
@@ -456,13 +456,15 @@ export function PreviewCsvImport({
|
||||
</Button>
|
||||
<Button
|
||||
disabled={
|
||||
selectedInputColumn.size === 0 &&
|
||||
selectedExpectedColumn.size === 0 &&
|
||||
selectedMetadataColumn.size === 0
|
||||
(selectedInputColumn.size === 0 &&
|
||||
selectedExpectedColumn.size === 0 &&
|
||||
selectedMetadataColumn.size === 0) ||
|
||||
progress.status === "processing"
|
||||
}
|
||||
loading={progress.status === "processing"}
|
||||
onClick={handleImport}
|
||||
>
|
||||
Import
|
||||
{progress.status === "processing" ? "Importing..." : "Import"}
|
||||
</Button>
|
||||
{progress.status === "processing" && (
|
||||
<div className="mt-2">
|
||||
|
||||
@@ -619,7 +619,7 @@ export class OtelIngestionProcessor {
|
||||
}
|
||||
|
||||
private hasTraceUpdates(attributes: Record<string, unknown>): boolean {
|
||||
return [
|
||||
const hasExactMatchingAttributeName = [
|
||||
LangfuseOtelSpanAttributes.TRACE_NAME,
|
||||
LangfuseOtelSpanAttributes.TRACE_INPUT,
|
||||
LangfuseOtelSpanAttributes.TRACE_OUTPUT,
|
||||
@@ -637,6 +637,13 @@ export class OtelIngestionProcessor {
|
||||
`${LangfuseOtelSpanAttributes.TRACE_METADATA}.langfuse_user_id`,
|
||||
`${LangfuseOtelSpanAttributes.TRACE_METADATA}.langfuse_tags`,
|
||||
].some((traceAttribute) => Boolean(attributes[traceAttribute]));
|
||||
|
||||
const attributeKeys = Object.keys(attributes);
|
||||
const hasTraceMetadataKey = attributeKeys.some((key) =>
|
||||
key.startsWith(LangfuseOtelSpanAttributes.TRACE_METADATA),
|
||||
);
|
||||
|
||||
return hasExactMatchingAttributeName || hasTraceMetadataKey;
|
||||
}
|
||||
|
||||
private extractResourceAttributes(
|
||||
|
||||
@@ -991,9 +991,42 @@ export function WidgetForm({
|
||||
value={selectedView}
|
||||
onValueChange={(value) => {
|
||||
if (value !== selectedView) {
|
||||
const newView = value as z.infer<typeof views>;
|
||||
const newViewDeclaration = viewDeclarations[newView];
|
||||
|
||||
// Reset regular chart fields
|
||||
setSelectedMeasure("count");
|
||||
setSelectedAggregation("count");
|
||||
setSelectedDimension("none");
|
||||
|
||||
// Handle pivot table metrics - filter out invalid measures for the new view
|
||||
if (selectedChartType === "PIVOT_TABLE") {
|
||||
const validMetrics = selectedMetrics.filter(
|
||||
(metric) =>
|
||||
metric.measure in newViewDeclaration.measures,
|
||||
);
|
||||
|
||||
// Ensure we have at least one valid metric (count is always available)
|
||||
if (validMetrics.length === 0) {
|
||||
validMetrics.push({
|
||||
id: "count_count",
|
||||
measure: "count",
|
||||
aggregation: "count" as z.infer<
|
||||
typeof metricAggregations
|
||||
>,
|
||||
label: "Count Count",
|
||||
});
|
||||
}
|
||||
|
||||
setSelectedMetrics(validMetrics);
|
||||
|
||||
// Handle pivot table dimensions - filter out invalid dimensions for the new view
|
||||
const validDimensions = pivotDimensions.filter(
|
||||
(dimension) =>
|
||||
dimension in newViewDeclaration.dimensions,
|
||||
);
|
||||
setPivotDimensions(validDimensions);
|
||||
}
|
||||
}
|
||||
setSelectedView(value as z.infer<typeof views>);
|
||||
}}
|
||||
@@ -1109,39 +1142,38 @@ export function WidgetForm({
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{currentMeasure &&
|
||||
currentMeasure !== "count" && (
|
||||
<div className="flex-1">
|
||||
<Select
|
||||
value={currentAggregation}
|
||||
onValueChange={(value) =>
|
||||
updatePivotMetric(
|
||||
index,
|
||||
currentMeasure,
|
||||
value as z.infer<
|
||||
typeof metricAggregations
|
||||
>,
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select aggregation" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{aggregationsForIndex.map(
|
||||
(aggregation) => (
|
||||
<SelectItem
|
||||
key={aggregation}
|
||||
value={aggregation}
|
||||
>
|
||||
{startCase(aggregation)}
|
||||
</SelectItem>
|
||||
),
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
{currentMeasure && currentMeasure !== "count" && (
|
||||
<div className="flex-1">
|
||||
<Select
|
||||
value={currentAggregation}
|
||||
onValueChange={(value) =>
|
||||
updatePivotMetric(
|
||||
index,
|
||||
currentMeasure,
|
||||
value as z.infer<
|
||||
typeof metricAggregations
|
||||
>,
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select aggregation" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{aggregationsForIndex.map(
|
||||
(aggregation) => (
|
||||
<SelectItem
|
||||
key={aggregation}
|
||||
value={aggregation}
|
||||
>
|
||||
{startCase(aggregation)}
|
||||
</SelectItem>
|
||||
),
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "worker",
|
||||
"version": "3.78.1",
|
||||
"version": "3.78.2",
|
||||
"description": "",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
@@ -13,7 +13,7 @@
|
||||
"start": "dotenv -e ../.env -- node dist/index.js",
|
||||
"build": "tsc",
|
||||
"dev": "dotenv -e ../.env -- nodemon src/index.ts",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 21",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --max-warnings 0",
|
||||
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
|
||||
"refill-ingestion-events": "dotenv -e ../.env -- tsx src/scripts/s3-ingestion-event-relpay.ts",
|
||||
"refill-billing-event": "dotenv -e ../.env -- tsx src/scripts/refill-billing-event.ts"
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v3.78.1";
|
||||
export const VERSION = "v3.78.2";
|
||||
|
||||
+1
-1
@@ -232,6 +232,6 @@ const EnvSchema = z.object({
|
||||
});
|
||||
|
||||
export const env: z.infer<typeof EnvSchema> =
|
||||
process.env.DOCKER_BUILD === "1"
|
||||
process.env.DOCKER_BUILD === "1" // eslint-disable-line turbo/no-undeclared-env-vars
|
||||
? (process.env as any)
|
||||
: EnvSchema.parse(removeEmptyEnvVariables(process.env));
|
||||
|
||||
@@ -49,6 +49,7 @@ import {
|
||||
TraceDomain,
|
||||
Observation,
|
||||
DatasetItem,
|
||||
QUEUE_ERROR_MESSAGES,
|
||||
} from "@langfuse/shared";
|
||||
import { kyselyPrisma, prisma } from "@langfuse/shared/src/db";
|
||||
import { backOff } from "exponential-backoff";
|
||||
@@ -877,11 +878,11 @@ export async function extractVariablesFromTracingData({
|
||||
// user facing errors
|
||||
if (!observation) {
|
||||
logger.warn(
|
||||
`Observation ${mapping.objectName} for trace ${traceId} not found. Please ensure the mapped data exists and consider extending the job delay.`,
|
||||
`Observation ${mapping.objectName} for trace ${traceId} not found. ${QUEUE_ERROR_MESSAGES.MAPPED_DATA_ERROR}`,
|
||||
);
|
||||
// this should only happen for deleted data or data replication lags across clickhouse nodes.
|
||||
throw new LangfuseNotFoundError(
|
||||
`Observation ${mapping.objectName} for trace ${traceId} not found. Please ensure the mapped data exists and consider extending the job delay.`,
|
||||
`Observation ${mapping.objectName} for trace ${traceId} not found. ${QUEUE_ERROR_MESSAGES.MAPPED_DATA_ERROR}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
LangfuseNotFoundError,
|
||||
type Prisma,
|
||||
PromptType,
|
||||
QUEUE_ERROR_MESSAGES,
|
||||
stringifyValue,
|
||||
} from "@langfuse/shared";
|
||||
import { backOff } from "exponential-backoff";
|
||||
@@ -51,8 +52,8 @@ const replaceVariablesInPrompt = (
|
||||
const processContent = (content: string) => {
|
||||
// Extract only Handlebars variables from itemInput (exclude message placeholders)
|
||||
const filteredContext = Object.fromEntries(
|
||||
Object.entries(itemInput).filter(([key]) =>
|
||||
variables.includes(key) && !placeholderNames.includes(key)
|
||||
Object.entries(itemInput).filter(
|
||||
([key]) => variables.includes(key) && !placeholderNames.includes(key),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -85,29 +86,36 @@ const replaceVariablesInPrompt = (
|
||||
|
||||
// for stringified arrays (e.g. from dataset processing)
|
||||
let actualValue = value;
|
||||
if (typeof value === 'string') {
|
||||
if (typeof value === "string") {
|
||||
try {
|
||||
actualValue = JSON.parse(value);
|
||||
} catch (_e) {
|
||||
throw new Error(`Invalid placeholder value for '${placeholderName}': unable to parse JSON`);
|
||||
throw new Error(
|
||||
`Invalid placeholder value for '${placeholderName}': unable to parse JSON`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.isArray(actualValue)) {
|
||||
throw new Error(`Placeholder '${placeholderName}' must be an array of messages`);
|
||||
throw new Error(
|
||||
`Placeholder '${placeholderName}' must be an array of messages`,
|
||||
);
|
||||
}
|
||||
|
||||
const validMessages = actualValue.every(msg =>
|
||||
typeof msg === 'object' &&
|
||||
msg !== null &&
|
||||
'role' in msg &&
|
||||
'content' in msg
|
||||
const validMessages = actualValue.every(
|
||||
(msg) =>
|
||||
typeof msg === "object" &&
|
||||
msg !== null &&
|
||||
"role" in msg &&
|
||||
"content" in msg,
|
||||
);
|
||||
if (!validMessages) {
|
||||
throw new Error(`Invalid placeholder value for '${placeholderName}': messages must have 'role' and 'content' properties`);
|
||||
throw new Error(
|
||||
`Invalid placeholder value for '${placeholderName}': messages must have 'role' and 'content' properties`,
|
||||
);
|
||||
}
|
||||
|
||||
placeholderValues[placeholderName] = actualValue.map(msg => ({
|
||||
placeholderValues[placeholderName] = actualValue.map((msg) => ({
|
||||
...msg,
|
||||
type: ChatMessageType.PublicAPICreated as const,
|
||||
}));
|
||||
@@ -116,7 +124,7 @@ const replaceVariablesInPrompt = (
|
||||
const compiledMessages = compileChatMessages(
|
||||
prompt as PromptMessage[],
|
||||
placeholderValues,
|
||||
{}
|
||||
{},
|
||||
);
|
||||
|
||||
return compiledMessages.map((message) => ({
|
||||
@@ -227,13 +235,13 @@ export const createExperimentJob = async ({
|
||||
});
|
||||
if (!apiKey) {
|
||||
throw new LangfuseNotFoundError(
|
||||
`API key for provider ${provider} not found`,
|
||||
`${QUEUE_ERROR_MESSAGES.API_KEY_ERROR} ${provider} not found`,
|
||||
);
|
||||
}
|
||||
const validatedApiKey = LLMApiKeySchema.safeParse(apiKey);
|
||||
if (!validatedApiKey.success) {
|
||||
throw new InvalidRequestError(
|
||||
`API key for provider ${provider} not found.`,
|
||||
`${QUEUE_ERROR_MESSAGES.API_KEY_ERROR} ${provider} not found.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -257,9 +265,10 @@ export const createExperimentJob = async ({
|
||||
);
|
||||
|
||||
// also extract placeholder names if prompt is a chat prompt
|
||||
const placeholderNames = prompt?.type === PromptType.Chat && Array.isArray(validatedPrompt.data)
|
||||
? extractPlaceholderNames(validatedPrompt.data as PromptMessage[])
|
||||
: [];
|
||||
const placeholderNames =
|
||||
prompt?.type === PromptType.Chat && Array.isArray(validatedPrompt.data)
|
||||
? extractPlaceholderNames(validatedPrompt.data as PromptMessage[])
|
||||
: [];
|
||||
const allVariables = [...extractedVariables, ...placeholderNames];
|
||||
|
||||
// validate dataset items against prompt configuration
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { Job } from "bullmq";
|
||||
import { ApiError, BaseError, LangfuseNotFoundError } from "@langfuse/shared";
|
||||
import {
|
||||
ApiError,
|
||||
BaseError,
|
||||
LangfuseNotFoundError,
|
||||
QUEUE_ERROR_MESSAGES,
|
||||
} from "@langfuse/shared";
|
||||
import { kyselyPrisma } from "@langfuse/shared/src/db";
|
||||
import { sql } from "kysely";
|
||||
import {
|
||||
@@ -150,22 +155,20 @@ export const evalJobExecutorQueueProcessor = async (
|
||||
e instanceof LangfuseNotFoundError ||
|
||||
(e instanceof BaseError &&
|
||||
e.message.includes(
|
||||
"Could not parse response content as the length limit was reached",
|
||||
QUEUE_ERROR_MESSAGES.OUTPUT_TOKENS_TOO_LONG_ERROR,
|
||||
)) || // output tokens too long
|
||||
(e instanceof BaseError && e.message.includes("API key for provider")) || // api key not provided
|
||||
(e instanceof BaseError &&
|
||||
e.message.includes(
|
||||
"`No default model or custom model found for project",
|
||||
)) || // api key not provided
|
||||
e.message.includes(QUEUE_ERROR_MESSAGES.API_KEY_ERROR)) || // api key not provided
|
||||
(e instanceof BaseError &&
|
||||
e.message.includes(QUEUE_ERROR_MESSAGES.NO_DEFAULT_MODEL_ERROR)) || // api key not provided
|
||||
(e instanceof ApiError && e.httpCode >= 400 && e.httpCode < 500) || // do not error and retry on 4xx errors. They are visible to the user in the UI but do not alert us.
|
||||
(e instanceof ApiError && e.message.includes("TypeError")) || // Zod parsing the response failed. User should update prompt to consistently return expected output structure.
|
||||
(e instanceof ApiError &&
|
||||
e.message.includes("Error: Unterminated string in JSON at position")) || // When evaluator model is configured with too low max_tokens, the structured output response is invalid JSON
|
||||
(e instanceof ApiError && e.message.includes("is not valid JSON")) || // When evaluator model is not consistently returning valid JSON on structured output calls
|
||||
e.message.includes(QUEUE_ERROR_MESSAGES.TOO_LOW_MAX_TOKENS_ERROR)) || // When evaluator model is configured with too low max_tokens, the structured output response is invalid JSON
|
||||
(e instanceof ApiError &&
|
||||
e.message.includes(QUEUE_ERROR_MESSAGES.INVALID_JSON_ERROR)) || // When evaluator model is not consistently returning valid JSON on structured output calls
|
||||
(e instanceof BaseError &&
|
||||
e.message.includes(
|
||||
"Please ensure the mapped data exists and consider extending the job delay.",
|
||||
)) // Trace not found.
|
||||
e.message.includes(QUEUE_ERROR_MESSAGES.MAPPED_DATA_ERROR)) // Trace not found.
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export class ClickhouseWriter {
|
||||
queue: ClickhouseQueue;
|
||||
|
||||
isIntervalFlushInProgress: boolean;
|
||||
intervalId: NodeJS.Timeout | null = null;
|
||||
intervalId: NodeJS.Timeout | null = null; // eslint-disable-line no-undef
|
||||
|
||||
private constructor() {
|
||||
this.batchSize = env.LANGFUSE_INGESTION_CLICKHOUSE_WRITE_BATCH_SIZE;
|
||||
@@ -239,11 +239,11 @@ export class ClickhouseWriter {
|
||||
}
|
||||
|
||||
export enum TableName {
|
||||
Traces = "traces",
|
||||
TracesMt = "traces_mt",
|
||||
Scores = "scores",
|
||||
Observations = "observations",
|
||||
BlobStorageFileLog = "blob_storage_file_log",
|
||||
Traces = "traces", // eslint-disable-line no-unused-vars
|
||||
TracesMt = "traces_mt", // eslint-disable-line no-unused-vars
|
||||
Scores = "scores", // eslint-disable-line no-unused-vars
|
||||
Observations = "observations", // eslint-disable-line no-unused-vars
|
||||
BlobStorageFileLog = "blob_storage_file_log", // eslint-disable-line no-unused-vars
|
||||
}
|
||||
|
||||
type RecordInsertType<T extends TableName> = T extends TableName.Scores
|
||||
|
||||
@@ -71,7 +71,11 @@ CREATE TABLE traces_all_amt
|
||||
`name` SimpleAggregateFunction(anyLast, String),
|
||||
|
||||
-- Metadata properties
|
||||
`metadata` AggregateFunction(argMax, Map(LowCardinality(String), String), DateTime64(3)),
|
||||
-- Metadata takes the last seen value in this form.
|
||||
-- If we spread it across multiple rows (keys + values) we might be able to allow updates/overwrites.
|
||||
-- Indexing speed in this case is unclear though.
|
||||
`metadata_argmax` AggregateFunction(argMax, Map(LowCardinality(String), String), DateTime64(3)),
|
||||
`metadata` SimpleAggregateFunction(anyLast, Map(String, String)),
|
||||
`user_id_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
`session_id_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
`environment_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
@@ -121,14 +125,15 @@ SELECT
|
||||
anyLast(t0.name) as name,
|
||||
|
||||
-- Metadata properties
|
||||
argMaxState(t0.metadata, t0.event_ts) as metadata,
|
||||
argMaxState(t0.metadata, if(t0.metadata <> '{}', t0.event_ts, toDateTime64(0,3))) as metadata_argmax,
|
||||
anyLastMap(t0.metadata) as metadata,
|
||||
argMaxState(t0.user_id, if(t0.user_id <> '', t0.event_ts, toDateTime64(0, 3))) as user_id_argmax,
|
||||
argMaxState(t0.session_id, if(t0.session_id <> '', t0.event_ts, toDateTime64(0, 3))) as session_id_argmax,
|
||||
argMaxState(t0.environment, if(t0.environment <> '', t0.event_ts, toDateTime64(0, 3))) as environment_argmax,
|
||||
anyLast(t0.user_id) as user_id,
|
||||
anyLast(t0.session_id) as session_id,
|
||||
anyLast(t0.environment) as environment,
|
||||
groupUniqArrayArray(t0.tags) as tags,
|
||||
groupUniqArrayArray(t0.tags) as tags,
|
||||
argMaxState(t0.version, if(t0.version <> '', t0.event_ts, toDateTime64(0, 3))) as version,
|
||||
argMaxState(t0.release, if(t0.release <> '', t0.event_ts, toDateTime64(0, 3))) as release,
|
||||
|
||||
@@ -165,7 +170,8 @@ CREATE TABLE traces_7d_amt
|
||||
`name` SimpleAggregateFunction(anyLast, String),
|
||||
|
||||
-- Metadata properties
|
||||
`metadata` AggregateFunction(argMax, Map(LowCardinality(String), String), DateTime64(3)),
|
||||
`metadata_argmax` AggregateFunction(argMax, Map(LowCardinality(String), String), DateTime64(3)),
|
||||
`metadata` SimpleAggregateFunction(anyLast, Map(String, String)),
|
||||
`user_id_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
`session_id_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
`environment_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
@@ -215,14 +221,15 @@ SELECT
|
||||
anyLast(t0.name) as name,
|
||||
|
||||
-- Metadata properties
|
||||
argMaxState(t0.metadata, t0.event_ts) as metadata,
|
||||
argMaxState(t0.metadata, if(t0.metadata <> '{}', t0.event_ts, toDateTime64(0,3))) as metadata_argmax,
|
||||
anyLastMap(t0.metadata) as metadata,
|
||||
argMaxState(t0.user_id, if(t0.user_id <> '', t0.event_ts, toDateTime64(0, 3))) as user_id_argmax,
|
||||
argMaxState(t0.session_id, if(t0.session_id <> '', t0.event_ts, toDateTime64(0, 3))) as session_id_argmax,
|
||||
argMaxState(t0.environment, if(t0.environment <> '', t0.event_ts, toDateTime64(0, 3))) as environment_argmax,
|
||||
anyLast(t0.user_id) as user_id,
|
||||
anyLast(t0.session_id) as session_id,
|
||||
anyLast(t0.environment) as environment,
|
||||
groupUniqArrayArray(t0.tags) as tags,
|
||||
groupUniqArrayArray(t0.tags) as tags,
|
||||
argMaxState(t0.version, if(t0.version <> '', t0.event_ts, toDateTime64(0, 3))) as version,
|
||||
argMaxState(t0.release, if(t0.release <> '', t0.event_ts, toDateTime64(0, 3))) as release,
|
||||
|
||||
@@ -259,7 +266,8 @@ CREATE TABLE traces_30d_amt
|
||||
`name` SimpleAggregateFunction(anyLast, String),
|
||||
|
||||
-- Metadata properties
|
||||
`metadata` AggregateFunction(argMax, Map(LowCardinality(String), String), DateTime64(3)),
|
||||
`metadata_argmax` AggregateFunction(argMax, Map(LowCardinality(String), String), DateTime64(3)),
|
||||
`metadata` SimpleAggregateFunction(anyLast, Map(String, String)),
|
||||
`user_id_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
`session_id_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
`environment_argmax` AggregateFunction(argMax, String, DateTime64(3)),
|
||||
@@ -309,14 +317,15 @@ SELECT
|
||||
anyLast(t0.name) as name,
|
||||
|
||||
-- Metadata properties
|
||||
argMaxState(t0.metadata, t0.event_ts) as metadata,
|
||||
argMaxState(t0.metadata, if(t0.metadata <> '{}', t0.event_ts, toDateTime64(0,3))) as metadata_argmax,
|
||||
anyLastMap(t0.metadata) as metadata,
|
||||
argMaxState(t0.user_id, if(t0.user_id <> '', t0.event_ts, toDateTime64(0, 3))) as user_id_argmax,
|
||||
argMaxState(t0.session_id, if(t0.session_id <> '', t0.event_ts, toDateTime64(0, 3))) as session_id_argmax,
|
||||
argMaxState(t0.environment, if(t0.environment <> '', t0.event_ts, toDateTime64(0, 3))) as environment_argmax,
|
||||
anyLast(t0.user_id) as user_id,
|
||||
anyLast(t0.session_id) as session_id,
|
||||
anyLast(t0.environment) as environment,
|
||||
groupUniqArrayArray(t0.tags) as tags,
|
||||
groupUniqArrayArray(t0.tags) as tags,
|
||||
argMaxState(t0.version, if(t0.version <> '', t0.event_ts, toDateTime64(0, 3))) as version,
|
||||
argMaxState(t0.release, if(t0.release <> '', t0.event_ts, toDateTime64(0, 3))) as release,
|
||||
|
||||
@@ -342,6 +351,8 @@ FROM traces_mt t0
|
||||
GROUP BY project_id, id;
|
||||
```
|
||||
|
||||
## Query AggregatingMergeTrees
|
||||
|
||||
We can query the properties of the resulting AggregatingMergeTree via (make sure to pick the right timeframe:
|
||||
```sql
|
||||
SELECT
|
||||
@@ -386,3 +397,129 @@ SELECT
|
||||
FROM traces_all_amt
|
||||
LIMIT 100;
|
||||
```
|
||||
|
||||
## Find discrepancies
|
||||
|
||||
We can identify discrepancies in the original and the new data using
|
||||
```sql
|
||||
-- Query to compare traces_all_amt with traces table and identify discrepancies
|
||||
WITH amt_data AS (
|
||||
-- First get the finalized values from the AMT table
|
||||
SELECT project_id,
|
||||
id,
|
||||
start_time,
|
||||
end_time,
|
||||
finalizeAggregation(name_argmax) AS name_argmax_value,
|
||||
name AS name_anylast_value,
|
||||
|
||||
finalizeAggregation(metadata_argmax) AS metadata_argmax_value,
|
||||
metadata AS metadata_anylast_value,
|
||||
finalizeAggregation(user_id_argmax) AS user_id_argmax_value,
|
||||
user_id AS user_id_anylast_value,
|
||||
finalizeAggregation(session_id_argmax) AS session_id_argmax_value,
|
||||
session_id AS session_id_anylast_value,
|
||||
finalizeAggregation(environment_argmax) AS environment_argmax_value,
|
||||
environment AS environment_anylast_value,
|
||||
tags,
|
||||
finalizeAggregation(version) AS version_value,
|
||||
finalizeAggregation(release) AS release_value,
|
||||
|
||||
finalizeAggregation(bookmarked) AS bookmarked_value,
|
||||
finalizeAggregation(public) AS public_value,
|
||||
|
||||
finalizeAggregation(input_argmax) AS input_argmax_value,
|
||||
input AS input_anylast_value,
|
||||
finalizeAggregation(output_argmax) AS output_argmax_value,
|
||||
output AS output_anylast_value,
|
||||
|
||||
created_at,
|
||||
updated_at
|
||||
FROM traces_all_amt
|
||||
)
|
||||
|
||||
-- Main query to compare AMT with original traces table
|
||||
SELECT t.project_id,
|
||||
t.id,
|
||||
-- Identify differences between tables
|
||||
t.timestamp != a.start_time AS timestamp_diff,
|
||||
t.name != a.name_anylast_value AS name_diff,
|
||||
t.user_id != a.user_id_anylast_value AS user_id_diff,
|
||||
t.session_id != a.session_id_anylast_value AS session_id_diff,
|
||||
t.release != a.release_value AS release_diff,
|
||||
t.version != a.version_value AS version_diff,
|
||||
t.public != a.public_value AS public_diff,
|
||||
t.bookmarked != a.bookmarked_value AS bookmarked_diff,
|
||||
arraySort(t.tags) != arraySort(a.tags) AS tags_diff,
|
||||
t.input != a.input_anylast_value AS input_diff,
|
||||
t.output != a.output_anylast_value AS output_diff,
|
||||
t.metadata != a.metadata_anylast_value AS metadata_diff,
|
||||
|
||||
a.name_argmax_value != a.name_anylast_value AS amt_name_diff,
|
||||
a.user_id_argmax_value != a.user_id_anylast_value AS amt_user_id_diff,
|
||||
a.session_id_argmax_value != a.session_id_anylast_value AS amt_session_id_diff,
|
||||
a.environment_argmax_value != a.environment_anylast_value AS amt_environment_diff,
|
||||
a.input_argmax_value != a.input_anylast_value AS amt_input_diff,
|
||||
a.output_argmax_value != a.output_anylast_value AS amt_output_diff,
|
||||
a.metadata_argmax_value != a.metadata_anylast_value AS amt_metadata_diff,
|
||||
|
||||
-- Include original values for comparison
|
||||
t.timestamp AS traces_timestamp,
|
||||
a.start_time AS amt_start_time,
|
||||
t.name AS traces_name,
|
||||
a.name_anylast_value AS amt_name_anylast,
|
||||
a.name_argmax_value AS amt_name_argmax,
|
||||
t.user_id AS traces_user_id,
|
||||
a.user_id_anylast_value AS amt_user_id_anylast,
|
||||
a.user_id_argmax_value AS amt_user_id_argmax,
|
||||
t.session_id AS traces_session_id,
|
||||
a.session_id_anylast_value AS amt_session_id_anylast,
|
||||
a.session_id_argmax_value AS amt_session_id_argmax,
|
||||
t.environment AS traces_environment,
|
||||
a.environment_anylast_value AS amt_environment_anylast,
|
||||
a.environment_argmax_value AS amt_environment_argmax,
|
||||
|
||||
t.metadata AS traces_metadata,
|
||||
a.metadata_anylast_value AS amt_metadata_anylast,
|
||||
a.metadata_argmax_value AS amt_metadata_argmax,
|
||||
arraySort(t.tags) AS traces_tags,
|
||||
arraySort(a.tags) AS amt_tags,
|
||||
t.bookmarked AS traces_bookmarked,
|
||||
a.bookmarked_value AS amt_bookmarked,
|
||||
t.public AS traces_public,
|
||||
a.public_value AS amt_public,
|
||||
t.release AS traces_release,
|
||||
a.release_value AS amt_release,
|
||||
t.version AS traces_version,
|
||||
a.version_value AS amt_version,
|
||||
|
||||
t.input AS traces_input,
|
||||
a.input_anylast_value AS amt_input_anylast,
|
||||
a.input_argmax_value AS amt_input_argmax,
|
||||
t.output AS traces_output,
|
||||
a.output_anylast_value AS amt_output_anylast,
|
||||
a.output_argmax_value AS amt_output_argmax,
|
||||
|
||||
timestamp_diff +
|
||||
name_diff +
|
||||
user_id_diff +
|
||||
session_id_diff +
|
||||
release_diff +
|
||||
version_diff +
|
||||
public_diff +
|
||||
bookmarked_diff +
|
||||
tags_diff +
|
||||
input_diff +
|
||||
output_diff +
|
||||
metadata_diff
|
||||
AS total_diff
|
||||
|
||||
FROM traces t FINAL
|
||||
LEFT JOIN amt_data a ON t.project_id = a.project_id AND t.id = a.id
|
||||
where (t.timestamp >= '2025-07-01'
|
||||
or a.start_time >= '2025-07-01')
|
||||
and t.project_id in (
|
||||
'some-project-id'
|
||||
)
|
||||
ORDER BY total_diff desc
|
||||
LIMIT 1000;
|
||||
```
|
||||
@@ -93,8 +93,8 @@ export class IngestionService {
|
||||
constructor(
|
||||
private redis: Redis | Cluster,
|
||||
private prisma: PrismaClient,
|
||||
private clickHouseWriter: ClickhouseWriter,
|
||||
private clickhouseClient: ClickhouseClientType,
|
||||
private clickHouseWriter: ClickhouseWriter, // eslint-disable-line no-unused-vars
|
||||
private clickhouseClient: ClickhouseClientType, // eslint-disable-line no-unused-vars
|
||||
) {
|
||||
this.promptService = new PromptService(prisma, redis);
|
||||
}
|
||||
@@ -220,6 +220,14 @@ export class IngestionService {
|
||||
clickhouseScoreRecord?.created_at ?? createdAtTimestamp.getTime();
|
||||
|
||||
this.clickHouseWriter.addToQueue(TableName.Scores, finalScoreRecord);
|
||||
|
||||
if (
|
||||
env.LANGFUSE_EXPERIMENT_INSERT_INTO_AGGREGATING_MERGE_TREES === "true" &&
|
||||
finalScoreRecord.trace_id
|
||||
) {
|
||||
const traceMtRecord = this.convertScoreToTraceMt(finalScoreRecord);
|
||||
this.clickHouseWriter.addToQueue(TableName.TracesMt, traceMtRecord);
|
||||
}
|
||||
}
|
||||
|
||||
private async processTraceEventList(params: {
|
||||
@@ -453,6 +461,14 @@ export class IngestionService {
|
||||
TableName.Observations,
|
||||
finalObservationRecord,
|
||||
);
|
||||
|
||||
if (
|
||||
env.LANGFUSE_EXPERIMENT_INSERT_INTO_AGGREGATING_MERGE_TREES === "true" &&
|
||||
finalObservationRecord.trace_id
|
||||
) {
|
||||
const traceMtRecord = this.convertObservationToTraceMt(finalObservationRecord);
|
||||
this.clickHouseWriter.addToQueue(TableName.TracesMt, traceMtRecord);
|
||||
}
|
||||
}
|
||||
|
||||
private async mergeScoreRecords(params: {
|
||||
@@ -543,6 +559,90 @@ export class IngestionService {
|
||||
};
|
||||
}
|
||||
|
||||
private convertObservationToTraceMt(
|
||||
observationRecord: ObservationRecordInsertType,
|
||||
): TraceMtRecordInsertType {
|
||||
return {
|
||||
// Identifiers
|
||||
project_id: observationRecord.project_id,
|
||||
// Use trace_id as the id in traces_mt. Always set given the conditions around calling the function
|
||||
id: observationRecord.trace_id || "",
|
||||
start_time: observationRecord.start_time,
|
||||
end_time: observationRecord.end_time || null,
|
||||
name: "",
|
||||
|
||||
// Metadata properties
|
||||
metadata: {},
|
||||
user_id: '',
|
||||
session_id: '',
|
||||
environment: observationRecord.environment,
|
||||
tags: [],
|
||||
version: null,
|
||||
release: null,
|
||||
|
||||
// UI properties - nullable to prevent absent values being interpreted as overwrites
|
||||
bookmarked: null,
|
||||
public: null,
|
||||
|
||||
// Aggregations - include this observation ID
|
||||
observation_ids: [observationRecord.id],
|
||||
score_ids: [],
|
||||
// We can fill the cost details here, but we shouldn't trust them.
|
||||
// Only used for verification to estimate how big the double-counting is.
|
||||
cost_details: observationRecord.cost_details || {},
|
||||
usage_details: observationRecord.usage_details || {},
|
||||
|
||||
// Input/Output
|
||||
input: "",
|
||||
output: "",
|
||||
|
||||
created_at: observationRecord.created_at,
|
||||
updated_at: observationRecord.updated_at,
|
||||
event_ts: observationRecord.event_ts,
|
||||
};
|
||||
}
|
||||
|
||||
private convertScoreToTraceMt(
|
||||
scoreRecord: ScoreRecordInsertType,
|
||||
): TraceMtRecordInsertType {
|
||||
return {
|
||||
// Identifiers
|
||||
project_id: scoreRecord.project_id,
|
||||
// Use trace_id as the id in traces_mt. Always set given the conditions around calling the function
|
||||
id: scoreRecord.trace_id || "",
|
||||
start_time: scoreRecord.timestamp,
|
||||
end_time: null, // scores don't have end_time
|
||||
name: "",
|
||||
|
||||
// Metadata properties
|
||||
metadata: {},
|
||||
user_id: '',
|
||||
session_id: '',
|
||||
environment: scoreRecord.environment,
|
||||
tags: [], // scores don't have tags
|
||||
version: null, // scores don't have version
|
||||
release: null, // scores don't have release
|
||||
|
||||
// UI properties - nullable to prevent absent values being interpreted as overwrites
|
||||
bookmarked: null,
|
||||
public: null,
|
||||
|
||||
// Aggregations - include this score ID
|
||||
observation_ids: [],
|
||||
score_ids: [scoreRecord.id],
|
||||
cost_details: {},
|
||||
usage_details: {},
|
||||
|
||||
// Input/Output
|
||||
input: "", // scores don't have input
|
||||
output: "", // scores don't have output
|
||||
|
||||
created_at: scoreRecord.created_at,
|
||||
updated_at: scoreRecord.updated_at,
|
||||
event_ts: scoreRecord.event_ts,
|
||||
};
|
||||
}
|
||||
|
||||
private async mergeObservationRecords(params: {
|
||||
projectId: string;
|
||||
observationRecords: ObservationRecordInsertType[];
|
||||
@@ -713,7 +813,7 @@ export class IngestionService {
|
||||
> {
|
||||
const providedUsageDetails = Object.fromEntries(
|
||||
Object.entries(observationRecord.provided_usage_details).filter(
|
||||
([k, v]) => v != null && v >= 0,
|
||||
([k, v]) => v != null && v >= 0, // eslint-disable-line no-unused-vars
|
||||
),
|
||||
);
|
||||
|
||||
@@ -771,7 +871,7 @@ export class IngestionService {
|
||||
const { provided_cost_details } = observationRecord;
|
||||
|
||||
const providedCostKeys = Object.entries(provided_cost_details ?? {})
|
||||
.filter(([_, value]) => value != null)
|
||||
.filter(([_, value]) => value != null) // eslint-disable-line no-unused-vars
|
||||
.map(([key]) => key);
|
||||
|
||||
// If user has provided any cost point, do not calculate any other cost points
|
||||
@@ -818,7 +918,7 @@ export class IngestionService {
|
||||
finalTotalCost = finalCostDetails.total;
|
||||
} else if (finalCostEntries.length > 0) {
|
||||
finalTotalCost = finalCostEntries.reduce(
|
||||
(acc, [_, cost]) => acc + cost,
|
||||
(acc, [_, cost]) => acc + cost, // eslint-disable-line no-unused-vars
|
||||
0,
|
||||
);
|
||||
|
||||
@@ -882,7 +982,7 @@ export class IngestionService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private async getClickhouseRecord(params: {
|
||||
private async getClickhouseRecord(params: { // eslint-disable-line no-unused-vars
|
||||
projectId: string;
|
||||
entityId: string;
|
||||
table: TableName.Traces;
|
||||
@@ -891,7 +991,7 @@ export class IngestionService {
|
||||
params: Record<string, unknown>;
|
||||
};
|
||||
}): Promise<TraceRecordInsertType | null>;
|
||||
private async getClickhouseRecord(params: {
|
||||
private async getClickhouseRecord(params: { // eslint-disable-line no-unused-vars, no-dupe-class-members
|
||||
projectId: string;
|
||||
entityId: string;
|
||||
table: TableName.Scores;
|
||||
@@ -900,7 +1000,7 @@ export class IngestionService {
|
||||
params: Record<string, unknown>;
|
||||
};
|
||||
}): Promise<ScoreRecordInsertType | null>;
|
||||
private async getClickhouseRecord(params: {
|
||||
private async getClickhouseRecord(params: { // eslint-disable-line no-unused-vars, no-dupe-class-members
|
||||
projectId: string;
|
||||
entityId: string;
|
||||
table: TableName.Observations;
|
||||
@@ -909,7 +1009,7 @@ export class IngestionService {
|
||||
params: Record<string, unknown>;
|
||||
};
|
||||
}): Promise<ObservationRecordInsertType | null>;
|
||||
private async getClickhouseRecord(params: {
|
||||
private async getClickhouseRecord(params: { // eslint-disable-line no-dupe-class-members
|
||||
projectId: string;
|
||||
entityId: string;
|
||||
table: TableName;
|
||||
@@ -1107,7 +1207,7 @@ export class IngestionService {
|
||||
...("usageDetails" in obs.body
|
||||
? (Object.fromEntries(
|
||||
Object.entries(obs.body.usageDetails ?? {}).filter(
|
||||
([_, val]) => val != null,
|
||||
([_, val]) => val != null, // eslint-disable-line no-unused-vars
|
||||
),
|
||||
) as Record<string, number>)
|
||||
: {}),
|
||||
@@ -1128,7 +1228,7 @@ export class IngestionService {
|
||||
...("costDetails" in obs.body
|
||||
? (Object.fromEntries(
|
||||
Object.entries(obs.body.costDetails ?? {}).filter(
|
||||
([_, val]) => val != null,
|
||||
([_, val]) => val != null, // eslint-disable-line no-unused-vars
|
||||
),
|
||||
) as Record<string, number>)
|
||||
: {}),
|
||||
|
||||
@@ -9,7 +9,7 @@ import { WorkerManager } from "../queues/workerManager";
|
||||
import { prisma } from "@langfuse/shared/src/db";
|
||||
import { BackgroundMigrationManager } from "../backgroundMigrations/backgroundMigrationManager";
|
||||
|
||||
export const onShutdown: NodeJS.SignalsListener = async (signal) => {
|
||||
export const onShutdown: NodeJS.SignalsListener = async (signal) => { // eslint-disable-line no-undef
|
||||
logger.info(`Received ${signal}, closing server...`);
|
||||
setSigtermReceived();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user