indent 0.1.10__py3-none-any.whl → 0.1.12__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.
Potentially problematic release.
This version of indent might be problematic. Click here for more details.
- exponent/__init__.py +16 -3
- exponent/commands/cloud_commands.py +582 -0
- exponent/commands/common.py +4 -9
- exponent/commands/config_commands.py +1 -161
- exponent/commands/run_commands.py +20 -9
- exponent/commands/utils.py +3 -3
- exponent/commands/workflow_commands.py +2 -2
- exponent/core/config.py +0 -1
- exponent/core/graphql/mutations.py +114 -0
- exponent/core/graphql/queries.py +23 -0
- exponent/core/graphql/subscriptions.py +0 -449
- exponent/core/remote_execution/cli_rpc_types.py +48 -1
- exponent/core/remote_execution/client.py +114 -26
- exponent/core/remote_execution/file_write.py +1 -376
- exponent/core/remote_execution/files.py +1 -102
- exponent/core/remote_execution/git.py +1 -1
- exponent/core/remote_execution/http_fetch.py +3 -4
- exponent/core/remote_execution/languages/python_execution.py +1 -1
- exponent/core/remote_execution/languages/shell_streaming.py +1 -1
- exponent/core/remote_execution/session.py +1 -1
- exponent/core/remote_execution/system_context.py +0 -3
- exponent/core/remote_execution/tool_execution.py +24 -4
- exponent/core/remote_execution/truncation.py +51 -47
- exponent/core/remote_execution/types.py +25 -79
- exponent/core/remote_execution/utils.py +23 -51
- exponent/core/types/event_types.py +2 -2
- exponent/core/types/generated/strategy_info.py +0 -12
- exponent/utils/version.py +1 -1
- {indent-0.1.10.dist-info → indent-0.1.12.dist-info}/METADATA +3 -3
- indent-0.1.12.dist-info/RECORD +52 -0
- exponent/core/graphql/cloud_config_queries.py +0 -77
- indent-0.1.10.dist-info/RECORD +0 -53
- {indent-0.1.10.dist-info → indent-0.1.12.dist-info}/WHEEL +0 -0
- {indent-0.1.10.dist-info → indent-0.1.12.dist-info}/entry_points.txt +0 -0
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from asyncio import
|
|
2
|
+
from asyncio import to_thread
|
|
3
3
|
from typing import Final, cast
|
|
4
4
|
|
|
5
5
|
from anyio import Path as AsyncPath
|
|
6
6
|
from python_ripgrep import PySortMode, PySortModeKind, files, search
|
|
7
|
-
from rapidfuzz import process
|
|
8
7
|
|
|
9
8
|
from exponent.core.remote_execution.cli_rpc_types import ErrorToolResult, GrepToolResult
|
|
10
9
|
from exponent.core.remote_execution.types import (
|
|
11
|
-
FileAttachment,
|
|
12
10
|
FilePath,
|
|
13
|
-
GetFileAttachmentRequest,
|
|
14
|
-
GetFileAttachmentResponse,
|
|
15
|
-
GetFileAttachmentsRequest,
|
|
16
|
-
GetFileAttachmentsResponse,
|
|
17
|
-
GetMatchingFilesRequest,
|
|
18
|
-
GetMatchingFilesResponse,
|
|
19
11
|
ListFilesRequest,
|
|
20
12
|
ListFilesResponse,
|
|
21
13
|
RemoteFile,
|
|
@@ -114,99 +106,6 @@ async def get_file_content(
|
|
|
114
106
|
return content, exists
|
|
115
107
|
|
|
116
108
|
|
|
117
|
-
async def get_file_attachments(
|
|
118
|
-
get_file_attachments_request: GetFileAttachmentsRequest,
|
|
119
|
-
client_working_directory: str,
|
|
120
|
-
) -> GetFileAttachmentsResponse:
|
|
121
|
-
"""Get the content of the files at the specified paths.
|
|
122
|
-
|
|
123
|
-
Args:
|
|
124
|
-
get_file_attachments_request: An object containing the file paths.
|
|
125
|
-
client_working_directory: The working directory of the client.
|
|
126
|
-
|
|
127
|
-
Returns:
|
|
128
|
-
A list of FileAttachment objects containing the content of the files.
|
|
129
|
-
"""
|
|
130
|
-
remote_files = get_file_attachments_request.files
|
|
131
|
-
attachments = await gather(
|
|
132
|
-
*[
|
|
133
|
-
get_file_content(
|
|
134
|
-
AsyncPath(client_working_directory) / remote_file.file_path
|
|
135
|
-
)
|
|
136
|
-
for remote_file in remote_files
|
|
137
|
-
]
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
files = [
|
|
141
|
-
FileAttachment(attachment_type="file", file=remote_file, content=content)
|
|
142
|
-
for remote_file, (content, _) in zip(remote_files, attachments)
|
|
143
|
-
]
|
|
144
|
-
|
|
145
|
-
return GetFileAttachmentsResponse(
|
|
146
|
-
correlation_id=get_file_attachments_request.correlation_id,
|
|
147
|
-
file_attachments=files,
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
async def get_file_attachment(
|
|
152
|
-
get_file_attachment_request: GetFileAttachmentRequest, client_working_directory: str
|
|
153
|
-
) -> GetFileAttachmentResponse:
|
|
154
|
-
"""Get the content of the file at the specified path.
|
|
155
|
-
|
|
156
|
-
Args:
|
|
157
|
-
get_file_attachment_request: An object containing the file path.
|
|
158
|
-
client_working_directory: The working directory of the client.
|
|
159
|
-
|
|
160
|
-
Returns:
|
|
161
|
-
A FileAttachment object containing the content of the file.
|
|
162
|
-
"""
|
|
163
|
-
file = get_file_attachment_request.file
|
|
164
|
-
absolute_path = await file.resolve(client_working_directory)
|
|
165
|
-
|
|
166
|
-
content, exists = await get_file_content(absolute_path)
|
|
167
|
-
|
|
168
|
-
return GetFileAttachmentResponse(
|
|
169
|
-
content=content,
|
|
170
|
-
exists=exists,
|
|
171
|
-
file=file,
|
|
172
|
-
correlation_id=get_file_attachment_request.correlation_id,
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
async def get_matching_files(
|
|
177
|
-
search_term: GetMatchingFilesRequest,
|
|
178
|
-
file_cache: FileCache,
|
|
179
|
-
) -> GetMatchingFilesResponse:
|
|
180
|
-
"""Get the files that match the search term.
|
|
181
|
-
|
|
182
|
-
Args:
|
|
183
|
-
search_term: The search term to match against the files.
|
|
184
|
-
file_cache: A cache of the files in the working directory.
|
|
185
|
-
|
|
186
|
-
Returns:
|
|
187
|
-
A list of RemoteFile objects that match the search term.
|
|
188
|
-
"""
|
|
189
|
-
# Use rapidfuzz to find the best matching files
|
|
190
|
-
matching_files = await to_thread(
|
|
191
|
-
process.extract,
|
|
192
|
-
search_term.search_term,
|
|
193
|
-
await file_cache.get_files(),
|
|
194
|
-
limit=MAX_MATCHING_FILES,
|
|
195
|
-
score_cutoff=0,
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
directory = file_cache.working_directory
|
|
199
|
-
files: list[RemoteFile] = [
|
|
200
|
-
RemoteFile(file_path=file, working_directory=directory)
|
|
201
|
-
for file, _, _ in matching_files
|
|
202
|
-
]
|
|
203
|
-
|
|
204
|
-
return GetMatchingFilesResponse(
|
|
205
|
-
files=files,
|
|
206
|
-
correlation_id=search_term.correlation_id,
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
|
|
210
109
|
async def search_files(
|
|
211
110
|
path_str: str,
|
|
212
111
|
file_pattern: str | None,
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"""HTTP fetch implementation for remote execution client."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Any
|
|
5
4
|
|
|
6
5
|
import httpx
|
|
7
6
|
|
|
8
7
|
from exponent.core.remote_execution.cli_rpc_types import (
|
|
9
|
-
HttpResponse,
|
|
10
8
|
HttpRequest,
|
|
9
|
+
HttpResponse,
|
|
11
10
|
)
|
|
12
11
|
|
|
13
12
|
logger = logging.getLogger(__name__)
|
|
@@ -79,7 +78,7 @@ async def fetch_http_content(http_request: HttpRequest) -> HttpResponse:
|
|
|
79
78
|
)
|
|
80
79
|
|
|
81
80
|
except httpx.RequestError as e:
|
|
82
|
-
error_msg = f"Request error for {http_request.url}: {
|
|
81
|
+
error_msg = f"Request error for {http_request.url}: {e!s}"
|
|
83
82
|
return HttpResponse(
|
|
84
83
|
status_code=None,
|
|
85
84
|
content="",
|
|
@@ -87,7 +86,7 @@ async def fetch_http_content(http_request: HttpRequest) -> HttpResponse:
|
|
|
87
86
|
)
|
|
88
87
|
|
|
89
88
|
except Exception as e:
|
|
90
|
-
error_msg = f"Unexpected error fetching {http_request.url}: {
|
|
89
|
+
error_msg = f"Unexpected error fetching {http_request.url}: {e!s}"
|
|
91
90
|
return HttpResponse(
|
|
92
91
|
status_code=None,
|
|
93
92
|
content="",
|
|
@@ -2,14 +2,11 @@ import getpass
|
|
|
2
2
|
import os
|
|
3
3
|
import platform
|
|
4
4
|
|
|
5
|
-
from anyio import Path as AsyncPath
|
|
6
|
-
|
|
7
5
|
from exponent.core.remote_execution.git import get_git_info
|
|
8
6
|
from exponent.core.remote_execution.languages import python_execution
|
|
9
7
|
from exponent.core.remote_execution.types import (
|
|
10
8
|
SystemInfo,
|
|
11
9
|
)
|
|
12
|
-
from exponent.core.remote_execution.utils import safe_read_file
|
|
13
10
|
|
|
14
11
|
|
|
15
12
|
async def get_system_info(working_directory: str) -> SystemInfo:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import uuid
|
|
2
3
|
from collections.abc import Callable
|
|
3
4
|
from pathlib import Path
|
|
@@ -36,9 +37,12 @@ from exponent.core.remote_execution.types import (
|
|
|
36
37
|
)
|
|
37
38
|
from exponent.core.remote_execution.utils import (
|
|
38
39
|
assert_unreachable,
|
|
40
|
+
safe_get_file_metadata,
|
|
39
41
|
safe_read_file,
|
|
40
42
|
)
|
|
41
43
|
|
|
44
|
+
logger = logging.getLogger(__name__)
|
|
45
|
+
|
|
42
46
|
|
|
43
47
|
async def execute_tool(
|
|
44
48
|
tool_input: ToolInputType, working_directory: str
|
|
@@ -116,9 +120,11 @@ async def execute_read_file( # noqa: PLR0911
|
|
|
116
120
|
return ErrorToolResult(
|
|
117
121
|
error_message="File appears to be binary or has invalid text encoding"
|
|
118
122
|
)
|
|
119
|
-
except Exception as e:
|
|
123
|
+
except Exception as e:
|
|
120
124
|
return ErrorToolResult(error_message=f"Error reading file: {e!s}")
|
|
121
125
|
|
|
126
|
+
metadata = await safe_get_file_metadata(file)
|
|
127
|
+
|
|
122
128
|
# Handle empty files
|
|
123
129
|
if not content:
|
|
124
130
|
return ReadToolResult(
|
|
@@ -126,6 +132,7 @@ async def execute_read_file( # noqa: PLR0911
|
|
|
126
132
|
num_lines=0,
|
|
127
133
|
start_line=0,
|
|
128
134
|
total_lines=0,
|
|
135
|
+
metadata=metadata,
|
|
129
136
|
)
|
|
130
137
|
|
|
131
138
|
content_lines = content.splitlines(keepends=True)
|
|
@@ -138,6 +145,7 @@ async def execute_read_file( # noqa: PLR0911
|
|
|
138
145
|
num_lines=0,
|
|
139
146
|
start_line=offset,
|
|
140
147
|
total_lines=total_lines,
|
|
148
|
+
metadata=metadata,
|
|
141
149
|
)
|
|
142
150
|
|
|
143
151
|
# Apply offset and limit
|
|
@@ -180,6 +188,7 @@ async def execute_read_file( # noqa: PLR0911
|
|
|
180
188
|
num_lines=num_lines,
|
|
181
189
|
start_line=offset,
|
|
182
190
|
total_lines=total_lines,
|
|
191
|
+
metadata=metadata,
|
|
183
192
|
)
|
|
184
193
|
|
|
185
194
|
|
|
@@ -213,6 +222,16 @@ async def execute_edit_file( # noqa: PLR0911
|
|
|
213
222
|
if not exists:
|
|
214
223
|
return ErrorToolResult(error_message="File not found")
|
|
215
224
|
|
|
225
|
+
if tool_input.last_known_modified_timestamp is not None:
|
|
226
|
+
metadata = await safe_get_file_metadata(file)
|
|
227
|
+
if (
|
|
228
|
+
metadata is not None
|
|
229
|
+
and metadata.modified_timestamp > tool_input.last_known_modified_timestamp
|
|
230
|
+
):
|
|
231
|
+
return ErrorToolResult(
|
|
232
|
+
error_message="File has been modified since last read/write"
|
|
233
|
+
)
|
|
234
|
+
|
|
216
235
|
try:
|
|
217
236
|
if await file.is_dir():
|
|
218
237
|
return ErrorToolResult(
|
|
@@ -232,7 +251,7 @@ async def execute_edit_file( # noqa: PLR0911
|
|
|
232
251
|
return ErrorToolResult(
|
|
233
252
|
error_message="File appears to be binary or has invalid text encoding"
|
|
234
253
|
)
|
|
235
|
-
except Exception as e:
|
|
254
|
+
except Exception as e:
|
|
236
255
|
return ErrorToolResult(error_message=f"Error reading file: {e!s}")
|
|
237
256
|
|
|
238
257
|
# Check if search text exists
|
|
@@ -265,9 +284,10 @@ async def execute_edit_file( # noqa: PLR0911
|
|
|
265
284
|
path = Path(working_directory, tool_input.file_path)
|
|
266
285
|
await execute_full_file_rewrite(path, new_content, working_directory)
|
|
267
286
|
return EditToolResult(
|
|
268
|
-
message=f"Successfully replaced text in {tool_input.file_path}"
|
|
287
|
+
message=f"Successfully replaced text in {tool_input.file_path}",
|
|
288
|
+
metadata=await safe_get_file_metadata(path),
|
|
269
289
|
)
|
|
270
|
-
except Exception as e:
|
|
290
|
+
except Exception as e:
|
|
271
291
|
return ErrorToolResult(error_message=f"Error writing file: {e!s}")
|
|
272
292
|
|
|
273
293
|
|
|
@@ -123,6 +123,56 @@ class CompositeTruncation(TruncationStrategy):
|
|
|
123
123
|
return result
|
|
124
124
|
|
|
125
125
|
|
|
126
|
+
class TailTruncation(TruncationStrategy):
|
|
127
|
+
"""Truncation strategy that keeps the end of the output (tail) instead of the beginning."""
|
|
128
|
+
|
|
129
|
+
def __init__(
|
|
130
|
+
self,
|
|
131
|
+
field_name: str,
|
|
132
|
+
character_limit: int = DEFAULT_CHARACTER_LIMIT,
|
|
133
|
+
):
|
|
134
|
+
self.field_name = field_name
|
|
135
|
+
self.character_limit = character_limit
|
|
136
|
+
|
|
137
|
+
def should_truncate(self, result: ToolResult) -> bool:
|
|
138
|
+
if hasattr(result, self.field_name):
|
|
139
|
+
value = getattr(result, self.field_name)
|
|
140
|
+
if isinstance(value, str):
|
|
141
|
+
return len(value) > self.character_limit
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
def truncate(self, result: ToolResult) -> ToolResult:
|
|
145
|
+
if not hasattr(result, self.field_name):
|
|
146
|
+
return result
|
|
147
|
+
|
|
148
|
+
value = getattr(result, self.field_name)
|
|
149
|
+
if not isinstance(value, str):
|
|
150
|
+
return result
|
|
151
|
+
|
|
152
|
+
if len(value) <= self.character_limit:
|
|
153
|
+
return result
|
|
154
|
+
|
|
155
|
+
# Keep the last character_limit characters
|
|
156
|
+
truncated_value = value[-self.character_limit :]
|
|
157
|
+
|
|
158
|
+
# Try to start at a newline if possible for cleaner output
|
|
159
|
+
newline_pos = truncated_value.find("\n")
|
|
160
|
+
if (
|
|
161
|
+
newline_pos != -1 and newline_pos < 1000
|
|
162
|
+
): # Only adjust if newline is reasonably close to start
|
|
163
|
+
truncated_value = truncated_value[newline_pos + 1 :]
|
|
164
|
+
|
|
165
|
+
# Add truncation indicator at the beginning
|
|
166
|
+
truncation_msg = f"... (output truncated, showing last {len(truncated_value)} characters) ...\n"
|
|
167
|
+
truncated_value = truncation_msg + truncated_value
|
|
168
|
+
|
|
169
|
+
updates: dict[str, Any] = {self.field_name: truncated_value}
|
|
170
|
+
if hasattr(result, "truncated"):
|
|
171
|
+
updates["truncated"] = True
|
|
172
|
+
|
|
173
|
+
return replace(result, **updates)
|
|
174
|
+
|
|
175
|
+
|
|
126
176
|
class StringListTruncation(TruncationStrategy):
|
|
127
177
|
"""Truncation for lists of strings that limits both number of items and individual string length."""
|
|
128
178
|
|
|
@@ -215,7 +265,7 @@ class StringListTruncation(TruncationStrategy):
|
|
|
215
265
|
TRUNCATION_REGISTRY: dict[type[ToolResult], TruncationStrategy] = {
|
|
216
266
|
ReadToolResult: StringFieldTruncation("content"),
|
|
217
267
|
WriteToolResult: StringFieldTruncation("message"),
|
|
218
|
-
BashToolResult:
|
|
268
|
+
BashToolResult: TailTruncation("shell_output"),
|
|
219
269
|
GrepToolResult: StringListTruncation("matches"),
|
|
220
270
|
GlobToolResult: StringListTruncation("filenames", max_item_length=4096),
|
|
221
271
|
ListToolResult: StringListTruncation("files", max_item_length=4096),
|
|
@@ -236,49 +286,3 @@ def truncate_tool_result(result: T) -> T:
|
|
|
236
286
|
return cast(T, strategy.truncate(result))
|
|
237
287
|
|
|
238
288
|
return result
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
def register_truncation_strategy(
|
|
242
|
-
result_type: type[ToolResult],
|
|
243
|
-
strategy: TruncationStrategy,
|
|
244
|
-
) -> None:
|
|
245
|
-
TRUNCATION_REGISTRY[result_type] = strategy
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
def configure_truncation_limits(
|
|
249
|
-
character_limit: int | None = None,
|
|
250
|
-
list_item_limit: int | None = None,
|
|
251
|
-
list_preview_items: int | None = None,
|
|
252
|
-
string_item_length: int | None = None,
|
|
253
|
-
) -> None:
|
|
254
|
-
for strategy in TRUNCATION_REGISTRY.values():
|
|
255
|
-
if isinstance(strategy, StringFieldTruncation) and character_limit is not None:
|
|
256
|
-
strategy.character_limit = character_limit
|
|
257
|
-
elif isinstance(strategy, ListFieldTruncation):
|
|
258
|
-
if list_item_limit is not None:
|
|
259
|
-
strategy.item_limit = list_item_limit
|
|
260
|
-
if list_preview_items is not None:
|
|
261
|
-
strategy.preview_items = list_preview_items
|
|
262
|
-
elif isinstance(strategy, StringListTruncation):
|
|
263
|
-
if list_item_limit is not None:
|
|
264
|
-
strategy.max_items = list_item_limit
|
|
265
|
-
if list_preview_items is not None:
|
|
266
|
-
strategy.preview_items = list_preview_items
|
|
267
|
-
if string_item_length is not None:
|
|
268
|
-
strategy.max_item_length = string_item_length
|
|
269
|
-
elif isinstance(strategy, CompositeTruncation):
|
|
270
|
-
for sub_strategy in strategy.strategies:
|
|
271
|
-
if isinstance(sub_strategy, StringFieldTruncation) and character_limit:
|
|
272
|
-
sub_strategy.character_limit = character_limit
|
|
273
|
-
elif isinstance(sub_strategy, ListFieldTruncation):
|
|
274
|
-
if list_item_limit is not None:
|
|
275
|
-
sub_strategy.item_limit = list_item_limit
|
|
276
|
-
if list_preview_items is not None:
|
|
277
|
-
sub_strategy.preview_items = list_preview_items
|
|
278
|
-
elif isinstance(sub_strategy, StringListTruncation):
|
|
279
|
-
if list_item_limit is not None:
|
|
280
|
-
sub_strategy.max_items = list_item_limit
|
|
281
|
-
if list_preview_items is not None:
|
|
282
|
-
sub_strategy.preview_items = list_preview_items
|
|
283
|
-
if string_item_length is not None:
|
|
284
|
-
sub_strategy.max_item_length = string_item_length
|
|
@@ -11,7 +11,6 @@ from typing import (
|
|
|
11
11
|
Generic,
|
|
12
12
|
Literal,
|
|
13
13
|
TypeVar,
|
|
14
|
-
Union,
|
|
15
14
|
)
|
|
16
15
|
|
|
17
16
|
from anyio import Path as AsyncPath
|
|
@@ -99,6 +98,7 @@ class HeartbeatInfo(BaseModel):
|
|
|
99
98
|
default_factory=lambda: datetime.datetime.now(datetime.UTC)
|
|
100
99
|
)
|
|
101
100
|
timestamp_received: datetime.datetime | None = None
|
|
101
|
+
cli_uuid: str | None = None
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
class RemoteFile(BaseModel):
|
|
@@ -226,9 +226,6 @@ Namespace = Literal[
|
|
|
226
226
|
"file_write",
|
|
227
227
|
"command",
|
|
228
228
|
"list_files",
|
|
229
|
-
"get_file_attachment",
|
|
230
|
-
"get_file_attachments",
|
|
231
|
-
"get_matching_files",
|
|
232
229
|
"error",
|
|
233
230
|
"create_checkpoint",
|
|
234
231
|
"rollback_to_checkpoint",
|
|
@@ -333,24 +330,6 @@ class ListFilesResponse(RemoteExecutionResponse):
|
|
|
333
330
|
files: list[RemoteFile]
|
|
334
331
|
|
|
335
332
|
|
|
336
|
-
class GetFileAttachmentResponse(RemoteExecutionResponse, FileAttachment):
|
|
337
|
-
namespace: ClassVar[Namespace] = "get_file_attachment"
|
|
338
|
-
|
|
339
|
-
exists: bool = Field(default=True)
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
class GetFileAttachmentsResponse(RemoteExecutionResponse):
|
|
343
|
-
namespace: ClassVar[Namespace] = "get_file_attachments"
|
|
344
|
-
|
|
345
|
-
file_attachments: list[FileAttachment]
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
class GetMatchingFilesResponse(RemoteExecutionResponse):
|
|
349
|
-
namespace: ClassVar[Namespace] = "get_matching_files"
|
|
350
|
-
|
|
351
|
-
files: list[RemoteFile]
|
|
352
|
-
|
|
353
|
-
|
|
354
333
|
class ErrorResponse(RemoteExecutionResponse):
|
|
355
334
|
namespace: ClassVar[Namespace] = "error"
|
|
356
335
|
# The namespace of the request that caused the error.
|
|
@@ -425,7 +404,7 @@ class CodeExecutionRequest(RemoteExecutionRequest[CodeExecutionResponse]):
|
|
|
425
404
|
|
|
426
405
|
class StreamingCodeExecutionRequest(
|
|
427
406
|
RemoteExecutionRequest[
|
|
428
|
-
|
|
407
|
+
StreamingCodeExecutionResponseChunk | StreamingCodeExecutionResponse
|
|
429
408
|
]
|
|
430
409
|
):
|
|
431
410
|
namespace: ClassVar[Namespace] = "streaming_code_execution"
|
|
@@ -452,24 +431,6 @@ class ListFilesRequest(RemoteExecutionRequest[ListFilesResponse]):
|
|
|
452
431
|
directory: str
|
|
453
432
|
|
|
454
433
|
|
|
455
|
-
class GetFileAttachmentRequest(RemoteExecutionRequest[GetFileAttachmentResponse]):
|
|
456
|
-
namespace: ClassVar[Namespace] = "get_file_attachment"
|
|
457
|
-
|
|
458
|
-
file: RemoteFile
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
class GetFileAttachmentsRequest(RemoteExecutionRequest[GetFileAttachmentsResponse]):
|
|
462
|
-
namespace: ClassVar[Namespace] = "get_file_attachments"
|
|
463
|
-
|
|
464
|
-
files: list[RemoteFile]
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
class GetMatchingFilesRequest(RemoteExecutionRequest[GetMatchingFilesResponse]):
|
|
468
|
-
namespace: ClassVar[Namespace] = "get_matching_files"
|
|
469
|
-
|
|
470
|
-
search_term: str
|
|
471
|
-
|
|
472
|
-
|
|
473
434
|
class CreateCheckpointRequest(RemoteExecutionRequest[CreateCheckpointResponse]):
|
|
474
435
|
namespace: ClassVar[Namespace] = "create_checkpoint"
|
|
475
436
|
|
|
@@ -508,39 +469,31 @@ class CommandRequest(RemoteExecutionRequest[CommandResponse]):
|
|
|
508
469
|
data: CommandDataType = Field(..., discriminator="type")
|
|
509
470
|
|
|
510
471
|
|
|
511
|
-
RemoteExecutionRequestType =
|
|
512
|
-
CodeExecutionRequest
|
|
513
|
-
FileWriteRequest
|
|
514
|
-
ListFilesRequest
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
CreateCheckpointRequest,
|
|
521
|
-
RollbackToCheckpointRequest,
|
|
522
|
-
]
|
|
472
|
+
RemoteExecutionRequestType = (
|
|
473
|
+
CodeExecutionRequest
|
|
474
|
+
| FileWriteRequest
|
|
475
|
+
| ListFilesRequest
|
|
476
|
+
| CommandRequest
|
|
477
|
+
| StreamingCodeExecutionRequest
|
|
478
|
+
| CreateCheckpointRequest
|
|
479
|
+
| RollbackToCheckpointRequest
|
|
480
|
+
)
|
|
523
481
|
|
|
524
|
-
RemoteExecutionResponseType =
|
|
525
|
-
CodeExecutionResponse
|
|
526
|
-
StreamingCodeExecutionResponseChunk
|
|
527
|
-
StreamingCodeExecutionResponse
|
|
528
|
-
FileWriteResponse
|
|
529
|
-
ListFilesResponse
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
CreateCheckpointResponse,
|
|
536
|
-
RollbackToCheckpointResponse,
|
|
537
|
-
]
|
|
482
|
+
RemoteExecutionResponseType = (
|
|
483
|
+
CodeExecutionResponse
|
|
484
|
+
| StreamingCodeExecutionResponseChunk
|
|
485
|
+
| StreamingCodeExecutionResponse
|
|
486
|
+
| FileWriteResponse
|
|
487
|
+
| ListFilesResponse
|
|
488
|
+
| CommandResponse
|
|
489
|
+
| ErrorResponse
|
|
490
|
+
| CreateCheckpointResponse
|
|
491
|
+
| RollbackToCheckpointResponse
|
|
492
|
+
)
|
|
538
493
|
|
|
539
|
-
StreamingResponseType =
|
|
540
|
-
StreamingCodeExecutionResponseChunk
|
|
541
|
-
|
|
542
|
-
ErrorResponse,
|
|
543
|
-
]
|
|
494
|
+
StreamingResponseType = (
|
|
495
|
+
StreamingCodeExecutionResponseChunk | StreamingCodeExecutionResponse | ErrorResponse
|
|
496
|
+
)
|
|
544
497
|
|
|
545
498
|
STREAMING_NAMESPACES = [
|
|
546
499
|
"streaming_code_execution",
|
|
@@ -553,17 +506,10 @@ class ChatMode(str, Enum):
|
|
|
553
506
|
CLI = "CLI"
|
|
554
507
|
CLOUD = "CLOUD" # chat with cloud devbox
|
|
555
508
|
CODEBASE = "CODEBASE" # chat with codebase
|
|
556
|
-
PYTHON_INTERPRETER = "PYTHON_INTERPRETER"
|
|
557
509
|
DATABASE = "DATABASE" # chat with database connection
|
|
558
510
|
WORKFLOW = "WORKFLOW"
|
|
559
511
|
|
|
560
512
|
|
|
561
|
-
DEVBOX_CHAT_MODES = [
|
|
562
|
-
ChatMode.CLOUD,
|
|
563
|
-
ChatMode.CODEBASE,
|
|
564
|
-
]
|
|
565
|
-
|
|
566
|
-
|
|
567
513
|
class ChatSource(str, Enum):
|
|
568
514
|
CLI_SHELL = "CLI_SHELL"
|
|
569
515
|
CLI_RUN = "CLI_RUN"
|