@lmnr-ai/lmnr 0.4.21 → 0.4.23

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/src/laminar.ts CHANGED
@@ -3,7 +3,8 @@ import {
3
3
  PipelineRunRequest,
4
4
  EvaluationDatapoint,
5
5
  CreateEvaluationResponse,
6
- GetDatapointsResponse
6
+ GetDatapointsResponse,
7
+ SemanticSearchResponse
7
8
  } from './types';
8
9
  import {
9
10
  Attributes,
@@ -228,6 +229,46 @@ export class Laminar {
228
229
  }
229
230
  }
230
231
 
232
+ /**
233
+ * Perform a semantic search on a dataset.
234
+ *
235
+ * @param query - The query string to search with.
236
+ * @param datasetId - The ID of the dataset to search in.
237
+ * @param limit - The maximum number of results to return.
238
+ * @param threshold - The minimum score for the results to be returned.
239
+ * @returns Response object containing the search results in descending order of relevance.
240
+ */
241
+ public static async semanticSearch({
242
+ query,
243
+ datasetId,
244
+ limit,
245
+ threshold,
246
+ }: {
247
+ query: string,
248
+ datasetId: string,
249
+ limit?: number,
250
+ threshold?: number,
251
+ }): Promise<SemanticSearchResponse> {
252
+ const body = JSON.stringify({
253
+ query,
254
+ datasetId,
255
+ limit,
256
+ threshold,
257
+ });
258
+
259
+ const response = await fetch(`${this.baseHttpUrl}/v1/semantic-search`, {
260
+ method: 'POST',
261
+ headers: this.getHeaders(),
262
+ body,
263
+ });
264
+
265
+ if (!response.ok) {
266
+ throw new Error(`Failed to perform semantic search. Response: ${response.statusText}`);
267
+ }
268
+
269
+ return await response.json() as SemanticSearchResponse;
270
+ }
271
+
231
272
  /**
232
273
  * Associates an event with the current span. If event with such name never
233
274
  * existed, Laminar will create a new event and infer its type from the value.
@@ -269,51 +310,90 @@ export class Laminar {
269
310
 
270
311
  /**
271
312
  * Sets the session information for the current span and returns the
272
- * context to use for the following spans.
313
+ * context to use for the following spans. Returns the result of the
314
+ * function execution, so can be used in an `await` statement.
273
315
  *
274
316
  * @param sessionId - The session ID to associate with the context.
275
- * @param userId - The user ID to associate with the context.
276
- * @returns The updated context with the association properties.
317
+ * @param fn - Function to execute within the session context.
318
+ * @returns The result of the function execution.
277
319
  *
278
320
  * @example
279
- * import { context as contextApi } from '@opentelemetry/api';
280
- * import { Laminar } from '@lmnr-ai/laminar';
281
- * const context = Laminar.contextWithSession({ sessionId: "1234", userId: "5678" });
282
- * contextApi.with(context, () => {
283
- * // Your code here
321
+ * import { Laminar, observe } from '@lmnr-ai/lmnr';
322
+ * const result = await Laminar.withSession("session1234", async () => {
323
+ * // Your code here
284
324
  * });
285
325
  */
286
- public static contextWithSession({
287
- sessionId,
288
- userId
289
- }: { sessionId?: string, userId?: string }): Context {
326
+ public static withSession<T>(
327
+ sessionId: string,
328
+ fn: () => T,
329
+ ): T {
290
330
  const currentSpan = trace.getActiveSpan();
291
331
  if (currentSpan !== undefined && isSpanContextValid(currentSpan.spanContext())) {
292
332
  if (sessionId) {
293
- currentSpan.setAttribute(SESSION_ID, sessionId);
294
- }
295
- if (userId) {
296
- currentSpan.setAttribute(USER_ID, userId);
333
+ currentSpan.setAttribute(SESSION_ID, JSON.stringify(sessionId));
297
334
  }
298
335
  }
299
336
  let associationProperties = {};
300
337
  if (sessionId) {
301
- associationProperties = { ...associationProperties, "session_id": sessionId };
302
- }
303
- if (userId) {
304
- associationProperties = { ...associationProperties, "user_id": userId };
338
+ associationProperties = { ...associationProperties, "session_id": JSON.stringify(sessionId) };
305
339
  }
306
340
 
307
341
  let entityContext = contextApi.active();
308
342
  const currentAssociationProperties = entityContext.getValue(ASSOCIATION_PROPERTIES_KEY);
309
- if (associationProperties) {
343
+ if (associationProperties && Object.keys(associationProperties).length > 0) {
310
344
  entityContext = entityContext.setValue(
311
345
  ASSOCIATION_PROPERTIES_KEY,
312
346
  { ...(currentAssociationProperties ?? {}), ...associationProperties },
313
347
  );
314
348
  }
349
+ return contextApi.with(entityContext, fn);
350
+ }
351
+
352
+ /**
353
+ * Sets the metadata for the current span and returns the context to use for
354
+ * the following spans. Returns the result of the function execution, so can
355
+ * be used in an `await` statement.
356
+ *
357
+ * @param metadata - The metadata to associate with the context. Set of string key
358
+ * string value pairs.
359
+ * @param fn - Function to execute within the metadata context.
360
+ * @returns The result of the function execution.
361
+ *
362
+ * @example
363
+ * import { Laminar } from '@lmnr-ai/lmnr';
364
+ * const result = await Laminar.withMetadata(
365
+ * {
366
+ * "my_metadata_key": "my_metadata_value"
367
+ * },
368
+ * async () => {
369
+ * // Your code here
370
+ * }
371
+ * );
372
+ */
373
+ public static withMetadata<T>(
374
+ metadata: Record<string, string>,
375
+ fn: () => T,
376
+ ): T {
377
+ const currentSpan = trace.getActiveSpan();
378
+ if (currentSpan !== undefined && isSpanContextValid(currentSpan.spanContext())) {
379
+ for (const [key, value] of Object.entries(metadata)) {
380
+ currentSpan.setAttribute(`${ASSOCIATION_PROPERTIES}.metadata.${key}`, JSON.stringify(value));
381
+ }
382
+ }
383
+ let metadataAttributes = {};
384
+ for (const [key, value] of Object.entries(metadata)) {
385
+ metadataAttributes = { ...metadataAttributes, [`metadata.${key}`]: JSON.stringify(value) };
386
+ }
315
387
 
316
- return entityContext;
388
+ let entityContext = contextApi.active();
389
+ const currentAssociationProperties = entityContext.getValue(ASSOCIATION_PROPERTIES_KEY);
390
+ if (metadataAttributes && Object.keys(metadataAttributes).length > 0) {
391
+ entityContext = entityContext.setValue(
392
+ ASSOCIATION_PROPERTIES_KEY,
393
+ { ...(currentAssociationProperties ?? {}), ...metadataAttributes },
394
+ );
395
+ }
396
+ return contextApi.with(entityContext, fn);
317
397
  }
318
398
 
319
399
  /**
package/src/types.ts CHANGED
@@ -62,6 +62,17 @@ export type GetDatapointsResponse<D, T> = {
62
62
  anyInProject: boolean;
63
63
  }
64
64
 
65
+ export type SemanticSearchResult = {
66
+ datasetId: StringUUID;
67
+ data: Record<string, any>;
68
+ content: string;
69
+ score: number;
70
+ }
71
+
72
+ export type SemanticSearchResponse = {
73
+ results: SemanticSearchResult[];
74
+ }
75
+
65
76
  /**
66
77
  * Span types to categorize spans.
67
78
  *