Skip to content

Commit 776f824

Browse files
author
Andrei Bratu
committed
QA for processor changes
1 parent e5cab4f commit 776f824

File tree

8 files changed

+82
-36
lines changed

8 files changed

+82
-36
lines changed

src/otel/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ export const HUMANLOOP_FILE_KEY = "humanloop.file";
44
export const HUMANLOOP_LOG_KEY = "humanloop.log";
55
export const HUMANLOOP_FILE_TYPE_KEY = "humanloop.file_type";
66
export const HUMANLOOP_PATH_KEY = "humanloop.file.path";
7-
export const HUMANLOOP_WRAPPED_FUNCTION_NAME = "humanloop.file.function_name";
7+
export const HUMANLOOP_META_FUNCTION_NAME = "humanloop.meta.function_name";
88
export const HUMANLOOP_PARENT_SPAN_CTX_KEY = "humanloop.context.parentSpanId";
99
export const HUMANLOOP_TRACE_FLOW_CTX_KEY = "humanloop.context.traceFlow";

src/otel/processor.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
HUMANLOOP_FILE_KEY,
1515
HUMANLOOP_FILE_TYPE_KEY,
1616
HUMANLOOP_LOG_KEY,
17-
HUMANLOOP_WRAPPED_FUNCTION_NAME,
17+
HUMANLOOP_META_FUNCTION_NAME,
1818
} from "./constants";
1919
import {
2020
NestedDict,
@@ -44,7 +44,7 @@ export class HumanloopSpanProcessor implements SpanProcessor {
4444

4545
async forceFlush(): Promise<void> {}
4646

47-
onStart(span: Span, parentContext: Context): void {
47+
onStart(span: Span, _: Context): void {
4848
// Handle stream case: when Prompt instrumented function calls a provider with streaming: true
4949
// The instrumentor span will end only when the ChunksResponse is consumed, which can happen
5050
// after the span created by the Prompt utility finishes. To handle this, we register all instrumentor
@@ -61,22 +61,23 @@ export class HumanloopSpanProcessor implements SpanProcessor {
6161
async shutdown(): Promise<void> {}
6262

6363
/**
64-
* Handles spans at the end of their lifecycle.
65-
* Enriches Humanloop spans and send both HL and
64+
* Handles spans at the end of their lifecycle. Enriches Humanloop spans and send both HL and
6665
* non-HL spans to the exporter.
6766
*/
6867
onEnd(span: ReadableSpan): void {
6968
if (isHumanloopSpan(span)) {
7069
new Promise<void>((resolve) => {
71-
while (true) {
70+
const checkChildrenSpans = () => {
7271
const childrenSpans = this.children.get(span.spanContext().spanId);
7372
if (
74-
(childrenSpans || [])?.every((childSpan) => childSpan.complete)
73+
(childrenSpans || []).every((childSpan) => childSpan.complete)
7574
) {
76-
break;
75+
resolve();
76+
} else {
77+
setTimeout(checkChildrenSpans, 100);
7778
}
78-
}
79-
resolve();
79+
};
80+
checkChildrenSpans();
8081
}).then((_) => {
8182
// All children/ instrumentor spans have arrived, we can process the
8283
// Humanloop parent span owning them
@@ -126,13 +127,21 @@ export class HumanloopSpanProcessor implements SpanProcessor {
126127
: childSpan,
127128
),
128129
);
129-
}
130130

131-
this.spanExporter.export([span], (result: ExportResult) => {
132-
if (result.code !== ExportResultCode.SUCCESS) {
133-
console.error("Failed to export span:", result.error);
134-
}
135-
});
131+
// Export the instrumentor span
132+
this.spanExporter.export([span], (result: ExportResult) => {
133+
if (result.code !== ExportResultCode.SUCCESS) {
134+
console.error("Failed to export span:", result.error);
135+
}
136+
});
137+
} else {
138+
// Unknown span, export as it is
139+
this.spanExporter.export([span], (result: ExportResult) => {
140+
if (result.code !== ExportResultCode.SUCCESS) {
141+
console.error("Failed to export span:", result.error);
142+
}
143+
});
144+
}
136145
}
137146

138147
/**
@@ -190,7 +199,7 @@ export class HumanloopSpanProcessor implements SpanProcessor {
190199
const prompt = (hlFile.prompt || {}) as unknown as PromptKernelRequest;
191200
if (!("model" in prompt) || !prompt.model) {
192201
const functionName =
193-
promptSpan.attributes[HUMANLOOP_WRAPPED_FUNCTION_NAME];
202+
promptSpan.attributes[HUMANLOOP_META_FUNCTION_NAME];
194203
throw Error(
195204
`Error in ${functionName}: the LLM provider and model could not be inferred. Call one of the supported providers in your prompt function definition or define them in the promptKernel argument of the prompt() function wrapper.`,
196205
);

src/utilities/flow.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import { FlowKernelRequest } from "../api/types/FlowKernelRequest";
55
import {
66
HUMANLOOP_FILE_TYPE_KEY,
77
HUMANLOOP_LOG_KEY,
8+
HUMANLOOP_META_FUNCTION_NAME,
89
HUMANLOOP_PARENT_SPAN_CTX_KEY,
910
HUMANLOOP_PATH_KEY,
1011
HUMANLOOP_TRACE_FLOW_CTX_KEY,
11-
HUMANLOOP_WRAPPED_FUNCTION_NAME,
1212
NestedDict,
1313
generateSpanId,
1414
jsonifyIfNotString,
@@ -67,7 +67,7 @@ export function flowUtilityFactory<I, M, O>(
6767
// Add span attributes
6868
span = span.setAttribute(HUMANLOOP_PATH_KEY, path || func.name);
6969
span = span.setAttribute(HUMANLOOP_FILE_TYPE_KEY, "flow");
70-
span = span.setAttribute(HUMANLOOP_WRAPPED_FUNCTION_NAME, func.name);
70+
span = span.setAttribute(HUMANLOOP_META_FUNCTION_NAME, func.name);
7171

7272
if (version) {
7373
writeToOpenTelemetrySpan(

src/utilities/prompt.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import { Humanloop } from "../index";
66
import {
77
HUMANLOOP_FILE_TYPE_KEY,
88
HUMANLOOP_LOG_KEY,
9+
HUMANLOOP_META_FUNCTION_NAME,
910
HUMANLOOP_PARENT_SPAN_CTX_KEY,
1011
HUMANLOOP_PATH_KEY,
1112
HUMANLOOP_TRACE_FLOW_CTX_KEY,
12-
HUMANLOOP_WRAPPED_FUNCTION_NAME,
1313
NestedDict,
1414
generateSpanId,
1515
jsonifyIfNotString,
@@ -87,7 +87,7 @@ export function promptUtilityFactory<I, M, O>(
8787
// Add span attributes
8888
span = span.setAttribute(HUMANLOOP_PATH_KEY, path || func.name);
8989
span = span.setAttribute(HUMANLOOP_FILE_TYPE_KEY, "prompt");
90-
span = span.setAttribute(HUMANLOOP_WRAPPED_FUNCTION_NAME, func.name);
90+
span = span.setAttribute(HUMANLOOP_META_FUNCTION_NAME, func.name);
9191

9292
if (version) {
9393
writeToOpenTelemetrySpan(

src/utilities/tool.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import {
1212
HUMANLOOP_FILE_KEY,
1313
HUMANLOOP_FILE_TYPE_KEY,
1414
HUMANLOOP_LOG_KEY,
15+
HUMANLOOP_META_FUNCTION_NAME,
1516
HUMANLOOP_PARENT_SPAN_CTX_KEY,
1617
HUMANLOOP_PATH_KEY,
1718
HUMANLOOP_TRACE_FLOW_CTX_KEY,
18-
HUMANLOOP_WRAPPED_FUNCTION_NAME,
1919
} from "../otel/constants";
2020
import { ToolCallableType } from "./types";
2121

@@ -78,7 +78,7 @@ export function toolUtilityFactory<I, O>(
7878
// Add span attributes
7979
span.setAttribute(HUMANLOOP_PATH_KEY, path || func.name);
8080
span.setAttribute(HUMANLOOP_FILE_TYPE_KEY, "tool");
81-
span = span.setAttribute(HUMANLOOP_WRAPPED_FUNCTION_NAME, func.name);
81+
span = span.setAttribute(HUMANLOOP_META_FUNCTION_NAME, func.name);
8282

8383
// @ts-ignore
8484
// Execute the wrapped function in the appropriate context
@@ -143,8 +143,9 @@ function validateArgumentsAgainstSchema(toolKernel: ToolKernelRequest, inputs?:
143143
if (inputs === undefined) {
144144
return;
145145
}
146+
console.log("BAI", parameters);
146147
throw new Error(
147-
`Tool function ${toolKernel.function?.name} received inputs when the JSON schema defines none.`,
148+
`Tool function ${toolKernel.function?.name} received inputs when the JSON schema defines none`,
148149
);
149150
}
150151

tests/utilities/flow.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,6 @@ describe("flow decorator", () => {
165165

166166
expect(createToolLogResponse.mock.calls).toHaveLength(1);
167167
},
168-
10 * 1000,
168+
20 * 1000,
169169
);
170170
});

tests/utilities/prompt.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ describe("prompt decorator", () => {
128128
{ provider, model },
129129
callLLMMessages() as Humanloop.ChatMessage[],
130130
);
131+
132+
// The HLProcessor contains waits for Instrumentor spans to enrich
133+
// the parent HL Spans in an async manner
134+
await new Promise((resolve) => setTimeout(resolve, 1000));
135+
131136
const spans = exporter.getFinishedSpans();
132137
expect(spans.length).toBe(2);
133138
expect(isHumanloopSpan(spans[0])).toBeFalsy();
@@ -148,6 +153,10 @@ describe("prompt decorator", () => {
148153
callLLMMessages() as Humanloop.ChatMessage[],
149154
);
150155

156+
// The HLProcessor contains waits for Instrumentor spans to enrich
157+
// the parent HL Spans in an async manner
158+
await new Promise((resolve) => setTimeout(resolve, 1000));
159+
151160
const spans = exporter.getFinishedSpans();
152161
expect(spans.length).toBe(2);
153162

@@ -181,6 +190,10 @@ describe("prompt decorator", () => {
181190
callLLMMessages() as Humanloop.ChatMessage[],
182191
);
183192

193+
// The HLProcessor contains waits for Instrumentor spans to enrich
194+
// the parent HL Spans in an async manner
195+
await new Promise((resolve) => setTimeout(resolve, 1000));
196+
184197
expect(exporter.getFinishedSpans().length).toBe(2);
185198

186199
const promptKernel = readFromOpenTelemetrySpan(

tests/utilities/tool.test.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Validator } from "jsonschema";
2+
import { add } from "lodash";
23

34
import {
45
HUMANLOOP_FILE_KEY,
56
HUMANLOOP_FILE_TYPE_KEY,
67
HUMANLOOP_LOG_KEY,
8+
HUMANLOOP_META_FUNCTION_NAME,
79
readFromOpenTelemetrySpan,
810
} from "../../src/otel";
911
import { toolUtilityFactory } from "../../src/utilities/tool";
@@ -57,9 +59,14 @@ describe("tool decorator", () => {
5759
description: "Perform arithmetic operations on two numbers.",
5860
strict: true,
5961
parameters: {
60-
operation: "string",
61-
num1: "number",
62-
num2: "number",
62+
type: "object",
63+
required: ["operation", "num1", "num2"],
64+
additionalProperties: false,
65+
properties: {
66+
operation: { type: "string" },
67+
num1: { type: "number" },
68+
num2: { type: "number" },
69+
},
6370
},
6471
},
6572
},
@@ -83,9 +90,14 @@ describe("tool decorator", () => {
8390
description: "Perform arithmetic operations on two numbers.",
8491
strict: true,
8592
parameters: {
86-
operation: "string",
87-
num1: "number",
88-
num2: "number",
93+
type: "object",
94+
required: ["operation", "num1", "num2"],
95+
additionalProperties: false,
96+
properties: {
97+
operation: { type: "string" },
98+
num1: { type: "number" },
99+
num2: { type: "number" },
100+
},
89101
},
90102
},
91103
},
@@ -103,12 +115,18 @@ describe("tool decorator", () => {
103115
name: "calculator",
104116
description: "Perform arithmetic operations on two numbers.",
105117
parameters: {
106-
operation: "string",
107-
num1: "number",
108-
num2: "number",
118+
type: "object",
119+
required: ["operation", "num1", "num2"],
120+
additionalProperties: false,
121+
properties: {
122+
operation: { type: "string" },
123+
num1: { type: "number" },
124+
num2: { type: "number" },
125+
},
109126
},
110127
strict: true,
111128
});
129+
expect(span.attributes[HUMANLOOP_META_FUNCTION_NAME] === "calculator");
112130
// @ts-ignore
113131
new Validator().validate(log, calculatorDecorated.jsonSchema);
114132
});
@@ -144,8 +162,13 @@ describe("tool decorator", () => {
144162
description: "Add two numbers.",
145163
strict: true,
146164
parameters: {
147-
a: "number",
148-
b: "number",
165+
type: "object",
166+
required: ["a", "b"],
167+
properties: {
168+
a: { type: "number" },
169+
b: { type: "number" },
170+
},
171+
additionalProperties: false,
149172
},
150173
},
151174
},

0 commit comments

Comments
 (0)