langfun 0.1.2.dev202509120804__py3-none-any.whl → 0.1.2.dev202512040805__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 (162) hide show
  1. langfun/__init__.py +1 -1
  2. langfun/core/__init__.py +7 -1
  3. langfun/core/agentic/__init__.py +8 -1
  4. langfun/core/agentic/action.py +740 -112
  5. langfun/core/agentic/action_eval.py +9 -2
  6. langfun/core/agentic/action_test.py +189 -24
  7. langfun/core/async_support.py +104 -5
  8. langfun/core/async_support_test.py +23 -0
  9. langfun/core/coding/python/correction.py +19 -9
  10. langfun/core/coding/python/execution.py +14 -12
  11. langfun/core/coding/python/generation.py +21 -16
  12. langfun/core/coding/python/sandboxing.py +23 -3
  13. langfun/core/component.py +42 -3
  14. langfun/core/concurrent.py +70 -6
  15. langfun/core/concurrent_test.py +9 -2
  16. langfun/core/console.py +1 -1
  17. langfun/core/data/conversion/anthropic.py +12 -3
  18. langfun/core/data/conversion/anthropic_test.py +8 -6
  19. langfun/core/data/conversion/gemini.py +11 -2
  20. langfun/core/data/conversion/gemini_test.py +48 -9
  21. langfun/core/data/conversion/openai.py +145 -31
  22. langfun/core/data/conversion/openai_test.py +161 -17
  23. langfun/core/eval/base.py +48 -44
  24. langfun/core/eval/base_test.py +5 -5
  25. langfun/core/eval/matching.py +5 -2
  26. langfun/core/eval/patching.py +3 -3
  27. langfun/core/eval/scoring.py +4 -3
  28. langfun/core/eval/v2/__init__.py +2 -0
  29. langfun/core/eval/v2/checkpointing.py +76 -7
  30. langfun/core/eval/v2/checkpointing_test.py +9 -2
  31. langfun/core/eval/v2/config_saver.py +37 -0
  32. langfun/core/eval/v2/config_saver_test.py +36 -0
  33. langfun/core/eval/v2/eval_test_helper.py +104 -3
  34. langfun/core/eval/v2/evaluation.py +92 -17
  35. langfun/core/eval/v2/evaluation_test.py +9 -3
  36. langfun/core/eval/v2/example.py +50 -40
  37. langfun/core/eval/v2/example_test.py +16 -8
  38. langfun/core/eval/v2/experiment.py +84 -15
  39. langfun/core/eval/v2/experiment_test.py +19 -0
  40. langfun/core/eval/v2/metric_values.py +31 -3
  41. langfun/core/eval/v2/metric_values_test.py +32 -0
  42. langfun/core/eval/v2/metrics.py +157 -44
  43. langfun/core/eval/v2/metrics_test.py +39 -18
  44. langfun/core/eval/v2/progress.py +31 -1
  45. langfun/core/eval/v2/progress_test.py +27 -0
  46. langfun/core/eval/v2/progress_tracking.py +13 -5
  47. langfun/core/eval/v2/progress_tracking_test.py +9 -1
  48. langfun/core/eval/v2/reporting.py +90 -71
  49. langfun/core/eval/v2/reporting_test.py +24 -6
  50. langfun/core/eval/v2/runners/__init__.py +30 -0
  51. langfun/core/eval/v2/{runners.py → runners/base.py} +72 -180
  52. langfun/core/eval/v2/runners/beam.py +354 -0
  53. langfun/core/eval/v2/runners/beam_test.py +153 -0
  54. langfun/core/eval/v2/runners/ckpt_monitor.py +294 -0
  55. langfun/core/eval/v2/runners/ckpt_monitor_test.py +162 -0
  56. langfun/core/eval/v2/runners/debug.py +40 -0
  57. langfun/core/eval/v2/runners/debug_test.py +76 -0
  58. langfun/core/eval/v2/runners/parallel.py +243 -0
  59. langfun/core/eval/v2/runners/parallel_test.py +182 -0
  60. langfun/core/eval/v2/runners/sequential.py +47 -0
  61. langfun/core/eval/v2/runners/sequential_test.py +169 -0
  62. langfun/core/langfunc.py +45 -130
  63. langfun/core/langfunc_test.py +7 -5
  64. langfun/core/language_model.py +189 -36
  65. langfun/core/language_model_test.py +54 -3
  66. langfun/core/llms/__init__.py +12 -1
  67. langfun/core/llms/anthropic.py +157 -2
  68. langfun/core/llms/azure_openai.py +29 -17
  69. langfun/core/llms/cache/base.py +25 -3
  70. langfun/core/llms/cache/in_memory.py +48 -7
  71. langfun/core/llms/cache/in_memory_test.py +14 -4
  72. langfun/core/llms/compositional.py +25 -1
  73. langfun/core/llms/deepseek.py +30 -2
  74. langfun/core/llms/fake.py +32 -1
  75. langfun/core/llms/gemini.py +64 -12
  76. langfun/core/llms/gemini_test.py +110 -0
  77. langfun/core/llms/google_genai.py +34 -1
  78. langfun/core/llms/groq.py +28 -3
  79. langfun/core/llms/llama_cpp.py +23 -4
  80. langfun/core/llms/openai.py +120 -3
  81. langfun/core/llms/openai_compatible.py +148 -27
  82. langfun/core/llms/openai_compatible_test.py +207 -20
  83. langfun/core/llms/openai_test.py +0 -2
  84. langfun/core/llms/rest.py +16 -1
  85. langfun/core/llms/vertexai.py +58 -8
  86. langfun/core/logging.py +1 -1
  87. langfun/core/mcp/__init__.py +10 -0
  88. langfun/core/mcp/client.py +177 -0
  89. langfun/core/mcp/client_test.py +71 -0
  90. langfun/core/mcp/session.py +241 -0
  91. langfun/core/mcp/session_test.py +54 -0
  92. langfun/core/mcp/testing/simple_mcp_client.py +33 -0
  93. langfun/core/mcp/testing/simple_mcp_server.py +33 -0
  94. langfun/core/mcp/tool.py +254 -0
  95. langfun/core/mcp/tool_test.py +197 -0
  96. langfun/core/memory.py +1 -0
  97. langfun/core/message.py +160 -55
  98. langfun/core/message_test.py +65 -81
  99. langfun/core/modalities/__init__.py +8 -0
  100. langfun/core/modalities/audio.py +21 -1
  101. langfun/core/modalities/image.py +73 -3
  102. langfun/core/modalities/image_test.py +116 -0
  103. langfun/core/modalities/mime.py +64 -3
  104. langfun/core/modalities/mime_test.py +11 -0
  105. langfun/core/modalities/pdf.py +19 -1
  106. langfun/core/modalities/video.py +21 -1
  107. langfun/core/modality.py +167 -29
  108. langfun/core/modality_test.py +42 -12
  109. langfun/core/natural_language.py +1 -1
  110. langfun/core/sampling.py +4 -4
  111. langfun/core/sampling_test.py +20 -4
  112. langfun/core/structured/__init__.py +2 -24
  113. langfun/core/structured/completion.py +34 -44
  114. langfun/core/structured/completion_test.py +23 -43
  115. langfun/core/structured/description.py +54 -50
  116. langfun/core/structured/function_generation.py +29 -12
  117. langfun/core/structured/mapping.py +81 -37
  118. langfun/core/structured/parsing.py +95 -79
  119. langfun/core/structured/parsing_test.py +0 -3
  120. langfun/core/structured/querying.py +230 -154
  121. langfun/core/structured/querying_test.py +69 -33
  122. langfun/core/structured/schema/__init__.py +49 -0
  123. langfun/core/structured/schema/base.py +664 -0
  124. langfun/core/structured/schema/base_test.py +531 -0
  125. langfun/core/structured/schema/json.py +174 -0
  126. langfun/core/structured/schema/json_test.py +121 -0
  127. langfun/core/structured/schema/python.py +316 -0
  128. langfun/core/structured/schema/python_test.py +410 -0
  129. langfun/core/structured/schema_generation.py +33 -14
  130. langfun/core/structured/scoring.py +47 -36
  131. langfun/core/structured/tokenization.py +26 -11
  132. langfun/core/subscription.py +2 -2
  133. langfun/core/template.py +175 -50
  134. langfun/core/template_test.py +123 -17
  135. langfun/env/__init__.py +43 -0
  136. langfun/env/base_environment.py +827 -0
  137. langfun/env/base_environment_test.py +473 -0
  138. langfun/env/base_feature.py +304 -0
  139. langfun/env/base_feature_test.py +228 -0
  140. langfun/env/base_sandbox.py +842 -0
  141. langfun/env/base_sandbox_test.py +1235 -0
  142. langfun/env/event_handlers/__init__.py +14 -0
  143. langfun/env/event_handlers/chain.py +233 -0
  144. langfun/env/event_handlers/chain_test.py +253 -0
  145. langfun/env/event_handlers/event_logger.py +472 -0
  146. langfun/env/event_handlers/event_logger_test.py +304 -0
  147. langfun/env/event_handlers/metric_writer.py +726 -0
  148. langfun/env/event_handlers/metric_writer_test.py +214 -0
  149. langfun/env/interface.py +1640 -0
  150. langfun/env/interface_test.py +153 -0
  151. langfun/env/load_balancers.py +59 -0
  152. langfun/env/load_balancers_test.py +141 -0
  153. langfun/env/test_utils.py +507 -0
  154. {langfun-0.1.2.dev202509120804.dist-info → langfun-0.1.2.dev202512040805.dist-info}/METADATA +7 -3
  155. langfun-0.1.2.dev202512040805.dist-info/RECORD +217 -0
  156. langfun/core/eval/v2/runners_test.py +0 -343
  157. langfun/core/structured/schema.py +0 -987
  158. langfun/core/structured/schema_test.py +0 -982
  159. langfun-0.1.2.dev202509120804.dist-info/RECORD +0 -172
  160. {langfun-0.1.2.dev202509120804.dist-info → langfun-0.1.2.dev202512040805.dist-info}/WHEEL +0 -0
  161. {langfun-0.1.2.dev202509120804.dist-info → langfun-0.1.2.dev202512040805.dist-info}/licenses/LICENSE +0 -0
  162. {langfun-0.1.2.dev202509120804.dist-info → langfun-0.1.2.dev202512040805.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,410 @@
1
+ # Copyright 2025 The Langfun Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ import dataclasses
15
+ import inspect
16
+ import typing
17
+ import unittest
18
+
19
+ import langfun.core as lf
20
+ from langfun.core.llms import fake
21
+ from langfun.core.structured.schema import base
22
+ from langfun.core.structured.schema import python
23
+ import pyglove as pg
24
+
25
+
26
+ class Activity(pg.Object):
27
+ description: str
28
+
29
+
30
+ class Itinerary(pg.Object):
31
+ """A travel itinerary for a day."""
32
+
33
+ day: pg.typing.Int[1, None]
34
+ type: pg.typing.Enum['daytime', 'nighttime']
35
+ activities: list[Activity]
36
+ hotel: pg.typing.Annotated[
37
+ pg.typing.Str['.*Hotel'] | None,
38
+ 'Hotel to stay if applicable.'
39
+ ]
40
+
41
+
42
+ class PlaceOfInterest(pg.Object):
43
+ """The name of a place of interest.
44
+
45
+ A place of interest is a place that people ususally visit during their
46
+ travels.
47
+ """
48
+
49
+ name: str
50
+
51
+
52
+ Itinerary.__serialization_key__ = 'Itinerary'
53
+
54
+
55
+ class Node(pg.Object):
56
+ children: list['Node']
57
+
58
+
59
+ class SchemaReprTest(unittest.TestCase):
60
+
61
+ def test_class_definition(self):
62
+ self.assertEqual(
63
+ python.class_definition(Activity, allowed_dependencies=set()),
64
+ 'class Activity:\n description: str\n',
65
+ )
66
+ self.assertEqual(
67
+ python.class_definition(Itinerary),
68
+ inspect.cleandoc("""
69
+ class Itinerary(Object):
70
+ \"\"\"A travel itinerary for a day.\"\"\"
71
+ day: int(min=1)
72
+ type: Literal['daytime', 'nighttime']
73
+ activities: list[Activity]
74
+ # Hotel to stay if applicable.
75
+ hotel: str(regex='.*Hotel') | None
76
+ """) + '\n',
77
+ )
78
+ self.assertEqual(
79
+ python.class_definition(
80
+ PlaceOfInterest, allowed_dependencies=set()
81
+ ),
82
+ inspect.cleandoc("""
83
+ class PlaceOfInterest:
84
+ \"\"\"The name of a place of interest.
85
+
86
+ A place of interest is a place that people ususally visit during their
87
+ travels.
88
+ \"\"\"
89
+ name: str
90
+ """) + '\n',
91
+ )
92
+
93
+ class A(pg.Object):
94
+ pass
95
+
96
+ self.assertEqual(
97
+ python.class_definition(A, allowed_dependencies=set()),
98
+ 'class A:\n pass\n',
99
+ )
100
+ self.assertEqual(
101
+ python.class_definition(A),
102
+ 'class A(Object):\n pass\n',
103
+ )
104
+
105
+ class C(pg.Object):
106
+ x: str
107
+ __kwargs__: typing.Any
108
+
109
+ self.assertEqual(
110
+ python.class_definition(C), 'class C(Object):\n x: str\n'
111
+ )
112
+
113
+ class D(pg.Object):
114
+ x: str
115
+ @python.include_method_in_prompt
116
+ def __call__(self, y: int) -> int:
117
+ return len(self.x) + y
118
+
119
+ self.assertEqual(
120
+ python.class_definition(D),
121
+ inspect.cleandoc(
122
+ """
123
+ class D(Object):
124
+ x: str
125
+
126
+ def __call__(self, y: int) -> int:
127
+ return len(self.x) + y
128
+ """) + '\n'
129
+ )
130
+
131
+ class E(pg.Object):
132
+ x: str
133
+ y: typing.Annotated[int, 'y', dict(exclude_from_prompt=True)]
134
+
135
+ self.assertEqual(
136
+ python.class_definition(E),
137
+ inspect.cleandoc(
138
+ """
139
+ class E(Object):
140
+ x: str
141
+ """) + '\n'
142
+ )
143
+
144
+ def test_repr(self):
145
+ class Foo(pg.Object):
146
+ x: int
147
+
148
+ @dataclasses.dataclass(frozen=True)
149
+ class Bar:
150
+ """Class Bar."""
151
+ y: str
152
+
153
+ @dataclasses.dataclass(frozen=True)
154
+ class Baz(Bar): # pylint: disable=unused-variable
155
+ pass
156
+
157
+ class A(pg.Object):
158
+ foo: Foo
159
+
160
+ @python.include_method_in_prompt
161
+ def foo_value(self) -> int:
162
+ return self.foo.x
163
+
164
+ def baz_value(self) -> str:
165
+ return 'baz'
166
+
167
+ class B(A):
168
+ bar: Bar
169
+ foo2: Foo
170
+
171
+ @python.include_method_in_prompt
172
+ def bar_value(self) -> str:
173
+ return self.bar.y
174
+
175
+ schema = base.Schema([B])
176
+ self.assertEqual(
177
+ python.PythonPromptingProtocol().class_definitions(schema),
178
+ inspect.cleandoc('''
179
+ class Foo:
180
+ x: int
181
+
182
+ class Bar:
183
+ """Class Bar."""
184
+ y: str
185
+
186
+ class Baz(Bar):
187
+ """Baz(y: str)"""
188
+ y: str
189
+
190
+ class B:
191
+ foo: Foo
192
+ bar: Bar
193
+ foo2: Foo
194
+
195
+ def bar_value(self) -> str:
196
+ return self.bar.y
197
+
198
+ def foo_value(self) -> int:
199
+ return self.foo.x
200
+ ''') + '\n',
201
+ )
202
+
203
+ self.assertEqual(
204
+ python.PythonPromptingProtocol().result_definition(schema), 'list[B]'
205
+ )
206
+
207
+ self.assertEqual(
208
+ base.schema_repr(schema),
209
+ inspect.cleandoc('''
210
+ list[B]
211
+
212
+ ```python
213
+ class Foo:
214
+ x: int
215
+
216
+ class Bar:
217
+ """Class Bar."""
218
+ y: str
219
+
220
+ class Baz(Bar):
221
+ """Baz(y: str)"""
222
+ y: str
223
+
224
+ class B:
225
+ foo: Foo
226
+ bar: Bar
227
+ foo2: Foo
228
+
229
+ def bar_value(self) -> str:
230
+ return self.bar.y
231
+
232
+ def foo_value(self) -> int:
233
+ return self.foo.x
234
+ ```
235
+ '''),
236
+ )
237
+ self.assertEqual(
238
+ python.PythonPromptingProtocol().schema_repr(
239
+ schema,
240
+ include_result_definition=False,
241
+ markdown=False,
242
+ ),
243
+ inspect.cleandoc('''
244
+ class Foo:
245
+ x: int
246
+
247
+ class Bar:
248
+ """Class Bar."""
249
+ y: str
250
+
251
+ class Baz(Bar):
252
+ """Baz(y: str)"""
253
+ y: str
254
+
255
+ class B:
256
+ foo: Foo
257
+ bar: Bar
258
+ foo2: Foo
259
+
260
+ def bar_value(self) -> str:
261
+ return self.bar.y
262
+
263
+ def foo_value(self) -> int:
264
+ return self.foo.x
265
+ '''),
266
+ )
267
+
268
+
269
+ class ValuePythonReprTest(unittest.TestCase):
270
+
271
+ def test_repr(self):
272
+ class Foo(pg.Object):
273
+ x: int
274
+
275
+ class A(pg.Object):
276
+ foo: list[Foo]
277
+ y: str | None
278
+
279
+ self.assertEqual(
280
+ base.value_repr(1, base.Schema(int)),
281
+ '```python\n1\n```'
282
+ )
283
+ self.assertEqual(
284
+ base.value_repr(lf.Template('hi, {{a}}', a='foo')),
285
+ 'hi, foo'
286
+ )
287
+ self.assertEqual(
288
+ base.value_repr(
289
+ A([Foo(1), Foo(2)], 'bar'), base.Schema(A), markdown=False,
290
+ ),
291
+ "A(foo=[Foo(x=1), Foo(x=2)], y='bar')",
292
+ )
293
+ self.assertEqual(
294
+ base.value_repr(
295
+ A([Foo(1), Foo(2)], 'bar'),
296
+ base.Schema(A),
297
+ markdown=True,
298
+ compact=False,
299
+ assign_to_var='output',
300
+ ),
301
+ inspect.cleandoc("""
302
+ ```python
303
+ output = A(
304
+ foo=[
305
+ Foo(
306
+ x=1
307
+ ),
308
+ Foo(
309
+ x=2
310
+ )
311
+ ],
312
+ y='bar'
313
+ )
314
+ ```
315
+ """),
316
+ )
317
+ self.assertEqual(
318
+ base.value_repr(A),
319
+ inspect.cleandoc("""
320
+ ```python
321
+ class Foo(Object):
322
+ x: int
323
+
324
+ class A(Object):
325
+ foo: list[Foo]
326
+ y: str | None
327
+ ```
328
+ """),
329
+ )
330
+ self.assertEqual(python.source_form(int), 'int')
331
+
332
+ def test_parse(self):
333
+ class Foo(pg.Object):
334
+ x: int
335
+
336
+ class A(pg.Object):
337
+ foo: list[Foo]
338
+ y: str | None
339
+
340
+ self.assertEqual(
341
+ base.parse_value(
342
+ "A(foo=[Foo(x=1), Foo(x=2)], y='bar')", base.Schema(A)
343
+ ),
344
+ A([Foo(1), Foo(2)], y='bar'),
345
+ )
346
+
347
+ def test_parse_with_correction(self):
348
+ class Foo(pg.Object):
349
+ x: int
350
+
351
+ class A(pg.Object):
352
+ foo: list[Foo]
353
+ y: str | None
354
+
355
+ self.assertEqual(
356
+ base.parse_value(
357
+ "A(foo=[Foo(x=1), Foo(x=2)], y='bar'",
358
+ base.Schema(A),
359
+ autofix=1,
360
+ autofix_lm=fake.StaticResponse(
361
+ inspect.cleandoc(
362
+ """
363
+ CorrectedCode(
364
+ corrected_code='A(foo=[Foo(x=1), Foo(x=2)], y=\\\'bar\\\')',
365
+ )
366
+ """
367
+ )
368
+ ),
369
+ ),
370
+ A([Foo(1), Foo(2)], y='bar'),
371
+ )
372
+
373
+ def test_parse_class_def(self):
374
+ self.assertTrue(
375
+ inspect.isclass(
376
+ base.parse_value(
377
+ """
378
+ class A:
379
+ x: Dict[str, Any]
380
+ y: Optional[Sequence[str]]
381
+ z: Union[int, List[int], Tuple[int]]
382
+ """,
383
+ permission=pg.coding.CodePermission.ALL,
384
+ )
385
+ )
386
+ )
387
+
388
+
389
+ class StructureFromPythonTest(unittest.TestCase):
390
+
391
+ def test_parse_class_def(self):
392
+
393
+ class B:
394
+ pass
395
+
396
+ schema = base.Schema([B])
397
+ v = python.structure_from_python(
398
+ """
399
+ class C(B):
400
+ pass
401
+ """,
402
+ global_vars=dict(B=B),
403
+ permission=pg.coding.CodePermission.ALL,
404
+ )
405
+ self.assertEqual(v.__module__, 'builtins')
406
+ self.assertEqual(schema.class_dependencies(), [B])
407
+
408
+
409
+ if __name__ == '__main__':
410
+ unittest.main()
@@ -90,16 +90,35 @@ def generate_class(
90
90
  skip_lm: bool = False,
91
91
  **kwargs,
92
92
  ) -> Type[Any] | lf.Message:
93
- """Generate a class with specified name based on the prompt.
94
-
95
- Example:
96
- ```
97
- trip_cls = lf.classgen(
98
- 'Trip',
99
- 'A trip plan to visit {{ city }}, city='San Francisco',
100
- lm=lf.llms.GeminiPro()
101
- )
102
- ```
93
+ """Generates a Python class dynamically from a prompt using an LLM.
94
+
95
+ `lf.structured.generate_class` takes a class name and a natural language
96
+ description (prompt) and uses a language model to generate a Python class
97
+ (inheriting from `pg.Object`) that matches the description.
98
+ This is useful for creating structured data types on-the-fly based on
99
+ dynamic requirements.
100
+
101
+ **Example:**
102
+
103
+ ```python
104
+ import langfun as lf
105
+ import pyglove as pg
106
+
107
+ trip_plan_cls = lf.structured.generate_class(
108
+ 'TripPlan',
109
+ 'A trip plan to visit San Francisco, including a list of destinations,'
110
+ 'start date, end date, and total budget.',
111
+ lm=lf.llms.Gemini25Flash())
112
+
113
+ # This might generate a class like:
114
+ # class TripPlan(pg.Object):
115
+ # destinations: list[str]
116
+ # start_date: str
117
+ # end_date: str
118
+ # total_budget: float
119
+
120
+ print(lf.Schema.from_value(trip_plan_cls).schema_str('python'))
121
+ ```
103
122
 
104
123
  Args:
105
124
  name: Class name to be generated.
@@ -108,17 +127,17 @@ def generate_class(
108
127
  lm: The language model to use. If not specified, the language model from
109
128
  `lf.context` context manager will be used.
110
129
  examples: An optional list of fewshot examples for helping class generation.
111
- If None, a default single shot example will be used. Use
112
- `lf.structured.classgen_example` to generate example.
130
+ If None, a default single-shot example will be used. Use
131
+ `lf.structured.classgen_example` to generate examples.
113
132
  returns_message: If True, returns `lf.Message` as the output, instead of
114
133
  returning the structured `message.result`.
115
134
  skip_lm: If True, returns the rendered prompt as a UserMessage object.
116
- otherwise return the LLM response based on the rendered prompt.
135
+ otherwise returns the LLM response based on the rendered prompt.
117
136
  **kwargs: Template variables passed to `prompt` and keyword arguments passed
118
137
  to `lf.structured.GenerateClass`.
119
138
 
120
139
  Returns:
121
- Generated class.
140
+ The generated Python class, or `lf.Message` if `returns_message` is True.
122
141
 
123
142
  Raises:
124
143
  CodeError: if generation failed.
@@ -31,42 +31,54 @@ def score(
31
31
  *,
32
32
  lm: lf.LanguageModel | None = None,
33
33
  examples: list[mapping.MappingExample] | None = None,
34
- protocol: schema_lib.SchemaProtocol = 'python',
34
+ protocol: str = 'python',
35
35
  return_scoring_results: bool = False,
36
36
  **kwargs,
37
37
  ) -> list[float] | list[lf.LMScoringResult]:
38
- """Scores the outputs based on the prompt.
39
-
40
- Examples:
41
- ```
42
- # Example 1: Scoring text output based on the user prompt.
43
- scores = lf.score('{{x}} + {{y}} =', ['1', '2', '3'], lm=lm, x=1, y=2)
44
- assert len(scores) == 3
45
-
46
- # Example 2: Scoring int output based on the formulated OOP prompt.
47
- scores = lf.score('1 + 1 =', [1, 2, 3], lm=lm)
48
- assert len(scores) == 3
49
-
50
- class Answer(pg.Object):
51
- result: int
52
-
53
- # Example 3: Scoring object output based on the formulated OOP prompt.
54
- scores = lf.score('1 + 1 =', [Answer(1), Answer(2), Answer(3)], lm=lm)
55
- assert len(scores) == 3
56
-
57
- # Example 4: Scoring object field value based on the formulated OOP prompt
58
- # and the generated tokens before the first `pg.oneof`.
59
- scores = lf.score('1 + 1 =', [Answer(pg.oneof([1, 2, 3]))], lm=lm)
60
- assert len(scores) == 3
61
-
62
- # Example 5: Scoring multiple prompt/completion pairs.
63
- scores = lf.score(
64
- ['1 + 1=', '2 + 3='],
65
- ['2', '4'],
66
- lm=lm
67
- )
68
- assert len(scores) == 2
69
- ```
38
+ """Scores completions based on a prompt using a language model.
39
+
40
+ `lf.score` computes the likelihood of each completion being generated given
41
+ a prompt, according to the specified language model. It can score text
42
+ completions or structured objects. If `schema` is provided, Langfun
43
+ formats the prompt and completions appropriately before scoring.
44
+
45
+ **Example 1: Score text completions**
46
+ ```python
47
+ import langfun as lf
48
+ scores = lf.score(
49
+ '1 + 1 =',
50
+ ['2', '3', '4'],
51
+ lm=lf.llms.Gemini25Flash())
52
+ print([f'{s:.3f}' for s in scores])
53
+ # Output: ['-0.001', '-2.345', '-3.456']
54
+ ```
55
+
56
+ **Example 2: Score structured completions**
57
+ ```python
58
+ import langfun as lf
59
+ import pyglove as pg
60
+
61
+ class Answer(pg.Object):
62
+ result: int
63
+
64
+ scores = lf.score(
65
+ '1 + 1 =',
66
+ [Answer(result=2), Answer(result=3), Answer(result=4)],
67
+ lm=lf.llms.Gemini25Flash())
68
+ print([f'{s:.3f}' for s in scores])
69
+ # Output: ['-0.001', '-2.345', '-3.456']
70
+ ```
71
+
72
+ **Example 3: Score multiple prompt/completion pairs**
73
+ ```python
74
+ import langfun as lf
75
+ scores = lf.score(
76
+ ['1 + 1 =', '2 + 2 ='],
77
+ ['2', '4'],
78
+ lm=lf.llms.Gemini25Flash())
79
+ print([f'{s:.3f}' for s in scores])
80
+ # Output: ['-0.001', '-0.002']
81
+ ```
70
82
 
71
83
  Args:
72
84
  prompt: The prompt(s) based on which each completion will be scored.
@@ -74,8 +86,7 @@ def score(
74
86
  schema: The schema as the output type. If None, it will be inferred from
75
87
  the completions.
76
88
  lm: The language model used for scoring.
77
- examples: Fewshot exemplars used together with the prompt in getting the
78
- completions.
89
+ examples: Few-shot examples used to construct the prompt for scoring.
79
90
  protocol: The protocol for formulating the prompt based on objects.
80
91
  return_scoring_results: If True, returns a list of `lf.LMScoringResult`,
81
92
  otherwise returns a list of floats as the scores of each completion.
@@ -190,7 +201,7 @@ async def ascore(
190
201
  *,
191
202
  lm: lf.LanguageModel | None = None,
192
203
  examples: list[mapping.MappingExample] | None = None,
193
- protocol: schema_lib.SchemaProtocol = 'python',
204
+ protocol: str = 'python',
194
205
  return_scoring_results: bool = False,
195
206
  **kwargs,
196
207
  ) -> list[float] | list[lf.LMScoringResult]:
@@ -23,30 +23,45 @@ import pyglove as pg
23
23
 
24
24
 
25
25
  def tokenize(
26
- prompt: Union[str, pg.Symbolic] | list[str | pg.Symbolic],
26
+ prompt: Union[str, pg.Symbolic, list[str | pg.Symbolic]],
27
27
  schema: Union[
28
28
  schema_lib.Schema, Type[Any], list[Type[Any]], dict[str, Any], None
29
29
  ] = None,
30
30
  *,
31
31
  lm: lf.LanguageModel | None = None,
32
32
  examples: list[mapping.MappingExample] | None = None,
33
- protocol: schema_lib.SchemaProtocol = 'python',
33
+ protocol: str = 'python',
34
34
  **kwargs,
35
35
  ) -> list[tuple[str | bytes, int]]:
36
- """Tokenize the prompt for `lf.query`.
36
+ """Renders a prompt and tokenizes it using a language model.
37
+
38
+ `lf.tokenize` first renders a prompt based on the provided `prompt`,
39
+ `schema`, and `examples`, similar to `lf.query`, and then uses the
40
+ specified language model (`lm`) to tokenize the resulting message.
41
+ This is useful for understanding how a prompt is seen by the model or
42
+ for estimating token counts before sending requests.
43
+
44
+ **Example:**
45
+
46
+ ```python
47
+ import langfun as lf
48
+ tokens = lf.tokenize('Hello world!', lm=lf.llms.Gpt4())
49
+ print(tokens)
50
+ # Output might look like: [('Hello', 15339), (' world', 1917), ('!', 0)]
51
+ ```
37
52
 
38
53
  Args:
39
- prompt: The prompt(s) based on which each completion will be scored.
40
- schema: The schema as the output type. If None, it will be inferred from
41
- the completions.
42
- lm: The language model used for scoring.
43
- examples: Fewshot exemplars used together with the prompt in getting the
44
- completions.
54
+ prompt: The prompt to render and tokenize. Can be a string, `pg.Symbolic`,
55
+ or `lf.Template`.
56
+ schema: The schema for formatting the prompt, if `prompt` is structured or
57
+ if schema-based formatting is needed.
58
+ lm: The language model to use for tokenization.
59
+ examples: Few-shot examples to include in the rendered prompt.
45
60
  protocol: The protocol for formulating the prompt based on objects.
46
61
  **kwargs: Keyword arguments that are referred by the prompt.
47
62
 
48
63
  Returns:
49
- A list of (text, token_id) tuples.
64
+ A list of (token_str, token_id) tuples representing the tokenized prompt.
50
65
  """
51
66
  input_message = querying.query_prompt(
52
67
  prompt,
@@ -72,7 +87,7 @@ async def atokenize(
72
87
  *,
73
88
  lm: lf.LanguageModel | None = None,
74
89
  examples: list[mapping.MappingExample] | None = None,
75
- protocol: schema_lib.SchemaProtocol = 'python',
90
+ protocol: str = 'python',
76
91
  **kwargs,
77
92
  ) -> list[tuple[str | bytes, int]]:
78
93
  """Async version of `lf.tokenize`."""
@@ -35,7 +35,7 @@ EventType = TypeVar('EventType')
35
35
 
36
36
 
37
37
  class EventHandler(Generic[EventType], metaclass=abc.ABCMeta):
38
- """Interface for event subscriber."""
38
+ """Interface for event handler."""
39
39
 
40
40
  @classmethod
41
41
  @functools.cache
@@ -51,7 +51,7 @@ class EventHandler(Generic[EventType], metaclass=abc.ABCMeta):
51
51
 
52
52
  @classmethod
53
53
  def accepts(cls, event: Event[Any]) -> bool:
54
- """Returns True if current event handler class can accepts an event."""
54
+ """Returns True if current event handler class can accept an event."""
55
55
  return isinstance(event, cls.event_type())
56
56
 
57
57
  @abc.abstractmethod