openlayer 0.4.0 → 0.7.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/CHANGELOG.md +35 -0
- package/README.md +6 -6
- package/index.d.mts +5 -0
- package/index.d.ts +5 -0
- package/index.d.ts.map +1 -1
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/index.mjs +2 -0
- package/index.mjs.map +1 -1
- package/lib/core/openai-monitor.d.ts +3 -0
- package/lib/core/openai-monitor.d.ts.map +1 -1
- package/lib/core/openai-monitor.js +7 -1
- package/lib/core/openai-monitor.js.map +1 -1
- package/lib/core/openai-monitor.mjs +4 -1
- package/lib/core/openai-monitor.mjs.map +1 -1
- package/lib/integrations/langchainCallback.d.ts +33 -0
- package/lib/integrations/langchainCallback.d.ts.map +1 -0
- package/lib/integrations/langchainCallback.js +114 -0
- package/lib/integrations/langchainCallback.js.map +1 -0
- package/lib/integrations/langchainCallback.mjs +110 -0
- package/lib/integrations/langchainCallback.mjs.map +1 -0
- package/lib/integrations/openAiTracer.d.ts +3 -0
- package/lib/integrations/openAiTracer.d.ts.map +1 -0
- package/lib/integrations/openAiTracer.js +125 -0
- package/lib/integrations/openAiTracer.js.map +1 -0
- package/lib/integrations/openAiTracer.mjs +121 -0
- package/lib/integrations/openAiTracer.mjs.map +1 -0
- package/lib/tracing/enums.d.ts +5 -0
- package/lib/tracing/enums.d.ts.map +1 -0
- package/lib/tracing/enums.js +9 -0
- package/lib/tracing/enums.js.map +1 -0
- package/lib/tracing/enums.mjs +6 -0
- package/lib/tracing/enums.mjs.map +1 -0
- package/lib/tracing/steps.d.ts +57 -0
- package/lib/tracing/steps.d.ts.map +1 -0
- package/lib/tracing/steps.js +84 -0
- package/lib/tracing/steps.js.map +1 -0
- package/lib/tracing/steps.mjs +78 -0
- package/lib/tracing/steps.mjs.map +1 -0
- package/lib/tracing/tracer.d.ts +18 -0
- package/lib/tracing/tracer.d.ts.map +1 -0
- package/lib/tracing/tracer.js +155 -0
- package/lib/tracing/tracer.js.map +1 -0
- package/lib/tracing/tracer.mjs +148 -0
- package/lib/tracing/tracer.mjs.map +1 -0
- package/lib/tracing/traces.d.ts +9 -0
- package/lib/tracing/traces.d.ts.map +1 -0
- package/lib/tracing/traces.js +17 -0
- package/lib/tracing/traces.js.map +1 -0
- package/lib/tracing/traces.mjs +13 -0
- package/lib/tracing/traces.mjs.map +1 -0
- package/package.json +2 -1
- package/resources/index.d.ts +2 -1
- package/resources/index.d.ts.map +1 -1
- package/resources/index.js +3 -1
- package/resources/index.js.map +1 -1
- package/resources/index.mjs +2 -1
- package/resources/index.mjs.map +1 -1
- package/resources/inference-pipelines/data.d.ts +1 -1
- package/resources/inference-pipelines/data.js +1 -1
- package/resources/inference-pipelines/data.mjs +1 -1
- package/resources/inference-pipelines/index.d.ts +1 -1
- package/resources/inference-pipelines/index.d.ts.map +1 -1
- package/resources/inference-pipelines/index.js.map +1 -1
- package/resources/inference-pipelines/index.mjs +1 -1
- package/resources/inference-pipelines/index.mjs.map +1 -1
- package/resources/inference-pipelines/inference-pipelines.d.ts +161 -0
- package/resources/inference-pipelines/inference-pipelines.d.ts.map +1 -1
- package/resources/inference-pipelines/inference-pipelines.js +22 -0
- package/resources/inference-pipelines/inference-pipelines.js.map +1 -1
- package/resources/inference-pipelines/inference-pipelines.mjs +22 -0
- package/resources/inference-pipelines/inference-pipelines.mjs.map +1 -1
- package/resources/storage/index.d.ts +3 -0
- package/resources/storage/index.d.ts.map +1 -0
- package/resources/storage/index.js +9 -0
- package/resources/storage/index.js.map +1 -0
- package/resources/storage/index.mjs +4 -0
- package/resources/storage/index.mjs.map +1 -0
- package/resources/storage/presigned-url.d.ts +34 -0
- package/resources/storage/presigned-url.d.ts.map +1 -0
- package/resources/storage/presigned-url.js +18 -0
- package/resources/storage/presigned-url.js.map +1 -0
- package/resources/storage/presigned-url.mjs +14 -0
- package/resources/storage/presigned-url.mjs.map +1 -0
- package/resources/storage/storage.d.ts +11 -0
- package/resources/storage/storage.d.ts.map +1 -0
- package/resources/storage/storage.js +40 -0
- package/resources/storage/storage.js.map +1 -0
- package/resources/storage/storage.mjs +13 -0
- package/resources/storage/storage.mjs.map +1 -0
- package/src/index.ts +6 -0
- package/src/lib/core/openai-monitor.ts +7 -1
- package/src/lib/index.d.ts +1 -0
- package/src/lib/integrations/langchainCallback.ts +141 -0
- package/src/lib/integrations/openAiTracer.ts +137 -0
- package/src/lib/tracing/enums.ts +4 -0
- package/src/lib/tracing/index.d.ts +1 -0
- package/src/lib/tracing/steps.ts +118 -0
- package/src/lib/tracing/tracer.ts +204 -0
- package/src/lib/tracing/traces.ts +19 -0
- package/src/resources/index.ts +7 -1
- package/src/resources/inference-pipelines/data.ts +1 -1
- package/src/resources/inference-pipelines/index.ts +6 -1
- package/src/resources/inference-pipelines/inference-pipelines.ts +227 -0
- package/src/resources/storage/index.ts +4 -0
- package/src/resources/storage/presigned-url.ts +47 -0
- package/src/resources/storage/storage.ts +14 -0
- package/src/version.ts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
- package/src/lib/.keep +0 -4
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
2
|
+
import { LLMResult } from '@langchain/core/dist/outputs';
|
|
3
|
+
import type { Serialized } from '@langchain/core/load/serializable';
|
|
4
|
+
import { AIMessage, BaseMessage, SystemMessage } from '@langchain/core/messages';
|
|
5
|
+
import { addChatCompletionStepToTrace } from '../tracing/tracer';
|
|
6
|
+
|
|
7
|
+
const LANGCHAIN_TO_OPENLAYER_PROVIDER_MAP: Record<string, string> = {
|
|
8
|
+
openai: 'OpenAI',
|
|
9
|
+
'openai-chat': 'OpenAI',
|
|
10
|
+
'chat-ollama': 'Ollama',
|
|
11
|
+
vertexai: 'Google',
|
|
12
|
+
};
|
|
13
|
+
const PROVIDER_TO_STEP_NAME: Record<string, string> = {
|
|
14
|
+
OpenAI: 'OpenAI Chat Completion',
|
|
15
|
+
Ollama: 'Ollama Chat Completion',
|
|
16
|
+
Google: 'Google Vertex AI Chat Completion',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export class OpenlayerHandler extends BaseCallbackHandler {
|
|
20
|
+
name = 'OpenlayerHandler';
|
|
21
|
+
startTime: number | null = null;
|
|
22
|
+
endTime: number | null = null;
|
|
23
|
+
prompt: Array<{ role: string; content: string }> | null = null;
|
|
24
|
+
latency: number = 0;
|
|
25
|
+
provider: string | undefined;
|
|
26
|
+
model: string | null = null;
|
|
27
|
+
modelParameters: Record<string, any> | null = null;
|
|
28
|
+
promptTokens: number | null = 0;
|
|
29
|
+
completionTokens: number | null = 0;
|
|
30
|
+
totalTokens: number | null = 0;
|
|
31
|
+
output: string = '';
|
|
32
|
+
metadata: Record<string, any>;
|
|
33
|
+
|
|
34
|
+
constructor(kwargs: Record<string, any> = {}) {
|
|
35
|
+
super();
|
|
36
|
+
this.metadata = kwargs;
|
|
37
|
+
}
|
|
38
|
+
override async handleChatModelStart(
|
|
39
|
+
llm: Serialized,
|
|
40
|
+
messages: BaseMessage[][],
|
|
41
|
+
runId: string,
|
|
42
|
+
parentRunId?: string | undefined,
|
|
43
|
+
extraParams?: Record<string, unknown> | undefined,
|
|
44
|
+
tags?: string[] | undefined,
|
|
45
|
+
metadata?: Record<string, unknown> | undefined,
|
|
46
|
+
name?: string,
|
|
47
|
+
): Promise<void> {
|
|
48
|
+
this.initializeRun(extraParams || {}, metadata || {});
|
|
49
|
+
this.prompt = this.langchainMassagesToPrompt(messages);
|
|
50
|
+
this.startTime = performance.now();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private initializeRun(extraParams: Record<string, any>, metadata: Record<string, unknown>): void {
|
|
54
|
+
this.modelParameters = extraParams['invocation_params'] || {};
|
|
55
|
+
|
|
56
|
+
const provider = metadata?.['ls_provider'] as string;
|
|
57
|
+
if (provider && LANGCHAIN_TO_OPENLAYER_PROVIDER_MAP[provider]) {
|
|
58
|
+
this.provider = LANGCHAIN_TO_OPENLAYER_PROVIDER_MAP[provider];
|
|
59
|
+
}
|
|
60
|
+
this.model = (this.modelParameters?.['model'] as string) || (metadata['ls_model_name'] as string) || null;
|
|
61
|
+
this.output = '';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private langchainMassagesToPrompt(messages: BaseMessage[][]): Array<{ role: string; content: string }> {
|
|
65
|
+
let prompt: Array<{ role: string; content: string }> = [];
|
|
66
|
+
for (const message of messages) {
|
|
67
|
+
for (const m of message) {
|
|
68
|
+
if (m instanceof AIMessage) {
|
|
69
|
+
prompt.push({ role: 'assistant', content: m.content as string });
|
|
70
|
+
} else if (m instanceof SystemMessage) {
|
|
71
|
+
prompt.push({ role: 'system', content: m.content as string });
|
|
72
|
+
} else {
|
|
73
|
+
prompt.push({ role: 'user', content: m.content as string });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return prompt;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
override async handleLLMStart(
|
|
81
|
+
llm: Serialized,
|
|
82
|
+
prompts: string[],
|
|
83
|
+
runId: string,
|
|
84
|
+
parentRunId?: string,
|
|
85
|
+
extraParams?: Record<string, unknown>,
|
|
86
|
+
tags?: string[],
|
|
87
|
+
metadata?: Record<string, unknown>,
|
|
88
|
+
runName?: string,
|
|
89
|
+
) {
|
|
90
|
+
this.initializeRun(extraParams || {}, metadata || {});
|
|
91
|
+
this.prompt = prompts.map((p) => ({ role: 'user', content: p }));
|
|
92
|
+
this.startTime = performance.now();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
override async handleLLMEnd(output: LLMResult, runId: string, parentRunId?: string, tags?: string[]) {
|
|
96
|
+
this.endTime = performance.now();
|
|
97
|
+
this.latency = this.endTime - this.startTime!;
|
|
98
|
+
this.extractTokenInformation(output);
|
|
99
|
+
this.extractOutput(output);
|
|
100
|
+
this.addToTrace();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private extractTokenInformation(output: LLMResult) {
|
|
104
|
+
if (this.provider === 'OpenAI') {
|
|
105
|
+
this.openaiTokenInformation(output);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private openaiTokenInformation(output: LLMResult) {
|
|
110
|
+
if (output.llmOutput && 'tokenUsage' in output.llmOutput) {
|
|
111
|
+
this.promptTokens = output.llmOutput?.['tokenUsage']?.promptTokens ?? 0;
|
|
112
|
+
this.completionTokens = output.llmOutput?.['tokenUsage']?.completionTokens ?? 0;
|
|
113
|
+
this.totalTokens = output.llmOutput?.['tokenUsage']?.totalTokens ?? 0;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private extractOutput(output: LLMResult) {
|
|
118
|
+
const lastResponse = output?.generations?.at(-1)?.at(-1) ?? undefined;
|
|
119
|
+
this.output += lastResponse?.text ?? '';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private addToTrace() {
|
|
123
|
+
let name = 'Chat Completion Model';
|
|
124
|
+
if (this.provider && this.provider in PROVIDER_TO_STEP_NAME) {
|
|
125
|
+
name = PROVIDER_TO_STEP_NAME[this.provider] ?? 'Chat Completion Model';
|
|
126
|
+
}
|
|
127
|
+
addChatCompletionStepToTrace({
|
|
128
|
+
name: name,
|
|
129
|
+
inputs: { prompt: this.prompt },
|
|
130
|
+
output: this.output,
|
|
131
|
+
latency: this.latency,
|
|
132
|
+
tokens: this.totalTokens,
|
|
133
|
+
promptTokens: this.promptTokens,
|
|
134
|
+
completionTokens: this.completionTokens,
|
|
135
|
+
model: this.model,
|
|
136
|
+
modelParameters: this.modelParameters,
|
|
137
|
+
metadata: this.metadata,
|
|
138
|
+
provider: this.provider ?? '',
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { Stream } from 'openai/src/streaming';
|
|
3
|
+
import { addChatCompletionStepToTrace } from '../tracing/tracer';
|
|
4
|
+
|
|
5
|
+
export function traceOpenAI(openai: OpenAI): OpenAI {
|
|
6
|
+
const createFunction = openai.chat.completions.create;
|
|
7
|
+
|
|
8
|
+
openai.chat.completions.create = async function (
|
|
9
|
+
this: typeof openai.chat.completions,
|
|
10
|
+
...args: Parameters<typeof createFunction>
|
|
11
|
+
): Promise<Stream<OpenAI.Chat.Completions.ChatCompletionChunk> | OpenAI.Chat.Completions.ChatCompletion> {
|
|
12
|
+
const [params, options] = args;
|
|
13
|
+
const stream = params?.stream ?? false;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const startTime = performance.now();
|
|
17
|
+
|
|
18
|
+
// Call the original `create` function
|
|
19
|
+
let response = await createFunction.apply(this, args);
|
|
20
|
+
|
|
21
|
+
if (stream) {
|
|
22
|
+
// Handle streaming responses
|
|
23
|
+
const chunks: OpenAI.Chat.Completions.ChatCompletionChunk[] = [];
|
|
24
|
+
let collectedOutputData: any[] = [];
|
|
25
|
+
let firstTokenTime: number | undefined;
|
|
26
|
+
let completionTokens: number = 0;
|
|
27
|
+
if (isAsyncIterable(response)) {
|
|
28
|
+
async function* tracedOutputGenerator(): AsyncGenerator<
|
|
29
|
+
OpenAI.Chat.Completions.ChatCompletionChunk,
|
|
30
|
+
void,
|
|
31
|
+
unknown
|
|
32
|
+
> {
|
|
33
|
+
for await (const rawChunk of response as AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>) {
|
|
34
|
+
if (chunks.length === 0) {
|
|
35
|
+
firstTokenTime = performance.now();
|
|
36
|
+
}
|
|
37
|
+
chunks.push(rawChunk);
|
|
38
|
+
const delta = rawChunk.choices[0]?.delta;
|
|
39
|
+
if (delta?.content) {
|
|
40
|
+
collectedOutputData.push(delta?.content);
|
|
41
|
+
} else if (delta?.tool_calls) {
|
|
42
|
+
const tool_call = delta.tool_calls[0];
|
|
43
|
+
if (tool_call?.function?.name) {
|
|
44
|
+
const functionName: string =
|
|
45
|
+
'{\n "name": ' + '"' + tool_call.function.name + '"' + '\n "arguments": ';
|
|
46
|
+
collectedOutputData.push(functionName);
|
|
47
|
+
} else if (tool_call?.function?.arguments) {
|
|
48
|
+
collectedOutputData.push(tool_call.function.arguments);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (rawChunk.choices[0]?.finish_reason === 'tool_calls') {
|
|
53
|
+
collectedOutputData.push('\n}');
|
|
54
|
+
}
|
|
55
|
+
completionTokens += 1;
|
|
56
|
+
yield rawChunk;
|
|
57
|
+
}
|
|
58
|
+
const endTime = performance.now();
|
|
59
|
+
const traceData = {
|
|
60
|
+
name: 'OpenAI Chat Completion',
|
|
61
|
+
inputs: { prompt: params.messages },
|
|
62
|
+
output: collectedOutputData.join(''),
|
|
63
|
+
latency: endTime - startTime,
|
|
64
|
+
model: chunks[0]?.model as string,
|
|
65
|
+
modelParameters: getModelParameters(args),
|
|
66
|
+
rawOutput: chunks.map((chunk) => JSON.stringify(chunk, null, 2)).join('\n'),
|
|
67
|
+
metadata: { timeToFistToken: firstTokenTime ? firstTokenTime - startTime : null },
|
|
68
|
+
provider: 'OpenAI',
|
|
69
|
+
completionTokens: completionTokens,
|
|
70
|
+
promptTokens: 0,
|
|
71
|
+
tokens: completionTokens,
|
|
72
|
+
};
|
|
73
|
+
addChatCompletionStepToTrace(traceData);
|
|
74
|
+
}
|
|
75
|
+
return tracedOutputGenerator() as unknown as Stream<OpenAI.Chat.Completions.ChatCompletionChunk>;
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
// Handle non-streaming responses
|
|
79
|
+
response = response as OpenAI.Chat.Completions.ChatCompletion;
|
|
80
|
+
const completion = response.choices[0];
|
|
81
|
+
const endTime = performance.now();
|
|
82
|
+
|
|
83
|
+
let output: string = '';
|
|
84
|
+
if (completion?.message?.content) {
|
|
85
|
+
output = completion.message.content;
|
|
86
|
+
} else if (completion?.message.tool_calls) {
|
|
87
|
+
const tool_call = completion.message.tool_calls[0];
|
|
88
|
+
output = JSON.stringify(tool_call?.function, null, 2);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const traceData = {
|
|
92
|
+
name: 'OpenAI Chat Completion',
|
|
93
|
+
inputs: { prompt: params.messages },
|
|
94
|
+
output: output,
|
|
95
|
+
latency: endTime - startTime,
|
|
96
|
+
tokens: response.usage?.total_tokens ?? null,
|
|
97
|
+
promptTokens: response.usage?.prompt_tokens ?? null,
|
|
98
|
+
completionTokens: response.usage?.completion_tokens ?? null,
|
|
99
|
+
model: response.model,
|
|
100
|
+
modelParameters: getModelParameters(args),
|
|
101
|
+
rawOutput: JSON.stringify(response, null, 2),
|
|
102
|
+
metadata: {},
|
|
103
|
+
provider: 'OpenAI',
|
|
104
|
+
};
|
|
105
|
+
addChatCompletionStepToTrace(traceData);
|
|
106
|
+
return response;
|
|
107
|
+
}
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('Failed to trace the create chat completion request with Openlayer', error);
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
// Ensure a return statement is present
|
|
113
|
+
return undefined as any;
|
|
114
|
+
} as typeof createFunction;
|
|
115
|
+
|
|
116
|
+
return openai;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function getModelParameters(args: any): Record<string, any> {
|
|
120
|
+
const params = args[0];
|
|
121
|
+
return {
|
|
122
|
+
frequency_penalty: params?.frequencyPenalty ?? 0,
|
|
123
|
+
logit_bias: params?.logitBias ?? null,
|
|
124
|
+
logprobs: params?.logprobs ?? false,
|
|
125
|
+
top_logprobs: params?.topLogprobs ?? null,
|
|
126
|
+
max_tokens: params?.maxTokens ?? null,
|
|
127
|
+
n: params?.n ?? 1,
|
|
128
|
+
presence_penalty: params?.presencePenalty ?? 0,
|
|
129
|
+
seed: params?.seed ?? null,
|
|
130
|
+
stop: params?.stop ?? null,
|
|
131
|
+
temperature: params?.temperature ?? 1,
|
|
132
|
+
top_p: params?.topP ?? 1,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const isAsyncIterable = (x: any) =>
|
|
137
|
+
x != null && typeof x === 'object' && typeof x[Symbol.asyncIterator] === 'function';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as tracer from './tracer';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import { StepType } from './enums';
|
|
3
|
+
|
|
4
|
+
export interface StepData {
|
|
5
|
+
name: string;
|
|
6
|
+
id: string;
|
|
7
|
+
type: StepType;
|
|
8
|
+
inputs: any;
|
|
9
|
+
output: any;
|
|
10
|
+
groundTruth: any;
|
|
11
|
+
metadata: Record<string, any>;
|
|
12
|
+
steps: StepData[];
|
|
13
|
+
latency: number | null;
|
|
14
|
+
startTime: number;
|
|
15
|
+
endTime: number | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ChatCompletionStepData extends StepData {
|
|
19
|
+
provider: string | null;
|
|
20
|
+
promptTokens: number | null;
|
|
21
|
+
completionTokens: number | null;
|
|
22
|
+
tokens: number | null;
|
|
23
|
+
cost: number | null;
|
|
24
|
+
model: string | null;
|
|
25
|
+
modelParameters: Record<string, any> | null;
|
|
26
|
+
rawOutput: string | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class Step {
|
|
30
|
+
name: string;
|
|
31
|
+
id: string;
|
|
32
|
+
inputs: any;
|
|
33
|
+
output: any;
|
|
34
|
+
metadata: Record<string, any>;
|
|
35
|
+
stepType: StepType | null = null;
|
|
36
|
+
startTime: number;
|
|
37
|
+
endTime: number | null = null;
|
|
38
|
+
groundTruth: any = null;
|
|
39
|
+
latency: number | null = null;
|
|
40
|
+
steps: Step[] = [];
|
|
41
|
+
|
|
42
|
+
constructor(name: string, inputs: any = null, output: any = null, metadata: Record<string, any> = {}) {
|
|
43
|
+
this.name = name;
|
|
44
|
+
this.id = uuidv4();
|
|
45
|
+
this.inputs = inputs;
|
|
46
|
+
this.output = output;
|
|
47
|
+
this.metadata = metadata;
|
|
48
|
+
|
|
49
|
+
this.startTime = Date.now();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
addNestedStep(nestedStep: Step): void {
|
|
53
|
+
this.steps.push(nestedStep);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
log(data: Partial<Record<keyof this, any>>): void {
|
|
57
|
+
Object.keys(data).forEach((key) => {
|
|
58
|
+
if (key in this) {
|
|
59
|
+
// @ts-ignore
|
|
60
|
+
this[key] = data[key];
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
toJSON(): StepData {
|
|
66
|
+
return {
|
|
67
|
+
name: this.name,
|
|
68
|
+
id: this.id,
|
|
69
|
+
type: this.stepType!,
|
|
70
|
+
inputs: this.inputs,
|
|
71
|
+
output: this.output,
|
|
72
|
+
groundTruth: this.groundTruth,
|
|
73
|
+
metadata: this.metadata,
|
|
74
|
+
steps: this.steps.map((nestedStep) => nestedStep.toJSON()),
|
|
75
|
+
latency: this.latency,
|
|
76
|
+
startTime: this.startTime,
|
|
77
|
+
endTime: this.endTime,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class UserCallStep extends Step {
|
|
83
|
+
constructor(name: string, inputs: any = null, output: any = null, metadata: Record<string, any> = {}) {
|
|
84
|
+
super(name, inputs, output, metadata);
|
|
85
|
+
this.stepType = StepType.USER_CALL;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export class ChatCompletionStep extends Step {
|
|
90
|
+
provider: string | null = null;
|
|
91
|
+
promptTokens: number | null = null;
|
|
92
|
+
completionTokens: number | null = null;
|
|
93
|
+
tokens: number | null = null;
|
|
94
|
+
cost: number | null = null;
|
|
95
|
+
model: string | null = null;
|
|
96
|
+
modelParameters: Record<string, any> | null = null;
|
|
97
|
+
rawOutput: string | null = null;
|
|
98
|
+
|
|
99
|
+
constructor(name: string, inputs: any = null, output: any = null, metadata: Record<string, any> = {}) {
|
|
100
|
+
super(name, inputs, output, metadata);
|
|
101
|
+
this.stepType = StepType.CHAT_COMPLETION;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
override toJSON(): ChatCompletionStepData {
|
|
105
|
+
const stepData = super.toJSON();
|
|
106
|
+
return {
|
|
107
|
+
...stepData,
|
|
108
|
+
provider: this.provider,
|
|
109
|
+
promptTokens: this.promptTokens,
|
|
110
|
+
completionTokens: this.completionTokens,
|
|
111
|
+
tokens: this.tokens,
|
|
112
|
+
cost: this.cost,
|
|
113
|
+
model: this.model,
|
|
114
|
+
modelParameters: this.modelParameters,
|
|
115
|
+
rawOutput: this.rawOutput,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// tracing/tracer.ts
|
|
2
|
+
|
|
3
|
+
import { Trace } from './traces';
|
|
4
|
+
import { Step, UserCallStep, ChatCompletionStep } from './steps';
|
|
5
|
+
import { StepType } from './enums';
|
|
6
|
+
import Openlayer from '../../index';
|
|
7
|
+
|
|
8
|
+
let currentTrace: Trace | null = null;
|
|
9
|
+
|
|
10
|
+
const publish = process.env['OPENLAYER_DISABLE_PUBLISH'] != 'true';
|
|
11
|
+
let client: Openlayer | null = null;
|
|
12
|
+
if (publish) {
|
|
13
|
+
console.debug('Publishing is enabled');
|
|
14
|
+
client = new Openlayer();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getCurrentTrace(): Trace | null {
|
|
18
|
+
return currentTrace;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function setCurrentTrace(trace: Trace | null) {
|
|
22
|
+
currentTrace = trace;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Function to create a new step
|
|
26
|
+
const stepStack: Step[] = [];
|
|
27
|
+
|
|
28
|
+
function createStep(
|
|
29
|
+
name: string,
|
|
30
|
+
stepType: StepType = StepType.USER_CALL,
|
|
31
|
+
inputs?: any,
|
|
32
|
+
output?: any,
|
|
33
|
+
metadata: Record<string, any> | null = null,
|
|
34
|
+
): [Step, () => void] {
|
|
35
|
+
metadata = metadata || {};
|
|
36
|
+
let newStep: Step;
|
|
37
|
+
if (stepType === StepType.CHAT_COMPLETION) {
|
|
38
|
+
newStep = new ChatCompletionStep(name, inputs, output, metadata);
|
|
39
|
+
} else {
|
|
40
|
+
newStep = new UserCallStep(name, inputs, output, metadata);
|
|
41
|
+
}
|
|
42
|
+
newStep.startTime = performance.now();
|
|
43
|
+
|
|
44
|
+
const parentStep = getCurrentStep();
|
|
45
|
+
const isRootStep = parentStep === null;
|
|
46
|
+
|
|
47
|
+
if (isRootStep) {
|
|
48
|
+
console.debug('Starting a new trace...');
|
|
49
|
+
console.debug(`Adding step ${name} as the root step`);
|
|
50
|
+
const currentTrace = new Trace();
|
|
51
|
+
setCurrentTrace(currentTrace);
|
|
52
|
+
currentTrace.addStep(newStep);
|
|
53
|
+
} else {
|
|
54
|
+
console.debug(`Adding step ${name} as a nested step to ${parentStep!.name}`);
|
|
55
|
+
currentTrace = getCurrentTrace()!;
|
|
56
|
+
parentStep!.addNestedStep(newStep);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
stepStack.push(newStep);
|
|
60
|
+
|
|
61
|
+
const endStep = () => {
|
|
62
|
+
newStep.endTime = performance.now();
|
|
63
|
+
newStep.latency = newStep.endTime - newStep.startTime;
|
|
64
|
+
|
|
65
|
+
stepStack.pop(); // Remove the current step from the stack
|
|
66
|
+
|
|
67
|
+
if (isRootStep) {
|
|
68
|
+
console.debug('Ending the trace...');
|
|
69
|
+
const traceData = getCurrentTrace();
|
|
70
|
+
// Post process trace and get the input variable names
|
|
71
|
+
const { traceData: processedTraceData, inputVariableNames } = postProcessTrace(traceData!);
|
|
72
|
+
|
|
73
|
+
if (publish && process.env['OPENLAYER_INFERENCE_PIPELINE_ID']) {
|
|
74
|
+
client!.inferencePipelines.data.stream(process.env['OPENLAYER_INFERENCE_PIPELINE_ID'], {
|
|
75
|
+
config: {
|
|
76
|
+
outputColumnName: 'output',
|
|
77
|
+
inputVariableNames: inputVariableNames,
|
|
78
|
+
groundTruthColumnName: 'groundTruth',
|
|
79
|
+
latencyColumnName: 'latency',
|
|
80
|
+
costColumnName: 'cost',
|
|
81
|
+
timestampColumnName: 'inferenceTimestamp',
|
|
82
|
+
inferenceIdColumnName: 'inferenceId',
|
|
83
|
+
numOfTokenColumnName: 'tokens',
|
|
84
|
+
},
|
|
85
|
+
rows: [processedTraceData],
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Reset the entire trace state
|
|
90
|
+
setCurrentTrace(null);
|
|
91
|
+
stepStack.length = 0; // Clear the step stack
|
|
92
|
+
} else {
|
|
93
|
+
console.debug(`Ending step ${name}`);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return [newStep, endStep];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getCurrentStep(): Step | null | undefined {
|
|
101
|
+
const currentStep = stepStack.length > 0 ? stepStack[stepStack.length - 1] : null;
|
|
102
|
+
return currentStep;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function getParamNames(func: Function): string[] {
|
|
106
|
+
const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
|
|
107
|
+
const ARGUMENT_NAMES = /([^\s,]+)/g;
|
|
108
|
+
const fnStr = func.toString().replace(STRIP_COMMENTS, '');
|
|
109
|
+
const result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
|
|
110
|
+
return result || [];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Higher-order function to trace synchronous or asynchronous functions
|
|
114
|
+
function trace(fn: Function, stepType: StepType = StepType.USER_CALL, stepName?: string): Function {
|
|
115
|
+
return async function (...args: any[]) {
|
|
116
|
+
const name = stepName || fn.name;
|
|
117
|
+
const paramNames = getParamNames(fn);
|
|
118
|
+
const inputs = Object.fromEntries(paramNames.map((name, index) => [name, args[index]]));
|
|
119
|
+
const [step, endStep] = createStep(name, stepType, args);
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const result = await fn(...args);
|
|
123
|
+
step.log({ inputs, output: result });
|
|
124
|
+
return result;
|
|
125
|
+
} catch (error: any) {
|
|
126
|
+
step.log({ inputs, metadata: { error: error.message } });
|
|
127
|
+
throw error;
|
|
128
|
+
} finally {
|
|
129
|
+
endStep();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function addChatCompletionStepToTrace({
|
|
135
|
+
name,
|
|
136
|
+
inputs,
|
|
137
|
+
output,
|
|
138
|
+
latency,
|
|
139
|
+
tokens = null,
|
|
140
|
+
promptTokens = null,
|
|
141
|
+
completionTokens = null,
|
|
142
|
+
model = null,
|
|
143
|
+
modelParameters = null,
|
|
144
|
+
rawOutput = null,
|
|
145
|
+
metadata = {},
|
|
146
|
+
provider = 'OpenAI',
|
|
147
|
+
}: {
|
|
148
|
+
name: string;
|
|
149
|
+
inputs: any;
|
|
150
|
+
output: any;
|
|
151
|
+
latency: number;
|
|
152
|
+
tokens?: number | null;
|
|
153
|
+
promptTokens?: number | null;
|
|
154
|
+
completionTokens?: number | null;
|
|
155
|
+
model?: string | null;
|
|
156
|
+
modelParameters?: Record<string, any> | null;
|
|
157
|
+
rawOutput?: string | null;
|
|
158
|
+
metadata?: Record<string, any>;
|
|
159
|
+
provider?: string;
|
|
160
|
+
}) {
|
|
161
|
+
const [step, endStep] = createStep(name, StepType.CHAT_COMPLETION, inputs, output, metadata);
|
|
162
|
+
|
|
163
|
+
if (step instanceof ChatCompletionStep) {
|
|
164
|
+
step.provider = provider;
|
|
165
|
+
step.promptTokens = promptTokens;
|
|
166
|
+
step.completionTokens = completionTokens;
|
|
167
|
+
step.tokens = tokens;
|
|
168
|
+
step.model = model;
|
|
169
|
+
step.modelParameters = modelParameters;
|
|
170
|
+
step.rawOutput = rawOutput;
|
|
171
|
+
step.latency = latency;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
step.log({ inputs, output, metadata });
|
|
175
|
+
endStep();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function postProcessTrace(traceObj: Trace): { traceData: any; inputVariableNames: string[] } {
|
|
179
|
+
const rootStep = traceObj.steps[0];
|
|
180
|
+
|
|
181
|
+
const input_variables = rootStep!.inputs;
|
|
182
|
+
const inputVariableNames = input_variables ? Object.keys(input_variables) : [];
|
|
183
|
+
|
|
184
|
+
const processed_steps = traceObj.toJSON();
|
|
185
|
+
|
|
186
|
+
const traceData = {
|
|
187
|
+
inferenceTimestamp: Date.now(),
|
|
188
|
+
inferenceId: rootStep!.id.toString(),
|
|
189
|
+
output: rootStep!.output,
|
|
190
|
+
groundTruth: rootStep!.groundTruth,
|
|
191
|
+
latency: rootStep!.latency,
|
|
192
|
+
cost: 0, // fix
|
|
193
|
+
tokens: 0, // fix
|
|
194
|
+
steps: processed_steps,
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
if (input_variables) {
|
|
198
|
+
Object.assign(traceData, input_variables);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return { traceData, inputVariableNames };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export default trace;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Step } from './steps';
|
|
2
|
+
|
|
3
|
+
export class Trace {
|
|
4
|
+
public steps: Step[];
|
|
5
|
+
private currentStep: Step | null;
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
this.steps = [];
|
|
9
|
+
this.currentStep = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public addStep(step: Step): void {
|
|
13
|
+
this.steps.push(step);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public toJSON(): Array<Record<string, any>> {
|
|
17
|
+
return this.steps.map((step) => step.toJSON());
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/resources/index.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
2
|
|
|
3
3
|
export { Commits } from './commits/commits';
|
|
4
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
InferencePipelineRetrieveResponse,
|
|
6
|
+
InferencePipelineUpdateResponse,
|
|
7
|
+
InferencePipelineUpdateParams,
|
|
8
|
+
InferencePipelines,
|
|
9
|
+
} from './inference-pipelines/inference-pipelines';
|
|
5
10
|
export {
|
|
6
11
|
ProjectCreateResponse,
|
|
7
12
|
ProjectListResponse,
|
|
@@ -9,3 +14,4 @@ export {
|
|
|
9
14
|
ProjectListParams,
|
|
10
15
|
Projects,
|
|
11
16
|
} from './projects/projects';
|
|
17
|
+
export { Storage } from './storage/storage';
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
2
|
|
|
3
3
|
export { DataStreamResponse, DataStreamParams, Data } from './data';
|
|
4
|
-
export {
|
|
4
|
+
export {
|
|
5
|
+
InferencePipelineRetrieveResponse,
|
|
6
|
+
InferencePipelineUpdateResponse,
|
|
7
|
+
InferencePipelineUpdateParams,
|
|
8
|
+
InferencePipelines,
|
|
9
|
+
} from './inference-pipelines';
|
|
5
10
|
export { RowUpdateResponse, RowUpdateParams, Rows } from './rows';
|
|
6
11
|
export { TestResultListResponse, TestResultListParams, TestResults } from './test-results';
|