langfun 0.1.2.dev202510270805__py3-none-any.whl → 0.1.2.dev202510290805__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/env/interface.py CHANGED
@@ -170,6 +170,9 @@ class SessionTeardownError(SandboxError):
170
170
  class Environment(pg.Object):
171
171
  """Base class for an environment."""
172
172
 
173
+ # Disable symbolic comparison and hashing for environment objects.
174
+ use_symbolic_comparison = False
175
+
173
176
  @dataclasses.dataclass(frozen=True)
174
177
  class Id:
175
178
  """Identifier for an environment."""
@@ -220,6 +223,20 @@ class Environment(pg.Object):
220
223
  def id(self) -> Id:
221
224
  """Returns the identifier for the environment."""
222
225
 
226
+ @property
227
+ @abc.abstractmethod
228
+ def image_ids(self) -> list[str]:
229
+ """Returns the non-dynamic image IDs served by the environment."""
230
+
231
+ def image_id_for(self, feature: 'Feature') -> str:
232
+ """Returns the default image ID for the environment."""
233
+ for image_id in self.image_ids:
234
+ if feature.is_applicable(image_id):
235
+ return image_id
236
+ raise ValueError(
237
+ f'No image ID found for feature {feature.name} in {self.image_ids}.'
238
+ )
239
+
223
240
  @property
224
241
  @abc.abstractmethod
225
242
  def status(self) -> Status:
@@ -245,9 +262,16 @@ class Environment(pg.Object):
245
262
  """
246
263
 
247
264
  @abc.abstractmethod
248
- def acquire(self) -> 'Sandbox':
265
+ def acquire(
266
+ self,
267
+ image_id: str | None = None,
268
+ ) -> 'Sandbox':
249
269
  """Acquires a free sandbox from the environment.
250
270
 
271
+ Args:
272
+ image_id: The image ID to use for the sandbox. If None, it will be
273
+ automatically determined by the environment.
274
+
251
275
  Returns:
252
276
  A free sandbox from the environment.
253
277
 
@@ -257,7 +281,7 @@ class Environment(pg.Object):
257
281
  """
258
282
 
259
283
  @abc.abstractmethod
260
- def new_session_id(self) -> str:
284
+ def new_session_id(self, feature_hint: str | None = None) -> str:
261
285
  """Generates a new session ID."""
262
286
 
263
287
  #
@@ -298,33 +322,63 @@ class Environment(pg.Object):
298
322
 
299
323
  def sandbox(
300
324
  self,
325
+ image_id: str | None = None,
301
326
  session_id: str | None = None,
302
327
  ) -> ContextManager['Sandbox']:
303
328
  """Gets a sandbox from the environment and starts a new user session."""
304
- return self.acquire().new_session(session_id)
329
+ return self.acquire(image_id=image_id).new_session(session_id)
305
330
 
306
331
  def __getattr__(self, name: str) -> Any:
307
- """Gets a feature from a free sandbox from the environment.
332
+ """Gets a feature session from a free sandbox from the environment.
308
333
 
309
334
  Example:
310
335
  ```
311
336
  with XboxEnvironment(
312
337
  features={'selenium': SeleniumFeature()}
313
338
  ) as env:
314
- driver = env.selenium.get_driver()
339
+ with env.selenium() as selenium:
340
+ driver = selenium.get_driver()
315
341
  ```
316
342
 
317
343
  Args:
318
344
  name: The name of the feature.
319
345
 
320
346
  Returns:
321
- A feature from a free sandbox from the environment.
347
+ A callable `(image_id, *, session_id) -> ContextManager[Feature]` that
348
+ creates a context manager for the requested feature under a new client
349
+ session.
322
350
  """
323
351
  if name in self.features:
324
- return self.acquire().features[name]
352
+ return _feature_session_creator(self, self.features[name])
325
353
  raise AttributeError(name)
326
354
 
327
355
 
356
+ @contextlib.contextmanager
357
+ def _session_for_feature(
358
+ environment: Environment,
359
+ feature: 'Feature',
360
+ image_id: str | None = None,
361
+ session_id: str | None = None,
362
+ ) -> Iterator['Feature']:
363
+ """Returns a context manager for a session for a feature."""
364
+ if image_id is None:
365
+ image_id = environment.image_id_for(feature)
366
+ elif not feature.is_applicable(image_id):
367
+ raise ValueError(
368
+ f'Feature {feature.name!r} is not applicable to image {image_id!r}.'
369
+ )
370
+ sandbox = environment.acquire(image_id=image_id)
371
+ with sandbox.new_session(session_id=session_id, feature_hint=feature.name):
372
+ yield sandbox.features[feature.name]
373
+
374
+
375
+ def _feature_session_creator(environment: Environment, feature: 'Feature'):
376
+ """Returns a callable that returns a context manager for a feature session."""
377
+ def fn(image_id: str | None = None, session_id: str | None = None):
378
+ return _session_for_feature(environment, feature, image_id, session_id)
379
+ return fn
380
+
381
+
328
382
  # Enable automatic conversion from str to Environment.Id.
329
383
  pg.typing.register_converter(str, Environment.Id, Environment.Id)
330
384
 
@@ -332,14 +386,18 @@ pg.typing.register_converter(str, Environment.Id, Environment.Id)
332
386
  class Sandbox(pg.Object):
333
387
  """Interface for sandboxes."""
334
388
 
389
+ # Disable symbolic comparison and hashing for sandbox objects.
390
+ use_symbolic_comparison = False
391
+
335
392
  @dataclasses.dataclass(frozen=True, slots=True)
336
393
  class Id:
337
394
  """Identifier for a sandbox."""
338
395
  environment_id: Environment.Id
396
+ image_id: str
339
397
  sandbox_id: str
340
398
 
341
399
  def __str__(self) -> str:
342
- return f'{self.environment_id}/{self.sandbox_id}'
400
+ return f'{self.environment_id}/{self.image_id}:{self.sandbox_id}'
343
401
 
344
402
  def working_dir(self, root_dir: str | None) -> str | None:
345
403
  """Returns the download directory for the sandbox."""
@@ -347,6 +405,7 @@ class Sandbox(pg.Object):
347
405
  return None
348
406
  return os.path.join(
349
407
  self.environment_id.working_dir(root_dir),
408
+ _make_path_compatible(self.image_id),
350
409
  _make_path_compatible(self.sandbox_id)
351
410
  )
352
411
 
@@ -438,6 +497,11 @@ class Sandbox(pg.Object):
438
497
  def id(self) -> Id:
439
498
  """Returns the identifier for the sandbox."""
440
499
 
500
+ @property
501
+ @abc.abstractmethod
502
+ def image_id(self) -> str:
503
+ """Returns the image ID used for bootstrapping the sandbox."""
504
+
441
505
  @property
442
506
  @abc.abstractmethod
443
507
  def environment(self) -> Environment:
@@ -626,6 +690,8 @@ class Sandbox(pg.Object):
626
690
  def new_session(
627
691
  self,
628
692
  session_id: str | None = None,
693
+ *,
694
+ feature_hint: str | None = None,
629
695
  ) -> Iterator['Sandbox']:
630
696
  """Context manager for obtaining a sandbox for a user session.
631
697
 
@@ -636,6 +702,9 @@ class Sandbox(pg.Object):
636
702
  Args:
637
703
  session_id: The identifier for the user session. If not provided, a random
638
704
  ID will be generated.
705
+ feature_hint: A hint of which feature is the main user intent when
706
+ starting the session. This is used for generating the session id if
707
+ `session_id` is not provided.
639
708
 
640
709
  Yields:
641
710
  The sandbox for the user session.
@@ -646,7 +715,7 @@ class Sandbox(pg.Object):
646
715
  errors.
647
716
  """
648
717
  if session_id is None:
649
- session_id = self.environment.new_session_id()
718
+ session_id = self.environment.new_session_id(feature_hint)
650
719
  self.start_session(session_id)
651
720
  try:
652
721
  yield self
@@ -683,6 +752,9 @@ class Sandbox(pg.Object):
683
752
  class Feature(pg.Object):
684
753
  """Interface for sandbox features."""
685
754
 
755
+ # Disable symbolic comparison and hashing for sandbox objects.
756
+ allow_symbolic_comparison = False
757
+
686
758
  @property
687
759
  @abc.abstractmethod
688
760
  def name(self) -> str:
@@ -700,6 +772,10 @@ class Feature(pg.Object):
700
772
  AssertError: If the feature is not set up with a sandbox yet.
701
773
  """
702
774
 
775
+ @abc.abstractmethod
776
+ def is_applicable(self, image_id: str) -> bool:
777
+ """Returns True if the feature is applicable to the given image."""
778
+
703
779
  @abc.abstractmethod
704
780
  def setup(self, sandbox: Sandbox) -> None:
705
781
  """Sets up the feature, which is called once when the sandbox is up.
@@ -29,12 +29,13 @@ class IdTest(unittest.TestCase):
29
29
  def test_sandbox_id(self):
30
30
  sandbox_id = interface.Sandbox.Id(
31
31
  environment_id=interface.Environment.Id('env'),
32
+ image_id='image:2025_01_01_00_00_00',
32
33
  sandbox_id='sandbox'
33
34
  )
34
- self.assertEqual(str(sandbox_id), 'env/sandbox')
35
+ self.assertEqual(str(sandbox_id), 'env/image:2025_01_01_00_00_00:sandbox')
35
36
  self.assertEqual(
36
37
  sandbox_id.working_dir(root_dir='/tmp'),
37
- '/tmp/env/sandbox'
38
+ '/tmp/env/image_2025_01_01_00_00_00/sandbox'
38
39
  )
39
40
  self.assertIsNone(sandbox_id.working_dir(root_dir=None))
40
41
 
@@ -22,6 +22,7 @@ from langfun.env import load_balancers
22
22
  class TestingSandbox(interface.Sandbox):
23
23
  sandbox_id: str
24
24
  status: interface.Sandbox.Status = interface.Sandbox.Status.READY
25
+ image_id: str = 'test_image'
25
26
 
26
27
  def _on_bound(self) -> None:
27
28
  super()._on_bound()
@@ -31,6 +32,7 @@ class TestingSandbox(interface.Sandbox):
31
32
  def id(self) -> interface.Sandbox.Id:
32
33
  return interface.Sandbox.Id(
33
34
  environment_id=interface.Environment.Id('testing-env'),
35
+ image_id=self.image_id,
34
36
  sandbox_id=self.sandbox_id
35
37
  )
36
38
 
langfun/env/test_utils.py CHANGED
@@ -27,7 +27,7 @@ import pyglove as pg
27
27
 
28
28
  class TestingEnvironment(base_environment.BaseEnvironment):
29
29
  """Testing environment for unit tests."""
30
-
30
+ image_ids: list[str] = ['test_image']
31
31
  housekeep_interval: float = 0.0
32
32
  simulate_start_error: Type[BaseException] | None = None
33
33
  simulate_shutdown_error: Type[BaseException] | None = None
@@ -45,6 +45,7 @@ class TestingEnvironment(base_environment.BaseEnvironment):
45
45
 
46
46
  def _create_sandbox(
47
47
  self,
48
+ image_id: str,
48
49
  sandbox_id: str,
49
50
  reusable: bool,
50
51
  proactive_session_setup: bool,
@@ -54,8 +55,10 @@ class TestingEnvironment(base_environment.BaseEnvironment):
54
55
  environment=self,
55
56
  id=interface.Sandbox.Id(
56
57
  environment_id=self.id,
58
+ image_id=image_id,
57
59
  sandbox_id=sandbox_id
58
60
  ),
61
+ image_id=image_id,
59
62
  reusable=reusable,
60
63
  proactive_session_setup=proactive_session_setup,
61
64
  keepalive_interval=keepalive_interval,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langfun
3
- Version: 0.1.2.dev202510270805
3
+ Version: 0.1.2.dev202510290805
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -6,7 +6,7 @@ langfun/assistant/capabilities/gui/drawing.py,sha256=8wgol61P7HovLg5EaevRmDPXTFu
6
6
  langfun/assistant/capabilities/gui/drawing_test.py,sha256=d6LQ1ctG78YRi58UVBdndwyEqTC_ITdk191oA3tASxM,3421
7
7
  langfun/assistant/capabilities/gui/location.py,sha256=QYJlY5kUNEwiZFiPYRyFAO7bD2ez4jL5hYn1_AK1ulc,8643
8
8
  langfun/assistant/capabilities/gui/location_test.py,sha256=pQUOH1sKuAwjTTYKu615RUnecc_lNrddfvkyxf9297w,9051
9
- langfun/core/__init__.py,sha256=GC4amBXybjSfYVrEQSLFb_KBhH75uD95GKkHNiJfwkY,5011
9
+ langfun/core/__init__.py,sha256=-HrGZb0Gv4nH6R2I2dXOVfkWKrGQfEu9UHBmXsG-x-E,5056
10
10
  langfun/core/async_support.py,sha256=WF4sflm0Q-UHJ8lPtlEo9hSwqXqm1kfaAYVPTyVP3n0,3062
11
11
  langfun/core/async_support_test.py,sha256=fMz1ulGrfUCuHp7RtYktuBwpbRN3kCBKnB4LFvaXSAA,1754
12
12
  langfun/core/component.py,sha256=g1kQM0bryYYYWVDrSMnHfc74wIBbpfe5_B3s-UIP5GE,3028
@@ -22,7 +22,7 @@ langfun/core/language_model_test.py,sha256=UIQpovmVfJnJ2EDOi9OZG_1UNClWs9lkTaE22
22
22
  langfun/core/logging.py,sha256=7IGAhp7mGokZxxqtL-XZvFLKaZ5k3F5_Xp2NUtR4GwE,9136
23
23
  langfun/core/logging_test.py,sha256=vbVGOQxwMmVSiFfbt2897gUt-8nqDpV64jCAeUG_q5U,6924
24
24
  langfun/core/memory.py,sha256=vyXVvfvSdLLJAzdIupnbn3k26OgclCx-OJ7gddS5e1Y,2070
25
- langfun/core/message.py,sha256=m36GDLtuDVUURkYORTEj61Uho6eILwSkCjrksK0HLWs,33964
25
+ langfun/core/message.py,sha256=DShgb0pHCfy8IvMzFccTO6mG0WS3O226UZNoxzNOGF4,34100
26
26
  langfun/core/message_test.py,sha256=hjnzxJbjLNau30Ex7h5B0qC8qUU4uscoUcEVayRiXFQ,38355
27
27
  langfun/core/modality.py,sha256=h56hfCyxX_rK_BU3pFxXpGD79TvFeRXVo71QvpzmZiw,6596
28
28
  langfun/core/modality_test.py,sha256=0MQz6e39XOd2UjAIc5Vq9Eems1IUgOxD7Skf0gTMGTg,3665
@@ -53,7 +53,7 @@ langfun/core/coding/python/sandboxing.py,sha256=ppeE4E9rwVpMO2wxZN6dA2OwSMyD2hQ9
53
53
  langfun/core/coding/python/sandboxing_test.py,sha256=H_0_pd-_uS-ci5yYhmDTR6-hyzosAFkExziAHndfdDo,2023
54
54
  langfun/core/data/__init__.py,sha256=qllw9ST1vveZv-1E0VM5hezn1YH-OcqGI-yFqQYnWgI,732
55
55
  langfun/core/data/conversion/__init__.py,sha256=ZcGntBruvvZSfESO-Tha1nzHfgWEK7I1u78Jw8gsoVU,883
56
- langfun/core/data/conversion/anthropic.py,sha256=0xf1sWt6WhmG8EsaeLY4Ee7S3FcDWKPOtn6caCBhtrQ,4431
56
+ langfun/core/data/conversion/anthropic.py,sha256=8JceJL4Z7qxgprKaByT1uDiyxpUTeHl2rgVEWRHr1Ms,4511
57
57
  langfun/core/data/conversion/anthropic_test.py,sha256=BMIyLgFOtFuJYJAkSLR1nwG7UOwtoT61R5xAXtJfSMY,8624
58
58
  langfun/core/data/conversion/gemini.py,sha256=mLft9j30W8aIi5a7tOdjfO2v8O8a61FSDKf2k-co93M,5825
59
59
  langfun/core/data/conversion/gemini_test.py,sha256=LeSToAqEhBHekSCjHFkC_cLN7Xv_cn-nnCURS95511M,7366
@@ -123,9 +123,11 @@ langfun/core/llms/cache/in_memory.py,sha256=i58oiQL28RDsq37dwqgVpC2mBETJjIEFS20y
123
123
  langfun/core/llms/cache/in_memory_test.py,sha256=AG9OGdxfyW9LdteFRF-aOIhxiH5Kna5U-pQk91ljHCQ,10538
124
124
  langfun/core/mcp/__init__.py,sha256=cyVP_YTjOmbjhYg8BE7-RnE4Txt8wDukYC0anhHKpuo,286
125
125
  langfun/core/mcp/client.py,sha256=NBo4W2fdvYyywlUHynAbyh7LNohILccTkCiisj-UEEg,3642
126
- langfun/core/mcp/client_test.py,sha256=Vjbh7bXM8xXMMe_QOnFJ4rE0wITovAZbwk7Nu-cqf8g,2766
127
- langfun/core/mcp/session.py,sha256=dyuNXpLvM0TgLoUmWEwy5XCRf-IK7H_BbcNI2oFa_ek,5626
128
- langfun/core/mcp/tool.py,sha256=eap46OK4lrw5G5uCwPi4kUMNdaN1Bgy0cUi0bdLJI5Q,3607
126
+ langfun/core/mcp/client_test.py,sha256=ytplbrnFDqnHkDQuf5UGJaFf-rXUtwONCJcmNZ_rNUY,2221
127
+ langfun/core/mcp/session.py,sha256=yFjt0TzV0HqkanFmcTb_JvTkJor2KTEdMoAsCSu3KuE,5163
128
+ langfun/core/mcp/session_test.py,sha256=V4UVH9uVDL10RUWUr4jldcZqn4HYB75WgkjAnNg6cVw,1952
129
+ langfun/core/mcp/tool.py,sha256=PRh4zHRXaSpYmjSrhh0vvoOs-Gi-4plDucKcM7o0umY,6056
130
+ langfun/core/mcp/tool_test.py,sha256=oKsIpkyb-2Pr7_Fyqn1WNX8B07_izfdUyo4fIAp7x3o,6372
129
131
  langfun/core/mcp/testing/simple_mcp_client.py,sha256=U5pUXa0SnB2-DdRI2vPhrdVUv14dX_OeS4mPLFpllMc,924
130
132
  langfun/core/mcp/testing/simple_mcp_server.py,sha256=dw4t6ERWMdmi6kDE38RU5oYu5MQbEX-GJ6CMxGcV-WE,994
131
133
  langfun/core/memories/__init__.py,sha256=HpghfZ-w1NQqzJXBx8Lz0daRhB2rcy2r9Xm491SBhC4,773
@@ -173,23 +175,23 @@ langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3AB
173
175
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
174
176
  langfun/core/templates/selfplay_test.py,sha256=Ot__1P1M8oJfoTp-M9-PQ6HUXqZKyMwvZ5f7yQ3yfyM,2326
175
177
  langfun/env/__init__.py,sha256=m6Y8y16ms9lytvO_r-Br8HmTp2rNDhb3R6JJaH5dEEk,1491
176
- langfun/env/base_environment.py,sha256=m7IJNHqt4dlgBRwv0E8BxKtARvcNJis9FrrALguzX1E,19472
177
- langfun/env/base_feature.py,sha256=gGUCWLcSaQZ7MoXNKogXEdcpfoqJxcfnoXhWQjqi8jk,6462
178
- langfun/env/base_sandbox.py,sha256=yG_4qG5MVIEP5uyXO2KssZFSFDewwNvF7Hr_qE7yGfQ,37301
179
- langfun/env/base_test.py,sha256=DrBtyweO4v8Fz3Oz-gnpJ4W_9hRhuVXA1CTLvXJDa9s,61099
180
- langfun/env/interface.py,sha256=2Amf-_op7dGRF8c4-wYxcFxs1UCBYz1AB20Lk7__V4E,25724
181
- langfun/env/interface_test.py,sha256=hfQn4RRTEo1YfVHXTPzH1puzD14BTo8R_5v1IpXVZ90,1398
178
+ langfun/env/base_environment.py,sha256=8Cpwb4D37zHj5AK4qgmGIPyxIMEDxTIPHXqxTSNkE_M,25030
179
+ langfun/env/base_feature.py,sha256=JDEhL9LkbBHB0c603guchry7cy_zaIReg5vqExyQQgg,6902
180
+ langfun/env/base_sandbox.py,sha256=aBzPWJGszWuwv8BObvBoIVtl8aiOp41YjTEfVbYYDKQ,37425
181
+ langfun/env/base_test.py,sha256=PqFLqT-IwOe3zH4JWeCtUdDjSqG9KQ4RBQebo67AIqc,74983
182
+ langfun/env/interface.py,sha256=_XguM6xjPQuiTUUrs-4_3ejm8rnolO5cfxpuYE6yoX8,28520
183
+ langfun/env/interface_test.py,sha256=1ZeLPsB9QUyervNrg2LdkJeYx-rQYQ1Zq_IzIKJtS5M,1496
182
184
  langfun/env/load_balancers.py,sha256=qRhCthqzjZIQBwta8qC1C0s0J-VQAVomJQqI7Nqv-r4,1948
183
- langfun/env/load_balancers_test.py,sha256=73QQG-Lufy5DBhQuzWNUaaH24YiZFdZEHe67TkJn7a0,3708
184
- langfun/env/test_utils.py,sha256=rnIQZ2ZpiFuB7yfl5ckGtacBoySAwguzBzXzqhyo8jw,14042
185
+ langfun/env/load_balancers_test.py,sha256=E1ksJ5Xsoj5aJTM4i9EKDiWKDFljs75FpoeJpbtCKL8,3771
186
+ langfun/env/test_utils.py,sha256=5_lCkTvXC1J9unPdgmqn5PxaucU7GCcro0iFtjehJo0,14160
185
187
  langfun/env/event_handlers/__init__.py,sha256=H34n-TbKSgtxqBhE-yAti8fY6weF2_v3yw59M9_zmGM,443
186
188
  langfun/env/event_handlers/base.py,sha256=eGdJ6N5em9kX-c9wzm1TdnRP5_5IAltX5JTHILdjzLM,10124
187
189
  langfun/env/event_handlers/event_logger.py,sha256=3dbPjBe53dBgntYHlyLlj_77hVecPSXkmKeiGXMxlO0,12699
188
- langfun/env/event_handlers/event_logger_test.py,sha256=PGof3rPllNnyzs3Yp8kaOHLeTkVrzUgCJwlODTrVRKI,9111
189
- langfun/env/event_handlers/metric_writer.py,sha256=NgJKsd6xWOtEd0IjYi7coGEaqGYkkPcDjXN9CQ3vxPU,18043
190
- langfun/env/event_handlers/metric_writer_test.py,sha256=deqCIdo-Q89rRCF2lerU3GpWmFG_SvDx162UQIZxPgE,5338
191
- langfun-0.1.2.dev202510270805.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
192
- langfun-0.1.2.dev202510270805.dist-info/METADATA,sha256=cQSg_RGaOWibKP72oV20cfWjqzwXA9oMRhDjRILfApQ,7522
193
- langfun-0.1.2.dev202510270805.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
194
- langfun-0.1.2.dev202510270805.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
195
- langfun-0.1.2.dev202510270805.dist-info/RECORD,,
190
+ langfun/env/event_handlers/event_logger_test.py,sha256=ryupxaEP9D8wdtSsSwZRSZwqFaHCaSD-bFSea_T7QJo,9133
191
+ langfun/env/event_handlers/metric_writer.py,sha256=F_Gk1lpJX5SZ6-Hyrf_-utf4gvSKvMmcov8VkKogZCU,19618
192
+ langfun/env/event_handlers/metric_writer_test.py,sha256=sntUifTPHGixUshIgVBX4Q9vJL-xbeS0Cpd5X5hSQyQ,5955
193
+ langfun-0.1.2.dev202510290805.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
194
+ langfun-0.1.2.dev202510290805.dist-info/METADATA,sha256=0QBqKpkm1e7B23GJpMUX5XQWfJEWwn_6nl-Qw_m2tos,7522
195
+ langfun-0.1.2.dev202510290805.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
196
+ langfun-0.1.2.dev202510290805.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
197
+ langfun-0.1.2.dev202510290805.dist-info/RECORD,,