lupislabs 1.0.0 → 1.0.1

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.
Files changed (60) hide show
  1. package/README.md +221 -359
  2. package/dist/cost-utils.d.ts +5 -0
  3. package/dist/cost-utils.d.ts.map +1 -0
  4. package/dist/cost-utils.js +51 -0
  5. package/dist/cost-utils.js.map +1 -0
  6. package/dist/endpoints.d.ts +2 -0
  7. package/dist/endpoints.d.ts.map +1 -0
  8. package/dist/endpoints.js +2 -0
  9. package/dist/endpoints.js.map +1 -0
  10. package/dist/http-interceptor.d.ts +18 -8
  11. package/dist/http-interceptor.d.ts.map +1 -1
  12. package/dist/http-interceptor.js +164 -416
  13. package/dist/http-interceptor.js.map +1 -1
  14. package/dist/index.d.ts +33 -6
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +96 -8
  17. package/dist/index.js.map +1 -1
  18. package/dist/interceptors/axios-interceptor.d.ts +18 -0
  19. package/dist/interceptors/axios-interceptor.d.ts.map +1 -0
  20. package/dist/interceptors/axios-interceptor.js +115 -0
  21. package/dist/interceptors/axios-interceptor.js.map +1 -0
  22. package/dist/interceptors/fetch-interceptor.d.ts +18 -0
  23. package/dist/interceptors/fetch-interceptor.d.ts.map +1 -0
  24. package/dist/interceptors/fetch-interceptor.js +228 -0
  25. package/dist/interceptors/fetch-interceptor.js.map +1 -0
  26. package/dist/interceptors/got-interceptor.d.ts +18 -0
  27. package/dist/interceptors/got-interceptor.d.ts.map +1 -0
  28. package/dist/interceptors/got-interceptor.js +103 -0
  29. package/dist/interceptors/got-interceptor.js.map +1 -0
  30. package/dist/interceptors/node-http-interceptor.d.ts +21 -0
  31. package/dist/interceptors/node-http-interceptor.d.ts.map +1 -0
  32. package/dist/interceptors/node-http-interceptor.js +301 -0
  33. package/dist/interceptors/node-http-interceptor.js.map +1 -0
  34. package/dist/providers/anthropic-handler.d.ts +3 -0
  35. package/dist/providers/anthropic-handler.d.ts.map +1 -0
  36. package/dist/providers/anthropic-handler.js +50 -0
  37. package/dist/providers/anthropic-handler.js.map +1 -0
  38. package/dist/providers/openai-handler.d.ts +3 -0
  39. package/dist/providers/openai-handler.d.ts.map +1 -0
  40. package/dist/providers/openai-handler.js +46 -0
  41. package/dist/providers/openai-handler.js.map +1 -0
  42. package/dist/providers/provider-detector.d.ts +4 -0
  43. package/dist/providers/provider-detector.d.ts.map +1 -0
  44. package/dist/providers/provider-detector.js +27 -0
  45. package/dist/providers/provider-detector.js.map +1 -0
  46. package/dist/sensitive-data-filter.d.ts +20 -0
  47. package/dist/sensitive-data-filter.d.ts.map +1 -0
  48. package/dist/sensitive-data-filter.js +280 -0
  49. package/dist/sensitive-data-filter.js.map +1 -0
  50. package/dist/trace-collector.d.ts +40 -0
  51. package/dist/trace-collector.d.ts.map +1 -0
  52. package/dist/trace-collector.js +59 -0
  53. package/dist/trace-collector.js.map +1 -0
  54. package/dist/tracer.d.ts +30 -7
  55. package/dist/tracer.d.ts.map +1 -1
  56. package/dist/tracer.js +76 -70
  57. package/dist/tracer.js.map +1 -1
  58. package/dist/types.d.ts +82 -6
  59. package/dist/types.d.ts.map +1 -1
  60. package/package.json +3 -17
@@ -0,0 +1,280 @@
1
+ export class SensitiveDataFilterUtil {
2
+ constructor(filter) {
3
+ this.defaultPatterns = [
4
+ // API Keys
5
+ 'sk-[a-zA-Z0-9]{20,}',
6
+ 'pk_[a-zA-Z0-9]{20,}',
7
+ 'ak-[a-zA-Z0-9]{20,}',
8
+ 'Bearer [a-zA-Z0-9._-]+',
9
+ 'x-api-key',
10
+ 'authorization',
11
+ // Tokens
12
+ 'token\\b',
13
+ 'access_token',
14
+ 'refresh_token',
15
+ 'session_token',
16
+ // Passwords
17
+ 'password',
18
+ 'passwd',
19
+ 'pwd',
20
+ // Secrets
21
+ 'secret',
22
+ 'private_key',
23
+ 'privateKey',
24
+ 'api_secret',
25
+ 'apiSecret',
26
+ // Personal Data
27
+ 'ssn',
28
+ 'social_security',
29
+ 'credit_card',
30
+ 'card_number',
31
+ 'cvv',
32
+ 'cvc',
33
+ // Email patterns (optional - can be configured)
34
+ // 'email',
35
+ // 'email_address',
36
+ ];
37
+ this.MAX_BODY_LENGTH = 100000;
38
+ this.filter = {
39
+ filterSensitiveData: filter.filterSensitiveData ?? true,
40
+ sensitiveDataPatterns: filter.sensitiveDataPatterns && filter.sensitiveDataPatterns.length > 0
41
+ ? filter.sensitiveDataPatterns
42
+ : this.defaultPatterns,
43
+ redactionMode: filter.redactionMode ?? 'mask',
44
+ };
45
+ }
46
+ filterObject(obj) {
47
+ if (!this.filter.filterSensitiveData) {
48
+ return obj;
49
+ }
50
+ if (typeof obj === 'string') {
51
+ return this.filterString(obj);
52
+ }
53
+ if (Array.isArray(obj)) {
54
+ return obj.map(item => this.filterObject(item));
55
+ }
56
+ if (obj && typeof obj === 'object') {
57
+ const filtered = {};
58
+ for (const [key, value] of Object.entries(obj)) {
59
+ if (this.isSensitiveKey(key)) {
60
+ filtered[key] = this.getRedactedValue();
61
+ }
62
+ else {
63
+ filtered[key] = this.filterObject(value);
64
+ }
65
+ }
66
+ return filtered;
67
+ }
68
+ return obj;
69
+ }
70
+ sanitizeRequestBody(body) {
71
+ const normalized = this.normalizeBodyToString(body);
72
+ if (normalized == null) {
73
+ return undefined;
74
+ }
75
+ const filtered = this.filterRequestBody(normalized);
76
+ return this.truncateBody(filtered);
77
+ }
78
+ sanitizeResponseBody(body) {
79
+ const normalized = this.normalizeBodyToString(body);
80
+ if (normalized == null) {
81
+ return undefined;
82
+ }
83
+ const filtered = this.filterResponseBody(normalized);
84
+ return this.truncateBody(filtered);
85
+ }
86
+ filterString(str) {
87
+ if (!this.filter.filterSensitiveData) {
88
+ return str;
89
+ }
90
+ let filtered = str;
91
+ for (const pattern of this.filter.sensitiveDataPatterns) {
92
+ const regex = new RegExp(pattern, 'gi');
93
+ filtered = filtered.replace(regex, (match) => {
94
+ return this.getRedactedValue(match);
95
+ });
96
+ }
97
+ return filtered;
98
+ }
99
+ isSensitiveKey(key) {
100
+ const lowerKey = key.toLowerCase();
101
+ return this.filter.sensitiveDataPatterns.some(pattern => {
102
+ // Check if key matches pattern (case insensitive)
103
+ const regex = new RegExp(pattern, 'i');
104
+ return regex.test(lowerKey);
105
+ });
106
+ }
107
+ getRedactedValue(original) {
108
+ switch (this.filter.redactionMode) {
109
+ case 'remove':
110
+ return '[REDACTED]';
111
+ case 'hash':
112
+ if (original) {
113
+ // Simple hash for debugging (not cryptographically secure)
114
+ let hash = 0;
115
+ for (let i = 0; i < original.length; i++) {
116
+ const char = original.charCodeAt(i);
117
+ hash = ((hash << 5) - hash) + char;
118
+ hash = hash & hash; // Convert to 32-bit integer
119
+ }
120
+ return `[HASH:${Math.abs(hash).toString(16)}]`;
121
+ }
122
+ return '[HASHED]';
123
+ case 'mask':
124
+ default:
125
+ if (original && original.length > 8) {
126
+ // Show first 4 and last 4 characters
127
+ const start = original.substring(0, 4);
128
+ const end = original.substring(original.length - 4);
129
+ return `${start}***${end}`;
130
+ }
131
+ return '***';
132
+ }
133
+ }
134
+ truncateBody(body) {
135
+ if (body.length > this.MAX_BODY_LENGTH) {
136
+ return `${body.slice(0, this.MAX_BODY_LENGTH)}...[truncated]`;
137
+ }
138
+ return body;
139
+ }
140
+ normalizeToString(value) {
141
+ if (value === undefined || value === null) {
142
+ return '';
143
+ }
144
+ if (typeof value === 'string') {
145
+ return value;
146
+ }
147
+ if (typeof value === 'number' || typeof value === 'boolean') {
148
+ return String(value);
149
+ }
150
+ if (Array.isArray(value)) {
151
+ return value.map(item => this.normalizeToString(item)).join(', ');
152
+ }
153
+ if (typeof value === 'object') {
154
+ try {
155
+ return JSON.stringify(value);
156
+ }
157
+ catch {
158
+ try {
159
+ return String(value);
160
+ }
161
+ catch {
162
+ return '';
163
+ }
164
+ }
165
+ }
166
+ try {
167
+ return String(value);
168
+ }
169
+ catch {
170
+ return '';
171
+ }
172
+ }
173
+ normalizeBodyToString(value) {
174
+ if (value === undefined || value === null) {
175
+ return undefined;
176
+ }
177
+ if (typeof value === 'string') {
178
+ return value;
179
+ }
180
+ if (typeof value === 'number' || typeof value === 'boolean') {
181
+ return String(value);
182
+ }
183
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer && Buffer.isBuffer(value)) {
184
+ return value.toString('utf8');
185
+ }
186
+ if (typeof Uint8Array !== 'undefined' && value instanceof Uint8Array) {
187
+ try {
188
+ if (typeof TextDecoder !== 'undefined') {
189
+ const decoder = new TextDecoder();
190
+ return decoder.decode(value);
191
+ }
192
+ }
193
+ catch {
194
+ }
195
+ try {
196
+ return Buffer.from(value).toString('utf8');
197
+ }
198
+ catch {
199
+ return undefined;
200
+ }
201
+ }
202
+ if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
203
+ try {
204
+ return Buffer.from(value).toString('utf8');
205
+ }
206
+ catch {
207
+ try {
208
+ return String(value);
209
+ }
210
+ catch {
211
+ return undefined;
212
+ }
213
+ }
214
+ }
215
+ if (typeof value === 'object') {
216
+ const ctorName = value?.constructor?.name;
217
+ if (ctorName === 'URLSearchParams') {
218
+ try {
219
+ return value.toString();
220
+ }
221
+ catch {
222
+ }
223
+ }
224
+ try {
225
+ return JSON.stringify(value);
226
+ }
227
+ catch {
228
+ try {
229
+ return String(value);
230
+ }
231
+ catch {
232
+ return undefined;
233
+ }
234
+ }
235
+ }
236
+ try {
237
+ return String(value);
238
+ }
239
+ catch {
240
+ return undefined;
241
+ }
242
+ }
243
+ filterHeaders(headers) {
244
+ if (!this.filter.filterSensitiveData) {
245
+ const normalizedHeaders = {};
246
+ for (const [key, value] of Object.entries(headers)) {
247
+ normalizedHeaders[key] = this.normalizeToString(value);
248
+ }
249
+ return normalizedHeaders;
250
+ }
251
+ const filtered = {};
252
+ for (const [key, value] of Object.entries(headers)) {
253
+ if (this.isSensitiveKey(key)) {
254
+ filtered[key] = this.getRedactedValue(typeof value === 'string' ? value : this.normalizeToString(value));
255
+ }
256
+ else {
257
+ filtered[key] = this.filterString(this.normalizeToString(value));
258
+ }
259
+ }
260
+ return filtered;
261
+ }
262
+ filterRequestBody(body) {
263
+ if (!this.filter.filterSensitiveData) {
264
+ return body;
265
+ }
266
+ try {
267
+ const parsed = JSON.parse(body);
268
+ const filtered = this.filterObject(parsed);
269
+ return JSON.stringify(filtered);
270
+ }
271
+ catch {
272
+ // If not JSON, filter as string
273
+ return this.filterString(body);
274
+ }
275
+ }
276
+ filterResponseBody(body) {
277
+ return this.filterRequestBody(body); // Same logic for request/response
278
+ }
279
+ }
280
+ //# sourceMappingURL=sensitive-data-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sensitive-data-filter.js","sourceRoot":"","sources":["../src/sensitive-data-filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { LupisMetadata } from './types.js';
2
+ export interface HttpTrace {
3
+ id: string;
4
+ projectId: string;
5
+ timestamp: number;
6
+ type: 'http_request';
7
+ duration: number;
8
+ url: string;
9
+ method: string;
10
+ statusCode: number;
11
+ provider: string;
12
+ requestHeaders?: Record<string, string>;
13
+ responseHeaders?: Record<string, string>;
14
+ tokenUsage?: any;
15
+ costBreakdown?: any;
16
+ model?: string;
17
+ chatId?: string;
18
+ metadata?: LupisMetadata;
19
+ requestBody?: string;
20
+ responseBody?: string;
21
+ error?: string;
22
+ }
23
+ export declare class TraceCollector {
24
+ private inFlight;
25
+ private endpoint;
26
+ private projectId;
27
+ private apiKey?;
28
+ private enabled;
29
+ constructor(config: {
30
+ endpoint?: string;
31
+ projectId: string;
32
+ apiKey?: string;
33
+ enabled?: boolean;
34
+ });
35
+ addTrace(trace: HttpTrace): void;
36
+ private sendTrace;
37
+ forceFlush(): Promise<void>;
38
+ shutdown(): Promise<void>;
39
+ }
40
+ //# sourceMappingURL=trace-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-collector.d.ts","sourceRoot":"","sources":["../src/trace-collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,OAAO,CAAU;gBAEb,MAAM,EAAE;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB;IAOD,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;YASlB,SAAS;IAiCjB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGhC"}
@@ -0,0 +1,59 @@
1
+ import { DEFAULT_TRACES_ENDPOINT } from './endpoints.js';
2
+ export class TraceCollector {
3
+ constructor(config) {
4
+ this.inFlight = new Set();
5
+ this.endpoint = config.endpoint ?? DEFAULT_TRACES_ENDPOINT;
6
+ this.projectId = config.projectId;
7
+ this.apiKey = config.apiKey;
8
+ this.enabled = config.enabled !== false;
9
+ }
10
+ addTrace(trace) {
11
+ console.log(`[Lupis SDK] Sending trace: ${trace.method} ${trace.url}`);
12
+ const sendPromise = this.sendTrace(trace);
13
+ this.inFlight.add(sendPromise);
14
+ sendPromise.finally(() => {
15
+ this.inFlight.delete(sendPromise);
16
+ });
17
+ }
18
+ async sendTrace(trace) {
19
+ if (!this.enabled) {
20
+ console.log('[Lupis SDK] Trace (not sent, disabled)');
21
+ return;
22
+ }
23
+ try {
24
+ const headers = {
25
+ 'Content-Type': 'application/json',
26
+ 'x-project-id': this.projectId,
27
+ };
28
+ if (this.apiKey) {
29
+ headers['x-api-key'] = this.apiKey;
30
+ }
31
+ const response = await fetch(this.endpoint, {
32
+ method: 'POST',
33
+ headers,
34
+ body: JSON.stringify(trace),
35
+ });
36
+ if (!response.ok) {
37
+ const error = await response.text();
38
+ console.error('[Lupis SDK] Failed to send trace:', error);
39
+ }
40
+ else {
41
+ console.log('[Lupis SDK] Successfully sent trace');
42
+ }
43
+ }
44
+ catch (error) {
45
+ console.error('[Lupis SDK] Error sending trace:', error);
46
+ }
47
+ }
48
+ async forceFlush() {
49
+ if (this.inFlight.size === 0) {
50
+ return;
51
+ }
52
+ const pending = Array.from(this.inFlight);
53
+ await Promise.allSettled(pending);
54
+ }
55
+ async shutdown() {
56
+ await this.forceFlush();
57
+ }
58
+ }
59
+ //# sourceMappingURL=trace-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-collector.js","sourceRoot":"","sources":["../src/trace-collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAyBzD,MAAM,OAAO,cAAc;IAOzB,YAAY,MAKX;QAXO,aAAQ,GAAG,IAAI,GAAG,EAAiB,CAAC;QAY1C,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,uBAAuB,CAAC;QAC3D,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,KAAK,KAAK,CAAC;IAC1C,CAAC;IAED,QAAQ,CAAC,KAAgB;QACvB,OAAO,CAAC,GAAG,CAAC,8BAA8B,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACvE,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/B,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE;YACvB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,KAAgB;QACtC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAA2B;gBACtC,cAAc,EAAE,kBAAkB;gBAClC,cAAc,EAAE,IAAI,CAAC,SAAS;aAC/B,CAAC;YAEF,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;YACrC,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE;gBAC1C,MAAM,EAAE,MAAM;gBACd,OAAO;gBACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;aAC5B,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;YAC5D,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,KAAK,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;IAC1B,CAAC;CACF"}
package/dist/tracer.d.ts CHANGED
@@ -1,21 +1,44 @@
1
- import * as api from '@opentelemetry/api';
1
+ import { LupisMetadata, ConversationContext, MessageData, ToolCallData } from './types.js';
2
2
  export declare class LupisTracer {
3
- private provider;
4
- private tracer;
5
- private chatIdProcessor;
3
+ private traceCollector;
6
4
  private httpInterceptor;
7
5
  private projectId;
6
+ private conversationTracker;
8
7
  constructor(config: {
9
8
  projectId: string;
9
+ apiKey?: string;
10
10
  enabled?: boolean;
11
- otlpEndpoint?: string;
12
11
  serviceName?: string;
13
12
  serviceVersion?: string;
13
+ filterSensitiveData?: boolean;
14
+ sensitiveDataPatterns?: string[];
15
+ redactionMode?: 'mask' | 'remove' | 'hash';
14
16
  });
15
- getTracer(): api.Tracer;
16
17
  setChatId(chatId: string): void;
17
18
  clearChatId(): void;
18
- createSpan(name: string, attributes?: api.Attributes, spanKind?: api.SpanKind): api.Span;
19
+ setMetadata(metadata: LupisMetadata): void;
20
+ clearMetadata(): void;
21
+ setConversationContext(context: ConversationContext): void;
22
+ trackMessage(message: MessageData): void;
23
+ trackToolCall(toolCall: ToolCallData): void;
24
+ trackToolResult(toolName: string): void;
25
+ getConversationData(): {
26
+ context: ConversationContext | undefined;
27
+ messageCounts: {
28
+ user: number;
29
+ assistant: number;
30
+ system: number;
31
+ };
32
+ totalMessageCount: number;
33
+ toolCallCounts: {
34
+ [k: string]: number;
35
+ };
36
+ toolResultCounts: {
37
+ [k: string]: number;
38
+ };
39
+ totalToolCallCount: number;
40
+ totalToolResultCount: number;
41
+ };
19
42
  shutdown(): Promise<void>;
20
43
  }
21
44
  //# sourceMappingURL=tracer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../src/tracer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,oBAAoB,CAAC;AAqC1C,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB;IAkDD,SAAS,IAAI,GAAG,CAAC,MAAM;IAIvB,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,WAAW;IAIX,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,IAAI;IAOlF,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAShC"}
1
+ {"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../src/tracer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAuB,mBAAmB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAkDhH,qBAAa,WAAW;IACtB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,mBAAmB,CAA6B;gBAE5C,MAAM,EAAE;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;QACjC,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;KAC5C;IA2BD,SAAS,CAAC,MAAM,EAAE,MAAM;IAIxB,WAAW;IAIX,WAAW,CAAC,QAAQ,EAAE,aAAa;IAInC,aAAa;IAIb,sBAAsB,CAAC,OAAO,EAAE,mBAAmB;IAInD,YAAY,CAAC,OAAO,EAAE,WAAW;IAIjC,aAAa,CAAC,QAAQ,EAAE,YAAY;IAIpC,eAAe,CAAC,QAAQ,EAAE,MAAM;IAIhC,mBAAmB;;;;;;;;;;;;;;;;;IAIb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAOhC"}
package/dist/tracer.js CHANGED
@@ -1,95 +1,101 @@
1
- import * as api from '@opentelemetry/api';
2
- import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
3
- import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
4
- import { BatchSpanProcessor, ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
5
- import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
6
- import { Resource } from '@opentelemetry/resources';
7
1
  import { HttpInterceptor } from './http-interceptor.js';
8
- class ChatIdSpanProcessor {
9
- setChatId(chatId) {
10
- this.currentChatId = chatId;
2
+ import { TraceCollector } from './trace-collector.js';
3
+ import { DEFAULT_TRACES_ENDPOINT } from './endpoints.js';
4
+ class ConversationTracker {
5
+ constructor() {
6
+ this.messageCounts = {
7
+ user: 0,
8
+ assistant: 0,
9
+ system: 0
10
+ };
11
+ this.toolCallCounts = new Map();
12
+ this.toolResultCounts = new Map();
11
13
  }
12
- clearChatId() {
13
- this.currentChatId = undefined;
14
+ setConversationContext(context) {
15
+ this.conversationContext = context;
14
16
  }
15
- onStart(span) {
16
- if (this.currentChatId) {
17
- span.setAttribute('lupis.chat.id', this.currentChatId);
18
- }
17
+ clearConversationContext() {
18
+ this.conversationContext = undefined;
19
+ this.messageCounts = { user: 0, assistant: 0, system: 0 };
20
+ this.toolCallCounts.clear();
21
+ this.toolResultCounts.clear();
22
+ }
23
+ trackMessage(message) {
24
+ this.messageCounts[message.role]++;
19
25
  }
20
- onEnd() {
26
+ trackToolCall(toolCall) {
27
+ const count = this.toolCallCounts.get(toolCall.name) || 0;
28
+ this.toolCallCounts.set(toolCall.name, count + 1);
21
29
  }
22
- forceFlush() {
23
- return Promise.resolve();
30
+ trackToolResult(toolName) {
31
+ const count = this.toolResultCounts.get(toolName) || 0;
32
+ this.toolResultCounts.set(toolName, count + 1);
24
33
  }
25
- shutdown() {
26
- return Promise.resolve();
34
+ getConversationData() {
35
+ return {
36
+ context: this.conversationContext,
37
+ messageCounts: this.messageCounts,
38
+ totalMessageCount: this.messageCounts.user + this.messageCounts.assistant + this.messageCounts.system,
39
+ toolCallCounts: Object.fromEntries(this.toolCallCounts),
40
+ toolResultCounts: Object.fromEntries(this.toolResultCounts),
41
+ totalToolCallCount: Array.from(this.toolCallCounts.values()).reduce((sum, count) => sum + count, 0),
42
+ totalToolResultCount: Array.from(this.toolResultCounts.values()).reduce((sum, count) => sum + count, 0)
43
+ };
27
44
  }
28
45
  }
29
46
  export class LupisTracer {
30
47
  constructor(config) {
48
+ this.conversationTracker = new ConversationTracker();
31
49
  this.projectId = config.projectId;
32
- const serviceName = config.serviceName || 'lupis-sdk';
33
- const serviceVersion = config.serviceVersion || '1.0.0';
34
50
  const enabled = config.enabled !== false;
35
- const resource = Resource.default().merge(new Resource({
36
- 'service.name': serviceName,
37
- 'service.version': serviceVersion,
38
- 'lupis.project.id': config.projectId,
39
- }));
40
- this.chatIdProcessor = new ChatIdSpanProcessor();
41
- const spanProcessors = [this.chatIdProcessor];
51
+ this.traceCollector = new TraceCollector({
52
+ endpoint: DEFAULT_TRACES_ENDPOINT,
53
+ projectId: config.projectId,
54
+ apiKey: config.apiKey,
55
+ enabled,
56
+ });
57
+ const sensitiveDataFilter = {
58
+ filterSensitiveData: config.filterSensitiveData ?? true,
59
+ sensitiveDataPatterns: config.sensitiveDataPatterns ?? [],
60
+ redactionMode: config.redactionMode ?? 'mask',
61
+ };
62
+ this.httpInterceptor = new HttpInterceptor(this.traceCollector, config.projectId, sensitiveDataFilter);
42
63
  if (enabled) {
43
- const otlpUrl = config.otlpEndpoint || 'http://localhost:3010/v1/traces';
44
- console.log(`[Lupis SDK] Initializing OTLP Exporter with URL: ${otlpUrl}`);
45
- const otlpExporter = new OTLPTraceExporter({
46
- url: otlpUrl,
47
- headers: {
48
- 'x-project-id': config.projectId,
49
- },
50
- });
51
- spanProcessors.push(new BatchSpanProcessor(otlpExporter, {
52
- scheduledDelayMillis: 5000,
53
- maxQueueSize: 2048,
54
- maxExportBatchSize: 512,
55
- exportTimeoutMillis: 30000,
56
- }));
57
- }
58
- else {
59
- spanProcessors.push(new SimpleSpanProcessor(new ConsoleSpanExporter()));
64
+ this.httpInterceptor.startIntercepting();
60
65
  }
61
- const isNode = typeof process !== 'undefined' && process.versions?.node;
62
- this.provider = isNode
63
- ? new NodeTracerProvider({ resource, spanProcessors })
64
- : new WebTracerProvider({ resource, spanProcessors });
65
- this.provider.register();
66
- this.tracer = api.trace.getTracer(serviceName, serviceVersion);
67
- // Initialize and start HTTP interception
68
- this.httpInterceptor = new HttpInterceptor(this.tracer, this.provider, config.projectId);
69
- this.httpInterceptor.startIntercepting();
70
- }
71
- getTracer() {
72
- return this.tracer;
73
66
  }
74
67
  setChatId(chatId) {
75
- this.chatIdProcessor.setChatId(chatId);
68
+ this.httpInterceptor.setChatId(chatId);
76
69
  }
77
70
  clearChatId() {
78
- this.chatIdProcessor.clearChatId();
71
+ this.httpInterceptor.clearChatId();
79
72
  }
80
- createSpan(name, attributes, spanKind) {
81
- return this.tracer.startSpan(name, {
82
- kind: spanKind || api.SpanKind.INTERNAL,
83
- attributes,
84
- });
73
+ setMetadata(metadata) {
74
+ this.httpInterceptor.setMetadata(metadata);
75
+ }
76
+ clearMetadata() {
77
+ this.httpInterceptor.clearMetadata();
78
+ }
79
+ setConversationContext(context) {
80
+ this.conversationTracker.setConversationContext(context);
81
+ }
82
+ trackMessage(message) {
83
+ this.conversationTracker.trackMessage(message);
84
+ }
85
+ trackToolCall(toolCall) {
86
+ this.conversationTracker.trackToolCall(toolCall);
87
+ }
88
+ trackToolResult(toolName) {
89
+ this.conversationTracker.trackToolResult(toolName);
90
+ }
91
+ getConversationData() {
92
+ return this.conversationTracker.getConversationData();
85
93
  }
86
94
  async shutdown() {
87
95
  console.log('[Lupis SDK] Stopping HTTP interception...');
88
- await this.httpInterceptor.stopIntercepting();
89
- console.log('[Lupis SDK] Flushing spans...');
90
- await this.provider.forceFlush();
91
- console.log('[Lupis SDK] Shutting down...');
92
- await this.provider.shutdown();
96
+ this.httpInterceptor.stopIntercepting();
97
+ console.log('[Lupis SDK] Flushing traces...');
98
+ await this.traceCollector.forceFlush();
93
99
  console.log('[Lupis SDK] Shutdown complete');
94
100
  }
95
101
  }