langfun 0.1.2.dev202504290805__py3-none-any.whl → 0.1.2.dev202504300804__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.

Potentially problematic release.


This version of langfun might be problematic. Click here for more details.

langfun/__init__.py CHANGED
@@ -37,6 +37,9 @@ generate_class = structured.generate_class
37
37
 
38
38
  track_queries = structured.track_queries
39
39
 
40
+ # Context manager for setting the query protocol for the scope.
41
+ query_protocol = structured.query_protocol
42
+
40
43
  # Helper function for map-reduce style querying.
41
44
  query_and_reduce = structured.query_and_reduce
42
45
 
@@ -35,13 +35,18 @@ class ActionEval(lf.eval.v2.Evaluation):
35
35
  example_input = example.input
36
36
  action = example_input.action
37
37
  session = action_lib.Session(id=f'{self.id}#example-{example.id}')
38
+
39
+ # NOTE(daiyip): Setting session as metadata before action execution, so we
40
+ # could use `Evaluation.state.in_progress_examples` to access the session
41
+ # for status reporting from other threads.
42
+ example.metadata['session'] = session
43
+
38
44
  with lf.logging.use_log_level('fatal'):
39
45
  kwargs = self.action_args.copy()
40
46
  kwargs.update(verbose=True)
41
47
  action(session=session, **kwargs)
42
48
  return session.final_result, dict(session=session)
43
49
 
44
-
45
50
  #
46
51
  # TODO(daiyip): Remove V1 once V2 is fully launched.
47
52
  #
@@ -195,7 +195,7 @@ class EvaluationTest(unittest.TestCase):
195
195
  score=1.0,
196
196
  logprobs=None,
197
197
  is_cached=False,
198
- usage=lf.LMSamplingUsage(387, 24, 411),
198
+ usage=lf.LMSamplingUsage(428, 24, 452),
199
199
  tags=['lm-response', 'lm-output', 'transformed'],
200
200
  ),
201
201
  )
@@ -234,12 +234,12 @@ class EvaluationTest(unittest.TestCase):
234
234
  }
235
235
  ),
236
236
  usage=dict(
237
- total_prompt_tokens=774,
237
+ total_prompt_tokens=856,
238
238
  total_completion_tokens=25,
239
239
  num_usages=2,
240
- average_prompt_tokens=387,
240
+ average_prompt_tokens=428,
241
241
  average_completion_tokens=12,
242
- average_total_tokens=399,
242
+ average_total_tokens=440,
243
243
  ),
244
244
  ),
245
245
  )
@@ -167,6 +167,8 @@ class Evaluation(experiment_lib.Experiment):
167
167
  example.input = self.example_input_by_id(example.id)
168
168
 
169
169
  checkpointed = self._state.ckpt_example(example.id)
170
+ self._state.update(example, in_progress=True)
171
+
170
172
  with pg.timeit('evaluate') as timeit, lf.track_usages() as usage_summary:
171
173
  if checkpointed is None or checkpointed.has_error:
172
174
  if checkpointed is None:
@@ -221,7 +223,7 @@ class Evaluation(experiment_lib.Experiment):
221
223
  if example.newly_processed:
222
224
  example.end_time = time.time()
223
225
 
224
- self._state.update(example)
226
+ self._state.update(example, in_progress=False)
225
227
  return example
226
228
 
227
229
  def _process(
@@ -501,6 +503,21 @@ class Evaluation(experiment_lib.Experiment):
501
503
  )
502
504
  )
503
505
 
506
+ def _in_progress_tab() -> pg.views.html.controls.Tab | None:
507
+ """Renders a tab for the in progress examples."""
508
+ if not self.state.in_progress_examples:
509
+ return None
510
+ return pg.views.html.controls.Tab(
511
+ label='In Progress',
512
+ content=pg.Html.element(
513
+ 'div', [
514
+ self._in_progress_view(
515
+ list(self.state.in_progress_examples.values())
516
+ )
517
+ ]
518
+ )
519
+ )
520
+
504
521
  def _metric_tab(metric: metrics_lib.Metric) -> pg.views.html.controls.Tab:
505
522
  """Renders a tab for a metric (group)."""
506
523
  return pg.views.html.controls.Tab(
@@ -571,10 +588,9 @@ class Evaluation(experiment_lib.Experiment):
571
588
  pg.views.html.controls.TabControl(
572
589
  [
573
590
  _definition_tab(),
574
- ] + [
575
- _metric_tab(m) for m in self.metrics
576
- ] + [
577
- _logs_tab()
591
+ [_metric_tab(m) for m in self.metrics],
592
+ _in_progress_tab(),
593
+ _logs_tab(),
578
594
  ],
579
595
  selected=1,
580
596
  )
@@ -598,6 +614,27 @@ class Evaluation(experiment_lib.Experiment):
598
614
  css_classes=['eval-details'],
599
615
  )
600
616
 
617
+ def _in_progress_view(
618
+ self, in_progress_examples: list[example_lib.Example]
619
+ ) -> pg.Html:
620
+ """Renders a HTML view for the in-progress examples."""
621
+ current_time = time.time()
622
+ logs = [f'(Total {len(in_progress_examples)} examples in progress)']
623
+ for example in in_progress_examples:
624
+ if example.newly_processed:
625
+ logs.append(
626
+ f'Example {example.id}: In progress for '
627
+ f'{current_time - example.start_time:.2f} seconds.'
628
+ )
629
+ else:
630
+ logs.append(f'Example {example.id}: Recomputing metrics...')
631
+ return pg.Html.element(
632
+ 'textarea',
633
+ [pg.Html.escape('\n'.join(logs))],
634
+ readonly=True,
635
+ css_classes=['logs-textarea'],
636
+ )
637
+
601
638
  def _html_tree_view_config(self) -> dict[str, Any]:
602
639
  return dict(
603
640
  css_classes=['eval-card'] if self.is_leaf else None
@@ -716,14 +753,27 @@ class EvaluationState:
716
753
  'Whether the example is evaluated.'
717
754
  ] = False
718
755
 
756
+ in_progress: Annotated[
757
+ bool,
758
+ (
759
+ 'Whether the example is in progress. '
760
+ )
761
+ ] = False
762
+
719
763
  newly_processed: Annotated[
720
764
  bool,
721
- 'Whether the example is newly processed.'
765
+ (
766
+ 'Whether the example is newly processed. '
767
+ 'Applicable only when evaluated is True.'
768
+ )
722
769
  ] = False
723
770
 
724
771
  has_error: Annotated[
725
772
  bool,
726
- 'Whether the example has error.'
773
+ (
774
+ 'Whether the example has error. '
775
+ 'Applicable only when evaluated is True.'
776
+ )
727
777
  ] = False
728
778
 
729
779
  def __init__(self):
@@ -732,6 +782,7 @@ class EvaluationState:
732
782
  self._evaluation_status: dict[
733
783
  int, EvaluationState.ExampleStatus
734
784
  ] = {}
785
+ self._in_progress_examples: dict[int, example_lib.Example] = {}
735
786
 
736
787
  def load(
737
788
  self,
@@ -758,6 +809,11 @@ class EvaluationState:
758
809
  """Returns the evaluation status of the examples."""
759
810
  return self._evaluation_status
760
811
 
812
+ @property
813
+ def in_progress_examples(self) -> dict[int, example_lib.Example]:
814
+ """Returns the in-progress examples."""
815
+ return self._in_progress_examples
816
+
761
817
  @property
762
818
  def ckpt_examples(self) -> dict[int, example_lib.Example]:
763
819
  """Returns the unevaluated examples from checkpoints."""
@@ -773,17 +829,27 @@ class EvaluationState:
773
829
  example_id, EvaluationState.ExampleStatus()
774
830
  )
775
831
 
776
- def update(self, example: example_lib.Example) -> None:
832
+ def update(self, example: example_lib.Example, in_progress: bool) -> None:
777
833
  """Updates the state with the given example."""
778
- self._update_status(example)
779
- # Processed examples will be removed once it's done.
780
- self._ckpt_examples.pop(example.id, None)
834
+ self._update_status(example, in_progress)
835
+
836
+ if in_progress:
837
+ self._in_progress_examples[example.id] = example
838
+ else:
839
+ self._in_progress_examples.pop(example.id, None)
840
+ # Processed examples will be removed once it's done.
841
+ self._ckpt_examples.pop(example.id, None)
781
842
 
782
- def _update_status(self, example: example_lib.Example) -> None:
843
+ def _update_status(
844
+ self,
845
+ example: example_lib.Example,
846
+ in_progress: bool
847
+ ) -> None:
783
848
  """Updates the evaluation status of the example."""
784
849
  self._evaluation_status[example.id] = (
785
850
  EvaluationState.ExampleStatus(
786
851
  evaluated=example.output != pg.MISSING_VALUE,
852
+ in_progress=in_progress,
787
853
  newly_processed=example.newly_processed,
788
854
  has_error=example.has_error,
789
855
  )
@@ -79,8 +79,10 @@ class EvaluationTest(unittest.TestCase):
79
79
  exp = eval_test_helper.TestEvaluation()
80
80
  example = exp.evaluate(Example(id=3))
81
81
  self.assertTrue(exp.state.get_status(3).evaluated)
82
+ self.assertFalse(exp.state.get_status(3).in_progress)
82
83
  self.assertTrue(exp.state.get_status(3).newly_processed)
83
84
  self.assertFalse(exp.state.get_status(3).has_error)
85
+ self.assertEqual(exp.state.in_progress_examples, {})
84
86
  self.assertTrue(example.newly_processed)
85
87
  self.assertEqual(example.input, pg.Dict(x=2, y=4, groundtruth=6))
86
88
  self.assertEqual(example.output, 6)
@@ -55,8 +55,11 @@ from langfun.core.structured.parsing import call
55
55
 
56
56
  from langfun.core.structured.querying import track_queries
57
57
  from langfun.core.structured.querying import QueryInvocation
58
+
59
+ from langfun.core.structured.querying import LfQuery
58
60
  from langfun.core.structured.querying import query
59
61
  from langfun.core.structured.querying import query_and_reduce
62
+ from langfun.core.structured.querying import query_protocol
60
63
 
61
64
  from langfun.core.structured.querying import query_prompt
62
65
  from langfun.core.structured.querying import query_output
@@ -340,8 +340,11 @@ class Mapping(lf.LangFunc):
340
340
  schema_title: Annotated[str, 'The section title for schema.'] = 'SCHEMA'
341
341
 
342
342
  protocol: Annotated[
343
- schema_lib.SchemaProtocol,
344
- 'The protocol for representing the schema and value.',
343
+ str,
344
+ (
345
+ 'A string representing the protocol for formatting the prompt. '
346
+ 'Built-in Langfun protocols are: `python` and `json`.'
347
+ ),
345
348
  ] = 'python'
346
349
 
347
350
  #
@@ -646,7 +646,7 @@ class CallTest(unittest.TestCase):
646
646
  score=1.0,
647
647
  logprobs=None,
648
648
  is_cached=False,
649
- usage=lf.LMSamplingUsage(315, 1, 316),
649
+ usage=lf.LMSamplingUsage(356, 1, 357),
650
650
  tags=['lm-response', 'lm-output', 'transformed']
651
651
  ),
652
652
  )
@@ -15,8 +15,9 @@
15
15
 
16
16
  import contextlib
17
17
  import functools
18
+ import inspect
18
19
  import time
19
- from typing import Annotated, Any, Callable, Iterator, Type, Union
20
+ from typing import Annotated, Any, Callable, ClassVar, Iterator, Type, Union
20
21
  import uuid
21
22
 
22
23
  import langfun.core as lf
@@ -26,8 +27,35 @@ import pyglove as pg
26
27
 
27
28
 
28
29
  @lf.use_init_args(['schema', 'default', 'examples'])
29
- class _QueryStructure(mapping.Mapping):
30
- """Query an object out from a natural language text."""
30
+ class LfQuery(mapping.Mapping):
31
+ """Base class for different implementations of `lf.query`.
32
+
33
+ By subclassing this class, users could create variations of prompts for
34
+ `lf.query` and associated them with specific protocols and versions.
35
+
36
+ For example:
37
+
38
+ ```
39
+ class _MyLfQuery(LFQuery):
40
+ protocol = 'my_format'
41
+ version = '1.0'
42
+
43
+ template_str = inspect.cleandoc(
44
+ '''
45
+ ...
46
+ '''
47
+ )
48
+ mapping_template = lf.Template(
49
+ '''
50
+ ...
51
+ '''
52
+ )
53
+
54
+ lf.query(..., protocol='my_format:1.0')
55
+ ```
56
+
57
+ (THIS IS NOT A TEMPLATE)
58
+ """
31
59
 
32
60
  context_title = 'CONTEXT'
33
61
  input_title = 'INPUT_OBJECT'
@@ -37,8 +65,81 @@ class _QueryStructure(mapping.Mapping):
37
65
  schema_lib.schema_spec(), 'Required schema for parsing.'
38
66
  ]
39
67
 
68
+ # A map from (protocol, version) to the query structure class.
69
+ # This is used to map different protocols/versions to different templates.
70
+ # So users can use `lf.query(..., protocol='<protocol>:<version>')` to use
71
+ # a specific version of the prompt. We use this feature to support variations
72
+ # of prompts and maintain backward compatibility.
73
+ _OOP_PROMPT_MAP: ClassVar[
74
+ dict[
75
+ str, # protocol.
76
+ dict[
77
+ str, # version.
78
+ Type['LfQuery']
79
+ ]
80
+ ]
81
+ ] = {}
82
+
83
+ # This the flag to update default protocol version.
84
+ _DEFAULT_PROTOCOL_VERSIONS: ClassVar[dict[str, str]] = {
85
+ 'python': '2.0',
86
+ 'json': '1.0',
87
+ }
88
+
89
+ def __init_subclass__(cls) -> Any:
90
+ super().__init_subclass__()
91
+ if not inspect.isabstract(cls):
92
+ protocol = cls.__schema__['protocol'].default_value
93
+ version_dict = cls._OOP_PROMPT_MAP.get(protocol)
94
+ if version_dict is None:
95
+ version_dict = {}
96
+ cls._OOP_PROMPT_MAP[protocol] = version_dict
97
+ dest_cls = version_dict.get(cls.version)
98
+ if dest_cls is not None and dest_cls.__type_name__ != cls.__type_name__:
99
+ raise ValueError(
100
+ f'Version {cls.version} is already registered for {dest_cls!r} '
101
+ f'under protocol {protocol!r}. Please use a different version.'
102
+ )
103
+ version_dict[cls.version] = cls
104
+
105
+ @classmethod
106
+ def from_protocol(cls, protocol: str) -> Type['LfQuery']:
107
+ """Returns a query structure from the given protocol and version."""
108
+ if ':' in protocol:
109
+ protocol, version = protocol.split(':')
110
+ else:
111
+ version = cls._DEFAULT_PROTOCOL_VERSIONS.get(protocol)
112
+ if version is None:
113
+ version_dict = cls._OOP_PROMPT_MAP.get(protocol)
114
+ if version_dict is None:
115
+ raise ValueError(
116
+ f'Protocol {protocol!r} is not supported. Available protocols: '
117
+ f'{sorted(cls._OOP_PROMPT_MAP.keys())}.'
118
+ )
119
+ elif len(version_dict) == 1:
120
+ version = list(version_dict.keys())[0]
121
+ else:
122
+ raise ValueError(
123
+ f'Multiple versions found for protocol {protocol!r}, please '
124
+ f'specify a version with "{protocol}:<version>".'
125
+ )
126
+
127
+ version_dict = cls._OOP_PROMPT_MAP.get(protocol)
128
+ if version_dict is None:
129
+ raise ValueError(
130
+ f'Protocol {protocol!r} is not supported. Available protocols: '
131
+ f'{sorted(cls._OOP_PROMPT_MAP.keys())}.'
132
+ )
133
+ dest_cls = version_dict.get(version)
134
+ if dest_cls is None:
135
+ raise ValueError(
136
+ f'Version {version!r} is not supported for protocol {protocol!r}. '
137
+ f'Available versions: {sorted(version_dict.keys())}.'
138
+ )
139
+ return dest_cls
40
140
 
41
- class _QueryStructureJson(_QueryStructure):
141
+
142
+ class _LfQueryJsonV1(LfQuery):
42
143
  """Query a structured value using JSON as the protocol."""
43
144
 
44
145
  preamble = """
@@ -58,12 +159,13 @@ class _QueryStructureJson(_QueryStructure):
58
159
  {"result": {"_type": "langfun.core.structured.query.Answer", "final_answer": 2}}
59
160
  """
60
161
 
162
+ version = '1.0'
61
163
  protocol = 'json'
62
164
  schema_title = 'SCHEMA'
63
165
  output_title = 'JSON'
64
166
 
65
167
 
66
- class _QueryStructurePython(_QueryStructure):
168
+ class _LfQueryPythonV1(LfQuery):
67
169
  """Query a structured value using Python as the protocol."""
68
170
 
69
171
  preamble = """
@@ -87,20 +189,87 @@ class _QueryStructurePython(_QueryStructure):
87
189
  )
88
190
  ```
89
191
  """
192
+ version = '1.0'
90
193
  protocol = 'python'
91
194
  schema_title = 'OUTPUT_TYPE'
92
195
  output_title = 'OUTPUT_OBJECT'
196
+ mapping_template = lf.Template(
197
+ """
198
+ {%- if example.context -%}
199
+ {{ context_title}}:
200
+ {{ example.context | indent(2, True)}}
93
201
 
202
+ {% endif -%}
94
203
 
95
- def _query_structure_cls(
96
- protocol: schema_lib.SchemaProtocol,
97
- ) -> Type[_QueryStructure]:
98
- if protocol == 'json':
99
- return _QueryStructureJson
100
- elif protocol == 'python':
101
- return _QueryStructurePython
102
- else:
103
- raise ValueError(f'Unknown protocol: {protocol!r}.')
204
+ {{ input_title }}:
205
+ {{ example.input_repr(protocol, compact=False) | indent(2, True) }}
206
+
207
+ {% if example.schema -%}
208
+ {{ schema_title }}:
209
+ {{ example.schema_repr(protocol) | indent(2, True) }}
210
+
211
+ {% endif -%}
212
+
213
+ {{ output_title }}:
214
+ {%- if example.has_output %}
215
+ {{ example.output_repr(protocol, compact=False) | indent(2, True) }}
216
+ {% endif -%}
217
+ """
218
+ )
219
+
220
+
221
+ class _LfQueryPythonV2(LfQuery):
222
+ """Query a structured value using Python as the protocol."""
223
+
224
+ preamble = """
225
+ Please respond to the last {{ input_title }} with {{ output_title }} only according to {{ schema_title }}.
226
+
227
+ {{ input_title }}:
228
+ 1 + 1 =
229
+
230
+ {{ schema_title }}:
231
+ Answer
232
+
233
+ ```python
234
+ class Answer:
235
+ final_answer: int
236
+ ```
237
+
238
+ {{ output_title }}:
239
+ ```python
240
+ output = Answer(
241
+ final_answer=2
242
+ )
243
+ ```
244
+ """
245
+ version = '2.0'
246
+ protocol = 'python'
247
+ input_title = 'REQUEST'
248
+ schema_title = 'OUTPUT PYTHON TYPE'
249
+ output_title = 'OUTPUT PYTHON OBJECT'
250
+ mapping_template = lf.Template(
251
+ """
252
+ {%- if example.context -%}
253
+ {{ context_title}}:
254
+ {{ example.context | indent(2, True)}}
255
+
256
+ {% endif -%}
257
+
258
+ {{ input_title }}:
259
+ {{ example.input_repr(protocol, compact=False) | indent(2, True) }}
260
+
261
+ {% if example.schema -%}
262
+ {{ schema_title }}:
263
+ {{ example.schema_repr(protocol) | indent(2, True) }}
264
+
265
+ {% endif -%}
266
+
267
+ {{ output_title }}:
268
+ {%- if example.has_output %}
269
+ {{ example.output_repr(protocol, compact=False, assign_to_var='output') | indent(2, True) }}
270
+ {% endif -%}
271
+ """
272
+ )
104
273
 
105
274
 
106
275
  def query(
@@ -116,7 +285,7 @@ def query(
116
285
  response_postprocess: Callable[[str], str] | None = None,
117
286
  autofix: int = 0,
118
287
  autofix_lm: lf.LanguageModel | None = None,
119
- protocol: schema_lib.SchemaProtocol = 'python',
288
+ protocol: str | None = None,
120
289
  returns_message: bool = False,
121
290
  skip_lm: bool = False,
122
291
  invocation_id: str | None = None,
@@ -259,8 +428,14 @@ def query(
259
428
  disable auto-fixing. Not supported with the `'json'` protocol.
260
429
  autofix_lm: The LM to use for auto-fixing. Defaults to the `autofix_lm`
261
430
  from `lf.context` or the main `lm`.
262
- protocol: Format for schema representation. Choices are `'json'` or
263
- `'python'`. Default is `'python'`.
431
+ protocol: Format for schema representation. Builtin choices are `'json'` or
432
+ `'python'`, users could extend with their own protocols by subclassing
433
+ `lf.structured.LfQuery'. Also protocol could be specified with a version
434
+ in the format of 'protocol:version', e.g., 'python:1.0', so users could
435
+ use a specific version of the prompt based on the protocol. Please see the
436
+ documentation of `LfQuery` for more details. If None, the protocol from
437
+ context manager `lf.query_protocol` will be used, or 'python' if not
438
+ specified.
264
439
  returns_message: If `True`, returns an `lf.Message` object instead of
265
440
  the final parsed result.
266
441
  skip_lm: If `True`, skips the LLM call and returns the rendered
@@ -280,6 +455,9 @@ def query(
280
455
  """
281
456
  # Internal usage logging.
282
457
 
458
+ if protocol is None:
459
+ protocol = lf.context_value('__query_protocol__', 'python')
460
+
283
461
  invocation_id = invocation_id or f'query@{uuid.uuid4().hex[-7:]}'
284
462
  # Multiple quries will be issued when `lm` is a list or `num_samples` is
285
463
  # greater than 1.
@@ -382,7 +560,7 @@ def query(
382
560
  output_message = lf.AIMessage(processed_text, source=output_message)
383
561
  else:
384
562
  # Query with structured output.
385
- output_message = _query_structure_cls(protocol)(
563
+ output_message = LfQuery.from_protocol(protocol)(
386
564
  input=(
387
565
  query_input.render(lm=lm)
388
566
  if isinstance(query_input, lf.Template)
@@ -436,6 +614,15 @@ def query(
436
614
  return output_message if returns_message else _result(output_message)
437
615
 
438
616
 
617
+ @contextlib.contextmanager
618
+ def query_protocol(protocol: str) -> Iterator[None]:
619
+ """Context manager for setting the query protocol for the scope."""
620
+ with lf.context(__query_protocol__=protocol):
621
+ try:
622
+ yield
623
+ finally:
624
+ pass
625
+
439
626
  #
440
627
  # Helper function for map-reduce style querying.
441
628
  #
@@ -90,7 +90,7 @@ class QueryTest(unittest.TestCase):
90
90
  score=1.0,
91
91
  logprobs=None,
92
92
  is_cached=False,
93
- usage=lf.LMSamplingUsage(323, 1, 324),
93
+ usage=lf.LMSamplingUsage(364, 1, 365),
94
94
  tags=['lm-response', 'lm-output', 'transformed'],
95
95
  ),
96
96
  )
@@ -143,26 +143,26 @@ class QueryTest(unittest.TestCase):
143
143
  y=2,
144
144
  lm=lm.clone(),
145
145
  expected_snippet=(
146
- 'Please respond to the last INPUT_OBJECT with OUTPUT_OBJECT '
147
- 'according to OUTPUT_TYPE.\n\n'
148
- 'INPUT_OBJECT:\n 1 + 1 =\n\n'
149
- 'OUTPUT_TYPE:\n'
146
+ 'Please respond to the last REQUEST with OUTPUT PYTHON OBJECT '
147
+ 'only according to OUTPUT PYTHON TYPE.\n\n'
148
+ 'REQUEST:\n 1 + 1 =\n\n'
149
+ 'OUTPUT PYTHON TYPE:\n'
150
150
  ' Answer\n\n'
151
151
  ' ```python\n'
152
152
  ' class Answer:\n'
153
153
  ' final_answer: int\n'
154
154
  ' ```\n\n'
155
- 'OUTPUT_OBJECT:\n'
155
+ 'OUTPUT PYTHON OBJECT:\n'
156
156
  ' ```python\n'
157
- ' Answer(\n'
157
+ ' output = Answer(\n'
158
158
  ' final_answer=2\n'
159
159
  ' )\n'
160
160
  ' ```\n\n'
161
- 'INPUT_OBJECT:\n'
161
+ 'REQUEST:\n'
162
162
  ' What is 1 + 2?\n\n'
163
- 'OUTPUT_TYPE:\n'
163
+ 'OUTPUT PYTHON TYPE:\n'
164
164
  ' int\n\n'
165
- 'OUTPUT_OBJECT:'
165
+ 'OUTPUT PYTHON OBJECT:'
166
166
  ),
167
167
  )
168
168
 
@@ -176,26 +176,26 @@ class QueryTest(unittest.TestCase):
176
176
  lm=lm.clone(),
177
177
  template_str='!!{{ DEFAULT }}!!',
178
178
  expected_snippet=(
179
- '!!Please respond to the last INPUT_OBJECT with OUTPUT_OBJECT '
180
- 'according to OUTPUT_TYPE.\n\n'
181
- 'INPUT_OBJECT:\n 1 + 1 =\n\n'
182
- 'OUTPUT_TYPE:\n'
179
+ '!!Please respond to the last REQUEST with OUTPUT PYTHON OBJECT '
180
+ 'only according to OUTPUT PYTHON TYPE.\n\n'
181
+ 'REQUEST:\n 1 + 1 =\n\n'
182
+ 'OUTPUT PYTHON TYPE:\n'
183
183
  ' Answer\n\n'
184
184
  ' ```python\n'
185
185
  ' class Answer:\n'
186
186
  ' final_answer: int\n'
187
187
  ' ```\n\n'
188
- 'OUTPUT_OBJECT:\n'
188
+ 'OUTPUT PYTHON OBJECT:\n'
189
189
  ' ```python\n'
190
- ' Answer(\n'
190
+ ' output = Answer(\n'
191
191
  ' final_answer=2\n'
192
192
  ' )\n'
193
193
  ' ```\n\n'
194
- 'INPUT_OBJECT:\n'
194
+ 'REQUEST:\n'
195
195
  ' What is 1 + 2?\n\n'
196
- 'OUTPUT_TYPE:\n'
196
+ 'OUTPUT PYTHON TYPE:\n'
197
197
  ' int\n\n'
198
- 'OUTPUT_OBJECT:!!'
198
+ 'OUTPUT PYTHON OBJECT:!!'
199
199
  ),
200
200
  )
201
201
 
@@ -220,7 +220,7 @@ class QueryTest(unittest.TestCase):
220
220
  y=2,
221
221
  lm=lm.clone(),
222
222
  expected_snippet=(
223
- '\n\nINPUT_OBJECT:\n ```python\n [\n 1\n ]\n ```\n\n'
223
+ '\n\nREQUEST:\n ```python\n [\n 1\n ]\n ```\n\n'
224
224
  ),
225
225
  )
226
226
 
@@ -236,7 +236,7 @@ class QueryTest(unittest.TestCase):
236
236
  modalities.Image.from_bytes(b'mock_image'),
237
237
  int,
238
238
  lm=lm,
239
- expected_snippet='\n\nINPUT_OBJECT:\n <<[[input]]>>\n\n',
239
+ expected_snippet='\n\nREQUEST:\n <<[[input]]>>\n\n',
240
240
  expected_modalities=1,
241
241
  )
242
242
 
@@ -290,7 +290,7 @@ class QueryTest(unittest.TestCase):
290
290
  list[str],
291
291
  lm=lm,
292
292
  expected_snippet=inspect.cleandoc("""
293
- INPUT_OBJECT:
293
+ REQUEST:
294
294
  ```python
295
295
  [
296
296
  <<[[input[0]]]>>,
@@ -318,31 +318,36 @@ class QueryTest(unittest.TestCase):
318
318
  ],
319
319
  lm=lm,
320
320
  expected_snippet=inspect.cleandoc("""
321
- INPUT_OBJECT:
321
+ REQUEST:
322
322
  ```python
323
323
  [
324
324
  <<[[examples[0].input[0]]]>>
325
325
  ]
326
326
  ```
327
327
 
328
- OUTPUT_TYPE:
328
+ OUTPUT PYTHON TYPE:
329
329
  list[str]
330
330
 
331
- OUTPUT_OBJECT:
331
+ OUTPUT PYTHON OBJECT:
332
332
  ```python
333
- [
333
+ output = [
334
334
  'dog'
335
335
  ]
336
336
  ```
337
337
 
338
338
 
339
- INPUT_OBJECT:
339
+ REQUEST:
340
340
  ```python
341
341
  [
342
342
  <<[[input[0]]]>>,
343
343
  <<[[input[1]]]>>
344
344
  ]
345
345
  ```
346
+
347
+ OUTPUT PYTHON TYPE:
348
+ list[str]
349
+
350
+ OUTPUT PYTHON OBJECT:
346
351
  """),
347
352
  expected_modalities=3,
348
353
  )
@@ -410,20 +415,69 @@ class QueryTest(unittest.TestCase):
410
415
  self.assertEqual([r.text for r in results], ['1', 'abc'])
411
416
  self.assertEqual([r.result for r in results], [1, 0])
412
417
 
413
- def test_bad_protocol(self):
414
- with self.assertRaisesRegex(ValueError, 'Unknown protocol'):
415
- querying.query('what is 1 + 1', int, protocol='text')
418
+ def test_from_protocol(self):
419
+ self.assertIs(
420
+ querying.LfQuery.from_protocol('python'), querying._LfQueryPythonV2
421
+ )
422
+ self.assertIs(
423
+ querying.LfQuery.from_protocol('python:1.0'),
424
+ querying._LfQueryPythonV1
425
+ )
426
+
427
+ class MyLfQuery(querying.LfQuery):
428
+ protocol = 'yaml'
429
+ version = '1.0'
430
+
431
+ self.assertIs(
432
+ querying.LfQuery.from_protocol('yaml:1.0'),
433
+ MyLfQuery
434
+ )
435
+ self.assertIs(
436
+ querying.LfQuery.from_protocol('yaml'),
437
+ MyLfQuery
438
+ )
439
+
440
+ with self.assertRaisesRegex(
441
+ ValueError, 'Version .* is already registered'
442
+ ):
443
+ class MyLfQuery2(querying.LfQuery): # pylint: disable=unused-variable
444
+ protocol = 'yaml'
445
+ version = '1.0'
446
+
447
+ with self.assertRaisesRegex(
448
+ ValueError, 'Version \'2.0\' is not supported for protocol \'yaml\''
449
+ ):
450
+ querying.LfQuery.from_protocol('yaml:2.0')
451
+
452
+ class MyLfQuery3(querying.LfQuery): # pylint: disable=unused-variable
453
+ protocol = 'yaml'
454
+ version = '3.0'
455
+
456
+ with self.assertRaisesRegex(
457
+ ValueError, 'Multiple versions found for protocol \'yaml\''
458
+ ):
459
+ querying.LfQuery.from_protocol('yaml')
460
+
461
+ with self.assertRaisesRegex(
462
+ ValueError, 'Protocol \'text\' is not supported'
463
+ ):
464
+ querying.LfQuery.from_protocol('text')
465
+
466
+ with self.assertRaisesRegex(
467
+ ValueError, 'Protocol \'text\' is not supported'
468
+ ):
469
+ querying.LfQuery.from_protocol('text:1.0')
416
470
 
417
471
  def test_query_prompt(self):
418
472
  self.assertEqual(
419
473
  querying.query_prompt('what is this?', int),
420
474
  inspect.cleandoc("""
421
- Please respond to the last INPUT_OBJECT with OUTPUT_OBJECT according to OUTPUT_TYPE.
475
+ Please respond to the last REQUEST with OUTPUT PYTHON OBJECT only according to OUTPUT PYTHON TYPE.
422
476
 
423
- INPUT_OBJECT:
477
+ REQUEST:
424
478
  1 + 1 =
425
479
 
426
- OUTPUT_TYPE:
480
+ OUTPUT PYTHON TYPE:
427
481
  Answer
428
482
 
429
483
  ```python
@@ -431,20 +485,20 @@ class QueryTest(unittest.TestCase):
431
485
  final_answer: int
432
486
  ```
433
487
 
434
- OUTPUT_OBJECT:
488
+ OUTPUT PYTHON OBJECT:
435
489
  ```python
436
- Answer(
490
+ output = Answer(
437
491
  final_answer=2
438
492
  )
439
493
  ```
440
494
 
441
- INPUT_OBJECT:
495
+ REQUEST:
442
496
  what is this?
443
497
 
444
- OUTPUT_TYPE:
498
+ OUTPUT PYTHON TYPE:
445
499
  int
446
500
 
447
- OUTPUT_OBJECT:
501
+ OUTPUT PYTHON OBJECT:
448
502
  """),
449
503
  )
450
504
 
@@ -632,10 +686,10 @@ class QueryTest(unittest.TestCase):
632
686
  )
633
687
 
634
688
 
635
- class QueryStructurePythonTest(unittest.TestCase):
689
+ class LfQueryPythonV1Test(unittest.TestCase):
636
690
 
637
691
  def test_render_no_examples(self):
638
- l = querying._QueryStructurePython(
692
+ l = querying.LfQuery.from_protocol('python:1.0')(
639
693
  input=lf.AIMessage('Compute 12 / 6 + 2.'), schema=int
640
694
  )
641
695
  self.assertEqual(
@@ -672,7 +726,7 @@ class QueryStructurePythonTest(unittest.TestCase):
672
726
  )
673
727
 
674
728
  def test_render(self):
675
- l = querying._QueryStructurePython(
729
+ l = querying.LfQuery.from_protocol('python:1.0')(
676
730
  input=lf.AIMessage('Compute 12 / 6 + 2.'),
677
731
  schema=int,
678
732
  examples=[
@@ -782,7 +836,7 @@ class QueryStructurePythonTest(unittest.TestCase):
782
836
  ),
783
837
  override_attrs=True,
784
838
  ):
785
- l = querying._QueryStructurePython(
839
+ l = querying.LfQuery.from_protocol('python:1.0')(
786
840
  input=lm_input,
787
841
  schema=[Itinerary],
788
842
  examples=[
@@ -810,6 +864,115 @@ class QueryStructurePythonTest(unittest.TestCase):
810
864
  self.assertEqual(len(r.result[0].activities), 3)
811
865
  self.assertIsNone(r.result[0].hotel)
812
866
 
867
+
868
+ class LfQueryPythonV2Test(unittest.TestCase):
869
+
870
+ def test_render_no_examples(self):
871
+ l = querying.LfQuery.from_protocol('python:2.0')(
872
+ input=lf.AIMessage('Compute 12 / 6 + 2.'), schema=int
873
+ )
874
+ self.assertEqual(
875
+ l.render().text,
876
+ inspect.cleandoc("""
877
+ Please respond to the last REQUEST with OUTPUT PYTHON OBJECT only according to OUTPUT PYTHON TYPE.
878
+
879
+ REQUEST:
880
+ 1 + 1 =
881
+
882
+ OUTPUT PYTHON TYPE:
883
+ Answer
884
+
885
+ ```python
886
+ class Answer:
887
+ final_answer: int
888
+ ```
889
+
890
+ OUTPUT PYTHON OBJECT:
891
+ ```python
892
+ output = Answer(
893
+ final_answer=2
894
+ )
895
+ ```
896
+
897
+ REQUEST:
898
+ Compute 12 / 6 + 2.
899
+
900
+ OUTPUT PYTHON TYPE:
901
+ int
902
+
903
+ OUTPUT PYTHON OBJECT:
904
+ """),
905
+ )
906
+
907
+ def test_render_with_examples(self):
908
+ l = querying.LfQuery.from_protocol('python:2.0')(
909
+ input=lf.AIMessage('Compute 12 / 6 + 2.'),
910
+ schema=int,
911
+ examples=[
912
+ mapping.MappingExample(
913
+ input='What is the answer of 1 plus 1?', output=2
914
+ ),
915
+ mapping.MappingExample(
916
+ input='Compute the value of 3 + (2 * 6).', output=15
917
+ ),
918
+ ],
919
+ )
920
+ self.assertEqual(
921
+ l.render().text,
922
+ inspect.cleandoc("""
923
+ Please respond to the last REQUEST with OUTPUT PYTHON OBJECT only according to OUTPUT PYTHON TYPE.
924
+
925
+ REQUEST:
926
+ 1 + 1 =
927
+
928
+ OUTPUT PYTHON TYPE:
929
+ Answer
930
+
931
+ ```python
932
+ class Answer:
933
+ final_answer: int
934
+ ```
935
+
936
+ OUTPUT PYTHON OBJECT:
937
+ ```python
938
+ output = Answer(
939
+ final_answer=2
940
+ )
941
+ ```
942
+
943
+ REQUEST:
944
+ What is the answer of 1 plus 1?
945
+
946
+ OUTPUT PYTHON TYPE:
947
+ int
948
+
949
+ OUTPUT PYTHON OBJECT:
950
+ ```python
951
+ output = 2
952
+ ```
953
+
954
+ REQUEST:
955
+ Compute the value of 3 + (2 * 6).
956
+
957
+ OUTPUT PYTHON TYPE:
958
+ int
959
+
960
+ OUTPUT PYTHON OBJECT:
961
+ ```python
962
+ output = 15
963
+ ```
964
+
965
+
966
+ REQUEST:
967
+ Compute 12 / 6 + 2.
968
+
969
+ OUTPUT PYTHON TYPE:
970
+ int
971
+
972
+ OUTPUT PYTHON OBJECT:
973
+ """),
974
+ )
975
+
813
976
  def test_bad_response(self):
814
977
  with lf.context(
815
978
  lm=fake.StaticSequence(['a2']),
@@ -849,11 +1012,80 @@ class QueryStructurePythonTest(unittest.TestCase):
849
1012
  3
850
1013
  )
851
1014
 
1015
+ def test_render(self):
1016
+ l = querying.LfQuery.from_protocol('python:2.0')(
1017
+ input=lf.AIMessage('Compute 12 / 6 + 2.'),
1018
+ schema=int,
1019
+ examples=[
1020
+ mapping.MappingExample(
1021
+ input='What is the answer of 1 plus 1?', output=2
1022
+ ),
1023
+ mapping.MappingExample(
1024
+ input='Compute the value of 3 + (2 * 6).', output=15
1025
+ ),
1026
+ ],
1027
+ )
1028
+ self.assertEqual(
1029
+ l.render().text,
1030
+ inspect.cleandoc("""
1031
+ Please respond to the last REQUEST with OUTPUT PYTHON OBJECT only according to OUTPUT PYTHON TYPE.
1032
+
1033
+ REQUEST:
1034
+ 1 + 1 =
1035
+
1036
+ OUTPUT PYTHON TYPE:
1037
+ Answer
1038
+
1039
+ ```python
1040
+ class Answer:
1041
+ final_answer: int
1042
+ ```
1043
+
1044
+ OUTPUT PYTHON OBJECT:
1045
+ ```python
1046
+ output = Answer(
1047
+ final_answer=2
1048
+ )
1049
+ ```
1050
+
1051
+ REQUEST:
1052
+ What is the answer of 1 plus 1?
1053
+
1054
+ OUTPUT PYTHON TYPE:
1055
+ int
1056
+
1057
+ OUTPUT PYTHON OBJECT:
1058
+ ```python
1059
+ output = 2
1060
+ ```
1061
+
1062
+ REQUEST:
1063
+ Compute the value of 3 + (2 * 6).
1064
+
1065
+ OUTPUT PYTHON TYPE:
1066
+ int
1067
+
1068
+ OUTPUT PYTHON OBJECT:
1069
+ ```python
1070
+ output = 15
1071
+ ```
1072
+
1073
+
1074
+ REQUEST:
1075
+ Compute 12 / 6 + 2.
1076
+
1077
+ OUTPUT PYTHON TYPE:
1078
+ int
1079
+
1080
+ OUTPUT PYTHON OBJECT:
1081
+ """),
1082
+ )
852
1083
 
853
- class QueryStructureJsonTest(unittest.TestCase):
1084
+
1085
+ class LfQueryJsonV1Test(unittest.TestCase):
854
1086
 
855
1087
  def test_render_no_examples(self):
856
- l = querying._QueryStructureJson(
1088
+ l = querying.LfQuery.from_protocol('json:1.0')(
857
1089
  input=lf.AIMessage('Compute 12 / 6 + 2.'), schema=int
858
1090
  )
859
1091
  self.assertEqual(
@@ -885,7 +1117,7 @@ class QueryStructureJsonTest(unittest.TestCase):
885
1117
  )
886
1118
 
887
1119
  def test_render(self):
888
- l = querying._QueryStructureJson(
1120
+ l = querying.LfQuery.from_protocol('json:1.0')(
889
1121
  input=lf.AIMessage('Compute 12 / 6 + 2.'),
890
1122
  schema=int,
891
1123
  examples=[
@@ -1020,7 +1252,7 @@ class QueryStructureJsonTest(unittest.TestCase):
1020
1252
  ),
1021
1253
  override_attrs=True,
1022
1254
  ):
1023
- l = querying._QueryStructureJson(
1255
+ l = querying.LfQuery.from_protocol('json:1.0')(
1024
1256
  input=lm_input,
1025
1257
  schema=[Itinerary],
1026
1258
  examples=[
@@ -1063,10 +1295,17 @@ class QueryStructureJsonTest(unittest.TestCase):
1063
1295
  self.assertEqual(len(cache), 0)
1064
1296
 
1065
1297
  def test_query(self):
1066
- lm = fake.StaticSequence(['{"result": 1}'])
1298
+ lm = fake.StaticResponse('{"result": 1}')
1067
1299
  self.assertEqual(
1068
1300
  querying.query('what is 1 + 0', int, lm=lm, protocol='json'), 1
1069
1301
  )
1302
+ self.assertEqual(
1303
+ querying.query('what is 1 + 0', int, lm=lm, protocol='json:1.0'), 1
1304
+ )
1305
+ with querying.query_protocol('json'):
1306
+ self.assertEqual(
1307
+ querying.query('what is 1 + 0', int, lm=lm), 1
1308
+ )
1070
1309
 
1071
1310
 
1072
1311
  class QueryInvocationTest(unittest.TestCase):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langfun
3
- Version: 0.1.2.dev202504290805
3
+ Version: 0.1.2.dev202504300804
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -1,4 +1,4 @@
1
- langfun/__init__.py,sha256=LuB1difPJsI8V9H4kmUJM2DAEmMEV_WtaBLGYp3qEFM,2527
1
+ langfun/__init__.py,sha256=krEJ1lyDkNARsacY6nBQpD3bQrFi4fifD-FwpwPbFPM,2635
2
2
  langfun/core/__init__.py,sha256=pW4prpiyWNkRbtWBGYF1thn7_0F_TgDVfAIZPvGn6HA,4758
3
3
  langfun/core/component.py,sha256=g1kQM0bryYYYWVDrSMnHfc74wIBbpfe5_B3s-UIP5GE,3028
4
4
  langfun/core/component_test.py,sha256=0CxTgjAud3aj8wBauFhG2FHDqrxCTl4OI4gzQTad-40,9254
@@ -27,7 +27,7 @@ langfun/core/template.py,sha256=jNhYSrbLIn9kZOa03w5QZbyjgfnzJzE_ZrrMvvWY4t4,2492
27
27
  langfun/core/template_test.py,sha256=AQv_m9qE93WxhEhSlm1xaBgB4hu0UVtA53dljngkUW0,17090
28
28
  langfun/core/agentic/__init__.py,sha256=qR3jlfUO4rhIoYdRDLz-d22YZf3FvU4FW88vsjiGDQQ,1224
29
29
  langfun/core/agentic/action.py,sha256=9P7xDiZVUV9MvJDfuAfLx-xa7qvS5F0EOGWDQnjAZBw,38931
30
- langfun/core/agentic/action_eval.py,sha256=8cdH-ubWUL1sscqagrQltPg19vTYNKrI3CKLvluGP24,4615
30
+ langfun/core/agentic/action_eval.py,sha256=NwjQ5hR-7YT6mo2q0mbDOgmNCKzTMpEzslYtR3fjXJY,4862
31
31
  langfun/core/agentic/action_eval_test.py,sha256=tRUkWmOE9p0rpNOq19xAY2oDEnYsEEykjg6sUpAwJk0,2832
32
32
  langfun/core/agentic/action_test.py,sha256=9EZKgLaBrqTErSRoxtrSlzmCz_cbnwWu0ZqpwKLst-s,10224
33
33
  langfun/core/coding/__init__.py,sha256=5utju_fwEsImaiftx4oXKl9FAM8p281k8-Esdh_-m1w,835
@@ -52,7 +52,7 @@ langfun/core/data/conversion/openai.py,sha256=sSpkDSxMJWJ3I1dNICBCzvLsJv4iiLg8FP
52
52
  langfun/core/data/conversion/openai_test.py,sha256=38WV_3ofFZiUF10bTKnZp4VyuDP5-81aR3h3Q0HlBm0,5283
53
53
  langfun/core/eval/__init__.py,sha256=OEXr1ZRuvLuhJJfuQ1ZWQ-SvYzjyrtiAAEogYaB7E6o,1933
54
54
  langfun/core/eval/base.py,sha256=qIJnrO1jX5pzY8yoQTtcTn5lGdD9adz5U6C_jla1BV4,75806
55
- langfun/core/eval/base_test.py,sha256=rFWCIDzNGadXMxxM4Ofavz52SsjtlH4wqS1fnaA4ksI,27191
55
+ langfun/core/eval/base_test.py,sha256=q4wEd2KDUxzUkeELwof0HXBKe9TMQYUq84ddA043VPg,27191
56
56
  langfun/core/eval/matching.py,sha256=AVKkGoc-BaHEzgSBamaAk3194TgqckDe_dinpS6LrXI,9323
57
57
  langfun/core/eval/matching_test.py,sha256=2xtwsTi-UzLTt0QnXl3u_eAG3fFjCG2tsae7YkcQTB0,5312
58
58
  langfun/core/eval/patching.py,sha256=R0s2eAd1m97exQt06dmUL0V_MBG0W2Hxg7fhNB7cXW0,3866
@@ -63,8 +63,8 @@ langfun/core/eval/v2/__init__.py,sha256=9lNKJwbvl0lcFblAXYT_OHI8fOubJsTOdSkxEqsP
63
63
  langfun/core/eval/v2/checkpointing.py,sha256=t47rBfzGZYgIqWW1N1Ak9yQnNtHd-IRbEO0cZjG2VRo,11755
64
64
  langfun/core/eval/v2/checkpointing_test.py,sha256=NggOSJ_6XSa4cNP6nGIu9wLsK59dUwe8SPWDiXtGGDE,9197
65
65
  langfun/core/eval/v2/eval_test_helper.py,sha256=sKFi_wPYCNmr96WyTduuXY0KnxjFxcJyEhXey-_nGX8,3962
66
- langfun/core/eval/v2/evaluation.py,sha256=07ebNx3bYlN25sg4Nam_QJRuikKVt9Pc0oXmSG6IS-k,24937
67
- langfun/core/eval/v2/evaluation_test.py,sha256=TKbeyeenoaUDH23E3TXXJ4otuq3VZBuWkWdV7c5vMk4,6804
66
+ langfun/core/eval/v2/evaluation.py,sha256=4Kcpve_dlti3FWxd7KtZaapsva_C7sOGjyJ69xsXLY4,26992
67
+ langfun/core/eval/v2/evaluation_test.py,sha256=QNp_HEvRTupvNuLEeYTvylykh1Ut2jpMqHQ-gCUZQ10,6919
68
68
  langfun/core/eval/v2/example.py,sha256=Jegt-viQSNYzPVkOZE_M19GON2TYGTct4Cp9HnJ7DGo,10861
69
69
  langfun/core/eval/v2/example_test.py,sha256=1DNm6EuyZOq827DKvf3oTRVFkMNM_qTnLUpvOjpgz5I,3419
70
70
  langfun/core/eval/v2/experiment.py,sha256=xlQvx-AgPCgHNaBoW1HxddA9wby-odADF0VJ3rQjw_M,32978
@@ -126,19 +126,19 @@ langfun/core/modalities/pdf.py,sha256=mfaeCbUA4JslFVTARiJh8hW7imvL4tLVw9gUhO5bAZ
126
126
  langfun/core/modalities/pdf_test.py,sha256=ulZ0FbnlsU0wkrdckJ4ONZPTYRyMPO9Aob1UO6FXygk,1950
127
127
  langfun/core/modalities/video.py,sha256=vI9apcHIHGyp90i34Srg7S3G6IBDtDCk8qiXhwRQmkw,967
128
128
  langfun/core/modalities/video_test.py,sha256=7OXZoohKMYjt7vrJUdPb553HLyl1oBOKRgzBePFv68Q,2042
129
- langfun/core/structured/__init__.py,sha256=3Wb4ks14D5E5z1nQ5trXSXiLqFN5E_3HvcEJQAfFRl0,3220
129
+ langfun/core/structured/__init__.py,sha256=xWO1RO-gy12REgiPn4oWWALZxJhHtBOOdDsawKN_SfY,3334
130
130
  langfun/core/structured/completion.py,sha256=yW95Yd4wbt964I5wIyPUtIVeeqeZbA6HidLgN0ZpWm0,8110
131
131
  langfun/core/structured/completion_test.py,sha256=VtYfI3ciVSSWbi8x3l1WwpWK-Ofn2DMHYEEqm2uTzhw,19314
132
132
  langfun/core/structured/description.py,sha256=6BztYOiucPkF4CrTQtPLPJo1gN2dwnKmaJW83GBf4H0,5213
133
133
  langfun/core/structured/description_test.py,sha256=UxaXnKKP7TnyPDPUyf3U-zPE0TvLlIP6DGr8thjcePw,7365
134
134
  langfun/core/structured/function_generation.py,sha256=g7AOR_e8HxFU6n6Df750aGkgMgV1KExLZMAz0yd5Agg,8555
135
135
  langfun/core/structured/function_generation_test.py,sha256=LaXYDXf9GlqUrR6v_gtmK_H4kxzonmU7SYbn7XXMgjU,12128
136
- langfun/core/structured/mapping.py,sha256=of-EeBq0RgmkiUaSk2rVEDVCzgn_wXU8tRke7NCcC6E,13649
136
+ langfun/core/structured/mapping.py,sha256=gxdcYQP9yqbDRtiJQ1RRAOrKHiCr0h6xBYLCRKE4I3c,13723
137
137
  langfun/core/structured/mapping_test.py,sha256=OntYvfDitAf0tAnzQty3YS90vyEn6FY1Mi93r_ViEk8,9594
138
138
  langfun/core/structured/parsing.py,sha256=MGvI7ypXlwfzr5XB8_TFU9Ei0_5reYqkWkv64eAy0EA,12015
139
- langfun/core/structured/parsing_test.py,sha256=kNPrhpdPY3iWhUld0TFYU-Zgn44wC0d6YuQ9XdVbQ8o,22346
140
- langfun/core/structured/querying.py,sha256=GGNtHtJcKh8rzLBNx_Df1ATvsPZzyfZuGkzSQVabdpo,24885
141
- langfun/core/structured/querying_test.py,sha256=vUuVUClYBFGEaO9KuD60huPE1dmP6RCRLeRnBv67NmQ,34263
139
+ langfun/core/structured/parsing_test.py,sha256=V8Cj1tJK4Lxv_b0YQj6-2hzXZgnYNBa2JR7rOLRBKoQ,22346
140
+ langfun/core/structured/querying.py,sha256=NA5LL97ny9aIml3wz4GPzFsvAH2XafZIGoZbIhuV8nA,30456
141
+ langfun/core/structured/querying_test.py,sha256=_npZ3ztaZc6VerP7nU_QTJscWGgBqiwTE02z_S3Ahd4,40197
142
142
  langfun/core/structured/schema.py,sha256=pGiAjez-ON2nKLUSeAls27gJsMto5aJnCXLVwH3pUKM,28296
143
143
  langfun/core/structured/schema_generation.py,sha256=3AcuKvv3VOtKY5zMVqODrxfOuDxzoZtGeBxHlOWDOWw,5308
144
144
  langfun/core/structured/schema_generation_test.py,sha256=RM9s71kMNg2jTePwInkiW9fK1ACN37eyPeF8OII-0zw,2950
@@ -156,8 +156,8 @@ langfun/core/templates/demonstration.py,sha256=vCrgYubdZM5Umqcgp8NUVGXgr4P_c-fik
156
156
  langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3ABKzup8jReCljHeK4,2162
157
157
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
158
158
  langfun/core/templates/selfplay_test.py,sha256=Ot__1P1M8oJfoTp-M9-PQ6HUXqZKyMwvZ5f7yQ3yfyM,2326
159
- langfun-0.1.2.dev202504290805.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
160
- langfun-0.1.2.dev202504290805.dist-info/METADATA,sha256=KWW7NslPxpSS2u0eVRcN022ylI5TeWFdswXMnve9144,8178
161
- langfun-0.1.2.dev202504290805.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
162
- langfun-0.1.2.dev202504290805.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
163
- langfun-0.1.2.dev202504290805.dist-info/RECORD,,
159
+ langfun-0.1.2.dev202504300804.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
160
+ langfun-0.1.2.dev202504300804.dist-info/METADATA,sha256=rlaBu8x--oQz7DAbnG3snNBBk7ltVc1RFvtOcE9cW3Q,8178
161
+ langfun-0.1.2.dev202504300804.dist-info/WHEEL,sha256=ooBFpIzZCPdw3uqIQsOo4qqbA4ZRPxHnOH7peeONza0,91
162
+ langfun-0.1.2.dev202504300804.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
163
+ langfun-0.1.2.dev202504300804.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.0.0)
2
+ Generator: setuptools (80.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5