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