Skip to content

Commit 002a109

Browse files
author
Andrei Bratu
committed
PR feedback from Harry
1 parent 11a64b9 commit 002a109

15 files changed

Lines changed: 551 additions & 445 deletions

File tree

src/humanloop/client.py

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,55 @@
1-
import logging
1+
from contextvars import ContextVar
22
import os
33
import typing
4-
from typing import Any, Callable, List, Optional, Sequence, Union
4+
from typing import Any, List, Optional, Sequence
55

66
import httpx
77
from opentelemetry.sdk.resources import Resource
88
from opentelemetry.sdk.trace import TracerProvider
99
from opentelemetry.trace import Tracer
1010

11+
from humanloop.core.client_wrapper import SyncClientWrapper
12+
from humanloop.eval_utils.context import EVALUATION_CONTEXT_VARIABLE_NAME, EvaluationContext
1113
from humanloop.types.model_endpoints import ModelEndpoints
1214
from humanloop.types.model_providers import ModelProviders
1315
from humanloop.types.prompt_kernel_request_stop import PromptKernelRequestStop
1416
from humanloop.types.prompt_kernel_request_template import PromptKernelRequestTemplate
1517
from humanloop.types.response_format import ResponseFormat
1618

1719
if typing.TYPE_CHECKING:
18-
from . import ToolFunctionParams
20+
from humanloop import ToolFunctionParams
1921

2022
from humanloop.eval_utils import log_with_evaluation_context, run_eval
2123
from humanloop.eval_utils.types import Dataset, Evaluator, EvaluatorCheck, File
2224

23-
from .base_client import AsyncBaseHumanloop, BaseHumanloop
24-
from .decorators.flow import flow as flow_decorator_factory
25-
from .decorators.prompt import prompt as prompt_decorator_factory
26-
from .decorators.tool import tool as tool_decorator_factory
27-
from .environment import HumanloopEnvironment
28-
from .evaluations.client import EvaluationsClient
29-
from .otel import instrument_provider
30-
from .otel.exporter import HumanloopSpanExporter
31-
from .otel.processor import HumanloopSpanProcessor
32-
from .prompt_utils import populate_template
33-
from .prompts.client import PromptsClient
25+
from humanloop.base_client import AsyncBaseHumanloop, BaseHumanloop
26+
from humanloop.decorators.flow import flow as flow_decorator_factory
27+
from humanloop.decorators.prompt import prompt as prompt_decorator_factory
28+
from humanloop.decorators.tool import tool as tool_decorator_factory
29+
from humanloop.environment import HumanloopEnvironment
30+
from humanloop.evaluations.client import EvaluationsClient
31+
from humanloop.otel import instrument_provider
32+
from humanloop.otel.exporter import HumanloopSpanExporter
33+
from humanloop.otel.processor import HumanloopSpanProcessor
34+
from humanloop.prompt_utils import populate_template
35+
from humanloop.prompts.client import PromptsClient
3436

3537

3638
class ExtendedEvalsClient(EvaluationsClient):
3739
client: BaseHumanloop
3840

41+
def __init__(
42+
self,
43+
*,
44+
client_wrapper: SyncClientWrapper,
45+
evaluation_context_variable: ContextVar[Optional[EvaluationContext]],
46+
):
47+
super().__init__(client_wrapper=client_wrapper)
48+
self._evaluation_context_variable = evaluation_context_variable
49+
3950
def run(
4051
self,
41-
file: Union[File, Callable],
52+
file: File,
4253
name: Optional[str],
4354
dataset: Dataset,
4455
evaluators: Optional[Sequence[Evaluator]] = None,
@@ -64,6 +75,7 @@ def run(
6475
dataset=dataset,
6576
evaluators=evaluators,
6677
workers=workers,
78+
evaluation_context_variable=self._evaluation_context_variable,
6779
)
6880

6981

@@ -111,18 +123,31 @@ def __init__(
111123
httpx_client=httpx_client,
112124
)
113125

114-
eval_client = ExtendedEvalsClient(client_wrapper=self._client_wrapper)
126+
self.evaluation_context_variable: ContextVar[Optional[EvaluationContext]] = ContextVar(
127+
EVALUATION_CONTEXT_VARIABLE_NAME
128+
)
129+
130+
eval_client = ExtendedEvalsClient(
131+
client_wrapper=self._client_wrapper,
132+
evaluation_context_variable=self.evaluation_context_variable,
133+
)
115134
eval_client.client = self
116135
self.evaluations = eval_client
117136
self.prompts = ExtendedPromptsClient(client_wrapper=self._client_wrapper)
118137

119138
# Overload the .log method of the clients to be aware of Evaluation Context
120139
# TODO: Overload the log for Evaluators and Tools once run_id is added
121140
# to them.
122-
self.prompts = log_with_evaluation_context(client=self.prompts)
141+
self.prompts = log_with_evaluation_context(
142+
client=self.prompts,
143+
evaluation_context_variable=self.evaluation_context_variable,
144+
)
123145
# self.evaluators = log_with_evaluation_context(client=self.evaluators)
124146
# self.tools = log_with_evaluation_context(client=self.tools)
125-
self.flows = log_with_evaluation_context(client=self.flows)
147+
self.flows = log_with_evaluation_context(
148+
client=self.flows,
149+
evaluation_context_variable=self.evaluation_context_variable,
150+
)
126151

127152
if opentelemetry_tracer_provider is not None:
128153
self._tracer_provider = opentelemetry_tracer_provider

src/humanloop/decorators/flow.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
2-
import traceback
3-
import uuid
42
from functools import wraps
3+
import os
4+
import sys
55
from typing import Any, Callable, Mapping, Optional, Sequence
66

77
from opentelemetry.sdk.trace import Span
@@ -11,8 +11,8 @@
1111
from humanloop.decorators.helpers import args_to_inputs
1212
from humanloop.eval_utils.types import File
1313
from humanloop.otel import TRACE_FLOW_CONTEXT, FlowContext
14-
from humanloop.otel.constants import HL_FILE_KEY, HL_FILE_TYPE_KEY, HL_LOG_KEY, HL_PATH_KEY
15-
from humanloop.otel.helpers import write_to_opentelemetry_span
14+
from humanloop.otel.constants import HUMANLOOP_FILE_KEY, HUMANLOOP_FILE_TYPE_KEY, HUMANLOOP_LOG_KEY, HUMANLOOP_PATH_KEY
15+
from humanloop.otel.helpers import generate_span_id, write_to_opentelemetry_span
1616
from humanloop.requests import FlowKernelRequestParams as FlowDict
1717

1818
logger = logging.getLogger("humanloop.sdk")
@@ -31,7 +31,7 @@ def decorator(func: Callable):
3131
@wraps(func)
3232
def wrapper(*args: Sequence[Any], **kwargs: Mapping[str, Any]) -> Any:
3333
span: Span
34-
with opentelemetry_tracer.start_as_current_span(str(uuid.uuid4())) as span:
34+
with opentelemetry_tracer.start_as_current_span(generate_span_id()) as span:
3535
span_id = span.get_span_context().span_id
3636
if span.parent:
3737
span_parent_id = span.parent.span_id
@@ -52,12 +52,12 @@ def wrapper(*args: Sequence[Any], **kwargs: Mapping[str, Any]) -> Any:
5252
is_flow_log=True,
5353
)
5454

55-
span.set_attribute(HL_PATH_KEY, path if path else func.__name__)
56-
span.set_attribute(HL_FILE_TYPE_KEY, "flow")
55+
span.set_attribute(HUMANLOOP_PATH_KEY, path if path else func.__name__)
56+
span.set_attribute(HUMANLOOP_FILE_TYPE_KEY, "flow")
5757
if attributes:
5858
write_to_opentelemetry_span(
5959
span=span,
60-
key=f"{HL_FILE_KEY}.flow.attributes",
60+
key=f"{HUMANLOOP_FILE_KEY}.flow.attributes",
6161
value=attributes, # type: ignore
6262
)
6363

@@ -68,7 +68,6 @@ def wrapper(*args: Sequence[Any], **kwargs: Mapping[str, Any]) -> Any:
6868
output = func(*args, **kwargs)
6969
error = None
7070
except Exception as e:
71-
# print error, line of code, and function name
7271
logger.error(f"Error calling {func.__name__}: {e}")
7372
output = None
7473
error = str(e)
@@ -87,18 +86,17 @@ def wrapper(*args: Sequence[Any], **kwargs: Mapping[str, Any]) -> Any:
8786
if flow_log:
8887
write_to_opentelemetry_span(
8988
span=span,
90-
key=HL_LOG_KEY,
89+
key=HUMANLOOP_LOG_KEY,
9190
value=flow_log, # type: ignore
9291
)
9392

9493
# Return the output of the decorated function
9594
return output
9695

97-
func.file = File( # type: ignore
96+
wrapper.file = File( # type: ignore
9897
path=path if path else func.__name__,
9998
type="flow",
10099
version=FlowDict(attributes=attributes), # type: ignore
101-
is_decorated=True,
102100
callable=wrapper,
103101
)
104102

src/humanloop/decorators/prompt.py

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import logging
2+
import os
3+
import sys
24
import typing
35
import uuid
46
from functools import wraps
@@ -7,13 +9,15 @@
79
from opentelemetry.sdk.trace import Span
810
from opentelemetry.trace import Tracer
911

12+
from humanloop.types.prompt_kernel_request import PromptKernelRequest
13+
1014
if typing.TYPE_CHECKING:
1115
from humanloop import ToolFunctionParams
1216
from humanloop.decorators.helpers import args_to_inputs
1317
from humanloop.eval_utils import File
1418
from humanloop.otel import TRACE_FLOW_CONTEXT, FlowContext
15-
from humanloop.otel.constants import HL_FILE_KEY, HL_FILE_TYPE_KEY, HL_LOG_KEY, HL_PATH_KEY
16-
from humanloop.otel.helpers import write_to_opentelemetry_span
19+
from humanloop.otel.constants import HUMANLOOP_FILE_KEY, HUMANLOOP_FILE_TYPE_KEY, HUMANLOOP_LOG_KEY, HUMANLOOP_PATH_KEY
20+
from humanloop.otel.helpers import generate_span_id, write_to_opentelemetry_span
1721
from humanloop.types.model_endpoints import ModelEndpoints
1822
from humanloop.types.model_providers import ModelProviders
1923
from humanloop.types.prompt_kernel_request_stop import PromptKernelRequestStop
@@ -45,27 +49,6 @@ def prompt(
4549
):
4650
def decorator(func: Callable):
4751
prompt_kernel = {}
48-
49-
if temperature is not None:
50-
if not 0 <= temperature < 1:
51-
raise ValueError(f"{func.__name__}: Temperature parameter must be between 0 and 1")
52-
prompt_kernel["temperature"] = temperature
53-
54-
if top_p is not None:
55-
if not 0 <= top_p <= 1:
56-
raise ValueError(f"{func.__name__}: Top-p parameter must be between 0 and 1")
57-
prompt_kernel["top_p"] = top_p
58-
59-
if presence_penalty is not None:
60-
if not -2 <= presence_penalty <= 2:
61-
raise ValueError(f"{func.__name__}: Presence penalty parameter must be between -2 and 2")
62-
prompt_kernel["presence_penalty"] = presence_penalty
63-
64-
if frequency_penalty is not None:
65-
if not -2 <= frequency_penalty <= 2:
66-
raise ValueError(f"{func.__name__}: Frequency penalty parameter must be between -2 and 2")
67-
prompt_kernel["frequency_penalty"] = frequency_penalty
68-
6952
for attr_name, attr_value in {
7053
"model": model,
7154
"endpoint": endpoint,
@@ -76,16 +59,19 @@ def decorator(func: Callable):
7659
"other": other,
7760
"seed": seed,
7861
"response_format": response_format,
79-
# {} -> None
8062
"attributes": attributes or None,
8163
"tools": tools,
64+
"temperature": temperature,
65+
"top_p": top_p,
66+
"presence_penalty": presence_penalty,
67+
"frequency_penalty": frequency_penalty,
8268
}.items():
8369
prompt_kernel[attr_name] = attr_value # type: ignore
8470

8571
@wraps(func)
8672
def wrapper(*args: Sequence[Any], **kwargs: Mapping[str, Any]) -> Any:
8773
span: Span
88-
with opentelemetry_tracer.start_as_current_span(str(uuid.uuid4())) as span:
74+
with opentelemetry_tracer.start_as_current_span(generate_span_id()) as span:
8975
span_id = span.get_span_context().span_id
9076
if span.parent:
9177
span_parent_id = span.parent.span_id
@@ -97,13 +83,13 @@ def wrapper(*args: Sequence[Any], **kwargs: Mapping[str, Any]) -> Any:
9783
is_flow_log=False,
9884
)
9985

100-
span.set_attribute(HL_PATH_KEY, path if path else func.__name__)
101-
span.set_attribute(HL_FILE_TYPE_KEY, "prompt")
86+
span.set_attribute(HUMANLOOP_PATH_KEY, path if path else func.__name__)
87+
span.set_attribute(HUMANLOOP_FILE_TYPE_KEY, "prompt")
10288

10389
if prompt_kernel:
10490
write_to_opentelemetry_span(
10591
span=span,
106-
key=f"{HL_FILE_KEY}.prompt",
92+
key=f"{HUMANLOOP_FILE_KEY}.prompt",
10793
value=prompt_kernel, # type: ignore
10894
)
10995

@@ -123,7 +109,7 @@ def wrapper(*args: Sequence[Any], **kwargs: Mapping[str, Any]) -> Any:
123109
}
124110
write_to_opentelemetry_span(
125111
span=span,
126-
key=HL_LOG_KEY,
112+
key=HUMANLOOP_LOG_KEY,
127113
value=prompt_log,
128114
)
129115

@@ -140,7 +126,6 @@ def wrapper(*args: Sequence[Any], **kwargs: Mapping[str, Any]) -> Any:
140126
path=path if path else func.__name__,
141127
type="prompt",
142128
version={**prompt_kernel_file}, # type: ignore
143-
is_decorated=True,
144129
callable=wrapper,
145130
)
146131

0 commit comments

Comments
 (0)