@llmops/sdk 1.0.0-beta.7 → 1.0.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{d1-store-D664VLg0.d.cts → d1-store-DC1FMAzk.d.mts} +1 -1
- package/dist/{d1-store-DBf99oU8.d.mts → d1-store-Pbuwjx6D.d.cts} +1 -1
- package/dist/index.cjs +3 -4
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{interface-BrJMazBg.d.mts → interface-CNLmcugg.d.mts} +3 -22
- package/dist/{interface-DMuF7YgM.d.cts → interface-SBcQ5H-b.d.cts} +3 -22
- package/dist/pg-store-CQMQHDtm.d.cts +25 -0
- package/dist/pg-store-Dr0F1Jq4.d.mts +25 -0
- package/dist/store/d1.d.cts +2 -2
- package/dist/store/d1.d.mts +2 -2
- package/dist/store/pg.cjs +613 -2
- package/dist/store/pg.d.cts +2 -1
- package/dist/store/pg.d.mts +2 -1
- package/dist/store/pg.mjs +612 -1
- package/dist/{pg-store-sIMdF_Pc.mjs → types-BerUVJ45.mjs} +2 -610
- package/dist/{pg-store-uawkO2hJ.cjs → types-uIsMdtuF.cjs} +27 -611
- package/dist/types.d.cts +3 -2
- package/dist/types.d.mts +3 -2
- package/package.json +3 -3
|
@@ -15,8 +15,6 @@ var __export = (all, symbols) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
//#endregion
|
|
18
|
-
let __llmops_core = require("@llmops/core");
|
|
19
|
-
let node_crypto = require("node:crypto");
|
|
20
18
|
|
|
21
19
|
//#region ../../node_modules/.pnpm/zod@4.3.5/node_modules/zod/v4/core/core.js
|
|
22
20
|
/** A special constant with type `never` */
|
|
@@ -12872,7 +12870,7 @@ config(en_default());
|
|
|
12872
12870
|
var zod_default = external_exports;
|
|
12873
12871
|
|
|
12874
12872
|
//#endregion
|
|
12875
|
-
//#region src/telemetry/
|
|
12873
|
+
//#region src/telemetry/types.ts
|
|
12876
12874
|
const guardrailResultSchema = zod_default.object({
|
|
12877
12875
|
checkId: zod_default.string(),
|
|
12878
12876
|
functionId: zod_default.string(),
|
|
@@ -12985,612 +12983,6 @@ const insertSpanEventSchema = zod_default.object({
|
|
|
12985
12983
|
timestamp: zod_default.date(),
|
|
12986
12984
|
attributes: zod_default.record(zod_default.string(), zod_default.unknown()).default({})
|
|
12987
12985
|
});
|
|
12988
|
-
function buildTagFilters(tags, paramOffset) {
|
|
12989
|
-
const conditions = [];
|
|
12990
|
-
const params = [];
|
|
12991
|
-
if (!tags) return {
|
|
12992
|
-
conditions,
|
|
12993
|
-
params
|
|
12994
|
-
};
|
|
12995
|
-
for (const [key, values] of Object.entries(tags)) {
|
|
12996
|
-
if (values.length === 0) continue;
|
|
12997
|
-
if (values.length === 1) {
|
|
12998
|
-
conditions.push(`"tags"->>'${key}' = $${paramOffset + params.length + 1}`);
|
|
12999
|
-
params.push(values[0]);
|
|
13000
|
-
} else {
|
|
13001
|
-
const placeholders = values.map((_, i) => `$${paramOffset + params.length + i + 1}`).join(", ");
|
|
13002
|
-
conditions.push(`"tags"->>'${key}' IN (${placeholders})`);
|
|
13003
|
-
params.push(...values);
|
|
13004
|
-
}
|
|
13005
|
-
}
|
|
13006
|
-
return {
|
|
13007
|
-
conditions,
|
|
13008
|
-
params
|
|
13009
|
-
};
|
|
13010
|
-
}
|
|
13011
|
-
function createLLMRequestsStore(pool) {
|
|
13012
|
-
return {
|
|
13013
|
-
batchInsertRequests: async (requests) => {
|
|
13014
|
-
if (requests.length === 0) return { count: 0 };
|
|
13015
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13016
|
-
const columns = [
|
|
13017
|
-
"id",
|
|
13018
|
-
"requestId",
|
|
13019
|
-
"configId",
|
|
13020
|
-
"variantId",
|
|
13021
|
-
"environmentId",
|
|
13022
|
-
"providerConfigId",
|
|
13023
|
-
"provider",
|
|
13024
|
-
"model",
|
|
13025
|
-
"promptTokens",
|
|
13026
|
-
"completionTokens",
|
|
13027
|
-
"totalTokens",
|
|
13028
|
-
"cachedTokens",
|
|
13029
|
-
"cacheCreationTokens",
|
|
13030
|
-
"cost",
|
|
13031
|
-
"cacheSavings",
|
|
13032
|
-
"inputCost",
|
|
13033
|
-
"outputCost",
|
|
13034
|
-
"endpoint",
|
|
13035
|
-
"statusCode",
|
|
13036
|
-
"latencyMs",
|
|
13037
|
-
"isStreaming",
|
|
13038
|
-
"userId",
|
|
13039
|
-
"tags",
|
|
13040
|
-
"guardrailResults",
|
|
13041
|
-
"traceId",
|
|
13042
|
-
"spanId",
|
|
13043
|
-
"parentSpanId",
|
|
13044
|
-
"sessionId",
|
|
13045
|
-
"createdAt",
|
|
13046
|
-
"updatedAt"
|
|
13047
|
-
];
|
|
13048
|
-
const colNames = columns.map((c) => `"${c}"`).join(", ");
|
|
13049
|
-
const params = [];
|
|
13050
|
-
const valueRows = [];
|
|
13051
|
-
for (const req of requests) {
|
|
13052
|
-
const result = insertLLMRequestSchema.safeParse(req);
|
|
13053
|
-
if (!result.success) {
|
|
13054
|
-
__llmops_core.logger.warn(`[batchInsertRequests] Skipping invalid request: ${result.error.message}`);
|
|
13055
|
-
continue;
|
|
13056
|
-
}
|
|
13057
|
-
const r = result.data;
|
|
13058
|
-
const offset = params.length;
|
|
13059
|
-
const placeholders = columns.map((_, i) => `$${offset + i + 1}`).join(", ");
|
|
13060
|
-
valueRows.push(`(${placeholders})`);
|
|
13061
|
-
params.push((0, node_crypto.randomUUID)(), r.requestId, r.configId ?? null, r.variantId ?? null, r.environmentId ?? null, r.providerConfigId ?? null, r.provider, r.model, r.promptTokens, r.completionTokens, r.totalTokens, r.cachedTokens, r.cacheCreationTokens, r.cost, r.cacheSavings, r.inputCost, r.outputCost, r.endpoint, r.statusCode, r.latencyMs, r.isStreaming, r.userId ?? null, JSON.stringify(r.tags), r.guardrailResults ? JSON.stringify(r.guardrailResults) : null, r.traceId ?? null, r.spanId ?? null, r.parentSpanId ?? null, r.sessionId ?? null, now, now);
|
|
13062
|
-
}
|
|
13063
|
-
if (valueRows.length === 0) return { count: 0 };
|
|
13064
|
-
await pool.query(`INSERT INTO "llm_requests" (${colNames}) VALUES ${valueRows.join(", ")}`, params);
|
|
13065
|
-
return { count: valueRows.length };
|
|
13066
|
-
},
|
|
13067
|
-
insertRequest: async (request) => {
|
|
13068
|
-
const result = insertLLMRequestSchema.safeParse(request);
|
|
13069
|
-
if (!result.success) throw new Error(`Invalid request data: ${result.error.message}`);
|
|
13070
|
-
const r = result.data;
|
|
13071
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13072
|
-
const { rows } = await pool.query(`INSERT INTO "llm_requests" (
|
|
13073
|
-
"id", "requestId", "configId", "variantId", "environmentId",
|
|
13074
|
-
"providerConfigId", "provider", "model", "promptTokens",
|
|
13075
|
-
"completionTokens", "totalTokens", "cachedTokens",
|
|
13076
|
-
"cacheCreationTokens", "cost", "cacheSavings", "inputCost",
|
|
13077
|
-
"outputCost", "endpoint", "statusCode", "latencyMs", "isStreaming",
|
|
13078
|
-
"userId", "tags", "guardrailResults", "traceId", "spanId",
|
|
13079
|
-
"parentSpanId", "sessionId", "createdAt", "updatedAt"
|
|
13080
|
-
) VALUES (
|
|
13081
|
-
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,
|
|
13082
|
-
$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30
|
|
13083
|
-
) RETURNING *`, [
|
|
13084
|
-
(0, node_crypto.randomUUID)(),
|
|
13085
|
-
r.requestId,
|
|
13086
|
-
r.configId ?? null,
|
|
13087
|
-
r.variantId ?? null,
|
|
13088
|
-
r.environmentId ?? null,
|
|
13089
|
-
r.providerConfigId ?? null,
|
|
13090
|
-
r.provider,
|
|
13091
|
-
r.model,
|
|
13092
|
-
r.promptTokens,
|
|
13093
|
-
r.completionTokens,
|
|
13094
|
-
r.totalTokens,
|
|
13095
|
-
r.cachedTokens,
|
|
13096
|
-
r.cacheCreationTokens,
|
|
13097
|
-
r.cost,
|
|
13098
|
-
r.cacheSavings,
|
|
13099
|
-
r.inputCost,
|
|
13100
|
-
r.outputCost,
|
|
13101
|
-
r.endpoint,
|
|
13102
|
-
r.statusCode,
|
|
13103
|
-
r.latencyMs,
|
|
13104
|
-
r.isStreaming,
|
|
13105
|
-
r.userId ?? null,
|
|
13106
|
-
JSON.stringify(r.tags),
|
|
13107
|
-
r.guardrailResults ? JSON.stringify(r.guardrailResults) : null,
|
|
13108
|
-
r.traceId ?? null,
|
|
13109
|
-
r.spanId ?? null,
|
|
13110
|
-
r.parentSpanId ?? null,
|
|
13111
|
-
r.sessionId ?? null,
|
|
13112
|
-
now,
|
|
13113
|
-
now
|
|
13114
|
-
]);
|
|
13115
|
-
return rows[0] ?? null;
|
|
13116
|
-
},
|
|
13117
|
-
listRequests: async (params) => {
|
|
13118
|
-
const { limit = 100, offset = 0, configId, variantId, environmentId, providerConfigId, provider, model, startDate, endDate, tags } = params ?? {};
|
|
13119
|
-
const conditions = ["TRUE"];
|
|
13120
|
-
const queryParams = [];
|
|
13121
|
-
let idx = 0;
|
|
13122
|
-
if (configId) {
|
|
13123
|
-
conditions.push(`"configId" = $${++idx}`);
|
|
13124
|
-
queryParams.push(configId);
|
|
13125
|
-
}
|
|
13126
|
-
if (variantId) {
|
|
13127
|
-
conditions.push(`"variantId" = $${++idx}`);
|
|
13128
|
-
queryParams.push(variantId);
|
|
13129
|
-
}
|
|
13130
|
-
if (environmentId) {
|
|
13131
|
-
conditions.push(`"environmentId" = $${++idx}`);
|
|
13132
|
-
queryParams.push(environmentId);
|
|
13133
|
-
}
|
|
13134
|
-
if (providerConfigId) {
|
|
13135
|
-
conditions.push(`"providerConfigId" = $${++idx}`);
|
|
13136
|
-
queryParams.push(providerConfigId);
|
|
13137
|
-
}
|
|
13138
|
-
if (provider) {
|
|
13139
|
-
conditions.push(`"provider" = $${++idx}`);
|
|
13140
|
-
queryParams.push(provider);
|
|
13141
|
-
}
|
|
13142
|
-
if (model) {
|
|
13143
|
-
conditions.push(`"model" = $${++idx}`);
|
|
13144
|
-
queryParams.push(model);
|
|
13145
|
-
}
|
|
13146
|
-
if (startDate) {
|
|
13147
|
-
conditions.push(`"createdAt" >= $${++idx}`);
|
|
13148
|
-
queryParams.push(startDate.toISOString());
|
|
13149
|
-
}
|
|
13150
|
-
if (endDate) {
|
|
13151
|
-
conditions.push(`"createdAt" <= $${++idx}`);
|
|
13152
|
-
queryParams.push(endDate.toISOString());
|
|
13153
|
-
}
|
|
13154
|
-
const tagFilter = buildTagFilters(tags, idx);
|
|
13155
|
-
conditions.push(...tagFilter.conditions);
|
|
13156
|
-
queryParams.push(...tagFilter.params);
|
|
13157
|
-
idx += tagFilter.params.length;
|
|
13158
|
-
const where = conditions.join(" AND ");
|
|
13159
|
-
const total = (await pool.query(`SELECT COUNT(*)::int AS "total" FROM "llm_requests" WHERE ${where}`, queryParams)).rows[0]?.total ?? 0;
|
|
13160
|
-
return {
|
|
13161
|
-
data: (await pool.query(`SELECT * FROM "llm_requests" WHERE ${where} ORDER BY "createdAt" DESC LIMIT $${++idx} OFFSET $${++idx}`, [
|
|
13162
|
-
...queryParams,
|
|
13163
|
-
limit,
|
|
13164
|
-
offset
|
|
13165
|
-
])).rows,
|
|
13166
|
-
total,
|
|
13167
|
-
limit,
|
|
13168
|
-
offset
|
|
13169
|
-
};
|
|
13170
|
-
},
|
|
13171
|
-
getRequestByRequestId: async (requestId) => {
|
|
13172
|
-
const { rows } = await pool.query(`SELECT * FROM "llm_requests" WHERE "requestId" = $1`, [requestId]);
|
|
13173
|
-
return rows[0] ?? void 0;
|
|
13174
|
-
},
|
|
13175
|
-
getTotalCost: async (params) => {
|
|
13176
|
-
const { startDate, endDate, configId, variantId, environmentId, tags } = params;
|
|
13177
|
-
const conditions = [`"createdAt" >= $1`, `"createdAt" <= $2`];
|
|
13178
|
-
const queryParams = [startDate.toISOString(), endDate.toISOString()];
|
|
13179
|
-
let idx = 2;
|
|
13180
|
-
if (configId) {
|
|
13181
|
-
conditions.push(`"configId" = $${++idx}`);
|
|
13182
|
-
queryParams.push(configId);
|
|
13183
|
-
}
|
|
13184
|
-
if (variantId) {
|
|
13185
|
-
conditions.push(`"variantId" = $${++idx}`);
|
|
13186
|
-
queryParams.push(variantId);
|
|
13187
|
-
}
|
|
13188
|
-
if (environmentId) {
|
|
13189
|
-
conditions.push(`"environmentId" = $${++idx}`);
|
|
13190
|
-
queryParams.push(environmentId);
|
|
13191
|
-
}
|
|
13192
|
-
const tagFilter = buildTagFilters(tags, idx);
|
|
13193
|
-
conditions.push(...tagFilter.conditions);
|
|
13194
|
-
queryParams.push(...tagFilter.params);
|
|
13195
|
-
const where = conditions.join(" AND ");
|
|
13196
|
-
const { rows } = await pool.query(`SELECT
|
|
13197
|
-
COALESCE(SUM("cost"), 0)::int AS "totalCost",
|
|
13198
|
-
COALESCE(SUM("inputCost"), 0)::int AS "totalInputCost",
|
|
13199
|
-
COALESCE(SUM("outputCost"), 0)::int AS "totalOutputCost",
|
|
13200
|
-
COALESCE(SUM("promptTokens"), 0)::int AS "totalPromptTokens",
|
|
13201
|
-
COALESCE(SUM("completionTokens"), 0)::int AS "totalCompletionTokens",
|
|
13202
|
-
COALESCE(SUM("totalTokens"), 0)::int AS "totalTokens",
|
|
13203
|
-
COALESCE(SUM("cachedTokens"), 0)::int AS "totalCachedTokens",
|
|
13204
|
-
COALESCE(SUM("cacheSavings"), 0)::int AS "totalCacheSavings",
|
|
13205
|
-
COUNT(*)::int AS "requestCount"
|
|
13206
|
-
FROM "llm_requests" WHERE ${where}`, queryParams);
|
|
13207
|
-
return rows[0];
|
|
13208
|
-
},
|
|
13209
|
-
getCostByModel: async (params) => {
|
|
13210
|
-
const { rows } = await pool.query(`SELECT "provider", "model",
|
|
13211
|
-
COALESCE(SUM("cost"), 0)::int AS "totalCost",
|
|
13212
|
-
COALESCE(SUM("inputCost"), 0)::int AS "totalInputCost",
|
|
13213
|
-
COALESCE(SUM("outputCost"), 0)::int AS "totalOutputCost",
|
|
13214
|
-
COALESCE(SUM("totalTokens"), 0)::int AS "totalTokens",
|
|
13215
|
-
COUNT(*)::int AS "requestCount",
|
|
13216
|
-
AVG("latencyMs") AS "avgLatencyMs"
|
|
13217
|
-
FROM "llm_requests"
|
|
13218
|
-
WHERE "createdAt" >= $1 AND "createdAt" <= $2
|
|
13219
|
-
GROUP BY "provider", "model"
|
|
13220
|
-
ORDER BY SUM("cost") DESC`, [params.startDate.toISOString(), params.endDate.toISOString()]);
|
|
13221
|
-
return rows;
|
|
13222
|
-
},
|
|
13223
|
-
getCostByProvider: async (params) => {
|
|
13224
|
-
const { rows } = await pool.query(`SELECT "provider",
|
|
13225
|
-
COALESCE(SUM("cost"), 0)::int AS "totalCost",
|
|
13226
|
-
COALESCE(SUM("inputCost"), 0)::int AS "totalInputCost",
|
|
13227
|
-
COALESCE(SUM("outputCost"), 0)::int AS "totalOutputCost",
|
|
13228
|
-
COALESCE(SUM("totalTokens"), 0)::int AS "totalTokens",
|
|
13229
|
-
COUNT(*)::int AS "requestCount",
|
|
13230
|
-
AVG("latencyMs") AS "avgLatencyMs"
|
|
13231
|
-
FROM "llm_requests"
|
|
13232
|
-
WHERE "createdAt" >= $1 AND "createdAt" <= $2
|
|
13233
|
-
GROUP BY "provider"
|
|
13234
|
-
ORDER BY SUM("cost") DESC`, [params.startDate.toISOString(), params.endDate.toISOString()]);
|
|
13235
|
-
return rows;
|
|
13236
|
-
},
|
|
13237
|
-
getDailyCosts: async (params) => {
|
|
13238
|
-
const { rows } = await pool.query(`SELECT DATE("createdAt")::text AS "date",
|
|
13239
|
-
COALESCE(SUM("cost"), 0)::int AS "totalCost",
|
|
13240
|
-
COALESCE(SUM("inputCost"), 0)::int AS "totalInputCost",
|
|
13241
|
-
COALESCE(SUM("outputCost"), 0)::int AS "totalOutputCost",
|
|
13242
|
-
COALESCE(SUM("totalTokens"), 0)::int AS "totalTokens",
|
|
13243
|
-
COUNT(*)::int AS "requestCount"
|
|
13244
|
-
FROM "llm_requests"
|
|
13245
|
-
WHERE "createdAt" >= $1 AND "createdAt" <= $2
|
|
13246
|
-
GROUP BY DATE("createdAt")
|
|
13247
|
-
ORDER BY DATE("createdAt") ASC`, [params.startDate.toISOString(), params.endDate.toISOString()]);
|
|
13248
|
-
return rows;
|
|
13249
|
-
},
|
|
13250
|
-
getCostSummary: async (params) => {
|
|
13251
|
-
const { startDate, endDate, groupBy, configId, variantId, environmentId, tags, tagKeys } = params;
|
|
13252
|
-
const baseParams = [
|
|
13253
|
-
startDate.toISOString(),
|
|
13254
|
-
endDate.toISOString(),
|
|
13255
|
-
configId ?? null,
|
|
13256
|
-
variantId ?? null,
|
|
13257
|
-
environmentId ?? null
|
|
13258
|
-
];
|
|
13259
|
-
if (groupBy === "tags") {
|
|
13260
|
-
const conditions = [
|
|
13261
|
-
`"createdAt" >= $1`,
|
|
13262
|
-
`"createdAt" <= $2`,
|
|
13263
|
-
`($3::uuid IS NULL OR "configId" = $3)`,
|
|
13264
|
-
`($4::uuid IS NULL OR "variantId" = $4)`,
|
|
13265
|
-
`($5::uuid IS NULL OR "environmentId" = $5)`
|
|
13266
|
-
];
|
|
13267
|
-
const queryParams = [...baseParams];
|
|
13268
|
-
let idx = 5;
|
|
13269
|
-
const tagFilter = buildTagFilters(tags, idx);
|
|
13270
|
-
conditions.push(...tagFilter.conditions);
|
|
13271
|
-
queryParams.push(...tagFilter.params);
|
|
13272
|
-
idx += tagFilter.params.length;
|
|
13273
|
-
if (tagKeys && tagKeys.length > 0) {
|
|
13274
|
-
const keyPlaceholders = tagKeys.map((_, i) => `$${idx + i + 1}`).join(", ");
|
|
13275
|
-
conditions.push(`t.key IN (${keyPlaceholders})`);
|
|
13276
|
-
queryParams.push(...tagKeys);
|
|
13277
|
-
}
|
|
13278
|
-
const where = conditions.join(" AND ");
|
|
13279
|
-
const { rows: rows$1 } = await pool.query(`SELECT t.key || ':' || t.value AS "groupKey",
|
|
13280
|
-
COALESCE(SUM("cost"), 0)::int AS "totalCost",
|
|
13281
|
-
COUNT(*)::int AS "requestCount"
|
|
13282
|
-
FROM "llm_requests", jsonb_each_text("tags") t
|
|
13283
|
-
WHERE ${where}
|
|
13284
|
-
GROUP BY t.key, t.value
|
|
13285
|
-
ORDER BY SUM("cost") DESC`, queryParams);
|
|
13286
|
-
return rows$1;
|
|
13287
|
-
}
|
|
13288
|
-
const sqlMap = {
|
|
13289
|
-
day: `SELECT DATE("createdAt")::text AS "groupKey", COALESCE(SUM("cost"),0)::int AS "totalCost", COUNT(*)::int AS "requestCount", COALESCE(SUM("totalTokens"),0)::int AS "totalTokens" FROM "llm_requests" WHERE "createdAt">=$1 AND "createdAt"<=$2 AND ($3::uuid IS NULL OR "configId"=$3) AND ($4::uuid IS NULL OR "variantId"=$4) AND ($5::uuid IS NULL OR "environmentId"=$5) GROUP BY DATE("createdAt") ORDER BY DATE("createdAt") ASC`,
|
|
13290
|
-
hour: `SELECT DATE_TRUNC('hour',"createdAt")::text AS "groupKey", COALESCE(SUM("cost"),0)::int AS "totalCost", COUNT(*)::int AS "requestCount", COALESCE(SUM("totalTokens"),0)::int AS "totalTokens" FROM "llm_requests" WHERE "createdAt">=$1 AND "createdAt"<=$2 AND ($3::uuid IS NULL OR "configId"=$3) AND ($4::uuid IS NULL OR "variantId"=$4) AND ($5::uuid IS NULL OR "environmentId"=$5) GROUP BY DATE_TRUNC('hour',"createdAt") ORDER BY DATE_TRUNC('hour',"createdAt") ASC`,
|
|
13291
|
-
model: `SELECT "provider"||'/'||"model" AS "groupKey", COALESCE(SUM("cost"),0)::int AS "totalCost", COUNT(*)::int AS "requestCount" FROM "llm_requests" WHERE "createdAt">=$1 AND "createdAt"<=$2 AND ($3::uuid IS NULL OR "configId"=$3) AND ($4::uuid IS NULL OR "variantId"=$4) AND ($5::uuid IS NULL OR "environmentId"=$5) GROUP BY "provider","model" ORDER BY SUM("cost") DESC`,
|
|
13292
|
-
provider: `SELECT "provider" AS "groupKey", COALESCE(SUM("cost"),0)::int AS "totalCost", COUNT(*)::int AS "requestCount" FROM "llm_requests" WHERE "createdAt">=$1 AND "createdAt"<=$2 AND ($3::uuid IS NULL OR "configId"=$3) AND ($4::uuid IS NULL OR "variantId"=$4) AND ($5::uuid IS NULL OR "environmentId"=$5) GROUP BY "provider" ORDER BY SUM("cost") DESC`,
|
|
13293
|
-
endpoint: `SELECT COALESCE("endpoint",'unknown') AS "groupKey", COALESCE(SUM("cost"),0)::int AS "totalCost", COUNT(*)::int AS "requestCount" FROM "llm_requests" WHERE "createdAt">=$1 AND "createdAt"<=$2 AND ($3::uuid IS NULL OR "configId"=$3) AND ($4::uuid IS NULL OR "variantId"=$4) AND ($5::uuid IS NULL OR "environmentId"=$5) GROUP BY "endpoint" ORDER BY SUM("cost") DESC`
|
|
13294
|
-
};
|
|
13295
|
-
const totalSql = `SELECT 'total' AS "groupKey", COALESCE(SUM("cost"),0)::int AS "totalCost", COUNT(*)::int AS "requestCount" FROM "llm_requests" WHERE "createdAt">=$1 AND "createdAt"<=$2 AND ($3::uuid IS NULL OR "configId"=$3) AND ($4::uuid IS NULL OR "variantId"=$4) AND ($5::uuid IS NULL OR "environmentId"=$5)`;
|
|
13296
|
-
const sql = groupBy ? sqlMap[groupBy] ?? totalSql : totalSql;
|
|
13297
|
-
const { rows } = await pool.query(sql, baseParams);
|
|
13298
|
-
return rows;
|
|
13299
|
-
},
|
|
13300
|
-
getRequestStats: async (params) => {
|
|
13301
|
-
const { startDate, endDate, configId, variantId, environmentId, tags } = params;
|
|
13302
|
-
const conditions = [`"createdAt" >= $1`, `"createdAt" <= $2`];
|
|
13303
|
-
const queryParams = [startDate.toISOString(), endDate.toISOString()];
|
|
13304
|
-
let idx = 2;
|
|
13305
|
-
if (configId) {
|
|
13306
|
-
conditions.push(`"configId" = $${++idx}`);
|
|
13307
|
-
queryParams.push(configId);
|
|
13308
|
-
}
|
|
13309
|
-
if (variantId) {
|
|
13310
|
-
conditions.push(`"variantId" = $${++idx}`);
|
|
13311
|
-
queryParams.push(variantId);
|
|
13312
|
-
}
|
|
13313
|
-
if (environmentId) {
|
|
13314
|
-
conditions.push(`"environmentId" = $${++idx}`);
|
|
13315
|
-
queryParams.push(environmentId);
|
|
13316
|
-
}
|
|
13317
|
-
const tagFilter = buildTagFilters(tags, idx);
|
|
13318
|
-
conditions.push(...tagFilter.conditions);
|
|
13319
|
-
queryParams.push(...tagFilter.params);
|
|
13320
|
-
const where = conditions.join(" AND ");
|
|
13321
|
-
const { rows } = await pool.query(`SELECT
|
|
13322
|
-
COUNT(*)::int AS "totalRequests",
|
|
13323
|
-
COUNT(CASE WHEN "statusCode">=200 AND "statusCode"<300 THEN 1 END)::int AS "successfulRequests",
|
|
13324
|
-
COUNT(CASE WHEN "statusCode">=400 THEN 1 END)::int AS "failedRequests",
|
|
13325
|
-
COUNT(CASE WHEN "isStreaming"=true THEN 1 END)::int AS "streamingRequests",
|
|
13326
|
-
AVG("latencyMs") AS "avgLatencyMs",
|
|
13327
|
-
MAX("latencyMs")::int AS "maxLatencyMs",
|
|
13328
|
-
MIN("latencyMs")::int AS "minLatencyMs"
|
|
13329
|
-
FROM "llm_requests" WHERE ${where}`, queryParams);
|
|
13330
|
-
return rows[0];
|
|
13331
|
-
},
|
|
13332
|
-
getDistinctTags: async () => {
|
|
13333
|
-
const { rows } = await pool.query(`SELECT DISTINCT key, value
|
|
13334
|
-
FROM "llm_requests", jsonb_each_text("tags") AS t(key, value)
|
|
13335
|
-
WHERE "tags" != '{}'::jsonb
|
|
13336
|
-
ORDER BY key, value`);
|
|
13337
|
-
return rows;
|
|
13338
|
-
}
|
|
13339
|
-
};
|
|
13340
|
-
}
|
|
13341
|
-
function createTracesStore(pool) {
|
|
13342
|
-
return {
|
|
13343
|
-
upsertTrace: async (data) => {
|
|
13344
|
-
const result = upsertTraceSchema.safeParse(data);
|
|
13345
|
-
if (!result.success) throw new Error(`Invalid trace data: ${result.error.message}`);
|
|
13346
|
-
const trace = result.data;
|
|
13347
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13348
|
-
await pool.query(`INSERT INTO "traces" (
|
|
13349
|
-
"id","traceId","name","sessionId","userId","status",
|
|
13350
|
-
"startTime","endTime","durationMs","spanCount",
|
|
13351
|
-
"totalInputTokens","totalOutputTokens","totalTokens","totalCost",
|
|
13352
|
-
"tags","metadata","createdAt","updatedAt"
|
|
13353
|
-
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15::jsonb,$16::jsonb,$17,$17)
|
|
13354
|
-
ON CONFLICT ("traceId") DO UPDATE SET
|
|
13355
|
-
"name" = COALESCE(EXCLUDED."name", "traces"."name"),
|
|
13356
|
-
"sessionId" = COALESCE(EXCLUDED."sessionId", "traces"."sessionId"),
|
|
13357
|
-
"userId" = COALESCE(EXCLUDED."userId", "traces"."userId"),
|
|
13358
|
-
"status" = CASE
|
|
13359
|
-
WHEN EXCLUDED."status" = 'error' THEN 'error'
|
|
13360
|
-
WHEN EXCLUDED."status" = 'ok' AND "traces"."status" != 'error' THEN 'ok'
|
|
13361
|
-
ELSE "traces"."status"
|
|
13362
|
-
END,
|
|
13363
|
-
"startTime" = LEAST("traces"."startTime", EXCLUDED."startTime"),
|
|
13364
|
-
"endTime" = GREATEST(
|
|
13365
|
-
COALESCE("traces"."endTime", EXCLUDED."endTime"),
|
|
13366
|
-
COALESCE(EXCLUDED."endTime", "traces"."endTime")
|
|
13367
|
-
),
|
|
13368
|
-
"durationMs" = EXTRACT(EPOCH FROM (
|
|
13369
|
-
GREATEST(COALESCE("traces"."endTime",EXCLUDED."endTime"),COALESCE(EXCLUDED."endTime","traces"."endTime")) -
|
|
13370
|
-
LEAST("traces"."startTime", EXCLUDED."startTime")
|
|
13371
|
-
))::integer * 1000,
|
|
13372
|
-
"spanCount" = "traces"."spanCount" + EXCLUDED."spanCount",
|
|
13373
|
-
"totalInputTokens" = "traces"."totalInputTokens" + EXCLUDED."totalInputTokens",
|
|
13374
|
-
"totalOutputTokens" = "traces"."totalOutputTokens" + EXCLUDED."totalOutputTokens",
|
|
13375
|
-
"totalTokens" = "traces"."totalTokens" + EXCLUDED."totalTokens",
|
|
13376
|
-
"totalCost" = "traces"."totalCost" + EXCLUDED."totalCost",
|
|
13377
|
-
"tags" = "traces"."tags" || EXCLUDED."tags",
|
|
13378
|
-
"metadata" = "traces"."metadata" || EXCLUDED."metadata",
|
|
13379
|
-
"updatedAt" = $17`, [
|
|
13380
|
-
(0, node_crypto.randomUUID)(),
|
|
13381
|
-
trace.traceId,
|
|
13382
|
-
trace.name ?? null,
|
|
13383
|
-
trace.sessionId ?? null,
|
|
13384
|
-
trace.userId ?? null,
|
|
13385
|
-
trace.status,
|
|
13386
|
-
trace.startTime.toISOString(),
|
|
13387
|
-
trace.endTime?.toISOString() ?? null,
|
|
13388
|
-
trace.durationMs ?? null,
|
|
13389
|
-
trace.spanCount,
|
|
13390
|
-
trace.totalInputTokens,
|
|
13391
|
-
trace.totalOutputTokens,
|
|
13392
|
-
trace.totalTokens,
|
|
13393
|
-
trace.totalCost,
|
|
13394
|
-
JSON.stringify(trace.tags),
|
|
13395
|
-
JSON.stringify(trace.metadata),
|
|
13396
|
-
now
|
|
13397
|
-
]);
|
|
13398
|
-
},
|
|
13399
|
-
batchInsertSpans: async (spans) => {
|
|
13400
|
-
if (spans.length === 0) return { count: 0 };
|
|
13401
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13402
|
-
const columns = [
|
|
13403
|
-
"id",
|
|
13404
|
-
"traceId",
|
|
13405
|
-
"spanId",
|
|
13406
|
-
"parentSpanId",
|
|
13407
|
-
"name",
|
|
13408
|
-
"kind",
|
|
13409
|
-
"status",
|
|
13410
|
-
"statusMessage",
|
|
13411
|
-
"startTime",
|
|
13412
|
-
"endTime",
|
|
13413
|
-
"durationMs",
|
|
13414
|
-
"provider",
|
|
13415
|
-
"model",
|
|
13416
|
-
"promptTokens",
|
|
13417
|
-
"completionTokens",
|
|
13418
|
-
"totalTokens",
|
|
13419
|
-
"cost",
|
|
13420
|
-
"configId",
|
|
13421
|
-
"variantId",
|
|
13422
|
-
"environmentId",
|
|
13423
|
-
"providerConfigId",
|
|
13424
|
-
"requestId",
|
|
13425
|
-
"source",
|
|
13426
|
-
"input",
|
|
13427
|
-
"output",
|
|
13428
|
-
"attributes",
|
|
13429
|
-
"createdAt",
|
|
13430
|
-
"updatedAt"
|
|
13431
|
-
];
|
|
13432
|
-
const colNames = columns.map((c) => `"${c}"`).join(", ");
|
|
13433
|
-
const params = [];
|
|
13434
|
-
const valueRows = [];
|
|
13435
|
-
for (const span of spans) {
|
|
13436
|
-
const result = insertSpanSchema.safeParse(span);
|
|
13437
|
-
if (!result.success) {
|
|
13438
|
-
__llmops_core.logger.warn(`[batchInsertSpans] Skipping invalid span ${span.spanId}: ${result.error.message}`);
|
|
13439
|
-
continue;
|
|
13440
|
-
}
|
|
13441
|
-
const s = result.data;
|
|
13442
|
-
const offset = params.length;
|
|
13443
|
-
const placeholders = columns.map((_, i) => `$${offset + i + 1}`).join(", ");
|
|
13444
|
-
valueRows.push(`(${placeholders})`);
|
|
13445
|
-
params.push((0, node_crypto.randomUUID)(), s.traceId, s.spanId, s.parentSpanId ?? null, s.name, s.kind, s.status, s.statusMessage ?? null, s.startTime.toISOString(), s.endTime?.toISOString() ?? null, s.durationMs ?? null, s.provider ?? null, s.model ?? null, s.promptTokens, s.completionTokens, s.totalTokens, s.cost, s.configId ?? null, s.variantId ?? null, s.environmentId ?? null, s.providerConfigId ?? null, s.requestId ?? null, s.source, s.input != null ? JSON.stringify(s.input) : null, s.output != null ? JSON.stringify(s.output) : null, JSON.stringify(s.attributes), now, now);
|
|
13446
|
-
}
|
|
13447
|
-
if (valueRows.length === 0) return { count: 0 };
|
|
13448
|
-
await pool.query(`INSERT INTO "spans" (${colNames}) VALUES ${valueRows.join(", ")} ON CONFLICT ("spanId") DO NOTHING`, params);
|
|
13449
|
-
return { count: valueRows.length };
|
|
13450
|
-
},
|
|
13451
|
-
batchInsertSpanEvents: async (events) => {
|
|
13452
|
-
if (events.length === 0) return { count: 0 };
|
|
13453
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
13454
|
-
const columns = [
|
|
13455
|
-
"id",
|
|
13456
|
-
"traceId",
|
|
13457
|
-
"spanId",
|
|
13458
|
-
"name",
|
|
13459
|
-
"timestamp",
|
|
13460
|
-
"attributes",
|
|
13461
|
-
"createdAt"
|
|
13462
|
-
];
|
|
13463
|
-
const colNames = columns.map((c) => `"${c}"`).join(", ");
|
|
13464
|
-
const params = [];
|
|
13465
|
-
const valueRows = [];
|
|
13466
|
-
for (const event of events) {
|
|
13467
|
-
const result = insertSpanEventSchema.safeParse(event);
|
|
13468
|
-
if (!result.success) {
|
|
13469
|
-
__llmops_core.logger.warn(`[batchInsertSpanEvents] Skipping invalid event: ${result.error.message}`);
|
|
13470
|
-
continue;
|
|
13471
|
-
}
|
|
13472
|
-
const e = result.data;
|
|
13473
|
-
const offset = params.length;
|
|
13474
|
-
const placeholders = columns.map((_, i) => `$${offset + i + 1}`).join(", ");
|
|
13475
|
-
valueRows.push(`(${placeholders})`);
|
|
13476
|
-
params.push((0, node_crypto.randomUUID)(), e.traceId, e.spanId, e.name, e.timestamp.toISOString(), JSON.stringify(e.attributes), now);
|
|
13477
|
-
}
|
|
13478
|
-
if (valueRows.length === 0) return { count: 0 };
|
|
13479
|
-
await pool.query(`INSERT INTO "span_events" (${colNames}) VALUES ${valueRows.join(", ")}`, params);
|
|
13480
|
-
return { count: valueRows.length };
|
|
13481
|
-
},
|
|
13482
|
-
listTraces: async (params) => {
|
|
13483
|
-
const { limit = 50, offset = 0, sessionId, userId, status, name, startDate, endDate, tags } = params ?? {};
|
|
13484
|
-
const conditions = ["TRUE"];
|
|
13485
|
-
const queryParams = [];
|
|
13486
|
-
let idx = 0;
|
|
13487
|
-
if (sessionId) {
|
|
13488
|
-
conditions.push(`"sessionId" = $${++idx}`);
|
|
13489
|
-
queryParams.push(sessionId);
|
|
13490
|
-
}
|
|
13491
|
-
if (userId) {
|
|
13492
|
-
conditions.push(`"userId" = $${++idx}`);
|
|
13493
|
-
queryParams.push(userId);
|
|
13494
|
-
}
|
|
13495
|
-
if (status) {
|
|
13496
|
-
conditions.push(`"status" = $${++idx}`);
|
|
13497
|
-
queryParams.push(status);
|
|
13498
|
-
}
|
|
13499
|
-
if (name) {
|
|
13500
|
-
conditions.push(`"name" ILIKE $${++idx}`);
|
|
13501
|
-
queryParams.push(`%${name}%`);
|
|
13502
|
-
}
|
|
13503
|
-
if (startDate) {
|
|
13504
|
-
conditions.push(`"startTime" >= $${++idx}`);
|
|
13505
|
-
queryParams.push(startDate.toISOString());
|
|
13506
|
-
}
|
|
13507
|
-
if (endDate) {
|
|
13508
|
-
conditions.push(`"startTime" <= $${++idx}`);
|
|
13509
|
-
queryParams.push(endDate.toISOString());
|
|
13510
|
-
}
|
|
13511
|
-
const tagFilter = buildTagFilters(tags, idx);
|
|
13512
|
-
conditions.push(...tagFilter.conditions);
|
|
13513
|
-
queryParams.push(...tagFilter.params);
|
|
13514
|
-
idx += tagFilter.params.length;
|
|
13515
|
-
const where = conditions.join(" AND ");
|
|
13516
|
-
const total = (await pool.query(`SELECT COUNT(*)::int AS "total" FROM "traces" WHERE ${where}`, queryParams)).rows[0]?.total ?? 0;
|
|
13517
|
-
return {
|
|
13518
|
-
data: (await pool.query(`SELECT * FROM "traces" WHERE ${where} ORDER BY "startTime" DESC LIMIT $${++idx} OFFSET $${++idx}`, [
|
|
13519
|
-
...queryParams,
|
|
13520
|
-
limit,
|
|
13521
|
-
offset
|
|
13522
|
-
])).rows,
|
|
13523
|
-
total,
|
|
13524
|
-
limit,
|
|
13525
|
-
offset
|
|
13526
|
-
};
|
|
13527
|
-
},
|
|
13528
|
-
getTraceWithSpans: async (traceId) => {
|
|
13529
|
-
const trace = (await pool.query(`SELECT * FROM "traces" WHERE "traceId" = $1`, [traceId])).rows[0];
|
|
13530
|
-
if (!trace) return void 0;
|
|
13531
|
-
const [spanResult, eventResult] = await Promise.all([pool.query(`SELECT * FROM "spans" WHERE "traceId" = $1 ORDER BY "startTime" ASC`, [traceId]), pool.query(`SELECT * FROM "span_events" WHERE "traceId" = $1 ORDER BY "timestamp" ASC`, [traceId])]);
|
|
13532
|
-
return {
|
|
13533
|
-
trace,
|
|
13534
|
-
spans: spanResult.rows,
|
|
13535
|
-
events: eventResult.rows
|
|
13536
|
-
};
|
|
13537
|
-
},
|
|
13538
|
-
getTraceStats: async (params) => {
|
|
13539
|
-
const { rows } = await pool.query(`SELECT
|
|
13540
|
-
COUNT(*)::int AS "totalTraces",
|
|
13541
|
-
COALESCE(AVG("durationMs"), 0) AS "avgDurationMs",
|
|
13542
|
-
COUNT(CASE WHEN "status" = 'error' THEN 1 END)::int AS "errorCount",
|
|
13543
|
-
COALESCE(SUM("totalCost"), 0)::int AS "totalCost",
|
|
13544
|
-
COALESCE(SUM("totalTokens"), 0)::int AS "totalTokens",
|
|
13545
|
-
COALESCE(SUM("spanCount"), 0)::int AS "totalSpans"
|
|
13546
|
-
FROM "traces"
|
|
13547
|
-
WHERE "startTime" >= $1 AND "startTime" <= $2
|
|
13548
|
-
AND ($3::varchar IS NULL OR "sessionId" = $3)
|
|
13549
|
-
AND ($4::varchar IS NULL OR "userId" = $4)`, [
|
|
13550
|
-
params.startDate.toISOString(),
|
|
13551
|
-
params.endDate.toISOString(),
|
|
13552
|
-
params.sessionId ?? null,
|
|
13553
|
-
params.userId ?? null
|
|
13554
|
-
]);
|
|
13555
|
-
return rows[0];
|
|
13556
|
-
}
|
|
13557
|
-
};
|
|
13558
|
-
}
|
|
13559
|
-
const pgStoreOptionsSchema = zod_default.object({ schema: zod_default.string().default("llmops") });
|
|
13560
|
-
/**
|
|
13561
|
-
* Create a PostgreSQL-backed telemetry store.
|
|
13562
|
-
*
|
|
13563
|
-
* Usage:
|
|
13564
|
-
* ```ts
|
|
13565
|
-
* import { llmops } from '@llmops/sdk'
|
|
13566
|
-
* import { pgStore } from '@llmops/sdk/store/pg'
|
|
13567
|
-
*
|
|
13568
|
-
* const ops = llmops({
|
|
13569
|
-
* telemetry: pgStore(process.env.DATABASE_URL),
|
|
13570
|
-
* })
|
|
13571
|
-
* ```
|
|
13572
|
-
*/
|
|
13573
|
-
function createPgStore(connectionString, options) {
|
|
13574
|
-
const parsed = zod_default.string().url().safeParse(connectionString);
|
|
13575
|
-
if (!parsed.success) throw new Error(`pgStore: invalid connection string — ${parsed.error.issues[0]?.message ?? "expected a postgres:// URL"}`);
|
|
13576
|
-
const { schema } = pgStoreOptionsSchema.parse(options ?? {});
|
|
13577
|
-
let pool;
|
|
13578
|
-
try {
|
|
13579
|
-
pool = new (require("pg")).Pool({ connectionString });
|
|
13580
|
-
} catch {
|
|
13581
|
-
throw new Error("pgStore requires the \"pg\" package. Install it with: pnpm add pg");
|
|
13582
|
-
}
|
|
13583
|
-
pool.on("connect", (client) => {
|
|
13584
|
-
client.query(`SET search_path TO "${schema}"`);
|
|
13585
|
-
});
|
|
13586
|
-
__llmops_core.logger.debug(`pgStore: initialized with schema "${schema}"`);
|
|
13587
|
-
return {
|
|
13588
|
-
...createLLMRequestsStore(pool),
|
|
13589
|
-
...createTracesStore(pool),
|
|
13590
|
-
_pool: pool,
|
|
13591
|
-
_schema: schema
|
|
13592
|
-
};
|
|
13593
|
-
}
|
|
13594
12986
|
|
|
13595
12987
|
//#endregion
|
|
13596
12988
|
Object.defineProperty(exports, 'COST_SUMMARY_GROUP_BY', {
|
|
@@ -13599,9 +12991,33 @@ Object.defineProperty(exports, 'COST_SUMMARY_GROUP_BY', {
|
|
|
13599
12991
|
return COST_SUMMARY_GROUP_BY;
|
|
13600
12992
|
}
|
|
13601
12993
|
});
|
|
13602
|
-
Object.defineProperty(exports, '
|
|
12994
|
+
Object.defineProperty(exports, 'insertLLMRequestSchema', {
|
|
12995
|
+
enumerable: true,
|
|
12996
|
+
get: function () {
|
|
12997
|
+
return insertLLMRequestSchema;
|
|
12998
|
+
}
|
|
12999
|
+
});
|
|
13000
|
+
Object.defineProperty(exports, 'insertSpanEventSchema', {
|
|
13001
|
+
enumerable: true,
|
|
13002
|
+
get: function () {
|
|
13003
|
+
return insertSpanEventSchema;
|
|
13004
|
+
}
|
|
13005
|
+
});
|
|
13006
|
+
Object.defineProperty(exports, 'insertSpanSchema', {
|
|
13007
|
+
enumerable: true,
|
|
13008
|
+
get: function () {
|
|
13009
|
+
return insertSpanSchema;
|
|
13010
|
+
}
|
|
13011
|
+
});
|
|
13012
|
+
Object.defineProperty(exports, 'upsertTraceSchema', {
|
|
13013
|
+
enumerable: true,
|
|
13014
|
+
get: function () {
|
|
13015
|
+
return upsertTraceSchema;
|
|
13016
|
+
}
|
|
13017
|
+
});
|
|
13018
|
+
Object.defineProperty(exports, 'zod_default', {
|
|
13603
13019
|
enumerable: true,
|
|
13604
13020
|
get: function () {
|
|
13605
|
-
return
|
|
13021
|
+
return zod_default;
|
|
13606
13022
|
}
|
|
13607
13023
|
});
|
package/dist/types.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as D1Store } from "./d1-store-
|
|
1
|
+
import { t as TelemetryStore } from "./interface-SBcQ5H-b.cjs";
|
|
2
|
+
import { t as D1Store } from "./d1-store-Pbuwjx6D.cjs";
|
|
3
|
+
import { t as PgStore } from "./pg-store-CQMQHDtm.cjs";
|
|
3
4
|
export { type D1Store, type PgStore, type TelemetryStore };
|
package/dist/types.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as D1Store } from "./d1-store-
|
|
1
|
+
import { t as TelemetryStore } from "./interface-CNLmcugg.mjs";
|
|
2
|
+
import { t as D1Store } from "./d1-store-DC1FMAzk.mjs";
|
|
3
|
+
import { t as PgStore } from "./pg-store-Dr0F1Jq4.mjs";
|
|
3
4
|
export { type D1Store, type PgStore, type TelemetryStore };
|