@anyway-sh/node-server-sdk 0.22.8 → 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.8";
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";
@@ -3415,6 +3419,9 @@ const onSpanEnd = (originalOnEnd, instrumentationLibraries) => {
3415
3419
  if (Math.random() < 0.01) {
3416
3420
  cleanupExpiredSpanAgentNames();
3417
3421
  }
3422
+ if (_pricingCalculator) {
3423
+ _pricingCalculator.addCostAttributes(span);
3424
+ }
3418
3425
  const compatibleSpan = ensureSpanCompatibility(span);
3419
3426
  originalOnEnd(compatibleSpan);
3420
3427
  };
@@ -3838,6 +3845,80 @@ const initializeRegistry = (options) => {
3838
3845
  });
3839
3846
  };
3840
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
+
3841
3922
  let _configuration;
3842
3923
  let _client;
3843
3924
  /**
@@ -3906,6 +3987,15 @@ const initialize = (options = {}) => {
3906
3987
  }
3907
3988
  startTracing(_configuration);
3908
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
+ }
3909
3999
  initializeRegistry(_configuration);
3910
4000
  if (options.apiKey) {
3911
4001
  _client = new TraceloopClient({
@@ -4378,5 +4468,5 @@ var AssociationProperty;
4378
4468
  AssociationProperty["SESSION_ID"] = "session_id";
4379
4469
  })(AssociationProperty || (AssociationProperty = {}));
4380
4470
 
4381
- 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 };
4382
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.8",
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",