@anyway-sh/node-server-sdk 0.22.9 → 0.22.10

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.mjs CHANGED
@@ -66,7 +66,7 @@ class PromptNotFoundError extends TraceloopError {
66
66
  }
67
67
  }
68
68
 
69
- var version = "0.22.9";
69
+ var version = "0.22.10";
70
70
 
71
71
  /**
72
72
  * Base class for handling annotation operations with the Traceloop API.
@@ -3238,6 +3238,10 @@ function parseKeyPairsIntoRecord(keyPairs) {
3238
3238
  }
3239
3239
 
3240
3240
  const ALL_INSTRUMENTATION_LIBRARIES = "all";
3241
+ let _pricingCalculator = null;
3242
+ const setPricingCalculator = (calculator) => {
3243
+ _pricingCalculator = calculator;
3244
+ };
3241
3245
  const spanAgentNames = new Map();
3242
3246
  const SPAN_AGENT_NAME_TTL = 5 * 60 * 1000;
3243
3247
  const AI_TELEMETRY_METADATA_AGENT = "ai.telemetry.metadata.agent";
@@ -3387,13 +3391,9 @@ const ensureSpanCompatibility = (span) => {
3387
3391
  const onSpanEnd = (originalOnEnd, instrumentationLibraries) => {
3388
3392
  return (span) => {
3389
3393
  var _a, _b, _c;
3390
- const libName = ((_a = span.instrumentationScope) === null || _a === void 0 ? void 0 : _a.name) ||
3391
- ((_b = span.instrumentationLibrary) === null || _b === void 0 ? void 0 : _b.name) ||
3392
- "unknown";
3393
- console.log(`[Anyway Debug] onSpanEnd: span="${span.name}" lib="${libName}"`);
3394
3394
  if (instrumentationLibraries &&
3395
- !instrumentationLibraries.includes(libName)) {
3396
- console.log(`[Anyway Debug] Dropping span="${span.name}" - lib="${libName}" not in allowed list`);
3395
+ !instrumentationLibraries.includes(((_a = span.instrumentationScope) === null || _a === void 0 ? void 0 : _a.name) ||
3396
+ ((_b = span.instrumentationLibrary) === null || _b === void 0 ? void 0 : _b.name))) {
3397
3397
  return;
3398
3398
  }
3399
3399
  transformAiSdkSpanAttributes(span);
@@ -3419,8 +3419,10 @@ const onSpanEnd = (originalOnEnd, instrumentationLibraries) => {
3419
3419
  if (Math.random() < 0.01) {
3420
3420
  cleanupExpiredSpanAgentNames();
3421
3421
  }
3422
+ if (_pricingCalculator) {
3423
+ _pricingCalculator.addCostAttributes(span);
3424
+ }
3422
3425
  const compatibleSpan = ensureSpanCompatibility(span);
3423
- console.log(`[Anyway Debug] Span queued for export: "${span.name}" lib="${libName}"`);
3424
3426
  originalOnEnd(compatibleSpan);
3425
3427
  };
3426
3428
  };
@@ -3706,19 +3708,6 @@ const startTracing = (options) => {
3706
3708
  url: `${baseUrl}/v1/traces`,
3707
3709
  headers,
3708
3710
  }));
3709
- // [Anyway Debug] Wrap exporter to log outgoing calls
3710
- const origExport = traceExporter.export.bind(traceExporter);
3711
- traceExporter.export = (spans, resultCallback) => {
3712
- var _a, _b;
3713
- console.log(`[Anyway Debug] Exporting ${spans.length} span(s) to ${baseUrl}/v1/traces`);
3714
- for (const s of spans) {
3715
- console.log(`[Anyway Debug] - ${s.name} (${((_a = s.instrumentationLibrary) === null || _a === void 0 ? void 0 : _a.name) || ((_b = s.instrumentationScope) === null || _b === void 0 ? void 0 : _b.name) || "unknown"})`);
3716
- }
3717
- return origExport(spans, (result) => {
3718
- console.log(`[Anyway Debug] Export result: code=${result.code}${result.error ? ` error=${result.error.message}` : ""}`);
3719
- resultCallback(result);
3720
- });
3721
- };
3722
3711
  _spanProcessor = createSpanProcessor({
3723
3712
  apiKey: options.apiKey,
3724
3713
  baseUrl: options.baseUrl,
@@ -3856,6 +3845,80 @@ const initializeRegistry = (options) => {
3856
3845
  });
3857
3846
  };
3858
3847
 
3848
+ const DATE_SUFFIX_PATTERN = /-\d{4}-\d{2}-\d{2}$/;
3849
+ const DATE_COMPACT_SUFFIX_PATTERN = /-\d{8}$/;
3850
+ class PricingCalculator {
3851
+ constructor(pricingData) {
3852
+ var _a;
3853
+ this.chatModels = (_a = pricingData.chat) !== null && _a !== void 0 ? _a : {};
3854
+ }
3855
+ findPricing(modelName) {
3856
+ if (!modelName)
3857
+ return null;
3858
+ const models = this.chatModels;
3859
+ // 1. Exact match
3860
+ if (models[modelName]) {
3861
+ return this.normalize(models[modelName]);
3862
+ }
3863
+ // 2. Strip date suffix and retry
3864
+ let stripped = modelName.replace(DATE_SUFFIX_PATTERN, "");
3865
+ stripped = stripped.replace(DATE_COMPACT_SUFFIX_PATTERN, "");
3866
+ if (stripped !== modelName && models[stripped]) {
3867
+ return this.normalize(models[stripped]);
3868
+ }
3869
+ // 3. Prefix match (longest wins)
3870
+ let bestMatch = null;
3871
+ let bestLen = 0;
3872
+ for (const baseModel of Object.keys(models)) {
3873
+ if (modelName.startsWith(baseModel) && baseModel.length > bestLen) {
3874
+ bestMatch = baseModel;
3875
+ bestLen = baseModel.length;
3876
+ }
3877
+ }
3878
+ if (bestMatch) {
3879
+ return this.normalize(models[bestMatch]);
3880
+ }
3881
+ return null;
3882
+ }
3883
+ addCostAttributes(span) {
3884
+ const attrs = span.attributes;
3885
+ if (!attrs)
3886
+ return;
3887
+ const model = attrs[ATTR_GEN_AI_RESPONSE_MODEL] ||
3888
+ attrs[ATTR_GEN_AI_REQUEST_MODEL];
3889
+ if (!model)
3890
+ return;
3891
+ const inputTokens = attrs[ATTR_GEN_AI_USAGE_INPUT_TOKENS];
3892
+ const outputTokens = attrs[ATTR_GEN_AI_USAGE_OUTPUT_TOKENS];
3893
+ if (inputTokens == null && outputTokens == null)
3894
+ return;
3895
+ const pricing = this.findPricing(model);
3896
+ if (!pricing)
3897
+ return;
3898
+ const inputCost = (inputTokens !== null && inputTokens !== void 0 ? inputTokens : 0) * pricing.inputCostPerToken;
3899
+ const outputCost = (outputTokens !== null && outputTokens !== void 0 ? outputTokens : 0) * pricing.outputCostPerToken;
3900
+ span.attributes["gen_ai.usage.input_cost"] = inputCost;
3901
+ span.attributes["gen_ai.usage.output_cost"] = outputCost;
3902
+ span.attributes["gen_ai.usage.cost"] = inputCost + outputCost;
3903
+ }
3904
+ normalize(pricing) {
3905
+ var _a, _b;
3906
+ return {
3907
+ inputCostPerToken: ((_a = pricing.promptPrice) !== null && _a !== void 0 ? _a : 0) / 1000,
3908
+ outputCostPerToken: ((_b = pricing.completionPrice) !== null && _b !== void 0 ? _b : 0) / 1000,
3909
+ };
3910
+ }
3911
+ }
3912
+
3913
+ function loadPricing(pricingJsonPath) {
3914
+ if (pricingJsonPath) {
3915
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
3916
+ const fs = require("fs");
3917
+ return JSON.parse(fs.readFileSync(pricingJsonPath, "utf-8"));
3918
+ }
3919
+ return require("./data/default_pricing.json");
3920
+ }
3921
+
3859
3922
  let _configuration;
3860
3923
  let _client;
3861
3924
  /**
@@ -3918,15 +3981,21 @@ const initialize = (options = {}) => {
3918
3981
  if (!options.silenceInitializationMessage) {
3919
3982
  console.log(`Traceloop exporting traces to ${_configuration.exporter ? "a custom exporter" : _configuration.baseUrl}`);
3920
3983
  }
3921
- console.log(`[Anyway Debug] Trace endpoint: ${_configuration.baseUrl}/v1/traces`);
3922
- console.log(`[Anyway Debug] API key present: ${!!_configuration.apiKey}`);
3923
- console.log(`[Anyway Debug] Using custom exporter: ${!!_configuration.exporter}`);
3924
3984
  if (options.tracingEnabled === undefined || options.tracingEnabled) {
3925
3985
  if (options.logLevel) {
3926
3986
  diag.setLogger(new DiagConsoleLogger(), logLevelToOtelLogLevel(options.logLevel));
3927
3987
  }
3928
3988
  startTracing(_configuration);
3929
3989
  }
3990
+ if (options.pricingEnabled !== false) {
3991
+ try {
3992
+ const pricingData = loadPricing(options.pricingJsonPath);
3993
+ setPricingCalculator(new PricingCalculator(pricingData));
3994
+ }
3995
+ catch (e) {
3996
+ console.warn(`[Traceloop] Failed to initialize pricing: ${e.message}`);
3997
+ }
3998
+ }
3930
3999
  initializeRegistry(_configuration);
3931
4000
  if (options.apiKey) {
3932
4001
  _client = new TraceloopClient({
@@ -4399,5 +4468,5 @@ var AssociationProperty;
4399
4468
  AssociationProperty["SESSION_ID"] = "session_id";
4400
4469
  })(AssociationProperty || (AssociationProperty = {}));
4401
4470
 
4402
- export { ALL_INSTRUMENTATION_LIBRARIES, ArgumentNotProvidedError, AssociationProperty, Attachment, AttachmentReference, AttachmentUploader, Column, Dataset, Datasets, Evaluator, EvaluatorMadeByTraceloop, Experiment, ExternalAttachment, ImageUploader, InitializationError, LLMSpan, NotInitializedError, PromptNotFoundError, Row, SEVERITY, TraceloopClient, TraceloopError, VectorSpan, agent, attachment, conversation, createEvaluator, createSpanProcessor, forceFlush, getAvailableEvaluatorSlugs, getClient, getEvaluatorSchemaInfo, getPrompt, getTraceloopTracer, initialize, isAnyAttachment, isAttachment, isAttachmentReference, isExternalAttachment, reportCustomMetric, task, tool, traceloopInstrumentationLibraries, validateEvaluatorInput, waitForInitialization, withAgent, withAssociationProperties, withConversation, withLLMCall, withTask, withTool, withVectorDBCall, withWorkflow, workflow };
4471
+ export { ALL_INSTRUMENTATION_LIBRARIES, ArgumentNotProvidedError, AssociationProperty, Attachment, AttachmentReference, AttachmentUploader, Column, Dataset, Datasets, Evaluator, EvaluatorMadeByTraceloop, Experiment, ExternalAttachment, ImageUploader, InitializationError, LLMSpan, NotInitializedError, PromptNotFoundError, Row, SEVERITY, TraceloopClient, TraceloopError, VectorSpan, agent, attachment, conversation, createEvaluator, createSpanProcessor, forceFlush, getAvailableEvaluatorSlugs, getClient, getEvaluatorSchemaInfo, getPrompt, getTraceloopTracer, initialize, isAnyAttachment, isAttachment, isAttachmentReference, isExternalAttachment, reportCustomMetric, setPricingCalculator, task, tool, traceloopInstrumentationLibraries, validateEvaluatorInput, waitForInitialization, withAgent, withAssociationProperties, withConversation, withLLMCall, withTask, withTool, withVectorDBCall, withWorkflow, workflow };
4403
4472
  //# sourceMappingURL=index.mjs.map
@@ -129,5 +129,15 @@ export interface InitializeOptions {
129
129
  * This is used to configure the Google Cloud Trace Exporter.
130
130
  */
131
131
  gcpProjectId?: string;
132
+ /**
133
+ * Whether to calculate and add cost attributes to spans. Optional.
134
+ * Defaults to true.
135
+ */
136
+ pricingEnabled?: boolean;
137
+ /**
138
+ * Path to a custom pricing JSON file. Optional.
139
+ * If not set, uses the bundled default pricing data.
140
+ */
141
+ pricingJsonPath?: string;
132
142
  }
133
143
  //# sourceMappingURL=initialize-options.interface.d.ts.map
@@ -0,0 +1,24 @@
1
+ import { ReadableSpan } from "@opentelemetry/sdk-trace-base";
2
+ interface NormalizedPricing {
3
+ inputCostPerToken: number;
4
+ outputCostPerToken: number;
5
+ }
6
+ interface ModelPricing {
7
+ promptPrice: number;
8
+ completionPrice: number;
9
+ }
10
+ export interface PricingData {
11
+ chat?: Record<string, ModelPricing>;
12
+ embeddings?: Record<string, number>;
13
+ images?: Record<string, unknown>;
14
+ audio?: Record<string, unknown>;
15
+ }
16
+ export declare class PricingCalculator {
17
+ private chatModels;
18
+ constructor(pricingData: PricingData);
19
+ findPricing(modelName: string): NormalizedPricing | null;
20
+ addCostAttributes(span: ReadableSpan): void;
21
+ private normalize;
22
+ }
23
+ export {};
24
+ //# sourceMappingURL=calculator.d.ts.map
@@ -0,0 +1,4 @@
1
+ export { PricingCalculator } from "./calculator";
2
+ export type { PricingData } from "./calculator";
3
+ export { loadPricing } from "./loader";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,3 @@
1
+ import { PricingData } from "./calculator";
2
+ export declare function loadPricing(pricingJsonPath?: string): PricingData;
3
+ //# sourceMappingURL=loader.d.ts.map
@@ -1,7 +1,9 @@
1
1
  import { SpanProcessor } from "@opentelemetry/sdk-trace-node";
2
2
  import { SpanExporter } from "@opentelemetry/sdk-trace-base";
3
+ import { PricingCalculator } from "../pricing";
3
4
  export declare const ALL_INSTRUMENTATION_LIBRARIES: "all";
4
5
  type AllInstrumentationLibraries = typeof ALL_INSTRUMENTATION_LIBRARIES;
6
+ export declare const setPricingCalculator: (calculator: PricingCalculator | null) => void;
5
7
  export interface SpanProcessorOptions {
6
8
  /**
7
9
  * The API Key for sending traces data. Optional.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anyway-sh/node-server-sdk",
3
- "version": "0.22.9",
3
+ "version": "0.22.10",
4
4
  "description": "Anyway Software Development Kit (SDK) for Node.js",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",