@llmops/app 1.0.0-beta.5 → 1.0.0-beta.6
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/index.cjs +29 -28
- package/dist/index.d.cts +2 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +29 -28
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -47,6 +47,7 @@ let node_url = require("node:url");
|
|
|
47
47
|
let node_path = require("node:path");
|
|
48
48
|
let node_fs = require("node:fs");
|
|
49
49
|
let __hono_zod_validator = require("@hono/zod-validator");
|
|
50
|
+
let __llmops_sdk = require("@llmops/sdk");
|
|
50
51
|
let hono_pretty_json = require("hono/pretty-json");
|
|
51
52
|
let hono_http_exception = require("hono/http-exception");
|
|
52
53
|
let hono_cors = require("hono/cors");
|
|
@@ -13779,7 +13780,7 @@ const app$7 = new hono.Hono().get("/requests", zv("query", zod_default.object({
|
|
|
13779
13780
|
return c.json(internalServerError("Failed to fetch daily costs", 500), 500);
|
|
13780
13781
|
}
|
|
13781
13782
|
}).get("/costs/summary", zv("query", dateRangeWithFiltersSchema.extend({
|
|
13782
|
-
groupBy: zod_default.enum(
|
|
13783
|
+
groupBy: zod_default.enum(__llmops_sdk.COST_SUMMARY_GROUP_BY).optional(),
|
|
13783
13784
|
tagKeys: zod_default.string().optional()
|
|
13784
13785
|
})), async (c) => {
|
|
13785
13786
|
const db = c.get("telemetryStore");
|
|
@@ -14547,14 +14548,14 @@ function createTraceBatchWriter(deps, config$1 = {}) {
|
|
|
14547
14548
|
let flushTimer = null;
|
|
14548
14549
|
let running = false;
|
|
14549
14550
|
let flushing = false;
|
|
14550
|
-
const log = debug ? (msg) =>
|
|
14551
|
+
const log = debug ? (msg) => __llmops_sdk.logger.debug(msg) : () => {};
|
|
14551
14552
|
async function flush() {
|
|
14552
14553
|
if (flushing || queue.length === 0) return;
|
|
14553
14554
|
flushing = true;
|
|
14554
14555
|
const batch = queue;
|
|
14555
14556
|
queue = [];
|
|
14556
14557
|
try {
|
|
14557
|
-
|
|
14558
|
+
__llmops_sdk.logger.debug(`[TraceBatchWriter] Flushing ${batch.length} items`);
|
|
14558
14559
|
log(`[TraceBatchWriter] Flushing ${batch.length} items`);
|
|
14559
14560
|
const traceMap = /* @__PURE__ */ new Map();
|
|
14560
14561
|
for (const item of batch) {
|
|
@@ -14588,11 +14589,11 @@ function createTraceBatchWriter(deps, config$1 = {}) {
|
|
|
14588
14589
|
const allEvents = batch.flatMap((item) => item.events ?? []);
|
|
14589
14590
|
if (allEvents.length > 0) await deps.batchInsertSpanEvents(allEvents);
|
|
14590
14591
|
for (const trace of traceMap.values()) await deps.upsertTrace(trace);
|
|
14591
|
-
|
|
14592
|
+
__llmops_sdk.logger.debug(`[TraceBatchWriter] Flushed ${traceMap.size} traces, ${allSpans.length} spans, ${allEvents.length} events`);
|
|
14592
14593
|
log(`[TraceBatchWriter] Flushed ${traceMap.size} traces, ${allSpans.length} spans, ${allEvents.length} events`);
|
|
14593
14594
|
} catch (error$47) {
|
|
14594
14595
|
const errorMsg = error$47 instanceof Error ? error$47.message : String(error$47);
|
|
14595
|
-
|
|
14596
|
+
__llmops_sdk.logger.error(`[TraceBatchWriter] Flush failed, re-queuing items: ${errorMsg}`);
|
|
14596
14597
|
queue = [...batch, ...queue];
|
|
14597
14598
|
} finally {
|
|
14598
14599
|
flushing = false;
|
|
@@ -14604,7 +14605,7 @@ function createTraceBatchWriter(deps, config$1 = {}) {
|
|
|
14604
14605
|
flushTimer = setInterval(() => {
|
|
14605
14606
|
flush().catch((err) => {
|
|
14606
14607
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
14607
|
-
|
|
14608
|
+
__llmops_sdk.logger.error(`[TraceBatchWriter] Periodic flush error: ${errorMsg}`);
|
|
14608
14609
|
});
|
|
14609
14610
|
}, flushIntervalMs);
|
|
14610
14611
|
log(`[TraceBatchWriter] Started with ${flushIntervalMs}ms flush interval`);
|
|
@@ -14627,7 +14628,7 @@ function createTraceBatchWriter(deps, config$1 = {}) {
|
|
|
14627
14628
|
log(`[TraceBatchWriter] Max batch size reached, forcing flush`);
|
|
14628
14629
|
flush().catch((err) => {
|
|
14629
14630
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
14630
|
-
|
|
14631
|
+
__llmops_sdk.logger.error(`[TraceBatchWriter] Forced flush error: ${errorMsg}`);
|
|
14631
14632
|
});
|
|
14632
14633
|
}
|
|
14633
14634
|
}
|
|
@@ -15453,13 +15454,13 @@ function extractTypedFields(attrs) {
|
|
|
15453
15454
|
output
|
|
15454
15455
|
};
|
|
15455
15456
|
}
|
|
15456
|
-
const pricingProvider$1 = (0,
|
|
15457
|
+
const pricingProvider$1 = (0, __llmops_sdk.getDefaultPricingProvider)();
|
|
15457
15458
|
/**
|
|
15458
15459
|
* OTLP ingestion endpoint
|
|
15459
15460
|
* Accepts OTLP JSON and Protobuf (ExportTraceServiceRequest) formats
|
|
15460
15461
|
*/
|
|
15461
15462
|
const app$3 = new hono.Hono().post("/v1/traces", async (c) => {
|
|
15462
|
-
|
|
15463
|
+
__llmops_sdk.logger.debug(`[OTLP] POST /v1/traces hit — url: ${c.req.url}`);
|
|
15463
15464
|
const authHeader = c.req.header("authorization");
|
|
15464
15465
|
if (!authHeader) return c.json({ error: "Authorization header required" }, 401);
|
|
15465
15466
|
const match = authHeader.match(/^Bearer\s+(.+)$/i);
|
|
@@ -15468,19 +15469,19 @@ const app$3 = new hono.Hono().post("/v1/traces", async (c) => {
|
|
|
15468
15469
|
c.set("envSec", envSec);
|
|
15469
15470
|
let body;
|
|
15470
15471
|
const contentType = c.req.header("content-type") ?? "";
|
|
15471
|
-
|
|
15472
|
+
__llmops_sdk.logger.debug(`[OTLP] Received request — Content-Type: ${contentType}`);
|
|
15472
15473
|
try {
|
|
15473
15474
|
if (contentType.includes("application/x-protobuf") || contentType.includes("application/protobuf")) {
|
|
15474
15475
|
const buffer = await c.req.arrayBuffer();
|
|
15475
|
-
|
|
15476
|
+
__llmops_sdk.logger.debug(`[OTLP] Protobuf body size: ${buffer.byteLength} bytes`);
|
|
15476
15477
|
body = decodeOtlpProtobuf(new Uint8Array(buffer));
|
|
15477
15478
|
} else body = await c.req.json();
|
|
15478
15479
|
} catch (e) {
|
|
15479
15480
|
const msg = e instanceof Error ? e.message : String(e);
|
|
15480
|
-
|
|
15481
|
+
__llmops_sdk.logger.error(`[OTLP] Failed to parse request body: ${msg}`);
|
|
15481
15482
|
return c.json({ error: "Invalid request body" }, 400);
|
|
15482
15483
|
}
|
|
15483
|
-
|
|
15484
|
+
__llmops_sdk.logger.debug(`[OTLP] Parsed body — resourceSpans count: ${body.resourceSpans?.length ?? 0}`);
|
|
15484
15485
|
if (!body.resourceSpans || !Array.isArray(body.resourceSpans)) return c.json({ error: "Missing resourceSpans" }, 400);
|
|
15485
15486
|
const db = c.get("telemetryStore");
|
|
15486
15487
|
if (!db) return c.json({ error: "Database not configured" }, 503);
|
|
@@ -15493,11 +15494,11 @@ const app$3 = new hono.Hono().post("/v1/traces", async (c) => {
|
|
|
15493
15494
|
try {
|
|
15494
15495
|
for (const resourceSpan of body.resourceSpans) {
|
|
15495
15496
|
const resourceAttrs = attributesToRecord(resourceSpan.resource?.attributes);
|
|
15496
|
-
|
|
15497
|
+
__llmops_sdk.logger.debug(`[OTLP] resourceSpan — scopeSpans count: ${resourceSpan.scopeSpans?.length ?? 0}, resource attrs: ${JSON.stringify(resourceAttrs)}`);
|
|
15497
15498
|
for (const scopeSpan of resourceSpan.scopeSpans) {
|
|
15498
|
-
|
|
15499
|
+
__llmops_sdk.logger.debug(`[OTLP] scopeSpan — scope: ${scopeSpan.scope?.name ?? "<none>"}, spans count: ${scopeSpan.spans?.length ?? 0}`);
|
|
15499
15500
|
for (const otlpSpan of scopeSpan.spans) {
|
|
15500
|
-
|
|
15501
|
+
__llmops_sdk.logger.debug(`[OTLP] raw span — traceId: ${otlpSpan.traceId}, spanId: ${otlpSpan.spanId}, parentSpanId: ${otlpSpan.parentSpanId ?? "null"}, name: ${otlpSpan.name}, startTimeUnixNano: ${otlpSpan.startTimeUnixNano}, endTimeUnixNano: ${otlpSpan.endTimeUnixNano ?? "null"}`);
|
|
15501
15502
|
const allAttrs = {
|
|
15502
15503
|
...resourceAttrs,
|
|
15503
15504
|
...attributesToRecord(otlpSpan.attributes)
|
|
@@ -15511,12 +15512,12 @@ const app$3 = new hono.Hono().post("/v1/traces", async (c) => {
|
|
|
15511
15512
|
let cost = 0;
|
|
15512
15513
|
if (typed.provider && typed.model && (typed.promptTokens > 0 || typed.completionTokens > 0)) try {
|
|
15513
15514
|
const pricing = await pricingProvider$1.getModelPricing(typed.provider, typed.model);
|
|
15514
|
-
if (pricing) cost = (0,
|
|
15515
|
+
if (pricing) cost = (0, __llmops_sdk.calculateCacheAwareCost)({
|
|
15515
15516
|
promptTokens: typed.promptTokens,
|
|
15516
15517
|
completionTokens: typed.completionTokens
|
|
15517
15518
|
}, pricing, typed.provider).totalCost;
|
|
15518
15519
|
} catch (e) {
|
|
15519
|
-
|
|
15520
|
+
__llmops_sdk.logger.debug(`[OTLP] Failed to calculate cost for ${typed.provider}/${typed.model}: ${e instanceof Error ? e.message : String(e)}`);
|
|
15520
15521
|
}
|
|
15521
15522
|
const spanData = {
|
|
15522
15523
|
traceId: otlpSpan.traceId,
|
|
@@ -15564,8 +15565,8 @@ const app$3 = new hono.Hono().post("/v1/traces", async (c) => {
|
|
|
15564
15565
|
tags: {},
|
|
15565
15566
|
metadata: {}
|
|
15566
15567
|
};
|
|
15567
|
-
|
|
15568
|
-
|
|
15568
|
+
__llmops_sdk.logger.debug(`[OTLP] spanData — traceId: ${spanData.traceId}, spanId: ${spanData.spanId}, parentSpanId: ${spanData.parentSpanId ?? "null"}, name: ${spanData.name}, source: ${spanData.source}, startTime: ${spanData.startTime.toISOString()}, endTime: ${spanData.endTime?.toISOString() ?? "null"}, durationMs: ${spanData.durationMs}`);
|
|
15569
|
+
__llmops_sdk.logger.debug(`[OTLP] traceData — traceId: ${traceData.traceId}, name: ${traceData.name ?? "null"}, status: ${traceData.status}, spanCount: ${traceData.spanCount}`);
|
|
15569
15570
|
const item = {
|
|
15570
15571
|
span: spanData,
|
|
15571
15572
|
events: spanEvents.length > 0 ? spanEvents : void 0,
|
|
@@ -15576,11 +15577,11 @@ const app$3 = new hono.Hono().post("/v1/traces", async (c) => {
|
|
|
15576
15577
|
}
|
|
15577
15578
|
}
|
|
15578
15579
|
}
|
|
15579
|
-
|
|
15580
|
+
__llmops_sdk.logger.debug(`[OTLP] Enqueued ${spanCount} spans total`);
|
|
15580
15581
|
return c.json({ partialSuccess: {} });
|
|
15581
15582
|
} catch (error$47) {
|
|
15582
15583
|
const msg = error$47 instanceof Error ? error$47.message : String(error$47);
|
|
15583
|
-
|
|
15584
|
+
__llmops_sdk.logger.error(`[OTLP] Failed to process traces: ${msg}`);
|
|
15584
15585
|
return c.json({ error: "Failed to process traces" }, 500);
|
|
15585
15586
|
}
|
|
15586
15587
|
});
|
|
@@ -15627,7 +15628,7 @@ function extractTokenUsage(run) {
|
|
|
15627
15628
|
totalTokens: Number(usageMeta.total_tokens ?? promptTokens + completionTokens)
|
|
15628
15629
|
};
|
|
15629
15630
|
}
|
|
15630
|
-
const pricingProvider = (0,
|
|
15631
|
+
const pricingProvider = (0, __llmops_sdk.getDefaultPricingProvider)();
|
|
15631
15632
|
async function runCreateToQueueItem(run) {
|
|
15632
15633
|
const traceId = run.trace_id ? uuidToHex(run.trace_id) : uuidToHex(run.id);
|
|
15633
15634
|
const spanId = uuidToHex(run.id);
|
|
@@ -15649,12 +15650,12 @@ async function runCreateToQueueItem(run) {
|
|
|
15649
15650
|
let cost = 0;
|
|
15650
15651
|
if (usage.provider && usage.model && (usage.promptTokens > 0 || usage.completionTokens > 0)) try {
|
|
15651
15652
|
const pricing = await pricingProvider.getModelPricing(usage.provider, usage.model);
|
|
15652
|
-
if (pricing) cost = (0,
|
|
15653
|
+
if (pricing) cost = (0, __llmops_sdk.calculateCacheAwareCost)({
|
|
15653
15654
|
promptTokens: usage.promptTokens,
|
|
15654
15655
|
completionTokens: usage.completionTokens
|
|
15655
15656
|
}, pricing, usage.provider).totalCost;
|
|
15656
15657
|
} catch (e) {
|
|
15657
|
-
|
|
15658
|
+
__llmops_sdk.logger.debug(`[LangSmith] Failed to calculate cost for ${usage.provider}/${usage.model}: ${e instanceof Error ? e.message : String(e)}`);
|
|
15658
15659
|
}
|
|
15659
15660
|
const attributes = { "langsmith.run_type": run.run_type };
|
|
15660
15661
|
if (run.session_name) attributes["langsmith.session_name"] = run.session_name;
|
|
@@ -15775,7 +15776,7 @@ const app$2 = new hono.Hono().get("/info", (c) => {
|
|
|
15775
15776
|
}
|
|
15776
15777
|
});
|
|
15777
15778
|
}).post("/runs/batch", async (c) => {
|
|
15778
|
-
|
|
15779
|
+
__llmops_sdk.logger.debug("[LangSmith] POST /runs/batch");
|
|
15779
15780
|
if (!c.req.header("x-api-key")?.trim()) return c.json({ error: "x-api-key header required" }, 401);
|
|
15780
15781
|
const db = c.get("telemetryStore");
|
|
15781
15782
|
if (!db) return c.json({ error: "Telemetry store not configured" }, 503);
|
|
@@ -15805,11 +15806,11 @@ const app$2 = new hono.Hono().get("/info", (c) => {
|
|
|
15805
15806
|
enqueued++;
|
|
15806
15807
|
}
|
|
15807
15808
|
}
|
|
15808
|
-
|
|
15809
|
+
__llmops_sdk.logger.debug(`[LangSmith] Enqueued ${enqueued} items`);
|
|
15809
15810
|
return c.json({}, 200);
|
|
15810
15811
|
} catch (error$47) {
|
|
15811
15812
|
const msg = error$47 instanceof Error ? error$47.message : String(error$47);
|
|
15812
|
-
|
|
15813
|
+
__llmops_sdk.logger.error(`[LangSmith] Failed to process batch: ${msg}`);
|
|
15813
15814
|
return c.json({ error: "Failed to process batch" }, 500);
|
|
15814
15815
|
}
|
|
15815
15816
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as hono_hono_base0 from "hono/hono-base";
|
|
2
2
|
import * as hono_types0 from "hono/types";
|
|
3
|
-
import { InlineProvidersConfig, LLMOpsConfig,
|
|
3
|
+
import { InlineProvidersConfig, LLMOpsConfig, ValidatedLLMOpsConfig } from "@llmops/core";
|
|
4
|
+
import { TelemetryStore } from "@llmops/sdk";
|
|
4
5
|
import { Hono } from "hono";
|
|
5
6
|
|
|
6
7
|
//#region src/server/types.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import { InlineProvidersConfig, LLMOpsConfig,
|
|
2
|
+
import { InlineProvidersConfig, LLMOpsConfig, ValidatedLLMOpsConfig } from "@llmops/core";
|
|
3
|
+
import { TelemetryStore } from "@llmops/sdk";
|
|
3
4
|
import * as hono_hono_base0 from "hono/hono-base";
|
|
4
5
|
import * as hono_types0 from "hono/types";
|
|
5
6
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import {
|
|
2
|
+
import { LLMOPS_REQUEST_ID_HEADER, LLMOPS_SESSION_ID_HEADER, LLMOPS_SPAN_ID_HEADER, LLMOPS_SPAN_NAME_HEADER, LLMOPS_TRACE_ID_HEADER, LLMOPS_TRACE_NAME_HEADER, LLMOPS_USER_ID_HEADER, SupportedProviders, calculateCacheAwareCost, getDefaultPricingProvider, logger, validateLLMOpsConfig } from "@llmops/core";
|
|
3
3
|
import nunjucks from "nunjucks";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
7
|
import { zValidator } from "@hono/zod-validator";
|
|
8
|
+
import { COST_SUMMARY_GROUP_BY, calculateCacheAwareCost as calculateCacheAwareCost$1, getDefaultPricingProvider as getDefaultPricingProvider$1, logger as logger$1 } from "@llmops/sdk";
|
|
8
9
|
import { prettyJSON } from "hono/pretty-json";
|
|
9
10
|
import { HTTPException } from "hono/http-exception";
|
|
10
11
|
import { cors } from "hono/cors";
|
|
@@ -14520,14 +14521,14 @@ function createTraceBatchWriter(deps, config$1 = {}) {
|
|
|
14520
14521
|
let flushTimer = null;
|
|
14521
14522
|
let running = false;
|
|
14522
14523
|
let flushing = false;
|
|
14523
|
-
const log = debug ? (msg) => logger.debug(msg) : () => {};
|
|
14524
|
+
const log = debug ? (msg) => logger$1.debug(msg) : () => {};
|
|
14524
14525
|
async function flush() {
|
|
14525
14526
|
if (flushing || queue.length === 0) return;
|
|
14526
14527
|
flushing = true;
|
|
14527
14528
|
const batch = queue;
|
|
14528
14529
|
queue = [];
|
|
14529
14530
|
try {
|
|
14530
|
-
logger.debug(`[TraceBatchWriter] Flushing ${batch.length} items`);
|
|
14531
|
+
logger$1.debug(`[TraceBatchWriter] Flushing ${batch.length} items`);
|
|
14531
14532
|
log(`[TraceBatchWriter] Flushing ${batch.length} items`);
|
|
14532
14533
|
const traceMap = /* @__PURE__ */ new Map();
|
|
14533
14534
|
for (const item of batch) {
|
|
@@ -14561,11 +14562,11 @@ function createTraceBatchWriter(deps, config$1 = {}) {
|
|
|
14561
14562
|
const allEvents = batch.flatMap((item) => item.events ?? []);
|
|
14562
14563
|
if (allEvents.length > 0) await deps.batchInsertSpanEvents(allEvents);
|
|
14563
14564
|
for (const trace of traceMap.values()) await deps.upsertTrace(trace);
|
|
14564
|
-
logger.debug(`[TraceBatchWriter] Flushed ${traceMap.size} traces, ${allSpans.length} spans, ${allEvents.length} events`);
|
|
14565
|
+
logger$1.debug(`[TraceBatchWriter] Flushed ${traceMap.size} traces, ${allSpans.length} spans, ${allEvents.length} events`);
|
|
14565
14566
|
log(`[TraceBatchWriter] Flushed ${traceMap.size} traces, ${allSpans.length} spans, ${allEvents.length} events`);
|
|
14566
14567
|
} catch (error$47) {
|
|
14567
14568
|
const errorMsg = error$47 instanceof Error ? error$47.message : String(error$47);
|
|
14568
|
-
logger.error(`[TraceBatchWriter] Flush failed, re-queuing items: ${errorMsg}`);
|
|
14569
|
+
logger$1.error(`[TraceBatchWriter] Flush failed, re-queuing items: ${errorMsg}`);
|
|
14569
14570
|
queue = [...batch, ...queue];
|
|
14570
14571
|
} finally {
|
|
14571
14572
|
flushing = false;
|
|
@@ -14577,7 +14578,7 @@ function createTraceBatchWriter(deps, config$1 = {}) {
|
|
|
14577
14578
|
flushTimer = setInterval(() => {
|
|
14578
14579
|
flush().catch((err) => {
|
|
14579
14580
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
14580
|
-
logger.error(`[TraceBatchWriter] Periodic flush error: ${errorMsg}`);
|
|
14581
|
+
logger$1.error(`[TraceBatchWriter] Periodic flush error: ${errorMsg}`);
|
|
14581
14582
|
});
|
|
14582
14583
|
}, flushIntervalMs);
|
|
14583
14584
|
log(`[TraceBatchWriter] Started with ${flushIntervalMs}ms flush interval`);
|
|
@@ -14600,7 +14601,7 @@ function createTraceBatchWriter(deps, config$1 = {}) {
|
|
|
14600
14601
|
log(`[TraceBatchWriter] Max batch size reached, forcing flush`);
|
|
14601
14602
|
flush().catch((err) => {
|
|
14602
14603
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
14603
|
-
logger.error(`[TraceBatchWriter] Forced flush error: ${errorMsg}`);
|
|
14604
|
+
logger$1.error(`[TraceBatchWriter] Forced flush error: ${errorMsg}`);
|
|
14604
14605
|
});
|
|
14605
14606
|
}
|
|
14606
14607
|
}
|
|
@@ -15426,13 +15427,13 @@ function extractTypedFields(attrs) {
|
|
|
15426
15427
|
output
|
|
15427
15428
|
};
|
|
15428
15429
|
}
|
|
15429
|
-
const pricingProvider$1 = getDefaultPricingProvider();
|
|
15430
|
+
const pricingProvider$1 = getDefaultPricingProvider$1();
|
|
15430
15431
|
/**
|
|
15431
15432
|
* OTLP ingestion endpoint
|
|
15432
15433
|
* Accepts OTLP JSON and Protobuf (ExportTraceServiceRequest) formats
|
|
15433
15434
|
*/
|
|
15434
15435
|
const app$3 = new Hono().post("/v1/traces", async (c) => {
|
|
15435
|
-
logger.debug(`[OTLP] POST /v1/traces hit — url: ${c.req.url}`);
|
|
15436
|
+
logger$1.debug(`[OTLP] POST /v1/traces hit — url: ${c.req.url}`);
|
|
15436
15437
|
const authHeader = c.req.header("authorization");
|
|
15437
15438
|
if (!authHeader) return c.json({ error: "Authorization header required" }, 401);
|
|
15438
15439
|
const match = authHeader.match(/^Bearer\s+(.+)$/i);
|
|
@@ -15441,19 +15442,19 @@ const app$3 = new Hono().post("/v1/traces", async (c) => {
|
|
|
15441
15442
|
c.set("envSec", envSec);
|
|
15442
15443
|
let body;
|
|
15443
15444
|
const contentType = c.req.header("content-type") ?? "";
|
|
15444
|
-
logger.debug(`[OTLP] Received request — Content-Type: ${contentType}`);
|
|
15445
|
+
logger$1.debug(`[OTLP] Received request — Content-Type: ${contentType}`);
|
|
15445
15446
|
try {
|
|
15446
15447
|
if (contentType.includes("application/x-protobuf") || contentType.includes("application/protobuf")) {
|
|
15447
15448
|
const buffer = await c.req.arrayBuffer();
|
|
15448
|
-
logger.debug(`[OTLP] Protobuf body size: ${buffer.byteLength} bytes`);
|
|
15449
|
+
logger$1.debug(`[OTLP] Protobuf body size: ${buffer.byteLength} bytes`);
|
|
15449
15450
|
body = decodeOtlpProtobuf(new Uint8Array(buffer));
|
|
15450
15451
|
} else body = await c.req.json();
|
|
15451
15452
|
} catch (e) {
|
|
15452
15453
|
const msg = e instanceof Error ? e.message : String(e);
|
|
15453
|
-
logger.error(`[OTLP] Failed to parse request body: ${msg}`);
|
|
15454
|
+
logger$1.error(`[OTLP] Failed to parse request body: ${msg}`);
|
|
15454
15455
|
return c.json({ error: "Invalid request body" }, 400);
|
|
15455
15456
|
}
|
|
15456
|
-
logger.debug(`[OTLP] Parsed body — resourceSpans count: ${body.resourceSpans?.length ?? 0}`);
|
|
15457
|
+
logger$1.debug(`[OTLP] Parsed body — resourceSpans count: ${body.resourceSpans?.length ?? 0}`);
|
|
15457
15458
|
if (!body.resourceSpans || !Array.isArray(body.resourceSpans)) return c.json({ error: "Missing resourceSpans" }, 400);
|
|
15458
15459
|
const db = c.get("telemetryStore");
|
|
15459
15460
|
if (!db) return c.json({ error: "Database not configured" }, 503);
|
|
@@ -15466,11 +15467,11 @@ const app$3 = new Hono().post("/v1/traces", async (c) => {
|
|
|
15466
15467
|
try {
|
|
15467
15468
|
for (const resourceSpan of body.resourceSpans) {
|
|
15468
15469
|
const resourceAttrs = attributesToRecord(resourceSpan.resource?.attributes);
|
|
15469
|
-
logger.debug(`[OTLP] resourceSpan — scopeSpans count: ${resourceSpan.scopeSpans?.length ?? 0}, resource attrs: ${JSON.stringify(resourceAttrs)}`);
|
|
15470
|
+
logger$1.debug(`[OTLP] resourceSpan — scopeSpans count: ${resourceSpan.scopeSpans?.length ?? 0}, resource attrs: ${JSON.stringify(resourceAttrs)}`);
|
|
15470
15471
|
for (const scopeSpan of resourceSpan.scopeSpans) {
|
|
15471
|
-
logger.debug(`[OTLP] scopeSpan — scope: ${scopeSpan.scope?.name ?? "<none>"}, spans count: ${scopeSpan.spans?.length ?? 0}`);
|
|
15472
|
+
logger$1.debug(`[OTLP] scopeSpan — scope: ${scopeSpan.scope?.name ?? "<none>"}, spans count: ${scopeSpan.spans?.length ?? 0}`);
|
|
15472
15473
|
for (const otlpSpan of scopeSpan.spans) {
|
|
15473
|
-
logger.debug(`[OTLP] raw span — traceId: ${otlpSpan.traceId}, spanId: ${otlpSpan.spanId}, parentSpanId: ${otlpSpan.parentSpanId ?? "null"}, name: ${otlpSpan.name}, startTimeUnixNano: ${otlpSpan.startTimeUnixNano}, endTimeUnixNano: ${otlpSpan.endTimeUnixNano ?? "null"}`);
|
|
15474
|
+
logger$1.debug(`[OTLP] raw span — traceId: ${otlpSpan.traceId}, spanId: ${otlpSpan.spanId}, parentSpanId: ${otlpSpan.parentSpanId ?? "null"}, name: ${otlpSpan.name}, startTimeUnixNano: ${otlpSpan.startTimeUnixNano}, endTimeUnixNano: ${otlpSpan.endTimeUnixNano ?? "null"}`);
|
|
15474
15475
|
const allAttrs = {
|
|
15475
15476
|
...resourceAttrs,
|
|
15476
15477
|
...attributesToRecord(otlpSpan.attributes)
|
|
@@ -15484,12 +15485,12 @@ const app$3 = new Hono().post("/v1/traces", async (c) => {
|
|
|
15484
15485
|
let cost = 0;
|
|
15485
15486
|
if (typed.provider && typed.model && (typed.promptTokens > 0 || typed.completionTokens > 0)) try {
|
|
15486
15487
|
const pricing = await pricingProvider$1.getModelPricing(typed.provider, typed.model);
|
|
15487
|
-
if (pricing) cost = calculateCacheAwareCost({
|
|
15488
|
+
if (pricing) cost = calculateCacheAwareCost$1({
|
|
15488
15489
|
promptTokens: typed.promptTokens,
|
|
15489
15490
|
completionTokens: typed.completionTokens
|
|
15490
15491
|
}, pricing, typed.provider).totalCost;
|
|
15491
15492
|
} catch (e) {
|
|
15492
|
-
logger.debug(`[OTLP] Failed to calculate cost for ${typed.provider}/${typed.model}: ${e instanceof Error ? e.message : String(e)}`);
|
|
15493
|
+
logger$1.debug(`[OTLP] Failed to calculate cost for ${typed.provider}/${typed.model}: ${e instanceof Error ? e.message : String(e)}`);
|
|
15493
15494
|
}
|
|
15494
15495
|
const spanData = {
|
|
15495
15496
|
traceId: otlpSpan.traceId,
|
|
@@ -15537,8 +15538,8 @@ const app$3 = new Hono().post("/v1/traces", async (c) => {
|
|
|
15537
15538
|
tags: {},
|
|
15538
15539
|
metadata: {}
|
|
15539
15540
|
};
|
|
15540
|
-
logger.debug(`[OTLP] spanData — traceId: ${spanData.traceId}, spanId: ${spanData.spanId}, parentSpanId: ${spanData.parentSpanId ?? "null"}, name: ${spanData.name}, source: ${spanData.source}, startTime: ${spanData.startTime.toISOString()}, endTime: ${spanData.endTime?.toISOString() ?? "null"}, durationMs: ${spanData.durationMs}`);
|
|
15541
|
-
logger.debug(`[OTLP] traceData — traceId: ${traceData.traceId}, name: ${traceData.name ?? "null"}, status: ${traceData.status}, spanCount: ${traceData.spanCount}`);
|
|
15541
|
+
logger$1.debug(`[OTLP] spanData — traceId: ${spanData.traceId}, spanId: ${spanData.spanId}, parentSpanId: ${spanData.parentSpanId ?? "null"}, name: ${spanData.name}, source: ${spanData.source}, startTime: ${spanData.startTime.toISOString()}, endTime: ${spanData.endTime?.toISOString() ?? "null"}, durationMs: ${spanData.durationMs}`);
|
|
15542
|
+
logger$1.debug(`[OTLP] traceData — traceId: ${traceData.traceId}, name: ${traceData.name ?? "null"}, status: ${traceData.status}, spanCount: ${traceData.spanCount}`);
|
|
15542
15543
|
const item = {
|
|
15543
15544
|
span: spanData,
|
|
15544
15545
|
events: spanEvents.length > 0 ? spanEvents : void 0,
|
|
@@ -15549,11 +15550,11 @@ const app$3 = new Hono().post("/v1/traces", async (c) => {
|
|
|
15549
15550
|
}
|
|
15550
15551
|
}
|
|
15551
15552
|
}
|
|
15552
|
-
logger.debug(`[OTLP] Enqueued ${spanCount} spans total`);
|
|
15553
|
+
logger$1.debug(`[OTLP] Enqueued ${spanCount} spans total`);
|
|
15553
15554
|
return c.json({ partialSuccess: {} });
|
|
15554
15555
|
} catch (error$47) {
|
|
15555
15556
|
const msg = error$47 instanceof Error ? error$47.message : String(error$47);
|
|
15556
|
-
logger.error(`[OTLP] Failed to process traces: ${msg}`);
|
|
15557
|
+
logger$1.error(`[OTLP] Failed to process traces: ${msg}`);
|
|
15557
15558
|
return c.json({ error: "Failed to process traces" }, 500);
|
|
15558
15559
|
}
|
|
15559
15560
|
});
|
|
@@ -15600,7 +15601,7 @@ function extractTokenUsage(run) {
|
|
|
15600
15601
|
totalTokens: Number(usageMeta.total_tokens ?? promptTokens + completionTokens)
|
|
15601
15602
|
};
|
|
15602
15603
|
}
|
|
15603
|
-
const pricingProvider = getDefaultPricingProvider();
|
|
15604
|
+
const pricingProvider = getDefaultPricingProvider$1();
|
|
15604
15605
|
async function runCreateToQueueItem(run) {
|
|
15605
15606
|
const traceId = run.trace_id ? uuidToHex(run.trace_id) : uuidToHex(run.id);
|
|
15606
15607
|
const spanId = uuidToHex(run.id);
|
|
@@ -15622,12 +15623,12 @@ async function runCreateToQueueItem(run) {
|
|
|
15622
15623
|
let cost = 0;
|
|
15623
15624
|
if (usage.provider && usage.model && (usage.promptTokens > 0 || usage.completionTokens > 0)) try {
|
|
15624
15625
|
const pricing = await pricingProvider.getModelPricing(usage.provider, usage.model);
|
|
15625
|
-
if (pricing) cost = calculateCacheAwareCost({
|
|
15626
|
+
if (pricing) cost = calculateCacheAwareCost$1({
|
|
15626
15627
|
promptTokens: usage.promptTokens,
|
|
15627
15628
|
completionTokens: usage.completionTokens
|
|
15628
15629
|
}, pricing, usage.provider).totalCost;
|
|
15629
15630
|
} catch (e) {
|
|
15630
|
-
logger.debug(`[LangSmith] Failed to calculate cost for ${usage.provider}/${usage.model}: ${e instanceof Error ? e.message : String(e)}`);
|
|
15631
|
+
logger$1.debug(`[LangSmith] Failed to calculate cost for ${usage.provider}/${usage.model}: ${e instanceof Error ? e.message : String(e)}`);
|
|
15631
15632
|
}
|
|
15632
15633
|
const attributes = { "langsmith.run_type": run.run_type };
|
|
15633
15634
|
if (run.session_name) attributes["langsmith.session_name"] = run.session_name;
|
|
@@ -15748,7 +15749,7 @@ const app$2 = new Hono().get("/info", (c) => {
|
|
|
15748
15749
|
}
|
|
15749
15750
|
});
|
|
15750
15751
|
}).post("/runs/batch", async (c) => {
|
|
15751
|
-
logger.debug("[LangSmith] POST /runs/batch");
|
|
15752
|
+
logger$1.debug("[LangSmith] POST /runs/batch");
|
|
15752
15753
|
if (!c.req.header("x-api-key")?.trim()) return c.json({ error: "x-api-key header required" }, 401);
|
|
15753
15754
|
const db = c.get("telemetryStore");
|
|
15754
15755
|
if (!db) return c.json({ error: "Telemetry store not configured" }, 503);
|
|
@@ -15778,11 +15779,11 @@ const app$2 = new Hono().get("/info", (c) => {
|
|
|
15778
15779
|
enqueued++;
|
|
15779
15780
|
}
|
|
15780
15781
|
}
|
|
15781
|
-
logger.debug(`[LangSmith] Enqueued ${enqueued} items`);
|
|
15782
|
+
logger$1.debug(`[LangSmith] Enqueued ${enqueued} items`);
|
|
15782
15783
|
return c.json({}, 200);
|
|
15783
15784
|
} catch (error$47) {
|
|
15784
15785
|
const msg = error$47 instanceof Error ? error$47.message : String(error$47);
|
|
15785
|
-
logger.error(`[LangSmith] Failed to process batch: ${msg}`);
|
|
15786
|
+
logger$1.error(`[LangSmith] Failed to process batch: ${msg}`);
|
|
15786
15787
|
return c.json({ error: "Failed to process batch" }, 500);
|
|
15787
15788
|
}
|
|
15788
15789
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llmops/app",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.6",
|
|
4
4
|
"description": "LLMOps application with server and client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -76,8 +76,9 @@
|
|
|
76
76
|
"react-hook-form": "^7.68.0",
|
|
77
77
|
"recharts": "^3.6.0",
|
|
78
78
|
"uuid": "^13.0.0",
|
|
79
|
-
"@llmops/core": "^1.0.0-beta.
|
|
80
|
-
"@llmops/
|
|
79
|
+
"@llmops/core": "^1.0.0-beta.6",
|
|
80
|
+
"@llmops/sdk": "^1.0.0-beta.6",
|
|
81
|
+
"@llmops/gateway": "^1.0.0-beta.6"
|
|
81
82
|
},
|
|
82
83
|
"peerDependencies": {
|
|
83
84
|
"react": "^19.2.1",
|