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,507 @@
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
+ """Test utils for base environment."""
15
+
16
+ import contextlib
17
+ import time
18
+ from typing import Iterator, Type
19
+
20
+ from langfun.env import base_environment
21
+ from langfun.env import base_feature
22
+ from langfun.env import base_sandbox
23
+ from langfun.env import interface
24
+ import pyglove as pg
25
+
26
+
27
+ class TestingEnvironment(base_environment.BaseEnvironment):
28
+ """Testing environment for unit tests."""
29
+ image_ids: list[str] = ['test_image']
30
+ housekeep_interval: float = 0.0
31
+ simulate_start_error: Type[BaseException] | None = None
32
+ simulate_shutdown_error: Type[BaseException] | None = None
33
+ simulate_ping_error: Type[BaseException] | None = None
34
+ offline: bool = False
35
+
36
+ __test__ = False
37
+
38
+ @property
39
+ def id(self) -> interface.Environment.Id:
40
+ return interface.Environment.Id('testing-env')
41
+
42
+ def wait_for_housekeeping(self):
43
+ housekeep_counter = self.housekeep_counter
44
+ while self.housekeep_counter == housekeep_counter:
45
+ time.sleep(0.01)
46
+
47
+ def _create_sandbox(
48
+ self,
49
+ image_id: str,
50
+ sandbox_id: str,
51
+ reusable: bool,
52
+ proactive_session_setup: bool,
53
+ keepalive_interval: float | None,
54
+ ) -> base_sandbox.BaseSandbox:
55
+ return TestingSandbox(
56
+ environment=self,
57
+ id=interface.Sandbox.Id(
58
+ environment_id=self.id,
59
+ image_id=image_id,
60
+ sandbox_id=sandbox_id
61
+ ),
62
+ image_id=image_id,
63
+ reusable=reusable,
64
+ proactive_session_setup=proactive_session_setup,
65
+ keepalive_interval=keepalive_interval,
66
+ simulate_start_error=self.simulate_start_error,
67
+ simulate_shutdown_error=self.simulate_shutdown_error,
68
+ simulate_ping_error=self.simulate_ping_error,
69
+ )
70
+
71
+
72
+ class TestingSandbox(base_sandbox.BaseSandbox):
73
+ """Testing sandbox for unit tests."""
74
+
75
+ simulate_start_error: Type[BaseException] | None = None
76
+ simulate_shutdown_error: Type[BaseException] | None = None
77
+ simulate_ping_error: Type[BaseException] | None = None
78
+
79
+ __test__ = False
80
+
81
+ def _on_bound(self) -> None:
82
+ super()._on_bound()
83
+ self._shell_history = []
84
+ self._ping_history = []
85
+
86
+ def _raise_error(self, message, error_type: Type[BaseException], **kwargs):
87
+ if (error_type is interface.SandboxStateError or
88
+ issubclass(error_type, interface.SandboxStateError)):
89
+ kwargs['sandbox'] = self
90
+ raise error_type(message, **kwargs)
91
+ else:
92
+ raise error_type(message)
93
+
94
+ def wait_until_not(
95
+ self,
96
+ status: interface.Sandbox.Status | tuple[interface.Sandbox.Status, ...]
97
+ ) -> None:
98
+ if not isinstance(status, tuple):
99
+ status = (status,)
100
+ while self.status in status:
101
+ time.sleep(0.01)
102
+
103
+ def wait_until_next_housekeep(self) -> None:
104
+ housekeep_counter = self.housekeep_counter
105
+ while self.housekeep_counter == housekeep_counter:
106
+ time.sleep(0.01)
107
+
108
+ def _start(self) -> None:
109
+ if self.simulate_start_error:
110
+ self._raise_error('Sandbox start error', self.simulate_start_error)
111
+ super()._start()
112
+
113
+ def _shutdown(self) -> None:
114
+ if self.simulate_shutdown_error:
115
+ self._raise_error('Sandbox shutdown error', self.simulate_shutdown_error)
116
+ super()._shutdown()
117
+
118
+ @interface.treat_as_sandbox_state_error(errors=(RuntimeError,))
119
+ @interface.log_activity()
120
+ def shell(
121
+ self,
122
+ code: str,
123
+ raise_error: Type[BaseException] | None = None,
124
+ ) -> str:
125
+ self._shell_history.append(code)
126
+ if raise_error is not None:
127
+ self._raise_error(f'shell "{code}" failed', raise_error)
128
+ return f'shell "{code}" succeeded'
129
+
130
+ def _ping(self) -> None:
131
+ self._ping_history.append(not self.simulate_ping_error)
132
+ if self.simulate_ping_error:
133
+ self._raise_error('Ping error', self.simulate_ping_error, code='ping')
134
+
135
+
136
+ class TestingFeature(base_feature.BaseFeature):
137
+ """Testing feature for unit tests."""
138
+
139
+ housekeep_interval = 0
140
+ setup_session_delay: float = 0.0
141
+ simulate_housekeep_error: Type[BaseException] | None = None
142
+ simulate_setup_error: Type[BaseException] | None = None
143
+ simulate_teardown_error: Type[BaseException] | None = None
144
+ simulate_setup_session_error: Type[BaseException] | None = None
145
+ simulate_teardown_session_error: Type[BaseException] | None = None
146
+ call_end_session_on_teardown_session: bool = False
147
+
148
+ __test__ = False
149
+
150
+ class Service:
151
+ """Sandbox."""
152
+
153
+ def __init__(self, sandbox: interface.Sandbox):
154
+ self._sandbox = sandbox
155
+
156
+ def do(self, code: str, raise_error: Type[BaseException] | None = None):
157
+ self._sandbox.shell(code, raise_error=raise_error)
158
+
159
+ def _raise_error(self, message, error_type: Type[BaseException], **kwargs):
160
+ self._sandbox._raise_error(message, error_type, **kwargs) # pylint: disable=protected-access
161
+
162
+ def _setup(self) -> None:
163
+ if self.simulate_setup_error:
164
+ self._raise_error(f'{self.name} setup error', self.simulate_setup_error)
165
+ self.sandbox.shell(f'"{self.name}" setup')
166
+
167
+ def _teardown(self) -> None:
168
+ if self.simulate_teardown_error:
169
+ self._raise_error(
170
+ f'{self.name} teardown error', self.simulate_teardown_error
171
+ )
172
+ self.sandbox.shell(f'"{self.name}" teardown')
173
+
174
+ def _setup_session(self) -> None:
175
+ if self.setup_session_delay > 0:
176
+ time.sleep(self.setup_session_delay)
177
+
178
+ if self.simulate_setup_session_error:
179
+ self._raise_error(
180
+ 'Feature session setup error', self.simulate_setup_session_error
181
+ )
182
+ self.sandbox.shell(f'"{self.name}" setup session')
183
+
184
+ def _teardown_session(self) -> None:
185
+ if self.simulate_teardown_session_error:
186
+ self._raise_error(
187
+ 'Feature session teardown error', self.simulate_teardown_session_error
188
+ )
189
+ self.sandbox.shell(f'"{self.name}" teardown session')
190
+ if self.call_end_session_on_teardown_session:
191
+ self.sandbox.end_session()
192
+
193
+ @interface.log_activity()
194
+ def num_shell_calls(self) -> int:
195
+ return len(self.sandbox._shell_history) # pylint: disable=protected-access
196
+
197
+ @interface.log_activity()
198
+ def bad_shell_call(self) -> None:
199
+ self.sandbox.shell('bad command', raise_error=RuntimeError)
200
+
201
+ @interface.log_activity()
202
+ def show_session_id(self):
203
+ return self.session_id
204
+
205
+ @interface.log_activity()
206
+ def call_with_varargs(self, code: str, *args, **kwargs):
207
+ del code, args, kwargs
208
+ return 0
209
+
210
+ def _on_bound(self) -> None:
211
+ super()._on_bound()
212
+ self._service = None
213
+
214
+ @contextlib.contextmanager
215
+ def my_service(self) -> Iterator[Service]:
216
+ try:
217
+ self._service = TestingFeature.Service(sandbox=self.sandbox)
218
+ yield self._service
219
+ finally:
220
+ self._service = None
221
+
222
+ def _housekeep(self) -> None:
223
+ if self.simulate_housekeep_error:
224
+ raise interface.SandboxStateError(
225
+ 'House keeping error', sandbox=self.sandbox
226
+ )
227
+
228
+
229
+ class TestingNonSandboxBasedFeature(base_feature.BaseFeature):
230
+ """Testing non-sandbox based feature for unit tests."""
231
+ is_sandbox_based: bool = False
232
+ simulate_setup_error: Type[BaseException] | None = None
233
+ simulate_teardown_error: Type[BaseException] | None = None
234
+ simulate_setup_session_error: Type[BaseException] | None = None
235
+ simulate_teardown_session_error: Type[BaseException] | None = None
236
+ simulate_housekeep_error: Type[BaseException] | None = None
237
+
238
+ __test__ = False
239
+
240
+ def _setup(self) -> None:
241
+ if self.simulate_setup_error:
242
+ raise self.simulate_setup_error('Feature setup error')
243
+
244
+ def _teardown(self) -> None:
245
+ if self.simulate_teardown_error:
246
+ raise self.simulate_teardown_error('Feature teardown error')
247
+
248
+ def _setup_session(self) -> None:
249
+ if self.simulate_setup_session_error:
250
+ raise self.simulate_setup_session_error('Feature session setup error')
251
+
252
+ def _teardown_session(self) -> None:
253
+ if self.simulate_teardown_session_error:
254
+ raise self.simulate_teardown_session_error(
255
+ 'Feature session teardown error'
256
+ )
257
+
258
+ def _housekeep(self) -> None:
259
+ if self.simulate_housekeep_error:
260
+ raise self.simulate_housekeep_error('Feature housekeeping error')
261
+ _ = self.foo(1)
262
+
263
+ @interface.log_activity()
264
+ def foo(self, x: int) -> int:
265
+ return x + 1
266
+
267
+
268
+ class TestingEventHandler(pg.Object, interface.EventHandler):
269
+ """Testing environment event handler for unit tests."""
270
+
271
+ log_sandbox_status: bool = False
272
+ log_feature_setup: bool = True
273
+ log_session_setup: bool = False
274
+ log_housekeep: bool = False
275
+
276
+ __test__ = False
277
+
278
+ def _on_bound(self) -> None:
279
+ super()._on_bound()
280
+ self._logs = []
281
+
282
+ @property
283
+ def logs(self) -> list[str]:
284
+ return self._logs
285
+
286
+ def _add_message(self, message: str, error: BaseException | None) -> None:
287
+ """Adds a message to the history."""
288
+ if error is None:
289
+ self._logs.append(message)
290
+ else:
291
+ self._logs.append(f'{message} with {error.__class__.__name__}')
292
+
293
+ def on_environment_start(
294
+ self,
295
+ environment: interface.Environment,
296
+ duration: float,
297
+ error: BaseException | None
298
+ ) -> None:
299
+ """Called when the environment is started."""
300
+ assert duration > 0
301
+ self._add_message(f'[{environment.id}] environment started', error)
302
+
303
+ def on_environment_housekeep(
304
+ self,
305
+ environment: interface.Environment,
306
+ counter: int,
307
+ duration: float,
308
+ error: BaseException | None,
309
+ **kwargs
310
+ ) -> None:
311
+ """Called when the environment finishes a round of housekeeping."""
312
+ assert duration > 0
313
+ if self.log_housekeep:
314
+ self._add_message(
315
+ f'[{environment.id}] environment housekeeping {counter}', error
316
+ )
317
+
318
+ def on_environment_shutdown(
319
+ self,
320
+ environment: interface.Environment,
321
+ duration: float,
322
+ lifetime: float,
323
+ error: BaseException | None
324
+ ) -> None:
325
+ """Called when the environment is shutdown."""
326
+ assert duration > 0 and lifetime is not None
327
+ self._add_message(f'[{environment.id}] environment shutdown', error)
328
+
329
+ def on_sandbox_start(
330
+ self,
331
+ sandbox: interface.Sandbox,
332
+ duration: float,
333
+ error: BaseException | None
334
+ ) -> None:
335
+ assert duration > 0
336
+ self._add_message(f'[{sandbox.id}] sandbox started', error)
337
+
338
+ def on_sandbox_status_change(
339
+ self,
340
+ sandbox: interface.Sandbox,
341
+ old_status: interface.Sandbox.Status,
342
+ new_status: interface.Sandbox.Status,
343
+ span: float
344
+ ) -> None:
345
+ assert span > 0
346
+ if self.log_sandbox_status:
347
+ self._add_message(
348
+ f'[{sandbox.id}] {old_status.value} -> {new_status.value}',
349
+ None,
350
+ )
351
+
352
+ def on_sandbox_shutdown(
353
+ self,
354
+ sandbox: interface.Sandbox,
355
+ duration: float,
356
+ lifetime: float,
357
+ error: BaseException | None
358
+ ) -> None:
359
+ assert duration > 0 and lifetime is not None
360
+ self._add_message(f'[{sandbox.id}] sandbox shutdown', error)
361
+
362
+ def on_sandbox_session_start(
363
+ self,
364
+ sandbox: interface.Sandbox,
365
+ session_id: str,
366
+ duration: float,
367
+ error: BaseException | None
368
+ ) -> None:
369
+ """Called when a sandbox session starts."""
370
+ assert duration > 0
371
+ self._add_message(
372
+ f'[{sandbox.id}] session {session_id!r} started', error
373
+ )
374
+
375
+ def on_sandbox_session_end(
376
+ self,
377
+ sandbox: interface.Sandbox,
378
+ session_id: str,
379
+ duration: float,
380
+ lifetime: float,
381
+ error: BaseException | None
382
+ ) -> None:
383
+ """Called when a sandbox session ends."""
384
+ assert duration > 0 and lifetime > 0
385
+ self._add_message(
386
+ f'[{sandbox.id}] session {session_id!r} ended', error
387
+ )
388
+
389
+ def on_sandbox_activity(
390
+ self,
391
+ name: str,
392
+ sandbox: interface.Sandbox,
393
+ session_id: str | None,
394
+ duration: float,
395
+ error: BaseException | None,
396
+ *,
397
+ code: str | None = None,
398
+ **kwargs
399
+ ) -> None:
400
+ """Called when a sandbox activity is performed."""
401
+ del kwargs
402
+ log_id = f'{sandbox.id}@{session_id or "<idle>"}'
403
+ self._add_message(
404
+ f'[{log_id}] {name}: {code}', error
405
+ )
406
+
407
+ def on_sandbox_housekeep(
408
+ self,
409
+ sandbox: interface.Sandbox,
410
+ counter: int,
411
+ duration: float,
412
+ error: BaseException | None,
413
+ **kwargs
414
+ ) -> None:
415
+ assert duration > 0
416
+ if self.log_housekeep:
417
+ self._add_message(
418
+ f'[{sandbox.id}] sandbox housekeeping {counter}', error
419
+ )
420
+
421
+ def on_feature_setup(
422
+ self,
423
+ feature: interface.Feature,
424
+ duration: float,
425
+ error: BaseException | None
426
+ ) -> None:
427
+ """Called when a sandbox feature is setup."""
428
+ assert duration > 0
429
+ if self.log_feature_setup:
430
+ self._add_message(
431
+ f'[{feature.id}] feature setup', error
432
+ )
433
+
434
+ def on_feature_teardown(
435
+ self,
436
+ feature: interface.Feature,
437
+ duration: float,
438
+ error: BaseException | None
439
+ ) -> None:
440
+ """Called when a sandbox feature is teardown."""
441
+ assert duration > 0
442
+ if self.log_feature_setup:
443
+ self._add_message(
444
+ f'[{feature.id}] feature teardown', error
445
+ )
446
+
447
+ def on_feature_setup_session(
448
+ self,
449
+ feature: interface.Feature,
450
+ session_id: str | None,
451
+ duration: float,
452
+ error: BaseException | None
453
+ ) -> None:
454
+ """Called when a sandbox feature is setup."""
455
+ assert duration > 0
456
+ if self.log_session_setup:
457
+ self._add_message(
458
+ f'[{feature.id}@{session_id or "<idle>"}] feature setup session',
459
+ error
460
+ )
461
+
462
+ def on_feature_teardown_session(
463
+ self,
464
+ feature: interface.Feature,
465
+ session_id: str,
466
+ duration: float,
467
+ error: BaseException | None
468
+ ) -> None:
469
+ """Called when a sandbox feature is teardown."""
470
+ assert duration > 0
471
+ if self.log_session_setup:
472
+ self._add_message(
473
+ f'[{feature.id}@{session_id}] feature teardown session', error
474
+ )
475
+
476
+ def on_feature_activity(
477
+ self,
478
+ name: str,
479
+ feature: interface.Feature,
480
+ session_id: str | None,
481
+ duration: float,
482
+ error: BaseException | None,
483
+ *,
484
+ code: str | None = None,
485
+ **kwargs
486
+ ) -> None:
487
+ """Called when a sandbox activity is performed."""
488
+ del kwargs
489
+ log_id = f'{feature.id}@{session_id or "<idle>"}'
490
+ self._add_message(
491
+ f'[{log_id}] {name}: {code}', error
492
+ )
493
+
494
+ def on_feature_housekeep(
495
+ self,
496
+ feature: interface.Feature,
497
+ counter: int,
498
+ duration: float,
499
+ error: BaseException | None,
500
+ **kwargs
501
+ ) -> None:
502
+ """Called when a sandbox feature is housekeeping."""
503
+ assert duration > 0
504
+ if self.log_housekeep:
505
+ self._add_message(
506
+ f'[{feature.id}] feature housekeeping {counter}', error
507
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langfun
3
- Version: 0.1.2.dev202509120804
3
+ Version: 0.1.2.dev202512040805
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -21,14 +21,18 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
21
  Classifier: Topic :: Software Development :: Libraries
22
22
  Description-Content-Type: text/markdown
23
23
  License-File: LICENSE
24
+ Requires-Dist: anyio>=4.7.0
24
25
  Requires-Dist: jinja2>=3.1.2
26
+ Requires-Dist: mcp>=1.17.0
25
27
  Requires-Dist: puremagic>=1.20
26
- Requires-Dist: pyglove>=0.4.5.dev202507140812
28
+ Requires-Dist: pyglove>=0.5.0.dev202510170226
27
29
  Requires-Dist: requests>=2.31.0
28
30
  Provides-Extra: all
31
+ Requires-Dist: anyio>=4.7.0; extra == "all"
29
32
  Requires-Dist: jinja2>=3.1.2; extra == "all"
33
+ Requires-Dist: mcp>=1.17.0; extra == "all"
30
34
  Requires-Dist: puremagic>=1.20; extra == "all"
31
- Requires-Dist: pyglove>=0.4.5.dev202507140812; extra == "all"
35
+ Requires-Dist: pyglove>=0.5.0.dev202510170226; extra == "all"
32
36
  Requires-Dist: requests>=2.31.0; extra == "all"
33
37
  Requires-Dist: google-auth>=2.16.0; extra == "all"
34
38
  Requires-Dist: pillow>=10.0.0; extra == "all"