-
Notifications
You must be signed in to change notification settings - Fork 2
Fixes ENG-1176: SDK Decorators V1 #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
3fa3b35 to
0359dac
Compare
f2f6a2c to
4d854ed
Compare
src/humanloop/decorators/tool.py
Outdated
| # Check if the parameter can be None, either via Optional[T] or T | None type hint | ||
| origin = typing.get_origin(parameter.annotation) | ||
| # sub_types refers to T inside the annotation | ||
| sub_types = typing.get_args(parameter.annotation) | ||
| return origin is typing.Union and len(sub_types) > 0 and sub_types[-1] is type(None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this work for None | T
testing locally, also running problems with origin is typing.Union - origin is types.UnionType for me.
(python 3.11)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added support for parsing python 3.10 style union annotation, added tests for it, and created a new action that runs the test suite on both 3.9 and 3.12
|
Collating unresolved comments:
tested with the cookbook's main.py yesterday and it worked well. some concerns around how helpful we're trying to be, but think we're at a good level here (of trying to be helpful while not making that many assumptions/limitations) that typing.Union/types.UnionType issue for |
ae815f3 to
03261c4
Compare
f621b31 to
52c6c7b
Compare
c2e7f67 to
0ae1b89
Compare
0ae1b89 to
b9668d2
Compare
|
@harry-humanloop ty for feedback:
|
harry-humanloop
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm. let's publish a beta version of the sdk.
suspect the dependency changes here need to be propagated to humanloop-docs.
🎉
|
@harry-humanloop it's actually the other way around regrading dependencies; we need to merge this first: https://github.com/humanloop/humanloop-docs/pull/147 |
Goal
Allow customers to declare Humanloop Files using code
Minimise how many lines need to be changed to integrate with Humanloop
How
Add decorators in the Python client that inspect the decorated function to create Files on the HL application.
Every call to a decorated function creates a Log against that File.
Every change to the decorated function results in a new version being created on HL
Added 3 decorators: Prompt, Tool, Flow
How to Test this PR
~/Desktop/humanloop-pythonpoetry add ~/Desktop/humanloop-python(or whatever path you have clonehumanloop-pythonrepo). Make sure the current branch inhumanloop-pythonisENG-1176-sdk-annotationsDesign
Primer on OpenTelemetry
OpenTelemetry is an open-source standard for instrumenting software. The new decorators rely on it for two reasons:
Instrumentorsto spy on LLM provider callsHere is a quick 101 to OTel terminology and domain to help you navigate this PR:
TracerProviderholds the telemetry configuration for your OTel-powered applicationTracerProvidercan be used to createTracers, which act as session objects in a telemetry TraceTracerProvidercan have one or multipleSpanProcessors. Spans created by aTracerspawned from aTracerProviderwill be passed to eachSpanProcessorregistered with theTracerProvider.SpanProcessorsform a pipeline, each being applied in order of being added. A Processor is responsible for filtering or modifying the Span and passing it along.SpanProcessortakes oneSpanExporterto which it passes the modified or filtered Spans. TheSpanExportercan be a Connector that passes the Span to anotherSpanProcessoror can act as a final destination, uploading theSpansto a backend (e.g., Humanloop, Datadog, etc.).Instrumentorsare libraries that spy on third-party libraries e.g.Django,SQLAlchemyand add Spans to theTracerProviderthey're added to automaticallySketch of the Design
Humanloopclient. AddInstrumentorsto it for spying on LLM providers' libraries (e.g.,OpenAI) and obtain a Tracer used as a backend for the decorators.HumanloopSpanProcessor. Its goal is to identify the Instrumentors we've added to spy on libraries of interest and add information from those spans to Spans created by our decorators. Spans not created by the decorators are dropped.HumanloopSpanExporterand pair it with theHumanloopSpanProcessor. TheExporterwill translate the spans into SDK calls.How To Review this PR:
src/humanloop/otel/helpers.pyand associated tests. Reviewsrc/humanloop/otel/__init__.pyandsrc/humanloop/client.pysrc/humanloop/decorators/*src/humanloop/otel/processor.pyandsrc/humanloop/otel/exporter.pysrc/humanloop/decorators/*Considerations
otel/helpers.pycontains:{'a': 7, 'b': 5}on keyfootranslates into writing two attributes on the Span:foo.a: 7andfoo.b: 5. This leads to a lot of 'fun' and makes the utils necessary for cleaner code.HL_OT_EMPTY_VALUEis sometimes used throughout the code whenHLProcessorsends Spans to theHLExporterin a bottom-up manner. With our current backend API, a Flow Trace must sent to HL top-to-bottom. To address this, the Exporter holds a work queue of unexported Spans and delays the upload until all ancestors in the Flow Trace have been uploaded. This is smelly; the backend should add an endpoint for uploading a Trace in one go.hl-alpharepo, where API keys are added to support similar integration tests.Open Questions
These points should be discussed before merging.