langwatch 0.2.8__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.8"
3
+ __version__ = "0.2.9"
@@ -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
 
@@ -673,6 +695,40 @@ class LangWatchTrackedMIPROv2(MIPROv2):
673
695
  Evaluate.__call__ = original_evaluate_call
674
696
 
675
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
+
676
732
  # === Tracer ===#
677
733
 
678
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.8
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=fVjSxPE9TfkSdSWhP2pKjFKPW2e6jMivB_7HF8_G-3Y,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=VQoriSl0Um4A0K3dbYxj6ZLUqNLgKKyODd3vkVp0wD4,32027
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.8.dist-info/METADATA,sha256=1M8Yyf8TEbm7UWcUkNPGMiFcvGFTb1y_eRn3whPdfKQ,12886
220
- langwatch-0.2.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
221
- langwatch-0.2.8.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,,