langfun 0.1.2.dev202501300804__py3-none-any.whl → 0.1.2.dev202502010803__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.
@@ -32,5 +32,9 @@ from langfun.core.coding.python.correction import correct
32
32
  from langfun.core.coding.python.correction import run_with_correction
33
33
  from langfun.core.coding.python.correction import CodeWithError
34
34
 
35
+ from langfun.core.coding.python.sandboxing import Sandbox
36
+ from langfun.core.coding.python.sandboxing import SandboxOutput
37
+ from langfun.core.coding.python.sandboxing import MultiProcessingSandbox
38
+
35
39
  # pylint: enable=g-importing-member
36
40
  # pylint: enable=g-bad-import-order
@@ -0,0 +1,152 @@
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
+ """Python sandboxing."""
15
+
16
+ import abc
17
+ import os
18
+ import tempfile
19
+ from typing import Annotated
20
+
21
+ from langfun.core.coding.python import parsing
22
+ import pyglove as pg
23
+
24
+
25
+ class SandboxOutput(pg.Object):
26
+ """Sandbox output."""
27
+
28
+ stdout: Annotated[
29
+ str,
30
+ 'The stdout of the sandbox execution.'
31
+ ] = ''
32
+
33
+ stderr: Annotated[
34
+ str,
35
+ 'The stderr of the sandbox execution.'
36
+ ] = ''
37
+
38
+
39
+ class Sandbox(pg.Object):
40
+ """Interface for Python sandbox."""
41
+
42
+ def _on_bound(self):
43
+ super()._on_bound()
44
+ self._uploaded_files: dict[str, str] = {}
45
+
46
+ def run(
47
+ self,
48
+ code: str,
49
+ *,
50
+ timeout: int | None = 30,
51
+ **kwargs
52
+ ) -> SandboxOutput:
53
+ """Runs code in the sandbox. Raises pg.coding.CodeError if failed."""
54
+ return self._run(self.normalize_code(code), timeout=timeout, **kwargs)
55
+
56
+ def normalize_code(self, code: str) -> str:
57
+ """Returns normalized code runnable in the sandbox."""
58
+ for original_path, uploaded_path in self._uploaded_files.items():
59
+ code = code.replace(original_path, uploaded_path)
60
+ return parsing.clean(code)
61
+
62
+ @abc.abstractmethod
63
+ def _run(
64
+ self,
65
+ code: str,
66
+ *,
67
+ timeout: int | None = 30,
68
+ **kwargs
69
+ ) -> SandboxOutput:
70
+ """Runs code in the sandbox. Raises pg.coding.CodeError if failed."""
71
+
72
+ def upload(self, path: str) -> str:
73
+ """Uploads a file to the sandbox. Returns the uploaded path."""
74
+ uploaded_path = self._upload(path)
75
+ self._uploaded_files[path] = uploaded_path
76
+ return uploaded_path
77
+
78
+ @abc.abstractmethod
79
+ def _upload(self, path: str) -> str:
80
+ """Uploads a file to the sandbox."""
81
+
82
+ def setup(self) -> None:
83
+ """Sets up the sandbox."""
84
+ self._uploaded_files = {}
85
+ self._setup()
86
+
87
+ def _setup(self) -> None:
88
+ """Sets up the sandbox."""
89
+
90
+ def cleanup(self) -> None:
91
+ """Cleans up the sandbox."""
92
+ self._uploaded_files = {}
93
+ self._cleanup()
94
+
95
+ def _cleanup(self) -> None:
96
+ """Cleans up the sandbox."""
97
+
98
+ def __enter__(self):
99
+ """Enters the sandbox."""
100
+ self.setup()
101
+ return self
102
+
103
+ def __exit__(self, exc_type, exc_value, traceback):
104
+ """Exits the sandbox."""
105
+ self.cleanup()
106
+
107
+
108
+ class MultiProcessingSandbox(Sandbox):
109
+ """Sandbox using multiprocessing."""
110
+
111
+ def _on_bound(self):
112
+ super()._on_bound()
113
+ self._working_dir = None
114
+
115
+ @property
116
+ def working_dir(self) -> str | None:
117
+ """Returns the directory of the sandbox."""
118
+ return self._working_dir
119
+
120
+ def _setup(self) -> None:
121
+ """Sets up the sandbox."""
122
+ self._working_dir = tempfile.TemporaryDirectory()
123
+
124
+ def _cleanup(self) -> None:
125
+ """Cleans up the sandbox."""
126
+ assert self._working_dir is not None
127
+ self._working_dir.cleanup()
128
+
129
+ def _run(
130
+ self,
131
+ code: str,
132
+ *,
133
+ timeout: int | None = 30,
134
+ **kwargs
135
+ ) -> SandboxOutput:
136
+ """Runs code in the sandbox."""
137
+ stdout = pg.coding.run(
138
+ code, returns_stdout=True, sandbox=True, timeout=timeout
139
+ )
140
+ return SandboxOutput(stdout=stdout)
141
+
142
+ def _upload(self, path: str) -> str:
143
+ """Uploads a file to the sandbox."""
144
+ if self._working_dir is None:
145
+ raise ValueError('Sandbox is not set up.')
146
+
147
+ # Upload the file to the sandbox directory.
148
+ uploaded_path = os.path.join(self._working_dir.name, os.path.basename(path))
149
+ with pg.io.open(path, 'r') as r:
150
+ with pg.io.open(uploaded_path, 'w') as w:
151
+ w.write(r.read())
152
+ return uploaded_path
@@ -0,0 +1,62 @@
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
+ import inspect
15
+ import os
16
+ import tempfile
17
+ import unittest
18
+
19
+ from langfun.core.coding.python import sandboxing
20
+ import pyglove as pg
21
+
22
+
23
+ class MultiProcessingSandboxTest(unittest.TestCase):
24
+ """Tests for MultiProcessingSandbox."""
25
+
26
+ def test_basics(self):
27
+ with tempfile.TemporaryDirectory() as dir1:
28
+ input_file = os.path.join(dir1, 'test.json')
29
+ pg.save(pg.Dict(x=1, y=2), input_file)
30
+ with sandboxing.MultiProcessingSandbox() as sandbox:
31
+ self.assertIsNotNone(sandbox.working_dir)
32
+ sandbox_input_file = sandbox.upload(input_file)
33
+ code = (
34
+ f"""
35
+ import pyglove as pg
36
+ print(pg.load({input_file!r}).x)
37
+ """
38
+ )
39
+ self.assertEqual(
40
+ sandbox.normalize_code(code),
41
+ inspect.cleandoc(
42
+ f"""
43
+ import pyglove as pg
44
+ print(pg.load({sandbox_input_file!r}).x)
45
+ """
46
+ ),
47
+ )
48
+ self.assertEqual(sandbox.run(code).stdout, '1\n')
49
+
50
+ def test_bad_code(self):
51
+ with sandboxing.MultiProcessingSandbox() as sandbox:
52
+ with self.assertRaisesRegex(pg.coding.CodeError, '.* is not defined'):
53
+ sandbox.run('print(x)')
54
+
55
+ def test_bad_usages(self):
56
+ sandbox = sandboxing.MultiProcessingSandbox()
57
+ with self.assertRaisesRegex(ValueError, 'Sandbox is not set up.'):
58
+ sandbox.upload('abc.txt')
59
+
60
+
61
+ if __name__ == '__main__':
62
+ unittest.main()
@@ -67,6 +67,7 @@ from langfun.core.llms.vertexai import VertexAIGeminiPro1
67
67
  # OpenAI models.
68
68
  from langfun.core.llms.openai import OpenAI
69
69
 
70
+ from langfun.core.llms.openai import GptO3Mini
70
71
  from langfun.core.llms.openai import GptO1
71
72
  from langfun.core.llms.openai import GptO1Preview
72
73
  from langfun.core.llms.openai import GptO1Preview_20240912
@@ -167,6 +168,7 @@ from langfun.core.llms.groq import GroqMistral_8x7B
167
168
  # DeepSeek models.
168
169
  from langfun.core.llms.deepseek import DeepSeek
169
170
  from langfun.core.llms.deepseek import DeepSeekChat
171
+ from langfun.core.llms.deepseek import DeepSeekReasoner
170
172
 
171
173
  # Whisper models.
172
174
  from langfun.core.llms.groq import GroqWhisper_Large_v3
@@ -25,6 +25,13 @@ SUPPORTED_MODELS_AND_SETTINGS = {
25
25
  # TODO(yifenglu): The RPM and TPM are arbitrary numbers. Update them once DeepSeek provides concrete guidelines.
26
26
  # DeepSeek doesn't control the rate limit at the moment: https://api-docs.deepseek.com/quick_start/rate_limit
27
27
  # The cost is based on: https://api-docs.deepseek.com/quick_start/pricing
28
+ 'deepseek-reasoner': pg.Dict(
29
+ in_service=True,
30
+ rpm=100,
31
+ tpm=1000000,
32
+ cost_per_1k_input_tokens=0.00055,
33
+ cost_per_1k_output_tokens=0.00219,
34
+ ),
28
35
  'deepseek-chat': pg.Dict(
29
36
  in_service=True,
30
37
  rpm=100,
@@ -107,6 +114,16 @@ class DeepSeek(openai_compatible.OpenAICompatible):
107
114
  return [k for k, v in SUPPORTED_MODELS_AND_SETTINGS.items() if v.in_service]
108
115
 
109
116
 
117
+ class DeepSeekReasoner(DeepSeek):
118
+ """DeepSeek Reasoner model.
119
+
120
+ Currently it is powered by DeepSeek-R1 model, 64k input context, 8k max
121
+ output, 32k max CoT output.
122
+ """
123
+
124
+ model = 'deepseek-reasoner'
125
+
126
+
110
127
  class DeepSeekChat(DeepSeek):
111
128
  """DeepSeek Chat model.
112
129
 
@@ -31,6 +31,20 @@ SUPPORTED_MODELS_AND_SETTINGS = {
31
31
  # o1 (preview) models.
32
32
  # Pricing in US dollars, from https://openai.com/api/pricing/
33
33
  # as of 2024-10-10.
34
+ 'o3-mini-2025-01-31': pg.Dict(
35
+ in_service=True,
36
+ rpm=10000,
37
+ tpm=5000000,
38
+ cost_per_1k_input_tokens=0.0011,
39
+ cost_per_1k_output_tokens=0.0044,
40
+ ),
41
+ 'o3-mini': pg.Dict(
42
+ in_service=True,
43
+ rpm=10000,
44
+ tpm=5000000,
45
+ cost_per_1k_input_tokens=0.0011,
46
+ cost_per_1k_output_tokens=0.0044,
47
+ ),
34
48
  'o1': pg.Dict(
35
49
  in_service=True,
36
50
  rpm=10000,
@@ -410,6 +424,14 @@ class OpenAI(openai_compatible.OpenAICompatible):
410
424
  return super()._request_args(options)
411
425
 
412
426
 
427
+ class GptO3Mini(OpenAI):
428
+ """GPT-O3-mini."""
429
+
430
+ model = 'o3-mini'
431
+ multimodal = True
432
+ timeout = None
433
+
434
+
413
435
  class GptO1(OpenAI):
414
436
  """GPT-O1."""
415
437
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: langfun
3
- Version: 0.1.2.dev202501300804
3
+ Version: 0.1.2.dev202502010803
4
4
  Summary: Langfun: Language as Functions.
5
5
  Home-page: https://github.com/google/langfun
6
6
  Author: Langfun Authors
@@ -31,7 +31,7 @@ langfun/core/agentic/action_eval.py,sha256=ZtjTh34S7XPIUqandQ0YwAtzw-S7ofuZ7rRXn
31
31
  langfun/core/agentic/action_eval_test.py,sha256=tRUkWmOE9p0rpNOq19xAY2oDEnYsEEykjg6sUpAwJk0,2832
32
32
  langfun/core/agentic/action_test.py,sha256=Gu7P5XQvzqbKawn2jjyTpWaARzzhzO04KkC1TuBnUnw,4612
33
33
  langfun/core/coding/__init__.py,sha256=5utju_fwEsImaiftx4oXKl9FAM8p281k8-Esdh_-m1w,835
34
- langfun/core/coding/python/__init__.py,sha256=K6jb2le6Hq-aaKqAF4pGW5JRwSyO-RnUTMIxxaVcsNA,1540
34
+ langfun/core/coding/python/__init__.py,sha256=4ByknuoNU-mOIHwHKnTtmo6oD64oMFtlqPlYWmA5Wic,1736
35
35
  langfun/core/coding/python/correction.py,sha256=7zBedlhQKMPA4cfchUMxAOFl6Zl5RqCyllRHGWys40s,7092
36
36
  langfun/core/coding/python/correction_test.py,sha256=sie88lAbsV15bvkRcYC88pgToybZYXI32Xmg_ym5V1A,4175
37
37
  langfun/core/coding/python/execution.py,sha256=tsXnJ-11RqNDro0C-6LwbHkqPuNVJ_cLxAq8-C5Wz20,4442
@@ -40,6 +40,8 @@ langfun/core/coding/python/generation.py,sha256=sA6t97qBflO3WtuL9axknEVQPgqXHeqa
40
40
  langfun/core/coding/python/generation_test.py,sha256=dcF5ef1UApzRfTpvICiChpynkzZ1mDsE0DvH0iMpTvg,2743
41
41
  langfun/core/coding/python/parsing.py,sha256=jvGDIwoaY3mdGXeFhjP27w0ukO0TtdCC7G4ODVNp8S4,4554
42
42
  langfun/core/coding/python/parsing_test.py,sha256=PIexYpSEhgNaSd4T6QYWzWHzm3sL4VhQJ4dhdvJAQk8,5005
43
+ langfun/core/coding/python/sandboxing.py,sha256=yeEdydMkfHk3Hj3-5ykeROpYyLbRfZ4BwGWJYvFBmSI,4001
44
+ langfun/core/coding/python/sandboxing_test.py,sha256=H_0_pd-_uS-ci5yYhmDTR6-hyzosAFkExziAHndfdDo,2023
43
45
  langfun/core/eval/__init__.py,sha256=OEXr1ZRuvLuhJJfuQ1ZWQ-SvYzjyrtiAAEogYaB7E6o,1933
44
46
  langfun/core/eval/base.py,sha256=XXerMVkK4wREo7K1_aCyay6vDjw3mfs389XThAdzv50,75768
45
47
  langfun/core/eval/base_test.py,sha256=-LsIV9DXlDal0EnOlaWpibJvfef0NbxtZAm0OH_abAE,27189
@@ -71,12 +73,12 @@ langfun/core/eval/v2/reporting.py,sha256=QOp5jX761Esvi5w_UIRLDqPY_XRO6ru02-DOrdq
71
73
  langfun/core/eval/v2/reporting_test.py,sha256=UmYSAQvD3AIXsSyWQ-WD2uLtEISYpmBeoKY5u5Qwc8E,5696
72
74
  langfun/core/eval/v2/runners.py,sha256=DKEmSlGXjOXKWFdBhTpLy7tMsBHZHd1Brl3hWIngsSQ,15931
73
75
  langfun/core/eval/v2/runners_test.py,sha256=A37fKK2MvAVTiShsg_laluJzJ9AuAQn52k7HPbfD0Ks,11666
74
- langfun/core/llms/__init__.py,sha256=50mJagAgkIhMwhOyHxGq_O5st4HhpnE-okeYzc7GU6c,7667
76
+ langfun/core/llms/__init__.py,sha256=PKkEVyGBSMc1CZOh8vVN-NCxBPDv3Sctt0fsN7NU1EU,7770
75
77
  langfun/core/llms/anthropic.py,sha256=z_DWDpR1VKNzv6wq-9CXLzWdqCDXRKuVFacJNpgBqAs,10826
76
78
  langfun/core/llms/anthropic_test.py,sha256=zZ2eSP8hhVv-RDSWxT7wX-NS5DfGfQmCjS9P0pusAHM,6556
77
79
  langfun/core/llms/compositional.py,sha256=csW_FLlgL-tpeyCOTVvfUQkMa_zCN5Y2I-YbSNuK27U,2872
78
80
  langfun/core/llms/compositional_test.py,sha256=4eTnOer-DncRKGaIJW2ZQQMLnt5r2R0UIx_DYOvGAQo,2027
79
- langfun/core/llms/deepseek.py,sha256=Y7DlLUWrukbPVyBMesppd-m75Q-PxD0b3KnMKaoY_8I,3744
81
+ langfun/core/llms/deepseek.py,sha256=9EbuNrngd5BwpsvsEfkW2XQdq3K23S3-jlI8RbMNZF4,4141
80
82
  langfun/core/llms/deepseek_test.py,sha256=dS72i52bwMpCN4dJDvpJI59AnNChpwxS5eYYFrhGh90,1843
81
83
  langfun/core/llms/fake.py,sha256=gCHBYBLvBCsC78HI1hpoqXCS-p1FMTgY1P1qh_sGBPk,3070
82
84
  langfun/core/llms/fake_test.py,sha256=2h13qkwEz_JR0mtUDPxdAhQo7MueXaFSwsD2DIRDW9g,7653
@@ -88,7 +90,7 @@ langfun/core/llms/groq.py,sha256=oGxyyCi5TtMVu2POdO8pXS7pK4Es56FtqjghZIGYopc,757
88
90
  langfun/core/llms/groq_test.py,sha256=9aOD3nO4dEoH57B-5iOr5DQjG0vyv1jzFtAe7HfoiNg,1963
89
91
  langfun/core/llms/llama_cpp.py,sha256=Z7P3gc4xeIjc2bX0Ey1y5EUYJVMnMa2Q67PZ9iye9sE,1409
90
92
  langfun/core/llms/llama_cpp_test.py,sha256=wfTO7nmUwL65U2kK9P9fcMt92JjNDuVia4G1E7znf_4,1086
91
- langfun/core/llms/openai.py,sha256=CHUg8c0FE30LZkhvj0Kc8w0oqckbZhrp45GA94HWPs8,16614
93
+ langfun/core/llms/openai.py,sha256=bIJae2UDO_uwoZGZRYP58GM4FdP4w9qjQhBIYJyGH34,17089
92
94
  langfun/core/llms/openai_compatible.py,sha256=MF9JCc0uTPkIK95uvQTMIBXk4z_xKQMZqQHFaVmXwcA,5898
93
95
  langfun/core/llms/openai_compatible_test.py,sha256=0uFYhCiuHo2Wrlgj16-GRG6rW8P6EaHCUguL3jS0QJ8,16708
94
96
  langfun/core/llms/openai_test.py,sha256=m85YjGCvWvV5ZYagjC0FqI0FcqyCEVCbUUs8Wm3iUrc,2475
@@ -146,8 +148,8 @@ langfun/core/templates/demonstration.py,sha256=vCrgYubdZM5Umqcgp8NUVGXgr4P_c-fik
146
148
  langfun/core/templates/demonstration_test.py,sha256=SafcDQ0WgI7pw05EmPI2S4v1t3ABKzup8jReCljHeK4,2162
147
149
  langfun/core/templates/selfplay.py,sha256=yhgrJbiYwq47TgzThmHrDQTF4nDrTI09CWGhuQPNv-s,2273
148
150
  langfun/core/templates/selfplay_test.py,sha256=Ot__1P1M8oJfoTp-M9-PQ6HUXqZKyMwvZ5f7yQ3yfyM,2326
149
- langfun-0.1.2.dev202501300804.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
150
- langfun-0.1.2.dev202501300804.dist-info/METADATA,sha256=sfy8YuZ4CkHAAwZCgEhkMUWQGumIpcO4IzzsfldRz_0,8172
151
- langfun-0.1.2.dev202501300804.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
152
- langfun-0.1.2.dev202501300804.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
153
- langfun-0.1.2.dev202501300804.dist-info/RECORD,,
151
+ langfun-0.1.2.dev202502010803.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
152
+ langfun-0.1.2.dev202502010803.dist-info/METADATA,sha256=sDqvjFmjKbCvYCNHOc4te_JsKdrhnzWgmPx5wwSI_GM,8172
153
+ langfun-0.1.2.dev202502010803.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
154
+ langfun-0.1.2.dev202502010803.dist-info/top_level.txt,sha256=RhlEkHxs1qtzmmtWSwYoLVJAc1YrbPtxQ52uh8Z9VvY,8
155
+ langfun-0.1.2.dev202502010803.dist-info/RECORD,,