opik 0.0.4 → 0.0.6

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/README.md ADDED
@@ -0,0 +1,66 @@
1
+ <h1 align="center" style="border-bottom: none">
2
+ <div>
3
+ <a href="https://www.comet.com/site/products/opik/?from=llm&utm_source=opik&utm_medium=github&utm_content=header_img&utm_campaign=opik"><picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="/apps/opik-documentation/documentation/static/img/logo-dark-mode.svg">
5
+ <source media="(prefers-color-scheme: light)" srcset="/apps/opik-documentation/documentation/static/img/opik-logo.svg">
6
+ <img alt="Comet Opik logo" src="/apps/opik-documentation/documentation/static/img/opik-logo.svg" width="200" />
7
+ </picture></a>
8
+ <br>
9
+ Opik
10
+ </div>
11
+ Open source LLM evaluation framework<br>
12
+ </h1>
13
+
14
+ ## Installation
15
+
16
+ You can install the `opik` package using your favorite package manager.
17
+
18
+ ```bash
19
+ npm install opik
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```typescript
25
+ import { Opik } from "opik";
26
+
27
+ // Create a new Opik client with your configuration
28
+ const client = new Opik({
29
+ apiKey: "<your-api-key>",
30
+ host: "https://www.comet.com/opik/api",
31
+ projectName: "<your-project-name>",
32
+ workspaceName: "<your-workspace-name>",
33
+ });
34
+
35
+ // Log 10 traces
36
+ for (let i = 0; i < 10; i++) {
37
+ const someTrace = client.trace({
38
+ name: `Trace ${i}`,
39
+ });
40
+
41
+ // For each trace, log 10 spans
42
+ for (let j = 0; j < 10; j++) {
43
+ const someSpan = someTrace.span({
44
+ name: `Span ${i}-${j}`,
45
+ type: "llm",
46
+ });
47
+
48
+ // Mark the span as ended
49
+ someSpan.end();
50
+ }
51
+
52
+ // Mark the trace as ended
53
+ someTrace.end();
54
+ }
55
+
56
+ // Flush the client to send all traces and spans
57
+ await client.flush();
58
+ ```
59
+
60
+ ## Contributing
61
+
62
+ Contributions are welcome! If you have any suggestions or improvements, please feel free to open an [issue](https://github.com/comet-ml/opik/issues) or submit a [pull request](https://github.com/comet-ml/opik/pulls).
63
+
64
+ ## License
65
+
66
+ This project is licensed under the [Apache License 2.0](https://github.com/comet-ml/opik/blob/main/LICENSE).
@@ -0,0 +1,220 @@
1
+ import "./chunk-MLKGABMK.js";
2
+
3
+ // src/opik/rest_api/core/fetcher/stream-wrappers/Node18UniversalStreamWrapper.ts
4
+ var Node18UniversalStreamWrapper = class _Node18UniversalStreamWrapper {
5
+ readableStream;
6
+ reader;
7
+ events;
8
+ paused;
9
+ resumeCallback;
10
+ encoding;
11
+ constructor(readableStream) {
12
+ this.readableStream = readableStream;
13
+ this.reader = this.readableStream.getReader();
14
+ this.events = {
15
+ data: [],
16
+ end: [],
17
+ error: [],
18
+ readable: [],
19
+ close: [],
20
+ pause: [],
21
+ resume: []
22
+ };
23
+ this.paused = false;
24
+ this.resumeCallback = null;
25
+ this.encoding = null;
26
+ }
27
+ on(event, callback) {
28
+ this.events[event]?.push(callback);
29
+ }
30
+ off(event, callback) {
31
+ this.events[event] = this.events[event]?.filter((cb) => cb !== callback);
32
+ }
33
+ pipe(dest) {
34
+ this.on("data", async (chunk) => {
35
+ if (dest instanceof _Node18UniversalStreamWrapper) {
36
+ dest._write(chunk);
37
+ } else if (dest instanceof WritableStream) {
38
+ const writer = dest.getWriter();
39
+ writer.write(chunk).then(() => writer.releaseLock());
40
+ } else {
41
+ dest.write(chunk);
42
+ }
43
+ });
44
+ this.on("end", async () => {
45
+ if (dest instanceof _Node18UniversalStreamWrapper) {
46
+ dest._end();
47
+ } else if (dest instanceof WritableStream) {
48
+ const writer = dest.getWriter();
49
+ writer.close();
50
+ } else {
51
+ dest.end();
52
+ }
53
+ });
54
+ this.on("error", async (error) => {
55
+ if (dest instanceof _Node18UniversalStreamWrapper) {
56
+ dest._error(error);
57
+ } else if (dest instanceof WritableStream) {
58
+ const writer = dest.getWriter();
59
+ writer.abort(error);
60
+ } else {
61
+ dest.destroy(error);
62
+ }
63
+ });
64
+ this._startReading();
65
+ return dest;
66
+ }
67
+ pipeTo(dest) {
68
+ return this.pipe(dest);
69
+ }
70
+ unpipe(dest) {
71
+ this.off("data", async (chunk) => {
72
+ if (dest instanceof _Node18UniversalStreamWrapper) {
73
+ dest._write(chunk);
74
+ } else if (dest instanceof WritableStream) {
75
+ const writer = dest.getWriter();
76
+ writer.write(chunk).then(() => writer.releaseLock());
77
+ } else {
78
+ dest.write(chunk);
79
+ }
80
+ });
81
+ this.off("end", async () => {
82
+ if (dest instanceof _Node18UniversalStreamWrapper) {
83
+ dest._end();
84
+ } else if (dest instanceof WritableStream) {
85
+ const writer = dest.getWriter();
86
+ writer.close();
87
+ } else {
88
+ dest.end();
89
+ }
90
+ });
91
+ this.off("error", async (error) => {
92
+ if (dest instanceof _Node18UniversalStreamWrapper) {
93
+ dest._error(error);
94
+ } else if (dest instanceof WritableStream) {
95
+ const writer = dest.getWriter();
96
+ writer.abort(error);
97
+ } else {
98
+ dest.destroy(error);
99
+ }
100
+ });
101
+ }
102
+ destroy(error) {
103
+ this.reader.cancel(error).then(() => {
104
+ this._emit("close");
105
+ }).catch((err) => {
106
+ this._emit("error", err);
107
+ });
108
+ }
109
+ pause() {
110
+ this.paused = true;
111
+ this._emit("pause");
112
+ }
113
+ resume() {
114
+ if (this.paused) {
115
+ this.paused = false;
116
+ this._emit("resume");
117
+ if (this.resumeCallback) {
118
+ this.resumeCallback();
119
+ this.resumeCallback = null;
120
+ }
121
+ }
122
+ }
123
+ get isPaused() {
124
+ return this.paused;
125
+ }
126
+ async read() {
127
+ if (this.paused) {
128
+ await new Promise((resolve) => {
129
+ this.resumeCallback = resolve;
130
+ });
131
+ }
132
+ const { done, value } = await this.reader.read();
133
+ if (done) {
134
+ return void 0;
135
+ }
136
+ return value;
137
+ }
138
+ setEncoding(encoding) {
139
+ this.encoding = encoding;
140
+ }
141
+ async text() {
142
+ const chunks = [];
143
+ while (true) {
144
+ const { done, value } = await this.reader.read();
145
+ if (done) {
146
+ break;
147
+ }
148
+ if (value) {
149
+ chunks.push(value);
150
+ }
151
+ }
152
+ const decoder = new TextDecoder(this.encoding || "utf-8");
153
+ return decoder.decode(await new Blob(chunks).arrayBuffer());
154
+ }
155
+ async json() {
156
+ const text = await this.text();
157
+ return JSON.parse(text);
158
+ }
159
+ _write(chunk) {
160
+ this._emit("data", chunk);
161
+ }
162
+ _end() {
163
+ this._emit("end");
164
+ }
165
+ _error(error) {
166
+ this._emit("error", error);
167
+ }
168
+ _emit(event, data) {
169
+ if (this.events[event]) {
170
+ for (const callback of this.events[event] || []) {
171
+ callback(data);
172
+ }
173
+ }
174
+ }
175
+ async _startReading() {
176
+ try {
177
+ this._emit("readable");
178
+ while (true) {
179
+ if (this.paused) {
180
+ await new Promise((resolve) => {
181
+ this.resumeCallback = resolve;
182
+ });
183
+ }
184
+ const { done, value } = await this.reader.read();
185
+ if (done) {
186
+ this._emit("end");
187
+ this._emit("close");
188
+ break;
189
+ }
190
+ if (value) {
191
+ this._emit("data", value);
192
+ }
193
+ }
194
+ } catch (error) {
195
+ this._emit("error", error);
196
+ }
197
+ }
198
+ [Symbol.asyncIterator]() {
199
+ return {
200
+ next: async () => {
201
+ if (this.paused) {
202
+ await new Promise((resolve) => {
203
+ this.resumeCallback = resolve;
204
+ });
205
+ }
206
+ const { done, value } = await this.reader.read();
207
+ if (done) {
208
+ return { done: true, value: void 0 };
209
+ }
210
+ return { done: false, value };
211
+ },
212
+ [Symbol.asyncIterator]() {
213
+ return this;
214
+ }
215
+ };
216
+ }
217
+ };
218
+ export {
219
+ Node18UniversalStreamWrapper
220
+ };
@@ -0,0 +1,90 @@
1
+ import "./chunk-MLKGABMK.js";
2
+
3
+ // src/opik/rest_api/core/fetcher/stream-wrappers/NodePre18StreamWrapper.ts
4
+ var NodePre18StreamWrapper = class {
5
+ readableStream;
6
+ encoding;
7
+ constructor(readableStream) {
8
+ this.readableStream = readableStream;
9
+ }
10
+ on(event, callback) {
11
+ this.readableStream.on(event, callback);
12
+ }
13
+ off(event, callback) {
14
+ this.readableStream.off(event, callback);
15
+ }
16
+ pipe(dest) {
17
+ this.readableStream.pipe(dest);
18
+ return dest;
19
+ }
20
+ pipeTo(dest) {
21
+ return this.pipe(dest);
22
+ }
23
+ unpipe(dest) {
24
+ if (dest) {
25
+ this.readableStream.unpipe(dest);
26
+ } else {
27
+ this.readableStream.unpipe();
28
+ }
29
+ }
30
+ destroy(error) {
31
+ this.readableStream.destroy(error);
32
+ }
33
+ pause() {
34
+ this.readableStream.pause();
35
+ }
36
+ resume() {
37
+ this.readableStream.resume();
38
+ }
39
+ get isPaused() {
40
+ return this.readableStream.isPaused();
41
+ }
42
+ async read() {
43
+ return new Promise((resolve, reject) => {
44
+ const chunk = this.readableStream.read();
45
+ if (chunk) {
46
+ resolve(chunk);
47
+ } else {
48
+ this.readableStream.once("readable", () => {
49
+ const chunk2 = this.readableStream.read();
50
+ resolve(chunk2);
51
+ });
52
+ this.readableStream.once("error", reject);
53
+ }
54
+ });
55
+ }
56
+ setEncoding(encoding) {
57
+ this.readableStream.setEncoding(encoding);
58
+ this.encoding = encoding;
59
+ }
60
+ async text() {
61
+ const chunks = [];
62
+ const encoder = new TextEncoder();
63
+ this.readableStream.setEncoding(this.encoding || "utf-8");
64
+ for await (const chunk of this.readableStream) {
65
+ chunks.push(encoder.encode(chunk));
66
+ }
67
+ const decoder = new TextDecoder(this.encoding || "utf-8");
68
+ return decoder.decode(Buffer.concat(chunks));
69
+ }
70
+ async json() {
71
+ const text = await this.text();
72
+ return JSON.parse(text);
73
+ }
74
+ [Symbol.asyncIterator]() {
75
+ const readableStream = this.readableStream;
76
+ const iterator = readableStream[Symbol.asyncIterator]();
77
+ return {
78
+ async next() {
79
+ const { value, done } = await iterator.next();
80
+ return { value, done };
81
+ },
82
+ [Symbol.asyncIterator]() {
83
+ return this;
84
+ }
85
+ };
86
+ }
87
+ };
88
+ export {
89
+ NodePre18StreamWrapper
90
+ };
@@ -0,0 +1,208 @@
1
+ import "./chunk-MLKGABMK.js";
2
+
3
+ // src/opik/rest_api/core/fetcher/stream-wrappers/UndiciStreamWrapper.ts
4
+ var UndiciStreamWrapper = class _UndiciStreamWrapper {
5
+ readableStream;
6
+ reader;
7
+ events;
8
+ paused;
9
+ resumeCallback;
10
+ encoding;
11
+ constructor(readableStream) {
12
+ this.readableStream = readableStream;
13
+ this.reader = this.readableStream.getReader();
14
+ this.events = {
15
+ data: [],
16
+ end: [],
17
+ error: [],
18
+ readable: [],
19
+ close: [],
20
+ pause: [],
21
+ resume: []
22
+ };
23
+ this.paused = false;
24
+ this.resumeCallback = null;
25
+ this.encoding = null;
26
+ }
27
+ on(event, callback) {
28
+ this.events[event]?.push(callback);
29
+ }
30
+ off(event, callback) {
31
+ this.events[event] = this.events[event]?.filter((cb) => cb !== callback);
32
+ }
33
+ pipe(dest) {
34
+ this.on("data", (chunk) => {
35
+ if (dest instanceof _UndiciStreamWrapper) {
36
+ dest._write(chunk);
37
+ } else {
38
+ const writer = dest.getWriter();
39
+ writer.write(chunk).then(() => writer.releaseLock());
40
+ }
41
+ });
42
+ this.on("end", () => {
43
+ if (dest instanceof _UndiciStreamWrapper) {
44
+ dest._end();
45
+ } else {
46
+ const writer = dest.getWriter();
47
+ writer.close();
48
+ }
49
+ });
50
+ this.on("error", (error) => {
51
+ if (dest instanceof _UndiciStreamWrapper) {
52
+ dest._error(error);
53
+ } else {
54
+ const writer = dest.getWriter();
55
+ writer.abort(error);
56
+ }
57
+ });
58
+ this._startReading();
59
+ return dest;
60
+ }
61
+ pipeTo(dest) {
62
+ return this.pipe(dest);
63
+ }
64
+ unpipe(dest) {
65
+ this.off("data", (chunk) => {
66
+ if (dest instanceof _UndiciStreamWrapper) {
67
+ dest._write(chunk);
68
+ } else {
69
+ const writer = dest.getWriter();
70
+ writer.write(chunk).then(() => writer.releaseLock());
71
+ }
72
+ });
73
+ this.off("end", () => {
74
+ if (dest instanceof _UndiciStreamWrapper) {
75
+ dest._end();
76
+ } else {
77
+ const writer = dest.getWriter();
78
+ writer.close();
79
+ }
80
+ });
81
+ this.off("error", (error) => {
82
+ if (dest instanceof _UndiciStreamWrapper) {
83
+ dest._error(error);
84
+ } else {
85
+ const writer = dest.getWriter();
86
+ writer.abort(error);
87
+ }
88
+ });
89
+ }
90
+ destroy(error) {
91
+ this.reader.cancel(error).then(() => {
92
+ this._emit("close");
93
+ }).catch((err) => {
94
+ this._emit("error", err);
95
+ });
96
+ }
97
+ pause() {
98
+ this.paused = true;
99
+ this._emit("pause");
100
+ }
101
+ resume() {
102
+ if (this.paused) {
103
+ this.paused = false;
104
+ this._emit("resume");
105
+ if (this.resumeCallback) {
106
+ this.resumeCallback();
107
+ this.resumeCallback = null;
108
+ }
109
+ }
110
+ }
111
+ get isPaused() {
112
+ return this.paused;
113
+ }
114
+ async read() {
115
+ if (this.paused) {
116
+ await new Promise((resolve) => {
117
+ this.resumeCallback = resolve;
118
+ });
119
+ }
120
+ const { done, value } = await this.reader.read();
121
+ if (done) {
122
+ return void 0;
123
+ }
124
+ return value;
125
+ }
126
+ setEncoding(encoding) {
127
+ this.encoding = encoding;
128
+ }
129
+ async text() {
130
+ const chunks = [];
131
+ while (true) {
132
+ const { done, value } = await this.reader.read();
133
+ if (done) {
134
+ break;
135
+ }
136
+ if (value) {
137
+ chunks.push(value);
138
+ }
139
+ }
140
+ const decoder = new TextDecoder(this.encoding || "utf-8");
141
+ return decoder.decode(await new Blob(chunks).arrayBuffer());
142
+ }
143
+ async json() {
144
+ const text = await this.text();
145
+ return JSON.parse(text);
146
+ }
147
+ _write(chunk) {
148
+ this._emit("data", chunk);
149
+ }
150
+ _end() {
151
+ this._emit("end");
152
+ }
153
+ _error(error) {
154
+ this._emit("error", error);
155
+ }
156
+ _emit(event, data) {
157
+ if (this.events[event]) {
158
+ for (const callback of this.events[event] || []) {
159
+ callback(data);
160
+ }
161
+ }
162
+ }
163
+ async _startReading() {
164
+ try {
165
+ this._emit("readable");
166
+ while (true) {
167
+ if (this.paused) {
168
+ await new Promise((resolve) => {
169
+ this.resumeCallback = resolve;
170
+ });
171
+ }
172
+ const { done, value } = await this.reader.read();
173
+ if (done) {
174
+ this._emit("end");
175
+ this._emit("close");
176
+ break;
177
+ }
178
+ if (value) {
179
+ this._emit("data", value);
180
+ }
181
+ }
182
+ } catch (error) {
183
+ this._emit("error", error);
184
+ }
185
+ }
186
+ [Symbol.asyncIterator]() {
187
+ return {
188
+ next: async () => {
189
+ if (this.paused) {
190
+ await new Promise((resolve) => {
191
+ this.resumeCallback = resolve;
192
+ });
193
+ }
194
+ const { done, value } = await this.reader.read();
195
+ if (done) {
196
+ return { done: true, value: void 0 };
197
+ }
198
+ return { done: false, value };
199
+ },
200
+ [Symbol.asyncIterator]() {
201
+ return this;
202
+ }
203
+ };
204
+ }
205
+ };
206
+ export {
207
+ UndiciStreamWrapper
208
+ };
package/dist/index.cjs CHANGED
@@ -560,6 +560,7 @@ var init_NodePre18StreamWrapper = __esm({
560
560
  var index_exports = {};
561
561
  __export(index_exports, {
562
562
  Opik: () => OpikClient,
563
+ flushAll: () => flushAll,
563
564
  track: () => track,
564
565
  trackOpikClient: () => trackOpikClient,
565
566
  withTrack: () => withTrack
@@ -12100,6 +12101,7 @@ var Span2 = class {
12100
12101
  this.update = (updates) => {
12101
12102
  var _a;
12102
12103
  const spanUpdates = {
12104
+ parentSpanId: this.data.parentSpanId,
12103
12105
  projectName: (_a = this.data.projectName) != null ? _a : this.opik.config.projectName,
12104
12106
  traceId: this.data.traceId,
12105
12107
  ...updates
@@ -12284,12 +12286,7 @@ var SpanBatchQueue = class extends BatchQueue {
12284
12286
  this.api = api;
12285
12287
  }
12286
12288
  async createEntities(spans) {
12287
- const groupedSpans = groupSpansByDependency(spans);
12288
- for (const spansGroup of Object.values(groupedSpans)) {
12289
- await this.api.spans.createSpans({
12290
- spans: spansGroup
12291
- });
12292
- }
12289
+ await this.api.spans.createSpans({ spans });
12293
12290
  }
12294
12291
  async getEntity(id) {
12295
12292
  return await this.api.spans.getSpanById(id);
@@ -12303,32 +12300,6 @@ var SpanBatchQueue = class extends BatchQueue {
12303
12300
  }
12304
12301
  }
12305
12302
  };
12306
- function groupSpansByDependency(spans) {
12307
- const groups = [];
12308
- const executed = /* @__PURE__ */ new Set();
12309
- let remaining = [...spans];
12310
- while (remaining.length > 0) {
12311
- const executable = remaining.filter((span) => {
12312
- if (!span.parentSpanId) {
12313
- return true;
12314
- }
12315
- const parentExists = spans.some((s) => s.id === span.parentSpanId);
12316
- if (!parentExists) {
12317
- return true;
12318
- }
12319
- return executed.has(span.parentSpanId);
12320
- });
12321
- if (executable.length === 0) {
12322
- break;
12323
- }
12324
- groups.push(executable);
12325
- for (const span of executable) {
12326
- executed.add(span.id);
12327
- }
12328
- remaining = remaining.filter((span) => !executed.has(span.id));
12329
- }
12330
- return groups;
12331
- }
12332
12303
 
12333
12304
  // src/opik/client/TraceBatchQueue.ts
12334
12305
  var TraceBatchQueue = class extends BatchQueue {
@@ -12351,6 +12322,7 @@ var TraceBatchQueue = class extends BatchQueue {
12351
12322
  };
12352
12323
 
12353
12324
  // src/opik/client/Client.ts
12325
+ var clients = [];
12354
12326
  var OpikClient = class {
12355
12327
  constructor(explicitConfig) {
12356
12328
  this.trace = (traceData) => {
@@ -12380,6 +12352,7 @@ var OpikClient = class {
12380
12352
  });
12381
12353
  this.spanBatchQueue = new SpanBatchQueue(this.api);
12382
12354
  this.traceBatchQueue = new TraceBatchQueue(this.api);
12355
+ clients.push(this);
12383
12356
  }
12384
12357
  };
12385
12358
 
@@ -12389,6 +12362,28 @@ var trackStorage = new import_node_async_hooks.AsyncLocalStorage();
12389
12362
  function isPromise(obj) {
12390
12363
  return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
12391
12364
  }
12365
+ function logSpan({
12366
+ name,
12367
+ parentSpan,
12368
+ projectName,
12369
+ trace,
12370
+ type = "llm"
12371
+ }) {
12372
+ let spanTrace = trace;
12373
+ if (!spanTrace) {
12374
+ spanTrace = trackOpikClient.trace({
12375
+ name,
12376
+ projectName
12377
+ });
12378
+ }
12379
+ const span = spanTrace.span({
12380
+ name,
12381
+ parentSpanId: parentSpan == null ? void 0 : parentSpan.data.id,
12382
+ projectName,
12383
+ type
12384
+ });
12385
+ return { span, trace: spanTrace };
12386
+ }
12392
12387
  function withTrack({
12393
12388
  name,
12394
12389
  projectName,
@@ -12408,7 +12403,7 @@ function withTrack({
12408
12403
  const fnThis = this;
12409
12404
  return trackStorage.run({ span, trace }, () => {
12410
12405
  try {
12411
- const result = originalFn.call(fnThis, args);
12406
+ const result = originalFn.apply(fnThis, args);
12412
12407
  if (isPromise(result)) {
12413
12408
  return result.then(
12414
12409
  (res) => {
@@ -12444,42 +12439,37 @@ function withTrack({
12444
12439
  return wrappedFn;
12445
12440
  };
12446
12441
  }
12447
- function track({
12448
- name,
12449
- projectName,
12450
- type
12451
- } = {}) {
12452
- return function(target, propertyKey, descriptor) {
12442
+ function track(options = {}) {
12443
+ return function(...args) {
12444
+ if (args.length === 2 && typeof args[1] === "object" && args[1] !== null && "kind" in args[1]) {
12445
+ const [originalMethod2, context] = args;
12446
+ if (context.kind !== "method") {
12447
+ throw new Error("track decorator is only applicable to methods");
12448
+ }
12449
+ return withTrack(options)(originalMethod2);
12450
+ }
12451
+ const [target, propertyKey, descriptor] = args;
12452
+ if (!descriptor || typeof descriptor.value !== "function") {
12453
+ throw new Error("track decorator can only be applied to methods");
12454
+ }
12453
12455
  const originalMethod = descriptor.value;
12454
- descriptor.value = withTrack({ name, projectName, type })(descriptor.value);
12456
+ descriptor.value = withTrack(options)(originalMethod);
12457
+ return descriptor;
12455
12458
  };
12456
12459
  }
12457
- function logSpan({
12458
- name,
12459
- parentSpan,
12460
- projectName,
12461
- trace,
12462
- type = "llm"
12463
- }) {
12464
- let spanTrace = trace;
12465
- if (!spanTrace) {
12466
- spanTrace = trackOpikClient.trace({
12467
- name,
12468
- projectName
12469
- });
12470
- }
12471
- const span = spanTrace.span({
12472
- name,
12473
- parentSpanId: parentSpan == null ? void 0 : parentSpan.data.id,
12474
- projectName,
12475
- type
12476
- });
12477
- return { span, trace: spanTrace };
12478
- }
12479
12460
  var trackOpikClient = new OpikClient();
12461
+
12462
+ // src/opik/flushAll.ts
12463
+ var flushAll = async () => {
12464
+ await Promise.all([
12465
+ trackOpikClient.flush(),
12466
+ ...clients.map((c) => c.flush())
12467
+ ]);
12468
+ };
12480
12469
  // Annotate the CommonJS export names for ESM import in node:
12481
12470
  0 && (module.exports = {
12482
12471
  Opik,
12472
+ flushAll,
12483
12473
  track,
12484
12474
  trackOpikClient,
12485
12475
  withTrack
package/dist/index.d.cts CHANGED
@@ -4627,11 +4627,13 @@ declare function withTrack({ name, projectName, type, }?: {
4627
4627
  projectName?: string;
4628
4628
  type?: SpanType;
4629
4629
  }): <T extends (...args: any[]) => any>(originalFn: T) => T;
4630
- declare function track({ name, projectName, type, }?: {
4630
+ declare function track(options?: {
4631
4631
  name?: string;
4632
4632
  projectName?: string;
4633
4633
  type?: SpanType;
4634
- }): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
4634
+ }): (...args: any[]) => any;
4635
4635
  declare const trackOpikClient: OpikClient;
4636
4636
 
4637
- export { OpikClient as Opik, type OpikConfig, track, trackOpikClient, withTrack };
4637
+ declare const flushAll: () => Promise<void>;
4638
+
4639
+ export { OpikClient as Opik, type OpikConfig, flushAll, track, trackOpikClient, withTrack };
package/dist/index.d.ts CHANGED
@@ -4627,11 +4627,13 @@ declare function withTrack({ name, projectName, type, }?: {
4627
4627
  projectName?: string;
4628
4628
  type?: SpanType;
4629
4629
  }): <T extends (...args: any[]) => any>(originalFn: T) => T;
4630
- declare function track({ name, projectName, type, }?: {
4630
+ declare function track(options?: {
4631
4631
  name?: string;
4632
4632
  projectName?: string;
4633
4633
  type?: SpanType;
4634
- }): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
4634
+ }): (...args: any[]) => any;
4635
4635
  declare const trackOpikClient: OpikClient;
4636
4636
 
4637
- export { OpikClient as Opik, type OpikConfig, track, trackOpikClient, withTrack };
4637
+ declare const flushAll: () => Promise<void>;
4638
+
4639
+ export { OpikClient as Opik, type OpikConfig, flushAll, track, trackOpikClient, withTrack };
package/dist/index.js CHANGED
@@ -11536,6 +11536,7 @@ var Span2 = class {
11536
11536
  this.update = (updates) => {
11537
11537
  var _a;
11538
11538
  const spanUpdates = {
11539
+ parentSpanId: this.data.parentSpanId,
11539
11540
  projectName: (_a = this.data.projectName) != null ? _a : this.opik.config.projectName,
11540
11541
  traceId: this.data.traceId,
11541
11542
  ...updates
@@ -11720,12 +11721,7 @@ var SpanBatchQueue = class extends BatchQueue {
11720
11721
  this.api = api;
11721
11722
  }
11722
11723
  async createEntities(spans) {
11723
- const groupedSpans = groupSpansByDependency(spans);
11724
- for (const spansGroup of Object.values(groupedSpans)) {
11725
- await this.api.spans.createSpans({
11726
- spans: spansGroup
11727
- });
11728
- }
11724
+ await this.api.spans.createSpans({ spans });
11729
11725
  }
11730
11726
  async getEntity(id) {
11731
11727
  return await this.api.spans.getSpanById(id);
@@ -11739,32 +11735,6 @@ var SpanBatchQueue = class extends BatchQueue {
11739
11735
  }
11740
11736
  }
11741
11737
  };
11742
- function groupSpansByDependency(spans) {
11743
- const groups = [];
11744
- const executed = /* @__PURE__ */ new Set();
11745
- let remaining = [...spans];
11746
- while (remaining.length > 0) {
11747
- const executable = remaining.filter((span) => {
11748
- if (!span.parentSpanId) {
11749
- return true;
11750
- }
11751
- const parentExists = spans.some((s) => s.id === span.parentSpanId);
11752
- if (!parentExists) {
11753
- return true;
11754
- }
11755
- return executed.has(span.parentSpanId);
11756
- });
11757
- if (executable.length === 0) {
11758
- break;
11759
- }
11760
- groups.push(executable);
11761
- for (const span of executable) {
11762
- executed.add(span.id);
11763
- }
11764
- remaining = remaining.filter((span) => !executed.has(span.id));
11765
- }
11766
- return groups;
11767
- }
11768
11738
 
11769
11739
  // src/opik/client/TraceBatchQueue.ts
11770
11740
  var TraceBatchQueue = class extends BatchQueue {
@@ -11787,6 +11757,7 @@ var TraceBatchQueue = class extends BatchQueue {
11787
11757
  };
11788
11758
 
11789
11759
  // src/opik/client/Client.ts
11760
+ var clients = [];
11790
11761
  var OpikClient = class {
11791
11762
  constructor(explicitConfig) {
11792
11763
  this.trace = (traceData) => {
@@ -11816,6 +11787,7 @@ var OpikClient = class {
11816
11787
  });
11817
11788
  this.spanBatchQueue = new SpanBatchQueue(this.api);
11818
11789
  this.traceBatchQueue = new TraceBatchQueue(this.api);
11790
+ clients.push(this);
11819
11791
  }
11820
11792
  };
11821
11793
 
@@ -11825,6 +11797,28 @@ var trackStorage = new AsyncLocalStorage();
11825
11797
  function isPromise(obj) {
11826
11798
  return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
11827
11799
  }
11800
+ function logSpan({
11801
+ name,
11802
+ parentSpan,
11803
+ projectName,
11804
+ trace,
11805
+ type = "llm"
11806
+ }) {
11807
+ let spanTrace = trace;
11808
+ if (!spanTrace) {
11809
+ spanTrace = trackOpikClient.trace({
11810
+ name,
11811
+ projectName
11812
+ });
11813
+ }
11814
+ const span = spanTrace.span({
11815
+ name,
11816
+ parentSpanId: parentSpan == null ? void 0 : parentSpan.data.id,
11817
+ projectName,
11818
+ type
11819
+ });
11820
+ return { span, trace: spanTrace };
11821
+ }
11828
11822
  function withTrack({
11829
11823
  name,
11830
11824
  projectName,
@@ -11844,7 +11838,7 @@ function withTrack({
11844
11838
  const fnThis = this;
11845
11839
  return trackStorage.run({ span, trace }, () => {
11846
11840
  try {
11847
- const result = originalFn.call(fnThis, args);
11841
+ const result = originalFn.apply(fnThis, args);
11848
11842
  if (isPromise(result)) {
11849
11843
  return result.then(
11850
11844
  (res) => {
@@ -11880,41 +11874,36 @@ function withTrack({
11880
11874
  return wrappedFn;
11881
11875
  };
11882
11876
  }
11883
- function track({
11884
- name,
11885
- projectName,
11886
- type
11887
- } = {}) {
11888
- return function(target, propertyKey, descriptor) {
11877
+ function track(options = {}) {
11878
+ return function(...args) {
11879
+ if (args.length === 2 && typeof args[1] === "object" && args[1] !== null && "kind" in args[1]) {
11880
+ const [originalMethod2, context] = args;
11881
+ if (context.kind !== "method") {
11882
+ throw new Error("track decorator is only applicable to methods");
11883
+ }
11884
+ return withTrack(options)(originalMethod2);
11885
+ }
11886
+ const [target, propertyKey, descriptor] = args;
11887
+ if (!descriptor || typeof descriptor.value !== "function") {
11888
+ throw new Error("track decorator can only be applied to methods");
11889
+ }
11889
11890
  const originalMethod = descriptor.value;
11890
- descriptor.value = withTrack({ name, projectName, type })(descriptor.value);
11891
+ descriptor.value = withTrack(options)(originalMethod);
11892
+ return descriptor;
11891
11893
  };
11892
11894
  }
11893
- function logSpan({
11894
- name,
11895
- parentSpan,
11896
- projectName,
11897
- trace,
11898
- type = "llm"
11899
- }) {
11900
- let spanTrace = trace;
11901
- if (!spanTrace) {
11902
- spanTrace = trackOpikClient.trace({
11903
- name,
11904
- projectName
11905
- });
11906
- }
11907
- const span = spanTrace.span({
11908
- name,
11909
- parentSpanId: parentSpan == null ? void 0 : parentSpan.data.id,
11910
- projectName,
11911
- type
11912
- });
11913
- return { span, trace: spanTrace };
11914
- }
11915
11895
  var trackOpikClient = new OpikClient();
11896
+
11897
+ // src/opik/flushAll.ts
11898
+ var flushAll = async () => {
11899
+ await Promise.all([
11900
+ trackOpikClient.flush(),
11901
+ ...clients.map((c) => c.flush())
11902
+ ]);
11903
+ };
11916
11904
  export {
11917
11905
  OpikClient as Opik,
11906
+ flushAll,
11918
11907
  track,
11919
11908
  trackOpikClient,
11920
11909
  withTrack
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opik",
3
3
  "description": "Opik TypeScript and JavaScript SDK",
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/comet-ml/opik.git",
@@ -28,7 +28,8 @@
28
28
  "comet"
29
29
  ],
30
30
  "files": [
31
- "dist/**/*"
31
+ "dist/**/*",
32
+ "README.md"
32
33
  ],
33
34
  "exports": {
34
35
  "./package.json": "./package.json",