Skip to content

Commit 0d33f55

Browse files
author
Andrei Bratu
committed
QA Changes
1 parent 1c18a7f commit 0d33f55

File tree

17 files changed

+10022
-123
lines changed

17 files changed

+10022
-123
lines changed

package-lock.json

Lines changed: 9871 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/decorators/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/humanloop.client.ts

Lines changed: 82 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,103 @@
11
import { NodeTracerProvider, Tracer } from "@opentelemetry/sdk-trace-node";
22
import { HumanloopClient as BaseHumanloopClient } from "./Client";
3-
import { HumanloopSpanProcessor } from "otel/processor";
4-
import { HumanloopSpanExporter } from "otel/exporter";
5-
import { instrumentProvider } from "otel";
6-
import { UtilityPromptKernel, prompt as promptUtilityFactory } from "decorators/prompt";
7-
import { tool as toolUtilityFactory } from "decorators/tool";
8-
import { flow as flowUtilityFactory } from "decorators/flow";
9-
import { ToolKernelRequest } from "api/types/ToolKernelRequest";
10-
import { FlowKernelRequest } from "api/types/FlowKernelRequest";
3+
import { HumanloopSpanProcessor } from "./otel/processor";
4+
import { HumanloopSpanExporter } from "./otel/exporter";
5+
import { UtilityPromptKernel, promptUtilityFactory } from "./utilities/prompt";
6+
import { toolUtilityFactory } from "./utilities/tool";
7+
import { flowUtilityFactory } from "./utilities/flow";
8+
import { ToolKernelRequest } from "./api/types/ToolKernelRequest";
9+
import { FlowKernelRequest } from "./api/types/FlowKernelRequest";
10+
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
11+
import { CohereInstrumentation } from "@traceloop/instrumentation-cohere";
12+
import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
13+
import { registerInstrumentations } from "@opentelemetry/instrumentation";
1114

1215
export class HumanloopClient extends BaseHumanloopClient {
1316
protected readonly opentelemetryTracerProvider: NodeTracerProvider;
1417
protected readonly opentelemetryTracer: Tracer;
1518

16-
constructor(
17-
_options: BaseHumanloopClient.Options,
18-
opentelemetryTracerProvider: NodeTracerProvider,
19-
opentelemetryTracer: Tracer
20-
) {
19+
constructor(_options: BaseHumanloopClient.Options) {
2120
super(_options);
2221

23-
if (opentelemetryTracerProvider) {
24-
this.opentelemetryTracerProvider = opentelemetryTracerProvider;
25-
} else {
26-
this.opentelemetryTracerProvider = new NodeTracerProvider({
27-
spanProcessors: [new HumanloopSpanProcessor(new HumanloopSpanExporter(this))],
28-
});
29-
}
22+
this.opentelemetryTracerProvider = new NodeTracerProvider({
23+
spanProcessors: [new HumanloopSpanProcessor(new HumanloopSpanExporter(this))],
24+
});
3025

31-
instrumentProvider(this.opentelemetryTracerProvider);
26+
// if (moduleIsInstalled("openai")) {
27+
// const openai = require("openai");
28+
// console.log("FOO", openai);
29+
// const instrumentor = new OpenAIInstrumentation({ enrichTokens: true });
30+
// instrumentor.manuallyInstrument(openai);
31+
// instrumentor.setTracerProvider(this.opentelemetryTracerProvider);
32+
// instrumentor.enable();
33+
// }
34+
35+
// if (moduleIsInstalled("@anthropic-ai/sdk")) {
36+
// const anthropic = require("@anthropic-ai/sdk");
37+
// const instrumentor = new AnthropicInstrumentation();
38+
// instrumentor.manuallyInstrument(anthropic);
39+
// instrumentor.setTracerProvider(this.opentelemetryTracerProvider);
40+
// instrumentor.enable();
41+
// }
42+
43+
// if (moduleIsInstalled("cohere-ai")) {
44+
// const cohere = require("cohere-ai");
45+
// const instrumentor = new CohereInstrumentation();
46+
// instrumentor.manuallyInstrument(cohere);
47+
// instrumentor.setTracerProvider(this.opentelemetryTracerProvider);
48+
// instrumentor.enable();
49+
// }
3250

3351
this.opentelemetryTracerProvider.register();
3452

35-
if (this.opentelemetryTracerProvider !== undefined) {
36-
this.opentelemetryTracer = this.opentelemetryTracerProvider.getTracer("humanloop.sdk");
37-
} else {
38-
this.opentelemetryTracer = opentelemetryTracer;
39-
}
53+
registerInstrumentations({
54+
tracerProvider: this.opentelemetryTracerProvider,
55+
instrumentations: [
56+
new OpenAIInstrumentation(),
57+
new AnthropicInstrumentation(),
58+
new CohereInstrumentation(),
59+
],
60+
});
61+
62+
this.opentelemetryTracer = this.opentelemetryTracerProvider.getTracer("humanloop.sdk");
4063
}
4164

42-
public prompt<T extends (...args: any[]) => any>(func: T, promptKernel?: UtilityPromptKernel, path?: string) {
43-
return promptUtilityFactory(this.opentelemetryTracer, func, promptKernel, path);
65+
public prompt<T extends (...args: any[]) => any>(promptUtilityArguments: {
66+
callable: T;
67+
promptKernel?: UtilityPromptKernel;
68+
path?: string;
69+
}) {
70+
return promptUtilityFactory(
71+
this.opentelemetryTracer,
72+
promptUtilityArguments.callable,
73+
promptUtilityArguments.promptKernel,
74+
promptUtilityArguments.path
75+
);
4476
}
4577

46-
public tool<T extends (...args: any[]) => any>(func: T, toolKernel: ToolKernelRequest, path?: string) {
47-
return toolUtilityFactory(this.opentelemetryTracer, func, toolKernel, path);
78+
public tool<T extends (...args: any[]) => any>(toolUtilityArguments: {
79+
callable: T;
80+
toolKernel: ToolKernelRequest;
81+
path?: string;
82+
}) {
83+
return toolUtilityFactory(
84+
this.opentelemetryTracer,
85+
toolUtilityArguments.callable,
86+
toolUtilityArguments.toolKernel,
87+
toolUtilityArguments.path
88+
);
4889
}
4990

50-
public flow<T extends (...args: any[]) => any>(func: T, flowKernel: FlowKernelRequest, path?: string) {
51-
return flowUtilityFactory(this.opentelemetryTracer, func, flowKernel, path);
91+
public flow<T extends (...args: any[]) => any>(flowUtilityArguments: {
92+
callable: T;
93+
flowKernel?: FlowKernelRequest;
94+
path?: string;
95+
}) {
96+
return flowUtilityFactory(
97+
this.opentelemetryTracer,
98+
flowUtilityArguments.callable,
99+
flowUtilityArguments.flowKernel,
100+
flowUtilityArguments.path
101+
);
52102
}
53103
}

src/otel/exporter.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ import { HumanloopClient } from "humanloop.client";
55
import { FlowKernelRequest, PromptKernelRequest, ToolKernelRequest } from "api";
66
import { HUMANLOOP_FILE_KEY, HUMANLOOP_FILE_TYPE_KEY, HUMANLOOP_LOG_KEY, HUMANLOOP_PATH_KEY } from "./constants";
77

8+
/**
9+
* Converts a high-resolution time tuple to a JavaScript Date object.
10+
*
11+
* @param hrTime - A tuple containing the high-resolution time, where the first element is the number of seconds
12+
* and the second element is the number of nanoseconds.
13+
* @returns A Date object representing the high-resolution time.
14+
*/
15+
function hrTimeToDate(hrTime: [number, number]): Date {
16+
const [seconds, nanoseconds] = hrTime;
17+
const secondsTotal = seconds + nanoseconds / 1e9;
18+
return new Date(secondsTotal * 1000);
19+
}
20+
821
export class HumanloopSpanExporter implements SpanExporter {
922
private readonly client: HumanloopClient;
1023
private readonly spanIdToUploadedLogId: Map<string, string | null>;
@@ -83,7 +96,10 @@ export class HumanloopSpanExporter implements SpanExporter {
8396

8497
private async exportPrompt(span: ReadableSpan): Promise<void> {
8598
const fileObject = readFromOpenTelemetrySpan(span, HUMANLOOP_FILE_KEY);
86-
const logObject = readFromOpenTelemetrySpan(span, HUMANLOOP_LOG_KEY);
99+
const logObject = readFromOpenTelemetrySpan(span, HUMANLOOP_LOG_KEY) as { [key: string]: unknown };
100+
logObject.startTime = hrTimeToDate(span.startTime);
101+
logObject.endTime = hrTimeToDate(span.endTime);
102+
logObject.createdAt = hrTimeToDate(span.endTime);
87103
const path = span.attributes[HUMANLOOP_PATH_KEY] as string;
88104

89105
const spanParentId = span.parentSpanId;
@@ -107,7 +123,10 @@ export class HumanloopSpanExporter implements SpanExporter {
107123

108124
private async exportTool(span: ReadableSpan): Promise<void> {
109125
const fileObject = readFromOpenTelemetrySpan(span, HUMANLOOP_FILE_KEY);
110-
const logObject = readFromOpenTelemetrySpan(span, HUMANLOOP_LOG_KEY);
126+
const logObject = readFromOpenTelemetrySpan(span, HUMANLOOP_LOG_KEY) as { [key: string]: unknown };
127+
logObject.startTime = hrTimeToDate(span.startTime);
128+
logObject.endTime = hrTimeToDate(span.endTime);
129+
logObject.createdAt = hrTimeToDate(span.endTime);
111130
const path = span.attributes[HUMANLOOP_PATH_KEY] as string;
112131

113132
const spanParentId = span.parentSpanId;
@@ -128,7 +147,10 @@ export class HumanloopSpanExporter implements SpanExporter {
128147

129148
private async exportFlow(span: ReadableSpan): Promise<void> {
130149
const fileObject = readFromOpenTelemetrySpan(span, HUMANLOOP_FILE_KEY);
131-
const logObject = readFromOpenTelemetrySpan(span, HUMANLOOP_LOG_KEY);
150+
const logObject = readFromOpenTelemetrySpan(span, HUMANLOOP_LOG_KEY) as { [key: string]: unknown };
151+
logObject.startTime = hrTimeToDate(span.startTime);
152+
logObject.endTime = hrTimeToDate(span.endTime);
153+
logObject.createdAt = hrTimeToDate(span.endTime);
132154

133155
const spanParentId = span.parentSpanId;
134156
const traceParentId = spanParentId ? (this.spanIdToUploadedLogId.get(spanParentId) as string) : undefined;
@@ -137,7 +159,7 @@ export class HumanloopSpanExporter implements SpanExporter {
137159
try {
138160
const response = await this.client.flows.log({
139161
path: path as string,
140-
flow: (fileObject.flow as unknown as FlowKernelRequest) || {},
162+
flow: (fileObject.flow as unknown as FlowKernelRequest) || { attributes: {} },
141163
traceParentId,
142164
...logObject,
143165
});

src/otel/helpers.ts

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ReadableSpan } from "@opentelemetry/sdk-trace-base";
22
import { SpanKind } from "@opentelemetry/api";
33
import { AttributeValue } from "@opentelemetry/api";
4-
import { InstrumentationBase } from "@opentelemetry/instrumentation";
54
import { v4 as uuidv4 } from "uuid";
65

76
// Constants for Humanloop attributes
@@ -231,29 +230,3 @@ export function jsonifyIfNotString(func: Function, output: any): string {
231230
}
232231
return output;
233232
}
234-
235-
export function instrumentProvider(provider: NodeTracerProvider) {
236-
const instrumentors = [];
237-
try {
238-
const openai = require("openai").openai;
239-
const openaiInstrumentor = new OpenAIInstrumentation({ enrichTokens: true });
240-
openaiInstrumentor.manuallyInstrument(openai);
241-
instrumentors.push(openaiInstrumentor);
242-
} catch (error) {}
243-
try {
244-
const anthropic = require("@anthropic-ai/sdk");
245-
const anthropicInstrumentor = new AnthropicInstrumentation();
246-
anthropicInstrumentor.manuallyInstrument(anthropic);
247-
instrumentors.push(anthropicInstrumentor);
248-
} catch (error) {}
249-
try {
250-
const cohere = require("cohere");
251-
const cohereInstrumentor = new CohereInstrumentation();
252-
cohereInstrumentor.manuallyInstrument(cohere);
253-
instrumentors.push(cohereInstrumentor);
254-
} catch (error) {}
255-
for (const instrumentor of instrumentors) {
256-
instrumentor.setTracerProvider(provider);
257-
instrumentor.enable();
258-
}
259-
}

src/otel/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
export * from "./constants";
2-
export * from "./flow.context";
3-
export * from "./helpers";
2+
export * from "./helpers";

src/otel/processor.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,6 @@ import { ModelEndpoints, ModelProviders } from "api";
1313
import { SpanAttributes as AiSemanticConventions } from "@traceloop/ai-semantic-conventions";
1414
import { Context } from "@opentelemetry/api";
1515

16-
/**
17-
* Converts HrTime to seconds with fractions.
18-
*
19-
* @param hrTime - The High-Resolution Time tuple [seconds, nanoseconds].
20-
* @returns The time in seconds as a floating-point number.
21-
*/
22-
function hrTimeToSeconds(hrTime: [number, number]): number {
23-
const [seconds, nanoseconds] = hrTime;
24-
return (seconds + nanoseconds) / 1e9;
25-
}
26-
2716
/**
2817
* Enriches Humanloop spans with data from their child spans.
2918
*/
@@ -47,6 +36,7 @@ export class HumanloopSpanProcessor implements SpanProcessor {
4736
* Enriches Humanloop spans or forwards non-Humanloop spans to the exporter.
4837
*/
4938
onEnd(span: ReadableSpan): void {
39+
console.log("onEnd", span.attributes);
5040
if (isHumanloopSpan(span)) {
5141
this.processSpanDispatch(span, this.children.get(span.spanContext().spanId) || []);
5242
this.children.delete(span.spanContext().spanId); // Release references
@@ -76,11 +66,11 @@ export class HumanloopSpanProcessor implements SpanProcessor {
7666

7767
// Common processing for all Humanloop spans
7868
if (span.startTime) {
79-
span.attributes[`${HUMANLOOP_LOG_KEY}.startTime`] = hrTimeToSeconds(span.startTime);
69+
span.attributes[`${HUMANLOOP_LOG_KEY}.startTime`] = span.startTime;
8070
}
8171
if (span.endTime) {
82-
span.attributes[`${HUMANLOOP_LOG_KEY}.endTime`] = hrTimeToSeconds(span.endTime);
83-
span.attributes[`${HUMANLOOP_LOG_KEY}.createdAt`] = hrTimeToSeconds(span.endTime);
72+
span.attributes[`${HUMANLOOP_LOG_KEY}.endTime`] = span.endTime;
73+
span.attributes[`${HUMANLOOP_LOG_KEY}.createdAt`] = span.endTime;
8474
}
8575

8676
switch (fileType) {
@@ -154,6 +144,7 @@ export class HumanloopSpanProcessor implements SpanProcessor {
154144
* Enriches the prompt log of a prompt span using information from a child span.
155145
*/
156146
private enrichPromptLog(promptSpan: ReadableSpan, llmProviderCallSpan: ReadableSpan): void {
147+
console.log("WOW", promptSpan.attributes, llmProviderCallSpan.attributes);
157148
let hlLog = readFromOpenTelemetrySpan(promptSpan, HUMANLOOP_LOG_KEY) || {};
158149

159150
if (!hlLog.output_tokens) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { argsToInputs } from "./helpers";
1414
import { HUMANLOOP_PARENT_SPAN_CTX_KEY, NestedDict } from "../otel"; // Define or import constants and context structures
1515
import { FlowKernelRequest } from "api/types/FlowKernelRequest";
1616

17-
export function flow<T extends (...args: any[]) => any>(
17+
export function flowUtilityFactory<T extends (...args: any[]) => any>(
1818
opentelemetryTracer: Tracer,
1919
func: T,
2020
flowKernel?: FlowKernelRequest,

src/utilities/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from "./helpers";
2+
export { UtilityPromptKernel, promptUtilityFactory } from "./prompt";
3+
export { toolUtilityFactory } from "./tool";
4+
export { flowUtilityFactory } from "./flow";

0 commit comments

Comments
 (0)