agentkit-sdk-python 0.6.0__py3-none-any.whl → 0.6.1__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.
- agentkit/toolkit/cli/sandbox/__init__.py +4 -0
- agentkit/toolkit/cli/sandbox/cli.py +12 -3
- agentkit/toolkit/cli/sandbox/cli_create.py +160 -25
- agentkit/toolkit/cli/sandbox/cli_exec.py +134 -0
- agentkit/toolkit/cli/sandbox/cli_file.py +915 -0
- agentkit/toolkit/cli/sandbox/cli_get.py +1 -0
- agentkit/toolkit/cli/sandbox/cli_shell.py +45 -0
- agentkit/toolkit/cli/sandbox/cli_web.py +95 -0
- agentkit/toolkit/cli/sandbox/session_create.py +11 -8
- agentkit/toolkit/cli/sandbox/tool_resolve.py +127 -8
- agentkit/toolkit/cli/sandbox/utils.py +56 -1
- agentkit/toolkit/volcengine/iam.py +12 -19
- agentkit/version.py +1 -1
- {agentkit_sdk_python-0.6.0.dist-info → agentkit_sdk_python-0.6.1.dist-info}/METADATA +1 -1
- {agentkit_sdk_python-0.6.0.dist-info → agentkit_sdk_python-0.6.1.dist-info}/RECORD +19 -17
- {agentkit_sdk_python-0.6.0.dist-info → agentkit_sdk_python-0.6.1.dist-info}/WHEEL +0 -0
- {agentkit_sdk_python-0.6.0.dist-info → agentkit_sdk_python-0.6.1.dist-info}/entry_points.txt +0 -0
- {agentkit_sdk_python-0.6.0.dist-info → agentkit_sdk_python-0.6.1.dist-info}/licenses/LICENSE +0 -0
- {agentkit_sdk_python-0.6.0.dist-info → agentkit_sdk_python-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -17,13 +17,17 @@
|
|
|
17
17
|
from agentkit.toolkit.cli.sandbox.cli import sandbox_app
|
|
18
18
|
from agentkit.toolkit.cli.sandbox.cli_create import create_command
|
|
19
19
|
from agentkit.toolkit.cli.sandbox.cli_exec import exec_command
|
|
20
|
+
from agentkit.toolkit.cli.sandbox.cli_file import file_command
|
|
20
21
|
from agentkit.toolkit.cli.sandbox.cli_get import get_command
|
|
21
22
|
from agentkit.toolkit.cli.sandbox.cli_shell import shell_command
|
|
23
|
+
from agentkit.toolkit.cli.sandbox.cli_web import web_command
|
|
22
24
|
|
|
23
25
|
__all__ = [
|
|
24
26
|
"create_command",
|
|
25
27
|
"exec_command",
|
|
28
|
+
"file_command",
|
|
26
29
|
"get_command",
|
|
27
30
|
"sandbox_app",
|
|
28
31
|
"shell_command",
|
|
32
|
+
"web_command",
|
|
29
33
|
]
|
|
@@ -20,8 +20,10 @@ import typer
|
|
|
20
20
|
|
|
21
21
|
from agentkit.toolkit.cli.sandbox.cli_create import create_command
|
|
22
22
|
from agentkit.toolkit.cli.sandbox.cli_exec import exec_command
|
|
23
|
+
from agentkit.toolkit.cli.sandbox.cli_file import file_command
|
|
23
24
|
from agentkit.toolkit.cli.sandbox.cli_get import get_command
|
|
24
25
|
from agentkit.toolkit.cli.sandbox.cli_shell import shell_command
|
|
26
|
+
from agentkit.toolkit.cli.sandbox.cli_web import web_command
|
|
25
27
|
|
|
26
28
|
sandbox_app = typer.Typer(
|
|
27
29
|
name="sandbox",
|
|
@@ -31,6 +33,13 @@ sandbox_app = typer.Typer(
|
|
|
31
33
|
|
|
32
34
|
sandbox_app.command(name="create")(create_command)
|
|
33
35
|
sandbox_app.command(name="get")(get_command)
|
|
34
|
-
sandbox_app.command(
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
sandbox_app.command(
|
|
37
|
+
name="exec",
|
|
38
|
+
context_settings={"allow_extra_args": True},
|
|
39
|
+
)(exec_command)
|
|
40
|
+
sandbox_app.command(
|
|
41
|
+
name="shell",
|
|
42
|
+
context_settings={"allow_extra_args": True},
|
|
43
|
+
)(shell_command)
|
|
44
|
+
sandbox_app.command(name="web")(web_command)
|
|
45
|
+
sandbox_app.add_typer(file_command, name="file")
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
+
import json
|
|
19
20
|
import os
|
|
20
21
|
import re
|
|
21
22
|
import time
|
|
@@ -45,7 +46,19 @@ SANDBOX_TOS_REGION_ENV = "AGENTKIT_SANDBOX_TOS_REGION"
|
|
|
45
46
|
DEFAULT_CREATE_TOOL_TYPE = "CodeEnv"
|
|
46
47
|
DEFAULT_TOS_BUCKET_PATH = "/sandbox-session/default/default"
|
|
47
48
|
DEFAULT_TOS_LOCAL_PATH = "/home/gem"
|
|
49
|
+
CODE_ENV_HOME = "/home/gem"
|
|
50
|
+
CODE_ENV_CODEX_HOME = "/home/gem/.codex"
|
|
51
|
+
CODEX_MODEL_CATALOG_PATH = f"{CODE_ENV_CODEX_HOME}/model-catalog.json"
|
|
48
52
|
DEFAULT_MODEL_NAME = "deepseek-v4-flash-260425"
|
|
53
|
+
DEFAULT_MODEL_NAME_LIST = (
|
|
54
|
+
DEFAULT_MODEL_NAME,
|
|
55
|
+
"deepseek-v4-pro-260425",
|
|
56
|
+
"doubao-seed-2-0-pro-260215",
|
|
57
|
+
)
|
|
58
|
+
DEFAULT_MODEL_CONTEXT_WINDOW = 1000000
|
|
59
|
+
MODEL_CONTEXT_WINDOW_OVERRIDES = {
|
|
60
|
+
"doubao-seed-2-0-pro-260215": 256000,
|
|
61
|
+
}
|
|
49
62
|
DEFAULT_MODEL_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"
|
|
50
63
|
DEFAULT_ANTHROPIC_BASE_URL = "https://ark.cn-beijing.volces.com/api/compatible"
|
|
51
64
|
MODEL_BASE_URL_ENV_KEYS = (
|
|
@@ -57,8 +70,6 @@ ANTHROPIC_BASE_URL_ENV_KEYS = ("ANTHROPIC_BASE_URL",)
|
|
|
57
70
|
DISABLED_SERVICE_ENV_KEYS = (
|
|
58
71
|
"DISABLE_JUPYTER",
|
|
59
72
|
"DISABLE_CODE_SERVER",
|
|
60
|
-
"DISABLE_BROWSER",
|
|
61
|
-
"DISABLE_VNC",
|
|
62
73
|
"DISABLE_NODEJS_REPL",
|
|
63
74
|
)
|
|
64
75
|
TOOL_READY_STATUS = "Ready"
|
|
@@ -98,13 +109,134 @@ def _append_tool_envs(
|
|
|
98
109
|
return
|
|
99
110
|
|
|
100
111
|
envs.extend(
|
|
101
|
-
tools_types.EnvsItemForCreateTool(
|
|
112
|
+
tools_types.EnvsItemForCreateTool(Key=key, Value=resolved)
|
|
102
113
|
for key in keys
|
|
103
114
|
)
|
|
104
115
|
|
|
105
116
|
|
|
117
|
+
def _toml_quote(value: str) -> str:
|
|
118
|
+
return json.dumps(value, ensure_ascii=False)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _build_codex_config_toml(model_name: str) -> str:
|
|
122
|
+
quoted_model = _toml_quote(model_name)
|
|
123
|
+
return "\n".join(
|
|
124
|
+
[
|
|
125
|
+
'model_provider = "codex"',
|
|
126
|
+
f"model = {quoted_model}",
|
|
127
|
+
f"review_model = {quoted_model}",
|
|
128
|
+
'approval_policy = "never"',
|
|
129
|
+
'sandbox_mode = "danger-full-access"',
|
|
130
|
+
'model_reasoning_effort = "medium"',
|
|
131
|
+
'personality = "pragmatic"',
|
|
132
|
+
"check_for_update_on_startup = false",
|
|
133
|
+
'web_search = "disabled"',
|
|
134
|
+
f"model_catalog_json = {_toml_quote(CODEX_MODEL_CATALOG_PATH)}",
|
|
135
|
+
"",
|
|
136
|
+
"[model_providers.codex]",
|
|
137
|
+
'name = "codex"',
|
|
138
|
+
f"base_url = {_toml_quote(DEFAULT_MODEL_BASE_URL)}",
|
|
139
|
+
'wire_api = "responses"',
|
|
140
|
+
'env_key = "CODEX_API_KEY"',
|
|
141
|
+
"",
|
|
142
|
+
"[tui]",
|
|
143
|
+
"show_tooltips = false",
|
|
144
|
+
"",
|
|
145
|
+
'[projects."/home/gem"]',
|
|
146
|
+
'trust_level = "trusted"',
|
|
147
|
+
"",
|
|
148
|
+
]
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _build_model_catalog_item(model_name: str, max_context_window: int) -> dict:
|
|
153
|
+
return {
|
|
154
|
+
"slug": model_name,
|
|
155
|
+
"display_name": model_name,
|
|
156
|
+
"supported_reasoning_levels": [
|
|
157
|
+
{
|
|
158
|
+
"effort": "low",
|
|
159
|
+
"description": "Fast responses with lighter reasoning",
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"effort": "medium",
|
|
163
|
+
"description": "Balances speed and reasoning depth",
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"effort": "high",
|
|
167
|
+
"description": "Greater reasoning depth",
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
"max_context_window": max_context_window,
|
|
171
|
+
"shell_type": "shell_command",
|
|
172
|
+
"visibility": "list",
|
|
173
|
+
"supported_in_api": True,
|
|
174
|
+
"priority": 100,
|
|
175
|
+
"base_instructions": "",
|
|
176
|
+
"supports_reasoning_summaries": True,
|
|
177
|
+
"support_verbosity": False,
|
|
178
|
+
"truncation_policy": {"mode": "tokens", "limit": 10000},
|
|
179
|
+
"supports_parallel_tool_calls": False,
|
|
180
|
+
"experimental_supported_tools": [],
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _model_catalog_context_window(model_name: str) -> int:
|
|
185
|
+
return MODEL_CONTEXT_WINDOW_OVERRIDES.get(
|
|
186
|
+
model_name,
|
|
187
|
+
DEFAULT_MODEL_CONTEXT_WINDOW,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _build_codex_model_catalog_json(model_name: str) -> str:
|
|
192
|
+
deduped_model_names = list(
|
|
193
|
+
dict.fromkeys((model_name, *DEFAULT_MODEL_NAME_LIST))
|
|
194
|
+
)
|
|
195
|
+
payload = {
|
|
196
|
+
"models": [
|
|
197
|
+
_build_model_catalog_item(
|
|
198
|
+
name,
|
|
199
|
+
_model_catalog_context_window(name),
|
|
200
|
+
)
|
|
201
|
+
for name in deduped_model_names
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
return json.dumps(payload, ensure_ascii=False, indent=2)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _append_code_env_tool_envs(
|
|
208
|
+
envs: list[tools_types.EnvsItemForCreateTool],
|
|
209
|
+
model_name: str,
|
|
210
|
+
) -> None:
|
|
211
|
+
envs.extend(
|
|
212
|
+
[
|
|
213
|
+
tools_types.EnvsItemForCreateTool(
|
|
214
|
+
Key="OPENCODE_DISABLE_AUTOUPDATE",
|
|
215
|
+
Value="1",
|
|
216
|
+
),
|
|
217
|
+
tools_types.EnvsItemForCreateTool(
|
|
218
|
+
Key="HOME",
|
|
219
|
+
Value=CODE_ENV_HOME,
|
|
220
|
+
),
|
|
221
|
+
tools_types.EnvsItemForCreateTool(
|
|
222
|
+
Key="CODEX_HOME",
|
|
223
|
+
Value=CODE_ENV_CODEX_HOME,
|
|
224
|
+
),
|
|
225
|
+
tools_types.EnvsItemForCreateTool(
|
|
226
|
+
Key="CODEX_CONFIG_TOML",
|
|
227
|
+
Value=_build_codex_config_toml(model_name),
|
|
228
|
+
),
|
|
229
|
+
tools_types.EnvsItemForCreateTool(
|
|
230
|
+
Key="CODEX_MODEL_CATALOG_JSON",
|
|
231
|
+
Value=_build_codex_model_catalog_json(model_name),
|
|
232
|
+
),
|
|
233
|
+
]
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
106
237
|
def _build_tool_model_envs(
|
|
107
238
|
*,
|
|
239
|
+
tool_type: str,
|
|
108
240
|
model_name: Optional[str] = None,
|
|
109
241
|
model_api_key: Optional[str] = None,
|
|
110
242
|
) -> list[tools_types.EnvsItemForCreateTool] | None:
|
|
@@ -124,6 +256,8 @@ def _build_tool_model_envs(
|
|
|
124
256
|
DEFAULT_ANTHROPIC_BASE_URL,
|
|
125
257
|
)
|
|
126
258
|
_append_tool_envs(envs, DISABLED_SERVICE_ENV_KEYS, "true")
|
|
259
|
+
if tool_type.strip() == DEFAULT_CREATE_TOOL_TYPE:
|
|
260
|
+
_append_code_env_tool_envs(envs, resolved_model_name)
|
|
127
261
|
return envs or None
|
|
128
262
|
|
|
129
263
|
|
|
@@ -141,20 +275,21 @@ def _build_create_tool_request(
|
|
|
141
275
|
tos_mount_config = _build_tos_mount_config(tos_bucket, tos_region)
|
|
142
276
|
|
|
143
277
|
return tools_types.CreateToolRequest(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
278
|
+
Name=resolved_name,
|
|
279
|
+
ToolType=resolved_tool_type,
|
|
280
|
+
AuthorizerConfiguration=tools_types.AuthorizerForCreateTool(
|
|
281
|
+
KeyAuth=tools_types.AuthorizerKeyAuthForCreateTool(
|
|
282
|
+
ApiKeyName=generate_apikey_name(),
|
|
283
|
+
ApiKeyLocation="Header",
|
|
150
284
|
)
|
|
151
285
|
),
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
286
|
+
NetworkConfiguration=tools_types.NetworkForCreateTool(
|
|
287
|
+
EnablePublicNetwork=True,
|
|
288
|
+
EnablePrivateNetwork=False,
|
|
155
289
|
),
|
|
156
|
-
|
|
157
|
-
|
|
290
|
+
TosMountConfig=tos_mount_config,
|
|
291
|
+
Envs=_build_tool_model_envs(
|
|
292
|
+
tool_type=resolved_tool_type,
|
|
158
293
|
model_name=model_name,
|
|
159
294
|
model_api_key=model_api_key,
|
|
160
295
|
),
|
|
@@ -183,18 +318,18 @@ def _to_create_tool_tos_mount_config(
|
|
|
183
318
|
mount_config: TOSMountConfig,
|
|
184
319
|
) -> tools_types.TosMountForCreateTool:
|
|
185
320
|
return tools_types.TosMountForCreateTool(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
321
|
+
EnableTos=True,
|
|
322
|
+
Credentials=tools_types.TosMountCredentialsForCreateTool(
|
|
323
|
+
AccessKeyId=mount_config.credentials.access_key_id,
|
|
324
|
+
SecretAccessKey=mount_config.credentials.secret_access_key,
|
|
190
325
|
),
|
|
191
|
-
|
|
326
|
+
MountPoints=[
|
|
192
327
|
tools_types.TosMountMountPointsItemForCreateTool(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
328
|
+
BucketName=mount.bucket_name,
|
|
329
|
+
BucketPath=mount.bucket_path,
|
|
330
|
+
Endpoint=mount.endpoint,
|
|
331
|
+
LocalMountPath=mount.local_mount_path,
|
|
332
|
+
ReadOnly=mount.read_only,
|
|
198
333
|
)
|
|
199
334
|
for mount in mount_config.mount_points
|
|
200
335
|
],
|
|
@@ -238,7 +373,7 @@ def _wait_for_tool_ready(
|
|
|
238
373
|
last_status = None
|
|
239
374
|
|
|
240
375
|
while True:
|
|
241
|
-
response = client.get_tool(tools_types.GetToolRequest(
|
|
376
|
+
response = client.get_tool(tools_types.GetToolRequest(ToolId=tool_id))
|
|
242
377
|
status = response.status or ""
|
|
243
378
|
if status != last_status:
|
|
244
379
|
typer.echo(f"工具状态:{status or 'Unknown'}")
|
|
@@ -26,10 +26,21 @@ import termios
|
|
|
26
26
|
import threading
|
|
27
27
|
import tty
|
|
28
28
|
from contextlib import contextmanager
|
|
29
|
+
from pathlib import Path
|
|
29
30
|
from typing import Iterator, Optional
|
|
30
31
|
|
|
31
32
|
import typer
|
|
32
33
|
|
|
34
|
+
from agentkit.toolkit.cli.sandbox.cli_file import (
|
|
35
|
+
_build_remote_extract_command,
|
|
36
|
+
_create_upload_archive,
|
|
37
|
+
_create_sources_upload_archive,
|
|
38
|
+
_exec_shell_command,
|
|
39
|
+
_new_remote_archive_path,
|
|
40
|
+
_normalize_workspace,
|
|
41
|
+
_resolve_sandbox_path,
|
|
42
|
+
_upload_remote_file,
|
|
43
|
+
)
|
|
33
44
|
from agentkit.toolkit.cli.sandbox.session_create import (
|
|
34
45
|
SANDBOX_TOOL_ID_ENV,
|
|
35
46
|
build_model_envs,
|
|
@@ -46,6 +57,7 @@ from agentkit.toolkit.cli.sandbox.utils import (
|
|
|
46
57
|
DETACH_SEQUENCE = b"\x1d"
|
|
47
58
|
DETACH_HINT = "Ctrl-]"
|
|
48
59
|
LOCAL_EXIT_COMMANDS = {"exit", "exit()"}
|
|
60
|
+
DEFAULT_EXEC_WORKSPACE = "/home/gem"
|
|
49
61
|
|
|
50
62
|
|
|
51
63
|
def _terminal_size() -> dict[str, int]:
|
|
@@ -232,10 +244,95 @@ def _connect_terminal(
|
|
|
232
244
|
signal.signal(sigwinch, previous_sigwinch)
|
|
233
245
|
|
|
234
246
|
|
|
247
|
+
def _resolve_exec_dst_dir(
|
|
248
|
+
*,
|
|
249
|
+
workspace: Optional[str],
|
|
250
|
+
dst_dir: Optional[str],
|
|
251
|
+
) -> str:
|
|
252
|
+
resolved_workspace = _normalize_workspace(workspace) or DEFAULT_EXEC_WORKSPACE
|
|
253
|
+
raw_dst_dir = (dst_dir or "").strip()
|
|
254
|
+
if not raw_dst_dir:
|
|
255
|
+
return resolved_workspace
|
|
256
|
+
if raw_dst_dir.startswith("/"):
|
|
257
|
+
error("--dst-dir must be relative to --workspace")
|
|
258
|
+
return _resolve_sandbox_path(
|
|
259
|
+
raw_dst_dir,
|
|
260
|
+
workspace=resolved_workspace,
|
|
261
|
+
option_name="--dst-dir",
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _resolve_exec_upload_sources(src_dirs: list[Path]) -> list[Path]:
|
|
266
|
+
resolved_sources = []
|
|
267
|
+
seen_names: set[str] = set()
|
|
268
|
+
for src_dir in src_dirs:
|
|
269
|
+
if not src_dir.exists():
|
|
270
|
+
error(f"Source path not found: {src_dir}")
|
|
271
|
+
if not src_dir.is_dir() and not src_dir.is_file():
|
|
272
|
+
error(f"Source path is not a file or directory: {src_dir}")
|
|
273
|
+
if src_dir.name in seen_names:
|
|
274
|
+
error(f"Duplicate source name: {src_dir.name}")
|
|
275
|
+
seen_names.add(src_dir.name)
|
|
276
|
+
resolved_sources.append(src_dir)
|
|
277
|
+
return resolved_sources
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _collect_exec_upload_sources(
|
|
281
|
+
ctx: typer.Context,
|
|
282
|
+
src_dir: Optional[Path],
|
|
283
|
+
) -> list[Path]:
|
|
284
|
+
src_dirs = [Path(value) for value in ctx.args]
|
|
285
|
+
if src_dirs and not src_dir:
|
|
286
|
+
error("Additional source paths require --src-dir")
|
|
287
|
+
if src_dir:
|
|
288
|
+
src_dirs.insert(0, src_dir)
|
|
289
|
+
return src_dirs
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _upload_source_before_exec(
|
|
293
|
+
session: dict[str, object],
|
|
294
|
+
*,
|
|
295
|
+
workspace: Optional[str],
|
|
296
|
+
src_dirs: list[Path],
|
|
297
|
+
dst_dir: Optional[str],
|
|
298
|
+
) -> str:
|
|
299
|
+
resolved_dst_dir = _resolve_exec_dst_dir(
|
|
300
|
+
workspace=workspace,
|
|
301
|
+
dst_dir=dst_dir,
|
|
302
|
+
)
|
|
303
|
+
resolved_sources = _resolve_exec_upload_sources(src_dirs)
|
|
304
|
+
if len(resolved_sources) == 1 and resolved_sources[0].is_dir():
|
|
305
|
+
archive_path = _create_upload_archive(
|
|
306
|
+
upload_dir=resolved_sources[0],
|
|
307
|
+
upload_files=[],
|
|
308
|
+
)
|
|
309
|
+
else:
|
|
310
|
+
archive_path = _create_sources_upload_archive(resolved_sources)
|
|
311
|
+
remote_archive_path = _new_remote_archive_path("agentkit-upload")
|
|
312
|
+
try:
|
|
313
|
+
_upload_remote_file(
|
|
314
|
+
session,
|
|
315
|
+
local_path=archive_path,
|
|
316
|
+
remote_path=remote_archive_path,
|
|
317
|
+
)
|
|
318
|
+
_exec_shell_command(
|
|
319
|
+
session,
|
|
320
|
+
_build_remote_extract_command(
|
|
321
|
+
archive_path=remote_archive_path,
|
|
322
|
+
dst_dir=resolved_dst_dir,
|
|
323
|
+
),
|
|
324
|
+
)
|
|
325
|
+
finally:
|
|
326
|
+
archive_path.unlink(missing_ok=True)
|
|
327
|
+
return resolved_dst_dir
|
|
328
|
+
|
|
329
|
+
|
|
235
330
|
def exec_command(
|
|
331
|
+
ctx: typer.Context,
|
|
236
332
|
session_id: Optional[str] = typer.Option(
|
|
237
333
|
None,
|
|
238
334
|
"--session-id",
|
|
335
|
+
"--sid",
|
|
239
336
|
help=(
|
|
240
337
|
"Sandbox session ID. Defaults to a generated UUID and creates "
|
|
241
338
|
"a sandbox session when needed."
|
|
@@ -264,6 +361,29 @@ def exec_command(
|
|
|
264
361
|
"--shell-id",
|
|
265
362
|
help="Existing shell terminal ID to connect to.",
|
|
266
363
|
),
|
|
364
|
+
workspace: str = typer.Option(
|
|
365
|
+
DEFAULT_EXEC_WORKSPACE,
|
|
366
|
+
"--workspace",
|
|
367
|
+
help=(
|
|
368
|
+
"Sandbox workspace root. Relative --dst-dir values are "
|
|
369
|
+
"resolved inside this directory."
|
|
370
|
+
),
|
|
371
|
+
),
|
|
372
|
+
src_dir: Optional[Path] = typer.Option(
|
|
373
|
+
None,
|
|
374
|
+
"--src-dir",
|
|
375
|
+
help=(
|
|
376
|
+
"Local file or directory to upload before opening the exec session."
|
|
377
|
+
),
|
|
378
|
+
),
|
|
379
|
+
dst_dir: Optional[str] = typer.Option(
|
|
380
|
+
None,
|
|
381
|
+
"--dst-dir",
|
|
382
|
+
help=(
|
|
383
|
+
"Relative sandbox destination directory for --src-dir. Defaults "
|
|
384
|
+
"to --workspace."
|
|
385
|
+
),
|
|
386
|
+
),
|
|
267
387
|
model_name: Optional[str] = typer.Option(
|
|
268
388
|
None,
|
|
269
389
|
"--model-name",
|
|
@@ -301,6 +421,20 @@ def exec_command(
|
|
|
301
421
|
if not isinstance(session_id, str) or not session_id:
|
|
302
422
|
error("Sandbox session missing session_id")
|
|
303
423
|
|
|
424
|
+
try:
|
|
425
|
+
src_dirs = _collect_exec_upload_sources(ctx, src_dir)
|
|
426
|
+
if src_dirs:
|
|
427
|
+
_upload_source_before_exec(
|
|
428
|
+
session,
|
|
429
|
+
workspace=workspace,
|
|
430
|
+
src_dirs=src_dirs,
|
|
431
|
+
dst_dir=dst_dir,
|
|
432
|
+
)
|
|
433
|
+
except typer.Exit:
|
|
434
|
+
raise
|
|
435
|
+
except Exception as exc:
|
|
436
|
+
error(str(exc))
|
|
437
|
+
|
|
304
438
|
ws_url = build_terminal_ws_url(session.get("endpoint"), shell_id=shell_id)
|
|
305
439
|
initial_command = command
|
|
306
440
|
|