openlit 1.0.0 → 1.2.0
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 +1 -1
- package/package.json +3 -2
- package/src/constant.ts +6 -5
- package/src/index.ts +2 -1
- package/src/instrumentation/anthropic/wrapper.ts +5 -26
- package/src/instrumentation/base-wrapper.ts +39 -0
- package/src/instrumentation/cohere/index.ts +79 -0
- package/src/instrumentation/cohere/wrapper.ts +286 -0
- package/src/instrumentation/index.ts +2 -0
- package/src/instrumentation/openai/wrapper.ts +10 -53
- package/src/prompt-hub.ts +64 -0
- package/src/types.ts +12 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ OpenTelemetry Auto-Instrumentation for GenAI & LLM Applications</h1>
|
|
|
6
6
|
|
|
7
7
|
[](https://github.com/openlit/openlit)
|
|
8
8
|
[](https://github.com/openlit/openlit/blob/main/LICENSE)
|
|
9
|
-
[](https://www.npmjs.com/package/openlit)
|
|
10
10
|
[](https://github.com/openlit/openlit/pulse)
|
|
11
11
|
[](https://github.com/openlit/openlit/graphs/contributors)
|
|
12
12
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openlit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"homepage": "https://github.com/openlit/openlit#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/openlit/openlit/issues",
|
|
@@ -53,8 +53,9 @@
|
|
|
53
53
|
"@opentelemetry/sdk-trace-base": "^1.24.1",
|
|
54
54
|
"@opentelemetry/sdk-trace-node": "^1.24.1",
|
|
55
55
|
"@opentelemetry/semantic-conventions": "^1.24.1",
|
|
56
|
+
"cohere-ai": "^7.13.0",
|
|
56
57
|
"js-tiktoken": "^1.0.12",
|
|
57
58
|
"openai": "^4.47.1",
|
|
58
59
|
"tiktoken": "^1.0.15"
|
|
59
60
|
}
|
|
60
|
-
}
|
|
61
|
+
}
|
package/src/constant.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export const SDK_NAME =
|
|
2
|
-
export const DEFAULT_ENVIRONMENT =
|
|
3
|
-
export const DEFAULT_APPLICATION_NAME =
|
|
4
|
-
export const INSTRUMENTATION_PREFIX =
|
|
5
|
-
export const TELEMETRY_SDK_NAME = 'opentelemetry';
|
|
1
|
+
export const SDK_NAME = 'openlit';
|
|
2
|
+
export const DEFAULT_ENVIRONMENT = 'default';
|
|
3
|
+
export const DEFAULT_APPLICATION_NAME = 'default';
|
|
4
|
+
export const INSTRUMENTATION_PREFIX = '@openlit';
|
|
5
|
+
export const TELEMETRY_SDK_NAME = 'opentelemetry';
|
|
6
|
+
export const OPENLIT_URL = 'http://127.0.0.1:3000';
|
package/src/index.ts
CHANGED
|
@@ -9,8 +9,9 @@ import { OpenlitOptions } from './types';
|
|
|
9
9
|
import Tracing from './tracing';
|
|
10
10
|
import { DEFAULT_APPLICATION_NAME, DEFAULT_ENVIRONMENT, SDK_NAME } from './constant';
|
|
11
11
|
import { SpanExporter } from '@opentelemetry/sdk-trace-base';
|
|
12
|
+
import PromptHub from './prompt-hub';
|
|
12
13
|
|
|
13
|
-
export default class Openlit {
|
|
14
|
+
export default class Openlit extends PromptHub {
|
|
14
15
|
static resource: Resource;
|
|
15
16
|
static options: OpenlitOptions;
|
|
16
17
|
static _sdk: NodeSDK;
|
|
@@ -1,29 +1,11 @@
|
|
|
1
|
-
import { Span, SpanKind,
|
|
1
|
+
import { Span, SpanKind, Tracer, context, trace } from '@opentelemetry/api';
|
|
2
2
|
import OpenlitConfig from '../../config';
|
|
3
3
|
import OpenLitHelper from '../../helpers';
|
|
4
4
|
import SemanticConvention from '../../semantic-convention';
|
|
5
|
-
import
|
|
5
|
+
import BaseWrapper from '../base-wrapper';
|
|
6
6
|
|
|
7
|
-
export default class AnthropicWrapper {
|
|
8
|
-
static
|
|
9
|
-
span: any,
|
|
10
|
-
{ genAIEndpoint, model, user, cost, environment, applicationName }: any
|
|
11
|
-
) {
|
|
12
|
-
span.setAttributes({
|
|
13
|
-
[TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
span.setAttribute(TELEMETRY_SDK_NAME, SDK_NAME);
|
|
17
|
-
span.setAttribute(SemanticConvention.GEN_AI_SYSTEM, SemanticConvention.GEN_AI_SYSTEM_ANTHROPIC);
|
|
18
|
-
span.setAttribute(SemanticConvention.GEN_AI_ENDPOINT, genAIEndpoint);
|
|
19
|
-
span.setAttribute(SemanticConvention.GEN_AI_ENVIRONMENT, environment);
|
|
20
|
-
span.setAttribute(SemanticConvention.GEN_AI_APPLICATION_NAME, applicationName);
|
|
21
|
-
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_MODEL, model);
|
|
22
|
-
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_USER, user);
|
|
23
|
-
if (cost !== undefined) span.setAttribute(SemanticConvention.GEN_AI_USAGE_COST, cost);
|
|
24
|
-
|
|
25
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
26
|
-
}
|
|
7
|
+
export default class AnthropicWrapper extends BaseWrapper {
|
|
8
|
+
static aiSystem = SemanticConvention.GEN_AI_SYSTEM_ANTHROPIC;
|
|
27
9
|
|
|
28
10
|
static _patchMessageCreate(tracer: Tracer): any {
|
|
29
11
|
const genAIEndpoint = 'anthropic.resources.messages';
|
|
@@ -174,8 +156,6 @@ export default class AnthropicWrapper {
|
|
|
174
156
|
result: any;
|
|
175
157
|
span: Span;
|
|
176
158
|
}) {
|
|
177
|
-
const applicationName = OpenlitConfig.applicationName;
|
|
178
|
-
const environment = OpenlitConfig.environment;
|
|
179
159
|
const traceContent = OpenlitConfig.traceContent;
|
|
180
160
|
const {
|
|
181
161
|
messages,
|
|
@@ -234,8 +214,7 @@ export default class AnthropicWrapper {
|
|
|
234
214
|
model,
|
|
235
215
|
user,
|
|
236
216
|
cost,
|
|
237
|
-
|
|
238
|
-
environment,
|
|
217
|
+
aiSystem: AnthropicWrapper.aiSystem,
|
|
239
218
|
});
|
|
240
219
|
|
|
241
220
|
// Request Params attributes : Start
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import OpenlitConfig from '../config';
|
|
2
|
+
import { SDK_NAME, TELEMETRY_SDK_NAME } from '../constant';
|
|
3
|
+
import SemanticConvention from '../semantic-convention';
|
|
4
|
+
import { Span, SpanStatusCode } from '@opentelemetry/api';
|
|
5
|
+
|
|
6
|
+
type BaseSpanAttributes = {
|
|
7
|
+
genAIEndpoint: string;
|
|
8
|
+
model: string;
|
|
9
|
+
user?: unknown;
|
|
10
|
+
cost?: number | string;
|
|
11
|
+
aiSystem: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default class BaseWrapper {
|
|
15
|
+
static setBaseSpanAttributes(
|
|
16
|
+
span: Span,
|
|
17
|
+
{ genAIEndpoint, model, user, cost, aiSystem }: BaseSpanAttributes
|
|
18
|
+
) {
|
|
19
|
+
const applicationName = OpenlitConfig.applicationName!;
|
|
20
|
+
const environment = OpenlitConfig.environment!;
|
|
21
|
+
|
|
22
|
+
span.setAttributes({
|
|
23
|
+
[TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
span.setAttribute(TELEMETRY_SDK_NAME, SDK_NAME);
|
|
27
|
+
span.setAttribute(SemanticConvention.GEN_AI_SYSTEM, aiSystem);
|
|
28
|
+
span.setAttribute(SemanticConvention.GEN_AI_ENDPOINT, genAIEndpoint);
|
|
29
|
+
span.setAttribute(SemanticConvention.GEN_AI_ENVIRONMENT, environment);
|
|
30
|
+
span.setAttribute(SemanticConvention.GEN_AI_APPLICATION_NAME, applicationName);
|
|
31
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_MODEL, model);
|
|
32
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_USER, user as any);
|
|
33
|
+
if (cost !== undefined) {
|
|
34
|
+
span.setAttribute(SemanticConvention.GEN_AI_USAGE_COST, cost);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InstrumentationBase,
|
|
3
|
+
InstrumentationModuleDefinition,
|
|
4
|
+
InstrumentationNodeModuleDefinition,
|
|
5
|
+
isWrapped,
|
|
6
|
+
} from '@opentelemetry/instrumentation';
|
|
7
|
+
import { InstrumentationConfig } from '@opentelemetry/instrumentation';
|
|
8
|
+
import { INSTRUMENTATION_PREFIX } from '../../constant';
|
|
9
|
+
import Cohere from 'cohere-ai';
|
|
10
|
+
import CohereWrapper from './wrapper';
|
|
11
|
+
|
|
12
|
+
export interface CohereInstrumentationConfig extends InstrumentationConfig {}
|
|
13
|
+
|
|
14
|
+
export default class OpenlitCohereInstrumentation extends InstrumentationBase {
|
|
15
|
+
constructor(config: CohereInstrumentationConfig = {}) {
|
|
16
|
+
super(`${INSTRUMENTATION_PREFIX}/instrumentation-cohere-ai`, '1.0.0', config);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected init(): void | InstrumentationModuleDefinition | InstrumentationModuleDefinition[] {
|
|
20
|
+
const module = new InstrumentationNodeModuleDefinition(
|
|
21
|
+
'cohere-ai',
|
|
22
|
+
['>=7.2.0'],
|
|
23
|
+
(moduleExports) => {
|
|
24
|
+
this._patch(moduleExports);
|
|
25
|
+
return moduleExports;
|
|
26
|
+
},
|
|
27
|
+
(moduleExports) => {
|
|
28
|
+
if (moduleExports !== undefined) {
|
|
29
|
+
this._unpatch(moduleExports);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
return [module];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public manualPatch(cohere: any): void {
|
|
37
|
+
this._patch(cohere);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected _patch(moduleExports: typeof Cohere) {
|
|
41
|
+
try {
|
|
42
|
+
if (isWrapped(moduleExports.CohereClient.prototype.embed)) {
|
|
43
|
+
this._unwrap(moduleExports.CohereClient.prototype, 'embed');
|
|
44
|
+
}
|
|
45
|
+
if (isWrapped(moduleExports.CohereClient.prototype.chat)) {
|
|
46
|
+
this._unwrap(moduleExports.CohereClient.prototype, 'chat');
|
|
47
|
+
}
|
|
48
|
+
if (isWrapped(moduleExports.CohereClient.prototype.chatStream)) {
|
|
49
|
+
this._unwrap(moduleExports.CohereClient.prototype, 'chatStream');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this._wrap(
|
|
53
|
+
moduleExports.CohereClient.prototype,
|
|
54
|
+
'embed',
|
|
55
|
+
CohereWrapper._patchEmbed(this.tracer)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
this._wrap(
|
|
59
|
+
moduleExports.CohereClient.prototype,
|
|
60
|
+
'chat',
|
|
61
|
+
CohereWrapper._patchChat(this.tracer)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
this._wrap(
|
|
65
|
+
moduleExports.CohereClient.prototype,
|
|
66
|
+
'chatStream',
|
|
67
|
+
CohereWrapper._patchChatStream(this.tracer)
|
|
68
|
+
);
|
|
69
|
+
} catch (e) {
|
|
70
|
+
console.error('Error in _patch method:', e);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
protected _unpatch(moduleExports: typeof Cohere) {
|
|
75
|
+
this._unwrap(moduleExports.CohereClient.prototype, 'embed');
|
|
76
|
+
this._unwrap(moduleExports.CohereClient.prototype, 'chat');
|
|
77
|
+
this._unwrap(moduleExports.CohereClient.prototype, 'chatStream');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { Span, SpanKind, Tracer, context, trace } from '@opentelemetry/api';
|
|
2
|
+
import OpenlitConfig from '../../config';
|
|
3
|
+
import OpenLitHelper from '../../helpers';
|
|
4
|
+
import SemanticConvention from '../../semantic-convention';
|
|
5
|
+
import { SDK_NAME, TELEMETRY_SDK_NAME } from '../../constant';
|
|
6
|
+
import BaseWrapper from '../base-wrapper';
|
|
7
|
+
|
|
8
|
+
export default class CohereWrapper extends BaseWrapper {
|
|
9
|
+
static aiSystem = SemanticConvention.GEN_AI_SYSTEM_COHERE;
|
|
10
|
+
static _patchEmbed(tracer: Tracer): any {
|
|
11
|
+
const genAIEndpoint = 'cohere.embed';
|
|
12
|
+
const traceContent = OpenlitConfig.traceContent;
|
|
13
|
+
|
|
14
|
+
return (originalMethod: (...args: any[]) => any) => {
|
|
15
|
+
return async function (this: any, ...args: any[]) {
|
|
16
|
+
const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
|
|
17
|
+
return context.with(trace.setSpan(context.active(), span), async () => {
|
|
18
|
+
try {
|
|
19
|
+
const response = await originalMethod.apply(this, args);
|
|
20
|
+
span.setAttributes({
|
|
21
|
+
[TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const model = response.model || 'embed-english-v2.0';
|
|
25
|
+
const pricingInfo = await OpenlitConfig.updatePricingJson(OpenlitConfig.pricing_json);
|
|
26
|
+
const cost = OpenLitHelper.getEmbedModelCost(
|
|
27
|
+
model,
|
|
28
|
+
pricingInfo,
|
|
29
|
+
response.meta.billedUnits.inputTokens
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
span.setAttribute(
|
|
33
|
+
SemanticConvention.GEN_AI_TYPE,
|
|
34
|
+
SemanticConvention.GEN_AI_TYPE_EMBEDDING
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const { dimensions, encoding_format = 'float', input, user, texts = [] } = args[0];
|
|
38
|
+
// Set base span attribues
|
|
39
|
+
CohereWrapper.setBaseSpanAttributes(span, {
|
|
40
|
+
genAIEndpoint,
|
|
41
|
+
model,
|
|
42
|
+
user,
|
|
43
|
+
cost,
|
|
44
|
+
aiSystem: CohereWrapper.aiSystem,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Request Params attributes : Start
|
|
48
|
+
|
|
49
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_EMBEDDING_FORMAT, encoding_format);
|
|
50
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_EMBEDDING_DIMENSION, dimensions);
|
|
51
|
+
if (traceContent) {
|
|
52
|
+
span.setAttribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, JSON.stringify(texts));
|
|
53
|
+
}
|
|
54
|
+
// Request Params attributes : End
|
|
55
|
+
|
|
56
|
+
span.setAttribute(SemanticConvention.GEN_AI_RESPONSE_ID, response.id);
|
|
57
|
+
|
|
58
|
+
span.setAttribute(
|
|
59
|
+
SemanticConvention.GEN_AI_USAGE_PROMPT_TOKENS,
|
|
60
|
+
response.meta.billedUnits.inputTokens
|
|
61
|
+
);
|
|
62
|
+
span.setAttribute(
|
|
63
|
+
SemanticConvention.GEN_AI_USAGE_TOTAL_TOKENS,
|
|
64
|
+
response.meta.billedUnits.inputTokens
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return response;
|
|
68
|
+
} catch (e: any) {
|
|
69
|
+
OpenLitHelper.handleException(span, e);
|
|
70
|
+
} finally {
|
|
71
|
+
span.end();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static _patchChat(tracer: Tracer): any {
|
|
79
|
+
const genAIEndpoint = 'cohere.chat';
|
|
80
|
+
return (originalMethod: (...args: any[]) => any) => {
|
|
81
|
+
return async function (this: any, ...args: any[]) {
|
|
82
|
+
const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
|
|
83
|
+
return context
|
|
84
|
+
.with(trace.setSpan(context.active(), span), async () => {
|
|
85
|
+
return originalMethod.apply(this, args);
|
|
86
|
+
})
|
|
87
|
+
.then((response) => {
|
|
88
|
+
return CohereWrapper._chat({ args, genAIEndpoint, response, span });
|
|
89
|
+
})
|
|
90
|
+
.catch((e: any) => {
|
|
91
|
+
OpenLitHelper.handleException(span, e);
|
|
92
|
+
span.end();
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static _patchChatStream(tracer: Tracer): any {
|
|
99
|
+
const genAIEndpoint = 'cohere.chat';
|
|
100
|
+
return (originalMethod: (...args: any[]) => any) => {
|
|
101
|
+
return async function (this: any, ...args: any[]) {
|
|
102
|
+
const span = tracer.startSpan(genAIEndpoint, { kind: SpanKind.CLIENT });
|
|
103
|
+
return context
|
|
104
|
+
.with(trace.setSpan(context.active(), span), async () => {
|
|
105
|
+
return originalMethod.apply(this, args);
|
|
106
|
+
})
|
|
107
|
+
.then((response) => {
|
|
108
|
+
return OpenLitHelper.createStreamProxy(
|
|
109
|
+
response,
|
|
110
|
+
CohereWrapper._chatGenerator({
|
|
111
|
+
args,
|
|
112
|
+
genAIEndpoint,
|
|
113
|
+
response,
|
|
114
|
+
span,
|
|
115
|
+
})
|
|
116
|
+
);
|
|
117
|
+
})
|
|
118
|
+
.catch((e: any) => {
|
|
119
|
+
OpenLitHelper.handleException(span, e);
|
|
120
|
+
span.end();
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static async _chat({
|
|
127
|
+
args,
|
|
128
|
+
genAIEndpoint,
|
|
129
|
+
response,
|
|
130
|
+
span,
|
|
131
|
+
}: {
|
|
132
|
+
args: any[];
|
|
133
|
+
genAIEndpoint: string;
|
|
134
|
+
response: any;
|
|
135
|
+
span: Span;
|
|
136
|
+
}): Promise<any> {
|
|
137
|
+
try {
|
|
138
|
+
await CohereWrapper._chatCommonSetter({
|
|
139
|
+
args,
|
|
140
|
+
genAIEndpoint,
|
|
141
|
+
result: response,
|
|
142
|
+
span,
|
|
143
|
+
stream: false,
|
|
144
|
+
});
|
|
145
|
+
return response;
|
|
146
|
+
} catch (e: any) {
|
|
147
|
+
OpenLitHelper.handleException(span, e);
|
|
148
|
+
} finally {
|
|
149
|
+
span.end();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static async *_chatGenerator({
|
|
154
|
+
args,
|
|
155
|
+
genAIEndpoint,
|
|
156
|
+
response,
|
|
157
|
+
span,
|
|
158
|
+
}: {
|
|
159
|
+
args: any[];
|
|
160
|
+
genAIEndpoint: string;
|
|
161
|
+
response: any;
|
|
162
|
+
span: Span;
|
|
163
|
+
}): AsyncGenerator<unknown, any, unknown> {
|
|
164
|
+
try {
|
|
165
|
+
let result = {
|
|
166
|
+
response_id: '',
|
|
167
|
+
text: '',
|
|
168
|
+
generationId: '',
|
|
169
|
+
chatHistory: [],
|
|
170
|
+
finishReason: '',
|
|
171
|
+
meta: {
|
|
172
|
+
apiVersion: { version: '1' },
|
|
173
|
+
billedUnits: { inputTokens: 0, outputTokens: 0 },
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
for await (const chunk of response) {
|
|
177
|
+
if (chunk.eventType === 'stream-end') {
|
|
178
|
+
result = chunk.response;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
yield chunk;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
await CohereWrapper._chatCommonSetter({
|
|
185
|
+
args,
|
|
186
|
+
genAIEndpoint,
|
|
187
|
+
result,
|
|
188
|
+
span,
|
|
189
|
+
stream: true,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return result;
|
|
193
|
+
} catch (e: any) {
|
|
194
|
+
OpenLitHelper.handleException(span, e);
|
|
195
|
+
} finally {
|
|
196
|
+
span.end();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
static async _chatCommonSetter({
|
|
201
|
+
args,
|
|
202
|
+
genAIEndpoint,
|
|
203
|
+
result,
|
|
204
|
+
span,
|
|
205
|
+
stream,
|
|
206
|
+
}: {
|
|
207
|
+
args: any[];
|
|
208
|
+
genAIEndpoint: string;
|
|
209
|
+
result: any;
|
|
210
|
+
span: Span;
|
|
211
|
+
stream: boolean;
|
|
212
|
+
}) {
|
|
213
|
+
const traceContent = OpenlitConfig.traceContent;
|
|
214
|
+
const {
|
|
215
|
+
message,
|
|
216
|
+
model = 'command-r-plus-08-2024',
|
|
217
|
+
frequency_penalty = 0,
|
|
218
|
+
max_tokens = null,
|
|
219
|
+
presence_penalty = 0,
|
|
220
|
+
seed = null,
|
|
221
|
+
temperature = 1,
|
|
222
|
+
user,
|
|
223
|
+
tools,
|
|
224
|
+
} = args[0];
|
|
225
|
+
|
|
226
|
+
// Request Params attributes : Start
|
|
227
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_MAX_TOKENS, max_tokens);
|
|
228
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_TEMPERATURE, temperature);
|
|
229
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_PRESENCE_PENALTY, presence_penalty);
|
|
230
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_FREQUENCY_PENALTY, frequency_penalty);
|
|
231
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_SEED, seed);
|
|
232
|
+
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_IS_STREAM, stream);
|
|
233
|
+
|
|
234
|
+
if (traceContent) {
|
|
235
|
+
span.setAttribute(SemanticConvention.GEN_AI_CONTENT_PROMPT, message);
|
|
236
|
+
}
|
|
237
|
+
// Request Params attributes : End
|
|
238
|
+
|
|
239
|
+
span.setAttribute(SemanticConvention.GEN_AI_TYPE, SemanticConvention.GEN_AI_TYPE_CHAT);
|
|
240
|
+
|
|
241
|
+
span.setAttribute(SemanticConvention.GEN_AI_RESPONSE_ID, result.response_id);
|
|
242
|
+
|
|
243
|
+
const pricingInfo = await OpenlitConfig.updatePricingJson(OpenlitConfig.pricing_json);
|
|
244
|
+
|
|
245
|
+
// Calculate cost of the operation
|
|
246
|
+
const cost = OpenLitHelper.getChatModelCost(
|
|
247
|
+
model,
|
|
248
|
+
pricingInfo,
|
|
249
|
+
result.meta.billedUnits.inputTokens,
|
|
250
|
+
result.meta.billedUnits.outputTokens
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
CohereWrapper.setBaseSpanAttributes(span, {
|
|
254
|
+
genAIEndpoint,
|
|
255
|
+
model,
|
|
256
|
+
user,
|
|
257
|
+
cost,
|
|
258
|
+
aiSystem: CohereWrapper.aiSystem,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
span.setAttribute(
|
|
262
|
+
SemanticConvention.GEN_AI_USAGE_PROMPT_TOKENS,
|
|
263
|
+
result.meta.billedUnits.inputTokens
|
|
264
|
+
);
|
|
265
|
+
span.setAttribute(
|
|
266
|
+
SemanticConvention.GEN_AI_USAGE_COMPLETION_TOKENS,
|
|
267
|
+
result.meta.billedUnits.outputTokens
|
|
268
|
+
);
|
|
269
|
+
span.setAttribute(
|
|
270
|
+
SemanticConvention.GEN_AI_USAGE_TOTAL_TOKENS,
|
|
271
|
+
result.meta.billedUnits.inputTokens + result.meta.billedUnits.outputTokens
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
if (result.finishReason) {
|
|
275
|
+
span.setAttribute(SemanticConvention.GEN_AI_RESPONSE_FINISH_REASON, result.finishReason);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (tools) {
|
|
279
|
+
span.setAttribute(SemanticConvention.GEN_AI_CONTENT_COMPLETION, 'Function called with tools');
|
|
280
|
+
} else {
|
|
281
|
+
if (traceContent) {
|
|
282
|
+
span.setAttribute(SemanticConvention.GEN_AI_CONTENT_COMPLETION, result.text);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -4,11 +4,13 @@ import { InstrumentationType, OpenlitInstrumentations } from '../types';
|
|
|
4
4
|
import { TracerProvider } from '@opentelemetry/api';
|
|
5
5
|
import OpenAIInstrumentation from './openai';
|
|
6
6
|
import AnthropicInstrumentation from './anthropic';
|
|
7
|
+
import CohereInstrumentation from './cohere';
|
|
7
8
|
|
|
8
9
|
export default class Instrumentations {
|
|
9
10
|
static availableInstrumentations: OpenlitInstrumentations = {
|
|
10
11
|
openai: new OpenAIInstrumentation(),
|
|
11
12
|
anthropic: new AnthropicInstrumentation(),
|
|
13
|
+
cohere: new CohereInstrumentation(),
|
|
12
14
|
};
|
|
13
15
|
|
|
14
16
|
static setup(
|
|
@@ -1,30 +1,11 @@
|
|
|
1
|
-
import { Span, SpanKind,
|
|
1
|
+
import { Span, SpanKind, Tracer, context, trace } from '@opentelemetry/api';
|
|
2
2
|
import OpenlitConfig from '../../config';
|
|
3
3
|
import OpenLitHelper from '../../helpers';
|
|
4
4
|
import SemanticConvention from '../../semantic-convention';
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
export default class OpenAIWrapper {
|
|
8
|
-
static setBaseSpanAttributes(
|
|
9
|
-
span: any,
|
|
10
|
-
{ genAIEndpoint, model, user, cost, environment, applicationName }: any
|
|
11
|
-
) {
|
|
12
|
-
span.setAttributes({
|
|
13
|
-
[TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
span.setAttribute(TELEMETRY_SDK_NAME, SDK_NAME);
|
|
17
|
-
span.setAttribute(SemanticConvention.GEN_AI_SYSTEM, SemanticConvention.GEN_AI_SYSTEM_OPENAI);
|
|
18
|
-
span.setAttribute(SemanticConvention.GEN_AI_ENDPOINT, genAIEndpoint);
|
|
19
|
-
span.setAttribute(SemanticConvention.GEN_AI_ENVIRONMENT, environment);
|
|
20
|
-
span.setAttribute(SemanticConvention.GEN_AI_APPLICATION_NAME, applicationName);
|
|
21
|
-
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_MODEL, model);
|
|
22
|
-
span.setAttribute(SemanticConvention.GEN_AI_REQUEST_USER, user);
|
|
23
|
-
if (cost !== undefined) span.setAttribute(SemanticConvention.GEN_AI_USAGE_COST, cost);
|
|
24
|
-
|
|
25
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
26
|
-
}
|
|
5
|
+
import BaseWrapper from '../base-wrapper';
|
|
27
6
|
|
|
7
|
+
export default class OpenAIWrapper extends BaseWrapper {
|
|
8
|
+
static aiSystem = SemanticConvention.GEN_AI_SYSTEM_OPENAI;
|
|
28
9
|
static _patchChatCompletionCreate(tracer: Tracer): any {
|
|
29
10
|
const genAIEndpoint = 'openai.resources.chat.completions';
|
|
30
11
|
return (originalMethod: (...args: any[]) => any) => {
|
|
@@ -184,8 +165,6 @@ export default class OpenAIWrapper {
|
|
|
184
165
|
result: any;
|
|
185
166
|
span: Span;
|
|
186
167
|
}) {
|
|
187
|
-
const applicationName = OpenlitConfig.applicationName;
|
|
188
|
-
const environment = OpenlitConfig.environment;
|
|
189
168
|
const traceContent = OpenlitConfig.traceContent;
|
|
190
169
|
const {
|
|
191
170
|
messages,
|
|
@@ -261,8 +240,7 @@ export default class OpenAIWrapper {
|
|
|
261
240
|
model,
|
|
262
241
|
user,
|
|
263
242
|
cost,
|
|
264
|
-
|
|
265
|
-
environment,
|
|
243
|
+
aiSystem: OpenAIWrapper.aiSystem,
|
|
266
244
|
});
|
|
267
245
|
|
|
268
246
|
span.setAttribute(SemanticConvention.GEN_AI_USAGE_PROMPT_TOKENS, result.usage.prompt_tokens);
|
|
@@ -302,8 +280,6 @@ export default class OpenAIWrapper {
|
|
|
302
280
|
|
|
303
281
|
static _patchEmbedding(tracer: Tracer): any {
|
|
304
282
|
const genAIEndpoint = 'openai.resources.embeddings';
|
|
305
|
-
const applicationName = OpenlitConfig.applicationName;
|
|
306
|
-
const environment = OpenlitConfig.environment;
|
|
307
283
|
const traceContent = OpenlitConfig.traceContent;
|
|
308
284
|
|
|
309
285
|
return (originalMethod: (...args: any[]) => any) => {
|
|
@@ -312,9 +288,6 @@ export default class OpenAIWrapper {
|
|
|
312
288
|
return context.with(trace.setSpan(context.active(), span), async () => {
|
|
313
289
|
try {
|
|
314
290
|
const response = await originalMethod.apply(this, args);
|
|
315
|
-
span.setAttributes({
|
|
316
|
-
[TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
317
|
-
});
|
|
318
291
|
|
|
319
292
|
const model = response.model || 'text-embedding-ada-002';
|
|
320
293
|
const pricingInfo = await OpenlitConfig.updatePricingJson(OpenlitConfig.pricing_json);
|
|
@@ -336,8 +309,7 @@ export default class OpenAIWrapper {
|
|
|
336
309
|
model,
|
|
337
310
|
user,
|
|
338
311
|
cost,
|
|
339
|
-
|
|
340
|
-
environment,
|
|
312
|
+
aiSystem: OpenAIWrapper.aiSystem,
|
|
341
313
|
});
|
|
342
314
|
|
|
343
315
|
// Request Params attributes : Start
|
|
@@ -371,8 +343,6 @@ export default class OpenAIWrapper {
|
|
|
371
343
|
|
|
372
344
|
static _patchFineTune(tracer: Tracer): any {
|
|
373
345
|
const genAIEndpoint = 'openai.resources.fine_tuning.jobs';
|
|
374
|
-
const applicationName = OpenlitConfig.applicationName;
|
|
375
|
-
const environment = OpenlitConfig.environment;
|
|
376
346
|
|
|
377
347
|
return (originalMethod: (...args: any[]) => any) => {
|
|
378
348
|
return async function (this: any, ...args: any[]) {
|
|
@@ -380,9 +350,6 @@ export default class OpenAIWrapper {
|
|
|
380
350
|
return context.with(trace.setSpan(context.active(), span), async () => {
|
|
381
351
|
try {
|
|
382
352
|
const response = await originalMethod.apply(this, args);
|
|
383
|
-
span.setAttributes({
|
|
384
|
-
[TELEMETRY_SDK_NAME]: SDK_NAME,
|
|
385
|
-
});
|
|
386
353
|
|
|
387
354
|
const model = response.model || 'gpt-3.5-turbo';
|
|
388
355
|
const {
|
|
@@ -398,8 +365,7 @@ export default class OpenAIWrapper {
|
|
|
398
365
|
genAIEndpoint,
|
|
399
366
|
model,
|
|
400
367
|
user,
|
|
401
|
-
|
|
402
|
-
environment,
|
|
368
|
+
aiSystem: OpenAIWrapper.aiSystem,
|
|
403
369
|
});
|
|
404
370
|
|
|
405
371
|
span.setAttribute(
|
|
@@ -446,8 +412,6 @@ export default class OpenAIWrapper {
|
|
|
446
412
|
|
|
447
413
|
static _patchImageGenerate(tracer: Tracer): any {
|
|
448
414
|
const genAIEndpoint = 'openai.resources.images';
|
|
449
|
-
const applicationName = OpenlitConfig.applicationName;
|
|
450
|
-
const environment = OpenlitConfig.environment;
|
|
451
415
|
const traceContent = OpenlitConfig.traceContent;
|
|
452
416
|
return (originalMethod: (...args: any[]) => any) => {
|
|
453
417
|
return async function (this: any, ...args: any[]) {
|
|
@@ -481,8 +445,7 @@ export default class OpenAIWrapper {
|
|
|
481
445
|
model,
|
|
482
446
|
user,
|
|
483
447
|
cost,
|
|
484
|
-
|
|
485
|
-
environment,
|
|
448
|
+
aiSystem: OpenAIWrapper.aiSystem,
|
|
486
449
|
});
|
|
487
450
|
|
|
488
451
|
// Request Params attributes : Start
|
|
@@ -524,8 +487,6 @@ export default class OpenAIWrapper {
|
|
|
524
487
|
|
|
525
488
|
static _patchImageVariation(tracer: Tracer): any {
|
|
526
489
|
const genAIEndpoint = 'openai.resources.images';
|
|
527
|
-
const applicationName = OpenlitConfig.applicationName;
|
|
528
|
-
const environment = OpenlitConfig.environment;
|
|
529
490
|
const traceContent = OpenlitConfig.traceContent;
|
|
530
491
|
return (originalMethod: (...args: any[]) => any) => {
|
|
531
492
|
return async function (this: any, ...args: any[]) {
|
|
@@ -560,8 +521,7 @@ export default class OpenAIWrapper {
|
|
|
560
521
|
model,
|
|
561
522
|
user,
|
|
562
523
|
cost,
|
|
563
|
-
|
|
564
|
-
environment,
|
|
524
|
+
aiSystem: OpenAIWrapper.aiSystem,
|
|
565
525
|
});
|
|
566
526
|
|
|
567
527
|
// Request Params attributes : Start
|
|
@@ -602,8 +562,6 @@ export default class OpenAIWrapper {
|
|
|
602
562
|
|
|
603
563
|
static _patchAudioCreate(tracer: Tracer): any {
|
|
604
564
|
const genAIEndpoint = 'openai.resources.audio.speech';
|
|
605
|
-
const applicationName = OpenlitConfig.applicationName;
|
|
606
|
-
const environment = OpenlitConfig.environment;
|
|
607
565
|
const traceContent = OpenlitConfig.traceContent;
|
|
608
566
|
return (originalMethod: (...args: any[]) => any) => {
|
|
609
567
|
return async function (this: any, ...args: any[]) {
|
|
@@ -628,8 +586,7 @@ export default class OpenAIWrapper {
|
|
|
628
586
|
model,
|
|
629
587
|
user,
|
|
630
588
|
cost,
|
|
631
|
-
|
|
632
|
-
environment,
|
|
589
|
+
aiSystem: OpenAIWrapper.aiSystem,
|
|
633
590
|
});
|
|
634
591
|
|
|
635
592
|
// Request Params attributes : Start
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import OpenlitConfig from './config';
|
|
2
|
+
import { OPENLIT_URL } from './constant';
|
|
3
|
+
import { PromptHubOptions } from './types';
|
|
4
|
+
|
|
5
|
+
export default class PromptHub {
|
|
6
|
+
static async getPrompts(options: PromptHubOptions) {
|
|
7
|
+
const url = process.env.OPENLIT_URL || options.url || OPENLIT_URL;
|
|
8
|
+
const apiKey = process.env.OPENLIT_API_KEY || options.apiKey || '';
|
|
9
|
+
let metaProperties = {
|
|
10
|
+
applicationName: OpenlitConfig.applicationName,
|
|
11
|
+
environment: OpenlitConfig.environment,
|
|
12
|
+
};
|
|
13
|
+
if (
|
|
14
|
+
options.metaProperties &&
|
|
15
|
+
typeof options.metaProperties === 'object' &&
|
|
16
|
+
!Array.isArray(options.metaProperties)
|
|
17
|
+
) {
|
|
18
|
+
metaProperties = {
|
|
19
|
+
...metaProperties,
|
|
20
|
+
...options.metaProperties,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
return await fetch(`${url}/api/prompt/get-compiled`, {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
name: options.name,
|
|
29
|
+
version: options.version,
|
|
30
|
+
shouldCompile: !!options.shouldCompile,
|
|
31
|
+
variables: options.variables || {},
|
|
32
|
+
id: options.promptId,
|
|
33
|
+
metaProperties,
|
|
34
|
+
source: 'ts-sdk',
|
|
35
|
+
}),
|
|
36
|
+
headers: {
|
|
37
|
+
Authorization: `Bearer ${apiKey}`,
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
.then(async (response) => {
|
|
41
|
+
if (!response.ok) {
|
|
42
|
+
return {
|
|
43
|
+
err: `Openlit Error : HTTP error! Status: ${response.status}`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return response.json();
|
|
47
|
+
})
|
|
48
|
+
.then((resp: any) => {
|
|
49
|
+
return resp;
|
|
50
|
+
});
|
|
51
|
+
} catch (e: any) {
|
|
52
|
+
if (e && typeof e.toString === 'function') {
|
|
53
|
+
return {
|
|
54
|
+
err: `Openlit Error : ${e.toString()}`,
|
|
55
|
+
data: null,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
err: `Openlit Error : ${e}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Resource } from '@opentelemetry/resources';
|
|
3
3
|
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
|
|
4
4
|
|
|
5
|
-
export type InstrumentationType = 'openai' | 'anthropic';
|
|
5
|
+
export type InstrumentationType = 'openai' | 'anthropic' | 'cohere';
|
|
6
6
|
|
|
7
7
|
export type OpenlitInstrumentations = Partial<Record<InstrumentationType, any>>;
|
|
8
8
|
|
|
@@ -46,3 +46,14 @@ export type OpenlitOptions = {
|
|
|
46
46
|
export type SetupTracerOptions = OpenlitOptions & {
|
|
47
47
|
resource: Resource;
|
|
48
48
|
};
|
|
49
|
+
|
|
50
|
+
export type PromptHubOptions = {
|
|
51
|
+
url?: string;
|
|
52
|
+
apiKey?: string;
|
|
53
|
+
name?: string;
|
|
54
|
+
version?: string;
|
|
55
|
+
shouldCompile?: boolean;
|
|
56
|
+
variables?: Record<string, any>;
|
|
57
|
+
promptId?: string;
|
|
58
|
+
metaProperties?: Record<string, any>;
|
|
59
|
+
};
|