langfun 0.1.2.dev202509120804__py3-none-any.whl → 0.1.2.dev202512150805__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.
- langfun/__init__.py +1 -1
- langfun/core/__init__.py +7 -1
- langfun/core/agentic/__init__.py +8 -1
- langfun/core/agentic/action.py +740 -112
- langfun/core/agentic/action_eval.py +9 -2
- langfun/core/agentic/action_test.py +189 -24
- langfun/core/async_support.py +104 -5
- langfun/core/async_support_test.py +23 -0
- langfun/core/coding/python/correction.py +19 -9
- langfun/core/coding/python/execution.py +14 -12
- langfun/core/coding/python/generation.py +21 -16
- langfun/core/coding/python/sandboxing.py +23 -3
- langfun/core/component.py +42 -3
- langfun/core/concurrent.py +70 -6
- langfun/core/concurrent_test.py +9 -2
- langfun/core/console.py +1 -1
- langfun/core/data/conversion/anthropic.py +12 -3
- langfun/core/data/conversion/anthropic_test.py +8 -6
- langfun/core/data/conversion/gemini.py +11 -2
- langfun/core/data/conversion/gemini_test.py +48 -9
- langfun/core/data/conversion/openai.py +145 -31
- langfun/core/data/conversion/openai_test.py +161 -17
- langfun/core/eval/base.py +48 -44
- langfun/core/eval/base_test.py +5 -5
- langfun/core/eval/matching.py +5 -2
- langfun/core/eval/patching.py +3 -3
- langfun/core/eval/scoring.py +4 -3
- langfun/core/eval/v2/__init__.py +3 -0
- langfun/core/eval/v2/checkpointing.py +148 -46
- langfun/core/eval/v2/checkpointing_test.py +9 -2
- langfun/core/eval/v2/config_saver.py +37 -0
- langfun/core/eval/v2/config_saver_test.py +36 -0
- langfun/core/eval/v2/eval_test_helper.py +104 -3
- langfun/core/eval/v2/evaluation.py +102 -19
- langfun/core/eval/v2/evaluation_test.py +9 -3
- langfun/core/eval/v2/example.py +50 -40
- langfun/core/eval/v2/example_test.py +16 -8
- langfun/core/eval/v2/experiment.py +95 -20
- langfun/core/eval/v2/experiment_test.py +19 -0
- langfun/core/eval/v2/metric_values.py +31 -3
- langfun/core/eval/v2/metric_values_test.py +32 -0
- langfun/core/eval/v2/metrics.py +157 -44
- langfun/core/eval/v2/metrics_test.py +39 -18
- langfun/core/eval/v2/progress.py +31 -1
- langfun/core/eval/v2/progress_test.py +27 -0
- langfun/core/eval/v2/progress_tracking.py +13 -5
- langfun/core/eval/v2/progress_tracking_test.py +9 -1
- langfun/core/eval/v2/reporting.py +88 -71
- langfun/core/eval/v2/reporting_test.py +24 -6
- langfun/core/eval/v2/runners/__init__.py +30 -0
- langfun/core/eval/v2/{runners.py → runners/base.py} +73 -180
- langfun/core/eval/v2/runners/beam.py +354 -0
- langfun/core/eval/v2/runners/beam_test.py +153 -0
- langfun/core/eval/v2/runners/ckpt_monitor.py +350 -0
- langfun/core/eval/v2/runners/ckpt_monitor_test.py +213 -0
- langfun/core/eval/v2/runners/debug.py +40 -0
- langfun/core/eval/v2/runners/debug_test.py +76 -0
- langfun/core/eval/v2/runners/parallel.py +243 -0
- langfun/core/eval/v2/runners/parallel_test.py +182 -0
- langfun/core/eval/v2/runners/sequential.py +47 -0
- langfun/core/eval/v2/runners/sequential_test.py +169 -0
- langfun/core/langfunc.py +45 -130
- langfun/core/langfunc_test.py +7 -5
- langfun/core/language_model.py +189 -36
- langfun/core/language_model_test.py +54 -3
- langfun/core/llms/__init__.py +14 -1
- langfun/core/llms/anthropic.py +157 -2
- langfun/core/llms/azure_openai.py +29 -17
- langfun/core/llms/cache/base.py +25 -3
- langfun/core/llms/cache/in_memory.py +48 -7
- langfun/core/llms/cache/in_memory_test.py +14 -4
- langfun/core/llms/compositional.py +25 -1
- langfun/core/llms/deepseek.py +30 -2
- langfun/core/llms/fake.py +32 -1
- langfun/core/llms/gemini.py +90 -12
- langfun/core/llms/gemini_test.py +110 -0
- langfun/core/llms/google_genai.py +52 -1
- langfun/core/llms/groq.py +28 -3
- langfun/core/llms/llama_cpp.py +23 -4
- langfun/core/llms/openai.py +120 -3
- langfun/core/llms/openai_compatible.py +148 -27
- langfun/core/llms/openai_compatible_test.py +207 -20
- langfun/core/llms/openai_test.py +0 -2
- langfun/core/llms/rest.py +16 -1
- langfun/core/llms/vertexai.py +78 -8
- langfun/core/logging.py +1 -1
- langfun/core/mcp/__init__.py +10 -0
- langfun/core/mcp/client.py +177 -0
- langfun/core/mcp/client_test.py +71 -0
- langfun/core/mcp/session.py +241 -0
- langfun/core/mcp/session_test.py +54 -0
- langfun/core/mcp/testing/simple_mcp_client.py +33 -0
- langfun/core/mcp/testing/simple_mcp_server.py +33 -0
- langfun/core/mcp/tool.py +254 -0
- langfun/core/mcp/tool_test.py +197 -0
- langfun/core/memory.py +1 -0
- langfun/core/message.py +160 -55
- langfun/core/message_test.py +65 -81
- langfun/core/modalities/__init__.py +8 -0
- langfun/core/modalities/audio.py +21 -1
- langfun/core/modalities/image.py +73 -3
- langfun/core/modalities/image_test.py +116 -0
- langfun/core/modalities/mime.py +78 -4
- langfun/core/modalities/mime_test.py +59 -0
- langfun/core/modalities/pdf.py +19 -1
- langfun/core/modalities/video.py +21 -1
- langfun/core/modality.py +167 -29
- langfun/core/modality_test.py +42 -12
- langfun/core/natural_language.py +1 -1
- langfun/core/sampling.py +4 -4
- langfun/core/sampling_test.py +20 -4
- langfun/core/structured/__init__.py +2 -24
- langfun/core/structured/completion.py +34 -44
- langfun/core/structured/completion_test.py +23 -43
- langfun/core/structured/description.py +54 -50
- langfun/core/structured/function_generation.py +29 -12
- langfun/core/structured/mapping.py +81 -37
- langfun/core/structured/parsing.py +95 -79
- langfun/core/structured/parsing_test.py +0 -3
- langfun/core/structured/querying.py +230 -154
- langfun/core/structured/querying_test.py +69 -33
- langfun/core/structured/schema/__init__.py +49 -0
- langfun/core/structured/schema/base.py +664 -0
- langfun/core/structured/schema/base_test.py +531 -0
- langfun/core/structured/schema/json.py +174 -0
- langfun/core/structured/schema/json_test.py +121 -0
- langfun/core/structured/schema/python.py +316 -0
- langfun/core/structured/schema/python_test.py +410 -0
- langfun/core/structured/schema_generation.py +33 -14
- langfun/core/structured/scoring.py +47 -36
- langfun/core/structured/tokenization.py +26 -11
- langfun/core/subscription.py +2 -2
- langfun/core/template.py +175 -50
- langfun/core/template_test.py +123 -17
- langfun/env/__init__.py +43 -0
- langfun/env/base_environment.py +827 -0
- langfun/env/base_environment_test.py +473 -0
- langfun/env/base_feature.py +304 -0
- langfun/env/base_feature_test.py +228 -0
- langfun/env/base_sandbox.py +842 -0
- langfun/env/base_sandbox_test.py +1235 -0
- langfun/env/event_handlers/__init__.py +14 -0
- langfun/env/event_handlers/chain.py +233 -0
- langfun/env/event_handlers/chain_test.py +253 -0
- langfun/env/event_handlers/event_logger.py +472 -0
- langfun/env/event_handlers/event_logger_test.py +304 -0
- langfun/env/event_handlers/metric_writer.py +726 -0
- langfun/env/event_handlers/metric_writer_test.py +214 -0
- langfun/env/interface.py +1640 -0
- langfun/env/interface_test.py +153 -0
- langfun/env/load_balancers.py +59 -0
- langfun/env/load_balancers_test.py +141 -0
- langfun/env/test_utils.py +507 -0
- {langfun-0.1.2.dev202509120804.dist-info → langfun-0.1.2.dev202512150805.dist-info}/METADATA +7 -3
- langfun-0.1.2.dev202512150805.dist-info/RECORD +217 -0
- langfun/core/eval/v2/runners_test.py +0 -343
- langfun/core/structured/schema.py +0 -987
- langfun/core/structured/schema_test.py +0 -982
- langfun-0.1.2.dev202509120804.dist-info/RECORD +0 -172
- {langfun-0.1.2.dev202509120804.dist-info → langfun-0.1.2.dev202512150805.dist-info}/WHEEL +0 -0
- {langfun-0.1.2.dev202509120804.dist-info → langfun-0.1.2.dev202512150805.dist-info}/licenses/LICENSE +0 -0
- {langfun-0.1.2.dev202509120804.dist-info → langfun-0.1.2.dev202512150805.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
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
|
+
|
|
15
|
+
import contextlib
|
|
16
|
+
import io
|
|
17
|
+
from typing import Iterator
|
|
18
|
+
import unittest
|
|
19
|
+
|
|
20
|
+
from langfun.env import interface
|
|
21
|
+
from langfun.env import test_utils
|
|
22
|
+
from langfun.env.event_handlers import event_logger as event_logger_lib
|
|
23
|
+
import pyglove as pg
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class EventLoggerTest(unittest.TestCase):
|
|
27
|
+
|
|
28
|
+
LOGGER_CLS = event_logger_lib.EventLogger
|
|
29
|
+
|
|
30
|
+
@contextlib.contextmanager
|
|
31
|
+
def _capture_logs(self, test_name: str) -> Iterator[io.StringIO]:
|
|
32
|
+
try:
|
|
33
|
+
stream = io.StringIO()
|
|
34
|
+
with pg.logging.redirect_stream(
|
|
35
|
+
stream, name=f'{self.LOGGER_CLS.__name__}.{test_name}'
|
|
36
|
+
):
|
|
37
|
+
yield stream
|
|
38
|
+
finally:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
def _test_logger(
|
|
42
|
+
self,
|
|
43
|
+
*,
|
|
44
|
+
test_name: str,
|
|
45
|
+
expected_substrings: list[str],
|
|
46
|
+
unexpected_substrings: list[str],
|
|
47
|
+
error_only: bool = False,
|
|
48
|
+
regex: str | None = None,
|
|
49
|
+
sandbox_status: bool = True,
|
|
50
|
+
session_status: bool = True,
|
|
51
|
+
feature_status: bool = True,
|
|
52
|
+
housekeep_status: bool = True,
|
|
53
|
+
stats_report_interval: float = 1.0,
|
|
54
|
+
):
|
|
55
|
+
event_logger = self.LOGGER_CLS(
|
|
56
|
+
error_only=error_only,
|
|
57
|
+
regex=regex,
|
|
58
|
+
sandbox_status=sandbox_status,
|
|
59
|
+
session_status=session_status,
|
|
60
|
+
feature_status=feature_status,
|
|
61
|
+
housekeep_status=housekeep_status,
|
|
62
|
+
stats_report_interval=stats_report_interval,
|
|
63
|
+
)
|
|
64
|
+
env = test_utils.TestingEnvironment(
|
|
65
|
+
features={
|
|
66
|
+
'test_feature1': test_utils.TestingFeature(housekeep_interval=0),
|
|
67
|
+
'test_feature2': test_utils.TestingFeature(housekeep_interval=None),
|
|
68
|
+
},
|
|
69
|
+
pool_size=2,
|
|
70
|
+
outage_grace_period=0,
|
|
71
|
+
outage_retry_interval=0,
|
|
72
|
+
housekeep_interval=1.0,
|
|
73
|
+
sandbox_keepalive_interval=1.0,
|
|
74
|
+
event_handler=event_logger,
|
|
75
|
+
)
|
|
76
|
+
with self._capture_logs(test_name) as stream:
|
|
77
|
+
with env:
|
|
78
|
+
with env.sandbox(session_id='session1') as sb:
|
|
79
|
+
self.assertEqual(sb.test_feature1.num_shell_calls(), 4)
|
|
80
|
+
|
|
81
|
+
with self.assertRaises(interface.SandboxStateError):
|
|
82
|
+
with env.sandbox(session_id='session2') as sb:
|
|
83
|
+
sb.shell('echo "bar"', raise_error=RuntimeError)
|
|
84
|
+
|
|
85
|
+
stdout = stream.getvalue()
|
|
86
|
+
for substring in expected_substrings:
|
|
87
|
+
self.assertIn(substring, stdout)
|
|
88
|
+
for substring in unexpected_substrings:
|
|
89
|
+
self.assertNotIn(substring, stdout)
|
|
90
|
+
|
|
91
|
+
def test_all_flags_on(self):
|
|
92
|
+
return self._test_logger(
|
|
93
|
+
test_name='test_all_flags_on',
|
|
94
|
+
expected_substrings=[
|
|
95
|
+
'environment starting',
|
|
96
|
+
'environment started',
|
|
97
|
+
'environment shutdown',
|
|
98
|
+
'environment housekeeping',
|
|
99
|
+
'environment stats',
|
|
100
|
+
'sandbox started',
|
|
101
|
+
'-> acquired',
|
|
102
|
+
'sandbox shutdown',
|
|
103
|
+
'sandbox housekeeping',
|
|
104
|
+
'feature setup complete',
|
|
105
|
+
'feature teardown complete',
|
|
106
|
+
'/test_feature1] feature housekeeping',
|
|
107
|
+
'sandbox session started',
|
|
108
|
+
'sandbox session ended',
|
|
109
|
+
'sandbox call \'shell\'',
|
|
110
|
+
'RuntimeError',
|
|
111
|
+
],
|
|
112
|
+
unexpected_substrings=[
|
|
113
|
+
'/test_feature2] feature housekeeping',
|
|
114
|
+
],
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def test_error_only(self):
|
|
118
|
+
return self._test_logger(
|
|
119
|
+
test_name='test_error_only',
|
|
120
|
+
expected_substrings=[
|
|
121
|
+
'session ended',
|
|
122
|
+
'call \'shell\'',
|
|
123
|
+
'RuntimeError',
|
|
124
|
+
],
|
|
125
|
+
unexpected_substrings=[
|
|
126
|
+
'environment starting',
|
|
127
|
+
'environment started',
|
|
128
|
+
'environment shutting down',
|
|
129
|
+
'environment shutdown',
|
|
130
|
+
'environment housekeeping',
|
|
131
|
+
'sandbox started',
|
|
132
|
+
'-> acquired',
|
|
133
|
+
'sandbox shutdown',
|
|
134
|
+
'feature setup complete',
|
|
135
|
+
'feature teardown complete',
|
|
136
|
+
'session started',
|
|
137
|
+
],
|
|
138
|
+
error_only=True,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def test_regex(self):
|
|
142
|
+
return self._test_logger(
|
|
143
|
+
test_name='test_regex',
|
|
144
|
+
expected_substrings=[
|
|
145
|
+
'environment starting',
|
|
146
|
+
'environment started',
|
|
147
|
+
'environment shutting down',
|
|
148
|
+
'environment shutdown',
|
|
149
|
+
'environment housekeeping',
|
|
150
|
+
],
|
|
151
|
+
unexpected_substrings=[
|
|
152
|
+
'sandbox started',
|
|
153
|
+
'-> acquired',
|
|
154
|
+
'sandbox shutdown',
|
|
155
|
+
'feature setup complete',
|
|
156
|
+
'feature teardown complete',
|
|
157
|
+
'sandbox session started',
|
|
158
|
+
'sandbox session ended',
|
|
159
|
+
'sandbox call \'shell\'',
|
|
160
|
+
'RuntimeError',
|
|
161
|
+
],
|
|
162
|
+
regex='.*environment.*',
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
def test_sandbox_status_off(self):
|
|
166
|
+
return self._test_logger(
|
|
167
|
+
test_name='test_sandbox_status_off',
|
|
168
|
+
expected_substrings=[
|
|
169
|
+
'environment starting',
|
|
170
|
+
'environment started',
|
|
171
|
+
'environment shutting down',
|
|
172
|
+
'environment shutdown',
|
|
173
|
+
'environment housekeeping',
|
|
174
|
+
'feature setup complete',
|
|
175
|
+
'feature teardown complete',
|
|
176
|
+
'feature housekeeping',
|
|
177
|
+
'sandbox session started',
|
|
178
|
+
'sandbox session ended',
|
|
179
|
+
'sandbox call \'shell\'',
|
|
180
|
+
'RuntimeError',
|
|
181
|
+
],
|
|
182
|
+
unexpected_substrings=[
|
|
183
|
+
'sandbox started',
|
|
184
|
+
'-> acquired',
|
|
185
|
+
'sandbox shutdown',
|
|
186
|
+
'sandbox housekeeping',
|
|
187
|
+
],
|
|
188
|
+
sandbox_status=False,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def test_feature_status_off(self):
|
|
192
|
+
return self._test_logger(
|
|
193
|
+
test_name='test_feature_status_off',
|
|
194
|
+
expected_substrings=[
|
|
195
|
+
'environment starting',
|
|
196
|
+
'environment started',
|
|
197
|
+
'environment shutting down',
|
|
198
|
+
'environment shutdown',
|
|
199
|
+
'environment housekeeping',
|
|
200
|
+
'environment stats',
|
|
201
|
+
'sandbox started',
|
|
202
|
+
'-> acquired',
|
|
203
|
+
'sandbox shutdown',
|
|
204
|
+
'sandbox housekeeping',
|
|
205
|
+
'sandbox session started',
|
|
206
|
+
'sandbox session ended',
|
|
207
|
+
'sandbox call \'shell\'',
|
|
208
|
+
'RuntimeError',
|
|
209
|
+
],
|
|
210
|
+
unexpected_substrings=[
|
|
211
|
+
'feature setup complete',
|
|
212
|
+
'feature teardown complete',
|
|
213
|
+
'feature housekeeping',
|
|
214
|
+
],
|
|
215
|
+
feature_status=False,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
def test_session_status_off(self):
|
|
219
|
+
return self._test_logger(
|
|
220
|
+
test_name='test_session_status_off',
|
|
221
|
+
expected_substrings=[
|
|
222
|
+
'environment starting',
|
|
223
|
+
'environment started',
|
|
224
|
+
'environment shutting down',
|
|
225
|
+
'environment shutdown',
|
|
226
|
+
'environment stats',
|
|
227
|
+
'environment housekeeping',
|
|
228
|
+
'sandbox started',
|
|
229
|
+
'-> acquired',
|
|
230
|
+
'sandbox shutdown',
|
|
231
|
+
'sandbox housekeeping',
|
|
232
|
+
'feature setup complete',
|
|
233
|
+
'feature teardown complete',
|
|
234
|
+
'feature housekeeping',
|
|
235
|
+
'sandbox call \'shell\'',
|
|
236
|
+
'RuntimeError',
|
|
237
|
+
],
|
|
238
|
+
unexpected_substrings=[
|
|
239
|
+
'sandbox session started',
|
|
240
|
+
'sandbox session ended',
|
|
241
|
+
],
|
|
242
|
+
session_status=False,
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
def test_housekeep_status_off(self):
|
|
246
|
+
return self._test_logger(
|
|
247
|
+
test_name='test_housekeep_status_off',
|
|
248
|
+
expected_substrings=[
|
|
249
|
+
'environment starting',
|
|
250
|
+
'environment started',
|
|
251
|
+
'environment shutting down',
|
|
252
|
+
'environment shutdown',
|
|
253
|
+
'environment stats',
|
|
254
|
+
'sandbox started',
|
|
255
|
+
'-> acquired',
|
|
256
|
+
'sandbox shutdown',
|
|
257
|
+
'feature setup complete',
|
|
258
|
+
'feature teardown complete',
|
|
259
|
+
'sandbox session started',
|
|
260
|
+
'sandbox session ended',
|
|
261
|
+
'sandbox call \'shell\'',
|
|
262
|
+
'RuntimeError',
|
|
263
|
+
],
|
|
264
|
+
unexpected_substrings=[
|
|
265
|
+
'environment housekeeping',
|
|
266
|
+
'sandbox housekeeping',
|
|
267
|
+
'feature housekeeping',
|
|
268
|
+
],
|
|
269
|
+
housekeep_status=False,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
def test_no_stats_report(self):
|
|
273
|
+
return self._test_logger(
|
|
274
|
+
test_name='test_housekeep_status_off',
|
|
275
|
+
expected_substrings=[
|
|
276
|
+
'environment starting',
|
|
277
|
+
'environment started',
|
|
278
|
+
'environment shutting down',
|
|
279
|
+
'environment shutdown',
|
|
280
|
+
'environment housekeeping',
|
|
281
|
+
],
|
|
282
|
+
unexpected_substrings=[
|
|
283
|
+
'environment stats',
|
|
284
|
+
],
|
|
285
|
+
stats_report_interval=None,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class ConsoleEventLoggerTest(EventLoggerTest):
|
|
290
|
+
|
|
291
|
+
LOGGER_CLS = event_logger_lib.ConsoleEventLogger
|
|
292
|
+
|
|
293
|
+
@contextlib.contextmanager
|
|
294
|
+
def _capture_logs(self, test_name: str) -> Iterator[io.StringIO]:
|
|
295
|
+
try:
|
|
296
|
+
stream = io.StringIO()
|
|
297
|
+
with contextlib.redirect_stdout(stream):
|
|
298
|
+
yield stream
|
|
299
|
+
finally:
|
|
300
|
+
pass
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
if __name__ == '__main__':
|
|
304
|
+
unittest.main()
|