aip-agents-binary 0.6.5__py3-none-macosx_13_0_arm64.whl → 0.6.6__py3-none-macosx_13_0_arm64.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.
- aip_agents/agent/langgraph_react_agent.py +66 -19
- aip_agents/examples/hello_world_ptc_custom_tools.py +83 -0
- aip_agents/examples/hello_world_ptc_custom_tools.pyi +7 -0
- aip_agents/examples/tools/multiply_tool.py +43 -0
- aip_agents/examples/tools/multiply_tool.pyi +18 -0
- aip_agents/ptc/__init__.py +42 -3
- aip_agents/ptc/__init__.pyi +5 -1
- aip_agents/ptc/custom_tools.py +473 -0
- aip_agents/ptc/custom_tools.pyi +184 -0
- aip_agents/ptc/custom_tools_payload.py +400 -0
- aip_agents/ptc/custom_tools_payload.pyi +31 -0
- aip_agents/ptc/custom_tools_templates/__init__.py +1 -0
- aip_agents/ptc/custom_tools_templates/__init__.pyi +0 -0
- aip_agents/ptc/custom_tools_templates/custom_build_function.py.template +23 -0
- aip_agents/ptc/custom_tools_templates/custom_init.py.template +15 -0
- aip_agents/ptc/custom_tools_templates/custom_invoke.py.template +60 -0
- aip_agents/ptc/custom_tools_templates/custom_registry.py.template +87 -0
- aip_agents/ptc/custom_tools_templates/custom_sources_init.py.template +7 -0
- aip_agents/ptc/custom_tools_templates/custom_wrapper.py.template +19 -0
- aip_agents/ptc/exceptions.py +18 -0
- aip_agents/ptc/exceptions.pyi +15 -0
- aip_agents/ptc/executor.py +151 -33
- aip_agents/ptc/executor.pyi +34 -8
- aip_agents/ptc/naming.py +13 -1
- aip_agents/ptc/naming.pyi +9 -0
- aip_agents/ptc/prompt_builder.py +118 -16
- aip_agents/ptc/prompt_builder.pyi +12 -8
- aip_agents/ptc/sandbox_bridge.py +206 -8
- aip_agents/ptc/sandbox_bridge.pyi +18 -5
- aip_agents/ptc/tool_def_helpers.py +101 -0
- aip_agents/ptc/tool_def_helpers.pyi +38 -0
- aip_agents/ptc/tool_enrichment.py +163 -0
- aip_agents/ptc/tool_enrichment.pyi +60 -0
- aip_agents/sandbox/defaults.py +197 -1
- aip_agents/sandbox/defaults.pyi +28 -0
- aip_agents/sandbox/e2b_runtime.py +28 -0
- aip_agents/sandbox/e2b_runtime.pyi +7 -1
- aip_agents/sandbox/template_builder.py +2 -2
- aip_agents/tools/execute_ptc_code.py +59 -10
- aip_agents/tools/execute_ptc_code.pyi +5 -5
- {aip_agents_binary-0.6.5.dist-info → aip_agents_binary-0.6.6.dist-info}/METADATA +3 -3
- {aip_agents_binary-0.6.5.dist-info → aip_agents_binary-0.6.6.dist-info}/RECORD +44 -24
- {aip_agents_binary-0.6.5.dist-info → aip_agents_binary-0.6.6.dist-info}/WHEEL +0 -0
- {aip_agents_binary-0.6.5.dist-info → aip_agents_binary-0.6.6.dist-info}/top_level.txt +0 -0
aip_agents/ptc/executor.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
"""PTC Executor implementations
|
|
1
|
+
"""PTC Executor implementations.
|
|
2
2
|
|
|
3
|
-
This module provides the sandboxed executor for Programmatic Tool Calling
|
|
4
|
-
with MCP tools.
|
|
3
|
+
This module provides the sandboxed executor for Programmatic Tool Calling.
|
|
5
4
|
|
|
6
5
|
Authors:
|
|
7
6
|
Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
@@ -9,9 +8,12 @@ Authors:
|
|
|
9
8
|
|
|
10
9
|
from __future__ import annotations
|
|
11
10
|
|
|
11
|
+
import asyncio
|
|
12
12
|
from dataclasses import dataclass, field
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
13
14
|
|
|
14
15
|
from aip_agents.mcp.client.base_mcp_client import BaseMCPClient
|
|
16
|
+
from aip_agents.ptc.custom_tools import PTCCustomToolConfig
|
|
15
17
|
from aip_agents.ptc.exceptions import PTCToolError
|
|
16
18
|
from aip_agents.ptc.prompt_builder import PromptConfig
|
|
17
19
|
from aip_agents.sandbox.defaults import DEFAULT_PTC_PACKAGES, DEFAULT_PTC_TEMPLATE
|
|
@@ -30,18 +32,22 @@ except ImportError:
|
|
|
30
32
|
|
|
31
33
|
logger = get_logger(__name__)
|
|
32
34
|
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from aip_agents.ptc.payload import SandboxPayload
|
|
37
|
+
|
|
33
38
|
|
|
34
39
|
@dataclass
|
|
35
40
|
class PTCSandboxConfig:
|
|
36
|
-
"""Configuration for PTC sandbox executor
|
|
41
|
+
"""Configuration for PTC sandbox executor.
|
|
37
42
|
|
|
38
43
|
Attributes:
|
|
39
44
|
enabled: Whether PTC is enabled. When False, PTC is disabled.
|
|
40
45
|
default_tool_timeout: Default timeout per tool call in seconds.
|
|
41
46
|
sandbox_template: Optional E2B sandbox template ID.
|
|
42
47
|
sandbox_timeout: Sandbox execution timeout in seconds (hard cap/TTL).
|
|
43
|
-
ptc_packages: List of packages to install in sandbox.
|
|
48
|
+
ptc_packages: List of packages to install in sandbox. Defaults to DEFAULT_PTC_PACKAGES.
|
|
44
49
|
prompt: Prompt configuration for PTC usage guidance.
|
|
50
|
+
custom_tools: Configuration for custom LangChain tools in sandbox.
|
|
45
51
|
"""
|
|
46
52
|
|
|
47
53
|
enabled: bool = False
|
|
@@ -50,31 +56,46 @@ class PTCSandboxConfig:
|
|
|
50
56
|
sandbox_timeout: float = 300.0
|
|
51
57
|
ptc_packages: list[str] | None = field(default_factory=lambda: list(DEFAULT_PTC_PACKAGES))
|
|
52
58
|
prompt: PromptConfig = field(default_factory=PromptConfig)
|
|
59
|
+
custom_tools: PTCCustomToolConfig = field(default_factory=PTCCustomToolConfig)
|
|
53
60
|
|
|
54
61
|
|
|
55
62
|
class PTCSandboxExecutor:
|
|
56
|
-
r"""Executes PTC code inside an E2B sandbox
|
|
63
|
+
r"""Executes PTC code inside an E2B sandbox.
|
|
57
64
|
|
|
58
65
|
This executor is used for LLM-generated code that requires sandboxing.
|
|
59
66
|
It builds a sandbox payload (MCP server config + generated tool modules)
|
|
60
67
|
and executes the code using the E2B runtime.
|
|
61
68
|
|
|
69
|
+
Static bundle caching:
|
|
70
|
+
The executor tracks whether the static bundle (wrappers, registry, sources)
|
|
71
|
+
has been uploaded. On the first run, it uploads the full payload. On subsequent
|
|
72
|
+
runs, it only uploads per-run files (e.g., tools/custom_defaults.json) to
|
|
73
|
+
reduce upload overhead.
|
|
74
|
+
|
|
75
|
+
If the sandbox is destroyed/recreated, call reset_static_bundle() to force
|
|
76
|
+
a full re-upload on the next execution.
|
|
77
|
+
|
|
78
|
+
Thread-safety:
|
|
79
|
+
The static bundle upload is guarded by an asyncio.Lock. Concurrent calls will
|
|
80
|
+
serialize while the initial upload completes. After the bundle is cached,
|
|
81
|
+
executions proceed without locking.
|
|
82
|
+
|
|
62
83
|
Example:
|
|
63
84
|
runtime = E2BSandboxRuntime()
|
|
64
85
|
executor = PTCSandboxExecutor(mcp_client, runtime)
|
|
65
|
-
result = await executor.execute_code("from tools.yfinance import get_stock
|
|
86
|
+
result = await executor.execute_code("from tools.yfinance import get_stock\\nprint(get_stock('AAPL'))")
|
|
66
87
|
"""
|
|
67
88
|
|
|
68
89
|
def __init__(
|
|
69
90
|
self,
|
|
70
|
-
mcp_client: BaseMCPClient,
|
|
91
|
+
mcp_client: BaseMCPClient | None,
|
|
71
92
|
runtime: E2BSandboxRuntime,
|
|
72
93
|
config: PTCSandboxConfig | None = None,
|
|
73
94
|
) -> None:
|
|
74
95
|
"""Initialize PTCSandboxExecutor.
|
|
75
96
|
|
|
76
97
|
Args:
|
|
77
|
-
mcp_client: The MCP client with configured servers.
|
|
98
|
+
mcp_client: The MCP client with configured servers. Can be None for custom-only configs.
|
|
78
99
|
runtime: The E2B sandbox runtime instance.
|
|
79
100
|
config: Optional sandbox executor configuration.
|
|
80
101
|
|
|
@@ -90,21 +111,127 @@ class PTCSandboxExecutor:
|
|
|
90
111
|
self._mcp_client = mcp_client
|
|
91
112
|
self._runtime = runtime
|
|
92
113
|
self._config = config or PTCSandboxConfig()
|
|
114
|
+
self._static_bundle_uploaded = False
|
|
115
|
+
self._bundle_lock = asyncio.Lock()
|
|
116
|
+
|
|
117
|
+
def _reset_bundle_state_if_inactive(self) -> None:
|
|
118
|
+
"""Reset cached bundle state when the runtime is inactive."""
|
|
119
|
+
if self._runtime.is_active:
|
|
120
|
+
return
|
|
121
|
+
if not self._static_bundle_uploaded:
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
logger.info("Runtime is inactive, resetting static bundle state")
|
|
125
|
+
self._static_bundle_uploaded = False
|
|
126
|
+
|
|
127
|
+
def _should_include_packages_path(self) -> bool:
|
|
128
|
+
"""Check if the packages path should be added to sys.path."""
|
|
129
|
+
custom_tools = self._config.custom_tools
|
|
130
|
+
if not custom_tools.enabled or not custom_tools.tools:
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
return any(tool.get("package_path") or tool.get("kind") == "file" for tool in custom_tools.tools)
|
|
134
|
+
|
|
135
|
+
async def _build_payload(self, tool_configs: dict[str, dict] | None) -> SandboxPayload:
|
|
136
|
+
"""Build the sandbox payload for execution."""
|
|
137
|
+
logger.info("Building sandbox payload")
|
|
138
|
+
return await build_sandbox_payload(
|
|
139
|
+
self._mcp_client,
|
|
140
|
+
self._config.default_tool_timeout,
|
|
141
|
+
custom_tools_config=self._config.custom_tools,
|
|
142
|
+
tool_configs=tool_configs,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def _wrap_code(self, code: str) -> str:
|
|
146
|
+
"""Wrap code with required imports and setup."""
|
|
147
|
+
logger.info("Wrapping PTC code")
|
|
148
|
+
return wrap_ptc_code(code, include_packages_path=self._should_include_packages_path())
|
|
149
|
+
|
|
150
|
+
async def _execute_payload(
|
|
151
|
+
self,
|
|
152
|
+
payload: SandboxPayload,
|
|
153
|
+
wrapped_code: str,
|
|
154
|
+
*,
|
|
155
|
+
upload_static_bundle: bool,
|
|
156
|
+
) -> SandboxExecutionResult:
|
|
157
|
+
"""Execute the wrapped code with the provided payload."""
|
|
158
|
+
if upload_static_bundle:
|
|
159
|
+
logger.info("Uploading static bundle and per-run files")
|
|
160
|
+
files_to_upload = {**payload.files, **payload.per_run_files}
|
|
161
|
+
else:
|
|
162
|
+
logger.debug("Static bundle already uploaded, uploading only per-run files")
|
|
163
|
+
files_to_upload = payload.per_run_files
|
|
164
|
+
|
|
165
|
+
logger.info(f"Executing code in sandbox (timeout: {self._config.sandbox_timeout}s)")
|
|
166
|
+
return await self._runtime.execute(
|
|
167
|
+
code=wrapped_code,
|
|
168
|
+
timeout=self._config.sandbox_timeout,
|
|
169
|
+
files=files_to_upload if files_to_upload else None,
|
|
170
|
+
env=payload.env,
|
|
171
|
+
template=self._config.sandbox_template,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
async def _execute_with_bundle(
|
|
175
|
+
self,
|
|
176
|
+
payload: SandboxPayload,
|
|
177
|
+
wrapped_code: str,
|
|
178
|
+
) -> SandboxExecutionResult:
|
|
179
|
+
"""Execute code using the cached static bundle when possible."""
|
|
180
|
+
if self._static_bundle_uploaded:
|
|
181
|
+
return await self._execute_payload(
|
|
182
|
+
payload,
|
|
183
|
+
wrapped_code,
|
|
184
|
+
upload_static_bundle=False,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
async with self._bundle_lock:
|
|
188
|
+
if self._static_bundle_uploaded:
|
|
189
|
+
return await self._execute_payload(
|
|
190
|
+
payload,
|
|
191
|
+
wrapped_code,
|
|
192
|
+
upload_static_bundle=False,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
result = await self._execute_payload(
|
|
196
|
+
payload,
|
|
197
|
+
wrapped_code,
|
|
198
|
+
upload_static_bundle=True,
|
|
199
|
+
)
|
|
200
|
+
self._update_static_bundle_cache(result)
|
|
201
|
+
return result
|
|
202
|
+
|
|
203
|
+
def _update_static_bundle_cache(self, result: SandboxExecutionResult) -> None:
|
|
204
|
+
"""Update cached bundle state after a successful upload."""
|
|
205
|
+
if result.exit_code != 0:
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
self._static_bundle_uploaded = True
|
|
209
|
+
logger.debug("Static bundle successfully uploaded and cached")
|
|
210
|
+
|
|
211
|
+
def _log_execution_result(self, result: SandboxExecutionResult) -> None:
|
|
212
|
+
"""Log execution results based on exit status."""
|
|
213
|
+
if result.exit_code == 0:
|
|
214
|
+
logger.info("Sandbox execution completed successfully")
|
|
215
|
+
else:
|
|
216
|
+
logger.warning(f"Sandbox execution failed with exit code {result.exit_code}")
|
|
93
217
|
|
|
94
218
|
async def execute_code(
|
|
95
219
|
self,
|
|
96
220
|
code: str,
|
|
221
|
+
tool_configs: dict[str, dict] | None = None,
|
|
97
222
|
) -> SandboxExecutionResult:
|
|
98
223
|
"""Execute code inside the sandbox with MCP access.
|
|
99
224
|
|
|
100
225
|
This method:
|
|
101
|
-
1. Builds the sandbox payload (MCP config + generated tool modules)
|
|
226
|
+
1. Builds the sandbox payload (MCP config + generated tool modules + custom tools)
|
|
102
227
|
2. Wraps the user code with necessary imports and setup
|
|
103
228
|
3. Executes the code in the E2B sandbox
|
|
104
229
|
4. Returns the execution result (stdout/stderr/exit_code)
|
|
105
230
|
|
|
106
231
|
Args:
|
|
107
232
|
code: Python code to execute in the sandbox.
|
|
233
|
+
tool_configs: Optional per-tool config values for custom LangChain tools.
|
|
234
|
+
These are merged with agent defaults and written to custom_defaults.json.
|
|
108
235
|
|
|
109
236
|
Returns:
|
|
110
237
|
SandboxExecutionResult with stdout, stderr, and exit_code.
|
|
@@ -113,31 +240,22 @@ class PTCSandboxExecutor:
|
|
|
113
240
|
PTCToolError: If sandbox execution fails.
|
|
114
241
|
"""
|
|
115
242
|
try:
|
|
116
|
-
|
|
117
|
-
payload = await
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
logger.info("Wrapping PTC code")
|
|
123
|
-
wrapped_code = wrap_ptc_code(code)
|
|
124
|
-
|
|
125
|
-
logger.info(f"Executing code in sandbox (timeout: {self._config.sandbox_timeout}s)")
|
|
126
|
-
result = await self._runtime.execute(
|
|
127
|
-
code=wrapped_code,
|
|
128
|
-
timeout=self._config.sandbox_timeout,
|
|
129
|
-
files=payload.files if payload.files else None,
|
|
130
|
-
env=payload.env,
|
|
131
|
-
template=self._config.sandbox_template,
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
if result.exit_code == 0:
|
|
135
|
-
logger.info("Sandbox execution completed successfully")
|
|
136
|
-
else:
|
|
137
|
-
logger.warning(f"Sandbox execution failed with exit code {result.exit_code}")
|
|
138
|
-
|
|
243
|
+
self._reset_bundle_state_if_inactive()
|
|
244
|
+
payload = await self._build_payload(tool_configs)
|
|
245
|
+
wrapped_code = self._wrap_code(code)
|
|
246
|
+
result = await self._execute_with_bundle(payload, wrapped_code)
|
|
247
|
+
self._log_execution_result(result)
|
|
139
248
|
return result
|
|
140
249
|
|
|
141
250
|
except Exception as exc:
|
|
142
251
|
logger.error(f"Sandbox execution failed: {exc}")
|
|
143
252
|
raise PTCToolError(f"Sandbox execution failed: {exc}") from exc
|
|
253
|
+
|
|
254
|
+
def reset_static_bundle(self) -> None:
|
|
255
|
+
"""Reset the static bundle upload state.
|
|
256
|
+
|
|
257
|
+
Call this method when the sandbox is destroyed/recreated to force
|
|
258
|
+
a full re-upload of the static bundle on the next execution.
|
|
259
|
+
"""
|
|
260
|
+
self._static_bundle_uploaded = False
|
|
261
|
+
logger.debug("Static bundle state reset, next execution will re-upload full payload")
|
aip_agents/ptc/executor.pyi
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from _typeshed import Incomplete
|
|
2
2
|
from aip_agents.mcp.client.base_mcp_client import BaseMCPClient as BaseMCPClient
|
|
3
|
+
from aip_agents.ptc.custom_tools import PTCCustomToolConfig as PTCCustomToolConfig
|
|
3
4
|
from aip_agents.ptc.exceptions import PTCToolError as PTCToolError
|
|
5
|
+
from aip_agents.ptc.payload import SandboxPayload as SandboxPayload
|
|
4
6
|
from aip_agents.ptc.prompt_builder import PromptConfig as PromptConfig
|
|
5
7
|
from aip_agents.ptc.sandbox_bridge import build_sandbox_payload as build_sandbox_payload, wrap_ptc_code as wrap_ptc_code
|
|
6
8
|
from aip_agents.sandbox.defaults import DEFAULT_PTC_PACKAGES as DEFAULT_PTC_PACKAGES, DEFAULT_PTC_TEMPLATE as DEFAULT_PTC_TEMPLATE
|
|
@@ -13,15 +15,16 @@ logger: Incomplete
|
|
|
13
15
|
|
|
14
16
|
@dataclass
|
|
15
17
|
class PTCSandboxConfig:
|
|
16
|
-
"""Configuration for PTC sandbox executor
|
|
18
|
+
"""Configuration for PTC sandbox executor.
|
|
17
19
|
|
|
18
20
|
Attributes:
|
|
19
21
|
enabled: Whether PTC is enabled. When False, PTC is disabled.
|
|
20
22
|
default_tool_timeout: Default timeout per tool call in seconds.
|
|
21
23
|
sandbox_template: Optional E2B sandbox template ID.
|
|
22
24
|
sandbox_timeout: Sandbox execution timeout in seconds (hard cap/TTL).
|
|
23
|
-
ptc_packages: List of packages to install in sandbox.
|
|
25
|
+
ptc_packages: List of packages to install in sandbox. Defaults to DEFAULT_PTC_PACKAGES.
|
|
24
26
|
prompt: Prompt configuration for PTC usage guidance.
|
|
27
|
+
custom_tools: Configuration for custom LangChain tools in sandbox.
|
|
25
28
|
"""
|
|
26
29
|
enabled: bool = ...
|
|
27
30
|
default_tool_timeout: float = ...
|
|
@@ -29,41 +32,58 @@ class PTCSandboxConfig:
|
|
|
29
32
|
sandbox_timeout: float = ...
|
|
30
33
|
ptc_packages: list[str] | None = field(default_factory=Incomplete)
|
|
31
34
|
prompt: PromptConfig = field(default_factory=PromptConfig)
|
|
35
|
+
custom_tools: PTCCustomToolConfig = field(default_factory=PTCCustomToolConfig)
|
|
32
36
|
|
|
33
37
|
class PTCSandboxExecutor:
|
|
34
|
-
'''Executes PTC code inside an E2B sandbox
|
|
38
|
+
'''Executes PTC code inside an E2B sandbox.
|
|
35
39
|
|
|
36
40
|
This executor is used for LLM-generated code that requires sandboxing.
|
|
37
41
|
It builds a sandbox payload (MCP server config + generated tool modules)
|
|
38
42
|
and executes the code using the E2B runtime.
|
|
39
43
|
|
|
44
|
+
Static bundle caching:
|
|
45
|
+
The executor tracks whether the static bundle (wrappers, registry, sources)
|
|
46
|
+
has been uploaded. On the first run, it uploads the full payload. On subsequent
|
|
47
|
+
runs, it only uploads per-run files (e.g., tools/custom_defaults.json) to
|
|
48
|
+
reduce upload overhead.
|
|
49
|
+
|
|
50
|
+
If the sandbox is destroyed/recreated, call reset_static_bundle() to force
|
|
51
|
+
a full re-upload on the next execution.
|
|
52
|
+
|
|
53
|
+
Thread-safety:
|
|
54
|
+
The static bundle upload is guarded by an asyncio.Lock. Concurrent calls will
|
|
55
|
+
serialize while the initial upload completes. After the bundle is cached,
|
|
56
|
+
executions proceed without locking.
|
|
57
|
+
|
|
40
58
|
Example:
|
|
41
59
|
runtime = E2BSandboxRuntime()
|
|
42
60
|
executor = PTCSandboxExecutor(mcp_client, runtime)
|
|
43
|
-
result = await executor.execute_code("from tools.yfinance import get_stock
|
|
61
|
+
result = await executor.execute_code("from tools.yfinance import get_stock\\\\nprint(get_stock(\'AAPL\'))")
|
|
44
62
|
'''
|
|
45
|
-
def __init__(self, mcp_client: BaseMCPClient, runtime: E2BSandboxRuntime, config: PTCSandboxConfig | None = None) -> None:
|
|
63
|
+
def __init__(self, mcp_client: BaseMCPClient | None, runtime: E2BSandboxRuntime, config: PTCSandboxConfig | None = None) -> None:
|
|
46
64
|
"""Initialize PTCSandboxExecutor.
|
|
47
65
|
|
|
48
66
|
Args:
|
|
49
|
-
mcp_client: The MCP client with configured servers.
|
|
67
|
+
mcp_client: The MCP client with configured servers. Can be None for custom-only configs.
|
|
50
68
|
runtime: The E2B sandbox runtime instance.
|
|
51
69
|
config: Optional sandbox executor configuration.
|
|
52
70
|
|
|
53
71
|
Raises:
|
|
54
72
|
ImportError: If sandbox dependencies are not available.
|
|
55
73
|
"""
|
|
56
|
-
async def execute_code(self, code: str) -> SandboxExecutionResult:
|
|
74
|
+
async def execute_code(self, code: str, tool_configs: dict[str, dict] | None = None) -> SandboxExecutionResult:
|
|
57
75
|
"""Execute code inside the sandbox with MCP access.
|
|
58
76
|
|
|
59
77
|
This method:
|
|
60
|
-
1. Builds the sandbox payload (MCP config + generated tool modules)
|
|
78
|
+
1. Builds the sandbox payload (MCP config + generated tool modules + custom tools)
|
|
61
79
|
2. Wraps the user code with necessary imports and setup
|
|
62
80
|
3. Executes the code in the E2B sandbox
|
|
63
81
|
4. Returns the execution result (stdout/stderr/exit_code)
|
|
64
82
|
|
|
65
83
|
Args:
|
|
66
84
|
code: Python code to execute in the sandbox.
|
|
85
|
+
tool_configs: Optional per-tool config values for custom LangChain tools.
|
|
86
|
+
These are merged with agent defaults and written to custom_defaults.json.
|
|
67
87
|
|
|
68
88
|
Returns:
|
|
69
89
|
SandboxExecutionResult with stdout, stderr, and exit_code.
|
|
@@ -71,3 +91,9 @@ class PTCSandboxExecutor:
|
|
|
71
91
|
Raises:
|
|
72
92
|
PTCToolError: If sandbox execution fails.
|
|
73
93
|
"""
|
|
94
|
+
def reset_static_bundle(self) -> None:
|
|
95
|
+
"""Reset the static bundle upload state.
|
|
96
|
+
|
|
97
|
+
Call this method when the sandbox is destroyed/recreated to force
|
|
98
|
+
a full re-upload of the static bundle on the next execution.
|
|
99
|
+
"""
|
aip_agents/ptc/naming.py
CHANGED
|
@@ -12,7 +12,7 @@ import re
|
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
14
|
# Reserved module names that cannot be used for server packages.
|
|
15
|
-
RESERVED_MODULE_NAMES = frozenset({"ptc_helper", "mcp_client"})
|
|
15
|
+
RESERVED_MODULE_NAMES = frozenset({"ptc_helper", "mcp_client", "custom"})
|
|
16
16
|
|
|
17
17
|
# Default placeholder for example values.
|
|
18
18
|
DEFAULT_EXAMPLE_PLACEHOLDER = '"example"'
|
|
@@ -87,6 +87,18 @@ def sanitize_param_name(name: str) -> str:
|
|
|
87
87
|
return sanitize_module_name(name)
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def is_valid_identifier(name: str) -> bool:
|
|
91
|
+
"""Check if a string is a valid Python identifier and not a keyword.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
name: Candidate identifier.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
True if name is a valid identifier and not a keyword.
|
|
98
|
+
"""
|
|
99
|
+
return name.isidentifier() and not keyword.iskeyword(name)
|
|
100
|
+
|
|
101
|
+
|
|
90
102
|
def json_type_to_python(json_type: str | list) -> str:
|
|
91
103
|
"""Convert JSON schema type to Python type hint.
|
|
92
104
|
|
aip_agents/ptc/naming.pyi
CHANGED
|
@@ -43,6 +43,15 @@ def sanitize_param_name(name: str) -> str:
|
|
|
43
43
|
Returns:
|
|
44
44
|
Valid Python parameter name (lowercase, underscored).
|
|
45
45
|
"""
|
|
46
|
+
def is_valid_identifier(name: str) -> bool:
|
|
47
|
+
"""Check if a string is a valid Python identifier and not a keyword.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
name: Candidate identifier.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
True if name is a valid identifier and not a keyword.
|
|
54
|
+
"""
|
|
46
55
|
def json_type_to_python(json_type: str | list) -> str:
|
|
47
56
|
"""Convert JSON schema type to Python type hint.
|
|
48
57
|
|