langfun 0.1.2.dev202501080804__py3-none-any.whl → 0.1.2.dev202501240804__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.
Files changed (56) hide show
  1. langfun/core/__init__.py +1 -6
  2. langfun/core/coding/python/__init__.py +5 -11
  3. langfun/core/coding/python/correction.py +4 -7
  4. langfun/core/coding/python/correction_test.py +2 -3
  5. langfun/core/coding/python/execution.py +22 -211
  6. langfun/core/coding/python/execution_test.py +11 -90
  7. langfun/core/coding/python/generation.py +3 -2
  8. langfun/core/coding/python/generation_test.py +2 -2
  9. langfun/core/coding/python/parsing.py +108 -194
  10. langfun/core/coding/python/parsing_test.py +2 -105
  11. langfun/core/component.py +11 -273
  12. langfun/core/component_test.py +2 -29
  13. langfun/core/concurrent.py +187 -82
  14. langfun/core/concurrent_test.py +28 -19
  15. langfun/core/console.py +7 -3
  16. langfun/core/eval/base.py +2 -3
  17. langfun/core/eval/v2/evaluation.py +3 -1
  18. langfun/core/eval/v2/reporting.py +8 -4
  19. langfun/core/language_model.py +84 -8
  20. langfun/core/language_model_test.py +84 -29
  21. langfun/core/llms/__init__.py +46 -11
  22. langfun/core/llms/anthropic.py +1 -123
  23. langfun/core/llms/anthropic_test.py +0 -48
  24. langfun/core/llms/deepseek.py +117 -0
  25. langfun/core/llms/deepseek_test.py +61 -0
  26. langfun/core/llms/gemini.py +1 -1
  27. langfun/core/llms/groq.py +12 -99
  28. langfun/core/llms/groq_test.py +31 -137
  29. langfun/core/llms/llama_cpp.py +17 -54
  30. langfun/core/llms/llama_cpp_test.py +2 -34
  31. langfun/core/llms/openai.py +9 -147
  32. langfun/core/llms/openai_compatible.py +179 -0
  33. langfun/core/llms/openai_compatible_test.py +495 -0
  34. langfun/core/llms/openai_test.py +13 -423
  35. langfun/core/llms/rest_test.py +1 -1
  36. langfun/core/llms/vertexai.py +387 -18
  37. langfun/core/llms/vertexai_test.py +52 -0
  38. langfun/core/message_test.py +3 -3
  39. langfun/core/modalities/mime.py +8 -0
  40. langfun/core/modalities/mime_test.py +19 -4
  41. langfun/core/modality_test.py +0 -1
  42. langfun/core/structured/mapping.py +13 -13
  43. langfun/core/structured/mapping_test.py +2 -2
  44. langfun/core/structured/schema.py +16 -8
  45. langfun/core/structured/schema_generation.py +1 -1
  46. {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/METADATA +13 -2
  47. {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/RECORD +50 -52
  48. {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/WHEEL +1 -1
  49. langfun/core/coding/python/errors.py +0 -108
  50. langfun/core/coding/python/errors_test.py +0 -99
  51. langfun/core/coding/python/permissions.py +0 -90
  52. langfun/core/coding/python/permissions_test.py +0 -86
  53. langfun/core/text_formatting.py +0 -168
  54. langfun/core/text_formatting_test.py +0 -65
  55. {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/LICENSE +0 -0
  56. {langfun-0.1.2.dev202501080804.dist-info → langfun-0.1.2.dev202501240804.dist-info}/top_level.txt +0 -0
langfun/core/component.py CHANGED
@@ -13,10 +13,7 @@
13
13
  # limitations under the License.
14
14
  """langfun Component."""
15
15
 
16
- import contextlib
17
- import dataclasses
18
- import threading
19
- from typing import Annotated, Any, ContextManager, Iterator, Type
16
+ from typing import ContextManager
20
17
  import pyglove as pg
21
18
 
22
19
 
@@ -24,22 +21,9 @@ import pyglove as pg
24
21
  RAISE_IF_HAS_ERROR = (pg.MISSING_VALUE,)
25
22
 
26
23
 
27
- class Component(pg.Object):
24
+ class Component(pg.ContextualObject):
28
25
  """Base class for langfun components."""
29
26
 
30
- # Override __repr__ format to use inferred values when available.
31
- __repr_format_kwargs__ = dict(
32
- compact=True,
33
- use_inferred=True,
34
- )
35
-
36
- # Override __str__ format to use inferred values when available.
37
- __str_format_kwargs__ = dict(
38
- compact=False,
39
- verbose=False,
40
- use_inferred=True,
41
- )
42
-
43
27
  # Allow symbolic assignment, which invalidates the object and recomputes
44
28
  # states upon update.
45
29
  allow_symbolic_assignment = True
@@ -75,122 +59,23 @@ class Component(pg.Object):
75
59
  if additional_fields:
76
60
  cls.update_schema(additional_fields)
77
61
 
78
- def _on_bound(self):
79
- super()._on_bound()
80
- self._tls = threading.local()
81
-
82
- def _sym_inferred(self, key: str, **kwargs):
83
- """Override to allow attribute to access scoped value.
84
-
85
- Args:
86
- key: attribute name.
87
- **kwargs: Optional keyword arguments for value inference.
88
-
89
- Returns:
90
- The value of the symbolic attribute. If not available, returns the
91
- default value.
92
-
93
- Raises:
94
- AttributeError: If the attribute does not exist or contextual attribute
95
- is not ready.
96
- """
97
- if key not in self._sym_attributes:
98
- raise AttributeError(key)
99
-
100
- # Step 1: Try use value from `self.override`.
101
- # The reason is that `self.override` is short-lived and explicitly specified
102
- # by the user in scenarios like `LangFunc.render`, which should not be
103
- # affected by `lf.context`.
104
- v = _get_scoped_value(self._tls, _CONTEXT_OVERRIDES, key)
105
- if v is not None:
106
- return v.value
107
-
108
- # Step 2: Try use value from `lf.context` with `override_attrs`.
109
- # This gives users a chance to override the bound attributes of components
110
- # from the top, allowing change of bindings without modifying the code
111
- # that produces the components.
112
- override = get_contextual_override(key)
113
- if override and override.override_attrs:
114
- return override.value
115
-
116
- # Step 3: Try use value from the symbolic tree, starting from self to
117
- # the root of the tree.
118
- # Step 4: If the value is not present, use the value from `context()` (
119
- # override_attrs=False).
120
- # Step 5: Otherwise use the default value from `ContextualAttribute`.
121
- return super()._sym_inferred(key, context_override=override, **kwargs)
122
-
123
- def override(
124
- self, **kwargs) -> ContextManager[dict[str, 'ContextualOverride']]:
125
- """Context manager to override the attributes of this component."""
126
- vs = {k: ContextualOverride(v) for k, v in kwargs.items()}
127
- return _contextual_scope(self._tls, _CONTEXT_OVERRIDES, **vs)
128
-
129
- def __getattribute__(self, name: str) -> Any:
130
- """Override __getattribute__ to deal with class attribute override."""
131
- if not name.startswith('_') and hasattr(self.__class__, name):
132
- tls = self.__dict__.get('_tls', None)
133
- if tls is not None:
134
- v = _get_scoped_value(tls, _CONTEXT_OVERRIDES, name)
135
- if v is not None:
136
- return v.value
137
- return super().__getattribute__(name)
138
-
139
-
140
- _global_tls = threading.local()
141
-
142
- _CONTEXT_OVERRIDES = 'context_overrides'
143
-
144
62
 
145
- @dataclasses.dataclass(frozen=True)
146
- class ContextualOverride:
147
- """Value marker for contextual override for an attribute."""
63
+ # Aliases from PyGlove for ease of access.
64
+ context = pg.contextual_override
65
+ get_contextual_override = pg.utils.get_contextual_override
66
+ context_value = pg.utils.contextual_value
67
+ all_contextual_values = pg.utils.all_contextual_values
68
+ contextual = pg.contextual_attribute
148
69
 
149
- # Overridden value.
150
- value: Any
151
-
152
- # If True, this override will apply to both current scope and nested scope,
153
- # meaning current `lf.context` will take precedence over all nested
154
- # `lf.context` on this attribute.
155
- cascade: bool = False
156
-
157
- # If True, this override will apply to attributes that already have values.
158
- override_attrs: bool = False
159
-
160
-
161
- def context(
162
- *,
163
- cascade: bool = False,
164
- override_attrs: bool = False,
165
- **variables,
166
- ) -> ContextManager[dict[str, ContextualOverride]]:
167
- """Context manager to provide overriden values for contextual attributes.
168
-
169
- Args:
170
- cascade: If True, this override will apply to both current scope and nested
171
- scope, meaning that this `lf.context` will take precedence over all
172
- nested `lf.context` on the overriden variables.
173
- override_attrs: If True, this override will apply to attributes that already
174
- have values. Otherwise overridden variables will only be used for
175
- contextual attributes whose values are not present.
176
- **variables: Key/values as override for contextual attributes.
177
-
178
- Returns:
179
- A dict of attribute names to their contextual overrides.
180
- """
181
- vs = {}
182
- for k, v in variables.items():
183
- if not isinstance(v, ContextualOverride):
184
- v = ContextualOverride(v, cascade, override_attrs)
185
- vs[k] = v
186
- return _contextual_scope(_global_tls, _CONTEXT_OVERRIDES, **vs)
70
+ # Decorator for setting the positional arguments for Component.
71
+ use_init_args = pg.use_init_args
187
72
 
188
73
 
189
74
  def use_settings(
190
75
  *,
191
76
  cascade: bool = False,
192
77
  **settings,
193
- ) -> ContextManager[dict[str, ContextualOverride]]:
78
+ ) -> ContextManager[dict[str, pg.utils.ContextualOverride]]:
194
79
  """Shortcut method for overriding component attributes.
195
80
 
196
81
  Args:
@@ -203,150 +88,3 @@ def use_settings(
203
88
  A dict of attribute names to their contextual overrides.
204
89
  """
205
90
  return context(cascade=cascade, override_attrs=True, **settings)
206
-
207
-
208
- def get_contextual_override(var_name: str) -> ContextualOverride | None:
209
- """Returns the overriden contextual value in current scope."""
210
- return _get_scoped_value(_global_tls, _CONTEXT_OVERRIDES, var_name)
211
-
212
-
213
- def context_value(var_name: str, default: Any = RAISE_IF_HAS_ERROR) -> Any:
214
- """Returns the value of a variable defined in `lf.context`."""
215
- override = get_contextual_override(var_name)
216
- if override is None:
217
- if default == RAISE_IF_HAS_ERROR:
218
- raise KeyError(f'{var_name!r} does not exist in current context.')
219
- return default
220
- return override.value
221
-
222
-
223
- def all_contextual_values() -> dict[str, Any]:
224
- """Returns all contextual values provided from `lf.context` in scope."""
225
- overrides = getattr(_global_tls, _CONTEXT_OVERRIDES, {})
226
- return {k: v.value for k, v in overrides.items()}
227
-
228
-
229
- @contextlib.contextmanager
230
- def _contextual_scope(
231
- tls: threading.local, tls_key, **variables
232
- ) -> Iterator[dict[str, ContextualOverride]]:
233
- """Context manager to set variables within a scope."""
234
- previous_values = getattr(tls, tls_key, {})
235
- current_values = dict(previous_values)
236
- for k, v in variables.items():
237
- old_v = current_values.get(k, None)
238
- if old_v and old_v.cascade:
239
- v = old_v
240
- current_values[k] = v
241
- try:
242
- setattr(tls, tls_key, current_values)
243
- yield current_values
244
- finally:
245
- setattr(tls, tls_key, previous_values)
246
-
247
-
248
- def _get_scoped_value(
249
- tls: threading.local, tls_key: str, var_name: str, default: Any = None
250
- ) -> ContextualOverride:
251
- """Gets the value for requested variable from current scope."""
252
- scoped_values = getattr(tls, tls_key, {})
253
- return scoped_values.get(var_name, default)
254
-
255
-
256
- class ContextualAttribute(
257
- pg.symbolic.ValueFromParentChain, pg.views.HtmlTreeView.Extension
258
- ):
259
- """Attributes whose values are inferred from the context of the component.
260
-
261
- Please see go/langfun-component#attribute-value-retrieval for details.
262
- """
263
-
264
- NO_DEFAULT = (pg.MISSING_VALUE,)
265
-
266
- type: Annotated[Type[Any] | None, 'An optional type constraint.'] = None
267
-
268
- default: Any = NO_DEFAULT
269
-
270
- def value_from(
271
- self,
272
- parent,
273
- *,
274
- context_override: ContextualOverride | None = None,
275
- **kwargs,
276
- ):
277
- if parent not in (None, self.sym_parent) and isinstance(parent, Component):
278
- # Apply original search logic along the component containing chain.
279
- return super().value_from(parent, **kwargs)
280
- elif parent is None:
281
- # When there is no value inferred from the symbolic tree.
282
- # Search context override, and then attribute-level default.
283
- if context_override:
284
- return context_override.value
285
- if self.default == ContextualAttribute.NO_DEFAULT:
286
- return pg.MISSING_VALUE
287
- return self.default
288
- else:
289
- return pg.MISSING_VALUE
290
-
291
- def _html_tree_view_content(
292
- self,
293
- *,
294
- view: pg.views.HtmlTreeView,
295
- parent: Any = None,
296
- root_path: pg.KeyPath | None = None,
297
- **kwargs,
298
- ) -> pg.Html:
299
- inferred_value = pg.MISSING_VALUE
300
- if isinstance(parent, pg.Symbolic) and root_path:
301
- inferred_value = parent.sym_inferred(root_path.key, pg.MISSING_VALUE)
302
-
303
- if inferred_value is not pg.MISSING_VALUE:
304
- kwargs.pop('name', None)
305
- return view.render(
306
- inferred_value, parent=self,
307
- root_path=pg.KeyPath('<inferred>', root_path),
308
- **view.get_passthrough_kwargs(**kwargs)
309
- )
310
- return pg.Html.element(
311
- 'div',
312
- [
313
- '(not available)',
314
- ],
315
- css_classes=['unavailable-contextual'],
316
- )
317
-
318
- def _html_tree_view_config(self) -> dict[str, Any]:
319
- return pg.views.HtmlTreeView.get_kwargs(
320
- super()._html_tree_view_config(),
321
- dict(
322
- collapse_level=1,
323
- )
324
- )
325
-
326
- @classmethod
327
- def _html_tree_view_css_styles(cls) -> list[str]:
328
- return super()._html_tree_view_css_styles() + [
329
- """
330
- .contextual-attribute {
331
- color: purple;
332
- }
333
- .unavailable-contextual {
334
- color: gray;
335
- font-style: italic;
336
- }
337
- """
338
- ]
339
-
340
-
341
- # NOTE(daiyip): Returning Any instead of `lf.ContextualAttribute` to avoid
342
- # pytype check error as `contextual()` can be assigned to any type.
343
- def contextual(
344
- type: Type[Any] | None = None, # pylint: disable=redefined-builtin
345
- default: Any = ContextualAttribute.NO_DEFAULT,
346
- ) -> Any:
347
- """Value marker for a contextual attribute."""
348
- return ContextualAttribute(type=type, default=default, allow_partial=True)
349
-
350
-
351
- # Decorator for setting the positional arguments for Component.
352
- use_init_args = pg.use_init_args
@@ -73,26 +73,7 @@ class ComponentContextTest(unittest.TestCase):
73
73
  self.assertEqual(a1.y, 2)
74
74
  self.assertEqual(a1.z, -1)
75
75
 
76
- with lf.context(x=3, y=3, z=3) as parent_override:
77
- self.assertEqual(
78
- parent_override,
79
- dict(
80
- x=lf.ContextualOverride(3, cascade=False, override_attrs=False),
81
- y=lf.ContextualOverride(3, cascade=False, override_attrs=False),
82
- z=lf.ContextualOverride(3, cascade=False, override_attrs=False),
83
- ),
84
- )
85
- self.assertEqual(
86
- lf.get_contextual_override('y'),
87
- lf.ContextualOverride(3, cascade=False, override_attrs=False),
88
- )
89
- self.assertEqual(lf.context_value('x'), 3)
90
- self.assertIsNone(lf.context_value('f', None))
91
- with self.assertRaisesRegex(KeyError, '.* does not exist'):
92
- lf.context_value('f')
93
-
94
- self.assertEqual(lf.all_contextual_values(), dict(x=3, y=3, z=3))
95
-
76
+ with lf.context(x=3, y=3, z=3):
96
77
  # Member attributes take precedence over `lf.context`.
97
78
  self.assertEqual(a1.x, 1)
98
79
  self.assertEqual(a1.y, 2)
@@ -109,15 +90,7 @@ class ComponentContextTest(unittest.TestCase):
109
90
  self.assertEqual(a1.z, 3)
110
91
 
111
92
  # Test nested contextual override with override_attrs=True (default).
112
- with lf.context(y=4, z=4, override_attrs=True) as nested_override:
113
- self.assertEqual(
114
- nested_override,
115
- dict(
116
- x=lf.ContextualOverride(3, cascade=False, override_attrs=False),
117
- y=lf.ContextualOverride(4, cascade=False, override_attrs=True),
118
- z=lf.ContextualOverride(4, cascade=False, override_attrs=True),
119
- ),
120
- )
93
+ with lf.context(y=4, z=4, override_attrs=True):
121
94
 
122
95
  # Member attribute is not overriden as current scope does not override
123
96
  # `x``.