langwatch 0.2.7__py3-none-any.whl → 0.2.9__py3-none-any.whl

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.
langwatch/__version__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """Version information for LangWatch."""
2
2
 
3
- __version__ = "0.2.7"
3
+ __version__ = "0.2.9"
@@ -9,7 +9,6 @@ from langwatch.utils.transformation import truncate_object_recursively
9
9
  from langwatch.telemetry.tracing import LangWatchTrace
10
10
  from typing_extensions import TypedDict
11
11
  import langwatch
12
- from langwatch.state import get_api_key, get_endpoint
13
12
  import httpx
14
13
  import json
15
14
  from pydantic import BaseModel
@@ -21,6 +20,7 @@ from dspy.teleprompt import (
21
20
  COPRO,
22
21
  MIPROv2,
23
22
  )
23
+ import dspy.teleprompt.copro_optimizer as copro_optimizer
24
24
  from dspy.signatures.signature import SignatureMeta
25
25
  from dspy.primitives.prediction import Prediction, Completions
26
26
  from dspy.primitives.example import Example
@@ -28,6 +28,7 @@ from pydantic.fields import FieldInfo
28
28
  from coolname import generate_slug
29
29
  from retry import retry
30
30
  from dspy.evaluate.evaluate import Evaluate
31
+ from dspy.utils.callback import with_callbacks
31
32
 
32
33
 
33
34
  class SerializableAndPydanticEncoder(json.JSONEncoder):
@@ -72,7 +73,16 @@ class SerializableAndPydanticEncoder(json.JSONEncoder):
72
73
  if isinstance(o, Completions):
73
74
  return {"__class__": classname} | o.__dict__
74
75
  if isinstance(o, BaseModel):
75
- return o.model_dump(exclude_unset=True)
76
+ try:
77
+ return o.model_dump(exclude_unset=True)
78
+ except Exception as e:
79
+ if 'MockValSer' in str(e):
80
+ return {
81
+ key: getattr(o, key)
82
+ for key in o.model_fields.keys()
83
+ if hasattr(o, key) and getattr(o, key) is not None
84
+ }
85
+ raise
76
86
  try:
77
87
  return super().default(o)
78
88
  except:
@@ -152,11 +162,12 @@ class LangWatchDSPy:
152
162
  def init(
153
163
  self,
154
164
  experiment: str,
155
- optimizer: Optional[Teleprompter],
165
+ optimizer: Optional[Teleprompter] = None,
156
166
  run_id: Optional[str] = None,
157
167
  slug: Optional[str] = None,
158
168
  workflow_id: Optional[str] = None,
159
169
  workflow_version_id: Optional[str] = None,
170
+ evaluator: Optional[Evaluate] = None,
160
171
  ):
161
172
  if langwatch.get_api_key() is None:
162
173
  print("API key was not detected, calling langwatch.login()...")
@@ -184,6 +195,9 @@ class LangWatchDSPy:
184
195
  )
185
196
  response.raise_for_status()
186
197
 
198
+ if optimizer and evaluator:
199
+ raise ValueError("You can only provide an optimizer or an evaluator, not both.")
200
+
187
201
  self.experiment_slug = slug or experiment
188
202
  random.seed() # MIPRO meses up the global seed, so we need to reset it to random to get a new run_id
189
203
  self.run_id = run_id or generate_slug(3)
@@ -193,9 +207,11 @@ class LangWatchDSPy:
193
207
  self.patch_llms()
194
208
  if optimizer is not None:
195
209
  self.patch_optimizer(optimizer)
210
+ elif evaluator is not None:
211
+ self.patch_evaluator(evaluator)
196
212
  else:
197
213
  print(
198
- "No optimizer provided, assuming custom optimizer tracking, make sure to call `track_metric` and `log_step` manually: https://docs.langwatch.ai/dspy-visualization/custom-optimizer"
214
+ "No optimizer or evaluator provided, assuming custom optimizer tracking, make sure to call `track_metric` and `log_step` manually: https://docs.langwatch.ai/dspy-visualization/custom-optimizer"
199
215
  )
200
216
 
201
217
  result = response.json()
@@ -205,6 +221,10 @@ class LangWatchDSPy:
205
221
  f"[LangWatch] Open {langwatch.get_endpoint()}{self.experiment_path}?runIds={self.run_id} to track your DSPy training session live\n"
206
222
  )
207
223
 
224
+ def patch_evaluator(self, evaluator: Evaluate):
225
+ evaluator.__class__ = LangWatchTrackedEvaluate
226
+ print(f"\n[LangWatch] `dspy.evaluate.Evaluate` object detected and patched for live tracking.")
227
+
208
228
  def patch_optimizer(self, optimizer: Teleprompter):
209
229
  METRIC_TRACKING_CLASSMAP = {
210
230
  BootstrapFewShot: LangWatchTrackedBootstrapFewShot,
@@ -379,14 +399,16 @@ langwatch_dspy = LangWatchDSPy()
379
399
 
380
400
  def init(
381
401
  experiment: str,
382
- optimizer: Optional[Teleprompter],
402
+ optimizer: Optional[Teleprompter] = None,
383
403
  run_id: Optional[str] = None,
384
404
  slug: Optional[str] = None,
385
405
  workflow_id: Optional[str] = None,
386
406
  workflow_version_id: Optional[str] = None,
407
+ evaluator: Optional[Evaluate] = None,
387
408
  ):
388
409
  langwatch_dspy.init(
389
- experiment, optimizer, run_id, slug, workflow_id, workflow_version_id
410
+ experiment, optimizer, run_id, slug, workflow_id, workflow_version_id,
411
+ evaluator=evaluator,
390
412
  )
391
413
 
392
414
 
@@ -521,7 +543,15 @@ class LangWatchTrackedCOPRO(COPRO):
521
543
 
522
544
  @contextmanager
523
545
  def _patch_logger_and_evaluate(self):
524
- original_logger_info = dspy.logger.info
546
+ legacy_logger = True
547
+ original_logger_info = None
548
+
549
+ if hasattr(copro_optimizer, "logger"):
550
+ legacy_logger = False
551
+ original_logger_info = copro_optimizer.logger.info
552
+ else:
553
+ original_logger_info = dspy.logger.info
554
+
525
555
  original_evaluate_call = Evaluate.__call__
526
556
  step = None
527
557
  scores = []
@@ -577,13 +607,20 @@ class LangWatchTrackedCOPRO(COPRO):
577
607
 
578
608
  return score
579
609
 
580
- dspy.logger.info = patched_logger_info
610
+ if legacy_logger:
611
+ dspy.logger.info = patched_logger_info
612
+ else:
613
+ copro_optimizer.logger.info = patched_logger_info
614
+
581
615
  Evaluate.__call__ = patched_evaluate_call
582
616
 
583
617
  try:
584
618
  yield
585
619
  finally:
586
- dspy.logger.info = original_logger_info
620
+ if legacy_logger:
621
+ dspy.logger.info = original_logger_info
622
+ else:
623
+ copro_optimizer.logger.info = original_logger_info
587
624
  Evaluate.__call__ = original_evaluate_call
588
625
 
589
626
 
@@ -658,6 +695,40 @@ class LangWatchTrackedMIPROv2(MIPROv2):
658
695
  Evaluate.__call__ = original_evaluate_call
659
696
 
660
697
 
698
+ class LangWatchTrackedEvaluate(Evaluate):
699
+ @with_callbacks
700
+ def __call__(self, program: dspy.Module, metric: Optional[Callable] = None, **kwargs):
701
+ lw_dspy = langwatch_dspy
702
+
703
+ metric_to_use = metric if metric is not None else self.metric
704
+ if not metric_to_use:
705
+ raise ValueError("Evaluation metric must be provided either during Evaluate initialization or during call.")
706
+
707
+ wrapped_metric = lw_dspy.track_metric(metric_to_use)
708
+
709
+ # Call the original evaluation logic with the wrapped metric.
710
+ # We need to make sure we pass the wrapped metric to the super call.
711
+ kwargs_for_super = kwargs.copy()
712
+ kwargs_for_super["metric"] = wrapped_metric
713
+ result = super().__call__(program, **kwargs_for_super)
714
+
715
+ score = result[0] if isinstance(result, tuple) else result
716
+
717
+ if lw_dspy.run_id:
718
+ lw_dspy.log_step(
719
+ optimizer=DSPyOptimizer(name="Evaluate", parameters={}),
720
+ index="0",
721
+ score=float(score),
722
+ label="score",
723
+ predictors=[
724
+ DSPyPredictor(name=name, predictor=predictor)
725
+ for name, predictor in program.named_predictors()
726
+ ],
727
+ )
728
+
729
+ return result
730
+
731
+
661
732
  # === Tracer ===#
662
733
 
663
734
 
@@ -267,9 +267,10 @@ class LangWatchTrace:
267
267
  self,
268
268
  ):
269
269
  ensure_setup()
270
- import langwatch.dspy
270
+ # Making sure it doesn't get mixed up with langwatch.dspy from `import langwatch`
271
+ from langwatch.dspy.__init__ import DSPyTracer
271
272
 
272
- langwatch.dspy.DSPyTracer(trace=self)
273
+ DSPyTracer(trace=self)
273
274
 
274
275
  def share(self) -> str:
275
276
  """Share this trace and get a shareable URL."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langwatch
3
- Version: 0.2.7
3
+ Version: 0.2.9
4
4
  Summary: LangWatch Python SDK, for monitoring your LLMs
5
5
  Author-email: Langwatch Engineers <engineering@langwatch.ai>
6
6
  License: MIT
@@ -1,5 +1,5 @@
1
1
  langwatch/__init__.py,sha256=nepKSqGG6MQnLgn3QrzcAQ24wlXc-wBAcS0Ks7oVUKk,3681
2
- langwatch/__version__.py,sha256=CIdkONm80uSwzT7YU83GCyb1uq6eb5rysgAb-GsiuQY,64
2
+ langwatch/__version__.py,sha256=_Ef6eRJnXlLxv6Pt9FrqxJZdOHx4onlAQg2rPnAnV1E,64
3
3
  langwatch/attributes.py,sha256=VsNstyDPaMIjsM4U7yAIDE7ouVxgwhOdbQlrhce9XU8,3699
4
4
  langwatch/batch_evaluation.py,sha256=cZ_OxDEpZhwVQap8fub3vcdWVYw9OdUCg7WTuy5FgoY,15748
5
5
  langwatch/client.py,sha256=w-WkYRwgFMlfljAwcR6GBT11kBQOc3Ifb3hGY1htOd4,13156
@@ -15,7 +15,7 @@ langwatch/tracer.py,sha256=t5FOdP1es9H_pPGqGUBLXCyEln0tTi4m4M9b6WxCrPU,975
15
15
  langwatch/types.py,sha256=DkZThS7ptUY0_Ao7PNO6ZGBE9Qj0YmJf5auRkq2Cphw,2570
16
16
  langwatch/dataset/__init__.py,sha256=1vUqnyFymnzcIOTahtsPvKTyAet_q-HTKByRUkuED80,2290
17
17
  langwatch/domain/__init__.py,sha256=luuin3-6mmMqDaOJE_1wb7M1ccjhhZL80UN0TBA_TXM,6040
18
- langwatch/dspy/__init__.py,sha256=CI0oRmljxudOVM3nUiZGRZb50Yfh7YIIojtvrx_m46A,31568
18
+ langwatch/dspy/__init__.py,sha256=E9rqyhOyIO3E-GxJSZlHtsvjapFjKQGF85QRcpKSvKE,34280
19
19
  langwatch/evaluation/__init__.py,sha256=Jy7PW5VQbMoDGdOLRlQmDEvo_9TDkBLmrLrfocxddLM,281
20
20
  langwatch/evaluation/evaluation.py,sha256=AF3VXCcTGB3F8ChsjwBxqjUXkLzvTbkWbiWYxRzVWik,16037
21
21
  langwatch/exporters/filterable_batch_span_exporter.py,sha256=MlhZjui56XD6p2sa8kEGyr-Hb3wqudknngmemnB4Twg,2142
@@ -207,7 +207,7 @@ langwatch/prompt/prompt.py,sha256=ujcyL_7d0fCLXT-UbFcdnH90D6tkSD5Ro5JGFncU9fQ,19
207
207
  langwatch/telemetry/context.py,sha256=ixKvTBZADFuWglFCK95r8bF4-f-iq_WixzC4ydirCE8,3888
208
208
  langwatch/telemetry/sampling.py,sha256=XDf6ZoXiwpHaHDYd_dDszSqH8_9-CHFNsGAZWOW1VYk,1327
209
209
  langwatch/telemetry/span.py,sha256=HKYouwWWHCsc1PtnrB3UFFB-X1LT7DA5cSy-iA5Qoug,32779
210
- langwatch/telemetry/tracing.py,sha256=pAYwpNzhqDrv2meWCtKgaNi4em2dKIAaGbsdvsZlvGg,26550
210
+ langwatch/telemetry/tracing.py,sha256=7zPQ1W3KZKi35vzs1veTLviWkRe6bEA4x5_baNsjP2c,26650
211
211
  langwatch/telemetry/types.py,sha256=Q9H7nT3GMK1aluRB7CCX8BR7VFKrQY_vdFdyF4Yc98U,501
212
212
  langwatch/utils/__init__.py,sha256=3rqQTgzEtmICJW_KSPuLa5q8p5udxt5SRi28Z2vZB10,138
213
213
  langwatch/utils/capture.py,sha256=uVKPqHCm-o8CpabsUfhqbNFr5sgUHzcKnBadvL2oIwI,1172
@@ -216,6 +216,6 @@ langwatch/utils/initialization.py,sha256=LOmGCiox7JRiHprnB04AdO8BhUggZtRbWgBPF9m
216
216
  langwatch/utils/module.py,sha256=KLBNOK3mA9gCSifCcQX_lOtU48BJQDWvFKtF6NMvwVA,688
217
217
  langwatch/utils/transformation.py,sha256=5XUnW7Oz8Ck9EMsKeKeoDOrIw3EXpLGMk_fMSeA0Zng,7216
218
218
  langwatch/utils/utils.py,sha256=ZCOSie4o9LdJ7odshNfCNjmgwgQ27ojc5ENqt1rXuSs,596
219
- langwatch-0.2.7.dist-info/METADATA,sha256=3CI4EW3Hfy6lGIoppPl8lsfGmB5HmT0M-_PfIwjO3n0,12886
220
- langwatch-0.2.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
221
- langwatch-0.2.7.dist-info/RECORD,,
219
+ langwatch-0.2.9.dist-info/METADATA,sha256=FbRafO8xi9pzIgZXDnJkchcqI6izMMaejU_EznN2KZU,12886
220
+ langwatch-0.2.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
221
+ langwatch-0.2.9.dist-info/RECORD,,