langfun 0.1.2.dev202410100804__py3-none-any.whl → 0.1.2.dev202410120803__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 (42) hide show
  1. langfun/core/__init__.py +1 -0
  2. langfun/core/eval/base_test.py +1 -0
  3. langfun/core/langfunc_test.py +2 -2
  4. langfun/core/language_model.py +140 -24
  5. langfun/core/language_model_test.py +166 -36
  6. langfun/core/llms/__init__.py +8 -1
  7. langfun/core/llms/anthropic.py +72 -7
  8. langfun/core/llms/cache/in_memory_test.py +3 -2
  9. langfun/core/llms/fake_test.py +7 -0
  10. langfun/core/llms/groq.py +154 -6
  11. langfun/core/llms/openai.py +300 -42
  12. langfun/core/llms/openai_test.py +35 -8
  13. langfun/core/llms/vertexai.py +121 -16
  14. langfun/core/logging.py +150 -43
  15. langfun/core/logging_test.py +33 -0
  16. langfun/core/message.py +249 -70
  17. langfun/core/message_test.py +70 -45
  18. langfun/core/modalities/audio.py +1 -1
  19. langfun/core/modalities/audio_test.py +1 -1
  20. langfun/core/modalities/image.py +1 -1
  21. langfun/core/modalities/image_test.py +9 -3
  22. langfun/core/modalities/mime.py +39 -3
  23. langfun/core/modalities/mime_test.py +39 -0
  24. langfun/core/modalities/ms_office.py +2 -5
  25. langfun/core/modalities/ms_office_test.py +1 -1
  26. langfun/core/modalities/pdf_test.py +1 -1
  27. langfun/core/modalities/video.py +1 -1
  28. langfun/core/modalities/video_test.py +2 -2
  29. langfun/core/structured/completion_test.py +1 -0
  30. langfun/core/structured/mapping.py +38 -0
  31. langfun/core/structured/mapping_test.py +55 -0
  32. langfun/core/structured/parsing_test.py +2 -1
  33. langfun/core/structured/prompting_test.py +1 -0
  34. langfun/core/structured/schema.py +34 -0
  35. langfun/core/template.py +110 -1
  36. langfun/core/template_test.py +37 -0
  37. langfun/core/templates/selfplay_test.py +4 -2
  38. {langfun-0.1.2.dev202410100804.dist-info → langfun-0.1.2.dev202410120803.dist-info}/METADATA +1 -1
  39. {langfun-0.1.2.dev202410100804.dist-info → langfun-0.1.2.dev202410120803.dist-info}/RECORD +42 -42
  40. {langfun-0.1.2.dev202410100804.dist-info → langfun-0.1.2.dev202410120803.dist-info}/LICENSE +0 -0
  41. {langfun-0.1.2.dev202410100804.dist-info → langfun-0.1.2.dev202410120803.dist-info}/WHEEL +0 -0
  42. {langfun-0.1.2.dev202410100804.dist-info → langfun-0.1.2.dev202410120803.dist-info}/top_level.txt +0 -0
@@ -178,14 +178,50 @@ class Mime(lf.Modality):
178
178
  assert content is not None
179
179
  return content
180
180
 
181
- def _repr_html_(self) -> str:
181
+ def _html_tree_view_content(
182
+ self,
183
+ **kwargs) -> str:
184
+ return self._raw_html()
185
+
186
+ def _html_tree_view_render(
187
+ self,
188
+ view: pg.views.HtmlTreeView,
189
+ raw_mime_content: bool = pg.View.PresetArgValue(False), # pytype: disable=annotation-type-mismatch
190
+ display_modality_when_hover: bool = pg.View.PresetArgValue(False), # pytype: disable=annotation-type-mismatch
191
+ **kwargs
192
+ ):
193
+ if raw_mime_content:
194
+ return pg.Html(self._raw_html())
195
+ else:
196
+ if display_modality_when_hover:
197
+ kwargs.update(
198
+ display_modality_when_hover=True,
199
+ enable_summary_tooltip=True,
200
+ )
201
+ return super()._html_tree_view_render(view=view, **kwargs)
202
+
203
+ def _html_tree_view_tooltip(
204
+ self,
205
+ *,
206
+ view: pg.views.HtmlTreeView,
207
+ content: pg.Html | str | None = None,
208
+ display_modality_when_hover: bool = pg.View.PresetArgValue(False), # pytype: disable=annotation-type-mismatch
209
+ **kwargs
210
+ ):
211
+ if content is None and display_modality_when_hover:
212
+ content = self._raw_html()
213
+ return super()._html_tree_view_tooltip(
214
+ view=view, content=content, **kwargs
215
+ )
216
+
217
+ def _raw_html(self) -> str:
182
218
  if self.uri and self.uri.lower().startswith(('http:', 'https:', 'ftp:')):
183
219
  uri = self.uri
184
220
  else:
185
221
  uri = self.content_uri
186
- return self._html(uri)
222
+ return self._mime_control_for(uri)
187
223
 
188
- def _html(self, uri) -> str:
224
+ def _mime_control_for(self, uri) -> str:
189
225
  return f'<embed type="{self.mime_type}" src="{uri}"/>'
190
226
 
191
227
 
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  """MIME tests."""
15
+ import inspect
15
16
  import unittest
16
17
  from unittest import mock
17
18
 
@@ -77,6 +78,44 @@ class CustomMimeTest(unittest.TestCase):
77
78
  self.assertEqual(content.to_bytes(), 'bar')
78
79
  self.assertEqual(content.mime_type, 'text/plain')
79
80
 
81
+ def assert_html_content(self, html, expected):
82
+ expected = inspect.cleandoc(expected).strip()
83
+ actual = html.content.strip()
84
+ if actual != expected:
85
+ print(actual)
86
+ self.assertEqual(actual, expected)
87
+
88
+ def test_html(self):
89
+ self.assert_html_content(
90
+ mime.Custom('text/plain', b'foo').to_html(
91
+ enable_summary_tooltip=False,
92
+ enable_key_tooltip=False,
93
+ ),
94
+ """
95
+ <details open class="pyglove custom"><summary><div class="summary_title">Custom(...)</div></summary><embed type="text/plain" src="data:text/plain;base64,Zm9v"/></details>
96
+ """
97
+ )
98
+ self.assert_html_content(
99
+ mime.Custom('text/plain', b'foo').to_html(
100
+ enable_summary_tooltip=False,
101
+ enable_key_tooltip=False,
102
+ raw_mime_content=True,
103
+ ),
104
+ """
105
+ <embed type="text/plain" src="data:text/plain;base64,Zm9v"/>
106
+ """
107
+ )
108
+ self.assert_html_content(
109
+ mime.Custom('text/plain', b'foo').to_html(
110
+ enable_summary_tooltip=False,
111
+ enable_key_tooltip=False,
112
+ display_modality_when_hover=True,
113
+ ),
114
+ """
115
+ <details open class="pyglove custom"><summary><div class="summary_title">Custom(...)</div><span class="tooltip custom"><embed type="text/plain" src="data:text/plain;base64,Zm9v"/></span></summary><embed type="text/plain" src="data:text/plain;base64,Zm9v"/></details>
116
+ """
117
+ )
118
+
80
119
 
81
120
  if __name__ == '__main__':
82
121
  unittest.main()
@@ -29,7 +29,7 @@ class Xlsx(mime.Mime):
29
29
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
30
30
  )
31
31
 
32
- def to_html(self) -> str:
32
+ def _raw_html(self) -> str:
33
33
  try:
34
34
  import pandas as pd # pylint: disable=g-import-not-at-top
35
35
  import openpyxl # pylint: disable=g-import-not-at-top, unused-import
@@ -40,9 +40,6 @@ class Xlsx(mime.Mime):
40
40
  'Please install "langfun[mime-xlsx]" to enable XLSX support.'
41
41
  ) from e
42
42
 
43
- def _repr_html_(self) -> str:
44
- return self.to_html()
45
-
46
43
  def _is_compatible(self, mime_types: Iterable[str]) -> bool:
47
44
  return bool(set(mime_types).intersection([
48
45
  'text/html',
@@ -52,7 +49,7 @@ class Xlsx(mime.Mime):
52
49
  def _make_compatible(self, mime_types: Iterable[str]) -> mime.Mime:
53
50
  """Returns the MimeType of the converted file."""
54
51
  del mime_types
55
- return mime.Mime(uri=self.uri, content=self.to_html())
52
+ return mime.Mime(uri=self.uri, content=self._raw_html())
56
53
 
57
54
 
58
55
  class Docx(mime.Mime):
@@ -347,7 +347,7 @@ class XlsxTest(unittest.TestCase):
347
347
  ),
348
348
  )
349
349
  self.assertEqual(content.to_bytes(), xlsx_bytes)
350
- self.assertEqual(content.to_html(), expected_xlsx_html)
350
+ self.assertEqual(content._raw_html(), expected_xlsx_html)
351
351
 
352
352
 
353
353
  class PptxTest(unittest.TestCase):
@@ -49,7 +49,7 @@ class PdfTest(unittest.TestCase):
49
49
  pdf = pdf_lib.PDF.from_bytes(pdf_bytes)
50
50
  self.assertIn(
51
51
  '<embed type="application/pdf" src="data:application/pdf;base64,',
52
- pdf._repr_html_()
52
+ pdf._raw_html()
53
53
  )
54
54
 
55
55
 
@@ -26,5 +26,5 @@ class Video(mime.Mime):
26
26
  def video_format(self) -> str:
27
27
  return self.mime_type.removeprefix(self.MIME_PREFIX + '/')
28
28
 
29
- def _html(self, uri: str) -> str:
29
+ def _mime_control_for(self, uri: str) -> str:
30
30
  return f'<video controls> <source src="{uri}"> </video>'
@@ -38,7 +38,7 @@ class VideoContentTest(unittest.TestCase):
38
38
  video = video_lib.Video.from_bytes(mp4_bytes)
39
39
  self.assertEqual(video.mime_type, 'video/mp4')
40
40
  self.assertEqual(video.video_format, 'mp4')
41
- self.assertIn('data:video/mp4;base64,', video._repr_html_())
41
+ self.assertIn('data:video/mp4;base64,', video._raw_html())
42
42
  self.assertEqual(video.to_bytes(), mp4_bytes)
43
43
 
44
44
  def test_bad_video(self):
@@ -56,7 +56,7 @@ class VideoFileTest(unittest.TestCase):
56
56
  self.assertEqual(video.video_format, 'mp4')
57
57
  self.assertEqual(video.mime_type, 'video/mp4')
58
58
  self.assertEqual(
59
- video._repr_html_(),
59
+ video._raw_html(),
60
60
  '<video controls> <source src="http://mock/web/a.mp4"> </video>',
61
61
  )
62
62
  self.assertEqual(video.to_bytes(), mp4_bytes)
@@ -581,6 +581,7 @@ class CompleteStructureTest(unittest.TestCase):
581
581
  text='Activity(description="foo")',
582
582
  result=Activity(description='foo'),
583
583
  score=1.0,
584
+ is_cached=False,
584
585
  logprobs=None,
585
586
  usage=lf.LMSamplingUsage(553, 27, 580),
586
587
  tags=['lm-response', 'lm-output', 'transformed']
@@ -183,6 +183,44 @@ class MappingExample(lf.NaturalLanguageFormattable, lf.Component):
183
183
  result.write(lf.colored(str(self.metadata), color='cyan'))
184
184
  return result.getvalue().strip()
185
185
 
186
+ def _html_tree_view_content(
187
+ self,
188
+ *,
189
+ parent: Any,
190
+ view: pg.views.HtmlTreeView,
191
+ root_path: pg.KeyPath,
192
+ **kwargs,
193
+ ):
194
+ def render_value(value, **kwargs):
195
+ if isinstance(value, lf.Template):
196
+ # Make a shallow copy to make sure modalities are rooted by
197
+ # the input.
198
+ value = value.clone().render()
199
+ return view.render(value, **kwargs)
200
+
201
+ exclude_keys = []
202
+ if not self.context:
203
+ exclude_keys.append('context')
204
+ if not self.schema:
205
+ exclude_keys.append('schema')
206
+ if not self.metadata:
207
+ exclude_keys.append('metadata')
208
+
209
+ kwargs.pop('special_keys', None)
210
+ kwargs.pop('exclude_keys', None)
211
+ return view.complex_value(
212
+ self.sym_init_args,
213
+ parent=self,
214
+ root_path=root_path,
215
+ render_value_fn=render_value,
216
+ special_keys=['input', 'output', 'context', 'schema', 'metadata'],
217
+ exclude_keys=exclude_keys,
218
+ **kwargs
219
+ )
220
+
221
+ def _html_tree_view_uncollapse_level(self) -> int:
222
+ return 2
223
+
186
224
 
187
225
  class Mapping(lf.LangFunc):
188
226
  """Base class for mapping.
@@ -14,6 +14,7 @@
14
14
  """Tests for structured mapping example."""
15
15
 
16
16
  import inspect
17
+ from typing import Any
17
18
  import unittest
18
19
 
19
20
  import langfun.core as lf
@@ -164,6 +165,60 @@ class MappingExampleTest(unittest.TestCase):
164
165
  pg.eq(pg.from_json_str(example.to_json_str()), example)
165
166
  )
166
167
 
168
+ def assert_html_content(self, html, expected):
169
+ expected = inspect.cleandoc(expected).strip()
170
+ actual = html.content.strip()
171
+ if actual != expected:
172
+ print(actual)
173
+ self.assertEqual(actual, expected)
174
+
175
+ def test_html(self):
176
+
177
+ class Answer(pg.Object):
178
+ answer: int
179
+
180
+ class Addition(lf.Template):
181
+ """Template Addition.
182
+
183
+ {{x}} + {{y}} = ?
184
+ """
185
+ x: Any
186
+ y: Any
187
+
188
+ example = mapping.MappingExample(
189
+ input=Addition(x=1, y=2),
190
+ schema=Answer,
191
+ context='compute 1 + 1',
192
+ output=Answer(answer=3),
193
+ metadata={'foo': 'bar'},
194
+ )
195
+ self.assert_html_content(
196
+ example.to_html(
197
+ enable_summary_tooltip=False, include_message_metadata=False
198
+ ),
199
+ """
200
+ <details open class="pyglove mapping-example"><summary><div class="summary_title">MappingExample(...)</div></summary><div class="complex_value mapping-example"><div class="special_value"><details open class="pyglove user-message lf-message"><summary><div class="summary_name">input</div><div class="summary_title">UserMessage(...)</div></summary><div class="complex_value"><div class="message-tags"><span>rendered</span></div><div class="message-text">1 + 2 = ?</div></div></details></div><div class="special_value"><details open class="pyglove answer"><summary><div class="summary_name">output</div><div class="summary_title">Answer(...)</div></summary><div class="complex_value answer"><table><tr><td><span class="object_key str">answer</span><span class="tooltip key-path">output.answer</span></td><td><div><span class="simple_value int">3</span></div></td></tr></table></div></details></div><div class="special_value"><details open class="pyglove str"><summary><div class="summary_name">context</div><div class="summary_title">&#x27;compute 1 + 1&#x27;</div></summary><span class="simple_value str">&#x27;compute 1 + 1&#x27;</span></details></div><div class="special_value"><details open class="pyglove schema"><summary><div class="summary_name">schema</div><div class="summary_title">Schema(...)</div></summary><div class="lf-schema-definition">Answer
201
+
202
+ ```python
203
+ class Answer:
204
+ answer: int
205
+ ```</div></details></div><div class="special_value"><details open class="pyglove dict"><summary><div class="summary_name">metadata</div><div class="summary_title">Dict(...)</div></summary><div class="complex_value dict"><table><tr><td><span class="object_key str">foo</span><span class="tooltip key-path">metadata.foo</span></td><td><div><span class="simple_value str">&#x27;bar&#x27;</span></div></td></tr></table></div></details></div></div></details>
206
+ """
207
+ )
208
+
209
+ example = mapping.MappingExample(
210
+ input=Addition(x=1, y=2),
211
+ output=Answer(answer=3),
212
+ )
213
+ self.assert_html_content(
214
+ example.to_html(
215
+ enable_summary_tooltip=False, include_message_metadata=False
216
+ ),
217
+ """
218
+ <details open class="pyglove mapping-example"><summary><div class="summary_title">MappingExample(...)</div></summary><div class="complex_value mapping-example"><div class="special_value"><details open class="pyglove user-message lf-message"><summary><div class="summary_name">input</div><div class="summary_title">UserMessage(...)</div></summary><div class="complex_value"><div class="message-tags"><span>rendered</span></div><div class="message-text">1 + 2 = ?</div></div></details></div><div class="special_value"><details open class="pyglove answer"><summary><div class="summary_name">output</div><div class="summary_title">Answer(...)</div></summary><div class="complex_value answer"><table><tr><td><span class="object_key str">answer</span><span class="tooltip key-path">output.answer</span></td><td><div><span class="simple_value int">3</span></div></td></tr></table></div></details></div></div></details>
219
+ """
220
+ )
221
+
167
222
 
168
223
  if __name__ == '__main__':
169
224
  unittest.main()
@@ -285,7 +285,7 @@ class ParseStructurePythonTest(unittest.TestCase):
285
285
  self.assertEqual(
286
286
  r,
287
287
  lf.AIMessage(
288
- '1', score=1.0, result=1, logprobs=None,
288
+ '1', score=1.0, result=1, logprobs=None, is_cached=False,
289
289
  usage=lf.LMSamplingUsage(652, 1, 653),
290
290
  tags=['lm-response', 'lm-output', 'transformed']
291
291
  ),
@@ -645,6 +645,7 @@ class CallTest(unittest.TestCase):
645
645
  result=3,
646
646
  score=1.0,
647
647
  logprobs=None,
648
+ is_cached=False,
648
649
  usage=lf.LMSamplingUsage(315, 1, 316),
649
650
  tags=['lm-response', 'lm-output', 'transformed']
650
651
  ),
@@ -82,6 +82,7 @@ class QueryTest(unittest.TestCase):
82
82
  result=1,
83
83
  score=1.0,
84
84
  logprobs=None,
85
+ is_cached=False,
85
86
  usage=lf.LMSamplingUsage(323, 1, 324),
86
87
  tags=['lm-response', 'lm-output', 'transformed'],
87
88
  ),
@@ -189,6 +189,40 @@ class Schema(lf.NaturalLanguageFormattable, pg.Object):
189
189
  return value
190
190
  return cls(parse_value_spec(value))
191
191
 
192
+ def _html_tree_view_content(
193
+ self,
194
+ *,
195
+ view: pg.views.HtmlTreeView,
196
+ root_path: pg.KeyPath,
197
+ **kwargs,
198
+ ):
199
+ return pg.Html.element(
200
+ 'div',
201
+ [self.schema_str(protocol='python')],
202
+ css_class=['lf-schema-definition']
203
+ ).add_style(
204
+ """
205
+ .lf-schema-definition {
206
+ color: blue;
207
+ margin: 5px;
208
+ white-space: pre-wrap;
209
+ }
210
+ """
211
+ )
212
+
213
+ def _html_tree_view_tooltip(
214
+ self,
215
+ *,
216
+ view: pg.views.HtmlTreeView,
217
+ content: pg.Html | str | None = None,
218
+ **kwargs,
219
+ ):
220
+ return view.tooltip(
221
+ self,
222
+ content=content or pg.Html.escape(self.schema_str(protocol='python')),
223
+ **kwargs
224
+ )
225
+
192
226
 
193
227
  def _top_level_object_specs_from_value(value: pg.Symbolic) -> list[Type[Any]]:
194
228
  """Returns a list of top level value specs from a symbolic value."""
langfun/core/template.py CHANGED
@@ -17,7 +17,7 @@ import contextlib
17
17
  import dataclasses
18
18
  import functools
19
19
  import inspect
20
- from typing import Annotated, Any, Callable, Iterator, Set, Tuple, Type, Union
20
+ from typing import Annotated, Any, Callable, Iterator, Sequence, Set, Tuple, Type, Union
21
21
 
22
22
  import jinja2
23
23
  from jinja2 import meta as jinja2_meta
@@ -526,6 +526,115 @@ class Template(
526
526
  return lfun
527
527
  return cls(template_str='{{input}}', input=value, **kwargs)
528
528
 
529
+ def _html_tree_view_content(
530
+ self,
531
+ *,
532
+ view: pg.views.HtmlTreeView,
533
+ root_path: pg.KeyPath,
534
+ collapse_template_vars_level: int | None = pg.View.PresetArgValue(1),
535
+ collapse_level: int | None = pg.View.PresetArgValue(1), # pytype: disable=annotation-type-mismatch
536
+ **kwargs,
537
+ ):
538
+ def render_template_str():
539
+ return pg.Html.element(
540
+ 'div',
541
+ [
542
+ pg.Html.element('span', [self.template_str])
543
+ ],
544
+ css_class=['template-str'],
545
+ )
546
+
547
+ def render_fields():
548
+ def render_value_fn(value, *, root_path, **kwargs):
549
+ if isinstance(value, component.ContextualAttribute):
550
+ inferred = self.sym_inferred(root_path.key, pg.MISSING_VALUE)
551
+ if inferred != pg.MISSING_VALUE:
552
+ return pg.Html.element(
553
+ 'div',
554
+ [
555
+ view.render(inferred, root_path=root_path, **kwargs)
556
+ ],
557
+ css_class=['inferred-value'],
558
+ )
559
+ else:
560
+ return pg.Html.element(
561
+ 'span',
562
+ ['(external)'],
563
+ css_class=['contextual-variable'],
564
+ )
565
+ return view.render(
566
+ value, root_path=root_path, **kwargs
567
+ )
568
+ return pg.Html.element(
569
+ 'fieldset',
570
+ [
571
+ pg.Html.element('legend', ['Template Variables']),
572
+ view.complex_value(
573
+ self.sym_init_args,
574
+ name='fields',
575
+ root_path=root_path,
576
+ render_value_fn=render_value_fn,
577
+ exclude_keys=['template_str', 'clean'],
578
+ parent=self,
579
+ collapse_level=view.max_collapse_level(
580
+ collapse_level,
581
+ collapse_template_vars_level,
582
+ root_path
583
+ ),
584
+ ),
585
+ ],
586
+ css_class=['template-fields'],
587
+ )
588
+
589
+ return pg.Html.element(
590
+ 'div',
591
+ [
592
+ render_template_str(),
593
+ render_fields(),
594
+ ],
595
+ css_class=['complex_value'],
596
+ )
597
+
598
+ def _html_style(self) -> list[str]:
599
+ return super()._html_style() + [
600
+ """
601
+ /* Langfun Template styles. */
602
+ .template-str {
603
+ padding: 10px;
604
+ margin: 10px 5px 10px 5px;
605
+ font-style: italic;
606
+ font-size: 1.1em;
607
+ white-space: pre-wrap;
608
+ border: 1px solid #EEE;
609
+ border-radius: 5px;
610
+ background-color: #EEE;
611
+ color: #cc2986;
612
+ }
613
+ .template-fields {
614
+ margin: 0px 0px 5px 0px;
615
+ border: 1px solid #EEE;
616
+ padding: 5px;
617
+ }
618
+ .template-fields > legend {
619
+ font-size: 0.8em;
620
+ margin: 5px 0px 5px 0px;
621
+ }
622
+ .inferred-value::after {
623
+ content: ' (inferred)';
624
+ color: gray;
625
+ font-style: italic;
626
+ }
627
+ .contextual-variable {
628
+ margin: 0px 0px 0px 5px;
629
+ font-style: italic;
630
+ color: gray;
631
+ }
632
+ """
633
+ ]
634
+
635
+ # Additional CSS class to add to the root <details> element.
636
+ def _html_element_class(self) -> Sequence[str] | None:
637
+ return super()._html_element_class() + ['lf-template']
529
638
 
530
639
  # Register converter from str to LangFunc, therefore we can always
531
640
  # pass strs to attributes that accept LangFunc.
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
  """Template test."""
15
15
  import inspect
16
+ from typing import Any
16
17
  import unittest
17
18
 
18
19
  from langfun.core import component
@@ -552,5 +553,41 @@ class TemplateRenderEventTest(unittest.TestCase):
552
553
  self.assertEqual(render_stacks, [[l]])
553
554
 
554
555
 
556
+ class HtmlTest(unittest.TestCase):
557
+
558
+ def assert_html_content(self, html, expected):
559
+ expected = inspect.cleandoc(expected).strip()
560
+ actual = html.content.strip()
561
+ if actual != expected:
562
+ print(actual)
563
+ self.assertEqual(actual, expected)
564
+
565
+ def test_html(self):
566
+
567
+ class Foo(Template):
568
+ """Template Foo.
569
+
570
+ {{x}} + {{y}} = ?
571
+ """
572
+ x: Any
573
+ y: Any
574
+
575
+ class Bar(Template):
576
+ """Template Bar.
577
+
578
+ {{y}} + {{z}}
579
+ """
580
+ y: Any
581
+
582
+ self.assert_html_content(
583
+ Foo(x=Bar('{{y}} + {{z}}'), y=1).to_html(
584
+ enable_summary_tooltip=False,
585
+ ),
586
+ """
587
+ <details open class="pyglove foo lf-template"><summary><div class="summary_title">Foo(...)</div></summary><div class="complex_value"><div class="template-str"><span>{{x}} + {{y}} = ?</span></div><fieldset class="template-fields"><legend>Template Variables</legend><div class="complex_value foo lf-template"><table><tr><td><span class="object_key str">x</span><span class="tooltip key-path">x</span></td><td><div><details class="pyglove bar lf-template"><summary><div class="summary_title">Bar(...)</div></summary><div class="complex_value"><div class="template-str"><span>{{y}} + {{z}}</span></div><fieldset class="template-fields"><legend>Template Variables</legend><div class="complex_value bar lf-template"><table><tr><td><span class="object_key str">y</span><span class="tooltip key-path">x.y</span></td><td><div><div class="inferred-value"><span class="simple_value int">1</span></div></div></td></tr><tr><td><span class="object_key str">z</span><span class="tooltip key-path">x.z</span></td><td><div><span class="contextual-variable">(external)</span></div></td></tr></table></div></fieldset></div></details></div></td></tr><tr><td><span class="object_key str">y</span><span class="tooltip key-path">y</span></td><td><div><span class="simple_value int">1</span></div></td></tr></table></div></fieldset></div></details>
588
+ """
589
+ )
590
+
591
+
555
592
  if __name__ == '__main__':
556
593
  unittest.main()
@@ -59,7 +59,8 @@ class SelfPlayTest(unittest.TestCase):
59
59
  self.assertEqual(
60
60
  g(),
61
61
  lf.AIMessage(
62
- '10', score=0.0, logprobs=None, usage=lf.UsageNotAvailable()
62
+ '10', score=0.0, logprobs=None, is_cached=False,
63
+ usage=lf.UsageNotAvailable()
63
64
  )
64
65
  )
65
66
 
@@ -72,7 +73,8 @@ class SelfPlayTest(unittest.TestCase):
72
73
  self.assertEqual(
73
74
  g(),
74
75
  lf.AIMessage(
75
- '2', score=0.0, logprobs=None, usage=lf.UsageNotAvailable()
76
+ '2', score=0.0, logprobs=None, is_cached=False,
77
+ usage=lf.UsageNotAvailable()
76
78
  )
77
79
  )
78
80
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langfun
3
- Version: 0.1.2.dev202410100804
3
+ Version: 0.1.2.dev202410120803
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors