@mynitorai/sdk 0.1.1 → 0.1.4
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.d.ts +8 -1
- package/dist/index.js +67 -18
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,19 +4,26 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export interface MyNitorConfig {
|
|
6
6
|
apiKey: string;
|
|
7
|
-
environment?: string;
|
|
8
7
|
endpoint?: string;
|
|
9
8
|
}
|
|
10
9
|
export declare class MyNitor {
|
|
11
10
|
private static instance;
|
|
12
11
|
private config;
|
|
13
12
|
private isInstrumented;
|
|
13
|
+
private pendingPromises;
|
|
14
14
|
private constructor();
|
|
15
15
|
static init(config: MyNitorConfig): MyNitor;
|
|
16
16
|
/**
|
|
17
17
|
* Automatically detect and wrap AI libraries like OpenAI
|
|
18
18
|
*/
|
|
19
19
|
instrument(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Waits for all pending network requests to complete.
|
|
22
|
+
* Call this before your process exits (e.g. in AWS Lambda or scripts).
|
|
23
|
+
* @param timeoutMs Maximum time to wait in milliseconds (default: 10000)
|
|
24
|
+
*/
|
|
25
|
+
flush(timeoutMs?: number): Promise<void>;
|
|
26
|
+
private getCallSite;
|
|
20
27
|
private sendEvent;
|
|
21
28
|
private wrapOpenAI;
|
|
22
29
|
}
|
package/dist/index.js
CHANGED
|
@@ -8,9 +8,9 @@ exports.init = exports.MyNitor = void 0;
|
|
|
8
8
|
class MyNitor {
|
|
9
9
|
constructor(config) {
|
|
10
10
|
this.isInstrumented = false;
|
|
11
|
+
this.pendingPromises = new Set();
|
|
11
12
|
this.config = {
|
|
12
|
-
|
|
13
|
-
endpoint: 'https://www.mynitor.ai/api/v1/events',
|
|
13
|
+
endpoint: 'https://app.mynitor.ai/api/v1/events',
|
|
14
14
|
...config
|
|
15
15
|
};
|
|
16
16
|
}
|
|
@@ -30,10 +30,54 @@ class MyNitor {
|
|
|
30
30
|
this.isInstrumented = true;
|
|
31
31
|
console.log('🚀 MyNitor: Auto-instrumentation active.');
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Waits for all pending network requests to complete.
|
|
35
|
+
* Call this before your process exits (e.g. in AWS Lambda or scripts).
|
|
36
|
+
* @param timeoutMs Maximum time to wait in milliseconds (default: 10000)
|
|
37
|
+
*/
|
|
38
|
+
async flush(timeoutMs = 10000) {
|
|
39
|
+
if (this.pendingPromises.size === 0)
|
|
40
|
+
return;
|
|
41
|
+
console.log(`🚀 MyNitor: Flushing ${this.pendingPromises.size} pending logs...`);
|
|
42
|
+
const timeoutPromise = new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
43
|
+
const allSettledPromise = Promise.allSettled(this.pendingPromises);
|
|
44
|
+
await Promise.race([allSettledPromise, timeoutPromise]);
|
|
45
|
+
}
|
|
46
|
+
getCallSite() {
|
|
47
|
+
try {
|
|
48
|
+
const err = new Error();
|
|
49
|
+
const stack = err.stack?.split('\n') || [];
|
|
50
|
+
// Look for the frame that called the LLM method
|
|
51
|
+
// Stack usually: Error -> getCallSite -> wrapOpenAI wrapper -> USER CODE
|
|
52
|
+
// We iterate to find the first frame NOT in MyNitor SDK
|
|
53
|
+
for (const line of stack) {
|
|
54
|
+
if (!line.includes('mynitor') && !line.includes('Error') && line.includes('/')) {
|
|
55
|
+
// Typical format: " at Object.myFunction (/path/to/file.ts:10:5)"
|
|
56
|
+
const match = line.match(/at\s+(?:(.+?)\s+\()?(.*?):(\d+):(\d+)\)?/);
|
|
57
|
+
if (match) {
|
|
58
|
+
const func = match[1] || 'anonymous';
|
|
59
|
+
const fullPath = match[2];
|
|
60
|
+
const filename = fullPath.split('/').pop()?.split('.')[0] || 'unknown';
|
|
61
|
+
return {
|
|
62
|
+
file: fullPath,
|
|
63
|
+
line: parseInt(match[3]),
|
|
64
|
+
functionName: func,
|
|
65
|
+
workflowGuess: `${filename}:${func}`.replace('Object.', '')
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
// fail safe
|
|
73
|
+
}
|
|
74
|
+
return { file: 'unknown', line: 0, functionName: 'unknown', workflowGuess: 'default-workflow' };
|
|
75
|
+
}
|
|
33
76
|
async sendEvent(payload) {
|
|
34
77
|
try {
|
|
35
|
-
// Fire and forget
|
|
36
|
-
|
|
78
|
+
// Fire and forget
|
|
79
|
+
// Fire and forget (but track)
|
|
80
|
+
const promise = fetch(this.config.endpoint, {
|
|
37
81
|
method: 'POST',
|
|
38
82
|
headers: {
|
|
39
83
|
'Content-Type': 'application/json',
|
|
@@ -41,20 +85,20 @@ class MyNitor {
|
|
|
41
85
|
},
|
|
42
86
|
body: JSON.stringify({
|
|
43
87
|
...payload,
|
|
44
|
-
environment: this.config.environment,
|
|
45
88
|
eventVersion: '1.0'
|
|
46
89
|
})
|
|
47
|
-
})
|
|
48
|
-
|
|
90
|
+
})
|
|
91
|
+
.then(() => { })
|
|
92
|
+
.catch(() => { })
|
|
93
|
+
.finally(() => {
|
|
94
|
+
this.pendingPromises.delete(promise);
|
|
49
95
|
});
|
|
96
|
+
this.pendingPromises.add(promise);
|
|
50
97
|
}
|
|
51
|
-
catch (e) {
|
|
52
|
-
/* Silently fail */
|
|
53
|
-
}
|
|
98
|
+
catch (e) { }
|
|
54
99
|
}
|
|
55
100
|
wrapOpenAI() {
|
|
56
101
|
try {
|
|
57
|
-
// Detect if OpenAI is installed
|
|
58
102
|
const OpenAI = require('openai');
|
|
59
103
|
if (!OpenAI || !OpenAI.OpenAI)
|
|
60
104
|
return;
|
|
@@ -63,14 +107,19 @@ class MyNitor {
|
|
|
63
107
|
OpenAI.OpenAI.Chat.Completions.prototype.create = async function (...args) {
|
|
64
108
|
const start = Date.now();
|
|
65
109
|
const body = args[0];
|
|
110
|
+
const callsite = self.getCallSite();
|
|
66
111
|
try {
|
|
67
112
|
const result = await originalChatCreate.apply(this, args);
|
|
68
113
|
const end = Date.now();
|
|
69
|
-
// Background capture
|
|
70
114
|
self.sendEvent({
|
|
71
115
|
requestId: result.id || `req_${Date.now()}`,
|
|
72
116
|
model: result.model || body.model,
|
|
73
117
|
provider: 'openai',
|
|
118
|
+
agent: 'default-agent',
|
|
119
|
+
workflow: callsite.workflowGuess,
|
|
120
|
+
file: callsite.file,
|
|
121
|
+
functionName: callsite.functionName,
|
|
122
|
+
lineNumber: callsite.line,
|
|
74
123
|
inputTokens: result.usage?.prompt_tokens || 0,
|
|
75
124
|
outputTokens: result.usage?.completion_tokens || 0,
|
|
76
125
|
latencyMs: end - start,
|
|
@@ -84,8 +133,10 @@ class MyNitor {
|
|
|
84
133
|
requestId: `err_${Date.now()}`,
|
|
85
134
|
model: body?.model || 'unknown',
|
|
86
135
|
provider: 'openai',
|
|
87
|
-
|
|
88
|
-
|
|
136
|
+
agent: 'default-agent',
|
|
137
|
+
workflow: callsite.workflowGuess,
|
|
138
|
+
file: callsite.file,
|
|
139
|
+
functionName: callsite.functionName,
|
|
89
140
|
latencyMs: end - start,
|
|
90
141
|
status: 'error',
|
|
91
142
|
errorType: error?.constructor?.name || 'Error'
|
|
@@ -94,11 +145,9 @@ class MyNitor {
|
|
|
94
145
|
}
|
|
95
146
|
};
|
|
96
147
|
}
|
|
97
|
-
catch (e) {
|
|
98
|
-
// Library not found or version mismatch - skip silently
|
|
99
|
-
}
|
|
148
|
+
catch (e) { }
|
|
100
149
|
}
|
|
101
150
|
}
|
|
102
151
|
exports.MyNitor = MyNitor;
|
|
103
|
-
// Global accessor
|
|
152
|
+
// Global accessor
|
|
104
153
|
exports.init = MyNitor.init;
|