@langfuse/client 4.0.0-beta.1 → 4.0.0-beta.3

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 CHANGED
@@ -46,9 +46,44 @@ var import_core5 = require("@langfuse/core");
46
46
 
47
47
  // src/dataset/index.ts
48
48
  var DatasetManager = class {
49
+ /**
50
+ * Creates a new DatasetManager instance.
51
+ *
52
+ * @param params - Configuration object containing the API client
53
+ * @internal
54
+ */
49
55
  constructor(params) {
50
56
  this.apiClient = params.apiClient;
51
57
  }
58
+ /**
59
+ * Retrieves a dataset by name along with all its items.
60
+ *
61
+ * This method automatically handles pagination to fetch all dataset items
62
+ * and enhances each item with a `link` function for easy experiment tracking.
63
+ *
64
+ * @param name - The name of the dataset to retrieve
65
+ * @param options - Optional configuration for fetching
66
+ * @param options.fetchItemsPageSize - Number of items to fetch per page (default: 50)
67
+ *
68
+ * @returns Promise that resolves to the dataset with enhanced items
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const dataset = await langfuse.dataset.get("my-dataset");
73
+ *
74
+ * for (const item of dataset.items) {
75
+ * // Use the item data for your experiment
76
+ * const result = await processItem(item.input);
77
+ *
78
+ * // Link the result to the dataset item
79
+ * await item.link(
80
+ * { otelSpan: currentSpan },
81
+ * "experiment-run-1",
82
+ * { description: "Testing new model" }
83
+ * );
84
+ * }
85
+ * ```
86
+ */
52
87
  async get(name, options) {
53
88
  var _a;
54
89
  const dataset = await this.apiClient.datasets.get(name);
@@ -75,6 +110,13 @@ var DatasetManager = class {
75
110
  };
76
111
  return returnDataset;
77
112
  }
113
+ /**
114
+ * Creates a link function for a specific dataset item.
115
+ *
116
+ * @param item - The dataset item to create a link function for
117
+ * @returns A function that can link the item to OpenTelemetry spans
118
+ * @internal
119
+ */
78
120
  createDatasetItemLinkFunction(item) {
79
121
  const linkFunction = async (obj, runName, runArgs) => {
80
122
  return await this.apiClient.datasetRunItems.create({
@@ -92,24 +134,27 @@ var DatasetManager = class {
92
134
  // src/media/index.ts
93
135
  var import_core = require("@langfuse/core");
94
136
  var MediaManager = class _MediaManager {
137
+ /**
138
+ * Creates a new MediaManager instance.
139
+ *
140
+ * @param params - Configuration object containing the API client
141
+ * @internal
142
+ */
95
143
  constructor(params) {
96
144
  this.apiClient = params.apiClient;
97
145
  }
98
146
  /**
99
- * Replaces the media reference strings in an object with base64 data URIs for the media content.
147
+ * Replaces media reference strings in an object with base64 data URIs.
100
148
  *
101
- * This method recursively traverses an object (up to a maximum depth of 10) looking for media reference strings
102
- * in the format "@@@langfuseMedia:...@@@". When found, it fetches the actual media content using the provided
103
- * Langfuse client and replaces the reference string with a base64 data URI.
149
+ * This method recursively traverses an object looking for media reference strings
150
+ * in the format "@@@langfuseMedia:...@@@". When found, it fetches the actual media
151
+ * content from Langfuse and replaces the reference string with a base64 data URI.
104
152
  *
105
- * If fetching media content fails for a reference string, a warning is logged and the reference string is left unchanged.
153
+ * If fetching media content fails for a reference string, a warning is logged
154
+ * and the reference string is left unchanged.
106
155
  *
107
156
  * @param params - Configuration object
108
- * @param params.obj - The object to process. Can be a primitive value, array, or nested object
109
- * @param params.resolveWith - The representation of the media content to replace the media reference string with. Currently only "base64DataUri" is supported.
110
- * @param params.maxDepth - Optional. Default is 10. The maximum depth to traverse the object.
111
- *
112
- * @returns A deep copy of the input object with all media references replaced with base64 data URIs where possible
157
+ * @returns A deep copy of the input object with media references resolved
113
158
  *
114
159
  * @example
115
160
  * ```typescript
@@ -120,9 +165,9 @@ var MediaManager = class _MediaManager {
120
165
  * }
121
166
  * };
122
167
  *
123
- * const result = await LangfuseMedia.resolveMediaReferences({
168
+ * const result = await langfuse.media.resolveReferences({
124
169
  * obj,
125
- * langfuseClient
170
+ * resolveWith: "base64DataUri"
126
171
  * });
127
172
  *
128
173
  * // Result:
@@ -331,6 +376,14 @@ import_mustache.default.escape = function(text) {
331
376
  return text;
332
377
  };
333
378
  var BasePromptClient = class {
379
+ /**
380
+ * Creates a new BasePromptClient instance.
381
+ *
382
+ * @param prompt - The base prompt data
383
+ * @param isFallback - Whether this is fallback content
384
+ * @param type - The prompt type
385
+ * @internal
386
+ */
334
387
  constructor(prompt, isFallback = false, type) {
335
388
  this.name = prompt.name;
336
389
  this.version = prompt.version;
@@ -398,14 +451,51 @@ var BasePromptClient = class {
398
451
  }
399
452
  };
400
453
  var TextPromptClient = class extends BasePromptClient {
454
+ /**
455
+ * Creates a new TextPromptClient instance.
456
+ *
457
+ * @param prompt - The text prompt data
458
+ * @param isFallback - Whether this is fallback content
459
+ */
401
460
  constructor(prompt, isFallback = false) {
402
461
  super(prompt, isFallback, "text");
403
462
  this.promptResponse = prompt;
404
463
  this.prompt = prompt.prompt;
405
464
  }
465
+ /**
466
+ * Compiles the text prompt by substituting variables.
467
+ *
468
+ * Uses Mustache templating to replace {{variable}} placeholders with provided values.
469
+ *
470
+ * @param variables - Key-value pairs for variable substitution
471
+ * @param _placeholders - Ignored for text prompts
472
+ * @returns The compiled text with variables substituted
473
+ *
474
+ * @example
475
+ * ```typescript
476
+ * const prompt = await langfuse.prompt.get("greeting", { type: "text" });
477
+ * const compiled = prompt.compile({ name: "Alice" });
478
+ * // If prompt is "Hello {{name}}!", result is "Hello Alice!"
479
+ * ```
480
+ */
406
481
  compile(variables, _placeholders) {
407
482
  return import_mustache.default.render(this.promptResponse.prompt, variables != null ? variables : {});
408
483
  }
484
+ /**
485
+ * Converts the prompt to LangChain PromptTemplate format.
486
+ *
487
+ * Transforms Mustache-style {{variable}} syntax to LangChain's {variable} format.
488
+ *
489
+ * @param _options - Ignored for text prompts
490
+ * @returns The prompt string compatible with LangChain PromptTemplate
491
+ *
492
+ * @example
493
+ * ```typescript
494
+ * const prompt = await langfuse.prompt.get("greeting", { type: "text" });
495
+ * const langchainFormat = prompt.getLangchainPrompt();
496
+ * // Transforms "Hello {{name}}!" to "Hello {name}!"
497
+ * ```
498
+ */
409
499
  getLangchainPrompt(_options) {
410
500
  return this._transformToLangchainVariables(this.prompt);
411
501
  }
@@ -423,6 +513,12 @@ var TextPromptClient = class extends BasePromptClient {
423
513
  }
424
514
  };
425
515
  var ChatPromptClient = class _ChatPromptClient extends BasePromptClient {
516
+ /**
517
+ * Creates a new ChatPromptClient instance.
518
+ *
519
+ * @param prompt - The chat prompt data
520
+ * @param isFallback - Whether this is fallback content
521
+ */
426
522
  constructor(prompt, isFallback = false) {
427
523
  const normalizedPrompt = _ChatPromptClient.normalizePrompt(prompt.prompt);
428
524
  const typedPrompt = {
@@ -445,6 +541,26 @@ var ChatPromptClient = class _ChatPromptClient extends BasePromptClient {
445
541
  }
446
542
  });
447
543
  }
544
+ /**
545
+ * Compiles the chat prompt by replacing placeholders and variables.
546
+ *
547
+ * First resolves placeholders with provided values, then applies variable substitution
548
+ * to message content using Mustache templating. Unresolved placeholders remain
549
+ * as placeholder objects in the output.
550
+ *
551
+ * @param variables - Key-value pairs for Mustache variable substitution in message content
552
+ * @param placeholders - Key-value pairs where keys are placeholder names and values are ChatMessage arrays
553
+ * @returns Array of ChatMessage objects and unresolved placeholder objects
554
+ *
555
+ * @example
556
+ * ```typescript
557
+ * const prompt = await langfuse.prompt.get("conversation", { type: "chat" });
558
+ * const compiled = prompt.compile(
559
+ * { user_name: "Alice" },
560
+ * { examples: [{ role: "user", content: "Hello" }, { role: "assistant", content: "Hi!" }] }
561
+ * );
562
+ * ```
563
+ */
448
564
  compile(variables, placeholders) {
449
565
  const messagesWithPlaceholdersReplaced = [];
450
566
  const placeholderValues = placeholders != null ? placeholders : {};
@@ -485,6 +601,25 @@ var ChatPromptClient = class _ChatPromptClient extends BasePromptClient {
485
601
  }
486
602
  });
487
603
  }
604
+ /**
605
+ * Converts the prompt to LangChain ChatPromptTemplate format.
606
+ *
607
+ * Resolves placeholders with provided values and converts unresolved ones
608
+ * to LangChain MessagesPlaceholder objects. Transforms variables from
609
+ * {{var}} to {var} format without rendering them.
610
+ *
611
+ * @param options - Configuration object
612
+ * @param options.placeholders - Key-value pairs for placeholder resolution
613
+ * @returns Array of ChatMessage objects and LangChain MessagesPlaceholder objects
614
+ *
615
+ * @example
616
+ * ```typescript
617
+ * const prompt = await langfuse.prompt.get("conversation", { type: "chat" });
618
+ * const langchainFormat = prompt.getLangchainPrompt({
619
+ * placeholders: { examples: [{ role: "user", content: "Hello" }] }
620
+ * });
621
+ * ```
622
+ */
488
623
  getLangchainPrompt(options) {
489
624
  var _a;
490
625
  const messagesWithPlaceholdersReplaced = [];
@@ -545,6 +680,12 @@ var ChatPromptClient = class _ChatPromptClient extends BasePromptClient {
545
680
 
546
681
  // src/prompt/promptManager.ts
547
682
  var PromptManager = class {
683
+ /**
684
+ * Creates a new PromptManager instance.
685
+ *
686
+ * @param params - Configuration object containing the API client
687
+ * @internal
688
+ */
548
689
  constructor(params) {
549
690
  const { apiClient } = params;
550
691
  this.apiClient = apiClient;
@@ -553,6 +694,35 @@ var PromptManager = class {
553
694
  get logger() {
554
695
  return (0, import_core3.getGlobalLogger)();
555
696
  }
697
+ /**
698
+ * Creates a new prompt in Langfuse.
699
+ *
700
+ * Supports both text and chat prompts. Chat prompts can include placeholders
701
+ * for dynamic content insertion.
702
+ *
703
+ * @param body - The prompt data to create
704
+ * @returns Promise that resolves to the appropriate prompt client
705
+ *
706
+ * @example
707
+ * ```typescript
708
+ * // Create a text prompt
709
+ * const textPrompt = await langfuse.prompt.create({
710
+ * name: "greeting",
711
+ * prompt: "Hello {{name}}!",
712
+ * type: "text"
713
+ * });
714
+ *
715
+ * // Create a chat prompt
716
+ * const chatPrompt = await langfuse.prompt.create({
717
+ * name: "conversation",
718
+ * type: "chat",
719
+ * prompt: [
720
+ * { role: "system", content: "You are a helpful assistant." },
721
+ * { role: "user", content: "{{user_message}}" }
722
+ * ]
723
+ * });
724
+ * ```
725
+ */
556
726
  async create(body) {
557
727
  var _a;
558
728
  const requestBody = body.type === "chat" ? {
@@ -577,6 +747,25 @@ var PromptManager = class {
577
747
  }
578
748
  return new TextPromptClient(promptResponse);
579
749
  }
750
+ /**
751
+ * Updates the labels of an existing prompt version.
752
+ *
753
+ * @param params - Update parameters
754
+ * @param params.name - Name of the prompt to update
755
+ * @param params.version - Version number of the prompt to update
756
+ * @param params.newLabels - New labels to apply to the prompt version
757
+ *
758
+ * @returns Promise that resolves to the updated prompt
759
+ *
760
+ * @example
761
+ * ```typescript
762
+ * const updatedPrompt = await langfuse.prompt.update({
763
+ * name: "my-prompt",
764
+ * version: 1,
765
+ * newLabels: ["production", "v2"]
766
+ * });
767
+ * ```
768
+ */
580
769
  async update(params) {
581
770
  const { name, version, newLabels } = params;
582
771
  const newPrompt = await this.apiClient.promptVersion.update(name, version, {
@@ -585,6 +774,40 @@ var PromptManager = class {
585
774
  this.cache.invalidate(name);
586
775
  return newPrompt;
587
776
  }
777
+ /**
778
+ * Retrieves a prompt by name with intelligent caching.
779
+ *
780
+ * This method implements sophisticated caching behavior:
781
+ * - Fresh prompts are returned immediately from cache
782
+ * - Expired prompts are returned from cache while being refreshed in background
783
+ * - Cache misses trigger immediate fetch with optional fallback support
784
+ *
785
+ * @param name - Name of the prompt to retrieve
786
+ * @param options - Optional retrieval configuration
787
+ * @returns Promise that resolves to the appropriate prompt client
788
+ *
789
+ * @example
790
+ * ```typescript
791
+ * // Get latest version with caching
792
+ * const prompt = await langfuse.prompt.get("my-prompt");
793
+ *
794
+ * // Get specific version
795
+ * const v2Prompt = await langfuse.prompt.get("my-prompt", {
796
+ * version: 2
797
+ * });
798
+ *
799
+ * // Get with label filter
800
+ * const prodPrompt = await langfuse.prompt.get("my-prompt", {
801
+ * label: "production"
802
+ * });
803
+ *
804
+ * // Get with fallback
805
+ * const promptWithFallback = await langfuse.prompt.get("my-prompt", {
806
+ * type: "text",
807
+ * fallback: "Hello {{name}}!"
808
+ * });
809
+ * ```
810
+ */
588
811
  async get(name, options) {
589
812
  var _a;
590
813
  const cacheKey = this.cache.createKey({
@@ -701,6 +924,12 @@ var import_api = require("@opentelemetry/api");
701
924
  var MAX_QUEUE_SIZE = 1e5;
702
925
  var MAX_BATCH_SIZE = 100;
703
926
  var ScoreManager = class {
927
+ /**
928
+ * Creates a new ScoreManager instance.
929
+ *
930
+ * @param params - Configuration object containing the API client
931
+ * @internal
932
+ */
704
933
  constructor(params) {
705
934
  this.eventQueue = [];
706
935
  this.flushPromise = null;
@@ -714,6 +943,25 @@ var ScoreManager = class {
714
943
  get logger() {
715
944
  return (0, import_core4.getGlobalLogger)();
716
945
  }
946
+ /**
947
+ * Creates a new score event and adds it to the processing queue.
948
+ *
949
+ * Scores are queued and sent in batches for efficiency. The score will be
950
+ * automatically sent when the queue reaches the flush threshold or after
951
+ * the flush interval expires.
952
+ *
953
+ * @param data - The score data to create
954
+ *
955
+ * @example
956
+ * ```typescript
957
+ * langfuse.score.create({
958
+ * name: "quality",
959
+ * value: 0.85,
960
+ * traceId: "trace-123",
961
+ * comment: "High quality response"
962
+ * });
963
+ * ```
964
+ */
717
965
  create(data) {
718
966
  var _a, _b;
719
967
  const scoreData = {
@@ -742,6 +990,26 @@ var ScoreManager = class {
742
990
  }, this.flushIntervalSeconds * 1e3);
743
991
  }
744
992
  }
993
+ /**
994
+ * Creates a score for a specific observation using its OpenTelemetry span.
995
+ *
996
+ * This method automatically extracts the trace ID and observation ID from
997
+ * the provided span context.
998
+ *
999
+ * @param observation - Object containing the OpenTelemetry span
1000
+ * @param data - Score data (traceId and observationId will be auto-populated)
1001
+ *
1002
+ * @example
1003
+ * ```typescript
1004
+ * import { startSpan } from '@langfuse/tracing';
1005
+ *
1006
+ * const span = startSpan({ name: "my-operation" });
1007
+ * langfuse.score.observation(
1008
+ * { otelSpan: span },
1009
+ * { name: "accuracy", value: 0.92 }
1010
+ * );
1011
+ * ```
1012
+ */
745
1013
  observation(observation, data) {
746
1014
  const { spanId, traceId } = observation.otelSpan.spanContext();
747
1015
  this.create({
@@ -750,6 +1018,26 @@ var ScoreManager = class {
750
1018
  observationId: spanId
751
1019
  });
752
1020
  }
1021
+ /**
1022
+ * Creates a score for a trace using an OpenTelemetry span.
1023
+ *
1024
+ * This method automatically extracts the trace ID from the provided
1025
+ * span context and creates a trace-level score.
1026
+ *
1027
+ * @param observation - Object containing the OpenTelemetry span
1028
+ * @param data - Score data (traceId will be auto-populated)
1029
+ *
1030
+ * @example
1031
+ * ```typescript
1032
+ * import { startSpan } from '@langfuse/tracing';
1033
+ *
1034
+ * const span = startSpan({ name: "my-operation" });
1035
+ * langfuse.score.trace(
1036
+ * { otelSpan: span },
1037
+ * { name: "overall_quality", value: 0.88 }
1038
+ * );
1039
+ * ```
1040
+ */
753
1041
  trace(observation, data) {
754
1042
  const { traceId } = observation.otelSpan.spanContext();
755
1043
  this.create({
@@ -757,6 +1045,28 @@ var ScoreManager = class {
757
1045
  traceId
758
1046
  });
759
1047
  }
1048
+ /**
1049
+ * Creates a score for the currently active observation.
1050
+ *
1051
+ * This method automatically detects the active OpenTelemetry span and
1052
+ * creates an observation-level score. If no active span is found,
1053
+ * a warning is logged and the operation is skipped.
1054
+ *
1055
+ * @param data - Score data (traceId and observationId will be auto-populated)
1056
+ *
1057
+ * @example
1058
+ * ```typescript
1059
+ * import { startActiveSpan } from '@langfuse/tracing';
1060
+ *
1061
+ * startActiveSpan({ name: "my-operation" }, (span) => {
1062
+ * // Inside the active span
1063
+ * langfuse.score.activeObservation({
1064
+ * name: "relevance",
1065
+ * value: 0.95
1066
+ * });
1067
+ * });
1068
+ * ```
1069
+ */
760
1070
  activeObservation(data) {
761
1071
  const currentOtelSpan = import_api.trace.getActiveSpan();
762
1072
  if (!currentOtelSpan) {
@@ -770,6 +1080,29 @@ var ScoreManager = class {
770
1080
  observationId: spanId
771
1081
  });
772
1082
  }
1083
+ /**
1084
+ * Creates a score for the currently active trace.
1085
+ *
1086
+ * This method automatically detects the active OpenTelemetry span and
1087
+ * creates a trace-level score. If no active span is found,
1088
+ * a warning is logged and the operation is skipped.
1089
+ *
1090
+ * @param data - Score data (traceId will be auto-populated)
1091
+ *
1092
+ * @example
1093
+ * ```typescript
1094
+ * import { startActiveSpan } from '@langfuse/tracing';
1095
+ *
1096
+ * startActiveSpan({ name: "my-operation" }, (span) => {
1097
+ * // Inside the active span
1098
+ * langfuse.score.activeTrace({
1099
+ * name: "user_satisfaction",
1100
+ * value: 4,
1101
+ * comment: "User rated 4 out of 5 stars"
1102
+ * });
1103
+ * });
1104
+ * ```
1105
+ */
773
1106
  activeTrace(data) {
774
1107
  const currentOtelSpan = import_api.trace.getActiveSpan();
775
1108
  if (!currentOtelSpan) {
@@ -809,10 +1142,38 @@ var ScoreManager = class {
809
1142
  this.flushPromise = null;
810
1143
  }
811
1144
  }
1145
+ /**
1146
+ * Flushes all pending score events to the Langfuse API.
1147
+ *
1148
+ * This method ensures all queued scores are sent immediately rather than
1149
+ * waiting for the automatic flush interval or batch size threshold.
1150
+ *
1151
+ * @returns Promise that resolves when all pending scores have been sent
1152
+ *
1153
+ * @example
1154
+ * ```typescript
1155
+ * langfuse.score.create({ name: "quality", value: 0.8 });
1156
+ * await langfuse.score.flush(); // Ensures the score is sent immediately
1157
+ * ```
1158
+ */
812
1159
  async flush() {
813
1160
  var _a;
814
1161
  return (_a = this.flushPromise) != null ? _a : this.handleFlush();
815
1162
  }
1163
+ /**
1164
+ * Gracefully shuts down the score manager by flushing all pending scores.
1165
+ *
1166
+ * This method should be called before your application exits to ensure
1167
+ * all score data is sent to Langfuse.
1168
+ *
1169
+ * @returns Promise that resolves when shutdown is complete
1170
+ *
1171
+ * @example
1172
+ * ```typescript
1173
+ * // Before application exit
1174
+ * await langfuse.score.shutdown();
1175
+ * ```
1176
+ */
816
1177
  async shutdown() {
817
1178
  await this.flush();
818
1179
  }
@@ -820,6 +1181,26 @@ var ScoreManager = class {
820
1181
 
821
1182
  // src/LangfuseClient.ts
822
1183
  var LangfuseClient = class {
1184
+ /**
1185
+ * Creates a new LangfuseClient instance.
1186
+ *
1187
+ * @param params - Configuration parameters. If not provided, will use environment variables.
1188
+ *
1189
+ * @throws Will log warnings if required credentials are not provided
1190
+ *
1191
+ * @example
1192
+ * ```typescript
1193
+ * // With explicit configuration
1194
+ * const client = new LangfuseClient({
1195
+ * publicKey: "pk_...",
1196
+ * secretKey: "sk_...",
1197
+ * baseUrl: "https://your-instance.langfuse.com"
1198
+ * });
1199
+ *
1200
+ * // Using environment variables
1201
+ * const client = new LangfuseClient();
1202
+ * ```
1203
+ */
823
1204
  constructor(params) {
824
1205
  this.projectId = null;
825
1206
  var _a, _b, _c, _d, _e, _f, _g;
@@ -878,12 +1259,53 @@ var LangfuseClient = class {
878
1259
  this.fetchMedia = this.api.media.get;
879
1260
  this.resolveMediaReferences = this.media.resolveReferences;
880
1261
  }
1262
+ /**
1263
+ * Flushes any pending score events to the Langfuse API.
1264
+ *
1265
+ * This method ensures all queued scores are sent immediately rather than
1266
+ * waiting for the automatic flush interval or batch size threshold.
1267
+ *
1268
+ * @returns Promise that resolves when all pending scores have been sent
1269
+ *
1270
+ * @example
1271
+ * ```typescript
1272
+ * langfuse.score.create({ name: "quality", value: 0.8 });
1273
+ * await langfuse.flush(); // Ensures the score is sent immediately
1274
+ * ```
1275
+ */
881
1276
  async flush() {
882
1277
  return this.score.flush();
883
1278
  }
1279
+ /**
1280
+ * Gracefully shuts down the client by flushing all pending data.
1281
+ *
1282
+ * This method should be called before your application exits to ensure
1283
+ * all data is sent to Langfuse.
1284
+ *
1285
+ * @returns Promise that resolves when shutdown is complete
1286
+ *
1287
+ * @example
1288
+ * ```typescript
1289
+ * // Before application exit
1290
+ * await langfuse.shutdown();
1291
+ * ```
1292
+ */
884
1293
  async shutdown() {
885
1294
  return this.score.shutdown();
886
1295
  }
1296
+ /**
1297
+ * Generates a URL to view a specific trace in the Langfuse UI.
1298
+ *
1299
+ * @param traceId - The ID of the trace to generate a URL for
1300
+ * @returns Promise that resolves to the trace URL
1301
+ *
1302
+ * @example
1303
+ * ```typescript
1304
+ * const traceId = "trace-123";
1305
+ * const url = await langfuse.getTraceUrl(traceId);
1306
+ * console.log(`View trace at: ${url}`);
1307
+ * ```
1308
+ */
887
1309
  async getTraceUrl(traceId) {
888
1310
  let projectId = this.projectId;
889
1311
  if (!projectId) {